On Mon, Apr 07, 2014 at 17:03 +0200, Mike Belopuhov wrote:
> a bit of an update, mainly style changes.  one functional change:
> don't rely on rtm_rmx.rmx_expire to set the F_STATIC flag as
> rt_getmetrics is not called consistenly (only with RTM_GETs) and
> besides RTF_STATIC flag is already present for static ARP entries.
> 
> http://www.vantronix.net/~mike/snmpd-arp.diff

I've ditched rdomain kludges to simplify the diff and because actual
rdomain support doesn't need any of those.

OK?

diff --git usr.sbin/snmpd/kroute.c usr.sbin/snmpd/kroute.c
index 1ed4d17..e157b25 100644
--- usr.sbin/snmpd/kroute.c
+++ usr.sbin/snmpd/kroute.c
@@ -69,10 +69,11 @@ struct kroute6_node {
 };
 
 struct kif_node {
        RB_ENTRY(kif_node)       entry;
        TAILQ_HEAD(, kif_addr)   addrs;
+       TAILQ_HEAD(, kif_arp)    arps;
        struct kif               k;
 };
 
 int    kroute_compare(struct kroute_node *, struct kroute_node *);
 int    kroute6_compare(struct kroute6_node *, struct kroute6_node *);
@@ -91,10 +92,14 @@ struct kroute6_node *kroute6_matchgw(struct kroute6_node *,
                            struct sockaddr_in6 *);
 int                     kroute6_insert(struct kroute6_node *);
 int                     kroute6_remove(struct kroute6_node *);
 void                    kroute6_clear(void);
 
+struct kif_arp         *karp_find(struct sockaddr *, u_short);
+int                     karp_insert(struct kif_node *, struct kif_arp *);
+int                     karp_remove(struct kif_node *, struct kif_arp *);
+
 struct kif_node                *kif_find(u_short);
 struct kif_node                *kif_insert(u_short);
 int                     kif_remove(struct kif_node *);
 void                    kif_clear(void);
 struct kif             *kif_update(u_short, int, struct if_data *,
@@ -118,10 +123,11 @@ void              if_deladdr(u_short, struct sockaddr *, 
struct sockaddr *,
                    struct sockaddr *);
 void           if_announce(void *);
 
 int            fetchtable(void);
 int            fetchifs(u_short);
+int            fetcharp(void);
 void           dispatch_rtmsg(int, short, void *);
 int            rtmsg_process(char *, int);
 int            dispatch_rtmsg_addr(struct rt_msghdr *,
                    struct sockaddr *[RTAX_MAX]);
 
@@ -182,10 +188,12 @@ kr_init(void)
 
        if (fetchifs(0) == -1)
                fatalx("kr_init fetchifs");
        if (fetchtable() == -1)
                fatalx("kr_init fetchtable");
+       if (fetcharp() == -1)
+               fatalx("kr_init fetcharp");
 
        event_set(&kr_state.ks_ev, kr_state.ks_fd, EV_READ | EV_PERSIST,
            dispatch_rtmsg, NULL);
        event_add(&kr_state.ks_ev, NULL);
 }
@@ -519,10 +527,123 @@ kroute6_clear(void)
 
        while ((kr = RB_MIN(kroute6_tree, &krt6)) != NULL)
                kroute6_remove(kr);
 }
 
+static inline int
+karp_compare(struct kif_arp *a, struct kif_arp *b)
+{
+       /* Interface indices are assumed equal */
+       if (ntohl(a->addr.sin.sin_addr.s_addr) >
+           ntohl(b->addr.sin.sin_addr.s_addr))
+               return (1);
+       if (ntohl(a->addr.sin.sin_addr.s_addr) <
+           ntohl(b->addr.sin.sin_addr.s_addr))
+               return (-1);
+       return (0);
+}
+
+static inline struct kif_arp *
+karp_search(struct kif_node *kn, struct kif_arp *ka)
+{
+       struct kif_arp          *pivot;
+
+       TAILQ_FOREACH(pivot, &kn->arps, entry) {
+               switch (karp_compare(ka, pivot)) {
+               case 0: /* found */
+                       return (pivot);
+               case -1: /* ka < pivot, end the search */
+                       return (NULL);
+               }
+       }
+       /* looped through the whole list and didn't find */
+       return (NULL);
+}
+
+struct kif_arp *
+karp_find(struct sockaddr *sa, u_short ifindex)
+{
+       struct kif_node         *kn;
+       struct kif_arp          *ka = NULL, s;
+
+       memcpy(&s.addr.sa, sa, sa->sa_len);
+
+       if (ifindex == 0) {
+               /*
+                * We iterate manually to handle zero ifindex special
+                * case differently from kif_find, in particular we
+                * want to look for the address on all available
+                * interfaces.
+                */
+               RB_FOREACH(kn, kif_tree, &kit) {
+                       if ((ka = karp_search(kn, &s)) != NULL)
+                               break;
+               }
+       } else {
+               if ((kn = kif_find(ifindex)) == NULL)
+                       return (NULL);
+               ka = karp_search(kn, &s);
+       }
+       return (ka);
+}
+
+int
+karp_insert(struct kif_node *kn, struct kif_arp *ka)
+{
+       struct kif_arp          *pivot;
+
+       if (ka->if_index == 0)
+               return (-1);
+       if (!kn && (kn = kif_find(ka->if_index)) == NULL)
+               return (-1);
+       /* Put entry on the list in the ascending lexical order */
+       TAILQ_FOREACH(pivot, &kn->arps, entry) {
+               switch (karp_compare(ka, pivot)) {
+               case 0: /* collision */
+                       return (-1);
+               case -1: /* ka < pivot */
+                       TAILQ_INSERT_BEFORE(pivot, ka, entry);
+                       return (0);
+               }
+       }
+       /* ka is larger than any other element on the list */
+       TAILQ_INSERT_TAIL(&kn->arps, ka, entry);
+       return (0);
+}
+
+int
+karp_remove(struct kif_node *kn, struct kif_arp *ka)
+{
+       if (ka->if_index == 0)
+               return (-1);
+       if (!kn && (kn = kif_find(ka->if_index)) == NULL)
+               return (-1);
+       TAILQ_REMOVE(&kn->arps, ka, entry);
+       free(ka);
+       return (0);
+}
+
+struct kif_arp *
+karp_first(u_short ifindex)
+{
+       struct kif_node         *kn;
+
+       if ((kn = kif_find(ifindex)) == NULL)
+               return (NULL);
+       return (TAILQ_FIRST(&kn->arps));
+}
+
+struct kif_arp *
+karp_getaddr(struct sockaddr *sa, u_short ifindex, int next)
+{
+       struct kif_arp          *ka;
+
+       if ((ka = karp_find(sa, ifindex)) == NULL)
+               return (NULL);
+       return (next ? TAILQ_NEXT(ka, entry) : ka);
+}
+
 struct kif_node *
 kif_find(u_short if_index)
 {
        struct kif_node s;
 
@@ -570,10 +691,11 @@ kif_insert(u_short if_index)
        if ((kif = calloc(1, sizeof(struct kif_node))) == NULL)
                return (NULL);
 
        kif->k.if_index = if_index;
        TAILQ_INIT(&kif->addrs);
+       TAILQ_INIT(&kif->arps);
 
        if (RB_INSERT(kif_tree, &kit, kif) != NULL)
                fatalx("kif_insert: RB_INSERT");
 
        kr_state.ks_nkif++;
@@ -584,20 +706,24 @@ kif_insert(u_short if_index)
 
 int
 kif_remove(struct kif_node *kif)
 {
        struct kif_addr *ka;
+       struct kif_arp  *kr;
 
        if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
                log_warnx("RB_REMOVE(kif_tree, &kit, kif)");
                return (-1);
        }
 
        while ((ka = TAILQ_FIRST(&kif->addrs)) != NULL) {
                TAILQ_REMOVE(&kif->addrs, ka, entry);
                ka_remove(ka);
        }
+       while ((kr = TAILQ_FIRST(&kif->arps)) != NULL) {
+               karp_remove(kif, kr);
+       }
        free(kif);
 
        kr_state.ks_nkif--;
        kr_state.ks_iflastchange = smi_getticks();
 
@@ -895,10 +1021,12 @@ if_announce(void *msg)
        switch (ifan->ifan_what) {
        case IFAN_ARRIVAL:
                kif = kif_insert(ifan->ifan_index);
                strlcpy(kif->k.if_name, ifan->ifan_name,
                    sizeof(kif->k.if_name));
+               /* Update the ARP table */
+               fetcharp();
                break;
        case IFAN_DEPARTURE:
                kif = kif_find(ifan->ifan_index);
                kif_remove(kif);
                break;
@@ -974,10 +1102,49 @@ fetchifs(u_short if_index)
        free(buf);
 
        return (rv);
 }
 
+int
+fetcharp(void)
+{
+       size_t                   len;
+       int                      mib[7];
+       char                    *buf;
+       int                      rv;
+
+       mib[0] = CTL_NET;
+       mib[1] = AF_ROUTE;
+       mib[2] = 0;
+       mib[3] = AF_INET;
+       mib[4] = NET_RT_FLAGS;
+       mib[5] = RTF_LLINFO;
+       mib[6] = 0;
+
+       if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               return (-1);
+       }
+       /* Empty table? */
+       if (len == 0)
+               return (0);
+       if ((buf = malloc(len)) == NULL) {
+               log_warn("fetcharp");
+               return (-1);
+       }
+       if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               free(buf);
+               return (-1);
+       }
+
+       rv = rtmsg_process(buf, len);
+       free(buf);
+
+       return (rv);
+}
+
 /* ARGSUSED */
 void
 dispatch_rtmsg(int fd, short event, void *arg)
 {
        char                     buf[RT_BUF_SIZE];
@@ -1018,14 +1185,13 @@ rtmsg_process(char *buf, int len)
                switch (rtm->rtm_type) {
                case RTM_ADD:
                case RTM_GET:
                case RTM_CHANGE:
                case RTM_DELETE:
+               case RTM_RESOLVE:
                        if (rtm->rtm_errno)              /* failed attempts */
                                continue;
-                       if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */
-                               continue;
 
                        if (dispatch_rtmsg_addr(rtm, rti_info) == -1)
                                return (-1);
                        break;
                case RTM_IFINFO:
@@ -1067,12 +1233,14 @@ int
 dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX])
 {
        struct sockaddr         *sa, *psa;
        struct sockaddr_in      *sa_in, *psa_in = NULL;
        struct sockaddr_in6     *sa_in6, *psa_in6 = NULL;
+       struct sockaddr_dl      *sa_dl;
        struct kroute_node      *kr;
        struct kroute6_node     *kr6;
+       struct kif_arp          *ka;
        int                      flags, mpath = 0;
        u_int16_t                ifindex;
        u_int8_t                 prefixlen;
        u_int8_t                 prio;
 
@@ -1129,16 +1297,29 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct 
sockaddr *rti_info[RTAX_MAX])
        if ((sa = rti_info[RTAX_GATEWAY]) != NULL)
                switch (sa->sa_family) {
                case AF_LINK:
                        flags |= F_CONNECTED;
                        ifindex = rtm->rtm_index;
-                       sa = NULL;
                        mpath = 0;      /* link local stuff can't be mpath */
                        break;
                }
 
        if (rtm->rtm_type == RTM_DELETE) {
+               if (sa != NULL && sa->sa_family == AF_LINK &&
+                   (rtm->rtm_flags & RTF_HOST) &&
+                   psa->sa_family == AF_INET) {
+                       if ((ka = karp_find(psa, ifindex)) == NULL)
+                               return (0);
+                       if (karp_remove(NULL, ka) == -1)
+                               return (-1);
+                       return (0);
+               } else if (sa == NULL && (rtm->rtm_flags & RTF_HOST) &&
+                   psa->sa_family == AF_INET) {
+                       if ((ka = karp_find(psa, ifindex)) != NULL)
+                               karp_remove(NULL, ka);
+                       /* Continue to the route section below  */
+               }
                switch (psa->sa_family) {
                case AF_INET:
                        sa_in = (struct sockaddr_in *)sa;
                        if ((kr = kroute_find(psa_in->sin_addr.s_addr,
                            prefixlen, prio)) == NULL)
@@ -1178,10 +1359,46 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct 
sockaddr *rti_info[RTAX_MAX])
        }
 
        if (sa == NULL && !(flags & F_CONNECTED))
                return (0);
 
+       /* Add or update an ARP entry */
+       if ((rtm->rtm_flags & RTF_LLINFO) && (rtm->rtm_flags & RTF_HOST) &&
+           sa != NULL && sa->sa_family == AF_LINK &&
+           psa->sa_family == AF_INET) {
+               sa_dl = (struct sockaddr_dl *)sa;
+               /* ignore incomplete entries */
+               if (!sa_dl->sdl_alen)
+                       return (0);
+               /* ignore entries that do not specify an interface */
+               if (ifindex == 0)
+                       return (0);
+               if ((ka = karp_find(psa, ifindex)) != NULL) {
+                       memcpy(&ka->target.sdl, sa_dl, sa_dl->sdl_len);
+                       if (rtm->rtm_flags & RTF_PERMANENT_ARP)
+                               flags |= F_STATIC;
+                       ka->flags = flags;
+               } else {
+                       if ((ka = calloc(1, sizeof(struct kif_arp))) == NULL) {
+                               log_warn("dispatch_rtmsg");
+                               return (-1);
+                       }
+                       memcpy(&ka->addr.sa, psa, psa->sa_len);
+                       memcpy(&ka->target.sdl, sa_dl, sa_dl->sdl_len);
+                       if (rtm->rtm_flags & RTF_PERMANENT_ARP)
+                               flags |= F_STATIC;
+                       ka->flags = flags;
+                       ka->if_index = ifindex;
+                       if (karp_insert(NULL, ka)) {
+                               free(ka);
+                               log_warnx("dispatch_rtmsg: failed to insert");
+                               return (-1);
+                       }
+               }
+               return (0);
+       }
+
        switch (psa->sa_family) {
        case AF_INET:
                sa_in = (struct sockaddr_in *)sa;
                if ((kr = kroute_find(psa_in->sin_addr.s_addr, prefixlen,
                    prio)) != NULL) {
diff --git usr.sbin/snmpd/mib.c usr.sbin/snmpd/mib.c
index 03387c9..1d15614 100644
--- usr.sbin/snmpd/mib.c
+++ usr.sbin/snmpd/mib.c
@@ -2923,10 +2923,13 @@ int mib_ipfragfails(struct oid *, struct ber_oid *, 
struct ber_element **);
 int mib_iproutingdiscards(struct oid *, struct ber_oid *,
     struct ber_element **);
 int mib_ipaddr(struct oid *, struct ber_oid *, struct ber_element **);
 struct ber_oid *
     mib_ipaddrtable(struct oid *, struct ber_oid *, struct ber_oid *);
+int mib_physaddr(struct oid *, struct ber_oid *, struct ber_element **);
+struct ber_oid *
+    mib_physaddrtable(struct oid *, struct ber_oid *, struct ber_oid *);
 
 static struct oid ip_mib[] = {
        { MIB(ipMIB),                   OID_MIB },
        { MIB(ipForwarding),            OID_RD, mib_ipforwarding },
        { MIB(ipDefaultTTL),            OID_RD, mib_ipdefaultttl },
@@ -2958,15 +2961,19 @@ static struct oid ip_mib[] = {
            mib_ipaddrtable },
        { MIB(ipAdEntBcastAddr),        OID_TRD, mib_ipaddr, NULL,
            mib_ipaddrtable },
        { MIB(ipAdEntReasmMaxSize),     OID_TRD, mib_ipaddr, NULL,
            mib_ipaddrtable },
+       { MIB(ipNetToMediaIfIndex),     OID_TRD, mib_physaddr, NULL,
+           mib_physaddrtable },
+       { MIB(ipNetToMediaPhysAddress), OID_TRD, mib_physaddr, NULL,
+           mib_physaddrtable },
+       { MIB(ipNetToMediaNetAddress),  OID_TRD, mib_physaddr, NULL,
+           mib_physaddrtable },
+       { MIB(ipNetToMediaType),        OID_TRD, mib_physaddr, NULL,
+           mib_physaddrtable },
 #ifdef notyet
-       { MIB(ipNetToMediaIfIndex) },
-       { MIB(ipNetToMediaPhysAddress) },
-       { MIB(ipNetToMediaNetAddress) },
-       { MIB(ipNetToMediaType) },
        { MIB(ipRoutingDiscards) },
 #endif
        { MIBEND }
 };
 
@@ -3251,10 +3258,153 @@ mib_ipaddr(struct oid *oid, struct ber_oid *o, struct 
ber_element **elm)
        }
 
        return (0);
 }
 
+struct ber_oid *
+mib_physaddrtable(struct oid *oid, struct ber_oid *o, struct ber_oid *no)
+{
+       struct sockaddr_in       addr;
+       struct oid               a, b;
+       struct kif              *kif;
+       struct kif_arp          *ka;
+       u_int32_t                id, idx = 0;
+
+       bcopy(&oid->o_id, no, sizeof(*no));
+       id = oid->o_oidlen - 1;
+
+       if (o->bo_n >= oid->o_oidlen) {
+               /*
+                * Compare the requested and the matched OID to see
+                * if we have to iterate to the next element.
+                */
+               bzero(&a, sizeof(a));
+               bcopy(o, &a.o_id, sizeof(struct ber_oid));
+               bzero(&b, sizeof(b));
+               bcopy(&oid->o_id, &b.o_id, sizeof(struct ber_oid));
+               b.o_oidlen--;
+               b.o_flags |= OID_TABLE;
+               if (smi_oid_cmp(&a, &b) == 0) {
+                       o->bo_id[id] = oid->o_oid[id];
+                       bcopy(o, no, sizeof(*no));
+               }
+       }
+
+       if (o->bo_n > OIDIDX_ipNetToMedia + 1)
+               idx = o->bo_id[OIDIDX_ipNetToMedia + 1];
+
+       bzero(&addr, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_len = sizeof(addr);
+       if (o->bo_n > OIDIDX_ipNetToMedia + 2)
+               mps_decodeinaddr(no, &addr.sin_addr, OIDIDX_ipNetToMedia + 2);
+
+       if ((kif = kr_getif(idx)) == NULL) {
+               /* No configured interfaces */
+               if (idx == 0)
+                       return (NULL);
+               /*
+                * It may happen that an interface with a specific index
+                * does not exist or has been removed.  Jump to the next
+                * available interface.
+                */
+               kif = kr_getif(0);
+ nextif:
+               for (; kif != NULL; kif = kr_getnextif(kif->if_index))
+                       if (kif->if_index > idx &&
+                           (ka = karp_first(kif->if_index)) != NULL)
+                               break;
+               if (kif == NULL) {
+                       /* No more interfaces with addresses on them */
+                       o->bo_id[OIDIDX_ipNetToMedia + 1] = 0;
+                       mps_encodeinaddr(no, NULL, OIDIDX_ipNetToMedia + 2);
+                       smi_oidlen(o);
+                       return (NULL);
+               }
+       } else {
+               if (idx == 0 || addr.sin_addr.s_addr == 0)
+                       ka = karp_first(kif->if_index);
+               else
+                       ka = karp_getaddr((struct sockaddr *)&addr, idx, 1);
+               if (ka == NULL) {
+                       /* Try next interface */
+                       goto nextif;
+               }
+       }
+       idx = kif->if_index;
+
+       no->bo_id[OIDIDX_ipNetToMedia + 1] = idx;
+       /* Encode real IPv4 address */
+       memcpy(&addr, &ka->addr.sin, ka->addr.sin.sin_len);
+       mps_encodeinaddr(no, &addr.sin_addr, OIDIDX_ipNetToMedia + 2);
+
+       smi_oidlen(o);
+       return (no);
+}
+
+int
+mib_physaddr(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
+{
+       struct ber_element      *ber = *elm;
+       struct sockaddr_in       addr;
+       struct kif_arp          *ka;
+       u_int32_t                val, idx = 0;
+
+       idx = o->bo_id[OIDIDX_ipNetToMedia + 1];
+       if (idx == 0) {
+               /* Strip invalid interface index and fail */
+               o->bo_n = OIDIDX_ipNetToMedia + 1;
+               return (1);
+       }
+
+       /* Get the IP address */
+       bzero(&addr, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_len = sizeof(addr);
+
+       if (mps_decodeinaddr(o, &addr.sin_addr,
+           OIDIDX_ipNetToMedia + 2) == -1) {
+               /* Strip invalid address and fail */
+               o->bo_n = OIDIDX_ipNetToMedia + 2;
+               return (1);
+       }
+       if ((ka = karp_getaddr((struct sockaddr *)&addr, idx, 0)) == NULL)
+               return (1);
+
+       /* write OID */
+       ber = ber_add_oid(ber, o);
+
+       switch (o->bo_id[OIDIDX_ipNetToMedia]) {
+       case 1: /* ipNetToMediaIfIndex */
+               ber = ber_add_integer(ber, ka->if_index);
+               break;
+       case 2: /* ipNetToMediaPhysAddress */
+               if (bcmp(LLADDR(&ka->target.sdl), ether_zeroaddr,
+                   sizeof(ether_zeroaddr)) == 0)
+                       ber = ber_add_nstring(ber, ether_zeroaddr,
+                           sizeof(ether_zeroaddr));
+               else
+                       ber = ber_add_nstring(ber, LLADDR(&ka->target.sdl),
+                           ka->target.sdl.sdl_alen);
+               break;
+       case 3: /* ipNetToMediaNetAddress */
+               val = addr.sin_addr.s_addr;
+               ber = ber_add_nstring(ber, (char *)&val, sizeof(u_int32_t));
+               ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_IPADDR);
+               break;
+       case 4: /* ipNetToMediaType */
+               if (ka->flags & F_STATIC)
+                       ber = ber_add_integer(ber, 4); /* static */
+               else
+                       ber = ber_add_integer(ber, 3); /* dynamic */
+               break;
+       default:
+               return (-1);
+       }
+       return (0);
+}
+
 /*
  * Defined in IP-FORWARD-MIB.txt (rfc4292)
  */
 
 int mib_ipfnroutes(struct oid *, struct ber_oid *, struct ber_element **);
diff --git usr.sbin/snmpd/mib.h usr.sbin/snmpd/mib.h
index 2551adb..4017508 100644
--- usr.sbin/snmpd/mib.h
+++ usr.sbin/snmpd/mib.h
@@ -324,10 +324,11 @@
 #define MIB_ipAdEntNetMask             MIB_ipAddrEntry, 3
 #define MIB_ipAdEntBcastAddr           MIB_ipAddrEntry, 4
 #define MIB_ipAdEntReasmMaxSize                MIB_ipAddrEntry, 5
 #define MIB_ipNetToMediaTable          MIB_ipMIB, 22
 #define MIB_ipNetToMediaEntry          MIB_ipNetToMediaTable, 1
+#define OIDIDX_ipNetToMedia            9
 #define MIB_ipNetToMediaIfIndex                MIB_ipNetToMediaEntry, 1
 #define MIB_ipNetToMediaPhysAddress    MIB_ipNetToMediaEntry, 2
 #define MIB_ipNetToMediaNetAddress     MIB_ipNetToMediaEntry, 3
 #define MIB_ipNetToMediaType           MIB_ipNetToMediaEntry, 4
 #define MIB_ipRoutingDiscards          MIB_ipMIB, 23
@@ -1283,11 +1284,10 @@
        { MIBDECL(ipNetToMediaEntry) },                 \
        { MIBDECL(ipNetToMediaIfIndex) },               \
        { MIBDECL(ipNetToMediaPhysAddress) },           \
        { MIBDECL(ipNetToMediaNetAddress) },            \
        { MIBDECL(ipNetToMediaType) },                  \
-       { MIBDECL(ipNetToMediaType) },                  \
                                                        \
        { MIBDECL(ipfMIB) },                            \
        { MIBDECL(ipfInetCidrRouteNumber) },            \
        { MIBDECL(ipfInetCidrRouteTable) },             \
        { MIBDECL(ipfInetCidrRouteEntry) },             \
diff --git usr.sbin/snmpd/snmpd.h usr.sbin/snmpd/snmpd.h
index 95244c4..bd5eae9 100644
--- usr.sbin/snmpd/snmpd.h
+++ usr.sbin/snmpd/snmpd.h
@@ -20,10 +20,11 @@
 #ifndef _SNMPD_H
 #define _SNMPD_H
 
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#include <net/if_dl.h>
 #include <net/pfvar.h>
 #include <net/route.h>
 
 #include "ber.h"
 #include <snmp.h>
@@ -173,10 +174,11 @@ extern  struct ctl_connlist ctl_conns;
 
 union kaddr {
        struct sockaddr         sa;
        struct sockaddr_in      sin;
        struct sockaddr_in6     sin6;
+       struct sockaddr_dl      sdl;
        char                    pad[32];
 };
 
 struct kroute {
        struct in_addr  prefix;
@@ -206,10 +208,19 @@ struct kif_addr {
 
        TAILQ_ENTRY(kif_addr)    entry;
        RB_ENTRY(kif_addr)       node;
 };
 
+struct kif_arp {
+       u_short                  flags;
+       u_short                  if_index;
+       union kaddr              addr;
+       union kaddr              target;
+
+       TAILQ_ENTRY(kif_arp)     entry;
+};
+
 struct kif {
        char                     if_name[IF_NAMESIZE];
        char                     if_descr[IFDESCRSIZE];
        u_int8_t                 if_lladdr[ETHER_ADDR_LEN];
        struct if_data           if_data;
@@ -538,10 +549,13 @@ struct kif_addr *kr_getaddr(struct sockaddr *);
 struct kif_addr *kr_getnextaddr(struct sockaddr *);
 
 struct kroute  *kroute_first(void);
 struct kroute  *kroute_getaddr(in_addr_t, u_int8_t, u_int8_t, int);
 
+struct kif_arp *karp_first(u_short);
+struct kif_arp *karp_getaddr(struct sockaddr *, u_short, int);
+
 /* snmpe.c */
 pid_t           snmpe(struct privsep *, struct privsep_proc *);
 void            snmpe_shutdown(struct privsep *, struct privsep_proc *);
 
 /* trap.c */

Reply via email to