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
This commit is contained in:
Robert Watson 2009-04-21 19:06:47 +00:00
parent 0cd51de155
commit ab5ed8a5aa
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=191365

View File

@ -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 @@ ifconf(u_long cmd, caddr_t data)
}
addrs = 0;
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
struct sockaddr *sa = ifa->ifa_addr;
@ -2357,6 +2382,7 @@ ifconf(u_long cmd, caddr_t data)
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));