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