if.c revision 1.16
1/*	$NetBSD: if.c,v 1.16 1996/05/07 05:30:45 thorpej 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. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#ifndef lint
37#if 0
38static char sccsid[] = "from: @(#)if.c	8.2 (Berkeley) 2/21/94";
39#else
40static char *rcsid = "$NetBSD: if.c,v 1.16 1996/05/07 05:30:45 thorpej Exp $";
41#endif
42#endif /* not lint */
43
44#include <sys/types.h>
45#include <sys/protosw.h>
46#include <sys/socket.h>
47
48#include <net/if.h>
49#include <net/if_dl.h>
50#include <netinet/in.h>
51#include <netinet/in_var.h>
52#include <netns/ns.h>
53#include <netns/ns_if.h>
54#include <netiso/iso.h>
55#include <netiso/iso_var.h>
56#include <arpa/inet.h>
57
58#include <signal.h>
59#include <stdio.h>
60#include <string.h>
61#include <unistd.h>
62
63#include "netstat.h"
64
65#define	YES	1
66#define	NO	0
67
68static void sidewaysintpr __P((u_int, u_long));
69static void catchalarm __P((int));
70
71/*
72 * Print a description of the network interfaces.
73 * NOTE: ifnetaddr is the location of the kernel global "ifnet",
74 * which is a TAILQ_HEAD.
75 */
76void
77intpr(interval, ifnetaddr)
78	int interval;
79	u_long ifnetaddr;
80{
81	struct ifnet ifnet;
82	union {
83		struct ifaddr ifa;
84		struct in_ifaddr in;
85		struct ns_ifaddr ns;
86		struct iso_ifaddr iso;
87	} ifaddr;
88	u_long ifaddraddr;
89	struct sockaddr *sa;
90	struct ifnet_head ifhead;	/* TAILQ_HEAD */
91	char name[IFNAMSIZ];
92
93	if (ifnetaddr == 0) {
94		printf("ifnet: symbol not defined\n");
95		return;
96	}
97	if (interval) {
98		sidewaysintpr((unsigned)interval, ifnetaddr);
99		return;
100	}
101
102	/*
103	 * Find the pointer to the first ifnet structure.  Replace
104	 * the pointer to the TAILQ_HEAD with the actual pointer
105	 * to the first list element.
106	 */
107	if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead))
108		return;
109	ifnetaddr = (u_long)ifhead.tqh_first;
110
111	printf("%-5.5s %-5.5s %-11.11s %-17.17s %8.8s %5.5s %8.8s %5.5s",
112		"Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs",
113		"Opkts", "Oerrs");
114	printf(" %5s", "Coll");
115	if (tflag)
116		printf(" %s", "Time");
117	if (dflag)
118		printf(" %s", "Drop");
119	putchar('\n');
120	ifaddraddr = 0;
121	while (ifnetaddr || ifaddraddr) {
122		struct sockaddr_in *sin;
123		register char *cp;
124		int n, m;
125
126		if (ifaddraddr == 0) {
127			if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
128				return;
129			bcopy(ifnet.if_xname, name, IFNAMSIZ);
130			name[IFNAMSIZ - 1] = '\0';	/* sanity */
131			ifnetaddr = (u_long)ifnet.if_list.tqe_next;
132			if (interface != 0 && strcmp(name, interface) != 0)
133				continue;
134			cp = index(name, '\0');
135			if ((ifnet.if_flags & IFF_UP) == 0)
136				*cp++ = '*';
137			*cp = '\0';
138			ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first;
139		}
140		printf("%-5.5s %-5d ", name, ifnet.if_mtu);
141		if (ifaddraddr == 0) {
142			printf("%-11.11s ", "none");
143			printf("%-15.15s ", "none");
144		} else {
145			if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
146				ifaddraddr = 0;
147				continue;
148			}
149#define CP(x) ((char *)(x))
150			cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
151				CP(&ifaddr); sa = (struct sockaddr *)cp;
152			switch (sa->sa_family) {
153			case AF_UNSPEC:
154				printf("%-11.11s ", "none");
155				printf("%-17.17s ", "none");
156				break;
157			case AF_INET:
158				sin = (struct sockaddr_in *)sa;
159#ifdef notdef
160				/* can't use inet_makeaddr because kernel
161				 * keeps nets unshifted.
162				 */
163				in = inet_makeaddr(ifaddr.in.ia_subnet,
164					INADDR_ANY);
165				printf("%-11.11s ", netname(in.s_addr,
166				    ifaddr.in.ia_subnetmask));
167#else
168				printf("%-11.11s ",
169				    netname(ifaddr.in.ia_subnet,
170				    ifaddr.in.ia_subnetmask));
171#endif
172				printf("%-17.17s ",
173				    routename(sin->sin_addr.s_addr));
174
175				if (aflag) {
176					u_long multiaddr;
177					struct in_multi inm;
178
179					multiaddr = (u_long)ifaddr.in.ia_multiaddrs.lh_first;
180					while (multiaddr != 0) {
181						kread(multiaddr, (char *)&inm,
182						    sizeof inm);
183						printf("\n%23s %-15.15s ", "",
184						    routename(inm.inm_addr.s_addr));
185						multiaddr = (u_long)inm.inm_list.le_next;
186					}
187				}
188				break;
189			case AF_NS:
190				{
191				struct sockaddr_ns *sns =
192					(struct sockaddr_ns *)sa;
193				u_long net;
194				char netnum[8];
195
196				*(union ns_net *) &net = sns->sns_addr.x_net;
197		sprintf(netnum, "%lxH", ntohl(net));
198				upHex(netnum);
199				printf("ns:%-8s ", netnum);
200				printf("%-17s ",
201				    ns_phost((struct sockaddr *)sns));
202				}
203				break;
204			case AF_LINK:
205				{
206				struct sockaddr_dl *sdl =
207					(struct sockaddr_dl *)sa;
208				    cp = (char *)LLADDR(sdl);
209				    n = sdl->sdl_alen;
210				}
211				m = printf("%-11.11s ", "<Link>");
212				goto hexprint;
213			default:
214				m = printf("(%d)", sa->sa_family);
215				for (cp = sa->sa_len + (char *)sa;
216					--cp > sa->sa_data && (*cp == 0);) {}
217				n = cp - sa->sa_data + 1;
218				cp = sa->sa_data;
219			hexprint:
220				while (--n >= 0)
221					m += printf("%x%c", *cp++ & 0xff,
222						    n > 0 ? '.' : ' ');
223				m = 30 - m;
224				while (m-- > 0)
225					putchar(' ');
226				break;
227			}
228			ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next;
229		}
230		printf("%8d %5d %8d %5d %5d",
231		    ifnet.if_ipackets, ifnet.if_ierrors,
232		    ifnet.if_opackets, ifnet.if_oerrors,
233		    ifnet.if_collisions);
234		if (tflag)
235			printf(" %3d", ifnet.if_timer);
236		if (dflag)
237			printf(" %3d", ifnet.if_snd.ifq_drops);
238		putchar('\n');
239	}
240}
241
242#define	MAXIF	10
243struct	iftot {
244	char	ift_name[IFNAMSIZ];	/* interface name */
245	int	ift_ip;			/* input packets */
246	int	ift_ie;			/* input errors */
247	int	ift_op;			/* output packets */
248	int	ift_oe;			/* output errors */
249	int	ift_co;			/* collisions */
250	int	ift_dr;			/* drops */
251} iftot[MAXIF];
252
253u_char	signalled;			/* set if alarm goes off "early" */
254
255/*
256 * Print a running summary of interface statistics.
257 * Repeat display every interval seconds, showing statistics
258 * collected over that interval.  Assumes that interval is non-zero.
259 * First line printed at top of screen is always cumulative.
260 */
261static void
262sidewaysintpr(interval, off)
263	unsigned interval;
264	u_long off;
265{
266	struct ifnet ifnet;
267	u_long firstifnet;
268	register struct iftot *ip, *total;
269	register int line;
270	struct iftot *lastif, *sum, *interesting;
271	struct ifnet_head ifhead;	/* TAILQ_HEAD */
272	int oldmask;
273
274	/*
275	 * Find the pointer to the first ifnet structure.  Replace
276	 * the pointer to the TAILQ_HEAD with the actual pointer
277	 * to the first list element.
278	 */
279	if (kread(off, (char *)&ifhead, sizeof ifhead))
280		return;
281	firstifnet = (u_long)ifhead.tqh_first;
282
283	lastif = iftot;
284	sum = iftot + MAXIF - 1;
285	total = sum - 1;
286	interesting = iftot;
287	for (off = firstifnet, ip = iftot; off;) {
288		if (kread(off, (char *)&ifnet, sizeof ifnet))
289			break;
290		ip->ift_name[0] = '(';
291		bcopy(ifnet.if_xname, ip->ift_name + 1, IFNAMSIZ - 1);
292		if (interface &&
293		    strcmp(ip->ift_name + 1, interface) == 0)
294			interesting = ip;
295		ip->ift_name[IFNAMSIZ - 1] = '\0';
296		ip++;
297		if (ip >= iftot + MAXIF - 2)
298			break;
299		off = (u_long)ifnet.if_list.tqe_next;
300	}
301	lastif = ip;
302
303	(void)signal(SIGALRM, catchalarm);
304	signalled = NO;
305	(void)alarm(interval);
306banner:
307	printf("   input    %-6.6s    output       ", interesting->ift_name);
308	if (lastif - iftot > 0) {
309		if (dflag)
310			printf("      ");
311		printf("     input   (Total)    output");
312	}
313	for (ip = iftot; ip < iftot + MAXIF; ip++) {
314		ip->ift_ip = 0;
315		ip->ift_ie = 0;
316		ip->ift_op = 0;
317		ip->ift_oe = 0;
318		ip->ift_co = 0;
319		ip->ift_dr = 0;
320	}
321	putchar('\n');
322	printf("%8.8s %5.5s %8.8s %5.5s %5.5s ",
323		"packets", "errs", "packets", "errs", "colls");
324	if (dflag)
325		printf("%5.5s ", "drops");
326	if (lastif - iftot > 0)
327		printf(" %8.8s %5.5s %8.8s %5.5s %5.5s",
328			"packets", "errs", "packets", "errs", "colls");
329	if (dflag)
330		printf(" %5.5s", "drops");
331	putchar('\n');
332	fflush(stdout);
333	line = 0;
334loop:
335	sum->ift_ip = 0;
336	sum->ift_ie = 0;
337	sum->ift_op = 0;
338	sum->ift_oe = 0;
339	sum->ift_co = 0;
340	sum->ift_dr = 0;
341	for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
342		if (kread(off, (char *)&ifnet, sizeof ifnet)) {
343			off = 0;
344			continue;
345		}
346		if (ip == interesting) {
347			printf("%8d %5d %8d %5d %5d",
348				ifnet.if_ipackets - ip->ift_ip,
349				ifnet.if_ierrors - ip->ift_ie,
350				ifnet.if_opackets - ip->ift_op,
351				ifnet.if_oerrors - ip->ift_oe,
352				ifnet.if_collisions - ip->ift_co);
353			if (dflag)
354				printf(" %5d",
355				    ifnet.if_snd.ifq_drops - ip->ift_dr);
356		}
357		ip->ift_ip = ifnet.if_ipackets;
358		ip->ift_ie = ifnet.if_ierrors;
359		ip->ift_op = ifnet.if_opackets;
360		ip->ift_oe = ifnet.if_oerrors;
361		ip->ift_co = ifnet.if_collisions;
362		ip->ift_dr = ifnet.if_snd.ifq_drops;
363		sum->ift_ip += ip->ift_ip;
364		sum->ift_ie += ip->ift_ie;
365		sum->ift_op += ip->ift_op;
366		sum->ift_oe += ip->ift_oe;
367		sum->ift_co += ip->ift_co;
368		sum->ift_dr += ip->ift_dr;
369		off = (u_long)ifnet.if_list.tqe_next;
370	}
371	if (lastif - iftot > 0) {
372		printf("  %8d %5d %8d %5d %5d",
373			sum->ift_ip - total->ift_ip,
374			sum->ift_ie - total->ift_ie,
375			sum->ift_op - total->ift_op,
376			sum->ift_oe - total->ift_oe,
377			sum->ift_co - total->ift_co);
378		if (dflag)
379			printf(" %5d", sum->ift_dr - total->ift_dr);
380	}
381	*total = *sum;
382	putchar('\n');
383	fflush(stdout);
384	line++;
385	oldmask = sigblock(sigmask(SIGALRM));
386	if (! signalled) {
387		sigpause(0);
388	}
389	sigsetmask(oldmask);
390	signalled = NO;
391	(void)alarm(interval);
392	if (line == 21)
393		goto banner;
394	goto loop;
395	/*NOTREACHED*/
396}
397
398/*
399 * Called if an interval expires before sidewaysintpr has completed a loop.
400 * Sets a flag to not wait for the alarm.
401 */
402static void
403catchalarm(signo)
404	int signo;
405{
406	signalled = YES;
407}
408