diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2016-08-22 16:01:53 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2016-08-22 16:01:53 +0000 |
commit | b85d92ec64ceb2e8fb6151eecfe07200f986b36a (patch) | |
tree | 90116d51d5b57a5ab29ab15d2366a0d0e35537c7 /sys/netinet6/nd6.c | |
parent | a07e28aafa5d40017ff294c88ff72166d862e568 (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/netinet6/nd6.c')
-rw-r--r-- | sys/netinet6/nd6.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 66676cc879b..6faced72f2d 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6.c,v 1.189 2016/08/22 10:33:22 mpi Exp $ */ +/* $OpenBSD: nd6.c,v 1.190 2016/08/22 16:01:52 mpi Exp $ */ /* $KAME: nd6.c,v 1.280 2002/06/08 19:52:07 itojun Exp $ */ /* @@ -93,6 +93,7 @@ struct nd_prhead nd_prefix = { 0 }; int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; void nd6_slowtimo(void *); +void nd6_invalidate(struct rtentry *); struct llinfo_nd6 *nd6_free(struct rtentry *, int); void nd6_llinfo_timer(void *); @@ -711,6 +712,17 @@ nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp) return (0); } +void +nd6_invalidate(struct rtentry *rt) +{ + struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; + + m_freem(ln->ln_hold); + ln->ln_hold = NULL; + ln->ln_state = ND6_LLINFO_INCOMPLETE; + ln->ln_asked = 0; +} + /* * Free an nd6 llinfo entry. * Since the function would cause significant changes in the kernel, DO NOT @@ -814,7 +826,7 @@ nd6_free(struct rtentry *rt, int gc) * caches, and disable the route entry not to be used in already * cached routes. */ - if (!ISSET(rt->rt_flags, RTF_STATIC)) + if (!ISSET(rt->rt_flags, RTF_STATIC|RTF_CACHED)) rtdeletemsg(rt, ifp, ifp->if_rdomain); splx(s); @@ -1097,6 +1109,11 @@ nd6_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt) rt->rt_flags &= ~RTF_LLINFO; m_freem(ln->ln_hold); pool_put(&nd6_pool, ln); + break; + + case RTM_INVALIDATE: + nd6_invalidate(rt); + break; } } @@ -1495,17 +1512,18 @@ nd6_resolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, struct sockaddr_dl *sdl; struct rtentry *rt; struct llinfo_nd6 *ln = NULL; - int error; if (m->m_flags & M_MCAST) { ETHER_MAP_IPV6_MULTICAST(&satosin6(dst)->sin6_addr, desten); 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); } /* |