xref: /freebsd/usr.bin/netstat/if.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
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 /*
36 static char sccsid[] = "@(#)if.c	8.3 (Berkeley) 4/28/95";
37 */
38 static const char rcsid[] =
39 	"$Id: if.c,v 1.23 1997/02/22 19:56:21 peter Exp $";
40 #endif /* not lint */
41 
42 #include <sys/types.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/time.h>
46 
47 #include <net/if.h>
48 #include <net/if_var.h>
49 #include <net/if_dl.h>
50 #include <net/if_types.h>
51 #include <net/ethernet.h>
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54 #include <netipx/ipx.h>
55 #include <netipx/ipx_if.h>
56 #ifdef NS
57 #include <netns/ns.h>
58 #include <netns/ns_if.h>
59 #endif
60 #ifdef ISO
61 #include <netiso/iso.h>
62 #include <netiso/iso_var.h>
63 #endif
64 #include <arpa/inet.h>
65 
66 #include <signal.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <unistd.h>
70 
71 #include "netstat.h"
72 
73 #define	YES	1
74 #define	NO	0
75 
76 static void sidewaysintpr __P((u_int, u_long));
77 static void catchalarm __P((int));
78 
79 /*
80  * Print a description of the network interfaces.
81  */
82 void
83 intpr(interval, ifnetaddr)
84 	int interval;
85 	u_long ifnetaddr;
86 {
87 	struct ifnet ifnet;
88 	struct ifnethead ifnethead;
89 	union {
90 		struct ifaddr ifa;
91 		struct in_ifaddr in;
92 		struct ipx_ifaddr ipx;
93 #ifdef NS
94 		struct ns_ifaddr ns;
95 #endif
96 #ifdef ISO
97 		struct iso_ifaddr iso;
98 #endif
99 	} ifaddr;
100 	u_long ifaddraddr;
101 	u_long ifaddrfound;
102 	u_long ifnetfound;
103 	struct sockaddr *sa;
104 	char name[32], tname[16];
105 
106 	if (ifnetaddr == 0) {
107 		printf("ifnet: symbol not defined\n");
108 		return;
109 	}
110 	if (interval) {
111 		sidewaysintpr((unsigned)interval, ifnetaddr);
112 		return;
113 	}
114 	if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead))
115 		return;
116 	ifnetaddr = (u_long)ifnethead.tqh_first;
117 	if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
118 		return;
119 
120 	printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
121 		"Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
122 	if (bflag)
123 		printf(" %10.10s","Ibytes");
124 	printf(" %8.8s %5.5s", "Opkts", "Oerrs");
125 	if (bflag)
126 		printf(" %10.10s","Obytes");
127 	printf(" %5s", "Coll");
128 	if (tflag)
129 		printf(" %s", "Time");
130 	if (dflag)
131 		printf(" %s", "Drop");
132 	putchar('\n');
133 	ifaddraddr = 0;
134 	while (ifnetaddr || ifaddraddr) {
135 		struct sockaddr_in *sin;
136 		register char *cp;
137 		int n, m;
138 
139 		if (ifaddraddr == 0) {
140 			ifnetfound = ifnetaddr;
141 			if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) ||
142 			    kread((u_long)ifnet.if_name, tname, 16))
143 				return;
144 			tname[15] = '\0';
145 			ifnetaddr = (u_long)ifnet.if_link.tqe_next;
146 			snprintf(name, 32, "%s%d", tname, ifnet.if_unit);
147 			if (interface != 0 && (strcmp(name, interface) != 0))
148 				continue;
149 			cp = index(name, '\0');
150 			if ((ifnet.if_flags&IFF_UP) == 0)
151 				*cp++ = '*';
152 			*cp = '\0';
153 			ifaddraddr = (u_long)ifnet.if_addrhead.tqh_first;
154 		}
155 		printf("%-5.5s %-5lu ", name, ifnet.if_mtu);
156 		ifaddrfound = ifaddraddr;
157 		if (ifaddraddr == 0) {
158 			printf("%-13.13s ", "none");
159 			printf("%-15.15s ", "none");
160 		} else {
161 			if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
162 				ifaddraddr = 0;
163 				continue;
164 			}
165 #define CP(x) ((char *)(x))
166 			cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
167 				CP(&ifaddr); sa = (struct sockaddr *)cp;
168 			switch (sa->sa_family) {
169 			case AF_UNSPEC:
170 				printf("%-13.13s ", "none");
171 				printf("%-15.15s ", "none");
172 				break;
173 			case AF_INET:
174 				sin = (struct sockaddr_in *)sa;
175 #ifdef notdef
176 				/* can't use inet_makeaddr because kernel
177 				 * keeps nets unshifted.
178 				 */
179 				in = inet_makeaddr(ifaddr.in.ia_subnet,
180 					INADDR_ANY);
181 				printf("%-13.13s ", netname(in.s_addr,
182 				    ifaddr.in.ia_subnetmask));
183 #else
184 				printf("%-13.13s ",
185 				    netname(htonl(ifaddr.in.ia_subnet),
186 				    ifaddr.in.ia_subnetmask));
187 #endif
188 				printf("%-15.15s ",
189 				    routename(sin->sin_addr.s_addr));
190 				break;
191 			case AF_IPX:
192 				{
193 				struct sockaddr_ipx *sipx =
194 					(struct sockaddr_ipx *)sa;
195 				u_long net;
196 				char netnum[10];
197 
198 				*(union ipx_net *) &net = sipx->sipx_addr.x_net;
199 				sprintf(netnum, "%lx", (u_long)ntohl(net));
200 				printf("ipx:%-8s ", netnum);
201 /*				printf("ipx:%-8s ", netname(net, 0L)); */
202 				printf("%-15s ",
203 				    ipx_phost((struct sockaddr *)sipx));
204 				}
205 				break;
206 
207 			case AF_APPLETALK:
208 				printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
209 				printf("%-9.9s  ",atalk_print(sa,0x0b) );
210 				break;
211 #ifdef NS
212 			case AF_NS:
213 				{
214 				struct sockaddr_ns *sns =
215 					(struct sockaddr_ns *)sa;
216 				u_long net;
217 				char netnum[10];
218 
219 				*(union ns_net *) &net = sns->sns_addr.x_net;
220 				sprintf(netnum, "%lxH", ntohl(net));
221 				upHex(netnum);
222 				printf("ns:%-8s ", netnum);
223 				printf("%-15s ",
224 				    ns_phost((struct sockaddr *)sns));
225 				}
226 				break;
227 #endif
228 			case AF_LINK:
229 				{
230 				struct sockaddr_dl *sdl =
231 					(struct sockaddr_dl *)sa;
232 				    cp = (char *)LLADDR(sdl);
233 				    n = sdl->sdl_alen;
234 				}
235 				m = printf("%-11.11s ", "<Link>");
236 				goto hexprint;
237 			default:
238 				m = printf("(%d)", sa->sa_family);
239 				for (cp = sa->sa_len + (char *)sa;
240 					--cp > sa->sa_data && (*cp == 0);) {}
241 				n = cp - sa->sa_data + 1;
242 				cp = sa->sa_data;
243 			hexprint:
244 				while (--n >= 0)
245 					m += printf("%02x%c", *cp++ & 0xff,
246 						    n > 0 ? '.' : ' ');
247 				m = 30 - m;
248 				while (m-- > 0)
249 					putchar(' ');
250 				break;
251 			}
252 			ifaddraddr = (u_long)ifaddr.ifa.ifa_link.tqe_next;
253 		}
254 		printf("%8lu %5lu ",
255 		    ifnet.if_ipackets, ifnet.if_ierrors);
256 		if (bflag)
257 			printf("%10lu ", ifnet.if_ibytes);
258 		printf("%8lu %5lu ",
259 		    ifnet.if_opackets, ifnet.if_oerrors);
260 		if (bflag)
261 			printf("%10lu ", ifnet.if_obytes);
262 		printf("%5lu", ifnet.if_collisions);
263 		if (tflag)
264 			printf(" %3d", ifnet.if_timer);
265 		if (dflag)
266 			printf(" %3d", ifnet.if_snd.ifq_drops);
267 		putchar('\n');
268 		if (aflag && ifaddrfound) {
269 			/*
270 			 * Print family's multicast addresses
271 			 */
272 			u_long multiaddr;
273 			struct ifmultiaddr ifma;
274 			union {
275 				struct sockaddr sa;
276 				struct sockaddr_in in;
277 				struct sockaddr_dl dl;
278 			} msa;
279 			const char *fmt;
280 
281 			for(multiaddr = (u_long)ifnet.if_multiaddrs.lh_first;
282 			    multiaddr;
283 			    multiaddr = (u_long)ifma.ifma_link.le_next) {
284 				if (kread(multiaddr, (char *)&ifma,
285 					  sizeof ifma))
286 					break;
287 				if (kread((u_long)ifma.ifma_addr, (char *)&msa,
288 					  sizeof msa))
289 					break;
290 				if (msa.sa.sa_family != sa->sa_family)
291 					continue;
292 
293 				fmt = 0;
294 				switch (msa.sa.sa_family) {
295 				case AF_INET:
296 					fmt = routename(msa.in.sin_addr.s_addr);
297 					break;
298 
299 				case AF_LINK:
300 					switch (ifnet.if_type) {
301 					case IFT_ETHER:
302 					case IFT_FDDI:
303 						fmt = ether_ntoa(
304 							(struct ether_addr *)
305 							LLADDR(&msa.dl));
306 						break;
307 					}
308 					break;
309 				}
310 				if (fmt)
311 					printf("%23s %s\n", "", fmt);
312 			}
313 		}
314 	}
315 }
316 
317 #define	MAXIF	10
318 struct	iftot {
319 	char	ift_name[16];		/* interface name */
320 	u_int	ift_ip;			/* input packets */
321 	u_int	ift_ie;			/* input errors */
322 	u_int	ift_op;			/* output packets */
323 	u_int	ift_oe;			/* output errors */
324 	u_int	ift_co;			/* collisions */
325 	u_int	ift_dr;			/* drops */
326 	u_int	ift_ib;			/* input bytes */
327 	u_int	ift_ob;			/* output bytes */
328 } iftot[MAXIF];
329 
330 u_char	signalled;			/* set if alarm goes off "early" */
331 
332 /*
333  * Print a running summary of interface statistics.
334  * Repeat display every interval seconds, showing statistics
335  * collected over that interval.  Assumes that interval is non-zero.
336  * First line printed at top of screen is always cumulative.
337  * XXX - should be rewritten to use ifmib(4).
338  */
339 static void
340 sidewaysintpr(interval, off)
341 	unsigned interval;
342 	u_long off;
343 {
344 	struct ifnet ifnet;
345 	u_long firstifnet;
346 	struct ifnethead ifnethead;
347 	register struct iftot *ip, *total;
348 	register int line;
349 	struct iftot *lastif, *sum, *interesting;
350 	int oldmask, first;
351 	u_long interesting_off;
352 
353 	if (kread(off, (char *)&ifnethead, sizeof ifnethead))
354 		return;
355 	firstifnet = (u_long)ifnethead.tqh_first;
356 
357 	lastif = iftot;
358 	sum = iftot + MAXIF - 1;
359 	total = sum - 1;
360 	interesting = NULL;
361 	interesting_off = 0;
362 	for (off = firstifnet, ip = iftot; off;) {
363 		char name[16], tname[16];
364 
365 		if (kread(off, (char *)&ifnet, sizeof ifnet))
366 			break;
367 		if (kread((u_long)ifnet.if_name, tname, 16))
368 			break;
369 		tname[15] = '\0';
370 		snprintf(name, 16, "%s%d", tname, ifnet.if_unit);
371 		if (interface && strcmp(name, interface) == 0) {
372 			interesting = ip;
373 			interesting_off = off;
374 		}
375 		snprintf(ip->ift_name, 16, "(%s)", name);;
376 		ip++;
377 		if (ip >= iftot + MAXIF - 2)
378 			break;
379 		off = (u_long) ifnet.if_link.tqe_next;
380 	}
381 	lastif = ip;
382 
383 	(void)signal(SIGALRM, catchalarm);
384 	signalled = NO;
385 	(void)alarm(interval);
386 	for (ip = iftot; ip < iftot + MAXIF; ip++) {
387 		ip->ift_ip = 0;
388 		ip->ift_ie = 0;
389 		ip->ift_ib = 0;
390 		ip->ift_op = 0;
391 		ip->ift_oe = 0;
392 		ip->ift_ob = 0;
393 		ip->ift_co = 0;
394 		ip->ift_dr = 0;
395 	}
396 	first = 1;
397 banner:
398 	printf("%17s %14s %16s", "input",
399 	    interesting ? interesting->ift_name : "(Total)", "output");
400 	putchar('\n');
401 	printf("%10s %5s %10s %10s %5s %10s %5s",
402 	    "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
403 	if (dflag)
404 		printf(" %5.5s", "drops");
405 	putchar('\n');
406 	fflush(stdout);
407 	line = 0;
408 loop:
409 	if (interesting != NULL) {
410 		ip = interesting;
411 		if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) {
412 			printf("???\n");
413 			exit(1);
414 		};
415 		if (!first) {
416 			printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
417 				ifnet.if_ipackets - ip->ift_ip,
418 				ifnet.if_ierrors - ip->ift_ie,
419 				ifnet.if_ibytes - ip->ift_ib,
420 				ifnet.if_opackets - ip->ift_op,
421 				ifnet.if_oerrors - ip->ift_oe,
422 				ifnet.if_obytes - ip->ift_ob,
423 				ifnet.if_collisions - ip->ift_co);
424 			if (dflag)
425 				printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr);
426 		}
427 		ip->ift_ip = ifnet.if_ipackets;
428 		ip->ift_ie = ifnet.if_ierrors;
429 		ip->ift_ib = ifnet.if_ibytes;
430 		ip->ift_op = ifnet.if_opackets;
431 		ip->ift_oe = ifnet.if_oerrors;
432 		ip->ift_ob = ifnet.if_obytes;
433 		ip->ift_co = ifnet.if_collisions;
434 		ip->ift_dr = ifnet.if_snd.ifq_drops;
435 	} else {
436 		sum->ift_ip = 0;
437 		sum->ift_ie = 0;
438 		sum->ift_ib = 0;
439 		sum->ift_op = 0;
440 		sum->ift_oe = 0;
441 		sum->ift_ob = 0;
442 		sum->ift_co = 0;
443 		sum->ift_dr = 0;
444 		for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
445 			if (kread(off, (char *)&ifnet, sizeof ifnet)) {
446 				off = 0;
447 				continue;
448 			}
449 			sum->ift_ip += ifnet.if_ipackets;
450 			sum->ift_ie += ifnet.if_ierrors;
451 			sum->ift_ib += ifnet.if_ibytes;
452 			sum->ift_op += ifnet.if_opackets;
453 			sum->ift_oe += ifnet.if_oerrors;
454 			sum->ift_ob += ifnet.if_obytes;
455 			sum->ift_co += ifnet.if_collisions;
456 			sum->ift_dr += ifnet.if_snd.ifq_drops;
457 			off = (u_long) ifnet.if_link.tqe_next;
458 		}
459 		if (!first) {
460 			printf("%10u %5u %10u %10u %5u %10u %5u",
461 				sum->ift_ip - total->ift_ip,
462 				sum->ift_ie - total->ift_ie,
463 				sum->ift_ib - total->ift_ib,
464 				sum->ift_op - total->ift_op,
465 				sum->ift_oe - total->ift_oe,
466 				sum->ift_ob - total->ift_ob,
467 				sum->ift_co - total->ift_co);
468 			if (dflag)
469 				printf(" %5u", sum->ift_dr - total->ift_dr);
470 		}
471 		*total = *sum;
472 	}
473 	if (!first)
474 		putchar('\n');
475 	fflush(stdout);
476 	oldmask = sigblock(sigmask(SIGALRM));
477 	if (! signalled) {
478 		sigpause(0);
479 	}
480 	sigsetmask(oldmask);
481 	signalled = NO;
482 	(void)alarm(interval);
483 	line++;
484 	first = 0;
485 	if (line == 21)
486 		goto banner;
487 	else
488 		goto loop;
489 	/*NOTREACHED*/
490 }
491 
492 /*
493  * Called if an interval expires before sidewaysintpr has completed a loop.
494  * Sets a flag to not wait for the alarm.
495  */
496 static void
497 catchalarm(signo)
498 	int signo;
499 {
500 	signalled = YES;
501 }
502