diff options
author | qingli <qingli@FreeBSD.org> | 2011-10-03 19:06:55 +0000 |
---|---|---|
committer | qingli <qingli@FreeBSD.org> | 2011-10-03 19:06:55 +0000 |
commit | f48490efae16713c890edce5fb2544d9847beaf3 (patch) | |
tree | d43410f8223f174b54388ff0ec9b49e5e404c896 /sys/netinet | |
parent | 2a8b804b9c089b204002d07853a836789c157899 (diff) | |
download | FreeBSD-src-f48490efae16713c890edce5fb2544d9847beaf3.zip FreeBSD-src-f48490efae16713c890edce5fb2544d9847beaf3.tar.gz |
This patch allows ARP to work properly in the presence of
self-referencing routes. This patch is a rework of r223862.
Reviewed by: bz, zec
MFC after: 5 days
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in.c | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 4547e39..c2e43cc 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -1411,6 +1411,8 @@ static int in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr) { struct rtentry *rt; + struct ifnet *xifp; + int error = 0; KASSERT(l3addr->sa_family == AF_INET, ("sin_family %d", l3addr->sa_family)); @@ -1418,30 +1420,35 @@ in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr /* XXX rtalloc1 should take a const param */ rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0); + if (rt == NULL) + return (EINVAL); + /* * If the gateway for an existing host route matches the target L3 - * address, allow for ARP to proceed. + * address, which is a special route inserted by some implementation + * such as MANET, and the interface is of the correct type, then + * allow for ARP to proceed. */ - if (rt != NULL && (rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) && - rt->rt_gateway->sa_family == AF_INET && - memcmp(rt->rt_gateway->sa_data, l3addr->sa_data, 4) == 0) { - RTFREE_LOCKED(rt); - return (0); - } + if (rt->rt_flags & (RTF_GATEWAY | RTF_HOST)) { + xifp = rt->rt_ifp; + + if (xifp && (xifp->if_type != IFT_ETHER || + (xifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0)) + error = EINVAL; - if (rt == NULL || (!(flags & LLE_PUB) && - ((rt->rt_flags & RTF_GATEWAY) || - (rt->rt_ifp != ifp)))) { + 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))) { #ifdef DIAGNOSTIC log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n", inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr)); #endif - if (rt != NULL) - RTFREE_LOCKED(rt); - return (EINVAL); + error = EINVAL; } RTFREE_LOCKED(rt); - return 0; + return (error); } /* |