aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
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
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')
-rw-r--r--net/mac80211/cfg.c77
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/iface.c7
-rw-r--r--net/mac80211/mlme.c37
4 files changed, 101 insertions, 22 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 19a7e6ff45d3..f789c3198af4 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1084,6 +1084,31 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
1084 return 0; 1084 return 0;
1085} 1085}
1086 1086
1087bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local)
1088{
1089 struct ieee80211_sub_if_data *sdata;
1090
1091 lockdep_assert_held(&local->mtx);
1092
1093 rcu_read_lock();
1094 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
1095 if (!ieee80211_sdata_running(sdata))
1096 continue;
1097
1098 if (!sdata->vif.csa_active)
1099 continue;
1100
1101 if (!sdata->csa_block_tx)
1102 continue;
1103
1104 rcu_read_unlock();
1105 return true;
1106 }
1107 rcu_read_unlock();
1108
1109 return false;
1110}
1111
1087static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) 1112static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
1088{ 1113{
1089 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1114 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1101,7 +1126,14 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
1101 old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata); 1126 old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
1102 1127
1103 /* abort any running channel switch */ 1128 /* abort any running channel switch */
1129 mutex_lock(&local->mtx);
1104 sdata->vif.csa_active = false; 1130 sdata->vif.csa_active = false;
1131 if (!ieee80211_csa_needs_block_tx(local))
1132 ieee80211_wake_queues_by_reason(&local->hw,
1133 IEEE80211_MAX_QUEUE_MAP,
1134 IEEE80211_QUEUE_STOP_REASON_CSA);
1135 mutex_unlock(&local->mtx);
1136
1105 kfree(sdata->u.ap.next_beacon); 1137 kfree(sdata->u.ap.next_beacon);
1106 sdata->u.ap.next_beacon = NULL; 1138 sdata->u.ap.next_beacon = NULL;
1107 1139
@@ -3027,11 +3059,10 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
3027 int err, changed = 0; 3059 int err, changed = 0;
3028 3060
3029 sdata_assert_lock(sdata); 3061 sdata_assert_lock(sdata);
3062 lockdep_assert_held(&local->mtx);
3030 3063
3031 mutex_lock(&local->mtx);
3032 sdata->radar_required = sdata->csa_radar_required; 3064 sdata->radar_required = sdata->csa_radar_required;
3033 err = ieee80211_vif_change_channel(sdata, &changed); 3065 err = ieee80211_vif_change_channel(sdata, &changed);
3034 mutex_unlock(&local->mtx);
3035 if (WARN_ON(err < 0)) 3066 if (WARN_ON(err < 0))
3036 return; 3067 return;
3037 3068
@@ -3072,11 +3103,12 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
3072 3103
3073 ieee80211_bss_info_change_notify(sdata, changed); 3104 ieee80211_bss_info_change_notify(sdata, changed);
3074 3105
3075 ieee80211_wake_queues_by_reason(&sdata->local->hw, 3106 cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
3107
3108 if (!ieee80211_csa_needs_block_tx(local))
3109 ieee80211_wake_queues_by_reason(&local->hw,
3076 IEEE80211_MAX_QUEUE_MAP, 3110 IEEE80211_MAX_QUEUE_MAP,
3077 IEEE80211_QUEUE_STOP_REASON_CSA); 3111 IEEE80211_QUEUE_STOP_REASON_CSA);
3078
3079 cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
3080} 3112}
3081 3113
3082void ieee80211_csa_finalize_work(struct work_struct *work) 3114void ieee80211_csa_finalize_work(struct work_struct *work)
@@ -3084,8 +3116,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
3084 struct ieee80211_sub_if_data *sdata = 3116 struct ieee80211_sub_if_data *sdata =
3085 container_of(work, struct ieee80211_sub_if_data, 3117 container_of(work, struct ieee80211_sub_if_data,
3086 csa_finalize_work); 3118 csa_finalize_work);
3119 struct ieee80211_local *local = sdata->local;
3087 3120
3088 sdata_lock(sdata); 3121 sdata_lock(sdata);
3122 mutex_lock(&local->mtx);
3123
3089 /* AP might have been stopped while waiting for the lock. */ 3124 /* AP might have been stopped while waiting for the lock. */
3090 if (!sdata->vif.csa_active) 3125 if (!sdata->vif.csa_active)
3091 goto unlock; 3126 goto unlock;
@@ -3096,6 +3131,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
3096 ieee80211_csa_finalize(sdata); 3131 ieee80211_csa_finalize(sdata);
3097 3132
3098unlock: 3133unlock:
3134 mutex_unlock(&local->mtx);
3099 sdata_unlock(sdata); 3135 sdata_unlock(sdata);
3100} 3136}
3101 3137
@@ -3222,8 +3258,8 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
3222 return 0; 3258 return 0;
3223} 3259}
3224 3260
3225int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, 3261int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3226 struct cfg80211_csa_settings *params) 3262 struct cfg80211_csa_settings *params)
3227{ 3263{
3228 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 3264 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3229 struct ieee80211_local *local = sdata->local; 3265 struct ieee80211_local *local = sdata->local;
@@ -3232,6 +3268,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3232 int err, num_chanctx, changed = 0; 3268 int err, num_chanctx, changed = 0;
3233 3269
3234 sdata_assert_lock(sdata); 3270 sdata_assert_lock(sdata);
3271 lockdep_assert_held(&local->mtx);
3235 3272
3236 if (!list_empty(&local->roc_list) || local->scanning) 3273 if (!list_empty(&local->roc_list) || local->scanning)
3237 return -EBUSY; 3274 return -EBUSY;
@@ -3274,15 +3311,15 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3274 return err; 3311 return err;
3275 3312
3276 sdata->csa_radar_required = params->radar_required; 3313 sdata->csa_radar_required = params->radar_required;
3277
3278 if (params->block_tx)
3279 ieee80211_stop_queues_by_reason(&local->hw,
3280 IEEE80211_MAX_QUEUE_MAP,
3281 IEEE80211_QUEUE_STOP_REASON_CSA);
3282
3283 sdata->csa_chandef = params->chandef; 3314 sdata->csa_chandef = params->chandef;
3315 sdata->csa_block_tx = params->block_tx;
3284 sdata->vif.csa_active = true; 3316 sdata->vif.csa_active = true;
3285 3317
3318 if (sdata->csa_block_tx)
3319 ieee80211_stop_queues_by_reason(&local->hw,
3320 IEEE80211_MAX_QUEUE_MAP,
3321 IEEE80211_QUEUE_STOP_REASON_CSA);
3322
3286 if (changed) { 3323 if (changed) {
3287 ieee80211_bss_info_change_notify(sdata, changed); 3324 ieee80211_bss_info_change_notify(sdata, changed);
3288 drv_channel_switch_beacon(sdata, &params->chandef); 3325 drv_channel_switch_beacon(sdata, &params->chandef);
@@ -3294,6 +3331,20 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3294 return 0; 3331 return 0;
3295} 3332}
3296 3333
3334int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3335 struct cfg80211_csa_settings *params)
3336{
3337 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3338 struct ieee80211_local *local = sdata->local;
3339 int err;
3340
3341 mutex_lock(&local->mtx);
3342 err = __ieee80211_channel_switch(wiphy, dev, params);
3343 mutex_unlock(&local->mtx);
3344
3345 return err;
3346}
3347
3297static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, 3348static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3298 struct cfg80211_mgmt_tx_params *params, 3349 struct cfg80211_mgmt_tx_params *params,
3299 u64 *cookie) 3350 u64 *cookie)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f86d06aaf54b..f4ba0c4a4314 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -756,6 +756,7 @@ struct ieee80211_sub_if_data {
756 int csa_counter_offset_beacon; 756 int csa_counter_offset_beacon;
757 int csa_counter_offset_presp; 757 int csa_counter_offset_presp;
758 bool csa_radar_required; 758 bool csa_radar_required;
759 bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
759 struct cfg80211_chan_def csa_chandef; 760 struct cfg80211_chan_def csa_chandef;
760 761
761 struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ 762 struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
@@ -1472,6 +1473,7 @@ void ieee80211_sw_roc_work(struct work_struct *work);
1472void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); 1473void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
1473 1474
1474/* channel switch handling */ 1475/* channel switch handling */
1476bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local);
1475void ieee80211_csa_finalize_work(struct work_struct *work); 1477void ieee80211_csa_finalize_work(struct work_struct *work);
1476int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, 1478int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
1477 struct cfg80211_csa_settings *params); 1479 struct cfg80211_csa_settings *params);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 7fff3dcaac43..79fc98815da8 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -838,8 +838,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
838 838
839 cancel_work_sync(&sdata->recalc_smps); 839 cancel_work_sync(&sdata->recalc_smps);
840 sdata_lock(sdata); 840 sdata_lock(sdata);
841 mutex_lock(&local->mtx);
841 sdata->vif.csa_active = false; 842 sdata->vif.csa_active = false;
843 if (!ieee80211_csa_needs_block_tx(local))
844 ieee80211_wake_queues_by_reason(&local->hw,
845 IEEE80211_MAX_QUEUE_MAP,
846 IEEE80211_QUEUE_STOP_REASON_CSA);
847 mutex_unlock(&local->mtx);
842 sdata_unlock(sdata); 848 sdata_unlock(sdata);
849
843 cancel_work_sync(&sdata->csa_finalize_work); 850 cancel_work_sync(&sdata->csa_finalize_work);
844 851
845 cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); 852 cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
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);