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