aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-04-09 09:10:59 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-05-06 09:10:00 -0400
commit59af6928d2099479c0bc2ef3f66cc7b33998120a (patch)
treeef9010f083ae04406516c0e8cac87d0ebcd23546 /net/mac80211/mlme.c
parent33926eb7785ac7ce7d45d1ae5afb0780a4270342 (diff)
mac80211: fix CSA tx queue stopping
It was possible for tx queues to be stuck stopped if AP CSA finalization failed. In that case neither stop_ap nor do_stop woke the queues up. This means it was impossible to perform tx at all until driver was reloaded or a successful CSA was performed later. It was possible to solve this in a simpler manner however this is more robust and future proof (having multi-vif CSA in mind). New sdata->csa_block_tx is introduced to keep track of which interfaces requested tx to be blocked for CSA. This is required because mac80211 stops all tx queues for that purpose. This means queues must be awoken only when last tx-blocking CSA interface is finished. It is still possible to have tx queues stopped after CSA failure but as soon as offending interfaces are stopped from userspace (stop_ap or ifdown) tx queues are woken up properly. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 488826f188a7..d68e73cbdcd6 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -975,16 +975,20 @@ static void ieee80211_chswitch_work(struct work_struct *work)
975 /* XXX: shouldn't really modify cfg80211-owned data! */ 975 /* XXX: shouldn't really modify cfg80211-owned data! */
976 ifmgd->associated->channel = sdata->csa_chandef.chan; 976 ifmgd->associated->channel = sdata->csa_chandef.chan;
977 977
978 ieee80211_bss_info_change_notify(sdata, changed);
979
980 mutex_lock(&local->mtx);
981 sdata->vif.csa_active = false;
978 /* XXX: wait for a beacon first? */ 982 /* XXX: wait for a beacon first? */
979 ieee80211_wake_queues_by_reason(&local->hw, 983 if (!ieee80211_csa_needs_block_tx(local))
984 ieee80211_wake_queues_by_reason(&local->hw,
980 IEEE80211_MAX_QUEUE_MAP, 985 IEEE80211_MAX_QUEUE_MAP,
981 IEEE80211_QUEUE_STOP_REASON_CSA); 986 IEEE80211_QUEUE_STOP_REASON_CSA);
987 mutex_unlock(&local->mtx);
982 988
983 ieee80211_bss_info_change_notify(sdata, changed);
984
985 out:
986 sdata->vif.csa_active = false;
987 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; 989 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
990
991out:
988 sdata_unlock(sdata); 992 sdata_unlock(sdata);
989} 993}
990 994
@@ -1100,12 +1104,16 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1100 mutex_unlock(&local->chanctx_mtx); 1104 mutex_unlock(&local->chanctx_mtx);
1101 1105
1102 sdata->csa_chandef = csa_ie.chandef; 1106 sdata->csa_chandef = csa_ie.chandef;
1107
1108 mutex_lock(&local->mtx);
1103 sdata->vif.csa_active = true; 1109 sdata->vif.csa_active = true;
1110 sdata->csa_block_tx = csa_ie.mode;
1104 1111
1105 if (csa_ie.mode) 1112 if (sdata->csa_block_tx)
1106 ieee80211_stop_queues_by_reason(&local->hw, 1113 ieee80211_stop_queues_by_reason(&local->hw,
1107 IEEE80211_MAX_QUEUE_MAP, 1114 IEEE80211_MAX_QUEUE_MAP,
1108 IEEE80211_QUEUE_STOP_REASON_CSA); 1115 IEEE80211_QUEUE_STOP_REASON_CSA);
1116 mutex_unlock(&local->mtx);
1109 1117
1110 if (local->ops->channel_switch) { 1118 if (local->ops->channel_switch) {
1111 /* use driver's channel switch callback */ 1119 /* use driver's channel switch callback */
@@ -1817,6 +1825,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1817 ifmgd->flags = 0; 1825 ifmgd->flags = 0;
1818 mutex_lock(&local->mtx); 1826 mutex_lock(&local->mtx);
1819 ieee80211_vif_release_channel(sdata); 1827 ieee80211_vif_release_channel(sdata);
1828
1829 sdata->vif.csa_active = false;
1830 if (!ieee80211_csa_needs_block_tx(local))
1831 ieee80211_wake_queues_by_reason(&local->hw,
1832 IEEE80211_MAX_QUEUE_MAP,
1833 IEEE80211_QUEUE_STOP_REASON_CSA);
1820 mutex_unlock(&local->mtx); 1834 mutex_unlock(&local->mtx);
1821 1835
1822 sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; 1836 sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
@@ -2045,6 +2059,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get);
2045 2059
2046static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) 2060static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
2047{ 2061{
2062 struct ieee80211_local *local = sdata->local;
2048 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 2063 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2049 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; 2064 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
2050 2065
@@ -2058,10 +2073,14 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
2058 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, 2073 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
2059 true, frame_buf); 2074 true, frame_buf);
2060 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; 2075 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
2076
2077 mutex_lock(&local->mtx);
2061 sdata->vif.csa_active = false; 2078 sdata->vif.csa_active = false;
2062 ieee80211_wake_queues_by_reason(&sdata->local->hw, 2079 if (!ieee80211_csa_needs_block_tx(local))
2080 ieee80211_wake_queues_by_reason(&local->hw,
2063 IEEE80211_MAX_QUEUE_MAP, 2081 IEEE80211_MAX_QUEUE_MAP,
2064 IEEE80211_QUEUE_STOP_REASON_CSA); 2082 IEEE80211_QUEUE_STOP_REASON_CSA);
2083 mutex_unlock(&local->mtx);
2065 2084
2066 cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, 2085 cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
2067 IEEE80211_DEAUTH_FRAME_LEN); 2086 IEEE80211_DEAUTH_FRAME_LEN);