--- //depot/projects/netperf_socket/sys/netinet/ip_encap.c	2004/01/18 09:46:57
+++ //depot/user/rwatson/netperf/sys/netinet/ip_encap.c	2004/03/09 16:02:59
@@ -98,31 +98,19 @@
 		const struct sockaddr *);
 static void encap_fillarg(struct mbuf *, const struct encaptab *);
 
-#ifndef LIST_HEAD_INITIALIZER
-/* rely upon BSS initialization */
-LIST_HEAD(, encaptab) encaptab;
-#else
+/*
+ * All global variables in ip_encap.c are locked using encapmtx.
+ */
+static struct mtx encapmtx;
+MTX_SYSINIT(encapmtx, &encapmtx, "encapmtx", MTX_DEF);
 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
-#endif
 
+/*
+ * XXXRW: encap_init() was entirely useless, so I deleted it.
+ */
 void
 encap_init()
 {
-	static int initialized = 0;
-
-	if (initialized)
-		return;
-	initialized++;
-#if 0
-	/*
-	 * we cannot use LIST_INIT() here, since drivers may want to call
-	 * encap_attach(), on driver attach.  encap_init() will be called
-	 * on AF_INET{,6} initialization, which happens after driver
-	 * initialization - using LIST_INIT() here can nuke encap_attach()
-	 * from drivers.
-	 */
-	LIST_INIT(&encaptab);
-#endif
 }
 
 #ifdef INET
@@ -152,6 +140,7 @@
 
 	match = NULL;
 	matchprio = 0;
+	mtx_lock(&encapmtx);
 	LIST_FOREACH(ep, &encaptab, chain) {
 		if (ep->af != AF_INET)
 			continue;
@@ -193,7 +182,12 @@
 			match = ep;
 		}
 	}
+	mtx_unlock(&encapmtx);
 
+	/*
+	 * XXXRW: Need drain mechanism to prevent the encapsulation
+	 * entry from being released while in use.
+	 */
 	if (match) {
 		/* found a match, "match" has the best one */
 		psw = match->psw;
@@ -237,6 +231,7 @@
 
 	match = NULL;
 	matchprio = 0;
+	mtx_lock(&encapmtx);
 	LIST_FOREACH(ep, &encaptab, chain) {
 		if (ep->af != AF_INET6)
 			continue;
@@ -261,7 +256,12 @@
 			match = ep;
 		}
 	}
+	mtx_unlock(&encapmtx);
 
+	/*
+	 * XXXRW: Need drain mechanism so the encap entry isn't freed
+	 * while in use.
+	 */
 	if (match) {
 		/* found a match */
 		psw = (const struct ip6protosw *)match->psw;
@@ -285,6 +285,7 @@
 	struct encaptab *ep;
 {
 
+	mtx_assert(&encapmtx, MA_OWNED);
 	LIST_INSERT_HEAD(&encaptab, ep, chain);
 }
 
@@ -303,21 +304,17 @@
 	void *arg;
 {
 	struct encaptab *ep;
-	int s;
 
-	s = splnet();
 	/* sanity check on args */
-	if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst)) {
-		goto fail;
-	}
-	if (sp->sa_len != dp->sa_len) {
-		goto fail;
-	}
-	if (af != sp->sa_family || af != dp->sa_family) {
-		goto fail;
-	}
+	if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst))
+		return (NULL);
+	if (sp->sa_len != dp->sa_len)
+		return (NULL);
+	if (af != sp->sa_family || af != dp->sa_family)
+		return (NULL);
 
 	/* check if anyone have already attached with exactly same config */
+	mtx_lock(&encapmtx);
 	LIST_FOREACH(ep, &encaptab, chain) {
 		if (ep->af != af)
 			continue;
@@ -332,12 +329,14 @@
 		    bcmp(&ep->dstmask, dm, dp->sa_len) != 0)
 			continue;
 
-		goto fail;
+		mtx_unlock(&encapmtx);
+		return (NULL);
 	}
 
 	ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);	/*XXX*/
 	if (ep == NULL) {
-		goto fail;
+		mtx_unlock(&encapmtx);
+		return (NULL);
 	}
 	bzero(ep, sizeof(*ep));
 
@@ -351,13 +350,8 @@
 	ep->arg = arg;
 
 	encap_add(ep);
-
-	splx(s);
-	return ep;
-
-fail:
-	splx(s);
-	return NULL;
+	mtx_unlock(&encapmtx);
+	return (ep);
 }
 
 const struct encaptab *
@@ -369,16 +363,14 @@
 	void *arg;
 {
 	struct encaptab *ep;
-	int s;
 
-	s = splnet();
 	/* sanity check on args */
 	if (!func)
-		goto fail;
+		return (NULL);
 
 	ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);	/*XXX*/
 	if (ep == NULL)
-		goto fail;
+		return (NULL);
 	bzero(ep, sizeof(*ep));
 
 	ep->af = af;
@@ -387,14 +379,10 @@
 	ep->psw = psw;
 	ep->arg = arg;
 
+	mtx_lock(&encapmtx);
 	encap_add(ep);
-
-	splx(s);
-	return ep;
-
-fail:
-	splx(s);
-	return NULL;
+	mtx_unlock(&encapmtx);
+	return (ep);
 }
 
 int
@@ -404,13 +392,16 @@
 	const struct encaptab *ep = cookie;
 	struct encaptab *p;
 
+	mtx_lock(&encapmtx);
 	LIST_FOREACH(p, &encaptab, chain) {
 		if (p == ep) {
 			LIST_REMOVE(p, chain);
+			mtx_unlock(&encapmtx);
 			free(p, M_NETADDR);	/*XXX*/
 			return 0;
 		}
 	}
+	mtx_unlock(&encapmtx);
 
 	return EINVAL;
 }
