xref: /freebsd/usr.bin/netstat/if.c (revision ef5d438ed4bc17ad7ece3e40fe4d1f9baf3aadf7)
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;
281 
282 	if (kread(off, (char *)&firstifnet, sizeof (u_long)))
283 		return;
284 	lastif = iftot;
285 	sum = iftot + MAXIF - 1;
286 	total = sum - 1;
287 	interesting = iftot;
288 	for (off = firstifnet, ip = iftot; off;) {
289 		char *cp;
290 		char name[16], tname[16];
291 
292 		if (kread(off, (char *)&ifnet, sizeof ifnet))
293 			break;
294 		if (kread((u_long)ifnet.if_name, tname, 16))
295 			break;
296 		tname[15] = '\0';
297 		snprintf(name, 16, "%s%d", tname, ifnet.if_unit);
298 		if (interface && strcmp(name, interface) == 0)
299 			interesting = ip;
300 		snprintf(ip->ift_name, 16, "(%s)", name);;
301 		ip++;
302 		if (ip >= iftot + MAXIF - 2)
303 			break;
304 		off = (u_long) ifnet.if_next;
305 	}
306 	lastif = ip;
307 
308 	(void)signal(SIGALRM, catchalarm);
309 	signalled = NO;
310 	(void)alarm(interval);
311 banner:
312 	printf("     input   %s%-6.6s  %soutput       ", bflag ? "          " : "",
313 	    interesting->ift_name, bflag ? "          " : "");
314 	if (lastif - iftot > 0) {
315 		if (dflag)
316 			printf("      ");
317 		printf("          input  %s(Total)  %soutput", bflag ? "          " : "",
318 		    bflag ? "          " : "");
319 	}
320 	for (ip = iftot; ip < iftot + MAXIF; ip++) {
321 		ip->ift_ip = 0;
322 		ip->ift_ie = 0;
323 		ip->ift_op = 0;
324 		ip->ift_oe = 0;
325 		ip->ift_co = 0;
326 		ip->ift_dr = 0;
327 		ip->ift_ib = 0;
328 		ip->ift_ob = 0;
329 	}
330 	putchar('\n');
331 	printf("%8.8s %5.5s ", "packets", "errs");
332 	if (bflag)
333 		printf("%10.10s ","bytes");
334 	printf("%8.8s %5.5s ", "packets", "errs");
335 	if (bflag)
336 		printf("%10.10s ","bytes");
337 	printf("%5.5s ", "colls");
338 	if (dflag)
339 		printf("%5.5s ", "drops");
340 	if (lastif - iftot > 0) {
341 		printf(" %8.8s %5.5s", "packets", "errs");
342 		if (bflag)
343 			printf(" %10.10s", "bytes");
344 		printf(" %8.8s %5.5s", "packets", "errs");
345 		if (bflag)
346 			printf(" %10.10s", "bytes");
347 		printf(" %5.5s", "colls");
348 		if (dflag)
349 			printf(" %5.5s", "drops");
350 	}
351 	putchar('\n');
352 	fflush(stdout);
353 	line = 0;
354 loop:
355 	sum->ift_ip = 0;
356 	sum->ift_ie = 0;
357 	sum->ift_op = 0;
358 	sum->ift_oe = 0;
359 	sum->ift_co = 0;
360 	sum->ift_dr = 0;
361 	sum->ift_ib = 0;
362 	sum->ift_ob = 0;
363 	for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
364 		if (kread(off, (char *)&ifnet, sizeof ifnet)) {
365 			off = 0;
366 			continue;
367 		}
368 		if (ip == interesting) {
369 			printf("%8u %5u ",
370 				ifnet.if_ipackets - ip->ift_ip,
371 				ifnet.if_ierrors - ip->ift_ie);
372 			if (bflag)
373 				printf("%10u ", ifnet.if_ibytes - ip->ift_ib);
374 			printf("%8u %5u ",
375 				ifnet.if_opackets - ip->ift_op,
376 				ifnet.if_oerrors - ip->ift_oe);
377 			if (bflag)
378 				printf("%10u ", ifnet.if_obytes - ip->ift_ob);
379 			printf("%5u", ifnet.if_collisions - ip->ift_co);
380 			if (dflag)
381 				printf(" %5u",
382 				    ifnet.if_snd.ifq_drops - ip->ift_dr);
383 		}
384 		ip->ift_ip = ifnet.if_ipackets;
385 		ip->ift_ie = ifnet.if_ierrors;
386 		ip->ift_op = ifnet.if_opackets;
387 		ip->ift_oe = ifnet.if_oerrors;
388 		ip->ift_co = ifnet.if_collisions;
389 		ip->ift_dr = ifnet.if_snd.ifq_drops;
390 		ip->ift_ib = ifnet.if_ibytes;
391 		ip->ift_ob = ifnet.if_obytes;
392 		sum->ift_ip += ip->ift_ip;
393 		sum->ift_ie += ip->ift_ie;
394 		sum->ift_op += ip->ift_op;
395 		sum->ift_oe += ip->ift_oe;
396 		sum->ift_co += ip->ift_co;
397 		sum->ift_dr += ip->ift_dr;
398 		sum->ift_ib += ip->ift_ib;
399 		sum->ift_ob += ip->ift_ob;
400 		off = (u_long) ifnet.if_next;
401 	}
402 	if (lastif - iftot > 0) {
403 		printf("  %8u %5u",
404 			sum->ift_ip - total->ift_ip,
405 			sum->ift_ie - total->ift_ie);
406 		if (bflag)
407 			printf(" %10u", sum->ift_ib - total->ift_ib);
408 		printf(" %8u %5u",
409 			sum->ift_op - total->ift_op,
410 			sum->ift_oe - total->ift_oe);
411 		if (bflag)
412 			printf(" %10u", sum->ift_ob - total->ift_ob);
413 		printf(" %5u", sum->ift_co - total->ift_co);
414 		if (dflag)
415 			printf(" %5u", sum->ift_dr - total->ift_dr);
416 	}
417 	*total = *sum;
418 	putchar('\n');
419 	fflush(stdout);
420 	line++;
421 	oldmask = sigblock(sigmask(SIGALRM));
422 	if (! signalled) {
423 		sigpause(0);
424 	}
425 	sigsetmask(oldmask);
426 	signalled = NO;
427 	(void)alarm(interval);
428 	if (line == 21)
429 		goto banner;
430 	goto loop;
431 	/*NOTREACHED*/
432 }
433 
434 /*
435  * Called if an interval expires before sidewaysintpr has completed a loop.
436  * Sets a flag to not wait for the alarm.
437  */
438 static void
439 catchalarm(signo)
440 	int signo;
441 {
442 	signalled = YES;
443 }
444