diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-01-08 14:29:19 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-01-08 14:29:19 +0000 |
commit | 6571bb75613e41eb1a6ea1f65cc04b539cb7159e (patch) | |
tree | 18641ce38c4950cbd3a5f04bb0410fc04e8bd094 /sys/net | |
parent | 4d3e239b7078bc404f29d5f8d6a584a1e6716f20 (diff) |
Factorize various duplicated chunks of (old and horrible) code, checking
for the validity of a given outgoing route entry into a single function.
This change is inspired from FreeBSD r111767. The function introduced
here, rt_checkgate(), should hopefully die in a near future. Why should
it die? Well, it is way too late to do such validity checks: if your
kernel can ends up in ether_output() with an invalid route, please do
not let it try to find a new one that might do the job.
Go read this function if you're wondering why you're getting messages
like:
"arpresolve: X.X.X.X: route without link local address"
Since this horrible logic has survived 20 years of copy & past and small
modifications for workarounds without a single clear commit message, let's
assume it is full of dragons and try to play safe. This factorization is
not intended to change any behavior.
With much inputs from bluhm@, tested by weerd@ and florian@ on setups
with p2p IPv6 interfaces.
ok bluhm@, benno@, florian@
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_ethersubr.c | 47 | ||||
-rw-r--r-- | sys/net/route.c | 41 | ||||
-rw-r--r-- | sys/net/route.h | 7 |
3 files changed, 56 insertions, 39 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 27193378ab8..d9d5da16ffe 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ethersubr.c,v 1.184 2014/12/19 17:14:39 tedu Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.185 2015/01/08 14:29:18 mpi Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* @@ -238,14 +238,13 @@ ether_addheader(struct mbuf **m, struct ifnet *ifp, u_int16_t etype, */ int ether_output(struct ifnet *ifp0, struct mbuf *m0, struct sockaddr *dst, - struct rtentry *rt0) + struct rtentry *rt) { u_int16_t etype; int s, len, error = 0; u_char edst[ETHER_ADDR_LEN]; u_char *esrc; struct mbuf *m = m0; - struct rtentry *rt; struct mbuf *mcopy = NULL; struct ether_header *eh; struct arpcom *ac = (struct arpcom *)ifp0; @@ -283,38 +282,12 @@ ether_output(struct ifnet *ifp0, struct mbuf *m0, struct sockaddr *dst, if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); - if ((rt = rt0) != NULL) { - if ((rt->rt_flags & RTF_UP) == 0) { - if ((rt0 = rt = rtalloc(dst, RT_REPORT|RT_RESOLVE, - m->m_pkthdr.ph_rtableid)) != NULL) - rt->rt_refcnt--; - else - senderr(EHOSTUNREACH); - } - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_gwroute == NULL) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); - rt = rt0; - lookup: - rt->rt_gwroute = rtalloc(rt->rt_gateway, - RT_REPORT|RT_RESOLVE, ifp->if_rdomain); - if ((rt = rt->rt_gwroute) == NULL) - senderr(EHOSTUNREACH); - } - } - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || - time_second < rt->rt_rmx.rmx_expire) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } switch (dst->sa_family) { - case AF_INET: - if (!arpresolve(ac, rt, m, dst, edst)) - return (0); /* if not yet resolved */ + error = arpresolve(ac, rt, m, dst, edst); + if (error) + return (error == EAGAIN ? 0 : error); /* If broadcasting on a simplex interface, loopback a copy */ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && !m->m_pkthdr.pf.routed) @@ -323,8 +296,9 @@ ether_output(struct ifnet *ifp0, struct mbuf *m0, struct sockaddr *dst, break; #ifdef INET6 case AF_INET6: - if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) - return (0); /* it must be impossible, but... */ + error = nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst); + if (error) + return (error); etype = htons(ETHERTYPE_IPV6); break; #endif @@ -347,8 +321,9 @@ ether_output(struct ifnet *ifp0, struct mbuf *m0, struct sockaddr *dst, sizeof(edst)); break; case AF_INET: - if (!arpresolve(ac, rt, m, dst, edst)) - return (0); /* if not yet resolved */ + error = arpresolve(ac, rt, m, dst, edst); + if (error) + return (error == EAGAIN ? 0 : error); break; default: senderr(EHOSTUNREACH); diff --git a/sys/net/route.c b/sys/net/route.c index 05f56763c50..427656a13c7 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.196 2014/12/29 11:53:58 mpi Exp $ */ +/* $OpenBSD: route.c,v 1.197 2015/01/08 14:29:18 mpi Exp $ */ /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */ /* @@ -1032,6 +1032,45 @@ rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate, return (0); } +int +rt_checkgate(struct ifnet *ifp, struct rtentry *rt, struct sockaddr *dst, + unsigned int rtableid, struct rtentry **rtp) +{ + struct rtentry *rt0; + + KASSERT(rt != NULL); + + if ((rt->rt_flags & RTF_UP) == 0) { + rt = rtalloc(dst, RT_REPORT|RT_RESOLVE, rtableid); + rt->rt_refcnt--; + if (rt == NULL || rt->rt_ifp != ifp) + return (EHOSTUNREACH); + } + + rt0 = rt; + + if (rt->rt_flags & RTF_GATEWAY) { + if (rt->rt_gwroute && !(rt->rt_gwroute->rt_flags & RTF_UP)) { + rtfree(rt->rt_gwroute); + rt->rt_gwroute = NULL; + } + if (rt->rt_gwroute == NULL) { + rt->rt_gwroute = rtalloc(rt->rt_gateway, + RT_REPORT|RT_RESOLVE, rtableid); + if (rt->rt_gwroute == NULL) + return (EHOSTUNREACH); + } + rt = rt->rt_gwroute; + } + + if (rt->rt_flags & RTF_REJECT) + if (rt->rt_expire == 0 || time_second < rt->rt_expire) + return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); + + *rtp = rt; + return (0); +} + void rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) diff --git a/sys/net/route.h b/sys/net/route.h index c48905bf4f2..6fb9659b2cf 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -1,4 +1,4 @@ -/* $OpenBSD: route.h,v 1.101 2014/11/24 12:43:54 mpi Exp $ */ +/* $OpenBSD: route.h,v 1.102 2015/01/08 14:29:18 mpi Exp $ */ /* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */ /* @@ -113,7 +113,8 @@ struct rtentry { u_int16_t rt_labelid; /* route label ID */ u_int8_t rt_priority; /* routing priority to use */ }; -#define rt_use rt_rmx.rmx_pksent +#define rt_use rt_rmx.rmx_pksent +#define rt_expire rt_rmx.rmx_expire #endif /* _KERNEL */ @@ -360,6 +361,8 @@ void rt_missmsg(int, struct rt_addrinfo *, int, struct ifnet *, int, void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *); int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *, u_int); +int rt_checkgate(struct ifnet *, struct rtentry *, struct sockaddr *, + unsigned int, struct rtentry **); void rt_setmetrics(u_long, struct rt_metrics *, struct rt_kmetrics *); void rt_getmetrics(struct rt_kmetrics *, struct rt_metrics *); |