Author: kevlo
Date: Fri Mar 14 06:37:08 2014
New Revision: 263153
URL: http://svnweb.freebsd.org/changeset/base/263153

Log:
  Similar to r246614, fix panic on removing urtwn(4).  It happens because
  nodes are freed after the adapter is gone.

Modified:
  head/sys/dev/usb/wlan/if_urtwn.c
  head/sys/dev/usb/wlan/if_urtwnreg.h

Modified: head/sys/dev/usb/wlan/if_urtwn.c
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwn.c    Fri Mar 14 06:29:43 2014        
(r263152)
+++ head/sys/dev/usb/wlan/if_urtwn.c    Fri Mar 14 06:37:08 2014        
(r263153)
@@ -247,8 +247,8 @@ static void         urtwn_iq_calib(struct urtwn
 static void            urtwn_lc_calib(struct urtwn_softc *);
 static void            urtwn_init(void *);
 static void            urtwn_init_locked(void *);
-static void            urtwn_stop(struct ifnet *, int);
-static void            urtwn_stop_locked(struct ifnet *, int);
+static void            urtwn_stop(struct ifnet *);
+static void            urtwn_stop_locked(struct ifnet *);
 static void            urtwn_abort_xfers(struct urtwn_softc *);
 static int             urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
                            const struct ieee80211_bpf_params *);
@@ -459,20 +459,40 @@ urtwn_detach(device_t self)
        struct urtwn_softc *sc = device_get_softc(self);
        struct ifnet *ifp = sc->sc_ifp;
        struct ieee80211com *ic = ifp->if_l2com;
+       unsigned int x;
        
-       if (!device_is_attached(self))
-               return (0);
+       /* Prevent further ioctls. */
+       URTWN_LOCK(sc);
+       sc->sc_flags |= URTWN_DETACHED;
+       URTWN_UNLOCK(sc);
 
-       urtwn_stop(ifp, 1);
+       urtwn_stop(ifp);
 
        callout_drain(&sc->sc_watchdog_ch);
 
-       /* stop all USB transfers */
-       usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER);
-       ieee80211_ifdetach(ic);
+       /* Prevent further allocations from RX/TX data lists. */
+       URTWN_LOCK(sc);
+       STAILQ_INIT(&sc->sc_tx_active);
+       STAILQ_INIT(&sc->sc_tx_inactive);
+       STAILQ_INIT(&sc->sc_tx_pending);
+
+       STAILQ_INIT(&sc->sc_rx_active);
+       STAILQ_INIT(&sc->sc_rx_inactive);
+       URTWN_UNLOCK(sc);
 
+       /* drain USB transfers */
+       for (x = 0; x != URTWN_N_TRANSFER; x++)
+               usbd_transfer_drain(sc->sc_xfer[x]);
+
+       /* Free data buffers. */
+       URTWN_LOCK(sc);
        urtwn_free_tx_list(sc);
        urtwn_free_rx_list(sc);
+       URTWN_UNLOCK(sc);
+
+       /* stop all USB transfers */
+       usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER);
+       ieee80211_ifdetach(ic);
 
        if_free(ifp);
        mtx_destroy(&sc->sc_mtx);
@@ -1758,10 +1778,17 @@ urtwn_start_locked(struct ifnet *ifp, st
 static int
 urtwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
+       struct urtwn_softc *sc = ifp->if_softc;
        struct ieee80211com *ic = ifp->if_l2com;
        struct ifreq *ifr = (struct ifreq *) data;
        int error = 0, startall = 0;
 
+       URTWN_LOCK(sc);
+       error = (sc->sc_flags & URTWN_DETACHED) ? ENXIO : 0;
+       URTWN_UNLOCK(sc);
+       if (error != 0)
+               return (error);
+
        switch (cmd) {
        case SIOCSIFFLAGS:
                if (ifp->if_flags & IFF_UP) {
@@ -1771,7 +1798,7 @@ urtwn_ioctl(struct ifnet *ifp, u_long cm
                        }
                } else {
                        if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-                               urtwn_stop(ifp, 1);
+                               urtwn_stop(ifp);
                }
                if (startall)
                        ieee80211_start_all(ic);
@@ -2785,7 +2812,7 @@ urtwn_init_locked(void *arg)
        int error;
 
        if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-               urtwn_stop_locked(ifp, 0);
+               urtwn_stop_locked(ifp);
 
        /* Init firmware commands ring. */
        sc->fwcur = 0;
@@ -2943,11 +2970,10 @@ urtwn_init(void *arg)
 }
 
 static void
-urtwn_stop_locked(struct ifnet *ifp, int disable)
+urtwn_stop_locked(struct ifnet *ifp)
 {
        struct urtwn_softc *sc = ifp->if_softc;
 
-       (void)disable;
        ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 
        callout_stop(&sc->sc_watchdog_ch);
@@ -2955,12 +2981,12 @@ urtwn_stop_locked(struct ifnet *ifp, int
 }
 
 static void
-urtwn_stop(struct ifnet *ifp, int disable)
+urtwn_stop(struct ifnet *ifp)
 {
        struct urtwn_softc *sc = ifp->if_softc;
 
        URTWN_LOCK(sc);
-       urtwn_stop_locked(ifp, disable);
+       urtwn_stop_locked(ifp);
        URTWN_UNLOCK(sc);
 }
 

Modified: head/sys/dev/usb/wlan/if_urtwnreg.h
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwnreg.h Fri Mar 14 06:29:43 2014        
(r263152)
+++ head/sys/dev/usb/wlan/if_urtwnreg.h Fri Mar 14 06:37:08 2014        
(r263153)
@@ -1119,6 +1119,7 @@ struct urtwn_softc {
        int                             ac2idx[WME_NUM_AC];
        u_int                           sc_flags;
 #define URTWN_FLAG_CCK_HIPWR   0x01
+#define URTWN_DETACHED         0x02
 
        u_int                           chip;
 #define URTWN_CHIP_92C         0x01
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to