diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index 89e2c5f55447..bd9226a3ba67 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -240,7 +240,7 @@ CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach,
 static void aue_reset_pegasus_II(struct aue_softc *);
 
 static void aue_uno_stop(struct ifnet *, int);
-static int aue_uno_ioctl(struct ifnet *, u_long, void *);
+static void aue_uno_mcast(struct ifnet *);
 static int aue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int aue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void aue_uno_mii_statchg(struct ifnet *);
@@ -252,7 +252,7 @@ static void aue_uno_intr(struct usbnet *, usbd_status);
 
 static const struct usbnet_ops aue_ops = {
 	.uno_stop = aue_uno_stop,
-	.uno_ioctl = aue_uno_ioctl,
+	.uno_mcast = aue_uno_mcast,
 	.uno_read_reg = aue_uno_mii_read_reg,
 	.uno_write_reg = aue_uno_mii_write_reg,
 	.uno_statchg = aue_uno_mii_statchg,
@@ -483,6 +483,8 @@ aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val)
 	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ);
 
 	for (i = 0; i < AUE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
 			break;
 	}
@@ -524,6 +526,8 @@ aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val)
 	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE);
 
 	for (i = 0; i < AUE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
 			break;
 	}
@@ -607,10 +611,10 @@ aue_crc(void *addrv)
 }
 
 static void
-aue_setiff_locked(struct usbnet *un)
+aue_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet * const un = ifp->if_softc;
 	struct aue_softc * const sc = usbnet_softc(un);
-	struct ifnet * const	ifp = usbnet_ifp(un);
 	struct ethercom *	ec = usbnet_ec(un);
 	struct ether_multi	*enm;
 	struct ether_multistep	step;
@@ -623,21 +627,20 @@ aue_setiff_locked(struct usbnet *un)
 	usbnet_isowned_core(un);
 
 	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
 allmulti:
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
 		return;
 	}
 
-	AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
-
 	/* now program new ones */
 	ETHER_LOCK(ec);
 	ETHER_FIRST_MULTI(step, ec, enm);
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo,
 		    enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -645,13 +648,14 @@ allmulti:
 		hashtbl[h >> 3] |= 1 << (h & 0x7);
 		ETHER_NEXT_MULTI(step, enm);
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
+	AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
+
 	/* write the hashtable */
 	for (i = 0; i < 8; i++)
 		aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]);
-
-	ifp->if_flags &= ~IFF_ALLMULTI;
 }
 
 static void
@@ -680,6 +684,8 @@ aue_reset(struct aue_softc *sc)
 	AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC);
 
 	for (i = 0; i < AUE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
 			break;
 	}
@@ -948,7 +954,7 @@ aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-aue_init_locked(struct ifnet *ifp)
+aue_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 	struct aue_softc	*sc = usbnet_softc(un);
@@ -982,7 +988,7 @@ aue_init_locked(struct ifnet *ifp)
 	rv = usbnet_init_rx_tx(un);
 
 	/* Load the multicast filter. */
-	aue_setiff_locked(un);
+	aue_uno_mcast(ifp);
 
 	/* Enable RX and TX */
 	aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
@@ -994,42 +1000,6 @@ aue_init_locked(struct ifnet *ifp)
 	return rv;
 }
 
-static int
-aue_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const	un = ifp->if_softc;
-	int rv;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	rv = aue_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return rv;
-}
-
-static int
-aue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
-{
-
-	AUEHIST_FUNC();
-	AUEHIST_CALLARGSN(5, "aue%jd: enter cmd %#jx data %#jx",
-	    device_unit(((struct usbnet *)(ifp->if_softc))->un_dev),
-	    cmd, (uintptr_t)data, 0);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		aue_uno_init(ifp);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
 static void
 aue_uno_stop(struct ifnet *ifp, int disable)
 {
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index eba67386e770..cb42c4ce17a3 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -259,7 +259,7 @@ CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc),
 	axe_match, axe_attach, usbnet_detach, usbnet_activate);
 
 static void	axe_uno_stop(struct ifnet *, int);
-static int	axe_uno_ioctl(struct ifnet *, u_long, void *);
+static void	axe_uno_mcast(struct ifnet *);
 static int	axe_uno_init(struct ifnet *);
 static int	axe_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int	axe_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
@@ -276,7 +276,7 @@ static void	axe_ax88772b_init(struct axe_softc *);
 
 static const struct usbnet_ops axe_ops = {
 	.uno_stop = axe_uno_stop,
-	.uno_ioctl = axe_uno_ioctl,
+	.uno_mcast = axe_uno_mcast,
 	.uno_read_reg = axe_uno_mii_read_reg,
 	.uno_write_reg = axe_uno_mii_write_reg,
 	.uno_statchg = axe_uno_mii_statchg,
@@ -426,11 +426,11 @@ axe_uno_mii_statchg(struct ifnet *ifp)
 }
 
 static void
-axe_rcvfilt_locked(struct usbnet *un)
+axe_uno_mcast(struct ifnet *ifp)
 {
 	AXEHIST_FUNC(); AXEHIST_CALLED();
+	struct usbnet * const un = ifp->if_softc;
 	struct axe_softc * const sc = usbnet_softc(un);
-	struct ifnet * const ifp = usbnet_ifp(un);
 	struct ethercom *ec = usbnet_ec(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -930,10 +930,8 @@ axe_attach(device_t parent, device_t self, void *aux)
 
 	/* We need the PHYID for init dance in some cases */
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 	if (axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, &sc->axe_phyaddrs)) {
 		aprint_error_dev(self, "failed to read phyaddrs\n");
-		usbnet_unbusy(un);
 		usbnet_unlock_core(un);
 		return;
 	}
@@ -964,13 +962,11 @@ axe_attach(device_t parent, device_t self, void *aux)
 	} else {
 		if (axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs)) {
 			aprint_error_dev(self, "failed to read ipg\n");
-			usbnet_unbusy(un);
 			usbnet_unlock_core(un);
 			return;
 		}
 	}
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	if (!AXE_IS_172(un))
@@ -1140,8 +1136,6 @@ axe_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 	size_t hdr_len = 0, tlr_len = 0;
 	int length, boundary;
 
-	usbnet_isowned_tx(un);
-
 	if (!AXE_IS_172(un)) {
 		/*
 		 * Copy the mbuf data into a contiguous buffer, leaving two
@@ -1216,7 +1210,7 @@ axe_csum_cfg(struct axe_softc *sc)
 }
 
 static int
-axe_init_locked(struct ifnet *ifp)
+axe_uno_init(struct ifnet *ifp)
 {
 	AXEHIST_FUNC(); AXEHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
@@ -1307,48 +1301,11 @@ axe_init_locked(struct ifnet *ifp)
 	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
 
 	/* Accept multicast frame or run promisc. mode */
-	axe_rcvfilt_locked(un);
+	axe_uno_mcast(ifp);
 
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-axe_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	int ret = axe_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return ret;
-}
-
-static int
-axe_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		axe_rcvfilt_locked(un);
-		break;
-	default:
-		break;
-	}
-
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return 0;
-}
-
 static void
 axe_uno_stop(struct ifnet *ifp, int disable)
 {
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index bf91d56b356d..55ffb9335e3b 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -80,6 +80,7 @@ static void	axen_ax88179_init(struct usbnet *);
 
 static void	axen_uno_stop(struct ifnet *, int);
 static int	axen_uno_ioctl(struct ifnet *, u_long, void *);
+static void	axen_uno_mcast(struct ifnet *);
 static int	axen_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int	axen_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void	axen_uno_mii_statchg(struct ifnet *);
@@ -92,6 +93,7 @@ static int	axen_uno_init(struct ifnet *);
 static const struct usbnet_ops axen_ops = {
 	.uno_stop = axen_uno_stop,
 	.uno_ioctl = axen_uno_ioctl,
+	.uno_mcast = axen_uno_mcast,
 	.uno_read_reg = axen_uno_mii_read_reg,
 	.uno_write_reg = axen_uno_mii_write_reg,
 	.uno_statchg = axen_uno_mii_statchg,
@@ -223,9 +225,9 @@ axen_uno_mii_statchg(struct ifnet *ifp)
 }
 
 static void
-axen_setiff_locked(struct usbnet *un)
+axen_uno_mcast(struct ifnet *ifp)
 {
-	struct ifnet * const ifp = usbnet_ifp(un);
+	struct usbnet * const un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -366,7 +368,6 @@ axen_ax88179_init(struct usbnet *un)
 	uint8_t val;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	/* XXX: ? */
 	axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val);
@@ -450,7 +451,6 @@ axen_ax88179_init(struct usbnet *un)
 	default:
 		aprint_error_dev(un->un_dev, "unknown uplink bus:0x%02x\n",
 		    val);
-		usbnet_unbusy(un);
 		usbnet_unlock_core(un);
 		return;
 	}
@@ -510,7 +510,6 @@ axen_ax88179_init(struct usbnet *un)
 	usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0000);
 #endif
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
@@ -556,15 +555,8 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		axen_setiff_locked(un);
-		break;
 	case SIOCSIFCAP:
 		axen_setoe_locked(un);
 		break;
@@ -572,7 +564,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		break;
 	}
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	return 0;
@@ -676,14 +667,11 @@ axen_attach(device_t parent, device_t self, void *aux)
 
 	/* Get station address.  */
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 	if (axen_get_eaddr(un, &un->un_eaddr)) {
-		usbnet_unbusy(un);
 		usbnet_unlock_core(un);
 		printf("EEPROM checksum error\n");
 		return;
 	}
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	axen_ax88179_init(un);
@@ -894,7 +882,7 @@ axen_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-axen_init_locked(struct ifnet *ifp)
+axen_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 	uint16_t rxmode;
@@ -920,7 +908,7 @@ axen_init_locked(struct ifnet *ifp)
 	axen_setoe_locked(un);
 
 	/* Program promiscuous mode and multicast filters. */
-	axen_setiff_locked(un);
+	axen_uno_mcast(ifp);
 
 	/* Enable receiver, set RX mode */
 	axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
@@ -932,20 +920,6 @@ axen_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-axen_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	int ret = axen_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return ret;
-}
-
 static void
 axen_uno_stop(struct ifnet *ifp, int disable)
 {
diff --git a/sys/dev/usb/if_cdce.c b/sys/dev/usb/if_cdce.c
index 3edf73d856ca..c7ee6bef2792 100644
--- a/sys/dev/usb/if_cdce.c
+++ b/sys/dev/usb/if_cdce.c
@@ -261,7 +261,6 @@ cdce_uno_init(struct ifnet *ifp)
 	struct usbnet		*un = ifp->if_softc;
 	int rv;
 
-	usbnet_lock_core(un);
 	if (usbnet_isdying(un))
 		rv = EIO;
 	else {
@@ -269,7 +268,6 @@ cdce_uno_init(struct ifnet *ifp)
 		rv = usbnet_init_rx_tx(un);
 		usbnet_set_link(un, rv == 0);
 	}
-	usbnet_unlock_core(un);
 
 	return rv;
 }
@@ -279,8 +277,6 @@ cdce_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len)
 {
 	struct ifnet		*ifp = usbnet_ifp(un);
 
-	usbnet_isowned_rx(un);
-
 	/* Strip off CRC added by Zaurus, if present */
 	if (un->un_flags & CDCE_ZAURUS && total_len > 4)
 		total_len -= 4;
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index e730297a939d..a3902bc54679 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -141,14 +141,14 @@ CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach,
 static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *,
 				   struct usbnet_chain *);
 static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
-static int cue_uno_ioctl(struct ifnet *, u_long, void *);
+static void cue_uno_mcast(struct ifnet *);
 static void cue_uno_stop(struct ifnet *, int);
 static int cue_uno_init(struct ifnet *);
 static void cue_uno_tick(struct usbnet *);
 
 static const struct usbnet_ops cue_ops = {
 	.uno_stop = cue_uno_stop,
-	.uno_ioctl = cue_uno_ioctl,
+	.uno_mcast = cue_uno_mcast,
 	.uno_tx_prepare = cue_uno_tx_prepare,
 	.uno_rx_loop = cue_uno_rx_loop,
 	.uno_init = cue_uno_init,
@@ -357,11 +357,11 @@ cue_crc(const char *addr)
 }
 
 static void
-cue_setiff_locked(struct usbnet *un)
+cue_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet		*un = ifp->if_softc;
 	struct cue_softc	*sc = usbnet_softc(un);
 	struct ethercom		*ec = usbnet_ec(un);
-	struct ifnet		*ifp = usbnet_ifp(un);
 	struct ether_multi	*enm;
 	struct ether_multistep	step;
 	uint32_t		h, i;
@@ -370,8 +370,10 @@ cue_setiff_locked(struct usbnet *un)
 	    device_xname(un->un_dev), ifp->if_flags));
 
 	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
 allmulti:
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
 			sc->cue_mctab[i] = 0xFF;
 		cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
@@ -389,7 +391,6 @@ allmulti:
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo,
 		    enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -397,10 +398,9 @@ allmulti:
 		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
 		ETHER_NEXT_MULTI(step, enm);
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
-	ifp->if_flags &= ~IFF_ALLMULTI;
-
 	/*
 	 * Also include the broadcast address in the filter
 	 * so we can receive broadcast frames.
@@ -613,7 +613,7 @@ cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-cue_init_locked(struct ifnet *ifp)
+cue_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 	int			i, ctl;
@@ -622,7 +622,7 @@ cue_init_locked(struct ifnet *ifp)
 	DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__));
 
 	if (usbnet_isdying(un))
-		return -1;
+		return ENXIO;
 
 	/* Cancel pending I/O */
 	usbnet_stop(un, ifp, 1);
@@ -648,7 +648,7 @@ cue_init_locked(struct ifnet *ifp)
 	cue_csr_write_1(un, CUE_ETHCTL, ctl);
 
 	/* Load the multicast filter. */
-	cue_setiff_locked(un);
+	cue_uno_mcast(ifp);
 
 	/*
 	 * Set the number of RX and TX buffers that we want
@@ -667,44 +667,6 @@ cue_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-cue_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const	un = ifp->if_softc;
-	int rv;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	rv = cue_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return rv;
-}
-
-static int
-cue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
-{
-	struct usbnet * const	un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		cue_setiff_locked(un);
-		break;
-	default:
-		break;
-	}
-
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return 0;
-}
-
 /* Stop and reset the adapter.  */
 static void
 cue_uno_stop(struct ifnet *ifp, int disable)
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index 172bc93fa301..15f32d81409f 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -174,11 +174,11 @@ CFATTACH_DECL_NEW(kue, sizeof(struct kue_softc), kue_match, kue_attach,
 static void kue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static unsigned kue_uno_tx_prepare(struct usbnet *, struct mbuf *,
 				   struct usbnet_chain *);
-static int kue_uno_ioctl(struct ifnet *, u_long, void *);
+static void kue_uno_mcast(struct ifnet *);
 static int kue_uno_init(struct ifnet *);
 
 static const struct usbnet_ops kue_ops = {
-	.uno_ioctl = kue_uno_ioctl,
+	.uno_mcast = kue_uno_mcast,
 	.uno_tx_prepare = kue_uno_tx_prepare,
 	.uno_rx_loop = kue_uno_rx_loop,
 	.uno_init = kue_uno_init,
@@ -318,11 +318,11 @@ kue_load_fw(struct usbnet *un)
 }
 
 static void
-kue_setiff_locked(struct usbnet *un)
+kue_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet *		un = ifp->if_softc;
 	struct ethercom *	ec = usbnet_ec(un);
 	struct kue_softc *	sc = usbnet_softc(un);
-	struct ifnet * const	ifp = usbnet_ifp(un);
 	struct ether_multi	*enm;
 	struct ether_multistep	step;
 	int			i;
@@ -336,8 +336,10 @@ kue_setiff_locked(struct usbnet *un)
 		sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC;
 
 	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
 allmulti:
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC;
 		sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST;
 		kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
@@ -353,7 +355,6 @@ allmulti:
 		if (i == KUE_MCFILTCNT(sc) ||
 		    memcmp(enm->enm_addrlo, enm->enm_addrhi,
 		    ETHER_ADDR_LEN) != 0) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -361,10 +362,9 @@ allmulti:
 		ETHER_NEXT_MULTI(step, enm);
 		i++;
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
-	ifp->if_flags &= ~IFF_ALLMULTI;
-
 	sc->kue_rxfilt |= KUE_RXFILT_MULTICAST;
 	kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS,
 	    i, sc->kue_mcfilters, i * ETHER_ADDR_LEN);
@@ -591,7 +591,7 @@ kue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-kue_init_locked(struct ifnet *ifp)
+kue_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 	struct kue_softc	*sc = usbnet_softc(un);
@@ -622,49 +622,11 @@ kue_init_locked(struct ifnet *ifp)
 	kue_setword(un, KUE_CMD_SET_URB_SIZE, 64);
 
 	/* Load the multicast filter. */
-	kue_setiff_locked(un);
+	kue_uno_mcast(ifp);
 
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-kue_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const	un = ifp->if_softc;
-	int rv;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	rv = kue_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return rv;
-}
-
-static int
-kue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
-{
-	struct usbnet * const	un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		kue_setiff_locked(un);
-		break;
-	default:
-		break;
-	}
-
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return 0;
-}
-
 #ifdef _MODULE
 #include "ioconf.c"
 #endif
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index 347104b7b0df..afe02a06ed22 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -145,7 +145,7 @@ CFATTACH_DECL_NEW(mos, sizeof(struct usbnet),
 static void mos_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static unsigned mos_uno_tx_prepare(struct usbnet *, struct mbuf *,
 				   struct usbnet_chain *);
-static int mos_uno_ioctl(struct ifnet *, u_long, void *);
+static void mos_uno_mcast(struct ifnet *);
 static int mos_uno_init(struct ifnet *);
 static void mos_chip_init(struct usbnet *);
 static void mos_uno_stop(struct ifnet *ifp, int disable);
@@ -164,7 +164,7 @@ static int mos_write_mcast(struct usbnet *, uint8_t *);
 
 static const struct usbnet_ops mos_ops = {
 	.uno_stop = mos_uno_stop,
-	.uno_ioctl = mos_uno_ioctl,
+	.uno_mcast = mos_uno_mcast,
 	.uno_read_reg = mos_uno_mii_read_reg,
 	.uno_write_reg = mos_uno_mii_write_reg,
 	.uno_statchg = mos_uno_mii_statchg,
@@ -364,6 +364,8 @@ mos_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val)
 	    MOS_PHYSTS_PENDING);
 
 	for (i = 0; i < MOS_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY)
 			break;
 	}
@@ -396,6 +398,8 @@ mos_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val)
 	    MOS_PHYSTS_PENDING);
 
 	for (i = 0; i < MOS_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY)
 			break;
 	}
@@ -454,9 +458,9 @@ mos_uno_mii_statchg(struct ifnet *ifp)
 }
 
 static void
-mos_rcvfilt_locked(struct usbnet *un)
+mos_uno_mcast(struct ifnet *ifp)
 {
-	struct ifnet		*ifp = usbnet_ifp(un);
+	struct usbnet		*un = ifp->if_softc;
 	struct ethercom		*ec = usbnet_ec(un);
 	struct ether_multi	*enm;
 	struct ether_multistep	step;
@@ -719,7 +723,7 @@ mos_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-mos_init_locked(struct ifnet *ifp)
+mos_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 	u_int8_t		rxmode;
@@ -744,7 +748,7 @@ mos_init_locked(struct ifnet *ifp)
 	mos_reg_write_1(un, MOS_IPG1, ipgs[1]);
 
 	/* Accept multicast frame or run promisc. mode */
-	mos_rcvfilt_locked(un);
+	mos_uno_mcast(ifp);
 
 	/* Enable receiver and transmitter, bridge controls speed/duplex mode */
 	rxmode = mos_reg_read_1(un, MOS_CTL);
@@ -755,43 +759,6 @@ mos_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-mos_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	int ret = mos_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return ret;
-}
-
-static int
-mos_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		mos_rcvfilt_locked(un);
-		break;
-	default:
-		break;
-	}
-
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return 0;
-}
-
 void
 mos_uno_stop(struct ifnet *ifp, int disable)
 {
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 559b9eff2569..c63911009771 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -92,7 +92,7 @@ static int	mue_chip_init(struct usbnet *);
 static void	mue_set_macaddr(struct usbnet *);
 static int	mue_get_macaddr(struct usbnet *, prop_dictionary_t);
 static int	mue_prepare_tso(struct usbnet *, struct mbuf *);
-static void	mue_setiff_locked(struct usbnet *);
+static void	mue_uno_mcast(struct ifnet *);
 static void	mue_sethwcsum_locked(struct usbnet *);
 static void	mue_setmtu_locked(struct usbnet *);
 static void	mue_reset(struct usbnet *);
@@ -111,6 +111,7 @@ static int	mue_uno_init(struct ifnet *);
 static const struct usbnet_ops mue_ops = {
 	.uno_stop = mue_uno_stop,
 	.uno_ioctl = mue_uno_ioctl,
+	.uno_mcast = mue_uno_mcast,
 	.uno_read_reg = mue_uno_mii_read_reg,
 	.uno_write_reg = mue_uno_mii_write_reg,
 	.uno_statchg = mue_uno_mii_statchg,
@@ -200,6 +201,8 @@ mue_wait_for_bits(struct usbnet *un, uint32_t reg,
 	int ntries;
 
 	for (ntries = 0; ntries < 1000; ntries++) {
+		if (usbnet_isdying(un))
+			return 1;
 		val = mue_csr_read(un, reg);
 		if ((val & set) || !(val & clear))
 			return 0;
@@ -993,10 +996,10 @@ mue_prepare_tso(struct usbnet *un, struct mbuf *m)
 }
 
 static void
-mue_setiff_locked(struct usbnet *un)
+mue_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet *un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
-	struct ifnet * const ifp = usbnet_ifp(un);
 	const uint8_t *enaddr = CLLADDR(ifp->if_sadl);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -1020,10 +1023,11 @@ mue_setiff_locked(struct usbnet *un)
 	/* Always accept broadcast frames. */
 	rxfilt |= MUE_RFE_CTL_BROADCAST;
 
+	ETHER_LOCK(ec);
 	if (ifp->if_flags & IFF_PROMISC) {
 		rxfilt |= MUE_RFE_CTL_UNICAST;
 allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
 		if (ifp->if_flags & IFF_PROMISC)
 			DPRINTF(un, "promisc\n");
 		else
@@ -1033,7 +1037,6 @@ allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
 		pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID;
 		pfiltbl[0][1] = MUE_ENADDR_LO(enaddr);
 		i = 1;
-		ETHER_LOCK(ec);
 		ETHER_FIRST_MULTI(step, ec, enm);
 		while (enm != NULL) {
 			if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
@@ -1041,7 +1044,6 @@ allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
 				memset(pfiltbl, 0, sizeof(pfiltbl));
 				memset(hashtbl, 0, sizeof(hashtbl));
 				rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH;
-				ETHER_UNLOCK(ec);
 				goto allmulti;
 			}
 			if (i < MUE_NUM_ADDR_FILTX) {
@@ -1059,14 +1061,14 @@ allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
 			i++;
 			ETHER_NEXT_MULTI(step, enm);
 		}
-		ETHER_UNLOCK(ec);
+		ec->ec_flags &= ~ETHER_F_ALLMULTI;
 		rxfilt |= MUE_RFE_CTL_PERFECT;
-		ifp->if_flags &= ~IFF_ALLMULTI;
 		if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH)
 			DPRINTF(un, "perfect filter and hash tables\n");
 		else
 			DPRINTF(un, "perfect filter\n");
 	}
+	ETHER_UNLOCK(ec);
 
 	for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) {
 		hireg = (un->un_flags & LAN7500) ?
@@ -1219,7 +1221,7 @@ mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
 }
 
 static int
-mue_init_locked(struct ifnet *ifp)
+mue_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
@@ -1238,7 +1240,7 @@ mue_init_locked(struct ifnet *ifp)
 	mue_set_macaddr(un);
 
 	/* Load the multicast filter. */
-	mue_setiff_locked(un);
+	mue_uno_mcast(ifp);
 
 	/* TCP/UDP checksum offload engines. */
 	mue_sethwcsum_locked(un);
@@ -1249,36 +1251,14 @@ mue_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-mue_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const	un = ifp->if_softc;
-	int rv;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	rv = mue_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return rv;
-}
-
 static int
 mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		mue_setiff_locked(un);
-		break;
 	case SIOCSIFCAP:
 		mue_sethwcsum_locked(un);
 		break;
@@ -1289,7 +1269,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		break;
 	}
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	return 0;
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 6cf37e507d1c..751d0c982eb7 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -174,7 +174,6 @@ static int	 smsc_chip_init(struct usbnet *);
 static int	 smsc_setmacaddress(struct usbnet *, const uint8_t *);
 
 static int	 smsc_uno_init(struct ifnet *);
-static int	 smsc_init_locked(struct ifnet *);
 static void	 smsc_uno_stop(struct ifnet *, int);
 
 static void	 smsc_reset(struct smsc_softc *);
@@ -187,6 +186,7 @@ static int	 smsc_uno_miibus_readreg(struct usbnet *, int, int, uint16_t *);
 static int	 smsc_uno_miibus_writereg(struct usbnet *, int, int, uint16_t);
 
 static int	 smsc_uno_ioctl(struct ifnet *, u_long, void *);
+static void	 smsc_uno_mcast(struct ifnet *);
 static unsigned	 smsc_uno_tx_prepare(struct usbnet *, struct mbuf *,
 		     struct usbnet_chain *);
 static void	 smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *,
@@ -195,6 +195,7 @@ static void	 smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *,
 static const struct usbnet_ops smsc_ops = {
 	.uno_stop = smsc_uno_stop,
 	.uno_ioctl = smsc_uno_ioctl,
+	.uno_mcast = smsc_uno_mcast,
 	.uno_read_reg = smsc_uno_miibus_readreg,
 	.uno_write_reg = smsc_uno_miibus_writereg,
 	.uno_statchg = smsc_uno_miibus_statchg,
@@ -264,6 +265,8 @@ smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits)
 	int err, i;
 
 	for (i = 0; i < 100; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if ((err = smsc_readreg(un, reg, &val)) != 0)
 			return err;
 		if (!(val & bits))
@@ -408,11 +411,11 @@ smsc_hash(uint8_t addr[ETHER_ADDR_LEN])
 }
 
 static void
-smsc_setiff_locked(struct usbnet *un)
+smsc_uno_mcast(struct ifnet *ifp)
 {
 	USMSCHIST_FUNC(); USMSCHIST_CALLED();
+	struct usbnet * const un = ifp->if_softc;
 	struct smsc_softc * const sc = usbnet_softc(un);
-	struct ifnet * const ifp = usbnet_ifp(un);
 	struct ethercom *ec = usbnet_ec(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -424,8 +427,11 @@ smsc_setiff_locked(struct usbnet *un)
 	if (usbnet_isdying(un))
 		return;
 
-	if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
+	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
 allmulti:
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		DPRINTF("receive all multicast enabled", 0, 0, 0, 0);
 		sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS;
 		sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT;
@@ -440,7 +446,6 @@ allmulti:
 	ETHER_FIRST_MULTI(step, ec, enm);
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -448,6 +453,7 @@ allmulti:
 		hashtbl[hash >> 5] |= 1 << (hash & 0x1F);
 		ETHER_NEXT_MULTI(step, enm);
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
 	/* Debug */
@@ -460,7 +466,6 @@ allmulti:
 	/* Write the hash table and mac control registers */
 
 	//XXX should we be doing this?
-	ifp->if_flags &= ~IFF_ALLMULTI;
 	smsc_writereg(un, SMSC_HASHH, hashtbl[1]);
 	smsc_writereg(un, SMSC_HASHL, hashtbl[0]);
 	smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr);
@@ -549,20 +554,6 @@ smsc_reset(struct smsc_softc *sc)
 
 static int
 smsc_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	int ret = smsc_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return ret;
-}
-
-static int
-smsc_init_locked(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 	struct smsc_softc * const sc = usbnet_softc(un);
@@ -579,7 +570,7 @@ smsc_init_locked(struct ifnet *ifp)
 	smsc_reset(sc);
 
 	/* Load the multicast filter. */
-	smsc_setiff_locked(un);
+	smsc_uno_mcast(ifp);
 
 	/* TCP/UDP checksum offload engines. */
 	smsc_setoe_locked(un);
@@ -754,15 +745,8 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		smsc_setiff_locked(un);
-		break;
 	case SIOCSIFCAP:
 		smsc_setoe_locked(un);
 		break;
@@ -770,7 +754,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		break;
 	}
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	return 0;
@@ -882,7 +865,6 @@ smsc_attach(device_t parent, device_t self, void *aux)
 	un->un_phyno = 1;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 	/*
 	 * Attempt to get the mac address, if an EEPROM is not attached this
 	 * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC
@@ -910,7 +892,6 @@ smsc_attach(device_t parent, device_t self, void *aux)
 			un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff);
 		}
 	}
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index a38a83a53df0..32978d4d2dd5 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -69,12 +69,11 @@ static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *,
 				    struct usbnet_chain *);
 static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static void udav_uno_stop(struct ifnet *, int);
-static int udav_uno_ioctl(struct ifnet *, u_long, void *);
+static void udav_uno_mcast(struct ifnet *);
 static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void udav_uno_mii_statchg(struct ifnet *);
 static int udav_uno_init(struct ifnet *);
-static void udav_setiff_locked(struct usbnet *);
 static void udav_reset(struct usbnet *);
 
 static int udav_csr_read(struct usbnet *, int, void *, int);
@@ -132,7 +131,7 @@ static const struct udav_type {
 
 static const struct usbnet_ops udav_ops = {
 	.uno_stop = udav_uno_stop,
-	.uno_ioctl = udav_uno_ioctl,
+	.uno_mcast = udav_uno_mcast,
 	.uno_read_reg = udav_uno_mii_read_reg,
 	.uno_write_reg = udav_uno_mii_write_reg,
 	.uno_statchg = udav_uno_mii_statchg,
@@ -240,14 +239,12 @@ udav_attach(device_t parent, device_t self, void *aux)
 	usbnet_attach(un, "udavdet");
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 // 	/* reset the adapter */
 // 	udav_reset(un);
 
 	/* Get Ethernet Address */
 	err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN);
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 	if (err) {
 		aprint_error_dev(self, "read MAC address failed\n");
@@ -478,10 +475,7 @@ udav_uno_init(struct ifnet *ifp)
 
 	DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__));
 
-	usbnet_lock_core(un);
-
 	if (usbnet_isdying(un)) {
-		usbnet_unlock_core(un);
 		return EIO;
 	}
 
@@ -489,8 +483,6 @@ udav_uno_init(struct ifnet *ifp)
 	if (ifp->if_flags & IFF_RUNNING)
 		usbnet_stop(un, ifp, 1);
 
-	usbnet_busy(un);
-
 	memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr));
 	udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN);
 
@@ -508,7 +500,7 @@ udav_uno_init(struct ifnet *ifp)
 		UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC);
 
 	/* Load the multicast filter */
-	udav_setiff_locked(un);
+	udav_uno_mcast(ifp);
 
 	/* Enable RX */
 	UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN);
@@ -521,8 +513,6 @@ udav_uno_init(struct ifnet *ifp)
 		rc = 0;
 
 	if (rc != 0) {
-		usbnet_unbusy(un);
-		usbnet_unlock_core(un);
 		return rc;
 	}
 
@@ -531,9 +521,6 @@ udav_uno_init(struct ifnet *ifp)
 	else
 		rc = usbnet_init_rx_tx(un);
 
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
 	return rc;
 }
 
@@ -573,6 +560,8 @@ udav_chip_init(struct usbnet *un)
 	UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST);
 
 	for (int i = 0; i < UDAV_TX_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST))
 			break;
 		delay(10);	/* XXX */
@@ -586,10 +575,10 @@ udav_chip_init(struct usbnet *un)
 	(ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1))
 
 static void
-udav_setiff_locked(struct usbnet *un)
+udav_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet * const un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
-	struct ifnet * const ifp = usbnet_ifp(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
 	uint8_t hashes[8];
@@ -609,11 +598,16 @@ udav_setiff_locked(struct usbnet *un)
 	}
 
 	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC);
 		return;
-	} else if (ifp->if_flags & IFF_ALLMULTI) {
+	} else if (ifp->if_flags & IFF_ALLMULTI) { /* XXX ??? Can't happen? */
+		ETHER_LOCK(ec);
 allmulti:
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL);
 		UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC);
 		return;
@@ -630,7 +624,6 @@ allmulti:
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
 		    ETHER_ADDR_LEN) != 0) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -638,10 +631,10 @@ allmulti:
 		hashes[h>>3] |= 1 << (h & 0x7);
 		ETHER_NEXT_MULTI(step, enm);
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
 	/* disable all multicast */
-	ifp->if_flags &= ~IFF_ALLMULTI;
 	UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL);
 
 	/* write hash value to the register */
@@ -721,29 +714,6 @@ udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
 	usbnet_enqueue(un, buf, pkt_len, 0, 0, 0);
 }
 
-static int
-udav_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		udav_setiff_locked(un);
-		break;
-	default:
-		break;
-	}
-
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return 0;
-}
-
 /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
 static void
 udav_uno_stop(struct ifnet *ifp, int disable)
diff --git a/sys/dev/usb/if_upl.c b/sys/dev/usb/if_upl.c
index fb99702f160e..cf4ba9de209f 100644
--- a/sys/dev/usb/if_upl.c
+++ b/sys/dev/usb/if_upl.c
@@ -257,12 +257,10 @@ upl_uno_init(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 	int rv;
 
-	usbnet_lock_core(un);
 	if (usbnet_isdying(un))
 		rv = EIO;
 	else
 		rv = usbnet_init_rx_tx(un);
-	usbnet_unlock_core(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index ea5b3023dd31..8d6da56a603a 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -86,7 +86,7 @@ static void	ure_disable_teredo(struct usbnet *);
 static void	ure_init_fifo(struct usbnet *);
 
 static void	ure_uno_stop(struct ifnet *, int);
-static int	ure_uno_ioctl(struct ifnet *, u_long, void *);
+static void	ure_uno_mcast(struct ifnet *);
 static int	ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int	ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void	ure_uno_miibus_statchg(struct ifnet *);
@@ -104,7 +104,7 @@ CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach,
 
 static const struct usbnet_ops ure_ops = {
 	.uno_stop = ure_uno_stop,
-	.uno_ioctl = ure_uno_ioctl,
+	.uno_mcast = ure_uno_mcast,
 	.uno_read_reg = ure_uno_mii_read_reg,
 	.uno_write_reg = ure_uno_mii_write_reg,
 	.uno_statchg = ure_uno_miibus_statchg,
@@ -331,10 +331,10 @@ ure_uno_miibus_statchg(struct ifnet *ifp)
 }
 
 static void
-ure_rcvfilt_locked(struct usbnet *un)
+ure_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet *un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
-	struct ifnet *ifp = usbnet_ifp(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
 	uint32_t mchash[2] = { 0, 0 };
@@ -396,6 +396,8 @@ ure_reset(struct usbnet *un)
 	ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST);
 
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) &
 		    URE_CR_RST))
 			break;
@@ -406,7 +408,7 @@ ure_reset(struct usbnet *un)
 }
 
 static int
-ure_init_locked(struct ifnet *ifp)
+ure_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 	uint8_t eaddr[8];
@@ -446,25 +448,11 @@ ure_init_locked(struct ifnet *ifp)
 	    ~URE_RXDY_GATED_EN);
 
 	/* Accept multicast frame or run promisc. mode. */
-	ure_rcvfilt_locked(un);
+	ure_uno_mcast(ifp);
 
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-ure_uno_init(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-	int ret = ure_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return ret;
-}
-
 static void
 ure_uno_stop(struct ifnet *ifp, int disable __unused)
 {
@@ -543,6 +531,8 @@ ure_rtl8153_init(struct usbnet *un)
 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
 
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) &
 		    URE_AUTOLOAD_DONE)
 			break;
@@ -552,6 +542,8 @@ ure_rtl8153_init(struct usbnet *un)
 		URE_PRINTF(un, "timeout waiting for chip autoload\n");
 
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) &
 		    URE_PHY_STAT_MASK;
 		if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN)
@@ -750,6 +742,8 @@ ure_init_fifo(struct usbnet *un)
 	    ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) &
 	    ~URE_MCU_BORW_EN);
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
 		    URE_LINK_LIST_READY)
 			break;
@@ -761,6 +755,8 @@ ure_init_fifo(struct usbnet *un)
 	    ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) |
 	    URE_RE_INIT_LL);
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
 		    URE_LINK_LIST_READY)
 			break;
@@ -794,29 +790,6 @@ ure_init_fifo(struct usbnet *un)
 	    URE_TXFIFO_THR_NORMAL);
 }
 
-static int
-ure_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		ure_rcvfilt_locked(un);
-		break;
-	default:
-		break;
-	}
-
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return 0;
-}
-
 static int
 ure_match(device_t parent, cfdata_t match, void *aux)
 {
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index 764b9c654682..9dbf854db9cb 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -77,11 +77,10 @@ static unsigned	url_uno_tx_prepare(struct usbnet *, struct mbuf *,
 static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
-static int url_uno_ioctl(struct ifnet *, u_long, void *);
 static void url_uno_stop(struct ifnet *, int);
 static void url_uno_mii_statchg(struct ifnet *);
 static int url_uno_init(struct ifnet *);
-static void url_rcvfilt_locked(struct usbnet *);
+static void url_uno_mcast(struct ifnet *);
 static void url_reset(struct usbnet *);
 
 static int url_csr_read_1(struct usbnet *, int);
@@ -93,7 +92,7 @@ static int url_mem(struct usbnet *, int, int, void *, int);
 
 static const struct usbnet_ops url_ops = {
 	.uno_stop = url_uno_stop,
-	.uno_ioctl = url_uno_ioctl,
+	.uno_mcast = url_uno_mcast,
 	.uno_read_reg = url_uno_mii_read_reg,
 	.uno_write_reg = url_uno_mii_write_reg,
 	.uno_statchg = url_uno_mii_statchg,
@@ -244,7 +243,6 @@ url_attach(device_t parent, device_t self, void *aux)
 	usbnet_attach(un, "urldet");
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	/* reset the adapter */
 	url_reset(un);
@@ -252,22 +250,15 @@ url_attach(device_t parent, device_t self, void *aux)
 	/* Get Ethernet Address */
 	err = url_mem(un, URL_CMD_READMEM, URL_IDR0, (void *)un->un_eaddr,
 		      ETHER_ADDR_LEN);
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 	if (err) {
 		aprint_error_dev(self, "read MAC address failed\n");
-		goto bad;
+		return;
 	}
 
 	/* initialize interface information */
 	usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
 	    0, &unm);
-
-	return;
-
- bad:
-	usbnet_set_dying(un, true);
-	return;
 }
 
 /* read/write memory */
@@ -401,7 +392,7 @@ url_init_locked(struct ifnet *ifp)
 	URL_SETBIT2(un, URL_RCR, URL_RCR_TAIL | URL_RCR_AD | URL_RCR_AB);
 
 	/* Accept multicast frame or run promisc. mode */
-	url_rcvfilt_locked(un);
+	url_uno_mcast(ifp);
 
 	/* Enable RX and TX */
 	URL_SETBIT(un, URL_CR, URL_CR_TE | URL_CR_RE);
@@ -412,13 +403,7 @@ url_init_locked(struct ifnet *ifp)
 static int
 url_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
 	int ret = url_init_locked(ifp);
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return ret;
 }
@@ -436,6 +421,8 @@ url_reset(struct usbnet *un)
 	URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST);
 
 	for (i = 0; i < URL_TX_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST))
 			break;
 		delay(10);	/* XXX */
@@ -445,9 +432,9 @@ url_reset(struct usbnet *un)
 }
 
 static void
-url_rcvfilt_locked(struct usbnet *un)
+url_uno_mcast(struct ifnet *ifp)
 {
-	struct ifnet * const ifp = usbnet_ifp(un);
+	struct usbnet * const un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -565,29 +552,6 @@ static void url_intr(void)
 }
 #endif
 
-static int
-url_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_lock_core(un);
-	usbnet_busy(un);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		url_rcvfilt_locked(un);
-		break;
-	default:
-		break;
-	}
-
-	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
-
-	return 0;
-}
-
 /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
 static void
 url_uno_stop(struct ifnet *ifp, int disable)
diff --git a/sys/dev/usb/if_urndis.c b/sys/dev/usb/if_urndis.c
index 381207450d72..ff4da0414739 100644
--- a/sys/dev/usb/if_urndis.c
+++ b/sys/dev/usb/if_urndis.c
@@ -883,8 +883,15 @@ static int
 urndis_uno_init(struct ifnet *ifp)
 {
 	struct usbnet *un = ifp->if_softc;
+	int error;
 
-	return urndis_init_un(ifp, un);
+	KASSERT(IFNET_LOCKED(ifp));
+
+	usbnet_unlock_core(un);
+	error = urndis_init_un(ifp, un);
+	usbnet_lock_core(un);
+
+	return error;
 }
 
 static int
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 1712d2f687f0..31562ec087a7 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -56,7 +56,6 @@ struct usbnet_private {
 	 *   and the MII / media data.
 	 * - unp_rxlock protects the rx path and its data
 	 * - unp_txlock protects the tx path and its data
-	 * - unp_detachcv handles detach vs open references
 	 *
 	 * the lock ordering is:
 	 *	ifnet lock -> unp_core_lock -> unp_rxlock -> unp_txlock
@@ -66,22 +65,22 @@ struct usbnet_private {
 	kmutex_t		unp_core_lock;
 	kmutex_t		unp_rxlock;
 	kmutex_t		unp_txlock;
-	kcondvar_t		unp_detachcv;
 
 	struct usbnet_cdata	unp_cdata;
 
 	struct ethercom		unp_ec;
 	struct mii_data		unp_mii;
+	struct usb_task		unp_mcasttask;
 	struct usb_task		unp_ticktask;
 	struct callout		unp_stat_ch;
 	struct usbd_pipe	*unp_ep[USBNET_ENDPT_MAX];
 
-	bool			unp_dying;
+	volatile bool		unp_dying;
 	bool			unp_stopping;
 	bool			unp_attached;
+	bool			unp_ifp_attached;
 	bool			unp_link;
 
-	int			unp_refcnt;
 	int			unp_timer;
 	unsigned short		unp_if_flags;
 	unsigned		unp_number;
@@ -97,6 +96,9 @@ struct usbnet_private {
 
 volatile unsigned usbnet_number;
 
+static void usbnet_isowned_rx(struct usbnet *);
+static void usbnet_isowned_tx(struct usbnet *);
+
 static int usbnet_modcmd(modcmd_t, void *);
 
 #ifdef USB_DEBUG
@@ -149,6 +151,8 @@ fail:
 static void
 uno_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 {
+	KASSERTMSG(!un->un_pri->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
 	usbnet_isowned_core(un);
 	if (un->un_ops->uno_stop)
 		(*un->un_ops->uno_stop)(ifp, disable);
@@ -157,11 +161,11 @@ uno_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 static int
 uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data)
 {
-	/*
-	 * There are cases where IFNET_LOCK will not be held when we
-	 * are called (e.g. add/delete multicast address), so we can't
-	 * assert it.
-	 */
+
+	KASSERTMSG(cmd != SIOCADDMULTI, "%s", ifp->if_xname);
+	KASSERTMSG(cmd != SIOCDELMULTI, "%s", ifp->if_xname);
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	if (un->un_ops->uno_ioctl)
 		return (*un->un_ops->uno_ioctl)(ifp, cmd, data);
 	return 0;
@@ -170,14 +174,22 @@ uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data)
 static int
 uno_override_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data)
 {
-	/* See above. */
+
+	switch (cmd) {
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		break;
+	default:
+		KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+	}
+
 	return (*un->un_ops->uno_override_ioctl)(ifp, cmd, data);
 }
 
 static int
 uno_init(struct usbnet *un, struct ifnet *ifp)
 {
-	KASSERT(IFNET_LOCKED(ifp));
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 	return (*un->un_ops->uno_init)(ifp);
 }
 
@@ -333,7 +345,6 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	struct usbnet_chain * const c = priv;
 	struct usbnet * const un = c->unc_un;
 	struct usbnet_private * const unp = un->un_pri;
-	struct ifnet * const ifp = usbnet_ifp(un);
 	uint32_t total_len;
 
 	USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx",
@@ -341,9 +352,9 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 
 	mutex_enter(&unp->unp_rxlock);
 
-	if (unp->unp_dying || unp->unp_stopping ||
+	if (usbnet_isdying(un) || unp->unp_stopping ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
-	    status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING))
+	    status == USBD_CANCELLED)
 		goto out;
 
 	if (status != USBD_NORMAL_COMPLETION) {
@@ -368,7 +379,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	usbnet_isowned_rx(un);
 
 done:
-	if (unp->unp_dying || unp->unp_stopping)
+	if (usbnet_isdying(un) || unp->unp_stopping)
 		goto out;
 
 	mutex_exit(&unp->unp_rxlock);
@@ -397,7 +408,7 @@ usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	    unp->unp_number, status, (uintptr_t)xfer, 0);
 
 	mutex_enter(&unp->unp_txlock);
-	if (unp->unp_stopping || unp->unp_dying) {
+	if (unp->unp_stopping || usbnet_isdying(un)) {
 		mutex_exit(&unp->unp_txlock);
 		return;
 	}
@@ -440,14 +451,13 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	struct usbnet * const un = priv;
 	struct usbnet_private * const unp = un->un_pri;
 	struct usbnet_intr * const uni = un->un_intr;
-	struct ifnet * const ifp = usbnet_ifp(un);
 
-	if (uni == NULL || unp->unp_dying || unp->unp_stopping ||
+	if (uni == NULL || usbnet_isdying(un) || unp->unp_stopping ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
-	    status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) {
+	    status == USBD_CANCELLED) {
 		USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx",
 		    unp->unp_number, (uintptr_t)uni,
-		    (unp->unp_dying << 8) | unp->unp_stopping, status);
+		    (usbnet_isdying(un) << 8) | unp->unp_stopping, status);
 		return;
 	}
 
@@ -818,14 +828,15 @@ usbnet_init_rx_tx(struct usbnet * const un)
 	usbd_status err;
 	int error = 0;
 
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
+
 	usbnet_isowned_core(un);
 
-	if (unp->unp_dying) {
+	if (usbnet_isdying(un)) {
 		return EIO;
 	}
 
-	usbnet_busy(un);
-
 	/* Open RX and TX pipes. */
 	err = usbnet_ep_open_pipes(un);
 	if (err) {
@@ -849,16 +860,15 @@ usbnet_init_rx_tx(struct usbnet * const un)
 		goto out;
 	}
 
-	/* Start up the receive pipe(s). */
-	usbnet_rx_start_pipes(un);
-
 	/* Indicate we are up and running. */
-#if 0
-	/* XXX if_mcast_op() can call this without ifnet locked */
-	KASSERT(ifp->if_softc == NULL || IFNET_LOCKED(ifp));
-#endif
+	/* XXX urndis calls usbnet_init_rx_tx before usbnet_attach_ifp.  */
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
 	ifp->if_flags |= IFF_RUNNING;
 
+	/* Start up the receive pipe(s). */
+	usbnet_rx_start_pipes(un);
+
 	callout_schedule(&unp->unp_stat_ch, hz);
 
 out:
@@ -867,34 +877,12 @@ out:
 		usbnet_tx_list_fini(un);
 		usbnet_ep_close_pipes(un);
 	}
-	usbnet_unbusy(un);
 
 	usbnet_isowned_core(un);
 
 	return error;
 }
 
-void
-usbnet_busy(struct usbnet *un)
-{
-	struct usbnet_private * const unp = un->un_pri;
-
-	usbnet_isowned_core(un);
-
-	unp->unp_refcnt++;
-}
-
-void
-usbnet_unbusy(struct usbnet *un)
-{
-	struct usbnet_private * const unp = un->un_pri;
-
-	usbnet_isowned_core(un);
-
-	if (--unp->unp_refcnt < 0)
-		cv_broadcast(&unp->unp_detachcv);
-}
-
 /* MII management. */
 
 int
@@ -902,23 +890,19 @@ usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val)
 {
 	USBNETHIST_FUNC();
 	struct usbnet * const un = device_private(dev);
-	struct usbnet_private * const unp = un->un_pri;
 	int err;
 
 	/* MII layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
-	if (unp->unp_dying) {
+	if (usbnet_isdying(un)) {
 		return EIO;
 	}
 
-	usbnet_busy(un);
 	err = uno_read_reg(un, phy, reg, val);
-	usbnet_unbusy(un);
-
 	if (err) {
 		USBNETHIST_CALLARGS("%jd: read PHY failed: %jd",
-		    unp->unp_number, err, 0, 0);
+		    un->un_pri->unp_number, err, 0, 0);
 		return err;
 	}
 
@@ -930,23 +914,19 @@ usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val)
 {
 	USBNETHIST_FUNC();
 	struct usbnet * const un = device_private(dev);
-	struct usbnet_private * const unp = un->un_pri;
 	int err;
 
 	/* MII layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
-	if (unp->unp_dying) {
+	if (usbnet_isdying(un)) {
 		return EIO;
 	}
 
-	usbnet_busy(un);
 	err = uno_write_reg(un, phy, reg, val);
-	usbnet_unbusy(un);
-
 	if (err) {
 		USBNETHIST_CALLARGS("%jd: write PHY failed: %jd",
-		    unp->unp_number, err, 0, 0);
+		    un->un_pri->unp_number, err, 0, 0);
 		return err;
 	}
 
@@ -962,9 +942,7 @@ usbnet_mii_statchg(struct ifnet *ifp)
 	/* MII layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
-	usbnet_busy(un);
 	uno_mii_statchg(un, ifp);
-	usbnet_unbusy(un);
 }
 
 static int
@@ -978,7 +956,10 @@ usbnet_media_upd(struct ifnet *ifp)
 	/* ifmedia layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
-	if (unp->unp_dying)
+	/* ifmedia changes only with IFNET_LOCK held.  */
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
+	if (usbnet_isdying(un))
 		return EIO;
 
 	unp->unp_link = false;
@@ -1004,7 +985,7 @@ usbnet_ifflags_cb(struct ethercom *ec)
 	struct usbnet_private * const unp = un->un_pri;
 	int rv = 0;
 
-	mutex_enter(&unp->unp_core_lock);
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 
 	const u_short changed = ifp->if_flags ^ unp->unp_if_flags;
 	if ((changed & ~(IFF_CANTCHANGE | IFF_DEBUG)) == 0) {
@@ -1015,8 +996,6 @@ usbnet_ifflags_cb(struct ethercom *ec)
 		rv = ENETRESET;
 	}
 
-	mutex_exit(&unp->unp_core_lock);
-
 	return rv;
 }
 
@@ -1035,12 +1014,61 @@ usbnet_if_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		return uno_override_ioctl(un, ifp, cmd, data);
 
 	error = ether_ioctl(ifp, cmd, data);
-	if (error == ENETRESET)
-		error = uno_ioctl(un, ifp, cmd, data);
+	if (error == ENETRESET) {
+		switch (cmd) {
+		case SIOCADDMULTI:
+		case SIOCDELMULTI:
+			usb_add_task(un->un_udev, &unp->unp_mcasttask,
+			    USB_TASKQ_DRIVER);
+			error = 0;
+			break;
+		default:
+			error = uno_ioctl(un, ifp, cmd, data);
+		}
+	}
 
 	return error;
 }
 
+static void
+usbnet_mcast_task(void *arg)
+{
+	USBNETHIST_FUNC();
+	struct usbnet * const un = arg;
+	struct ifnet * const ifp = usbnet_ifp(un);
+
+	USBNETHIST_CALLARGSN(10, "%jd: enter",
+	    un->un_pri->unp_number, 0, 0, 0);
+
+	/*
+	 * If we're detaching, we must check usbnet_isdying _before_
+	 * touching IFNET_LOCK -- the ifnet may have been detached by
+	 * the time this task runs.  This is racy -- unp_dying may be
+	 * set immediately after we test it -- but nevertheless safe,
+	 * because usbnet_detach waits for the task to complete before
+	 * issuing if_detach, and necessary, so that we don't touch
+	 * IFNET_LOCK after if_detach.  See usbnet_detach for details.
+	 */
+	if (usbnet_isdying(un))
+		return;
+
+	/*
+	 * If the hardware is running, ask the driver to reprogram the
+	 * multicast filter.  If the hardware is not running, the
+	 * driver is responsible for programming the multicast filter
+	 * as part of its uno_init routine to bring the hardware up.
+	 */
+	IFNET_LOCK(ifp);
+	if (ifp->if_flags & IFF_RUNNING) {
+		if (un->un_ops->uno_mcast) {
+			mutex_enter(&un->un_pri->unp_core_lock);
+			(*un->un_ops->uno_mcast)(ifp);
+			mutex_exit(&un->un_pri->unp_core_lock);
+		}
+	}
+	IFNET_UNLOCK(ifp);
+}
+
 /*
  * Generic stop network function:
  *	- mark as stopping
@@ -1061,32 +1089,44 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
 	usbnet_isowned_core(un);
 
-	usbnet_busy(un);
-
+	/*
+	 * Prevent new activity (rescheduling ticks, xfers, &c.) and
+	 * clear the watchdog timer.
+	 */
 	mutex_enter(&unp->unp_rxlock);
 	mutex_enter(&unp->unp_txlock);
 	unp->unp_stopping = true;
+	unp->unp_timer = 0;
 	mutex_exit(&unp->unp_txlock);
 	mutex_exit(&unp->unp_rxlock);
 
-	uno_stop(un, ifp, disable);
-
 	/*
-	 * XXXSMP Would like to
-	 *	KASSERT(IFNET_LOCKED(ifp))
-	 * here but the locking order is:
-	 *	ifnet -> core_lock -> rxlock -> txlock
-	 * and core_lock is already held.
+	 * Stop the timer first, then the task -- if the timer was
+	 * already firing, we stop the task or wait for it complete
+	 * only after if last fired.  Setting unp_stopping prevents the
+	 * timer task from being scheduled again.
 	 */
-	ifp->if_flags &= ~IFF_RUNNING;
-	unp->unp_timer = 0;
-
 	callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock);
 	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
 	    &unp->unp_core_lock);
 
+	/*
+	 * Now that the software is quiescent, ask the driver to stop
+	 * the hardware.  The driver's uno_stop routine now has
+	 * exclusive access to any registers that might previously have
+	 * been used by to ifmedia, mii, or ioctl callbacks.
+	 *
+	 * Don't bother if the device is being detached, though -- if
+	 * it's been unplugged then there's no point in trying to touch
+	 * the registers.
+	 */
+	if (!usbnet_isdying(un))
+		uno_stop(un, ifp, disable);
+
 	/* Stop transfers. */
 	usbnet_ep_stop_pipes(un);
 
@@ -1097,7 +1137,10 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	/* Close pipes. */
 	usbnet_ep_close_pipes(un);
 
-	usbnet_unbusy(un);
+	/* Everything is quesced now. */
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
+	ifp->if_flags &= ~IFF_RUNNING;
 }
 
 static void
@@ -1106,6 +1149,8 @@ usbnet_if_stop(struct ifnet *ifp, int disable)
 	struct usbnet * const un = ifp->if_softc;
 	struct usbnet_private * const unp = un->un_pri;
 
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	mutex_enter(&unp->unp_core_lock);
 	usbnet_stop(un, ifp, disable);
 	mutex_exit(&unp->unp_core_lock);
@@ -1126,10 +1171,8 @@ usbnet_tick(void *arg)
 
 	USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0);
 
-	if (unp != NULL && !unp->unp_stopping && !unp->unp_dying) {
-		/* Perform periodic stuff in process context */
-		usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER);
-	}
+	/* Perform periodic stuff in process context */
+	usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER);
 }
 
 static void
@@ -1164,27 +1207,15 @@ usbnet_tick_task(void *arg)
 	USBNETHIST_FUNC();
 	struct usbnet * const un = arg;
 	struct usbnet_private * const unp = un->un_pri;
-
-	if (unp == NULL)
-		return;
-
-	USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0);
-
-	mutex_enter(&unp->unp_core_lock);
-	if (unp->unp_stopping || unp->unp_dying) {
-		mutex_exit(&unp->unp_core_lock);
-		return;
-	}
-
 	struct ifnet * const ifp = usbnet_ifp(un);
 	struct mii_data * const mii = usbnet_mii(un);
 
-	KASSERT(ifp != NULL);	/* embedded member */
-
-	usbnet_busy(un);
-	mutex_exit(&unp->unp_core_lock);
+	USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0);
 
-	if (unp->unp_timer != 0 && --unp->unp_timer == 0)
+	mutex_enter(&unp->unp_txlock);
+	const bool timeout = unp->unp_timer != 0 && --unp->unp_timer == 0;
+	mutex_exit(&unp->unp_txlock);
+	if (timeout)
 		usbnet_watchdog(ifp);
 
 	DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0);
@@ -1200,8 +1231,7 @@ usbnet_tick_task(void *arg)
 	uno_tick(un);
 
 	mutex_enter(&unp->unp_core_lock);
-	usbnet_unbusy(un);
-	if (!unp->unp_stopping && !unp->unp_dying)
+	if (!unp->unp_stopping && !usbnet_isdying(un))
 		callout_schedule(&unp->unp_stat_ch, hz);
 	mutex_exit(&unp->unp_core_lock);
 }
@@ -1211,8 +1241,22 @@ usbnet_if_init(struct ifnet *ifp)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
+	int error;
+
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
+	/*
+	 * Prevent anyone from bringing the interface back up once
+	 * we're detaching.
+	 */
+	if (usbnet_isdying(un))
+		return EIO;
+
+	mutex_enter(&un->un_pri->unp_core_lock);
+	error = uno_init(un, ifp);
+	mutex_exit(&un->un_pri->unp_core_lock);
 
-	return uno_init(un, ifp);
+	return error;
 }
 
 
@@ -1224,12 +1268,6 @@ usbnet_set_link(struct usbnet *un, bool link)
 	un->un_pri->unp_link = link;
 }
 
-void
-usbnet_set_dying(struct usbnet *un, bool link)
-{
-	un->un_pri->unp_dying = link;
-}
-
 struct ifnet *
 usbnet_ifp(struct usbnet *un)
 {
@@ -1269,7 +1307,7 @@ usbnet_havelink(struct usbnet *un)
 bool
 usbnet_isdying(struct usbnet *un)
 {
-	return un->un_pri == NULL || un->un_pri->unp_dying;
+	return atomic_load_relaxed(&un->un_pri->unp_dying);
 }
 
 
@@ -1287,46 +1325,22 @@ usbnet_unlock_core(struct usbnet *un)
 	mutex_exit(&un->un_pri->unp_core_lock);
 }
 
-kmutex_t *
+kmutex_t*
 usbnet_mutex_core(struct usbnet *un)
 {
 	return &un->un_pri->unp_core_lock;
 }
 
-void
-usbnet_lock_rx(struct usbnet *un)
-{
-	mutex_enter(&un->un_pri->unp_rxlock);
-}
-
-void
-usbnet_unlock_rx(struct usbnet *un)
-{
-	mutex_exit(&un->un_pri->unp_rxlock);
-}
-
-kmutex_t *
-usbnet_mutex_rx(struct usbnet *un)
-{
-	return &un->un_pri->unp_rxlock;
-}
-
-void
-usbnet_lock_tx(struct usbnet *un)
-{
-	mutex_enter(&un->un_pri->unp_txlock);
-}
-
-void
-usbnet_unlock_tx(struct usbnet *un)
+static void
+usbnet_isowned_rx(struct usbnet *un)
 {
-	mutex_exit(&un->un_pri->unp_txlock);
+	KASSERT(mutex_owned(&un->un_pri->unp_rxlock));
 }
 
-kmutex_t *
-usbnet_mutex_tx(struct usbnet *un)
+static void
+usbnet_isowned_tx(struct usbnet *un)
 {
-	return &un->un_pri->unp_txlock;
+	KASSERT(mutex_owned(&un->un_pri->unp_txlock));
 }
 
 /* Autoconf management. */
@@ -1373,14 +1387,16 @@ usbnet_attach(struct usbnet *un,
 	un->un_pri = kmem_zalloc(sizeof(*un->un_pri), KM_SLEEP);
 	struct usbnet_private * const unp = un->un_pri;
 
-	usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un, USB_TASKQ_MPSAFE);
+	usb_init_task(&unp->unp_mcasttask, usbnet_mcast_task, un,
+	    USB_TASKQ_MPSAFE);
+	usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un,
+	    USB_TASKQ_MPSAFE);
 	callout_init(&unp->unp_stat_ch, CALLOUT_MPSAFE);
 	callout_setfunc(&unp->unp_stat_ch, usbnet_tick, un);
 
 	mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
 	mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
 	mutex_init(&unp->unp_core_lock, MUTEX_DEFAULT, IPL_NONE);
-	cv_init(&unp->unp_detachcv, detname);
 
 	rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
@@ -1435,7 +1451,9 @@ usbnet_attach_ifp(struct usbnet *un,
 	struct ifnet * const ifp = usbnet_ifp(un);
 
 	KASSERT(unp->unp_attached);
+	KASSERT(!unp->unp_ifp_attached);
 
+	ifp->if_softc = un;
 	strlcpy(ifp->if_xname, device_xname(un->un_dev), IFNAMSIZ);
 	ifp->if_flags = if_flags;
 	ifp->if_extflags = IFEF_MPSAFE | if_extflags;
@@ -1454,6 +1472,7 @@ usbnet_attach_ifp(struct usbnet *un,
 	if (ifp->_if_input == NULL)
 		ifp->if_percpuq = if_percpuq_create(ifp);
 	if_register(ifp);
+	unp->unp_ifp_attached = true;
 
 	/*
 	 * If ethernet address is all zero, skip ether_ifattach() and
@@ -1471,7 +1490,6 @@ usbnet_attach_ifp(struct usbnet *un,
 
 	/* Now ready, and attached. */
 	IFQ_SET_READY(&ifp->if_snd);
-	ifp->if_softc = un;
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, un->un_udev, un->un_dev);
 
@@ -1493,39 +1511,42 @@ usbnet_detach(device_t self, int flags)
 	struct ifnet * const ifp = usbnet_ifp(un);
 	struct mii_data * const mii = usbnet_mii(un);
 
-	mutex_enter(&unp->unp_core_lock);
-	unp->unp_dying = true;
-	mutex_exit(&unp->unp_core_lock);
+	/*
+	 * Prevent new activity.  After we stop the interface, it
+	 * cannot be brought back up.
+	 */
+	atomic_store_relaxed(&unp->unp_dying, true);
 
-	if (ifp->if_flags & IFF_RUNNING) {
+	/*
+	 * If we're still running on the network, stop and wait for all
+	 * asynchronous activity to finish.
+	 *
+	 * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but
+	 * no activity is possible, so just skip this part.
+	 */
+	if (unp->unp_ifp_attached) {
 		IFNET_LOCK(ifp);
-		usbnet_if_stop(ifp, 1);
+		if (ifp->if_flags & IFF_RUNNING) {
+			usbnet_if_stop(ifp, 1);
+		}
 		IFNET_UNLOCK(ifp);
 	}
 
-	callout_halt(&unp->unp_stat_ch, NULL);
-	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
-	    NULL);
-
-	mutex_enter(&unp->unp_core_lock);
-	unp->unp_refcnt--;
-	while (unp->unp_refcnt >= 0) {
-		/* Wait for processes to go away */
-		cv_wait(&unp->unp_detachcv, &unp->unp_core_lock);
-	}
-	mutex_exit(&unp->unp_core_lock);
-
-	usbnet_rx_list_free(un);
-	usbnet_tx_list_free(un);
+	/*
+	 * The callout and tick task can't be scheduled anew at this
+	 * point, and usbnet_if_stop has waited for them to complete.
+	 */
+	KASSERT(!callout_pending(&unp->unp_stat_ch));
+	KASSERT(!usb_task_pending(un->un_udev, &unp->unp_ticktask));
 
-	callout_destroy(&unp->unp_stat_ch);
-	rnd_detach_source(&unp->unp_rndsrc);
+	usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, USB_TASKQ_DRIVER,
+	    NULL);
 
 	if (mii) {
 		mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY);
 		ifmedia_fini(&mii->mii_media);
 	}
-	if (ifp->if_softc) {
+	if (unp->unp_ifp_attached) {
 		if (!usbnet_empty_eaddr(un))
 			ether_ifdetach(ifp);
 		else
@@ -1534,14 +1555,61 @@ usbnet_detach(device_t self, int flags)
 	}
 	usbnet_ec(un)->ec_mii = NULL;
 
-	cv_destroy(&unp->unp_detachcv);
+	/*
+	 * We have already waited for the multicast task to complete.
+	 * Unfortunately, until if_detach, nothing has prevented it
+	 * from running again -- another thread might issue if_mcast_op
+	 * between the time of our first usb_rem_task_wait and the time
+	 * we actually get around to if_detach.
+	 *
+	 * Fortunately, the first usb_rem_task_wait ensures that if the
+	 * task is scheduled again, it will witness our setting of
+	 * unp_dying to true[*].  So after that point, if the task is
+	 * scheduled again, it will decline to touch IFNET_LOCK and do
+	 * nothing.  But we still need to wait for it to complete.
+	 *
+	 * It would be nice if we could write
+	 *
+	 *	if_pleasestopissuingmcastopsthanks(ifp);
+	 *	usb_rem_task_wait(..., &unp->unp_mcasttask, ...);
+	 *	if_detach(ifp);
+	 *
+	 * and then we would need only one usb_rem_task_wait.
+	 *
+	 * Unfortunately, there is no such operation available in
+	 * sys/net at the moment, and it would require a bit of
+	 * coordination with if_mcast_op and doifioctl probably under a
+	 * new lock.  So we'll use this kludge until that mechanism is
+	 * invented.
+	 *
+	 * [*] This is not exactly a documented property of the API,
+	 * but it is implied by the single lock in the task queue
+	 * serializing changes to the task state.
+	 */
+	usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, USB_TASKQ_DRIVER,
+	    NULL);
+
+	usbnet_rx_list_free(un);
+	usbnet_tx_list_free(un);
+
+	rnd_detach_source(&unp->unp_rndsrc);
+
 	mutex_destroy(&unp->unp_core_lock);
 	mutex_destroy(&unp->unp_rxlock);
 	mutex_destroy(&unp->unp_txlock);
 
+	callout_destroy(&unp->unp_stat_ch);
+
 	pmf_device_deregister(un->un_dev);
 
-	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, un->un_dev);
+	/*
+	 * Notify userland that we're going away, if we arrived in the
+	 * first place.
+	 */
+	if (unp->unp_ifp_attached) {
+		usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev,
+		    un->un_dev);
+	}
 
 	kmem_free(unp, sizeof(*unp));
 	un->un_pri = NULL;
@@ -1561,9 +1629,7 @@ usbnet_activate(device_t self, devact_t act)
 	case DVACT_DEACTIVATE:
 		if_deactivate(ifp);
 
-		mutex_enter(&unp->unp_core_lock);
-		unp->unp_dying = true;
-		mutex_exit(&unp->unp_core_lock);
+		atomic_store_relaxed(&unp->unp_dying, true);
 
 		mutex_enter(&unp->unp_rxlock);
 		mutex_enter(&unp->unp_txlock);
diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h
index 15e9dfc7b351..9ce537d7b849 100644
--- a/sys/dev/usb/usbnet.h
+++ b/sys/dev/usb/usbnet.h
@@ -131,6 +131,8 @@ enum usbnet_ep {
 typedef void (*usbnet_stop_cb)(struct ifnet *, int);
 /* Interface ioctl callback. */
 typedef int (*usbnet_ioctl_cb)(struct ifnet *, u_long, void *);
+/* Reprogram multicast filters callback. */
+typedef void (*usbnet_mcast_cb)(struct ifnet *);
 /* Initialise device callback. */
 typedef int (*usbnet_init_cb)(struct ifnet *);
 
@@ -170,16 +172,17 @@ typedef void (*usbnet_intr_cb)(struct usbnet *, usbd_status);
  * Note that when CORE_LOCK is held, IFNET_LOCK may or may not also
  * be held.
  *
- * Note that the IFNET_LOCK **may not be held** for some ioctl
- * operations (add/delete multicast addresses, for example).
- *
- * Busy reference counts are maintained across calls to: uno_stop,
- * uno_read_reg, uno_write_reg, uno_statchg, and uno_tick.
+ * Note that the IFNET_LOCK **may not be held** for some the ioctl
+ * commands SIOCADDMULTI/SIOCDELMULTI.  These commands are only passed
+ * explicitly to uno_override_ioctl; for all other devices, they are
+ * handled inside usbnet by scheduling a task to asynchronously call
+ * uno_mcast with IFNET_LOCK held.
  */
 struct usbnet_ops {
 	usbnet_stop_cb		uno_stop;		/* C */
-	usbnet_ioctl_cb		uno_ioctl;		/* I (maybe) */
-	usbnet_ioctl_cb		uno_override_ioctl;	/* I (maybe) */
+	usbnet_ioctl_cb		uno_ioctl;		/* I */
+	usbnet_ioctl_cb		uno_override_ioctl;	/* I (except mcast) */
+	usbnet_mcast_cb		uno_mcast;		/* I */
 	usbnet_init_cb		uno_init;		/* I */
 	usbnet_mii_read_reg_cb	uno_read_reg;		/* C */
 	usbnet_mii_write_reg_cb uno_write_reg;		/* C */
@@ -284,7 +287,6 @@ struct usbnet {
 /* Various accessors. */
 
 void usbnet_set_link(struct usbnet *, bool);
-void usbnet_set_dying(struct usbnet *, bool);
 
 struct ifnet *usbnet_ifp(struct usbnet *);
 struct ethercom *usbnet_ec(struct usbnet *);
@@ -309,27 +311,6 @@ usbnet_isowned_core(struct usbnet *un)
 	KASSERT(mutex_owned(usbnet_mutex_core(un)));
 }
 
-void	usbnet_busy(struct usbnet *);
-void	usbnet_unbusy(struct usbnet *);
-
-void	usbnet_lock_rx(struct usbnet *);
-void	usbnet_unlock_rx(struct usbnet *);
-kmutex_t *usbnet_mutex_rx(struct usbnet *);
-static __inline__ void
-usbnet_isowned_rx(struct usbnet *un)
-{
-	KASSERT(mutex_owned(usbnet_mutex_rx(un)));
-}
-
-void	usbnet_lock_tx(struct usbnet *);
-void	usbnet_unlock_tx(struct usbnet *);
-kmutex_t *usbnet_mutex_tx(struct usbnet *);
-static __inline__ void
-usbnet_isowned_tx(struct usbnet *un)
-{
-	KASSERT(mutex_owned(usbnet_mutex_tx(un)));
-}
-
 /*
  * Endpoint / rx/tx chain management:
  *