1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char copyright[] = 36 "@(#) Copyright (c) 1983, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; 43 #endif 44 static const char rcsid[] = 45 "$FreeBSD$"; 46 #endif /* not lint */ 47 48 #include <sys/param.h> 49 #include <sys/ioctl.h> 50 #include <sys/socket.h> 51 #include <sys/sysctl.h> 52 #include <sys/time.h> 53 #include <sys/module.h> 54 #include <sys/linker.h> 55 56 #include <net/ethernet.h> 57 #include <net/if.h> 58 #include <net/if_var.h> 59 #include <net/if_dl.h> 60 #include <net/if_types.h> 61 #include <net/route.h> 62 63 /* IP */ 64 #include <netinet/in.h> 65 #include <netinet/in_var.h> 66 #include <arpa/inet.h> 67 #include <netdb.h> 68 69 #ifdef INET6 70 #include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */ 71 #endif 72 73 /* IPX */ 74 #define IPXIP 75 #define IPTUNNEL 76 #include <netipx/ipx.h> 77 #include <netipx/ipx_if.h> 78 79 /* Appletalk */ 80 #include <netatalk/at.h> 81 82 /* XNS */ 83 #ifdef NS 84 #define NSIP 85 #include <netns/ns.h> 86 #include <netns/ns_if.h> 87 #endif 88 89 /* OSI */ 90 91 #include <ctype.h> 92 #include <err.h> 93 #include <errno.h> 94 #include <fcntl.h> 95 #include <stdio.h> 96 #include <stdlib.h> 97 #include <string.h> 98 #include <unistd.h> 99 100 #include "ifconfig.h" 101 102 /* wrapper for KAME-special getnameinfo() */ 103 #ifndef NI_WITHSCOPEID 104 #define NI_WITHSCOPEID 0 105 #endif 106 107 struct ifreq ifr, ridreq; 108 struct ifaliasreq addreq; 109 #ifdef INET6 110 struct in6_ifreq in6_ridreq; 111 struct in6_aliasreq in6_addreq = 112 { { 0 }, 113 { 0 }, 114 { 0 }, 115 { 0 }, 116 0, 117 { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } }; 118 #endif 119 struct sockaddr_in netmask; 120 struct netrange at_nr; /* AppleTalk net range */ 121 122 char name[32]; 123 int flags; 124 int metric; 125 int mtu; 126 int setaddr; 127 int setipdst; 128 int doalias; 129 int clearaddr; 130 int newaddr = 1; 131 #ifdef INET6 132 static int ip6lifetime; 133 #endif 134 135 struct afswtch; 136 137 int supmedia = 0; 138 int listcloners = 0; 139 140 #ifdef INET6 141 char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ 142 #endif 143 144 void Perror __P((const char *cmd)); 145 void checkatrange __P((struct sockaddr_at *)); 146 int ifconfig __P((int argc, char *const *argv, const struct afswtch *afp)); 147 void notealias __P((const char *, int, int, const struct afswtch *afp)); 148 void list_cloners __P((void)); 149 void printb __P((const char *s, unsigned value, const char *bits)); 150 void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); 151 void status __P((const struct afswtch *afp, int addrcount, 152 struct sockaddr_dl *sdl, struct if_msghdr *ifm, 153 struct ifa_msghdr *ifam)); 154 void tunnel_status __P((int s)); 155 void usage __P((void)); 156 void ifmaybeload __P((char *name)); 157 158 #ifdef INET6 159 void in6_fillscopeid __P((struct sockaddr_in6 *sin6)); 160 int prefix __P((void *, int)); 161 static char *sec2str __P((time_t)); 162 int explicit_prefix = 0; 163 #endif 164 165 typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp)); 166 typedef void c_func2 __P((const char *arg, const char *arg2, int s, const struct afswtch *afp)); 167 c_func setatphase, setatrange; 168 c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask; 169 c_func2 settunnel; 170 c_func deletetunnel; 171 #ifdef INET6 172 c_func setifprefixlen; 173 c_func setip6flags; 174 c_func setip6pltime; 175 c_func setip6vltime; 176 c_func2 setip6lifetime; 177 #endif 178 c_func setifipdst; 179 c_func setifflags, setifmetric, setifmtu, setiflladdr; 180 c_func clone_destroy; 181 182 183 void clone_create __P((void)); 184 185 186 #define NEXTARG 0xffffff 187 #define NEXTARG2 0xfffffe 188 189 const 190 struct cmd { 191 const char *c_name; 192 int c_parameter; /* NEXTARG means next argv */ 193 void (*c_func) __P((const char *, int, int, const struct afswtch *afp)); 194 void (*c_func2) __P((const char *, const char *, int, const struct afswtch *afp)); 195 } cmds[] = { 196 { "up", IFF_UP, setifflags } , 197 { "down", -IFF_UP, setifflags }, 198 { "arp", -IFF_NOARP, setifflags }, 199 { "-arp", IFF_NOARP, setifflags }, 200 { "debug", IFF_DEBUG, setifflags }, 201 { "-debug", -IFF_DEBUG, setifflags }, 202 { "add", IFF_UP, notealias }, 203 { "alias", IFF_UP, notealias }, 204 { "-alias", -IFF_UP, notealias }, 205 { "delete", -IFF_UP, notealias }, 206 { "remove", -IFF_UP, notealias }, 207 #ifdef notdef 208 #define EN_SWABIPS 0x1000 209 { "swabips", EN_SWABIPS, setifflags }, 210 { "-swabips", -EN_SWABIPS, setifflags }, 211 #endif 212 { "netmask", NEXTARG, setifnetmask }, 213 #ifdef INET6 214 { "prefixlen", NEXTARG, setifprefixlen }, 215 { "anycast", IN6_IFF_ANYCAST, setip6flags }, 216 { "tentative", IN6_IFF_TENTATIVE, setip6flags }, 217 { "-tentative", -IN6_IFF_TENTATIVE, setip6flags }, 218 { "deprecated", IN6_IFF_DEPRECATED, setip6flags }, 219 { "-deprecated", -IN6_IFF_DEPRECATED, setip6flags }, 220 { "autoconf", IN6_IFF_AUTOCONF, setip6flags }, 221 { "-autoconf", -IN6_IFF_AUTOCONF, setip6flags }, 222 { "pltime", NEXTARG, setip6pltime }, 223 { "vltime", NEXTARG, setip6vltime }, 224 #endif 225 { "range", NEXTARG, setatrange }, 226 { "phase", NEXTARG, setatphase }, 227 { "metric", NEXTARG, setifmetric }, 228 { "broadcast", NEXTARG, setifbroadaddr }, 229 { "ipdst", NEXTARG, setifipdst }, 230 { "tunnel", NEXTARG2, NULL, settunnel }, 231 { "deletetunnel", 0, deletetunnel }, 232 { "link0", IFF_LINK0, setifflags }, 233 { "-link0", -IFF_LINK0, setifflags }, 234 { "link1", IFF_LINK1, setifflags }, 235 { "-link1", -IFF_LINK1, setifflags }, 236 { "link2", IFF_LINK2, setifflags }, 237 { "-link2", -IFF_LINK2, setifflags }, 238 #ifdef USE_IF_MEDIA 239 { "media", NEXTARG, setmedia }, 240 { "mediaopt", NEXTARG, setmediaopt }, 241 { "-mediaopt", NEXTARG, unsetmediaopt }, 242 #endif 243 #ifdef USE_VLANS 244 { "vlan", NEXTARG, setvlantag }, 245 { "vlandev", NEXTARG, setvlandev }, 246 { "-vlandev", NEXTARG, unsetvlandev }, 247 #endif 248 #if 0 249 /* XXX `create' special-cased below */ 250 {"create", 0, clone_create }, 251 {"plumb", 0, clone_create }, 252 #endif 253 {"destroy", 0, clone_destroy }, 254 {"unplumb", 0, clone_destroy }, 255 #ifdef USE_IEEE80211 256 { "ssid", NEXTARG, set80211ssid }, 257 { "nwid", NEXTARG, set80211ssid }, 258 { "stationname", NEXTARG, set80211stationname }, 259 { "station", NEXTARG, set80211stationname }, /* BSD/OS */ 260 { "channel", NEXTARG, set80211channel }, 261 { "authmode", NEXTARG, set80211authmode }, 262 { "powersavemode", NEXTARG, set80211powersavemode }, 263 { "powersave", 1, set80211powersave }, 264 { "-powersave", 0, set80211powersave }, 265 { "powersavesleep", NEXTARG, set80211powersavesleep }, 266 { "wepmode", NEXTARG, set80211wepmode }, 267 { "wep", 1, set80211wep }, 268 { "-wep", 0, set80211wep }, 269 { "weptxkey", NEXTARG, set80211weptxkey }, 270 { "wepkey", NEXTARG, set80211wepkey }, 271 { "nwkey", NEXTARG, set80211nwkey }, /* NetBSD */ 272 { "-nwkey", 0, set80211wep }, /* NetBSD */ 273 #endif 274 { "normal", -IFF_LINK0, setifflags }, 275 { "compress", IFF_LINK0, setifflags }, 276 { "noicmp", IFF_LINK1, setifflags }, 277 { "mtu", NEXTARG, setifmtu }, 278 { "lladdr", NEXTARG, setiflladdr }, 279 { 0, 0, setifaddr }, 280 { 0, 0, setifdstaddr }, 281 }; 282 283 /* 284 * XNS support liberally adapted from code written at the University of 285 * Maryland principally by James O'Toole and Chris Torek. 286 */ 287 typedef void af_status __P((int, struct rt_addrinfo *)); 288 typedef void af_getaddr __P((const char *, int)); 289 typedef void af_getprefix __P((const char *, int)); 290 291 af_status in_status, ipx_status, at_status, ether_status; 292 af_getaddr in_getaddr, ipx_getaddr, at_getaddr, ether_getaddr; 293 294 #ifdef INET6 295 af_status in6_status; 296 af_getaddr in6_getaddr; 297 af_getprefix in6_getprefix; 298 #endif /*INET6*/ 299 #ifdef NS 300 af_status xns_status; 301 af_getaddr xns_getaddr; 302 #endif 303 304 /* Known address families */ 305 const 306 struct afswtch { 307 const char *af_name; 308 short af_af; 309 af_status *af_status; 310 af_getaddr *af_getaddr; 311 af_getprefix *af_getprefix; 312 u_long af_difaddr; 313 u_long af_aifaddr; 314 caddr_t af_ridreq; 315 caddr_t af_addreq; 316 } afs[] = { 317 #define C(x) ((caddr_t) &x) 318 { "inet", AF_INET, in_status, in_getaddr, NULL, 319 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, 320 #ifdef INET6 321 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix, 322 SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, 323 C(in6_ridreq), C(in6_addreq) }, 324 #endif /*INET6*/ 325 { "ipx", AF_IPX, ipx_status, ipx_getaddr, NULL, 326 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, 327 { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL, 328 SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) }, 329 #ifdef NS 330 { "ns", AF_NS, xns_status, xns_getaddr, NULL, 331 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, 332 #endif 333 { "ether", AF_LINK, ether_status, ether_getaddr, NULL, 334 0, SIOCSIFLLADDR, NULL, C(ridreq) }, 335 #if 0 /* XXX conflicts with the media command */ 336 #ifdef USE_IF_MEDIA 337 { "media", AF_UNSPEC, media_status, NULL, NULL, }, /* XXX not real!! */ 338 #endif 339 #ifdef USE_VLANS 340 { "vlan", AF_UNSPEC, vlan_status, NULL, NULL, }, /* XXX not real!! */ 341 #endif 342 #ifdef USE_IEEE80211 343 { "ieee80211", AF_UNSPEC, ieee80211_status, NULL, NULL, }, /* XXX not real!! */ 344 #endif 345 #endif 346 { 0, 0, 0, 0 } 347 }; 348 349 /* 350 * Expand the compacted form of addresses as returned via the 351 * configuration read via sysctl(). 352 */ 353 354 #define ROUNDUP(a) \ 355 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 356 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 357 358 void 359 rt_xaddrs(cp, cplim, rtinfo) 360 caddr_t cp, cplim; 361 struct rt_addrinfo *rtinfo; 362 { 363 struct sockaddr *sa; 364 int i; 365 366 memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); 367 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 368 if ((rtinfo->rti_addrs & (1 << i)) == 0) 369 continue; 370 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 371 ADVANCE(cp, sa); 372 } 373 } 374 375 376 void 377 usage() 378 { 379 #ifndef INET6 380 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 381 "usage: ifconfig interface address_family [address [dest_address]]", 382 " [parameters]", 383 " ifconfig -C", 384 " ifconfig interface create", 385 " ifconfig -a [-d] [-m] [-u] [address_family]", 386 " ifconfig -l [-d] [-u] [address_family]", 387 " ifconfig [-d] [-m] [-u]"); 388 #else 389 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 390 "usage: ifconfig [-L] interface address_family [address [dest_address]]", 391 " [parameters]", 392 " ifconfig -C", 393 " ifconfig interface create", 394 " ifconfig -a [-L] [-d] [-m] [-u] [address_family]", 395 " ifconfig -l [-d] [-u] [address_family]", 396 " ifconfig [-L] [-d] [-m] [-u]"); 397 #endif 398 exit(1); 399 } 400 401 int 402 main(argc, argv) 403 int argc; 404 char *const *argv; 405 { 406 int c; 407 int all, namesonly, downonly, uponly; 408 int foundit = 0, need_nl = 0; 409 const struct afswtch *afp = 0; 410 int addrcount; 411 struct if_msghdr *ifm, *nextifm; 412 struct ifa_msghdr *ifam; 413 struct sockaddr_dl *sdl; 414 char *buf, *lim, *next; 415 416 417 size_t needed; 418 int mib[6]; 419 420 /* Parse leading line options */ 421 all = downonly = uponly = namesonly = 0; 422 while ((c = getopt(argc, argv, "adlmuC" 423 #ifdef INET6 424 "L" 425 #endif 426 )) != -1) { 427 switch (c) { 428 case 'a': /* scan all interfaces */ 429 all++; 430 break; 431 case 'd': /* restrict scan to "down" interfaces */ 432 downonly++; 433 break; 434 case 'l': /* scan interface names only */ 435 namesonly++; 436 break; 437 case 'm': /* show media choices in status */ 438 supmedia = 1; 439 break; 440 case 'u': /* restrict scan to "up" interfaces */ 441 uponly++; 442 break; 443 case 'C': 444 listcloners = 1; 445 break; 446 #ifdef INET6 447 case 'L': 448 ip6lifetime++; /* print IPv6 address lifetime */ 449 break; 450 #endif 451 default: 452 usage(); 453 break; 454 } 455 } 456 argc -= optind; 457 argv += optind; 458 459 if (listcloners) { 460 /* -C must be solitary */ 461 if (all || supmedia || uponly || downonly || namesonly || 462 argc > 0) 463 usage(); 464 465 list_cloners(); 466 exit(0); 467 } 468 469 /* -l cannot be used with -a or -m */ 470 if (namesonly && (all || supmedia)) 471 usage(); 472 473 /* nonsense.. */ 474 if (uponly && downonly) 475 usage(); 476 477 /* no arguments is equivalent to '-a' */ 478 if (!namesonly && argc < 1) 479 all = 1; 480 481 /* -a and -l allow an address family arg to limit the output */ 482 if (all || namesonly) { 483 if (argc > 1) 484 usage(); 485 486 if (argc == 1) { 487 for (afp = afs; afp->af_name; afp++) 488 if (strcmp(afp->af_name, *argv) == 0) { 489 argc--, argv++; 490 break; 491 } 492 if (afp->af_name == NULL) 493 usage(); 494 /* leave with afp non-zero */ 495 } 496 } else { 497 /* not listing, need an argument */ 498 if (argc < 1) 499 usage(); 500 501 strncpy(name, *argv, sizeof(name)); 502 argc--, argv++; 503 504 /* check and maybe load support for this interface */ 505 ifmaybeload(name); 506 507 /* 508 * NOTE: We must special-case the `create' command right 509 * here as we would otherwise fail when trying to find 510 * the interface. 511 */ 512 if (argc > 0 && strcmp(argv[0], "create") == 0) { 513 clone_create(); 514 argc--, argv++; 515 if (argc == 0) 516 exit(0); 517 } 518 } 519 520 /* Check for address family */ 521 if (argc > 0) { 522 for (afp = afs; afp->af_name; afp++) 523 if (strcmp(afp->af_name, *argv) == 0) { 524 argc--, argv++; 525 break; 526 } 527 if (afp->af_name == NULL) 528 afp = NULL; /* not a family, NULL */ 529 } 530 531 mib[0] = CTL_NET; 532 mib[1] = PF_ROUTE; 533 mib[2] = 0; 534 mib[3] = 0; /* address family */ 535 mib[4] = NET_RT_IFLIST; 536 mib[5] = 0; 537 538 /* if particular family specified, only ask about it */ 539 if (afp) 540 mib[3] = afp->af_af; 541 542 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 543 errx(1, "iflist-sysctl-estimate"); 544 if ((buf = malloc(needed)) == NULL) 545 errx(1, "malloc"); 546 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 547 errx(1, "actual retrieval of interface table"); 548 lim = buf + needed; 549 550 next = buf; 551 while (next < lim) { 552 553 ifm = (struct if_msghdr *)next; 554 555 if (ifm->ifm_type == RTM_IFINFO) { 556 sdl = (struct sockaddr_dl *)(ifm + 1); 557 flags = ifm->ifm_flags; 558 } else { 559 fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n"); 560 fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, 561 ifm->ifm_type); 562 fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen); 563 fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, 564 lim); 565 exit (1); 566 } 567 568 next += ifm->ifm_msglen; 569 ifam = NULL; 570 addrcount = 0; 571 while (next < lim) { 572 573 nextifm = (struct if_msghdr *)next; 574 575 if (nextifm->ifm_type != RTM_NEWADDR) 576 break; 577 578 if (ifam == NULL) 579 ifam = (struct ifa_msghdr *)nextifm; 580 581 addrcount++; 582 next += nextifm->ifm_msglen; 583 } 584 585 if (all || namesonly) { 586 if (uponly) 587 if ((flags & IFF_UP) == 0) 588 continue; /* not up */ 589 if (downonly) 590 if (flags & IFF_UP) 591 continue; /* not down */ 592 strncpy(name, sdl->sdl_data, sdl->sdl_nlen); 593 name[sdl->sdl_nlen] = '\0'; 594 if (namesonly) { 595 if (afp == NULL || 596 afp->af_status != ether_status || 597 sdl->sdl_type == IFT_ETHER) { 598 if (need_nl) 599 putchar(' '); 600 fputs(name, stdout); 601 need_nl++; 602 } 603 continue; 604 } 605 } else { 606 if (strlen(name) != sdl->sdl_nlen) 607 continue; /* not same len */ 608 if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0) 609 continue; /* not same name */ 610 } 611 612 if (argc > 0) 613 ifconfig(argc, argv, afp); 614 else 615 status(afp, addrcount, sdl, ifm, ifam); 616 617 if (all == 0 && namesonly == 0) { 618 foundit++; /* flag it as 'done' */ 619 break; 620 } 621 } 622 free(buf); 623 624 if (namesonly && need_nl > 0) 625 putchar('\n'); 626 627 if (all == 0 && namesonly == 0 && foundit == 0) 628 errx(1, "interface %s does not exist", name); 629 630 631 exit (0); 632 } 633 634 635 int 636 ifconfig(argc, argv, afp) 637 int argc; 638 char *const *argv; 639 const struct afswtch *afp; 640 { 641 int s; 642 643 if (afp == NULL) 644 afp = &afs[0]; 645 ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; 646 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); 647 648 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) 649 err(1, "socket"); 650 651 while (argc > 0) { 652 register const struct cmd *p; 653 654 for (p = cmds; p->c_name; p++) 655 if (strcmp(*argv, p->c_name) == 0) 656 break; 657 if (p->c_name == 0 && setaddr) 658 p++; /* got src, do dst */ 659 if (p->c_func || p->c_func2) { 660 if (p->c_parameter == NEXTARG) { 661 if (argv[1] == NULL) 662 errx(1, "'%s' requires argument", 663 p->c_name); 664 (*p->c_func)(argv[1], 0, s, afp); 665 argc--, argv++; 666 } else if (p->c_parameter == NEXTARG2) { 667 if (argc < 3) 668 errx(1, "'%s' requires 2 arguments", 669 p->c_name); 670 (*p->c_func2)(argv[1], argv[2], s, afp); 671 argc -= 2, argv += 2; 672 } else 673 (*p->c_func)(*argv, p->c_parameter, s, afp); 674 } 675 argc--, argv++; 676 } 677 #ifdef INET6 678 if (ifr.ifr_addr.sa_family == AF_INET6 && explicit_prefix == 0) { 679 /* Aggregatable address architecture defines all prefixes 680 are 64. So, it is convenient to set prefixlen to 64 if 681 it is not specified. */ 682 setifprefixlen("64", 0, s, afp); 683 /* in6_getprefix("64", MASK) if MASK is available here... */ 684 } 685 #endif 686 if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) { 687 struct ipxip_req rq; 688 int size = sizeof(rq); 689 690 rq.rq_ipx = addreq.ifra_addr; 691 rq.rq_ip = addreq.ifra_dstaddr; 692 693 if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0) 694 Perror("Encapsulation Routing"); 695 } 696 if (ifr.ifr_addr.sa_family == AF_APPLETALK) 697 checkatrange((struct sockaddr_at *) &addreq.ifra_addr); 698 #ifdef NS 699 if (setipdst && ifr.ifr_addr.sa_family == AF_NS) { 700 struct nsip_req rq; 701 int size = sizeof(rq); 702 703 rq.rq_ns = addreq.ifra_addr; 704 rq.rq_ip = addreq.ifra_dstaddr; 705 706 if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0) 707 Perror("Encapsulation Routing"); 708 } 709 #endif 710 if (clearaddr) { 711 if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { 712 warnx("interface %s cannot change %s addresses!", 713 name, afp->af_name); 714 clearaddr = NULL; 715 } 716 } 717 if (clearaddr) { 718 int ret; 719 strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name); 720 if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) { 721 if (errno == EADDRNOTAVAIL && (doalias >= 0)) { 722 /* means no previous address for interface */ 723 } else 724 Perror("ioctl (SIOCDIFADDR)"); 725 } 726 } 727 if (newaddr) { 728 if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { 729 warnx("interface %s cannot change %s addresses!", 730 name, afp->af_name); 731 newaddr = 0; 732 } 733 } 734 if (newaddr && setaddr) { 735 strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); 736 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) 737 Perror("ioctl (SIOCAIFADDR)"); 738 } 739 close(s); 740 return(0); 741 } 742 #define RIDADDR 0 743 #define ADDR 1 744 #define MASK 2 745 #define DSTADDR 3 746 747 /*ARGSUSED*/ 748 void 749 setifaddr(addr, param, s, afp) 750 const char *addr; 751 int param; 752 int s; 753 const struct afswtch *afp; 754 { 755 if (*afp->af_getaddr == NULL) 756 return; 757 /* 758 * Delay the ioctl to set the interface addr until flags are all set. 759 * The address interpretation may depend on the flags, 760 * and the flags may change when the address is set. 761 */ 762 setaddr++; 763 if (doalias == 0 && afp->af_af != AF_LINK) 764 clearaddr = 1; 765 (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR)); 766 } 767 768 void 769 settunnel(src, dst, s, afp) 770 const char *src, *dst; 771 int s; 772 const struct afswtch *afp; 773 { 774 struct addrinfo hints, *srcres, *dstres; 775 struct ifaliasreq addreq; 776 int ecode; 777 #ifdef INET6 778 struct in6_aliasreq in6_addreq; 779 #endif 780 781 memset(&hints, 0, sizeof(hints)); 782 hints.ai_family = afp->af_af; 783 784 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) 785 errx(1, "error in parsing address string: %s", 786 gai_strerror(ecode)); 787 788 if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) 789 errx(1, "error in parsing address string: %s", 790 gai_strerror(ecode)); 791 792 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) 793 errx(1, 794 "source and destination address families do not match"); 795 796 switch (srcres->ai_addr->sa_family) { 797 case AF_INET: 798 memset(&addreq, 0, sizeof(addreq)); 799 strncpy(addreq.ifra_name, name, IFNAMSIZ); 800 memcpy(&addreq.ifra_addr, srcres->ai_addr, 801 srcres->ai_addr->sa_len); 802 memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, 803 dstres->ai_addr->sa_len); 804 805 if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) 806 warn("SIOCSIFPHYADDR"); 807 break; 808 809 #ifdef INET6 810 case AF_INET6: 811 memset(&in6_addreq, 0, sizeof(in6_addreq)); 812 strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); 813 memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, 814 srcres->ai_addr->sa_len); 815 memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, 816 dstres->ai_addr->sa_len); 817 818 if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0) 819 warn("SIOCSIFPHYADDR_IN6"); 820 break; 821 #endif /* INET6 */ 822 823 default: 824 warn("address family not supported"); 825 } 826 827 freeaddrinfo(srcres); 828 freeaddrinfo(dstres); 829 } 830 831 /* ARGSUSED */ 832 void 833 deletetunnel(vname, param, s, afp) 834 const char *vname; 835 int param; 836 int s; 837 const struct afswtch *afp; 838 { 839 840 if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) 841 err(1, "SIOCDIFPHYADDR"); 842 } 843 844 void 845 setifnetmask(addr, dummy, s, afp) 846 const char *addr; 847 int dummy __unused; 848 int s; 849 const struct afswtch *afp; 850 { 851 if (*afp->af_getaddr == NULL) 852 return; 853 (*afp->af_getaddr)(addr, MASK); 854 } 855 856 #ifdef INET6 857 void 858 setifprefixlen(addr, dummy, s, afp) 859 const char *addr; 860 int dummy __unused; 861 int s; 862 const struct afswtch *afp; 863 { 864 if (*afp->af_getprefix) 865 (*afp->af_getprefix)(addr, MASK); 866 explicit_prefix = 1; 867 } 868 869 void 870 setip6flags(dummyaddr, flag, dummysoc, afp) 871 const char *dummyaddr __unused; 872 int flag; 873 int dummysoc __unused; 874 const struct afswtch *afp; 875 { 876 if (afp->af_af != AF_INET6) 877 err(1, "address flags can be set only for inet6 addresses"); 878 879 if (flag < 0) 880 in6_addreq.ifra_flags &= ~(-flag); 881 else 882 in6_addreq.ifra_flags |= flag; 883 } 884 885 void 886 setip6pltime(seconds, dummy, s, afp) 887 const char *seconds; 888 int dummy __unused; 889 int s; 890 const struct afswtch *afp; 891 { 892 setip6lifetime("pltime", seconds, s, afp); 893 } 894 895 void 896 setip6vltime(seconds, dummy, s, afp) 897 const char *seconds; 898 int dummy __unused; 899 int s; 900 const struct afswtch *afp; 901 { 902 setip6lifetime("vltime", seconds, s, afp); 903 } 904 905 void 906 setip6lifetime(cmd, val, s, afp) 907 const char *cmd; 908 const char *val; 909 int s; 910 const struct afswtch *afp; 911 { 912 time_t newval, t; 913 char *ep; 914 915 t = time(NULL); 916 newval = (time_t)strtoul(val, &ep, 0); 917 if (val == ep) 918 errx(1, "invalid %s", cmd); 919 if (afp->af_af != AF_INET6) 920 errx(1, "%s not allowed for the AF", cmd); 921 if (strcmp(cmd, "vltime") == 0) { 922 in6_addreq.ifra_lifetime.ia6t_expire = t + newval; 923 in6_addreq.ifra_lifetime.ia6t_vltime = newval; 924 } else if (strcmp(cmd, "pltime") == 0) { 925 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; 926 in6_addreq.ifra_lifetime.ia6t_pltime = newval; 927 } 928 } 929 #endif 930 931 void 932 setifbroadaddr(addr, dummy, s, afp) 933 const char *addr; 934 int dummy __unused; 935 int s; 936 const struct afswtch *afp; 937 { 938 if (*afp->af_getaddr == NULL) 939 return; 940 (*afp->af_getaddr)(addr, DSTADDR); 941 } 942 943 void 944 setifipdst(addr, dummy, s, afp) 945 const char *addr; 946 int dummy __unused; 947 int s; 948 const struct afswtch *afp; 949 { 950 in_getaddr(addr, DSTADDR); 951 setipdst++; 952 clearaddr = 0; 953 newaddr = 0; 954 } 955 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) 956 957 void 958 notealias(addr, param, s, afp) 959 const char *addr; 960 int param; 961 int s; 962 const struct afswtch *afp; 963 { 964 if (setaddr && doalias == 0 && param < 0) 965 bcopy((caddr_t)rqtosa(af_addreq), 966 (caddr_t)rqtosa(af_ridreq), 967 rqtosa(af_addreq)->sa_len); 968 doalias = param; 969 if (param < 0) { 970 clearaddr = 1; 971 newaddr = 0; 972 } else 973 clearaddr = 0; 974 } 975 976 /*ARGSUSED*/ 977 void 978 setifdstaddr(addr, param, s, afp) 979 const char *addr; 980 int param __unused; 981 int s; 982 const struct afswtch *afp; 983 { 984 if (*afp->af_getaddr == NULL) 985 return; 986 (*afp->af_getaddr)(addr, DSTADDR); 987 } 988 989 /* 990 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion 991 * of the ifreq structure, which may confuse other parts of ifconfig. 992 * Make a private copy so we can avoid that. 993 */ 994 void 995 setifflags(vname, value, s, afp) 996 const char *vname; 997 int value; 998 int s; 999 const struct afswtch *afp; 1000 { 1001 struct ifreq my_ifr; 1002 1003 bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq)); 1004 1005 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { 1006 Perror("ioctl (SIOCGIFFLAGS)"); 1007 exit(1); 1008 } 1009 strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name)); 1010 flags = my_ifr.ifr_flags; 1011 1012 if (value < 0) { 1013 value = -value; 1014 flags &= ~value; 1015 } else 1016 flags |= value; 1017 my_ifr.ifr_flags = flags; 1018 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) 1019 Perror(vname); 1020 } 1021 1022 void 1023 setifmetric(val, dummy, s, afp) 1024 const char *val; 1025 int dummy __unused; 1026 int s; 1027 const struct afswtch *afp; 1028 { 1029 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 1030 ifr.ifr_metric = atoi(val); 1031 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) 1032 warn("ioctl (set metric)"); 1033 } 1034 1035 void 1036 setifmtu(val, dummy, s, afp) 1037 const char *val; 1038 int dummy __unused; 1039 int s; 1040 const struct afswtch *afp; 1041 { 1042 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 1043 ifr.ifr_mtu = atoi(val); 1044 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) 1045 warn("ioctl (set mtu)"); 1046 } 1047 1048 void 1049 setiflladdr(val, dummy, s, afp) 1050 const char *val; 1051 int dummy __unused; 1052 int s; 1053 const struct afswtch *afp; 1054 { 1055 struct ether_addr *ea; 1056 1057 ea = ether_aton(val); 1058 if (ea == NULL) { 1059 warn("malformed link-level address"); 1060 return; 1061 } 1062 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 1063 ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; 1064 ifr.ifr_addr.sa_family = AF_LINK; 1065 bcopy(ea, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN); 1066 if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0) 1067 warn("ioctl (set lladdr)"); 1068 1069 return; 1070 } 1071 1072 #define IFFBITS \ 1073 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ 1074 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ 1075 "\20MULTICAST" 1076 1077 /* 1078 * Print the status of the interface. If an address family was 1079 * specified, show it and it only; otherwise, show them all. 1080 */ 1081 void 1082 status(afp, addrcount, sdl, ifm, ifam) 1083 const struct afswtch *afp; 1084 int addrcount; 1085 struct sockaddr_dl *sdl; 1086 struct if_msghdr *ifm; 1087 struct ifa_msghdr *ifam; 1088 { 1089 const struct afswtch *p = NULL; 1090 struct rt_addrinfo info; 1091 int allfamilies, s; 1092 struct ifstat ifs; 1093 1094 if (afp == NULL) { 1095 allfamilies = 1; 1096 afp = &afs[0]; 1097 } else 1098 allfamilies = 0; 1099 1100 ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; 1101 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); 1102 1103 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) 1104 err(1, "socket"); 1105 1106 /* 1107 * XXX is it we are doing a SIOCGIFMETRIC etc for one family. 1108 * is it possible that the metric and mtu can be different for 1109 * each family? If so, we have a format problem, because the 1110 * metric and mtu is printed on the global the flags line. 1111 */ 1112 if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0) 1113 warn("ioctl (SIOCGIFMETRIC)"); 1114 else 1115 metric = ifr.ifr_metric; 1116 1117 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) 1118 warn("ioctl (SIOCGIFMTU)"); 1119 else 1120 mtu = ifr.ifr_mtu; 1121 1122 printf("%s: ", name); 1123 printb("flags", flags, IFFBITS); 1124 if (metric) 1125 printf(" metric %d", metric); 1126 if (mtu) 1127 printf(" mtu %d", mtu); 1128 putchar('\n'); 1129 1130 tunnel_status(s); 1131 1132 while (addrcount > 0) { 1133 1134 info.rti_addrs = ifam->ifam_addrs; 1135 1136 /* Expand the compacted addresses */ 1137 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, 1138 &info); 1139 1140 if (!allfamilies) { 1141 if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) { 1142 p = afp; 1143 (*p->af_status)(s, &info); 1144 } 1145 } else for (p = afs; p->af_name; p++) { 1146 if (p->af_af == info.rti_info[RTAX_IFA]->sa_family) 1147 (*p->af_status)(s, &info); 1148 } 1149 addrcount--; 1150 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); 1151 } 1152 if (allfamilies || afp->af_status == ether_status) 1153 ether_status(s, (struct rt_addrinfo *)sdl); 1154 #ifdef USE_IF_MEDIA 1155 if (allfamilies || afp->af_status == media_status) 1156 media_status(s, NULL); 1157 #endif 1158 #ifdef USE_VLANS 1159 if (allfamilies || afp->af_status == vlan_status) 1160 vlan_status(s, NULL); 1161 #endif 1162 #ifdef USE_IEEE80211 1163 if (allfamilies || afp->af_status == ieee80211_status) 1164 ieee80211_status(s, NULL); 1165 #endif 1166 strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); 1167 if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 1168 printf("%s", ifs.ascii); 1169 1170 if (!allfamilies && !p && afp->af_status != media_status && 1171 afp->af_status != ether_status 1172 #ifdef USE_VLANS 1173 && afp->af_status != vlan_status 1174 #endif 1175 ) 1176 warnx("%s has no %s interface address!", name, afp->af_name); 1177 1178 close(s); 1179 return; 1180 } 1181 1182 void 1183 tunnel_status(s) 1184 int s; 1185 { 1186 char psrcaddr[NI_MAXHOST]; 1187 char pdstaddr[NI_MAXHOST]; 1188 u_long srccmd, dstcmd; 1189 struct ifreq *ifrp; 1190 const char *ver = ""; 1191 #ifdef NI_WITHSCOPEID 1192 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; 1193 #else 1194 const int niflag = NI_NUMERICHOST; 1195 #endif 1196 #ifdef INET6 1197 struct in6_ifreq in6_ifr; 1198 int s6; 1199 #endif /* INET6 */ 1200 1201 psrcaddr[0] = pdstaddr[0] = '\0'; 1202 1203 #ifdef INET6 1204 memset(&in6_ifr, 0, sizeof(in6_ifr)); 1205 strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); 1206 s6 = socket(AF_INET6, SOCK_DGRAM, 0); 1207 if (s6 < 0) { 1208 srccmd = SIOCGIFPSRCADDR; 1209 dstcmd = SIOCGIFPDSTADDR; 1210 ifrp = 𝔦 1211 } else { 1212 close(s6); 1213 srccmd = SIOCGIFPSRCADDR_IN6; 1214 dstcmd = SIOCGIFPDSTADDR_IN6; 1215 ifrp = (struct ifreq *)&in6_ifr; 1216 } 1217 #else /* INET6 */ 1218 srccmd = SIOCGIFPSRCADDR; 1219 dstcmd = SIOCGIFPDSTADDR; 1220 ifrp = 𝔦 1221 #endif /* INET6 */ 1222 1223 if (ioctl(s, srccmd, (caddr_t)ifrp) < 0) 1224 return; 1225 #ifdef INET6 1226 if (ifrp->ifr_addr.sa_family == AF_INET6) 1227 in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); 1228 #endif 1229 getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, 1230 psrcaddr, sizeof(psrcaddr), 0, 0, niflag); 1231 #ifdef INET6 1232 if (ifrp->ifr_addr.sa_family == AF_INET6) 1233 ver = "6"; 1234 #endif 1235 1236 if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0) 1237 return; 1238 #ifdef INET6 1239 if (ifrp->ifr_addr.sa_family == AF_INET6) 1240 in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); 1241 #endif 1242 getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, 1243 pdstaddr, sizeof(pdstaddr), 0, 0, niflag); 1244 1245 printf("\ttunnel inet%s %s --> %s\n", ver, 1246 psrcaddr, pdstaddr); 1247 } 1248 1249 void 1250 in_status(s, info) 1251 int s __unused; 1252 struct rt_addrinfo * info; 1253 { 1254 struct sockaddr_in *sin, null_sin; 1255 1256 memset(&null_sin, 0, sizeof(null_sin)); 1257 1258 sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA]; 1259 printf("\tinet %s ", inet_ntoa(sin->sin_addr)); 1260 1261 if (flags & IFF_POINTOPOINT) { 1262 /* note RTAX_BRD overlap with IFF_BROADCAST */ 1263 sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD]; 1264 if (!sin) 1265 sin = &null_sin; 1266 printf("--> %s ", inet_ntoa(sin->sin_addr)); 1267 } 1268 1269 sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK]; 1270 if (!sin) 1271 sin = &null_sin; 1272 printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); 1273 1274 if (flags & IFF_BROADCAST) { 1275 /* note RTAX_BRD overlap with IFF_POINTOPOINT */ 1276 sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD]; 1277 if (sin && sin->sin_addr.s_addr != 0) 1278 printf("broadcast %s", inet_ntoa(sin->sin_addr)); 1279 } 1280 putchar('\n'); 1281 } 1282 1283 #ifdef INET6 1284 void 1285 in6_fillscopeid(sin6) 1286 struct sockaddr_in6 *sin6; 1287 { 1288 #if defined(__KAME__) && defined(KAME_SCOPEID) 1289 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1290 sin6->sin6_scope_id = 1291 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); 1292 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; 1293 } 1294 #endif 1295 } 1296 1297 void 1298 in6_status(s, info) 1299 int s __unused; 1300 struct rt_addrinfo * info; 1301 { 1302 struct sockaddr_in6 *sin, null_sin; 1303 struct in6_ifreq ifr6; 1304 int s6; 1305 u_int32_t flags6; 1306 struct in6_addrlifetime lifetime; 1307 time_t t = time(NULL); 1308 int error; 1309 u_int32_t scopeid; 1310 1311 memset(&null_sin, 0, sizeof(null_sin)); 1312 1313 sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA]; 1314 strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); 1315 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1316 perror("ifconfig: socket"); 1317 return; 1318 } 1319 ifr6.ifr_addr = *sin; 1320 if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 1321 perror("ifconfig: ioctl(SIOCGIFAFLAG_IN6)"); 1322 close(s6); 1323 return; 1324 } 1325 flags6 = ifr6.ifr_ifru.ifru_flags6; 1326 memset(&lifetime, 0, sizeof(lifetime)); 1327 ifr6.ifr_addr = *sin; 1328 if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) { 1329 perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)"); 1330 close(s6); 1331 return; 1332 } 1333 lifetime = ifr6.ifr_ifru.ifru_lifetime; 1334 close(s6); 1335 1336 /* XXX: embedded link local addr check */ 1337 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && 1338 *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { 1339 u_short index; 1340 1341 index = *(u_short *)&sin->sin6_addr.s6_addr[2]; 1342 *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; 1343 if (sin->sin6_scope_id == 0) 1344 sin->sin6_scope_id = ntohs(index); 1345 } 1346 scopeid = sin->sin6_scope_id; 1347 1348 error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, 1349 sizeof(addr_buf), NULL, 0, 1350 NI_NUMERICHOST|NI_WITHSCOPEID); 1351 if (error != 0) 1352 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, 1353 sizeof(addr_buf)); 1354 printf("\tinet6 %s ", addr_buf); 1355 1356 if (flags & IFF_POINTOPOINT) { 1357 /* note RTAX_BRD overlap with IFF_BROADCAST */ 1358 sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD]; 1359 /* 1360 * some of the interfaces do not have valid destination 1361 * address. 1362 */ 1363 if (sin && sin->sin6_family == AF_INET6) { 1364 int error; 1365 1366 /* XXX: embedded link local addr check */ 1367 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && 1368 *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { 1369 u_short index; 1370 1371 index = *(u_short *)&sin->sin6_addr.s6_addr[2]; 1372 *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; 1373 if (sin->sin6_scope_id == 0) 1374 sin->sin6_scope_id = ntohs(index); 1375 } 1376 1377 error = getnameinfo((struct sockaddr *)sin, 1378 sin->sin6_len, addr_buf, 1379 sizeof(addr_buf), NULL, 0, 1380 NI_NUMERICHOST|NI_WITHSCOPEID); 1381 if (error != 0) 1382 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, 1383 sizeof(addr_buf)); 1384 printf("--> %s ", addr_buf); 1385 } 1386 } 1387 1388 sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK]; 1389 if (!sin) 1390 sin = &null_sin; 1391 printf("prefixlen %d ", prefix(&sin->sin6_addr, 1392 sizeof(struct in6_addr))); 1393 1394 if ((flags6 & IN6_IFF_ANYCAST) != 0) 1395 printf("anycast "); 1396 if ((flags6 & IN6_IFF_TENTATIVE) != 0) 1397 printf("tentative "); 1398 if ((flags6 & IN6_IFF_DUPLICATED) != 0) 1399 printf("duplicated "); 1400 if ((flags6 & IN6_IFF_DETACHED) != 0) 1401 printf("detached "); 1402 if ((flags6 & IN6_IFF_DEPRECATED) != 0) 1403 printf("deprecated "); 1404 if ((flags6 & IN6_IFF_AUTOCONF) != 0) 1405 printf("autoconf "); 1406 if ((flags6 & IN6_IFF_TEMPORARY) != 0) 1407 printf("temporary "); 1408 1409 if (scopeid) 1410 printf("scopeid 0x%x ", scopeid); 1411 1412 if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { 1413 printf("pltime "); 1414 if (lifetime.ia6t_preferred) { 1415 printf("%s ", lifetime.ia6t_preferred < t 1416 ? "0" : sec2str(lifetime.ia6t_preferred - t)); 1417 } else 1418 printf("infty "); 1419 1420 printf("vltime "); 1421 if (lifetime.ia6t_expire) { 1422 printf("%s ", lifetime.ia6t_expire < t 1423 ? "0" : sec2str(lifetime.ia6t_expire - t)); 1424 } else 1425 printf("infty "); 1426 } 1427 1428 putchar('\n'); 1429 } 1430 #endif /*INET6*/ 1431 1432 void 1433 ipx_status(s, info) 1434 int s __unused; 1435 struct rt_addrinfo * info; 1436 { 1437 struct sockaddr_ipx *sipx, null_sipx; 1438 1439 memset(&null_sipx, 0, sizeof(null_sipx)); 1440 1441 sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA]; 1442 printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr)); 1443 1444 if (flags & IFF_POINTOPOINT) { 1445 sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD]; 1446 if (!sipx) 1447 sipx = &null_sipx; 1448 printf("--> %s ", ipx_ntoa(sipx->sipx_addr)); 1449 } 1450 putchar('\n'); 1451 } 1452 1453 void 1454 at_status(s, info) 1455 int s __unused; 1456 struct rt_addrinfo * info; 1457 { 1458 struct sockaddr_at *sat, null_sat; 1459 struct netrange *nr; 1460 1461 memset(&null_sat, 0, sizeof(null_sat)); 1462 1463 sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA]; 1464 nr = &sat->sat_range.r_netrange; 1465 printf("\tatalk %d.%d range %d-%d phase %d", 1466 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, 1467 ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase); 1468 if (flags & IFF_POINTOPOINT) { 1469 /* note RTAX_BRD overlap with IFF_BROADCAST */ 1470 sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD]; 1471 if (!sat) 1472 sat = &null_sat; 1473 printf("--> %d.%d", 1474 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 1475 } 1476 if (flags & IFF_BROADCAST) { 1477 /* note RTAX_BRD overlap with IFF_POINTOPOINT */ 1478 sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD]; 1479 if (sat) 1480 printf(" broadcast %d.%d", 1481 ntohs(sat->sat_addr.s_net), 1482 sat->sat_addr.s_node); 1483 } 1484 1485 putchar('\n'); 1486 } 1487 1488 #ifdef NS 1489 void 1490 xns_status(s, info) 1491 int s __unused; 1492 struct rt_addrinfo * info; 1493 { 1494 struct sockaddr_ns *sns, null_sns; 1495 1496 memset(&null_sns, 0, sizeof(null_sns)); 1497 1498 sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA]; 1499 printf("\tns %s ", ns_ntoa(sns->sns_addr)); 1500 1501 if (flags & IFF_POINTOPOINT) { 1502 sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD]; 1503 if (!sns) 1504 sns = &null_sns; 1505 printf("--> %s ", ns_ntoa(sns->sns_addr)); 1506 } 1507 1508 putchar('\n'); 1509 close(s); 1510 } 1511 #endif 1512 1513 1514 void 1515 ether_status(s, info) 1516 int s __unused; 1517 struct rt_addrinfo *info; 1518 { 1519 char *cp; 1520 int n; 1521 struct sockaddr_dl *sdl = (struct sockaddr_dl *)info; 1522 1523 cp = (char *)LLADDR(sdl); 1524 if ((n = sdl->sdl_alen) > 0) { 1525 if (sdl->sdl_type == IFT_ETHER) 1526 printf ("\tether "); 1527 else 1528 printf ("\tlladdr "); 1529 while (--n >= 0) 1530 printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' '); 1531 putchar('\n'); 1532 } 1533 } 1534 1535 void 1536 Perror(cmd) 1537 const char *cmd; 1538 { 1539 switch (errno) { 1540 1541 case ENXIO: 1542 errx(1, "%s: no such interface", cmd); 1543 break; 1544 1545 case EPERM: 1546 errx(1, "%s: permission denied", cmd); 1547 break; 1548 1549 default: 1550 err(1, "%s", cmd); 1551 } 1552 } 1553 1554 #define SIN(x) ((struct sockaddr_in *) &(x)) 1555 struct sockaddr_in *sintab[] = { 1556 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr), 1557 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)}; 1558 1559 void 1560 in_getaddr(s, which) 1561 const char *s; 1562 int which; 1563 { 1564 register struct sockaddr_in *sin = sintab[which]; 1565 struct hostent *hp; 1566 struct netent *np; 1567 1568 sin->sin_len = sizeof(*sin); 1569 if (which != MASK) 1570 sin->sin_family = AF_INET; 1571 1572 if (which == ADDR) { 1573 char *p = NULL; 1574 1575 if((p = strrchr(s, '/')) != NULL) { 1576 /* address is `name/masklen' */ 1577 int masklen; 1578 int ret; 1579 struct sockaddr_in *min = sintab[MASK]; 1580 *p = '\0'; 1581 ret = sscanf(p+1, "%u", &masklen); 1582 if(ret != 1 || (masklen < 0 || masklen > 32)) { 1583 *p = '/'; 1584 errx(1, "%s: bad value", s); 1585 } 1586 min->sin_len = sizeof(*min); 1587 min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 1588 0xffffffff); 1589 } 1590 } 1591 1592 if (inet_aton(s, &sin->sin_addr)) 1593 return; 1594 if ((hp = gethostbyname(s)) != 0) 1595 bcopy(hp->h_addr, (char *)&sin->sin_addr, 1596 MIN(hp->h_length, sizeof(sin->sin_addr))); 1597 else if ((np = getnetbyname(s)) != 0) 1598 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 1599 else 1600 errx(1, "%s: bad value", s); 1601 } 1602 1603 #ifdef INET6 1604 #define SIN6(x) ((struct sockaddr_in6 *) &(x)) 1605 struct sockaddr_in6 *sin6tab[] = { 1606 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr), 1607 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)}; 1608 1609 void 1610 in6_getaddr(s, which) 1611 const char *s; 1612 int which; 1613 { 1614 register struct sockaddr_in6 *sin = sin6tab[which]; 1615 struct addrinfo hints, *res; 1616 int error = -1; 1617 1618 newaddr &= 1; 1619 1620 sin->sin6_len = sizeof(*sin); 1621 if (which != MASK) 1622 sin->sin6_family = AF_INET6; 1623 1624 if (which == ADDR) { 1625 char *p = NULL; 1626 if((p = strrchr(s, '/')) != NULL) { 1627 *p = '\0'; 1628 in6_getprefix(p + 1, MASK); 1629 explicit_prefix = 1; 1630 } 1631 } 1632 1633 if (sin->sin6_family == AF_INET6) { 1634 bzero(&hints, sizeof(struct addrinfo)); 1635 hints.ai_family = AF_INET6; 1636 error = getaddrinfo(s, NULL, &hints, &res); 1637 } 1638 if (error != 0) { 1639 if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) 1640 errx(1, "%s: bad value", s); 1641 } else 1642 bcopy(res->ai_addr, sin, res->ai_addrlen); 1643 } 1644 1645 void 1646 in6_getprefix(plen, which) 1647 const char *plen; 1648 int which; 1649 { 1650 register struct sockaddr_in6 *sin = sin6tab[which]; 1651 register u_char *cp; 1652 int len = atoi(plen); 1653 1654 if ((len < 0) || (len > 128)) 1655 errx(1, "%s: bad value", plen); 1656 sin->sin6_len = sizeof(*sin); 1657 if (which != MASK) 1658 sin->sin6_family = AF_INET6; 1659 if ((len == 0) || (len == 128)) { 1660 memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr)); 1661 return; 1662 } 1663 memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr)); 1664 for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8) 1665 *cp++ = 0xff; 1666 *cp = 0xff << (8 - len); 1667 } 1668 #endif 1669 1670 /* 1671 * Print a value a la the %b format of the kernel's printf 1672 */ 1673 void 1674 printb(s, v, bits) 1675 const char *s; 1676 register unsigned v; 1677 register const char *bits; 1678 { 1679 register int i, any = 0; 1680 register char c; 1681 1682 if (bits && *bits == 8) 1683 printf("%s=%o", s, v); 1684 else 1685 printf("%s=%x", s, v); 1686 bits++; 1687 if (bits) { 1688 putchar('<'); 1689 while ((i = *bits++) != '\0') { 1690 if (v & (1 << (i-1))) { 1691 if (any) 1692 putchar(','); 1693 any = 1; 1694 for (; (c = *bits) > 32; bits++) 1695 putchar(c); 1696 } else 1697 for (; *bits > 32; bits++) 1698 ; 1699 } 1700 putchar('>'); 1701 } 1702 } 1703 1704 #define SIPX(x) ((struct sockaddr_ipx *) &(x)) 1705 struct sockaddr_ipx *sipxtab[] = { 1706 SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr), 1707 SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)}; 1708 1709 void 1710 ipx_getaddr(addr, which) 1711 const char *addr; 1712 int which; 1713 { 1714 struct sockaddr_ipx *sipx = sipxtab[which]; 1715 1716 sipx->sipx_family = AF_IPX; 1717 sipx->sipx_len = sizeof(*sipx); 1718 sipx->sipx_addr = ipx_addr(addr); 1719 if (which == MASK) 1720 printf("Attempt to set IPX netmask will be ineffectual\n"); 1721 } 1722 1723 void 1724 at_getaddr(addr, which) 1725 const char *addr; 1726 int which; 1727 { 1728 struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr; 1729 u_int net, node; 1730 1731 sat->sat_family = AF_APPLETALK; 1732 sat->sat_len = sizeof(*sat); 1733 if (which == MASK) 1734 errx(1, "AppleTalk does not use netmasks"); 1735 if (sscanf(addr, "%u.%u", &net, &node) != 2 1736 || net > 0xffff || node > 0xfe) 1737 errx(1, "%s: illegal address", addr); 1738 sat->sat_addr.s_net = htons(net); 1739 sat->sat_addr.s_node = node; 1740 } 1741 1742 void 1743 ether_getaddr(addr, which) 1744 const char *addr; 1745 int which; 1746 { 1747 struct ether_addr *ea; 1748 struct sockaddr *sea = &ridreq.ifr_addr; 1749 1750 ea = ether_aton(addr); 1751 if (ea == NULL) 1752 errx(1, "malformed ether address"); 1753 if (which == MASK) 1754 errx(1, "Ethernet does not use netmasks"); 1755 sea->sa_family = AF_LINK; 1756 sea->sa_len = ETHER_ADDR_LEN; 1757 bcopy(ea, sea->sa_data, ETHER_ADDR_LEN); 1758 } 1759 1760 /* XXX FIXME -- should use strtoul for better parsing. */ 1761 void 1762 setatrange(range, dummy, s, afp) 1763 const char *range; 1764 int dummy __unused; 1765 int s; 1766 const struct afswtch *afp; 1767 { 1768 u_short first = 123, last = 123; 1769 1770 if (sscanf(range, "%hu-%hu", &first, &last) != 2 1771 || first == 0 || first > 0xffff 1772 || last == 0 || last > 0xffff || first > last) 1773 errx(1, "%s: illegal net range: %u-%u", range, first, last); 1774 at_nr.nr_firstnet = htons(first); 1775 at_nr.nr_lastnet = htons(last); 1776 } 1777 1778 void 1779 setatphase(phase, dummy, s, afp) 1780 const char *phase; 1781 int dummy __unused; 1782 int s; 1783 const struct afswtch *afp; 1784 { 1785 if (!strcmp(phase, "1")) 1786 at_nr.nr_phase = 1; 1787 else if (!strcmp(phase, "2")) 1788 at_nr.nr_phase = 2; 1789 else 1790 errx(1, "%s: illegal phase", phase); 1791 } 1792 1793 void 1794 checkatrange(struct sockaddr_at *sat) 1795 { 1796 if (at_nr.nr_phase == 0) 1797 at_nr.nr_phase = 2; /* Default phase 2 */ 1798 if (at_nr.nr_firstnet == 0) 1799 at_nr.nr_firstnet = /* Default range of one */ 1800 at_nr.nr_lastnet = sat->sat_addr.s_net; 1801 printf("\tatalk %d.%d range %d-%d phase %d\n", 1802 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, 1803 ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase); 1804 if ((u_short) ntohs(at_nr.nr_firstnet) > 1805 (u_short) ntohs(sat->sat_addr.s_net) 1806 || (u_short) ntohs(at_nr.nr_lastnet) < 1807 (u_short) ntohs(sat->sat_addr.s_net)) 1808 errx(1, "AppleTalk address is not in range"); 1809 sat->sat_range.r_netrange = at_nr; 1810 } 1811 1812 #ifdef NS 1813 #define SNS(x) ((struct sockaddr_ns *) &(x)) 1814 struct sockaddr_ns *snstab[] = { 1815 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr), 1816 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)}; 1817 1818 void 1819 xns_getaddr(addr, which) 1820 const char *addr; 1821 int which; 1822 { 1823 struct sockaddr_ns *sns = snstab[which]; 1824 1825 sns->sns_family = AF_NS; 1826 sns->sns_len = sizeof(*sns); 1827 sns->sns_addr = ns_addr(addr); 1828 if (which == MASK) 1829 printf("Attempt to set XNS netmask will be ineffectual\n"); 1830 } 1831 #endif 1832 1833 #ifdef INET6 1834 int 1835 prefix(val, size) 1836 void *val; 1837 int size; 1838 { 1839 register u_char *name = (u_char *)val; 1840 register int byte, bit, plen = 0; 1841 1842 for (byte = 0; byte < size; byte++, plen += 8) 1843 if (name[byte] != 0xff) 1844 break; 1845 if (byte == size) 1846 return (plen); 1847 for (bit = 7; bit != 0; bit--, plen++) 1848 if (!(name[byte] & (1 << bit))) 1849 break; 1850 for (; bit != 0; bit--) 1851 if (name[byte] & (1 << bit)) 1852 return(0); 1853 byte++; 1854 for (; byte < size; byte++) 1855 if (name[byte]) 1856 return(0); 1857 return (plen); 1858 } 1859 1860 static char * 1861 sec2str(total) 1862 time_t total; 1863 { 1864 static char result[256]; 1865 int days, hours, mins, secs; 1866 int first = 1; 1867 char *p = result; 1868 1869 if (0) { 1870 days = total / 3600 / 24; 1871 hours = (total / 3600) % 24; 1872 mins = (total / 60) % 60; 1873 secs = total % 60; 1874 1875 if (days) { 1876 first = 0; 1877 p += sprintf(p, "%dd", days); 1878 } 1879 if (!first || hours) { 1880 first = 0; 1881 p += sprintf(p, "%dh", hours); 1882 } 1883 if (!first || mins) { 1884 first = 0; 1885 p += sprintf(p, "%dm", mins); 1886 } 1887 sprintf(p, "%ds", secs); 1888 } else 1889 sprintf(result, "%lu", (unsigned long)total); 1890 1891 return(result); 1892 } 1893 #endif /*INET6*/ 1894 1895 void 1896 ifmaybeload(name) 1897 char *name; 1898 { 1899 struct module_stat mstat; 1900 int fileid, modid; 1901 char ifkind[35], *cp, *dp; 1902 1903 1904 /* turn interface and unit into module name */ 1905 strcpy(ifkind, "if_"); 1906 for (cp = name, dp = ifkind + 3; 1907 (*cp != 0) && !isdigit(*cp); cp++, dp++) 1908 *dp = *cp; 1909 *dp = 0; 1910 1911 /* scan files in kernel */ 1912 mstat.version = sizeof(struct module_stat); 1913 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 1914 /* scan modules in file */ 1915 for (modid = kldfirstmod(fileid); modid > 0; 1916 modid = modfnext(modid)) { 1917 if (modstat(modid, &mstat) < 0) 1918 continue; 1919 /* strip bus name if present */ 1920 if ((cp = strchr(mstat.name, '/')) != NULL) { 1921 cp++; 1922 } else { 1923 cp = mstat.name; 1924 } 1925 /* already loaded? */ 1926 if (!strcmp(ifkind, cp)) 1927 return; 1928 } 1929 } 1930 1931 /* not present, we should try to load it */ 1932 kldload(ifkind); 1933 } 1934 1935 void 1936 list_cloners(void) 1937 { 1938 struct if_clonereq ifcr; 1939 char *cp, *buf; 1940 int idx; 1941 int s; 1942 1943 s = socket(AF_INET, SOCK_DGRAM, 0); 1944 if (s == -1) 1945 err(1, "socket"); 1946 1947 memset(&ifcr, 0, sizeof(ifcr)); 1948 1949 if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) 1950 err(1, "SIOCIFGCLONERS for count"); 1951 1952 buf = malloc(ifcr.ifcr_total * IFNAMSIZ); 1953 if (buf == NULL) 1954 err(1, "unable to allocate cloner name buffer"); 1955 1956 ifcr.ifcr_count = ifcr.ifcr_total; 1957 ifcr.ifcr_buffer = buf; 1958 1959 if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) 1960 err(1, "SIOCIFGCLONERS for names"); 1961 1962 /* 1963 * In case some disappeared in the mean time, clamp it down. 1964 */ 1965 if (ifcr.ifcr_count > ifcr.ifcr_total) 1966 ifcr.ifcr_count = ifcr.ifcr_total; 1967 1968 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { 1969 if (idx > 0) 1970 putchar(' '); 1971 printf("%s", cp); 1972 } 1973 1974 putchar('\n'); 1975 free(buf); 1976 } 1977 1978 void 1979 clone_create() 1980 { 1981 int s; 1982 1983 s = socket(AF_INET, SOCK_DGRAM, 0); 1984 if (s == -1) 1985 err(1, "socket"); 1986 1987 memset(&ifr, 0, sizeof(ifr)); 1988 (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1989 if (ioctl(s, SIOCIFCREATE, &ifr) < 0) 1990 err(1, "SIOCIFCREATE"); 1991 1992 if (strcmp(name, ifr.ifr_name) != 0) { 1993 printf("%s\n", ifr.ifr_name); 1994 strlcpy(name, ifr.ifr_name, sizeof(name)); 1995 } 1996 1997 close(s); 1998 } 1999 2000 void 2001 clone_destroy(val, d, s, rafp) 2002 const char *val; 2003 int d; 2004 int s; 2005 const struct afswtch *rafp; 2006 { 2007 2008 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 2009 if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) 2010 err(1, "SIOCIFDESTROY"); 2011 } 2012