--- a/sys/bus/u4b/net/if_mos.c +++ b/sys/bus/u4b/net/if_mos.c @@ -703,7 +703,7 @@ if (error) { device_printf(dev, "allocating USB transfers failed\n"); - goto detach; + goto detach_usb; } ue->ue_sc = sc; ue->ue_dev = dev; @@ -722,14 +722,23 @@ error = uether_ifattach(ue); if (error) { device_printf(dev, "could not attach interface\n"); - goto detach; + goto detach_usb; } return (0); -detach: - mos_detach(dev); - return (ENXIO); +detach_usb: + /* + * The usb_ether was never attached (or failed halfway): do NOT + * call mos_detach()/uether_ifdetach() on it -- with ue_lock still + * NULL (USB transfer setup failure) uether_ifdetach() lockmgr()s + * through the NULL pointer, and after a failed uether_ifattach() + * the embedded ifnet was never if_attach()ed, so ether_ifdetach() + * would corrupt ifindex2ifnet[0] and the global ifnet list. + */ + usbd_transfer_unsetup(sc->sc_xfer, MOS_ENDPT_MAX); + lockuninit(&sc->sc_lock); + return (ENXIO); /* failure */ } --- a/sys/bus/u4b/net/usb_ethernet.c +++ b/sys/bus/u4b/net/usb_ethernet.c @@ -269,6 +269,16 @@ { struct ifnet *ifp; + /* + * A driver attach() failure may call detach() on a usb_ether that + * was never uether_ifattach()ed: ue_lock is still NULL there and + * the embedded ifnet was never if_attach()ed. Bail out instead + * of lockmgr()ing through the NULL pointer and tearing down a + * non-existent ifnet. + */ + if (ue->ue_lock == NULL) + return; + /* wait for any post attach or other command to complete */ usb_proc_drain(&ue->ue_tq);