xref: /freebsd/usr.bin/netstat/if.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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 %-5lu ", 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 
190 			case AF_APPLETALK:
191 				printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
192 				printf("%-9.9s  ",atalk_print(sa,0x0b) );
193 				break;
194 #ifdef NS
195 			case AF_NS:
196 				{
197 				struct sockaddr_ns *sns =
198 					(struct sockaddr_ns *)sa;
199 				u_long net;
200 				char netnum[10];
201 
202 				*(union ns_net *) &net = sns->sns_addr.x_net;
203 				sprintf(netnum, "%lxH", ntohl(net));
204 				upHex(netnum);
205 				printf("ns:%-8s ", netnum);
206 				printf("%-15s ",
207 				    ns_phost((struct sockaddr *)sns));
208 				}
209 				break;
210 #endif
211 			case AF_LINK:
212 				{
213 				struct sockaddr_dl *sdl =
214 					(struct sockaddr_dl *)sa;
215 				    cp = (char *)LLADDR(sdl);
216 				    n = sdl->sdl_alen;
217 				}
218 				m = printf("%-11.11s ", "<Link>");
219 				goto hexprint;
220 			default:
221 				m = printf("(%d)", sa->sa_family);
222 				for (cp = sa->sa_len + (char *)sa;
223 					--cp > sa->sa_data && (*cp == 0);) {}
224 				n = cp - sa->sa_data + 1;
225 				cp = sa->sa_data;
226 			hexprint:
227 				while (--n >= 0)
228 					m += printf("%02x%c", *cp++ & 0xff,
229 						    n > 0 ? '.' : ' ');
230 				m = 30 - m;
231 				while (m-- > 0)
232 					putchar(' ');
233 				break;
234 			}
235 			ifaddraddr = (u_long)ifaddr.ifa.ifa_next;
236 		}
237 		printf("%8lu %5lu ",
238 		    ifnet.if_ipackets, ifnet.if_ierrors);
239 		if (bflag)
240 			printf("%10lu ", ifnet.if_ibytes);
241 		printf("%8lu %5lu ",
242 		    ifnet.if_opackets, ifnet.if_oerrors);
243 		if (bflag)
244 			printf("%10lu ", ifnet.if_obytes);
245 		printf("%5lu", ifnet.if_collisions);
246 		if (tflag)
247 			printf(" %3d", ifnet.if_timer);
248 		if (dflag)
249 			printf(" %3d", ifnet.if_snd.ifq_drops);
250 		putchar('\n');
251 	}
252 }
253 
254 #define	MAXIF	10
255 struct	iftot {
256 	char	ift_name[16];		/* interface name */
257 	u_int	ift_ip;			/* input packets */
258 	u_int	ift_ie;			/* input errors */
259 	u_int	ift_op;			/* output packets */
260 	u_int	ift_oe;			/* output errors */
261 	u_int	ift_co;			/* collisions */
262 	u_int	ift_dr;			/* drops */
263 	u_int	ift_ib;			/* input bytes */
264 	u_int	ift_ob;			/* output bytes */
265 } iftot[MAXIF];
266 
267 u_char	signalled;			/* set if alarm goes off "early" */
268 
269 /*
270  * Print a running summary of interface statistics.
271  * Repeat display every interval seconds, showing statistics
272  * collected over that interval.  Assumes that interval is non-zero.
273  * First line printed at top of screen is always cumulative.
274  */
275 static void
276 sidewaysintpr(interval, off)
277 	unsigned interval;
278 	u_long off;
279 {
280 	struct ifnet ifnet;
281 	u_long firstifnet;
282 	register struct iftot *ip, *total;
283 	register int line;
284 	struct iftot *lastif, *sum, *interesting;
285 	int oldmask, first;
286 	u_long interesting_off;
287 
288 	if (kread(off, (char *)&firstifnet, sizeof (u_long)))
289 		return;
290 	lastif = iftot;
291 	sum = iftot + MAXIF - 1;
292 	total = sum - 1;
293 	interesting = NULL;
294 	interesting_off = 0;
295 	for (off = firstifnet, ip = iftot; off;) {
296 		char name[16], tname[16];
297 
298 		if (kread(off, (char *)&ifnet, sizeof ifnet))
299 			break;
300 		if (kread((u_long)ifnet.if_name, tname, 16))
301 			break;
302 		tname[15] = '\0';
303 		snprintf(name, 16, "%s%d", tname, ifnet.if_unit);
304 		if (interface && strcmp(name, interface) == 0) {
305 			interesting = ip;
306 			interesting_off = off;
307 		}
308 		snprintf(ip->ift_name, 16, "(%s)", name);;
309 		ip++;
310 		if (ip >= iftot + MAXIF - 2)
311 			break;
312 		off = (u_long) ifnet.if_next;
313 	}
314 	lastif = ip;
315 
316 	(void)signal(SIGALRM, catchalarm);
317 	signalled = NO;
318 	(void)alarm(interval);
319 	for (ip = iftot; ip < iftot + MAXIF; ip++) {
320 		ip->ift_ip = 0;
321 		ip->ift_ie = 0;
322 		ip->ift_ib = 0;
323 		ip->ift_op = 0;
324 		ip->ift_oe = 0;
325 		ip->ift_ob = 0;
326 		ip->ift_co = 0;
327 		ip->ift_dr = 0;
328 	}
329 	first = 1;
330 banner:
331 	printf("%17s %14s %16s", "input",
332 	    interesting ? interesting->ift_name : "(Total)", "output");
333 	putchar('\n');
334 	printf("%10s %5s %10s %10s %5s %10s %5s",
335 	    "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
336 	if (dflag)
337 		printf(" %5.5s", "drops");
338 	putchar('\n');
339 	fflush(stdout);
340 	line = 0;
341 loop:
342 	if (interesting != NULL) {
343 		ip = interesting;
344 		if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) {
345 			printf("???\n");
346 			exit(1);
347 		};
348 		if (!first) {
349 			printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
350 				ifnet.if_ipackets - ip->ift_ip,
351 				ifnet.if_ierrors - ip->ift_ie,
352 				ifnet.if_ibytes - ip->ift_ib,
353 				ifnet.if_opackets - ip->ift_op,
354 				ifnet.if_oerrors - ip->ift_oe,
355 				ifnet.if_obytes - ip->ift_ob,
356 				ifnet.if_collisions - ip->ift_co);
357 			if (dflag)
358 				printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr);
359 		}
360 		ip->ift_ip = ifnet.if_ipackets;
361 		ip->ift_ie = ifnet.if_ierrors;
362 		ip->ift_ib = ifnet.if_ibytes;
363 		ip->ift_op = ifnet.if_opackets;
364 		ip->ift_oe = ifnet.if_oerrors;
365 		ip->ift_ob = ifnet.if_obytes;
366 		ip->ift_co = ifnet.if_collisions;
367 		ip->ift_dr = ifnet.if_snd.ifq_drops;
368 	} else {
369 		sum->ift_ip = 0;
370 		sum->ift_ie = 0;
371 		sum->ift_ib = 0;
372 		sum->ift_op = 0;
373 		sum->ift_oe = 0;
374 		sum->ift_ob = 0;
375 		sum->ift_co = 0;
376 		sum->ift_dr = 0;
377 		for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
378 			if (kread(off, (char *)&ifnet, sizeof ifnet)) {
379 				off = 0;
380 				continue;
381 			}
382 			sum->ift_ip += ifnet.if_ipackets;
383 			sum->ift_ie += ifnet.if_ierrors;
384 			sum->ift_ib += ifnet.if_ibytes;
385 			sum->ift_op += ifnet.if_opackets;
386 			sum->ift_oe += ifnet.if_oerrors;
387 			sum->ift_ob += ifnet.if_obytes;
388 			sum->ift_co += ifnet.if_collisions;
389 			sum->ift_dr += ifnet.if_snd.ifq_drops;
390 			off = (u_long) ifnet.if_next;
391 		}
392 		if (!first) {
393 			printf("%10u %5u %10u %10u %5u %10u %5u",
394 				sum->ift_ip - total->ift_ip,
395 				sum->ift_ie - total->ift_ie,
396 				sum->ift_ib - total->ift_ib,
397 				sum->ift_op - total->ift_op,
398 				sum->ift_oe - total->ift_oe,
399 				sum->ift_ob - total->ift_ob,
400 				sum->ift_co - total->ift_co);
401 			if (dflag)
402 				printf(" %5u", sum->ift_dr - total->ift_dr);
403 		}
404 		*total = *sum;
405 	}
406 	if (!first)
407 		putchar('\n');
408 	fflush(stdout);
409 	oldmask = sigblock(sigmask(SIGALRM));
410 	if (! signalled) {
411 		sigpause(0);
412 	}
413 	sigsetmask(oldmask);
414 	signalled = NO;
415 	(void)alarm(interval);
416 	line++;
417 	first = 0;
418 	if (line == 21)
419 		goto banner;
420 	else
421 		goto loop;
422 	/*NOTREACHED*/
423 }
424 
425 /*
426  * Called if an interval expires before sidewaysintpr has completed a loop.
427  * Sets a flag to not wait for the alarm.
428  */
429 static void
430 catchalarm(signo)
431 	int signo;
432 {
433 	signalled = YES;
434 }
435