Acquire interface address list lock around access to if_addrhead,

closing several writer-writer races, and some read-write races.

MFC after:	2 weeks
This commit is contained in:
Robert Watson 2009-04-20 21:37:46 +00:00
parent f68ffa034b
commit 1e6a41398c
4 changed files with 40 additions and 8 deletions

View File

@ -1653,12 +1653,14 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
{ {
struct ifaddr *ifa; struct ifaddr *ifa;
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) { TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) {
if (ifa->ifa_addr->sa_family != AF_INET6) if (ifa->ifa_addr->sa_family != AF_INET6)
continue; continue;
if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
break; break;
} }
IF_ADDR_UNLOCK(ifp);
return ((struct in6_ifaddr *)ifa); return ((struct in6_ifaddr *)ifa);
} }

View File

@ -233,6 +233,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
static u_int8_t allone[8] = static u_int8_t allone[8] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) { TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) {
if (ifa->ifa_addr->sa_family != AF_LINK) if (ifa->ifa_addr->sa_family != AF_LINK)
continue; continue;
@ -244,6 +245,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
goto found; goto found;
} }
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
@ -267,18 +269,24 @@ found:
addrlen = 8; addrlen = 8;
/* look at IEEE802/EUI64 only */ /* look at IEEE802/EUI64 only */
if (addrlen != 8 && addrlen != 6) if (addrlen != 8 && addrlen != 6) {
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
}
/* /*
* check for invalid MAC address - on bsdi, we see it a lot * check for invalid MAC address - on bsdi, we see it a lot
* since wildboar configures all-zero MAC on pccard before * since wildboar configures all-zero MAC on pccard before
* card insertion. * card insertion.
*/ */
if (bcmp(addr, allzero, addrlen) == 0) if (bcmp(addr, allzero, addrlen) == 0) {
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
if (bcmp(addr, allone, addrlen) == 0) }
if (bcmp(addr, allone, addrlen) == 0) {
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
}
/* make EUI64 address */ /* make EUI64 address */
if (addrlen == 8) if (addrlen == 8)
@ -296,10 +304,14 @@ found:
break; break;
case IFT_ARCNET: case IFT_ARCNET:
if (addrlen != 1) if (addrlen != 1) {
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
if (!addr[0]) }
if (!addr[0]) {
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
}
bzero(&in6->s6_addr[8], 8); bzero(&in6->s6_addr[8], 8);
in6->s6_addr[15] = addr[0]; in6->s6_addr[15] = addr[0];
@ -321,15 +333,19 @@ found:
* identifier source (can be renumbered). * identifier source (can be renumbered).
* we don't do this. * we don't do this.
*/ */
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
default: default:
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
} }
/* sanity check: g bit must not indicate "group" */ /* sanity check: g bit must not indicate "group" */
if (EUI64_GROUP(in6)) if (EUI64_GROUP(in6)) {
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
}
/* convert EUI64 into IPv6 interface identifier */ /* convert EUI64 into IPv6 interface identifier */
EUI64_TO_IFID(in6); EUI64_TO_IFID(in6);
@ -340,9 +356,11 @@ found:
*/ */
if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
bcmp(&in6->s6_addr[9], allzero, 7) == 0) { bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
IF_ADDR_UNLOCK(ifp);
return -1; return -1;
} }
IF_ADDR_UNLOCK(ifp);
return 0; return 0;
} }
@ -783,7 +801,9 @@ in6_ifdetach(struct ifnet *ifp)
} }
/* remove from the linked list */ /* remove from the linked list */
IF_ADDR_LOCK(ifp);
TAILQ_REMOVE(&ifp->if_addrhead, (struct ifaddr *)ia, ifa_list); TAILQ_REMOVE(&ifp->if_addrhead, (struct ifaddr *)ia, ifa_list);
IF_ADDR_UNLOCK(ifp);
IFAFREE(&ia->ia_ifa); IFAFREE(&ia->ia_ifa);
/* also remove from the IPv6 address chain(itojun&jinmei) */ /* also remove from the IPv6 address chain(itojun&jinmei) */

View File

@ -727,6 +727,7 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
struct in6_ifaddr *public_ifa6 = NULL; struct in6_ifaddr *public_ifa6 = NULL;
ifp = ia6->ia_ifa.ifa_ifp; ifp = ia6->ia_ifa.ifa_ifp;
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) { TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) {
struct in6_ifaddr *it6; struct in6_ifaddr *it6;
@ -770,13 +771,16 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
int e; int e;
if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) {
IF_ADDR_UNLOCK(ifp);
log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"
" tmp addr,errno=%d\n", e); " tmp addr,errno=%d\n", e);
return (-1); return (-1);
} }
IF_ADDR_UNLOCK(ifp);
return (0); return (0);
} }
IF_ADDR_UNLOCK(ifp);
return (-1); return (-1);
} }

View File

@ -435,14 +435,18 @@ static void
nd6_rtmsg(int cmd, struct rtentry *rt) nd6_rtmsg(int cmd, struct rtentry *rt)
{ {
struct rt_addrinfo info; struct rt_addrinfo info;
struct ifnet *ifp;
bzero((caddr_t)&info, sizeof(info)); bzero((caddr_t)&info, sizeof(info));
info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_DST] = rt_key(rt);
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
info.rti_info[RTAX_NETMASK] = rt_mask(rt); info.rti_info[RTAX_NETMASK] = rt_mask(rt);
if (rt->rt_ifp) { ifp = rt->rt_ifp;
if (ifp != NULL) {
IF_ADDR_LOCK(ifp);
info.rti_info[RTAX_IFP] = info.rti_info[RTAX_IFP] =
TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr; TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
IF_ADDR_UNLOCK(ifp);
info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
} }
@ -1120,6 +1124,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
* consider autoconfigured addresses while RFC2462 simply said * consider autoconfigured addresses while RFC2462 simply said
* "address". * "address".
*/ */
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) { TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) {
struct in6_ifaddr *ifa6; struct in6_ifaddr *ifa6;
u_int32_t remaininglifetime; u_int32_t remaininglifetime;
@ -1242,6 +1247,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
ifa6->ia6_lifetime = lt6_tmp; ifa6->ia6_lifetime = lt6_tmp;
ifa6->ia6_updatetime = time_second; ifa6->ia6_updatetime = time_second;
} }
IF_ADDR_UNLOCK(ifp);
if (ia6_match == NULL && new->ndpr_vltime) { if (ia6_match == NULL && new->ndpr_vltime) {
int ifidlen; int ifidlen;