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