diff options
author | Simon Wunderlich <sw@simonwunderlich.de> | 2013-11-21 12:19:51 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-12-02 05:51:54 -0500 |
commit | e487eaeb076a44c69dc61348cbc903151bb8fcbd (patch) | |
tree | 715d57f18ec0f3e3565a711f43248a3b8c8a42eb /net/mac80211 | |
parent | 7ca133bc7f9dd5cee2b469eb917bd352be80a690 (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.c | 21 |
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 | |||
3045 | unlock: | ||
3046 | sdata_unlock(sdata); | ||
3038 | } | 3047 | } |
3039 | 3048 | ||
3040 | static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 3049 | static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |