svn commit: r191337 - head/sys/netinet6

Robert Watson rwatson at FreeBSD.org
Mon Apr 20 21:37:47 UTC 2009


Author: rwatson
Date: Mon Apr 20 21:37:46 2009
New Revision: 191337
URL: http://svn.freebsd.org/changeset/base/191337

Log:
  Acquire interface address list lock around access to if_addrhead,
  closing several writer-writer races, and some read-write races.
  
  MFC after:	2 weeks

Modified:
  head/sys/netinet6/in6.c
  head/sys/netinet6/in6_ifattach.c
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6_rtr.c

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Mon Apr 20 21:05:37 2009	(r191336)
+++ head/sys/netinet6/in6.c	Mon Apr 20 21:37:46 2009	(r191337)
@@ -1653,12 +1653,14 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, st
 {
 	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);
 }

Modified: head/sys/netinet6/in6_ifattach.c
==============================================================================
--- head/sys/netinet6/in6_ifattach.c	Mon Apr 20 21:05:37 2009	(r191336)
+++ head/sys/netinet6/in6_ifattach.c	Mon Apr 20 21:37:46 2009	(r191337)
@@ -233,6 +233,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struc
 	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, struc
 
 		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) */

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Mon Apr 20 21:05:37 2009	(r191336)
+++ head/sys/netinet6/nd6.c	Mon Apr 20 21:37:46 2009	(r191337)
@@ -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);
 }
 

Modified: head/sys/netinet6/nd6_rtr.c
==============================================================================
--- head/sys/netinet6/nd6_rtr.c	Mon Apr 20 21:05:37 2009	(r191336)
+++ head/sys/netinet6/nd6_rtr.c	Mon Apr 20 21:37:46 2009	(r191337)
@@ -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,
 	 * 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,
 		ifa6->ia6_lifetime = lt6_tmp;
 		ifa6->ia6_updatetime = time_second;
 	}
+	IF_ADDR_UNLOCK(ifp);
 	if (ia6_match == NULL && new->ndpr_vltime) {
 		int ifidlen;
 


More information about the svn-src-all mailing list