if.c revision 1.99 1 /* $NetBSD: if.c,v 1.99 2022/09/02 06:25:43 msaitoh 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.99 2022/09/02 06:25:43 msaitoh 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 u_quad_t ift_dr; /* drops */
84 };
85
86 static void set_lines(void);
87 static void print_addr(const int, 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 static sig_atomic_t signalled; /* set when alarm goes off */
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 static void
142 intpr_header(void)
143 {
144
145 if (!sflag && !pflag) {
146 if (bflag) {
147 printf("%-5.5s %-5.5s %-13.13s %-17.17s "
148 "%10.10s %10.10s",
149 "Name", "Mtu", "Network", "Address",
150 "Ibytes", "Obytes");
151 } else {
152 printf("%-5.5s %-5.5s %-13.13s %-17.17s "
153 "%8.8s %5.5s",
154 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
155 if (dflag)
156 printf(" %6.6s", "Idrops");
157 printf(" %8.8s %5.5s %5.5s",
158 "Opkts", "Oerrs", "Colls");
159 }
160 if (dflag)
161 printf(" %6.6s", "Odrops");
162 if (tflag)
163 printf(" %4.4s", "Time");
164 putchar('\n');
165 }
166 }
167
168 static void
169 intpr_sysctl(void)
170 {
171 struct if_msghdr *ifm;
172 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
173 static char *buf = NULL;
174 static size_t olen;
175 char *next, *lim, *cp;
176 struct rt_msghdr *rtm;
177 struct ifa_msghdr *ifam;
178 struct if_data *ifd = NULL;
179 struct sockaddr *sa, *rti_info[RTAX_MAX];
180 struct sockaddr_dl *sdl;
181 uint64_t total = 0;
182 size_t len;
183 int did = 1, rtax = 0, n;
184 char name[IFNAMSIZ + 1]; /* + 1 for `*' */
185 int ifindex = 0;
186
187 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
188 err(1, "sysctl");
189 if (len > olen) {
190 free(buf);
191 if ((buf = malloc(len)) == NULL)
192 err(1, NULL);
193 olen = len;
194 }
195 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1)
196 err(1, "sysctl");
197
198 intpr_header();
199
200 lim = buf + len;
201 for (next = buf; next < lim; next += rtm->rtm_msglen) {
202 rtm = (struct rt_msghdr *)next;
203 if (rtm->rtm_version != RTM_VERSION)
204 continue;
205 switch (rtm->rtm_type) {
206 case RTM_IFINFO:
207 total = 0;
208 ifm = (struct if_msghdr *)next;
209 ifd = &ifm->ifm_data;
210
211 sa = (struct sockaddr *)(ifm + 1);
212 get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
213
214 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP];
215 if (sdl == NULL || sdl->sdl_family != AF_LINK)
216 continue;
217
218 bzero(name, sizeof(name));
219 if (sdl->sdl_nlen >= IFNAMSIZ)
220 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1);
221 else if (sdl->sdl_nlen > 0)
222 memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
223
224 if (interface != NULL && strcmp(name, interface) != 0)
225 continue;
226
227 ifindex = sdl->sdl_index;
228
229 /* mark inactive interfaces with a '*' */
230 cp = strchr(name, '\0');
231 if ((ifm->ifm_flags & IFF_UP) == 0)
232 *cp++ = '*';
233 *cp = '\0';
234
235 if (qflag) {
236 total = ifd->ifi_ibytes + ifd->ifi_obytes +
237 ifd->ifi_ipackets + ifd->ifi_ierrors +
238 ifd->ifi_opackets + ifd->ifi_oerrors +
239 ifd->ifi_collisions;
240 if (dflag)
241 total += ifd->ifi_iqdrops;
242 if (total == 0)
243 continue;
244 }
245 /* Skip the first one */
246 if (did) {
247 did = 0;
248 continue;
249 }
250 rtax = RTAX_IFP;
251 break;
252 case RTM_NEWADDR:
253 if (qflag && total == 0)
254 continue;
255 if (interface != NULL && strcmp(name, interface) != 0)
256 continue;
257 ifam = (struct ifa_msghdr *)next;
258 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
259 RTA_BRD)) == 0)
260 break;
261
262 sa = (struct sockaddr *)(ifam + 1);
263
264 get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
265 rtax = RTAX_IFA;
266 did = 1;
267 break;
268 default:
269 continue;
270 }
271 if (vflag)
272 n = strlen(name) < 5 ? 5 : strlen(name);
273 else
274 n = 5;
275
276 printf("%-*.*s %-5" PRIu64 " ", n, n, name, ifd->ifi_mtu);
277 print_addr(ifindex, rti_info[rtax], rti_info, ifd, NULL);
278 }
279 }
280
281 union ifaddr_u {
282 struct ifaddr ifa;
283 struct in_ifaddr in;
284 #ifdef INET6
285 struct in6_ifaddr in6;
286 #endif /* INET6 */
287 };
288
289 static void
290 ifnet_to_ifdata_kvm(const struct ifnet * const ifp, struct if_data * const ifd)
291 {
292
293 /*
294 * Interface statistics are no longer kept in struct ifnet,
295 * and thus an if_data is no longer embedded in struct ifnet.
296 * We cannot read stats via kvm without chasing per-cpu data,
297 * and maybe someday we could do that. But for now, this is
298 * what we have.
299 *
300 * Just copy the fields that do exist.
301 */
302 memset(ifd, 0, sizeof(*ifd));
303 ifd->ifi_type = ifp->if_type;
304 ifd->ifi_addrlen = ifp->if_addrlen;
305 ifd->ifi_hdrlen = ifp->if_hdrlen;
306 ifd->ifi_link_state = ifp->if_link_state;
307 ifd->ifi_mtu = ifp->if_mtu;
308 ifd->ifi_metric = ifp->if_metric;
309 ifd->ifi_baudrate = ifp->if_baudrate;
310 ifd->ifi_lastchange = ifp->if_lastchange;
311 }
312
313 static void
314 intpr_kvm(u_long ifnetaddr, void (*pfunc)(const char *))
315 {
316 struct ifnet ifnet;
317 struct if_data ifd;
318 union ifaddr_u ifaddr;
319 u_long ifaddraddr;
320 struct ifnet_head ifhead; /* TAILQ_HEAD */
321 char name[IFNAMSIZ + 1]; /* + 1 for `*' */
322
323 if (ifnetaddr == 0) {
324 printf("ifnet: symbol not defined\n");
325 return;
326 }
327
328 /*
329 * Find the pointer to the first ifnet structure. Replace
330 * the pointer to the TAILQ_HEAD with the actual pointer
331 * to the first list element.
332 */
333 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead))
334 return;
335 ifnetaddr = (u_long)ifhead.tqh_first;
336
337 intpr_header();
338
339 ifaddraddr = 0;
340 while (ifnetaddr || ifaddraddr) {
341 char *cp;
342 int n;
343
344 if (ifaddraddr == 0) {
345 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
346 return;
347 memmove(name, ifnet.if_xname, IFNAMSIZ);
348 name[IFNAMSIZ - 1] = '\0'; /* sanity */
349 ifnetaddr = (u_long)ifnet.if_list.tqe_next;
350 if (interface != NULL && strcmp(name, interface) != 0)
351 continue;
352 cp = strchr(name, '\0');
353
354 if (pfunc) {
355 (*pfunc)(name);
356 continue;
357 }
358
359 if ((ifnet.if_flags & IFF_UP) == 0)
360 *cp++ = '*';
361 *cp = '\0';
362 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first;
363 }
364 if (vflag)
365 n = strlen(name) < 5 ? 5 : strlen(name);
366 else
367 n = 5;
368 printf("%-*.*s %-5llu ", n, n, name,
369 (unsigned long long)ifnet.if_mtu);
370 if (ifaddraddr == 0) {
371 printf("%-13.13s ", "none");
372 printf("%-17.17s ", "none");
373 } else {
374 struct sockaddr *sa;
375
376 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr))
377 {
378 ifaddraddr = 0;
379 continue;
380 }
381 #define CP(x) ((char *)(x))
382 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
383 CP(&ifaddr);
384 sa = (struct sockaddr *)cp;
385 ifnet_to_ifdata_kvm(&ifnet, &ifd);
386 print_addr(ifnet.if_index, sa, (void *)&ifaddr,
387 &ifd, &ifnet);
388 }
389 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next;
390 }
391
392 }
393
394 static void
395 mc_print(const int ifindex, const size_t ias, const char *oid, int *mcast_oids,
396 void (*pr)(const void *))
397 {
398 uint8_t *mcast_addrs, *p;
399 const size_t incr = 2 * ias + sizeof(uint32_t);
400 size_t len;
401
402 if (mcast_oids[0] == 0) {
403 size_t oidlen = 4;
404 if (sysctlnametomib(oid, mcast_oids, &oidlen) == -1) {
405 warnx("'%s' not found", oid);
406 return;
407 }
408 if (oidlen != 3) {
409 warnx("Wrong OID path for '%s'", oid);
410 return;
411 }
412 }
413
414 if (mcast_oids[3] == ifindex)
415 return;
416 mcast_oids[3] = ifindex;
417
418 mcast_addrs = asysctl(mcast_oids, 4, &len);
419 if (mcast_addrs == NULL && len != 0) {
420 warn("failed to read '%s'", oid);
421 return;
422 }
423 if (len) {
424 p = mcast_addrs;
425 while (len >= incr) {
426 (*pr)((p + ias));
427 p += incr;
428 len -= incr;
429 }
430 }
431 free(mcast_addrs);
432 }
433
434 #ifdef INET6
435 static void
436 ia6_print(const struct in6_addr *ia)
437 {
438 struct sockaddr_in6 as6;
439 char hbuf[NI_MAXHOST]; /* for getnameinfo() */
440 int n;
441
442 memset(&as6, 0, sizeof(as6));
443 as6.sin6_len = sizeof(struct sockaddr_in6);
444 as6.sin6_family = AF_INET6;
445 as6.sin6_addr = *ia;
446 inet6_getscopeid(&as6, INET6_IS_ADDR_MC_LINKLOCAL);
447 if (getnameinfo((struct sockaddr *)&as6, as6.sin6_len, hbuf,
448 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) {
449 strlcpy(hbuf, "??", sizeof(hbuf));
450 }
451 if (vflag)
452 n = strlen(hbuf) < 17 ? 17 : strlen(hbuf);
453 else
454 n = 17;
455 printf("\n%25s %-*.*s ", "", n, n, hbuf);
456 }
457
458 static void
459 mc6_print(const int ifindex)
460 {
461 static int mcast_oids[4];
462
463 mc_print(ifindex, sizeof(struct in6_addr), "net.inet6.multicast",
464 mcast_oids, (void (*)(const void *))ia6_print);
465 }
466 #endif
467
468 static void
469 ia4_print(const struct in_addr *ia)
470 {
471 printf("\n%25s %-17.17s ", "", routename4(ia->s_addr, nflag));
472 }
473
474 static void
475 mc4_print(const int ifindex)
476 {
477 static int mcast_oids[4];
478
479 mc_print(ifindex, sizeof(struct in_addr), "net.inet.multicast",
480 mcast_oids, (void (*)(const void *))ia4_print);
481 }
482
483 static void
484 print_addr(const int ifindex, struct sockaddr *sa,
485 struct sockaddr **rtinfo, struct if_data *ifd, struct ifnet *ifnet)
486 {
487 char hexsep = '.'; /* for hexprint */
488 static const char hexfmt[] = "%02x%c"; /* for hexprint */
489 char hbuf[NI_MAXHOST]; /* for getnameinfo() */
490 #ifdef INET6
491 const int niflag = NI_NUMERICHOST;
492 struct sockaddr_in6 *sin6, *netmask6;
493 #endif
494 struct sockaddr_in netmask;
495 struct sockaddr_in *sin;
496 char *cp;
497 int n, m;
498
499 switch (sa->sa_family) {
500 case AF_UNSPEC:
501 printf("%-13.13s ", "none");
502 printf("%-17.17s ", "none");
503 break;
504 case AF_INET:
505 sin = (struct sockaddr_in *)sa;
506 if (use_sysctl) {
507 netmask =
508 *((struct sockaddr_in *)rtinfo[RTAX_NETMASK]);
509 } else {
510 struct in_ifaddr *ifaddr_in = (void *)rtinfo;
511 netmask.sin_addr.s_addr = ifaddr_in->ia_subnetmask;
512 }
513 cp = netname4(sin, &netmask, nflag);
514 if (vflag)
515 n = strlen(cp) < 13 ? 13 : strlen(cp);
516 else
517 n = 13;
518 printf("%-*.*s ", n, n, cp);
519 cp = routename4(sin->sin_addr.s_addr, nflag);
520 if (vflag)
521 n = strlen(cp) < 17 ? 17 : strlen(cp);
522 else
523 n = 17;
524 printf("%-*.*s ", n, n, cp);
525
526 if (!aflag)
527 break;
528 if (ifnet) {
529 u_long multiaddr;
530 struct in_multi inm;
531 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo;
532
533 multiaddr = (u_long)ifaddr->in.ia_multiaddrs.lh_first;
534 while (multiaddr != 0) {
535 kread(multiaddr, (char *)&inm, sizeof inm);
536 ia4_print(&inm.inm_addr);
537 multiaddr = (u_long)inm.inm_list.le_next;
538 }
539 } else
540 mc4_print(ifindex);
541 break;
542 #ifdef INET6
543 case AF_INET6:
544 sin6 = (struct sockaddr_in6 *)sa;
545 inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL);
546 #ifdef __KAME__
547 if (!vflag)
548 sin6->sin6_scope_id = 0;
549 #endif
550
551 if (use_sysctl)
552 netmask6 = (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK];
553 else {
554 struct in6_ifaddr *ifaddr_in6 = (void *)rtinfo;
555 netmask6 = &ifaddr_in6->ia_prefixmask;
556 }
557
558 cp = netname6(sin6, netmask6, nflag);
559 if (vflag)
560 n = strlen(cp) < 13 ? 13 : strlen(cp);
561 else
562 n = 13;
563 printf("%-*.*s ", n, n, cp);
564 if (getnameinfo((struct sockaddr *)sin6,
565 sin6->sin6_len,
566 hbuf, sizeof(hbuf), NULL, 0,
567 niflag) != 0) {
568 strlcpy(hbuf, "?", sizeof(hbuf));
569 }
570 cp = hbuf;
571 if (vflag)
572 n = strlen(cp) < 17 ? 17 : strlen(cp);
573 else
574 n = 17;
575 printf("%-*.*s ", n, n, cp);
576
577 if (!aflag)
578 break;
579 if (ifnet) {
580 u_long multiaddr;
581 struct in6_multi inm;
582 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo;
583
584 multiaddr = (u_long)ifaddr->in6._ia6_multiaddrs.lh_first;
585 while (multiaddr != 0) {
586 kread(multiaddr, (char *)&inm, sizeof inm);
587 ia6_print(&inm.in6m_addr);
588 multiaddr = (u_long)inm.in6m_entry.le_next;
589 }
590 } else
591 mc6_print(ifindex);
592 break;
593 #endif /*INET6*/
594 #ifndef SMALL
595 case AF_APPLETALK:
596 printf("atalk:%-7.7s ", atalk_print(sa, 0x10));
597 printf("%-17.17s ", atalk_print(sa, 0x0b));
598 break;
599 #endif
600 case AF_LINK:
601 printf("%-13.13s ", "<Link>");
602 if (getnameinfo(sa, sa->sa_len,
603 hbuf, sizeof(hbuf), NULL, 0,
604 NI_NUMERICHOST) != 0) {
605 strlcpy(hbuf, "?", sizeof(hbuf));
606 }
607 cp = hbuf;
608 if (vflag)
609 n = strlen(cp) < 17 ? 17 : strlen(cp);
610 else
611 n = 17;
612 printf("%-*.*s ", n, n, cp);
613 break;
614
615 default:
616 m = printf("(%d)", sa->sa_family);
617 for (cp = sa->sa_len + (char *)sa;
618 --cp > sa->sa_data && (*cp == 0);) {}
619 n = cp - sa->sa_data + 1;
620 cp = sa->sa_data;
621
622 while (--n >= 0)
623 m += printf(hexfmt, *cp++ & 0xff,
624 n > 0 ? hexsep : ' ');
625 m = 32 - m;
626 while (m-- > 0)
627 putchar(' ');
628 break;
629 }
630
631 if (bflag) {
632 char humbuf[HUMBUF_SIZE];
633
634 if (hflag && humanize_number(humbuf, sizeof(humbuf),
635 ifd->ifi_ibytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0)
636 printf("%10s ", humbuf);
637 else
638 printf("%10llu ", (unsigned long long)ifd->ifi_ibytes);
639
640 if (hflag && humanize_number(humbuf, sizeof(humbuf),
641 ifd->ifi_obytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0)
642 printf("%10s", humbuf);
643 else
644 printf("%10llu", (unsigned long long)ifd->ifi_obytes);
645 } else {
646 printf("%8llu %5llu",
647 (unsigned long long)ifd->ifi_ipackets,
648 (unsigned long long)ifd->ifi_ierrors);
649 if (dflag)
650 printf(" %6" PRIu64, ifd->ifi_iqdrops);
651 printf(" %8llu %5llu %5llu",
652 (unsigned long long)ifd->ifi_opackets,
653 (unsigned long long)ifd->ifi_oerrors,
654 (unsigned long long)ifd->ifi_collisions);
655 }
656 if (dflag)
657 printf(" %6lld", ifnet ?
658 (unsigned long long)ifnet->if_snd.ifq_drops : 0);
659 if (tflag)
660 printf(" %4d", ifnet ? ifnet->if_timer : 0);
661 putchar('\n');
662 }
663
664 static void
665 iftot_banner(struct iftot *ift)
666 {
667 if (bflag)
668 printf("%7.7s in %8.8s %6.6s out %5.5s",
669 ift->ift_name, " ",
670 ift->ift_name, " ");
671 else
672 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s",
673 ift->ift_name, " ",
674 ift->ift_name, " ", " ");
675 if (dflag)
676 printf(" %5.5s", " ");
677
678 if (bflag)
679 printf(" %7.7s in %8.8s %6.6s out %5.5s",
680 "total", " ", "total", " ");
681 else
682 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s",
683 "total", " ", "total", " ", " ");
684 if (dflag)
685 printf(" %5.5s", " ");
686 putchar('\n');
687 if (bflag)
688 printf("%10.10s %8.8s %10.10s %5.5s",
689 "bytes", " ", "bytes", " ");
690 else
691 printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
692 "packets", "errs", "packets", "errs", "colls");
693 if (dflag)
694 printf(" %5.5s", "drops");
695
696 if (bflag)
697 printf(" %10.10s %8.8s %10.10s %5.5s",
698 "bytes", " ", "bytes", " ");
699 else
700 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s",
701 "packets", "errs", "packets", "errs", "colls");
702 if (dflag)
703 printf(" %5.5s", "drops");
704 putchar('\n');
705 fflush(stdout);
706 }
707
708 static void
709 iftot_print(struct iftot *cur, struct iftot *old)
710 {
711 if (bflag)
712 printf("%10" PRIu64 " %8.8s %10" PRIu64 " %5.5s",
713 cur->ift_ib - old->ift_ib, " ",
714 cur->ift_ob - old->ift_ob, " ");
715 else
716 printf("%8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64,
717 cur->ift_ip - old->ift_ip,
718 cur->ift_ie - old->ift_ie,
719 cur->ift_op - old->ift_op,
720 cur->ift_oe - old->ift_oe,
721 cur->ift_co - old->ift_co);
722 if (dflag)
723 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr);
724 }
725
726 static void
727 iftot_print_sum(struct iftot *cur, struct iftot *old)
728 {
729 if (bflag)
730 printf(" %10" PRIu64 " %8.8s %10" PRIu64 " %5.5s",
731 cur->ift_ib - old->ift_ib, " ",
732 cur->ift_ob - old->ift_ob, " ");
733 else
734 printf(" %8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64,
735 cur->ift_ip - old->ift_ip,
736 cur->ift_ie - old->ift_ie,
737 cur->ift_op - old->ift_op,
738 cur->ift_oe - old->ift_oe,
739 cur->ift_co - old->ift_co);
740
741 if (dflag)
742 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr);
743 }
744
745 __dead static void
746 sidewaysintpr_sysctl(unsigned interval)
747 {
748 struct itimerval it;
749 sigset_t emptyset;
750 sigset_t noalrm;
751 unsigned line;
752
753 set_lines();
754
755 fetchifs();
756 if (ip_cur.ift_name[0] == '\0') {
757 fprintf(stderr, "%s: %s: unknown interface\n",
758 getprogname(), interface);
759 exit(1);
760 }
761
762 sigemptyset(&emptyset);
763 sigemptyset(&noalrm);
764 sigaddset(&noalrm, SIGALRM);
765 sigprocmask(SIG_SETMASK, &noalrm, NULL);
766
767 signalled = 0;
768 (void)signal(SIGALRM, catchalarm);
769
770 it.it_interval.tv_sec = it.it_value.tv_sec = interval;
771 it.it_interval.tv_usec = it.it_value.tv_usec = 0;
772 setitimer(ITIMER_REAL, &it, NULL);
773
774 banner:
775 iftot_banner(&ip_cur);
776
777 line = 0;
778 bzero(&ip_old, sizeof(ip_old));
779 bzero(&sum_old, sizeof(sum_old));
780 loop:
781 bzero(&sum_cur, sizeof(sum_cur));
782
783 fetchifs();
784
785 iftot_print(&ip_cur, &ip_old);
786
787 ip_old = ip_cur;
788
789 iftot_print_sum(&sum_cur, &sum_old);
790
791 sum_old = sum_cur;
792
793 putchar('\n');
794 fflush(stdout);
795 line++;
796 if (signalled == 0)
797 sigsuspend(&emptyset);
798
799 signalled = 0;
800 if (line == redraw_lines)
801 goto banner;
802 goto loop;
803 /*NOTREACHED*/
804 }
805
806 static void
807 sidewaysintpr_kvm(unsigned interval, u_long off)
808 {
809 struct itimerval it;
810 sigset_t emptyset;
811 sigset_t noalrm;
812 struct ifnet ifnet;
813 struct if_data ifd;
814 u_long firstifnet;
815 struct iftot *ip, *total;
816 unsigned line;
817 struct iftot *lastif, *sum, *interesting;
818 struct ifnet_head ifhead; /* TAILQ_HEAD */
819
820 set_lines();
821
822 /*
823 * Find the pointer to the first ifnet structure. Replace
824 * the pointer to the TAILQ_HEAD with the actual pointer
825 * to the first list element.
826 */
827 if (kread(off, (char *)&ifhead, sizeof ifhead))
828 return;
829 firstifnet = (u_long)ifhead.tqh_first;
830
831 lastif = iftot;
832 sum = iftot + MAXIF - 1;
833 total = sum - 1;
834 interesting = (interface == NULL) ? iftot : NULL;
835 for (off = firstifnet, ip = iftot; off;) {
836 if (kread(off, (char *)&ifnet, sizeof ifnet))
837 break;
838 memset(ip->ift_name, 0, sizeof(ip->ift_name));
839 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname);
840 if (interface && strcmp(ifnet.if_xname, interface) == 0)
841 interesting = ip;
842 ip++;
843 if (ip >= iftot + MAXIF - 2)
844 break;
845 off = (u_long)ifnet.if_list.tqe_next;
846 }
847 if (interesting == NULL) {
848 fprintf(stderr, "%s: %s: unknown interface\n",
849 getprogname(), interface);
850 exit(1);
851 }
852 lastif = ip;
853
854 sigemptyset(&emptyset);
855 sigemptyset(&noalrm);
856 sigaddset(&noalrm, SIGALRM);
857 sigprocmask(SIG_SETMASK, &noalrm, NULL);
858
859 signalled = 0;
860 (void)signal(SIGALRM, catchalarm);
861
862 it.it_interval.tv_sec = it.it_value.tv_sec = interval;
863 it.it_interval.tv_usec = it.it_value.tv_usec = 0;
864 setitimer(ITIMER_REAL, &it, NULL);
865
866 banner:
867 if (bflag)
868 printf("%7.7s in %8.8s %6.6s out %5.5s",
869 interesting->ift_name, " ",
870 interesting->ift_name, " ");
871 else
872 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s",
873 interesting->ift_name, " ",
874 interesting->ift_name, " ", " ");
875 if (dflag)
876 printf(" %5.5s", " ");
877 if (lastif - iftot > 0) {
878 if (bflag)
879 printf(" %7.7s in %8.8s %6.6s out %5.5s",
880 "total", " ", "total", " ");
881 else
882 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s",
883 "total", " ", "total", " ", " ");
884 if (dflag)
885 printf(" %5.5s", " ");
886 }
887 for (ip = iftot; ip < iftot + MAXIF; ip++) {
888 ip->ift_ip = 0;
889 ip->ift_ib = 0;
890 ip->ift_ie = 0;
891 ip->ift_op = 0;
892 ip->ift_ob = 0;
893 ip->ift_oe = 0;
894 ip->ift_co = 0;
895 ip->ift_dr = 0;
896 }
897 putchar('\n');
898 if (bflag)
899 printf("%10.10s %8.8s %10.10s %5.5s",
900 "bytes", " ", "bytes", " ");
901 else
902 printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
903 "packets", "errs", "packets", "errs", "colls");
904 if (dflag)
905 printf(" %5.5s", "drops");
906 if (lastif - iftot > 0) {
907 if (bflag)
908 printf(" %10.10s %8.8s %10.10s %5.5s",
909 "bytes", " ", "bytes", " ");
910 else
911 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s",
912 "packets", "errs", "packets", "errs", "colls");
913 if (dflag)
914 printf(" %5.5s", "drops");
915 }
916 putchar('\n');
917 fflush(stdout);
918 line = 0;
919 loop:
920 sum->ift_ip = 0;
921 sum->ift_ib = 0;
922 sum->ift_ie = 0;
923 sum->ift_op = 0;
924 sum->ift_ob = 0;
925 sum->ift_oe = 0;
926 sum->ift_co = 0;
927 sum->ift_dr = 0;
928 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
929 if (kread(off, (char *)&ifnet, sizeof ifnet)) {
930 off = 0;
931 continue;
932 }
933 ifnet_to_ifdata_kvm(&ifnet, &ifd);
934 if (ip == interesting) {
935 if (bflag) {
936 char humbuf[HUMBUF_SIZE];
937
938 if (hflag && humanize_number(humbuf,
939 sizeof(humbuf),
940 ifd.ifi_ibytes - ip->ift_ib, "",
941 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0)
942 printf("%10s %8.8s ", humbuf, " ");
943 else
944 printf("%10llu %8.8s ",
945 (unsigned long long)
946 (ifd.ifi_ibytes-ip->ift_ib), " ");
947
948 if (hflag && humanize_number(humbuf,
949 sizeof(humbuf),
950 ifd.ifi_obytes - ip->ift_ob, "",
951 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0)
952 printf("%10s %5.5s", humbuf, " ");
953 else
954 printf("%10llu %5.5s",
955 (unsigned long long)
956 (ifd.ifi_obytes-ip->ift_ob), " ");
957 } else {
958 printf("%8llu %5llu %8llu %5llu %5llu",
959 (unsigned long long)
960 (ifd.ifi_ipackets - ip->ift_ip),
961 (unsigned long long)
962 (ifd.ifi_ierrors - ip->ift_ie),
963 (unsigned long long)
964 (ifd.ifi_opackets - ip->ift_op),
965 (unsigned long long)
966 (ifd.ifi_oerrors - ip->ift_oe),
967 (unsigned long long)
968 (ifd.ifi_collisions - ip->ift_co));
969 }
970 if (dflag)
971 printf(" %5" PRIu64,
972 ifnet.if_snd.ifq_drops - ip->ift_dr);
973 }
974 ip->ift_ip = ifd.ifi_ipackets;
975 ip->ift_ib = ifd.ifi_ibytes;
976 ip->ift_ie = ifd.ifi_ierrors;
977 ip->ift_op = ifd.ifi_opackets;
978 ip->ift_ob = ifd.ifi_obytes;
979 ip->ift_oe = ifd.ifi_oerrors;
980 ip->ift_co = ifd.ifi_collisions;
981 ip->ift_dr = ifnet.if_snd.ifq_drops;
982 sum->ift_ip += ip->ift_ip;
983 sum->ift_ib += ip->ift_ib;
984 sum->ift_ie += ip->ift_ie;
985 sum->ift_op += ip->ift_op;
986 sum->ift_ob += ip->ift_ob;
987 sum->ift_oe += ip->ift_oe;
988 sum->ift_co += ip->ift_co;
989 sum->ift_dr += ip->ift_dr;
990 off = (u_long)ifnet.if_list.tqe_next;
991 }
992 if (lastif - iftot > 0) {
993 if (bflag) {
994 char humbuf[HUMBUF_SIZE];
995
996 if (hflag && humanize_number(humbuf,
997 sizeof(humbuf), sum->ift_ib - total->ift_ib, "",
998 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0)
999 printf(" %10s %8.8s ", humbuf, " ");
1000 else
1001 printf(" %10llu %8.8s ",
1002 (unsigned long long)
1003 (sum->ift_ib - total->ift_ib), " ");
1004
1005 if (hflag && humanize_number(humbuf,
1006 sizeof(humbuf), sum->ift_ob - total->ift_ob, "",
1007 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0)
1008 printf("%10s %5.5s", humbuf, " ");
1009 else
1010 printf("%10llu %5.5s",
1011 (unsigned long long)
1012 (sum->ift_ob - total->ift_ob), " ");
1013 } else {
1014 printf(" %8llu %5llu %8llu %5llu %5llu",
1015 (unsigned long long)
1016 (sum->ift_ip - total->ift_ip),
1017 (unsigned long long)
1018 (sum->ift_ie - total->ift_ie),
1019 (unsigned long long)
1020 (sum->ift_op - total->ift_op),
1021 (unsigned long long)
1022 (sum->ift_oe - total->ift_oe),
1023 (unsigned long long)
1024 (sum->ift_co - total->ift_co));
1025 }
1026 if (dflag)
1027 printf(" %5llu",
1028 (unsigned long long)(sum->ift_dr - total->ift_dr));
1029 }
1030 *total = *sum;
1031 putchar('\n');
1032 fflush(stdout);
1033 line++;
1034 if (signalled == 0)
1035 sigsuspend(&emptyset);
1036
1037 signalled = 0;
1038 if (line == redraw_lines)
1039 goto banner;
1040 goto loop;
1041 /*NOTREACHED*/
1042 }
1043
1044 /*
1045 * Print a running summary of interface statistics.
1046 * Repeat display every interval seconds, showing statistics
1047 * collected over that interval. Assumes that interval is non-zero.
1048 * First line printed at top of screen is always cumulative.
1049 */
1050 static void
1051 sidewaysintpr(unsigned int interval, u_long off)
1052 {
1053
1054 if (use_sysctl)
1055 sidewaysintpr_sysctl(interval);
1056 else
1057 sidewaysintpr_kvm(interval, off);
1058 }
1059
1060 /*
1061 * Called if an interval expires before sidewaysintpr has completed a loop.
1062 * Sets a flag to not wait for the alarm.
1063 */
1064 static void
1065 catchalarm(int signo)
1066 {
1067
1068 signalled = true;
1069 }
1070
1071 static void
1072 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
1073 {
1074 int i;
1075
1076 for (i = 0; i < RTAX_MAX; i++) {
1077 if (addrs & (1 << i)) {
1078 rti_info[i] = sa;
1079 sa = (struct sockaddr *)((char *)(sa) +
1080 RT_ROUNDUP(sa->sa_len));
1081 } else
1082 rti_info[i] = NULL;
1083 }
1084 }
1085
1086 static void
1087 fetchifs(void)
1088 {
1089 struct if_msghdr *ifm;
1090 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
1091 struct rt_msghdr *rtm;
1092 struct if_data *ifd = NULL;
1093 struct sockaddr *sa, *rti_info[RTAX_MAX];
1094 struct sockaddr_dl *sdl;
1095 static char *buf = NULL;
1096 static size_t olen;
1097 char *next, *lim;
1098 char name[IFNAMSIZ];
1099 size_t len;
1100
1101 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
1102 err(1, "sysctl");
1103 if (len > olen) {
1104 free(buf);
1105 if ((buf = malloc(len)) == NULL)
1106 err(1, NULL);
1107 olen = len;
1108 }
1109 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1)
1110 err(1, "sysctl");
1111
1112 lim = buf + len;
1113 for (next = buf; next < lim; next += rtm->rtm_msglen) {
1114 rtm = (struct rt_msghdr *)next;
1115 if (rtm->rtm_version != RTM_VERSION)
1116 continue;
1117 switch (rtm->rtm_type) {
1118 case RTM_IFINFO:
1119 ifm = (struct if_msghdr *)next;
1120 ifd = &ifm->ifm_data;
1121
1122 sa = (struct sockaddr *)(ifm + 1);
1123 get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
1124
1125 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP];
1126 if (sdl == NULL || sdl->sdl_family != AF_LINK)
1127 continue;
1128 bzero(name, sizeof(name));
1129 if (sdl->sdl_nlen >= IFNAMSIZ)
1130 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1);
1131 else if (sdl->sdl_nlen > 0)
1132 memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
1133
1134 if (interface != NULL && !strcmp(name, interface)) {
1135 strlcpy(ip_cur.ift_name, name,
1136 sizeof(ip_cur.ift_name));
1137 ip_cur.ift_ip = ifd->ifi_ipackets;
1138 ip_cur.ift_ib = ifd->ifi_ibytes;
1139 ip_cur.ift_ie = ifd->ifi_ierrors;
1140 ip_cur.ift_op = ifd->ifi_opackets;
1141 ip_cur.ift_ob = ifd->ifi_obytes;
1142 ip_cur.ift_oe = ifd->ifi_oerrors;
1143 ip_cur.ift_co = ifd->ifi_collisions;
1144 ip_cur.ift_dr = ifd->ifi_iqdrops;
1145 }
1146
1147 sum_cur.ift_ip += ifd->ifi_ipackets;
1148 sum_cur.ift_ib += ifd->ifi_ibytes;
1149 sum_cur.ift_ie += ifd->ifi_ierrors;
1150 sum_cur.ift_op += ifd->ifi_opackets;
1151 sum_cur.ift_ob += ifd->ifi_obytes;
1152 sum_cur.ift_oe += ifd->ifi_oerrors;
1153 sum_cur.ift_co += ifd->ifi_collisions;
1154 sum_cur.ift_dr += ifd->ifi_iqdrops;
1155 break;
1156 }
1157 }
1158 if (interface == NULL) {
1159 strlcpy(ip_cur.ift_name, name,
1160 sizeof(ip_cur.ift_name));
1161 ip_cur.ift_ip = ifd->ifi_ipackets;
1162 ip_cur.ift_ib = ifd->ifi_ibytes;
1163 ip_cur.ift_ie = ifd->ifi_ierrors;
1164 ip_cur.ift_op = ifd->ifi_opackets;
1165 ip_cur.ift_ob = ifd->ifi_obytes;
1166 ip_cur.ift_oe = ifd->ifi_oerrors;
1167 ip_cur.ift_co = ifd->ifi_collisions;
1168 ip_cur.ift_dr = ifd->ifi_iqdrops;
1169 }
1170 }
1171