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 <stdio.h> 84 #include <stdlib.h> 85 #include <string.h> 86 #include <unistd.h> 87 88 #include "ifconfig.h" 89 90 static void domediaopt(const char *, int, int); 91 static int get_media_subtype(int, const char *); 92 static int get_media_mode(int, const char *); 93 static int get_media_options(int, const char *); 94 static int lookup_media_word(struct ifmedia_description *, const char *); 95 static void print_media_word(int, int); 96 static void print_media_word_ifconfig(int); 97 98 static struct ifmedia_description *get_toptype_desc(int); 99 static struct ifmedia_type_to_subtype *get_toptype_ttos(int); 100 static struct ifmedia_description *get_subtype_desc(int, 101 struct ifmedia_type_to_subtype *ttos); 102 103 #define IFM_OPMODE(x) \ 104 ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \ 105 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \ 106 IFM_IEEE80211_MBSS)) 107 #define IFM_IEEE80211_STA 0 108 109 static void 110 media_status(int s) 111 { 112 struct ifmediareq ifmr; 113 int *media_list, i; 114 int xmedia = 1; 115 116 (void) memset(&ifmr, 0, sizeof(ifmr)); 117 (void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 118 119 /* 120 * Check if interface supports extended media types. 121 */ 122 if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) 123 xmedia = 0; 124 if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 125 /* 126 * Interface doesn't support SIOC{G,S}IFMEDIA. 127 */ 128 return; 129 } 130 131 if (ifmr.ifm_count == 0) { 132 warnx("%s: no media types?", name); 133 return; 134 } 135 136 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); 137 if (media_list == NULL) 138 err(1, "malloc"); 139 ifmr.ifm_ulist = media_list; 140 141 if (xmedia) { 142 if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) 143 err(1, "SIOCGIFXMEDIA"); 144 } else { 145 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 146 err(1, "SIOCGIFMEDIA"); 147 } 148 149 printf("\tmedia: "); 150 print_media_word(ifmr.ifm_current, 1); 151 if (ifmr.ifm_active != ifmr.ifm_current) { 152 putchar(' '); 153 putchar('('); 154 print_media_word(ifmr.ifm_active, 0); 155 putchar(')'); 156 } 157 158 putchar('\n'); 159 160 if (ifmr.ifm_status & IFM_AVALID) { 161 printf("\tstatus: "); 162 switch (IFM_TYPE(ifmr.ifm_active)) { 163 case IFM_ETHER: 164 case IFM_ATM: 165 if (ifmr.ifm_status & IFM_ACTIVE) 166 printf("active"); 167 else 168 printf("no carrier"); 169 break; 170 171 case IFM_FDDI: 172 case IFM_TOKEN: 173 if (ifmr.ifm_status & IFM_ACTIVE) 174 printf("inserted"); 175 else 176 printf("no ring"); 177 break; 178 179 case IFM_IEEE80211: 180 if (ifmr.ifm_status & IFM_ACTIVE) { 181 /* NB: only sta mode associates */ 182 if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA) 183 printf("associated"); 184 else 185 printf("running"); 186 } else 187 printf("no carrier"); 188 break; 189 } 190 putchar('\n'); 191 } 192 193 if (ifmr.ifm_count > 0 && supmedia) { 194 printf("\tsupported media:\n"); 195 for (i = 0; i < ifmr.ifm_count; i++) { 196 printf("\t\t"); 197 print_media_word_ifconfig(media_list[i]); 198 putchar('\n'); 199 } 200 } 201 202 free(media_list); 203 } 204 205 struct ifmediareq * 206 ifmedia_getstate(int s) 207 { 208 static struct ifmediareq *ifmr = NULL; 209 int *mwords; 210 int xmedia = 1; 211 212 if (ifmr == NULL) { 213 ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq)); 214 if (ifmr == NULL) 215 err(1, "malloc"); 216 217 (void) memset(ifmr, 0, sizeof(struct ifmediareq)); 218 (void) strlcpy(ifmr->ifm_name, name, 219 sizeof(ifmr->ifm_name)); 220 221 ifmr->ifm_count = 0; 222 ifmr->ifm_ulist = NULL; 223 224 /* 225 * We must go through the motions of reading all 226 * supported media because we need to know both 227 * the current media type and the top-level type. 228 */ 229 230 if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) { 231 xmedia = 0; 232 } 233 if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) { 234 err(1, "SIOCGIFMEDIA"); 235 } 236 237 if (ifmr->ifm_count == 0) 238 errx(1, "%s: no media types?", name); 239 240 mwords = (int *)malloc(ifmr->ifm_count * sizeof(int)); 241 if (mwords == NULL) 242 err(1, "malloc"); 243 244 ifmr->ifm_ulist = mwords; 245 if (xmedia) { 246 if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) 247 err(1, "SIOCGIFXMEDIA"); 248 } else { 249 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) 250 err(1, "SIOCGIFMEDIA"); 251 } 252 } 253 254 return ifmr; 255 } 256 257 static void 258 setifmediacallback(int s, void *arg) 259 { 260 struct ifmediareq *ifmr = (struct ifmediareq *)arg; 261 static int did_it = 0; 262 263 if (!did_it) { 264 ifr.ifr_media = ifmr->ifm_current; 265 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) 266 err(1, "SIOCSIFMEDIA (media)"); 267 free(ifmr->ifm_ulist); 268 free(ifmr); 269 did_it = 1; 270 } 271 } 272 273 static void 274 setmedia(const char *val, int d, int s, const struct afswtch *afp) 275 { 276 struct ifmediareq *ifmr; 277 int subtype; 278 279 ifmr = ifmedia_getstate(s); 280 281 /* 282 * We are primarily concerned with the top-level type. 283 * However, "current" may be only IFM_NONE, so we just look 284 * for the top-level type in the first "supported type" 285 * entry. 286 * 287 * (I'm assuming that all supported media types for a given 288 * interface will be the same top-level type..) 289 */ 290 subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val); 291 292 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 293 ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) | 294 IFM_TYPE(ifmr->ifm_ulist[0]) | subtype; 295 296 ifmr->ifm_current = ifr.ifr_media; 297 callback_register(setifmediacallback, (void *)ifmr); 298 } 299 300 static void 301 setmediaopt(const char *val, int d, int s, const struct afswtch *afp) 302 { 303 304 domediaopt(val, 0, s); 305 } 306 307 static void 308 unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp) 309 { 310 311 domediaopt(val, 1, s); 312 } 313 314 static void 315 domediaopt(const char *val, int clear, int s) 316 { 317 struct ifmediareq *ifmr; 318 int options; 319 320 ifmr = ifmedia_getstate(s); 321 322 options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val); 323 324 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 325 ifr.ifr_media = ifmr->ifm_current; 326 if (clear) 327 ifr.ifr_media &= ~options; 328 else { 329 if (options & IFM_HDX) { 330 ifr.ifr_media &= ~IFM_FDX; 331 options &= ~IFM_HDX; 332 } 333 ifr.ifr_media |= options; 334 } 335 ifmr->ifm_current = ifr.ifr_media; 336 callback_register(setifmediacallback, (void *)ifmr); 337 } 338 339 static void 340 setmediainst(const char *val, int d, int s, const struct afswtch *afp) 341 { 342 struct ifmediareq *ifmr; 343 int inst; 344 345 ifmr = ifmedia_getstate(s); 346 347 inst = atoi(val); 348 if (inst < 0 || inst > (int)IFM_INST_MAX) 349 errx(1, "invalid media instance: %s", val); 350 351 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 352 ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT; 353 354 ifmr->ifm_current = ifr.ifr_media; 355 callback_register(setifmediacallback, (void *)ifmr); 356 } 357 358 static void 359 setmediamode(const char *val, int d, int s, const struct afswtch *afp) 360 { 361 struct ifmediareq *ifmr; 362 int mode; 363 364 ifmr = ifmedia_getstate(s); 365 366 mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val); 367 368 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 369 ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode; 370 371 ifmr->ifm_current = ifr.ifr_media; 372 callback_register(setifmediacallback, (void *)ifmr); 373 } 374 375 /********************************************************************** 376 * A good chunk of this is duplicated from sys/net/if_media.c 377 **********************************************************************/ 378 379 static struct ifmedia_description ifm_type_descriptions[] = 380 IFM_TYPE_DESCRIPTIONS; 381 382 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = 383 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; 384 385 static struct ifmedia_description ifm_subtype_ethernet_aliases[] = 386 IFM_SUBTYPE_ETHERNET_ALIASES; 387 388 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = 389 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; 390 391 static struct ifmedia_description ifm_subtype_tokenring_descriptions[] = 392 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; 393 394 static struct ifmedia_description ifm_subtype_tokenring_aliases[] = 395 IFM_SUBTYPE_TOKENRING_ALIASES; 396 397 static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = 398 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; 399 400 static struct ifmedia_description ifm_subtype_fddi_descriptions[] = 401 IFM_SUBTYPE_FDDI_DESCRIPTIONS; 402 403 static struct ifmedia_description ifm_subtype_fddi_aliases[] = 404 IFM_SUBTYPE_FDDI_ALIASES; 405 406 static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = 407 IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; 408 409 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = 410 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; 411 412 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] = 413 IFM_SUBTYPE_IEEE80211_ALIASES; 414 415 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = 416 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; 417 418 struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = 419 IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; 420 421 struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] = 422 IFM_SUBTYPE_IEEE80211_MODE_ALIASES; 423 424 static struct ifmedia_description ifm_subtype_atm_descriptions[] = 425 IFM_SUBTYPE_ATM_DESCRIPTIONS; 426 427 static struct ifmedia_description ifm_subtype_atm_aliases[] = 428 IFM_SUBTYPE_ATM_ALIASES; 429 430 static struct ifmedia_description ifm_subtype_atm_option_descriptions[] = 431 IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS; 432 433 static struct ifmedia_description ifm_subtype_shared_descriptions[] = 434 IFM_SUBTYPE_SHARED_DESCRIPTIONS; 435 436 static struct ifmedia_description ifm_subtype_shared_aliases[] = 437 IFM_SUBTYPE_SHARED_ALIASES; 438 439 static struct ifmedia_description ifm_shared_option_descriptions[] = 440 IFM_SHARED_OPTION_DESCRIPTIONS; 441 442 static struct ifmedia_description ifm_shared_option_aliases[] = 443 IFM_SHARED_OPTION_ALIASES; 444 445 struct ifmedia_type_to_subtype { 446 struct { 447 struct ifmedia_description *desc; 448 int alias; 449 } subtypes[5]; 450 struct { 451 struct ifmedia_description *desc; 452 int alias; 453 } options[4]; 454 struct { 455 struct ifmedia_description *desc; 456 int alias; 457 } modes[3]; 458 }; 459 460 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ 461 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { 462 { 463 { 464 { &ifm_subtype_shared_descriptions[0], 0 }, 465 { &ifm_subtype_shared_aliases[0], 1 }, 466 { &ifm_subtype_ethernet_descriptions[0], 0 }, 467 { &ifm_subtype_ethernet_aliases[0], 1 }, 468 { NULL, 0 }, 469 }, 470 { 471 { &ifm_shared_option_descriptions[0], 0 }, 472 { &ifm_shared_option_aliases[0], 1 }, 473 { &ifm_subtype_ethernet_option_descriptions[0], 0 }, 474 { NULL, 0 }, 475 }, 476 { 477 { NULL, 0 }, 478 }, 479 }, 480 { 481 { 482 { &ifm_subtype_shared_descriptions[0], 0 }, 483 { &ifm_subtype_shared_aliases[0], 1 }, 484 { &ifm_subtype_tokenring_descriptions[0], 0 }, 485 { &ifm_subtype_tokenring_aliases[0], 1 }, 486 { NULL, 0 }, 487 }, 488 { 489 { &ifm_shared_option_descriptions[0], 0 }, 490 { &ifm_shared_option_aliases[0], 1 }, 491 { &ifm_subtype_tokenring_option_descriptions[0], 0 }, 492 { NULL, 0 }, 493 }, 494 { 495 { NULL, 0 }, 496 }, 497 }, 498 { 499 { 500 { &ifm_subtype_shared_descriptions[0], 0 }, 501 { &ifm_subtype_shared_aliases[0], 1 }, 502 { &ifm_subtype_fddi_descriptions[0], 0 }, 503 { &ifm_subtype_fddi_aliases[0], 1 }, 504 { NULL, 0 }, 505 }, 506 { 507 { &ifm_shared_option_descriptions[0], 0 }, 508 { &ifm_shared_option_aliases[0], 1 }, 509 { &ifm_subtype_fddi_option_descriptions[0], 0 }, 510 { NULL, 0 }, 511 }, 512 { 513 { NULL, 0 }, 514 }, 515 }, 516 { 517 { 518 { &ifm_subtype_shared_descriptions[0], 0 }, 519 { &ifm_subtype_shared_aliases[0], 1 }, 520 { &ifm_subtype_ieee80211_descriptions[0], 0 }, 521 { &ifm_subtype_ieee80211_aliases[0], 1 }, 522 { NULL, 0 }, 523 }, 524 { 525 { &ifm_shared_option_descriptions[0], 0 }, 526 { &ifm_shared_option_aliases[0], 1 }, 527 { &ifm_subtype_ieee80211_option_descriptions[0], 0 }, 528 { NULL, 0 }, 529 }, 530 { 531 { &ifm_subtype_ieee80211_mode_descriptions[0], 0 }, 532 { &ifm_subtype_ieee80211_mode_aliases[0], 0 }, 533 { NULL, 0 }, 534 }, 535 }, 536 { 537 { 538 { &ifm_subtype_shared_descriptions[0], 0 }, 539 { &ifm_subtype_shared_aliases[0], 1 }, 540 { &ifm_subtype_atm_descriptions[0], 0 }, 541 { &ifm_subtype_atm_aliases[0], 1 }, 542 { NULL, 0 }, 543 }, 544 { 545 { &ifm_shared_option_descriptions[0], 0 }, 546 { &ifm_shared_option_aliases[0], 1 }, 547 { &ifm_subtype_atm_option_descriptions[0], 0 }, 548 { NULL, 0 }, 549 }, 550 { 551 { NULL, 0 }, 552 }, 553 }, 554 }; 555 556 static int 557 get_media_subtype(int type, const char *val) 558 { 559 struct ifmedia_description *desc; 560 struct ifmedia_type_to_subtype *ttos; 561 int rval, i; 562 563 /* Find the top-level interface type. */ 564 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 565 desc->ifmt_string != NULL; desc++, ttos++) 566 if (type == desc->ifmt_word) 567 break; 568 if (desc->ifmt_string == NULL) 569 errx(1, "unknown media type 0x%x", type); 570 571 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 572 rval = lookup_media_word(ttos->subtypes[i].desc, val); 573 if (rval != -1) 574 return (rval); 575 } 576 errx(1, "unknown media subtype: %s", val); 577 /*NOTREACHED*/ 578 } 579 580 static int 581 get_media_mode(int type, const char *val) 582 { 583 struct ifmedia_description *desc; 584 struct ifmedia_type_to_subtype *ttos; 585 int rval, i; 586 587 /* Find the top-level interface type. */ 588 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 589 desc->ifmt_string != NULL; desc++, ttos++) 590 if (type == desc->ifmt_word) 591 break; 592 if (desc->ifmt_string == NULL) 593 errx(1, "unknown media mode 0x%x", type); 594 595 for (i = 0; ttos->modes[i].desc != NULL; i++) { 596 rval = lookup_media_word(ttos->modes[i].desc, val); 597 if (rval != -1) 598 return (rval); 599 } 600 return -1; 601 } 602 603 static int 604 get_media_options(int type, const char *val) 605 { 606 struct ifmedia_description *desc; 607 struct ifmedia_type_to_subtype *ttos; 608 char *optlist, *optptr; 609 int option = 0, i, rval = 0; 610 611 /* We muck with the string, so copy it. */ 612 optlist = strdup(val); 613 if (optlist == NULL) 614 err(1, "strdup"); 615 616 /* Find the top-level interface type. */ 617 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 618 desc->ifmt_string != NULL; desc++, ttos++) 619 if (type == desc->ifmt_word) 620 break; 621 if (desc->ifmt_string == NULL) 622 errx(1, "unknown media type 0x%x", type); 623 624 /* 625 * Look up the options in the user-provided comma-separated 626 * list. 627 */ 628 optptr = optlist; 629 for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) { 630 for (i = 0; ttos->options[i].desc != NULL; i++) { 631 option = lookup_media_word(ttos->options[i].desc, optptr); 632 if (option != -1) 633 break; 634 } 635 if (option == 0) 636 errx(1, "unknown option: %s", optptr); 637 rval |= option; 638 } 639 640 free(optlist); 641 return (rval); 642 } 643 644 static int 645 lookup_media_word(struct ifmedia_description *desc, const char *val) 646 { 647 648 for (; desc->ifmt_string != NULL; desc++) 649 if (strcasecmp(desc->ifmt_string, val) == 0) 650 return (desc->ifmt_word); 651 652 return (-1); 653 } 654 655 static struct ifmedia_description *get_toptype_desc(int ifmw) 656 { 657 struct ifmedia_description *desc; 658 659 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) 660 if (IFM_TYPE(ifmw) == desc->ifmt_word) 661 break; 662 663 return desc; 664 } 665 666 static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw) 667 { 668 struct ifmedia_description *desc; 669 struct ifmedia_type_to_subtype *ttos; 670 671 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 672 desc->ifmt_string != NULL; desc++, ttos++) 673 if (IFM_TYPE(ifmw) == desc->ifmt_word) 674 break; 675 676 return ttos; 677 } 678 679 static struct ifmedia_description *get_subtype_desc(int ifmw, 680 struct ifmedia_type_to_subtype *ttos) 681 { 682 int i; 683 struct ifmedia_description *desc; 684 685 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 686 if (ttos->subtypes[i].alias) 687 continue; 688 for (desc = ttos->subtypes[i].desc; 689 desc->ifmt_string != NULL; desc++) { 690 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) 691 return desc; 692 } 693 } 694 695 return NULL; 696 } 697 698 static struct ifmedia_description *get_mode_desc(int ifmw, 699 struct ifmedia_type_to_subtype *ttos) 700 { 701 int i; 702 struct ifmedia_description *desc; 703 704 for (i = 0; ttos->modes[i].desc != NULL; i++) { 705 if (ttos->modes[i].alias) 706 continue; 707 for (desc = ttos->modes[i].desc; 708 desc->ifmt_string != NULL; desc++) { 709 if (IFM_MODE(ifmw) == desc->ifmt_word) 710 return desc; 711 } 712 } 713 714 return NULL; 715 } 716 717 static void 718 print_media_word(int ifmw, int print_toptype) 719 { 720 struct ifmedia_description *desc; 721 struct ifmedia_type_to_subtype *ttos; 722 int seen_option = 0, i; 723 724 /* Find the top-level interface type. */ 725 desc = get_toptype_desc(ifmw); 726 ttos = get_toptype_ttos(ifmw); 727 if (desc->ifmt_string == NULL) { 728 printf("<unknown type>"); 729 return; 730 } else if (print_toptype) { 731 printf("%s", desc->ifmt_string); 732 } 733 734 /* 735 * Don't print the top-level type; it's not like we can 736 * change it, or anything. 737 */ 738 739 /* Find subtype. */ 740 desc = get_subtype_desc(ifmw, ttos); 741 if (desc == NULL) { 742 printf("<unknown subtype>"); 743 return; 744 } 745 746 if (print_toptype) 747 putchar(' '); 748 749 printf("%s", desc->ifmt_string); 750 751 if (print_toptype) { 752 desc = get_mode_desc(ifmw, ttos); 753 if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string)) 754 printf(" mode %s", desc->ifmt_string); 755 } 756 757 /* Find options. */ 758 for (i = 0; ttos->options[i].desc != NULL; i++) { 759 if (ttos->options[i].alias) 760 continue; 761 for (desc = ttos->options[i].desc; 762 desc->ifmt_string != NULL; desc++) { 763 if (ifmw & desc->ifmt_word) { 764 if (seen_option == 0) 765 printf(" <"); 766 printf("%s%s", seen_option++ ? "," : "", 767 desc->ifmt_string); 768 } 769 } 770 } 771 printf("%s", seen_option ? ">" : ""); 772 773 if (print_toptype && IFM_INST(ifmw) != 0) 774 printf(" instance %d", IFM_INST(ifmw)); 775 } 776 777 static void 778 print_media_word_ifconfig(int ifmw) 779 { 780 struct ifmedia_description *desc; 781 struct ifmedia_type_to_subtype *ttos; 782 int seen_option = 0, i; 783 784 /* Find the top-level interface type. */ 785 desc = get_toptype_desc(ifmw); 786 ttos = get_toptype_ttos(ifmw); 787 if (desc->ifmt_string == NULL) { 788 printf("<unknown type>"); 789 return; 790 } 791 792 /* 793 * Don't print the top-level type; it's not like we can 794 * change it, or anything. 795 */ 796 797 /* Find subtype. */ 798 desc = get_subtype_desc(ifmw, ttos); 799 if (desc == NULL) { 800 printf("<unknown subtype>"); 801 return; 802 } 803 804 printf("media %s", desc->ifmt_string); 805 806 desc = get_mode_desc(ifmw, ttos); 807 if (desc != NULL) 808 printf(" mode %s", desc->ifmt_string); 809 810 /* Find options. */ 811 for (i = 0; ttos->options[i].desc != NULL; i++) { 812 if (ttos->options[i].alias) 813 continue; 814 for (desc = ttos->options[i].desc; 815 desc->ifmt_string != NULL; desc++) { 816 if (ifmw & desc->ifmt_word) { 817 if (seen_option == 0) 818 printf(" mediaopt "); 819 printf("%s%s", seen_option++ ? "," : "", 820 desc->ifmt_string); 821 } 822 } 823 } 824 825 if (IFM_INST(ifmw) != 0) 826 printf(" instance %d", IFM_INST(ifmw)); 827 } 828 829 /********************************************************************** 830 * ...until here. 831 **********************************************************************/ 832 833 static struct cmd media_cmds[] = { 834 DEF_CMD_ARG("media", setmedia), 835 DEF_CMD_ARG("mode", setmediamode), 836 DEF_CMD_ARG("mediaopt", setmediaopt), 837 DEF_CMD_ARG("-mediaopt",unsetmediaopt), 838 DEF_CMD_ARG("inst", setmediainst), 839 DEF_CMD_ARG("instance", setmediainst), 840 }; 841 static struct afswtch af_media = { 842 .af_name = "af_media", 843 .af_af = AF_UNSPEC, 844 .af_other_status = media_status, 845 }; 846 847 static __constructor void 848 ifmedia_ctor(void) 849 { 850 size_t i; 851 852 for (i = 0; i < nitems(media_cmds); i++) 853 cmd_register(&media_cmds[i]); 854 af_register(&af_media); 855 } 856