summaryrefslogtreecommitdiff
path: root/sys/net/route.c
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/route.c
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/route.c')
-rw-r--r--sys/net/route.c41
1 files changed, 40 insertions, 1 deletions
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)