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