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