1 /* $NetBSD: if.c,v 1.91 2017/01/11 01:25:05 ozaki-r Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; 36 #else 37 __RCSID("$NetBSD: if.c,v 1.91 2017/01/11 01:25:05 ozaki-r Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/types.h> 43 #include <sys/protosw.h> 44 #include <sys/socket.h> 45 #include <sys/time.h> 46 #include <sys/sysctl.h> 47 #include <sys/ioctl.h> 48 49 #include <net/if.h> 50 #include <net/if_dl.h> 51 #include <net/if_types.h> 52 #include <net/route.h> 53 #include <netinet/in.h> 54 #include <netinet/in_var.h> 55 #include <arpa/inet.h> 56 57 #include <kvm.h> 58 #include <signal.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 #include <netdb.h> 64 #include <err.h> 65 66 #include "netstat.h" 67 #include "rtutil.h" 68 #include "prog_ops.h" 69 70 #define MAXIF 100 71 72 #define HUMBUF_SIZE 7 73 74 struct iftot { 75 char ift_name[IFNAMSIZ]; /* interface name */ 76 u_quad_t ift_ip; /* input packets */ 77 u_quad_t ift_ib; /* input bytes */ 78 u_quad_t ift_ie; /* input errors */ 79 u_quad_t ift_op; /* output packets */ 80 u_quad_t ift_ob; /* output bytes */ 81 u_quad_t ift_oe; /* output errors */ 82 u_quad_t ift_co; /* collisions */ 83 u_quad_t ift_dr; /* drops */ 84 }; 85 86 static void set_lines(void); 87 static void print_addr(const int, struct sockaddr *, struct sockaddr **, 88 struct if_data *, struct ifnet *); 89 static void sidewaysintpr(u_int, u_long); 90 91 static void iftot_banner(struct iftot *); 92 static void iftot_print_sum(struct iftot *, struct iftot *); 93 static void iftot_print(struct iftot *, struct iftot *); 94 95 static void catchalarm(int); 96 static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 97 static void fetchifs(void); 98 99 static void intpr_sysctl(void); 100 static void intpr_kvm(u_long, void (*)(const char *)); 101 102 struct iftot iftot[MAXIF], ip_cur, ip_old, sum_cur, sum_old; 103 static sig_atomic_t signalled; /* set when alarm goes off */ 104 105 static unsigned redraw_lines = 21; 106 107 static void 108 set_lines(void) 109 { 110 static bool first = true; 111 struct ttysize ts; 112 113 if (!first) 114 return; 115 first = false; 116 if (ioctl(STDOUT_FILENO, TIOCGSIZE, &ts) != -1 && ts.ts_lines) 117 redraw_lines = ts.ts_lines - 3; 118 } 119 120 121 /* 122 * Print a description of the network interfaces. 123 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 124 * which is a TAILQ_HEAD. 125 */ 126 void 127 intpr(int interval, u_long ifnetaddr, void (*pfunc)(const char *)) 128 { 129 130 if (interval) { 131 sidewaysintpr((unsigned)interval, ifnetaddr); 132 return; 133 } 134 135 if (use_sysctl) { 136 intpr_sysctl(); 137 } else { 138 intpr_kvm(ifnetaddr, pfunc); 139 } 140 141 } 142 143 static void 144 intpr_header(void) 145 { 146 147 if (!sflag && !pflag) { 148 if (bflag) { 149 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 150 "%10.10s %10.10s", 151 "Name", "Mtu", "Network", "Address", 152 "Ibytes", "Obytes"); 153 } else { 154 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 155 "%8.8s %5.5s %8.8s %5.5s %5.5s", 156 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", 157 "Opkts", "Oerrs", "Colls"); 158 } 159 if (tflag) 160 printf(" %4.4s", "Time"); 161 if (dflag) 162 printf(" %5.5s", "Drops"); 163 putchar('\n'); 164 } 165 } 166 167 static void 168 intpr_sysctl(void) 169 { 170 struct if_msghdr *ifm; 171 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 172 char *buf = NULL, *next, *lim, *cp; 173 struct rt_msghdr *rtm; 174 struct ifa_msghdr *ifam; 175 struct if_data *ifd = NULL; 176 struct sockaddr *sa, *rti_info[RTAX_MAX]; 177 struct sockaddr_dl *sdl; 178 uint64_t total = 0; 179 size_t len; 180 int did = 1, rtax = 0, n; 181 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 182 int ifindex = 0; 183 184 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 185 err(1, "sysctl"); 186 if ((buf = malloc(len)) == NULL) 187 err(1, NULL); 188 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 189 err(1, "sysctl"); 190 191 intpr_header(); 192 193 lim = buf + len; 194 for (next = buf; next < lim; next += rtm->rtm_msglen) { 195 rtm = (struct rt_msghdr *)next; 196 if (rtm->rtm_version != RTM_VERSION) 197 continue; 198 switch (rtm->rtm_type) { 199 case RTM_IFINFO: 200 total = 0; 201 ifm = (struct if_msghdr *)next; 202 ifd = &ifm->ifm_data; 203 204 sa = (struct sockaddr *)(ifm + 1); 205 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 206 207 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 208 if (sdl == NULL || sdl->sdl_family != AF_LINK) { 209 continue; 210 } 211 bzero(name, sizeof(name)); 212 if (sdl->sdl_nlen >= IFNAMSIZ) 213 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 214 else if (sdl->sdl_nlen > 0) 215 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 216 217 if (interface != 0 && strcmp(name, interface) != 0) 218 continue; 219 220 ifindex = sdl->sdl_index; 221 222 /* mark inactive interfaces with a '*' */ 223 cp = strchr(name, '\0'); 224 if ((ifm->ifm_flags & IFF_UP) == 0) 225 *cp++ = '*'; 226 *cp = '\0'; 227 228 if (qflag) { 229 total = ifd->ifi_ibytes + ifd->ifi_obytes + 230 ifd->ifi_ipackets + ifd->ifi_ierrors + 231 ifd->ifi_opackets + ifd->ifi_oerrors + 232 ifd->ifi_collisions; 233 if (dflag) 234 total += ifd->ifi_iqdrops; 235 if (total == 0) 236 continue; 237 } 238 /* Skip the first one */ 239 if (did) { 240 did = 0; 241 continue; 242 } 243 rtax = RTAX_IFP; 244 break; 245 case RTM_NEWADDR: 246 if (qflag && total == 0) 247 continue; 248 if (interface != 0 && strcmp(name, interface) != 0) 249 continue; 250 ifam = (struct ifa_msghdr *)next; 251 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 252 RTA_BRD)) == 0) 253 break; 254 255 sa = (struct sockaddr *)(ifam + 1); 256 257 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 258 rtax = RTAX_IFA; 259 did = 1; 260 break; 261 default: 262 continue; 263 } 264 if (vflag) 265 n = strlen(name) < 5 ? 5 : strlen(name); 266 else 267 n = 5; 268 269 printf("%-*.*s %-5" PRIu64 " ", n, n, name, ifd->ifi_mtu); 270 print_addr(ifindex, rti_info[rtax], rti_info, ifd, NULL); 271 } 272 } 273 274 union ifaddr_u { 275 struct ifaddr ifa; 276 struct in_ifaddr in; 277 #ifdef INET6 278 struct in6_ifaddr in6; 279 #endif /* INET6 */ 280 }; 281 282 static void 283 intpr_kvm(u_long ifnetaddr, void (*pfunc)(const char *)) 284 { 285 struct ifnet ifnet; 286 union ifaddr_u ifaddr; 287 u_long ifaddraddr; 288 struct ifnet_head ifhead; /* TAILQ_HEAD */ 289 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 290 291 if (ifnetaddr == 0) { 292 printf("ifnet: symbol not defined\n"); 293 return; 294 } 295 296 /* 297 * Find the pointer to the first ifnet structure. Replace 298 * the pointer to the TAILQ_HEAD with the actual pointer 299 * to the first list element. 300 */ 301 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 302 return; 303 ifnetaddr = (u_long)ifhead.tqh_first; 304 305 intpr_header(); 306 307 ifaddraddr = 0; 308 while (ifnetaddr || ifaddraddr) { 309 char *cp; 310 int n; 311 312 if (ifaddraddr == 0) { 313 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 314 return; 315 memmove(name, ifnet.if_xname, IFNAMSIZ); 316 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 317 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 318 if (interface != 0 && strcmp(name, interface) != 0) 319 continue; 320 cp = strchr(name, '\0'); 321 322 if (pfunc) { 323 (*pfunc)(name); 324 continue; 325 } 326 327 if ((ifnet.if_flags & IFF_UP) == 0) 328 *cp++ = '*'; 329 *cp = '\0'; 330 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 331 } 332 if (vflag) 333 n = strlen(name) < 5 ? 5 : strlen(name); 334 else 335 n = 5; 336 printf("%-*.*s %-5llu ", n, n, name, 337 (unsigned long long)ifnet.if_mtu); 338 if (ifaddraddr == 0) { 339 printf("%-13.13s ", "none"); 340 printf("%-17.17s ", "none"); 341 } else { 342 struct sockaddr *sa; 343 344 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 345 ifaddraddr = 0; 346 continue; 347 } 348 #define CP(x) ((char *)(x)) 349 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 350 CP(&ifaddr); 351 sa = (struct sockaddr *)cp; 352 print_addr(ifnet.if_index, sa, (void *)&ifaddr, 353 &ifnet.if_data, &ifnet); 354 } 355 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 356 } 357 358 } 359 360 static void 361 mc_print(const int ifindex, const size_t ias, const char *oid, int *mcast_oids, 362 void (*pr)(const void *)) 363 { 364 uint8_t *mcast_addrs, *p; 365 const size_t incr = 2 * ias + sizeof(uint32_t); 366 size_t len; 367 368 if (mcast_oids[0] == 0) { 369 size_t oidlen = 4; 370 if (sysctlnametomib(oid, mcast_oids, &oidlen) == -1) { 371 warnx("'%s' not found", oid); 372 return; 373 } 374 if (oidlen != 3) { 375 warnx("Wrong OID path for '%s'", oid); 376 return; 377 } 378 } 379 380 if (mcast_oids[3] == ifindex) 381 return; 382 mcast_oids[3] = ifindex; 383 384 mcast_addrs = asysctl(mcast_oids, 4, &len); 385 if (mcast_addrs == NULL && len != 0) { 386 warn("failed to read '%s'", oid); 387 return; 388 } 389 if (len) { 390 p = mcast_addrs; 391 while (len >= incr) { 392 (*pr)((p + ias)); 393 p += incr; 394 len -= incr; 395 } 396 } 397 free(mcast_addrs); 398 } 399 400 #ifdef INET6 401 static void 402 ia6_print(const struct in6_addr *ia) 403 { 404 struct sockaddr_in6 as6; 405 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 406 int n; 407 408 memset(&as6, 0, sizeof(as6)); 409 as6.sin6_len = sizeof(struct sockaddr_in6); 410 as6.sin6_family = AF_INET6; 411 as6.sin6_addr = *ia; 412 inet6_getscopeid(&as6, INET6_IS_ADDR_MC_LINKLOCAL); 413 if (getnameinfo((struct sockaddr *)&as6, as6.sin6_len, hbuf, 414 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 415 strlcpy(hbuf, "??", sizeof(hbuf)); 416 } 417 if (vflag) 418 n = strlen(hbuf) < 17 ? 17 : strlen(hbuf); 419 else 420 n = 17; 421 printf("\n%25s %-*.*s ", "", n, n, hbuf); 422 } 423 424 static void 425 mc6_print(const int ifindex) 426 { 427 static int mcast_oids[4]; 428 429 mc_print(ifindex, sizeof(struct in6_addr), "net.inet6.multicast", 430 mcast_oids, (void (*)(const void *))ia6_print); 431 } 432 #endif 433 434 static void 435 ia4_print(const struct in_addr *ia) 436 { 437 printf("\n%25s %-17.17s ", "", routename4(ia->s_addr, nflag)); 438 } 439 440 static void 441 mc4_print(const int ifindex) 442 { 443 static int mcast_oids[4]; 444 445 mc_print(ifindex, sizeof(struct in_addr), "net.inet.multicast", 446 mcast_oids, (void (*)(const void *))ia4_print); 447 } 448 449 static void 450 print_addr(const int ifindex, struct sockaddr *sa, 451 struct sockaddr **rtinfo, struct if_data *ifd, struct ifnet *ifnet) 452 { 453 char hexsep = '.'; /* for hexprint */ 454 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 455 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 456 #ifdef INET6 457 const int niflag = NI_NUMERICHOST; 458 struct sockaddr_in6 *sin6, *netmask6; 459 #endif 460 struct sockaddr_in netmask; 461 struct sockaddr_in *sin; 462 char *cp; 463 int n, m; 464 465 switch (sa->sa_family) { 466 case AF_UNSPEC: 467 printf("%-13.13s ", "none"); 468 printf("%-17.17s ", "none"); 469 break; 470 case AF_INET: 471 sin = (struct sockaddr_in *)sa; 472 if (use_sysctl) { 473 netmask = *((struct sockaddr_in *)rtinfo[RTAX_NETMASK]); 474 } else { 475 struct in_ifaddr *ifaddr_in = (void *)rtinfo; 476 netmask.sin_addr.s_addr = ifaddr_in->ia_subnetmask; 477 } 478 cp = netname4(sin, &netmask, nflag); 479 if (vflag) 480 n = strlen(cp) < 13 ? 13 : strlen(cp); 481 else 482 n = 13; 483 printf("%-*.*s ", n, n, cp); 484 cp = routename4(sin->sin_addr.s_addr, nflag); 485 if (vflag) 486 n = strlen(cp) < 17 ? 17 : strlen(cp); 487 else 488 n = 17; 489 printf("%-*.*s ", n, n, cp); 490 491 if (!aflag) 492 break; 493 if (ifnet) { 494 u_long multiaddr; 495 struct in_multi inm; 496 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 497 498 multiaddr = (u_long)ifaddr->in.ia_multiaddrs.lh_first; 499 while (multiaddr != 0) { 500 kread(multiaddr, (char *)&inm, sizeof inm); 501 ia4_print(&inm.inm_addr); 502 multiaddr = (u_long)inm.inm_list.le_next; 503 } 504 } else { 505 mc4_print(ifindex); 506 } 507 break; 508 #ifdef INET6 509 case AF_INET6: 510 sin6 = (struct sockaddr_in6 *)sa; 511 inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL); 512 #ifdef __KAME__ 513 if (!vflag) 514 sin6->sin6_scope_id = 0; 515 #endif 516 517 if (use_sysctl) { 518 netmask6 = (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]; 519 } else { 520 struct in6_ifaddr *ifaddr_in6 = (void *)rtinfo; 521 netmask6 = &ifaddr_in6->ia_prefixmask; 522 } 523 524 cp = netname6(sin6, netmask6, nflag); 525 if (vflag) 526 n = strlen(cp) < 13 ? 13 : strlen(cp); 527 else 528 n = 13; 529 printf("%-*.*s ", n, n, cp); 530 if (getnameinfo((struct sockaddr *)sin6, 531 sin6->sin6_len, 532 hbuf, sizeof(hbuf), NULL, 0, 533 niflag) != 0) { 534 strlcpy(hbuf, "?", sizeof(hbuf)); 535 } 536 cp = hbuf; 537 if (vflag) 538 n = strlen(cp) < 17 ? 17 : strlen(cp); 539 else 540 n = 17; 541 printf("%-*.*s ", n, n, cp); 542 543 if (!aflag) 544 break; 545 if (ifnet) { 546 u_long multiaddr; 547 struct in6_multi inm; 548 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 549 550 multiaddr = (u_long)ifaddr->in6.ia6_multiaddrs.lh_first; 551 while (multiaddr != 0) { 552 kread(multiaddr, (char *)&inm, sizeof inm); 553 ia6_print(&inm.in6m_addr); 554 multiaddr = (u_long)inm.in6m_entry.le_next; 555 } 556 } else { 557 mc6_print(ifindex); 558 } 559 break; 560 #endif /*INET6*/ 561 #ifndef SMALL 562 case AF_APPLETALK: 563 printf("atalk:%-7.7s ", 564 atalk_print(sa,0x10)); 565 printf("%-17.17s ", atalk_print(sa,0x0b)); 566 break; 567 #endif 568 case AF_LINK: 569 printf("%-13.13s ", "<Link>"); 570 if (getnameinfo(sa, sa->sa_len, 571 hbuf, sizeof(hbuf), NULL, 0, 572 NI_NUMERICHOST) != 0) { 573 strlcpy(hbuf, "?", sizeof(hbuf)); 574 } 575 cp = hbuf; 576 if (vflag) 577 n = strlen(cp) < 17 ? 17 : strlen(cp); 578 else 579 n = 17; 580 printf("%-*.*s ", n, n, cp); 581 break; 582 583 default: 584 m = printf("(%d)", sa->sa_family); 585 for (cp = sa->sa_len + (char *)sa; 586 --cp > sa->sa_data && (*cp == 0);) {} 587 n = cp - sa->sa_data + 1; 588 cp = sa->sa_data; 589 590 while (--n >= 0) 591 m += printf(hexfmt, *cp++ & 0xff, 592 n > 0 ? hexsep : ' '); 593 m = 32 - m; 594 while (m-- > 0) 595 putchar(' '); 596 break; 597 } 598 599 if (bflag) { 600 char humbuf[HUMBUF_SIZE]; 601 602 if (hflag && humanize_number(humbuf, sizeof(humbuf), 603 ifd->ifi_ibytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 604 printf("%10s ", humbuf); 605 else 606 printf("%10llu ", (unsigned long long)ifd->ifi_ibytes); 607 608 if (hflag && humanize_number(humbuf, sizeof(humbuf), 609 ifd->ifi_obytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 610 printf("%10s", humbuf); 611 else 612 printf("%10llu", (unsigned long long)ifd->ifi_obytes); 613 } else { 614 printf("%8llu %5llu %8llu %5llu %5llu", 615 (unsigned long long)ifd->ifi_ipackets, 616 (unsigned long long)ifd->ifi_ierrors, 617 (unsigned long long)ifd->ifi_opackets, 618 (unsigned long long)ifd->ifi_oerrors, 619 (unsigned long long)ifd->ifi_collisions); 620 } 621 if (tflag) 622 printf(" %4d", ifnet ? ifnet->if_timer : 0); 623 if (dflag) 624 printf(" %5lld", ifnet ? 625 (unsigned long long)ifnet->if_snd.ifq_drops : 626 ifd->ifi_iqdrops); 627 putchar('\n'); 628 } 629 630 static void 631 iftot_banner(struct iftot *ift) 632 { 633 if (bflag) 634 printf("%7.7s in %8.8s %6.6s out %5.5s", 635 ift->ift_name, " ", 636 ift->ift_name, " "); 637 else 638 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 639 ift->ift_name, " ", 640 ift->ift_name, " ", " "); 641 if (dflag) 642 printf(" %5.5s", " "); 643 644 if (bflag) 645 printf(" %7.7s in %8.8s %6.6s out %5.5s", 646 "total", " ", "total", " "); 647 else 648 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 649 "total", " ", "total", " ", " "); 650 if (dflag) 651 printf(" %5.5s", " "); 652 putchar('\n'); 653 if (bflag) 654 printf("%10.10s %8.8s %10.10s %5.5s", 655 "bytes", " ", "bytes", " "); 656 else 657 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 658 "packets", "errs", "packets", "errs", "colls"); 659 if (dflag) 660 printf(" %5.5s", "drops"); 661 662 if (bflag) 663 printf(" %10.10s %8.8s %10.10s %5.5s", 664 "bytes", " ", "bytes", " "); 665 else 666 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 667 "packets", "errs", "packets", "errs", "colls"); 668 if (dflag) 669 printf(" %5.5s", "drops"); 670 putchar('\n'); 671 fflush(stdout); 672 } 673 674 static void 675 iftot_print(struct iftot *cur, struct iftot *old) 676 { 677 if (bflag) 678 printf("%10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 679 cur->ift_ib - old->ift_ib, " ", 680 cur->ift_ob - old->ift_ob, " "); 681 else 682 printf("%8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 683 cur->ift_ip - old->ift_ip, 684 cur->ift_ie - old->ift_ie, 685 cur->ift_op - old->ift_op, 686 cur->ift_oe - old->ift_oe, 687 cur->ift_co - old->ift_co); 688 if (dflag) 689 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr); 690 } 691 692 static void 693 iftot_print_sum(struct iftot *cur, struct iftot *old) 694 { 695 if (bflag) 696 printf(" %10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 697 cur->ift_ib - old->ift_ib, " ", 698 cur->ift_ob - old->ift_ob, " "); 699 else 700 printf(" %8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 701 cur->ift_ip - old->ift_ip, 702 cur->ift_ie - old->ift_ie, 703 cur->ift_op - old->ift_op, 704 cur->ift_oe - old->ift_oe, 705 cur->ift_co - old->ift_co); 706 707 if (dflag) 708 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr); 709 } 710 711 __dead static void 712 sidewaysintpr_sysctl(unsigned interval) 713 { 714 struct itimerval it; 715 sigset_t emptyset; 716 sigset_t noalrm; 717 unsigned line; 718 719 set_lines(); 720 721 fetchifs(); 722 if (ip_cur.ift_name[0] == '\0') { 723 fprintf(stderr, "%s: %s: unknown interface\n", 724 getprogname(), interface); 725 exit(1); 726 } 727 728 sigemptyset(&emptyset); 729 sigemptyset(&noalrm); 730 sigaddset(&noalrm, SIGALRM); 731 sigprocmask(SIG_SETMASK, &noalrm, NULL); 732 733 signalled = 0; 734 (void)signal(SIGALRM, catchalarm); 735 736 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 737 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 738 setitimer(ITIMER_REAL, &it, NULL); 739 740 banner: 741 iftot_banner(&ip_cur); 742 743 line = 0; 744 bzero(&ip_old, sizeof(ip_old)); 745 bzero(&sum_old, sizeof(sum_old)); 746 loop: 747 bzero(&sum_cur, sizeof(sum_cur)); 748 749 fetchifs(); 750 751 iftot_print(&ip_cur, &ip_old); 752 753 ip_old = ip_cur; 754 755 iftot_print_sum(&sum_cur, &sum_old); 756 757 sum_old = sum_cur; 758 759 putchar('\n'); 760 fflush(stdout); 761 line++; 762 if (signalled == 0) { 763 sigsuspend(&emptyset); 764 } 765 signalled = 0; 766 if (line == redraw_lines) 767 goto banner; 768 goto loop; 769 /*NOTREACHED*/ 770 } 771 772 static void 773 sidewaysintpr_kvm(unsigned interval, u_long off) 774 { 775 struct itimerval it; 776 sigset_t emptyset; 777 sigset_t noalrm; 778 struct ifnet ifnet; 779 u_long firstifnet; 780 struct iftot *ip, *total; 781 unsigned line; 782 struct iftot *lastif, *sum, *interesting; 783 struct ifnet_head ifhead; /* TAILQ_HEAD */ 784 785 set_lines(); 786 787 /* 788 * Find the pointer to the first ifnet structure. Replace 789 * the pointer to the TAILQ_HEAD with the actual pointer 790 * to the first list element. 791 */ 792 if (kread(off, (char *)&ifhead, sizeof ifhead)) 793 return; 794 firstifnet = (u_long)ifhead.tqh_first; 795 796 lastif = iftot; 797 sum = iftot + MAXIF - 1; 798 total = sum - 1; 799 interesting = (interface == NULL) ? iftot : NULL; 800 for (off = firstifnet, ip = iftot; off;) { 801 if (kread(off, (char *)&ifnet, sizeof ifnet)) 802 break; 803 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 804 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 805 if (interface && strcmp(ifnet.if_xname, interface) == 0) 806 interesting = ip; 807 ip++; 808 if (ip >= iftot + MAXIF - 2) 809 break; 810 off = (u_long)ifnet.if_list.tqe_next; 811 } 812 if (interesting == NULL) { 813 fprintf(stderr, "%s: %s: unknown interface\n", 814 getprogname(), interface); 815 exit(1); 816 } 817 lastif = ip; 818 819 sigemptyset(&emptyset); 820 sigemptyset(&noalrm); 821 sigaddset(&noalrm, SIGALRM); 822 sigprocmask(SIG_SETMASK, &noalrm, NULL); 823 824 signalled = 0; 825 (void)signal(SIGALRM, catchalarm); 826 827 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 828 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 829 setitimer(ITIMER_REAL, &it, NULL); 830 831 banner: 832 if (bflag) 833 printf("%7.7s in %8.8s %6.6s out %5.5s", 834 interesting->ift_name, " ", 835 interesting->ift_name, " "); 836 else 837 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 838 interesting->ift_name, " ", 839 interesting->ift_name, " ", " "); 840 if (dflag) 841 printf(" %5.5s", " "); 842 if (lastif - iftot > 0) { 843 if (bflag) 844 printf(" %7.7s in %8.8s %6.6s out %5.5s", 845 "total", " ", "total", " "); 846 else 847 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 848 "total", " ", "total", " ", " "); 849 if (dflag) 850 printf(" %5.5s", " "); 851 } 852 for (ip = iftot; ip < iftot + MAXIF; ip++) { 853 ip->ift_ip = 0; 854 ip->ift_ib = 0; 855 ip->ift_ie = 0; 856 ip->ift_op = 0; 857 ip->ift_ob = 0; 858 ip->ift_oe = 0; 859 ip->ift_co = 0; 860 ip->ift_dr = 0; 861 } 862 putchar('\n'); 863 if (bflag) 864 printf("%10.10s %8.8s %10.10s %5.5s", 865 "bytes", " ", "bytes", " "); 866 else 867 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 868 "packets", "errs", "packets", "errs", "colls"); 869 if (dflag) 870 printf(" %5.5s", "drops"); 871 if (lastif - iftot > 0) { 872 if (bflag) 873 printf(" %10.10s %8.8s %10.10s %5.5s", 874 "bytes", " ", "bytes", " "); 875 else 876 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 877 "packets", "errs", "packets", "errs", "colls"); 878 if (dflag) 879 printf(" %5.5s", "drops"); 880 } 881 putchar('\n'); 882 fflush(stdout); 883 line = 0; 884 loop: 885 sum->ift_ip = 0; 886 sum->ift_ib = 0; 887 sum->ift_ie = 0; 888 sum->ift_op = 0; 889 sum->ift_ob = 0; 890 sum->ift_oe = 0; 891 sum->ift_co = 0; 892 sum->ift_dr = 0; 893 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 894 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 895 off = 0; 896 continue; 897 } 898 if (ip == interesting) { 899 if (bflag) { 900 char humbuf[HUMBUF_SIZE]; 901 902 if (hflag && humanize_number(humbuf, 903 sizeof(humbuf), 904 ifnet.if_ibytes - ip->ift_ib, "", 905 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 906 printf("%10s %8.8s ", humbuf, " "); 907 else 908 printf("%10llu %8.8s ", 909 (unsigned long long) 910 (ifnet.if_ibytes-ip->ift_ib), " "); 911 912 if (hflag && humanize_number(humbuf, 913 sizeof(humbuf), 914 ifnet.if_obytes - ip->ift_ob, "", 915 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 916 printf("%10s %5.5s", humbuf, " "); 917 else 918 printf("%10llu %5.5s", 919 (unsigned long long) 920 (ifnet.if_obytes-ip->ift_ob), " "); 921 } else { 922 printf("%8llu %5llu %8llu %5llu %5llu", 923 (unsigned long long) 924 (ifnet.if_ipackets - ip->ift_ip), 925 (unsigned long long) 926 (ifnet.if_ierrors - ip->ift_ie), 927 (unsigned long long) 928 (ifnet.if_opackets - ip->ift_op), 929 (unsigned long long) 930 (ifnet.if_oerrors - ip->ift_oe), 931 (unsigned long long) 932 (ifnet.if_collisions - ip->ift_co)); 933 } 934 if (dflag) 935 printf(" %5" PRIu64, 936 ifnet.if_snd.ifq_drops - ip->ift_dr); 937 } 938 ip->ift_ip = ifnet.if_ipackets; 939 ip->ift_ib = ifnet.if_ibytes; 940 ip->ift_ie = ifnet.if_ierrors; 941 ip->ift_op = ifnet.if_opackets; 942 ip->ift_ob = ifnet.if_obytes; 943 ip->ift_oe = ifnet.if_oerrors; 944 ip->ift_co = ifnet.if_collisions; 945 ip->ift_dr = ifnet.if_snd.ifq_drops; 946 sum->ift_ip += ip->ift_ip; 947 sum->ift_ib += ip->ift_ib; 948 sum->ift_ie += ip->ift_ie; 949 sum->ift_op += ip->ift_op; 950 sum->ift_ob += ip->ift_ob; 951 sum->ift_oe += ip->ift_oe; 952 sum->ift_co += ip->ift_co; 953 sum->ift_dr += ip->ift_dr; 954 off = (u_long)ifnet.if_list.tqe_next; 955 } 956 if (lastif - iftot > 0) { 957 if (bflag) { 958 char humbuf[HUMBUF_SIZE]; 959 960 if (hflag && humanize_number(humbuf, 961 sizeof(humbuf), sum->ift_ib - total->ift_ib, "", 962 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 963 printf(" %10s %8.8s ", humbuf, " "); 964 else 965 printf(" %10llu %8.8s ", 966 (unsigned long long) 967 (sum->ift_ib - total->ift_ib), " "); 968 969 if (hflag && humanize_number(humbuf, 970 sizeof(humbuf), sum->ift_ob - total->ift_ob, "", 971 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 972 printf("%10s %5.5s", humbuf, " "); 973 else 974 printf("%10llu %5.5s", 975 (unsigned long long) 976 (sum->ift_ob - total->ift_ob), " "); 977 } else { 978 printf(" %8llu %5llu %8llu %5llu %5llu", 979 (unsigned long long) 980 (sum->ift_ip - total->ift_ip), 981 (unsigned long long) 982 (sum->ift_ie - total->ift_ie), 983 (unsigned long long) 984 (sum->ift_op - total->ift_op), 985 (unsigned long long) 986 (sum->ift_oe - total->ift_oe), 987 (unsigned long long) 988 (sum->ift_co - total->ift_co)); 989 } 990 if (dflag) 991 printf(" %5llu", 992 (unsigned long long)(sum->ift_dr - total->ift_dr)); 993 } 994 *total = *sum; 995 putchar('\n'); 996 fflush(stdout); 997 line++; 998 if (signalled == 0) { 999 sigsuspend(&emptyset); 1000 } 1001 signalled = 0; 1002 if (line == redraw_lines) 1003 goto banner; 1004 goto loop; 1005 /*NOTREACHED*/ 1006 } 1007 1008 /* 1009 * Print a running summary of interface statistics. 1010 * Repeat display every interval seconds, showing statistics 1011 * collected over that interval. Assumes that interval is non-zero. 1012 * First line printed at top of screen is always cumulative. 1013 */ 1014 static void 1015 sidewaysintpr(unsigned int interval, u_long off) 1016 { 1017 1018 if (use_sysctl) { 1019 sidewaysintpr_sysctl(interval); 1020 } else { 1021 sidewaysintpr_kvm(interval, off); 1022 } 1023 } 1024 1025 /* 1026 * Called if an interval expires before sidewaysintpr has completed a loop. 1027 * Sets a flag to not wait for the alarm. 1028 */ 1029 static void 1030 catchalarm(int signo) 1031 { 1032 1033 signalled = true; 1034 } 1035 1036 static void 1037 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 1038 { 1039 int i; 1040 1041 for (i = 0; i < RTAX_MAX; i++) { 1042 if (addrs & (1 << i)) { 1043 rti_info[i] = sa; 1044 sa = (struct sockaddr *)((char *)(sa) + 1045 RT_ROUNDUP(sa->sa_len)); 1046 } else 1047 rti_info[i] = NULL; 1048 } 1049 } 1050 1051 static void 1052 fetchifs(void) 1053 { 1054 struct if_msghdr *ifm; 1055 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 1056 struct rt_msghdr *rtm; 1057 struct if_data *ifd = NULL; 1058 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1059 struct sockaddr_dl *sdl; 1060 char *buf, *next, *lim; 1061 char name[IFNAMSIZ]; 1062 size_t len; 1063 1064 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 1065 err(1, "sysctl"); 1066 if ((buf = malloc(len)) == NULL) 1067 err(1, NULL); 1068 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 1069 err(1, "sysctl"); 1070 1071 lim = buf + len; 1072 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1073 rtm = (struct rt_msghdr *)next; 1074 if (rtm->rtm_version != RTM_VERSION) 1075 continue; 1076 switch (rtm->rtm_type) { 1077 case RTM_IFINFO: 1078 ifm = (struct if_msghdr *)next; 1079 ifd = &ifm->ifm_data; 1080 1081 sa = (struct sockaddr *)(ifm + 1); 1082 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 1083 1084 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 1085 if (sdl == NULL || sdl->sdl_family != AF_LINK) 1086 continue; 1087 bzero(name, sizeof(name)); 1088 if (sdl->sdl_nlen >= IFNAMSIZ) 1089 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 1090 else if (sdl->sdl_nlen > 0) 1091 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 1092 1093 if (interface != 0 && !strcmp(name, interface)) { 1094 strlcpy(ip_cur.ift_name, name, 1095 sizeof(ip_cur.ift_name)); 1096 ip_cur.ift_ip = ifd->ifi_ipackets; 1097 ip_cur.ift_ib = ifd->ifi_ibytes; 1098 ip_cur.ift_ie = ifd->ifi_ierrors; 1099 ip_cur.ift_op = ifd->ifi_opackets; 1100 ip_cur.ift_ob = ifd->ifi_obytes; 1101 ip_cur.ift_oe = ifd->ifi_oerrors; 1102 ip_cur.ift_co = ifd->ifi_collisions; 1103 ip_cur.ift_dr = ifd->ifi_iqdrops; 1104 } 1105 1106 sum_cur.ift_ip += ifd->ifi_ipackets; 1107 sum_cur.ift_ib += ifd->ifi_ibytes; 1108 sum_cur.ift_ie += ifd->ifi_ierrors; 1109 sum_cur.ift_op += ifd->ifi_opackets; 1110 sum_cur.ift_ob += ifd->ifi_obytes; 1111 sum_cur.ift_oe += ifd->ifi_oerrors; 1112 sum_cur.ift_co += ifd->ifi_collisions; 1113 sum_cur.ift_dr += ifd->ifi_iqdrops; 1114 break; 1115 } 1116 } 1117 if (interface == NULL) { 1118 strlcpy(ip_cur.ift_name, name, 1119 sizeof(ip_cur.ift_name)); 1120 ip_cur.ift_ip = ifd->ifi_ipackets; 1121 ip_cur.ift_ib = ifd->ifi_ibytes; 1122 ip_cur.ift_ie = ifd->ifi_ierrors; 1123 ip_cur.ift_op = ifd->ifi_opackets; 1124 ip_cur.ift_ob = ifd->ifi_obytes; 1125 ip_cur.ift_oe = ifd->ifi_oerrors; 1126 ip_cur.ift_co = ifd->ifi_collisions; 1127 ip_cur.ift_dr = ifd->ifi_iqdrops; 1128 } 1129 } 1130