diff options
author | Weongyo Jeong <weongyo@FreeBSD.org> | 2009-06-17 04:15:19 +0000 |
---|---|---|
committer | Weongyo Jeong <weongyo@FreeBSD.org> | 2009-06-17 04:15:19 +0000 |
commit | c39515adc43b9e098b9cd5bdd35a667d64d1b900 (patch) | |
tree | 04ff91100a6bd85de23b35ff30897297fc3f1cbc /sys/dev/usb | |
parent | 5d11bdc65147dbdc5172b3be3fc6404a77b6b7e3 (diff) |
reorders the sequence when the device is detached. After detaching the
interface is completed then it'll process other parts to avoid a race
condition.
Pointed by: jhb
Notes
Notes:
svn path=/head/; revision=194329
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/wlan/if_uath.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/sys/dev/usb/wlan/if_uath.c b/sys/dev/usb/wlan/if_uath.c index 29f23985c9ff..bc1531f71751 100644 --- a/sys/dev/usb/wlan/if_uath.c +++ b/sys/dev/usb/wlan/if_uath.c @@ -513,14 +513,17 @@ uath_detach(device_t dev) if (!device_is_attached(dev)) return (0); + UATH_LOCK(sc); sc->sc_flags |= UATH_FLAG_INVALID; + UATH_UNLOCK(sc); + + ieee80211_ifdetach(ic); uath_stop(ifp); callout_drain(&sc->stat_ch); callout_drain(&sc->watchdog_ch); usbd_transfer_unsetup(sc->sc_xfer, UATH_N_XFERS); - ieee80211_ifdetach(ic); /* free buffers */ UATH_LOCK(sc); @@ -1857,7 +1860,8 @@ uath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, struct uath_softc *sc = ifp->if_softc; /* prevent management frames from being sent if we're not ready */ - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + if ((sc->sc_flags & UATH_FLAG_INVALID) || + !(ifp->if_drv_flags & IFF_DRV_RUNNING)) { m_freem(m); ieee80211_free_node(ni); return (ENETDOWN); @@ -1907,6 +1911,11 @@ uath_set_channel(struct ieee80211com *ic) struct uath_softc *sc = ifp->if_softc; UATH_LOCK(sc); + if ((sc->sc_flags & UATH_FLAG_INVALID) || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + UATH_UNLOCK(sc); + return; + } (void)uath_switch_channel(sc, ic->ic_curchan); UATH_UNLOCK(sc); } @@ -1923,6 +1932,11 @@ uath_update_mcast(struct ifnet *ifp) struct uath_softc *sc = ifp->if_softc; UATH_LOCK(sc); + if ((sc->sc_flags & UATH_FLAG_INVALID) || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + UATH_UNLOCK(sc); + return; + } /* * this is for avoiding the race condition when we're try to * connect to the AP with WPA. @@ -1938,6 +1952,11 @@ uath_update_promisc(struct ifnet *ifp) struct uath_softc *sc = ifp->if_softc; UATH_LOCK(sc); + if ((sc->sc_flags & UATH_FLAG_INVALID) || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + UATH_UNLOCK(sc); + return; + } if (sc->sc_flags & UATH_FLAG_INITDONE) { uath_set_rxfilter(sc, UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST | @@ -2649,7 +2668,8 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, } /* there are a lot more fields in the RX descriptor */ - if (ieee80211_radiotap_active(ic)) { + if ((sc->sc_flags & UATH_FLAG_INVALID) == 0 && + ieee80211_radiotap_active(ic)) { struct uath_rx_radiotap_header *tap = &sc->sc_rxtap; uint32_t tsf_hi = be32toh(desc->tstamp_high); uint32_t tsf_lo = be32toh(desc->tstamp_low); @@ -2717,6 +2737,11 @@ setup: * ieee80211_input() because here is at the end of a USB * callback and safe to unlock. */ + if (sc->sc_flags & UATH_FLAG_INVALID) { + if (m != NULL) + m_freem(m); + return; + } UATH_UNLOCK(sc); if (m != NULL && desc != NULL) { wh = mtod(m, struct ieee80211_frame *); @@ -2769,7 +2794,8 @@ uath_data_txeof(struct usb_xfer *xfer, struct uath_data *data) */ if (data->m) { m = data->m; - if (m->m_flags & M_TXCB) { + if (m->m_flags & M_TXCB && + (sc->sc_flags & UATH_FLAG_INVALID) == 0) { /* XXX status? */ ieee80211_process_callback(data->ni, m, 0); } @@ -2777,7 +2803,8 @@ uath_data_txeof(struct usb_xfer *xfer, struct uath_data *data) data->m = NULL; } if (data->ni) { - ieee80211_free_node(data->ni); + if ((sc->sc_flags & UATH_FLAG_INVALID) == 0) + ieee80211_free_node(data->ni); data->ni = NULL; } sc->sc_tx_timer = 0; @@ -2831,7 +2858,8 @@ setup: if (data == NULL) goto setup; if (data->ni != NULL) { - ieee80211_free_node(data->ni); + if ((sc->sc_flags & UATH_FLAG_INVALID) == 0) + ieee80211_free_node(data->ni); data->ni = NULL; ifp->if_oerrors++; } |