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