xref: /openbsd/usr.bin/netstat/if.c (revision cca36db2)
1 /*	$OpenBSD: if.c,v 1.64 2011/07/09 00:45:40 henning Exp $	*/
2 /*	$NetBSD: if.c,v 1.16.4.2 1996/06/07 21:46:46 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <sys/protosw.h>
37 #include <sys/socket.h>
38 #include <sys/sysctl.h>
39 
40 #include <net/if.h>
41 #include <net/if_dl.h>
42 #include <net/if_types.h>
43 #include <net/route.h>
44 #include <netinet/in.h>
45 #include <netinet/in_var.h>
46 #include <netinet/if_ether.h>
47 #include <arpa/inet.h>
48 
49 #include <err.h>
50 #include <limits.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 
57 #include "netstat.h"
58 
59 static void print_addr(struct sockaddr *, struct sockaddr **, struct if_data *);
60 static void sidewaysintpr(u_int, int);
61 static void catchalarm(int);
62 static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
63 static void fetchifs(void);
64 
65 /*
66  * Print a description of the network interfaces.
67  * NOTE: ifnetaddr is the location of the kernel global "ifnet",
68  * which is a TAILQ_HEAD.
69  */
70 void
71 intpr(int interval, int repeatcount)
72 {
73 	struct if_msghdr ifm;
74 	int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
75 	char name[IFNAMSIZ + 1];	/* + 1 for the '*' */
76 	char *buf, *next, *lim, *cp;
77 	struct rt_msghdr *rtm;
78 	struct ifa_msghdr *ifam;
79 	struct if_data *ifd;
80 	struct sockaddr *sa, *rti_info[RTAX_MAX];
81 	struct sockaddr_dl *sdl;
82 	u_int64_t total = 0;
83 	size_t len;
84 
85 	if (interval) {
86 		sidewaysintpr((unsigned)interval, repeatcount);
87 		return;
88 	}
89 
90 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
91 		err(1, "sysctl");
92 	if ((buf = malloc(len)) == NULL)
93 		err(1, NULL);
94 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1)
95 		err(1, "sysctl");
96 
97 	printf("%-7.7s %-5.5s %-11.11s %-17.17s ",
98 	    "Name", "Mtu", "Network", "Address");
99 	if (bflag)
100 		printf("%10.10s %10.10s", "Ibytes", "Obytes");
101 	else
102 		printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
103 		    "Ipkts", "Ierrs", "Opkts", "Oerrs", "Colls");
104 	if (tflag)
105 		printf(" %s", "Time");
106 	if (dflag)
107 		printf(" %s", "Drop");
108 	putchar('\n');
109 
110 	lim = buf + len;
111 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
112 		rtm = (struct rt_msghdr *)next;
113 		if (rtm->rtm_version != RTM_VERSION)
114 			continue;
115 		switch (rtm->rtm_type) {
116 		case RTM_IFINFO:
117 			total = 0;
118 			bcopy(next, &ifm, sizeof ifm);
119 			ifd = &ifm.ifm_data;
120 
121 			sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
122 			get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
123 
124 			sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP];
125 			if (sdl == NULL || sdl->sdl_family != AF_LINK)
126 				continue;
127 			bzero(name, sizeof(name));
128 			if (sdl->sdl_nlen >= IFNAMSIZ)
129 				memcpy(name, sdl->sdl_data, IFNAMSIZ - 1);
130 			else if (sdl->sdl_nlen > 0)
131 				memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
132 
133 			if (interface != 0 && strcmp(name, interface) != 0)
134 				continue;
135 
136 			/* mark inactive interfaces with a '*' */
137 			cp = strchr(name, '\0');
138 			if ((ifm.ifm_flags & IFF_UP) == 0)
139 				*cp++ = '*';
140 			*cp = '\0';
141 
142 			if (qflag) {
143 				total = ifd->ifi_ibytes + ifd->ifi_obytes +
144 				    ifd->ifi_ipackets + ifd->ifi_ierrors +
145 				    ifd->ifi_opackets + ifd->ifi_oerrors +
146 				    ifd->ifi_collisions;
147 				if (tflag)
148 					total += 0; // XXX ifnet.if_timer;
149 				if (dflag)
150 					total += 0; // XXX ifnet.if_snd.ifq_drops;
151 				if (total == 0)
152 					continue;
153 			}
154 
155 			printf("%-7s %-5d ", name, ifd->ifi_mtu);
156 			print_addr(rti_info[RTAX_IFP], rti_info, ifd);
157 			break;
158 		case RTM_NEWADDR:
159 			if (qflag && total == 0)
160 				continue;
161 			if (interface != 0 && strcmp(name, interface) != 0)
162 				continue;
163 
164 			ifam = (struct ifa_msghdr *)next;
165 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
166 			    RTA_BRD)) == 0)
167 				break;
168 
169 			sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
170 			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
171 
172 			printf("%-7s %-5d ", name, ifd->ifi_mtu);
173 			print_addr(rti_info[RTAX_IFA], rti_info, ifd);
174 			break;
175 		}
176 	}
177 	free(buf);
178 }
179 
180 static void
181 print_addr(struct sockaddr *sa, struct sockaddr **rtinfo, struct if_data *ifd)
182 {
183 	struct sockaddr_dl *sdl;
184 	struct sockaddr_in *sin;
185 	struct sockaddr_in6 *sin6;
186 	char *cp;
187 	int m, n;
188 
189 	switch (sa->sa_family) {
190 	case AF_UNSPEC:
191 		printf("%-11.11s ", "none");
192 		printf("%-17.17s ", "none");
193 		break;
194 	case AF_INET:
195 		sin = (struct sockaddr_in *)sa;
196 		cp = netname4(sin->sin_addr.s_addr,
197 		    ((struct sockaddr_in *)rtinfo[RTAX_NETMASK])->sin_addr.s_addr);
198 		if (vflag)
199 			n = strlen(cp) < 11 ? 11 : strlen(cp);
200 		else
201 			n = 11;
202 		printf("%-*.*s ", n, n, cp);
203 		cp = routename4(sin->sin_addr.s_addr);
204 		if (vflag)
205 			n = strlen(cp) < 17 ? 17 : strlen(cp);
206 		else
207 			n = 17;
208 		printf("%-*.*s ", n, n, cp);
209 
210 #if 0
211 		if (aflag) {
212 			u_long multiaddr;
213 			struct in_multi inm;
214 
215 			multiaddr = (u_long)LIST_FIRST(&ifaddr.in.ia_multiaddrs);
216 			while (multiaddr != 0) {
217 				kread(multiaddr, &inm, sizeof inm);
218 				printf("\n%25s %-17.17s ", "",
219 				    routename4(inm.inm_addr.s_addr));
220 				multiaddr = (u_long)LIST_NEXT(&inm, inm_list);
221 			}
222 		}
223 #endif
224 		break;
225 	case AF_INET6:
226 		sin6 = (struct sockaddr_in6 *)sa;
227 #ifdef __KAME__
228 		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
229 			sin6->sin6_scope_id =
230 			    ntohs(*(u_int16_t *)
231 			    &sin6->sin6_addr.s6_addr[2]);
232 			sin6->sin6_addr.s6_addr[2] = 0;
233 			sin6->sin6_addr.s6_addr[3] = 0;
234 		}
235 #endif
236 		cp = netname6(sin6,
237 		    (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]);
238 		if (vflag)
239 			n = strlen(cp) < 11 ? 11 : strlen(cp);
240 		else
241 			n = 11;
242 		printf("%-*.*s ", n, n, cp);
243 		cp = routename6(sin6);
244 		if (vflag)
245 			n = strlen(cp) < 17 ? 17 : strlen(cp);
246 		else
247 			n = 17;
248 		printf("%-*.*s ", n, n, cp);
249 #if 0
250 		if (aflag) {
251 			u_long multiaddr;
252 			struct in6_multi inm;
253 			struct sockaddr_in6 m6;
254 
255 			multiaddr = (u_long)LIST_FIRST(&ifaddr.in6.ia6_multiaddrs);
256 			while (multiaddr != 0) {
257 				kread(multiaddr, &inm, sizeof inm);
258 				memset(&m6, 0, sizeof(m6));
259 				m6.sin6_len = sizeof(struct sockaddr_in6);
260 				m6.sin6_family = AF_INET6;
261 				m6.sin6_addr = inm.in6m_addr;
262 #ifdef __KAME__
263 				if (IN6_IS_ADDR_MC_LINKLOCAL(&m6.sin6_addr) ||
264 				    IN6_IS_ADDR_MC_INTFACELOCAL(&m6.sin6_addr)) {
265 					m6.sin6_scope_id =
266 					    ntohs(*(u_int16_t *)
267 					    &m6.sin6_addr.s6_addr[2]);
268 					m6.sin6_addr.s6_addr[2] = 0;
269 					m6.sin6_addr.s6_addr[3] = 0;
270 				}
271 #endif
272 				cp = routename6(&m6);
273 				if (vflag)
274 					n = strlen(cp) < 17 ? 17 : strlen(cp);
275 				else
276 					n = 17;
277 				printf("\n%25s %-*.*s ", "",
278 				    n, n, cp);
279 				multiaddr = (u_long)LIST_NEXT(&inm, in6m_entry);
280 			}
281 		}
282 #endif
283 		break;
284 	case AF_LINK:
285 		sdl = (struct sockaddr_dl *)sa;
286 		m = printf("%-11.11s ", "<Link>");
287 		if (sdl->sdl_type == IFT_ETHER ||
288 		    sdl->sdl_type == IFT_CARP ||
289 		    sdl->sdl_type == IFT_FDDI ||
290 		    sdl->sdl_type == IFT_ISO88025)
291 			printf("%-17.17s ",
292 			    ether_ntoa((struct ether_addr *)LLADDR(sdl)));
293 		else {
294 			cp = (char *)LLADDR(sdl);
295 			n = sdl->sdl_alen;
296 			goto hexprint;
297 		}
298 		break;
299 	default:
300 		m = printf("(%d)", sa->sa_family);
301 		for (cp = sa->sa_len + (char *)sa;
302 			--cp > sa->sa_data && (*cp == 0);) {}
303 		n = cp - sa->sa_data + 1;
304 		cp = sa->sa_data;
305 hexprint:
306 		while (--n >= 0)
307 			m += printf("%x%c", *cp++ & 0xff,
308 				    n > 0 ? '.' : ' ');
309 		m = 30 - m;
310 		while (m-- > 0)
311 			putchar(' ');
312 		break;
313 	}
314 	if (bflag)
315 		printf("%10llu %10llu",
316 		    ifd->ifi_ibytes, ifd->ifi_obytes);
317 	else
318 		printf("%8llu %5llu %8llu %5llu %5llu",
319 		    ifd->ifi_ipackets, ifd->ifi_ierrors,
320 		    ifd->ifi_opackets, ifd->ifi_oerrors,
321 		    ifd->ifi_collisions);
322 	if (tflag)
323 		printf(" %4d", 0 /* XXX ifnet.if_timer */);
324 	if (dflag)
325 		printf(" %4d", 0 /* XXX ifnet.if_snd.ifq_drops */);
326 	putchar('\n');
327 }
328 
329 struct	iftot {
330 	char	ift_name[IFNAMSIZ];	/* interface name */
331 	u_int64_t ift_ip;		/* input packets */
332 	u_int64_t ift_ib;		/* input bytes */
333 	u_int64_t ift_ie;		/* input errors */
334 	u_int64_t ift_op;		/* output packets */
335 	u_int64_t ift_ob;		/* output bytes */
336 	u_int64_t ift_oe;		/* output errors */
337 	u_int64_t ift_co;		/* collisions */
338 	u_int64_t ift_dr;		/* drops */
339 } ip_cur, ip_old, sum_cur, sum_old;
340 
341 volatile sig_atomic_t signalled;	/* set if alarm goes off "early" */
342 
343 /*
344  * Print a running summary of interface statistics.
345  * Repeat display every interval seconds, showing statistics
346  * collected over that interval.  Assumes that interval is non-zero.
347  * First line printed at top of screen is always cumulative.
348  */
349 static void
350 sidewaysintpr(unsigned int interval, int repeatcount)
351 {
352 	sigset_t emptyset;
353 	int line;
354 
355 	fetchifs();
356 	if (ip_cur.ift_name[0] == '\0') {
357 		fprintf(stderr, "%s: %s: unknown interface\n",
358 		    __progname, interface);
359 		exit(1);
360 	}
361 
362 	(void)signal(SIGALRM, catchalarm);
363 	signalled = 0;
364 	(void)alarm(interval);
365 banner:
366 	if (bflag)
367 		printf("%7.7s in %8.8s %6.6s out %5.5s",
368 		    ip_cur.ift_name, " ",
369 		    ip_cur.ift_name, " ");
370 	else
371 		printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s",
372 		    ip_cur.ift_name, " ",
373 		    ip_cur.ift_name, " ", " ");
374 	if (dflag)
375 		printf(" %5.5s", " ");
376 
377 	if (bflag)
378 		printf("  %7.7s in %8.8s %6.6s out %5.5s",
379 		    "total", " ", "total", " ");
380 	else
381 		printf("  %5.5s in %5.5s%5.5s out %5.5s %5.5s",
382 		    "total", " ", "total", " ", " ");
383 	if (dflag)
384 		printf(" %5.5s", " ");
385 	putchar('\n');
386 	if (bflag)
387 		printf("%10.10s %8.8s %10.10s %5.5s",
388 		    "bytes", " ", "bytes", " ");
389 	else
390 		printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
391 		    "packets", "errs", "packets", "errs", "colls");
392 	if (dflag)
393 		printf(" %5.5s", "drops");
394 
395 	if (bflag)
396 		printf("  %10.10s %8.8s %10.10s %5.5s",
397 		    "bytes", " ", "bytes", " ");
398 	else
399 		printf("  %8.8s %5.5s %8.8s %5.5s %5.5s",
400 		    "packets", "errs", "packets", "errs", "colls");
401 	if (dflag)
402 		printf(" %5.5s", "drops");
403 	putchar('\n');
404 	fflush(stdout);
405 	line = 0;
406 	bzero(&ip_old, sizeof(ip_old));
407 	bzero(&sum_old, sizeof(sum_old));
408 loop:
409 	bzero(&sum_cur, sizeof(sum_cur));
410 
411 	fetchifs();
412 
413 	if (bflag)
414 		printf("%10llu %8.8s %10llu %5.5s",
415 		    ip_cur.ift_ib - ip_old.ift_ib, " ",
416 		    ip_cur.ift_ob - ip_old.ift_ob, " ");
417 	else
418 		printf("%8llu %5llu %8llu %5llu %5llu",
419 		    ip_cur.ift_ip - ip_old.ift_ip,
420 		    ip_cur.ift_ie - ip_old.ift_ie,
421 		    ip_cur.ift_op - ip_old.ift_op,
422 		    ip_cur.ift_oe - ip_old.ift_oe,
423 		    ip_cur.ift_co - ip_old.ift_co);
424 	if (dflag)
425 		printf(" %5llu",
426 		    /* XXX ifnet.if_snd.ifq_drops - ip->ift_dr); */
427 		    0LL);
428 
429 	ip_old = ip_cur;
430 
431 	if (bflag)
432 		printf("  %10llu %8.8s %10llu %5.5s",
433 		    sum_cur.ift_ib - sum_old.ift_ib, " ",
434 		    sum_cur.ift_ob - sum_old.ift_ob, " ");
435 	else
436 		printf("  %8llu %5llu %8llu %5llu %5llu",
437 		    sum_cur.ift_ip - sum_old.ift_ip,
438 		    sum_cur.ift_ie - sum_old.ift_ie,
439 		    sum_cur.ift_op - sum_old.ift_op,
440 		    sum_cur.ift_oe - sum_old.ift_oe,
441 		    sum_cur.ift_co - sum_old.ift_co);
442 	if (dflag)
443 		printf(" %5llu", sum_cur.ift_dr - sum_old.ift_dr);
444 
445 	sum_old = sum_cur;
446 
447 	putchar('\n');
448 	fflush(stdout);
449 	if (repeatcount && --repeatcount == 0)
450 		return;
451 	line++;
452 	sigemptyset(&emptyset);
453 	if (!signalled)
454 		sigsuspend(&emptyset);
455 	signalled = 0;
456 	(void)alarm(interval);
457 	if (line == 21 && isatty(STDOUT_FILENO))
458 		goto banner;
459 	goto loop;
460 }
461 
462 /*
463  * Called if an interval expires before sidewaysintpr has completed a loop.
464  * Sets a flag to not wait for the alarm.
465  */
466 /* ARGSUSED */
467 static void
468 catchalarm(int signo)
469 {
470 	signalled = 1;
471 }
472 
473 static void
474 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
475 {
476 	int i;
477 
478 	for (i = 0; i < RTAX_MAX; i++) {
479 		if (addrs & (1 << i)) {
480 			rti_info[i] = sa;
481 			sa = (struct sockaddr *)((char *)(sa) +
482 			    roundup(sa->sa_len, sizeof(long)));
483 		} else
484 			rti_info[i] = NULL;
485 	}
486 }
487 
488 
489 static int
490 isegress(char *name)
491 {
492 	static int s = -1;
493 	int len;
494 	struct ifgroupreq ifgr;
495 	struct ifg_req *ifg;
496 	int rv = 0;
497 
498 	if (s == -1) {
499 		if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
500 			return 0;
501 	}
502 
503 	memset(&ifgr, 0, sizeof(ifgr));
504 	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
505 
506 	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
507 		return 0;
508 	}
509 
510 	len = ifgr.ifgr_len;
511 	ifgr.ifgr_groups = calloc(len, 1);
512 	if (ifgr.ifgr_groups == NULL)
513 		err(1, "getifgroups");
514 	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
515 		err(1, "SIOCGIFGROUP");
516 
517 	ifg = ifgr.ifgr_groups;
518 	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
519 		len -= sizeof(struct ifg_req);
520 		if (strcmp(ifg->ifgrq_group, IFG_EGRESS) == 0)
521 			rv = 1;
522 	}
523 
524 	free(ifgr.ifgr_groups);
525 	return rv;
526 }
527 
528 static void
529 fetchifs(void)
530 {
531 	struct if_msghdr ifm;
532 	int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
533 	struct rt_msghdr *rtm;
534 	struct if_data *ifd;
535 	struct sockaddr *sa, *rti_info[RTAX_MAX];
536 	struct sockaddr_dl *sdl;
537 	char *buf, *next, *lim;
538 	char name[IFNAMSIZ];
539 	size_t len;
540 	int takeit = 0;
541 	int foundone = 0;
542 
543 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
544 		err(1, "sysctl");
545 	if ((buf = malloc(len)) == NULL)
546 		err(1, NULL);
547 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1)
548 		err(1, "sysctl");
549 
550 	memset(&ip_cur, 0, sizeof(ip_cur));
551 	lim = buf + len;
552 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
553 		rtm = (struct rt_msghdr *)next;
554 		if (rtm->rtm_version != RTM_VERSION)
555 			continue;
556 		switch (rtm->rtm_type) {
557 		case RTM_IFINFO:
558 			bcopy(next, &ifm, sizeof ifm);
559 			ifd = &ifm.ifm_data;
560 
561 			sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
562 			get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
563 
564 			sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP];
565 			if (sdl == NULL || sdl->sdl_family != AF_LINK)
566 				continue;
567 			bzero(name, sizeof(name));
568 			if (sdl->sdl_nlen >= IFNAMSIZ)
569 				memcpy(name, sdl->sdl_data, IFNAMSIZ - 1);
570 			else if (sdl->sdl_nlen > 0)
571 				memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
572 
573 			if (interface != NULL && !strcmp(name, interface)) {
574 				takeit = 1;
575 			} else if (interface == NULL && foundone == 0 &&
576 			    isegress(name)) {
577 				takeit = 1;
578 				foundone = 1;
579 			} else
580 				takeit = 0;
581 			if (takeit) {
582 				strlcpy(ip_cur.ift_name, name,
583 				    sizeof(ip_cur.ift_name));
584 				ip_cur.ift_ip = ifd->ifi_ipackets;
585 				ip_cur.ift_ib = ifd->ifi_ibytes;
586 				ip_cur.ift_ie = ifd->ifi_ierrors;
587 				ip_cur.ift_op = ifd->ifi_opackets;
588 				ip_cur.ift_ob = ifd->ifi_obytes;
589 				ip_cur.ift_oe = ifd->ifi_oerrors;
590 				ip_cur.ift_co = ifd->ifi_collisions;
591 				ip_cur.ift_dr = 0;
592 				    /* XXX ifnet.if_snd.ifq_drops */
593 			}
594 
595 			sum_cur.ift_ip += ifd->ifi_ipackets;
596 			sum_cur.ift_ib += ifd->ifi_ibytes;
597 			sum_cur.ift_ie += ifd->ifi_ierrors;
598 			sum_cur.ift_op += ifd->ifi_opackets;
599 			sum_cur.ift_ob += ifd->ifi_obytes;
600 			sum_cur.ift_oe += ifd->ifi_oerrors;
601 			sum_cur.ift_co += ifd->ifi_collisions;
602 			sum_cur.ift_dr += 0; /* XXX ifnet.if_snd.ifq_drops */
603 			break;
604 		}
605 	}
606 	if (interface == NULL && foundone == 0) {
607 		strlcpy(ip_cur.ift_name, name,
608 		    sizeof(ip_cur.ift_name));
609 		ip_cur.ift_ip = ifd->ifi_ipackets;
610 		ip_cur.ift_ib = ifd->ifi_ibytes;
611 		ip_cur.ift_ie = ifd->ifi_ierrors;
612 		ip_cur.ift_op = ifd->ifi_opackets;
613 		ip_cur.ift_ob = ifd->ifi_obytes;
614 		ip_cur.ift_oe = ifd->ifi_oerrors;
615 		ip_cur.ift_co = ifd->ifi_collisions;
616 		ip_cur.ift_dr = 0;
617 		    /* XXX ifnet.if_snd.ifq_drops */
618 	}
619 	free(buf);
620 }
621