]> git.saurik.com Git - apple/network_cmds.git/blobdiff - netstat.tproj/if.c
network_cmds-356.8.tar.gz
[apple/network_cmds.git] / netstat.tproj / if.c
index 18986be75567356fbba54ee653e5f75f4f18c9ee..962a3ba40934002d514499096c812512882f1563 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -76,6 +76,7 @@ static const char rcsid[] =
 #include <net/if_dl.h>
 #include <net/if_types.h>
 #include <net/if_mib.h>
+#include <net/if_llreach.h>
 #include <net/ethernet.h>
 #include <net/route.h>
 
@@ -90,6 +91,7 @@ static const char rcsid[] =
 #include <unistd.h>
 #include <stdlib.h>
 #include <err.h>
+#include <errno.h>
 
 #include "netstat.h"
 
@@ -104,6 +106,8 @@ static const char rcsid[] =
 
 static void sidewaysintpr ();
 static void catchalarm (int);
+static char *sec2str(time_t);
+static void llreach_sysctl(uint32_t);
 
 #ifdef INET6
 char *netname6 (struct sockaddr_in6 *, struct sockaddr *);
@@ -120,10 +124,10 @@ show_stat(const char *fmt, int width, u_int64_t value, short showvalue)
 
        /* Construct the format string */
        if (showvalue) {
-               sprintf(newfmt, "%%%d%s", width, fmt);
+               snprintf(newfmt, sizeof(newfmt), "%%%d%s", width, fmt);
                printf(newfmt, value);
        } else {
-               sprintf(newfmt, "%%%ds", width);
+               snprintf(newfmt, sizeof(newfmt), "%%%ds", width);
                printf(newfmt, "-");
        }
 }
@@ -184,6 +188,7 @@ multipr(int family, char *buf, char *lim)
                                memcpy(&sin6, sa, sizeof(struct sockaddr_in6));
 
                                if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+                                       IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
                                        IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) {
                                        sin6.sin6_scope_id = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
                                        sin6.sin6_addr.s6_addr[2] = 0;
@@ -267,14 +272,25 @@ intpr(void (*pfunc)(char *))
                        free(buf);
                return;
        }
+
        if (!pfunc) {
                printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
                       "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
-               if (bflag)
+               if (prioflag >= 0)
+                       printf(" %8.8s", "Itcpkts");
+               if (bflag) {
                        printf(" %10.10s","Ibytes");
+                       if (prioflag >= 0)
+                               printf(" %10.10s", "Itcbytes");
+               }
                printf(" %8.8s %5.5s", "Opkts", "Oerrs");
-               if (bflag)
+               if (prioflag >= 0)
+                       printf(" %8.8s", "Otcpkts");
+               if (bflag) {
                        printf(" %10.10s","Obytes");
+                       if (prioflag >= 0)
+                               printf(" %10.10s", "Otcbytes");
+               }
                printf(" %5s", "Coll");
                if (tflag)
                        printf(" %s", "Time");
@@ -286,6 +302,13 @@ intpr(void (*pfunc)(char *))
     for (next = buf; next < lim; ) {
                char *cp;
                int n, m;
+               struct ifmibdata_supplemental ifmsupp;
+               u_int64_t       ift_itcp = 0;           /* input tc packets */
+               u_int64_t       ift_itcb = 0;           /* input tc bytes */
+               u_int64_t       ift_otcp = 0;           /* output tc packets */
+               u_int64_t       ift_otcb = 0;           /* output tc bytes */
+               
+               bzero(&ifmsupp, sizeof(struct ifmibdata_supplemental));
                
                network_layer = 0;
                link_layer = 0;
@@ -326,6 +349,48 @@ intpr(void (*pfunc)(char *))
                        drops = if2m->ifm_snd_drops;
                        mtu = if2m->ifm_data.ifi_mtu;
 
+                       if (prioflag >= 0) {
+                               int name[6];
+                               size_t miblen = sizeof(struct ifmibdata_supplemental);
+       
+                               /* Common OID prefix */
+                               name[0] = CTL_NET;
+                               name[1] = PF_LINK;
+                               name[2] = NETLINK_GENERIC;
+                               name[3] = IFMIB_IFDATA;
+                               name[4] = if2m->ifm_index;
+                               name[5] = IFDATA_SUPPLEMENTAL;
+                               if (sysctl(name, 6, &ifmsupp, &miblen, (void *)0, 0) == -1)
+                                       err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+                               switch (prioflag) {
+                                       case SO_TC_BK:
+                                               ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
+                                               ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
+                                               ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obkpackets;
+                                               ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obkbytes;
+                                               break;
+                                       case SO_TC_VI:
+                                               ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivipackets;
+                                               ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivibytes;
+                                               ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovipackets;
+                                               ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovibytes;
+                                               break;
+                                       case SO_TC_VO:
+                                               ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivopackets;
+                                               ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivobytes;
+                                               ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovopackets;
+                                               ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovobytes;
+                                               break;
+                                       default:
+                                               ift_itcp = 0;
+                                               ift_itcb = 0;
+                                               ift_otcp = 0;
+                                               ift_otcb = 0;
+                                               break;
+                               }
+                       }
+
             get_rti_info(if2m->ifm_addrs, (struct sockaddr*)(if2m + 1), rti_info);
                        sa = rti_info[RTAX_IFP];
         } else if (ifm->ifm_type == RTM_NEWADDR) {
@@ -392,7 +457,7 @@ intpr(void (*pfunc)(char *))
                                char linknum[10];
                                cp = (char *)LLADDR(sdl);
                                n = sdl->sdl_alen;
-                               sprintf(linknum, "<Link#%d>", sdl->sdl_index);
+                               snprintf(linknum, sizeof(linknum), "<Link#%d>", sdl->sdl_index);
                                m = printf("%-11.11s ", linknum);
                                goto hexprint;
                        }
@@ -420,17 +485,33 @@ intpr(void (*pfunc)(char *))
                printf(" ");
                show_stat("llu", 5, ierrors, link_layer);
                printf(" ");
+               if (prioflag >= 0) {
+                       show_stat("llu", 8, ift_itcp, link_layer|network_layer);
+                       printf(" ");
+               }
                if (bflag) {
                        show_stat("llu", 10, ibytes, link_layer|network_layer);
                        printf(" ");
+                       if (prioflag >= 0) {
+                               show_stat("llu", 8, ift_itcb, link_layer|network_layer);
+                               printf(" ");
+                       }
                }
                show_stat("llu", 8, opackets, link_layer|network_layer);
                printf(" ");
                show_stat("llu", 5, oerrors, link_layer);
                printf(" ");
+               if (prioflag >= 0) {
+                       show_stat("llu", 8, ift_otcp, link_layer|network_layer);
+                       printf(" ");
+               }
                if (bflag) {
                        show_stat("llu", 10, obytes, link_layer|network_layer);
                        printf(" ");
+                       if (prioflag >= 0) {
+                               show_stat("llu", 8, ift_otcb, link_layer|network_layer);
+                               printf(" ");
+                       }
                }
                show_stat("llu", 5, collisions, link_layer);
                if (tflag) {
@@ -446,6 +527,7 @@ intpr(void (*pfunc)(char *))
                if (aflag) 
                        multipr(sa->sa_family, next, lim);
        }
+       free(buf);
 }
 
 struct iftot {
@@ -459,8 +541,10 @@ struct     iftot {
        u_int64_t       ift_dr;                 /* drops */
        u_int64_t       ift_ib;                 /* input bytes */
        u_int64_t       ift_ob;                 /* output bytes */
-       u_int64_t       ift_obgp;               /* output bg packets */
-       u_int64_t       ift_obgb;               /* output bg bytes */
+       u_int64_t       ift_itcp;               /* input tc packets */
+       u_int64_t       ift_itcb;               /* input tc bytes */
+       u_int64_t       ift_otcp;               /* output tc packets */
+       u_int64_t       ift_otcb;               /* output tc bytes */
 };
 
 u_char signalled;                      /* set if alarm goes off "early" */
@@ -486,7 +570,6 @@ sidewaysintpr()
        sigset_t sigset, oldsigset;
        struct itimerval timer_interval;
 
-
        /* Common OID prefix */
        name[0] = CTL_NET;
        name[1] = PF_LINK;
@@ -516,7 +599,7 @@ sidewaysintpr()
                if (interface && strcmp(ifmd->ifmd_name, interface) == 0) {
                        if ((interesting = calloc(ifcount, sizeof(struct iftot))) == NULL)
                                err(1, "malloc failed");
-                       interesting_row = i + 1;
+                       interesting_row = if_nametoindex(interface);
                        snprintf(interesting->ift_name, 16, "(%s)", ifmd->ifmd_name);;
                }
        }
@@ -536,21 +619,30 @@ sidewaysintpr()
        (void)setitimer(ITIMER_REAL, &timer_interval, NULL);
        first = 1;
 banner:
-       printf("%17s %14s %16s", "input",
-           interesting ? interesting->ift_name : "(Total)", "output");
+       if (prioflag >= 0)
+               printf("%37s %14s %16s", "input",
+                   interesting ? interesting->ift_name : "(Total)", "output");
+       else
+               printf("%17s %14s %16s", "input",
+                   interesting ? interesting->ift_name : "(Total)", "output");
        putchar('\n');
-       printf("%10s %5s %10s %10s %5s %10s %5s",
-           "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
+       printf("%10s %5s %10s ", 
+           "packets", "errs", "bytes");
+       if (prioflag >= 0)
+               printf(" %10s %10s", "tcpkts", "tcbytes");
+       printf("%10s %5s %10s %5s",
+           "packets", "errs", "bytes", "colls");
        if (dflag)
                printf(" %5.5s", "drops");
-       if (prioflag)
-               printf(" %10s %10s", "obgpkts", "obgbytes");
+       if (prioflag >= 0)
+               printf(" %10s %10s", "tcpkts", "tcbytes");
        putchar('\n');
        fflush(stdout);
        line = 0;
 loop:
        if (interesting != NULL) {
                struct ifmibdata ifmd;
+               struct ifmibdata_supplemental ifmsupp;
                
                len = sizeof(struct ifmibdata);
                name[3] = IFMIB_IFDATA;
@@ -559,21 +651,64 @@ loop:
                if (sysctl(name, 6, &ifmd, &len, (void *)0, 0) == -1)
                        err(1, "sysctl IFDATA_GENERAL %d", interesting_row);
 
+               if (prioflag >= 0) {
+                       len = sizeof(struct ifmibdata_supplemental);
+                       name[3] = IFMIB_IFDATA;
+                       name[4] = interesting_row;
+                       name[5] = IFDATA_SUPPLEMENTAL;
+                       if (sysctl(name, 6, &ifmsupp, &len, (void *)0, 0) == -1)
+                               err(1, "sysctl IFDATA_SUPPLEMENTAL %d", interesting_row);
+               }
                if (!first) {
-                       printf("%10llu %5llu %10llu %10llu %5llu %10llu %5llu",
+                       printf("%10llu %5llu %10llu ",
                                ifmd.ifmd_data.ifi_ipackets - interesting->ift_ip,
                                ifmd.ifmd_data.ifi_ierrors - interesting->ift_ie,
-                               ifmd.ifmd_data.ifi_ibytes - interesting->ift_ib,
+                               ifmd.ifmd_data.ifi_ibytes - interesting->ift_ib);
+                       switch (prioflag) {
+                               case SO_TC_BK:
+                                       printf("%10llu %10llu ",
+                                           ifmsupp.ifmd_traffic_class.ifi_ibkpackets - interesting->ift_itcp,
+                                           ifmsupp.ifmd_traffic_class.ifi_ibkbytes - interesting->ift_itcb);
+                                       break;
+                               case SO_TC_VI:
+                                       printf("%10llu %10llu ",
+                                           ifmsupp.ifmd_traffic_class.ifi_ivipackets - interesting->ift_itcp,
+                                           ifmsupp.ifmd_traffic_class.ifi_ivibytes - interesting->ift_itcb);
+                                       break;
+                               case SO_TC_VO:
+                                       printf("%10llu %10llu ",
+                                           ifmsupp.ifmd_traffic_class.ifi_ivopackets - interesting->ift_itcp,
+                                           ifmsupp.ifmd_traffic_class.ifi_ivobytes - interesting->ift_itcb);
+                                       break;
+                               default:
+                                       break;
+                       }
+                       printf("%10llu %5llu %10llu %5llu",
                                ifmd.ifmd_data.ifi_opackets - interesting->ift_op,
                                ifmd.ifmd_data.ifi_oerrors - interesting->ift_oe,
                                ifmd.ifmd_data.ifi_obytes - interesting->ift_ob,
                                ifmd.ifmd_data.ifi_collisions - interesting->ift_co);
                        if (dflag)
                                printf(" %5llu", ifmd.ifmd_snd_drops - interesting->ift_dr);
-                       if (prioflag)
-                               printf(" %10llu %10llu",
-                                   ifmd.ifmd_filler[0] - interesting->ift_obgp,
-                                   ifmd.ifmd_filler[1] - interesting->ift_obgb);
+                       switch (prioflag) {
+                               case SO_TC_BK:
+                                       printf(" %10llu %10llu",
+                                           ifmsupp.ifmd_traffic_class.ifi_obkpackets - interesting->ift_otcp,
+                                           ifmsupp.ifmd_traffic_class.ifi_obkbytes - interesting->ift_otcb);
+                                       break;
+                               case SO_TC_VI:
+                                       printf(" %10llu %10llu",
+                                           ifmsupp.ifmd_traffic_class.ifi_ovipackets - interesting->ift_otcp,
+                                           ifmsupp.ifmd_traffic_class.ifi_ovibytes - interesting->ift_otcb);
+                                       break;
+                               case SO_TC_VO:
+                                       printf(" %10llu %10llu",
+                                           ifmsupp.ifmd_traffic_class.ifi_ovopackets - interesting->ift_otcp,
+                                           ifmsupp.ifmd_traffic_class.ifi_ovobytes - interesting->ift_otcb);
+                                       break;
+                               default:
+                                       break;
+                       }
                }
                interesting->ift_ip = ifmd.ifmd_data.ifi_ipackets;
                interesting->ift_ie = ifmd.ifmd_data.ifi_ierrors;
@@ -584,10 +719,31 @@ loop:
                interesting->ift_co = ifmd.ifmd_data.ifi_collisions;
                interesting->ift_dr = ifmd.ifmd_snd_drops;
                /* private counters */
-               interesting->ift_obgp = ifmd.ifmd_filler[0];
-               interesting->ift_obgb = ifmd.ifmd_filler[1];
+               switch (prioflag) {
+                       case SO_TC_BK:
+                               interesting->ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
+                               interesting->ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
+                               interesting->ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obkpackets;
+                               interesting->ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obkbytes;
+                               break;
+                       case SO_TC_VI:
+                               interesting->ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivipackets;
+                               interesting->ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivibytes;
+                               interesting->ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovipackets;
+                               interesting->ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovibytes;
+                               break;
+                       case SO_TC_VO:
+                               interesting->ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivopackets;
+                               interesting->ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivobytes;
+                               interesting->ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovopackets;
+                               interesting->ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovobytes;
+                               break;
+                       default:
+                               break;
+               }
        } else {
                unsigned int latest_ifcount;
+               struct ifmibdata_supplemental *ifmsuppall = NULL;
                
                len = sizeof(int);
                name[3] = IFMIB_SYSTEM;
@@ -600,7 +756,7 @@ loop:
                        free(ifmdall);
                        ifmdall = malloc(len);
                        if (ifmdall == 0)
-                               err(1, "malloc failed");
+                               err(1, "malloc ifmdall failed");
                } else if (latest_ifcount > ifcount) {
                        ifcount = latest_ifcount;
                        len = ifcount * sizeof(struct ifmibdata);
@@ -611,7 +767,17 @@ loop:
                name[5] = IFDATA_GENERAL;
                if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
                        err(1, "sysctl IFMIB_IFALLDATA");
-                       
+               if (prioflag >= 0) {
+                       len = ifcount * sizeof(struct ifmibdata_supplemental);
+                       ifmsuppall = malloc(len);
+                       if (ifmsuppall == NULL)
+                               err(1, "malloc ifmsuppall failed");
+                       name[3] = IFMIB_IFALLDATA;
+                       name[4] = 0;
+                       name[5] = IFDATA_SUPPLEMENTAL;
+                       if (sysctl(name, 6, ifmsuppall, &len, (void *)0, 0) == -1)
+                               err(1, "sysctl IFMIB_IFALLDATA SUPPLEMENTAL");
+               }                       
                sum->ift_ip = 0;
                sum->ift_ie = 0;
                sum->ift_ib = 0;
@@ -620,8 +786,10 @@ loop:
                sum->ift_ob = 0;
                sum->ift_co = 0;
                sum->ift_dr = 0;
-               sum->ift_obgp = 0;
-               sum->ift_obgb = 0;
+               sum->ift_itcp = 0;
+               sum->ift_itcb = 0;
+               sum->ift_otcp = 0;
+               sum->ift_otcb = 0;
                for (i = 0; i < ifcount; i++) {
                        struct ifmibdata *ifmd = ifmdall + i;
                        
@@ -634,24 +802,52 @@ loop:
                        sum->ift_co += ifmd->ifmd_data.ifi_collisions;
                        sum->ift_dr += ifmd->ifmd_snd_drops;
                        /* private counters */
-                       sum->ift_obgp += ifmd->ifmd_filler[0];
-                       sum->ift_obgb += ifmd->ifmd_filler[1];
+                       if (prioflag >= 0) {
+                               struct ifmibdata_supplemental *ifmsupp = ifmsuppall + i;
+                               switch (prioflag) {
+                                       case SO_TC_BK:
+                                               sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibkpackets;
+                                               sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibkbytes;
+                                               sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obkpackets;
+                                               sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obkbytes;
+                                               break;
+                                       case SO_TC_VI:
+                                               sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivipackets;
+                                               sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivibytes;
+                                               sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovipackets;
+                                               sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovibytes;
+                                               break;
+                                       case SO_TC_VO:
+                                               sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivopackets;
+                                               sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivobytes;
+                                               sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovopackets;
+                                               sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovobytes;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
                }
                if (!first) {
-                       printf("%10llu %5llu %10llu %10llu %5llu %10llu %5llu",
+                       printf("%10llu %5llu %10llu ",
                                sum->ift_ip - total->ift_ip,
                                sum->ift_ie - total->ift_ie,
-                               sum->ift_ib - total->ift_ib,
+                               sum->ift_ib - total->ift_ib);
+                       if (prioflag >= 0)
+                               printf(" %10llu %10llu",
+                                   sum->ift_itcp - total->ift_itcp,
+                                   sum->ift_itcb - total->ift_itcb);
+                       printf("%10llu %5llu %10llu %5llu",
                                sum->ift_op - total->ift_op,
                                sum->ift_oe - total->ift_oe,
                                sum->ift_ob - total->ift_ob,
                                sum->ift_co - total->ift_co);
                        if (dflag)
                                printf(" %5llu", sum->ift_dr - total->ift_dr);
-                       if (prioflag)
+                       if (prioflag >= 0)
                                printf(" %10llu %10llu",
-                                   sum->ift_obgp - total->ift_obgp,
-                                   sum->ift_obgb - total->ift_obgb);
+                                   sum->ift_otcp - total->ift_otcp,
+                                   sum->ift_otcb - total->ift_otcb);
                }
                *total = *sum;
        }
@@ -717,3 +913,165 @@ catchalarm(int signo )
 {
        signalled = YES;
 }
+
+static char *
+sec2str(total)
+       time_t total;
+{
+       static char result[256];
+       int days, hours, mins, secs;
+       int first = 1;
+       char *p = result;
+
+       days = total / 3600 / 24;
+       hours = (total / 3600) % 24;
+       mins = (total / 60) % 60;
+       secs = total % 60;
+
+       if (days) {
+               first = 0;
+               p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+       }
+       if (!first || hours) {
+               first = 0;
+               p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+       }
+       if (!first || mins) {
+               first = 0;
+               p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+       }
+       snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+
+       return(result);
+}
+
+void
+intpr_ri(void (*pfunc)(char *))
+{
+       int mib[6];
+       char *buf = NULL, *lim, *next;
+       size_t len;
+       unsigned int ifindex = 0;
+       struct if_msghdr2 *if2m;
+
+       if (interface != 0) {
+               ifindex = if_nametoindex(interface);
+               if (ifindex == 0) {
+                       printf("interface name is not valid: %s\n", interface);
+                       exit(1);
+               }
+       }
+
+       mib[0]  = CTL_NET;              /* networking subsystem */
+       mib[1]  = PF_ROUTE;             /* type of information */
+       mib[2]  = 0;                    /* protocol (IPPROTO_xxx) */
+       mib[3]  = 0;                    /* address family */
+       mib[4]  = NET_RT_IFLIST2;       /* operation */
+       mib[5]  = 0;
+       if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+               return;
+       if ((buf = malloc(len)) == NULL) {
+               printf("malloc failed\n");
+               exit(1);
+       }
+       if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+               free(buf);
+               return;
+       }
+
+       printf("%-6s %-17s %8.8s %-9.9s %4s %4s\n",
+              "Proto", "Linklayer Address", "Netif", "Expire", "Refs", "Prbs");
+
+       lim = buf + len;
+       if2m = (struct if_msghdr2 *)buf;
+
+       for (next = buf; next < lim; ) {
+               if2m = (struct if_msghdr2 *)next;
+               next += if2m->ifm_msglen;
+
+               if (if2m->ifm_type != RTM_IFINFO2)
+                       continue;
+               else if (interface != 0 && if2m->ifm_index != ifindex)
+                       continue;
+
+               llreach_sysctl(if2m->ifm_index);
+       }
+       free(buf);
+}
+
+static void
+llreach_sysctl(uint32_t ifindex)
+{
+#define        MAX_SYSCTL_TRY  5
+       int mib[6], i, ntry = 0;
+       size_t mibsize, len, needed, cnt;
+       struct if_llreach_info *lri;
+       struct timeval time;
+       char *buf;
+       char ifname[IF_NAMESIZE];
+
+       bzero(&mib, sizeof (mib));
+       mibsize = sizeof (mib) / sizeof (mib[0]);
+       if (sysctlnametomib("net.link.generic.system.llreach_info", mib,
+           &mibsize) == -1) {
+               perror("sysctlnametomib");
+               return;
+       }
+
+       needed = 0;
+       mib[5] = ifindex;
+
+       mibsize = sizeof (mib) / sizeof (mib[0]);
+       do {
+               if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+                       perror("sysctl net.link.generic.system.llreach_info");
+                       return;
+               }
+               if ((buf = malloc(needed)) == NULL) {
+                       perror("malloc");
+                       return;
+               }
+               if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+                       if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+                               perror("sysctl");
+                               goto out_free;
+                       }
+                       free(buf);
+                       buf = NULL;
+               }
+       } while (buf == NULL);
+
+       len = needed;
+       cnt = len / sizeof (*lri);
+       lri = (struct if_llreach_info *)buf;
+
+       gettimeofday(&time, 0);
+       if (if_indextoname(ifindex, ifname) == NULL)
+               snprintf(ifname, sizeof (ifname), "%s", "?");
+
+       for (i = 0; i < cnt; i++, lri++) {
+               printf("0x%-4x %-17s %8.8s ", lri->lri_proto,
+                   ether_ntoa((struct ether_addr *)lri->lri_addr), ifname);
+
+               if (lri->lri_expire > time.tv_sec)
+                       printf("%-9.9s", sec2str(lri->lri_expire - time.tv_sec));
+               else if (lri->lri_expire == 0)
+                       printf("%-9.9s", "permanent");
+               else
+                       printf("%-9.9s", "expired");
+
+               printf(" %4d", lri->lri_refcnt);
+               if (lri->lri_probes)
+                       printf(" %4d", lri->lri_probes);
+               printf("\n");
+               len -= sizeof (*lri);
+       }
+       if (len > 0) {
+               fprintf(stderr, "warning: %u trailing bytes from %s\n",
+                   (unsigned int)len, "net.link.generic.system.llreach_info");
+       }
+
+out_free:
+       free(buf);
+#undef MAX_SYSCTL_TRY
+}