1 /* $NetBSD: if.c,v 1.95 2018/07/11 07:46:20 msaitoh 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.95 2018/07/11 07:46:20 msaitoh 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", 156 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); 157 if (dflag) 158 printf(" %6.6s", "Idrops"); 159 printf(" %8.8s %5.5s %5.5s", 160 "Opkts", "Oerrs", "Colls"); 161 } 162 if (dflag) 163 printf(" %6.6s", "Odrops"); 164 if (tflag) 165 printf(" %4.4s", "Time"); 166 putchar('\n'); 167 } 168 } 169 170 static void 171 intpr_sysctl(void) 172 { 173 struct if_msghdr *ifm; 174 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 175 static char *buf = NULL; 176 static size_t olen; 177 char *next, *lim, *cp; 178 struct rt_msghdr *rtm; 179 struct ifa_msghdr *ifam; 180 struct if_data *ifd = NULL; 181 struct sockaddr *sa, *rti_info[RTAX_MAX]; 182 struct sockaddr_dl *sdl; 183 uint64_t total = 0; 184 size_t len; 185 int did = 1, rtax = 0, n; 186 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 187 int ifindex = 0; 188 189 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 190 err(1, "sysctl"); 191 if (len > olen) { 192 free(buf); 193 if ((buf = malloc(len)) == NULL) 194 err(1, NULL); 195 olen = len; 196 } 197 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 198 err(1, "sysctl"); 199 200 intpr_header(); 201 202 lim = buf + len; 203 for (next = buf; next < lim; next += rtm->rtm_msglen) { 204 rtm = (struct rt_msghdr *)next; 205 if (rtm->rtm_version != RTM_VERSION) 206 continue; 207 switch (rtm->rtm_type) { 208 case RTM_IFINFO: 209 total = 0; 210 ifm = (struct if_msghdr *)next; 211 ifd = &ifm->ifm_data; 212 213 sa = (struct sockaddr *)(ifm + 1); 214 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 215 216 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 217 if (sdl == NULL || sdl->sdl_family != AF_LINK) { 218 continue; 219 } 220 bzero(name, sizeof(name)); 221 if (sdl->sdl_nlen >= IFNAMSIZ) 222 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 223 else if (sdl->sdl_nlen > 0) 224 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 225 226 if (interface != 0 && strcmp(name, interface) != 0) 227 continue; 228 229 ifindex = sdl->sdl_index; 230 231 /* mark inactive interfaces with a '*' */ 232 cp = strchr(name, '\0'); 233 if ((ifm->ifm_flags & IFF_UP) == 0) 234 *cp++ = '*'; 235 *cp = '\0'; 236 237 if (qflag) { 238 total = ifd->ifi_ibytes + ifd->ifi_obytes + 239 ifd->ifi_ipackets + ifd->ifi_ierrors + 240 ifd->ifi_opackets + ifd->ifi_oerrors + 241 ifd->ifi_collisions; 242 if (dflag) 243 total += ifd->ifi_iqdrops; 244 if (total == 0) 245 continue; 246 } 247 /* Skip the first one */ 248 if (did) { 249 did = 0; 250 continue; 251 } 252 rtax = RTAX_IFP; 253 break; 254 case RTM_NEWADDR: 255 if (qflag && total == 0) 256 continue; 257 if (interface != 0 && strcmp(name, interface) != 0) 258 continue; 259 ifam = (struct ifa_msghdr *)next; 260 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 261 RTA_BRD)) == 0) 262 break; 263 264 sa = (struct sockaddr *)(ifam + 1); 265 266 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 267 rtax = RTAX_IFA; 268 did = 1; 269 break; 270 default: 271 continue; 272 } 273 if (vflag) 274 n = strlen(name) < 5 ? 5 : strlen(name); 275 else 276 n = 5; 277 278 printf("%-*.*s %-5" PRIu64 " ", n, n, name, ifd->ifi_mtu); 279 print_addr(ifindex, rti_info[rtax], rti_info, ifd, NULL); 280 } 281 } 282 283 union ifaddr_u { 284 struct ifaddr ifa; 285 struct in_ifaddr in; 286 #ifdef INET6 287 struct in6_ifaddr in6; 288 #endif /* INET6 */ 289 }; 290 291 static void 292 intpr_kvm(u_long ifnetaddr, void (*pfunc)(const char *)) 293 { 294 struct ifnet ifnet; 295 union ifaddr_u ifaddr; 296 u_long ifaddraddr; 297 struct ifnet_head ifhead; /* TAILQ_HEAD */ 298 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 299 300 if (ifnetaddr == 0) { 301 printf("ifnet: symbol not defined\n"); 302 return; 303 } 304 305 /* 306 * Find the pointer to the first ifnet structure. Replace 307 * the pointer to the TAILQ_HEAD with the actual pointer 308 * to the first list element. 309 */ 310 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 311 return; 312 ifnetaddr = (u_long)ifhead.tqh_first; 313 314 intpr_header(); 315 316 ifaddraddr = 0; 317 while (ifnetaddr || ifaddraddr) { 318 char *cp; 319 int n; 320 321 if (ifaddraddr == 0) { 322 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 323 return; 324 memmove(name, ifnet.if_xname, IFNAMSIZ); 325 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 326 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 327 if (interface != 0 && strcmp(name, interface) != 0) 328 continue; 329 cp = strchr(name, '\0'); 330 331 if (pfunc) { 332 (*pfunc)(name); 333 continue; 334 } 335 336 if ((ifnet.if_flags & IFF_UP) == 0) 337 *cp++ = '*'; 338 *cp = '\0'; 339 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 340 } 341 if (vflag) 342 n = strlen(name) < 5 ? 5 : strlen(name); 343 else 344 n = 5; 345 printf("%-*.*s %-5llu ", n, n, name, 346 (unsigned long long)ifnet.if_mtu); 347 if (ifaddraddr == 0) { 348 printf("%-13.13s ", "none"); 349 printf("%-17.17s ", "none"); 350 } else { 351 struct sockaddr *sa; 352 353 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 354 ifaddraddr = 0; 355 continue; 356 } 357 #define CP(x) ((char *)(x)) 358 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 359 CP(&ifaddr); 360 sa = (struct sockaddr *)cp; 361 print_addr(ifnet.if_index, sa, (void *)&ifaddr, 362 &ifnet.if_data, &ifnet); 363 } 364 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 365 } 366 367 } 368 369 static void 370 mc_print(const int ifindex, const size_t ias, const char *oid, int *mcast_oids, 371 void (*pr)(const void *)) 372 { 373 uint8_t *mcast_addrs, *p; 374 const size_t incr = 2 * ias + sizeof(uint32_t); 375 size_t len; 376 377 if (mcast_oids[0] == 0) { 378 size_t oidlen = 4; 379 if (sysctlnametomib(oid, mcast_oids, &oidlen) == -1) { 380 warnx("'%s' not found", oid); 381 return; 382 } 383 if (oidlen != 3) { 384 warnx("Wrong OID path for '%s'", oid); 385 return; 386 } 387 } 388 389 if (mcast_oids[3] == ifindex) 390 return; 391 mcast_oids[3] = ifindex; 392 393 mcast_addrs = asysctl(mcast_oids, 4, &len); 394 if (mcast_addrs == NULL && len != 0) { 395 warn("failed to read '%s'", oid); 396 return; 397 } 398 if (len) { 399 p = mcast_addrs; 400 while (len >= incr) { 401 (*pr)((p + ias)); 402 p += incr; 403 len -= incr; 404 } 405 } 406 free(mcast_addrs); 407 } 408 409 #ifdef INET6 410 static void 411 ia6_print(const struct in6_addr *ia) 412 { 413 struct sockaddr_in6 as6; 414 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 415 int n; 416 417 memset(&as6, 0, sizeof(as6)); 418 as6.sin6_len = sizeof(struct sockaddr_in6); 419 as6.sin6_family = AF_INET6; 420 as6.sin6_addr = *ia; 421 inet6_getscopeid(&as6, INET6_IS_ADDR_MC_LINKLOCAL); 422 if (getnameinfo((struct sockaddr *)&as6, as6.sin6_len, hbuf, 423 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 424 strlcpy(hbuf, "??", sizeof(hbuf)); 425 } 426 if (vflag) 427 n = strlen(hbuf) < 17 ? 17 : strlen(hbuf); 428 else 429 n = 17; 430 printf("\n%25s %-*.*s ", "", n, n, hbuf); 431 } 432 433 static void 434 mc6_print(const int ifindex) 435 { 436 static int mcast_oids[4]; 437 438 mc_print(ifindex, sizeof(struct in6_addr), "net.inet6.multicast", 439 mcast_oids, (void (*)(const void *))ia6_print); 440 } 441 #endif 442 443 static void 444 ia4_print(const struct in_addr *ia) 445 { 446 printf("\n%25s %-17.17s ", "", routename4(ia->s_addr, nflag)); 447 } 448 449 static void 450 mc4_print(const int ifindex) 451 { 452 static int mcast_oids[4]; 453 454 mc_print(ifindex, sizeof(struct in_addr), "net.inet.multicast", 455 mcast_oids, (void (*)(const void *))ia4_print); 456 } 457 458 static void 459 print_addr(const int ifindex, struct sockaddr *sa, 460 struct sockaddr **rtinfo, struct if_data *ifd, struct ifnet *ifnet) 461 { 462 char hexsep = '.'; /* for hexprint */ 463 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 464 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 465 #ifdef INET6 466 const int niflag = NI_NUMERICHOST; 467 struct sockaddr_in6 *sin6, *netmask6; 468 #endif 469 struct sockaddr_in netmask; 470 struct sockaddr_in *sin; 471 char *cp; 472 int n, m; 473 474 switch (sa->sa_family) { 475 case AF_UNSPEC: 476 printf("%-13.13s ", "none"); 477 printf("%-17.17s ", "none"); 478 break; 479 case AF_INET: 480 sin = (struct sockaddr_in *)sa; 481 if (use_sysctl) { 482 netmask = *((struct sockaddr_in *)rtinfo[RTAX_NETMASK]); 483 } else { 484 struct in_ifaddr *ifaddr_in = (void *)rtinfo; 485 netmask.sin_addr.s_addr = ifaddr_in->ia_subnetmask; 486 } 487 cp = netname4(sin, &netmask, nflag); 488 if (vflag) 489 n = strlen(cp) < 13 ? 13 : strlen(cp); 490 else 491 n = 13; 492 printf("%-*.*s ", n, n, cp); 493 cp = routename4(sin->sin_addr.s_addr, nflag); 494 if (vflag) 495 n = strlen(cp) < 17 ? 17 : strlen(cp); 496 else 497 n = 17; 498 printf("%-*.*s ", n, n, cp); 499 500 if (!aflag) 501 break; 502 if (ifnet) { 503 u_long multiaddr; 504 struct in_multi inm; 505 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 506 507 multiaddr = (u_long)ifaddr->in.ia_multiaddrs.lh_first; 508 while (multiaddr != 0) { 509 kread(multiaddr, (char *)&inm, sizeof inm); 510 ia4_print(&inm.inm_addr); 511 multiaddr = (u_long)inm.inm_list.le_next; 512 } 513 } else { 514 mc4_print(ifindex); 515 } 516 break; 517 #ifdef INET6 518 case AF_INET6: 519 sin6 = (struct sockaddr_in6 *)sa; 520 inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL); 521 #ifdef __KAME__ 522 if (!vflag) 523 sin6->sin6_scope_id = 0; 524 #endif 525 526 if (use_sysctl) { 527 netmask6 = (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]; 528 } else { 529 struct in6_ifaddr *ifaddr_in6 = (void *)rtinfo; 530 netmask6 = &ifaddr_in6->ia_prefixmask; 531 } 532 533 cp = netname6(sin6, netmask6, nflag); 534 if (vflag) 535 n = strlen(cp) < 13 ? 13 : strlen(cp); 536 else 537 n = 13; 538 printf("%-*.*s ", n, n, cp); 539 if (getnameinfo((struct sockaddr *)sin6, 540 sin6->sin6_len, 541 hbuf, sizeof(hbuf), NULL, 0, 542 niflag) != 0) { 543 strlcpy(hbuf, "?", sizeof(hbuf)); 544 } 545 cp = hbuf; 546 if (vflag) 547 n = strlen(cp) < 17 ? 17 : strlen(cp); 548 else 549 n = 17; 550 printf("%-*.*s ", n, n, cp); 551 552 if (!aflag) 553 break; 554 if (ifnet) { 555 u_long multiaddr; 556 struct in6_multi inm; 557 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 558 559 multiaddr = (u_long)ifaddr->in6._ia6_multiaddrs.lh_first; 560 while (multiaddr != 0) { 561 kread(multiaddr, (char *)&inm, sizeof inm); 562 ia6_print(&inm.in6m_addr); 563 multiaddr = (u_long)inm.in6m_entry.le_next; 564 } 565 } else { 566 mc6_print(ifindex); 567 } 568 break; 569 #endif /*INET6*/ 570 #ifndef SMALL 571 case AF_APPLETALK: 572 printf("atalk:%-7.7s ", 573 atalk_print(sa,0x10)); 574 printf("%-17.17s ", atalk_print(sa,0x0b)); 575 break; 576 #endif 577 case AF_LINK: 578 printf("%-13.13s ", "<Link>"); 579 if (getnameinfo(sa, sa->sa_len, 580 hbuf, sizeof(hbuf), NULL, 0, 581 NI_NUMERICHOST) != 0) { 582 strlcpy(hbuf, "?", sizeof(hbuf)); 583 } 584 cp = hbuf; 585 if (vflag) 586 n = strlen(cp) < 17 ? 17 : strlen(cp); 587 else 588 n = 17; 589 printf("%-*.*s ", n, n, cp); 590 break; 591 592 default: 593 m = printf("(%d)", sa->sa_family); 594 for (cp = sa->sa_len + (char *)sa; 595 --cp > sa->sa_data && (*cp == 0);) {} 596 n = cp - sa->sa_data + 1; 597 cp = sa->sa_data; 598 599 while (--n >= 0) 600 m += printf(hexfmt, *cp++ & 0xff, 601 n > 0 ? hexsep : ' '); 602 m = 32 - m; 603 while (m-- > 0) 604 putchar(' '); 605 break; 606 } 607 608 if (bflag) { 609 char humbuf[HUMBUF_SIZE]; 610 611 if (hflag && humanize_number(humbuf, sizeof(humbuf), 612 ifd->ifi_ibytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 613 printf("%10s ", humbuf); 614 else 615 printf("%10llu ", (unsigned long long)ifd->ifi_ibytes); 616 617 if (hflag && humanize_number(humbuf, sizeof(humbuf), 618 ifd->ifi_obytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 619 printf("%10s", humbuf); 620 else 621 printf("%10llu", (unsigned long long)ifd->ifi_obytes); 622 } else { 623 printf("%8llu %5llu", 624 (unsigned long long)ifd->ifi_ipackets, 625 (unsigned long long)ifd->ifi_ierrors); 626 if (dflag) 627 printf(" %6" PRIu64, ifd->ifi_iqdrops); 628 printf(" %8llu %5llu %5llu", 629 (unsigned long long)ifd->ifi_opackets, 630 (unsigned long long)ifd->ifi_oerrors, 631 (unsigned long long)ifd->ifi_collisions); 632 } 633 if (dflag) 634 printf(" %6lld", ifnet ? 635 (unsigned long long)ifnet->if_snd.ifq_drops : 0); 636 if (tflag) 637 printf(" %4d", ifnet ? ifnet->if_timer : 0); 638 putchar('\n'); 639 } 640 641 static void 642 iftot_banner(struct iftot *ift) 643 { 644 if (bflag) 645 printf("%7.7s in %8.8s %6.6s out %5.5s", 646 ift->ift_name, " ", 647 ift->ift_name, " "); 648 else 649 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 650 ift->ift_name, " ", 651 ift->ift_name, " ", " "); 652 if (dflag) 653 printf(" %5.5s", " "); 654 655 if (bflag) 656 printf(" %7.7s in %8.8s %6.6s out %5.5s", 657 "total", " ", "total", " "); 658 else 659 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 660 "total", " ", "total", " ", " "); 661 if (dflag) 662 printf(" %5.5s", " "); 663 putchar('\n'); 664 if (bflag) 665 printf("%10.10s %8.8s %10.10s %5.5s", 666 "bytes", " ", "bytes", " "); 667 else 668 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 669 "packets", "errs", "packets", "errs", "colls"); 670 if (dflag) 671 printf(" %5.5s", "drops"); 672 673 if (bflag) 674 printf(" %10.10s %8.8s %10.10s %5.5s", 675 "bytes", " ", "bytes", " "); 676 else 677 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 678 "packets", "errs", "packets", "errs", "colls"); 679 if (dflag) 680 printf(" %5.5s", "drops"); 681 putchar('\n'); 682 fflush(stdout); 683 } 684 685 static void 686 iftot_print(struct iftot *cur, struct iftot *old) 687 { 688 if (bflag) 689 printf("%10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 690 cur->ift_ib - old->ift_ib, " ", 691 cur->ift_ob - old->ift_ob, " "); 692 else 693 printf("%8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 694 cur->ift_ip - old->ift_ip, 695 cur->ift_ie - old->ift_ie, 696 cur->ift_op - old->ift_op, 697 cur->ift_oe - old->ift_oe, 698 cur->ift_co - old->ift_co); 699 if (dflag) 700 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr); 701 } 702 703 static void 704 iftot_print_sum(struct iftot *cur, struct iftot *old) 705 { 706 if (bflag) 707 printf(" %10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 708 cur->ift_ib - old->ift_ib, " ", 709 cur->ift_ob - old->ift_ob, " "); 710 else 711 printf(" %8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 712 cur->ift_ip - old->ift_ip, 713 cur->ift_ie - old->ift_ie, 714 cur->ift_op - old->ift_op, 715 cur->ift_oe - old->ift_oe, 716 cur->ift_co - old->ift_co); 717 718 if (dflag) 719 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr); 720 } 721 722 __dead static void 723 sidewaysintpr_sysctl(unsigned interval) 724 { 725 struct itimerval it; 726 sigset_t emptyset; 727 sigset_t noalrm; 728 unsigned line; 729 730 set_lines(); 731 732 fetchifs(); 733 if (ip_cur.ift_name[0] == '\0') { 734 fprintf(stderr, "%s: %s: unknown interface\n", 735 getprogname(), interface); 736 exit(1); 737 } 738 739 sigemptyset(&emptyset); 740 sigemptyset(&noalrm); 741 sigaddset(&noalrm, SIGALRM); 742 sigprocmask(SIG_SETMASK, &noalrm, NULL); 743 744 signalled = 0; 745 (void)signal(SIGALRM, catchalarm); 746 747 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 748 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 749 setitimer(ITIMER_REAL, &it, NULL); 750 751 banner: 752 iftot_banner(&ip_cur); 753 754 line = 0; 755 bzero(&ip_old, sizeof(ip_old)); 756 bzero(&sum_old, sizeof(sum_old)); 757 loop: 758 bzero(&sum_cur, sizeof(sum_cur)); 759 760 fetchifs(); 761 762 iftot_print(&ip_cur, &ip_old); 763 764 ip_old = ip_cur; 765 766 iftot_print_sum(&sum_cur, &sum_old); 767 768 sum_old = sum_cur; 769 770 putchar('\n'); 771 fflush(stdout); 772 line++; 773 if (signalled == 0) { 774 sigsuspend(&emptyset); 775 } 776 signalled = 0; 777 if (line == redraw_lines) 778 goto banner; 779 goto loop; 780 /*NOTREACHED*/ 781 } 782 783 static void 784 sidewaysintpr_kvm(unsigned interval, u_long off) 785 { 786 struct itimerval it; 787 sigset_t emptyset; 788 sigset_t noalrm; 789 struct ifnet ifnet; 790 u_long firstifnet; 791 struct iftot *ip, *total; 792 unsigned line; 793 struct iftot *lastif, *sum, *interesting; 794 struct ifnet_head ifhead; /* TAILQ_HEAD */ 795 796 set_lines(); 797 798 /* 799 * Find the pointer to the first ifnet structure. Replace 800 * the pointer to the TAILQ_HEAD with the actual pointer 801 * to the first list element. 802 */ 803 if (kread(off, (char *)&ifhead, sizeof ifhead)) 804 return; 805 firstifnet = (u_long)ifhead.tqh_first; 806 807 lastif = iftot; 808 sum = iftot + MAXIF - 1; 809 total = sum - 1; 810 interesting = (interface == NULL) ? iftot : NULL; 811 for (off = firstifnet, ip = iftot; off;) { 812 if (kread(off, (char *)&ifnet, sizeof ifnet)) 813 break; 814 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 815 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 816 if (interface && strcmp(ifnet.if_xname, interface) == 0) 817 interesting = ip; 818 ip++; 819 if (ip >= iftot + MAXIF - 2) 820 break; 821 off = (u_long)ifnet.if_list.tqe_next; 822 } 823 if (interesting == NULL) { 824 fprintf(stderr, "%s: %s: unknown interface\n", 825 getprogname(), interface); 826 exit(1); 827 } 828 lastif = ip; 829 830 sigemptyset(&emptyset); 831 sigemptyset(&noalrm); 832 sigaddset(&noalrm, SIGALRM); 833 sigprocmask(SIG_SETMASK, &noalrm, NULL); 834 835 signalled = 0; 836 (void)signal(SIGALRM, catchalarm); 837 838 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 839 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 840 setitimer(ITIMER_REAL, &it, NULL); 841 842 banner: 843 if (bflag) 844 printf("%7.7s in %8.8s %6.6s out %5.5s", 845 interesting->ift_name, " ", 846 interesting->ift_name, " "); 847 else 848 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 849 interesting->ift_name, " ", 850 interesting->ift_name, " ", " "); 851 if (dflag) 852 printf(" %5.5s", " "); 853 if (lastif - iftot > 0) { 854 if (bflag) 855 printf(" %7.7s in %8.8s %6.6s out %5.5s", 856 "total", " ", "total", " "); 857 else 858 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 859 "total", " ", "total", " ", " "); 860 if (dflag) 861 printf(" %5.5s", " "); 862 } 863 for (ip = iftot; ip < iftot + MAXIF; ip++) { 864 ip->ift_ip = 0; 865 ip->ift_ib = 0; 866 ip->ift_ie = 0; 867 ip->ift_op = 0; 868 ip->ift_ob = 0; 869 ip->ift_oe = 0; 870 ip->ift_co = 0; 871 ip->ift_dr = 0; 872 } 873 putchar('\n'); 874 if (bflag) 875 printf("%10.10s %8.8s %10.10s %5.5s", 876 "bytes", " ", "bytes", " "); 877 else 878 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 879 "packets", "errs", "packets", "errs", "colls"); 880 if (dflag) 881 printf(" %5.5s", "drops"); 882 if (lastif - iftot > 0) { 883 if (bflag) 884 printf(" %10.10s %8.8s %10.10s %5.5s", 885 "bytes", " ", "bytes", " "); 886 else 887 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 888 "packets", "errs", "packets", "errs", "colls"); 889 if (dflag) 890 printf(" %5.5s", "drops"); 891 } 892 putchar('\n'); 893 fflush(stdout); 894 line = 0; 895 loop: 896 sum->ift_ip = 0; 897 sum->ift_ib = 0; 898 sum->ift_ie = 0; 899 sum->ift_op = 0; 900 sum->ift_ob = 0; 901 sum->ift_oe = 0; 902 sum->ift_co = 0; 903 sum->ift_dr = 0; 904 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 905 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 906 off = 0; 907 continue; 908 } 909 if (ip == interesting) { 910 if (bflag) { 911 char humbuf[HUMBUF_SIZE]; 912 913 if (hflag && humanize_number(humbuf, 914 sizeof(humbuf), 915 ifnet.if_ibytes - ip->ift_ib, "", 916 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 917 printf("%10s %8.8s ", humbuf, " "); 918 else 919 printf("%10llu %8.8s ", 920 (unsigned long long) 921 (ifnet.if_ibytes-ip->ift_ib), " "); 922 923 if (hflag && humanize_number(humbuf, 924 sizeof(humbuf), 925 ifnet.if_obytes - ip->ift_ob, "", 926 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 927 printf("%10s %5.5s", humbuf, " "); 928 else 929 printf("%10llu %5.5s", 930 (unsigned long long) 931 (ifnet.if_obytes-ip->ift_ob), " "); 932 } else { 933 printf("%8llu %5llu %8llu %5llu %5llu", 934 (unsigned long long) 935 (ifnet.if_ipackets - ip->ift_ip), 936 (unsigned long long) 937 (ifnet.if_ierrors - ip->ift_ie), 938 (unsigned long long) 939 (ifnet.if_opackets - ip->ift_op), 940 (unsigned long long) 941 (ifnet.if_oerrors - ip->ift_oe), 942 (unsigned long long) 943 (ifnet.if_collisions - ip->ift_co)); 944 } 945 if (dflag) 946 printf(" %5" PRIu64, 947 ifnet.if_snd.ifq_drops - ip->ift_dr); 948 } 949 ip->ift_ip = ifnet.if_ipackets; 950 ip->ift_ib = ifnet.if_ibytes; 951 ip->ift_ie = ifnet.if_ierrors; 952 ip->ift_op = ifnet.if_opackets; 953 ip->ift_ob = ifnet.if_obytes; 954 ip->ift_oe = ifnet.if_oerrors; 955 ip->ift_co = ifnet.if_collisions; 956 ip->ift_dr = ifnet.if_snd.ifq_drops; 957 sum->ift_ip += ip->ift_ip; 958 sum->ift_ib += ip->ift_ib; 959 sum->ift_ie += ip->ift_ie; 960 sum->ift_op += ip->ift_op; 961 sum->ift_ob += ip->ift_ob; 962 sum->ift_oe += ip->ift_oe; 963 sum->ift_co += ip->ift_co; 964 sum->ift_dr += ip->ift_dr; 965 off = (u_long)ifnet.if_list.tqe_next; 966 } 967 if (lastif - iftot > 0) { 968 if (bflag) { 969 char humbuf[HUMBUF_SIZE]; 970 971 if (hflag && humanize_number(humbuf, 972 sizeof(humbuf), sum->ift_ib - total->ift_ib, "", 973 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 974 printf(" %10s %8.8s ", humbuf, " "); 975 else 976 printf(" %10llu %8.8s ", 977 (unsigned long long) 978 (sum->ift_ib - total->ift_ib), " "); 979 980 if (hflag && humanize_number(humbuf, 981 sizeof(humbuf), sum->ift_ob - total->ift_ob, "", 982 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 983 printf("%10s %5.5s", humbuf, " "); 984 else 985 printf("%10llu %5.5s", 986 (unsigned long long) 987 (sum->ift_ob - total->ift_ob), " "); 988 } else { 989 printf(" %8llu %5llu %8llu %5llu %5llu", 990 (unsigned long long) 991 (sum->ift_ip - total->ift_ip), 992 (unsigned long long) 993 (sum->ift_ie - total->ift_ie), 994 (unsigned long long) 995 (sum->ift_op - total->ift_op), 996 (unsigned long long) 997 (sum->ift_oe - total->ift_oe), 998 (unsigned long long) 999 (sum->ift_co - total->ift_co)); 1000 } 1001 if (dflag) 1002 printf(" %5llu", 1003 (unsigned long long)(sum->ift_dr - total->ift_dr)); 1004 } 1005 *total = *sum; 1006 putchar('\n'); 1007 fflush(stdout); 1008 line++; 1009 if (signalled == 0) { 1010 sigsuspend(&emptyset); 1011 } 1012 signalled = 0; 1013 if (line == redraw_lines) 1014 goto banner; 1015 goto loop; 1016 /*NOTREACHED*/ 1017 } 1018 1019 /* 1020 * Print a running summary of interface statistics. 1021 * Repeat display every interval seconds, showing statistics 1022 * collected over that interval. Assumes that interval is non-zero. 1023 * First line printed at top of screen is always cumulative. 1024 */ 1025 static void 1026 sidewaysintpr(unsigned int interval, u_long off) 1027 { 1028 1029 if (use_sysctl) { 1030 sidewaysintpr_sysctl(interval); 1031 } else { 1032 sidewaysintpr_kvm(interval, off); 1033 } 1034 } 1035 1036 /* 1037 * Called if an interval expires before sidewaysintpr has completed a loop. 1038 * Sets a flag to not wait for the alarm. 1039 */ 1040 static void 1041 catchalarm(int signo) 1042 { 1043 1044 signalled = true; 1045 } 1046 1047 static void 1048 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 1049 { 1050 int i; 1051 1052 for (i = 0; i < RTAX_MAX; i++) { 1053 if (addrs & (1 << i)) { 1054 rti_info[i] = sa; 1055 sa = (struct sockaddr *)((char *)(sa) + 1056 RT_ROUNDUP(sa->sa_len)); 1057 } else 1058 rti_info[i] = NULL; 1059 } 1060 } 1061 1062 static void 1063 fetchifs(void) 1064 { 1065 struct if_msghdr *ifm; 1066 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 1067 struct rt_msghdr *rtm; 1068 struct if_data *ifd = NULL; 1069 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1070 struct sockaddr_dl *sdl; 1071 static char *buf = NULL; 1072 static size_t olen; 1073 char *next, *lim; 1074 char name[IFNAMSIZ]; 1075 size_t len; 1076 1077 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 1078 err(1, "sysctl"); 1079 if (len > olen) { 1080 free(buf); 1081 if ((buf = malloc(len)) == NULL) 1082 err(1, NULL); 1083 olen = len; 1084 } 1085 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 1086 err(1, "sysctl"); 1087 1088 lim = buf + len; 1089 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1090 rtm = (struct rt_msghdr *)next; 1091 if (rtm->rtm_version != RTM_VERSION) 1092 continue; 1093 switch (rtm->rtm_type) { 1094 case RTM_IFINFO: 1095 ifm = (struct if_msghdr *)next; 1096 ifd = &ifm->ifm_data; 1097 1098 sa = (struct sockaddr *)(ifm + 1); 1099 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 1100 1101 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 1102 if (sdl == NULL || sdl->sdl_family != AF_LINK) 1103 continue; 1104 bzero(name, sizeof(name)); 1105 if (sdl->sdl_nlen >= IFNAMSIZ) 1106 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 1107 else if (sdl->sdl_nlen > 0) 1108 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 1109 1110 if (interface != 0 && !strcmp(name, interface)) { 1111 strlcpy(ip_cur.ift_name, name, 1112 sizeof(ip_cur.ift_name)); 1113 ip_cur.ift_ip = ifd->ifi_ipackets; 1114 ip_cur.ift_ib = ifd->ifi_ibytes; 1115 ip_cur.ift_ie = ifd->ifi_ierrors; 1116 ip_cur.ift_op = ifd->ifi_opackets; 1117 ip_cur.ift_ob = ifd->ifi_obytes; 1118 ip_cur.ift_oe = ifd->ifi_oerrors; 1119 ip_cur.ift_co = ifd->ifi_collisions; 1120 ip_cur.ift_dr = ifd->ifi_iqdrops; 1121 } 1122 1123 sum_cur.ift_ip += ifd->ifi_ipackets; 1124 sum_cur.ift_ib += ifd->ifi_ibytes; 1125 sum_cur.ift_ie += ifd->ifi_ierrors; 1126 sum_cur.ift_op += ifd->ifi_opackets; 1127 sum_cur.ift_ob += ifd->ifi_obytes; 1128 sum_cur.ift_oe += ifd->ifi_oerrors; 1129 sum_cur.ift_co += ifd->ifi_collisions; 1130 sum_cur.ift_dr += ifd->ifi_iqdrops; 1131 break; 1132 } 1133 } 1134 if (interface == NULL) { 1135 strlcpy(ip_cur.ift_name, name, 1136 sizeof(ip_cur.ift_name)); 1137 ip_cur.ift_ip = ifd->ifi_ipackets; 1138 ip_cur.ift_ib = ifd->ifi_ibytes; 1139 ip_cur.ift_ie = ifd->ifi_ierrors; 1140 ip_cur.ift_op = ifd->ifi_opackets; 1141 ip_cur.ift_ob = ifd->ifi_obytes; 1142 ip_cur.ift_oe = ifd->ifi_oerrors; 1143 ip_cur.ift_co = ifd->ifi_collisions; 1144 ip_cur.ift_dr = ifd->ifi_iqdrops; 1145 } 1146 } 1147