1/*	$NetBSD$	*/
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$");
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
74struct	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
86static void print_addr(struct sockaddr *, struct sockaddr **, struct if_data *,
87    struct ifnet *);
88static void sidewaysintpr(u_int, u_long);
89
90static void iftot_banner(struct iftot *);
91static void iftot_print_sum(struct iftot *, struct iftot *);
92static void iftot_print(struct iftot *, struct iftot *);
93
94static void catchalarm __P((int));
95static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
96static void fetchifs(void);
97
98static void intpr_sysctl(void);
99static void intpr_kvm(u_long, void (*)(const char *));
100
101struct iftot iftot[MAXIF], ip_cur, ip_old, sum_cur, sum_old;
102bool	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 */
109void
110intpr(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
129static void
130intpr_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
153static void
154intpr_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
248union 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
257static void
258intpr_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
334static void
335print_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
559static void
560iftot_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
603static void
604iftot_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
623static void
624iftot_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
643sidewaysintpr_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);
658banner:
659	iftot_banner(&ip_cur);
660
661	line = 0;
662	bzero(&ip_old, sizeof(ip_old));
663	bzero(&sum_old, sizeof(sum_old));
664loop:
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
691static void
692sidewaysintpr_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
742banner:
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;
795loop:
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 */
928static void
929sidewaysintpr(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 */
945static void
946catchalarm(signo)
947	int signo;
948{
949
950	signalled = true;
951}
952
953static void
954get_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
968static void
969fetchifs(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