ath9k: Fix panic when adding an AP interface
authorSujith Manoharan <c_manoha@qca.qualcomm.com>
Fri, 5 Sep 2014 02:33:11 +0000 (08:03 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 9 Sep 2014 19:27:20 +0000 (15:27 -0400)
If a station interface is already assigned to a context
and is active and a second interface of type AP is added,
then beaconing on the new interface has to be begin only
after the BSS_CHANGED_BEACON_ENABLED flag is sent by mac80211
to the driver.

But, since we issue ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL as soon
as a new channel context is added, a switch occurs almost immediately
before BSS_CHANGED_BEACON_ENABLED is received. When a HW reset
is done for the new context, beacons are enabled for the
interface since "enable_beacon" in the BSS config maintained
in mac80211 is true - but the driver hasn't been notified yet.
This causes a panic, since the beacon interval is zero for this
interface and ath9k_cmn_beacon_config_ap() doesn't have a safety check.

Fix this panic by checking if the beacon params has been cached
for this context and use the "enable_beacon" flag maintained
locally in the driver. Also, recalculate the summary data
after the beacon params have been cached when BSS_CHANGED_BEACON_ENABLED
is received.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/main.c

index 0b3d4d8..2333776 100644 (file)
@@ -916,8 +916,6 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
        switch (vif->type) {
        case NL80211_IFTYPE_AP:
                iter_data->naps++;
-               if (vif->bss_conf.enable_beacon)
-                       iter_data->beacons = true;
                break;
        case NL80211_IFTYPE_STATION:
                iter_data->nstations++;
@@ -1021,6 +1019,7 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_vif_iter_data iter_data;
+       struct ath_beacon_config *cur_conf;
 
        ath_chanctx_check_active(sc, ctx);
 
@@ -1037,8 +1036,11 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
        ath_hw_setbssidmask(common);
 
        if (iter_data.naps > 0) {
+               cur_conf = &ctx->beacon;
                ath9k_hw_set_tsfadjust(ah, true);
                ah->opmode = NL80211_IFTYPE_AP;
+               if (cur_conf->enable_beacon)
+                       iter_data.beacons = true;
        } else {
                ath9k_hw_set_tsfadjust(ah, false);
 
@@ -1695,9 +1697,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
            (changed & BSS_CHANGED_BEACON_INT) ||
            (changed & BSS_CHANGED_BEACON_INFO)) {
+               ath9k_beacon_config(sc, vif, changed);
                if (changed & BSS_CHANGED_BEACON_ENABLED)
                        ath9k_calculate_summary_state(sc, avp->chanctx);
-               ath9k_beacon_config(sc, vif, changed);
        }
 
        if ((avp->chanctx == sc->cur_chan) &&