diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-06-24 10:33:35 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-06-24 10:33:35 +0000 |
commit | 4bbf479ced91674e3eea5636ffc8e776fa1d741c (patch) | |
tree | e96015b37ef97bddbf925bdc5f77a211b5e1c76f /sys | |
parent | 16b92db4cdd4f185b371177716f4b58594612d20 (diff) | |
download | FreeBSD-src-4bbf479ced91674e3eea5636ffc8e776fa1d741c.zip FreeBSD-src-4bbf479ced91674e3eea5636ffc8e776fa1d741c.tar.gz |
In ARP input, more consistently acquire and release ifaddr references.
MFC after: 6 weeks
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/if_ether.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 91172ba..a8cfe45 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -512,13 +512,16 @@ in_arpinput(struct mbuf *m) LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { if (((bridged && ia->ia_ifp->if_bridge != NULL) || ia->ia_ifp == ifp) && - itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) + itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { + ifa_ref(&ia->ia_ifa); goto match; + } #ifdef DEV_CARP if (ifp->if_carp != NULL && carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { carp_match = 1; + ifa_ref(&ia->ia_ifa); goto match; } #endif @@ -526,8 +529,10 @@ in_arpinput(struct mbuf *m) LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) if (((bridged && ia->ia_ifp->if_bridge != NULL) || ia->ia_ifp == ifp) && - isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) + isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { + ifa_ref(&ia->ia_ifa); goto match; + } #define BDG_MEMBER_MATCHES_ARP(addr, ifp, ia) \ (ia->ia_ifp->if_bridge == ifp->if_softc && \ @@ -542,6 +547,7 @@ in_arpinput(struct mbuf *m) if (is_bridge) { LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia)) { + ifa_ref(&ia->ia_ifa); ifp = ia->ia_ifp; goto match; } @@ -553,20 +559,26 @@ in_arpinput(struct mbuf *m) * No match, use the first inet address on the receive interface * as a dummy address for the rest of the function. */ + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET) { ia = ifatoia(ifa); + ifa_ref(ifa); goto match; } + IF_ADDR_UNLOCK(ifp); + /* * If bridging, fall back to using any inet address. */ if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL) goto drop; + ifa_ref(&ia->ia_ifa); match: if (!enaddr) enaddr = (u_int8_t *)IF_LLADDR(ifp); myaddr = ia->ia_addr.sin_addr; + ifa_free(&ia->ia_ifa); if (!bcmp(ar_sha(ah), enaddr, ifp->if_addrlen)) goto drop; /* it's from me, ignore it. */ if (!bcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) { |