summaryrefslogtreecommitdiff
path: root/sys/netinet/if_ether.c
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2016-08-22 16:01:53 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2016-08-22 16:01:53 +0000
commitb85d92ec64ceb2e8fb6151eecfe07200f986b36a (patch)
tree90116d51d5b57a5ab29ab15d2366a0d0e35537c7 /sys/netinet/if_ether.c
parenta07e28aafa5d40017ff294c88ff72166d862e568 (diff)
Make the ``rt_gwroute'' pointer of RTF_GATEWAY entries immutable.
This means that no protection is needed to guarantee that the next hop route wont be modified by CPU1 while CPU0 is dereferencing it in a L2 resolution functions. While here also fix an ``ifa'' leak resulting in RTF_GATEWAY being always invalid. dlg@ likes it, inputs and ok bluhm@
Diffstat (limited to 'sys/netinet/if_ether.c')
-rw-r--r--sys/netinet/if_ether.c42
1 files changed, 29 insertions, 13 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 1c4839d8c73..cab6f574d10 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ether.c,v 1.220 2016/07/14 14:01:40 mpi Exp $ */
+/* $OpenBSD: if_ether.c,v 1.221 2016/08/22 16:01:52 mpi Exp $ */
/* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */
/*
@@ -78,6 +78,7 @@ int arpt_prune = (5 * 60); /* walk list every 5 minutes */
int arpt_keep = (20 * 60); /* once resolved, cache for 20 minutes */
int arpt_down = 20; /* once declared down, don't send for 20 secs */
+void arpinvalidate(struct rtentry *);
void arptfree(struct rtentry *);
void arptimer(void *);
struct rtentry *arplookup(struct in_addr *, int, int, unsigned int);
@@ -215,6 +216,12 @@ arp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt)
rt->rt_flags &= ~RTF_LLINFO;
la_hold_total -= ml_purge(&la->la_ml);
pool_put(&arp_pool, la);
+ break;
+
+ case RTM_INVALIDATE:
+ if (!ISSET(rt->rt_flags, RTF_LOCAL))
+ arpinvalidate(rt);
+ break;
}
}
@@ -306,7 +313,6 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
struct sockaddr_dl *sdl;
struct rtentry *rt = NULL;
char addr[INET_ADDRSTRLEN];
- int error;
if (m->m_flags & M_BCAST) { /* broadcast */
memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr));
@@ -317,10 +323,12 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
return (0);
}
- error = rt_checkgate(rt0, &rt);
- if (error) {
+ rt = rt_getll(rt0);
+
+ if (ISSET(rt->rt_flags, RTF_REJECT) &&
+ (rt->rt_expire == 0 || time_uptime < rt->rt_expire)) {
m_freem(m);
- return (error);
+ return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
}
if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
@@ -667,23 +675,31 @@ arpcache(struct ifnet *ifp, struct ether_arp *ea, struct rtentry *rt)
return (0);
}
+
+void
+arpinvalidate(struct rtentry *rt)
+{
+ struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
+ struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
+
+ la_hold_total -= ml_purge(&la->la_ml);
+ sdl->sdl_alen = 0;
+ la->la_asked = 0;
+}
+
/*
* Free an arp entry.
*/
void
arptfree(struct rtentry *rt)
{
- struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
- struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
struct ifnet *ifp;
- ifp = if_get(rt->rt_ifidx);
- if ((sdl != NULL) && (sdl->sdl_family == AF_LINK)) {
- sdl->sdl_alen = 0;
- la->la_asked = 0;
- }
+ arpinvalidate(rt);
- if (!ISSET(rt->rt_flags, RTF_STATIC))
+ ifp = if_get(rt->rt_ifidx);
+ KASSERT(ifp != NULL);
+ if (!ISSET(rt->rt_flags, RTF_STATIC|RTF_CACHED))
rtdeletemsg(rt, ifp, ifp->if_rdomain);
if_put(ifp);
}