if.c revision 1.65
1/*	$NetBSD: if.c,v 1.65 2009/09/13 19:04:29 elad 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
35static char sccsid[] = "from: @(#)if.c	8.2 (Berkeley) 2/21/94";
36#else
37__RCSID("$NetBSD: if.c,v 1.65 2009/09/13 19:04:29 elad 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
69#define	MAXIF	100
70
71struct	iftot {
72	char ift_name[IFNAMSIZ];	/* interface name */
73	u_quad_t ift_ip;		/* input packets */
74	u_quad_t ift_ib;		/* input bytes */
75	u_quad_t ift_ie;		/* input errors */
76	u_quad_t ift_op;		/* output packets */
77	u_quad_t ift_ob;		/* output bytes */
78	u_quad_t ift_oe;		/* output errors */
79	u_quad_t ift_co;		/* collisions */
80	int ift_dr;			/* drops */
81};
82
83static void print_addr(struct sockaddr *, struct sockaddr **, struct if_data *);
84static void sidewaysintpr(u_int, u_long);
85
86static void iftot_banner(struct iftot *);
87static void iftot_print_sum(struct iftot *, struct iftot *);
88static void iftot_print(struct iftot *, struct iftot *);
89
90static void catchalarm __P((int));
91static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
92static void fetchifs(void);
93
94static void intpr_sysctl(void);
95static void intpr_kvm(u_long, void (*)(const char *));
96
97struct iftot iftot[MAXIF], ip_cur, ip_old, sum_cur, sum_old;
98bool	signalled;			/* set if alarm goes off "early" */
99
100/*
101 * Print a description of the network interfaces.
102 * NOTE: ifnetaddr is the location of the kernel global "ifnet",
103 * which is a TAILQ_HEAD.
104 */
105void
106intpr(interval, ifnetaddr, pfunc)
107	int interval;
108	u_long ifnetaddr;
109	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
125static void
126intpr_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
149static void
150intpr_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 (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
165		err(1, "sysctl");
166	if ((buf = malloc(len)) == NULL)
167		err(1, NULL);
168	if (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 %-5qu ", name, ifd->ifi_mtu);
220			print_addr(rti_info[RTAX_IFP], rti_info, ifd);
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 %-5qu ", name, ifd->ifi_mtu);
238			print_addr(rti_info[RTAX_IFA], rti_info, ifd);
239			break;
240		}
241	}
242}
243
244static void
245intpr_kvm(u_long ifnetaddr, void (*pfunc)(const char *))
246{
247	struct ifnet ifnet;
248	union {
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	} 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);
322		}
323		ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next;
324	}
325
326}
327
328static void
329print_addr(struct sockaddr *sa, struct sockaddr **rtinfo, struct if_data *ifd)
330{
331	char hexsep = '.';		/* for hexprint */
332	static const char hexfmt[] = "%02x%c";	/* for hexprint */
333	char hbuf[NI_MAXHOST];		/* for getnameinfo() */
334#ifdef INET6
335	const int niflag = NI_NUMERICHOST;
336#endif
337	in_addr_t netmask;
338	struct sockaddr_in *sin;
339	struct sockaddr_in6 *sin6, *netmask6;
340	char *cp;
341	int n, m;
342
343	switch (sa->sa_family) {
344	case AF_UNSPEC:
345		printf("%-13.13s ", "none");
346		printf("%-17.17s ", "none");
347		break;
348	case AF_INET:
349		sin = (struct sockaddr_in *)sa;
350#ifdef notdef
351		/*
352		 * can't use inet_makeaddr because kernel
353		 * keeps nets unshifted.
354		 */
355		in = inet_makeaddr(ifaddr.in.ia_subnet,
356			INADDR_ANY);
357		cp = netname4(in.s_addr,
358			ifaddr.in.ia_subnetmask);
359#else
360		if (use_sysctl) {
361			netmask = ((struct sockaddr_in *)rtinfo[RTAX_NETMASK])->sin_addr.s_addr;
362		} else {
363			struct in_ifaddr *ifaddr_in = (void *)rtinfo;
364			netmask = ifaddr_in->ia_subnetmask;
365		}
366		cp = netname4(sin->sin_addr.s_addr, netmask);
367#endif
368		if (vflag)
369			n = strlen(cp) < 13 ? 13 : strlen(cp);
370		else
371			n = 13;
372		printf("%-*.*s ", n, n, cp);
373		cp = routename4(sin->sin_addr.s_addr);
374		if (vflag)
375			n = strlen(cp) < 17 ? 17 : strlen(cp);
376		else
377			n = 17;
378		printf("%-*.*s ", n, n, cp);
379
380#if 0 /* XXX-elad */
381		if (aflag) {
382			u_long multiaddr;
383			struct in_multi inm;
384
385			multiaddr = (u_long)
386			    ifaddr.in.ia_multiaddrs.lh_first;
387			while (multiaddr != 0) {
388				kread(multiaddr, (char *)&inm,
389				   sizeof inm);
390				printf("\n%25s %-17.17s ", "",
391				   routename4(
392				      inm.inm_addr.s_addr));
393				multiaddr =
394				   (u_long)inm.inm_list.le_next;
395			}
396		}
397#endif /* 0 */
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 0 /* XXX-elad */
442		if (aflag) {
443			u_long multiaddr;
444			struct in6_multi inm;
445			struct sockaddr_in6 as6;
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#endif /* 0 */
485		break;
486#endif /*INET6*/
487#ifndef SMALL
488	case AF_APPLETALK:
489		printf("atalk:%-7.7s ",
490		       atalk_print(sa,0x10));
491		printf("%-17.17s ", atalk_print(sa,0x0b));
492		break;
493#endif
494	case AF_LINK:
495		printf("%-13.13s ", "<Link>");
496		if (getnameinfo(sa, sa->sa_len,
497		    hbuf, sizeof(hbuf), NULL, 0,
498		    NI_NUMERICHOST) != 0) {
499			strlcpy(hbuf, "?", sizeof(hbuf));
500		}
501		cp = hbuf;
502		if (vflag)
503			n = strlen(cp) < 17 ? 17 : strlen(cp);
504		else
505			n = 17;
506		printf("%-*.*s ", n, n, cp);
507		break;
508
509	default:
510		m = printf("(%d)", sa->sa_family);
511		for (cp = sa->sa_len + (char *)sa;
512			--cp > sa->sa_data && (*cp == 0);) {}
513		n = cp - sa->sa_data + 1;
514		cp = sa->sa_data;
515
516		while (--n >= 0)
517			m += printf(hexfmt, *cp++ & 0xff,
518				    n > 0 ? hexsep : ' ');
519		m = 32 - m;
520		while (m-- > 0)
521			putchar(' ');
522		break;
523	}
524
525	if (bflag) {
526		printf("%10llu %10llu",
527			(unsigned long long)ifd->ifi_ibytes,
528			(unsigned long long)ifd->ifi_obytes);
529	} else {
530		printf("%8llu %5llu %8llu %5llu %5llu",
531			(unsigned long long)ifd->ifi_ipackets,
532			(unsigned long long)ifd->ifi_ierrors,
533			(unsigned long long)ifd->ifi_opackets,
534			(unsigned long long)ifd->ifi_oerrors,
535			(unsigned long long)ifd->ifi_collisions);
536	}
537	if (tflag)
538		printf(" %4d", 0 /* XXX-elad ifnet.if_timer */);
539	if (dflag)
540		printf(" %5d", 0 /* XXX-elad ifnet.if_snd.ifq_drops */);
541	putchar('\n');
542}
543
544static void
545iftot_banner(struct iftot *ift)
546{
547	if (bflag)
548		printf("%7.7s in %8.8s %6.6s out %5.5s",
549		    ift->ift_name, " ",
550		    ift->ift_name, " ");
551	else
552		printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s",
553		    ift->ift_name, " ",
554		    ift->ift_name, " ", " ");
555	if (dflag)
556		printf(" %5.5s", " ");
557
558	if (bflag)
559		printf("  %7.7s in %8.8s %6.6s out %5.5s",
560		    "total", " ", "total", " ");
561	else
562		printf("  %5.5s in %5.5s%5.5s out %5.5s %5.5s",
563		    "total", " ", "total", " ", " ");
564	if (dflag)
565		printf(" %5.5s", " ");
566	putchar('\n');
567	if (bflag)
568		printf("%10.10s %8.8s %10.10s %5.5s",
569		    "bytes", " ", "bytes", " ");
570	else
571		printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
572		    "packets", "errs", "packets", "errs", "colls");
573	if (dflag)
574		printf(" %5.5s", "drops");
575
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	putchar('\n');
585	fflush(stdout);
586}
587
588static void
589iftot_print(struct iftot *cur, struct iftot *old)
590{
591	if (bflag)
592		printf("%10llu %8.8s %10llu %5.5s",
593		    (unsigned long long)(cur->ift_ib - old->ift_ib), " ",
594		    (unsigned long long)(cur->ift_ob - old->ift_ob), " ");
595	else
596		printf("%8llu %5llu %8llu %5llu %5llu",
597		    (unsigned long long)(cur->ift_ip - old->ift_ip),
598		    (unsigned long long)(cur->ift_ie - old->ift_ie),
599		    (unsigned long long)(cur->ift_op - old->ift_op),
600		    (unsigned long long)(cur->ift_oe - old->ift_oe),
601		    (unsigned long long)(cur->ift_co - old->ift_co));
602	if (dflag)
603		printf(" %5llu",
604		    /* XXX ifnet.if_snd.ifq_drops - ip->ift_dr); */
605		    0LL);
606}
607
608static void
609iftot_print_sum(struct iftot *cur, struct iftot *old)
610{
611	if (bflag)
612		printf("  %10llu %8.8s %10llu %5.5s",
613		    (unsigned long long)(cur->ift_ib - old->ift_ib), " ",
614		    (unsigned long long)(cur->ift_ob - old->ift_ob), " ");
615	else
616		printf("  %8llu %5llu %8llu %5llu %5llu",
617		    (unsigned long long)(cur->ift_ip - old->ift_ip),
618		    (unsigned long long)(cur->ift_ie - old->ift_ie),
619		    (unsigned long long)(cur->ift_op - old->ift_op),
620		    (unsigned long long)(cur->ift_oe - old->ift_oe),
621		    (unsigned long long)(cur->ift_co - old->ift_co));
622
623	if (dflag)
624		printf(" %5llu", (unsigned long long)(cur->ift_dr - old->ift_dr));
625}
626
627static void
628sidewaysintpr_sysctl(unsigned interval)
629{
630	sigset_t emptyset;
631	int line;
632
633	fetchifs();
634	if (ip_cur.ift_name[0] == '\0') {
635		fprintf(stderr, "%s: %s: unknown interface\n",
636		    getprogname(), interface);
637		exit(1);
638	}
639
640	(void)signal(SIGALRM, catchalarm);
641	signalled = 0;
642	(void)alarm(interval);
643banner:
644	iftot_banner(&ip_cur);
645
646	line = 0;
647	bzero(&ip_old, sizeof(ip_old));
648	bzero(&sum_old, sizeof(sum_old));
649loop:
650	bzero(&sum_cur, sizeof(sum_cur));
651
652	fetchifs();
653
654	iftot_print(&ip_cur, &ip_old);
655
656	ip_old = ip_cur;
657
658	iftot_print_sum(&sum_cur, &sum_old);
659
660	sum_old = sum_cur;
661
662	putchar('\n');
663	fflush(stdout);
664	line++;
665	sigemptyset(&emptyset);
666	if (!signalled)
667		sigsuspend(&emptyset);
668	signalled = 0;
669	(void)alarm(interval);
670	if (line == 21)
671		goto banner;
672	goto loop;
673	/*NOTREACHED*/
674}
675
676static void
677sidewaysintpr_kvm(unsigned interval, u_long off)
678{
679	struct itimerval it;
680	struct ifnet ifnet;
681	u_long firstifnet;
682	struct iftot *ip, *total;
683	int line;
684	struct iftot *lastif, *sum, *interesting;
685	struct ifnet_head ifhead;	/* TAILQ_HEAD */
686	int oldmask;
687
688	/*
689	 * Find the pointer to the first ifnet structure.  Replace
690	 * the pointer to the TAILQ_HEAD with the actual pointer
691	 * to the first list element.
692	 */
693	if (kread(off, (char *)&ifhead, sizeof ifhead))
694		return;
695	firstifnet = (u_long)ifhead.tqh_first;
696
697	lastif = iftot;
698	sum = iftot + MAXIF - 1;
699	total = sum - 1;
700	interesting = (interface == NULL) ? iftot : NULL;
701	for (off = firstifnet, ip = iftot; off;) {
702		if (kread(off, (char *)&ifnet, sizeof ifnet))
703			break;
704		memset(ip->ift_name, 0, sizeof(ip->ift_name));
705		snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname);
706		if (interface && strcmp(ifnet.if_xname, interface) == 0)
707			interesting = ip;
708		ip++;
709		if (ip >= iftot + MAXIF - 2)
710			break;
711		off = (u_long)ifnet.if_list.tqe_next;
712	}
713	if (interesting == NULL) {
714		fprintf(stderr, "%s: %s: unknown interface\n",
715		    getprogname(), interface);
716		exit(1);
717	}
718	lastif = ip;
719
720	(void)signal(SIGALRM, catchalarm);
721	signalled = false;
722
723	it.it_interval.tv_sec = it.it_value.tv_sec = interval;
724	it.it_interval.tv_usec = it.it_value.tv_usec = 0;
725	setitimer(ITIMER_REAL, &it, NULL);
726
727banner:
728	if (bflag)
729		printf("%7.7s in %8.8s %6.6s out %5.5s",
730		    interesting->ift_name, " ",
731		    interesting->ift_name, " ");
732	else
733		printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s",
734		    interesting->ift_name, " ",
735		    interesting->ift_name, " ", " ");
736	if (dflag)
737		printf(" %5.5s", " ");
738	if (lastif - iftot > 0) {
739		if (bflag)
740			printf("  %7.7s in %8.8s %6.6s out %5.5s",
741			    "total", " ", "total", " ");
742		else
743			printf("  %5.5s in %5.5s%5.5s out %5.5s %5.5s",
744			    "total", " ", "total", " ", " ");
745		if (dflag)
746			printf(" %5.5s", " ");
747	}
748	for (ip = iftot; ip < iftot + MAXIF; ip++) {
749		ip->ift_ip = 0;
750		ip->ift_ib = 0;
751		ip->ift_ie = 0;
752		ip->ift_op = 0;
753		ip->ift_ob = 0;
754		ip->ift_oe = 0;
755		ip->ift_co = 0;
756		ip->ift_dr = 0;
757	}
758	putchar('\n');
759	if (bflag)
760		printf("%10.10s %8.8s %10.10s %5.5s",
761		    "bytes", " ", "bytes", " ");
762	else
763		printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
764		    "packets", "errs", "packets", "errs", "colls");
765	if (dflag)
766		printf(" %5.5s", "drops");
767	if (lastif - iftot > 0) {
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	}
777	putchar('\n');
778	fflush(stdout);
779	line = 0;
780loop:
781	sum->ift_ip = 0;
782	sum->ift_ib = 0;
783	sum->ift_ie = 0;
784	sum->ift_op = 0;
785	sum->ift_ob = 0;
786	sum->ift_oe = 0;
787	sum->ift_co = 0;
788	sum->ift_dr = 0;
789	for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
790		if (kread(off, (char *)&ifnet, sizeof ifnet)) {
791			off = 0;
792			continue;
793		}
794		if (ip == interesting) {
795			if (bflag) {
796				printf("%10llu %8.8s %10llu %5.5s",
797				    (unsigned long long)(ifnet.if_ibytes -
798					ip->ift_ib), " ",
799				    (unsigned long long)(ifnet.if_obytes -
800					ip->ift_ob), " ");
801			} else {
802				printf("%8llu %5llu %8llu %5llu %5llu",
803				    (unsigned long long)
804					(ifnet.if_ipackets - ip->ift_ip),
805				    (unsigned long long)
806					(ifnet.if_ierrors - ip->ift_ie),
807				    (unsigned long long)
808					(ifnet.if_opackets - ip->ift_op),
809				    (unsigned long long)
810					(ifnet.if_oerrors - ip->ift_oe),
811				    (unsigned long long)
812					(ifnet.if_collisions - ip->ift_co));
813			}
814			if (dflag)
815				printf(" %5llu",
816				    (unsigned long long)
817					(ifnet.if_snd.ifq_drops - ip->ift_dr));
818		}
819		ip->ift_ip = ifnet.if_ipackets;
820		ip->ift_ib = ifnet.if_ibytes;
821		ip->ift_ie = ifnet.if_ierrors;
822		ip->ift_op = ifnet.if_opackets;
823		ip->ift_ob = ifnet.if_obytes;
824		ip->ift_oe = ifnet.if_oerrors;
825		ip->ift_co = ifnet.if_collisions;
826		ip->ift_dr = ifnet.if_snd.ifq_drops;
827		sum->ift_ip += ip->ift_ip;
828		sum->ift_ib += ip->ift_ib;
829		sum->ift_ie += ip->ift_ie;
830		sum->ift_op += ip->ift_op;
831		sum->ift_ob += ip->ift_ob;
832		sum->ift_oe += ip->ift_oe;
833		sum->ift_co += ip->ift_co;
834		sum->ift_dr += ip->ift_dr;
835		off = (u_long)ifnet.if_list.tqe_next;
836	}
837	if (lastif - iftot > 0) {
838		if (bflag) {
839			printf("  %10llu %8.8s %10llu %5.5s",
840			    (unsigned long long)
841				(sum->ift_ib - total->ift_ib), " ",
842			    (unsigned long long)
843				(sum->ift_ob - total->ift_ob), " ");
844		} else {
845			printf("  %8llu %5llu %8llu %5llu %5llu",
846			    (unsigned long long)
847				(sum->ift_ip - total->ift_ip),
848			    (unsigned long long)
849				(sum->ift_ie - total->ift_ie),
850			    (unsigned long long)
851				(sum->ift_op - total->ift_op),
852			    (unsigned long long)
853				(sum->ift_oe - total->ift_oe),
854			    (unsigned long long)
855				(sum->ift_co - total->ift_co));
856		}
857		if (dflag)
858			printf(" %5llu",
859			    (unsigned long long)(sum->ift_dr - total->ift_dr));
860	}
861	*total = *sum;
862	putchar('\n');
863	fflush(stdout);
864	line++;
865	oldmask = sigblock(sigmask(SIGALRM));
866	if (! signalled) {
867		sigpause(0);
868	}
869	sigsetmask(oldmask);
870	signalled = false;
871	if (line == 21)
872		goto banner;
873	goto loop;
874	/*NOTREACHED*/
875}
876
877/*
878 * Print a running summary of interface statistics.
879 * Repeat display every interval seconds, showing statistics
880 * collected over that interval.  Assumes that interval is non-zero.
881 * First line printed at top of screen is always cumulative.
882 */
883static void
884sidewaysintpr(interval, off)
885	unsigned interval;
886	u_long off;
887{
888
889	if (use_sysctl) {
890		sidewaysintpr_sysctl(interval);
891	} else {
892		sidewaysintpr_kvm(interval, off);
893	}
894}
895
896/*
897 * Called if an interval expires before sidewaysintpr has completed a loop.
898 * Sets a flag to not wait for the alarm.
899 */
900static void
901catchalarm(signo)
902	int signo;
903{
904
905	signalled = true;
906}
907
908#define ROUNDUP(a, size) \
909	(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
910
911#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
912	((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
913	sizeof(u_long)) : sizeof(u_long)))
914
915static void
916get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
917{
918	int i;
919
920	for (i = 0; i < RTAX_MAX; i++) {
921		if (addrs & (1 << i)) {
922			rti_info[i] = sa;
923			NEXT_SA(sa);
924			/* sa = (struct sockaddr *)((char *)(sa) +
925			    roundup(sa->sa_len, sizeof(long))); */
926		} else
927			rti_info[i] = NULL;
928	}
929}
930
931static void
932fetchifs(void)
933{
934	struct if_msghdr *ifm;
935	int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
936	struct rt_msghdr *rtm;
937	struct if_data *ifd = NULL;
938	struct sockaddr *sa, *rti_info[RTAX_MAX];
939	struct sockaddr_dl *sdl;
940	char *buf, *next, *lim;
941	char name[IFNAMSIZ];
942	size_t len;
943
944	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
945		err(1, "sysctl");
946	if ((buf = malloc(len)) == NULL)
947		err(1, NULL);
948	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1)
949		err(1, "sysctl");
950
951	lim = buf + len;
952	for (next = buf; next < lim; next += rtm->rtm_msglen) {
953		rtm = (struct rt_msghdr *)next;
954		if (rtm->rtm_version != RTM_VERSION)
955			continue;
956		switch (rtm->rtm_type) {
957		case RTM_IFINFO:
958			ifm = (struct if_msghdr *)next;
959			ifd = &ifm->ifm_data;
960
961			sa = (struct sockaddr *)(ifm + 1);
962			get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
963
964			sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP];
965			if (sdl == NULL || sdl->sdl_family != AF_LINK)
966				continue;
967			bzero(name, sizeof(name));
968			if (sdl->sdl_nlen >= IFNAMSIZ)
969				memcpy(name, sdl->sdl_data, IFNAMSIZ - 1);
970			else if (sdl->sdl_nlen > 0)
971				memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
972
973			if (interface != 0 && !strcmp(name, interface)) {
974				strlcpy(ip_cur.ift_name, name,
975				    sizeof(ip_cur.ift_name));
976				ip_cur.ift_ip = ifd->ifi_ipackets;
977				ip_cur.ift_ib = ifd->ifi_ibytes;
978				ip_cur.ift_ie = ifd->ifi_ierrors;
979				ip_cur.ift_op = ifd->ifi_opackets;
980				ip_cur.ift_ob = ifd->ifi_obytes;
981				ip_cur.ift_oe = ifd->ifi_oerrors;
982				ip_cur.ift_co = ifd->ifi_collisions;
983				ip_cur.ift_dr = 0;
984				    /* XXX-elad ifnet.if_snd.ifq_drops */
985			}
986
987			sum_cur.ift_ip += ifd->ifi_ipackets;
988			sum_cur.ift_ib += ifd->ifi_ibytes;
989			sum_cur.ift_ie += ifd->ifi_ierrors;
990			sum_cur.ift_op += ifd->ifi_opackets;
991			sum_cur.ift_ob += ifd->ifi_obytes;
992			sum_cur.ift_oe += ifd->ifi_oerrors;
993			sum_cur.ift_co += ifd->ifi_collisions;
994			sum_cur.ift_dr += 0; /* XXX-elad ifnet.if_snd.ifq_drops */
995			break;
996		}
997	}
998	if (interface == NULL) {
999		strlcpy(ip_cur.ift_name, name,
1000		    sizeof(ip_cur.ift_name));
1001		ip_cur.ift_ip = ifd->ifi_ipackets;
1002		ip_cur.ift_ib = ifd->ifi_ibytes;
1003		ip_cur.ift_ie = ifd->ifi_ierrors;
1004		ip_cur.ift_op = ifd->ifi_opackets;
1005		ip_cur.ift_ob = ifd->ifi_obytes;
1006		ip_cur.ift_oe = ifd->ifi_oerrors;
1007		ip_cur.ift_co = ifd->ifi_collisions;
1008		ip_cur.ift_dr = 0;
1009		    /* XXX-elad ifnet.if_snd.ifq_drops */
1010	}
1011}
1012