1 /* 2 * Copyright (c) 1983, 1988, 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 /* 36 static char sccsid[] = "@(#)if.c 8.3 (Berkeley) 4/28/95"; 37 */ 38 static const char rcsid[] = 39 "$FreeBSD$"; 40 #endif /* not lint */ 41 42 #include <sys/types.h> 43 #include <sys/protosw.h> 44 #include <sys/socket.h> 45 #include <sys/sysctl.h> 46 #include <sys/time.h> 47 48 #include <net/if.h> 49 #include <net/if_var.h> 50 #include <net/if_dl.h> 51 #include <net/if_types.h> 52 #include <net/bridge.h> 53 #include <net/ethernet.h> 54 #include <netinet/in.h> 55 #include <netinet/in_var.h> 56 #include <netipx/ipx.h> 57 #include <netipx/ipx_if.h> 58 #include <arpa/inet.h> 59 60 #include <signal.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <unistd.h> 65 66 #include "netstat.h" 67 68 #define YES 1 69 #define NO 0 70 71 static void sidewaysintpr (u_int, u_long); 72 static void catchalarm (int); 73 74 #ifdef INET6 75 static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */ 76 static int bdg_done; 77 #endif 78 79 /* print bridge statistics */ 80 void 81 bdg_stats(u_long dummy __unused, const char *name, int af1 __unused) 82 { 83 int i; 84 size_t slen ; 85 struct bdg_stats s ; 86 int mib[4] ; 87 88 slen = sizeof(s); 89 90 mib[0] = CTL_NET ; 91 mib[1] = PF_LINK ; 92 mib[2] = IFT_ETHER ; 93 mib[3] = PF_BDG ; 94 if (sysctl(mib,4, &s,&slen,NULL,0)==-1) 95 return ; /* no bridging */ 96 #ifdef INET6 97 if (bdg_done != 0) 98 return; 99 else 100 bdg_done = 1; 101 #endif 102 printf("-- Bridging statistics (%s) --\n", name) ; 103 printf( 104 "Name In Out Forward Drop Bcast Mcast Local Unknown\n"); 105 for (i = 0 ; i < 16 ; i++) { 106 if (s.s[i].name[0]) 107 printf("%-6s %9ld%9ld%9ld%9ld%9ld%9ld%9ld%9ld\n", 108 s.s[i].name, 109 s.s[i].p_in[(int)BDG_IN], 110 s.s[i].p_in[(int)BDG_OUT], 111 s.s[i].p_in[(int)BDG_FORWARD], 112 s.s[i].p_in[(int)BDG_DROP], 113 s.s[i].p_in[(int)BDG_BCAST], 114 s.s[i].p_in[(int)BDG_MCAST], 115 s.s[i].p_in[(int)BDG_LOCAL], 116 s.s[i].p_in[(int)BDG_UNKNOWN] ); 117 } 118 } 119 120 121 122 123 /* 124 * Display a formatted value, or a '-' in the same space. 125 */ 126 static void 127 show_stat(const char *fmt, int width, u_long value, short showvalue) 128 { 129 char newfmt[32]; 130 131 /* Construct the format string */ 132 if (showvalue) { 133 sprintf(newfmt, "%%%d%s", width, fmt); 134 printf(newfmt, value); 135 } else { 136 sprintf(newfmt, "%%%ds", width); 137 printf(newfmt, "-"); 138 } 139 } 140 141 142 143 /* 144 * Print a description of the network interfaces. 145 */ 146 void 147 intpr(int _interval, u_long ifnetaddr, void (*pfunc)(char *)) 148 { 149 struct ifnet ifnet; 150 struct ifnethead ifnethead; 151 union { 152 struct ifaddr ifa; 153 struct in_ifaddr in; 154 #ifdef INET6 155 struct in6_ifaddr in6; 156 #endif 157 struct ipx_ifaddr ipx; 158 } ifaddr; 159 u_long ifaddraddr; 160 u_long ifaddrfound; 161 u_long ifnetfound; 162 u_long opackets; 163 u_long ipackets; 164 u_long obytes; 165 u_long ibytes; 166 u_long oerrors; 167 u_long ierrors; 168 u_long collisions; 169 short timer; 170 int drops; 171 struct sockaddr *sa = NULL; 172 char name[IFNAMSIZ]; 173 short network_layer; 174 short link_layer; 175 176 if (ifnetaddr == 0) { 177 printf("ifnet: symbol not defined\n"); 178 return; 179 } 180 if (_interval) { 181 sidewaysintpr((unsigned)_interval, ifnetaddr); 182 return; 183 } 184 if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead)) 185 return; 186 ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead); 187 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 188 return; 189 190 if (!pfunc) { 191 if (Wflag) 192 printf("%-7.7s", "Name"); 193 else 194 printf("%-5.5s", "Name"); 195 printf(" %5.5s %-13.13s %-17.17s %8.8s %5.5s", 196 "Mtu", "Network", "Address", "Ipkts", "Ierrs"); 197 if (bflag) 198 printf(" %10.10s","Ibytes"); 199 printf(" %8.8s %5.5s", "Opkts", "Oerrs"); 200 if (bflag) 201 printf(" %10.10s","Obytes"); 202 printf(" %5s", "Coll"); 203 if (tflag) 204 printf(" %s", "Time"); 205 if (dflag) 206 printf(" %s", "Drop"); 207 putchar('\n'); 208 } 209 ifaddraddr = 0; 210 while (ifnetaddr || ifaddraddr) { 211 struct sockaddr_in *sin; 212 #ifdef INET6 213 struct sockaddr_in6 *sin6; 214 #endif 215 char *cp; 216 int n, m; 217 218 network_layer = 0; 219 link_layer = 0; 220 221 if (ifaddraddr == 0) { 222 ifnetfound = ifnetaddr; 223 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 224 return; 225 strlcpy(name, ifnet.if_xname, sizeof(name)); 226 ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link); 227 if (interface != 0 && (strcmp(name, interface) != 0)) 228 continue; 229 cp = index(name, '\0'); 230 231 if (pfunc) { 232 (*pfunc)(name); 233 continue; 234 } 235 236 if ((ifnet.if_flags&IFF_UP) == 0) 237 *cp++ = '*'; 238 *cp = '\0'; 239 ifaddraddr = (u_long)TAILQ_FIRST(&ifnet.if_addrhead); 240 } 241 ifaddrfound = ifaddraddr; 242 243 /* 244 * Get the interface stats. These may get 245 * overriden below on a per-interface basis. 246 */ 247 opackets = ifnet.if_opackets; 248 ipackets = ifnet.if_ipackets; 249 obytes = ifnet.if_obytes; 250 ibytes = ifnet.if_ibytes; 251 oerrors = ifnet.if_oerrors; 252 ierrors = ifnet.if_ierrors; 253 collisions = ifnet.if_collisions; 254 timer = ifnet.if_timer; 255 drops = ifnet.if_snd.ifq_drops; 256 257 if (ifaddraddr == 0) { 258 if (Wflag) 259 printf("%-7.7s", name); 260 else 261 printf("%-5.5s", name); 262 printf(" %5lu ", ifnet.if_mtu); 263 printf("%-13.13s ", "none"); 264 printf("%-17.17s ", "none"); 265 } else { 266 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 267 ifaddraddr = 0; 268 continue; 269 } 270 #define CP(x) ((char *)(x)) 271 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 272 CP(&ifaddr); 273 sa = (struct sockaddr *)cp; 274 if (af != AF_UNSPEC && sa->sa_family != af) { 275 ifaddraddr = 276 (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link); 277 continue; 278 } 279 if (Wflag) 280 printf("%-7.7s", name); 281 else 282 printf("%-5.5s", name); 283 printf(" %5lu ", ifnet.if_mtu); 284 switch (sa->sa_family) { 285 case AF_UNSPEC: 286 printf("%-13.13s ", "none"); 287 printf("%-15.15s ", "none"); 288 break; 289 case AF_INET: 290 sin = (struct sockaddr_in *)sa; 291 #ifdef notdef 292 /* can't use inet_makeaddr because kernel 293 * keeps nets unshifted. 294 */ 295 in = inet_makeaddr(ifaddr.in.ia_subnet, 296 INADDR_ANY); 297 printf("%-13.13s ", netname(in.s_addr, 298 ifaddr.in.ia_subnetmask)); 299 #else 300 printf("%-13.13s ", 301 netname(htonl(ifaddr.in.ia_subnet), 302 ifaddr.in.ia_subnetmask)); 303 #endif 304 printf("%-17.17s ", 305 routename(sin->sin_addr.s_addr)); 306 307 network_layer = 1; 308 break; 309 #ifdef INET6 310 case AF_INET6: 311 sin6 = (struct sockaddr_in6 *)sa; 312 printf("%-13.13s ", 313 netname6(&ifaddr.in6.ia_addr, 314 &ifaddr.in6.ia_prefixmask.sin6_addr)); 315 printf("%-17.17s ", 316 inet_ntop(AF_INET6, 317 &sin6->sin6_addr, 318 ntop_buf, sizeof(ntop_buf))); 319 320 network_layer = 1; 321 break; 322 #endif /*INET6*/ 323 case AF_IPX: 324 { 325 struct sockaddr_ipx *sipx = 326 (struct sockaddr_ipx *)sa; 327 u_long net; 328 char netnum[10]; 329 330 *(union ipx_net *) &net = sipx->sipx_addr.x_net; 331 sprintf(netnum, "%lx", (u_long)ntohl(net)); 332 printf("ipx:%-8s ", netnum); 333 /* printf("ipx:%-8s ", netname(net, 0L)); */ 334 printf("%-17s ", 335 ipx_phost((struct sockaddr *)sipx)); 336 } 337 338 network_layer = 1; 339 break; 340 341 case AF_APPLETALK: 342 printf("atalk:%-12.12s ",atalk_print(sa,0x10) ); 343 printf("%-11.11s ",atalk_print(sa,0x0b) ); 344 break; 345 case AF_LINK: 346 { 347 struct sockaddr_dl *sdl = 348 (struct sockaddr_dl *)sa; 349 char linknum[10]; 350 cp = (char *)LLADDR(sdl); 351 n = sdl->sdl_alen; 352 sprintf(linknum, "<Link#%d>", sdl->sdl_index); 353 m = printf("%-13.13s ", linknum); 354 } 355 goto hexprint; 356 default: 357 m = printf("(%d)", sa->sa_family); 358 for (cp = sa->sa_len + (char *)sa; 359 --cp > sa->sa_data && (*cp == 0);) {} 360 n = cp - sa->sa_data + 1; 361 cp = sa->sa_data; 362 hexprint: 363 while (--n >= 0) 364 m += printf("%02x%c", *cp++ & 0xff, 365 n > 0 ? ':' : ' '); 366 m = 32 - m; 367 while (m-- > 0) 368 putchar(' '); 369 370 link_layer = 1; 371 break; 372 } 373 374 /* 375 * Fixup the statistics for interfaces that 376 * update stats for their network addresses 377 */ 378 if (network_layer) { 379 opackets = ifaddr.in.ia_ifa.if_opackets; 380 ipackets = ifaddr.in.ia_ifa.if_ipackets; 381 obytes = ifaddr.in.ia_ifa.if_obytes; 382 ibytes = ifaddr.in.ia_ifa.if_ibytes; 383 } 384 385 ifaddraddr = (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link); 386 } 387 388 show_stat("lu", 8, ipackets, link_layer|network_layer); 389 printf(" "); 390 show_stat("lu", 5, ierrors, link_layer); 391 printf(" "); 392 if (bflag) { 393 show_stat("lu", 10, ibytes, link_layer|network_layer); 394 printf(" "); 395 } 396 show_stat("lu", 8, opackets, link_layer|network_layer); 397 printf(" "); 398 show_stat("lu", 5, oerrors, link_layer); 399 printf(" "); 400 if (bflag) { 401 show_stat("lu", 10, obytes, link_layer|network_layer); 402 printf(" "); 403 } 404 show_stat("lu", 5, collisions, link_layer); 405 if (tflag) { 406 printf(" "); 407 show_stat("d", 3, timer, link_layer); 408 } 409 if (dflag) { 410 printf(" "); 411 show_stat("d", 3, drops, link_layer); 412 } 413 putchar('\n'); 414 if (aflag && ifaddrfound) { 415 /* 416 * Print family's multicast addresses 417 */ 418 struct ifmultiaddr *multiaddr; 419 struct ifmultiaddr ifma; 420 union { 421 struct sockaddr sa; 422 struct sockaddr_in in; 423 #ifdef INET6 424 struct sockaddr_in6 in6; 425 #endif /* INET6 */ 426 struct sockaddr_dl dl; 427 } msa; 428 const char *fmt; 429 430 TAILQ_FOREACH(multiaddr, &ifnet.if_multiaddrs, ifma_link) { 431 if (kread((u_long)multiaddr, (char *)&ifma, 432 sizeof ifma)) 433 break; 434 multiaddr = &ifma; 435 if (kread((u_long)ifma.ifma_addr, (char *)&msa, 436 sizeof msa)) 437 break; 438 if (msa.sa.sa_family != sa->sa_family) 439 continue; 440 441 fmt = 0; 442 switch (msa.sa.sa_family) { 443 case AF_INET: 444 fmt = routename(msa.in.sin_addr.s_addr); 445 break; 446 #ifdef INET6 447 case AF_INET6: 448 printf("%23s %-19.19s(refs: %d)\n", "", 449 inet_ntop(AF_INET6, 450 &msa.in6.sin6_addr, 451 ntop_buf, 452 sizeof(ntop_buf)), 453 ifma.ifma_refcount); 454 break; 455 #endif /* INET6 */ 456 case AF_LINK: 457 switch (msa.dl.sdl_type) { 458 case IFT_ETHER: 459 case IFT_FDDI: 460 fmt = ether_ntoa( 461 (struct ether_addr *) 462 LLADDR(&msa.dl)); 463 break; 464 } 465 break; 466 } 467 if (fmt) 468 printf("%23s %s\n", "", fmt); 469 } 470 } 471 } 472 } 473 474 struct iftot { 475 SLIST_ENTRY(iftot) chain; 476 char ift_name[IFNAMSIZ]; /* interface name */ 477 u_long ift_ip; /* input packets */ 478 u_long ift_ie; /* input errors */ 479 u_long ift_op; /* output packets */ 480 u_long ift_oe; /* output errors */ 481 u_long ift_co; /* collisions */ 482 u_int ift_dr; /* drops */ 483 u_long ift_ib; /* input bytes */ 484 u_long ift_ob; /* output bytes */ 485 }; 486 487 u_char signalled; /* set if alarm goes off "early" */ 488 489 /* 490 * Print a running summary of interface statistics. 491 * Repeat display every interval seconds, showing statistics 492 * collected over that interval. Assumes that interval is non-zero. 493 * First line printed at top of screen is always cumulative. 494 * XXX - should be rewritten to use ifmib(4). 495 */ 496 static void 497 sidewaysintpr(unsigned interval1, u_long off) 498 { 499 struct ifnet ifnet; 500 u_long firstifnet; 501 struct ifnethead ifnethead; 502 struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting; 503 int line; 504 int oldmask, first; 505 u_long interesting_off; 506 507 if (kread(off, (char *)&ifnethead, sizeof ifnethead)) 508 return; 509 firstifnet = (u_long)TAILQ_FIRST(&ifnethead); 510 511 if ((iftot = malloc(sizeof(struct iftot))) == NULL) { 512 printf("malloc failed\n"); 513 exit(1); 514 } 515 memset(iftot, 0, sizeof(struct iftot)); 516 517 interesting = NULL; 518 interesting_off = 0; 519 for (off = firstifnet, ip = iftot; off;) { 520 char name[IFNAMSIZ]; 521 522 if (kread(off, (char *)&ifnet, sizeof ifnet)) 523 break; 524 strlcpy(name, ifnet.if_xname, sizeof(name)); 525 if (interface && strcmp(name, interface) == 0) { 526 interesting = ip; 527 interesting_off = off; 528 } 529 snprintf(ip->ift_name, sizeof(ip->ift_name), "(%s)", name);; 530 if ((ipn = malloc(sizeof(struct iftot))) == NULL) { 531 printf("malloc failed\n"); 532 exit(1); 533 } 534 memset(ipn, 0, sizeof(struct iftot)); 535 SLIST_NEXT(ip, chain) = ipn; 536 ip = ipn; 537 off = (u_long)TAILQ_NEXT(&ifnet, if_link); 538 } 539 if ((total = malloc(sizeof(struct iftot))) == NULL) { 540 printf("malloc failed\n"); 541 exit(1); 542 } 543 memset(total, 0, sizeof(struct iftot)); 544 if ((sum = malloc(sizeof(struct iftot))) == NULL) { 545 printf("malloc failed\n"); 546 exit(1); 547 } 548 memset(sum, 0, sizeof(struct iftot)); 549 550 (void)signal(SIGALRM, catchalarm); 551 signalled = NO; 552 (void)alarm(interval1); 553 first = 1; 554 banner: 555 printf("%17s %14s %16s", "input", 556 interesting ? interesting->ift_name : "(Total)", "output"); 557 putchar('\n'); 558 printf("%10s %5s %10s %10s %5s %10s %5s", 559 "packets", "errs", "bytes", "packets", "errs", "bytes", "colls"); 560 if (dflag) 561 printf(" %5.5s", "drops"); 562 putchar('\n'); 563 fflush(stdout); 564 line = 0; 565 loop: 566 if (interesting != NULL) { 567 ip = interesting; 568 if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) { 569 printf("???\n"); 570 exit(1); 571 }; 572 if (!first) { 573 printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", 574 ifnet.if_ipackets - ip->ift_ip, 575 ifnet.if_ierrors - ip->ift_ie, 576 ifnet.if_ibytes - ip->ift_ib, 577 ifnet.if_opackets - ip->ift_op, 578 ifnet.if_oerrors - ip->ift_oe, 579 ifnet.if_obytes - ip->ift_ob, 580 ifnet.if_collisions - ip->ift_co); 581 if (dflag) 582 printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr); 583 } 584 ip->ift_ip = ifnet.if_ipackets; 585 ip->ift_ie = ifnet.if_ierrors; 586 ip->ift_ib = ifnet.if_ibytes; 587 ip->ift_op = ifnet.if_opackets; 588 ip->ift_oe = ifnet.if_oerrors; 589 ip->ift_ob = ifnet.if_obytes; 590 ip->ift_co = ifnet.if_collisions; 591 ip->ift_dr = ifnet.if_snd.ifq_drops; 592 } else { 593 sum->ift_ip = 0; 594 sum->ift_ie = 0; 595 sum->ift_ib = 0; 596 sum->ift_op = 0; 597 sum->ift_oe = 0; 598 sum->ift_ob = 0; 599 sum->ift_co = 0; 600 sum->ift_dr = 0; 601 for (off = firstifnet, ip = iftot; 602 off && SLIST_NEXT(ip, chain) != NULL; 603 ip = SLIST_NEXT(ip, chain)) { 604 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 605 off = 0; 606 continue; 607 } 608 sum->ift_ip += ifnet.if_ipackets; 609 sum->ift_ie += ifnet.if_ierrors; 610 sum->ift_ib += ifnet.if_ibytes; 611 sum->ift_op += ifnet.if_opackets; 612 sum->ift_oe += ifnet.if_oerrors; 613 sum->ift_ob += ifnet.if_obytes; 614 sum->ift_co += ifnet.if_collisions; 615 sum->ift_dr += ifnet.if_snd.ifq_drops; 616 off = (u_long)TAILQ_NEXT(&ifnet, if_link); 617 } 618 if (!first) { 619 printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", 620 sum->ift_ip - total->ift_ip, 621 sum->ift_ie - total->ift_ie, 622 sum->ift_ib - total->ift_ib, 623 sum->ift_op - total->ift_op, 624 sum->ift_oe - total->ift_oe, 625 sum->ift_ob - total->ift_ob, 626 sum->ift_co - total->ift_co); 627 if (dflag) 628 printf(" %5u", sum->ift_dr - total->ift_dr); 629 } 630 *total = *sum; 631 } 632 if (!first) 633 putchar('\n'); 634 fflush(stdout); 635 oldmask = sigblock(sigmask(SIGALRM)); 636 if (! signalled) { 637 sigpause(0); 638 } 639 sigsetmask(oldmask); 640 signalled = NO; 641 (void)alarm(interval1); 642 line++; 643 first = 0; 644 if (line == 21) 645 goto banner; 646 else 647 goto loop; 648 /*NOTREACHED*/ 649 } 650 651 /* 652 * Called if an interval expires before sidewaysintpr has completed a loop. 653 * Sets a flag to not wait for the alarm. 654 */ 655 static void 656 catchalarm(int signo __unused) 657 { 658 signalled = YES; 659 } 660