summaryrefslogtreecommitdiffstats
path: root/sys/netinet/in.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/in.c')
-rw-r--r--sys/netinet/in.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index c2e43cc..da4e8a0 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -1439,14 +1439,43 @@ in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr
if (memcmp(rt->rt_gateway->sa_data, l3addr->sa_data,
sizeof(in_addr_t)) != 0)
error = EINVAL;
- } else if (!(flags & LLE_PUB) && ((rt->rt_flags & RTF_GATEWAY) ||
- (rt->rt_ifp != ifp))) {
+ }
+
+ if (rt->rt_flags & RTF_GATEWAY) {
+ RTFREE_LOCKED(rt);
+ return (EINVAL);
+ }
+
+ /*
+ * Make sure that at least the destination address is covered
+ * by the route. This is for handling the case where 2 or more
+ * interfaces have the same prefix. An incoming packet arrives
+ * on one interface and the corresponding outgoing packet leaves
+ * another interface.
+ *
+ */
+ if (rt->rt_ifp != ifp) {
+ char *sa, *mask, *addr, *lim;
+ int len;
+
+ sa = (char *)rt_key(rt);
+ mask = (char *)rt_mask(rt);
+ addr = (char *)__DECONST(struct sockaddr *, l3addr);
+ len = ((struct sockaddr_in *)__DECONST(struct sockaddr *, l3addr))->sin_len;
+ lim = addr + len;
+
+ for ( ; addr < lim; sa++, mask++, addr++) {
+ if ((*sa ^ *addr) & *mask) {
+ error = EINVAL;
#ifdef DIAGNOSTIC
- log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
- inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
+ log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
+ inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
#endif
- error = EINVAL;
+ break;
+ }
+ }
}
+
RTFREE_LOCKED(rt);
return (error);
}
OpenPOWER on IntegriCloud