1 /* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */ 2 /* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.6.2.3 2001/11/14 04:35:07 yar Exp $ */ 3 /* $DragonFly: src/sbin/ifconfig/ifmedia.c,v 1.3 2003/09/28 14:39:18 hmp Exp $ */ 4 5 /* 6 * Copyright (c) 1997 Jason R. Thorpe. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project 20 * by Jason R. Thorpe. 21 * 4. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 /* 38 * Copyright (c) 1983, 1993 39 * The Regents of the University of California. All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed by the University of 52 * California, Berkeley and its contributors. 53 * 4. Neither the name of the University nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * SUCH DAMAGE. 68 */ 69 70 #include <sys/param.h> 71 #include <sys/ioctl.h> 72 #include <sys/socket.h> 73 #include <sys/sysctl.h> 74 #include <sys/time.h> 75 76 #include <net/if.h> 77 #include <net/if_dl.h> 78 #include <net/if_types.h> 79 #include <net/if_media.h> 80 #include <net/route.h> 81 82 #include <ctype.h> 83 #include <err.h> 84 #include <errno.h> 85 #include <fcntl.h> 86 #include <stdio.h> 87 #include <stdlib.h> 88 #include <string.h> 89 #include <unistd.h> 90 91 #include "ifconfig.h" 92 93 static void domediaopt __P((const char *, int, int)); 94 static int get_media_subtype __P((int, const char *)); 95 static int get_media_options __P((int, const char *)); 96 static int lookup_media_word __P((struct ifmedia_description *, const char *)); 97 static void print_media_word __P((int, int)); 98 static void print_media_word_ifconfig __P((int)); 99 100 static struct ifmedia_description *get_toptype_desc __P((int)); 101 static struct ifmedia_type_to_subtype *get_toptype_ttos __P((int)); 102 static struct ifmedia_description *get_subtype_desc __P((int, 103 struct ifmedia_type_to_subtype *ttos)); 104 105 void 106 media_status(int s, struct rt_addrinfo *info __unused) 107 { 108 struct ifmediareq ifmr; 109 int *media_list, i; 110 111 (void) memset(&ifmr, 0, sizeof(ifmr)); 112 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 113 114 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 115 /* 116 * Interface doesn't support SIOC{G,S}IFMEDIA. 117 */ 118 return; 119 } 120 121 if (ifmr.ifm_count == 0) { 122 warnx("%s: no media types?", name); 123 return; 124 } 125 126 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); 127 if (media_list == NULL) 128 err(1, "malloc"); 129 ifmr.ifm_ulist = media_list; 130 131 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 132 err(1, "SIOCGIFMEDIA"); 133 134 printf("\tmedia: "); 135 print_media_word(ifmr.ifm_current, 1); 136 if (ifmr.ifm_active != ifmr.ifm_current) { 137 putchar(' '); 138 putchar('('); 139 print_media_word(ifmr.ifm_active, 0); 140 putchar(')'); 141 } 142 143 putchar('\n'); 144 145 if (ifmr.ifm_status & IFM_AVALID) { 146 printf("\tstatus: "); 147 switch (IFM_TYPE(ifmr.ifm_active)) { 148 case IFM_ETHER: 149 if (ifmr.ifm_status & IFM_ACTIVE) 150 printf("active"); 151 else 152 printf("no carrier"); 153 break; 154 155 case IFM_FDDI: 156 case IFM_TOKEN: 157 if (ifmr.ifm_status & IFM_ACTIVE) 158 printf("inserted"); 159 else 160 printf("no ring"); 161 break; 162 case IFM_IEEE80211: 163 /* XXX: Different value for adhoc? */ 164 if (ifmr.ifm_status & IFM_ACTIVE) 165 printf("associated"); 166 else 167 printf("no carrier"); 168 break; 169 } 170 putchar('\n'); 171 } 172 173 if (ifmr.ifm_count > 0 && supmedia) { 174 printf("\tsupported media:\n"); 175 for (i = 0; i < ifmr.ifm_count; i++) { 176 printf("\t\t"); 177 print_media_word_ifconfig(media_list[i]); 178 putchar('\n'); 179 } 180 } 181 182 free(media_list); 183 } 184 185 void 186 setmedia(const char *val, int d, int s, const struct afswtch *afp) 187 { 188 struct ifmediareq ifmr; 189 int first_type, subtype; 190 191 (void) memset(&ifmr, 0, sizeof(ifmr)); 192 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 193 194 ifmr.ifm_count = 1; 195 ifmr.ifm_ulist = &first_type; 196 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 197 /* 198 * If we get E2BIG, the kernel is telling us 199 * that there are more, so we can ignore it. 200 */ 201 if (errno != E2BIG) 202 err(1, "SIOCGIFMEDIA"); 203 } 204 205 if (ifmr.ifm_count == 0) 206 errx(1, "%s: no media types?", name); 207 208 /* 209 * We are primarily concerned with the top-level type. 210 * However, "current" may be only IFM_NONE, so we just look 211 * for the top-level type in the first "supported type" 212 * entry. 213 * 214 * (I'm assuming that all supported media types for a given 215 * interface will be the same top-level type..) 216 */ 217 subtype = get_media_subtype(IFM_TYPE(first_type), val); 218 219 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 220 ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) | 221 IFM_TYPE(first_type) | subtype; 222 223 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) 224 err(1, "SIOCSIFMEDIA"); 225 } 226 227 void 228 setmediaopt(const char *val, int d, int s, const struct afswtch *afp) 229 { 230 231 domediaopt(val, 0, s); 232 } 233 234 void 235 unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp) 236 { 237 238 domediaopt(val, 1, s); 239 } 240 241 static void 242 domediaopt(const char *val, int clear, int s) 243 { 244 struct ifmediareq ifmr; 245 int *mwords, options; 246 247 (void) memset(&ifmr, 0, sizeof(ifmr)); 248 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 249 250 /* 251 * We must go through the motions of reading all 252 * supported media because we need to know both 253 * the current media type and the top-level type. 254 */ 255 256 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 257 err(1, "SIOCGIFMEDIA"); 258 259 if (ifmr.ifm_count == 0) 260 errx(1, "%s: no media types?", name); 261 262 mwords = (int *)malloc(ifmr.ifm_count * sizeof(int)); 263 if (mwords == NULL) 264 err(1, "malloc"); 265 266 ifmr.ifm_ulist = mwords; 267 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 268 err(1, "SIOCGIFMEDIA"); 269 270 options = get_media_options(IFM_TYPE(mwords[0]), val); 271 272 free(mwords); 273 274 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 275 ifr.ifr_media = ifmr.ifm_current; 276 if (clear) 277 ifr.ifr_media &= ~options; 278 else 279 ifr.ifr_media |= options; 280 281 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) 282 err(1, "SIOCSIFMEDIA"); 283 } 284 285 /********************************************************************** 286 * A good chunk of this is duplicated from sys/net/ifmedia.c 287 **********************************************************************/ 288 289 static struct ifmedia_description ifm_type_descriptions[] = 290 IFM_TYPE_DESCRIPTIONS; 291 292 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = 293 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; 294 295 static struct ifmedia_description ifm_subtype_ethernet_aliases[] = 296 IFM_SUBTYPE_ETHERNET_ALIASES; 297 298 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = 299 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; 300 301 static struct ifmedia_description ifm_subtype_tokenring_descriptions[] = 302 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; 303 304 static struct ifmedia_description ifm_subtype_tokenring_aliases[] = 305 IFM_SUBTYPE_TOKENRING_ALIASES; 306 307 static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = 308 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; 309 310 static struct ifmedia_description ifm_subtype_fddi_descriptions[] = 311 IFM_SUBTYPE_FDDI_DESCRIPTIONS; 312 313 static struct ifmedia_description ifm_subtype_fddi_aliases[] = 314 IFM_SUBTYPE_FDDI_ALIASES; 315 316 static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = 317 IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; 318 319 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = 320 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; 321 322 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] = 323 IFM_SUBTYPE_IEEE80211_ALIASES; 324 325 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = 326 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; 327 328 static struct ifmedia_description ifm_subtype_shared_descriptions[] = 329 IFM_SUBTYPE_SHARED_DESCRIPTIONS; 330 331 static struct ifmedia_description ifm_subtype_shared_aliases[] = 332 IFM_SUBTYPE_SHARED_ALIASES; 333 334 static struct ifmedia_description ifm_shared_option_descriptions[] = 335 IFM_SHARED_OPTION_DESCRIPTIONS; 336 337 struct ifmedia_type_to_subtype { 338 struct { 339 struct ifmedia_description *desc; 340 int alias; 341 } subtypes[5]; 342 struct { 343 struct ifmedia_description *desc; 344 int alias; 345 } options[3]; 346 }; 347 348 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ 349 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { 350 { 351 { 352 { &ifm_subtype_shared_descriptions[0], 0 }, 353 { &ifm_subtype_shared_aliases[0], 1 }, 354 { &ifm_subtype_ethernet_descriptions[0], 0 }, 355 { &ifm_subtype_ethernet_aliases[0], 1 }, 356 { NULL, 0 }, 357 }, 358 { 359 { &ifm_shared_option_descriptions[0], 0 }, 360 { &ifm_subtype_ethernet_option_descriptions[0], 0 }, 361 { NULL, 0 }, 362 }, 363 }, 364 { 365 { 366 { &ifm_subtype_shared_descriptions[0], 0 }, 367 { &ifm_subtype_shared_aliases[0], 1 }, 368 { &ifm_subtype_tokenring_descriptions[0], 0 }, 369 { &ifm_subtype_tokenring_aliases[0], 1 }, 370 { NULL, 0 }, 371 }, 372 { 373 { &ifm_shared_option_descriptions[0], 0 }, 374 { &ifm_subtype_tokenring_option_descriptions[0], 0 }, 375 { NULL, 0 }, 376 }, 377 }, 378 { 379 { 380 { &ifm_subtype_shared_descriptions[0], 0 }, 381 { &ifm_subtype_shared_aliases[0], 1 }, 382 { &ifm_subtype_fddi_descriptions[0], 0 }, 383 { &ifm_subtype_fddi_aliases[0], 1 }, 384 { NULL, 0 }, 385 }, 386 { 387 { &ifm_shared_option_descriptions[0], 0 }, 388 { &ifm_subtype_fddi_option_descriptions[0], 0 }, 389 { NULL, 0 }, 390 }, 391 }, 392 { 393 { 394 { &ifm_subtype_shared_descriptions[0], 0 }, 395 { &ifm_subtype_shared_aliases[0], 1 }, 396 { &ifm_subtype_ieee80211_descriptions[0], 0 }, 397 { &ifm_subtype_ieee80211_aliases[0], 1 }, 398 { NULL, 0 }, 399 }, 400 { 401 { &ifm_shared_option_descriptions[0], 0 }, 402 { &ifm_subtype_ieee80211_option_descriptions[0], 0 }, 403 { NULL, 0 }, 404 }, 405 }, 406 }; 407 408 static int 409 get_media_subtype(int type, const char *val) 410 { 411 struct ifmedia_description *desc; 412 struct ifmedia_type_to_subtype *ttos; 413 int rval, i; 414 415 /* Find the top-level interface type. */ 416 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 417 desc->ifmt_string != NULL; desc++, ttos++) 418 if (type == desc->ifmt_word) 419 break; 420 if (desc->ifmt_string == NULL) 421 errx(1, "unknown media type 0x%x", type); 422 423 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 424 rval = lookup_media_word(ttos->subtypes[i].desc, val); 425 if (rval != -1) 426 return (rval); 427 } 428 errx(1, "unknown media subtype: %s", val); 429 /* NOTREACHED */ 430 } 431 432 static int 433 get_media_options(int type, const char *val) 434 { 435 struct ifmedia_description *desc; 436 struct ifmedia_type_to_subtype *ttos; 437 char *optlist, *optptr; 438 int option = 0, i, rval = 0; 439 440 /* We muck with the string, so copy it. */ 441 optlist = strdup(val); 442 if (optlist == NULL) 443 err(1, "strdup"); 444 445 /* Find the top-level interface type. */ 446 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 447 desc->ifmt_string != NULL; desc++, ttos++) 448 if (type == desc->ifmt_word) 449 break; 450 if (desc->ifmt_string == NULL) 451 errx(1, "unknown media type 0x%x", type); 452 453 /* 454 * Look up the options in the user-provided comma-separated 455 * list. 456 */ 457 optptr = optlist; 458 for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) { 459 for (i = 0; ttos->options[i].desc != NULL; i++) { 460 option = lookup_media_word(ttos->options[i].desc, optptr); 461 if (option != -1) 462 break; 463 } 464 if (option == 0) 465 errx(1, "unknown option: %s", optptr); 466 rval |= option; 467 } 468 469 free(optlist); 470 return (rval); 471 } 472 473 static int 474 lookup_media_word(struct ifmedia_description *desc, const char *val) 475 { 476 477 for (; desc->ifmt_string != NULL; desc++) 478 if (strcasecmp(desc->ifmt_string, val) == 0) 479 return (desc->ifmt_word); 480 481 return (-1); 482 } 483 484 static struct ifmedia_description *get_toptype_desc(int ifmw) 485 { 486 struct ifmedia_description *desc; 487 488 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) 489 if (IFM_TYPE(ifmw) == desc->ifmt_word) 490 break; 491 492 return desc; 493 } 494 495 static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw) 496 { 497 struct ifmedia_description *desc; 498 struct ifmedia_type_to_subtype *ttos; 499 500 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 501 desc->ifmt_string != NULL; desc++, ttos++) 502 if (IFM_TYPE(ifmw) == desc->ifmt_word) 503 break; 504 505 return ttos; 506 } 507 508 static struct ifmedia_description *get_subtype_desc(int ifmw, 509 struct ifmedia_type_to_subtype *ttos) 510 { 511 int i; 512 struct ifmedia_description *desc; 513 514 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 515 if (ttos->subtypes[i].alias) 516 continue; 517 for (desc = ttos->subtypes[i].desc; 518 desc->ifmt_string != NULL; desc++) { 519 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) 520 return desc; 521 } 522 } 523 524 return NULL; 525 } 526 527 static void 528 print_media_word(int ifmw, int print_toptype) 529 { 530 struct ifmedia_description *desc; 531 struct ifmedia_type_to_subtype *ttos; 532 int seen_option = 0, i; 533 534 /* Find the top-level interface type. */ 535 desc = get_toptype_desc(ifmw); 536 ttos = get_toptype_ttos(ifmw); 537 if (desc->ifmt_string == NULL) { 538 printf("<unknown type>"); 539 return; 540 } else if (print_toptype) { 541 printf("%s", desc->ifmt_string); 542 } 543 544 /* 545 * Don't print the top-level type; it's not like we can 546 * change it, or anything. 547 */ 548 549 /* Find subtype. */ 550 desc = get_subtype_desc(ifmw, ttos); 551 if (desc != NULL) 552 goto got_subtype; 553 554 /* Falling to here means unknown subtype. */ 555 printf("<unknown subtype>"); 556 return; 557 558 got_subtype: 559 if (print_toptype) 560 putchar(' '); 561 562 printf("%s", desc->ifmt_string); 563 564 /* Find options. */ 565 for (i = 0; ttos->options[i].desc != NULL; i++) { 566 if (ttos->options[i].alias) 567 continue; 568 for (desc = ttos->options[i].desc; 569 desc->ifmt_string != NULL; desc++) { 570 if (ifmw & desc->ifmt_word) { 571 if (seen_option == 0) 572 printf(" <"); 573 printf("%s%s", seen_option++ ? "," : "", 574 desc->ifmt_string); 575 } 576 } 577 } 578 printf("%s", seen_option ? ">" : ""); 579 } 580 581 static void 582 print_media_word_ifconfig(int ifmw) 583 { 584 struct ifmedia_description *desc; 585 struct ifmedia_type_to_subtype *ttos; 586 int i; 587 588 /* Find the top-level interface type. */ 589 desc = get_toptype_desc(ifmw); 590 ttos = get_toptype_ttos(ifmw); 591 if (desc->ifmt_string == NULL) { 592 printf("<unknown type>"); 593 return; 594 } 595 596 /* 597 * Don't print the top-level type; it's not like we can 598 * change it, or anything. 599 */ 600 601 /* Find subtype. */ 602 desc = get_subtype_desc(ifmw, ttos); 603 if (desc != NULL) 604 goto got_subtype; 605 606 /* Falling to here means unknown subtype. */ 607 printf("<unknown subtype>"); 608 return; 609 610 got_subtype: 611 printf("media %s", desc->ifmt_string); 612 613 /* Find options. */ 614 for (i = 0; ttos->options[i].desc != NULL; i++) { 615 if (ttos->options[i].alias) 616 continue; 617 for (desc = ttos->options[i].desc; 618 desc->ifmt_string != NULL; desc++) { 619 if (ifmw & desc->ifmt_word) { 620 printf(" mediaopt %s", desc->ifmt_string); 621 } 622 } 623 } 624 } 625 626 /********************************************************************** 627 * ...until here. 628 **********************************************************************/ 629