ath9k: race condition in SCANNING state check during ANI calibration
authorSenthil Balasubramanian <senthilkumar@atheros.com>
Wed, 24 Jun 2009 13:26:41 +0000 (18:56 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 10 Jul 2009 19:02:24 +0000 (15:02 -0400)
ANI calibration shouldn't be done when we are not on our home channel.
This is already verified. However, it is racy. Fix this by proper
spin locks.

Signed-off-by: Senthil Balasubramanian <senthilkumar@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/main.c

index 747e046b03b0cc75d211dd57003fd7fab5abbacd..eb9d5228cb6c4e6bf3e2991ac49a1cd60d6c4770 100644 (file)
@@ -540,6 +540,7 @@ struct ath_softc {
        int irq;
        spinlock_t sc_resetlock;
        spinlock_t sc_serial_rw;
        int irq;
        spinlock_t sc_resetlock;
        spinlock_t sc_serial_rw;
+       spinlock_t ani_lock;
        struct mutex mutex;
 
        u8 curbssid[ETH_ALEN];
        struct mutex mutex;
 
        u8 curbssid[ETH_ALEN];
index 6d63126a81f1a0225c7e58bd559f8d0b8d388297..52dfa43bc5298412348b85049fa8ef7b0c3bdfc3 100644 (file)
@@ -342,6 +342,7 @@ static void ath_ani_calibrate(unsigned long data)
        * don't calibrate when we're scanning.
        * we are most likely not on our home channel.
        */
        * don't calibrate when we're scanning.
        * we are most likely not on our home channel.
        */
+       spin_lock(&sc->ani_lock);
        if (sc->sc_flags & SC_OP_SCANNING)
                goto set_timer;
 
        if (sc->sc_flags & SC_OP_SCANNING)
                goto set_timer;
 
@@ -405,6 +406,7 @@ static void ath_ani_calibrate(unsigned long data)
        ath9k_ps_restore(sc);
 
 set_timer:
        ath9k_ps_restore(sc);
 
 set_timer:
+       spin_unlock(&sc->ani_lock);
        /*
        * Set timer interval based on previous results.
        * The interval must be the shortest necessary to satisfy ANI,
        /*
        * Set timer interval based on previous results.
        * The interval must be the shortest necessary to satisfy ANI,
@@ -1310,6 +1312,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
        spin_lock_init(&sc->wiphy_lock);
        spin_lock_init(&sc->sc_resetlock);
        spin_lock_init(&sc->sc_serial_rw);
        spin_lock_init(&sc->wiphy_lock);
        spin_lock_init(&sc->sc_resetlock);
        spin_lock_init(&sc->sc_serial_rw);
+       spin_lock_init(&sc->ani_lock);
        mutex_init(&sc->mutex);
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
        tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
        mutex_init(&sc->mutex);
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
        tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -2682,9 +2685,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
        aphy->state = ATH_WIPHY_SCAN;
        ath9k_wiphy_pause_all_forced(sc, aphy);
 
        aphy->state = ATH_WIPHY_SCAN;
        ath9k_wiphy_pause_all_forced(sc, aphy);
 
-       mutex_lock(&sc->mutex);
+       spin_lock_bh(&sc->ani_lock);
        sc->sc_flags |= SC_OP_SCANNING;
        sc->sc_flags |= SC_OP_SCANNING;
-       mutex_unlock(&sc->mutex);
+       spin_unlock_bh(&sc->ani_lock);
 }
 
 static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 }
 
 static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@@ -2692,11 +2695,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
 
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
 
-       mutex_lock(&sc->mutex);
+       spin_lock_bh(&sc->ani_lock);
        aphy->state = ATH_WIPHY_ACTIVE;
        sc->sc_flags &= ~SC_OP_SCANNING;
        sc->sc_flags |= SC_OP_FULL_RESET;
        aphy->state = ATH_WIPHY_ACTIVE;
        sc->sc_flags &= ~SC_OP_SCANNING;
        sc->sc_flags |= SC_OP_FULL_RESET;
-       mutex_unlock(&sc->mutex);
+       spin_unlock_bh(&sc->ani_lock);
 }
 
 struct ieee80211_ops ath9k_ops = {
 }
 
 struct ieee80211_ops ath9k_ops = {