summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRajkumar Manoharan <rmanoharan@atheros.com>2010-12-07 12:12:18 (GMT)
committerJohn W. Linville <linville@tuxdriver.com>2010-12-07 19:57:06 (GMT)
commit884a963fa1c828a5c5fa7a46b2877dd463bfd47c (patch)
treea44694ceaea70ed4beb362bac3ac6b59054b063a
parent38852b20c8b6d97618204ac64abbf14f0080393e (diff)
downloadlinux-884a963fa1c828a5c5fa7a46b2877dd463bfd47c.tar.xz
ath9k: fix beacon resource related race condition
The beacon tasklet is accesssing the bslot info for beacon generation. Meanwhile the same slot can be freed on interface deletion. Current the remove_interface disables the beacon alert after freeing the slot. This may leads to null pointer access. This patch disables SWBA and kills the beacon tasklet to prevent access to the slot to be freed. After releasing the slot, swba will be enabled again upon the availablity of beaconing interfaces. Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c21
1 files changed, 7 insertions, 14 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 928ef68..c0c3464 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1520,8 +1520,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
- bool bs_valid = false;
- int i;
ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
@@ -1535,26 +1533,21 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
(sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
(sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) {
+ /* Disable SWBA interrupt */
+ sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
ath9k_ps_wakeup(sc);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
ath9k_ps_restore(sc);
+ tasklet_kill(&sc->bcon_tasklet);
}
ath_beacon_return(sc, avp);
sc->sc_flags &= ~SC_OP_BEACONS;
- for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
- if (sc->beacon.bslot[i] == vif) {
- printk(KERN_DEBUG "%s: vif had allocated beacon "
- "slot\n", __func__);
- sc->beacon.bslot[i] = NULL;
- sc->beacon.bslot_aphy[i] = NULL;
- } else if (sc->beacon.bslot[i])
- bs_valid = true;
- }
- if (!bs_valid && (sc->sc_ah->imask & ATH9K_INT_SWBA)) {
- /* Disable SWBA interrupt */
- sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
+ if (sc->nbcnvifs) {
+ /* Re-enable SWBA interrupt */
+ sc->sc_ah->imask |= ATH9K_INT_SWBA;
ath9k_ps_wakeup(sc);
ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
ath9k_ps_restore(sc);