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 printf("%-5.5s %5.5s %-13.13s %-17.17s %8.8s %5.5s", 192 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); 193 if (bflag) 194 printf(" %10.10s","Ibytes"); 195 printf(" %8.8s %5.5s", "Opkts", "Oerrs"); 196 if (bflag) 197 printf(" %10.10s","Obytes"); 198 printf(" %5s", "Coll"); 199 if (tflag) 200 printf(" %s", "Time"); 201 if (dflag) 202 printf(" %s", "Drop"); 203 putchar('\n'); 204 } 205 ifaddraddr = 0; 206 while (ifnetaddr || ifaddraddr) { 207 struct sockaddr_in *sin; 208 #ifdef INET6 209 struct sockaddr_in6 *sin6; 210 #endif 211 char *cp; 212 int n, m; 213 214 network_layer = 0; 215 link_layer = 0; 216 217 if (ifaddraddr == 0) { 218 ifnetfound = ifnetaddr; 219 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 220 return; 221 strlcpy(name, ifnet.if_xname, sizeof(name)); 222 ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link); 223 if (interface != 0 && (strcmp(name, interface) != 0)) 224 continue; 225 cp = index(name, '\0'); 226 227 if (pfunc) { 228 (*pfunc)(name); 229 continue; 230 } 231 232 if ((ifnet.if_flags&IFF_UP) == 0) 233 *cp++ = '*'; 234 *cp = '\0'; 235 ifaddraddr = (u_long)TAILQ_FIRST(&ifnet.if_addrhead); 236 } 237 ifaddrfound = ifaddraddr; 238 239 /* 240 * Get the interface stats. These may get 241 * overriden below on a per-interface basis. 242 */ 243 opackets = ifnet.if_opackets; 244 ipackets = ifnet.if_ipackets; 245 obytes = ifnet.if_obytes; 246 ibytes = ifnet.if_ibytes; 247 oerrors = ifnet.if_oerrors; 248 ierrors = ifnet.if_ierrors; 249 collisions = ifnet.if_collisions; 250 timer = ifnet.if_timer; 251 drops = ifnet.if_snd.ifq_drops; 252 253 if (ifaddraddr == 0) { 254 printf("%-5.5s %5lu ", name, ifnet.if_mtu); 255 printf("%-13.13s ", "none"); 256 printf("%-17.17s ", "none"); 257 } else { 258 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 259 ifaddraddr = 0; 260 continue; 261 } 262 #define CP(x) ((char *)(x)) 263 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 264 CP(&ifaddr); 265 sa = (struct sockaddr *)cp; 266 if (af != AF_UNSPEC && sa->sa_family != af) { 267 ifaddraddr = 268 (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link); 269 continue; 270 } 271 printf("%-5.5s %5lu ", name, ifnet.if_mtu); 272 switch (sa->sa_family) { 273 case AF_UNSPEC: 274 printf("%-13.13s ", "none"); 275 printf("%-15.15s ", "none"); 276 break; 277 case AF_INET: 278 sin = (struct sockaddr_in *)sa; 279 #ifdef notdef 280 /* can't use inet_makeaddr because kernel 281 * keeps nets unshifted. 282 */ 283 in = inet_makeaddr(ifaddr.in.ia_subnet, 284 INADDR_ANY); 285 printf("%-13.13s ", netname(in.s_addr, 286 ifaddr.in.ia_subnetmask)); 287 #else 288 printf("%-13.13s ", 289 netname(htonl(ifaddr.in.ia_subnet), 290 ifaddr.in.ia_subnetmask)); 291 #endif 292 printf("%-17.17s ", 293 routename(sin->sin_addr.s_addr)); 294 295 network_layer = 1; 296 break; 297 #ifdef INET6 298 case AF_INET6: 299 sin6 = (struct sockaddr_in6 *)sa; 300 printf("%-13.13s ", 301 netname6(&ifaddr.in6.ia_addr, 302 &ifaddr.in6.ia_prefixmask.sin6_addr)); 303 printf("%-17.17s ", 304 inet_ntop(AF_INET6, 305 &sin6->sin6_addr, 306 ntop_buf, sizeof(ntop_buf))); 307 308 network_layer = 1; 309 break; 310 #endif /*INET6*/ 311 case AF_IPX: 312 { 313 struct sockaddr_ipx *sipx = 314 (struct sockaddr_ipx *)sa; 315 u_long net; 316 char netnum[10]; 317 318 *(union ipx_net *) &net = sipx->sipx_addr.x_net; 319 sprintf(netnum, "%lx", (u_long)ntohl(net)); 320 printf("ipx:%-8s ", netnum); 321 /* printf("ipx:%-8s ", netname(net, 0L)); */ 322 printf("%-17s ", 323 ipx_phost((struct sockaddr *)sipx)); 324 } 325 326 network_layer = 1; 327 break; 328 329 case AF_APPLETALK: 330 printf("atalk:%-12.12s ",atalk_print(sa,0x10) ); 331 printf("%-11.11s ",atalk_print(sa,0x0b) ); 332 break; 333 case AF_LINK: 334 { 335 struct sockaddr_dl *sdl = 336 (struct sockaddr_dl *)sa; 337 char linknum[10]; 338 cp = (char *)LLADDR(sdl); 339 n = sdl->sdl_alen; 340 sprintf(linknum, "<Link#%d>", sdl->sdl_index); 341 m = printf("%-13.13s ", linknum); 342 } 343 goto hexprint; 344 default: 345 m = printf("(%d)", sa->sa_family); 346 for (cp = sa->sa_len + (char *)sa; 347 --cp > sa->sa_data && (*cp == 0);) {} 348 n = cp - sa->sa_data + 1; 349 cp = sa->sa_data; 350 hexprint: 351 while (--n >= 0) 352 m += printf("%02x%c", *cp++ & 0xff, 353 n > 0 ? ':' : ' '); 354 m = 32 - m; 355 while (m-- > 0) 356 putchar(' '); 357 358 link_layer = 1; 359 break; 360 } 361 362 /* 363 * Fixup the statistics for interfaces that 364 * update stats for their network addresses 365 */ 366 if (network_layer) { 367 opackets = ifaddr.in.ia_ifa.if_opackets; 368 ipackets = ifaddr.in.ia_ifa.if_ipackets; 369 obytes = ifaddr.in.ia_ifa.if_obytes; 370 ibytes = ifaddr.in.ia_ifa.if_ibytes; 371 } 372 373 ifaddraddr = (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link); 374 } 375 376 show_stat("lu", 8, ipackets, link_layer|network_layer); 377 printf(" "); 378 show_stat("lu", 5, ierrors, link_layer); 379 printf(" "); 380 if (bflag) { 381 show_stat("lu", 10, ibytes, link_layer|network_layer); 382 printf(" "); 383 } 384 show_stat("lu", 8, opackets, link_layer|network_layer); 385 printf(" "); 386 show_stat("lu", 5, oerrors, link_layer); 387 printf(" "); 388 if (bflag) { 389 show_stat("lu", 10, obytes, link_layer|network_layer); 390 printf(" "); 391 } 392 show_stat("lu", 5, collisions, link_layer); 393 if (tflag) { 394 printf(" "); 395 show_stat("d", 3, timer, link_layer); 396 } 397 if (dflag) { 398 printf(" "); 399 show_stat("d", 3, drops, link_layer); 400 } 401 putchar('\n'); 402 if (aflag && ifaddrfound) { 403 /* 404 * Print family's multicast addresses 405 */ 406 struct ifmultiaddr *multiaddr; 407 struct ifmultiaddr ifma; 408 union { 409 struct sockaddr sa; 410 struct sockaddr_in in; 411 #ifdef INET6 412 struct sockaddr_in6 in6; 413 #endif /* INET6 */ 414 struct sockaddr_dl dl; 415 } msa; 416 const char *fmt; 417 418 TAILQ_FOREACH(multiaddr, &ifnet.if_multiaddrs, ifma_link) { 419 if (kread((u_long)multiaddr, (char *)&ifma, 420 sizeof ifma)) 421 break; 422 multiaddr = &ifma; 423 if (kread((u_long)ifma.ifma_addr, (char *)&msa, 424 sizeof msa)) 425 break; 426 if (msa.sa.sa_family != sa->sa_family) 427 continue; 428 429 fmt = 0; 430 switch (msa.sa.sa_family) { 431 case AF_INET: 432 fmt = routename(msa.in.sin_addr.s_addr); 433 break; 434 #ifdef INET6 435 case AF_INET6: 436 printf("%23s %-19.19s(refs: %d)\n", "", 437 inet_ntop(AF_INET6, 438 &msa.in6.sin6_addr, 439 ntop_buf, 440 sizeof(ntop_buf)), 441 ifma.ifma_refcount); 442 break; 443 #endif /* INET6 */ 444 case AF_LINK: 445 switch (msa.dl.sdl_type) { 446 case IFT_ETHER: 447 case IFT_FDDI: 448 fmt = ether_ntoa( 449 (struct ether_addr *) 450 LLADDR(&msa.dl)); 451 break; 452 } 453 break; 454 } 455 if (fmt) 456 printf("%23s %s\n", "", fmt); 457 } 458 } 459 } 460 } 461 462 struct iftot { 463 SLIST_ENTRY(iftot) chain; 464 char ift_name[IFNAMSIZ]; /* interface name */ 465 u_long ift_ip; /* input packets */ 466 u_long ift_ie; /* input errors */ 467 u_long ift_op; /* output packets */ 468 u_long ift_oe; /* output errors */ 469 u_long ift_co; /* collisions */ 470 u_int ift_dr; /* drops */ 471 u_long ift_ib; /* input bytes */ 472 u_long ift_ob; /* output bytes */ 473 }; 474 475 u_char signalled; /* set if alarm goes off "early" */ 476 477 /* 478 * Print a running summary of interface statistics. 479 * Repeat display every interval seconds, showing statistics 480 * collected over that interval. Assumes that interval is non-zero. 481 * First line printed at top of screen is always cumulative. 482 * XXX - should be rewritten to use ifmib(4). 483 */ 484 static void 485 sidewaysintpr(unsigned interval1, u_long off) 486 { 487 struct ifnet ifnet; 488 u_long firstifnet; 489 struct ifnethead ifnethead; 490 struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting; 491 int line; 492 int oldmask, first; 493 u_long interesting_off; 494 495 if (kread(off, (char *)&ifnethead, sizeof ifnethead)) 496 return; 497 firstifnet = (u_long)TAILQ_FIRST(&ifnethead); 498 499 if ((iftot = malloc(sizeof(struct iftot))) == NULL) { 500 printf("malloc failed\n"); 501 exit(1); 502 } 503 memset(iftot, 0, sizeof(struct iftot)); 504 505 interesting = NULL; 506 interesting_off = 0; 507 for (off = firstifnet, ip = iftot; off;) { 508 char name[IFNAMSIZ]; 509 510 if (kread(off, (char *)&ifnet, sizeof ifnet)) 511 break; 512 strlcpy(name, ifnet.if_xname, sizeof(name)); 513 if (interface && strcmp(name, interface) == 0) { 514 interesting = ip; 515 interesting_off = off; 516 } 517 snprintf(ip->ift_name, sizeof(ip->ift_name), "(%s)", name);; 518 if ((ipn = malloc(sizeof(struct iftot))) == NULL) { 519 printf("malloc failed\n"); 520 exit(1); 521 } 522 memset(ipn, 0, sizeof(struct iftot)); 523 SLIST_NEXT(ip, chain) = ipn; 524 ip = ipn; 525 off = (u_long)TAILQ_NEXT(&ifnet, if_link); 526 } 527 if ((total = malloc(sizeof(struct iftot))) == NULL) { 528 printf("malloc failed\n"); 529 exit(1); 530 } 531 memset(total, 0, sizeof(struct iftot)); 532 if ((sum = malloc(sizeof(struct iftot))) == NULL) { 533 printf("malloc failed\n"); 534 exit(1); 535 } 536 memset(sum, 0, sizeof(struct iftot)); 537 538 (void)signal(SIGALRM, catchalarm); 539 signalled = NO; 540 (void)alarm(interval1); 541 first = 1; 542 banner: 543 printf("%17s %14s %16s", "input", 544 interesting ? interesting->ift_name : "(Total)", "output"); 545 putchar('\n'); 546 printf("%10s %5s %10s %10s %5s %10s %5s", 547 "packets", "errs", "bytes", "packets", "errs", "bytes", "colls"); 548 if (dflag) 549 printf(" %5.5s", "drops"); 550 putchar('\n'); 551 fflush(stdout); 552 line = 0; 553 loop: 554 if (interesting != NULL) { 555 ip = interesting; 556 if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) { 557 printf("???\n"); 558 exit(1); 559 }; 560 if (!first) { 561 printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", 562 ifnet.if_ipackets - ip->ift_ip, 563 ifnet.if_ierrors - ip->ift_ie, 564 ifnet.if_ibytes - ip->ift_ib, 565 ifnet.if_opackets - ip->ift_op, 566 ifnet.if_oerrors - ip->ift_oe, 567 ifnet.if_obytes - ip->ift_ob, 568 ifnet.if_collisions - ip->ift_co); 569 if (dflag) 570 printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr); 571 } 572 ip->ift_ip = ifnet.if_ipackets; 573 ip->ift_ie = ifnet.if_ierrors; 574 ip->ift_ib = ifnet.if_ibytes; 575 ip->ift_op = ifnet.if_opackets; 576 ip->ift_oe = ifnet.if_oerrors; 577 ip->ift_ob = ifnet.if_obytes; 578 ip->ift_co = ifnet.if_collisions; 579 ip->ift_dr = ifnet.if_snd.ifq_drops; 580 } else { 581 sum->ift_ip = 0; 582 sum->ift_ie = 0; 583 sum->ift_ib = 0; 584 sum->ift_op = 0; 585 sum->ift_oe = 0; 586 sum->ift_ob = 0; 587 sum->ift_co = 0; 588 sum->ift_dr = 0; 589 for (off = firstifnet, ip = iftot; 590 off && SLIST_NEXT(ip, chain) != NULL; 591 ip = SLIST_NEXT(ip, chain)) { 592 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 593 off = 0; 594 continue; 595 } 596 sum->ift_ip += ifnet.if_ipackets; 597 sum->ift_ie += ifnet.if_ierrors; 598 sum->ift_ib += ifnet.if_ibytes; 599 sum->ift_op += ifnet.if_opackets; 600 sum->ift_oe += ifnet.if_oerrors; 601 sum->ift_ob += ifnet.if_obytes; 602 sum->ift_co += ifnet.if_collisions; 603 sum->ift_dr += ifnet.if_snd.ifq_drops; 604 off = (u_long)TAILQ_NEXT(&ifnet, if_link); 605 } 606 if (!first) { 607 printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", 608 sum->ift_ip - total->ift_ip, 609 sum->ift_ie - total->ift_ie, 610 sum->ift_ib - total->ift_ib, 611 sum->ift_op - total->ift_op, 612 sum->ift_oe - total->ift_oe, 613 sum->ift_ob - total->ift_ob, 614 sum->ift_co - total->ift_co); 615 if (dflag) 616 printf(" %5u", sum->ift_dr - total->ift_dr); 617 } 618 *total = *sum; 619 } 620 if (!first) 621 putchar('\n'); 622 fflush(stdout); 623 oldmask = sigblock(sigmask(SIGALRM)); 624 if (! signalled) { 625 sigpause(0); 626 } 627 sigsetmask(oldmask); 628 signalled = NO; 629 (void)alarm(interval1); 630 line++; 631 first = 0; 632 if (line == 21) 633 goto banner; 634 else 635 goto loop; 636 /*NOTREACHED*/ 637 } 638 639 /* 640 * Called if an interval expires before sidewaysintpr has completed a loop. 641 * Sets a flag to not wait for the alarm. 642 */ 643 static void 644 catchalarm(int signo __unused) 645 { 646 signalled = YES; 647 } 648