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