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 */