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