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:adDf: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 'D': /* Print driver name */ 471 args->drivername = true; 472 break; 473 case 'f': 474 if (optarg == NULL) 475 usage(); 476 setformat(optarg); 477 break; 478 case 'G': 479 if (optarg == NULL || args->all == 0) 480 usage(); 481 args->nogroup = optarg; 482 break; 483 case 'j': 484 #ifdef JAIL 485 if (optarg == NULL) 486 usage(); 487 args->jail_name = optarg; 488 #else 489 Perror("not built with jail support"); 490 #endif 491 break; 492 case 'k': 493 args->printkeys = true; 494 break; 495 case 'l': /* scan interface names only */ 496 args->namesonly = true; 497 break; 498 case 'm': /* show media choices in status */ 499 args->supmedia = true; 500 break; 501 case 'n': /* suppress module loading */ 502 args->noload = true; 503 break; 504 case 'u': /* restrict scan to "up" interfaces */ 505 args->uponly = true; 506 break; 507 case 'v': 508 args->verbose++; 509 break; 510 case 'g': 511 if (args->all) { 512 if (optarg == NULL) 513 usage(); 514 args->matchgroup = optarg; 515 break; 516 } 517 /* FALLTHROUGH */ 518 default: 519 for (p = opts; p != NULL; p = p->next) 520 if (p->opt[0] == c) { 521 p->cb(optarg); 522 break; 523 } 524 if (p == NULL) 525 usage(); 526 break; 527 } 528 } 529 argc -= optind; 530 argv += optind; 531 532 /* -l cannot be used with -a or -m */ 533 if (args->namesonly && (args->all || args->supmedia)) 534 usage(); 535 536 /* nonsense.. */ 537 if (args->uponly && args->downonly) 538 usage(); 539 540 /* no arguments is equivalent to '-a' */ 541 if (!args->namesonly && argc < 1) 542 args->all = 1; 543 544 /* -a and -l allow an address family arg to limit the output */ 545 if (args->all || args->namesonly) { 546 if (argc > 1) 547 usage(); 548 549 if (argc == 1) { 550 const struct afswtch *afp = af_getbyname(*argv); 551 552 if (afp == NULL) { 553 warnx("Address family '%s' unknown.", *argv); 554 usage(); 555 } 556 if (afp->af_name != NULL) 557 argc--, argv++; 558 /* leave with afp non-zero */ 559 args->afp = afp; 560 } 561 } else { 562 /* not listing, need an argument */ 563 if (argc < 1) 564 usage(); 565 } 566 567 args->argc = argc; 568 args->argv = argv; 569 } 570 571 static int 572 ifconfig(if_ctx *ctx, int iscreate, const struct afswtch *uafp) 573 { 574 #ifdef WITHOUT_NETLINK 575 return (ifconfig_ioctl(ctx, iscreate, uafp)); 576 #else 577 return (ifconfig_nl(ctx, iscreate, uafp)); 578 #endif 579 } 580 581 static bool 582 isargcreate(const char *arg) 583 { 584 if (arg == NULL) 585 return (false); 586 587 if (strcmp(arg, "create") == 0 || strcmp(arg, "plumb") == 0) 588 return (true); 589 590 return (false); 591 } 592 593 static bool 594 isnametoolong(const char *ifname) 595 { 596 return (strlen(ifname) >= IFNAMSIZ); 597 } 598 599 int 600 main(int ac, char *av[]) 601 { 602 char *envformat; 603 int flags; 604 #ifdef JAIL 605 int jid; 606 #endif 607 struct ifconfig_args _args = {}; 608 struct ifconfig_args *args = &_args; 609 610 struct ifconfig_context ctx = { 611 .args = args, 612 .io_s = -1, 613 }; 614 615 f_inet = f_inet6 = f_ether = f_addr = NULL; 616 617 lifh = ifconfig_open(); 618 if (lifh == NULL) 619 err(EXIT_FAILURE, "ifconfig_open"); 620 621 envformat = getenv("IFCONFIG_FORMAT"); 622 if (envformat != NULL) 623 setformat(envformat); 624 625 /* 626 * Ensure we print interface name when expected to, 627 * even if we terminate early due to error. 628 */ 629 atexit(printifnamemaybe); 630 631 args_parse(args, ac, av); 632 633 #ifdef JAIL 634 if (args->jail_name) { 635 jid = jail_getid(args->jail_name); 636 if (jid == -1) 637 Perror("jail not found"); 638 if (jail_attach(jid) != 0) 639 Perror("cannot attach to jail"); 640 } 641 #endif 642 643 if (!args->all && !args->namesonly) { 644 /* not listing, need an argument */ 645 args->ifname = args_pop(args); 646 ctx.ifname = args->ifname; 647 648 /* check and maybe load support for this interface */ 649 ifmaybeload(args, args->ifname); 650 651 char *arg = args_peek(args); 652 if (if_nametoindex(args->ifname) == 0) { 653 /* 654 * NOTE: We must special-case the `create' command 655 * right here as we would otherwise fail when trying 656 * to find the interface. 657 */ 658 if (isargcreate(arg)) { 659 if (isnametoolong(args->ifname)) 660 errx(1, "%s: cloning name too long", 661 args->ifname); 662 ifconfig(&ctx, 1, NULL); 663 exit(exit_code); 664 } 665 #ifdef JAIL 666 /* 667 * NOTE: We have to special-case the `-vnet' command 668 * right here as we would otherwise fail when trying 669 * to find the interface as it lives in another vnet. 670 */ 671 if (arg != NULL && (strcmp(arg, "-vnet") == 0)) { 672 if (isnametoolong(args->ifname)) 673 errx(1, "%s: interface name too long", 674 args->ifname); 675 ifconfig(&ctx, 0, NULL); 676 exit(exit_code); 677 } 678 #endif 679 errx(1, "interface %s does not exist", args->ifname); 680 } else { 681 /* 682 * Do not allow use `create` command as hostname if 683 * address family is not specified. 684 */ 685 if (isargcreate(arg)) { 686 if (args->argc == 1) 687 errx(1, "interface %s already exists", 688 args->ifname); 689 args_pop(args); 690 } 691 } 692 } 693 694 /* Check for address family */ 695 if (args->argc > 0) { 696 args->afp = af_getbyname(args_peek(args)); 697 if (args->afp != NULL) 698 args_pop(args); 699 } 700 701 /* 702 * Check for a requested configuration action on a single interface, 703 * which doesn't require building, sorting, and searching the entire 704 * system address list 705 */ 706 if ((args->argc > 0) && (args->ifname != NULL)) { 707 if (isnametoolong(args->ifname)) 708 warnx("%s: interface name too long, skipping", args->ifname); 709 else { 710 flags = getifflags(args->ifname, -1, false); 711 if (!(((flags & IFF_CANTCONFIG) != 0) || 712 (args->downonly && (flags & IFF_UP) != 0) || 713 (args->uponly && (flags & IFF_UP) == 0))) 714 ifconfig(&ctx, 0, args->afp); 715 } 716 goto done; 717 } 718 719 args->allfamilies = args->afp == NULL; 720 721 list_interfaces(&ctx); 722 723 done: 724 freeformat(); 725 ifconfig_close(lifh); 726 exit(exit_code); 727 } 728 729 bool 730 match_ether(const struct sockaddr_dl *sdl) 731 { 732 switch (sdl->sdl_type) { 733 case IFT_ETHER: 734 case IFT_L2VLAN: 735 case IFT_BRIDGE: 736 if (sdl->sdl_alen == ETHER_ADDR_LEN) 737 return (true); 738 default: 739 return (false); 740 } 741 } 742 743 bool 744 match_if_flags(struct ifconfig_args *args, int if_flags) 745 { 746 if ((if_flags & IFF_CANTCONFIG) != 0) 747 return (false); 748 if (args->downonly && (if_flags & IFF_UP) != 0) 749 return (false); 750 if (args->uponly && (if_flags & IFF_UP) == 0) 751 return (false); 752 return (true); 753 } 754 755 #ifdef WITHOUT_NETLINK 756 static bool 757 match_afp(const struct afswtch *afp, int sa_family, const struct sockaddr_dl *sdl) 758 { 759 if (afp == NULL) 760 return (true); 761 /* special case for "ether" address family */ 762 if (!strcmp(afp->af_name, "ether")) { 763 if (sdl == NULL || !match_ether(sdl)) 764 return (false); 765 return (true); 766 } 767 return (afp->af_af == sa_family); 768 } 769 770 static void 771 list_interfaces_ioctl(if_ctx *ctx) 772 { 773 struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); 774 struct ifaddrs *ifap, *sifap, *ifa; 775 struct ifa_order_elt *cur, *tmp; 776 char *namecp = NULL; 777 int ifindex; 778 struct ifconfig_args *args = ctx->args; 779 780 if (getifaddrs(&ifap) != 0) 781 err(EXIT_FAILURE, "getifaddrs"); 782 783 char *cp = NULL; 784 785 if (calcorders(ifap, &q) != 0) 786 err(EXIT_FAILURE, "calcorders"); 787 788 sifap = sortifaddrs(ifap, cmpifaddrs, &q); 789 790 TAILQ_FOREACH_SAFE(cur, &q, link, tmp) 791 free(cur); 792 793 ifindex = 0; 794 for (ifa = sifap; ifa; ifa = ifa->ifa_next) { 795 struct ifreq paifr = {}; 796 const struct sockaddr_dl *sdl; 797 798 strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); 799 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) { 800 memcpy(&paifr.ifr_addr, ifa->ifa_addr, 801 ifa->ifa_addr->sa_len); 802 } 803 804 if (args->ifname != NULL && strcmp(args->ifname, ifa->ifa_name) != 0) 805 continue; 806 if (ifa->ifa_addr->sa_family == AF_LINK) 807 sdl = satosdl_c(ifa->ifa_addr); 808 else 809 sdl = NULL; 810 if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !args->namesonly) 811 continue; 812 if (isnametoolong(ifa->ifa_name)) { 813 warnx("%s: interface name too long, skipping", 814 ifa->ifa_name); 815 continue; 816 } 817 cp = ifa->ifa_name; 818 819 if (!match_if_flags(args, ifa->ifa_flags)) 820 continue; 821 if (!group_member(ifa->ifa_name, args->matchgroup, args->nogroup)) 822 continue; 823 ctx->ifname = cp; 824 /* 825 * Are we just listing the interfaces? 826 */ 827 if (args->namesonly) { 828 if (namecp == cp) 829 continue; 830 if (!match_afp(args->afp, ifa->ifa_addr->sa_family, sdl)) 831 continue; 832 namecp = cp; 833 ifindex++; 834 if (ifindex > 1) 835 printf(" "); 836 fputs(cp, stdout); 837 continue; 838 } 839 ifindex++; 840 841 if (args->argc > 0) 842 ifconfig(ctx, 0, args->afp); 843 else 844 status(ctx, sdl, ifa); 845 } 846 if (args->namesonly) 847 printf("\n"); 848 freeifaddrs(ifap); 849 } 850 #endif 851 852 /* 853 * Returns true if an interface should be listed because any its groups 854 * matches shell pattern "match" and none of groups matches pattern "nomatch". 855 * If any pattern is NULL, corresponding condition is skipped. 856 */ 857 bool 858 group_member(const char *ifname, const char *match, const char *nomatch) 859 { 860 static int sock = -1; 861 862 struct ifgroupreq ifgr; 863 struct ifg_req *ifg; 864 unsigned int len; 865 bool matched, nomatched; 866 867 /* Sanity checks. */ 868 if (match == NULL && nomatch == NULL) 869 return (true); 870 if (ifname == NULL) 871 return (false); 872 873 memset(&ifgr, 0, sizeof(ifgr)); 874 strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ); 875 876 /* The socket is opened once. Let _exit() close it. */ 877 if (sock == -1) { 878 sock = socket(AF_LOCAL, SOCK_DGRAM, 0); 879 if (sock == -1) 880 errx(1, "%s: socket(AF_LOCAL,SOCK_DGRAM)", __func__); 881 } 882 883 /* Determine amount of memory for the list of groups. */ 884 if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) { 885 if (errno == EINVAL || errno == ENOTTY) 886 return (false); 887 else 888 errx(1, "%s: SIOCGIFGROUP", __func__); 889 } 890 891 /* Obtain the list of groups. */ 892 len = ifgr.ifgr_len; 893 ifgr.ifgr_groups = 894 (struct ifg_req *)calloc(len / sizeof(*ifg), sizeof(*ifg)); 895 896 if (ifgr.ifgr_groups == NULL) 897 errx(1, "%s: no memory", __func__); 898 if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) 899 errx(1, "%s: SIOCGIFGROUP", __func__); 900 901 /* Perform matching. */ 902 matched = false; 903 nomatched = true; 904 for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(*ifg); ifg++) { 905 len -= sizeof(*ifg); 906 if (match && !matched) 907 matched = !fnmatch(match, ifg->ifgrq_group, 0); 908 if (nomatch && nomatched) 909 nomatched = fnmatch(nomatch, ifg->ifgrq_group, 0); 910 } 911 free(ifgr.ifgr_groups); 912 913 if (match && !nomatch) 914 return (matched); 915 if (!match && nomatch) 916 return (nomatched); 917 return (matched && nomatched); 918 } 919 920 static struct afswtch *afs = NULL; 921 922 void 923 af_register(struct afswtch *p) 924 { 925 p->af_next = afs; 926 afs = p; 927 } 928 929 static struct afswtch * 930 af_getbyname(const char *name) 931 { 932 struct afswtch *afp; 933 934 for (afp = afs; afp != NULL; afp = afp->af_next) 935 if (strcmp(afp->af_name, name) == 0) 936 return afp; 937 return NULL; 938 } 939 940 struct afswtch * 941 af_getbyfamily(int af) 942 { 943 struct afswtch *afp; 944 945 for (afp = afs; afp != NULL; afp = afp->af_next) 946 if (afp->af_af == af) 947 return afp; 948 return NULL; 949 } 950 951 void 952 af_other_status(if_ctx *ctx) 953 { 954 struct afswtch *afp; 955 uint8_t afmask[howmany(AF_MAX, NBBY)]; 956 957 memset(afmask, 0, sizeof(afmask)); 958 for (afp = afs; afp != NULL; afp = afp->af_next) { 959 if (afp->af_other_status == NULL) 960 continue; 961 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) 962 continue; 963 afp->af_other_status(ctx); 964 setbit(afmask, afp->af_af); 965 } 966 } 967 968 static void 969 af_all_tunnel_status(if_ctx *ctx) 970 { 971 struct afswtch *afp; 972 uint8_t afmask[howmany(AF_MAX, NBBY)]; 973 974 memset(afmask, 0, sizeof(afmask)); 975 for (afp = afs; afp != NULL; afp = afp->af_next) { 976 if (afp->af_status_tunnel == NULL) 977 continue; 978 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) 979 continue; 980 afp->af_status_tunnel(ctx); 981 setbit(afmask, afp->af_af); 982 } 983 } 984 985 static struct cmd *cmds = NULL; 986 987 void 988 cmd_register(struct cmd *p) 989 { 990 p->c_next = cmds; 991 cmds = p; 992 } 993 994 static const struct cmd * 995 cmd_lookup(const char *name, int iscreate) 996 { 997 const struct cmd *p; 998 999 for (p = cmds; p != NULL; p = p->c_next) 1000 if (strcmp(name, p->c_name) == 0) { 1001 if (iscreate) { 1002 if (p->c_iscloneop) 1003 return p; 1004 } else { 1005 if (!p->c_iscloneop) 1006 return p; 1007 } 1008 } 1009 return NULL; 1010 } 1011 1012 struct callback { 1013 callback_func *cb_func; 1014 void *cb_arg; 1015 struct callback *cb_next; 1016 }; 1017 static struct callback *callbacks = NULL; 1018 1019 void 1020 callback_register(callback_func *func, void *arg) 1021 { 1022 struct callback *cb; 1023 1024 cb = malloc(sizeof(struct callback)); 1025 if (cb == NULL) 1026 errx(1, "unable to allocate memory for callback"); 1027 cb->cb_func = func; 1028 cb->cb_arg = arg; 1029 cb->cb_next = callbacks; 1030 callbacks = cb; 1031 } 1032 1033 /* specially-handled commands */ 1034 static void setifaddr(if_ctx *ctx, const char *addr, int param); 1035 static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr); 1036 1037 static void setifdstaddr(if_ctx *ctx, const char *addr, int param __unused); 1038 static const struct cmd setifdstaddr_cmd = 1039 DEF_CMD("ifdstaddr", 0, setifdstaddr); 1040 1041 int 1042 af_exec_ioctl(if_ctx *ctx, unsigned long action, void *data) 1043 { 1044 struct ifreq *req = (struct ifreq *)data; 1045 1046 strlcpy(req->ifr_name, ctx->ifname, sizeof(req->ifr_name)); 1047 if (ioctl_ctx(ctx, action, req) == 0) 1048 return (0); 1049 return (errno); 1050 } 1051 1052 static void 1053 delifaddr(if_ctx *ctx, const struct afswtch *afp) 1054 { 1055 int error; 1056 1057 if (afp->af_exec == NULL) { 1058 warnx("interface %s cannot change %s addresses!", 1059 ctx->ifname, afp->af_name); 1060 clearaddr = 0; 1061 return; 1062 } 1063 1064 error = afp->af_exec(ctx, afp->af_difaddr, afp->af_ridreq); 1065 if (error != 0) { 1066 if (error == EADDRNOTAVAIL && (doalias >= 0)) { 1067 /* means no previous address for interface */ 1068 } else 1069 Perrorc("ioctl (SIOCDIFADDR)", error); 1070 } 1071 } 1072 1073 static void 1074 addifaddr(if_ctx *ctx, const struct afswtch *afp) 1075 { 1076 if (afp->af_exec == NULL) { 1077 warnx("interface %s cannot change %s addresses!", 1078 ctx->ifname, afp->af_name); 1079 newaddr = 0; 1080 return; 1081 } 1082 1083 if (setaddr || setmask) { 1084 int error = afp->af_exec(ctx, afp->af_aifaddr, afp->af_addreq); 1085 if (error != 0) 1086 Perrorc("ioctl (SIOCAIFADDR)", error); 1087 } 1088 } 1089 1090 int 1091 ifconfig_ioctl(if_ctx *orig_ctx, int iscreate, const struct afswtch *uafp) 1092 { 1093 const struct afswtch *afp, *nafp; 1094 const struct cmd *p; 1095 struct callback *cb; 1096 int s; 1097 int argc = orig_ctx->args->argc; 1098 char *const *argv = orig_ctx->args->argv; 1099 struct ifconfig_context _ctx = { 1100 .args = orig_ctx->args, 1101 .io_ss = orig_ctx->io_ss, 1102 .ifname = orig_ctx->ifname, 1103 }; 1104 struct ifconfig_context *ctx = &_ctx; 1105 1106 struct ifreq ifr = {}; 1107 strlcpy(ifr.ifr_name, ctx->ifname, sizeof ifr.ifr_name); 1108 afp = NULL; 1109 if (uafp != NULL) 1110 afp = uafp; 1111 /* 1112 * This is the historical "accident" allowing users to configure IPv4 1113 * addresses without the "inet" keyword which while a nice feature has 1114 * proven to complicate other things. We cannot remove this but only 1115 * make sure we will never have a similar implicit default for IPv6 or 1116 * any other address familiy. We need a fallback though for 1117 * ifconfig IF up/down etc. to work without INET support as people 1118 * never used ifconfig IF link up/down, etc. either. 1119 */ 1120 #ifndef RESCUE 1121 #ifdef INET 1122 if (afp == NULL && feature_present("inet")) 1123 afp = af_getbyname("inet"); 1124 #endif 1125 #endif 1126 if (afp == NULL) 1127 afp = af_getbyname("link"); 1128 if (afp == NULL) { 1129 warnx("Please specify an address_family."); 1130 usage(); 1131 } 1132 1133 top: 1134 ifr.ifr_addr.sa_family = 1135 afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ? 1136 AF_LOCAL : afp->af_af; 1137 1138 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 && 1139 (uafp != NULL || errno != EAFNOSUPPORT || 1140 (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)) 1141 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); 1142 1143 ctx->io_s = s; 1144 ctx->afp = afp; 1145 1146 while (argc > 0) { 1147 p = cmd_lookup(*argv, iscreate); 1148 if (iscreate && p == NULL) { 1149 /* 1150 * Push the clone create callback so the new 1151 * device is created and can be used for any 1152 * remaining arguments. 1153 */ 1154 cb = callbacks; 1155 if (cb == NULL) 1156 errx(1, "internal error, no callback"); 1157 callbacks = cb->cb_next; 1158 cb->cb_func(ctx, cb->cb_arg); 1159 iscreate = 0; 1160 /* 1161 * Handle any address family spec that 1162 * immediately follows and potentially 1163 * recreate the socket. 1164 */ 1165 nafp = af_getbyname(*argv); 1166 if (nafp != NULL) { 1167 argc--, argv++; 1168 if (nafp != afp) { 1169 close(s); 1170 afp = nafp; 1171 goto top; 1172 } 1173 } 1174 /* 1175 * Look for a normal parameter. 1176 */ 1177 continue; 1178 } 1179 if (p == NULL) { 1180 /* 1181 * Not a recognized command, choose between setting 1182 * the interface address and the dst address. 1183 */ 1184 p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd); 1185 } 1186 if (p->c_parameter == NEXTARG && p->c_u.c_func) { 1187 if (argv[1] == NULL) 1188 errx(1, "'%s' requires argument", 1189 p->c_name); 1190 p->c_u.c_func(ctx, argv[1], 0); 1191 argc--, argv++; 1192 } else if (p->c_parameter == OPTARG && p->c_u.c_func) { 1193 p->c_u.c_func(ctx, argv[1], 0); 1194 if (argv[1] != NULL) 1195 argc--, argv++; 1196 } else if (p->c_parameter == NEXTARG2 && p->c_u.c_func2) { 1197 if (argc < 3) 1198 errx(1, "'%s' requires 2 arguments", 1199 p->c_name); 1200 p->c_u.c_func2(ctx, argv[1], argv[2]); 1201 argc -= 2, argv += 2; 1202 } else if (p->c_parameter == SPARAM && p->c_u.c_func3) { 1203 p->c_u.c_func3(ctx, *argv, p->c_sparameter); 1204 } else if (p->c_u.c_func) 1205 p->c_u.c_func(ctx, *argv, p->c_parameter); 1206 argc--, argv++; 1207 } 1208 1209 /* 1210 * Do any post argument processing required by the address family. 1211 */ 1212 if (afp->af_postproc != NULL) 1213 afp->af_postproc(ctx, newaddr, getifflags(ctx->ifname, s, true)); 1214 /* 1215 * Do deferred callbacks registered while processing 1216 * command-line arguments. 1217 */ 1218 for (cb = callbacks; cb != NULL; cb = cb->cb_next) 1219 cb->cb_func(ctx, cb->cb_arg); 1220 /* 1221 * Do deferred operations. 1222 */ 1223 if (clearaddr) 1224 delifaddr(ctx, afp); 1225 if (newaddr) 1226 addifaddr(ctx, afp); 1227 1228 close(s); 1229 return(0); 1230 } 1231 1232 static void 1233 setifaddr(if_ctx *ctx, const char *addr, int param __unused) 1234 { 1235 const struct afswtch *afp = ctx->afp; 1236 1237 if (afp->af_getaddr == NULL) 1238 return; 1239 /* 1240 * Delay the ioctl to set the interface addr until flags are all set. 1241 * The address interpretation may depend on the flags, 1242 * and the flags may change when the address is set. 1243 */ 1244 setaddr++; 1245 if (doalias == 0 && afp->af_af != AF_LINK) 1246 clearaddr = 1; 1247 afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR)); 1248 } 1249 1250 static void 1251 settunnel(if_ctx *ctx, const char *src, const char *dst) 1252 { 1253 const struct afswtch *afp = ctx->afp; 1254 struct addrinfo *srcres, *dstres; 1255 int ecode; 1256 1257 if (afp->af_settunnel == NULL) { 1258 warn("address family %s does not support tunnel setup", 1259 afp->af_name); 1260 return; 1261 } 1262 1263 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) 1264 errx(1, "error in parsing address string: %s", 1265 gai_strerror(ecode)); 1266 1267 if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) 1268 errx(1, "error in parsing address string: %s", 1269 gai_strerror(ecode)); 1270 1271 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) 1272 errx(1, 1273 "source and destination address families do not match"); 1274 1275 afp->af_settunnel(ctx, srcres, dstres); 1276 1277 freeaddrinfo(srcres); 1278 freeaddrinfo(dstres); 1279 } 1280 1281 static void 1282 deletetunnel(if_ctx *ctx, const char *vname __unused, int param __unused) 1283 { 1284 struct ifreq ifr = {}; 1285 1286 if (ioctl_ctx_ifr(ctx, SIOCDIFPHYADDR, &ifr) < 0) 1287 err(1, "SIOCDIFPHYADDR"); 1288 } 1289 1290 #ifdef JAIL 1291 static void 1292 setifvnet(if_ctx *ctx, const char *jname, int dummy __unused) 1293 { 1294 struct ifreq ifr = {}; 1295 1296 ifr.ifr_jid = jail_getid(jname); 1297 if (ifr.ifr_jid < 0) 1298 errx(1, "%s", jail_errmsg); 1299 if (ioctl_ctx_ifr(ctx, SIOCSIFVNET, &ifr) < 0) 1300 err(1, "SIOCSIFVNET"); 1301 } 1302 1303 static void 1304 setifrvnet(if_ctx *ctx, const char *jname, int dummy __unused) 1305 { 1306 struct ifreq ifr = {}; 1307 1308 ifr.ifr_jid = jail_getid(jname); 1309 if (ifr.ifr_jid < 0) 1310 errx(1, "%s", jail_errmsg); 1311 if (ioctl_ctx_ifr(ctx, SIOCSIFRVNET, &ifr) < 0) 1312 err(1, "SIOCSIFRVNET(%d, %s)", ifr.ifr_jid, ifr.ifr_name); 1313 } 1314 #endif 1315 1316 static void 1317 setifnetmask(if_ctx *ctx, const char *addr, int dummy __unused) 1318 { 1319 const struct afswtch *afp = ctx->afp; 1320 1321 if (afp->af_getaddr != NULL) { 1322 setmask++; 1323 afp->af_getaddr(addr, MASK); 1324 } 1325 } 1326 1327 static void 1328 setifbroadaddr(if_ctx *ctx, const char *addr, int dummy __unused) 1329 { 1330 const struct afswtch *afp = ctx->afp; 1331 1332 if (afp->af_getaddr != NULL) 1333 afp->af_getaddr(addr, BRDADDR); 1334 } 1335 1336 static void 1337 notealias(if_ctx *ctx, const char *addr __unused, int param) 1338 { 1339 const struct afswtch *afp = ctx->afp; 1340 1341 if (setaddr && doalias == 0 && param < 0) { 1342 if (afp->af_copyaddr != NULL) 1343 afp->af_copyaddr(ctx, RIDADDR, ADDR); 1344 } 1345 doalias = param; 1346 if (param < 0) { 1347 clearaddr = 1; 1348 newaddr = 0; 1349 } else 1350 clearaddr = 0; 1351 } 1352 1353 static void 1354 setifdstaddr(if_ctx *ctx, const char *addr, int param __unused) 1355 { 1356 const struct afswtch *afp = ctx->afp; 1357 1358 if (afp->af_getaddr != NULL) 1359 afp->af_getaddr(addr, DSTADDR); 1360 } 1361 1362 static int 1363 getifflags(const char *ifname, int us, bool err_ok) 1364 { 1365 struct ifreq my_ifr; 1366 int s; 1367 1368 memset(&my_ifr, 0, sizeof(my_ifr)); 1369 (void) strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name)); 1370 if (us < 0) { 1371 if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) 1372 err(1, "socket(family AF_LOCAL,SOCK_DGRAM"); 1373 } else 1374 s = us; 1375 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { 1376 if (!err_ok) { 1377 Perror("ioctl (SIOCGIFFLAGS)"); 1378 exit(1); 1379 } 1380 } 1381 if (us < 0) 1382 close(s); 1383 return ((my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16)); 1384 } 1385 1386 /* 1387 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion 1388 * of the ifreq structure, which may confuse other parts of ifconfig. 1389 * Make a private copy so we can avoid that. 1390 */ 1391 static void 1392 clearifflags(if_ctx *ctx, const char *vname, int value) 1393 { 1394 struct ifreq my_ifr; 1395 int flags; 1396 1397 flags = getifflags(ctx->ifname, ctx->io_s, false); 1398 flags &= ~value; 1399 memset(&my_ifr, 0, sizeof(my_ifr)); 1400 strlcpy(my_ifr.ifr_name, ctx->ifname, sizeof(my_ifr.ifr_name)); 1401 my_ifr.ifr_flags = flags & 0xffff; 1402 my_ifr.ifr_flagshigh = flags >> 16; 1403 if (ioctl(ctx->io_s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) 1404 Perror(vname); 1405 } 1406 1407 static void 1408 setifflags(if_ctx *ctx, const char *vname, int value) 1409 { 1410 struct ifreq my_ifr; 1411 int flags; 1412 1413 flags = getifflags(ctx->ifname, ctx->io_s, false); 1414 flags |= value; 1415 memset(&my_ifr, 0, sizeof(my_ifr)); 1416 strlcpy(my_ifr.ifr_name, ctx->ifname, sizeof(my_ifr.ifr_name)); 1417 my_ifr.ifr_flags = flags & 0xffff; 1418 my_ifr.ifr_flagshigh = flags >> 16; 1419 if (ioctl(ctx->io_s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) 1420 Perror(vname); 1421 } 1422 1423 void 1424 clearifcap(if_ctx *ctx, const char *vname, int value) 1425 { 1426 struct ifreq ifr = {}; 1427 int flags; 1428 1429 if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) { 1430 Perror("ioctl (SIOCGIFCAP)"); 1431 exit(1); 1432 } 1433 flags = ifr.ifr_curcap; 1434 flags &= ~value; 1435 flags &= ifr.ifr_reqcap; 1436 /* Check for no change in capabilities. */ 1437 if (ifr.ifr_curcap == flags) 1438 return; 1439 ifr.ifr_reqcap = flags; 1440 if (ioctl_ctx(ctx, SIOCSIFCAP, &ifr) < 0) 1441 Perror(vname); 1442 } 1443 1444 void 1445 setifcap(if_ctx *ctx, const char *vname, int value) 1446 { 1447 struct ifreq ifr = {}; 1448 int flags; 1449 1450 if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) { 1451 Perror("ioctl (SIOCGIFCAP)"); 1452 exit(1); 1453 } 1454 flags = ifr.ifr_curcap; 1455 flags |= value; 1456 flags &= ifr.ifr_reqcap; 1457 /* Check for no change in capabilities. */ 1458 if (ifr.ifr_curcap == flags) 1459 return; 1460 ifr.ifr_reqcap = flags; 1461 if (ioctl_ctx(ctx, SIOCSIFCAP, &ifr) < 0) 1462 Perror(vname); 1463 } 1464 1465 void 1466 setifcapnv(if_ctx *ctx, const char *vname, const char *arg) 1467 { 1468 nvlist_t *nvcap; 1469 void *buf; 1470 char *marg, *mopt; 1471 size_t nvbuflen; 1472 bool neg; 1473 struct ifreq ifr = {}; 1474 1475 if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) 1476 Perror("ioctl (SIOCGIFCAP)"); 1477 if ((ifr.ifr_curcap & IFCAP_NV) == 0) { 1478 warnx("IFCAP_NV not supported"); 1479 return; /* Not exit() */ 1480 } 1481 1482 marg = strdup(arg); 1483 if (marg == NULL) 1484 Perror("strdup"); 1485 nvcap = nvlist_create(0); 1486 if (nvcap == NULL) 1487 Perror("nvlist_create"); 1488 while ((mopt = strsep(&marg, ",")) != NULL) { 1489 neg = *mopt == '-'; 1490 if (neg) 1491 mopt++; 1492 if (strcmp(mopt, "rxtls") == 0) { 1493 nvlist_add_bool(nvcap, "rxtls4", !neg); 1494 nvlist_add_bool(nvcap, "rxtls6", !neg); 1495 } else { 1496 nvlist_add_bool(nvcap, mopt, !neg); 1497 } 1498 } 1499 buf = nvlist_pack(nvcap, &nvbuflen); 1500 if (buf == NULL) { 1501 errx(1, "nvlist_pack error"); 1502 exit(1); 1503 } 1504 ifr.ifr_cap_nv.buf_length = ifr.ifr_cap_nv.length = nvbuflen; 1505 ifr.ifr_cap_nv.buffer = buf; 1506 if (ioctl_ctx(ctx, SIOCSIFCAPNV, (caddr_t)&ifr) < 0) 1507 Perror(vname); 1508 free(buf); 1509 nvlist_destroy(nvcap); 1510 free(marg); 1511 } 1512 1513 static void 1514 setifmetric(if_ctx *ctx, const char *val, int dummy __unused) 1515 { 1516 struct ifreq ifr = {}; 1517 1518 ifr.ifr_metric = atoi(val); 1519 if (ioctl_ctx_ifr(ctx, SIOCSIFMETRIC, &ifr) < 0) 1520 err(1, "ioctl SIOCSIFMETRIC (set metric)"); 1521 } 1522 1523 static void 1524 setifmtu(if_ctx *ctx, const char *val, int dummy __unused) 1525 { 1526 struct ifreq ifr = {}; 1527 1528 ifr.ifr_mtu = atoi(val); 1529 if (ioctl_ctx_ifr(ctx, SIOCSIFMTU, &ifr) < 0) 1530 err(1, "ioctl SIOCSIFMTU (set mtu)"); 1531 } 1532 1533 static void 1534 setifpcp(if_ctx *ctx, const char *val, int arg __unused) 1535 { 1536 struct ifreq ifr = {}; 1537 u_long ul; 1538 char *endp; 1539 1540 ul = strtoul(val, &endp, 0); 1541 if (*endp != '\0') 1542 errx(1, "invalid value for pcp"); 1543 if (ul > 7) 1544 errx(1, "value for pcp out of range"); 1545 ifr.ifr_lan_pcp = ul; 1546 if (ioctl_ctx_ifr(ctx, SIOCSLANPCP, &ifr) == -1) 1547 err(1, "SIOCSLANPCP"); 1548 } 1549 1550 static void 1551 disableifpcp(if_ctx *ctx, const char *val __unused, int arg __unused) 1552 { 1553 struct ifreq ifr = {}; 1554 1555 ifr.ifr_lan_pcp = IFNET_PCP_NONE; 1556 if (ioctl_ctx_ifr(ctx, SIOCSLANPCP, &ifr) == -1) 1557 err(1, "SIOCSLANPCP"); 1558 } 1559 1560 static void 1561 setifname(if_ctx *ctx, const char *val, int dummy __unused) 1562 { 1563 struct ifreq ifr = {}; 1564 char *newname; 1565 1566 ifr_set_name(&ifr, ctx->ifname); 1567 newname = strdup(val); 1568 if (newname == NULL) 1569 err(1, "no memory to set ifname"); 1570 ifr.ifr_data = newname; 1571 if (ioctl_ctx(ctx, SIOCSIFNAME, (caddr_t)&ifr) < 0) { 1572 free(newname); 1573 err(1, "ioctl SIOCSIFNAME (set name)"); 1574 } 1575 ifname_update(ctx, newname); 1576 free(newname); 1577 } 1578 1579 static void 1580 setifdescr(if_ctx *ctx, const char *val, int dummy __unused) 1581 { 1582 struct ifreq ifr = {}; 1583 char *newdescr; 1584 1585 ifr.ifr_buffer.length = strlen(val) + 1; 1586 if (ifr.ifr_buffer.length == 1) { 1587 ifr.ifr_buffer.buffer = newdescr = NULL; 1588 ifr.ifr_buffer.length = 0; 1589 } else { 1590 newdescr = strdup(val); 1591 ifr.ifr_buffer.buffer = newdescr; 1592 if (newdescr == NULL) { 1593 warn("no memory to set ifdescr"); 1594 return; 1595 } 1596 } 1597 1598 if (ioctl_ctx_ifr(ctx, SIOCSIFDESCR, &ifr) < 0) 1599 err(1, "ioctl SIOCSIFDESCR (set descr)"); 1600 1601 free(newdescr); 1602 } 1603 1604 static void 1605 unsetifdescr(if_ctx *ctx, const char *val __unused, int value __unused) 1606 { 1607 setifdescr(ctx, "", 0); 1608 } 1609 1610 #ifdef WITHOUT_NETLINK 1611 1612 #define IFFBITS \ 1613 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \ 1614 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ 1615 "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP\25STICKYARP" 1616 1617 #define IFCAPBITS \ 1618 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \ 1619 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \ 1620 "\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \ 1621 "\26RXCSUM_IPV6\27TXCSUM_IPV6\31TXRTLMT\32HWRXTSTMP\33NOMAP\34TXTLS4\35TXTLS6" \ 1622 "\36VXLAN_HWCSUM\37VXLAN_HWTSO\40TXTLS_RTLMT" 1623 1624 static void 1625 print_ifcap_nv(if_ctx *ctx) 1626 { 1627 struct ifreq ifr = {}; 1628 nvlist_t *nvcap; 1629 const char *nvname; 1630 void *buf, *cookie; 1631 bool first, val; 1632 int type; 1633 1634 buf = malloc(IFR_CAP_NV_MAXBUFSIZE); 1635 if (buf == NULL) 1636 Perror("malloc"); 1637 ifr.ifr_cap_nv.buffer = buf; 1638 ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE; 1639 if (ioctl_ctx_ifr(ctx, SIOCGIFCAPNV, &ifr) != 0) 1640 Perror("ioctl (SIOCGIFCAPNV)"); 1641 nvcap = nvlist_unpack(ifr.ifr_cap_nv.buffer, 1642 ifr.ifr_cap_nv.length, 0); 1643 if (nvcap == NULL) 1644 Perror("nvlist_unpack"); 1645 printf("\toptions"); 1646 cookie = NULL; 1647 for (first = true;; first = false) { 1648 nvname = nvlist_next(nvcap, &type, &cookie); 1649 if (nvname == NULL) { 1650 printf("\n"); 1651 break; 1652 } 1653 if (type == NV_TYPE_BOOL) { 1654 val = nvlist_get_bool(nvcap, nvname); 1655 if (val) { 1656 printf("%c%s", 1657 first ? ' ' : ',', nvname); 1658 } 1659 } 1660 } 1661 if (ctx->args->supmedia) { 1662 printf("\tcapabilities"); 1663 cookie = NULL; 1664 for (first = true;; first = false) { 1665 nvname = nvlist_next(nvcap, &type, 1666 &cookie); 1667 if (nvname == NULL) { 1668 printf("\n"); 1669 break; 1670 } 1671 if (type == NV_TYPE_BOOL) 1672 printf("%c%s", first ? ' ' : 1673 ',', nvname); 1674 } 1675 } 1676 nvlist_destroy(nvcap); 1677 free(buf); 1678 1679 if (ioctl_ctx(ctx, SIOCGIFCAP, (caddr_t)&ifr) != 0) 1680 Perror("ioctl (SIOCGIFCAP)"); 1681 } 1682 1683 static void 1684 print_ifcap(if_ctx *ctx) 1685 { 1686 struct ifreq ifr = {}; 1687 1688 if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) != 0) 1689 return; 1690 1691 if ((ifr.ifr_curcap & IFCAP_NV) != 0) 1692 print_ifcap_nv(ctx); 1693 else { 1694 printb("\toptions", ifr.ifr_curcap, IFCAPBITS); 1695 putchar('\n'); 1696 if (ctx->args->supmedia && ifr.ifr_reqcap != 0) { 1697 printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); 1698 putchar('\n'); 1699 } 1700 } 1701 } 1702 #endif 1703 1704 void 1705 print_ifstatus(if_ctx *ctx) 1706 { 1707 struct ifstat ifs; 1708 1709 strlcpy(ifs.ifs_name, ctx->ifname, sizeof ifs.ifs_name); 1710 if (ioctl_ctx(ctx, SIOCGIFSTATUS, &ifs) == 0) 1711 printf("%s", ifs.ascii); 1712 } 1713 1714 void 1715 print_metric(if_ctx *ctx) 1716 { 1717 struct ifreq ifr = {}; 1718 1719 if (ioctl_ctx_ifr(ctx, SIOCGIFMETRIC, &ifr) != -1) 1720 printf(" metric %d", ifr.ifr_metric); 1721 } 1722 1723 #ifdef WITHOUT_NETLINK 1724 static void 1725 print_mtu(if_ctx *ctx) 1726 { 1727 struct ifreq ifr = {}; 1728 1729 if (ioctl_ctx_ifr(ctx, SIOCGIFMTU, &ifr) != -1) 1730 printf(" mtu %d", ifr.ifr_mtu); 1731 } 1732 1733 static void 1734 print_description(if_ctx *ctx) 1735 { 1736 struct ifreq ifr = {}; 1737 1738 ifr_set_name(&ifr, ctx->ifname); 1739 for (;;) { 1740 if ((descr = reallocf(descr, descrlen)) != NULL) { 1741 ifr.ifr_buffer.buffer = descr; 1742 ifr.ifr_buffer.length = descrlen; 1743 if (ioctl_ctx(ctx, SIOCGIFDESCR, &ifr) == 0) { 1744 if (ifr.ifr_buffer.buffer == descr) { 1745 if (strlen(descr) > 0) 1746 printf("\tdescription: %s\n", 1747 descr); 1748 } else if (ifr.ifr_buffer.length > descrlen) { 1749 descrlen = ifr.ifr_buffer.length; 1750 continue; 1751 } 1752 } 1753 } else 1754 warn("unable to allocate memory for interface" 1755 "description"); 1756 break; 1757 } 1758 } 1759 1760 /* 1761 * Print the status of the interface. If an address family was 1762 * specified, show only it; otherwise, show them all. 1763 */ 1764 static void 1765 status(if_ctx *ctx, const struct sockaddr_dl *sdl __unused, struct ifaddrs *ifa) 1766 { 1767 struct ifaddrs *ift; 1768 int s, old_s; 1769 struct ifconfig_args *args = ctx->args; 1770 bool allfamilies = args->afp == NULL; 1771 struct ifreq ifr = {}; 1772 1773 if (args->afp == NULL) 1774 ifr.ifr_addr.sa_family = AF_LOCAL; 1775 else 1776 ifr.ifr_addr.sa_family = 1777 args->afp->af_af == AF_LINK ? AF_LOCAL : args->afp->af_af; 1778 1779 s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); 1780 if (s < 0) 1781 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); 1782 old_s = ctx->io_s; 1783 ctx->io_s = s; 1784 1785 printf("%s: ", ctx->ifname); 1786 printb("flags", ifa->ifa_flags, IFFBITS); 1787 print_metric(ctx); 1788 print_mtu(ctx); 1789 putchar('\n'); 1790 1791 print_description(ctx); 1792 1793 print_ifcap(ctx); 1794 1795 tunnel_status(ctx); 1796 1797 for (ift = ifa; ift != NULL; ift = ift->ifa_next) { 1798 if (ift->ifa_addr == NULL) 1799 continue; 1800 if (strcmp(ifa->ifa_name, ift->ifa_name) != 0) 1801 continue; 1802 if (allfamilies) { 1803 const struct afswtch *p; 1804 p = af_getbyfamily(ift->ifa_addr->sa_family); 1805 if (p != NULL && p->af_status != NULL) 1806 p->af_status(ctx, ift); 1807 } else if (args->afp->af_af == ift->ifa_addr->sa_family) 1808 args->afp->af_status(ctx, ift); 1809 } 1810 #if 0 1811 if (allfamilies || afp->af_af == AF_LINK) { 1812 const struct afswtch *lafp; 1813 1814 /* 1815 * Hack; the link level address is received separately 1816 * from the routing information so any address is not 1817 * handled above. Cobble together an entry and invoke 1818 * the status method specially. 1819 */ 1820 lafp = af_getbyname("lladdr"); 1821 if (lafp != NULL) { 1822 info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl; 1823 lafp->af_status(s, &info); 1824 } 1825 } 1826 #endif 1827 if (allfamilies) 1828 af_other_status(ctx); 1829 else if (args->afp->af_other_status != NULL) 1830 args->afp->af_other_status(ctx); 1831 1832 print_ifstatus(ctx); 1833 if (args->verbose > 0) 1834 sfp_status(ctx); 1835 1836 close(s); 1837 ctx->io_s = old_s; 1838 return; 1839 } 1840 #endif 1841 1842 void 1843 tunnel_status(if_ctx *ctx) 1844 { 1845 af_all_tunnel_status(ctx); 1846 } 1847 1848 static void 1849 Perrorc(const char *cmd, int error) 1850 { 1851 switch (errno) { 1852 1853 case ENXIO: 1854 errx(1, "%s: no such interface", cmd); 1855 break; 1856 1857 case EPERM: 1858 errx(1, "%s: permission denied", cmd); 1859 break; 1860 1861 default: 1862 errc(1, error, "%s", cmd); 1863 } 1864 } 1865 1866 void 1867 Perror(const char *cmd) 1868 { 1869 Perrorc(cmd, errno); 1870 } 1871 1872 /* 1873 * Print a value a la the %b format of the kernel's printf 1874 */ 1875 void 1876 printb(const char *s, unsigned v, const char *bits) 1877 { 1878 int i, any = 0; 1879 char c; 1880 1881 if (bits && *bits == 8) 1882 printf("%s=%o", s, v); 1883 else 1884 printf("%s=%x", s, v); 1885 if (bits) { 1886 bits++; 1887 putchar('<'); 1888 while ((i = *bits++) != '\0') { 1889 if (v & (1u << (i-1))) { 1890 if (any) 1891 putchar(','); 1892 any = 1; 1893 for (; (c = *bits) > 32; bits++) 1894 putchar(c); 1895 } else 1896 for (; *bits > 32; bits++) 1897 ; 1898 } 1899 putchar('>'); 1900 } 1901 } 1902 1903 void 1904 print_vhid(const struct ifaddrs *ifa) 1905 { 1906 struct if_data *ifd; 1907 1908 if (ifa->ifa_data == NULL) 1909 return; 1910 1911 ifd = ifa->ifa_data; 1912 if (ifd->ifi_vhid == 0) 1913 return; 1914 1915 printf(" vhid %d", ifd->ifi_vhid); 1916 } 1917 1918 void 1919 ifmaybeload(struct ifconfig_args *args, const char *name) 1920 { 1921 #define MOD_PREFIX_LEN 3 /* "if_" */ 1922 struct module_stat mstat; 1923 int fileid, modid; 1924 char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp; 1925 const char *cp; 1926 struct module_map_entry *mme; 1927 bool found; 1928 1929 /* loading suppressed by the user */ 1930 if (args->noload) 1931 return; 1932 1933 /* trim the interface number off the end */ 1934 strlcpy(ifname, name, sizeof(ifname)); 1935 dp = ifname + strlen(ifname) - 1; 1936 for (; dp > ifname; dp--) { 1937 if (isdigit(*dp)) 1938 *dp = '\0'; 1939 else 1940 break; 1941 } 1942 1943 /* Either derive it from the map or guess otherwise */ 1944 *ifkind = '\0'; 1945 found = false; 1946 for (unsigned i = 0; i < nitems(module_map); ++i) { 1947 mme = &module_map[i]; 1948 if (strcmp(mme->ifname, ifname) == 0) { 1949 strlcpy(ifkind, mme->kldname, sizeof(ifkind)); 1950 found = true; 1951 break; 1952 } 1953 } 1954 1955 /* We didn't have an alias for it... we'll guess. */ 1956 if (!found) { 1957 /* turn interface and unit into module name */ 1958 strlcpy(ifkind, "if_", sizeof(ifkind)); 1959 strlcat(ifkind, ifname, sizeof(ifkind)); 1960 } 1961 1962 /* scan files in kernel */ 1963 mstat.version = sizeof(struct module_stat); 1964 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 1965 /* scan modules in file */ 1966 for (modid = kldfirstmod(fileid); modid > 0; 1967 modid = modfnext(modid)) { 1968 if (modstat(modid, &mstat) < 0) 1969 continue; 1970 /* strip bus name if present */ 1971 if ((cp = strchr(mstat.name, '/')) != NULL) { 1972 cp++; 1973 } else { 1974 cp = mstat.name; 1975 } 1976 /* 1977 * Is it already loaded? Don't compare with ifname if 1978 * we were specifically told which kld to use. Doing 1979 * so could lead to conflicts not trivially solved. 1980 */ 1981 if ((!found && strcmp(ifname, cp) == 0) || 1982 strcmp(ifkind, cp) == 0) 1983 return; 1984 } 1985 } 1986 1987 /* 1988 * Try to load the module. But ignore failures, because ifconfig can't 1989 * infer the names of all drivers (eg mlx4en(4)). 1990 */ 1991 (void) kldload(ifkind); 1992 } 1993 1994 static struct cmd basic_cmds[] = { 1995 DEF_CMD("up", IFF_UP, setifflags), 1996 DEF_CMD("down", IFF_UP, clearifflags), 1997 DEF_CMD("arp", IFF_NOARP, clearifflags), 1998 DEF_CMD("-arp", IFF_NOARP, setifflags), 1999 DEF_CMD("debug", IFF_DEBUG, setifflags), 2000 DEF_CMD("-debug", IFF_DEBUG, clearifflags), 2001 DEF_CMD_ARG("description", setifdescr), 2002 DEF_CMD_ARG("descr", setifdescr), 2003 DEF_CMD("-description", 0, unsetifdescr), 2004 DEF_CMD("-descr", 0, unsetifdescr), 2005 DEF_CMD("promisc", IFF_PPROMISC, setifflags), 2006 DEF_CMD("-promisc", IFF_PPROMISC, clearifflags), 2007 DEF_CMD("add", IFF_UP, notealias), 2008 DEF_CMD("alias", IFF_UP, notealias), 2009 DEF_CMD("-alias", -IFF_UP, notealias), 2010 DEF_CMD("delete", -IFF_UP, notealias), 2011 DEF_CMD("remove", -IFF_UP, notealias), 2012 #ifdef notdef 2013 #define EN_SWABIPS 0x1000 2014 DEF_CMD("swabips", EN_SWABIPS, setifflags), 2015 DEF_CMD("-swabips", EN_SWABIPS, clearifflags), 2016 #endif 2017 DEF_CMD_ARG("netmask", setifnetmask), 2018 DEF_CMD_ARG("metric", setifmetric), 2019 DEF_CMD_ARG("broadcast", setifbroadaddr), 2020 DEF_CMD_ARG2("tunnel", settunnel), 2021 DEF_CMD("-tunnel", 0, deletetunnel), 2022 DEF_CMD("deletetunnel", 0, deletetunnel), 2023 #ifdef JAIL 2024 DEF_CMD_ARG("vnet", setifvnet), 2025 DEF_CMD_ARG("-vnet", setifrvnet), 2026 #endif 2027 DEF_CMD("link0", IFF_LINK0, setifflags), 2028 DEF_CMD("-link0", IFF_LINK0, clearifflags), 2029 DEF_CMD("link1", IFF_LINK1, setifflags), 2030 DEF_CMD("-link1", IFF_LINK1, clearifflags), 2031 DEF_CMD("link2", IFF_LINK2, setifflags), 2032 DEF_CMD("-link2", IFF_LINK2, clearifflags), 2033 DEF_CMD("monitor", IFF_MONITOR, setifflags), 2034 DEF_CMD("-monitor", IFF_MONITOR, clearifflags), 2035 DEF_CMD("mextpg", IFCAP_MEXTPG, setifcap), 2036 DEF_CMD("-mextpg", IFCAP_MEXTPG, clearifcap), 2037 DEF_CMD("staticarp", IFF_STATICARP, setifflags), 2038 DEF_CMD("-staticarp", IFF_STATICARP, clearifflags), 2039 DEF_CMD("stickyarp", IFF_STICKYARP, setifflags), 2040 DEF_CMD("-stickyarp", IFF_STICKYARP, clearifflags), 2041 DEF_CMD("rxcsum6", IFCAP_RXCSUM_IPV6, setifcap), 2042 DEF_CMD("-rxcsum6", IFCAP_RXCSUM_IPV6, clearifcap), 2043 DEF_CMD("txcsum6", IFCAP_TXCSUM_IPV6, setifcap), 2044 DEF_CMD("-txcsum6", IFCAP_TXCSUM_IPV6, clearifcap), 2045 DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), 2046 DEF_CMD("-rxcsum", IFCAP_RXCSUM, clearifcap), 2047 DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), 2048 DEF_CMD("-txcsum", IFCAP_TXCSUM, clearifcap), 2049 DEF_CMD("netcons", IFCAP_NETCONS, setifcap), 2050 DEF_CMD("-netcons", IFCAP_NETCONS, clearifcap), 2051 DEF_CMD_ARG("pcp", setifpcp), 2052 DEF_CMD("-pcp", 0, disableifpcp), 2053 DEF_CMD("polling", IFCAP_POLLING, setifcap), 2054 DEF_CMD("-polling", IFCAP_POLLING, clearifcap), 2055 DEF_CMD("tso6", IFCAP_TSO6, setifcap), 2056 DEF_CMD("-tso6", IFCAP_TSO6, clearifcap), 2057 DEF_CMD("tso4", IFCAP_TSO4, setifcap), 2058 DEF_CMD("-tso4", IFCAP_TSO4, clearifcap), 2059 DEF_CMD("tso", IFCAP_TSO, setifcap), 2060 DEF_CMD("-tso", IFCAP_TSO, clearifcap), 2061 DEF_CMD("toe", IFCAP_TOE, setifcap), 2062 DEF_CMD("-toe", IFCAP_TOE, clearifcap), 2063 DEF_CMD("lro", IFCAP_LRO, setifcap), 2064 DEF_CMD("-lro", IFCAP_LRO, clearifcap), 2065 DEF_CMD("txtls", IFCAP_TXTLS, setifcap), 2066 DEF_CMD("-txtls", IFCAP_TXTLS, clearifcap), 2067 DEF_CMD_SARG("rxtls", IFCAP2_RXTLS4_NAME "," IFCAP2_RXTLS6_NAME, 2068 setifcapnv), 2069 DEF_CMD_SARG("-rxtls", "-"IFCAP2_RXTLS4_NAME ",-" IFCAP2_RXTLS6_NAME, 2070 setifcapnv), 2071 DEF_CMD("wol", IFCAP_WOL, setifcap), 2072 DEF_CMD("-wol", IFCAP_WOL, clearifcap), 2073 DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap), 2074 DEF_CMD("-wol_ucast", IFCAP_WOL_UCAST, clearifcap), 2075 DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap), 2076 DEF_CMD("-wol_mcast", IFCAP_WOL_MCAST, clearifcap), 2077 DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap), 2078 DEF_CMD("-wol_magic", IFCAP_WOL_MAGIC, clearifcap), 2079 DEF_CMD("txrtlmt", IFCAP_TXRTLMT, setifcap), 2080 DEF_CMD("-txrtlmt", IFCAP_TXRTLMT, clearifcap), 2081 DEF_CMD("txtlsrtlmt", IFCAP_TXTLS_RTLMT, setifcap), 2082 DEF_CMD("-txtlsrtlmt", IFCAP_TXTLS_RTLMT, clearifcap), 2083 DEF_CMD("hwrxtstmp", IFCAP_HWRXTSTMP, setifcap), 2084 DEF_CMD("-hwrxtstmp", IFCAP_HWRXTSTMP, clearifcap), 2085 DEF_CMD("normal", IFF_LINK0, clearifflags), 2086 DEF_CMD("compress", IFF_LINK0, setifflags), 2087 DEF_CMD("noicmp", IFF_LINK1, setifflags), 2088 DEF_CMD_ARG("mtu", setifmtu), 2089 DEF_CMD_ARG("name", setifname), 2090 }; 2091 2092 static __constructor void 2093 ifconfig_ctor(void) 2094 { 2095 size_t i; 2096 2097 for (i = 0; i < nitems(basic_cmds); i++) 2098 cmd_register(&basic_cmds[i]); 2099 } 2100