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