Index: igmp.c
===================================================================
RCS file: /data/ncvs/src/sys/netinet/igmp.c,v
retrieving revision 1.43
diff -u -r1.43 igmp.c
--- igmp.c	20 Aug 2003 17:32:17 -0000	1.43
+++ igmp.c	27 Aug 2003 19:06:51 -0000
@@ -53,9 +53,11 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/lock.h>
 #include <sys/mac.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
+#include <sys/mutex.h>
 #include <sys/socket.h>
 #include <sys/protosw.h>
 #include <sys/kernel.h>
@@ -91,6 +93,16 @@
 static struct mbuf *router_alert;
 static struct route igmprt;
 
+/*
+ * igmp_mtx protects the structure and contents of the router_info
+ * linked list.
+ */
+static struct mtx igmp_mtx;
+
+#define	RTI_LOCK()	mtx_lock(&igmp_mtx);
+#define	RTI_UNLOCK()	mtx_unlock(&igmp_mtx);
+#define	RTI_ASSERT()	mtx_assert(&igmp_mtx, MA_OWNED);
+
 #ifdef IGMP_DEBUG
 #define	IGMP_PRINTF(x)	printf(x)
 #else
@@ -123,6 +135,7 @@
 	router_alert->m_len = sizeof(ra->ipopt_dst) + ra->ipopt_list[1];
 
 	SLIST_INIT(&router_info_head);
+	mtx_init(&igmp_mtx, "igmp", NULL, MTX_DEF);
 }
 
 static struct router_info *
@@ -130,8 +143,10 @@
 {
 	struct router_info *rti;
 
-	rti = SLIST_FIRST(&router_info_head);
 	IGMP_PRINTF("[igmp.c, _find_rti] --> entering \n");
+
+	RTI_ASSERT();
+	rti = SLIST_FIRST(&router_info_head);
 	SLIST_FOREACH(rti, &router_info_head, rti_list) {
 		if (rti->rti_ifp == ifp) {
 			IGMP_PRINTF(
@@ -202,7 +217,6 @@
 	timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
 	if (timer == 0)
 		timer = 1;
-	rti = find_rti(ifp);
 
 	/*
 	 * In the IGMPv2 specification, there are 3 states and a flag.
@@ -229,8 +243,11 @@
 			 * value in RFC 1112.
 			 */
 
+			RTI_LOCK();
+			rti = find_rti(ifp);
 			rti->rti_type = IGMP_V1_ROUTER;
 			rti->rti_time = 0;
+			RTI_UNLOCK();
 
 			timer = IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ;
 
@@ -343,14 +360,19 @@
 igmp_joingroup(struct in_multi *inm)
 {
 	int s = splnet();
+	int rti_type;
 
 	if (inm->inm_addr.s_addr == igmp_all_hosts_group
 	    || inm->inm_ifp->if_flags & IFF_LOOPBACK) {
 		inm->inm_timer = 0;
 		inm->inm_state = IGMP_OTHERMEMBER;
 	} else {
+		RTI_LOCK();
 		inm->inm_rti = find_rti(inm->inm_ifp);
-		igmp_sendpkt(inm, inm->inm_rti->rti_type, 0);
+		rti_type = inm->inm_rti->rti_type;
+		RTI_UNLOCK();
+
+		igmp_sendpkt(inm, rti_type, 0);
 		inm->inm_timer = IGMP_RANDOM_DELAY(
 					IGMP_MAX_HOST_REPORT_DELAY*PR_FASTHZ);
 		inm->inm_state = IGMP_IREPORTEDLAST;
@@ -363,10 +385,16 @@
 igmp_leavegroup(struct in_multi *inm)
 {
 
+	RTI_LOCK();
+	if (inm->inm_rti->rti_type == IGMP_V1_ROUTER) {
+		RTI_UNLOCK();
+		return;
+	}
+	RTI_UNLOCK();
+
 	if (inm->inm_state == IGMP_IREPORTEDLAST &&
 	    inm->inm_addr.s_addr != igmp_all_hosts_group &&
-	    !(inm->inm_ifp->if_flags & IFF_LOOPBACK) &&
-	    inm->inm_rti->rti_type != IGMP_V1_ROUTER)
+	    !(inm->inm_ifp->if_flags & IFF_LOOPBACK))
 		igmp_sendpkt(inm, IGMP_V2_LEAVE_GROUP, igmp_all_rtrs_group);
 }
 
@@ -375,7 +403,7 @@
 {
 	register struct in_multi *inm;
 	struct in_multistep step;
-	int s;
+	int rti_type, s;
 
 	/*
 	 * Quick check to see if any work needs to be done, in order
@@ -392,7 +420,15 @@
 		if (inm->inm_timer == 0) {
 			/* do nothing */
 		} else if (--inm->inm_timer == 0) {
-			igmp_sendpkt(inm, inm->inm_rti->rti_type, 0);
+			/*
+			 * XXX: We grab and the release the lock for
+			 * each multicast address, which is far too
+			 * much locking and unlocking.
+			 */
+			RTI_LOCK();
+			rti_type = inm->inm_rti->rti_type;
+			RTI_UNLOCK();
+			igmp_sendpkt(inm, rti_type, 0);
 			inm->inm_state = IGMP_IREPORTEDLAST;
 		} else {
 			igmp_timers_are_running = 1;
@@ -405,10 +441,10 @@
 void
 igmp_slowtimo(void)
 {
-	int s = splnet();
 	struct router_info *rti;
 
 	IGMP_PRINTF("[igmp.c,_slowtimo] -- > entering \n");
+	RTI_LOCK();
 	SLIST_FOREACH(rti, &router_info_head, rti_list) {
 		if (rti->rti_type == IGMP_V1_ROUTER) {
 			rti->rti_time++;
@@ -416,8 +452,8 @@
 				rti->rti_type = IGMP_V2_ROUTER;
 		}
 	}
+	RTI_UNLOCK();
 	IGMP_PRINTF("[igmp.c,_slowtimo] -- > exiting \n");
-	splx(s);
 }
 
 static void
Index: in_var.h
===================================================================
RCS file: /data/ncvs/src/sys/netinet/in_var.h,v
retrieving revision 1.47
diff -u -r1.47 in_var.h
--- in_var.h	20 Aug 2003 17:09:01 -0000	1.47
+++ in_var.h	27 Aug 2003 18:52:07 -0000
@@ -133,7 +133,8 @@
 
 /*
  * This information should be part of the ifnet structure but we don't wish
- * to change that - as it might break a number of things
+ * to change that - as it might break a number of things.  The fields
+ * in this structure are protected by RTI_LOCK() in igmp.c.
  */
 
 struct router_info {
