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