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