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