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