ath9k: fix beacon resource related race condition
authorRajkumar Manoharan <rmanoharan@atheros.com>
Tue, 7 Dec 2010 12:12:18 +0000 (17:42 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 7 Dec 2010 19:57:06 +0000 (14:57 -0500)
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>
drivers/net/wireless/ath/ath9k/main.c

index 928ef68ab40c948d4d4a037d7a555c54b11446bb..c0c3464d3a861162e1142a0e2931a73aedae1fab 100644 (file)
@@ -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);