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