ifconfig.c revision 50476
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 50476 1999-08-28 00:22:10Z peter $"; 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 54#include <net/if.h> 55#include <net/if_var.h> 56#include <net/if_dl.h> 57#include <net/if_types.h> 58#include <net/route.h> 59 60/* IP */ 61#include <netinet/in.h> 62#include <netinet/in_var.h> 63#include <arpa/inet.h> 64#include <netdb.h> 65 66/* IPX */ 67#define IPXIP 68#define IPTUNNEL 69#include <netipx/ipx.h> 70#include <netipx/ipx_if.h> 71 72/* Appletalk */ 73#include <netatalk/at.h> 74 75/* XNS */ 76#ifdef NS 77#define NSIP 78#include <netns/ns.h> 79#include <netns/ns_if.h> 80#endif 81 82/* OSI */ 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 93#include "ifconfig.h" 94 95struct ifreq ifr, ridreq; 96struct ifaliasreq addreq; 97struct sockaddr_in netmask; 98struct netrange at_nr; /* AppleTalk net range */ 99 100char name[32]; 101int flags; 102int metric; 103int mtu; 104int setaddr; 105int setipdst; 106int doalias; 107int clearaddr; 108int newaddr = 1; 109 110struct afswtch; 111 112void Perror __P((const char *cmd)); 113void checkatrange __P((struct sockaddr_at *)); 114int ifconfig __P((int argc, char *const *argv, const struct afswtch *afp)); 115void notealias __P((const char *, int, int, const struct afswtch *afp)); 116void printb __P((const char *s, unsigned value, const char *bits)); 117void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); 118void status __P((const struct afswtch *afp, int addrcount, 119 struct sockaddr_dl *sdl, struct if_msghdr *ifm, 120 struct ifa_msghdr *ifam)); 121void usage __P((void)); 122 123typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp)); 124c_func setatphase, setatrange; 125c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask; 126c_func setifipdst; 127c_func setifflags, setifmetric, setifmtu; 128 129 130#define NEXTARG 0xffffff 131 132const 133struct cmd { 134 const char *c_name; 135 int c_parameter; /* NEXTARG means next argv */ 136 void (*c_func) __P((const char *, int, int, const struct afswtch *afp)); 137} cmds[] = { 138 { "up", IFF_UP, setifflags } , 139 { "down", -IFF_UP, setifflags }, 140 { "arp", -IFF_NOARP, setifflags }, 141 { "-arp", IFF_NOARP, setifflags }, 142 { "debug", IFF_DEBUG, setifflags }, 143 { "-debug", -IFF_DEBUG, setifflags }, 144 { "alias", IFF_UP, notealias }, 145 { "-alias", -IFF_UP, notealias }, 146 { "delete", -IFF_UP, notealias }, 147#ifdef notdef 148#define EN_SWABIPS 0x1000 149 { "swabips", EN_SWABIPS, setifflags }, 150 { "-swabips", -EN_SWABIPS, setifflags }, 151#endif 152 { "netmask", NEXTARG, setifnetmask }, 153 { "range", NEXTARG, setatrange }, 154 { "phase", NEXTARG, setatphase }, 155 { "metric", NEXTARG, setifmetric }, 156 { "broadcast", NEXTARG, setifbroadaddr }, 157 { "ipdst", NEXTARG, setifipdst }, 158 { "link0", IFF_LINK0, setifflags }, 159 { "-link0", -IFF_LINK0, setifflags }, 160 { "link1", IFF_LINK1, setifflags }, 161 { "-link1", -IFF_LINK1, setifflags }, 162 { "link2", IFF_LINK2, setifflags }, 163 { "-link2", -IFF_LINK2, setifflags }, 164#ifdef USE_IF_MEDIA 165 { "media", NEXTARG, setmedia }, 166 { "mediaopt", NEXTARG, setmediaopt }, 167 { "-mediaopt", NEXTARG, unsetmediaopt }, 168#endif 169#ifdef USE_VLANS 170 { "vlan", NEXTARG, setvlantag }, 171 { "vlandev", NEXTARG, setvlandev }, 172 { "-vlandev", NEXTARG, unsetvlandev }, 173#endif 174 { "normal", -IFF_LINK0, setifflags }, 175 { "compress", IFF_LINK0, setifflags }, 176 { "noicmp", IFF_LINK1, setifflags }, 177 { "mtu", NEXTARG, setifmtu }, 178 { 0, 0, setifaddr }, 179 { 0, 0, setifdstaddr }, 180}; 181 182/* 183 * XNS support liberally adapted from code written at the University of 184 * Maryland principally by James O'Toole and Chris Torek. 185 */ 186typedef void af_status __P((int, struct rt_addrinfo *)); 187typedef void af_getaddr __P((const char *, int)); 188 189af_status in_status, ipx_status, at_status, ether_status; 190af_getaddr in_getaddr, ipx_getaddr, at_getaddr; 191 192#ifdef NS 193af_status xns_status; 194af_getaddr xns_getaddr; 195#endif 196 197/* Known address families */ 198const 199struct afswtch { 200 const char *af_name; 201 short af_af; 202 af_status *af_status; 203 af_getaddr *af_getaddr; 204 u_long af_difaddr; 205 u_long af_aifaddr; 206 caddr_t af_ridreq; 207 caddr_t af_addreq; 208} afs[] = { 209#define C(x) ((caddr_t) &x) 210 { "inet", AF_INET, in_status, in_getaddr, 211 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, 212 { "ipx", AF_IPX, ipx_status, ipx_getaddr, 213 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, 214 { "atalk", AF_APPLETALK, at_status, at_getaddr, 215 SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) }, 216#ifdef NS 217 { "ns", AF_NS, xns_status, xns_getaddr, 218 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, 219#endif 220 { "ether", AF_INET, ether_status, NULL }, /* XXX not real!! */ 221#if 0 /* XXX conflicts with the media command */ 222#ifdef USE_IF_MEDIA 223 { "media", AF_INET, media_status, NULL }, /* XXX not real!! */ 224#endif 225#ifdef USE_VLANS 226 { "vlan", AF_INET, media_status, NULL }, /* XXX not real!! */ 227#endif 228#endif 229 { 0, 0, 0, 0 } 230}; 231 232/* 233 * Expand the compacted form of addresses as returned via the 234 * configuration read via sysctl(). 235 */ 236 237#define ROUNDUP(a) \ 238 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 239#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 240 241void 242rt_xaddrs(cp, cplim, rtinfo) 243 caddr_t cp, cplim; 244 struct rt_addrinfo *rtinfo; 245{ 246 struct sockaddr *sa; 247 int i; 248 249 memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); 250 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 251 if ((rtinfo->rti_addrs & (1 << i)) == 0) 252 continue; 253 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 254 ADVANCE(cp, sa); 255 } 256} 257 258 259void 260usage() 261{ 262 fprintf(stderr, "%s\n%s\n%s\n%s\n", 263 "usage: ifconfig interface address_family [address [dest_address]]", 264 " [parameters]", 265 " ifconfig -a [-d] [-u] [address_family]", 266 " ifconfig -l [-d] [-u] [address_family]"); 267 exit(1); 268} 269 270int 271main(argc, argv) 272 int argc; 273 char *const *argv; 274{ 275 int c; 276 int all, namesonly, downonly, uponly; 277 int foundit = 0, need_nl = 0; 278 const struct afswtch *afp = 0; 279 int addrcount; 280 struct if_msghdr *ifm, *nextifm; 281 struct ifa_msghdr *ifam; 282 struct sockaddr_dl *sdl; 283 char *buf, *lim, *next; 284 285 286 size_t needed; 287 int mib[6]; 288 289 /* Parse leading line options */ 290 all = downonly = uponly = namesonly = 0; 291 while ((c = getopt(argc, argv, "adlmu")) != -1) { 292 switch (c) { 293 case 'a': /* scan all interfaces */ 294 all++; 295 break; 296 case 'l': /* scan interface names only */ 297 namesonly++; 298 break; 299 case 'd': /* restrict scan to "down" interfaces */ 300 downonly++; 301 break; 302 case 'u': /* restrict scan to "up" interfaces */ 303 uponly++; 304 break; 305 case 'm': /* show media choices in status */ 306 /* ignored for compatibility */ 307 break; 308 default: 309 usage(); 310 break; 311 } 312 } 313 argc -= optind; 314 argv += optind; 315 316 /* -l cannot be used with -a or -m */ 317 if (namesonly && all) 318 usage(); 319 320 /* nonsense.. */ 321 if (uponly && downonly) 322 usage(); 323 324 /* -a and -l allow an address family arg to limit the output */ 325 if (all || namesonly) { 326 if (argc > 1) 327 usage(); 328 329 if (argc == 1) { 330 for (afp = afs; afp->af_name; afp++) 331 if (strcmp(afp->af_name, *argv) == 0) { 332 argc--, argv++; 333 break; 334 } 335 if (afp->af_name == NULL) 336 usage(); 337 /* leave with afp non-zero */ 338 } 339 } else { 340 /* not listing, need an argument */ 341 if (argc < 1) 342 usage(); 343 344 strncpy(name, *argv, sizeof(name)); 345 argc--, argv++; 346 } 347 348 /* Check for address family */ 349 if (argc > 0) { 350 for (afp = afs; afp->af_name; afp++) 351 if (strcmp(afp->af_name, *argv) == 0) { 352 argc--, argv++; 353 break; 354 } 355 if (afp->af_name == NULL) 356 afp = NULL; /* not a family, NULL */ 357 } 358 359 mib[0] = CTL_NET; 360 mib[1] = PF_ROUTE; 361 mib[2] = 0; 362 mib[3] = 0; /* address family */ 363 mib[4] = NET_RT_IFLIST; 364 mib[5] = 0; 365 366 /* if particular family specified, only ask about it */ 367 if (afp) 368 mib[3] = afp->af_af; 369 370 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 371 errx(1, "iflist-sysctl-estimate"); 372 if ((buf = malloc(needed)) == NULL) 373 errx(1, "malloc"); 374 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 375 errx(1, "actual retrieval of interface table"); 376 lim = buf + needed; 377 378 next = buf; 379 while (next < lim) { 380 381 ifm = (struct if_msghdr *)next; 382 383 if (ifm->ifm_type == RTM_IFINFO) { 384 sdl = (struct sockaddr_dl *)(ifm + 1); 385 flags = ifm->ifm_flags; 386 } else { 387 fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n"); 388 fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, 389 ifm->ifm_type); 390 fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen); 391 fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, 392 lim); 393 exit (1); 394 } 395 396 next += ifm->ifm_msglen; 397 ifam = NULL; 398 addrcount = 0; 399 while (next < lim) { 400 401 nextifm = (struct if_msghdr *)next; 402 403 if (nextifm->ifm_type != RTM_NEWADDR) 404 break; 405 406 if (ifam == NULL) 407 ifam = (struct ifa_msghdr *)nextifm; 408 409 addrcount++; 410 next += nextifm->ifm_msglen; 411 } 412 413 if (all || namesonly) { 414 if (uponly) 415 if ((flags & IFF_UP) == 0) 416 continue; /* not up */ 417 if (downonly) 418 if (flags & IFF_UP) 419 continue; /* not down */ 420 strncpy(name, sdl->sdl_data, sdl->sdl_nlen); 421 name[sdl->sdl_nlen] = '\0'; 422 if (namesonly) { 423 if (afp == NULL || 424 afp->af_status != ether_status || 425 sdl->sdl_type == IFT_ETHER) { 426 if (need_nl) 427 putchar(' '); 428 fputs(name, stdout); 429 need_nl++; 430 } 431 continue; 432 } 433 } else { 434 if (strlen(name) != sdl->sdl_nlen) 435 continue; /* not same len */ 436 if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0) 437 continue; /* not same name */ 438 } 439 440 if (argc > 0) 441 ifconfig(argc, argv, afp); 442 else 443 status(afp, addrcount, sdl, ifm, ifam); 444 445 if (all == 0 && namesonly == 0) { 446 foundit++; /* flag it as 'done' */ 447 break; 448 } 449 } 450 free(buf); 451 452 if (namesonly && need_nl > 0) 453 putchar('\n'); 454 455 if (all == 0 && namesonly == 0 && foundit == 0) 456 errx(1, "interface %s does not exist", name); 457 458 459 exit (0); 460} 461 462 463int 464ifconfig(argc, argv, afp) 465 int argc; 466 char *const *argv; 467 const struct afswtch *afp; 468{ 469 int s; 470 471 if (afp == NULL) 472 afp = &afs[0]; 473 ifr.ifr_addr.sa_family = afp->af_af; 474 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); 475 476 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) 477 err(1, "socket"); 478 479 while (argc > 0) { 480 register const struct cmd *p; 481 482 for (p = cmds; p->c_name; p++) 483 if (strcmp(*argv, p->c_name) == 0) 484 break; 485 if (p->c_name == 0 && setaddr) 486 p++; /* got src, do dst */ 487 if (p->c_func) { 488 if (p->c_parameter == NEXTARG) { 489 if (argv[1] == NULL) 490 errx(1, "'%s' requires argument", 491 p->c_name); 492 (*p->c_func)(argv[1], 0, s, afp); 493 argc--, argv++; 494 } else 495 (*p->c_func)(*argv, p->c_parameter, s, afp); 496 } 497 argc--, argv++; 498 } 499 if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) { 500 struct ipxip_req rq; 501 int size = sizeof(rq); 502 503 rq.rq_ipx = addreq.ifra_addr; 504 rq.rq_ip = addreq.ifra_dstaddr; 505 506 if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0) 507 Perror("Encapsulation Routing"); 508 } 509 if (ifr.ifr_addr.sa_family == AF_APPLETALK) 510 checkatrange((struct sockaddr_at *) &addreq.ifra_addr); 511#ifdef NS 512 if (setipdst && ifr.ifr_addr.sa_family == AF_NS) { 513 struct nsip_req rq; 514 int size = sizeof(rq); 515 516 rq.rq_ns = addreq.ifra_addr; 517 rq.rq_ip = addreq.ifra_dstaddr; 518 519 if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0) 520 Perror("Encapsulation Routing"); 521 } 522#endif 523 if (clearaddr) { 524 if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { 525 warnx("interface %s cannot change %s addresses!", 526 name, afp->af_name); 527 clearaddr = NULL; 528 } 529 } 530 if (clearaddr) { 531 int ret; 532 strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name); 533 if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) { 534 if (errno == EADDRNOTAVAIL && (doalias >= 0)) { 535 /* means no previous address for interface */ 536 } else 537 Perror("ioctl (SIOCDIFADDR)"); 538 } 539 } 540 if (newaddr) { 541 if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { 542 warnx("interface %s cannot change %s addresses!", 543 name, afp->af_name); 544 newaddr = NULL; 545 } 546 } 547 if (newaddr) { 548 strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); 549 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) 550 Perror("ioctl (SIOCAIFADDR)"); 551 } 552 close(s); 553 return(0); 554} 555#define RIDADDR 0 556#define ADDR 1 557#define MASK 2 558#define DSTADDR 3 559 560/*ARGSUSED*/ 561void 562setifaddr(addr, param, s, afp) 563 const char *addr; 564 int param; 565 int s; 566 const struct afswtch *afp; 567{ 568 /* 569 * Delay the ioctl to set the interface addr until flags are all set. 570 * The address interpretation may depend on the flags, 571 * and the flags may change when the address is set. 572 */ 573 setaddr++; 574 if (doalias == 0) 575 clearaddr = 1; 576 (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR)); 577} 578 579void 580setifnetmask(addr, dummy, s, afp) 581 const char *addr; 582 int dummy __unused; 583 int s; 584 const struct afswtch *afp; 585{ 586 (*afp->af_getaddr)(addr, MASK); 587} 588 589void 590setifbroadaddr(addr, dummy, s, afp) 591 const char *addr; 592 int dummy __unused; 593 int s; 594 const struct afswtch *afp; 595{ 596 (*afp->af_getaddr)(addr, DSTADDR); 597} 598 599void 600setifipdst(addr, dummy, s, afp) 601 const char *addr; 602 int dummy __unused; 603 int s; 604 const struct afswtch *afp; 605{ 606 in_getaddr(addr, DSTADDR); 607 setipdst++; 608 clearaddr = 0; 609 newaddr = 0; 610} 611#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) 612 613void 614notealias(addr, param, s, afp) 615 const char *addr; 616 int param; 617 int s; 618 const struct afswtch *afp; 619{ 620 if (setaddr && doalias == 0 && param < 0) 621 bcopy((caddr_t)rqtosa(af_addreq), 622 (caddr_t)rqtosa(af_ridreq), 623 rqtosa(af_addreq)->sa_len); 624 doalias = param; 625 if (param < 0) { 626 clearaddr = 1; 627 newaddr = 0; 628 } else 629 clearaddr = 0; 630} 631 632/*ARGSUSED*/ 633void 634setifdstaddr(addr, param, s, afp) 635 const char *addr; 636 int param __unused; 637 int s; 638 const struct afswtch *afp; 639{ 640 (*afp->af_getaddr)(addr, DSTADDR); 641} 642 643/* 644 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion 645 * of the ifreq structure, which may confuse other parts of ifconfig. 646 * Make a private copy so we can avoid that. 647 */ 648void 649setifflags(vname, value, s, afp) 650 const char *vname; 651 int value; 652 int s; 653 const struct afswtch *afp; 654{ 655 struct ifreq my_ifr; 656 657 bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq)); 658 659 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { 660 Perror("ioctl (SIOCGIFFLAGS)"); 661 exit(1); 662 } 663 strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name)); 664 flags = my_ifr.ifr_flags; 665 666 if (value < 0) { 667 value = -value; 668 flags &= ~value; 669 } else 670 flags |= value; 671 my_ifr.ifr_flags = flags; 672 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) 673 Perror(vname); 674} 675 676void 677setifmetric(val, dummy, s, afp) 678 const char *val; 679 int dummy __unused; 680 int s; 681 const struct afswtch *afp; 682{ 683 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 684 ifr.ifr_metric = atoi(val); 685 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) 686 warn("ioctl (set metric)"); 687} 688 689void 690setifmtu(val, dummy, s, afp) 691 const char *val; 692 int dummy __unused; 693 int s; 694 const struct afswtch *afp; 695{ 696 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 697 ifr.ifr_mtu = atoi(val); 698 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) 699 warn("ioctl (set mtu)"); 700} 701 702 703#define IFFBITS \ 704"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ 705"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ 706"\20MULTICAST" 707 708/* 709 * Print the status of the interface. If an address family was 710 * specified, show it and it only; otherwise, show them all. 711 */ 712void 713status(afp, addrcount, sdl, ifm, ifam) 714 const struct afswtch *afp; 715 int addrcount; 716 struct sockaddr_dl *sdl; 717 struct if_msghdr *ifm; 718 struct ifa_msghdr *ifam; 719{ 720 const struct afswtch *p = NULL; 721 struct rt_addrinfo info; 722 int allfamilies, s; 723 struct ifstat ifs; 724 725 if (afp == NULL) { 726 allfamilies = 1; 727 afp = &afs[0]; 728 } else 729 allfamilies = 0; 730 731 ifr.ifr_addr.sa_family = afp->af_af; 732 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); 733 734 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) 735 err(1, "socket"); 736 737 /* 738 * XXX is it we are doing a SIOCGIFMETRIC etc for one family. 739 * is it possible that the metric and mtu can be different for 740 * each family? If so, we have a format problem, because the 741 * metric and mtu is printed on the global the flags line. 742 */ 743 if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0) 744 warn("ioctl (SIOCGIFMETRIC)"); 745 else 746 metric = ifr.ifr_metric; 747 748 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) 749 warn("ioctl (SIOCGIFMTU)"); 750 else 751 mtu = ifr.ifr_mtu; 752 753 printf("%s: ", name); 754 printb("flags", flags, IFFBITS); 755 if (metric) 756 printf(" metric %d", metric); 757 if (mtu) 758 printf(" mtu %d", mtu); 759 putchar('\n'); 760 761 while (addrcount > 0) { 762 763 info.rti_addrs = ifam->ifam_addrs; 764 765 /* Expand the compacted addresses */ 766 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, 767 &info); 768 769 if (!allfamilies) { 770 if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family && 771#ifdef USE_IF_MEDIA 772 afp->af_status != media_status && 773#endif 774#ifdef USE_VLANS 775 afp->af_status != vlan_status && 776#endif 777 afp->af_status != ether_status) { 778 p = afp; 779 (*p->af_status)(s, &info); 780 } 781 } else for (p = afs; p->af_name; p++) { 782 if (p->af_af == info.rti_info[RTAX_IFA]->sa_family && 783#ifdef USE_IF_MEDIA 784 p->af_status != media_status && 785#endif 786#ifdef USE_VLANS 787 p->af_status != vlan_status && 788#endif 789 p->af_status != ether_status) 790 (*p->af_status)(s, &info); 791 } 792 addrcount--; 793 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); 794 } 795 if (allfamilies || afp->af_status == ether_status) 796 ether_status(s, (struct rt_addrinfo *)sdl); 797#ifdef USE_IF_MEDIA 798 if (allfamilies || afp->af_status == media_status) 799 media_status(s, NULL); 800#endif 801#ifdef USE_VLANS 802 if (allfamilies || afp->af_status == vlan_status) 803 vlan_status(s, NULL); 804#endif 805 strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); 806 if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 807 printf("%s", ifs.ascii); 808 809 if (!allfamilies && !p && afp->af_status != media_status && 810 afp->af_status != ether_status && afp->af_status != vlan_status) 811 warnx("%s has no %s interface address!", name, afp->af_name); 812 813 close(s); 814 return; 815} 816 817void 818in_status(s, info) 819 int s __unused; 820 struct rt_addrinfo * info; 821{ 822 struct sockaddr_in *sin, null_sin; 823 824 memset(&null_sin, 0, sizeof(null_sin)); 825 826 sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA]; 827 printf("\tinet %s ", inet_ntoa(sin->sin_addr)); 828 829 if (flags & IFF_POINTOPOINT) { 830 /* note RTAX_BRD overlap with IFF_BROADCAST */ 831 sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD]; 832 if (!sin) 833 sin = &null_sin; 834 printf("--> %s ", inet_ntoa(sin->sin_addr)); 835 } 836 837 sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK]; 838 if (!sin) 839 sin = &null_sin; 840 printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); 841 842 if (flags & IFF_BROADCAST) { 843 /* note RTAX_BRD overlap with IFF_POINTOPOINT */ 844 sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD]; 845 if (sin && sin->sin_addr.s_addr != 0) 846 printf("broadcast %s", inet_ntoa(sin->sin_addr)); 847 } 848 putchar('\n'); 849} 850 851void 852ipx_status(s, info) 853 int s __unused; 854 struct rt_addrinfo * info; 855{ 856 struct sockaddr_ipx *sipx, null_sipx; 857 858 memset(&null_sipx, 0, sizeof(null_sipx)); 859 860 sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA]; 861 printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr)); 862 863 if (flags & IFF_POINTOPOINT) { 864 sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD]; 865 if (!sipx) 866 sipx = &null_sipx; 867 printf("--> %s ", ipx_ntoa(sipx->sipx_addr)); 868 } 869 putchar('\n'); 870} 871 872void 873at_status(s, info) 874 int s __unused; 875 struct rt_addrinfo * info; 876{ 877 struct sockaddr_at *sat, null_sat; 878 struct netrange *nr; 879 880 memset(&null_sat, 0, sizeof(null_sat)); 881 882 sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA]; 883 nr = &sat->sat_range.r_netrange; 884 printf("\tatalk %d.%d range %d-%d phase %d", 885 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, 886 ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase); 887 if (flags & IFF_POINTOPOINT) { 888 /* note RTAX_BRD overlap with IFF_BROADCAST */ 889 sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD]; 890 if (!sat) 891 sat = &null_sat; 892 printf("--> %d.%d", 893 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 894 } 895 if (flags & IFF_BROADCAST) { 896 /* note RTAX_BRD overlap with IFF_POINTOPOINT */ 897 sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD]; 898 if (sat) 899 printf(" broadcast %d.%d", 900 ntohs(sat->sat_addr.s_net), 901 sat->sat_addr.s_node); 902 } 903 904 putchar('\n'); 905} 906 907#ifdef NS 908void 909xns_status(s, info) 910 int s __unused; 911 struct rt_addrinfo * info; 912{ 913 struct sockaddr_ns *sns, null_sns; 914 915 memset(&null_sns, 0, sizeof(null_sns)); 916 917 sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA]; 918 printf("\tns %s ", ns_ntoa(sns->sns_addr)); 919 920 if (flags & IFF_POINTOPOINT) { 921 sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD]; 922 if (!sns) 923 sns = &null_sns; 924 printf("--> %s ", ns_ntoa(sns->sns_addr)); 925 } 926 927 putchar('\n'); 928 close(s); 929} 930#endif 931 932 933void 934ether_status(s, info) 935 int s __unused; 936 struct rt_addrinfo *info; 937{ 938 char *cp; 939 int n; 940 struct sockaddr_dl *sdl = (struct sockaddr_dl *)info; 941 942 cp = (char *)LLADDR(sdl); 943 if ((n = sdl->sdl_alen) > 0) { 944 if (sdl->sdl_type == IFT_ETHER) 945 printf ("\tether "); 946 else 947 printf ("\tlladdr "); 948 while (--n >= 0) 949 printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' '); 950 putchar('\n'); 951 } 952} 953 954void 955Perror(cmd) 956 const char *cmd; 957{ 958 switch (errno) { 959 960 case ENXIO: 961 errx(1, "%s: no such interface", cmd); 962 break; 963 964 case EPERM: 965 errx(1, "%s: permission denied", cmd); 966 break; 967 968 default: 969 err(1, "%s", cmd); 970 } 971} 972 973#define SIN(x) ((struct sockaddr_in *) &(x)) 974struct sockaddr_in *sintab[] = { 975SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr), 976SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)}; 977 978void 979in_getaddr(s, which) 980 const char *s; 981 int which; 982{ 983 register struct sockaddr_in *sin = sintab[which]; 984 struct hostent *hp; 985 struct netent *np; 986 987 sin->sin_len = sizeof(*sin); 988 if (which != MASK) 989 sin->sin_family = AF_INET; 990 991 if (inet_aton(s, &sin->sin_addr)) 992 return; 993 if ((hp = gethostbyname(s)) != 0) 994 bcopy(hp->h_addr, (char *)&sin->sin_addr, 995 MIN(hp->h_length, sizeof(sin->sin_addr))); 996 else if ((np = getnetbyname(s)) != 0) 997 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 998 else 999 errx(1, "%s: bad value", s); 1000} 1001 1002/* 1003 * Print a value a la the %b format of the kernel's printf 1004 */ 1005void 1006printb(s, v, bits) 1007 const char *s; 1008 register unsigned v; 1009 register const char *bits; 1010{ 1011 register int i, any = 0; 1012 register char c; 1013 1014 if (bits && *bits == 8) 1015 printf("%s=%o", s, v); 1016 else 1017 printf("%s=%x", s, v); 1018 bits++; 1019 if (bits) { 1020 putchar('<'); 1021 while ((i = *bits++) != '\0') { 1022 if (v & (1 << (i-1))) { 1023 if (any) 1024 putchar(','); 1025 any = 1; 1026 for (; (c = *bits) > 32; bits++) 1027 putchar(c); 1028 } else 1029 for (; *bits > 32; bits++) 1030 ; 1031 } 1032 putchar('>'); 1033 } 1034} 1035 1036#define SIPX(x) ((struct sockaddr_ipx *) &(x)) 1037struct sockaddr_ipx *sipxtab[] = { 1038SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr), 1039SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)}; 1040 1041void 1042ipx_getaddr(addr, which) 1043 const char *addr; 1044 int which; 1045{ 1046 struct sockaddr_ipx *sipx = sipxtab[which]; 1047 1048 sipx->sipx_family = AF_IPX; 1049 sipx->sipx_len = sizeof(*sipx); 1050 sipx->sipx_addr = ipx_addr(addr); 1051 if (which == MASK) 1052 printf("Attempt to set IPX netmask will be ineffectual\n"); 1053} 1054 1055void 1056at_getaddr(addr, which) 1057 const char *addr; 1058 int which; 1059{ 1060 struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr; 1061 u_int net, node; 1062 1063 sat->sat_family = AF_APPLETALK; 1064 sat->sat_len = sizeof(*sat); 1065 if (which == MASK) 1066 errx(1, "AppleTalk does not use netmasks"); 1067 if (sscanf(addr, "%u.%u", &net, &node) != 2 1068 || net > 0xffff || node > 0xfe) 1069 errx(1, "%s: illegal address", addr); 1070 sat->sat_addr.s_net = htons(net); 1071 sat->sat_addr.s_node = node; 1072} 1073 1074/* XXX FIXME -- should use strtoul for better parsing. */ 1075void 1076setatrange(range, dummy, s, afp) 1077 const char *range; 1078 int dummy __unused; 1079 int s; 1080 const struct afswtch *afp; 1081{ 1082 u_short first = 123, last = 123; 1083 1084 if (sscanf(range, "%hu-%hu", &first, &last) != 2 1085 || first == 0 || first > 0xffff 1086 || last == 0 || last > 0xffff || first > last) 1087 errx(1, "%s: illegal net range: %u-%u", range, first, last); 1088 at_nr.nr_firstnet = htons(first); 1089 at_nr.nr_lastnet = htons(last); 1090} 1091 1092void 1093setatphase(phase, dummy, s, afp) 1094 const char *phase; 1095 int dummy __unused; 1096 int s; 1097 const struct afswtch *afp; 1098{ 1099 if (!strcmp(phase, "1")) 1100 at_nr.nr_phase = 1; 1101 else if (!strcmp(phase, "2")) 1102 at_nr.nr_phase = 2; 1103 else 1104 errx(1, "%s: illegal phase", phase); 1105} 1106 1107void 1108checkatrange(struct sockaddr_at *sat) 1109{ 1110 if (at_nr.nr_phase == 0) 1111 at_nr.nr_phase = 2; /* Default phase 2 */ 1112 if (at_nr.nr_firstnet == 0) 1113 at_nr.nr_firstnet = /* Default range of one */ 1114 at_nr.nr_lastnet = sat->sat_addr.s_net; 1115printf("\tatalk %d.%d range %d-%d phase %d\n", 1116 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, 1117 ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase); 1118 if ((u_short) ntohs(at_nr.nr_firstnet) > 1119 (u_short) ntohs(sat->sat_addr.s_net) 1120 || (u_short) ntohs(at_nr.nr_lastnet) < 1121 (u_short) ntohs(sat->sat_addr.s_net)) 1122 errx(1, "AppleTalk address is not in range"); 1123 sat->sat_range.r_netrange = at_nr; 1124} 1125 1126#ifdef NS 1127#define SNS(x) ((struct sockaddr_ns *) &(x)) 1128struct sockaddr_ns *snstab[] = { 1129SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr), 1130SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)}; 1131 1132void 1133xns_getaddr(addr, which) 1134 const char *addr; 1135 int which; 1136{ 1137 struct sockaddr_ns *sns = snstab[which]; 1138 1139 sns->sns_family = AF_NS; 1140 sns->sns_len = sizeof(*sns); 1141 sns->sns_addr = ns_addr(addr); 1142 if (which == MASK) 1143 printf("Attempt to set XNS netmask will be ineffectual\n"); 1144} 1145#endif 1146 1147