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