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