summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2015-01-08 14:29:19 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2015-01-08 14:29:19 +0000
commit6571bb75613e41eb1a6ea1f65cc04b539cb7159e (patch)
tree18641ce38c4950cbd3a5f04bb0410fc04e8bd094 /sys/net
parent4d3e239b7078bc404f29d5f8d6a584a1e6716f20 (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.c47
-rw-r--r--sys/net/route.c41
-rw-r--r--sys/net/route.h7
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 *);