diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-04-20 21:37:46 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-04-20 21:37:46 +0000 |
commit | 6fc60785e72960c0c2c1b7cda150d79811e9dab9 (patch) | |
tree | 9a698ac1753a7414dd68d56d32bf69d1bf432607 | |
parent | 084ce14c28bf83c651c7963eacdea97f7f32d914 (diff) | |
download | FreeBSD-src-6fc60785e72960c0c2c1b7cda150d79811e9dab9.zip FreeBSD-src-6fc60785e72960c0c2c1b7cda150d79811e9dab9.tar.gz |
Acquire interface address list lock around access to if_addrhead,
closing several writer-writer races, and some read-write races.
MFC after: 2 weeks
-rw-r--r-- | sys/netinet6/in6.c | 2 | ||||
-rw-r--r-- | sys/netinet6/in6_ifattach.c | 32 | ||||
-rw-r--r-- | sys/netinet6/nd6.c | 4 | ||||
-rw-r--r-- | sys/netinet6/nd6_rtr.c | 10 |
4 files changed, 40 insertions, 8 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 662cdc5..cc64ff1 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1653,12 +1653,14 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr) { struct ifaddr *ifa; + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) break; } + IF_ADDR_UNLOCK(ifp); return ((struct in6_ifaddr *)ifa); } diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 4cf4862..2c11ca9 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -233,6 +233,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) static u_int8_t allone[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; @@ -244,6 +245,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) goto found; } + IF_ADDR_UNLOCK(ifp); return -1; @@ -267,18 +269,24 @@ found: addrlen = 8; /* look at IEEE802/EUI64 only */ - if (addrlen != 8 && addrlen != 6) + if (addrlen != 8 && addrlen != 6) { + IF_ADDR_UNLOCK(ifp); return -1; + } /* * check for invalid MAC address - on bsdi, we see it a lot * since wildboar configures all-zero MAC on pccard before * card insertion. */ - if (bcmp(addr, allzero, addrlen) == 0) + if (bcmp(addr, allzero, addrlen) == 0) { + IF_ADDR_UNLOCK(ifp); return -1; - if (bcmp(addr, allone, addrlen) == 0) + } + if (bcmp(addr, allone, addrlen) == 0) { + IF_ADDR_UNLOCK(ifp); return -1; + } /* make EUI64 address */ if (addrlen == 8) @@ -296,10 +304,14 @@ found: break; case IFT_ARCNET: - if (addrlen != 1) + if (addrlen != 1) { + IF_ADDR_UNLOCK(ifp); return -1; - if (!addr[0]) + } + if (!addr[0]) { + IF_ADDR_UNLOCK(ifp); return -1; + } bzero(&in6->s6_addr[8], 8); in6->s6_addr[15] = addr[0]; @@ -321,15 +333,19 @@ found: * identifier source (can be renumbered). * we don't do this. */ + IF_ADDR_UNLOCK(ifp); return -1; default: + IF_ADDR_UNLOCK(ifp); return -1; } /* sanity check: g bit must not indicate "group" */ - if (EUI64_GROUP(in6)) + if (EUI64_GROUP(in6)) { + IF_ADDR_UNLOCK(ifp); return -1; + } /* convert EUI64 into IPv6 interface identifier */ EUI64_TO_IFID(in6); @@ -340,9 +356,11 @@ found: */ if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && bcmp(&in6->s6_addr[9], allzero, 7) == 0) { + IF_ADDR_UNLOCK(ifp); return -1; } + IF_ADDR_UNLOCK(ifp); return 0; } @@ -783,7 +801,9 @@ in6_ifdetach(struct ifnet *ifp) } /* remove from the linked list */ + IF_ADDR_LOCK(ifp); TAILQ_REMOVE(&ifp->if_addrhead, (struct ifaddr *)ia, ifa_list); + IF_ADDR_UNLOCK(ifp); IFAFREE(&ia->ia_ifa); /* also remove from the IPv6 address chain(itojun&jinmei) */ diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index a6b7974..0dd6900 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -727,6 +727,7 @@ regen_tmpaddr(struct in6_ifaddr *ia6) struct in6_ifaddr *public_ifa6 = NULL; ifp = ia6->ia_ifa.ifa_ifp; + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) { struct in6_ifaddr *it6; @@ -770,13 +771,16 @@ regen_tmpaddr(struct in6_ifaddr *ia6) int e; if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { + IF_ADDR_UNLOCK(ifp); log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" " tmp addr,errno=%d\n", e); return (-1); } + IF_ADDR_UNLOCK(ifp); return (0); } + IF_ADDR_UNLOCK(ifp); return (-1); } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 525bfba..33807bc 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -435,14 +435,18 @@ static void nd6_rtmsg(int cmd, struct rtentry *rt) { struct rt_addrinfo info; + struct ifnet *ifp; bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 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] = - 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; } @@ -1120,6 +1124,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, * consider autoconfigured addresses while RFC2462 simply said * "address". */ + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_list) { struct in6_ifaddr *ifa6; 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_updatetime = time_second; } + IF_ADDR_UNLOCK(ifp); if (ia6_match == NULL && new->ndpr_vltime) { int ifidlen; |