diff --git a/sys/altq/altq_afmap.c b/sys/altq/altq_afmap.c
index ae04bddbc3a2..5f80b20bd10a 100644
--- a/sys/altq/altq_afmap.c
+++ b/sys/altq/altq_afmap.c
@@ -369,10 +369,15 @@ afmioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag,
 	flowmap = (struct atm_flowmap *)addr;
 	flowmap->af_ifname[IFNAMSIZ-1] = '\0';
 	ifp = ifunit(flowmap->af_ifname);
-	if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0)
+	if (ifp == NULL)
+		return ENXIO;
+
+	IFNET_LOCK(ifp);
+	if ((ifp->if_flags & IFF_RUNNING) == 0)
 		error = ENXIO;
 	else
-		error = ifp->if_ioctl(ifp, cmd, addr);
+		error = if_ioctl(ifp, cmd, addr);
+	IFNET_UNLOCK(ifp);
 
 	return error;
 }
diff --git a/sys/arch/arm/imx/if_enet.c b/sys/arch/arm/imx/if_enet.c
index e2e93a03b1cb..a50e74006338 100644
--- a/sys/arch/arm/imx/if_enet.c
+++ b/sys/arch/arm/imx/if_enet.c
@@ -1027,7 +1027,7 @@ enet_ioctl(struct ifnet *ifp, u_long command, void *data)
 		error = 0;
 		switch (command) {
 		case SIOCSIFCAP:
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 			break;
 		case SIOCADDMULTI:
 		case SIOCDELMULTI:
diff --git a/sys/arch/arm/sociox/if_ave.c b/sys/arch/arm/sociox/if_ave.c
index afde8ca26ea4..b7f5305ec75b 100644
--- a/sys/arch/arm/sociox/if_ave.c
+++ b/sys/arch/arm/sociox/if_ave.c
@@ -790,7 +790,7 @@ ave_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		error = 0;
 
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags & IFF_RUNNING) {
diff --git a/sys/arch/arm/sociox/if_scx.c b/sys/arch/arm/sociox/if_scx.c
index 49514a1455aa..6ddc33c62a17 100644
--- a/sys/arch/arm/sociox/if_scx.c
+++ b/sys/arch/arm/sociox/if_scx.c
@@ -1201,7 +1201,7 @@ scx_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 			break;
 		error = 0;
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags & IFF_RUNNING) {
diff --git a/sys/arch/arm/sunxi/sunxi_emac.c b/sys/arch/arm/sunxi/sunxi_emac.c
index 60c01c989466..c4de05281e98 100644
--- a/sys/arch/arm/sunxi/sunxi_emac.c
+++ b/sys/arch/arm/sunxi/sunxi_emac.c
@@ -932,7 +932,7 @@ sunxi_emac_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		error = 0;
 
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if ((ifp->if_flags & IFF_RUNNING) != 0) {
diff --git a/sys/arch/arm/xscale/ixp425_if_npe.c b/sys/arch/arm/xscale/ixp425_if_npe.c
index 4533c483c1c3..49aabbb5b4af 100644
--- a/sys/arch/arm/xscale/ixp425_if_npe.c
+++ b/sys/arch/arm/xscale/ixp425_if_npe.c
@@ -1429,13 +1429,13 @@ npeioctl(struct ifnet *ifp, u_long cmd, void *data)
 			 * If interface is marked down and it is running,
 			 * then stop and disable it.
 			 */
-			(*ifp->if_stop)(ifp, 1);
+			if_stop(ifp, 1);
 		} else if ((ifp->if_flags & (IFF_UP |IFF_RUNNING)) == IFF_UP) {
 			/*
 			 * If interface is marked up and it is stopped, then
 			 * start it.
 			 */
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		} else if ((ifp->if_flags & IFF_UP) != 0) {
 			u_short diff;
 
@@ -1457,7 +1457,7 @@ npeioctl(struct ifnet *ifp, u_long cmd, void *data)
 				 * any other flags that affect the hardware
 				 * state.
 				 */
-				error = (*ifp->if_init)(ifp);
+				error = if_init(ifp);
 			}
 		}
 		sc->sc_if_flags = ifp->if_flags;
diff --git a/sys/dev/cadence/if_cemac.c b/sys/dev/cadence/if_cemac.c
index fd5aaf36ad3b..ce9457c32e2d 100644
--- a/sys/dev/cadence/if_cemac.c
+++ b/sys/dev/cadence/if_cemac.c
@@ -759,7 +759,7 @@ cemac_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
 		error = 0;
 
 		if (cmd == SIOCSIFCAP) {
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		} else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags & IFF_RUNNING) {
diff --git a/sys/dev/ic/bcmgenet.c b/sys/dev/ic/bcmgenet.c
index 2040f1e12bc6..2043655959a7 100644
--- a/sys/dev/ic/bcmgenet.c
+++ b/sys/dev/ic/bcmgenet.c
@@ -916,7 +916,7 @@ genet_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		error = 0;
 
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if ((ifp->if_flags & IFF_RUNNING) != 0) {
diff --git a/sys/dev/ic/dm9000.c b/sys/dev/ic/dm9000.c
index e3c68052c42f..93ead7296756 100644
--- a/sys/dev/ic/dm9000.c
+++ b/sys/dev/ic/dm9000.c
@@ -833,7 +833,7 @@ dme_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 			break;
 		error = 0;
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags && IFF_RUNNING) {
diff --git a/sys/dev/ic/rtl8169.c b/sys/dev/ic/rtl8169.c
index dd36ea119cbf..a71d27f8e72c 100644
--- a/sys/dev/ic/rtl8169.c
+++ b/sys/dev/ic/rtl8169.c
@@ -2130,7 +2130,7 @@ re_ioctl(struct ifnet *ifp, u_long command, void *data)
 		error = 0;
 
 		if (command == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		else if (command != SIOCADDMULTI && command != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags & IFF_RUNNING)
diff --git a/sys/dev/midi.c b/sys/dev/midi.c
index f3f0ffe73876..ce824813367e 100644
--- a/sys/dev/midi.c
+++ b/sys/dev/midi.c
@@ -207,11 +207,6 @@ mididetach(device_t self, int flags)
 
 	mutex_enter(sc->lock);
 	sc->dying = 1;
-
-	if (--sc->refcnt >= 0) {
-		/* Wake anything? */
-		(void)cv_timedwait(&sc->detach_cv, sc->lock, hz * 60);
-	}
 	cv_broadcast(&sc->wchan);
 	cv_broadcast(&sc->rchan);
 	mutex_exit(sc->lock);
@@ -230,6 +225,16 @@ mididetach(device_t self, int flags)
 	mn = device_unit(self);
 	vdevgone(maj, mn, mn, VCHR);
 
+	mutex_enter(sc->lock);
+	if (--sc->refcnt >= 0) {
+		(void)cv_timedwait(&sc->detach_cv, sc->lock, hz * 60);
+		if (sc->refcnt >= 0) {
+			aprint_error_dev(self, "refcnt failed to drain,"
+			    " bashing my brains out anyway\n");
+		}
+	}
+	mutex_exit(sc->lock);
+
 	if (!(sc->props & MIDI_PROP_NO_OUTPUT)) {
 		evcnt_detach(&sc->xmt.bytesDiscarded);
 		evcnt_detach(&sc->xmt.incompleteMessages);
@@ -244,10 +249,8 @@ mididetach(device_t self, int flags)
 		sc->sih = NULL;
 	}
 
-	mutex_enter(sc->lock);
-	callout_halt(&sc->xmt_asense_co, sc->lock);
-	callout_halt(&sc->rcv_asense_co, sc->lock);
-	mutex_exit(sc->lock);
+	callout_halt(&sc->xmt_asense_co, NULL);
+	callout_halt(&sc->rcv_asense_co, NULL);
 
 	callout_destroy(&sc->xmt_asense_co);
 	callout_destroy(&sc->rcv_asense_co);
diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c
index 06925d5c96cb..62714cc7b0d2 100644
--- a/sys/dev/mii/mii_physubr.c
+++ b/sys/dev/mii/mii_physubr.c
@@ -429,8 +429,20 @@ mii_phy_down(struct mii_softc *sc)
 	KASSERT(mii_locked(sc->mii_pdata));
 
 	if (sc->mii_flags & MIIF_DOINGAUTO) {
-		sc->mii_flags &= ~MIIF_DOINGAUTO;
-		callout_stop(&sc->mii_nway_ch);
+		/*
+		 * Try to stop it.
+		 *
+		 * - If we stopped it before it expired, callout_stop
+		 *   returns 0, and it is our responsibility to clear
+		 *   MIIF_DOINGAUTO.
+		 *
+		 * - Otherwise, we're too late -- the callout has
+		 *   already begun, and we must leave MIIF_DOINGAUTO
+		 *   set so mii_phy_detach will wait for it to
+		 *   complete.
+		 */
+		if (!callout_stop(&sc->mii_nway_ch))
+			sc->mii_flags &= ~MIIF_DOINGAUTO;
 	}
 }
 
diff --git a/sys/dev/pci/if_dge.c b/sys/dev/pci/if_dge.c
index 565a16a70b01..ff4b04187384 100644
--- a/sys/dev/pci/if_dge.c
+++ b/sys/dev/pci/if_dge.c
@@ -1453,7 +1453,7 @@ dge_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		else if ((error = ifioctl_common(ifp, cmd, data)) != ENETRESET)
 			break;
 		else if (ifp->if_flags & IFF_UP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		else
 			error = 0;
 		break;
@@ -1488,7 +1488,7 @@ dge_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		error = 0;
 
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags & IFF_RUNNING) {
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c
index 0c63cef8c1dd..5fad5e8a915f 100644
--- a/sys/dev/pci/if_iwn.c
+++ b/sys/dev/pci/if_iwn.c
@@ -973,7 +973,7 @@ iwn_power(int why, void *arg)
 	s = splnet();
 	ifp = &sc->sc_ic.ic_if;
 	if (ifp->if_flags & IFF_UP) {
-		ifp->if_init(ifp);
+		if_init(ifp);
 		if (ifp->if_flags & IFF_RUNNING)
 			ifp->if_start(ifp);
 	}
diff --git a/sys/dev/pci/if_kse.c b/sys/dev/pci/if_kse.c
index f3f5c2ce1021..26dd7d0bf5b4 100644
--- a/sys/dev/pci/if_kse.c
+++ b/sys/dev/pci/if_kse.c
@@ -689,7 +689,7 @@ kse_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 			break;
 		error = 0;
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags & IFF_RUNNING) {
diff --git a/sys/dev/pci/if_sip.c b/sys/dev/pci/if_sip.c
index bc340603ffc4..cd345843495d 100644
--- a/sys/dev/pci/if_sip.c
+++ b/sys/dev/pci/if_sip.c
@@ -1869,7 +1869,7 @@ sipcom_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		error = 0;
 
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags & IFF_RUNNING) {
diff --git a/sys/dev/pci/if_wm.c b/sys/dev/pci/if_wm.c
index 1c2a6a9f2b56..951e3b746bc1 100644
--- a/sys/dev/pci/if_wm.c
+++ b/sys/dev/pci/if_wm.c
@@ -3675,7 +3675,7 @@ wm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		error = 0;
 
 		if (cmd == SIOCSIFCAP)
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
 		else if (ifp->if_flags & IFF_RUNNING) {
diff --git a/sys/dev/pci/ixgbe/ixgbe.c b/sys/dev/pci/ixgbe/ixgbe.c
index 86e73fbf5892..aec31c1a79c7 100644
--- a/sys/dev/pci/ixgbe/ixgbe.c
+++ b/sys/dev/pci/ixgbe/ixgbe.c
@@ -5770,7 +5770,7 @@ ixgbe_sysctl_dmac(SYSCTLFN_ARGS)
 
 	/* Re-initialize hardware if it's already running */
 	if (ifp->if_flags & IFF_RUNNING)
-		ifp->if_init(ifp);
+		if_init(ifp);
 
 	return (0);
 }
@@ -6103,7 +6103,7 @@ ixgbe_sysctl_eee_state(SYSCTLFN_ARGS)
 	}
 
 	/* Restart auto-neg */
-	ifp->if_init(ifp);
+	if_init(ifp);
 
 	device_printf(dev, "New EEE state: %d\n", new_eee);
 
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index bf91d56b356d..fe433722d185 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -559,8 +559,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		axen_setiff_locked(un);
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 559b9eff2569..16a52e4c6ed4 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1273,8 +1273,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		mue_setiff_locked(un);
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 6cf37e507d1c..12eaf3fa3cc6 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -757,8 +757,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		smsc_setiff_locked(un);
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index 764b9c654682..dbb57bf66ca7 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -256,18 +256,12 @@ url_attach(device_t parent, device_t self, void *aux)
 	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 */
diff --git a/sys/dev/usb/if_urtw.c b/sys/dev/usb/if_urtw.c
index d0a55c951839..e451bbb48d82 100644
--- a/sys/dev/usb/if_urtw.c
+++ b/sys/dev/usb/if_urtw.c
@@ -1045,7 +1045,7 @@ urtw_media_change(struct ifnet *ifp)
 
 	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
 	    (IFF_UP | IFF_RUNNING))
-		ifp->if_init(ifp);
+		if_init(ifp);
 
 	return 0;
 }
@@ -2395,7 +2395,7 @@ urtw_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		case IFF_UP|IFF_RUNNING:
 			break;
 		case IFF_UP:
-			ifp->if_init(ifp);
+			if_init(ifp);
 			break;
 		case IFF_RUNNING:
 			urtw_stop(ifp, 1);
@@ -2419,7 +2419,7 @@ urtw_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	if (error == ENETRESET) {
 		if (IS_RUNNING(ifp) &&
 		    (ic->ic_roaming != IEEE80211_ROAMING_MANUAL))
-			ifp->if_init(ifp);
+			if_init(ifp);
 		error = 0;
 	}
 
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c
index 6d17cd50e533..4657dfacf1b2 100644
--- a/sys/dev/usb/umass.c
+++ b/sys/dev/usb/umass.c
@@ -392,7 +392,6 @@ umass_attach(device_t parent, device_t self, void *aux)
 	aprint_normal("\n");
 
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
-	cv_init(&sc->sc_detach_cv, "umassdet");
 
 	devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0);
 	aprint_normal_dev(self, "%s\n", devinfop);
@@ -872,18 +871,6 @@ umass_detach(device_t self, int flags)
 	}
 	usbd_abort_default_pipe(sc->sc_udev);
 
-	/* Do we really need reference counting?  Perhaps in ioctl() */
-	mutex_enter(&sc->sc_lock);
-	if (--sc->sc_refcnt >= 0) {
-#ifdef DIAGNOSTIC
-		aprint_normal_dev(self, "waiting for refcnt\n");
-#endif
-		/* Wait for processes to go away. */
-		if (cv_timedwait(&sc->sc_detach_cv, &sc->sc_lock, hz * 60))
-			aprint_error_dev(self, ": didn't detach\n");
-	}
-	mutex_exit(&sc->sc_lock);
-
 	scbus = sc->bus;
 	if (scbus != NULL) {
 		if (scbus->sc_child != NULL)
@@ -925,7 +912,6 @@ umass_detach(device_t self, int flags)
 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
 
 	mutex_destroy(&sc->sc_lock);
-	cv_destroy(&sc->sc_detach_cv);
 
 out:	SDT_PROBE2(usb, umass, device, detach__done,  sc, rv);
 	return rv;
diff --git a/sys/dev/usb/umass_scsipi.c b/sys/dev/usb/umass_scsipi.c
index d502c248be03..6898c68df290 100644
--- a/sys/dev/usb/umass_scsipi.c
+++ b/sys/dev/usb/umass_scsipi.c
@@ -131,6 +131,8 @@ umass_scsi_attach(struct umass_softc *sc)
 	UMASSHIST_FUNC(); UMASSHIST_CALLED();
 	struct umass_scsipi_softc *scbus;
 
+	KASSERT(KERNEL_LOCKED_P());
+
 	scbus = umass_scsipi_setup(sc);
 
 	scbus->sc_channel.chan_bustype = &scsi_bustype;
@@ -139,17 +141,9 @@ umass_scsi_attach(struct umass_softc *sc)
 	scbus->sc_channel.chan_id = scbus->sc_channel.chan_ntargets - 1;
 	DPRINTFM(UDMASS_USB, "sc %#jx: SCSI", (uintptr_t)sc, 0, 0, 0);
 
-	mutex_enter(&sc->sc_lock);
-	sc->sc_refcnt++;
-	mutex_exit(&sc->sc_lock);
 	scbus->base.sc_child =
 	    config_found(sc->sc_dev, &scbus->sc_channel, scsiprint,
 			 CFARGS(.iattr = "scsi"));
-	mutex_enter(&sc->sc_lock);
-	if (--sc->sc_refcnt < 0)
-		cv_broadcast(&sc->sc_detach_cv);
-	mutex_exit(&sc->sc_lock);
-
 
 	return 0;
 }
@@ -171,6 +165,8 @@ umass_atapi_attach(struct umass_softc *sc)
 	UMASSHIST_FUNC(); UMASSHIST_CALLED();
 	struct umass_scsipi_softc *scbus;
 
+	KASSERT(KERNEL_LOCKED_P());
+
 	scbus = umass_scsipi_setup(sc);
 	scbus->sc_atapi_adapter.atapi_probe_device =  umass_atapi_probe_device;
 
@@ -181,16 +177,9 @@ umass_atapi_attach(struct umass_softc *sc)
 	scbus->sc_channel.chan_defquirks |= sc->sc_busquirks;
 	DPRINTFM(UDMASS_USB, "sc %#jxp: ATAPI", (uintptr_t)sc, 0, 0, 0);
 
-	mutex_enter(&sc->sc_lock);
-	sc->sc_refcnt++;
-	mutex_exit(&sc->sc_lock);
 	scbus->base.sc_child =
 	    config_found(sc->sc_dev, &scbus->sc_channel, atapiprint,
 			 CFARGS(.iattr = "atapi"));
-	mutex_enter(&sc->sc_lock);
-	if (--sc->sc_refcnt < 0)
-		cv_broadcast(&sc->sc_detach_cv);
-	mutex_exit(&sc->sc_lock);
 
 	return 0;
 }
diff --git a/sys/dev/usb/umassvar.h b/sys/dev/usb/umassvar.h
index f434873e8666..7bc5ccf000b5 100644
--- a/sys/dev/usb/umassvar.h
+++ b/sys/dev/usb/umassvar.h
@@ -167,7 +167,6 @@ struct umass_softc {
 	const struct umass_wire_methods *sc_methods;
 
 	kmutex_t		sc_lock;
-	kcondvar_t		sc_detach_cv;
 
 	uint8_t			sc_wire;	/* wire protocol */
 #define	UMASS_WPROTO_UNSPEC	0
@@ -276,7 +275,6 @@ struct umass_softc {
 #endif
 
 	char			sc_dying;
-	int			sc_refcnt;
 	int			sc_sense;
 
 	struct umassbus_softc	*bus;		 /* bus dependent data */
diff --git a/sys/dev/usb/umidi.c b/sys/dev/usb/umidi.c
index 07f762516996..c4c3842a8a53 100644
--- a/sys/dev/usb/umidi.c
+++ b/sys/dev/usb/umidi.c
@@ -209,9 +209,6 @@ struct umidi_softc {
 
 	kmutex_t		sc_lock;
 	kcondvar_t		sc_cv;
-	kcondvar_t		sc_detach_cv;
-
-	int			sc_refcnt;
 };
 
 #ifdef UMIDI_DEBUG
@@ -365,8 +362,6 @@ umidi_attach(device_t parent, device_t self, void *aux)
 
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
 	cv_init(&sc->sc_cv, "umidopcl");
-	cv_init(&sc->sc_detach_cv, "umidetcv");
-	sc->sc_refcnt = 0;
 
 	err = alloc_all_endpoints(sc);
 	if (err != USBD_NORMAL_COMPLETION) {
@@ -459,9 +454,6 @@ umidi_detach(device_t self, int flags)
 
 	mutex_enter(&sc->sc_lock);
 	sc->sc_dying = 1;
-	if (--sc->sc_refcnt >= 0)
-		if (cv_timedwait(&sc->sc_detach_cv, &sc->sc_lock, hz * 60))
-			aprint_error_dev(self, ": didn't detach\n");
 	mutex_exit(&sc->sc_lock);
 
 	detach_all_mididevs(sc, flags);
@@ -472,7 +464,6 @@ umidi_detach(device_t self, int flags)
 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
 
 	mutex_destroy(&sc->sc_lock);
-	cv_destroy(&sc->sc_detach_cv);
 	cv_destroy(&sc->sc_cv);
 
 	return 0;
@@ -531,7 +522,7 @@ void
 umidi_close(void *addr)
 {
 	struct umidi_mididev *mididev = addr;
-	struct umidi_softc *sc = mididev->sc;
+	struct umidi_softc *sc __diagused = mididev->sc;
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 
@@ -540,16 +531,11 @@ umidi_close(void *addr)
 
 	mididev->closing = 1;
 
-	sc->sc_refcnt++;
-
 	if ((mididev->flags & FWRITE) && mididev->out_jack)
 		close_out_jack(mididev->out_jack);
 	if ((mididev->flags & FREAD) && mididev->in_jack)
 		close_in_jack(mididev->in_jack);
 
-	if (--sc->sc_refcnt < 0)
-		cv_broadcast(&sc->sc_detach_cv);
-
 	mididev->opened = 0;
 	mididev->closing = 0;
 }
@@ -1731,8 +1717,6 @@ out_jack_output(struct umidi_jack *out_jack, u_char *src, int len, int cin)
 	if (!out_jack->opened)
 		return ENODEV; /* XXX as it was, is this the right errno? */
 
-	sc->sc_refcnt++;
-
 #ifdef UMIDI_DEBUG
 	if (umididebug >= 100)
 		microtime(&umidi_tv);
@@ -1791,9 +1775,6 @@ out_jack_output(struct umidi_jack *out_jack, u_char *src, int len, int cin)
 		kpreempt_enable();
 	}
 
-	if (--sc->sc_refcnt < 0)
-		cv_broadcast(&sc->sc_detach_cv);
-
 	return 0;
 }
 
@@ -1811,10 +1792,14 @@ in_intr(struct usbd_xfer *xfer, void *priv,
 	unsigned char *data;
 	uint32_t count;
 
-	if (ep->sc->sc_dying || !ep->num_open)
+	if (!ep->num_open)
 		return;
 
 	mutex_enter(&sc->sc_lock);
+	if (sc->sc_dying) {
+		mutex_exit(&sc->sc_lock);
+		return;
+	}
 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
 	if (0 == count % UMIDI_PACKET_SIZE) {
 		DPRINTFN(200,("%s: input endpoint %p transfer length %u\n",
@@ -1880,10 +1865,11 @@ out_intr(struct usbd_xfer *xfer, void *priv,
 	struct umidi_softc *sc = ep->sc;
 	uint32_t count;
 
-	if (sc->sc_dying)
-		return;
-
 	mutex_enter(&sc->sc_lock);
+	if (sc->sc_dying) {
+		mutex_exit(&sc->sc_lock);
+		return;
+	}
 #ifdef UMIDI_DEBUG
 	if (umididebug >= 200)
 		microtime(&umidi_tv);
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 1712d2f687f0..5338b4e3d430 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -72,6 +72,7 @@ struct usbnet_private {
 
 	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];
@@ -79,6 +80,7 @@ struct usbnet_private {
 	bool			unp_dying;
 	bool			unp_stopping;
 	bool			unp_attached;
+	bool			unp_ifp_attached;
 	bool			unp_link;
 
 	int			unp_refcnt;
@@ -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);
@@ -333,7 +337,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",
@@ -343,7 +346,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 
 	if (unp->unp_dying || 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) {
@@ -440,11 +443,10 @@ 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 ||
 	    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);
@@ -818,6 +820,9 @@ 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) {
@@ -849,16 +854,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:
@@ -978,6 +982,9 @@ usbnet_media_upd(struct ifnet *ifp)
 	/* ifmedia layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
+	/* ifmedia changes only with IFNET_LOCK held.  */
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	if (unp->unp_dying)
 		return EIO;
 
@@ -1004,6 +1011,8 @@ usbnet_ifflags_cb(struct ethercom *ec)
 	struct usbnet_private * const unp = un->un_pri;
 	int rv = 0;
 
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	mutex_enter(&unp->unp_core_lock);
 
 	const u_short changed = ifp->if_flags ^ unp->unp_if_flags;
@@ -1035,12 +1044,48 @@ 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:
+			mutex_enter(&unp->unp_core_lock);
+			if (!unp->unp_stopping) {
+				usb_add_task(un->un_udev, &unp->unp_mcasttask,
+				    USB_TASKQ_DRIVER);
+			}
+			mutex_exit(&unp->unp_core_lock);
+			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);
+	struct ifreq ifr;
+
+	USBNETHIST_CALLARGSN(10, "%jd: enter",
+	    un->un_pri->unp_number, 0, 0, 0);
+
+	/*
+	 * Pass a bogus ifr with SIOCDELMULTI -- the goal is to just
+	 * notify the driver to reprogram any hardware multicast
+	 * filter, according to what's already stored in the ethercom.
+	 * None of the drivers actually examine this argument, so it
+	 * doesn't change the ABI as far as they can tell.
+	 */
+	memset(&ifr, 0, sizeof(ifr));
+	(void)uno_ioctl(un, ifp, SIOCDELMULTI, &ifr);
+}
+
 /*
  * Generic stop network function:
  *	- mark as stopping
@@ -1061,31 +1106,42 @@ 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 and multicast 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);
+	usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, 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.
+	 */
+	uno_stop(un, ifp, disable);
 
 	/* Stop transfers. */
 	usbnet_ep_stop_pipes(un);
@@ -1097,6 +1153,11 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	/* Close pipes. */
 	usbnet_ep_close_pipes(un);
 
+	/* Everything is quesced now. */
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
+	ifp->if_flags &= ~IFF_RUNNING;
+
 	usbnet_unbusy(un);
 }
 
@@ -1106,6 +1167,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 +1189,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 +1225,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,7 +1249,6 @@ usbnet_tick_task(void *arg)
 	uno_tick(un);
 
 	mutex_enter(&unp->unp_core_lock);
-	usbnet_unbusy(un);
 	if (!unp->unp_stopping && !unp->unp_dying)
 		callout_schedule(&unp->unp_stat_ch, hz);
 	mutex_exit(&unp->unp_core_lock);
@@ -1212,6 +1260,15 @@ usbnet_if_init(struct ifnet *ifp)
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
 
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
+	/*
+	 * Prevent anyone from bringing the interface back up once
+	 * we're detaching.
+	 */
+	if (un->un_pri->unp_dying)
+		return EIO;
+
 	return uno_init(un, ifp);
 }
 
@@ -1224,12 +1281,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 +1320,7 @@ usbnet_havelink(struct usbnet *un)
 bool
 usbnet_isdying(struct usbnet *un)
 {
-	return un->un_pri == NULL || un->un_pri->unp_dying;
+	return un->un_pri->unp_dying;
 }
 
 
@@ -1373,7 +1424,10 @@ 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);
 
@@ -1435,7 +1489,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 +1510,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 +1528,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,22 +1549,47 @@ usbnet_detach(device_t self, int flags)
 	struct ifnet * const ifp = usbnet_ifp(un);
 	struct mii_data * const mii = usbnet_mii(un);
 
+	/*
+	 * Prevent new activity.  If we're still running on the
+	 * network, stop and wait for all asynchronous activity to
+	 * finish.
+	 */
+	IFNET_LOCK(ifp);
 	mutex_enter(&unp->unp_core_lock);
 	unp->unp_dying = true;
 	mutex_exit(&unp->unp_core_lock);
-
 	if (ifp->if_flags & IFF_RUNNING) {
-		IFNET_LOCK(ifp);
 		usbnet_if_stop(ifp, 1);
-		IFNET_UNLOCK(ifp);
 	}
+	IFNET_UNLOCK(ifp);
 
-	callout_halt(&unp->unp_stat_ch, NULL);
-	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
-	    NULL);
+	/*
+	 * The callout and tasks 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));
+	KASSERT(!usb_task_pending(un->un_udev, &unp->unp_mcasttask));
+
+	if (mii) {
+		mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY);
+		ifmedia_fini(&mii->mii_media);
+	}
+	if (unp->unp_ifp_attached) {
+		if (!usbnet_empty_eaddr(un))
+			ether_ifdetach(ifp);
+		else
+			bpf_detach(ifp);
+		if_detach(ifp);
+	}
+	usbnet_ec(un)->ec_mii = NULL;
 
 	mutex_enter(&unp->unp_core_lock);
 	unp->unp_refcnt--;
+	if (unp->unp_refcnt >= 0) {
+		aprint_error_dev(un->un_dev, "%d stragglers\n",
+		    unp->unp_refcnt + 1);
+	}
 	while (unp->unp_refcnt >= 0) {
 		/* Wait for processes to go away */
 		cv_wait(&unp->unp_detachcv, &unp->unp_core_lock);
@@ -1518,30 +1599,25 @@ usbnet_detach(device_t self, int flags)
 	usbnet_rx_list_free(un);
 	usbnet_tx_list_free(un);
 
-	callout_destroy(&unp->unp_stat_ch);
 	rnd_detach_source(&unp->unp_rndsrc);
 
-	if (mii) {
-		mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY);
-		ifmedia_fini(&mii->mii_media);
-	}
-	if (ifp->if_softc) {
-		if (!usbnet_empty_eaddr(un))
-			ether_ifdetach(ifp);
-		else
-			bpf_detach(ifp);
-		if_detach(ifp);
-	}
-	usbnet_ec(un)->ec_mii = NULL;
-
 	cv_destroy(&unp->unp_detachcv);
 	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;
@@ -1563,13 +1639,13 @@ usbnet_activate(device_t self, devact_t act)
 
 		mutex_enter(&unp->unp_core_lock);
 		unp->unp_dying = true;
-		mutex_exit(&unp->unp_core_lock);
 
 		mutex_enter(&unp->unp_rxlock);
 		mutex_enter(&unp->unp_txlock);
 		unp->unp_stopping = true;
 		mutex_exit(&unp->unp_txlock);
 		mutex_exit(&unp->unp_rxlock);
+		mutex_exit(&unp->unp_core_lock);
 
 		return 0;
 	default:
diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h
index 15e9dfc7b351..1faa822887c5 100644
--- a/sys/dev/usb/usbnet.h
+++ b/sys/dev/usb/usbnet.h
@@ -284,7 +284,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 *);
diff --git a/sys/external/bsd/drm2/dist/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/sys/external/bsd/drm2/dist/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index c8cbf7a6f68e..d0386f514457 100644
--- a/sys/external/bsd/drm2/dist/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/sys/external/bsd/drm2/dist/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -361,7 +361,7 @@ static void dm_pflip_high_irq(void *interrupt_params)
 			drm_crtc_send_vblank_event(&amdgpu_crtc->base, e);
 
 			/* Event sent, so done with vblank for this flip */
-			drm_crtc_vblank_put(&amdgpu_crtc->base);
+			drm_crtc_vblank_put_locked(&amdgpu_crtc->base);
 		}
 	} else if (e) {
 		/* VRR active and inside front-porch: vblank count and
diff --git a/sys/external/bsd/drm2/dist/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/sys/external/bsd/drm2/dist/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 79cb94ea67dc..5a154037c524 100644
--- a/sys/external/bsd/drm2/dist/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/sys/external/bsd/drm2/dist/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -319,7 +319,9 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
 				       &crcs[0], &crcs[1], &crcs[2]))
 			return;
 
+		spin_lock(&crtc->dev->event_lock);
 		drm_crtc_add_crc_entry(crtc, true,
 				       drm_crtc_accurate_vblank_count(crtc), crcs);
+		spin_unlock(&crtc->dev->event_lock);
 	}
 }
diff --git a/sys/external/bsd/drm2/dist/drm/drm_vblank.c b/sys/external/bsd/drm2/dist/drm/drm_vblank.c
index 9ced81bd7ed8..ec91bbe9391b 100644
--- a/sys/external/bsd/drm2/dist/drm/drm_vblank.c
+++ b/sys/external/bsd/drm2/dist/drm/drm_vblank.c
@@ -337,7 +337,7 @@ static u64 drm_vblank_count(struct drm_device *dev, unsigned int pipe)
  * This is mostly useful for hardware that can obtain the scanout position, but
  * doesn't have a hardware frame counter.
  */
-static u64 drm_crtc_accurate_vblank_count_locked(struct drm_crtc *crtc)
+u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	unsigned int pipe = drm_crtc_index(crtc);
@@ -358,17 +358,6 @@ static u64 drm_crtc_accurate_vblank_count_locked(struct drm_crtc *crtc)
 
 	return vblank;
 }
-
-u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc)
-{
-	u64 vblank;
-
-	spin_lock(&crtc->dev->event_lock);
-	vblank = drm_crtc_accurate_vblank_count_locked(crtc);
-	spin_unlock(&crtc->dev->event_lock);
-
-	return vblank;
-}
 EXPORT_SYMBOL(drm_crtc_accurate_vblank_count);
 
 static void __disable_vblank(struct drm_device *dev, unsigned int pipe)
@@ -972,7 +961,7 @@ void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
 	assert_spin_locked(&dev->event_lock);
 
 	e->pipe = pipe;
-	e->sequence = drm_crtc_accurate_vblank_count_locked(crtc) + 1;
+	e->sequence = drm_crtc_accurate_vblank_count(crtc) + 1;
 	list_add_tail(&e->base.link, &dev->vblank_event_list);
 }
 EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
diff --git a/sys/external/bsd/drm2/dist/drm/nouveau/dispnv50/nouveau_dispnv50_disp.c b/sys/external/bsd/drm2/dist/drm/nouveau/dispnv50/nouveau_dispnv50_disp.c
index b9423cdc84fb..f49bb2ddf56d 100644
--- a/sys/external/bsd/drm2/dist/drm/nouveau/dispnv50/nouveau_dispnv50_disp.c
+++ b/sys/external/bsd/drm2/dist/drm/nouveau/dispnv50/nouveau_dispnv50_disp.c
@@ -2136,9 +2136,9 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
 		if (new_crtc_state->event) {
 			unsigned long flags;
 			/* Get correct count/ts if racing with vblank irq */
+			spin_lock_irqsave(&crtc->dev->event_lock, flags);
 			if (new_crtc_state->active)
 				drm_crtc_accurate_vblank_count(crtc);
-			spin_lock_irqsave(&crtc->dev->event_lock, flags);
 			drm_crtc_send_vblank_event(crtc, new_crtc_state->event);
 			spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 
diff --git a/sys/net/agr/if_agr.c b/sys/net/agr/if_agr.c
index 735d15f5b74b..75e6fd3e68de 100644
--- a/sys/net/agr/if_agr.c
+++ b/sys/net/agr/if_agr.c
@@ -759,7 +759,7 @@ agrport_cleanup(struct agr_softc *sc, struct agr_port *port)
 		memcpy(LLADDR(ifp_port->if_sadl), port->port_origlladdr,
 		    ifp_port->if_addrlen);
 		if (ifp_port->if_init != NULL) {
-			error = (*ifp_port->if_init)(ifp_port);
+			error = if_init(ifp_port);
 		}
 #else
 		union {
diff --git a/sys/net/if.c b/sys/net/if.c
index 130ca14235ad..c6fe8066c3a7 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1622,7 +1622,7 @@ if_clone_destroy(const char *name)
 	struct ifnet *ifp;
 	struct psref psref;
 	int error;
-	int (*if_ioctl)(struct ifnet *, u_long, void *);
+	int (*if_ioctlfn)(struct ifnet *, u_long, void *);
 
 	KASSERT(mutex_owned(&if_clone_mtx));
 
@@ -1639,7 +1639,7 @@ if_clone_destroy(const char *name)
 
 	/* We have to disable ioctls here */
 	IFNET_LOCK(ifp);
-	if_ioctl = ifp->if_ioctl;
+	if_ioctlfn = ifp->if_ioctl;
 	ifp->if_ioctl = if_nullioctl;
 	IFNET_UNLOCK(ifp);
 
@@ -1654,7 +1654,7 @@ if_clone_destroy(const char *name)
 	if (error != 0) {
 		/* We have to restore if_ioctl on error */
 		IFNET_LOCK(ifp);
-		ifp->if_ioctl = if_ioctl;
+		ifp->if_ioctl = if_ioctlfn;
 		IFNET_UNLOCK(ifp);
 	}
 
@@ -2727,6 +2727,73 @@ ifpromisc(struct ifnet *ifp, int pswitch)
 	return e;
 }
 
+/*
+ * if_ioctl(ifp, cmd, data)
+ *
+ *	Apply an ioctl command to the interface.  Returns 0 on success,
+ *	nonzero errno(3) number on failure.
+ *
+ *	For SIOCADDMULTI/SIOCDELMULTI, caller need not hold locks -- it
+ *	is the driver's responsibility to take any internal locks.
+ *	(Kernel logic should generally invoke these only through
+ *	if_mcast_op.)
+ *
+ *	For all other ioctls, caller must hold ifp->if_ioctl_lock,
+ *	a.k.a. IFNET_LOCK.  May sleep.
+ */
+int
+if_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+{
+
+	switch (cmd) {
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		break;
+	default:
+		KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+	}
+
+	return (*ifp->if_ioctl)(ifp, cmd, data);
+}
+
+/*
+ * if_init(ifp)
+ *
+ *	Prepare the hardware underlying ifp to process packets
+ *	according to its current configuration.  Returns 0 on success,
+ *	nonzero errno(3) number on failure.
+ *
+ *	May sleep.  Caller must hold ifp->if_ioctl_lock, a.k.a
+ *	IFNET_LOCK.
+ */
+int
+if_init(struct ifnet *ifp)
+{
+
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
+	return (*ifp->if_init)(ifp);
+}
+
+/*
+ * if_stop(ifp, disable)
+ *
+ *	Stop the hardware underlying ifp from processing packets.
+ *
+ *	If disable is true, ... XXX(?)
+ *
+ *	May sleep.  Caller must hold ifp->if_ioctl_lock, a.k.a
+ *	IFNET_LOCK.
+ */
+void
+if_stop(struct ifnet *ifp, int disable)
+{
+
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
+	(*ifp->if_stop)(ifp, disable);
+}
+
 /*
  * Map interface name to
  * interface structure pointer.
@@ -3427,7 +3494,7 @@ doifioctl(struct socket *so, u_long cmd, void *data, struct lwp *l)
 	KERNEL_LOCK_UNLESS_IFP_MPSAFE(ifp);
 	IFNET_LOCK(ifp);
 
-	error = (*ifp->if_ioctl)(ifp, cmd, data);
+	error = if_ioctl(ifp, cmd, data);
 	if (error != ENOTTY)
 		;
 	else if (so->so_proto == NULL)
@@ -3726,8 +3793,8 @@ if_addr_init(ifnet_t *ifp, struct ifaddr *ifa, const bool src)
 	if (ifp->if_initaddr != NULL)
 		rc = (*ifp->if_initaddr)(ifp, ifa, src);
 	else if (src ||
-	         (rc = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ifa)) == ENOTTY)
-		rc = (*ifp->if_ioctl)(ifp, SIOCINITIFADDR, ifa);
+	         (rc = if_ioctl(ifp, SIOCSIFDSTADDR, ifa)) == ENOTTY)
+		rc = if_ioctl(ifp, SIOCINITIFADDR, ifa);
 
 	return rc;
 }
@@ -3765,6 +3832,15 @@ if_do_dad(struct ifnet *ifp)
 	}
 }
 
+/*
+ * if_flags_set(ifp, flags)
+ *
+ *	Ask ifp to change ifp->if_flags to flags, as if with the
+ *	SIOCSIFFLAGS ioctl command.
+ *
+ *	May sleep.  Caller must hold ifp->if_ioctl_lock, a.k.a
+ *	IFNET_LOCK.
+ */
 int
 if_flags_set(ifnet_t *ifp, const u_short flags)
 {
@@ -3794,7 +3870,7 @@ if_flags_set(ifnet_t *ifp, const u_short flags)
 		memset(&ifr, 0, sizeof(ifr));
 
 		ifr.ifr_flags = flags & ~IFF_CANTCHANGE;
-		rc = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, &ifr);
+		rc = if_ioctl(ifp, SIOCSIFFLAGS, &ifr);
 
 		if (rc != 0 && cantflags != 0)
 			ifp->if_flags ^= cantflags;
@@ -3803,19 +3879,33 @@ if_flags_set(ifnet_t *ifp, const u_short flags)
 	return rc;
 }
 
+/*
+ * if_mcast_op(ifp, cmd, sa)
+ *
+ *	Apply a multicast command, SIOCADDMULTI/SIOCDELMULTI, to the
+ *	interface.  Returns 0 on success, nonzero errno(3) number on
+ *	failure.
+ *
+ *	May sleep.
+ *
+ *	Use this, not if_ioctl, for the multicast commands.
+ */
 int
 if_mcast_op(ifnet_t *ifp, const unsigned long cmd, const struct sockaddr *sa)
 {
 	int rc;
 	struct ifreq ifr;
 
-	/*
-	 * XXX NOMPSAFE - this calls if_ioctl without holding IFNET_LOCK()
-	 * in some cases - e.g. when called from vlan/netinet/netinet6 code
-	 * directly rather than via doifoictl()
-	 */
+	switch (cmd) {
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		break;
+	default:
+		panic("invalid ifnet multicast command: 0x%lx", cmd);
+	}
+
 	ifreq_setaddr(cmd, &ifr, sa);
-	rc = (*ifp->if_ioctl)(ifp, cmd, &ifr);
+	rc = if_ioctl(ifp, cmd, &ifr);
 
 	return rc;
 }
diff --git a/sys/net/if.h b/sys/net/if.h
index 00cfaf3aca23..722979c1c5b0 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -1143,6 +1143,10 @@ int	if_mcast_op(ifnet_t *, const unsigned long, const struct sockaddr *);
 int	if_flags_set(struct ifnet *, const u_short);
 int	if_clone_list(int, char *, int *);
 
+int	if_ioctl(struct ifnet *, u_long, void *);
+int	if_init(struct ifnet *);
+void	if_stop(struct ifnet *, int);
+
 struct	ifnet *ifunit(const char *);
 struct	ifnet *if_get(const char *, struct psref *);
 ifnet_t *if_byindex(u_int);
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 817469654f04..cbac8bcea4ad 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -611,14 +611,14 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 			 * If interface is marked down and it is running,
 			 * then stop and disable it.
 			 */
-			(*ifp->if_stop)(ifp, 1);
+			if_stop(ifp, 1);
 			break;
 		case IFF_UP:
 			/*
 			 * If interface is marked up and it is stopped, then
 			 * start it.
 			 */
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 			break;
 		default:
 			break;
@@ -869,7 +869,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
 			memset(&ifr, 0, sizeof(ifr));
 			ifr.ifr_mtu = sc->sc_if.if_mtu;
 			IFNET_LOCK(ifs);
-			error = ifs->if_ioctl(ifs, SIOCSIFMTU, &ifr);
+			error = if_ioctl(ifs, SIOCSIFMTU, &ifr);
 			IFNET_UNLOCK(ifs);
 			if (error != 0)
 				goto out;
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 2848be7ce6d1..05adeccb0159 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1455,20 +1455,22 @@ ether_ioctl_reinit(struct ethercom *ec)
 	struct ifnet *ifp = &ec->ec_if;
 	int error;
 
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
 	case IFF_RUNNING:
 		/*
 		 * If interface is marked down and it is running,
 		 * then stop and disable it.
 		 */
-		(*ifp->if_stop)(ifp, 1);
+		if_stop(ifp, 1);
 		break;
 	case IFF_UP:
 		/*
 		 * If interface is marked up and it is stopped, then
 		 * start it.
 		 */
-		return (*ifp->if_init)(ifp);
+		return if_init(ifp);
 	case IFF_UP | IFF_RUNNING:
 		error = 0;
 		if (ec->ec_ifflags_cb != NULL) {
@@ -1479,10 +1481,10 @@ ether_ioctl_reinit(struct ethercom *ec)
 				 * changes in any other flags that
 				 * affect the hardware state.
 				 */
-				return (*ifp->if_init)(ifp);
+				return if_init(ifp);
 			}
 		} else
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 		return error;
 	case 0:
 		break;
@@ -1514,7 +1516,7 @@ ether_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		    && (ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
 		       (IFF_UP | IFF_RUNNING)) {
 			ifp->if_flags |= IFF_UP;
-			if ((error = (*ifp->if_init)(ifp)) != 0)
+			if ((error = if_init(ifp)) != 0)
 				return error;
 		}
 #ifdef INET
@@ -1539,7 +1541,7 @@ ether_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 			return error;
 		else if (ifp->if_flags & IFF_UP) {
 			/* Make sure the device notices the MTU change. */
-			return (*ifp->if_init)(ifp);
+			return if_init(ifp);
 		} else
 			return 0;
 	    }
diff --git a/sys/net/if_ieee1394subr.c b/sys/net/if_ieee1394subr.c
index 94f895c91d0b..ca4825f0171d 100644
--- a/sys/net/if_ieee1394subr.c
+++ b/sys/net/if_ieee1394subr.c
@@ -681,13 +681,13 @@ ieee1394_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		switch (ifa->ifa_addr->sa_family) {
 #ifdef INET
 		case AF_INET:
-			if ((error = (*ifp->if_init)(ifp)) != 0)
+			if ((error = if_init(ifp)) != 0)
 				break;
 			arp_ifinit(ifp, ifa);
 			break;
 #endif /* INET */
 		default:
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 			break;
 		}
 		break;
diff --git a/sys/net/if_wg.c b/sys/net/if_wg.c
index 696ad075d05e..ea9fc2afe8b5 100644
--- a/sys/net/if_wg.c
+++ b/sys/net/if_wg.c
@@ -4619,7 +4619,7 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		    (ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
 		    (IFF_UP | IFF_RUNNING)) {
 			ifp->if_flags |= IFF_UP;
-			error = ifp->if_init(ifp);
+			error = if_init(ifp);
 		}
 		return error;
 	case SIOCADDMULTI:
@@ -4666,14 +4666,14 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 			 * If interface is marked down and it is running,
 			 * then stop and disable it.
 			 */
-			(*ifp->if_stop)(ifp, 1);
+			if_stop(ifp, 1);
 			break;
 		case IFF_UP:
 			/*
 			 * If interface is marked up and it is stopped, then
 			 * start it.
 			 */
-			error = (*ifp->if_init)(ifp);
+			error = if_init(ifp);
 			break;
 		default:
 			break;
diff --git a/sys/net/lagg/if_lagg.c b/sys/net/lagg/if_lagg.c
index 326680c5a3ef..7443adafd697 100644
--- a/sys/net/lagg/if_lagg.c
+++ b/sys/net/lagg/if_lagg.c
@@ -721,11 +721,11 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 
 		switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
 		case IFF_RUNNING:
-			ifp->if_stop(ifp, 1);
+			if_stop(ifp, 1);
 			break;
 		case IFF_UP:
 		case IFF_UP | IFF_RUNNING:
-			error = ifp->if_init(ifp);
+			error = if_init(ifp);
 			break;
 		}
 
@@ -2115,7 +2115,7 @@ lagg_port_setsadl(struct lagg_port *lp, uint8_t *lladdr,
 		if (ifp_port->if_init != NULL) {
 			error = 0;
 			if (ISSET(ifp_port->if_flags, IFF_RUNNING))
-				error = ifp_port->if_init(ifp_port);
+				error = if_init(ifp_port);
 
 			if (error != 0) {
 				lagg_log(lp->lp_softc, LOG_WARNING,
@@ -2161,7 +2161,7 @@ lagg_port_unsetsadl(struct lagg_port *lp)
 		if (ifp_port->if_init != NULL) {
 			error = 0;
 			if (ISSET(ifp_port->if_flags, IFF_RUNNING))
-				error = ifp_port->if_init(ifp_port);
+				error = if_init(ifp_port);
 
 			if (error != 0) {
 				lagg_log(lp->lp_softc, LOG_WARNING,
@@ -2354,7 +2354,7 @@ lagg_port_setup(struct lagg_softc *sc,
 
 	if (ISSET(ifp_port->if_flags, IFF_RUNNING) &&
 	    ifp_port->if_init != NULL) {
-		ifp_port->if_stop(ifp_port, 0);
+		if_stop(ifp_port, 0);
 		stopped = true;
 	}
 
@@ -2385,7 +2385,7 @@ lagg_port_setup(struct lagg_softc *sc,
 	lagg_port_syncvlan(sc, lp);
 
 	if (stopped) {
-		error = ifp_port->if_init(ifp_port);
+		error = if_init(ifp_port);
 		if (error != 0)
 			goto remove_port;
 	}
@@ -2415,7 +2415,7 @@ restore_ipv6lla:
 	KASSERT(IFNET_LOCKED(ifp_port));
 	lagg_in6_ifdetach(ifp_port);
 	if (stopped) {
-		if (ifp_port->if_init(ifp_port) != 0) {
+		if (if_init(ifp_port) != 0) {
 			lagg_log(sc, LOG_WARNING,
 			    "couldn't re-start port %s\n",
 			    ifp_port->if_xname);
@@ -2475,7 +2475,7 @@ lagg_port_teardown(struct lagg_softc *sc, struct lagg_port *lp,
 	IFNET_LOCK(ifp_port);
 	if (ISSET(ifp_port->if_flags, IFF_RUNNING) &&
 	    ifp_port->if_init != NULL) {
-		ifp_port->if_stop(ifp_port, 0);
+		if_stop(ifp_port, 0);
 		stopped = true;
 	}
 
@@ -2487,7 +2487,7 @@ lagg_port_teardown(struct lagg_softc *sc, struct lagg_port *lp,
 	IFNET_UNLOCK(ifp_port);
 
 	if (stopped) {
-		ifp_port->if_init(ifp_port);
+		if_init(ifp_port);
 	}
 
 	if (is_ifdetach == false) {
diff --git a/sys/net/lagg/if_lagg_lacp.c b/sys/net/lagg/if_lagg_lacp.c
index dfc7a6635a4f..abec367c43f2 100644
--- a/sys/net/lagg/if_lagg_lacp.c
+++ b/sys/net/lagg/if_lagg_lacp.c
@@ -839,7 +839,7 @@ lacp_linkstate(struct lagg_proto_softc *xlsc, struct lagg_port *lp)
 
 	memset(&ifmr, 0, sizeof(ifmr));
 	ifmr.ifm_count = 0;
-	error = ifp_port->if_ioctl(ifp_port, SIOCGIFMEDIA, (void *)&ifmr);
+	error = if_ioctl(ifp_port, SIOCGIFMEDIA, (void *)&ifmr);
 	if (error == 0) {
 		media = lacp_ifmedia2lacpmedia(ifmr.ifm_active);
 	} else if (error != ENOTTY){
diff --git a/sys/net/link_proto.c b/sys/net/link_proto.c
index 2c4ecf621ba4..58531aacb620 100644
--- a/sys/net/link_proto.c
+++ b/sys/net/link_proto.c
@@ -255,7 +255,7 @@ link_control(struct socket *so, unsigned long cmd, void *data,
 			return error;
 		else if ((ifp->if_flags & IFF_RUNNING) != 0 &&
 		         ifp->if_init != NULL)
-			return (*ifp->if_init)(ifp);
+			return if_init(ifp);
 		else
 			return 0;
 	default:
diff --git a/sys/netcan/can.c b/sys/netcan/can.c
index 0a0c67c0704e..adf70a9495ed 100644
--- a/sys/netcan/can.c
+++ b/sys/netcan/can.c
@@ -187,7 +187,7 @@ can_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 	default:
 		if (ifp->if_ioctl == 0)
 			return (EOPNOTSUPP);
-		return ((*ifp->if_ioctl)(ifp, cmd, data));
+		return (if_ioctl(ifp, cmd, data));
 	}
 	return (0);
 }