aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorSimon Wunderlich <sw@simonwunderlich.de>2013-11-21 12:19:51 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-12-02 05:51:54 -0500
commite487eaeb076a44c69dc61348cbc903151bb8fcbd (patch)
tree715d57f18ec0f3e3565a711f43248a3b8c8a42eb /net/mac80211
parent7ca133bc7f9dd5cee2b469eb917bd352be80a690 (diff)
cfg80211/mac80211/ath6kl: acquire wdev lock outside ch_switch_notify
The channel switch notification should be sent under the wdev/sdata-lock, preferably in the same moment as the channel change happens, to avoid races by other callers (e.g. start/stop_ap). This also adds the previously missing sdata_lock protection in csa_finalize_work. Reported-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4a5c21ed64d1..1d446ac97ab5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2988,13 +2988,18 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
2988 struct ieee80211_local *local = sdata->local; 2988 struct ieee80211_local *local = sdata->local;
2989 int err, changed = 0; 2989 int err, changed = 0;
2990 2990
2991 sdata_lock(sdata);
2992 /* AP might have been stopped while waiting for the lock. */
2993 if (!sdata->vif.csa_active)
2994 goto unlock;
2995
2991 if (!ieee80211_sdata_running(sdata)) 2996 if (!ieee80211_sdata_running(sdata))
2992 return; 2997 goto unlock;
2993 2998
2994 sdata->radar_required = sdata->csa_radar_required; 2999 sdata->radar_required = sdata->csa_radar_required;
2995 err = ieee80211_vif_change_channel(sdata, &changed); 3000 err = ieee80211_vif_change_channel(sdata, &changed);
2996 if (WARN_ON(err < 0)) 3001 if (WARN_ON(err < 0))
2997 return; 3002 goto unlock;
2998 3003
2999 if (!local->use_chanctx) { 3004 if (!local->use_chanctx) {
3000 local->_oper_chandef = sdata->csa_chandef; 3005 local->_oper_chandef = sdata->csa_chandef;
@@ -3003,11 +3008,13 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
3003 3008
3004 ieee80211_bss_info_change_notify(sdata, changed); 3009 ieee80211_bss_info_change_notify(sdata, changed);
3005 3010
3011 sdata->vif.csa_active = false;
3006 switch (sdata->vif.type) { 3012 switch (sdata->vif.type) {
3007 case NL80211_IFTYPE_AP: 3013 case NL80211_IFTYPE_AP:
3008 err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); 3014 err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
3009 if (err < 0) 3015 if (err < 0)
3010 return; 3016 goto unlock;
3017
3011 changed |= err; 3018 changed |= err;
3012 kfree(sdata->u.ap.next_beacon); 3019 kfree(sdata->u.ap.next_beacon);
3013 sdata->u.ap.next_beacon = NULL; 3020 sdata->u.ap.next_beacon = NULL;
@@ -3021,20 +3028,22 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
3021 case NL80211_IFTYPE_MESH_POINT: 3028 case NL80211_IFTYPE_MESH_POINT:
3022 err = ieee80211_mesh_finish_csa(sdata); 3029 err = ieee80211_mesh_finish_csa(sdata);
3023 if (err < 0) 3030 if (err < 0)
3024 return; 3031 goto unlock;
3025 break; 3032 break;
3026#endif 3033#endif
3027 default: 3034 default:
3028 WARN_ON(1); 3035 WARN_ON(1);
3029 return; 3036 goto unlock;
3030 } 3037 }
3031 sdata->vif.csa_active = false;
3032 3038
3033 ieee80211_wake_queues_by_reason(&sdata->local->hw, 3039 ieee80211_wake_queues_by_reason(&sdata->local->hw,
3034 IEEE80211_MAX_QUEUE_MAP, 3040 IEEE80211_MAX_QUEUE_MAP,
3035 IEEE80211_QUEUE_STOP_REASON_CSA); 3041 IEEE80211_QUEUE_STOP_REASON_CSA);
3036 3042
3037 cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); 3043 cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
3044
3045unlock:
3046 sdata_unlock(sdata);
3038} 3047}
3039 3048
3040static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, 3049static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,