aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRajkumar Manoharan <rmanoharan@atheros.com>2010-12-07 07:12:18 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-07 14:57:06 -0500
commit884a963fa1c828a5c5fa7a46b2877dd463bfd47c (patch)
treea44694ceaea70ed4beb362bac3ac6b59054b063a /drivers
parent38852b20c8b6d97618204ac64abbf14f0080393e (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.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 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);