1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifndef lint 31 static const char copyright[] = 32 "@(#) Copyright (c) 1983, 1993\n\ 33 The Regents of the University of California. All rights reserved.\n"; 34 #endif /* not lint */ 35 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; 39 #endif 40 static const char rcsid[] = 41 "$FreeBSD$"; 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 #include <sys/ioctl.h> 46 #include <sys/module.h> 47 #include <sys/linker.h> 48 #include <sys/queue.h> 49 #include <sys/socket.h> 50 #include <sys/time.h> 51 52 #include <net/ethernet.h> 53 #include <net/if.h> 54 #include <net/if_dl.h> 55 #include <net/if_types.h> 56 #include <net/route.h> 57 58 /* IP */ 59 #include <netinet/in.h> 60 #include <netinet/in_var.h> 61 #include <arpa/inet.h> 62 #include <netdb.h> 63 64 #include <ifaddrs.h> 65 #include <ctype.h> 66 #include <err.h> 67 #include <errno.h> 68 #include <fcntl.h> 69 #ifdef JAIL 70 #include <jail.h> 71 #endif 72 #include <stdio.h> 73 #include <stdlib.h> 74 #include <string.h> 75 #include <unistd.h> 76 77 #include "ifconfig.h" 78 79 /* 80 * Since "struct ifreq" is composed of various union members, callers 81 * should pay special attention to interpret the value. 82 * (.e.g. little/big endian difference in the structure.) 83 */ 84 struct ifreq ifr; 85 86 char name[IFNAMSIZ]; 87 char *descr = NULL; 88 size_t descrlen = 64; 89 int setaddr; 90 int setmask; 91 int doalias; 92 int clearaddr; 93 int newaddr = 1; 94 int verbose; 95 int noload; 96 int printifname = 0; 97 98 int supmedia = 0; 99 int printkeys = 0; /* Print keying material for interfaces. */ 100 101 static int ifconfig(int argc, char *const *argv, int iscreate, 102 const struct afswtch *afp); 103 static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, 104 struct ifaddrs *ifa); 105 static void tunnel_status(int s); 106 static void usage(void); 107 108 static struct afswtch *af_getbyname(const char *name); 109 static struct afswtch *af_getbyfamily(int af); 110 static void af_other_status(int); 111 112 void printifnamemaybe(void); 113 114 static struct option *opts = NULL; 115 116 struct ifa_order_elt { 117 int if_order; 118 int af_orders[255]; 119 struct ifaddrs *ifa; 120 TAILQ_ENTRY(ifa_order_elt) link; 121 }; 122 123 TAILQ_HEAD(ifa_queue, ifa_order_elt); 124 125 void 126 opt_register(struct option *p) 127 { 128 p->next = opts; 129 opts = p; 130 } 131 132 static void 133 usage(void) 134 { 135 char options[1024]; 136 struct option *p; 137 138 /* XXX not right but close enough for now */ 139 options[0] = '\0'; 140 for (p = opts; p != NULL; p = p->next) { 141 strlcat(options, p->opt_usage, sizeof(options)); 142 strlcat(options, " ", sizeof(options)); 143 } 144 145 fprintf(stderr, 146 "usage: ifconfig %sinterface address_family [address [dest_address]]\n" 147 " [parameters]\n" 148 " ifconfig interface create\n" 149 " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n" 150 " ifconfig -l [-d] [-u] [address_family]\n" 151 " ifconfig %s[-d] [-m] [-u] [-v]\n", 152 options, options, options); 153 exit(1); 154 } 155 156 #define ORDERS_SIZE(x) sizeof(x) / sizeof(x[0]) 157 158 static int 159 calcorders(struct ifaddrs *ifa, struct ifa_queue *q) 160 { 161 struct ifaddrs *prev; 162 struct ifa_order_elt *cur; 163 unsigned int ord, af, ifa_ord; 164 165 prev = NULL; 166 cur = NULL; 167 ord = 0; 168 ifa_ord = 0; 169 170 while (ifa != NULL) { 171 if (prev == NULL || 172 strcmp(ifa->ifa_name, prev->ifa_name) != 0) { 173 cur = calloc(1, sizeof(*cur)); 174 175 if (cur == NULL) 176 return (-1); 177 178 TAILQ_INSERT_TAIL(q, cur, link); 179 cur->if_order = ifa_ord ++; 180 cur->ifa = ifa; 181 ord = 0; 182 } 183 184 if (ifa->ifa_addr) { 185 af = ifa->ifa_addr->sa_family; 186 187 if (af < ORDERS_SIZE(cur->af_orders) && 188 cur->af_orders[af] == 0) 189 cur->af_orders[af] = ++ord; 190 } 191 prev = ifa; 192 ifa = ifa->ifa_next; 193 } 194 195 return (0); 196 } 197 198 static int 199 cmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q) 200 { 201 struct ifa_order_elt *cur, *e1, *e2; 202 unsigned int af1, af2; 203 int ret; 204 205 e1 = e2 = NULL; 206 207 ret = strcmp(a->ifa_name, b->ifa_name); 208 if (ret != 0) { 209 TAILQ_FOREACH(cur, q, link) { 210 if (e1 && e2) 211 break; 212 213 if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) 214 e1 = cur; 215 else if (strcmp(cur->ifa->ifa_name, b->ifa_name) == 0) 216 e2 = cur; 217 } 218 219 if (!e1 || !e2) 220 return (0); 221 else 222 return (e1->if_order - e2->if_order); 223 224 } else if (a->ifa_addr != NULL && b->ifa_addr != NULL) { 225 TAILQ_FOREACH(cur, q, link) { 226 if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) { 227 e1 = cur; 228 break; 229 } 230 } 231 232 if (!e1) 233 return (0); 234 235 af1 = a->ifa_addr->sa_family; 236 af2 = b->ifa_addr->sa_family; 237 238 if (af1 < ORDERS_SIZE(e1->af_orders) && 239 af2 < ORDERS_SIZE(e1->af_orders)) 240 return (e1->af_orders[af1] - e1->af_orders[af2]); 241 } 242 243 return (0); 244 } 245 246 #undef ORDERS_SIZE 247 248 static struct ifaddrs * 249 sortifaddrs(struct ifaddrs *list, 250 int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *), 251 struct ifa_queue *q) 252 { 253 struct ifaddrs *right, *temp, *last, *result, *next, *tail; 254 255 right = list; 256 temp = list; 257 last = list; 258 result = NULL; 259 next = NULL; 260 tail = NULL; 261 262 if (!list || !list->ifa_next) 263 return (list); 264 265 while (temp && temp->ifa_next) { 266 last = right; 267 right = right->ifa_next; 268 temp = temp->ifa_next->ifa_next; 269 } 270 271 last->ifa_next = NULL; 272 273 list = sortifaddrs(list, compare, q); 274 right = sortifaddrs(right, compare, q); 275 276 while (list || right) { 277 278 if (!right) { 279 next = list; 280 list = list->ifa_next; 281 } else if (!list) { 282 next = right; 283 right = right->ifa_next; 284 } else if (compare(list, right, q) <= 0) { 285 next = list; 286 list = list->ifa_next; 287 } else { 288 next = right; 289 right = right->ifa_next; 290 } 291 292 if (!result) 293 result = next; 294 else 295 tail->ifa_next = next; 296 297 tail = next; 298 } 299 300 return (result); 301 } 302 303 void printifnamemaybe() 304 { 305 if (printifname) 306 printf("%s\n", name); 307 } 308 309 int 310 main(int argc, char *argv[]) 311 { 312 int c, all, namesonly, downonly, uponly; 313 const struct afswtch *afp = NULL; 314 int ifindex; 315 struct ifaddrs *ifap, *sifap, *ifa; 316 struct ifreq paifr; 317 const struct sockaddr_dl *sdl; 318 char options[1024], *cp, *namecp = NULL; 319 struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); 320 struct ifa_order_elt *cur, *tmp; 321 const char *ifname; 322 struct option *p; 323 size_t iflen; 324 325 all = downonly = uponly = namesonly = noload = verbose = 0; 326 327 /* 328 * Ensure we print interface name when expected to, 329 * even if we terminate early due to error. 330 */ 331 atexit(printifnamemaybe); 332 333 /* Parse leading line options */ 334 strlcpy(options, "adklmnuv", sizeof(options)); 335 for (p = opts; p != NULL; p = p->next) 336 strlcat(options, p->opt, sizeof(options)); 337 while ((c = getopt(argc, argv, options)) != -1) { 338 switch (c) { 339 case 'a': /* scan all interfaces */ 340 all++; 341 break; 342 case 'd': /* restrict scan to "down" interfaces */ 343 downonly++; 344 break; 345 case 'k': 346 printkeys++; 347 break; 348 case 'l': /* scan interface names only */ 349 namesonly++; 350 break; 351 case 'm': /* show media choices in status */ 352 supmedia = 1; 353 break; 354 case 'n': /* suppress module loading */ 355 noload++; 356 break; 357 case 'u': /* restrict scan to "up" interfaces */ 358 uponly++; 359 break; 360 case 'v': 361 verbose++; 362 break; 363 default: 364 for (p = opts; p != NULL; p = p->next) 365 if (p->opt[0] == c) { 366 p->cb(optarg); 367 break; 368 } 369 if (p == NULL) 370 usage(); 371 break; 372 } 373 } 374 argc -= optind; 375 argv += optind; 376 377 /* -l cannot be used with -a or -m */ 378 if (namesonly && (all || supmedia)) 379 usage(); 380 381 /* nonsense.. */ 382 if (uponly && downonly) 383 usage(); 384 385 /* no arguments is equivalent to '-a' */ 386 if (!namesonly && argc < 1) 387 all = 1; 388 389 /* -a and -l allow an address family arg to limit the output */ 390 if (all || namesonly) { 391 if (argc > 1) 392 usage(); 393 394 ifname = NULL; 395 ifindex = 0; 396 if (argc == 1) { 397 afp = af_getbyname(*argv); 398 if (afp == NULL) { 399 warnx("Address family '%s' unknown.", *argv); 400 usage(); 401 } 402 if (afp->af_name != NULL) 403 argc--, argv++; 404 /* leave with afp non-zero */ 405 } 406 } else { 407 /* not listing, need an argument */ 408 if (argc < 1) 409 usage(); 410 411 ifname = *argv; 412 argc--, argv++; 413 414 /* check and maybe load support for this interface */ 415 ifmaybeload(ifname); 416 417 ifindex = if_nametoindex(ifname); 418 if (ifindex == 0) { 419 /* 420 * NOTE: We must special-case the `create' command 421 * right here as we would otherwise fail when trying 422 * to find the interface. 423 */ 424 if (argc > 0 && (strcmp(argv[0], "create") == 0 || 425 strcmp(argv[0], "plumb") == 0)) { 426 iflen = strlcpy(name, ifname, sizeof(name)); 427 if (iflen >= sizeof(name)) 428 errx(1, "%s: cloning name too long", 429 ifname); 430 ifconfig(argc, argv, 1, NULL); 431 exit(0); 432 } 433 #ifdef JAIL 434 /* 435 * NOTE: We have to special-case the `-vnet' command 436 * right here as we would otherwise fail when trying 437 * to find the interface as it lives in another vnet. 438 */ 439 if (argc > 0 && (strcmp(argv[0], "-vnet") == 0)) { 440 iflen = strlcpy(name, ifname, sizeof(name)); 441 if (iflen >= sizeof(name)) 442 errx(1, "%s: interface name too long", 443 ifname); 444 ifconfig(argc, argv, 0, NULL); 445 exit(0); 446 } 447 #endif 448 errx(1, "interface %s does not exist", ifname); 449 } 450 } 451 452 /* Check for address family */ 453 if (argc > 0) { 454 afp = af_getbyname(*argv); 455 if (afp != NULL) 456 argc--, argv++; 457 } 458 459 if (getifaddrs(&ifap) != 0) 460 err(EXIT_FAILURE, "getifaddrs"); 461 462 cp = NULL; 463 464 if (calcorders(ifap, &q) != 0) 465 err(EXIT_FAILURE, "calcorders"); 466 467 sifap = sortifaddrs(ifap, cmpifaddrs, &q); 468 469 TAILQ_FOREACH_SAFE(cur, &q, link, tmp) 470 free(cur); 471 472 ifindex = 0; 473 for (ifa = sifap; ifa; ifa = ifa->ifa_next) { 474 memset(&paifr, 0, sizeof(paifr)); 475 strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); 476 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) { 477 memcpy(&paifr.ifr_addr, ifa->ifa_addr, 478 ifa->ifa_addr->sa_len); 479 } 480 481 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0) 482 continue; 483 if (ifa->ifa_addr->sa_family == AF_LINK) 484 sdl = (const struct sockaddr_dl *) ifa->ifa_addr; 485 else 486 sdl = NULL; 487 if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !namesonly) 488 continue; 489 iflen = strlcpy(name, ifa->ifa_name, sizeof(name)); 490 if (iflen >= sizeof(name)) { 491 warnx("%s: interface name too long, skipping", 492 ifa->ifa_name); 493 continue; 494 } 495 cp = ifa->ifa_name; 496 497 if ((ifa->ifa_flags & IFF_CANTCONFIG) != 0) 498 continue; 499 if (downonly && (ifa->ifa_flags & IFF_UP) != 0) 500 continue; 501 if (uponly && (ifa->ifa_flags & IFF_UP) == 0) 502 continue; 503 /* 504 * Are we just listing the interfaces? 505 */ 506 if (namesonly) { 507 if (namecp == cp) 508 continue; 509 if (afp != NULL) { 510 /* special case for "ether" address family */ 511 if (!strcmp(afp->af_name, "ether")) { 512 if (sdl == NULL || 513 (sdl->sdl_type != IFT_ETHER && 514 sdl->sdl_type != IFT_L2VLAN && 515 sdl->sdl_type != IFT_BRIDGE) || 516 sdl->sdl_alen != ETHER_ADDR_LEN) 517 continue; 518 } else { 519 if (ifa->ifa_addr->sa_family 520 != afp->af_af) 521 continue; 522 } 523 } 524 namecp = cp; 525 ifindex++; 526 if (ifindex > 1) 527 printf(" "); 528 fputs(name, stdout); 529 continue; 530 } 531 ifindex++; 532 533 if (argc > 0) 534 ifconfig(argc, argv, 0, afp); 535 else 536 status(afp, sdl, ifa); 537 } 538 if (namesonly) 539 printf("\n"); 540 freeifaddrs(ifap); 541 542 exit(0); 543 } 544 545 static struct afswtch *afs = NULL; 546 547 void 548 af_register(struct afswtch *p) 549 { 550 p->af_next = afs; 551 afs = p; 552 } 553 554 static struct afswtch * 555 af_getbyname(const char *name) 556 { 557 struct afswtch *afp; 558 559 for (afp = afs; afp != NULL; afp = afp->af_next) 560 if (strcmp(afp->af_name, name) == 0) 561 return afp; 562 return NULL; 563 } 564 565 static struct afswtch * 566 af_getbyfamily(int af) 567 { 568 struct afswtch *afp; 569 570 for (afp = afs; afp != NULL; afp = afp->af_next) 571 if (afp->af_af == af) 572 return afp; 573 return NULL; 574 } 575 576 static void 577 af_other_status(int s) 578 { 579 struct afswtch *afp; 580 uint8_t afmask[howmany(AF_MAX, NBBY)]; 581 582 memset(afmask, 0, sizeof(afmask)); 583 for (afp = afs; afp != NULL; afp = afp->af_next) { 584 if (afp->af_other_status == NULL) 585 continue; 586 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) 587 continue; 588 afp->af_other_status(s); 589 setbit(afmask, afp->af_af); 590 } 591 } 592 593 static void 594 af_all_tunnel_status(int s) 595 { 596 struct afswtch *afp; 597 uint8_t afmask[howmany(AF_MAX, NBBY)]; 598 599 memset(afmask, 0, sizeof(afmask)); 600 for (afp = afs; afp != NULL; afp = afp->af_next) { 601 if (afp->af_status_tunnel == NULL) 602 continue; 603 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) 604 continue; 605 afp->af_status_tunnel(s); 606 setbit(afmask, afp->af_af); 607 } 608 } 609 610 static struct cmd *cmds = NULL; 611 612 void 613 cmd_register(struct cmd *p) 614 { 615 p->c_next = cmds; 616 cmds = p; 617 } 618 619 static const struct cmd * 620 cmd_lookup(const char *name, int iscreate) 621 { 622 const struct cmd *p; 623 624 for (p = cmds; p != NULL; p = p->c_next) 625 if (strcmp(name, p->c_name) == 0) { 626 if (iscreate) { 627 if (p->c_iscloneop) 628 return p; 629 } else { 630 if (!p->c_iscloneop) 631 return p; 632 } 633 } 634 return NULL; 635 } 636 637 struct callback { 638 callback_func *cb_func; 639 void *cb_arg; 640 struct callback *cb_next; 641 }; 642 static struct callback *callbacks = NULL; 643 644 void 645 callback_register(callback_func *func, void *arg) 646 { 647 struct callback *cb; 648 649 cb = malloc(sizeof(struct callback)); 650 if (cb == NULL) 651 errx(1, "unable to allocate memory for callback"); 652 cb->cb_func = func; 653 cb->cb_arg = arg; 654 cb->cb_next = callbacks; 655 callbacks = cb; 656 } 657 658 /* specially-handled commands */ 659 static void setifaddr(const char *, int, int, const struct afswtch *); 660 static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr); 661 662 static void setifdstaddr(const char *, int, int, const struct afswtch *); 663 static const struct cmd setifdstaddr_cmd = 664 DEF_CMD("ifdstaddr", 0, setifdstaddr); 665 666 static int 667 ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp) 668 { 669 const struct afswtch *afp, *nafp; 670 const struct cmd *p; 671 struct callback *cb; 672 int s; 673 674 strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); 675 afp = NULL; 676 if (uafp != NULL) 677 afp = uafp; 678 /* 679 * This is the historical "accident" allowing users to configure IPv4 680 * addresses without the "inet" keyword which while a nice feature has 681 * proven to complicate other things. We cannot remove this but only 682 * make sure we will never have a similar implicit default for IPv6 or 683 * any other address familiy. We need a fallback though for 684 * ifconfig IF up/down etc. to work without INET support as people 685 * never used ifconfig IF link up/down, etc. either. 686 */ 687 #ifndef RESCUE 688 #ifdef INET 689 if (afp == NULL && feature_present("inet")) 690 afp = af_getbyname("inet"); 691 #endif 692 #endif 693 if (afp == NULL) 694 afp = af_getbyname("link"); 695 if (afp == NULL) { 696 warnx("Please specify an address_family."); 697 usage(); 698 } 699 top: 700 ifr.ifr_addr.sa_family = 701 afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ? 702 AF_LOCAL : afp->af_af; 703 704 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 && 705 (uafp != NULL || errno != EAFNOSUPPORT || 706 (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)) 707 err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family); 708 709 while (argc > 0) { 710 p = cmd_lookup(*argv, iscreate); 711 if (iscreate && p == NULL) { 712 /* 713 * Push the clone create callback so the new 714 * device is created and can be used for any 715 * remaining arguments. 716 */ 717 cb = callbacks; 718 if (cb == NULL) 719 errx(1, "internal error, no callback"); 720 callbacks = cb->cb_next; 721 cb->cb_func(s, cb->cb_arg); 722 iscreate = 0; 723 /* 724 * Handle any address family spec that 725 * immediately follows and potentially 726 * recreate the socket. 727 */ 728 nafp = af_getbyname(*argv); 729 if (nafp != NULL) { 730 argc--, argv++; 731 if (nafp != afp) { 732 close(s); 733 afp = nafp; 734 goto top; 735 } 736 } 737 /* 738 * Look for a normal parameter. 739 */ 740 continue; 741 } 742 if (p == NULL) { 743 /* 744 * Not a recognized command, choose between setting 745 * the interface address and the dst address. 746 */ 747 p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd); 748 } 749 if (p->c_u.c_func || p->c_u.c_func2) { 750 if (p->c_parameter == NEXTARG) { 751 if (argv[1] == NULL) 752 errx(1, "'%s' requires argument", 753 p->c_name); 754 p->c_u.c_func(argv[1], 0, s, afp); 755 argc--, argv++; 756 } else if (p->c_parameter == OPTARG) { 757 p->c_u.c_func(argv[1], 0, s, afp); 758 if (argv[1] != NULL) 759 argc--, argv++; 760 } else if (p->c_parameter == NEXTARG2) { 761 if (argc < 3) 762 errx(1, "'%s' requires 2 arguments", 763 p->c_name); 764 p->c_u.c_func2(argv[1], argv[2], s, afp); 765 argc -= 2, argv += 2; 766 } else 767 p->c_u.c_func(*argv, p->c_parameter, s, afp); 768 } 769 argc--, argv++; 770 } 771 772 /* 773 * Do any post argument processing required by the address family. 774 */ 775 if (afp->af_postproc != NULL) 776 afp->af_postproc(s, afp); 777 /* 778 * Do deferred callbacks registered while processing 779 * command-line arguments. 780 */ 781 for (cb = callbacks; cb != NULL; cb = cb->cb_next) 782 cb->cb_func(s, cb->cb_arg); 783 /* 784 * Do deferred operations. 785 */ 786 if (clearaddr) { 787 if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { 788 warnx("interface %s cannot change %s addresses!", 789 name, afp->af_name); 790 clearaddr = 0; 791 } 792 } 793 if (clearaddr) { 794 int ret; 795 strlcpy(((struct ifreq *)afp->af_ridreq)->ifr_name, name, 796 sizeof ifr.ifr_name); 797 ret = ioctl(s, afp->af_difaddr, afp->af_ridreq); 798 if (ret < 0) { 799 if (errno == EADDRNOTAVAIL && (doalias >= 0)) { 800 /* means no previous address for interface */ 801 } else 802 Perror("ioctl (SIOCDIFADDR)"); 803 } 804 } 805 if (newaddr) { 806 if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { 807 warnx("interface %s cannot change %s addresses!", 808 name, afp->af_name); 809 newaddr = 0; 810 } 811 } 812 if (newaddr && (setaddr || setmask)) { 813 strlcpy(((struct ifreq *)afp->af_addreq)->ifr_name, name, 814 sizeof ifr.ifr_name); 815 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) 816 Perror("ioctl (SIOCAIFADDR)"); 817 } 818 819 close(s); 820 return(0); 821 } 822 823 /*ARGSUSED*/ 824 static void 825 setifaddr(const char *addr, int param, int s, const struct afswtch *afp) 826 { 827 if (afp->af_getaddr == NULL) 828 return; 829 /* 830 * Delay the ioctl to set the interface addr until flags are all set. 831 * The address interpretation may depend on the flags, 832 * and the flags may change when the address is set. 833 */ 834 setaddr++; 835 if (doalias == 0 && afp->af_af != AF_LINK) 836 clearaddr = 1; 837 afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR)); 838 } 839 840 static void 841 settunnel(const char *src, const char *dst, int s, const struct afswtch *afp) 842 { 843 struct addrinfo *srcres, *dstres; 844 int ecode; 845 846 if (afp->af_settunnel == NULL) { 847 warn("address family %s does not support tunnel setup", 848 afp->af_name); 849 return; 850 } 851 852 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) 853 errx(1, "error in parsing address string: %s", 854 gai_strerror(ecode)); 855 856 if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) 857 errx(1, "error in parsing address string: %s", 858 gai_strerror(ecode)); 859 860 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) 861 errx(1, 862 "source and destination address families do not match"); 863 864 afp->af_settunnel(s, srcres, dstres); 865 866 freeaddrinfo(srcres); 867 freeaddrinfo(dstres); 868 } 869 870 /* ARGSUSED */ 871 static void 872 deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) 873 { 874 875 if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) 876 err(1, "SIOCDIFPHYADDR"); 877 } 878 879 #ifdef JAIL 880 static void 881 setifvnet(const char *jname, int dummy __unused, int s, 882 const struct afswtch *afp) 883 { 884 struct ifreq my_ifr; 885 886 memcpy(&my_ifr, &ifr, sizeof(my_ifr)); 887 my_ifr.ifr_jid = jail_getid(jname); 888 if (my_ifr.ifr_jid < 0) 889 errx(1, "%s", jail_errmsg); 890 if (ioctl(s, SIOCSIFVNET, &my_ifr) < 0) 891 err(1, "SIOCSIFVNET"); 892 } 893 894 static void 895 setifrvnet(const char *jname, int dummy __unused, int s, 896 const struct afswtch *afp) 897 { 898 struct ifreq my_ifr; 899 900 memcpy(&my_ifr, &ifr, sizeof(my_ifr)); 901 my_ifr.ifr_jid = jail_getid(jname); 902 if (my_ifr.ifr_jid < 0) 903 errx(1, "%s", jail_errmsg); 904 if (ioctl(s, SIOCSIFRVNET, &my_ifr) < 0) 905 err(1, "SIOCSIFRVNET(%d, %s)", my_ifr.ifr_jid, my_ifr.ifr_name); 906 } 907 #endif 908 909 static void 910 setifnetmask(const char *addr, int dummy __unused, int s, 911 const struct afswtch *afp) 912 { 913 if (afp->af_getaddr != NULL) { 914 setmask++; 915 afp->af_getaddr(addr, MASK); 916 } 917 } 918 919 static void 920 setifbroadaddr(const char *addr, int dummy __unused, int s, 921 const struct afswtch *afp) 922 { 923 if (afp->af_getaddr != NULL) 924 afp->af_getaddr(addr, DSTADDR); 925 } 926 927 static void 928 notealias(const char *addr, int param, int s, const struct afswtch *afp) 929 { 930 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) 931 if (setaddr && doalias == 0 && param < 0) 932 if (afp->af_addreq != NULL && afp->af_ridreq != NULL) 933 bcopy((caddr_t)rqtosa(af_addreq), 934 (caddr_t)rqtosa(af_ridreq), 935 rqtosa(af_addreq)->sa_len); 936 doalias = param; 937 if (param < 0) { 938 clearaddr = 1; 939 newaddr = 0; 940 } else 941 clearaddr = 0; 942 #undef rqtosa 943 } 944 945 /*ARGSUSED*/ 946 static void 947 setifdstaddr(const char *addr, int param __unused, int s, 948 const struct afswtch *afp) 949 { 950 if (afp->af_getaddr != NULL) 951 afp->af_getaddr(addr, DSTADDR); 952 } 953 954 /* 955 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion 956 * of the ifreq structure, which may confuse other parts of ifconfig. 957 * Make a private copy so we can avoid that. 958 */ 959 static void 960 setifflags(const char *vname, int value, int s, const struct afswtch *afp) 961 { 962 struct ifreq my_ifr; 963 int flags; 964 965 memset(&my_ifr, 0, sizeof(my_ifr)); 966 (void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name)); 967 968 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { 969 Perror("ioctl (SIOCGIFFLAGS)"); 970 exit(1); 971 } 972 flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16); 973 974 if (value < 0) { 975 value = -value; 976 flags &= ~value; 977 } else 978 flags |= value; 979 my_ifr.ifr_flags = flags & 0xffff; 980 my_ifr.ifr_flagshigh = flags >> 16; 981 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) 982 Perror(vname); 983 } 984 985 void 986 setifcap(const char *vname, int value, int s, const struct afswtch *afp) 987 { 988 int flags; 989 990 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) { 991 Perror("ioctl (SIOCGIFCAP)"); 992 exit(1); 993 } 994 flags = ifr.ifr_curcap; 995 if (value < 0) { 996 value = -value; 997 flags &= ~value; 998 } else 999 flags |= value; 1000 flags &= ifr.ifr_reqcap; 1001 ifr.ifr_reqcap = flags; 1002 if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0) 1003 Perror(vname); 1004 } 1005 1006 static void 1007 setifmetric(const char *val, int dummy __unused, int s, 1008 const struct afswtch *afp) 1009 { 1010 strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 1011 ifr.ifr_metric = atoi(val); 1012 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) 1013 err(1, "ioctl SIOCSIFMETRIC (set metric)"); 1014 } 1015 1016 static void 1017 setifmtu(const char *val, int dummy __unused, int s, 1018 const struct afswtch *afp) 1019 { 1020 strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 1021 ifr.ifr_mtu = atoi(val); 1022 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) 1023 err(1, "ioctl SIOCSIFMTU (set mtu)"); 1024 } 1025 1026 static void 1027 setifname(const char *val, int dummy __unused, int s, 1028 const struct afswtch *afp) 1029 { 1030 char *newname; 1031 1032 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1033 1034 newname = strdup(val); 1035 if (newname == NULL) 1036 err(1, "no memory to set ifname"); 1037 ifr.ifr_data = newname; 1038 if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { 1039 free(newname); 1040 err(1, "ioctl SIOCSIFNAME (set name)"); 1041 } 1042 printifname = 1; 1043 strlcpy(name, newname, sizeof(name)); 1044 free(newname); 1045 } 1046 1047 /* ARGSUSED */ 1048 static void 1049 setifdescr(const char *val, int dummy __unused, int s, 1050 const struct afswtch *afp) 1051 { 1052 char *newdescr; 1053 1054 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1055 1056 ifr.ifr_buffer.length = strlen(val) + 1; 1057 if (ifr.ifr_buffer.length == 1) { 1058 ifr.ifr_buffer.buffer = newdescr = NULL; 1059 ifr.ifr_buffer.length = 0; 1060 } else { 1061 newdescr = strdup(val); 1062 ifr.ifr_buffer.buffer = newdescr; 1063 if (newdescr == NULL) { 1064 warn("no memory to set ifdescr"); 1065 return; 1066 } 1067 } 1068 1069 if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) 1070 err(1, "ioctl SIOCSIFDESCR (set descr)"); 1071 1072 free(newdescr); 1073 } 1074 1075 /* ARGSUSED */ 1076 static void 1077 unsetifdescr(const char *val, int value, int s, const struct afswtch *afp) 1078 { 1079 1080 setifdescr("", 0, s, 0); 1081 } 1082 1083 #define IFFBITS \ 1084 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \ 1085 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ 1086 "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP" 1087 1088 #define IFCAPBITS \ 1089 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \ 1090 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \ 1091 "\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \ 1092 "\26RXCSUM_IPV6\27TXCSUM_IPV6" 1093 1094 /* 1095 * Print the status of the interface. If an address family was 1096 * specified, show only it; otherwise, show them all. 1097 */ 1098 static void 1099 status(const struct afswtch *afp, const struct sockaddr_dl *sdl, 1100 struct ifaddrs *ifa) 1101 { 1102 struct ifaddrs *ift; 1103 int allfamilies, s; 1104 struct ifstat ifs; 1105 1106 if (afp == NULL) { 1107 allfamilies = 1; 1108 ifr.ifr_addr.sa_family = AF_LOCAL; 1109 } else { 1110 allfamilies = 0; 1111 ifr.ifr_addr.sa_family = 1112 afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af; 1113 } 1114 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1115 1116 s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); 1117 if (s < 0) 1118 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); 1119 1120 printf("%s: ", name); 1121 printb("flags", ifa->ifa_flags, IFFBITS); 1122 if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1) 1123 printf(" metric %d", ifr.ifr_metric); 1124 if (ioctl(s, SIOCGIFMTU, &ifr) != -1) 1125 printf(" mtu %d", ifr.ifr_mtu); 1126 putchar('\n'); 1127 1128 for (;;) { 1129 if ((descr = reallocf(descr, descrlen)) != NULL) { 1130 ifr.ifr_buffer.buffer = descr; 1131 ifr.ifr_buffer.length = descrlen; 1132 if (ioctl(s, SIOCGIFDESCR, &ifr) == 0) { 1133 if (ifr.ifr_buffer.buffer == descr) { 1134 if (strlen(descr) > 0) 1135 printf("\tdescription: %s\n", 1136 descr); 1137 } else if (ifr.ifr_buffer.length > descrlen) { 1138 descrlen = ifr.ifr_buffer.length; 1139 continue; 1140 } 1141 } 1142 } else 1143 warn("unable to allocate memory for interface" 1144 "description"); 1145 break; 1146 } 1147 1148 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { 1149 if (ifr.ifr_curcap != 0) { 1150 printb("\toptions", ifr.ifr_curcap, IFCAPBITS); 1151 putchar('\n'); 1152 } 1153 if (supmedia && ifr.ifr_reqcap != 0) { 1154 printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); 1155 putchar('\n'); 1156 } 1157 } 1158 1159 tunnel_status(s); 1160 1161 for (ift = ifa; ift != NULL; ift = ift->ifa_next) { 1162 if (ift->ifa_addr == NULL) 1163 continue; 1164 if (strcmp(ifa->ifa_name, ift->ifa_name) != 0) 1165 continue; 1166 if (allfamilies) { 1167 const struct afswtch *p; 1168 p = af_getbyfamily(ift->ifa_addr->sa_family); 1169 if (p != NULL && p->af_status != NULL) 1170 p->af_status(s, ift); 1171 } else if (afp->af_af == ift->ifa_addr->sa_family) 1172 afp->af_status(s, ift); 1173 } 1174 #if 0 1175 if (allfamilies || afp->af_af == AF_LINK) { 1176 const struct afswtch *lafp; 1177 1178 /* 1179 * Hack; the link level address is received separately 1180 * from the routing information so any address is not 1181 * handled above. Cobble together an entry and invoke 1182 * the status method specially. 1183 */ 1184 lafp = af_getbyname("lladdr"); 1185 if (lafp != NULL) { 1186 info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl; 1187 lafp->af_status(s, &info); 1188 } 1189 } 1190 #endif 1191 if (allfamilies) 1192 af_other_status(s); 1193 else if (afp->af_other_status != NULL) 1194 afp->af_other_status(s); 1195 1196 strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name); 1197 if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 1198 printf("%s", ifs.ascii); 1199 1200 if (verbose > 0) 1201 sfp_status(s, &ifr, verbose); 1202 1203 close(s); 1204 return; 1205 } 1206 1207 static void 1208 tunnel_status(int s) 1209 { 1210 af_all_tunnel_status(s); 1211 } 1212 1213 void 1214 Perror(const char *cmd) 1215 { 1216 switch (errno) { 1217 1218 case ENXIO: 1219 errx(1, "%s: no such interface", cmd); 1220 break; 1221 1222 case EPERM: 1223 errx(1, "%s: permission denied", cmd); 1224 break; 1225 1226 default: 1227 err(1, "%s", cmd); 1228 } 1229 } 1230 1231 /* 1232 * Print a value a la the %b format of the kernel's printf 1233 */ 1234 void 1235 printb(const char *s, unsigned v, const char *bits) 1236 { 1237 int i, any = 0; 1238 char c; 1239 1240 if (bits && *bits == 8) 1241 printf("%s=%o", s, v); 1242 else 1243 printf("%s=%x", s, v); 1244 bits++; 1245 if (bits) { 1246 putchar('<'); 1247 while ((i = *bits++) != '\0') { 1248 if (v & (1 << (i-1))) { 1249 if (any) 1250 putchar(','); 1251 any = 1; 1252 for (; (c = *bits) > 32; bits++) 1253 putchar(c); 1254 } else 1255 for (; *bits > 32; bits++) 1256 ; 1257 } 1258 putchar('>'); 1259 } 1260 } 1261 1262 void 1263 print_vhid(const struct ifaddrs *ifa, const char *s) 1264 { 1265 struct if_data *ifd; 1266 1267 if (ifa->ifa_data == NULL) 1268 return; 1269 1270 ifd = ifa->ifa_data; 1271 if (ifd->ifi_vhid == 0) 1272 return; 1273 1274 printf("vhid %d ", ifd->ifi_vhid); 1275 } 1276 1277 void 1278 ifmaybeload(const char *name) 1279 { 1280 #define MOD_PREFIX_LEN 3 /* "if_" */ 1281 struct module_stat mstat; 1282 int fileid, modid; 1283 char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp; 1284 const char *cp; 1285 1286 /* loading suppressed by the user */ 1287 if (noload) 1288 return; 1289 1290 /* trim the interface number off the end */ 1291 strlcpy(ifname, name, sizeof(ifname)); 1292 for (dp = ifname; *dp != 0; dp++) 1293 if (isdigit(*dp)) { 1294 *dp = 0; 1295 break; 1296 } 1297 1298 /* turn interface and unit into module name */ 1299 strlcpy(ifkind, "if_", sizeof(ifkind)); 1300 strlcat(ifkind, ifname, sizeof(ifkind)); 1301 1302 /* scan files in kernel */ 1303 mstat.version = sizeof(struct module_stat); 1304 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 1305 /* scan modules in file */ 1306 for (modid = kldfirstmod(fileid); modid > 0; 1307 modid = modfnext(modid)) { 1308 if (modstat(modid, &mstat) < 0) 1309 continue; 1310 /* strip bus name if present */ 1311 if ((cp = strchr(mstat.name, '/')) != NULL) { 1312 cp++; 1313 } else { 1314 cp = mstat.name; 1315 } 1316 /* already loaded? */ 1317 if (strcmp(ifname, cp) == 0 || 1318 strcmp(ifkind, cp) == 0) 1319 return; 1320 } 1321 } 1322 1323 /* not present, we should try to load it */ 1324 kldload(ifkind); 1325 } 1326 1327 static struct cmd basic_cmds[] = { 1328 DEF_CMD("up", IFF_UP, setifflags), 1329 DEF_CMD("down", -IFF_UP, setifflags), 1330 DEF_CMD("arp", -IFF_NOARP, setifflags), 1331 DEF_CMD("-arp", IFF_NOARP, setifflags), 1332 DEF_CMD("debug", IFF_DEBUG, setifflags), 1333 DEF_CMD("-debug", -IFF_DEBUG, setifflags), 1334 DEF_CMD_ARG("description", setifdescr), 1335 DEF_CMD_ARG("descr", setifdescr), 1336 DEF_CMD("-description", 0, unsetifdescr), 1337 DEF_CMD("-descr", 0, unsetifdescr), 1338 DEF_CMD("promisc", IFF_PPROMISC, setifflags), 1339 DEF_CMD("-promisc", -IFF_PPROMISC, setifflags), 1340 DEF_CMD("add", IFF_UP, notealias), 1341 DEF_CMD("alias", IFF_UP, notealias), 1342 DEF_CMD("-alias", -IFF_UP, notealias), 1343 DEF_CMD("delete", -IFF_UP, notealias), 1344 DEF_CMD("remove", -IFF_UP, notealias), 1345 #ifdef notdef 1346 #define EN_SWABIPS 0x1000 1347 DEF_CMD("swabips", EN_SWABIPS, setifflags), 1348 DEF_CMD("-swabips", -EN_SWABIPS, setifflags), 1349 #endif 1350 DEF_CMD_ARG("netmask", setifnetmask), 1351 DEF_CMD_ARG("metric", setifmetric), 1352 DEF_CMD_ARG("broadcast", setifbroadaddr), 1353 DEF_CMD_ARG2("tunnel", settunnel), 1354 DEF_CMD("-tunnel", 0, deletetunnel), 1355 DEF_CMD("deletetunnel", 0, deletetunnel), 1356 #ifdef JAIL 1357 DEF_CMD_ARG("vnet", setifvnet), 1358 DEF_CMD_ARG("-vnet", setifrvnet), 1359 #endif 1360 DEF_CMD("link0", IFF_LINK0, setifflags), 1361 DEF_CMD("-link0", -IFF_LINK0, setifflags), 1362 DEF_CMD("link1", IFF_LINK1, setifflags), 1363 DEF_CMD("-link1", -IFF_LINK1, setifflags), 1364 DEF_CMD("link2", IFF_LINK2, setifflags), 1365 DEF_CMD("-link2", -IFF_LINK2, setifflags), 1366 DEF_CMD("monitor", IFF_MONITOR, setifflags), 1367 DEF_CMD("-monitor", -IFF_MONITOR, setifflags), 1368 DEF_CMD("staticarp", IFF_STATICARP, setifflags), 1369 DEF_CMD("-staticarp", -IFF_STATICARP, setifflags), 1370 DEF_CMD("rxcsum6", IFCAP_RXCSUM_IPV6, setifcap), 1371 DEF_CMD("-rxcsum6", -IFCAP_RXCSUM_IPV6, setifcap), 1372 DEF_CMD("txcsum6", IFCAP_TXCSUM_IPV6, setifcap), 1373 DEF_CMD("-txcsum6", -IFCAP_TXCSUM_IPV6, setifcap), 1374 DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), 1375 DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap), 1376 DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), 1377 DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap), 1378 DEF_CMD("netcons", IFCAP_NETCONS, setifcap), 1379 DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap), 1380 DEF_CMD("polling", IFCAP_POLLING, setifcap), 1381 DEF_CMD("-polling", -IFCAP_POLLING, setifcap), 1382 DEF_CMD("tso6", IFCAP_TSO6, setifcap), 1383 DEF_CMD("-tso6", -IFCAP_TSO6, setifcap), 1384 DEF_CMD("tso4", IFCAP_TSO4, setifcap), 1385 DEF_CMD("-tso4", -IFCAP_TSO4, setifcap), 1386 DEF_CMD("tso", IFCAP_TSO, setifcap), 1387 DEF_CMD("-tso", -IFCAP_TSO, setifcap), 1388 DEF_CMD("toe", IFCAP_TOE, setifcap), 1389 DEF_CMD("-toe", -IFCAP_TOE, setifcap), 1390 DEF_CMD("lro", IFCAP_LRO, setifcap), 1391 DEF_CMD("-lro", -IFCAP_LRO, setifcap), 1392 DEF_CMD("wol", IFCAP_WOL, setifcap), 1393 DEF_CMD("-wol", -IFCAP_WOL, setifcap), 1394 DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap), 1395 DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap), 1396 DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap), 1397 DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap), 1398 DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap), 1399 DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap), 1400 DEF_CMD("normal", -IFF_LINK0, setifflags), 1401 DEF_CMD("compress", IFF_LINK0, setifflags), 1402 DEF_CMD("noicmp", IFF_LINK1, setifflags), 1403 DEF_CMD_ARG("mtu", setifmtu), 1404 DEF_CMD_ARG("name", setifname), 1405 }; 1406 1407 static __constructor void 1408 ifconfig_ctor(void) 1409 { 1410 size_t i; 1411 1412 for (i = 0; i < nitems(basic_cmds); i++) 1413 cmd_register(&basic_cmds[i]); 1414 } 1415