diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-04-21 19:06:47 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-04-21 19:06:47 +0000 |
commit | 72b01124b7c13e20360c6a772667b8d7fd551556 (patch) | |
tree | a3ab54562c353908994ed481dd0a12599aaa0434 | |
parent | 657f6b7fcd165570b0303362ce9e16a788c97477 (diff) | |
download | FreeBSD-src-72b01124b7c13e20360c6a772667b8d7fd551556.zip FreeBSD-src-72b01124b7c13e20360c6a772667b8d7fd551556.tar.gz |
Acquire the interface address list lock over some iterations over
if_addrhead. This closes some reader-writer races associated with
the address list.
MFC after: 2 weeks
-rw-r--r-- | sys/net/if.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 5c422c1..457b763 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1249,19 +1249,26 @@ ifa_ifwithaddr(struct sockaddr *addr) struct ifaddr *ifa; IFNET_RLOCK(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) + TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; - if (sa_equal(addr, ifa->ifa_addr)) + if (sa_equal(addr, ifa->ifa_addr)) { + IF_ADDR_UNLOCK(ifp); goto done; + } /* IP6 doesn't have broadcast */ if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && ifa->ifa_broadaddr->sa_len != 0 && - sa_equal(ifa->ifa_broadaddr, addr)) + sa_equal(ifa->ifa_broadaddr, addr)) { + IF_ADDR_UNLOCK(ifp); goto done; + } } + IF_ADDR_UNLOCK(ifp); + } ifa = NULL; done: IFNET_RUNLOCK(); @@ -1280,16 +1287,21 @@ ifa_ifwithbroadaddr(struct sockaddr *addr) struct ifaddr *ifa; IFNET_RLOCK(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) + TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && ifa->ifa_broadaddr->sa_len != 0 && - sa_equal(ifa->ifa_broadaddr, addr)) + sa_equal(ifa->ifa_broadaddr, addr)) { + IF_ADDR_UNLOCK(ifp); goto done; + } } + IF_ADDR_UNLOCK(ifp); + } ifa = NULL; done: IFNET_RUNLOCK(); @@ -1311,13 +1323,17 @@ ifa_ifwithdstaddr(struct sockaddr *addr) TAILQ_FOREACH(ifp, &V_ifnet, if_link) { if ((ifp->if_flags & IFF_POINTOPOINT) == 0) continue; + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if (ifa->ifa_dstaddr != NULL && - sa_equal(addr, ifa->ifa_dstaddr)) + sa_equal(addr, ifa->ifa_dstaddr)) { + IF_ADDR_UNLOCK(ifp); goto done; + } } + IF_ADDR_UNLOCK(ifp); } ifa = NULL; done: @@ -1355,6 +1371,7 @@ ifa_ifwithnet(struct sockaddr *addr) */ IFNET_RLOCK(); TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { char *cp, *cp2, *cp3; @@ -1370,16 +1387,20 @@ next: continue; * netmask for the remote end. */ if (ifa->ifa_dstaddr != NULL && - sa_equal(addr, ifa->ifa_dstaddr)) + sa_equal(addr, ifa->ifa_dstaddr)) { + IF_ADDR_UNLOCK(ifp); goto done; + } } else { /* * if we have a special address handler, * then use it instead of the generic one. */ if (ifa->ifa_claim_addr) { - if ((*ifa->ifa_claim_addr)(ifa, addr)) + if ((*ifa->ifa_claim_addr)(ifa, addr)) { + IF_ADDR_UNLOCK(ifp); goto done; + } continue; } @@ -1413,6 +1434,7 @@ next: continue; ifa_maybe = ifa; } } + IF_ADDR_UNLOCK(ifp); } ifa = ifa_maybe; done: @@ -1435,6 +1457,7 @@ ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp) if (af >= AF_MAX) return (0); + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != af) continue; @@ -1464,6 +1487,7 @@ ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp) } ifa = ifa_maybe; done: + IF_ADDR_UNLOCK(ifp); return (ifa); } @@ -2326,6 +2350,7 @@ again: } addrs = 0; + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct sockaddr *sa = ifa->ifa_addr; @@ -2357,6 +2382,7 @@ again: if (!sbuf_overflowed(sb)) valid_len = sbuf_len(sb); } + IF_ADDR_UNLOCK(ifp); if (addrs == 0) { bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); sbuf_bcat(sb, &ifr, sizeof(ifr)); |