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(const char *, int, int); 93 static int get_media_subtype(int, const char *); 94 static int get_media_options(int, const char *); 95 static int lookup_media_word(struct ifmedia_description *, const char *); 96 static void print_media_word(int, int); 97 static void print_media_word_ifconfig(int); 98 99 static struct ifmedia_description *get_toptype_desc(int); 100 static struct ifmedia_type_to_subtype *get_toptype_ttos(int); 101 static struct ifmedia_description *get_subtype_desc(int, 102 struct ifmedia_type_to_subtype *ttos); 103 104 void 105 media_status(int s, struct rt_addrinfo *info __unused) 106 { 107 struct ifmediareq ifmr; 108 int *media_list, i; 109 110 (void) memset(&ifmr, 0, sizeof(ifmr)); 111 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 112 113 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 114 /* 115 * Interface doesn't support SIOC{G,S}IFMEDIA. 116 */ 117 return; 118 } 119 120 if (ifmr.ifm_count == 0) { 121 warnx("%s: no media types?", name); 122 return; 123 } 124 125 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); 126 if (media_list == NULL) 127 err(1, "malloc"); 128 ifmr.ifm_ulist = media_list; 129 130 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 131 err(1, "SIOCGIFMEDIA"); 132 133 printf("\tmedia: "); 134 print_media_word(ifmr.ifm_current, 1); 135 if (ifmr.ifm_active != ifmr.ifm_current) { 136 putchar(' '); 137 putchar('('); 138 print_media_word(ifmr.ifm_active, 0); 139 putchar(')'); 140 } 141 142 putchar('\n'); 143 144 if (ifmr.ifm_status & IFM_AVALID) { 145 printf("\tstatus: "); 146 switch (IFM_TYPE(ifmr.ifm_active)) { 147 case IFM_ETHER: 148 if (ifmr.ifm_status & IFM_ACTIVE) 149 printf("active"); 150 else 151 printf("no carrier"); 152 break; 153 154 case IFM_FDDI: 155 case IFM_TOKEN: 156 if (ifmr.ifm_status & IFM_ACTIVE) 157 printf("inserted"); 158 else 159 printf("no ring"); 160 break; 161 case IFM_IEEE80211: 162 /* XXX: Different value for adhoc? */ 163 if (ifmr.ifm_status & IFM_ACTIVE) 164 printf("associated"); 165 else 166 printf("no carrier"); 167 break; 168 } 169 putchar('\n'); 170 } 171 172 if (ifmr.ifm_count > 0 && supmedia) { 173 printf("\tsupported media:\n"); 174 for (i = 0; i < ifmr.ifm_count; i++) { 175 printf("\t\t"); 176 print_media_word_ifconfig(media_list[i]); 177 putchar('\n'); 178 } 179 } 180 181 free(media_list); 182 } 183 184 void 185 setmedia(const char *val, int d, int s, const struct afswtch *afp) 186 { 187 struct ifmediareq ifmr; 188 int first_type, subtype; 189 190 (void) memset(&ifmr, 0, sizeof(ifmr)); 191 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 192 193 ifmr.ifm_count = 1; 194 ifmr.ifm_ulist = &first_type; 195 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 196 /* 197 * If we get E2BIG, the kernel is telling us 198 * that there are more, so we can ignore it. 199 */ 200 if (errno != E2BIG) 201 err(1, "SIOCGIFMEDIA"); 202 } 203 204 if (ifmr.ifm_count == 0) 205 errx(1, "%s: no media types?", name); 206 207 /* 208 * We are primarily concerned with the top-level type. 209 * However, "current" may be only IFM_NONE, so we just look 210 * for the top-level type in the first "supported type" 211 * entry. 212 * 213 * (I'm assuming that all supported media types for a given 214 * interface will be the same top-level type..) 215 */ 216 subtype = get_media_subtype(IFM_TYPE(first_type), val); 217 218 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 219 ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) | 220 IFM_TYPE(first_type) | subtype; 221 222 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) 223 err(1, "SIOCSIFMEDIA"); 224 } 225 226 void 227 setmediaopt(const char *val, int d, int s, const struct afswtch *afp) 228 { 229 230 domediaopt(val, 0, s); 231 } 232 233 void 234 unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp) 235 { 236 237 domediaopt(val, 1, s); 238 } 239 240 static void 241 domediaopt(const char *val, int clear, int s) 242 { 243 struct ifmediareq ifmr; 244 int *mwords, options; 245 246 (void) memset(&ifmr, 0, sizeof(ifmr)); 247 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 248 249 /* 250 * We must go through the motions of reading all 251 * supported media because we need to know both 252 * the current media type and the top-level type. 253 */ 254 255 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 256 err(1, "SIOCGIFMEDIA"); 257 258 if (ifmr.ifm_count == 0) 259 errx(1, "%s: no media types?", name); 260 261 mwords = (int *)malloc(ifmr.ifm_count * sizeof(int)); 262 if (mwords == NULL) 263 err(1, "malloc"); 264 265 ifmr.ifm_ulist = mwords; 266 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 267 err(1, "SIOCGIFMEDIA"); 268 269 options = get_media_options(IFM_TYPE(mwords[0]), val); 270 271 free(mwords); 272 273 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 274 ifr.ifr_media = ifmr.ifm_current; 275 if (clear) 276 ifr.ifr_media &= ~options; 277 else 278 ifr.ifr_media |= options; 279 280 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) 281 err(1, "SIOCSIFMEDIA"); 282 } 283 284 /********************************************************************** 285 * A good chunk of this is duplicated from sys/net/ifmedia.c 286 **********************************************************************/ 287 288 static struct ifmedia_description ifm_type_descriptions[] = 289 IFM_TYPE_DESCRIPTIONS; 290 291 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = 292 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; 293 294 static struct ifmedia_description ifm_subtype_ethernet_aliases[] = 295 IFM_SUBTYPE_ETHERNET_ALIASES; 296 297 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = 298 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; 299 300 static struct ifmedia_description ifm_subtype_tokenring_descriptions[] = 301 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; 302 303 static struct ifmedia_description ifm_subtype_tokenring_aliases[] = 304 IFM_SUBTYPE_TOKENRING_ALIASES; 305 306 static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = 307 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; 308 309 static struct ifmedia_description ifm_subtype_fddi_descriptions[] = 310 IFM_SUBTYPE_FDDI_DESCRIPTIONS; 311 312 static struct ifmedia_description ifm_subtype_fddi_aliases[] = 313 IFM_SUBTYPE_FDDI_ALIASES; 314 315 static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = 316 IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; 317 318 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = 319 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; 320 321 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] = 322 IFM_SUBTYPE_IEEE80211_ALIASES; 323 324 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = 325 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; 326 327 static struct ifmedia_description ifm_subtype_shared_descriptions[] = 328 IFM_SUBTYPE_SHARED_DESCRIPTIONS; 329 330 static struct ifmedia_description ifm_subtype_shared_aliases[] = 331 IFM_SUBTYPE_SHARED_ALIASES; 332 333 static struct ifmedia_description ifm_shared_option_descriptions[] = 334 IFM_SHARED_OPTION_DESCRIPTIONS; 335 336 struct ifmedia_type_to_subtype { 337 struct { 338 struct ifmedia_description *desc; 339 int alias; 340 } subtypes[5]; 341 struct { 342 struct ifmedia_description *desc; 343 int alias; 344 } options[3]; 345 }; 346 347 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ 348 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { 349 { 350 { 351 { &ifm_subtype_shared_descriptions[0], 0 }, 352 { &ifm_subtype_shared_aliases[0], 1 }, 353 { &ifm_subtype_ethernet_descriptions[0], 0 }, 354 { &ifm_subtype_ethernet_aliases[0], 1 }, 355 { NULL, 0 }, 356 }, 357 { 358 { &ifm_shared_option_descriptions[0], 0 }, 359 { &ifm_subtype_ethernet_option_descriptions[0], 0 }, 360 { NULL, 0 }, 361 }, 362 }, 363 { 364 { 365 { &ifm_subtype_shared_descriptions[0], 0 }, 366 { &ifm_subtype_shared_aliases[0], 1 }, 367 { &ifm_subtype_tokenring_descriptions[0], 0 }, 368 { &ifm_subtype_tokenring_aliases[0], 1 }, 369 { NULL, 0 }, 370 }, 371 { 372 { &ifm_shared_option_descriptions[0], 0 }, 373 { &ifm_subtype_tokenring_option_descriptions[0], 0 }, 374 { NULL, 0 }, 375 }, 376 }, 377 { 378 { 379 { &ifm_subtype_shared_descriptions[0], 0 }, 380 { &ifm_subtype_shared_aliases[0], 1 }, 381 { &ifm_subtype_fddi_descriptions[0], 0 }, 382 { &ifm_subtype_fddi_aliases[0], 1 }, 383 { NULL, 0 }, 384 }, 385 { 386 { &ifm_shared_option_descriptions[0], 0 }, 387 { &ifm_subtype_fddi_option_descriptions[0], 0 }, 388 { NULL, 0 }, 389 }, 390 }, 391 { 392 { 393 { &ifm_subtype_shared_descriptions[0], 0 }, 394 { &ifm_subtype_shared_aliases[0], 1 }, 395 { &ifm_subtype_ieee80211_descriptions[0], 0 }, 396 { &ifm_subtype_ieee80211_aliases[0], 1 }, 397 { NULL, 0 }, 398 }, 399 { 400 { &ifm_shared_option_descriptions[0], 0 }, 401 { &ifm_subtype_ieee80211_option_descriptions[0], 0 }, 402 { NULL, 0 }, 403 }, 404 }, 405 }; 406 407 static int 408 get_media_subtype(int type, const char *val) 409 { 410 struct ifmedia_description *desc; 411 struct ifmedia_type_to_subtype *ttos; 412 int rval, i; 413 414 /* Find the top-level interface type. */ 415 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 416 desc->ifmt_string != NULL; desc++, ttos++) 417 if (type == desc->ifmt_word) 418 break; 419 if (desc->ifmt_string == NULL) 420 errx(1, "unknown media type 0x%x", type); 421 422 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 423 rval = lookup_media_word(ttos->subtypes[i].desc, val); 424 if (rval != -1) 425 return (rval); 426 } 427 errx(1, "unknown media subtype: %s", val); 428 /* NOTREACHED */ 429 } 430 431 static int 432 get_media_options(int type, const char *val) 433 { 434 struct ifmedia_description *desc; 435 struct ifmedia_type_to_subtype *ttos; 436 char *optlist, *optptr; 437 int option = 0, i, rval = 0; 438 439 /* We muck with the string, so copy it. */ 440 optlist = strdup(val); 441 if (optlist == NULL) 442 err(1, "strdup"); 443 444 /* Find the top-level interface type. */ 445 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 446 desc->ifmt_string != NULL; desc++, ttos++) 447 if (type == desc->ifmt_word) 448 break; 449 if (desc->ifmt_string == NULL) 450 errx(1, "unknown media type 0x%x", type); 451 452 /* 453 * Look up the options in the user-provided comma-separated 454 * list. 455 */ 456 optptr = optlist; 457 for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) { 458 for (i = 0; ttos->options[i].desc != NULL; i++) { 459 option = lookup_media_word(ttos->options[i].desc, optptr); 460 if (option != -1) 461 break; 462 } 463 if (option == 0) 464 errx(1, "unknown option: %s", optptr); 465 rval |= option; 466 } 467 468 free(optlist); 469 return (rval); 470 } 471 472 static int 473 lookup_media_word(struct ifmedia_description *desc, const char *val) 474 { 475 476 for (; desc->ifmt_string != NULL; desc++) 477 if (strcasecmp(desc->ifmt_string, val) == 0) 478 return (desc->ifmt_word); 479 480 return (-1); 481 } 482 483 static struct ifmedia_description *get_toptype_desc(int ifmw) 484 { 485 struct ifmedia_description *desc; 486 487 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) 488 if (IFM_TYPE(ifmw) == desc->ifmt_word) 489 break; 490 491 return desc; 492 } 493 494 static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw) 495 { 496 struct ifmedia_description *desc; 497 struct ifmedia_type_to_subtype *ttos; 498 499 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 500 desc->ifmt_string != NULL; desc++, ttos++) 501 if (IFM_TYPE(ifmw) == desc->ifmt_word) 502 break; 503 504 return ttos; 505 } 506 507 static struct ifmedia_description *get_subtype_desc(int ifmw, 508 struct ifmedia_type_to_subtype *ttos) 509 { 510 int i; 511 struct ifmedia_description *desc; 512 513 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 514 if (ttos->subtypes[i].alias) 515 continue; 516 for (desc = ttos->subtypes[i].desc; 517 desc->ifmt_string != NULL; desc++) { 518 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) 519 return desc; 520 } 521 } 522 523 return NULL; 524 } 525 526 static void 527 print_media_word(int ifmw, int print_toptype) 528 { 529 struct ifmedia_description *desc; 530 struct ifmedia_type_to_subtype *ttos; 531 int seen_option = 0, i; 532 533 /* Find the top-level interface type. */ 534 desc = get_toptype_desc(ifmw); 535 ttos = get_toptype_ttos(ifmw); 536 if (desc->ifmt_string == NULL) { 537 printf("<unknown type>"); 538 return; 539 } else if (print_toptype) { 540 printf("%s", desc->ifmt_string); 541 } 542 543 /* 544 * Don't print the top-level type; it's not like we can 545 * change it, or anything. 546 */ 547 548 /* Find subtype. */ 549 desc = get_subtype_desc(ifmw, ttos); 550 if (desc != NULL) 551 goto got_subtype; 552 553 /* Falling to here means unknown subtype. */ 554 printf("<unknown subtype>"); 555 return; 556 557 got_subtype: 558 if (print_toptype) 559 putchar(' '); 560 561 printf("%s", desc->ifmt_string); 562 563 /* Find options. */ 564 for (i = 0; ttos->options[i].desc != NULL; i++) { 565 if (ttos->options[i].alias) 566 continue; 567 for (desc = ttos->options[i].desc; 568 desc->ifmt_string != NULL; desc++) { 569 if (ifmw & desc->ifmt_word) { 570 if (seen_option == 0) 571 printf(" <"); 572 printf("%s%s", seen_option++ ? "," : "", 573 desc->ifmt_string); 574 } 575 } 576 } 577 printf("%s", seen_option ? ">" : ""); 578 } 579 580 static void 581 print_media_word_ifconfig(int ifmw) 582 { 583 struct ifmedia_description *desc; 584 struct ifmedia_type_to_subtype *ttos; 585 int i; 586 587 /* Find the top-level interface type. */ 588 desc = get_toptype_desc(ifmw); 589 ttos = get_toptype_ttos(ifmw); 590 if (desc->ifmt_string == NULL) { 591 printf("<unknown type>"); 592 return; 593 } 594 595 /* 596 * Don't print the top-level type; it's not like we can 597 * change it, or anything. 598 */ 599 600 /* Find subtype. */ 601 desc = get_subtype_desc(ifmw, ttos); 602 if (desc != NULL) 603 goto got_subtype; 604 605 /* Falling to here means unknown subtype. */ 606 printf("<unknown subtype>"); 607 return; 608 609 got_subtype: 610 printf("media %s", desc->ifmt_string); 611 612 /* Find options. */ 613 for (i = 0; ttos->options[i].desc != NULL; i++) { 614 if (ttos->options[i].alias) 615 continue; 616 for (desc = ttos->options[i].desc; 617 desc->ifmt_string != NULL; desc++) { 618 if (ifmw & desc->ifmt_word) { 619 printf(" mediaopt %s", desc->ifmt_string); 620 } 621 } 622 } 623 } 624 625 /********************************************************************** 626 * ...until here. 627 **********************************************************************/ 628