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