1/* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */ 2/* $FreeBSD: stable/11/sbin/ifconfig/ifmedia.c 352650 2019-09-24 06:37:01Z kib $ */ 3 4/* 5 * Copyright (c) 1997 Jason R. Thorpe. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed for the NetBSD Project 19 * by Jason R. Thorpe. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36/* 37 * Copyright (c) 1983, 1993 38 * The Regents of the University of California. All rights reserved. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 4. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65#include <sys/param.h> 66#include <sys/ioctl.h> 67#include <sys/socket.h> 68#include <sys/sysctl.h> 69#include <sys/time.h> 70 71#include <net/if.h> 72#include <net/if_dl.h> 73#include <net/if_types.h> 74#include <net/if_media.h> 75#include <net/route.h> 76 77#include <ctype.h> 78#include <err.h> 79#include <errno.h> 80#include <fcntl.h> 81#include <stdbool.h> 82#include <stdio.h> 83#include <stdlib.h> 84#include <string.h> 85#include <unistd.h> 86 87#include "ifconfig.h" 88 89static void domediaopt(const char *, int, int); 90static int get_media_subtype(int, const char *); 91static int get_media_mode(int, const char *); 92static int get_media_options(int, const char *); 93static int lookup_media_word(struct ifmedia_description *, const char *); 94static void print_media_word(int, int); 95static void print_media_word_ifconfig(int); 96 97static struct ifmedia_description *get_toptype_desc(int); 98static struct ifmedia_type_to_subtype *get_toptype_ttos(int); 99static struct ifmedia_description *get_subtype_desc(int, 100 struct ifmedia_type_to_subtype *ttos); 101 102#define IFM_OPMODE(x) \ 103 ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \ 104 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \ 105 IFM_IEEE80211_MBSS)) 106#define IFM_IEEE80211_STA 0 107 108static void 109media_status(int s) 110{ 111 struct ifmediareq ifmr; 112 struct ifdownreason ifdr; 113 int *media_list, i; 114 bool no_carrier, xmedia; 115 116 (void) memset(&ifmr, 0, sizeof(ifmr)); 117 (void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 118 xmedia = true; 119 120 /* 121 * Check if interface supports extended media types. 122 */ 123 if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) 124 xmedia = false; 125 if (!xmedia && ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 126 /* 127 * Interface doesn't support SIOC{G,S}IFMEDIA. 128 */ 129 return; 130 } 131 132 if (ifmr.ifm_count == 0) { 133 warnx("%s: no media types?", name); 134 return; 135 } 136 137 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); 138 if (media_list == NULL) 139 err(1, "malloc"); 140 ifmr.ifm_ulist = media_list; 141 142 if (xmedia) { 143 if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) 144 err(1, "SIOCGIFXMEDIA"); 145 } else { 146 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 147 err(1, "SIOCGIFMEDIA"); 148 } 149 150 printf("\tmedia: "); 151 print_media_word(ifmr.ifm_current, 1); 152 if (ifmr.ifm_active != ifmr.ifm_current) { 153 putchar(' '); 154 putchar('('); 155 print_media_word(ifmr.ifm_active, 0); 156 putchar(')'); 157 } 158 159 putchar('\n'); 160 161 if (ifmr.ifm_status & IFM_AVALID) { 162 no_carrier = false; 163 printf("\tstatus: "); 164 switch (IFM_TYPE(ifmr.ifm_active)) { 165 case IFM_ETHER: 166 case IFM_ATM: 167 if (ifmr.ifm_status & IFM_ACTIVE) 168 printf("active"); 169 else 170 no_carrier = true; 171 break; 172 173 case IFM_FDDI: 174 case IFM_TOKEN: 175 if (ifmr.ifm_status & IFM_ACTIVE) 176 printf("inserted"); 177 else 178 printf("no ring"); 179 break; 180 181 case IFM_IEEE80211: 182 if (ifmr.ifm_status & IFM_ACTIVE) { 183 /* NB: only sta mode associates */ 184 if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA) 185 printf("associated"); 186 else 187 printf("running"); 188 } else 189 no_carrier = true; 190 break; 191 } 192 if (no_carrier) { 193 printf("no carrier"); 194 memset(&ifdr, 0, sizeof(ifdr)); 195 strlcpy(ifdr.ifdr_name, name, sizeof(ifdr.ifdr_name)); 196 if (ioctl(s, SIOCGIFDOWNREASON, (caddr_t)&ifdr) == 0) { 197 switch (ifdr.ifdr_reason) { 198 case IFDR_REASON_MSG: 199 printf(" (%s)", ifdr.ifdr_msg); 200 break; 201 case IFDR_REASON_VENDOR: 202 printf(" (vendor code %d)", 203 ifdr.ifdr_vendor); 204 break; 205 default: 206 break; 207 } 208 } 209 } 210 putchar('\n'); 211 } 212 213 if (ifmr.ifm_count > 0 && supmedia) { 214 printf("\tsupported media:\n"); 215 for (i = 0; i < ifmr.ifm_count; i++) { 216 printf("\t\t"); 217 print_media_word_ifconfig(media_list[i]); 218 putchar('\n'); 219 } 220 } 221 222 free(media_list); 223} 224 225struct ifmediareq * 226ifmedia_getstate(int s) 227{ 228 static struct ifmediareq *ifmr = NULL; 229 int *mwords; 230 int xmedia = 1; 231 232 if (ifmr == NULL) { 233 ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq)); 234 if (ifmr == NULL) 235 err(1, "malloc"); 236 237 (void) memset(ifmr, 0, sizeof(struct ifmediareq)); 238 (void) strlcpy(ifmr->ifm_name, name, 239 sizeof(ifmr->ifm_name)); 240 241 ifmr->ifm_count = 0; 242 ifmr->ifm_ulist = NULL; 243 244 /* 245 * We must go through the motions of reading all 246 * supported media because we need to know both 247 * the current media type and the top-level type. 248 */ 249 250 if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) { 251 xmedia = 0; 252 } 253 if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) { 254 err(1, "SIOCGIFMEDIA"); 255 } 256 257 if (ifmr->ifm_count == 0) 258 errx(1, "%s: no media types?", name); 259 260 mwords = (int *)malloc(ifmr->ifm_count * sizeof(int)); 261 if (mwords == NULL) 262 err(1, "malloc"); 263 264 ifmr->ifm_ulist = mwords; 265 if (xmedia) { 266 if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) 267 err(1, "SIOCGIFXMEDIA"); 268 } else { 269 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) 270 err(1, "SIOCGIFMEDIA"); 271 } 272 } 273 274 return ifmr; 275} 276 277static void 278setifmediacallback(int s, void *arg) 279{ 280 struct ifmediareq *ifmr = (struct ifmediareq *)arg; 281 static int did_it = 0; 282 283 if (!did_it) { 284 ifr.ifr_media = ifmr->ifm_current; 285 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) 286 err(1, "SIOCSIFMEDIA (media)"); 287 free(ifmr->ifm_ulist); 288 free(ifmr); 289 did_it = 1; 290 } 291} 292 293static void 294setmedia(const char *val, int d, int s, const struct afswtch *afp) 295{ 296 struct ifmediareq *ifmr; 297 int subtype; 298 299 ifmr = ifmedia_getstate(s); 300 301 /* 302 * We are primarily concerned with the top-level type. 303 * However, "current" may be only IFM_NONE, so we just look 304 * for the top-level type in the first "supported type" 305 * entry. 306 * 307 * (I'm assuming that all supported media types for a given 308 * interface will be the same top-level type..) 309 */ 310 subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val); 311 312 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 313 ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) | 314 IFM_TYPE(ifmr->ifm_ulist[0]) | subtype; 315 316 ifmr->ifm_current = ifr.ifr_media; 317 callback_register(setifmediacallback, (void *)ifmr); 318} 319 320static void 321setmediaopt(const char *val, int d, int s, const struct afswtch *afp) 322{ 323 324 domediaopt(val, 0, s); 325} 326 327static void 328unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp) 329{ 330 331 domediaopt(val, 1, s); 332} 333 334static void 335domediaopt(const char *val, int clear, int s) 336{ 337 struct ifmediareq *ifmr; 338 int options; 339 340 ifmr = ifmedia_getstate(s); 341 342 options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val); 343 344 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 345 ifr.ifr_media = ifmr->ifm_current; 346 if (clear) 347 ifr.ifr_media &= ~options; 348 else { 349 if (options & IFM_HDX) { 350 ifr.ifr_media &= ~IFM_FDX; 351 options &= ~IFM_HDX; 352 } 353 ifr.ifr_media |= options; 354 } 355 ifmr->ifm_current = ifr.ifr_media; 356 callback_register(setifmediacallback, (void *)ifmr); 357} 358 359static void 360setmediainst(const char *val, int d, int s, const struct afswtch *afp) 361{ 362 struct ifmediareq *ifmr; 363 int inst; 364 365 ifmr = ifmedia_getstate(s); 366 367 inst = atoi(val); 368 if (inst < 0 || inst > (int)IFM_INST_MAX) 369 errx(1, "invalid media instance: %s", val); 370 371 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 372 ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT; 373 374 ifmr->ifm_current = ifr.ifr_media; 375 callback_register(setifmediacallback, (void *)ifmr); 376} 377 378static void 379setmediamode(const char *val, int d, int s, const struct afswtch *afp) 380{ 381 struct ifmediareq *ifmr; 382 int mode; 383 384 ifmr = ifmedia_getstate(s); 385 386 mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val); 387 388 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 389 ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode; 390 391 ifmr->ifm_current = ifr.ifr_media; 392 callback_register(setifmediacallback, (void *)ifmr); 393} 394 395/********************************************************************** 396 * A good chunk of this is duplicated from sys/net/ifmedia.c 397 **********************************************************************/ 398 399static struct ifmedia_description ifm_type_descriptions[] = 400 IFM_TYPE_DESCRIPTIONS; 401 402static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = 403 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; 404 405static struct ifmedia_description ifm_subtype_ethernet_aliases[] = 406 IFM_SUBTYPE_ETHERNET_ALIASES; 407 408static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = 409 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; 410 411static struct ifmedia_description ifm_subtype_tokenring_descriptions[] = 412 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; 413 414static struct ifmedia_description ifm_subtype_tokenring_aliases[] = 415 IFM_SUBTYPE_TOKENRING_ALIASES; 416 417static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = 418 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; 419 420static struct ifmedia_description ifm_subtype_fddi_descriptions[] = 421 IFM_SUBTYPE_FDDI_DESCRIPTIONS; 422 423static struct ifmedia_description ifm_subtype_fddi_aliases[] = 424 IFM_SUBTYPE_FDDI_ALIASES; 425 426static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = 427 IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; 428 429static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = 430 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; 431 432static struct ifmedia_description ifm_subtype_ieee80211_aliases[] = 433 IFM_SUBTYPE_IEEE80211_ALIASES; 434 435static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = 436 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; 437 438struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = 439 IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; 440 441struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] = 442 IFM_SUBTYPE_IEEE80211_MODE_ALIASES; 443 444static struct ifmedia_description ifm_subtype_atm_descriptions[] = 445 IFM_SUBTYPE_ATM_DESCRIPTIONS; 446 447static struct ifmedia_description ifm_subtype_atm_aliases[] = 448 IFM_SUBTYPE_ATM_ALIASES; 449 450static struct ifmedia_description ifm_subtype_atm_option_descriptions[] = 451 IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS; 452 453static struct ifmedia_description ifm_subtype_shared_descriptions[] = 454 IFM_SUBTYPE_SHARED_DESCRIPTIONS; 455 456static struct ifmedia_description ifm_subtype_shared_aliases[] = 457 IFM_SUBTYPE_SHARED_ALIASES; 458 459static struct ifmedia_description ifm_shared_option_descriptions[] = 460 IFM_SHARED_OPTION_DESCRIPTIONS; 461 462static struct ifmedia_description ifm_shared_option_aliases[] = 463 IFM_SHARED_OPTION_ALIASES; 464 465struct ifmedia_type_to_subtype { 466 struct { 467 struct ifmedia_description *desc; 468 int alias; 469 } subtypes[5]; 470 struct { 471 struct ifmedia_description *desc; 472 int alias; 473 } options[4]; 474 struct { 475 struct ifmedia_description *desc; 476 int alias; 477 } modes[3]; 478}; 479 480/* must be in the same order as IFM_TYPE_DESCRIPTIONS */ 481static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { 482 { 483 { 484 { &ifm_subtype_shared_descriptions[0], 0 }, 485 { &ifm_subtype_shared_aliases[0], 1 }, 486 { &ifm_subtype_ethernet_descriptions[0], 0 }, 487 { &ifm_subtype_ethernet_aliases[0], 1 }, 488 { NULL, 0 }, 489 }, 490 { 491 { &ifm_shared_option_descriptions[0], 0 }, 492 { &ifm_shared_option_aliases[0], 1 }, 493 { &ifm_subtype_ethernet_option_descriptions[0], 0 }, 494 { NULL, 0 }, 495 }, 496 { 497 { NULL, 0 }, 498 }, 499 }, 500 { 501 { 502 { &ifm_subtype_shared_descriptions[0], 0 }, 503 { &ifm_subtype_shared_aliases[0], 1 }, 504 { &ifm_subtype_tokenring_descriptions[0], 0 }, 505 { &ifm_subtype_tokenring_aliases[0], 1 }, 506 { NULL, 0 }, 507 }, 508 { 509 { &ifm_shared_option_descriptions[0], 0 }, 510 { &ifm_shared_option_aliases[0], 1 }, 511 { &ifm_subtype_tokenring_option_descriptions[0], 0 }, 512 { NULL, 0 }, 513 }, 514 { 515 { NULL, 0 }, 516 }, 517 }, 518 { 519 { 520 { &ifm_subtype_shared_descriptions[0], 0 }, 521 { &ifm_subtype_shared_aliases[0], 1 }, 522 { &ifm_subtype_fddi_descriptions[0], 0 }, 523 { &ifm_subtype_fddi_aliases[0], 1 }, 524 { NULL, 0 }, 525 }, 526 { 527 { &ifm_shared_option_descriptions[0], 0 }, 528 { &ifm_shared_option_aliases[0], 1 }, 529 { &ifm_subtype_fddi_option_descriptions[0], 0 }, 530 { NULL, 0 }, 531 }, 532 { 533 { NULL, 0 }, 534 }, 535 }, 536 { 537 { 538 { &ifm_subtype_shared_descriptions[0], 0 }, 539 { &ifm_subtype_shared_aliases[0], 1 }, 540 { &ifm_subtype_ieee80211_descriptions[0], 0 }, 541 { &ifm_subtype_ieee80211_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_ieee80211_option_descriptions[0], 0 }, 548 { NULL, 0 }, 549 }, 550 { 551 { &ifm_subtype_ieee80211_mode_descriptions[0], 0 }, 552 { &ifm_subtype_ieee80211_mode_aliases[0], 0 }, 553 { NULL, 0 }, 554 }, 555 }, 556 { 557 { 558 { &ifm_subtype_shared_descriptions[0], 0 }, 559 { &ifm_subtype_shared_aliases[0], 1 }, 560 { &ifm_subtype_atm_descriptions[0], 0 }, 561 { &ifm_subtype_atm_aliases[0], 1 }, 562 { NULL, 0 }, 563 }, 564 { 565 { &ifm_shared_option_descriptions[0], 0 }, 566 { &ifm_shared_option_aliases[0], 1 }, 567 { &ifm_subtype_atm_option_descriptions[0], 0 }, 568 { NULL, 0 }, 569 }, 570 { 571 { NULL, 0 }, 572 }, 573 }, 574}; 575 576static int 577get_media_subtype(int type, const char *val) 578{ 579 struct ifmedia_description *desc; 580 struct ifmedia_type_to_subtype *ttos; 581 int rval, i; 582 583 /* Find the top-level interface type. */ 584 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 585 desc->ifmt_string != NULL; desc++, ttos++) 586 if (type == desc->ifmt_word) 587 break; 588 if (desc->ifmt_string == NULL) 589 errx(1, "unknown media type 0x%x", type); 590 591 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 592 rval = lookup_media_word(ttos->subtypes[i].desc, val); 593 if (rval != -1) 594 return (rval); 595 } 596 errx(1, "unknown media subtype: %s", val); 597 /*NOTREACHED*/ 598} 599 600static int 601get_media_mode(int type, const char *val) 602{ 603 struct ifmedia_description *desc; 604 struct ifmedia_type_to_subtype *ttos; 605 int rval, i; 606 607 /* Find the top-level interface type. */ 608 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 609 desc->ifmt_string != NULL; desc++, ttos++) 610 if (type == desc->ifmt_word) 611 break; 612 if (desc->ifmt_string == NULL) 613 errx(1, "unknown media mode 0x%x", type); 614 615 for (i = 0; ttos->modes[i].desc != NULL; i++) { 616 rval = lookup_media_word(ttos->modes[i].desc, val); 617 if (rval != -1) 618 return (rval); 619 } 620 return -1; 621} 622 623static int 624get_media_options(int type, const char *val) 625{ 626 struct ifmedia_description *desc; 627 struct ifmedia_type_to_subtype *ttos; 628 char *optlist, *optptr; 629 int option = 0, i, rval = 0; 630 631 /* We muck with the string, so copy it. */ 632 optlist = strdup(val); 633 if (optlist == NULL) 634 err(1, "strdup"); 635 636 /* Find the top-level interface type. */ 637 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 638 desc->ifmt_string != NULL; desc++, ttos++) 639 if (type == desc->ifmt_word) 640 break; 641 if (desc->ifmt_string == NULL) 642 errx(1, "unknown media type 0x%x", type); 643 644 /* 645 * Look up the options in the user-provided comma-separated 646 * list. 647 */ 648 optptr = optlist; 649 for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) { 650 for (i = 0; ttos->options[i].desc != NULL; i++) { 651 option = lookup_media_word(ttos->options[i].desc, optptr); 652 if (option != -1) 653 break; 654 } 655 if (option == 0) 656 errx(1, "unknown option: %s", optptr); 657 rval |= option; 658 } 659 660 free(optlist); 661 return (rval); 662} 663 664static int 665lookup_media_word(struct ifmedia_description *desc, const char *val) 666{ 667 668 for (; desc->ifmt_string != NULL; desc++) 669 if (strcasecmp(desc->ifmt_string, val) == 0) 670 return (desc->ifmt_word); 671 672 return (-1); 673} 674 675static struct ifmedia_description *get_toptype_desc(int ifmw) 676{ 677 struct ifmedia_description *desc; 678 679 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) 680 if (IFM_TYPE(ifmw) == desc->ifmt_word) 681 break; 682 683 return desc; 684} 685 686static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw) 687{ 688 struct ifmedia_description *desc; 689 struct ifmedia_type_to_subtype *ttos; 690 691 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 692 desc->ifmt_string != NULL; desc++, ttos++) 693 if (IFM_TYPE(ifmw) == desc->ifmt_word) 694 break; 695 696 return ttos; 697} 698 699static struct ifmedia_description *get_subtype_desc(int ifmw, 700 struct ifmedia_type_to_subtype *ttos) 701{ 702 int i; 703 struct ifmedia_description *desc; 704 705 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 706 if (ttos->subtypes[i].alias) 707 continue; 708 for (desc = ttos->subtypes[i].desc; 709 desc->ifmt_string != NULL; desc++) { 710 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) 711 return desc; 712 } 713 } 714 715 return NULL; 716} 717 718static struct ifmedia_description *get_mode_desc(int ifmw, 719 struct ifmedia_type_to_subtype *ttos) 720{ 721 int i; 722 struct ifmedia_description *desc; 723 724 for (i = 0; ttos->modes[i].desc != NULL; i++) { 725 if (ttos->modes[i].alias) 726 continue; 727 for (desc = ttos->modes[i].desc; 728 desc->ifmt_string != NULL; desc++) { 729 if (IFM_MODE(ifmw) == desc->ifmt_word) 730 return desc; 731 } 732 } 733 734 return NULL; 735} 736 737static void 738print_media_word(int ifmw, int print_toptype) 739{ 740 struct ifmedia_description *desc; 741 struct ifmedia_type_to_subtype *ttos; 742 int seen_option = 0, i; 743 744 /* Find the top-level interface type. */ 745 desc = get_toptype_desc(ifmw); 746 ttos = get_toptype_ttos(ifmw); 747 if (desc->ifmt_string == NULL) { 748 printf("<unknown type>"); 749 return; 750 } else if (print_toptype) { 751 printf("%s", desc->ifmt_string); 752 } 753 754 /* 755 * Don't print the top-level type; it's not like we can 756 * change it, or anything. 757 */ 758 759 /* Find subtype. */ 760 desc = get_subtype_desc(ifmw, ttos); 761 if (desc == NULL) { 762 printf("<unknown subtype>"); 763 return; 764 } 765 766 if (print_toptype) 767 putchar(' '); 768 769 printf("%s", desc->ifmt_string); 770 771 if (print_toptype) { 772 desc = get_mode_desc(ifmw, ttos); 773 if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string)) 774 printf(" mode %s", desc->ifmt_string); 775 } 776 777 /* Find options. */ 778 for (i = 0; ttos->options[i].desc != NULL; i++) { 779 if (ttos->options[i].alias) 780 continue; 781 for (desc = ttos->options[i].desc; 782 desc->ifmt_string != NULL; desc++) { 783 if (ifmw & desc->ifmt_word) { 784 if (seen_option == 0) 785 printf(" <"); 786 printf("%s%s", seen_option++ ? "," : "", 787 desc->ifmt_string); 788 } 789 } 790 } 791 printf("%s", seen_option ? ">" : ""); 792 793 if (print_toptype && IFM_INST(ifmw) != 0) 794 printf(" instance %d", IFM_INST(ifmw)); 795} 796 797static void 798print_media_word_ifconfig(int ifmw) 799{ 800 struct ifmedia_description *desc; 801 struct ifmedia_type_to_subtype *ttos; 802 int seen_option = 0, i; 803 804 /* Find the top-level interface type. */ 805 desc = get_toptype_desc(ifmw); 806 ttos = get_toptype_ttos(ifmw); 807 if (desc->ifmt_string == NULL) { 808 printf("<unknown type>"); 809 return; 810 } 811 812 /* 813 * Don't print the top-level type; it's not like we can 814 * change it, or anything. 815 */ 816 817 /* Find subtype. */ 818 desc = get_subtype_desc(ifmw, ttos); 819 if (desc == NULL) { 820 printf("<unknown subtype>"); 821 return; 822 } 823 824 printf("media %s", desc->ifmt_string); 825 826 desc = get_mode_desc(ifmw, ttos); 827 if (desc != NULL) 828 printf(" mode %s", desc->ifmt_string); 829 830 /* Find options. */ 831 for (i = 0; ttos->options[i].desc != NULL; i++) { 832 if (ttos->options[i].alias) 833 continue; 834 for (desc = ttos->options[i].desc; 835 desc->ifmt_string != NULL; desc++) { 836 if (ifmw & desc->ifmt_word) { 837 if (seen_option == 0) 838 printf(" mediaopt "); 839 printf("%s%s", seen_option++ ? "," : "", 840 desc->ifmt_string); 841 } 842 } 843 } 844 845 if (IFM_INST(ifmw) != 0) 846 printf(" instance %d", IFM_INST(ifmw)); 847} 848 849/********************************************************************** 850 * ...until here. 851 **********************************************************************/ 852 853static struct cmd media_cmds[] = { 854 DEF_CMD_ARG("media", setmedia), 855 DEF_CMD_ARG("mode", setmediamode), 856 DEF_CMD_ARG("mediaopt", setmediaopt), 857 DEF_CMD_ARG("-mediaopt",unsetmediaopt), 858 DEF_CMD_ARG("inst", setmediainst), 859 DEF_CMD_ARG("instance", setmediainst), 860}; 861static struct afswtch af_media = { 862 .af_name = "af_media", 863 .af_af = AF_UNSPEC, 864 .af_other_status = media_status, 865}; 866 867static __constructor void 868ifmedia_ctor(void) 869{ 870 size_t i; 871 872 for (i = 0; i < nitems(media_cmds); i++) 873 cmd_register(&media_cmds[i]); 874 af_register(&af_media); 875} 876