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