summaryrefslogtreecommitdiffstats
path: root/sys/netinet/if_ether.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/if_ether.c')
-rw-r--r--sys/netinet/if_ether.c85
1 files changed, 53 insertions, 32 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 239c616..4cc1d4e 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -105,11 +105,13 @@ struct llinfo_arp {
static LIST_HEAD(, llinfo_arp) llinfo_arp;
static struct ifqueue arpintrq;
-static int arp_inuse, arp_allocated, arpinit_done;
+static int arp_allocated;
+static int arpinit_done;
static int arp_maxtries = 5;
static int useloopback = 1; /* use loopback interface for local traffic */
static int arp_proxyall = 0;
+static struct callout arp_callout;
SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,
&arp_maxtries, 0, "");
@@ -140,7 +142,6 @@ arptimer(ignored_arg)
void *ignored_arg;
{
struct llinfo_arp *la, *ola;
- int s = splnet();
RADIX_NODE_HEAD_LOCK(rt_tables[AF_INET]);
la = LIST_FIRST(&llinfo_arp);
@@ -152,8 +153,8 @@ arptimer(ignored_arg)
arptfree(ola); /* timer has expired, clear */
}
RADIX_NODE_HEAD_UNLOCK(rt_tables[AF_INET]);
- splx(s);
- timeout(arptimer, NULL, arpt_prune * hz);
+
+ callout_reset(&arp_callout, arpt_prune * hz, arptimer, NULL);
}
/*
@@ -165,16 +166,20 @@ arp_rtrequest(req, rt, info)
register struct rtentry *rt;
struct rt_addrinfo *info;
{
- register struct sockaddr *gate = rt->rt_gateway;
- register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
+ register struct sockaddr *gate;
+ register struct llinfo_arp *la;
static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
+ RT_LOCK_ASSERT(rt);
+
if (!arpinit_done) {
arpinit_done = 1;
- timeout(arptimer, (caddr_t)0, hz);
+ callout_reset(&arp_callout, hz, arptimer, NULL);
}
if (rt->rt_flags & RTF_GATEWAY)
return;
+ gate = rt->rt_gateway;
+ la = (struct llinfo_arp *)rt->rt_llinfo;
switch (req) {
case RTM_ADD:
@@ -208,7 +213,7 @@ arp_rtrequest(req, rt, info)
case RTM_RESOLVE:
if (gate->sa_family != AF_LINK ||
gate->sa_len < sizeof(null_sdl)) {
- log(LOG_DEBUG, "arp_rtrequest: bad gateway %s%s\n",
+ log(LOG_DEBUG, "%s: bad gateway %s%s\n", __func__,
inet_ntoa(SIN(rt_key(rt))->sin_addr),
(gate->sa_family != AF_LINK) ?
" (!AF_LINK)": "");
@@ -222,14 +227,13 @@ arp_rtrequest(req, rt, info)
* Case 2: This route may come from cloning, or a manual route
* add with a LL address.
*/
- R_Malloc(la, struct llinfo_arp *, sizeof(*la));
+ R_Zalloc(la, struct llinfo_arp *, sizeof(*la));
rt->rt_llinfo = (caddr_t)la;
if (la == 0) {
- log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
+ log(LOG_DEBUG, "%s: malloc failed\n", __func__);
break;
}
- arp_inuse++, arp_allocated++;
- Bzero(la, sizeof(*la));
+ arp_allocated++;
la->la_rt = rt;
rt->rt_flags |= RTF_LLINFO;
RADIX_NODE_HEAD_LOCK_ASSERT(rt_tables[AF_INET]);
@@ -280,7 +284,6 @@ arp_rtrequest(req, rt, info)
case RTM_DELETE:
if (la == 0)
break;
- arp_inuse--;
RADIX_NODE_HEAD_LOCK_ASSERT(rt_tables[AF_INET]);
LIST_REMOVE(la, la_le);
rt->rt_llinfo = 0;
@@ -475,6 +478,7 @@ arpresolve(ifp, rt, m, dst, desten, rt0)
m_freem(la->la_hold);
la->la_hold = m;
if (rt->rt_expire) {
+ RT_LOCK(rt);
rt->rt_flags &= ~RTF_REJECT;
if (la->la_asked == 0 || rt->rt_expire != time_second) {
rt->rt_expire = time_second;
@@ -491,6 +495,7 @@ arpresolve(ifp, rt, m, dst, desten, rt0)
}
}
+ RT_UNLOCK(rt);
}
return (0);
}
@@ -505,8 +510,9 @@ arpintr(struct mbuf *m)
struct arphdr *ar;
if (!arpinit_done) {
+ /* NB: this race should not matter */
arpinit_done = 1;
- timeout(arptimer, (caddr_t)0, hz);
+ callout_reset(&arp_callout, hz, arptimer, NULL);
}
if (m->m_len < sizeof(struct arphdr) &&
((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) {
@@ -736,9 +742,11 @@ match:
m->m_pkthdr.len += 8;
th->rcf = trld->trld_rcf;
}
+ RT_LOCK(rt);
if (rt->rt_expire)
rt->rt_expire = time_second + arpt_keep;
rt->rt_flags &= ~RTF_REJECT;
+ RT_UNLOCK(rt);
la->la_asked = 0;
la->la_preempt = arp_maxtries;
if (la->la_hold) {
@@ -885,13 +893,16 @@ arptfree(la)
{
register struct rtentry *rt = la->la_rt;
register struct sockaddr_dl *sdl;
+
if (rt == 0)
panic("arptfree");
if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
sdl->sdl_family == AF_LINK) {
sdl->sdl_alen = 0;
la->la_preempt = la->la_asked = 0;
+ RT_LOCK(rt); /* XXX needed or move higher? */
rt->rt_flags &= ~RTF_REJECT;
+ RT_UNLOCK(rt);
return;
}
rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
@@ -906,15 +917,18 @@ arplookup(addr, create, proxy)
int create, proxy;
{
register struct rtentry *rt;
- static struct sockaddr_inarp sin = {sizeof(sin), AF_INET };
+ struct sockaddr_inarp sin;
const char *why = 0;
+ bzero(&sin, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
sin.sin_addr.s_addr = addr;
- sin.sin_other = proxy ? SIN_PROXY : 0;
+ if (proxy)
+ sin.sin_other = SIN_PROXY;
rt = rtalloc1((struct sockaddr *)&sin, create, 0UL);
if (rt == 0)
return (0);
- rt->rt_refcnt--;
if (rt->rt_flags & RTF_GATEWAY)
why = "host is not on local network";
@@ -924,25 +938,32 @@ arplookup(addr, create, proxy)
why = "gateway route is not ours";
if (why) {
- if (create) {
+#define ISDYNCLONE(_rt) \
+ (((_rt)->rt_flags & (RTF_STATIC | RTF_WASCLONED)) == RTF_WASCLONED)
+ if (create)
log(LOG_DEBUG, "arplookup %s failed: %s\n",
inet_ntoa(sin.sin_addr), why);
- /*
- * If there are no references to this Layer 2 route,
- * and it is a cloned route, and not static, and
- * arplookup() is creating the route, then purge
- * it from the routing table as it is probably bogus.
- */
- if (((rt->rt_flags & (RTF_STATIC | RTF_WASCLONED)) ==
- RTF_WASCLONED) && (rt->rt_refcnt == 0))
- rtrequest(RTM_DELETE,
- (struct sockaddr *)rt_key(rt),
- rt->rt_gateway, rt_mask(rt),
- rt->rt_flags, 0);
+ /*
+ * If there are no references to this Layer 2 route,
+ * and it is a cloned route, and not static, and
+ * arplookup() is creating the route, then purge
+ * it from the routing table as it is probably bogus.
+ */
+ RT_UNLOCK(rt);
+ if (rt->rt_refcnt == 1 && ISDYNCLONE(rt)) {
+ rtrequest(RTM_DELETE,
+ (struct sockaddr *)rt_key(rt),
+ rt->rt_gateway, rt_mask(rt),
+ rt->rt_flags, 0);
}
+ RTFREE(rt);
return (0);
+#undef ISDYNCLONE
+ } else {
+ rt->rt_refcnt--;
+ RT_UNLOCK(rt);
+ return ((struct llinfo_arp *)rt->rt_llinfo);
}
- return ((struct llinfo_arp *)rt->rt_llinfo);
}
void
@@ -964,7 +985,7 @@ arp_init(void)
arpintrq.ifq_maxlen = 50;
mtx_init(&arpintrq.ifq_mtx, "arp_inq", NULL, MTX_DEF);
LIST_INIT(&llinfo_arp);
+ callout_init(&arp_callout, CALLOUT_MPSAFE);
netisr_register(NETISR_ARP, arpintr, &arpintrq);
}
-
SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0);
OpenPOWER on IntegriCloud