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