ifmedia.c revision 25450
1/* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */ 2/* $Id$ */ 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_var.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 93static void domediaopt __P((const char *, int, int)); 94static int get_media_subtype __P((int, const char *)); 95static int get_media_options __P((int, const char *)); 96static int lookup_media_word __P((struct ifmedia_description *, const char *)); 97static void print_media_word __P((int)); 98 99void 100media_status(s) 101 int s; 102{ 103 struct ifmediareq ifmr; 104 int *media_list, i; 105 106 (void) memset(&ifmr, 0, sizeof(ifmr)); 107 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 108 109 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 110 /* 111 * Interface doesn't support SIOC{G,S}IFMEDIA. 112 */ 113 return; 114 } 115 116 if (ifmr.ifm_count == 0) { 117 warnx("%s: no media types?", name); 118 return; 119 } 120 121 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); 122 if (media_list == NULL) 123 err(1, "malloc"); 124 ifmr.ifm_ulist = media_list; 125 126 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 127 err(1, "SIOCGIFMEDIA"); 128 129 printf("\tmedia: "); 130 print_media_word(ifmr.ifm_current); 131 if (ifmr.ifm_active != ifmr.ifm_current) { 132 putchar(' '); 133 putchar('('); 134 print_media_word(ifmr.ifm_active); 135 putchar(')'); 136 } 137 138 if (ifmr.ifm_status & IFM_AVALID) { 139 printf(" status: "); 140 switch (IFM_TYPE(ifmr.ifm_active)) { 141 case IFM_ETHER: 142 if (ifmr.ifm_status & IFM_ACTIVE) 143 printf("active"); 144 else 145 printf("no carrier"); 146 break; 147 148 case IFM_FDDI: 149 case IFM_TOKEN: 150 if (ifmr.ifm_status & IFM_ACTIVE) 151 printf("inserted"); 152 else 153 printf("no ring"); 154 break; 155 } 156 } 157 158 putchar('\n'); 159 160 if (allmedia) { 161 printf("\tsupported media:"); 162 for (i = 0; i < ifmr.ifm_count; i++) { 163 putchar(' '); 164 print_media_word(media_list[i]); 165 } 166 putchar('\n'); 167 } 168 169 free(media_list); 170} 171 172void 173setmedia(val, d, s) 174 const char *val; 175 int d; 176 int s; 177{ 178 struct ifmediareq ifmr; 179 int first_type, subtype; 180 181 (void) memset(&ifmr, 0, sizeof(ifmr)); 182 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 183 184 ifmr.ifm_count = 1; 185 ifmr.ifm_ulist = &first_type; 186 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 187 /* 188 * If we get E2BIG, the kernel is telling us 189 * that there are more, so we can ignore it. 190 */ 191 if (errno != E2BIG) 192 err(1, "SIOCGIFMEDIA"); 193 } 194 195 if (ifmr.ifm_count == 0) 196 errx(1, "%s: no media types?", name); 197 198 /* 199 * We are primarily concerned with the top-level type. 200 * However, "current" may be only IFM_NONE, so we just look 201 * for the top-level type in the first "supported type" 202 * entry. 203 * 204 * (I'm assuming that all supported media types for a given 205 * interface will be the same top-level type..) 206 */ 207 subtype = get_media_subtype(IFM_TYPE(first_type), val); 208 209 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 210 ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) | 211 IFM_TYPE(first_type) | subtype; 212 213 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) 214 err(1, "SIOCSIFMEDIA"); 215} 216 217void 218setmediaopt(val, d, s) 219 const char *val; 220 int d; 221 int s; 222{ 223 224 domediaopt(val, 0, s); 225} 226 227void 228unsetmediaopt(val, d, s) 229 const char *val; 230 int d; 231 int s; 232{ 233 234 domediaopt(val, 1, s); 235} 236 237static void 238domediaopt(val, clear, s) 239 const char *val; 240 int clear; 241 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 288static struct ifmedia_description ifm_type_descriptions[] = 289 IFM_TYPE_DESCRIPTIONS; 290 291static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = 292 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; 293 294static struct ifmedia_description ifm_subtype_ethernet_aliases[] = 295 IFM_SUBTYPE_ETHERNET_ALIASES; 296 297static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = 298 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; 299 300static struct ifmedia_description ifm_subtype_tokenring_descriptions[] = 301 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; 302 303static struct ifmedia_description ifm_subtype_tokenring_aliases[] = 304 IFM_SUBTYPE_TOKENRING_ALIASES; 305 306static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = 307 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; 308 309static struct ifmedia_description ifm_subtype_fddi_descriptions[] = 310 IFM_SUBTYPE_FDDI_DESCRIPTIONS; 311 312static struct ifmedia_description ifm_subtype_fddi_aliases[] = 313 IFM_SUBTYPE_FDDI_ALIASES; 314 315static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = 316 IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; 317 318static struct ifmedia_description ifm_subtype_shared_descriptions[] = 319 IFM_SUBTYPE_SHARED_DESCRIPTIONS; 320 321static struct ifmedia_description ifm_subtype_shared_aliases[] = 322 IFM_SUBTYPE_SHARED_ALIASES; 323 324static struct ifmedia_description ifm_shared_option_descriptions[] = 325 IFM_SHARED_OPTION_DESCRIPTIONS; 326 327struct ifmedia_type_to_subtype { 328 struct { 329 struct ifmedia_description *desc; 330 int alias; 331 } subtypes[5]; 332 struct { 333 struct ifmedia_description *desc; 334 int alias; 335 } options[3]; 336}; 337 338/* must be in the same order as IFM_TYPE_DESCRIPTIONS */ 339static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { 340 { 341 { 342 { &ifm_subtype_shared_descriptions[0], 0 }, 343 { &ifm_subtype_shared_aliases[0], 1 }, 344 { &ifm_subtype_ethernet_descriptions[0], 0 }, 345 { &ifm_subtype_ethernet_aliases[0], 1 }, 346 { NULL, 0 }, 347 }, 348 { 349 { &ifm_shared_option_descriptions[0], 0 }, 350 { &ifm_subtype_ethernet_option_descriptions[0], 1 }, 351 { NULL, 0 }, 352 }, 353 }, 354 { 355 { 356 { &ifm_subtype_shared_descriptions[0], 0 }, 357 { &ifm_subtype_shared_aliases[0], 1 }, 358 { &ifm_subtype_tokenring_descriptions[0], 0 }, 359 { &ifm_subtype_tokenring_aliases[0], 1 }, 360 { NULL, 0 }, 361 }, 362 { 363 { &ifm_shared_option_descriptions[0], 0 }, 364 { &ifm_subtype_tokenring_option_descriptions[0], 1 }, 365 { NULL, 0 }, 366 }, 367 }, 368 { 369 { 370 { &ifm_subtype_shared_descriptions[0], 0 }, 371 { &ifm_subtype_shared_aliases[0], 1 }, 372 { &ifm_subtype_fddi_descriptions[0], 0 }, 373 { &ifm_subtype_fddi_aliases[0], 1 }, 374 { NULL, 0 }, 375 }, 376 { 377 { &ifm_shared_option_descriptions[0], 0 }, 378 { &ifm_subtype_fddi_option_descriptions[0], 1 }, 379 { NULL, 0 }, 380 }, 381 }, 382}; 383 384static int 385get_media_subtype(type, val) 386 int type; 387 const char *val; 388{ 389 struct ifmedia_description *desc; 390 struct ifmedia_type_to_subtype *ttos; 391 int rval, i; 392 393 /* Find the top-level interface type. */ 394 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 395 desc->ifmt_string != NULL; desc++, ttos++) 396 if (type == desc->ifmt_word) 397 break; 398 if (desc->ifmt_string == NULL) 399 errx(1, "unknown media type 0x%x", type); 400 401 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 402 rval = lookup_media_word(ttos->subtypes[i].desc, val); 403 if (rval != -1) 404 return (rval); 405 } 406 errx(1, "unknown media subtype: %s", val); 407 /* NOTREACHED */ 408} 409 410static int 411get_media_options(type, val) 412 int type; 413 const char *val; 414{ 415 struct ifmedia_description *desc; 416 struct ifmedia_type_to_subtype *ttos; 417 char *optlist, *optptr; 418 int option = 0, i, rval = 0; 419 420 /* We muck with the string, so copy it. */ 421 optlist = strdup(val); 422 if (optlist == NULL) 423 err(1, "strdup"); 424 425 /* Find the top-level interface type. */ 426 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 427 desc->ifmt_string != NULL; desc++, ttos++) 428 if (type == desc->ifmt_word) 429 break; 430 if (desc->ifmt_string == NULL) 431 errx(1, "unknown media type 0x%x", type); 432 433 /* 434 * Look up the options in the user-provided comma-separated 435 * list. 436 */ 437 optptr = optlist; 438 for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) { 439 for (i = 0; ttos->options[i].desc != NULL; i++) { 440 option = lookup_media_word(ttos->options[i].desc, optptr); 441 if (option != -1) 442 break; 443 } 444 if (option == 0) 445 errx(1, "unknown option: %s", optptr); 446 rval |= option; 447 } 448 449 free(optlist); 450 return (rval); 451} 452 453static int 454lookup_media_word(desc, val) 455 struct ifmedia_description *desc; 456 const char *val; 457{ 458 459 for (; desc->ifmt_string != NULL; desc++) 460 if (strcasecmp(desc->ifmt_string, val) == 0) 461 return (desc->ifmt_word); 462 463 return (-1); 464} 465 466static void 467print_media_word(ifmw) 468 int ifmw; 469{ 470 struct ifmedia_description *desc; 471 struct ifmedia_type_to_subtype *ttos; 472 int seen_option = 0, i; 473 474 /* Find the top-level interface type. */ 475 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 476 desc->ifmt_string != NULL; desc++, ttos++) 477 if (IFM_TYPE(ifmw) == desc->ifmt_word) 478 break; 479 if (desc->ifmt_string == NULL) { 480 printf("<unknown type>"); 481 return; 482 } 483 484 /* 485 * Don't print the top-level type; it's not like we can 486 * change it, or anything. 487 */ 488 489 /* Find subtype. */ 490 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 491 if (ttos->subtypes[i].alias) 492 continue; 493 for (desc = ttos->subtypes[i].desc; 494 desc->ifmt_string != NULL; desc++) { 495 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) 496 goto got_subtype; 497 } 498 } 499 500 /* Falling to here means unknown subtype. */ 501 printf("<unknown subtype>"); 502 return; 503 504 got_subtype: 505 printf("%s", desc->ifmt_string); 506 507 /* Find options. */ 508 for (i = 0; ttos->options[i].desc != NULL; i++) { 509 if (ttos->options[i].alias) 510 continue; 511 for (desc = ttos->options[i].desc; 512 desc->ifmt_string != NULL; desc++) { 513 if (ifmw & desc->ifmt_word) { 514 if (seen_option == 0) 515 printf(" <"); 516 printf("%s%s", seen_option++ ? "," : "", 517 desc->ifmt_string); 518 } 519 } 520 } 521 printf("%s", seen_option ? ">" : ""); 522} 523 524/********************************************************************** 525 * ...until here. 526 **********************************************************************/ 527