diff options
author | Rajkumar Manoharan <rmanoharan@atheros.com> | 2010-12-07 07:12:18 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-07 14:57:06 -0500 |
commit | 884a963fa1c828a5c5fa7a46b2877dd463bfd47c (patch) | |
tree | a44694ceaea70ed4beb362bac3ac6b59054b063a /drivers | |
parent | 38852b20c8b6d97618204ac64abbf14f0080393e (diff) |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 21 |
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 928ef68ab40c..c0c3464d3a86 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, | |||
1520 | struct ath_softc *sc = aphy->sc; | 1520 | struct ath_softc *sc = aphy->sc; |
1521 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1521 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1522 | struct ath_vif *avp = (void *)vif->drv_priv; | 1522 | struct ath_vif *avp = (void *)vif->drv_priv; |
1523 | bool bs_valid = false; | ||
1524 | int i; | ||
1525 | 1523 | ||
1526 | ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); | 1524 | ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); |
1527 | 1525 | ||
@@ -1535,26 +1533,21 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
1535 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || | 1533 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || |
1536 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || | 1534 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || |
1537 | (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { | 1535 | (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { |
1536 | /* Disable SWBA interrupt */ | ||
1537 | sc->sc_ah->imask &= ~ATH9K_INT_SWBA; | ||
1538 | ath9k_ps_wakeup(sc); | 1538 | ath9k_ps_wakeup(sc); |
1539 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); | ||
1539 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | 1540 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); |
1540 | ath9k_ps_restore(sc); | 1541 | ath9k_ps_restore(sc); |
1542 | tasklet_kill(&sc->bcon_tasklet); | ||
1541 | } | 1543 | } |
1542 | 1544 | ||
1543 | ath_beacon_return(sc, avp); | 1545 | ath_beacon_return(sc, avp); |
1544 | sc->sc_flags &= ~SC_OP_BEACONS; | 1546 | sc->sc_flags &= ~SC_OP_BEACONS; |
1545 | 1547 | ||
1546 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { | 1548 | if (sc->nbcnvifs) { |
1547 | if (sc->beacon.bslot[i] == vif) { | 1549 | /* Re-enable SWBA interrupt */ |
1548 | printk(KERN_DEBUG "%s: vif had allocated beacon " | 1550 | sc->sc_ah->imask |= ATH9K_INT_SWBA; |
1549 | "slot\n", __func__); | ||
1550 | sc->beacon.bslot[i] = NULL; | ||
1551 | sc->beacon.bslot_aphy[i] = NULL; | ||
1552 | } else if (sc->beacon.bslot[i]) | ||
1553 | bs_valid = true; | ||
1554 | } | ||
1555 | if (!bs_valid && (sc->sc_ah->imask & ATH9K_INT_SWBA)) { | ||
1556 | /* Disable SWBA interrupt */ | ||
1557 | sc->sc_ah->imask &= ~ATH9K_INT_SWBA; | ||
1558 | ath9k_ps_wakeup(sc); | 1551 | ath9k_ps_wakeup(sc); |
1559 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); | 1552 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); |
1560 | ath9k_ps_restore(sc); | 1553 | ath9k_ps_restore(sc); |