1 /* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */ 2 /* $FreeBSD$ */ 3 4 /*- 5 * SPDX-License-Identifier: BSD-4-Clause 6 * 7 * Copyright (c) 1997 Jason R. Thorpe. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed for the NetBSD Project 21 * by Jason R. Thorpe. 22 * 4. The name of the author may not be used to endorse or promote products 23 * derived from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 /* 39 * Copyright (c) 1983, 1993 40 * The Regents of the University of California. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 4. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 */ 66 67 #include <sys/param.h> 68 #include <sys/ioctl.h> 69 #include <sys/socket.h> 70 #include <sys/sysctl.h> 71 #include <sys/time.h> 72 73 #include <net/if.h> 74 #include <net/if_dl.h> 75 #include <net/if_types.h> 76 #include <net/if_media.h> 77 #include <net/route.h> 78 79 #include <ctype.h> 80 #include <err.h> 81 #include <errno.h> 82 #include <fcntl.h> 83 #include <stdbool.h> 84 #include <stdio.h> 85 #include <stdlib.h> 86 #include <string.h> 87 #include <unistd.h> 88 89 #include <libifconfig.h> 90 91 #include "ifconfig.h" 92 93 static void domediaopt(if_ctx *, const char *, bool); 94 static ifmedia_t get_media_subtype(ifmedia_t, const char *); 95 static ifmedia_t get_media_mode(ifmedia_t, const char *); 96 static ifmedia_t get_media_options(ifmedia_t, const char *); 97 static void print_media(ifmedia_t, bool); 98 static void print_media_ifconfig(ifmedia_t); 99 100 static void 101 media_status(if_ctx *ctx) 102 { 103 struct ifmediareq *ifmr; 104 105 if (ifconfig_media_get_mediareq(lifh, ctx->ifname, &ifmr) == -1) 106 return; 107 108 if (ifmr->ifm_count == 0) { 109 warnx("%s: no media types?", ctx->ifname); 110 goto free; 111 } 112 113 printf("\tmedia: "); 114 print_media(ifmr->ifm_current, true); 115 if (ifmr->ifm_active != ifmr->ifm_current) { 116 putchar(' '); 117 putchar('('); 118 print_media(ifmr->ifm_active, false); 119 putchar(')'); 120 } 121 122 putchar('\n'); 123 124 if (ifmr->ifm_status & IFM_AVALID) { 125 struct ifdownreason ifdr; 126 const char *status; 127 128 status = ifconfig_media_get_status(ifmr); 129 printf("\tstatus: %s", status); 130 if (strcmp(status, "no carrier") == 0 && 131 ifconfig_media_get_downreason(lifh, ctx->ifname, &ifdr) == 0) { 132 switch (ifdr.ifdr_reason) { 133 case IFDR_REASON_MSG: 134 printf(" (%s)", ifdr.ifdr_msg); 135 break; 136 case IFDR_REASON_VENDOR: 137 printf(" (vendor code %d)", 138 ifdr.ifdr_vendor); 139 break; 140 default: 141 break; 142 } 143 } 144 putchar('\n'); 145 } 146 147 if (ctx->args->supmedia) { 148 printf("\tsupported media:\n"); 149 for (int i = 0; i < ifmr->ifm_count; ++i) { 150 printf("\t\t"); 151 print_media_ifconfig(ifmr->ifm_ulist[i]); 152 putchar('\n'); 153 } 154 } 155 free: 156 free(ifmr); 157 } 158 159 struct ifmediareq * 160 ifmedia_getstate(if_ctx *ctx) 161 { 162 static struct ifmediareq *ifmr = NULL; 163 164 if (ifmr != NULL) 165 return (ifmr); 166 167 if (ifconfig_media_get_mediareq(lifh, ctx->ifname, &ifmr) == -1) 168 errc(1, ifconfig_err_errno(lifh), 169 "%s: ifconfig_media_get_mediareq", ctx->ifname); 170 171 if (ifmr->ifm_count == 0) 172 errx(1, "%s: no media types?", ctx->ifname); 173 174 return (ifmr); 175 } 176 177 static void 178 setifmediacallback(if_ctx *ctx, void *arg) 179 { 180 struct ifmediareq *ifmr = (struct ifmediareq *)arg; 181 static bool did_it = false; 182 183 if (!did_it) { 184 ifr.ifr_media = ifmr->ifm_current; 185 if (ioctl_ctx(ctx, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) 186 err(1, "SIOCSIFMEDIA (media)"); 187 free(ifmr); 188 did_it = true; 189 } 190 } 191 192 static void 193 setmedia(if_ctx *ctx, const char *val, int d __unused) 194 { 195 struct ifmediareq *ifmr; 196 int subtype; 197 198 ifmr = ifmedia_getstate(ctx); 199 200 /* 201 * We are primarily concerned with the top-level type. 202 * However, "current" may be only IFM_NONE, so we just look 203 * for the top-level type in the first "supported type" 204 * entry. 205 * 206 * (I'm assuming that all supported media types for a given 207 * interface will be the same top-level type..) 208 */ 209 subtype = get_media_subtype(ifmr->ifm_ulist[0], val); 210 211 strlcpy(ifr.ifr_name, ctx->ifname, sizeof(ifr.ifr_name)); 212 ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) | 213 IFM_TYPE(ifmr->ifm_ulist[0]) | subtype; 214 215 ifmr->ifm_current = ifr.ifr_media; 216 callback_register(setifmediacallback, (void *)ifmr); 217 } 218 219 static void 220 setmediaopt(if_ctx *ctx, const char *val, int d __unused) 221 { 222 223 domediaopt(ctx, val, false); 224 } 225 226 static void 227 unsetmediaopt(if_ctx *ctx, const char *val, int d __unused) 228 { 229 230 domediaopt(ctx, val, true); 231 } 232 233 static void 234 domediaopt(if_ctx *ctx, const char *val, bool clear) 235 { 236 struct ifmediareq *ifmr; 237 ifmedia_t options; 238 239 ifmr = ifmedia_getstate(ctx); 240 241 options = get_media_options(ifmr->ifm_ulist[0], val); 242 243 strlcpy(ifr.ifr_name, ctx->ifname, sizeof(ifr.ifr_name)); 244 ifr.ifr_media = ifmr->ifm_current; 245 if (clear) 246 ifr.ifr_media &= ~options; 247 else { 248 if (options & IFM_HDX) { 249 ifr.ifr_media &= ~IFM_FDX; 250 options &= ~IFM_HDX; 251 } 252 ifr.ifr_media |= options; 253 } 254 ifmr->ifm_current = ifr.ifr_media; 255 callback_register(setifmediacallback, (void *)ifmr); 256 } 257 258 static void 259 setmediainst(if_ctx *ctx, const char *val, int d __unused) 260 { 261 struct ifmediareq *ifmr; 262 int inst; 263 264 ifmr = ifmedia_getstate(ctx); 265 266 inst = atoi(val); 267 if (inst < 0 || inst > (int)IFM_INST_MAX) 268 errx(1, "invalid media instance: %s", val); 269 270 strlcpy(ifr.ifr_name, ctx->ifname, sizeof(ifr.ifr_name)); 271 ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT; 272 273 ifmr->ifm_current = ifr.ifr_media; 274 callback_register(setifmediacallback, (void *)ifmr); 275 } 276 277 static void 278 setmediamode(if_ctx *ctx, const char *val, int d __unused) 279 { 280 struct ifmediareq *ifmr; 281 int mode; 282 283 ifmr = ifmedia_getstate(ctx); 284 285 mode = get_media_mode(ifmr->ifm_ulist[0], val); 286 287 strlcpy(ifr.ifr_name, ctx->ifname, sizeof(ifr.ifr_name)); 288 ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode; 289 290 ifmr->ifm_current = ifr.ifr_media; 291 callback_register(setifmediacallback, (void *)ifmr); 292 } 293 294 static ifmedia_t 295 get_media_subtype(ifmedia_t media, const char *val) 296 { 297 ifmedia_t subtype; 298 299 subtype = ifconfig_media_lookup_subtype(media, val); 300 if (subtype != INVALID_IFMEDIA) 301 return (subtype); 302 switch (errno) { 303 case EINVAL: 304 errx(EXIT_FAILURE, "unknown media type 0x%x", media); 305 case ENOENT: 306 errx(EXIT_FAILURE, "unknown media subtype: %s", val); 307 default: 308 err(EXIT_FAILURE, "ifconfig_media_lookup_subtype"); 309 } 310 /*NOTREACHED*/ 311 } 312 313 static ifmedia_t 314 get_media_mode(ifmedia_t media, const char *val) 315 { 316 ifmedia_t mode; 317 318 mode = ifconfig_media_lookup_mode(media, val); 319 if (mode != INVALID_IFMEDIA) 320 return (mode); 321 switch (errno) { 322 case EINVAL: 323 errx(EXIT_FAILURE, "unknown media type 0x%x", media); 324 case ENOENT: 325 return (INVALID_IFMEDIA); 326 default: 327 err(EXIT_FAILURE, "ifconfig_media_lookup_subtype"); 328 } 329 /*NOTREACHED*/ 330 } 331 332 static ifmedia_t 333 get_media_options(ifmedia_t media, const char *val) 334 { 335 ifmedia_t *options; 336 const char **optnames; 337 char *opts, *opt; 338 size_t nopts; 339 int rval; 340 341 /* 342 * We muck with the string, so copy it. 343 */ 344 opts = strdup(val); 345 if (opts == NULL) 346 err(EXIT_FAILURE, "strdup"); 347 348 /* 349 * Split the comma-delimited list into separate strings. 350 */ 351 nopts = 0; 352 for (opt = opts; (opt = strtok(opt, ",")) != NULL; opt = NULL) 353 ++nopts; 354 if (nopts == 0) { 355 free(opts); 356 return (0); 357 } 358 optnames = calloc(nopts, sizeof(*optnames)); 359 if (optnames == NULL) 360 err(EXIT_FAILURE, "calloc"); 361 opt = opts; 362 for (size_t i = 0; i < nopts; ++i) { 363 optnames[i] = opt; 364 opt = strchr(opt, '\0') + 1; 365 } 366 367 /* 368 * Look up the options in the user-provided list. 369 */ 370 options = ifconfig_media_lookup_options(media, optnames, nopts); 371 if (options == NULL) 372 err(EXIT_FAILURE, "ifconfig_media_lookup_options"); 373 rval = 0; 374 for (size_t i = 0; i < nopts; ++i) { 375 if (options[i] == INVALID_IFMEDIA) 376 errx(EXIT_FAILURE, "unknown option: %s", optnames[i]); 377 rval |= options[i]; 378 } 379 free(options); 380 free(optnames); 381 free(opts); 382 return (rval); 383 } 384 385 static void 386 print_media(ifmedia_t media, bool print_toptype) 387 { 388 const char *val, **options; 389 390 val = ifconfig_media_get_type(media); 391 if (val == NULL) { 392 printf("<unknown type>"); 393 return; 394 } else if (print_toptype) { 395 printf("%s", val); 396 } 397 398 val = ifconfig_media_get_subtype(media); 399 if (val == NULL) { 400 printf("<unknown subtype>"); 401 return; 402 } 403 404 if (print_toptype) 405 putchar(' '); 406 407 printf("%s", val); 408 409 if (print_toptype) { 410 val = ifconfig_media_get_mode(media); 411 if (val != NULL && strcasecmp("autoselect", val) != 0) 412 printf(" mode %s", val); 413 } 414 415 options = ifconfig_media_get_options(media); 416 if (options != NULL && options[0] != NULL) { 417 printf(" <%s", options[0]); 418 for (size_t i = 1; options[i] != NULL; ++i) 419 printf(",%s", options[i]); 420 printf(">"); 421 } 422 free(options); 423 424 if (print_toptype && IFM_INST(media) != 0) 425 printf(" instance %d", IFM_INST(media)); 426 } 427 428 static void 429 print_media_ifconfig(ifmedia_t media) 430 { 431 const char *val, **options; 432 433 val = ifconfig_media_get_type(media); 434 if (val == NULL) { 435 printf("<unknown type>"); 436 return; 437 } 438 439 /* 440 * Don't print the top-level type; it's not like we can 441 * change it, or anything. 442 */ 443 444 val = ifconfig_media_get_subtype(media); 445 if (val == NULL) { 446 printf("<unknown subtype>"); 447 return; 448 } 449 450 printf("media %s", val); 451 452 val = ifconfig_media_get_mode(media); 453 if (val != NULL) 454 printf(" mode %s", val); 455 456 options = ifconfig_media_get_options(media); 457 if (options != NULL && options[0] != NULL) { 458 printf(" mediaopt %s", options[0]); 459 for (size_t i = 1; options[i] != NULL; ++i) 460 printf(",%s", options[i]); 461 } 462 free(options); 463 464 if (IFM_INST(media) != 0) 465 printf(" instance %d", IFM_INST(media)); 466 } 467 468 /********************************************************************** 469 * ...until here. 470 **********************************************************************/ 471 472 static struct cmd media_cmds[] = { 473 DEF_CMD_ARG("media", setmedia), 474 DEF_CMD_ARG("mode", setmediamode), 475 DEF_CMD_ARG("mediaopt", setmediaopt), 476 DEF_CMD_ARG("-mediaopt",unsetmediaopt), 477 DEF_CMD_ARG("inst", setmediainst), 478 DEF_CMD_ARG("instance", setmediainst), 479 }; 480 static struct afswtch af_media = { 481 .af_name = "af_media", 482 .af_af = AF_UNSPEC, 483 .af_other_status = media_status, 484 }; 485 486 static __constructor void 487 ifmedia_ctor(void) 488 { 489 for (size_t i = 0; i < nitems(media_cmds); i++) 490 cmd_register(&media_cmds[i]); 491 af_register(&af_media); 492 } 493