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