xref: /freebsd/usr.bin/netstat/if.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
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.2 (Berkeley) 2/21/94";
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 #include <netns/ns.h>
49 #include <netns/ns_if.h>
50 #include <netiso/iso.h>
51 #include <netiso/iso_var.h>
52 #include <arpa/inet.h>
53 
54 #include <signal.h>
55 #include <stdio.h>
56 #include <string.h>
57 #include <unistd.h>
58 
59 #include "netstat.h"
60 
61 #define	YES	1
62 #define	NO	0
63 
64 static void sidewaysintpr __P((u_int, u_long));
65 static void catchalarm __P((int));
66 
67 /*
68  * Print a description of the network interfaces.
69  */
70 void
71 intpr(interval, ifnetaddr)
72 	int interval;
73 	u_long ifnetaddr;
74 {
75 	struct ifnet ifnet;
76 	union {
77 		struct ifaddr ifa;
78 		struct in_ifaddr in;
79 		struct ipx_ifaddr ipx;
80 		struct ns_ifaddr ns;
81 		struct iso_ifaddr iso;
82 	} ifaddr;
83 	u_long ifaddraddr;
84 	struct sockaddr *sa;
85 	char name[32], tname[16];
86 
87 	if (ifnetaddr == 0) {
88 		printf("ifnet: symbol not defined\n");
89 		return;
90 	}
91 	if (interval) {
92 		sidewaysintpr((unsigned)interval, ifnetaddr);
93 		return;
94 	}
95 	if (kread(ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr))
96 		return;
97 	printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
98 		"Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
99 	if (bflag)
100 		printf(" %10.10s","Ibytes");
101 	printf(" %8.8s %5.5s", "Opkts", "Oerrs");
102 	if (bflag)
103 		printf(" %10.10s","Obytes");
104 	printf(" %5s", "Coll");
105 	if (tflag)
106 		printf(" %s", "Time");
107 	if (dflag)
108 		printf(" %s", "Drop");
109 	putchar('\n');
110 	ifaddraddr = 0;
111 	while (ifnetaddr || ifaddraddr) {
112 		struct sockaddr_in *sin;
113 		register char *cp;
114 		int n, m;
115 
116 		if (ifaddraddr == 0) {
117 			if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) ||
118 			    kread((u_long)ifnet.if_name, tname, 16))
119 				return;
120 			tname[15] = '\0';
121 			ifnetaddr = (u_long)ifnet.if_next;
122 			snprintf(name, 32, "%s%d", tname, ifnet.if_unit);
123 			if (interface != 0 && (strcmp(name, interface) != 0))
124 				continue;
125 			cp = index(name, '\0');
126 			if ((ifnet.if_flags&IFF_UP) == 0)
127 				*cp++ = '*';
128 			*cp = '\0';
129 			ifaddraddr = (u_long)ifnet.if_addrlist;
130 		}
131 		printf("%-5.5s %-5d ", name, ifnet.if_mtu);
132 		if (ifaddraddr == 0) {
133 			printf("%-13.13s ", "none");
134 			printf("%-15.15s ", "none");
135 		} else {
136 			if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
137 				ifaddraddr = 0;
138 				continue;
139 			}
140 #define CP(x) ((char *)(x))
141 			cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
142 				CP(&ifaddr); sa = (struct sockaddr *)cp;
143 			switch (sa->sa_family) {
144 			case AF_UNSPEC:
145 				printf("%-13.13s ", "none");
146 				printf("%-15.15s ", "none");
147 				break;
148 			case AF_INET:
149 				sin = (struct sockaddr_in *)sa;
150 #ifdef notdef
151 				/* can't use inet_makeaddr because kernel
152 				 * keeps nets unshifted.
153 				 */
154 				in = inet_makeaddr(ifaddr.in.ia_subnet,
155 					INADDR_ANY);
156 				printf("%-11.11s ", netname(in.s_addr,
157 				    ifaddr.in.ia_subnetmask));
158 #else
159 				printf("%-11.11s ",
160 				    netname(htonl(ifaddr.in.ia_subnet),
161 				    ifaddr.in.ia_subnetmask));
162 #endif
163 				printf("%-15.15s ",
164 				    routename(sin->sin_addr.s_addr));
165 				break;
166 			case AF_IPX:
167 				{
168 				struct sockaddr_ipx *sipx =
169 					(struct sockaddr_ipx *)sa;
170 				u_long net;
171 				char netnum[10];
172 
173 				*(union ipx_net *) &net = sipx->sipx_addr.x_net;
174 				sprintf(netnum, "%lx", ntohl(net));
175 				printf("ipx:%-8s ", netnum);
176 /*				printf("ipx:%-8s ", netname(net, 0L)); */
177 				printf("%-15s ",
178 				    ipx_phost((struct sockaddr *)sipx));
179 				}
180 				break;
181 			case AF_NS:
182 				{
183 				struct sockaddr_ns *sns =
184 					(struct sockaddr_ns *)sa;
185 				u_long net;
186 				char netnum[10];
187 
188 				*(union ns_net *) &net = sns->sns_addr.x_net;
189 				sprintf(netnum, "%lxH", ntohl(net));
190 				upHex(netnum);
191 				printf("ns:%-8s ", netnum);
192 				printf("%-15s ",
193 				    ns_phost((struct sockaddr *)sns));
194 				}
195 				break;
196 			case AF_LINK:
197 				{
198 				struct sockaddr_dl *sdl =
199 					(struct sockaddr_dl *)sa;
200 				    cp = (char *)LLADDR(sdl);
201 				    n = sdl->sdl_alen;
202 				}
203 				m = printf("<Link>");
204 				goto hexprint;
205 			default:
206 				m = printf("(%d)", sa->sa_family);
207 				for (cp = sa->sa_len + (char *)sa;
208 					--cp > sa->sa_data && (*cp == 0);) {}
209 				n = cp - sa->sa_data + 1;
210 				cp = sa->sa_data;
211 			hexprint:
212 				while (--n >= 0)
213 					m += printf("%02x%c", *cp++ & 0xff,
214 						    n > 0 ? '.' : ' ');
215 				m = 30 - m;
216 				while (m-- > 0)
217 					putchar(' ');
218 				break;
219 			}
220 			ifaddraddr = (u_long)ifaddr.ifa.ifa_next;
221 		}
222 		printf("%8d %5d ",
223 		    ifnet.if_ipackets, ifnet.if_ierrors);
224 		if (bflag)
225 			printf("%10d ", ifnet.if_ibytes);
226 		printf("%8d %5d ",
227 		    ifnet.if_opackets, ifnet.if_oerrors);
228 		if (bflag)
229 			printf("%10d ", ifnet.if_obytes);
230 		printf("%5d", ifnet.if_collisions);
231 		if (tflag)
232 			printf(" %3d", ifnet.if_timer);
233 		if (dflag)
234 			printf(" %3d", ifnet.if_snd.ifq_drops);
235 		putchar('\n');
236 	}
237 }
238 
239 #define	MAXIF	10
240 struct	iftot {
241 	char	ift_name[16];		/* interface name */
242 	u_int	ift_ip;			/* input packets */
243 	u_int	ift_ie;			/* input errors */
244 	u_int	ift_op;			/* output packets */
245 	u_int	ift_oe;			/* output errors */
246 	u_int	ift_co;			/* collisions */
247 	u_int	ift_dr;			/* drops */
248 	u_int	ift_ib;			/* input bytes */
249 	u_int	ift_ob;			/* output bytes */
250 } iftot[MAXIF];
251 
252 u_char	signalled;			/* set if alarm goes off "early" */
253 
254 /*
255  * Print a running summary of interface statistics.
256  * Repeat display every interval seconds, showing statistics
257  * collected over that interval.  Assumes that interval is non-zero.
258  * First line printed at top of screen is always cumulative.
259  */
260 static void
261 sidewaysintpr(interval, off)
262 	unsigned interval;
263 	u_long off;
264 {
265 	struct ifnet ifnet;
266 	u_long firstifnet;
267 	register struct iftot *ip, *total;
268 	register int line;
269 	struct iftot *lastif, *sum, *interesting;
270 	int oldmask;
271 
272 	if (kread(off, (char *)&firstifnet, sizeof (u_long)))
273 		return;
274 	lastif = iftot;
275 	sum = iftot + MAXIF - 1;
276 	total = sum - 1;
277 	interesting = iftot;
278 	for (off = firstifnet, ip = iftot; off;) {
279 		char *cp;
280 		char name[16], tname[16];
281 
282 		if (kread(off, (char *)&ifnet, sizeof ifnet))
283 			break;
284 		if (kread((u_long)ifnet.if_name, tname, 16))
285 			break;
286 		tname[15] = '\0';
287 		snprintf(name, 16, "%s%d", tname, ifnet.if_unit);
288 		if (interface && strcmp(name, interface) == 0)
289 			interesting = ip;
290 		snprintf(ip->ift_name, 16, "(%s)", name);;
291 		ip++;
292 		if (ip >= iftot + MAXIF - 2)
293 			break;
294 		off = (u_long) ifnet.if_next;
295 	}
296 	lastif = ip;
297 
298 	(void)signal(SIGALRM, catchalarm);
299 	signalled = NO;
300 	(void)alarm(interval);
301 banner:
302 	printf("     input   %s%-6.6s  %soutput       ", bflag ? "          " : "",
303 	    interesting->ift_name, bflag ? "          " : "");
304 	if (lastif - iftot > 0) {
305 		if (dflag)
306 			printf("      ");
307 		printf("          input  %s(Total)  %soutput", bflag ? "          " : "",
308 		    bflag ? "          " : "");
309 	}
310 	for (ip = iftot; ip < iftot + MAXIF; ip++) {
311 		ip->ift_ip = 0;
312 		ip->ift_ie = 0;
313 		ip->ift_op = 0;
314 		ip->ift_oe = 0;
315 		ip->ift_co = 0;
316 		ip->ift_dr = 0;
317 		ip->ift_ib = 0;
318 		ip->ift_ob = 0;
319 	}
320 	putchar('\n');
321 	printf("%8.8s %5.5s ", "packets", "errs");
322 	if (bflag)
323 		printf("%10.10s ","bytes");
324 	printf("%8.8s %5.5s ", "packets", "errs");
325 	if (bflag)
326 		printf("%10.10s ","bytes");
327 	printf("%5.5s ", "colls");
328 	if (dflag)
329 		printf("%5.5s ", "drops");
330 	if (lastif - iftot > 0) {
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 	}
341 	putchar('\n');
342 	fflush(stdout);
343 	line = 0;
344 loop:
345 	sum->ift_ip = 0;
346 	sum->ift_ie = 0;
347 	sum->ift_op = 0;
348 	sum->ift_oe = 0;
349 	sum->ift_co = 0;
350 	sum->ift_dr = 0;
351 	sum->ift_ib = 0;
352 	sum->ift_ob = 0;
353 	for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
354 		if (kread(off, (char *)&ifnet, sizeof ifnet)) {
355 			off = 0;
356 			continue;
357 		}
358 		if (ip == interesting) {
359 			printf("%8u %5u ",
360 				ifnet.if_ipackets - ip->ift_ip,
361 				ifnet.if_ierrors - ip->ift_ie);
362 			if (bflag)
363 				printf("%10u ", ifnet.if_ibytes - ip->ift_ib);
364 			printf("%8u %5u ",
365 				ifnet.if_opackets - ip->ift_op,
366 				ifnet.if_oerrors - ip->ift_oe);
367 			if (bflag)
368 				printf("%10u ", ifnet.if_obytes - ip->ift_ob);
369 			printf("%5u", ifnet.if_collisions - ip->ift_co);
370 			if (dflag)
371 				printf(" %5u",
372 				    ifnet.if_snd.ifq_drops - ip->ift_dr);
373 		}
374 		ip->ift_ip = ifnet.if_ipackets;
375 		ip->ift_ie = ifnet.if_ierrors;
376 		ip->ift_op = ifnet.if_opackets;
377 		ip->ift_oe = ifnet.if_oerrors;
378 		ip->ift_co = ifnet.if_collisions;
379 		ip->ift_dr = ifnet.if_snd.ifq_drops;
380 		ip->ift_ib = ifnet.if_ibytes;
381 		ip->ift_ob = ifnet.if_obytes;
382 		sum->ift_ip += ip->ift_ip;
383 		sum->ift_ie += ip->ift_ie;
384 		sum->ift_op += ip->ift_op;
385 		sum->ift_oe += ip->ift_oe;
386 		sum->ift_co += ip->ift_co;
387 		sum->ift_dr += ip->ift_dr;
388 		sum->ift_ib += ip->ift_ib;
389 		sum->ift_ob += ip->ift_ob;
390 		off = (u_long) ifnet.if_next;
391 	}
392 	if (lastif - iftot > 0) {
393 		printf("  %8u %5u",
394 			sum->ift_ip - total->ift_ip,
395 			sum->ift_ie - total->ift_ie);
396 		if (bflag)
397 			printf(" %10u", sum->ift_ib - total->ift_ib);
398 		printf(" %8u %5u",
399 			sum->ift_op - total->ift_op,
400 			sum->ift_oe - total->ift_oe);
401 		if (bflag)
402 			printf(" %10u", sum->ift_ob - total->ift_ob);
403 		printf(" %5u", sum->ift_co - total->ift_co);
404 		if (dflag)
405 			printf(" %5u", sum->ift_dr - total->ift_dr);
406 	}
407 	*total = *sum;
408 	putchar('\n');
409 	fflush(stdout);
410 	line++;
411 	oldmask = sigblock(sigmask(SIGALRM));
412 	if (! signalled) {
413 		sigpause(0);
414 	}
415 	sigsetmask(oldmask);
416 	signalled = NO;
417 	(void)alarm(interval);
418 	if (line == 21)
419 		goto banner;
420 	goto loop;
421 	/*NOTREACHED*/
422 }
423 
424 /*
425  * Called if an interval expires before sidewaysintpr has completed a loop.
426  * Sets a flag to not wait for the alarm.
427  */
428 static void
429 catchalarm(signo)
430 	int signo;
431 {
432 	signalled = YES;
433 }
434