xref: /openbsd-src/usr.bin/netstat/if.c (revision ac9b4aacc1da35008afea06a5d23c2f2dea9b93e)
1 /*	$OpenBSD: if.c,v 1.66 2012/08/26 19:42:53 tedu 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 #include <util.h>
57 
58 #include "netstat.h"
59 
60 static void print_addr(struct sockaddr *, struct sockaddr **, struct if_data *);
61 static void sidewaysintpr(u_int, int);
62 static void catchalarm(int);
63 static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
64 static void fetchifs(void);
65 
66 /*
67  * Print a description of the network interfaces.
68  * NOTE: ifnetaddr is the location of the kernel global "ifnet",
69  * which is a TAILQ_HEAD.
70  */
71 void
72 intpr(int interval, int repeatcount)
73 {
74 	struct if_msghdr ifm;
75 	int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
76 	char name[IFNAMSIZ + 1];	/* + 1 for the '*' */
77 	char *buf, *next, *lim, *cp;
78 	struct rt_msghdr *rtm;
79 	struct ifa_msghdr *ifam;
80 	struct if_data *ifd;
81 	struct sockaddr *sa, *rti_info[RTAX_MAX];
82 	struct sockaddr_dl *sdl;
83 	u_int64_t total = 0;
84 	size_t len;
85 
86 	if (interval) {
87 		sidewaysintpr((unsigned)interval, repeatcount);
88 		return;
89 	}
90 
91 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
92 		err(1, "sysctl");
93 	if ((buf = malloc(len)) == NULL)
94 		err(1, NULL);
95 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1)
96 		err(1, "sysctl");
97 
98 	printf("%-7.7s %-5.5s %-11.11s %-17.17s ",
99 	    "Name", "Mtu", "Network", "Address");
100 	if (bflag)
101 		printf("%10.10s %10.10s", "Ibytes", "Obytes");
102 	else
103 		printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
104 		    "Ipkts", "Ierrs", "Opkts", "Oerrs", "Colls");
105 	if (tflag)
106 		printf(" %s", "Time");
107 	if (dflag)
108 		printf(" %s", "Drop");
109 	putchar('\n');
110 
111 	lim = buf + len;
112 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
113 		rtm = (struct rt_msghdr *)next;
114 		if (rtm->rtm_version != RTM_VERSION)
115 			continue;
116 		switch (rtm->rtm_type) {
117 		case RTM_IFINFO:
118 			total = 0;
119 			bcopy(next, &ifm, sizeof ifm);
120 			ifd = &ifm.ifm_data;
121 
122 			sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
123 			get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
124 
125 			sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP];
126 			if (sdl == NULL || sdl->sdl_family != AF_LINK)
127 				continue;
128 			bzero(name, sizeof(name));
129 			if (sdl->sdl_nlen >= IFNAMSIZ)
130 				memcpy(name, sdl->sdl_data, IFNAMSIZ - 1);
131 			else if (sdl->sdl_nlen > 0)
132 				memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
133 
134 			if (interface != 0 && strcmp(name, interface) != 0)
135 				continue;
136 
137 			/* mark inactive interfaces with a '*' */
138 			cp = strchr(name, '\0');
139 			if ((ifm.ifm_flags & IFF_UP) == 0)
140 				*cp++ = '*';
141 			*cp = '\0';
142 
143 			if (qflag) {
144 				total = ifd->ifi_ibytes + ifd->ifi_obytes +
145 				    ifd->ifi_ipackets + ifd->ifi_ierrors +
146 				    ifd->ifi_opackets + ifd->ifi_oerrors +
147 				    ifd->ifi_collisions;
148 				if (tflag)
149 					total += 0; // XXX ifnet.if_timer;
150 				if (dflag)
151 					total += 0; // XXX ifnet.if_snd.ifq_drops;
152 				if (total == 0)
153 					continue;
154 			}
155 
156 			printf("%-7s %-5d ", name, ifd->ifi_mtu);
157 			print_addr(rti_info[RTAX_IFP], rti_info, ifd);
158 			break;
159 		case RTM_NEWADDR:
160 			if (qflag && total == 0)
161 				continue;
162 			if (interface != 0 && strcmp(name, interface) != 0)
163 				continue;
164 
165 			ifam = (struct ifa_msghdr *)next;
166 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
167 			    RTA_BRD)) == 0)
168 				break;
169 
170 			sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
171 			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
172 
173 			printf("%-7s %-5d ", name, ifd->ifi_mtu);
174 			print_addr(rti_info[RTAX_IFA], rti_info, ifd);
175 			break;
176 		}
177 	}
178 	free(buf);
179 }
180 
181 static void
182 print_addr(struct sockaddr *sa, struct sockaddr **rtinfo, struct if_data *ifd)
183 {
184 	struct sockaddr_dl *sdl;
185 	struct sockaddr_in *sin;
186 	struct sockaddr_in6 *sin6;
187 	char *cp;
188 	int m, n;
189 
190 	switch (sa->sa_family) {
191 	case AF_UNSPEC:
192 		printf("%-11.11s ", "none");
193 		printf("%-17.17s ", "none");
194 		break;
195 	case AF_INET:
196 		sin = (struct sockaddr_in *)sa;
197 		cp = netname4(sin->sin_addr.s_addr,
198 		    ((struct sockaddr_in *)rtinfo[RTAX_NETMASK])->sin_addr.s_addr);
199 		if (vflag)
200 			n = strlen(cp) < 11 ? 11 : strlen(cp);
201 		else
202 			n = 11;
203 		printf("%-*.*s ", n, n, cp);
204 		cp = routename4(sin->sin_addr.s_addr);
205 		if (vflag)
206 			n = strlen(cp) < 17 ? 17 : strlen(cp);
207 		else
208 			n = 17;
209 		printf("%-*.*s ", n, n, cp);
210 
211 #if 0
212 		if (aflag) {
213 			u_long multiaddr;
214 			struct in_multi inm;
215 
216 			multiaddr = (u_long)LIST_FIRST(&ifaddr.in.ia_multiaddrs);
217 			while (multiaddr != 0) {
218 				kread(multiaddr, &inm, sizeof inm);
219 				printf("\n%25s %-17.17s ", "",
220 				    routename4(inm.inm_addr.s_addr));
221 				multiaddr = (u_long)LIST_NEXT(&inm, inm_list);
222 			}
223 		}
224 #endif
225 		break;
226 	case AF_INET6:
227 		sin6 = (struct sockaddr_in6 *)sa;
228 #ifdef __KAME__
229 		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
230 			sin6->sin6_scope_id =
231 			    ntohs(*(u_int16_t *)
232 			    &sin6->sin6_addr.s6_addr[2]);
233 			sin6->sin6_addr.s6_addr[2] = 0;
234 			sin6->sin6_addr.s6_addr[3] = 0;
235 		}
236 #endif
237 		cp = netname6(sin6,
238 		    (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]);
239 		if (vflag)
240 			n = strlen(cp) < 11 ? 11 : strlen(cp);
241 		else
242 			n = 11;
243 		printf("%-*.*s ", n, n, cp);
244 		cp = routename6(sin6);
245 		if (vflag)
246 			n = strlen(cp) < 17 ? 17 : strlen(cp);
247 		else
248 			n = 17;
249 		printf("%-*.*s ", n, n, cp);
250 #if 0
251 		if (aflag) {
252 			u_long multiaddr;
253 			struct in6_multi inm;
254 			struct sockaddr_in6 m6;
255 
256 			multiaddr = (u_long)LIST_FIRST(&ifaddr.in6.ia6_multiaddrs);
257 			while (multiaddr != 0) {
258 				kread(multiaddr, &inm, sizeof inm);
259 				memset(&m6, 0, sizeof(m6));
260 				m6.sin6_len = sizeof(struct sockaddr_in6);
261 				m6.sin6_family = AF_INET6;
262 				m6.sin6_addr = inm.in6m_addr;
263 #ifdef __KAME__
264 				if (IN6_IS_ADDR_MC_LINKLOCAL(&m6.sin6_addr) ||
265 				    IN6_IS_ADDR_MC_INTFACELOCAL(&m6.sin6_addr)) {
266 					m6.sin6_scope_id =
267 					    ntohs(*(u_int16_t *)
268 					    &m6.sin6_addr.s6_addr[2]);
269 					m6.sin6_addr.s6_addr[2] = 0;
270 					m6.sin6_addr.s6_addr[3] = 0;
271 				}
272 #endif
273 				cp = routename6(&m6);
274 				if (vflag)
275 					n = strlen(cp) < 17 ? 17 : strlen(cp);
276 				else
277 					n = 17;
278 				printf("\n%25s %-*.*s ", "",
279 				    n, n, cp);
280 				multiaddr = (u_long)LIST_NEXT(&inm, in6m_entry);
281 			}
282 		}
283 #endif
284 		break;
285 	case AF_LINK:
286 		sdl = (struct sockaddr_dl *)sa;
287 		m = printf("%-11.11s ", "<Link>");
288 		if (sdl->sdl_type == IFT_ETHER ||
289 		    sdl->sdl_type == IFT_CARP ||
290 		    sdl->sdl_type == IFT_FDDI ||
291 		    sdl->sdl_type == IFT_ISO88025)
292 			printf("%-17.17s ",
293 			    ether_ntoa((struct ether_addr *)LLADDR(sdl)));
294 		else {
295 			cp = (char *)LLADDR(sdl);
296 			n = sdl->sdl_alen;
297 			goto hexprint;
298 		}
299 		break;
300 	default:
301 		m = printf("(%d)", sa->sa_family);
302 		for (cp = sa->sa_len + (char *)sa;
303 			--cp > sa->sa_data && (*cp == 0);) {}
304 		n = cp - sa->sa_data + 1;
305 		cp = sa->sa_data;
306 hexprint:
307 		while (--n >= 0)
308 			m += printf("%x%c", *cp++ & 0xff,
309 				    n > 0 ? '.' : ' ');
310 		m = 30 - m;
311 		while (m-- > 0)
312 			putchar(' ');
313 		break;
314 	}
315 	if (bflag) {
316 		if (hflag) {
317 			char ibytes[FMT_SCALED_STRSIZE];
318 			char obytes[FMT_SCALED_STRSIZE];
319 			fmt_scaled(ifd->ifi_ibytes, ibytes);
320 			fmt_scaled(ifd->ifi_obytes, obytes);
321 			printf("%10s %10s", ibytes, obytes);
322 		} else
323 			printf("%10llu %10llu",
324 			    ifd->ifi_ibytes, ifd->ifi_obytes);
325 	} else
326 		printf("%8llu %5llu %8llu %5llu %5llu",
327 		    ifd->ifi_ipackets, ifd->ifi_ierrors,
328 		    ifd->ifi_opackets, ifd->ifi_oerrors,
329 		    ifd->ifi_collisions);
330 	if (tflag)
331 		printf(" %4d", 0 /* XXX ifnet.if_timer */);
332 	if (dflag)
333 		printf(" %4d", 0 /* XXX ifnet.if_snd.ifq_drops */);
334 	putchar('\n');
335 }
336 
337 struct	iftot {
338 	char	ift_name[IFNAMSIZ];	/* interface name */
339 	u_int64_t ift_ip;		/* input packets */
340 	u_int64_t ift_ib;		/* input bytes */
341 	u_int64_t ift_ie;		/* input errors */
342 	u_int64_t ift_op;		/* output packets */
343 	u_int64_t ift_ob;		/* output bytes */
344 	u_int64_t ift_oe;		/* output errors */
345 	u_int64_t ift_co;		/* collisions */
346 	u_int64_t ift_dr;		/* drops */
347 } ip_cur, ip_old, sum_cur, sum_old;
348 
349 volatile sig_atomic_t signalled;	/* set if alarm goes off "early" */
350 
351 /*
352  * Print a running summary of interface statistics.
353  * Repeat display every interval seconds, showing statistics
354  * collected over that interval.  Assumes that interval is non-zero.
355  * First line printed at top of screen is always cumulative.
356  */
357 static void
358 sidewaysintpr(unsigned int interval, int repeatcount)
359 {
360 	sigset_t emptyset;
361 	int line;
362 	char ibytes[FMT_SCALED_STRSIZE];
363 	char obytes[FMT_SCALED_STRSIZE];
364 
365 	fetchifs();
366 	if (ip_cur.ift_name[0] == '\0') {
367 		fprintf(stderr, "%s: %s: unknown interface\n",
368 		    __progname, interface);
369 		exit(1);
370 	}
371 
372 	(void)signal(SIGALRM, catchalarm);
373 	signalled = 0;
374 	(void)alarm(interval);
375 banner:
376 	if (bflag)
377 		printf("%7.7s in %8.8s %6.6s out %5.5s",
378 		    ip_cur.ift_name, " ",
379 		    ip_cur.ift_name, " ");
380 	else
381 		printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s",
382 		    ip_cur.ift_name, " ",
383 		    ip_cur.ift_name, " ", " ");
384 	if (dflag)
385 		printf(" %5.5s", " ");
386 
387 	if (bflag)
388 		printf("  %7.7s in %8.8s %6.6s out %5.5s",
389 		    "total", " ", "total", " ");
390 	else
391 		printf("  %5.5s in %5.5s%5.5s out %5.5s %5.5s",
392 		    "total", " ", "total", " ", " ");
393 	if (dflag)
394 		printf(" %5.5s", " ");
395 	putchar('\n');
396 	if (bflag)
397 		printf("%10.10s %8.8s %10.10s %5.5s",
398 		    "bytes", " ", "bytes", " ");
399 	else
400 		printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
401 		    "packets", "errs", "packets", "errs", "colls");
402 	if (dflag)
403 		printf(" %5.5s", "drops");
404 
405 	if (bflag)
406 		printf("%10.10s %8.8s %10.10s %5.5s",
407 		    "bytes", " ", "bytes", " ");
408 	else
409 		printf("  %8.8s %5.5s %8.8s %5.5s %5.5s",
410 		    "packets", "errs", "packets", "errs", "colls");
411 	if (dflag)
412 		printf(" %5.5s", "drops");
413 	putchar('\n');
414 	fflush(stdout);
415 	line = 0;
416 	bzero(&ip_old, sizeof(ip_old));
417 	bzero(&sum_old, sizeof(sum_old));
418 loop:
419 	bzero(&sum_cur, sizeof(sum_cur));
420 
421 	fetchifs();
422 
423 	if (bflag) {
424 		if (hflag) {
425 			fmt_scaled(ip_cur.ift_ib - ip_old.ift_ib, ibytes);
426 			fmt_scaled(ip_cur.ift_ob - ip_old.ift_ob, obytes);
427 			printf("%10s %8.8s %10s %5.5s",
428 			    ibytes, " ", obytes, " ");
429 		} else
430 			printf("%10llu %8.8s %10llu %5.5s",
431 			    ip_cur.ift_ib - ip_old.ift_ib, " ",
432 			    ip_cur.ift_ob - ip_old.ift_ob, " ");
433 	} else
434 		printf("%8llu %5llu %8llu %5llu %5llu",
435 		    ip_cur.ift_ip - ip_old.ift_ip,
436 		    ip_cur.ift_ie - ip_old.ift_ie,
437 		    ip_cur.ift_op - ip_old.ift_op,
438 		    ip_cur.ift_oe - ip_old.ift_oe,
439 		    ip_cur.ift_co - ip_old.ift_co);
440 	if (dflag)
441 		printf(" %5llu",
442 		    /* XXX ifnet.if_snd.ifq_drops - ip->ift_dr); */
443 		    0LL);
444 
445 	ip_old = ip_cur;
446 
447 	if (bflag) {
448 		if (hflag) {
449 			fmt_scaled(sum_cur.ift_ib - sum_old.ift_ib, ibytes);
450 			fmt_scaled(sum_cur.ift_ob - sum_old.ift_ob, obytes);
451 			printf("  %10s %8.8s %10s %5.5s",
452 			    ibytes, " ", obytes, " ");
453 		} else
454 			printf("  %10llu %8.8s %10llu %5.5s",
455 			    sum_cur.ift_ib - sum_old.ift_ib, " ",
456 			    sum_cur.ift_ob - sum_old.ift_ob, " ");
457 	} else
458 		printf("  %8llu %5llu %8llu %5llu %5llu",
459 		    sum_cur.ift_ip - sum_old.ift_ip,
460 		    sum_cur.ift_ie - sum_old.ift_ie,
461 		    sum_cur.ift_op - sum_old.ift_op,
462 		    sum_cur.ift_oe - sum_old.ift_oe,
463 		    sum_cur.ift_co - sum_old.ift_co);
464 	if (dflag)
465 		printf(" %5llu", sum_cur.ift_dr - sum_old.ift_dr);
466 
467 	sum_old = sum_cur;
468 
469 	putchar('\n');
470 	fflush(stdout);
471 	if (repeatcount && --repeatcount == 0)
472 		return;
473 	line++;
474 	sigemptyset(&emptyset);
475 	if (!signalled)
476 		sigsuspend(&emptyset);
477 	signalled = 0;
478 	(void)alarm(interval);
479 	if (line == 21 && isatty(STDOUT_FILENO))
480 		goto banner;
481 	goto loop;
482 }
483 
484 /*
485  * Called if an interval expires before sidewaysintpr has completed a loop.
486  * Sets a flag to not wait for the alarm.
487  */
488 /* ARGSUSED */
489 static void
490 catchalarm(int signo)
491 {
492 	signalled = 1;
493 }
494 
495 static void
496 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
497 {
498 	int i;
499 
500 	for (i = 0; i < RTAX_MAX; i++) {
501 		if (addrs & (1 << i)) {
502 			rti_info[i] = sa;
503 			sa = (struct sockaddr *)((char *)(sa) +
504 			    roundup(sa->sa_len, sizeof(long)));
505 		} else
506 			rti_info[i] = NULL;
507 	}
508 }
509 
510 
511 static int
512 isegress(char *name)
513 {
514 	static int s = -1;
515 	int len;
516 	struct ifgroupreq ifgr;
517 	struct ifg_req *ifg;
518 	int rv = 0;
519 
520 	if (s == -1) {
521 		if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
522 			return 0;
523 	}
524 
525 	memset(&ifgr, 0, sizeof(ifgr));
526 	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
527 
528 	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
529 		return 0;
530 	}
531 
532 	len = ifgr.ifgr_len;
533 	ifgr.ifgr_groups = calloc(len, 1);
534 	if (ifgr.ifgr_groups == NULL)
535 		err(1, "getifgroups");
536 	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
537 		err(1, "SIOCGIFGROUP");
538 
539 	ifg = ifgr.ifgr_groups;
540 	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
541 		len -= sizeof(struct ifg_req);
542 		if (strcmp(ifg->ifgrq_group, IFG_EGRESS) == 0)
543 			rv = 1;
544 	}
545 
546 	free(ifgr.ifgr_groups);
547 	return rv;
548 }
549 
550 static void
551 fetchifs(void)
552 {
553 	struct if_msghdr ifm;
554 	int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
555 	struct rt_msghdr *rtm;
556 	struct if_data *ifd;
557 	struct sockaddr *sa, *rti_info[RTAX_MAX];
558 	struct sockaddr_dl *sdl;
559 	char *buf, *next, *lim;
560 	char name[IFNAMSIZ];
561 	size_t len;
562 	int takeit = 0;
563 	int foundone = 0;
564 
565 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
566 		err(1, "sysctl");
567 	if ((buf = malloc(len)) == NULL)
568 		err(1, NULL);
569 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1)
570 		err(1, "sysctl");
571 
572 	memset(&ip_cur, 0, sizeof(ip_cur));
573 	lim = buf + len;
574 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
575 		rtm = (struct rt_msghdr *)next;
576 		if (rtm->rtm_version != RTM_VERSION)
577 			continue;
578 		switch (rtm->rtm_type) {
579 		case RTM_IFINFO:
580 			bcopy(next, &ifm, sizeof ifm);
581 			ifd = &ifm.ifm_data;
582 
583 			sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
584 			get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
585 
586 			sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP];
587 			if (sdl == NULL || sdl->sdl_family != AF_LINK)
588 				continue;
589 			bzero(name, sizeof(name));
590 			if (sdl->sdl_nlen >= IFNAMSIZ)
591 				memcpy(name, sdl->sdl_data, IFNAMSIZ - 1);
592 			else if (sdl->sdl_nlen > 0)
593 				memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
594 
595 			if (interface != NULL && !strcmp(name, interface)) {
596 				takeit = 1;
597 			} else if (interface == NULL && foundone == 0 &&
598 			    isegress(name)) {
599 				takeit = 1;
600 				foundone = 1;
601 			} else
602 				takeit = 0;
603 			if (takeit) {
604 				strlcpy(ip_cur.ift_name, name,
605 				    sizeof(ip_cur.ift_name));
606 				ip_cur.ift_ip = ifd->ifi_ipackets;
607 				ip_cur.ift_ib = ifd->ifi_ibytes;
608 				ip_cur.ift_ie = ifd->ifi_ierrors;
609 				ip_cur.ift_op = ifd->ifi_opackets;
610 				ip_cur.ift_ob = ifd->ifi_obytes;
611 				ip_cur.ift_oe = ifd->ifi_oerrors;
612 				ip_cur.ift_co = ifd->ifi_collisions;
613 				ip_cur.ift_dr = 0;
614 				    /* XXX ifnet.if_snd.ifq_drops */
615 			}
616 
617 			sum_cur.ift_ip += ifd->ifi_ipackets;
618 			sum_cur.ift_ib += ifd->ifi_ibytes;
619 			sum_cur.ift_ie += ifd->ifi_ierrors;
620 			sum_cur.ift_op += ifd->ifi_opackets;
621 			sum_cur.ift_ob += ifd->ifi_obytes;
622 			sum_cur.ift_oe += ifd->ifi_oerrors;
623 			sum_cur.ift_co += ifd->ifi_collisions;
624 			sum_cur.ift_dr += 0; /* XXX ifnet.if_snd.ifq_drops */
625 			break;
626 		}
627 	}
628 	if (interface == NULL && foundone == 0) {
629 		strlcpy(ip_cur.ift_name, name,
630 		    sizeof(ip_cur.ift_name));
631 		ip_cur.ift_ip = ifd->ifi_ipackets;
632 		ip_cur.ift_ib = ifd->ifi_ibytes;
633 		ip_cur.ift_ie = ifd->ifi_ierrors;
634 		ip_cur.ift_op = ifd->ifi_opackets;
635 		ip_cur.ift_ob = ifd->ifi_obytes;
636 		ip_cur.ift_oe = ifd->ifi_oerrors;
637 		ip_cur.ift_co = ifd->ifi_collisions;
638 		ip_cur.ift_dr = 0;
639 		    /* XXX ifnet.if_snd.ifq_drops */
640 	}
641 	free(buf);
642 }
643