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