On Mon, Apr 07, 2014 at 04:04:24PM +0200, Mike Belopuhov wrote:
> Hi,
> 
> With some help from blambert@ and thorough testing by sthen@, I was
> able to get this working fairly well.  There are some rough edges
> however, namely the rdomain kludge and the need for an RTM_DELETE
> notification, but apart from that it seems to be doing the right
> thing.
> 
> The ARP part of the kroute builds sorted ARP lists hanging off of
> the interface nodes in the interface R/B tree.  There's fetcharp()
> that fetches and updates ARP entries on all interfaces within an
> rdomain and kernel notifications arriving at the routing socket
> that add or remove entries.  When interface goes away its ARP list
> gets purged.
> 
> The MIB part iterates over all interfaces and all ARP entries and
> calls mib_physaddr for each one of them that completes filling all
> node's fields.
> 
> OK?

One nit, one possible improvement inline below.

> 
> diff --git usr.sbin/snmpd/kroute.c usr.sbin/snmpd/kroute.c
> index 1ed4d17..7c0989b 100644
> --- usr.sbin/snmpd/kroute.c
> +++ usr.sbin/snmpd/kroute.c
> @@ -45,10 +45,12 @@
>  
>  #include "snmpd.h"
>  
>  extern struct snmpd  *env;
>  
> +u_short                       snmpd_rtableid;
> +
>  struct {
>       struct event             ks_ev;
>       u_long                   ks_iflastchange;
>       u_long                   ks_nroutes;    /* 4 billions enough? */
>       int                      ks_fd;
> @@ -69,10 +71,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 +94,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 +125,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]);
>  
> @@ -145,10 +153,12 @@ void
>  kr_init(void)
>  {
>       int             opt = 0, rcvbuf, default_rcvbuf;
>       socklen_t       optlen;
>  
> +     snmpd_rtableid = getrtable();
> +
>       if ((kr_state.ks_ifd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
>               fatal("kr_init: ioctl socket");
>  
>       if ((kr_state.ks_fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
>               fatal("kr_init: route socket");
> @@ -182,10 +192,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 +531,126 @@ 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_arp *s, struct kif_node *kn)
> +{
> +     struct kif_arp          *ka;
> +
> +     TAILQ_FOREACH(ka, &kn->arps, entry) {
> +             switch (karp_compare(s, ka)) {
> +             case 0: /* found */
> +                     return (ka);
> +             case -1: /* s < ka, end the search */
> +                     return (NULL);
> +             }
> +     }
> +     /* looped throught the whole list and didn't find */
                         ^
  a random typo appears!

> +     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 && (kn = kif_find(ifindex)) == NULL)
> +             return (NULL);
> +
> +     if (ifindex == 0) {
> +             /*
> +              * We do this manually, because we want to handle zero
> +              * ifindex special case differently from kif_find, in
> +              * particular it means that we have to look for the
> +              * address on all available interfaces.
> +              */
> +             RB_FOREACH(kn, kif_tree, &kit) {
> +                     if ((ka = karp_search(&s, kn)) != NULL)
> +                             break;
> +             }
> +     } else {
> +             if ((kn = kif_find(ifindex)) == NULL)
> +                     return (NULL);
> +             ka = karp_search(&s, kn);
> +     }
> +     return (ka);
> +}

If I'm following the logic correctly here (ifindex, being unsigned,
is either 0 or >0), you check for a non-zero ifindex, perform a
lookup via kif_find, and then immediately check for a non-zero
ifindex and perform a lookup via kif_find again.

If I'm missing something here, please point it out.

Other than these, looks good to me.

> +
> +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 +698,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 +713,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 +1028,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 +1109,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] = snmpd_rtableid;
> +
> +     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 +1192,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 +1240,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 +1304,33 @@ 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 (rtm->rtm_tableid != snmpd_rtableid)
> +                             return (0);
> +                     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 (rtm->rtm_tableid != snmpd_rtableid)
> +                             return (0);
> +                     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 +1370,52 @@ 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) {
> +             if (rtm->rtm_tableid != snmpd_rtableid)
> +                     return (0);
> +             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);
> +                     /* save static/permanent flags */
> +                     if (rtm->rtm_rmx.rmx_expire == 0 ||
> +                         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);
> +                     /* save static/permanent flags */
> +                     if (rtm->rtm_rmx.rmx_expire == 0 ||
> +                         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 e124a03..c284472 100644
> --- usr.sbin/snmpd/mib.c
> +++ usr.sbin/snmpd/mib.c
> @@ -2928,10 +2928,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 },
> @@ -2963,15 +2966,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 }
>  };
>  
> @@ -3256,10 +3263,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