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