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