Index: frag6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/frag6.c,v
retrieving revision 1.16
diff -u -r1.16 frag6.c
--- frag6.c	7 Oct 2003 17:46:18 -0000	1.16
+++ frag6.c	19 Oct 2003 19:54:36 -0000
@@ -34,8 +34,10 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
+#include <sys/mutex.h>
 #include <sys/domain.h>
 #include <sys/protosw.h>
 #include <sys/socket.h>
@@ -68,10 +70,18 @@
 static void frag6_remque __P((struct ip6q *));
 static void frag6_freef __P((struct ip6q *));
 
-/* XXX we eventually need splreass6, or some real semaphore */
-int frag6_doing_reass;
-u_int frag6_nfragpackets;
-struct	ip6q ip6q;	/* ip6 reassemble queue */
+static struct mtx ip6qlock;
+#define	IP6Q_LOCK_INIT()	mtx_init(&ip6qlock, "ip6qlock", NULL, MTX_DEF);
+#define	IP6Q_LOCK()		mtx_lock(&ip6qlock);
+#define	IP6Q_UNLOCK()		mtx_unlock(&ip6qlock);
+#define	IP6Q_LOCK_ASSERT()	mtx_assert(&ip6qlock, MA_OWNED);
+
+/*
+ * These fields all protected by ip6qlock.
+ */
+static int frag6_doing_reass;
+static u_int frag6_nfragpackets;
+static struct	ip6q ip6q;	/* ip6 reassemble queue */
 
 /* FreeBSD tweak */
 static MALLOC_DEFINE(M_FTABLE, "fragment", "fragment reassembly header");
@@ -84,7 +94,7 @@
 {
 
 	ip6_maxfragpackets = nmbclusters / 4;
-
+	IP6Q_LOCK_INIT();
 #ifndef RANDOM_IP_ID
 	ip6_id = arc4random();
 #endif
@@ -204,6 +214,7 @@
 	/* offset now points to data portion */
 	offset += sizeof(struct ip6_frag);
 
+	IP6Q_LOCK();
 	frag6_doing_reass = 1;
 
 	for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
@@ -274,6 +285,7 @@
 			    offset - sizeof(struct ip6_frag) +
 			    offsetof(struct ip6_frag, ip6f_offlg));
 			frag6_doing_reass = 0;
+			IP6Q_UNLOCK();
 			return (IPPROTO_DONE);
 		}
 	} else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
@@ -281,6 +293,7 @@
 		    offset - sizeof(struct ip6_frag) +
 		    offsetof(struct ip6_frag, ip6f_offlg));
 		frag6_doing_reass = 0;
+		IP6Q_UNLOCK();
 		return (IPPROTO_DONE);
 	}
 	/*
@@ -436,12 +449,14 @@
 	     af6 = af6->ip6af_down) {
 		if (af6->ip6af_off != next) {
 			frag6_doing_reass = 0;
+			IP6Q_UNLOCK();
 			return IPPROTO_DONE;
 		}
 		next += af6->ip6af_frglen;
 	}
 	if (af6->ip6af_up->ip6af_mff) {
 		frag6_doing_reass = 0;
+		IP6Q_UNLOCK();
 		return IPPROTO_DONE;
 	}
 
@@ -525,13 +540,15 @@
 	*offp = offset;
 
 	frag6_doing_reass = 0;
+	IP6Q_UNLOCK();
 	return nxt;
 
  dropfrag:
+	frag6_doing_reass = 0;
+	IP6Q_UNLOCK();
 	in6_ifstat_inc(dstifp, ifs6_reass_fail);
 	ip6stat.ip6s_fragdropped++;
 	m_freem(m);
-	frag6_doing_reass = 0;
 	return IPPROTO_DONE;
 }
 
@@ -545,6 +562,7 @@
 {
 	struct ip6asfrag *af6, *down6;
 
+	IP6Q_LOCK_ASSERT();
 	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
 	     af6 = down6) {
 		struct mbuf *m = IP6_REASS_MBUF(af6);
@@ -585,6 +603,8 @@
 frag6_enq(af6, up6)
 	struct ip6asfrag *af6, *up6;
 {
+
+	IP6Q_LOCK_ASSERT();
 	af6->ip6af_up = up6;
 	af6->ip6af_down = up6->ip6af_down;
 	up6->ip6af_down->ip6af_up = af6;
@@ -598,6 +618,8 @@
 frag6_deq(af6)
 	struct ip6asfrag *af6;
 {
+
+	IP6Q_LOCK_ASSERT();
 	af6->ip6af_up->ip6af_down = af6->ip6af_down;
 	af6->ip6af_down->ip6af_up = af6->ip6af_up;
 }
@@ -606,6 +628,8 @@
 frag6_insque(new, old)
 	struct ip6q *new, *old;
 {
+
+	IP6Q_LOCK_ASSERT();
 	new->ip6q_prev = old;
 	new->ip6q_next = old->ip6q_next;
 	old->ip6q_next->ip6q_prev= new;
@@ -616,6 +640,8 @@
 frag6_remque(p6)
 	struct ip6q *p6;
 {
+
+	IP6Q_LOCK_ASSERT();
 	p6->ip6q_prev->ip6q_next = p6->ip6q_next;
 	p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
 }
@@ -631,6 +657,7 @@
 	struct ip6q *q6;
 	int s = splnet();
 
+	IP6Q_LOCK();
 	frag6_doing_reass = 1;
 	q6 = ip6q.ip6q_next;
 	if (q6)
@@ -655,6 +682,7 @@
 		frag6_freef(ip6q.ip6q_prev);
 	}
 	frag6_doing_reass = 0;
+	IP6Q_UNLOCK();
 
 #if 0
 	/*
@@ -681,11 +709,16 @@
 void
 frag6_drain()
 {
-	if (frag6_doing_reass)
+
+	IP6Q_LOCK();
+	if (frag6_doing_reass) {
+		IP6Q_UNLOCK();
 		return;
+	}
 	while (ip6q.ip6q_next != &ip6q) {
 		ip6stat.ip6s_fragdropped++;
 		/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
 		frag6_freef(ip6q.ip6q_next);
 	}
+	IP6Q_UNLOCK();
 }
Index: scope6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/scope6.c,v
retrieving revision 1.8
diff -u -r1.8 scope6.c
--- scope6.c	17 Oct 2003 15:46:31 -0000	1.8
+++ scope6.c	19 Oct 2003 20:28:51 -0000
@@ -45,6 +45,16 @@
 #include <netinet6/in6_var.h>
 #include <netinet6/scope6_var.h>
 
+/*
+ * The scope6_lock protects both the global sid default stored in
+ * sid_default below, but also per-interface sid data.
+ */
+static struct mtx scope6_lock;
+#define	SCOPE6_LOCK_INIT()	mtx_init(&scope6_lock, "scope6_lock", NULL, MTX_DEF);
+#define	SCOPE6_LOCK()		mtx_lock(&scope6_lock);
+#define	SCOPE6_UNLOCK()		mtx_unlock(&scope6_lock);
+#define	SCOPE6_LOCK_ASSERT()	mtx_assert(&scope7_lock, MA_OWNED);
+
 static struct scope6_id sid_default;
 #define SID(ifp) \
 	(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id)
@@ -53,6 +63,7 @@
 scope6_init()
 {
 
+	SCOPE6_LOCK_INIT();
 	bzero(&sid_default, sizeof(sid_default));
 }
 
@@ -113,7 +124,7 @@
 	 */
 
 	s = splnet();
-
+	SCOPE6_LOCK();
 	for (i = 0; i < 16; i++) {
 		if (idlist->s6id_list[i] &&
 		    idlist->s6id_list[i] != sid->s6id_list[i]) {
@@ -137,6 +148,7 @@
 			sid->s6id_list[i] = idlist->s6id_list[i];
 		}
 	}
+	SCOPE6_UNLOCK();
 	splx(s);
 
 	return (error);
@@ -151,9 +163,9 @@
 
 	if (sid == NULL)	/* paranoid? */
 		return (EINVAL);
-
+	SCOPE6_LOCK();
 	*idlist = *sid;
-
+	SCOPE6_UNLOCK();
 	return (0);
 }
 
@@ -224,6 +236,7 @@
 {
 	int scope;
 	struct scope6_id *sid = SID(ifp);
+	u_int32_t retval;
 
 #ifdef DIAGNOSTIC
 	if (sid == NULL) { /* should not happen */
@@ -245,22 +258,32 @@
 
 	scope = in6_addrscope(addr);
 
+	/*
+	 * XXX: These are all u_int32_t reads, so may not require locking.
+	 */
+	SCOPE6_LOCK();
 	switch(scope) {
 	case IPV6_ADDR_SCOPE_NODELOCAL:
-		return (-1);	/* XXX: is this an appropriate value? */
+		retval = -1;	/* XXX: is this an appropriate value? */
+		break;
 
 	case IPV6_ADDR_SCOPE_LINKLOCAL:
-		return (sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]);
+		retval = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
+		break;
 
 	case IPV6_ADDR_SCOPE_SITELOCAL:
-		return (sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]);
+		retval  = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
+		break;
 
 	case IPV6_ADDR_SCOPE_ORGLOCAL:
-		return (sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]);
+		retval =  sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
+		break;
 
 	default:
-		return (0);	/* XXX: treat as global. */
+		retval =  0;	/* XXX: treat as global. */
 	}
+	SCOPE6_UNLOCK();
+	return (retval);
 }
 
 void
@@ -273,6 +296,7 @@
 	 * We might eventually have to separate the notion of "link" from
 	 * "interface" and provide a user interface to set the default.
 	 */
+	SCOPE6_LOCK();
 	if (ifp) {
 		sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] =
 			ifp->if_index;
@@ -282,13 +306,17 @@
 		sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = 0;
 		sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
 	}
+	SCOPE6_UNLOCK();
 }
 
 int
 scope6_get_default(idlist)
 	struct scope6_id *idlist;
 {
+
+	SCOPE6_LOCK();
 	*idlist = sid_default;
+	SCOPE6_UNLOCK();
 
 	return (0);
 }
@@ -297,6 +325,8 @@
 scope6_addr2default(addr)
 	struct in6_addr *addr;
 {
+	u_int32_t id;
+
 	/*
 	 * special case: The loopback address should be considered as
 	 * link-local, but there's no ambiguity in the syntax.
@@ -304,5 +334,13 @@
 	if (IN6_IS_ADDR_LOOPBACK(addr))
 		return (0);
 
-	return (sid_default.s6id_list[in6_addrscope(addr)]);
+	/*
+	 * XXX: 32-bit read is atomic on all our platforms, is it OK
+	 * not to lock here?
+	 */
+	SCOPE6_LOCK();
+	id = sid_default.s6id_list[in6_addrscope(addr)];
+	SCOPE6_UNLOCK();
+
+	return (id);
 }
