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