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