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