1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/ioctl.h> 34 #ifdef JAIL 35 #include <sys/jail.h> 36 #endif 37 #include <sys/module.h> 38 #include <sys/linker.h> 39 #include <sys/nv.h> 40 #include <sys/queue.h> 41 #include <sys/socket.h> 42 #include <sys/time.h> 43 44 #include <net/ethernet.h> 45 #include <net/if.h> 46 #include <net/if_dl.h> 47 #include <net/if_strings.h> 48 #include <net/if_types.h> 49 #include <net/route.h> 50 51 /* IP */ 52 #include <netinet/in.h> 53 #include <netinet/in_var.h> 54 #include <arpa/inet.h> 55 #include <netdb.h> 56 57 #include <fnmatch.h> 58 #include <ifaddrs.h> 59 #include <ctype.h> 60 #include <err.h> 61 #include <errno.h> 62 #include <fcntl.h> 63 #ifdef JAIL 64 #include <jail.h> 65 #endif 66 #include <stdbool.h> 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <string.h> 70 #include <unistd.h> 71 72 #include <libifconfig.h> 73 74 #include "ifconfig.h" 75 76 ifconfig_handle_t *lifh; 77 78 #ifdef WITHOUT_NETLINK 79 static char *descr = NULL; 80 static size_t descrlen = 64; 81 #endif 82 static int setaddr; 83 static int setmask; 84 static int doalias; 85 static int clearaddr; 86 static int newaddr = 1; 87 88 int exit_code = 0; 89 90 static char ifname_to_print[IFNAMSIZ]; /* Helper for printifnamemaybe() */ 91 92 /* Formatter Strings */ 93 char *f_inet, *f_inet6, *f_ether, *f_addr; 94 95 #ifdef WITHOUT_NETLINK 96 static void list_interfaces_ioctl(if_ctx *ctx); 97 static void status(if_ctx *ctx, const struct sockaddr_dl *sdl, 98 struct ifaddrs *ifa); 99 #endif 100 static _Noreturn void usage(void); 101 static void Perrorc(const char *cmd, int error); 102 103 static int getifflags(const char *ifname, int us, bool err_ok); 104 105 static struct afswtch *af_getbyname(const char *name); 106 107 static struct option *opts = NULL; 108 109 struct ifa_order_elt { 110 int if_order; 111 int af_orders[255]; 112 struct ifaddrs *ifa; 113 TAILQ_ENTRY(ifa_order_elt) link; 114 }; 115 116 TAILQ_HEAD(ifa_queue, ifa_order_elt); 117 118 static struct module_map_entry { 119 const char *ifname; 120 const char *kldname; 121 } module_map[] = { 122 { 123 .ifname = "tun", 124 .kldname = "if_tuntap", 125 }, 126 { 127 .ifname = "tap", 128 .kldname = "if_tuntap", 129 }, 130 { 131 .ifname = "vmnet", 132 .kldname = "if_tuntap", 133 }, 134 { 135 .ifname = "ipsec", 136 .kldname = "ipsec", 137 }, 138 { 139 /* 140 * This mapping exists because there is a conflicting enc module 141 * in CAM. ifconfig's guessing behavior will attempt to match 142 * the ifname to a module as well as if_${ifname} and clash with 143 * CAM enc. This is an assertion of the correct module to load. 144 */ 145 .ifname = "enc", 146 .kldname = "if_enc", 147 }, 148 }; 149 150 151 void 152 opt_register(struct option *p) 153 { 154 p->next = opts; 155 opts = p; 156 } 157 158 static void 159 usage(void) 160 { 161 char options[1024]; 162 struct option *p; 163 164 /* XXX not right but close enough for now */ 165 options[0] = '\0'; 166 for (p = opts; p != NULL; p = p->next) { 167 strlcat(options, p->opt_usage, sizeof(options)); 168 strlcat(options, " ", sizeof(options)); 169 } 170 171 fprintf(stderr, 172 "usage: ifconfig [-j jail] [-f type:format] %sinterface address_family\n" 173 " [address [dest_address]] [parameters]\n" 174 " ifconfig [-j jail] interface create\n" 175 " ifconfig [-j jail] -a %s[-d] [-m] [-u] [-v] [address_family]\n" 176 " ifconfig [-j jail] -l [-d] [-u] [address_family]\n" 177 " ifconfig [-j jail] %s[-d] [-m] [-u] [-v]\n", 178 options, options, options); 179 exit(1); 180 } 181 182 static void 183 ifname_update(if_ctx *ctx, const char *name) 184 { 185 strlcpy(ctx->_ifname_storage_ioctl, name, sizeof(ctx->_ifname_storage_ioctl)); 186 ctx->ifname = ctx->_ifname_storage_ioctl; 187 188 strlcpy(ifname_to_print, name, sizeof(ifname_to_print)); 189 } 190 191 static void 192 ifr_set_name(struct ifreq *ifr, const char *name) 193 { 194 strlcpy(ifr->ifr_name, name, sizeof(ifr->ifr_name)); 195 } 196 197 int 198 ioctl_ctx_ifr(if_ctx *ctx, unsigned long cmd, struct ifreq *ifr) 199 { 200 ifr_set_name(ifr, ctx->ifname); 201 return (ioctl_ctx(ctx, cmd, ifr)); 202 } 203 204 void 205 ifcreate_ioctl(if_ctx *ctx, struct ifreq *ifr) 206 { 207 char ifname_orig[IFNAMSIZ]; 208 209 strlcpy(ifname_orig, ifr->ifr_name, sizeof(ifname_orig)); 210 211 if (ioctl(ctx->io_s, SIOCIFCREATE2, ifr) < 0) { 212 switch (errno) { 213 case EEXIST: 214 errx(1, "interface %s already exists", ifr->ifr_name); 215 default: 216 err(1, "SIOCIFCREATE2 (%s)", ifr->ifr_name); 217 } 218 } 219 220 if (strncmp(ifname_orig, ifr->ifr_name, sizeof(ifname_orig)) != 0) 221 ifname_update(ctx, ifr->ifr_name); 222 } 223 224 #ifdef WITHOUT_NETLINK 225 static int 226 calcorders(struct ifaddrs *ifa, struct ifa_queue *q) 227 { 228 struct ifaddrs *prev; 229 struct ifa_order_elt *cur; 230 unsigned int ord, af, ifa_ord; 231 232 prev = NULL; 233 cur = NULL; 234 ord = 0; 235 ifa_ord = 0; 236 237 while (ifa != NULL) { 238 if (prev == NULL || 239 strcmp(ifa->ifa_name, prev->ifa_name) != 0) { 240 cur = calloc(1, sizeof(*cur)); 241 242 if (cur == NULL) 243 return (-1); 244 245 TAILQ_INSERT_TAIL(q, cur, link); 246 cur->if_order = ifa_ord ++; 247 cur->ifa = ifa; 248 ord = 0; 249 } 250 251 if (ifa->ifa_addr) { 252 af = ifa->ifa_addr->sa_family; 253 254 if (af < nitems(cur->af_orders) && 255 cur->af_orders[af] == 0) 256 cur->af_orders[af] = ++ord; 257 } 258 prev = ifa; 259 ifa = ifa->ifa_next; 260 } 261 262 return (0); 263 } 264 265 static int 266 cmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q) 267 { 268 struct ifa_order_elt *cur, *e1, *e2; 269 unsigned int af1, af2; 270 int ret; 271 272 e1 = e2 = NULL; 273 274 ret = strcmp(a->ifa_name, b->ifa_name); 275 if (ret != 0) { 276 TAILQ_FOREACH(cur, q, link) { 277 if (e1 && e2) 278 break; 279 280 if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) 281 e1 = cur; 282 else if (strcmp(cur->ifa->ifa_name, b->ifa_name) == 0) 283 e2 = cur; 284 } 285 286 if (!e1 || !e2) 287 return (0); 288 else 289 return (e1->if_order - e2->if_order); 290 291 } else if (a->ifa_addr != NULL && b->ifa_addr != NULL) { 292 TAILQ_FOREACH(cur, q, link) { 293 if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) { 294 e1 = cur; 295 break; 296 } 297 } 298 299 if (!e1) 300 return (0); 301 302 af1 = a->ifa_addr->sa_family; 303 af2 = b->ifa_addr->sa_family; 304 305 if (af1 < nitems(e1->af_orders) && af2 < nitems(e1->af_orders)) 306 return (e1->af_orders[af1] - e1->af_orders[af2]); 307 } 308 309 return (0); 310 } 311 #endif 312 313 static void freeformat(void) 314 { 315 316 if (f_inet != NULL) 317 free(f_inet); 318 if (f_inet6 != NULL) 319 free(f_inet6); 320 if (f_ether != NULL) 321 free(f_ether); 322 if (f_addr != NULL) 323 free(f_addr); 324 } 325 326 static void setformat(char *input) 327 { 328 char *formatstr, *category, *modifier; 329 330 formatstr = strdup(input); 331 while ((category = strsep(&formatstr, ",")) != NULL) { 332 modifier = strchr(category, ':'); 333 if (modifier == NULL || modifier[1] == '\0') { 334 warnx("Skipping invalid format specification: %s\n", 335 category); 336 continue; 337 } 338 339 /* Split the string on the separator, then seek past it */ 340 modifier[0] = '\0'; 341 modifier++; 342 343 if (strcmp(category, "addr") == 0) 344 f_addr = strdup(modifier); 345 else if (strcmp(category, "ether") == 0) 346 f_ether = strdup(modifier); 347 else if (strcmp(category, "inet") == 0) 348 f_inet = strdup(modifier); 349 else if (strcmp(category, "inet6") == 0) 350 f_inet6 = strdup(modifier); 351 } 352 free(formatstr); 353 } 354 355 #ifdef WITHOUT_NETLINK 356 static struct ifaddrs * 357 sortifaddrs(struct ifaddrs *list, 358 int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *), 359 struct ifa_queue *q) 360 { 361 struct ifaddrs *right, *temp, *last, *result, *next, *tail; 362 363 right = list; 364 temp = list; 365 last = list; 366 result = NULL; 367 next = NULL; 368 tail = NULL; 369 370 if (!list || !list->ifa_next) 371 return (list); 372 373 while (temp && temp->ifa_next) { 374 last = right; 375 right = right->ifa_next; 376 temp = temp->ifa_next->ifa_next; 377 } 378 379 last->ifa_next = NULL; 380 381 list = sortifaddrs(list, compare, q); 382 right = sortifaddrs(right, compare, q); 383 384 while (list || right) { 385 386 if (!right) { 387 next = list; 388 list = list->ifa_next; 389 } else if (!list) { 390 next = right; 391 right = right->ifa_next; 392 } else if (compare(list, right, q) <= 0) { 393 next = list; 394 list = list->ifa_next; 395 } else { 396 next = right; 397 right = right->ifa_next; 398 } 399 400 if (!result) 401 result = next; 402 else 403 tail->ifa_next = next; 404 405 tail = next; 406 } 407 408 return (result); 409 } 410 #endif 411 412 static void 413 printifnamemaybe(void) 414 { 415 if (ifname_to_print[0] != '\0') 416 printf("%s\n", ifname_to_print); 417 } 418 419 static void 420 list_interfaces(if_ctx *ctx) 421 { 422 #ifdef WITHOUT_NETLINK 423 list_interfaces_ioctl(ctx); 424 #else 425 list_interfaces_nl(ctx->args); 426 #endif 427 } 428 429 static char * 430 args_peek(struct ifconfig_args *args) 431 { 432 if (args->argc > 0) 433 return (args->argv[0]); 434 return (NULL); 435 } 436 437 static char * 438 args_pop(struct ifconfig_args *args) 439 { 440 if (args->argc == 0) 441 return (NULL); 442 443 char *arg = args->argv[0]; 444 445 args->argc--; 446 args->argv++; 447 448 return (arg); 449 } 450 451 static void 452 args_parse(struct ifconfig_args *args, int argc, char *argv[]) 453 { 454 char options[1024]; 455 struct option *p; 456 int c; 457 458 /* Parse leading line options */ 459 strlcpy(options, "G:adf:j:klmnuv", sizeof(options)); 460 for (p = opts; p != NULL; p = p->next) 461 strlcat(options, p->opt, sizeof(options)); 462 while ((c = getopt(argc, argv, options)) != -1) { 463 switch (c) { 464 case 'a': /* scan all interfaces */ 465 args->all = true; 466 break; 467 case 'd': /* restrict scan to "down" interfaces */ 468 args->downonly = true; 469 break; 470 case 'f': 471 if (optarg == NULL) 472 usage(); 473 setformat(optarg); 474 break; 475 case 'G': 476 if (optarg == NULL || args->all == 0) 477 usage(); 478 args->nogroup = optarg; 479 break; 480 case 'j': 481 #ifdef JAIL 482 if (optarg == NULL) 483 usage(); 484 args->jail_name = optarg; 485 #else 486 Perror("not built with jail support"); 487 #endif 488 break; 489 case 'k': 490 args->printkeys = true; 491 break; 492 case 'l': /* scan interface names only */ 493 args->namesonly = true; 494 break; 495 case 'm': /* show media choices in status */ 496 args->supmedia = true; 497 break; 498 case 'n': /* suppress module loading */ 499 args->noload = true; 500 break; 501 case 'u': /* restrict scan to "up" interfaces */ 502 args->uponly = true; 503 break; 504 case 'v': 505 args->verbose++; 506 break; 507 case 'g': 508 if (args->all) { 509 if (optarg == NULL) 510 usage(); 511 args->matchgroup = optarg; 512 break; 513 } 514 /* FALLTHROUGH */ 515 default: 516 for (p = opts; p != NULL; p = p->next) 517 if (p->opt[0] == c) { 518 p->cb(optarg); 519 break; 520 } 521 if (p == NULL) 522 usage(); 523 break; 524 } 525 } 526 argc -= optind; 527 argv += optind; 528 529 /* -l cannot be used with -a or -m */ 530 if (args->namesonly && (args->all || args->supmedia)) 531 usage(); 532 533 /* nonsense.. */ 534 if (args->uponly && args->downonly) 535 usage(); 536 537 /* no arguments is equivalent to '-a' */ 538 if (!args->namesonly && argc < 1) 539 args->all = 1; 540 541 /* -a and -l allow an address family arg to limit the output */ 542 if (args->all || args->namesonly) { 543 if (argc > 1) 544 usage(); 545 546 if (argc == 1) { 547 const struct afswtch *afp = af_getbyname(*argv); 548 549 if (afp == NULL) { 550 warnx("Address family '%s' unknown.", *argv); 551 usage(); 552 } 553 if (afp->af_name != NULL) 554 argc--, argv++; 555 /* leave with afp non-zero */ 556 args->afp = afp; 557 } 558 } else { 559 /* not listing, need an argument */ 560 if (argc < 1) 561 usage(); 562 } 563 564 args->argc = argc; 565 args->argv = argv; 566 } 567 568 static int 569 ifconfig(if_ctx *ctx, int iscreate, const struct afswtch *uafp) 570 { 571 #ifdef WITHOUT_NETLINK 572 return (ifconfig_ioctl(ctx, iscreate, uafp)); 573 #else 574 return (ifconfig_nl(ctx, iscreate, uafp)); 575 #endif 576 } 577 578 static bool 579 isargcreate(const char *arg) 580 { 581 if (arg == NULL) 582 return (false); 583 584 if (strcmp(arg, "create") == 0 || strcmp(arg, "plumb") == 0) 585 return (true); 586 587 return (false); 588 } 589 590 static bool 591 isnametoolong(const char *ifname) 592 { 593 return (strlen(ifname) >= IFNAMSIZ); 594 } 595 596 int 597 main(int ac, char *av[]) 598 { 599 char *envformat; 600 int flags; 601 #ifdef JAIL 602 int jid; 603 #endif 604 struct ifconfig_args _args = {}; 605 struct ifconfig_args *args = &_args; 606 607 struct ifconfig_context ctx = { 608 .args = args, 609 .io_s = -1, 610 }; 611 612 f_inet = f_inet6 = f_ether = f_addr = NULL; 613 614 lifh = ifconfig_open(); 615 if (lifh == NULL) 616 err(EXIT_FAILURE, "ifconfig_open"); 617 618 envformat = getenv("IFCONFIG_FORMAT"); 619 if (envformat != NULL) 620 setformat(envformat); 621 622 /* 623 * Ensure we print interface name when expected to, 624 * even if we terminate early due to error. 625 */ 626 atexit(printifnamemaybe); 627 628 args_parse(args, ac, av); 629 630 #ifdef JAIL 631 if (args->jail_name) { 632 jid = jail_getid(args->jail_name); 633 if (jid == -1) 634 Perror("jail not found"); 635 if (jail_attach(jid) != 0) 636 Perror("cannot attach to jail"); 637 } 638 #endif 639 640 if (!args->all && !args->namesonly) { 641 /* not listing, need an argument */ 642 args->ifname = args_pop(args); 643 ctx.ifname = args->ifname; 644 645 /* check and maybe load support for this interface */ 646 ifmaybeload(args, args->ifname); 647 648 char *arg = args_peek(args); 649 if (if_nametoindex(args->ifname) == 0) { 650 /* 651 * NOTE: We must special-case the `create' command 652 * right here as we would otherwise fail when trying 653 * to find the interface. 654 */ 655 if (isargcreate(arg)) { 656 if (isnametoolong(args->ifname)) 657 errx(1, "%s: cloning name too long", 658 args->ifname); 659 ifconfig(&ctx, 1, NULL); 660 exit(exit_code); 661 } 662 #ifdef JAIL 663 /* 664 * NOTE: We have to special-case the `-vnet' command 665 * right here as we would otherwise fail when trying 666 * to find the interface as it lives in another vnet. 667 */ 668 if (arg != NULL && (strcmp(arg, "-vnet") == 0)) { 669 if (isnametoolong(args->ifname)) 670 errx(1, "%s: interface name too long", 671 args->ifname); 672 ifconfig(&ctx, 0, NULL); 673 exit(exit_code); 674 } 675 #endif 676 errx(1, "interface %s does not exist", args->ifname); 677 } else { 678 /* 679 * Do not allow use `create` command as hostname if 680 * address family is not specified. 681 */ 682 if (isargcreate(arg)) { 683 if (args->argc == 1) 684 errx(1, "interface %s already exists", 685 args->ifname); 686 args_pop(args); 687 } 688 } 689 } 690 691 /* Check for address family */ 692 if (args->argc > 0) { 693 args->afp = af_getbyname(args_peek(args)); 694 if (args->afp != NULL) 695 args_pop(args); 696 } 697 698 /* 699 * Check for a requested configuration action on a single interface, 700 * which doesn't require building, sorting, and searching the entire 701 * system address list 702 */ 703 if ((args->argc > 0) && (args->ifname != NULL)) { 704 if (isnametoolong(args->ifname)) 705 warnx("%s: interface name too long, skipping", args->ifname); 706 else { 707 flags = getifflags(args->ifname, -1, false); 708 if (!(((flags & IFF_CANTCONFIG) != 0) || 709 (args->downonly && (flags & IFF_UP) != 0) || 710 (args->uponly && (flags & IFF_UP) == 0))) 711 ifconfig(&ctx, 0, args->afp); 712 } 713 goto done; 714 } 715 716 args->allfamilies = args->afp == NULL; 717 718 list_interfaces(&ctx); 719 720 done: 721 freeformat(); 722 ifconfig_close(lifh); 723 exit(exit_code); 724 } 725 726 bool 727 match_ether(const struct sockaddr_dl *sdl) 728 { 729 switch (sdl->sdl_type) { 730 case IFT_ETHER: 731 case IFT_L2VLAN: 732 case IFT_BRIDGE: 733 if (sdl->sdl_alen == ETHER_ADDR_LEN) 734 return (true); 735 default: 736 return (false); 737 } 738 } 739 740 bool 741 match_if_flags(struct ifconfig_args *args, int if_flags) 742 { 743 if ((if_flags & IFF_CANTCONFIG) != 0) 744 return (false); 745 if (args->downonly && (if_flags & IFF_UP) != 0) 746 return (false); 747 if (args->uponly && (if_flags & IFF_UP) == 0) 748 return (false); 749 return (true); 750 } 751 752 #ifdef WITHOUT_NETLINK 753 static bool 754 match_afp(const struct afswtch *afp, int sa_family, const struct sockaddr_dl *sdl) 755 { 756 if (afp == NULL) 757 return (true); 758 /* special case for "ether" address family */ 759 if (!strcmp(afp->af_name, "ether")) { 760 if (sdl == NULL || !match_ether(sdl)) 761 return (false); 762 return (true); 763 } 764 return (afp->af_af == sa_family); 765 } 766 767 static void 768 list_interfaces_ioctl(if_ctx *ctx) 769 { 770 struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); 771 struct ifaddrs *ifap, *sifap, *ifa; 772 struct ifa_order_elt *cur, *tmp; 773 char *namecp = NULL; 774 int ifindex; 775 struct ifconfig_args *args = ctx->args; 776 777 if (getifaddrs(&ifap) != 0) 778 err(EXIT_FAILURE, "getifaddrs"); 779 780 char *cp = NULL; 781 782 if (calcorders(ifap, &q) != 0) 783 err(EXIT_FAILURE, "calcorders"); 784 785 sifap = sortifaddrs(ifap, cmpifaddrs, &q); 786 787 TAILQ_FOREACH_SAFE(cur, &q, link, tmp) 788 free(cur); 789 790 ifindex = 0; 791 for (ifa = sifap; ifa; ifa = ifa->ifa_next) { 792 struct ifreq paifr = {}; 793 const struct sockaddr_dl *sdl; 794 795 strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); 796 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) { 797 memcpy(&paifr.ifr_addr, ifa->ifa_addr, 798 ifa->ifa_addr->sa_len); 799 } 800 801 if (args->ifname != NULL && strcmp(args->ifname, ifa->ifa_name) != 0) 802 continue; 803 if (ifa->ifa_addr->sa_family == AF_LINK) 804 sdl = satosdl_c(ifa->ifa_addr); 805 else 806 sdl = NULL; 807 if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !args->namesonly) 808 continue; 809 if (isnametoolong(ifa->ifa_name)) { 810 warnx("%s: interface name too long, skipping", 811 ifa->ifa_name); 812 continue; 813 } 814 cp = ifa->ifa_name; 815 816 if (!match_if_flags(args, ifa->ifa_flags)) 817 continue; 818 if (!group_member(ifa->ifa_name, args->matchgroup, args->nogroup)) 819 continue; 820 ctx->ifname = cp; 821 /* 822 * Are we just listing the interfaces? 823 */ 824 if (args->namesonly) { 825 if (namecp == cp) 826 continue; 827 if (!match_afp(args->afp, ifa->ifa_addr->sa_family, sdl)) 828 continue; 829 namecp = cp; 830 ifindex++; 831 if (ifindex > 1) 832 printf(" "); 833 fputs(cp, stdout); 834 continue; 835 } 836 ifindex++; 837 838 if (args->argc > 0) 839 ifconfig(ctx, 0, args->afp); 840 else 841 status(ctx, sdl, ifa); 842 } 843 if (args->namesonly) 844 printf("\n"); 845 freeifaddrs(ifap); 846 } 847 #endif 848 849 /* 850 * Returns true if an interface should be listed because any its groups 851 * matches shell pattern "match" and none of groups matches pattern "nomatch". 852 * If any pattern is NULL, corresponding condition is skipped. 853 */ 854 bool 855 group_member(const char *ifname, const char *match, const char *nomatch) 856 { 857 static int sock = -1; 858 859 struct ifgroupreq ifgr; 860 struct ifg_req *ifg; 861 unsigned int len; 862 bool matched, nomatched; 863 864 /* Sanity checks. */ 865 if (match == NULL && nomatch == NULL) 866 return (true); 867 if (ifname == NULL) 868 return (false); 869 870 memset(&ifgr, 0, sizeof(ifgr)); 871 strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ); 872 873 /* The socket is opened once. Let _exit() close it. */ 874 if (sock == -1) { 875 sock = socket(AF_LOCAL, SOCK_DGRAM, 0); 876 if (sock == -1) 877 errx(1, "%s: socket(AF_LOCAL,SOCK_DGRAM)", __func__); 878 } 879 880 /* Determine amount of memory for the list of groups. */ 881 if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) { 882 if (errno == EINVAL || errno == ENOTTY) 883 return (false); 884 else 885 errx(1, "%s: SIOCGIFGROUP", __func__); 886 } 887 888 /* Obtain the list of groups. */ 889 len = ifgr.ifgr_len; 890 ifgr.ifgr_groups = 891 (struct ifg_req *)calloc(len / sizeof(*ifg), sizeof(*ifg)); 892 893 if (ifgr.ifgr_groups == NULL) 894 errx(1, "%s: no memory", __func__); 895 if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) 896 errx(1, "%s: SIOCGIFGROUP", __func__); 897 898 /* Perform matching. */ 899 matched = false; 900 nomatched = true; 901 for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(*ifg); ifg++) { 902 len -= sizeof(*ifg); 903 if (match && !matched) 904 matched = !fnmatch(match, ifg->ifgrq_group, 0); 905 if (nomatch && nomatched) 906 nomatched = fnmatch(nomatch, ifg->ifgrq_group, 0); 907 } 908 free(ifgr.ifgr_groups); 909 910 if (match && !nomatch) 911 return (matched); 912 if (!match && nomatch) 913 return (nomatched); 914 return (matched && nomatched); 915 } 916 917 static struct afswtch *afs = NULL; 918 919 void 920 af_register(struct afswtch *p) 921 { 922 p->af_next = afs; 923 afs = p; 924 } 925 926 static struct afswtch * 927 af_getbyname(const char *name) 928 { 929 struct afswtch *afp; 930 931 for (afp = afs; afp != NULL; afp = afp->af_next) 932 if (strcmp(afp->af_name, name) == 0) 933 return afp; 934 return NULL; 935 } 936 937 struct afswtch * 938 af_getbyfamily(int af) 939 { 940 struct afswtch *afp; 941 942 for (afp = afs; afp != NULL; afp = afp->af_next) 943 if (afp->af_af == af) 944 return afp; 945 return NULL; 946 } 947 948 void 949 af_other_status(if_ctx *ctx) 950 { 951 struct afswtch *afp; 952 uint8_t afmask[howmany(AF_MAX, NBBY)]; 953 954 memset(afmask, 0, sizeof(afmask)); 955 for (afp = afs; afp != NULL; afp = afp->af_next) { 956 if (afp->af_other_status == NULL) 957 continue; 958 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) 959 continue; 960 afp->af_other_status(ctx); 961 setbit(afmask, afp->af_af); 962 } 963 } 964 965 static void 966 af_all_tunnel_status(if_ctx *ctx) 967 { 968 struct afswtch *afp; 969 uint8_t afmask[howmany(AF_MAX, NBBY)]; 970 971 memset(afmask, 0, sizeof(afmask)); 972 for (afp = afs; afp != NULL; afp = afp->af_next) { 973 if (afp->af_status_tunnel == NULL) 974 continue; 975 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) 976 continue; 977 afp->af_status_tunnel(ctx); 978 setbit(afmask, afp->af_af); 979 } 980 } 981 982 static struct cmd *cmds = NULL; 983 984 void 985 cmd_register(struct cmd *p) 986 { 987 p->c_next = cmds; 988 cmds = p; 989 } 990 991 static const struct cmd * 992 cmd_lookup(const char *name, int iscreate) 993 { 994 const struct cmd *p; 995 996 for (p = cmds; p != NULL; p = p->c_next) 997 if (strcmp(name, p->c_name) == 0) { 998 if (iscreate) { 999 if (p->c_iscloneop) 1000 return p; 1001 } else { 1002 if (!p->c_iscloneop) 1003 return p; 1004 } 1005 } 1006 return NULL; 1007 } 1008 1009 struct callback { 1010 callback_func *cb_func; 1011 void *cb_arg; 1012 struct callback *cb_next; 1013 }; 1014 static struct callback *callbacks = NULL; 1015 1016 void 1017 callback_register(callback_func *func, void *arg) 1018 { 1019 struct callback *cb; 1020 1021 cb = malloc(sizeof(struct callback)); 1022 if (cb == NULL) 1023 errx(1, "unable to allocate memory for callback"); 1024 cb->cb_func = func; 1025 cb->cb_arg = arg; 1026 cb->cb_next = callbacks; 1027 callbacks = cb; 1028 } 1029 1030 /* specially-handled commands */ 1031 static void setifaddr(if_ctx *ctx, const char *addr, int param); 1032 static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr); 1033 1034 static void setifdstaddr(if_ctx *ctx, const char *addr, int param __unused); 1035 static const struct cmd setifdstaddr_cmd = 1036 DEF_CMD("ifdstaddr", 0, setifdstaddr); 1037 1038 int 1039 af_exec_ioctl(if_ctx *ctx, unsigned long action, void *data) 1040 { 1041 struct ifreq *req = (struct ifreq *)data; 1042 1043 strlcpy(req->ifr_name, ctx->ifname, sizeof(req->ifr_name)); 1044 if (ioctl_ctx(ctx, action, req) == 0) 1045 return (0); 1046 return (errno); 1047 } 1048 1049 static void 1050 delifaddr(if_ctx *ctx, const struct afswtch *afp) 1051 { 1052 int error; 1053 1054 if (afp->af_exec == NULL) { 1055 warnx("interface %s cannot change %s addresses!", 1056 ctx->ifname, afp->af_name); 1057 clearaddr = 0; 1058 return; 1059 } 1060 1061 error = afp->af_exec(ctx, afp->af_difaddr, afp->af_ridreq); 1062 if (error != 0) { 1063 if (error == EADDRNOTAVAIL && (doalias >= 0)) { 1064 /* means no previous address for interface */ 1065 } else 1066 Perrorc("ioctl (SIOCDIFADDR)", error); 1067 } 1068 } 1069 1070 static void 1071 addifaddr(if_ctx *ctx, const struct afswtch *afp) 1072 { 1073 if (afp->af_exec == NULL) { 1074 warnx("interface %s cannot change %s addresses!", 1075 ctx->ifname, afp->af_name); 1076 newaddr = 0; 1077 return; 1078 } 1079 1080 if (setaddr || setmask) { 1081 int error = afp->af_exec(ctx, afp->af_aifaddr, afp->af_addreq); 1082 if (error != 0) 1083 Perrorc("ioctl (SIOCAIFADDR)", error); 1084 } 1085 } 1086 1087 int 1088 ifconfig_ioctl(if_ctx *orig_ctx, int iscreate, const struct afswtch *uafp) 1089 { 1090 const struct afswtch *afp, *nafp; 1091 const struct cmd *p; 1092 struct callback *cb; 1093 int s; 1094 int argc = orig_ctx->args->argc; 1095 char *const *argv = orig_ctx->args->argv; 1096 struct ifconfig_context _ctx = { 1097 .args = orig_ctx->args, 1098 .io_ss = orig_ctx->io_ss, 1099 .ifname = orig_ctx->ifname, 1100 }; 1101 struct ifconfig_context *ctx = &_ctx; 1102 1103 struct ifreq ifr = {}; 1104 strlcpy(ifr.ifr_name, ctx->ifname, sizeof ifr.ifr_name); 1105 afp = NULL; 1106 if (uafp != NULL) 1107 afp = uafp; 1108 /* 1109 * This is the historical "accident" allowing users to configure IPv4 1110 * addresses without the "inet" keyword which while a nice feature has 1111 * proven to complicate other things. We cannot remove this but only 1112 * make sure we will never have a similar implicit default for IPv6 or 1113 * any other address familiy. We need a fallback though for 1114 * ifconfig IF up/down etc. to work without INET support as people 1115 * never used ifconfig IF link up/down, etc. either. 1116 */ 1117 #ifndef RESCUE 1118 #ifdef INET 1119 if (afp == NULL && feature_present("inet")) 1120 afp = af_getbyname("inet"); 1121 #endif 1122 #endif 1123 if (afp == NULL) 1124 afp = af_getbyname("link"); 1125 if (afp == NULL) { 1126 warnx("Please specify an address_family."); 1127 usage(); 1128 } 1129 1130 top: 1131 ifr.ifr_addr.sa_family = 1132 afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ? 1133 AF_LOCAL : afp->af_af; 1134 1135 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 && 1136 (uafp != NULL || errno != EAFNOSUPPORT || 1137 (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)) 1138 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); 1139 1140 ctx->io_s = s; 1141 ctx->afp = afp; 1142 1143 while (argc > 0) { 1144 p = cmd_lookup(*argv, iscreate); 1145 if (iscreate && p == NULL) { 1146 /* 1147 * Push the clone create callback so the new 1148 * device is created and can be used for any 1149 * remaining arguments. 1150 */ 1151 cb = callbacks; 1152 if (cb == NULL) 1153 errx(1, "internal error, no callback"); 1154 callbacks = cb->cb_next; 1155 cb->cb_func(ctx, cb->cb_arg); 1156 iscreate = 0; 1157 /* 1158 * Handle any address family spec that 1159 * immediately follows and potentially 1160 * recreate the socket. 1161 */ 1162 nafp = af_getbyname(*argv); 1163 if (nafp != NULL) { 1164 argc--, argv++; 1165 if (nafp != afp) { 1166 close(s); 1167 afp = nafp; 1168 goto top; 1169 } 1170 } 1171 /* 1172 * Look for a normal parameter. 1173 */ 1174 continue; 1175 } 1176 if (p == NULL) { 1177 /* 1178 * Not a recognized command, choose between setting 1179 * the interface address and the dst address. 1180 */ 1181 p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd); 1182 } 1183 if (p->c_parameter == NEXTARG && p->c_u.c_func) { 1184 if (argv[1] == NULL) 1185 errx(1, "'%s' requires argument", 1186 p->c_name); 1187 p->c_u.c_func(ctx, argv[1], 0); 1188 argc--, argv++; 1189 } else if (p->c_parameter == OPTARG && p->c_u.c_func) { 1190 p->c_u.c_func(ctx, argv[1], 0); 1191 if (argv[1] != NULL) 1192 argc--, argv++; 1193 } else if (p->c_parameter == NEXTARG2 && p->c_u.c_func2) { 1194 if (argc < 3) 1195 errx(1, "'%s' requires 2 arguments", 1196 p->c_name); 1197 p->c_u.c_func2(ctx, argv[1], argv[2]); 1198 argc -= 2, argv += 2; 1199 } else if (p->c_parameter == SPARAM && p->c_u.c_func3) { 1200 p->c_u.c_func3(ctx, *argv, p->c_sparameter); 1201 } else if (p->c_u.c_func) 1202 p->c_u.c_func(ctx, *argv, p->c_parameter); 1203 argc--, argv++; 1204 } 1205 1206 /* 1207 * Do any post argument processing required by the address family. 1208 */ 1209 if (afp->af_postproc != NULL) 1210 afp->af_postproc(ctx, newaddr, getifflags(ctx->ifname, s, true)); 1211 /* 1212 * Do deferred callbacks registered while processing 1213 * command-line arguments. 1214 */ 1215 for (cb = callbacks; cb != NULL; cb = cb->cb_next) 1216 cb->cb_func(ctx, cb->cb_arg); 1217 /* 1218 * Do deferred operations. 1219 */ 1220 if (clearaddr) 1221 delifaddr(ctx, afp); 1222 if (newaddr) 1223 addifaddr(ctx, afp); 1224 1225 close(s); 1226 return(0); 1227 } 1228 1229 static void 1230 setifaddr(if_ctx *ctx, const char *addr, int param __unused) 1231 { 1232 const struct afswtch *afp = ctx->afp; 1233 1234 if (afp->af_getaddr == NULL) 1235 return; 1236 /* 1237 * Delay the ioctl to set the interface addr until flags are all set. 1238 * The address interpretation may depend on the flags, 1239 * and the flags may change when the address is set. 1240 */ 1241 setaddr++; 1242 if (doalias == 0 && afp->af_af != AF_LINK) 1243 clearaddr = 1; 1244 afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR)); 1245 } 1246 1247 static void 1248 settunnel(if_ctx *ctx, const char *src, const char *dst) 1249 { 1250 const struct afswtch *afp = ctx->afp; 1251 struct addrinfo *srcres, *dstres; 1252 int ecode; 1253 1254 if (afp->af_settunnel == NULL) { 1255 warn("address family %s does not support tunnel setup", 1256 afp->af_name); 1257 return; 1258 } 1259 1260 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) 1261 errx(1, "error in parsing address string: %s", 1262 gai_strerror(ecode)); 1263 1264 if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) 1265 errx(1, "error in parsing address string: %s", 1266 gai_strerror(ecode)); 1267 1268 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) 1269 errx(1, 1270 "source and destination address families do not match"); 1271 1272 afp->af_settunnel(ctx, srcres, dstres); 1273 1274 freeaddrinfo(srcres); 1275 freeaddrinfo(dstres); 1276 } 1277 1278 static void 1279 deletetunnel(if_ctx *ctx, const char *vname __unused, int param __unused) 1280 { 1281 struct ifreq ifr = {}; 1282 1283 if (ioctl_ctx_ifr(ctx, SIOCDIFPHYADDR, &ifr) < 0) 1284 err(1, "SIOCDIFPHYADDR"); 1285 } 1286 1287 #ifdef JAIL 1288 static void 1289 setifvnet(if_ctx *ctx, const char *jname, int dummy __unused) 1290 { 1291 struct ifreq ifr = {}; 1292 1293 ifr.ifr_jid = jail_getid(jname); 1294 if (ifr.ifr_jid < 0) 1295 errx(1, "%s", jail_errmsg); 1296 if (ioctl_ctx_ifr(ctx, SIOCSIFVNET, &ifr) < 0) 1297 err(1, "SIOCSIFVNET"); 1298 } 1299 1300 static void 1301 setifrvnet(if_ctx *ctx, const char *jname, int dummy __unused) 1302 { 1303 struct ifreq ifr = {}; 1304 1305 ifr.ifr_jid = jail_getid(jname); 1306 if (ifr.ifr_jid < 0) 1307 errx(1, "%s", jail_errmsg); 1308 if (ioctl_ctx_ifr(ctx, SIOCSIFRVNET, &ifr) < 0) 1309 err(1, "SIOCSIFRVNET(%d, %s)", ifr.ifr_jid, ifr.ifr_name); 1310 } 1311 #endif 1312 1313 static void 1314 setifnetmask(if_ctx *ctx, const char *addr, int dummy __unused) 1315 { 1316 const struct afswtch *afp = ctx->afp; 1317 1318 if (afp->af_getaddr != NULL) { 1319 setmask++; 1320 afp->af_getaddr(addr, MASK); 1321 } 1322 } 1323 1324 static void 1325 setifbroadaddr(if_ctx *ctx, const char *addr, int dummy __unused) 1326 { 1327 const struct afswtch *afp = ctx->afp; 1328 1329 if (afp->af_getaddr != NULL) 1330 afp->af_getaddr(addr, BRDADDR); 1331 } 1332 1333 static void 1334 notealias(if_ctx *ctx, const char *addr __unused, int param) 1335 { 1336 const struct afswtch *afp = ctx->afp; 1337 1338 if (setaddr && doalias == 0 && param < 0) { 1339 if (afp->af_copyaddr != NULL) 1340 afp->af_copyaddr(ctx, RIDADDR, ADDR); 1341 } 1342 doalias = param; 1343 if (param < 0) { 1344 clearaddr = 1; 1345 newaddr = 0; 1346 } else 1347 clearaddr = 0; 1348 } 1349 1350 static void 1351 setifdstaddr(if_ctx *ctx, const char *addr, int param __unused) 1352 { 1353 const struct afswtch *afp = ctx->afp; 1354 1355 if (afp->af_getaddr != NULL) 1356 afp->af_getaddr(addr, DSTADDR); 1357 } 1358 1359 static int 1360 getifflags(const char *ifname, int us, bool err_ok) 1361 { 1362 struct ifreq my_ifr; 1363 int s; 1364 1365 memset(&my_ifr, 0, sizeof(my_ifr)); 1366 (void) strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name)); 1367 if (us < 0) { 1368 if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) 1369 err(1, "socket(family AF_LOCAL,SOCK_DGRAM"); 1370 } else 1371 s = us; 1372 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { 1373 if (!err_ok) { 1374 Perror("ioctl (SIOCGIFFLAGS)"); 1375 exit(1); 1376 } 1377 } 1378 if (us < 0) 1379 close(s); 1380 return ((my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16)); 1381 } 1382 1383 /* 1384 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion 1385 * of the ifreq structure, which may confuse other parts of ifconfig. 1386 * Make a private copy so we can avoid that. 1387 */ 1388 static void 1389 clearifflags(if_ctx *ctx, const char *vname, int value) 1390 { 1391 struct ifreq my_ifr; 1392 int flags; 1393 1394 flags = getifflags(ctx->ifname, ctx->io_s, false); 1395 flags &= ~value; 1396 memset(&my_ifr, 0, sizeof(my_ifr)); 1397 strlcpy(my_ifr.ifr_name, ctx->ifname, sizeof(my_ifr.ifr_name)); 1398 my_ifr.ifr_flags = flags & 0xffff; 1399 my_ifr.ifr_flagshigh = flags >> 16; 1400 if (ioctl(ctx->io_s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) 1401 Perror(vname); 1402 } 1403 1404 static void 1405 setifflags(if_ctx *ctx, const char *vname, int value) 1406 { 1407 struct ifreq my_ifr; 1408 int flags; 1409 1410 flags = getifflags(ctx->ifname, ctx->io_s, false); 1411 flags |= value; 1412 memset(&my_ifr, 0, sizeof(my_ifr)); 1413 strlcpy(my_ifr.ifr_name, ctx->ifname, sizeof(my_ifr.ifr_name)); 1414 my_ifr.ifr_flags = flags & 0xffff; 1415 my_ifr.ifr_flagshigh = flags >> 16; 1416 if (ioctl(ctx->io_s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) 1417 Perror(vname); 1418 } 1419 1420 void 1421 clearifcap(if_ctx *ctx, const char *vname, int value) 1422 { 1423 struct ifreq ifr = {}; 1424 int flags; 1425 1426 if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) { 1427 Perror("ioctl (SIOCGIFCAP)"); 1428 exit(1); 1429 } 1430 flags = ifr.ifr_curcap; 1431 flags &= ~value; 1432 flags &= ifr.ifr_reqcap; 1433 /* Check for no change in capabilities. */ 1434 if (ifr.ifr_curcap == flags) 1435 return; 1436 ifr.ifr_reqcap = flags; 1437 if (ioctl_ctx(ctx, SIOCSIFCAP, &ifr) < 0) 1438 Perror(vname); 1439 } 1440 1441 void 1442 setifcap(if_ctx *ctx, const char *vname, int value) 1443 { 1444 struct ifreq ifr = {}; 1445 int flags; 1446 1447 if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) { 1448 Perror("ioctl (SIOCGIFCAP)"); 1449 exit(1); 1450 } 1451 flags = ifr.ifr_curcap; 1452 flags |= value; 1453 flags &= ifr.ifr_reqcap; 1454 /* Check for no change in capabilities. */ 1455 if (ifr.ifr_curcap == flags) 1456 return; 1457 ifr.ifr_reqcap = flags; 1458 if (ioctl_ctx(ctx, SIOCSIFCAP, &ifr) < 0) 1459 Perror(vname); 1460 } 1461 1462 void 1463 setifcapnv(if_ctx *ctx, const char *vname, const char *arg) 1464 { 1465 nvlist_t *nvcap; 1466 void *buf; 1467 char *marg, *mopt; 1468 size_t nvbuflen; 1469 bool neg; 1470 struct ifreq ifr = {}; 1471 1472 if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) 1473 Perror("ioctl (SIOCGIFCAP)"); 1474 if ((ifr.ifr_curcap & IFCAP_NV) == 0) { 1475 warnx("IFCAP_NV not supported"); 1476 return; /* Not exit() */ 1477 } 1478 1479 marg = strdup(arg); 1480 if (marg == NULL) 1481 Perror("strdup"); 1482 nvcap = nvlist_create(0); 1483 if (nvcap == NULL) 1484 Perror("nvlist_create"); 1485 while ((mopt = strsep(&marg, ",")) != NULL) { 1486 neg = *mopt == '-'; 1487 if (neg) 1488 mopt++; 1489 if (strcmp(mopt, "rxtls") == 0) { 1490 nvlist_add_bool(nvcap, "rxtls4", !neg); 1491 nvlist_add_bool(nvcap, "rxtls6", !neg); 1492 } else { 1493 nvlist_add_bool(nvcap, mopt, !neg); 1494 } 1495 } 1496 buf = nvlist_pack(nvcap, &nvbuflen); 1497 if (buf == NULL) { 1498 errx(1, "nvlist_pack error"); 1499 exit(1); 1500 } 1501 ifr.ifr_cap_nv.buf_length = ifr.ifr_cap_nv.length = nvbuflen; 1502 ifr.ifr_cap_nv.buffer = buf; 1503 if (ioctl_ctx(ctx, SIOCSIFCAPNV, (caddr_t)&ifr) < 0) 1504 Perror(vname); 1505 free(buf); 1506 nvlist_destroy(nvcap); 1507 free(marg); 1508 } 1509 1510 static void 1511 setifmetric(if_ctx *ctx, const char *val, int dummy __unused) 1512 { 1513 struct ifreq ifr = {}; 1514 1515 ifr.ifr_metric = atoi(val); 1516 if (ioctl_ctx_ifr(ctx, SIOCSIFMETRIC, &ifr) < 0) 1517 err(1, "ioctl SIOCSIFMETRIC (set metric)"); 1518 } 1519 1520 static void 1521 setifmtu(if_ctx *ctx, const char *val, int dummy __unused) 1522 { 1523 struct ifreq ifr = {}; 1524 1525 ifr.ifr_mtu = atoi(val); 1526 if (ioctl_ctx_ifr(ctx, SIOCSIFMTU, &ifr) < 0) 1527 err(1, "ioctl SIOCSIFMTU (set mtu)"); 1528 } 1529 1530 static void 1531 setifpcp(if_ctx *ctx, const char *val, int arg __unused) 1532 { 1533 struct ifreq ifr = {}; 1534 u_long ul; 1535 char *endp; 1536 1537 ul = strtoul(val, &endp, 0); 1538 if (*endp != '\0') 1539 errx(1, "invalid value for pcp"); 1540 if (ul > 7) 1541 errx(1, "value for pcp out of range"); 1542 ifr.ifr_lan_pcp = ul; 1543 if (ioctl_ctx_ifr(ctx, SIOCSLANPCP, &ifr) == -1) 1544 err(1, "SIOCSLANPCP"); 1545 } 1546 1547 static void 1548 disableifpcp(if_ctx *ctx, const char *val __unused, int arg __unused) 1549 { 1550 struct ifreq ifr = {}; 1551 1552 ifr.ifr_lan_pcp = IFNET_PCP_NONE; 1553 if (ioctl_ctx_ifr(ctx, SIOCSLANPCP, &ifr) == -1) 1554 err(1, "SIOCSLANPCP"); 1555 } 1556 1557 static void 1558 setifname(if_ctx *ctx, const char *val, int dummy __unused) 1559 { 1560 struct ifreq ifr = {}; 1561 char *newname; 1562 1563 ifr_set_name(&ifr, ctx->ifname); 1564 newname = strdup(val); 1565 if (newname == NULL) 1566 err(1, "no memory to set ifname"); 1567 ifr.ifr_data = newname; 1568 if (ioctl_ctx(ctx, SIOCSIFNAME, (caddr_t)&ifr) < 0) { 1569 free(newname); 1570 err(1, "ioctl SIOCSIFNAME (set name)"); 1571 } 1572 ifname_update(ctx, newname); 1573 free(newname); 1574 } 1575 1576 static void 1577 setifdescr(if_ctx *ctx, const char *val, int dummy __unused) 1578 { 1579 struct ifreq ifr = {}; 1580 char *newdescr; 1581 1582 ifr.ifr_buffer.length = strlen(val) + 1; 1583 if (ifr.ifr_buffer.length == 1) { 1584 ifr.ifr_buffer.buffer = newdescr = NULL; 1585 ifr.ifr_buffer.length = 0; 1586 } else { 1587 newdescr = strdup(val); 1588 ifr.ifr_buffer.buffer = newdescr; 1589 if (newdescr == NULL) { 1590 warn("no memory to set ifdescr"); 1591 return; 1592 } 1593 } 1594 1595 if (ioctl_ctx_ifr(ctx, SIOCSIFDESCR, &ifr) < 0) 1596 err(1, "ioctl SIOCSIFDESCR (set descr)"); 1597 1598 free(newdescr); 1599 } 1600 1601 static void 1602 unsetifdescr(if_ctx *ctx, const char *val __unused, int value __unused) 1603 { 1604 setifdescr(ctx, "", 0); 1605 } 1606 1607 #ifdef WITHOUT_NETLINK 1608 1609 #define IFFBITS \ 1610 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \ 1611 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ 1612 "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP\25STICKYARP" 1613 1614 #define IFCAPBITS \ 1615 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \ 1616 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \ 1617 "\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \ 1618 "\26RXCSUM_IPV6\27TXCSUM_IPV6\31TXRTLMT\32HWRXTSTMP\33NOMAP\34TXTLS4\35TXTLS6" \ 1619 "\36VXLAN_HWCSUM\37VXLAN_HWTSO\40TXTLS_RTLMT" 1620 1621 static void 1622 print_ifcap_nv(if_ctx *ctx) 1623 { 1624 struct ifreq ifr = {}; 1625 nvlist_t *nvcap; 1626 const char *nvname; 1627 void *buf, *cookie; 1628 bool first, val; 1629 int type; 1630 1631 buf = malloc(IFR_CAP_NV_MAXBUFSIZE); 1632 if (buf == NULL) 1633 Perror("malloc"); 1634 ifr.ifr_cap_nv.buffer = buf; 1635 ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE; 1636 if (ioctl_ctx_ifr(ctx, SIOCGIFCAPNV, &ifr) != 0) 1637 Perror("ioctl (SIOCGIFCAPNV)"); 1638 nvcap = nvlist_unpack(ifr.ifr_cap_nv.buffer, 1639 ifr.ifr_cap_nv.length, 0); 1640 if (nvcap == NULL) 1641 Perror("nvlist_unpack"); 1642 printf("\toptions"); 1643 cookie = NULL; 1644 for (first = true;; first = false) { 1645 nvname = nvlist_next(nvcap, &type, &cookie); 1646 if (nvname == NULL) { 1647 printf("\n"); 1648 break; 1649 } 1650 if (type == NV_TYPE_BOOL) { 1651 val = nvlist_get_bool(nvcap, nvname); 1652 if (val) { 1653 printf("%c%s", 1654 first ? ' ' : ',', nvname); 1655 } 1656 } 1657 } 1658 if (ctx->args->supmedia) { 1659 printf("\tcapabilities"); 1660 cookie = NULL; 1661 for (first = true;; first = false) { 1662 nvname = nvlist_next(nvcap, &type, 1663 &cookie); 1664 if (nvname == NULL) { 1665 printf("\n"); 1666 break; 1667 } 1668 if (type == NV_TYPE_BOOL) 1669 printf("%c%s", first ? ' ' : 1670 ',', nvname); 1671 } 1672 } 1673 nvlist_destroy(nvcap); 1674 free(buf); 1675 1676 if (ioctl_ctx(ctx, SIOCGIFCAP, (caddr_t)&ifr) != 0) 1677 Perror("ioctl (SIOCGIFCAP)"); 1678 } 1679 1680 static void 1681 print_ifcap(if_ctx *ctx) 1682 { 1683 struct ifreq ifr = {}; 1684 1685 if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) != 0) 1686 return; 1687 1688 if ((ifr.ifr_curcap & IFCAP_NV) != 0) 1689 print_ifcap_nv(ctx); 1690 else { 1691 printb("\toptions", ifr.ifr_curcap, IFCAPBITS); 1692 putchar('\n'); 1693 if (ctx->args->supmedia && ifr.ifr_reqcap != 0) { 1694 printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); 1695 putchar('\n'); 1696 } 1697 } 1698 } 1699 #endif 1700 1701 void 1702 print_ifstatus(if_ctx *ctx) 1703 { 1704 struct ifstat ifs; 1705 1706 strlcpy(ifs.ifs_name, ctx->ifname, sizeof ifs.ifs_name); 1707 if (ioctl_ctx(ctx, SIOCGIFSTATUS, &ifs) == 0) 1708 printf("%s", ifs.ascii); 1709 } 1710 1711 void 1712 print_metric(if_ctx *ctx) 1713 { 1714 struct ifreq ifr = {}; 1715 1716 if (ioctl_ctx_ifr(ctx, SIOCGIFMETRIC, &ifr) != -1) 1717 printf(" metric %d", ifr.ifr_metric); 1718 } 1719 1720 #ifdef WITHOUT_NETLINK 1721 static void 1722 print_mtu(if_ctx *ctx) 1723 { 1724 struct ifreq ifr = {}; 1725 1726 if (ioctl_ctx_ifr(ctx, SIOCGIFMTU, &ifr) != -1) 1727 printf(" mtu %d", ifr.ifr_mtu); 1728 } 1729 1730 static void 1731 print_description(if_ctx *ctx) 1732 { 1733 struct ifreq ifr = {}; 1734 1735 ifr_set_name(&ifr, ctx->ifname); 1736 for (;;) { 1737 if ((descr = reallocf(descr, descrlen)) != NULL) { 1738 ifr.ifr_buffer.buffer = descr; 1739 ifr.ifr_buffer.length = descrlen; 1740 if (ioctl_ctx(ctx, SIOCGIFDESCR, &ifr) == 0) { 1741 if (ifr.ifr_buffer.buffer == descr) { 1742 if (strlen(descr) > 0) 1743 printf("\tdescription: %s\n", 1744 descr); 1745 } else if (ifr.ifr_buffer.length > descrlen) { 1746 descrlen = ifr.ifr_buffer.length; 1747 continue; 1748 } 1749 } 1750 } else 1751 warn("unable to allocate memory for interface" 1752 "description"); 1753 break; 1754 } 1755 } 1756 1757 /* 1758 * Print the status of the interface. If an address family was 1759 * specified, show only it; otherwise, show them all. 1760 */ 1761 static void 1762 status(if_ctx *ctx, const struct sockaddr_dl *sdl __unused, struct ifaddrs *ifa) 1763 { 1764 struct ifaddrs *ift; 1765 int s, old_s; 1766 struct ifconfig_args *args = ctx->args; 1767 bool allfamilies = args->afp == NULL; 1768 struct ifreq ifr = {}; 1769 1770 if (args->afp == NULL) 1771 ifr.ifr_addr.sa_family = AF_LOCAL; 1772 else 1773 ifr.ifr_addr.sa_family = 1774 args->afp->af_af == AF_LINK ? AF_LOCAL : args->afp->af_af; 1775 1776 s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); 1777 if (s < 0) 1778 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); 1779 old_s = ctx->io_s; 1780 ctx->io_s = s; 1781 1782 printf("%s: ", ctx->ifname); 1783 printb("flags", ifa->ifa_flags, IFFBITS); 1784 print_metric(ctx); 1785 print_mtu(ctx); 1786 putchar('\n'); 1787 1788 print_description(ctx); 1789 1790 print_ifcap(ctx); 1791 1792 tunnel_status(ctx); 1793 1794 for (ift = ifa; ift != NULL; ift = ift->ifa_next) { 1795 if (ift->ifa_addr == NULL) 1796 continue; 1797 if (strcmp(ifa->ifa_name, ift->ifa_name) != 0) 1798 continue; 1799 if (allfamilies) { 1800 const struct afswtch *p; 1801 p = af_getbyfamily(ift->ifa_addr->sa_family); 1802 if (p != NULL && p->af_status != NULL) 1803 p->af_status(ctx, ift); 1804 } else if (args->afp->af_af == ift->ifa_addr->sa_family) 1805 args->afp->af_status(ctx, ift); 1806 } 1807 #if 0 1808 if (allfamilies || afp->af_af == AF_LINK) { 1809 const struct afswtch *lafp; 1810 1811 /* 1812 * Hack; the link level address is received separately 1813 * from the routing information so any address is not 1814 * handled above. Cobble together an entry and invoke 1815 * the status method specially. 1816 */ 1817 lafp = af_getbyname("lladdr"); 1818 if (lafp != NULL) { 1819 info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl; 1820 lafp->af_status(s, &info); 1821 } 1822 } 1823 #endif 1824 if (allfamilies) 1825 af_other_status(ctx); 1826 else if (args->afp->af_other_status != NULL) 1827 args->afp->af_other_status(ctx); 1828 1829 print_ifstatus(ctx); 1830 if (args->verbose > 0) 1831 sfp_status(ctx); 1832 1833 close(s); 1834 ctx->io_s = old_s; 1835 return; 1836 } 1837 #endif 1838 1839 void 1840 tunnel_status(if_ctx *ctx) 1841 { 1842 af_all_tunnel_status(ctx); 1843 } 1844 1845 static void 1846 Perrorc(const char *cmd, int error) 1847 { 1848 switch (errno) { 1849 1850 case ENXIO: 1851 errx(1, "%s: no such interface", cmd); 1852 break; 1853 1854 case EPERM: 1855 errx(1, "%s: permission denied", cmd); 1856 break; 1857 1858 default: 1859 errc(1, error, "%s", cmd); 1860 } 1861 } 1862 1863 void 1864 Perror(const char *cmd) 1865 { 1866 Perrorc(cmd, errno); 1867 } 1868 1869 /* 1870 * Print a value a la the %b format of the kernel's printf 1871 */ 1872 void 1873 printb(const char *s, unsigned v, const char *bits) 1874 { 1875 int i, any = 0; 1876 char c; 1877 1878 if (bits && *bits == 8) 1879 printf("%s=%o", s, v); 1880 else 1881 printf("%s=%x", s, v); 1882 if (bits) { 1883 bits++; 1884 putchar('<'); 1885 while ((i = *bits++) != '\0') { 1886 if (v & (1u << (i-1))) { 1887 if (any) 1888 putchar(','); 1889 any = 1; 1890 for (; (c = *bits) > 32; bits++) 1891 putchar(c); 1892 } else 1893 for (; *bits > 32; bits++) 1894 ; 1895 } 1896 putchar('>'); 1897 } 1898 } 1899 1900 void 1901 print_vhid(const struct ifaddrs *ifa) 1902 { 1903 struct if_data *ifd; 1904 1905 if (ifa->ifa_data == NULL) 1906 return; 1907 1908 ifd = ifa->ifa_data; 1909 if (ifd->ifi_vhid == 0) 1910 return; 1911 1912 printf(" vhid %d", ifd->ifi_vhid); 1913 } 1914 1915 void 1916 ifmaybeload(struct ifconfig_args *args, const char *name) 1917 { 1918 #define MOD_PREFIX_LEN 3 /* "if_" */ 1919 struct module_stat mstat; 1920 int fileid, modid; 1921 char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp; 1922 const char *cp; 1923 struct module_map_entry *mme; 1924 bool found; 1925 1926 /* loading suppressed by the user */ 1927 if (args->noload) 1928 return; 1929 1930 /* trim the interface number off the end */ 1931 strlcpy(ifname, name, sizeof(ifname)); 1932 dp = ifname + strlen(ifname) - 1; 1933 for (; dp > ifname; dp--) { 1934 if (isdigit(*dp)) 1935 *dp = '\0'; 1936 else 1937 break; 1938 } 1939 1940 /* Either derive it from the map or guess otherwise */ 1941 *ifkind = '\0'; 1942 found = false; 1943 for (unsigned i = 0; i < nitems(module_map); ++i) { 1944 mme = &module_map[i]; 1945 if (strcmp(mme->ifname, ifname) == 0) { 1946 strlcpy(ifkind, mme->kldname, sizeof(ifkind)); 1947 found = true; 1948 break; 1949 } 1950 } 1951 1952 /* We didn't have an alias for it... we'll guess. */ 1953 if (!found) { 1954 /* turn interface and unit into module name */ 1955 strlcpy(ifkind, "if_", sizeof(ifkind)); 1956 strlcat(ifkind, ifname, sizeof(ifkind)); 1957 } 1958 1959 /* scan files in kernel */ 1960 mstat.version = sizeof(struct module_stat); 1961 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 1962 /* scan modules in file */ 1963 for (modid = kldfirstmod(fileid); modid > 0; 1964 modid = modfnext(modid)) { 1965 if (modstat(modid, &mstat) < 0) 1966 continue; 1967 /* strip bus name if present */ 1968 if ((cp = strchr(mstat.name, '/')) != NULL) { 1969 cp++; 1970 } else { 1971 cp = mstat.name; 1972 } 1973 /* 1974 * Is it already loaded? Don't compare with ifname if 1975 * we were specifically told which kld to use. Doing 1976 * so could lead to conflicts not trivially solved. 1977 */ 1978 if ((!found && strcmp(ifname, cp) == 0) || 1979 strcmp(ifkind, cp) == 0) 1980 return; 1981 } 1982 } 1983 1984 /* 1985 * Try to load the module. But ignore failures, because ifconfig can't 1986 * infer the names of all drivers (eg mlx4en(4)). 1987 */ 1988 (void) kldload(ifkind); 1989 } 1990 1991 static struct cmd basic_cmds[] = { 1992 DEF_CMD("up", IFF_UP, setifflags), 1993 DEF_CMD("down", IFF_UP, clearifflags), 1994 DEF_CMD("arp", IFF_NOARP, clearifflags), 1995 DEF_CMD("-arp", IFF_NOARP, setifflags), 1996 DEF_CMD("debug", IFF_DEBUG, setifflags), 1997 DEF_CMD("-debug", IFF_DEBUG, clearifflags), 1998 DEF_CMD_ARG("description", setifdescr), 1999 DEF_CMD_ARG("descr", setifdescr), 2000 DEF_CMD("-description", 0, unsetifdescr), 2001 DEF_CMD("-descr", 0, unsetifdescr), 2002 DEF_CMD("promisc", IFF_PPROMISC, setifflags), 2003 DEF_CMD("-promisc", IFF_PPROMISC, clearifflags), 2004 DEF_CMD("add", IFF_UP, notealias), 2005 DEF_CMD("alias", IFF_UP, notealias), 2006 DEF_CMD("-alias", -IFF_UP, notealias), 2007 DEF_CMD("delete", -IFF_UP, notealias), 2008 DEF_CMD("remove", -IFF_UP, notealias), 2009 #ifdef notdef 2010 #define EN_SWABIPS 0x1000 2011 DEF_CMD("swabips", EN_SWABIPS, setifflags), 2012 DEF_CMD("-swabips", EN_SWABIPS, clearifflags), 2013 #endif 2014 DEF_CMD_ARG("netmask", setifnetmask), 2015 DEF_CMD_ARG("metric", setifmetric), 2016 DEF_CMD_ARG("broadcast", setifbroadaddr), 2017 DEF_CMD_ARG2("tunnel", settunnel), 2018 DEF_CMD("-tunnel", 0, deletetunnel), 2019 DEF_CMD("deletetunnel", 0, deletetunnel), 2020 #ifdef JAIL 2021 DEF_CMD_ARG("vnet", setifvnet), 2022 DEF_CMD_ARG("-vnet", setifrvnet), 2023 #endif 2024 DEF_CMD("link0", IFF_LINK0, setifflags), 2025 DEF_CMD("-link0", IFF_LINK0, clearifflags), 2026 DEF_CMD("link1", IFF_LINK1, setifflags), 2027 DEF_CMD("-link1", IFF_LINK1, clearifflags), 2028 DEF_CMD("link2", IFF_LINK2, setifflags), 2029 DEF_CMD("-link2", IFF_LINK2, clearifflags), 2030 DEF_CMD("monitor", IFF_MONITOR, setifflags), 2031 DEF_CMD("-monitor", IFF_MONITOR, clearifflags), 2032 DEF_CMD("mextpg", IFCAP_MEXTPG, setifcap), 2033 DEF_CMD("-mextpg", IFCAP_MEXTPG, clearifcap), 2034 DEF_CMD("staticarp", IFF_STATICARP, setifflags), 2035 DEF_CMD("-staticarp", IFF_STATICARP, clearifflags), 2036 DEF_CMD("stickyarp", IFF_STICKYARP, setifflags), 2037 DEF_CMD("-stickyarp", IFF_STICKYARP, clearifflags), 2038 DEF_CMD("rxcsum6", IFCAP_RXCSUM_IPV6, setifcap), 2039 DEF_CMD("-rxcsum6", IFCAP_RXCSUM_IPV6, clearifcap), 2040 DEF_CMD("txcsum6", IFCAP_TXCSUM_IPV6, setifcap), 2041 DEF_CMD("-txcsum6", IFCAP_TXCSUM_IPV6, clearifcap), 2042 DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), 2043 DEF_CMD("-rxcsum", IFCAP_RXCSUM, clearifcap), 2044 DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), 2045 DEF_CMD("-txcsum", IFCAP_TXCSUM, clearifcap), 2046 DEF_CMD("netcons", IFCAP_NETCONS, setifcap), 2047 DEF_CMD("-netcons", IFCAP_NETCONS, clearifcap), 2048 DEF_CMD_ARG("pcp", setifpcp), 2049 DEF_CMD("-pcp", 0, disableifpcp), 2050 DEF_CMD("polling", IFCAP_POLLING, setifcap), 2051 DEF_CMD("-polling", IFCAP_POLLING, clearifcap), 2052 DEF_CMD("tso6", IFCAP_TSO6, setifcap), 2053 DEF_CMD("-tso6", IFCAP_TSO6, clearifcap), 2054 DEF_CMD("tso4", IFCAP_TSO4, setifcap), 2055 DEF_CMD("-tso4", IFCAP_TSO4, clearifcap), 2056 DEF_CMD("tso", IFCAP_TSO, setifcap), 2057 DEF_CMD("-tso", IFCAP_TSO, clearifcap), 2058 DEF_CMD("toe", IFCAP_TOE, setifcap), 2059 DEF_CMD("-toe", IFCAP_TOE, clearifcap), 2060 DEF_CMD("lro", IFCAP_LRO, setifcap), 2061 DEF_CMD("-lro", IFCAP_LRO, clearifcap), 2062 DEF_CMD("txtls", IFCAP_TXTLS, setifcap), 2063 DEF_CMD("-txtls", IFCAP_TXTLS, clearifcap), 2064 DEF_CMD_SARG("rxtls", IFCAP2_RXTLS4_NAME "," IFCAP2_RXTLS6_NAME, 2065 setifcapnv), 2066 DEF_CMD_SARG("-rxtls", "-"IFCAP2_RXTLS4_NAME ",-" IFCAP2_RXTLS6_NAME, 2067 setifcapnv), 2068 DEF_CMD("wol", IFCAP_WOL, setifcap), 2069 DEF_CMD("-wol", IFCAP_WOL, clearifcap), 2070 DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap), 2071 DEF_CMD("-wol_ucast", IFCAP_WOL_UCAST, clearifcap), 2072 DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap), 2073 DEF_CMD("-wol_mcast", IFCAP_WOL_MCAST, clearifcap), 2074 DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap), 2075 DEF_CMD("-wol_magic", IFCAP_WOL_MAGIC, clearifcap), 2076 DEF_CMD("txrtlmt", IFCAP_TXRTLMT, setifcap), 2077 DEF_CMD("-txrtlmt", IFCAP_TXRTLMT, clearifcap), 2078 DEF_CMD("txtlsrtlmt", IFCAP_TXTLS_RTLMT, setifcap), 2079 DEF_CMD("-txtlsrtlmt", IFCAP_TXTLS_RTLMT, clearifcap), 2080 DEF_CMD("hwrxtstmp", IFCAP_HWRXTSTMP, setifcap), 2081 DEF_CMD("-hwrxtstmp", IFCAP_HWRXTSTMP, clearifcap), 2082 DEF_CMD("normal", IFF_LINK0, clearifflags), 2083 DEF_CMD("compress", IFF_LINK0, setifflags), 2084 DEF_CMD("noicmp", IFF_LINK1, setifflags), 2085 DEF_CMD_ARG("mtu", setifmtu), 2086 DEF_CMD_ARG("name", setifname), 2087 }; 2088 2089 static __constructor void 2090 ifconfig_ctor(void) 2091 { 2092 size_t i; 2093 2094 for (i = 0; i < nitems(basic_cmds); i++) 2095 cmd_register(&basic_cmds[i]); 2096 } 2097