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