Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Jul 2005 01:25:20 +0100 (BST)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        Ed Maste <emaste@phaedrus.sandvine.ca>
Cc:        freebsd-net@freebsd.org, gnn@FreeBSD.org
Subject:   Re: what to replace splnet in FreeBSD 5.x?
Message-ID:  <20050723012046.K40216@fledge.watson.org>
In-Reply-To: <20050712220452.GB38249@sandvine.com>
References:  <42CEF0EB.4000107@borderware.com> <42D006DB.8080108@errno.com> <20050712150224.GA38249@sandvine.com> <20050712162332.Q79478@fledge.watson.org> <20050712220452.GB38249@sandvine.com>

next in thread | previous in thread | raw e-mail | index | archive | help

On Tue, 12 Jul 2005, Ed Maste wrote:

> On Tue, Jul 12, 2005 at 04:30:18PM +0100, Robert Watson wrote:
>
>> I'm concerned about the multicast address list problems you've been
>> experiencing, but haven't yet had a chance to investigate.  If you could
>> provide a code fragment that exercises this problem, that would probably
>> get me started a lot more quickly.
>
> Thanks Robert.  So far we've reproduced it only within our test lab 
> environment and with our product executables -- a large amount of code 
> and infrastructure.  I've attempted to reduce it to a small amount of 
> code that demonstrates the problem but have had no success yet.

Ed,

The attached patch introduces locking around the link layer and IPv4 
multicast address lists, as well as updates drivers to use the locking. 
It's a fairly large diff, but other than the changes to if.c, in.c, and 
igmp.c, is fairly mechanical.  It may well correct the problem you've been 
seeing.  If possible, and given sufficient review, I'd like to get this 
change into 6.0, especially given that it affects the layout of struct 
ifnet which is part of the ABI for network interface device drivers.

I've tested it with a basic IPv4 multicast regression test locally, but 
not with a lot of multicast parallelism, since I don't have easily 
accessible real-world workloads.  Any testing you could provide would be 
most welcome.  Likewise, code review :-).

Similar changes will also be needed in the IPv6 multicast code.  I've CC'd 
George to victimize him further ... er ... to see if he's interested in 
this area.

Robert N M Watson

--- //depot/vendor/freebsd/src/sys/dev/ath/if_ath.c	2005/07/22 18:00:59
+++ //depot/projects/netsmp/src/sys/dev/ath/if_ath.c	2005/07/23 00:06:01
@@ -1661,6 +1661,7 @@
  	/* calculate and install multicast filter */
  	if ((ifp->if_flags & IFF_ALLMULTI) == 0) {
  		mfilt[0] = mfilt[1] = 0;
+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  			caddr_t dl;

@@ -1673,6 +1674,7 @@
  			pos &= 0x3f;
  			mfilt[pos / 32] |= (1 << (pos % 32));
  		}
+		IF_ADDR_UNLOCK(ifp);
  	} else {
  		mfilt[0] = mfilt[1] = ~0;
  	}
--- //depot/vendor/freebsd/src/sys/dev/awi/awi.c	2005/07/22 16:50:36
+++ //depot/projects/netsmp/src/sys/dev/awi/awi.c	2005/07/23 00:06:01
@@ -1146,15 +1146,19 @@
  #ifdef __FreeBSD__
  	if (ifp->if_flags & IFF_ALLMULTI)
  		goto set_mib;
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
-		if (n == AWI_GROUP_ADDR_SIZE)
+		if (n == AWI_GROUP_ADDR_SIZE) {
+			IF_ADDR_UNLOCK(ifp);
  			goto set_mib;
+		}
  		IEEE80211_ADDR_COPY(sc->sc_mib_addr.aGroup_Addresses[n],
  		    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
  		n++;
  	}
+	IF_ADDR_UNLOCK(ifp);
  #else
  	ETHER_FIRST_MULTI(step, &sc->sc_ic.ic_ec, enm);
  	while (enm != NULL) {
--- //depot/vendor/freebsd/src/sys/dev/bfe/if_bfe.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/bfe/if_bfe.c	2005/07/19 21:29:46
@@ -883,12 +883,14 @@
  		val |= BFE_RXCONF_ALLMULTI;
  	else {
  		val &= ~BFE_RXCONF_ALLMULTI;
+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  			if (ifma->ifma_addr->sa_family != AF_LINK)
  				continue;
  			bfe_cam_write(sc,
  			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i++);
  		}
+		IF_ADDR_UNLOCK(ifp);
  	}

  	CSR_WRITE_4(sc, BFE_RXCONF, val);
--- //depot/vendor/freebsd/src/sys/dev/bge/if_bge.c	2005/06/24 21:45:25
+++ //depot/projects/netsmp/src/sys/dev/bge/if_bge.c	2005/07/19 21:29:46
@@ -1171,6 +1171,7 @@
  		CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0);

  	/* Now program new ones. */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1178,6 +1179,7 @@
  		    ifma->ifma_addr), ETHER_ADDR_LEN) & 0x7F;
  		hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F);
  	}
+	IF_ADDR_UNLOCK(ifp);

  	for (i = 0; i < 4; i++)
  		CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), hashes[i]);
--- //depot/vendor/freebsd/src/sys/dev/ed/if_ed.c	2005/06/15 20:25:30
+++ //depot/projects/netsmp/src/sys/dev/ed/if_ed.c	2005/07/19 21:29:46
@@ -1778,6 +1778,7 @@
  	mcaf[0] = 0;
  	mcaf[1] = 0;

+	IF_ADDR_LOCK(sc->ifp);
  	TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1785,6 +1786,7 @@
  		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
  		af[index >> 3] |= 1 << (index & 7);
  	}
+	IF_ADDR_UNLOCK(sc->ifp);
  }

  int
--- //depot/vendor/freebsd/src/sys/dev/em/if_em.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/em/if_em.c	2005/07/19 21:29:46
@@ -1596,7 +1596,8 @@
                  E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
                  msec_delay(5);
          }
- 
+
+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version < 500000
          LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  #else
@@ -1611,6 +1612,7 @@
                        &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
                  mcnt++;
          }
+	IF_ADDR_UNLOCK(ifp);

          if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
                  reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
--- //depot/vendor/freebsd/src/sys/dev/ex/if_ex.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/ex/if_ex.c	2005/07/19 21:29:46
@@ -840,11 +840,13 @@
  	ifp = sc->ifp;

  	count = 0;
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
  		if (maddr->ifma_addr->sa_family != AF_LINK)
  			continue;
  		count++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if ((ifp->if_flags & IFF_PROMISC) || (ifp->if_flags & IFF_ALLMULTI)
  			|| count > 63) {
@@ -871,7 +873,8 @@
  		CSR_WRITE_2(sc, IO_PORT_REG, 0);
  		CSR_WRITE_2(sc, IO_PORT_REG, 0);
  		CSR_WRITE_2(sc, IO_PORT_REG, (count + 1) * 6);
- 
+
+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
  			if (maddr->ifma_addr->sa_family != AF_LINK)
  				continue;
@@ -882,6 +885,7 @@
  			CSR_WRITE_2(sc, IO_PORT_REG, *addr++);
  			CSR_WRITE_2(sc, IO_PORT_REG, *addr++);
  		}
+		IF_ADDR_UNLOCK(ifp);

  		/* Program our MAC address as well */
  		/* XXX: Is this necessary?  The Linux driver does this
--- //depot/vendor/freebsd/src/sys/dev/fe/if_fe.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/fe/if_fe.c	2005/07/19 21:29:46
@@ -2060,6 +2060,7 @@
  	struct ifmultiaddr *ifma;

  	filter = fe_filter_nothing;
+	IF_ADDR_LOCK(sc->ifp);
  	TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -2072,6 +2073,7 @@

  		filter.data[index >> 3] |= 1 << (index & 7);
  	}
+	IF_ADDR_UNLOCK(sc->ifp);
  	return ( filter );
  }

--- //depot/vendor/freebsd/src/sys/dev/fxp/if_fxp.c	2005/06/11 00:50:21
+++ //depot/projects/netsmp/src/sys/dev/fxp/if_fxp.c	2005/07/19 21:29:46
@@ -2484,6 +2484,7 @@

  	nmcasts = 0;
  	if ((sc->flags & FXP_FLAG_ALL_MCAST) == 0) {
+		IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version < 500000
  		LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  #else
@@ -2500,6 +2501,7 @@
  			    &sc->mcsp->mc_addr[nmcasts][0], ETHER_ADDR_LEN);
  			nmcasts++;
  		}
+		IF_ADDR_UNLOCK(ifp);
  	}
  	mcsp->mc_cnt = htole16(nmcasts * ETHER_ADDR_LEN);
  	return (nmcasts);
--- //depot/vendor/freebsd/src/sys/dev/gem/if_gem.c	2005/06/12 15:35:17
+++ //depot/projects/netsmp/src/sys/dev/gem/if_gem.c	2005/07/19 21:29:46
@@ -1894,6 +1894,7 @@
  	/* Clear hash table */
  	memset(hash, 0, sizeof(hash));

+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) {
  		if (inm->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1906,6 +1907,7 @@
  		/* Set the corresponding bit in the filter. */
  		hash[crc >> 4] |= 1 << (15 - (crc & 15));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	v |= GEM_MAC_RX_HASH_FILTER;
  	ifp->if_flags &= ~IFF_ALLMULTI;
--- //depot/vendor/freebsd/src/sys/dev/hme/if_hme.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/hme/if_hme.c	2005/07/19 21:29:46
@@ -1679,6 +1679,7 @@
  	 * the word.
  	 */

+	IF_ADDR_LOCK(sc->sc_ifp);
  	TAILQ_FOREACH(inm, &sc->sc_ifp->if_multiaddrs, ifma_link) {
  		if (inm->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1691,6 +1692,7 @@
  		/* Set the corresponding bit in the filter. */
  		hash[crc >> 4] |= 1 << (crc & 0xf);
  	}
+	IF_ADDR_UNLOCK(sc->sc_ifp);

  	ifp->if_flags &= ~IFF_ALLMULTI;

--- //depot/vendor/freebsd/src/sys/dev/ie/if_ie.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/ie/if_ie.c	2005/07/19 21:29:46
@@ -1676,6 +1676,7 @@
  	 * Step through the list of addresses.
  	 */
  	sc->mcast_count = 0;
+	IF_ADDR_LOCK(sc->ifp);
  	TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1690,6 +1691,7 @@
  		      &(sc->mcast_addrs[sc->mcast_count]), 6);
  		sc->mcast_count++;
  	}
+	IF_ADDR_UNLOCK(sc->ifp);

  setflag:
  	sc->want_mcsetup = 1;
--- //depot/vendor/freebsd/src/sys/dev/if_ndis/if_ndis.c	2005/06/14 17:50:27
+++ //depot/projects/netsmp/src/sys/dev/if_ndis/if_ndis.c	2005/07/19 21:29:46
@@ -265,6 +265,7 @@
  	sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST;

  	len = 0;
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -272,11 +273,13 @@
  		    mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN);
  		len++;
  		if (len > mclistsz) {
+			IF_ADDR_UNLOCK(ifp);
  			sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
  			sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
  			goto out;
  		}
  	}
+	IF_ADDR_UNLOCK(ifp);

  	len = len * ETHER_ADDR_LEN;
  	error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len);
--- //depot/vendor/freebsd/src/sys/dev/ixgb/if_ixgb.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/ixgb/if_ixgb.c	2005/07/19 21:29:46
@@ -1065,6 +1065,7 @@

  	IOCTL_DEBUGOUT("ixgb_set_multi: begin");

+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version < 500000
  	LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  #else
@@ -1077,6 +1078,7 @@
  		      &mta[mcnt * IXGB_ETH_LENGTH_OF_ADDRESS], IXGB_ETH_LENGTH_OF_ADDRESS);
  		mcnt++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) {
  		reg_rctl = IXGB_READ_REG(&adapter->hw, RCTL);
--- //depot/vendor/freebsd/src/sys/dev/lge/if_lge.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/lge/if_lge.c	2005/07/19 21:29:46
@@ -390,6 +390,7 @@
  	CSR_WRITE_4(sc, LGE_MAR1, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -400,6 +401,7 @@
  		else
  			hashes[1] |= (1 << (h - 32));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	CSR_WRITE_4(sc, LGE_MAR0, hashes[0]);
  	CSR_WRITE_4(sc, LGE_MAR1, hashes[1]);
--- //depot/vendor/freebsd/src/sys/dev/lnc/if_lnc.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/lnc/if_lnc.c	2005/07/19 21:29:46
@@ -239,6 +239,7 @@
  	 */

  	bzero(sc->init_block->ladrf, MULTICAST_FILTER_LEN);
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -247,6 +248,7 @@
  		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
  		sc->init_block->ladrf[index >> 3] |= 1 << (index & 7);
  	}
+	IF_ADDR_UNLOCK(ifp);
  }

  void
--- //depot/vendor/freebsd/src/sys/dev/my/if_my.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/my/if_my.c	2005/07/19 21:29:46
@@ -346,6 +346,7 @@
  	CSR_WRITE_4(sc, MY_MAR1, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -357,6 +358,7 @@
  			hashes[1] |= (1 << (h - 32));
  		mcnt++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt)
  		rxfilt |= MY_AM;
--- //depot/vendor/freebsd/src/sys/dev/nge/if_nge.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/nge/if_nge.c	2005/07/19 21:29:46
@@ -705,6 +705,7 @@
  	 * that needs to be updated, and the lower 4 bits represent
  	 * which bit within that byte needs to be set.
  	 */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -716,6 +717,7 @@
  		    NGE_FILTADDR_MCAST_LO + (index * 2));
  		NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave);

--- //depot/vendor/freebsd/src/sys/dev/nve/if_nve.c	2005/06/11 01:40:36
+++ //depot/projects/netsmp/src/sys/dev/nve/if_nve.c	2005/07/19 21:29:46
@@ -1074,6 +1074,7 @@
  		return;
  	}
  	/* Setup multicast filter */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		u_char *addrp;

@@ -1087,6 +1088,7 @@
  			oraddr[i] |= mcaddr;
  		}
  	}
+	IF_ADDR_UNLOCK(ifp);
  	for (i = 0; i < 6; i++) {
  		hwfilter.acMulticastAddress[i] = andaddr[i] & oraddr[i];
  		hwfilter.acMulticastMask[i] = andaddr[i] | (~oraddr[i]);
--- //depot/vendor/freebsd/src/sys/dev/owi/if_owi.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/owi/if_owi.c	2005/07/19 21:29:46
@@ -1213,6 +1213,7 @@
  		return;
  	}

+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1225,6 +1226,7 @@
  			break;
  		}
  	}
+	IF_ADDR_UNLOCK(ifp);

  	mcast.wi_len = (i * 3) + 1;
  	wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
--- //depot/vendor/freebsd/src/sys/dev/pdq/pdq_ifsubr.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/pdq/pdq_ifsubr.c	2005/07/19 21:29:46
@@ -273,6 +273,7 @@
      PDQ_IFNET(sc)->if_flags &= ~IFF_ALLMULTI;
  #endif

+    IF_ADDR_LOCK(PDQ_IFNET(sc));
      for (ifma = TAILQ_FIRST(&PDQ_IFNET(sc)->if_multiaddrs); ifma && num_addrs > 0;
  	 ifma = TAILQ_NEXT(ifma, ifma_link)) {
  	    char *mcaddr;
@@ -285,6 +286,7 @@
  	    addr++;
  	    num_addrs--;
      }
+    IF_ADDR_UNLOCK(PDQ_IFNET(sc));
      /*
       * If not all the address fit into the CAM, turn on all-multicast mode.
       */
--- //depot/vendor/freebsd/src/sys/dev/ray/if_ray.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/ray/if_ray.c	2005/07/19 21:29:46
@@ -2704,6 +2704,7 @@
  	 * The multicast list is only 16 items long so use promiscuous
  	 * mode and don't bother updating the multicast list.
  	 */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
  		count++;
  	if (count == 0) {
@@ -2711,6 +2712,7 @@
  		return;
  	} else if (count > 16) {
  		ifp->if_flags |= IFF_ALLMULTI;
+		IF_ADDR_UNLOCK(ifp);
  		ray_com_runq_done(sc);
  		return;
  	} else if (ifp->if_flags & IFF_ALLMULTI)
@@ -2732,6 +2734,7 @@
  		);
  		bufp += ETHER_ADDR_LEN;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	ray_com_ecf(sc, com);
  }
--- //depot/vendor/freebsd/src/sys/dev/re/if_re.c	2005/07/01 04:16:05
+++ //depot/projects/netsmp/src/sys/dev/re/if_re.c	2005/07/19 21:29:46
@@ -601,6 +601,7 @@
  	CSR_WRITE_4(sc, RL_MAR4, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -612,6 +613,7 @@
  			hashes[1] |= (1 << (h - 32));
  		mcnt++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt)
  		rxfilt |= RL_RXCFG_RX_MULTI;
--- //depot/vendor/freebsd/src/sys/dev/sn/if_sn.c	2005/07/18 23:45:24
+++ //depot/projects/netsmp/src/sys/dev/sn/if_sn.c	2005/07/19 21:29:46
@@ -1410,6 +1410,7 @@

  	bzero(mcf, MCFSZ);

+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  	    if (ifma->ifma_addr->sa_family != AF_LINK)
  		return 0;
@@ -1423,5 +1424,6 @@
  	    }
  	    af[index2 >> 3] |= 1 << (index2 & 7);
  	}
+	IF_ADDR_UNLOCK(ifp);
  	return 1;  /* use multicast filter */
  }
--- //depot/vendor/freebsd/src/sys/dev/snc/dp83932.c	2005/06/12 15:25:25
+++ //depot/projects/netsmp/src/sys/dev/snc/dp83932.c	2005/07/19 21:29:46
@@ -675,6 +675,7 @@
  	ifp->if_flags &= ~IFF_ALLMULTI;

  	/* Loop through multicast addresses */
+	IF_ADDR_LOCK(ifp);
          TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
                  if (ifma->ifma_addr->sa_family != AF_LINK)
                          continue;
@@ -688,6 +689,7 @@
  			 LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
  		mcount++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	NIC_PUT(sc, SNCR_CDP, LOWER(sc->v_cda));
  	NIC_PUT(sc, SNCR_CDC, MAXCAM);
--- //depot/vendor/freebsd/src/sys/dev/tx/if_tx.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/tx/if_tx.c	2005/07/19 21:29:46
@@ -1409,6 +1409,7 @@
  	filter[2] = 0;
  	filter[3] = 0;

+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version < 500000
  	LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  #else
@@ -1420,6 +1421,7 @@
  		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
  		filter[h >> 4] |= 1 << (h & 0xF);
  	}
+	IF_ADDR_UNLOCK(ifp);

  	CSR_WRITE_4(sc, MC0, filter[0]);
  	CSR_WRITE_4(sc, MC1, filter[1]);
--- //depot/vendor/freebsd/src/sys/dev/txp/if_txp.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/txp/if_txp.c	2005/07/19 21:29:46
@@ -1774,6 +1774,7 @@
  	else {
  		hash[0] = hash[1] = 0;

+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  			if (ifma->ifma_addr->sa_family != AF_LINK)
  				continue;
@@ -1797,6 +1798,7 @@
  			hashbit = (u_int16_t)(crc & (64 - 1));
  			hash[hashbit / 32] |= (1 << hashbit % 32);
  		}
+		IF_ADDR_UNLOCK(ifp);

  		if (mcnt > 0) {
  			filter |= TXP_RXFILT_HASHMULTI;
--- //depot/vendor/freebsd/src/sys/dev/usb/if_aue.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/usb/if_aue.c	2005/07/19 21:29:46
@@ -539,6 +539,7 @@
  		aue_csr_write_1(sc, AUE_MAR0 + i, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version >= 500000
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
  #else
@@ -551,6 +552,7 @@
  		    ifma->ifma_addr), ETHER_ADDR_LEN) & ((1 << AUE_BITS) - 1);
  		AUE_SETBIT(sc, AUE_MAR + (h >> 3), 1 << (h & 0x7));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	return;
  }
--- //depot/vendor/freebsd/src/sys/dev/usb/if_axe.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/usb/if_axe.c	2005/07/19 21:29:46
@@ -338,6 +338,7 @@
  	} else
  		rxmode &= ~AXE_RXCMD_ALLMULTI;

+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version >= 500000
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
  #else
@@ -350,6 +351,7 @@
  		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
  		hashtbl[h / 8] |= 1 << (h % 8);
  	}
+	IF_ADDR_UNLOCK(ifp);

  	axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl);
  	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
--- //depot/vendor/freebsd/src/sys/dev/usb/if_cue.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/usb/if_cue.c	2005/07/19 21:29:46
@@ -356,6 +356,7 @@
  		sc->cue_mctab[i] = 0;

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version >= 500000
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
  #else
@@ -367,6 +368,7 @@
  		h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
  		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
  	}
+	IF_ADDR_UNLOCK(ifp);

  	/*
  	 * Also include the broadcast address in the filter
--- //depot/vendor/freebsd/src/sys/dev/usb/if_kue.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/usb/if_kue.c	2005/07/19 21:29:46
@@ -327,6 +327,7 @@

  	sc->kue_rxfilt &= ~KUE_RXFILT_ALLMULTI;

+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version >= 500000
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
  #else
@@ -345,6 +346,7 @@
  		    KUE_MCFILT(sc, i), ETHER_ADDR_LEN);
  		i++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (i == KUE_MCFILTCNT(sc))
  		sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI;
--- //depot/vendor/freebsd/src/sys/dev/usb/if_rue.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/usb/if_rue.c	2005/07/19 22:53:09
@@ -500,6 +500,7 @@
  	rue_csr_write_4(sc, RUE_MAR4, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version >= 500000
  	TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link)
  #else
@@ -516,6 +517,7 @@
  			hashes[1] |= (1 << (h - 32));
  		mcnt++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt)
  		rxcfg |= RUE_RCR_AM;
--- //depot/vendor/freebsd/src/sys/dev/usb/if_udav.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/usb/if_udav.c	2005/07/19 21:29:46
@@ -1044,6 +1044,7 @@
  		ETHER_NEXT_MULTI(step, enm);
  	}
  #elif defined(__FreeBSD__)
+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version >= 500000
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
  #else
@@ -1056,6 +1057,7 @@
  		    ifma->ifma_addr));
  		hashes[h>>3] |= 1 << (h & 0x7);
  	}
+	IF_ADDR_UNLOCK(ifp);
  #endif

  	/* disable all multicast */
--- //depot/vendor/freebsd/src/sys/dev/vge/if_vge.c	2005/06/11 01:40:36
+++ //depot/projects/netsmp/src/sys/dev/vge/if_vge.c	2005/07/19 21:29:46
@@ -594,6 +594,7 @@
  	}

  	/* Now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -626,6 +627,7 @@
  		CSR_WRITE_4(sc, VGE_MAR0, hashes[0]);
  		CSR_WRITE_4(sc, VGE_MAR1, hashes[1]);
  	}
+	IF_ADDR_UNLOCK(ifp);

  	return;
  }
--- //depot/vendor/freebsd/src/sys/dev/wi/if_wi.c	2005/07/22 16:50:36
+++ //depot/projects/netsmp/src/sys/dev/wi/if_wi.c	2005/07/23 00:06:01
@@ -1739,6 +1739,7 @@
  	}

  	n = 0;
+	IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version < 500000
  	LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  #else
@@ -1752,6 +1753,7 @@
  		    (LLADDR((struct sockaddr_dl *)ifma->ifma_addr)));
  		n++;
  	}
+	IF_ADDR_UNLOCK(ifp);
  	return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist,
  	    IEEE80211_ADDR_LEN * n);
  }
--- //depot/vendor/freebsd/src/sys/dev/wl/if_wl.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/dev/wl/if_wl.c	2005/07/19 21:29:46
@@ -2121,6 +2121,7 @@
      outw(PIOP1(base), 0);				/* ac_status */
      outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);		/* ac_command */
      outw(PIOR1(base), OFFSET_CU + 8);
+    IF_ADDR_LOCK(sc->ifp);
      TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) {
  	if (ifma->ifma_addr->sa_family != AF_LINK)
  	    continue;
@@ -2131,6 +2132,7 @@
          outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
          ++cnt;
      }
+    IF_ADDR_UNLOCK(sc->ifp);
      outw(PIOR1(base), OFFSET_CU + 6);		/* mc-cnt */
      outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
      if (wlcmd(sc, "config()-mcaddress") == 0)
--- //depot/vendor/freebsd/src/sys/dev/xe/if_xe.c	2005/07/15 06:11:01
+++ //depot/projects/netsmp/src/sys/dev/xe/if_xe.c	2005/07/19 21:29:46
@@ -1274,6 +1274,7 @@

    /* Iterate over multicast address list */
    count = 0;
+  IF_ADDR_LOCK(ifp);
  #if __FreeBSD_version < 500000
    LIST_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
  #else
@@ -1295,6 +1296,7 @@
  	/* Nowhere else to put them on CE2 */
  	break;
    }
+  IF_ADDR_UNLOCK(ifp);

    DEVPRINTF(2, (scp->dev, "set_multicast: count = %u\n", count));

--- //depot/vendor/freebsd/src/sys/net/if.c	2005/07/19 10:16:50
+++ //depot/projects/netsmp/src/sys/net/if.c	2005/07/22 23:59:30
@@ -417,6 +417,8 @@
  {

  	if_free_type(ifp, ifp->if_type);
+
+	IF_ADDR_LOCK_DESTROY(ifp);
  }

  void
@@ -460,6 +462,7 @@
  	TASK_INIT(&ifp->if_starttask, 0, if_start_deferred, ifp);
  	TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp);
  	IF_AFDATA_LOCK_INIT(ifp);
+	IF_ADDR_LOCK_INIT(ifp);
  	ifp->if_afdata_initialized = 0;
  	IFNET_WLOCK();
  	TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
@@ -1824,99 +1827,229 @@
  	return (if_setflag(ifp, IFF_ALLMULTI, 0, &ifp->if_amcount, onswitch));
  }

+struct ifmultiaddr *
+ifmaof_ifpforaddr(struct sockaddr *sa, struct ifnet *ifp)
+{
+	struct ifmultiaddr *ifma;
+
+	IF_ADDR_LOCK_ASSERT(ifp);
+
+	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+		if (sa_equal(ifma->ifma_addr, sa))
+			break;
+	}
+
+	return ifma;
+}
+
+/*
+ * XXXRW: ifmaof_ifpforaddr() is an unsensible name, and appears not to be
+ * used, so use my more sensibly named version here.
+ */
+static struct ifmultiaddr *
+if_findmulti(struct ifnet *ifp, struct sockaddr *sa)
+{
+
+	IF_ADDR_LOCK_ASSERT(ifp);
+
+	return (ifmaof_ifpforaddr(sa, ifp));
+}
+
+/*
+ * Allocate a new ifmultiaddr and initialize based on passed arguments.  We
+ * make copies of passed sockaddrs.  The ifmultiaddr will not be added to
+ * the ifnet multicast address list here, so the caller must do that and
+ * other setup work (such as notifying the device driver).  The reference
+ * count is initialized to 1.
+ */
+static struct ifmultiaddr *
+if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa,
+    int mflags)
+{
+	struct ifmultiaddr *ifma;
+	struct sockaddr *dupsa;
+
+	MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, mflags |
+	    M_ZERO);
+	if (ifma == NULL)
+		return (NULL);
+
+	MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, mflags);
+	if (dupsa == NULL) {
+		FREE(ifma, M_IFMADDR);
+		return (NULL);
+	}
+	bcopy(sa, dupsa, sa->sa_len);
+	ifma->ifma_addr = dupsa;
+
+	ifma->ifma_ifp = ifp;
+	ifma->ifma_refcount = 1;
+	ifma->ifma_protospec = NULL;
+
+	if (llsa == NULL) {
+		ifma->ifma_lladdr = NULL;
+		return (ifma);
+	}
+
+	MALLOC(dupsa, struct sockaddr *, llsa->sa_len, M_IFMADDR, mflags);
+	if (dupsa == NULL) {
+		FREE(ifma->ifma_addr, M_IFMADDR);
+		FREE(ifma, M_IFMADDR);
+		return (NULL);
+	}
+	bcopy(llsa, dupsa, llsa->sa_len);
+	ifma->ifma_lladdr = dupsa;
+
+	return (ifma);
+}
+
+/*
+ * if_freemulti: free ifmultiaddr structure and possibly attached related
+ * addresses.  The caller is responsible for implementing reference
+ * counting, notifying the driver, handling routing messages, and releasing
+ * any dependent link layer state.
+ */
+static void
+if_freemulti(struct ifmultiaddr *ifma)
+{
+
+	KASSERT(ifma->ifma_refcount == 1, ("if_freemulti: refcount %d",
+	    ifma->ifma_refcount));
+	KASSERT(ifma->ifma_protospec == NULL,
+	    ("if_freemulti: protospec not NULL"));
+
+	if (ifma->ifma_lladdr != NULL)
+		FREE(ifma->ifma_lladdr, M_IFMADDR);
+	FREE(ifma->ifma_addr, M_IFMADDR);
+	FREE(ifma, M_IFMADDR);
+}
+
  /*
- * Add a multicast listenership to the interface in question.
- * The link layer provides a routine which converts
+ * Register an additional multicast address with a network interface.
+ *
+ * - If the address is already present, bump the reference count on the
+ *   address and return.
+ * - If the address is not link-layer, look up a link layer address.
+ * - Allocate address structures for one or both addresses, and attach to the
+ *   multicast address list on the interface.  If automatically adding a link
+ *   layer address, the protocol address will own a reference to the link
+ *   layer address, to be freed when it is freed.
+ * - Notify the network device driver of an addition to the multicast address
+ *   list.
+ *
+ * 'sa' points to caller-owned memory with the desired multicast address.
+ *
+ * 'retifma' will be used to return a pointer to the resulting multicast
+ * address reference, if desired.
   */
  int
-if_addmulti(struct ifnet *ifp, struct sockaddr *sa, struct ifmultiaddr **retifma)
+if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
+    struct ifmultiaddr **retifma)
  {
-	struct sockaddr *llsa, *dupsa;
-	int error, s;
-	struct ifmultiaddr *ifma;
+	struct ifmultiaddr *ifma, *ll_ifma;
+	struct sockaddr *llsa;
+	int error;

  	/*
-	 * If the matching multicast address already exists
-	 * then don't add a new one, just add a reference
+	 * If the address is already present, return a new reference to it;
+	 * otherwise, allocate storage and set up a new address.
  	 */
-	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
-		if (sa_equal(sa, ifma->ifma_addr)) {
-			ifma->ifma_refcount++;
-			if (retifma)
-				*retifma = ifma;
-			return 0;
-		}
+	IF_ADDR_LOCK(ifp);
+	ifma = if_findmulti(ifp, sa);
+	if (ifma != NULL) {
+		ifma->ifma_refcount++;
+		if (retifma != NULL)
+			*retifma = ifma;
+		IF_ADDR_UNLOCK(ifp);
+		return (0);
  	}

  	/*
-	 * Give the link layer a chance to accept/reject it, and also
-	 * find out which AF_LINK address this maps to, if it isn't one
-	 * already.
+	 * The address isn't already present; resolve the protocol address
+	 * into a link layer address, and then look that up, bump its
+	 * refcount or allocate an ifma for that also.  If 'llsa' was
+	 * returned, we will need to free it later.
  	 */
+	llsa = NULL;
+	ll_ifma = NULL;
  	if (ifp->if_resolvemulti != NULL) {
  		error = ifp->if_resolvemulti(ifp, &llsa, sa);
-		if (error) return error;
-	} else {
-		llsa = NULL;
+		if (error)
+			goto unlock_out;
  	}

-	MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
-	MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
-	bcopy(sa, dupsa, sa->sa_len);
+	/*
+	 * Allocate the new address.  Don't hook it up yet, as we may also
+	 * need to allocate a link layer multicast address.
+	 */
+	ifma = if_allocmulti(ifp, sa, llsa, M_NOWAIT);
+	if (ifma == NULL) {
+		error = ENOMEM;
+		goto free_llsa_out;
+	}

-	ifma->ifma_addr = dupsa;
-	ifma->ifma_lladdr = llsa;
-	ifma->ifma_ifp = ifp;
-	ifma->ifma_refcount = 1;
-	ifma->ifma_protospec = NULL;
-	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
+	/*
+	 * If a link layer address is found, we'll need to see if it's
+	 * already present in the address list, or allocate is as well.
+	 * When this block finishes, the link layer address will be on the
+	 * list.
+	 */
+	if (llsa != NULL) {
+		ll_ifma = if_findmulti(ifp, llsa);
+		if (ll_ifma == NULL) {
+			ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT);
+			if (ll_ifma == NULL) {
+				if_freemulti(ifma);
+				error = ENOMEM;
+				goto free_llsa_out;
+			}
+			TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma,
+			    ifma_link);
+		} else
+			ll_ifma->ifma_refcount++;
+	}

  	/*
-	 * Some network interfaces can scan the address list at
-	 * interrupt time; lock them out.
+	 * We now have a new multicast address, ifma, and possibly a new or
+	 * referenced link layer address.  Add the primary address to the
+	 * ifnet address list.
  	 */
-	s = splimp();
  	TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
-	splx(s);
+
  	if (retifma != NULL)
  		*retifma = ifma;

-	if (llsa != NULL) {
-		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
-			if (sa_equal(ifma->ifma_addr, llsa))
-				break;
-		}
-		if (ifma) {
-			ifma->ifma_refcount++;
-		} else {
-			MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
-			       M_IFMADDR, M_WAITOK);
-			MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
-			       M_IFMADDR, M_WAITOK);
-			bcopy(llsa, dupsa, llsa->sa_len);
-			ifma->ifma_addr = dupsa;
-			ifma->ifma_lladdr = NULL;
-			ifma->ifma_ifp = ifp;
-			ifma->ifma_refcount = 1;
-			ifma->ifma_protospec = NULL;
-			s = splimp();
-			TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
-			splx(s);
-		}
-	}
+	/*
+	 * Must generate the message while holding the lock so that 'ifma'
+	 * pointer is still valid.
+	 *
+	 * XXXRW: How come we don't announce ll_ifma?
+	 */
+	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
+	IF_ADDR_UNLOCK(ifp);
+
  	/*
  	 * We are certain we have added something, so call down to the
  	 * interface to let them know about it.
  	 */
  	if (ifp->if_ioctl != NULL) {
-		s = splimp();
  		IFF_LOCKGIANT(ifp);
  		(void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
  		IFF_UNLOCKGIANT(ifp);
-		splx(s);
  	}

-	return 0;
+	if (llsa != NULL)
+		FREE(llsa, M_IFMADDR);
+
+	return (0);
+
+free_llsa_out:
+	if (llsa != NULL)
+		FREE(llsa, M_IFMADDR);
+
+unlock_out:
+	IF_ADDR_UNLOCK(ifp);
+	return (error);
  }

  /*
@@ -1926,72 +2059,53 @@
  int
  if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
  {
-	struct ifmultiaddr *ifma;
-	int s;
+	struct ifmultiaddr *ifma, *ll_ifma;

-	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
-		if (sa_equal(sa, ifma->ifma_addr))
-			break;
-	if (ifma == NULL)
+	IF_ADDR_LOCK(ifp);
+	ifma = if_findmulti(ifp, sa);
+	if (ifma == NULL) {
+		IF_ADDR_UNLOCK(ifp);
  		return ENOENT;
+	}

  	if (ifma->ifma_refcount > 1) {
  		ifma->ifma_refcount--;
+		IF_ADDR_UNLOCK(ifp);
  		return 0;
  	}

-	rt_newmaddrmsg(RTM_DELMADDR, ifma);
  	sa = ifma->ifma_lladdr;
-	s = splimp();
-	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
+	if (sa != NULL)
+		ll_ifma = if_findmulti(ifp, sa);
+	else
+		ll_ifma = NULL;
+
  	/*
-	 * Make sure the interface driver is notified
-	 * in the case of a link layer mcast group being left.
+	 * XXXRW: How come we don't announce ll_ifma?
  	 */
-	if (ifp->if_ioctl && ifma->ifma_addr->sa_family == AF_LINK && sa == 0) {
-		IFF_LOCKGIANT(ifp);
-		(void) (*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0);
-		IFF_UNLOCKGIANT(ifp);
+	rt_newmaddrmsg(RTM_DELMADDR, ifma);
+
+	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
+	if_freemulti(ifma);
+
+	if (ll_ifma != NULL) {
+		if (ll_ifma->ifma_refcount == 1) {
+			TAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifma_link);
+			if_freemulti(ll_ifma);
+		} else
+			ll_ifma->ifma_refcount--;
  	}
-	splx(s);
-	free(ifma->ifma_addr, M_IFMADDR);
-	free(ifma, M_IFMADDR);
-	if (sa == NULL)
-		return 0;
+	IF_ADDR_UNLOCK(ifp);

  	/*
-	 * Now look for the link-layer address which corresponds to
-	 * this network address.  It had been squirreled away in
-	 * ifma->ifma_lladdr for this purpose (so we don't have
-	 * to call ifp->if_resolvemulti() again), and we saved that
-	 * value in sa above.  If some nasty deleted the
-	 * link-layer address out from underneath us, we can deal because
-	 * the address we stored was is not the same as the one which was
-	 * in the record for the link-layer address.  (So we don't complain
-	 * in that case.)
+	 * Make sure the interface driver is notified
+	 * in the case of a link layer mcast group being left.
  	 */
-	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
-		if (sa_equal(sa, ifma->ifma_addr))
-			break;
-	if (ifma == NULL)
-		return 0;
-
-	if (ifma->ifma_refcount > 1) {
-		ifma->ifma_refcount--;
-		return 0;
-	}
-
-	s = splimp();
-	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
-	if (ifp->if_ioctl != NULL) {
+	if (ifp->if_ioctl) {
  		IFF_LOCKGIANT(ifp);
  		(void) (*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0);
  		IFF_UNLOCKGIANT(ifp);
  	}
-	splx(s);
-	free(ifma->ifma_addr, M_IFMADDR);
-	free(sa, M_IFMADDR);
-	free(ifma, M_IFMADDR);

  	return 0;
  }
@@ -2070,18 +2184,6 @@
  	return (0);
  }

-struct ifmultiaddr *
-ifmaof_ifpforaddr(struct sockaddr *sa, struct ifnet *ifp)
-{
-	struct ifmultiaddr *ifma;
-
-	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
-		if (sa_equal(ifma->ifma_addr, sa))
-			break;
-
-	return ifma;
-}
-
  /*
   * The name argument must be a pointer to storage which will last as
   * long as the interface does.  For physical devices, the result of
--- //depot/vendor/freebsd/src/sys/net/if_arcsubr.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/net/if_arcsubr.c	2005/07/22 02:45:35
@@ -798,7 +798,9 @@
  		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
  			return EADDRNOTAVAIL;
  		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
-		       M_ZERO);
+		       M_NOWAIT | M_ZERO);
+		if (sdl == NULL)
+			return ENOMEM;
  		sdl->sdl_len = sizeof *sdl;
  		sdl->sdl_family = AF_LINK;
  		sdl->sdl_index = ifp->if_index;
@@ -824,7 +826,9 @@
  		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
  			return EADDRNOTAVAIL;
  		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
-		       M_ZERO);
+		       M_NOWAIT | M_ZERO);
+		if (sdl == NULL)
+			return ENOMEM;
  		sdl->sdl_len = sizeof *sdl;
  		sdl->sdl_family = AF_LINK;
  		sdl->sdl_index = ifp->if_index;
--- //depot/vendor/freebsd/src/sys/net/if_ethersubr.c	2005/07/21 09:02:12
+++ //depot/projects/netsmp/src/sys/net/if_ethersubr.c	2005/07/23 00:06:01
@@ -1144,7 +1144,9 @@
  		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
  			return EADDRNOTAVAIL;
  		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
-		       M_WAITOK|M_ZERO);
+		       M_NOWAIT|M_ZERO);
+		if (sdl == NULL)
+			return ENOMEM;
  		sdl->sdl_len = sizeof *sdl;
  		sdl->sdl_family = AF_LINK;
  		sdl->sdl_index = ifp->if_index;
@@ -1171,7 +1173,9 @@
  		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
  			return EADDRNOTAVAIL;
  		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
-		       M_WAITOK|M_ZERO);
+		       M_NOWAIT|M_ZERO);
+		if (sdl == NULL)
+			return (ENOMEM);
  		sdl->sdl_len = sizeof *sdl;
  		sdl->sdl_family = AF_LINK;
  		sdl->sdl_index = ifp->if_index;
--- //depot/vendor/freebsd/src/sys/net/if_fddisubr.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/net/if_fddisubr.c	2005/07/22 02:45:35
@@ -720,7 +720,9 @@
  		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
  			return (EADDRNOTAVAIL);
  		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
-		       M_WAITOK);
+		       M_NOWAIT | M_ZERO);
+		if (sdl == NULL)
+			return (ENOMEM);
  		sdl->sdl_len = sizeof *sdl;
  		sdl->sdl_family = AF_LINK;
  		sdl->sdl_index = ifp->if_index;
@@ -749,7 +751,9 @@
  		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
  			return (EADDRNOTAVAIL);
  		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
-		       M_WAITOK);
+		       M_NOWAIT | M_ZERO);
+		if (sdl == NULL)
+			return (ENOMEM);
  		sdl->sdl_len = sizeof *sdl;
  		sdl->sdl_family = AF_LINK;
  		sdl->sdl_index = ifp->if_index;
--- //depot/vendor/freebsd/src/sys/net/if_iso88025subr.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/net/if_iso88025subr.c	2005/07/22 02:45:35
@@ -720,7 +720,9 @@
  			return (EADDRNOTAVAIL);
  		}
  		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
-		       M_WAITOK|M_ZERO);
+		       M_NOWAIT|M_ZERO);
+		if (sdl == NULL)
+			return (ENOMEM);
  		sdl->sdl_len = sizeof *sdl;
  		sdl->sdl_family = AF_LINK;
  		sdl->sdl_index = ifp->if_index;
@@ -748,7 +750,9 @@
  			return (EADDRNOTAVAIL);
  		}
  		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
-		       M_WAITOK|M_ZERO);
+		       M_NOWAIT|M_ZERO);
+		if (sdl == NULL)
+			return (ENOMEM);
  		sdl->sdl_len = sizeof *sdl;
  		sdl->sdl_family = AF_LINK;
  		sdl->sdl_index = ifp->if_index;
--- //depot/vendor/freebsd/src/sys/net/if_var.h	2005/07/21 22:05:31
+++ //depot/projects/netsmp/src/sys/net/if_var.h	2005/07/23 00:06:01
@@ -177,6 +177,7 @@
  	void	*if_afdata[AF_MAX];
  	int	if_afdata_initialized;
  	struct	mtx if_afdata_mtx;
+	struct	mtx if_addr_mtx;	/* mutex to protect address lists */
  	struct	task if_starttask;	/* task for IFF_NEEDSGIANT */
  	struct	task if_linktask;	/* task for link change events */
  };
@@ -217,6 +218,16 @@
  #define	if_list		if_link

  /*
+ * Locks for address lists on the network interface.
+ */
+#define	IF_ADDR_LOCK_INIT(if)	mtx_init(&(if)->if_addr_mtx,		\
+				    "if_addr_mtx", NULL, MTX_DEF)
+#define	IF_ADDR_LOCK_DESTROY(if)	mtx_destroy(&(if)->if_addr_mtx)
+#define	IF_ADDR_LOCK(if)	mtx_lock(&(if)->if_addr_mtx)
+#define	IF_ADDR_UNLOCK(if)	mtx_unlock(&(if)->if_addr_mtx)
+#define	IF_ADDR_LOCK_ASSERT(if)	mtx_assert(&(if)->if_addr_mtx, MA_OWNED)
+
+/*
   * Output queues (ifp->if_snd) and slow device input queues (*ifp->if_slowq)
   * are queues of messages stored on ifqueue structures
   * (defined above).  Entries are added to and deleted from these structures
--- //depot/vendor/freebsd/src/sys/net/if_vlan.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/net/if_vlan.c	2005/07/19 21:29:46
@@ -188,21 +188,27 @@
  	}

  	/* Now program new ones. */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
  		mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT);
-		if (mc == NULL)
+		if (mc == NULL) {
+			IF_ADDR_UNLOCK(ifp);
  			return (ENOMEM);
+		}
  		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
  		    (char *)&mc->mc_addr, ETHER_ADDR_LEN);
  		SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
  		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
  		    LLADDR(&sdl), ETHER_ADDR_LEN);
  		error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma);
-		if (error)
+		if (error) {
+			IF_ADDR_UNLOCK(ifp);
  			return (error);
+		}
  	}
+	IF_ADDR_UNLOCK(ifp);

  	return (0);
  }
--- //depot/vendor/freebsd/src/sys/net/rtsock.c	2005/07/15 09:51:31
+++ //depot/projects/netsmp/src/sys/net/rtsock.c	2005/07/19 21:29:46
@@ -1178,6 +1178,11 @@
  			continue;
  		ifa = ifaddr_byindex(ifp->if_index);
  		info.rti_info[RTAX_IFP] = ifa ? ifa->ifa_addr : NULL;
+
+		/*
+		 * XXXRW: Can't acquire IF_ADDR_LOCK() due to call
+	 	 * to SYSCTL_OUT().
+		 */
  		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  			if (af && af != ifma->ifma_addr->sa_family)
  				continue;
--- //depot/vendor/freebsd/src/sys/netinet/igmp.c	2005/03/26 22:25:15
+++ //depot/projects/netsmp/src/sys/netinet/igmp.c	2005/07/22 02:49:24
@@ -286,6 +286,7 @@
  		 * - Use the value specified in the query message as
  		 *   the maximum timeout.
  		 */
+		IN_MULTI_LOCK();
  		IN_FIRST_MULTI(step, inm);
  		while (inm != NULL) {
  			if (inm->inm_ifp == ifp &&
@@ -301,6 +302,7 @@
  			}
  			IN_NEXT_MULTI(step, inm);
  		}
+		IN_MULTI_UNLOCK();

  		break;

@@ -343,14 +345,15 @@
  		 * If we belong to the group being reported, stop
  		 * our timer for that group.
  		 */
+		IN_MULTI_LOCK();
  		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
-
  		if (inm != NULL) {
  			inm->inm_timer = 0;
  			++igmpstat.igps_rcv_ourreports;

  			inm->inm_state = IGMP_OTHERMEMBER;
  		}
+		IN_MULTI_UNLOCK();

  		break;
  	}
@@ -367,6 +370,8 @@
  {
  	int s = splnet();

+	IN_MULTI_LOCK_ASSERT();
+
  	if (inm->inm_addr.s_addr == igmp_all_hosts_group
  	    || inm->inm_ifp->if_flags & IFF_LOOPBACK) {
  		inm->inm_timer = 0;
@@ -391,6 +396,8 @@
  igmp_leavegroup(struct in_multi *inm)
  {

+	IN_MULTI_LOCK_ASSERT();
+
  	if (inm->inm_state == IGMP_IREPORTEDLAST &&
  	    inm->inm_addr.s_addr != igmp_all_hosts_group &&
  	    !(inm->inm_ifp->if_flags & IFF_LOOPBACK) &&
@@ -414,6 +421,7 @@
  		return;

  	s = splnet();
+	IN_MULTI_LOCK();
  	igmp_timers_are_running = 0;
  	IN_FIRST_MULTI(step, inm);
  	while (inm != NULL) {
@@ -427,6 +435,7 @@
  		}
  		IN_NEXT_MULTI(step, inm);
  	}
+	IN_MULTI_UNLOCK();
  	splx(s);
  }

@@ -458,6 +467,8 @@
  	struct ip *ip;
  	struct ip_moptions imo;

+	IN_MULTI_LOCK_ASSERT();
+
  	MGETHDR(m, M_DONTWAIT, MT_HEADER);
  	if (m == NULL)
  		return;
--- //depot/vendor/freebsd/src/sys/netinet/in.c	2005/06/02 00:07:10
+++ //depot/projects/netsmp/src/sys/netinet/in.c	2005/07/23 00:17:48
@@ -68,7 +68,14 @@
  SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
  	&subnetsarelocal, 0, "Treat all subnets as directly connected");

+/*
+ * The IPv4 multicast list (in_multihead and associated structures)
+ * are protected by the global in_multi_mtx.  See in_var.h for
+ * more details.
+ */
  struct in_multihead in_multihead; /* XXX BSS initialization */
+struct mtx in_multi_mtx;
+MTX_SYSINIT(in_multi_mtx, &in_multi_mtx, "in_multi_mtx", MTX_DEF);

  extern struct inpcbinfo ripcbinfo;
  extern struct inpcbinfo udbinfo;
@@ -949,8 +956,8 @@
  	int error;
  	struct sockaddr_in sin;
  	struct ifmultiaddr *ifma;
-	int s = splnet();

+	IN_MULTI_LOCK();
  	/*
  	 * Call generic routine to add membership or increment
  	 * refcount.  It wants addresses in the form of a sockaddr,
@@ -962,7 +969,7 @@
  	sin.sin_addr = *ap;
  	error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma);
  	if (error) {
-		splx(s);
+		IN_MULTI_UNLOCK();
  		return 0;
  	}

@@ -971,16 +978,14 @@
  	 * a new record.  Otherwise, we are done.
  	 */
  	if (ifma->ifma_protospec != NULL) {
-		splx(s);
+		IN_MULTI_UNLOCK();
  		return ifma->ifma_protospec;
  	}

-	/* XXX - if_addmulti uses M_WAITOK.  Can this really be called
-	   at interrupt time?  If so, need to fix if_addmulti. XXX */
  	inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR,
  	    M_NOWAIT | M_ZERO);
  	if (inm == NULL) {
-		splx(s);
+		IN_MULTI_UNLOCK();
  		return (NULL);
  	}

@@ -994,7 +999,7 @@
  	 * Let IGMP know that we have joined a new IP multicast group.
  	 */
  	igmp_joingroup(inm);
-	splx(s);
+	IN_MULTI_UNLOCK();
  	return (inm);
  }

@@ -1005,10 +1010,11 @@
  in_delmulti(inm)
  	register struct in_multi *inm;
  {
-	struct ifmultiaddr *ifma = inm->inm_ifma;
+	struct ifmultiaddr *ifma;
  	struct in_multi my_inm;
-	int s = splnet();

+	IN_MULTI_LOCK();
+	ifma = inm->inm_ifma;
  	my_inm.inm_ifp = NULL ; /* don't send the leave msg */
  	if (ifma->ifma_refcount == 1) {
  		/*
@@ -1026,5 +1032,5 @@
  	if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
  	if (my_inm.inm_ifp != NULL)
  		igmp_leavegroup(&my_inm);
-	splx(s);
+	IN_MULTI_UNLOCK();
  }
--- //depot/vendor/freebsd/src/sys/netinet/in_var.h	2005/01/07 01:52:23
+++ //depot/projects/netsmp/src/sys/netinet/in_var.h	2005/07/22 02:48:12
@@ -167,6 +167,17 @@
  extern LIST_HEAD(in_multihead, in_multi) in_multihead;

  /*
+ * Lock macros for IPv4 layer multicast address lists.  IPv4 lock goes
+ * before link layer multicast locks in the lock order.  In most cases,
+ * consumers of IN_*_MULTI() macros should acquire the locks before
+ * calling them; users of the in_{add,del}multi() functions should not.
+ */
+extern struct mtx in_multi_mtx;
+#define	IN_MULTI_LOCK()		mtx_lock(&in_multi_mtx)
+#define	IN_MULTI_UNLOCK()	mtx_unlock(&in_multi_mtx)
+#define	IN_MULTI_LOCK_ASSERT()	mtx_assert(&in_multi_mtx, MA_OWNED)
+
+/*
   * Structure used by macros below to remember position when stepping through
   * all of the in_multi records.
   */
@@ -177,6 +188,8 @@
  /*
   * Macro for looking up the in_multi record for a given IP multicast address
   * on a given interface.  If no matching record is found, "inm" is set null.
+ *
+ * Caller must hold IF_ADDR_LOCK().
   */
  #define IN_LOOKUP_MULTI(addr, ifp, inm) \
  	/* struct in_addr addr; */ \
@@ -185,6 +198,8 @@
  do { \
  	struct ifmultiaddr *ifma; \
  \
+	IN_MULTI_LOCK_ASSERT(); \
+	IF_ADDR_LOCK(ifp); \
  	TAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) { \
  		if (ifma->ifma_addr->sa_family == AF_INET \
  		    && ((struct sockaddr_in *)ifma->ifma_addr)->sin_addr.s_addr == \
@@ -192,6 +207,7 @@
  			break; \
  	} \
  	(inm) = ifma ? ifma->ifma_protospec : 0; \
+	IF_ADDR_UNLOCK(ifp); \
  } while(0)

  /*
@@ -205,6 +221,7 @@
  	/* struct in_multistep  step; */ \
  	/* struct in_multi *inm; */ \
  do { \
+	IN_MULTI_LOCK_ASSERT(); \
  	if (((inm) = (step).i_inm) != NULL) \
  		(step).i_inm = LIST_NEXT((step).i_inm, inm_link); \
  } while(0)
@@ -213,6 +230,7 @@
  	/* struct in_multistep step; */ \
  	/* struct in_multi *inm; */ \
  do { \
+	IN_MULTI_LOCK_ASSERT(); \
  	(step).i_inm = LIST_FIRST(&in_multihead); \
  	IN_NEXT_MULTI((step), (inm)); \
  } while(0)
--- //depot/vendor/freebsd/src/sys/netinet/ip_input.c	2005/07/19 12:16:03
+++ //depot/projects/netsmp/src/sys/netinet/ip_input.c	2005/07/22 02:49:24
@@ -607,7 +607,9 @@
  		 * See if we belong to the destination multicast group on the
  		 * arrival interface.
  		 */
+		IN_MULTI_LOCK();
  		IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
+		IN_MULTI_UNLOCK();
  		if (inm == NULL) {
  			ipstat.ips_notmember++;
  			m_freem(m);
--- //depot/vendor/freebsd/src/sys/netinet/ip_output.c	2005/07/05 23:40:38
+++ //depot/projects/netsmp/src/sys/netinet/ip_output.c	2005/07/22 02:49:24
@@ -291,9 +291,15 @@
  				ip->ip_src = IA_SIN(ia)->sin_addr;
  		}

+		/*
+		 * XXXRW: Should the in_multi_mtx be held over
+		 * ip_mloopback() or ip_mforward()?
+		 */
+		IN_MULTI_LOCK();
  		IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
  		if (inm != NULL &&
  		   (imo == NULL || imo->imo_multicast_loop)) {
+			IN_MULTI_UNLOCK();
  			/*
  			 * If we belong to the destination multicast group
  			 * on the outgoing interface, and the caller did not
@@ -302,6 +308,7 @@
  			ip_mloopback(ifp, m, dst, hlen);
  		}
  		else {
+			IN_MULTI_UNLOCK();
  			/*
  			 * If we are acting as a multicast router, perform
  			 * multicast forwarding as if the packet had just
--- //depot/vendor/freebsd/src/sys/netinet6/in6_var.h	2005/02/22 13:06:15
+++ //depot/projects/netsmp/src/sys/netinet6/in6_var.h	2005/07/23 00:13:17
@@ -543,6 +543,7 @@
  /* struct in6_multi *in6m; */					\
  do { \
  	struct ifmultiaddr *ifma; \
+	IF_ADDR_LOCK(ifp); \
  	TAILQ_FOREACH(ifma, &(ifp)->if_multiaddrs, ifma_link) { \
  		if (ifma->ifma_addr->sa_family == AF_INET6 \
  		    && IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)ifma->ifma_addr)->sin6_addr, \
@@ -550,6 +551,7 @@
  			break; \
  	} \
  	(in6m) = (struct in6_multi *)(ifma ? ifma->ifma_protospec : 0); \
+	IF_ADDR_UNLOCK(ifp); \
  } while(0)

  /*
--- //depot/vendor/freebsd/src/sys/netinet6/mld6.c	2005/07/21 15:10:30
+++ //depot/projects/netsmp/src/sys/netinet6/mld6.c	2005/07/23 00:06:01
@@ -266,6 +266,7 @@
  		mld6_all_nodes_linklocal.s6_addr16[1] =
  			htons(ifp->if_index); /* XXX */

+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  			if (ifma->ifma_addr->sa_family != AF_INET6)
  				continue;
@@ -296,6 +297,7 @@
  				}
  			}
  		}
+		IF_ADDR_UNLOCK(ifp);

  		if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
  			mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
--- //depot/vendor/freebsd/src/sys/pci/if_dc.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/pci/if_dc.c	2005/07/19 21:29:46
@@ -1110,6 +1110,7 @@
  	else
  		DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);

+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1117,6 +1118,7 @@
  		    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
  		sp[h >> 4] |= htole32(1 << (h & 0xF));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (ifp->if_flags & IFF_BROADCAST) {
  		h = dc_mchash_le(sc, ifp->if_broadcastaddr);
@@ -1179,6 +1181,7 @@
  		return;

  	/* Now program new ones. */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1193,6 +1196,7 @@
  		else
  			hashes[1] |= (1 << (h - 32));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	CSR_WRITE_4(sc, DC_AL_MAR0, hashes[0]);
  	CSR_WRITE_4(sc, DC_AL_MAR1, hashes[1]);
@@ -1250,6 +1254,7 @@
  		return;

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1259,6 +1264,7 @@
  		else
  			hashes[1] |= (1 << (h - 32));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0);
  	CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[0]);
@@ -1302,6 +1308,7 @@
  	else
  		DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);

+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1309,6 +1316,7 @@
  		    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
  		sp[h >> 4] |= htole32(1 << (h & 0xF));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (ifp->if_flags & IFF_BROADCAST) {
  		h = dc_mchash_le(sc, ifp->if_broadcastaddr);
--- //depot/vendor/freebsd/src/sys/pci/if_de.c	2005/07/21 16:45:20
+++ //depot/projects/netsmp/src/sys/pci/if_de.c	2005/07/23 00:06:01
@@ -2968,6 +2968,7 @@
  #endif

      multicnt = 0;
+    IF_ADDR_LOCK(sc->tulip_ifp);
      TAILQ_FOREACH(ifma, &sc->tulip_ifp->if_multiaddrs, ifma_link) {

  	    if (ifma->ifma_addr->sa_family == AF_LINK)
@@ -3089,6 +3090,7 @@
  #endif
  	}
      }
+    IF_ADDR_UNLOCK(sc->tulip_ifp);
  #if defined(IFF_ALLMULTI)
      if (sc->tulip_flags & TULIP_ALLMULTI)
  	sc->tulip_ifp->if_flags |= IFF_ALLMULTI;
--- //depot/vendor/freebsd/src/sys/pci/if_pcn.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/pci/if_pcn.c	2005/07/19 21:29:46
@@ -351,6 +351,7 @@
  		pcn_csr_write(sc, PCN_CSR_MAR0 + i, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -358,6 +359,7 @@
  		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
  		hashes[h >> 4] |= 1 << (h & 0xF);
  	}
+	IF_ADDR_UNLOCK(ifp);

  	for (i = 0; i < 4; i++)
  		pcn_csr_write(sc, PCN_CSR_MAR0 + i, hashes[i]);
--- //depot/vendor/freebsd/src/sys/pci/if_rl.c	2005/06/11 01:40:36
+++ //depot/projects/netsmp/src/sys/pci/if_rl.c	2005/07/19 21:29:46
@@ -685,6 +685,7 @@
  	CSR_WRITE_4(sc, RL_MAR4, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -696,6 +697,7 @@
  			hashes[1] |= (1 << (h - 32));
  		mcnt++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt)
  		rxfilt |= RL_RXCFG_RX_MULTI;
--- //depot/vendor/freebsd/src/sys/pci/if_sf.c	2005/06/11 01:40:36
+++ //depot/projects/netsmp/src/sys/pci/if_sf.c	2005/07/19 21:29:46
@@ -431,6 +431,7 @@
  		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
  	} else {
  		i = 1;
+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
  			if (ifma->ifma_addr->sa_family != AF_LINK)
  				continue;
@@ -449,6 +450,7 @@
  			sf_sethash(sc,
  			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
  		}
+		IF_ADDR_UNLOCK(ifp);
  	}
  }

--- //depot/vendor/freebsd/src/sys/pci/if_sis.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/pci/if_sis.c	2005/07/19 21:29:46
@@ -763,6 +763,7 @@
  		CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
  	}

+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -775,6 +776,7 @@
  			bit -= 0x10;
  		SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);

@@ -813,6 +815,7 @@
  		for (i = 0; i < n; i++)
  			hashes[i] = 0;
  		i = 0;
+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  			if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -821,6 +824,7 @@
  			hashes[h >> 4] |= 1 << (h & 0xf);
  			i++;
  		}
+		IF_ADDR_UNLOCK(ifp);
  		if (i > n) {
  			ctl |= SIS_RXFILTCTL_ALLMULTI;
  			for (i = 0; i < n; i++)
--- //depot/vendor/freebsd/src/sys/pci/if_sk.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/pci/if_sk.c	2005/07/19 21:29:46
@@ -823,6 +823,7 @@
  		hashes[1] = 0xFFFFFFFF;
  	} else {
  		i = 1;
+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
  			if (ifma->ifma_addr->sa_family != AF_LINK)
  				continue;
@@ -855,6 +856,7 @@
  			else
  				hashes[1] |= (1 << (h - 32));
  		}
+		IF_ADDR_UNLOCK(ifp);
  	}

  	switch(sc->sk_type) {
--- //depot/vendor/freebsd/src/sys/pci/if_ste.c	2005/07/08 13:11:56
+++ //depot/projects/netsmp/src/sys/pci/if_ste.c	2005/07/19 21:29:46
@@ -579,6 +579,7 @@
  	CSR_WRITE_2(sc, STE_MAR3, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -589,6 +590,7 @@
  		else
  			hashes[1] |= (1 << (h - 32));
  	}
+	IF_ADDR_UNLOCK(ifp);

  	CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF);
  	CSR_WRITE_2(sc, STE_MAR1, (hashes[0] >> 16) & 0xFFFF);
--- //depot/vendor/freebsd/src/sys/pci/if_ti.c	2005/07/07 01:10:31
+++ //depot/projects/netsmp/src/sys/pci/if_ti.c	2005/07/19 21:29:46
@@ -1621,6 +1621,7 @@
  	}

  	/* Now program new ones. */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -1634,6 +1635,7 @@
  		SLIST_INSERT_HEAD(&sc->ti_mc_listhead, mc, mc_entries);
  		ti_add_mcast(sc, &mc->mc_addr);
  	}
+	IF_ADDR_UNLOCK(ifp);

  	/* Re-enable interrupts. */
  	CSR_WRITE_4(sc, TI_MB_HOSTINTR, intrs);
--- //depot/vendor/freebsd/src/sys/pci/if_tl.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/pci/if_tl.c	2005/07/19 21:29:46
@@ -960,6 +960,7 @@
  		hashes[1] = 0xFFFFFFFF;
  	} else {
  		i = 1;
+		IF_ADDR_LOCK(ifp);
  		TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
  			if (ifma->ifma_addr->sa_family != AF_LINK)
  				continue;
@@ -982,6 +983,7 @@
  			else
  				hashes[1] |= (1 << (h - 32));
  		}
+		IF_ADDR_UNLOCK(ifp);
  	}

  	tl_dio_write32(sc, TL_HASH1, hashes[0]);
--- //depot/vendor/freebsd/src/sys/pci/if_vr.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/pci/if_vr.c	2005/07/19 21:29:46
@@ -533,6 +533,7 @@
  	CSR_WRITE_4(sc, VR_MAR1, 0);

  	/* Now program new ones. */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -544,6 +545,7 @@
  			hashes[1] |= (1 << (h - 32));
  		mcnt++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt)
  		rxfilt |= VR_RXCFG_RX_MULTI;
--- //depot/vendor/freebsd/src/sys/pci/if_wb.c	2005/06/10 16:51:34
+++ //depot/projects/netsmp/src/sys/pci/if_wb.c	2005/07/19 21:29:46
@@ -614,6 +614,7 @@
  	CSR_WRITE_4(sc, WB_MAR1, 0);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -625,6 +626,7 @@
  			hashes[1] |= (1 << (h - 32));
  		mcnt++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt)
  		rxfilt |= WB_NETCFG_RX_MULTI;
--- //depot/vendor/freebsd/src/sys/pci/if_xl.c	2005/07/13 14:10:33
+++ //depot/projects/netsmp/src/sys/pci/if_xl.c	2005/07/19 21:29:46
@@ -777,8 +777,10 @@
  		return;
  	}

+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
  		mcnt++;
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt)
  		rxfilt |= XL_RXFILTER_ALLMULTI;
@@ -817,6 +819,7 @@
  		CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|i);

  	/* now program new ones */
+	IF_ADDR_LOCK(ifp);
  	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  		if (ifma->ifma_addr->sa_family != AF_LINK)
  			continue;
@@ -838,6 +841,7 @@
  		    h | XL_CMD_RX_SET_HASH | XL_HASH_SET);
  		mcnt++;
  	}
+	IF_ADDR_UNLOCK(ifp);

  	if (mcnt)
  		rxfilt |= XL_RXFILTER_MULTIHASH;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050723012046.K40216>