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