aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-12-18 03:43:33 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-12-19 07:33:33 -0500
commit34a3740d6b392896b71e36cd5cd68837a8f94a5c (patch)
tree128f9a3e35af1e7fc768b55fc7173cac9e1a3b08 /net/mac80211
parent6924d0138acdf5026ee4463134d98e139fe025a2 (diff)
mac80211: fix iflist_mtx/mtx locking in radar detection
The scan code creates an iflist_mtx -> mtx locking dependency, and a few other places, notably radar detection, were creating the opposite dependency, causing lockdep to complain. As scan and radar detection are mutually exclusive, the deadlock can't really happen in practice, but it's still bad form. A similar issue exists in the monitor mode code, but this is only used by channel-context drivers right now and those have to have hardware scan, so that also can't happen. Still, fix these issues by making some of the channel context code require the mtx to be held rather than acquiring it, thus allowing the monitor/radar callers to keep the iflist_mtx->mtx lock ordering. While at it, also fix access to the local->scanning variable in the radar code, and document that radar_detect_enabled is now properly protected by the mtx. All this would now introduce an ABBA deadlock between the DFS work cancelling and local->mtx, so change the locking there a bit to not need to use cancel_delayed_work_sync() but be able to just use cancel_delayed_work(). The work is also safely stopped/removed when the interface is stopped, so no extra changes are needed. Reported-by: Kalle Valo <kvalo@qca.qualcomm.com> Tested-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.c26
-rw-r--r--net/mac80211/chan.c21
-rw-r--r--net/mac80211/ibss.c7
-rw-r--r--net/mac80211/iface.c6
-rw-r--r--net/mac80211/mlme.c25
-rw-r--r--net/mac80211/util.c8
6 files changed, 73 insertions, 20 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index bfe54daab4b1..aab3c2f29de3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -828,6 +828,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
828 if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) 828 if (cfg80211_chandef_identical(&local->monitor_chandef, chandef))
829 return 0; 829 return 0;
830 830
831 mutex_lock(&local->mtx);
831 mutex_lock(&local->iflist_mtx); 832 mutex_lock(&local->iflist_mtx);
832 if (local->use_chanctx) { 833 if (local->use_chanctx) {
833 sdata = rcu_dereference_protected( 834 sdata = rcu_dereference_protected(
@@ -846,6 +847,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
846 if (ret == 0) 847 if (ret == 0)
847 local->monitor_chandef = *chandef; 848 local->monitor_chandef = *chandef;
848 mutex_unlock(&local->iflist_mtx); 849 mutex_unlock(&local->iflist_mtx);
850 mutex_unlock(&local->mtx);
849 851
850 return ret; 852 return ret;
851} 853}
@@ -951,6 +953,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
951 struct cfg80211_ap_settings *params) 953 struct cfg80211_ap_settings *params)
952{ 954{
953 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 955 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
956 struct ieee80211_local *local = sdata->local;
954 struct beacon_data *old; 957 struct beacon_data *old;
955 struct ieee80211_sub_if_data *vlan; 958 struct ieee80211_sub_if_data *vlan;
956 u32 changed = BSS_CHANGED_BEACON_INT | 959 u32 changed = BSS_CHANGED_BEACON_INT |
@@ -969,8 +972,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
969 sdata->needed_rx_chains = sdata->local->rx_chains; 972 sdata->needed_rx_chains = sdata->local->rx_chains;
970 sdata->radar_required = params->radar_required; 973 sdata->radar_required = params->radar_required;
971 974
975 mutex_lock(&local->mtx);
972 err = ieee80211_vif_use_channel(sdata, &params->chandef, 976 err = ieee80211_vif_use_channel(sdata, &params->chandef,
973 IEEE80211_CHANCTX_SHARED); 977 IEEE80211_CHANCTX_SHARED);
978 mutex_unlock(&local->mtx);
974 if (err) 979 if (err)
975 return err; 980 return err;
976 ieee80211_vif_copy_chanctx_to_vlans(sdata, false); 981 ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
@@ -1121,7 +1126,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
1121 skb_queue_purge(&sdata->u.ap.ps.bc_buf); 1126 skb_queue_purge(&sdata->u.ap.ps.bc_buf);
1122 1127
1123 ieee80211_vif_copy_chanctx_to_vlans(sdata, true); 1128 ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
1129 mutex_lock(&local->mtx);
1124 ieee80211_vif_release_channel(sdata); 1130 ieee80211_vif_release_channel(sdata);
1131 mutex_unlock(&local->mtx);
1125 1132
1126 return 0; 1133 return 0;
1127} 1134}
@@ -1944,8 +1951,10 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
1944 sdata->smps_mode = IEEE80211_SMPS_OFF; 1951 sdata->smps_mode = IEEE80211_SMPS_OFF;
1945 sdata->needed_rx_chains = sdata->local->rx_chains; 1952 sdata->needed_rx_chains = sdata->local->rx_chains;
1946 1953
1954 mutex_lock(&sdata->local->mtx);
1947 err = ieee80211_vif_use_channel(sdata, &setup->chandef, 1955 err = ieee80211_vif_use_channel(sdata, &setup->chandef,
1948 IEEE80211_CHANCTX_SHARED); 1956 IEEE80211_CHANCTX_SHARED);
1957 mutex_unlock(&sdata->local->mtx);
1949 if (err) 1958 if (err)
1950 return err; 1959 return err;
1951 1960
@@ -1957,7 +1966,9 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
1957 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1966 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1958 1967
1959 ieee80211_stop_mesh(sdata); 1968 ieee80211_stop_mesh(sdata);
1969 mutex_lock(&sdata->local->mtx);
1960 ieee80211_vif_release_channel(sdata); 1970 ieee80211_vif_release_channel(sdata);
1971 mutex_unlock(&sdata->local->mtx);
1961 1972
1962 return 0; 1973 return 0;
1963} 1974}
@@ -2895,8 +2906,11 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
2895 unsigned long timeout; 2906 unsigned long timeout;
2896 int err; 2907 int err;
2897 2908
2898 if (!list_empty(&local->roc_list) || local->scanning) 2909 mutex_lock(&local->mtx);
2899 return -EBUSY; 2910 if (!list_empty(&local->roc_list) || local->scanning) {
2911 err = -EBUSY;
2912 goto out_unlock;
2913 }
2900 2914
2901 /* whatever, but channel contexts should not complain about that one */ 2915 /* whatever, but channel contexts should not complain about that one */
2902 sdata->smps_mode = IEEE80211_SMPS_OFF; 2916 sdata->smps_mode = IEEE80211_SMPS_OFF;
@@ -2906,13 +2920,15 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
2906 err = ieee80211_vif_use_channel(sdata, chandef, 2920 err = ieee80211_vif_use_channel(sdata, chandef,
2907 IEEE80211_CHANCTX_SHARED); 2921 IEEE80211_CHANCTX_SHARED);
2908 if (err) 2922 if (err)
2909 return err; 2923 goto out_unlock;
2910 2924
2911 timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); 2925 timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
2912 ieee80211_queue_delayed_work(&sdata->local->hw, 2926 ieee80211_queue_delayed_work(&sdata->local->hw,
2913 &sdata->dfs_cac_timer_work, timeout); 2927 &sdata->dfs_cac_timer_work, timeout);
2914 2928
2915 return 0; 2929 out_unlock:
2930 mutex_unlock(&local->mtx);
2931 return err;
2916} 2932}
2917 2933
2918static struct cfg80211_beacon_data * 2934static struct cfg80211_beacon_data *
@@ -2988,7 +3004,9 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
2988 goto unlock; 3004 goto unlock;
2989 3005
2990 sdata->radar_required = sdata->csa_radar_required; 3006 sdata->radar_required = sdata->csa_radar_required;
3007 mutex_lock(&local->mtx);
2991 err = ieee80211_vif_change_channel(sdata, &changed); 3008 err = ieee80211_vif_change_channel(sdata, &changed);
3009 mutex_unlock(&local->mtx);
2992 if (WARN_ON(err < 0)) 3010 if (WARN_ON(err < 0))
2993 goto unlock; 3011 goto unlock;
2994 3012
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index f20a98a70cc0..f43613a97dd6 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -232,8 +232,8 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
232 if (!local->use_chanctx) 232 if (!local->use_chanctx)
233 local->hw.conf.radar_enabled = ctx->conf.radar_enabled; 233 local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
234 234
235 /* acquire mutex to prevent idle from changing */ 235 /* we hold the mutex to prevent idle from changing */
236 mutex_lock(&local->mtx); 236 lockdep_assert_held(&local->mtx);
237 /* turn idle off *before* setting channel -- some drivers need that */ 237 /* turn idle off *before* setting channel -- some drivers need that */
238 changed = ieee80211_idle_off(local); 238 changed = ieee80211_idle_off(local);
239 if (changed) 239 if (changed)
@@ -246,19 +246,14 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
246 err = drv_add_chanctx(local, ctx); 246 err = drv_add_chanctx(local, ctx);
247 if (err) { 247 if (err) {
248 kfree(ctx); 248 kfree(ctx);
249 ctx = ERR_PTR(err);
250
251 ieee80211_recalc_idle(local); 249 ieee80211_recalc_idle(local);
252 goto out; 250 return ERR_PTR(err);
253 } 251 }
254 } 252 }
255 253
256 /* and keep the mutex held until the new chanctx is on the list */ 254 /* and keep the mutex held until the new chanctx is on the list */
257 list_add_rcu(&ctx->list, &local->chanctx_list); 255 list_add_rcu(&ctx->list, &local->chanctx_list);
258 256
259 out:
260 mutex_unlock(&local->mtx);
261
262 return ctx; 257 return ctx;
263} 258}
264 259
@@ -294,9 +289,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
294 /* throw a warning if this wasn't the only channel context. */ 289 /* throw a warning if this wasn't the only channel context. */
295 WARN_ON(check_single_channel && !list_empty(&local->chanctx_list)); 290 WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
296 291
297 mutex_lock(&local->mtx);
298 ieee80211_recalc_idle(local); 292 ieee80211_recalc_idle(local);
299 mutex_unlock(&local->mtx);
300} 293}
301 294
302static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 295static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
@@ -364,6 +357,8 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
364 bool radar_enabled; 357 bool radar_enabled;
365 358
366 lockdep_assert_held(&local->chanctx_mtx); 359 lockdep_assert_held(&local->chanctx_mtx);
360 /* for setting local->radar_detect_enabled */
361 lockdep_assert_held(&local->mtx);
367 362
368 radar_enabled = ieee80211_is_radar_required(local); 363 radar_enabled = ieee80211_is_radar_required(local);
369 364
@@ -518,6 +513,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
518 struct ieee80211_chanctx *ctx; 513 struct ieee80211_chanctx *ctx;
519 int ret; 514 int ret;
520 515
516 lockdep_assert_held(&local->mtx);
517
521 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 518 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
522 519
523 mutex_lock(&local->chanctx_mtx); 520 mutex_lock(&local->chanctx_mtx);
@@ -558,6 +555,8 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
558 int ret; 555 int ret;
559 u32 chanctx_changed = 0; 556 u32 chanctx_changed = 0;
560 557
558 lockdep_assert_held(&local->mtx);
559
561 /* should never be called if not performing a channel switch. */ 560 /* should never be called if not performing a channel switch. */
562 if (WARN_ON(!sdata->vif.csa_active)) 561 if (WARN_ON(!sdata->vif.csa_active))
563 return -EINVAL; 562 return -EINVAL;
@@ -655,6 +654,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
655{ 654{
656 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 655 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
657 656
657 lockdep_assert_held(&sdata->local->mtx);
658
658 mutex_lock(&sdata->local->chanctx_mtx); 659 mutex_lock(&sdata->local->chanctx_mtx);
659 __ieee80211_vif_release_channel(sdata); 660 __ieee80211_vif_release_channel(sdata);
660 mutex_unlock(&sdata->local->chanctx_mtx); 661 mutex_unlock(&sdata->local->chanctx_mtx);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d6ba841437b6..771080ec7212 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -293,14 +293,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
293 radar_required = true; 293 radar_required = true;
294 } 294 }
295 295
296 mutex_lock(&local->mtx);
296 ieee80211_vif_release_channel(sdata); 297 ieee80211_vif_release_channel(sdata);
297 if (ieee80211_vif_use_channel(sdata, &chandef, 298 if (ieee80211_vif_use_channel(sdata, &chandef,
298 ifibss->fixed_channel ? 299 ifibss->fixed_channel ?
299 IEEE80211_CHANCTX_SHARED : 300 IEEE80211_CHANCTX_SHARED :
300 IEEE80211_CHANCTX_EXCLUSIVE)) { 301 IEEE80211_CHANCTX_EXCLUSIVE)) {
301 sdata_info(sdata, "Failed to join IBSS, no channel context\n"); 302 sdata_info(sdata, "Failed to join IBSS, no channel context\n");
303 mutex_unlock(&local->mtx);
302 return; 304 return;
303 } 305 }
306 mutex_unlock(&local->mtx);
304 307
305 memcpy(ifibss->bssid, bssid, ETH_ALEN); 308 memcpy(ifibss->bssid, bssid, ETH_ALEN);
306 309
@@ -363,7 +366,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
363 sdata->vif.bss_conf.ssid_len = 0; 366 sdata->vif.bss_conf.ssid_len = 0;
364 RCU_INIT_POINTER(ifibss->presp, NULL); 367 RCU_INIT_POINTER(ifibss->presp, NULL);
365 kfree_rcu(presp, rcu_head); 368 kfree_rcu(presp, rcu_head);
369 mutex_lock(&local->mtx);
366 ieee80211_vif_release_channel(sdata); 370 ieee80211_vif_release_channel(sdata);
371 mutex_unlock(&local->mtx);
367 sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", 372 sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
368 err); 373 err);
369 return; 374 return;
@@ -747,7 +752,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
747 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | 752 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
748 BSS_CHANGED_IBSS); 753 BSS_CHANGED_IBSS);
749 drv_leave_ibss(local, sdata); 754 drv_leave_ibss(local, sdata);
755 mutex_lock(&local->mtx);
750 ieee80211_vif_release_channel(sdata); 756 ieee80211_vif_release_channel(sdata);
757 mutex_unlock(&local->mtx);
751} 758}
752 759
753static void ieee80211_csa_connection_drop_work(struct work_struct *work) 760static void ieee80211_csa_connection_drop_work(struct work_struct *work)
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 0c0be9097664..0aa9675319ef 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -418,8 +418,10 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
418 return ret; 418 return ret;
419 } 419 }
420 420
421 mutex_lock(&local->mtx);
421 ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, 422 ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
422 IEEE80211_CHANCTX_EXCLUSIVE); 423 IEEE80211_CHANCTX_EXCLUSIVE);
424 mutex_unlock(&local->mtx);
423 if (ret) { 425 if (ret) {
424 drv_remove_interface(local, sdata); 426 drv_remove_interface(local, sdata);
425 kfree(sdata); 427 kfree(sdata);
@@ -456,7 +458,9 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
456 458
457 synchronize_net(); 459 synchronize_net();
458 460
461 mutex_lock(&local->mtx);
459 ieee80211_vif_release_channel(sdata); 462 ieee80211_vif_release_channel(sdata);
463 mutex_unlock(&local->mtx);
460 464
461 drv_remove_interface(local, sdata); 465 drv_remove_interface(local, sdata);
462 466
@@ -826,7 +830,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
826 if (sdata->wdev.cac_started) { 830 if (sdata->wdev.cac_started) {
827 chandef = sdata->vif.bss_conf.chandef; 831 chandef = sdata->vif.bss_conf.chandef;
828 WARN_ON(local->suspended); 832 WARN_ON(local->suspended);
833 mutex_lock(&local->mtx);
829 ieee80211_vif_release_channel(sdata); 834 ieee80211_vif_release_channel(sdata);
835 mutex_unlock(&local->mtx);
830 cfg80211_cac_event(sdata->dev, &chandef, 836 cfg80211_cac_event(sdata->dev, &chandef,
831 NL80211_RADAR_CAC_ABORTED, 837 NL80211_RADAR_CAC_ABORTED,
832 GFP_KERNEL); 838 GFP_KERNEL);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9c2c7ee2cc30..fc1d82465b3c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -888,7 +888,9 @@ static void ieee80211_chswitch_work(struct work_struct *work)
888 if (!ifmgd->associated) 888 if (!ifmgd->associated)
889 goto out; 889 goto out;
890 890
891 mutex_lock(&local->mtx);
891 ret = ieee80211_vif_change_channel(sdata, &changed); 892 ret = ieee80211_vif_change_channel(sdata, &changed);
893 mutex_unlock(&local->mtx);
892 if (ret) { 894 if (ret) {
893 sdata_info(sdata, 895 sdata_info(sdata,
894 "vif channel switch failed, disconnecting\n"); 896 "vif channel switch failed, disconnecting\n");
@@ -1401,10 +1403,14 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
1401 dfs_cac_timer_work); 1403 dfs_cac_timer_work);
1402 struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef; 1404 struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
1403 1405
1404 ieee80211_vif_release_channel(sdata); 1406 mutex_lock(&sdata->local->mtx);
1405 cfg80211_cac_event(sdata->dev, &chandef, 1407 if (sdata->wdev.cac_started) {
1406 NL80211_RADAR_CAC_FINISHED, 1408 ieee80211_vif_release_channel(sdata);
1407 GFP_KERNEL); 1409 cfg80211_cac_event(sdata->dev, &chandef,
1410 NL80211_RADAR_CAC_FINISHED,
1411 GFP_KERNEL);
1412 }
1413 mutex_unlock(&sdata->local->mtx);
1408} 1414}
1409 1415
1410/* MLME */ 1416/* MLME */
@@ -1747,7 +1753,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1747 ifmgd->have_beacon = false; 1753 ifmgd->have_beacon = false;
1748 1754
1749 ifmgd->flags = 0; 1755 ifmgd->flags = 0;
1756 mutex_lock(&local->mtx);
1750 ieee80211_vif_release_channel(sdata); 1757 ieee80211_vif_release_channel(sdata);
1758 mutex_unlock(&local->mtx);
1751 1759
1752 sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; 1760 sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
1753} 1761}
@@ -2070,7 +2078,9 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
2070 memset(sdata->u.mgd.bssid, 0, ETH_ALEN); 2078 memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
2071 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); 2079 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
2072 sdata->u.mgd.flags = 0; 2080 sdata->u.mgd.flags = 0;
2081 mutex_lock(&sdata->local->mtx);
2073 ieee80211_vif_release_channel(sdata); 2082 ieee80211_vif_release_channel(sdata);
2083 mutex_unlock(&sdata->local->mtx);
2074 } 2084 }
2075 2085
2076 cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss); 2086 cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss);
@@ -2319,7 +2329,9 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
2319 memset(sdata->u.mgd.bssid, 0, ETH_ALEN); 2329 memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
2320 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); 2330 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
2321 sdata->u.mgd.flags = 0; 2331 sdata->u.mgd.flags = 0;
2332 mutex_lock(&sdata->local->mtx);
2322 ieee80211_vif_release_channel(sdata); 2333 ieee80211_vif_release_channel(sdata);
2334 mutex_unlock(&sdata->local->mtx);
2323 } 2335 }
2324 2336
2325 kfree(assoc_data); 2337 kfree(assoc_data);
@@ -3670,6 +3682,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3670 /* will change later if needed */ 3682 /* will change later if needed */
3671 sdata->smps_mode = IEEE80211_SMPS_OFF; 3683 sdata->smps_mode = IEEE80211_SMPS_OFF;
3672 3684
3685 mutex_lock(&local->mtx);
3673 /* 3686 /*
3674 * If this fails (possibly due to channel context sharing 3687 * If this fails (possibly due to channel context sharing
3675 * on incompatible channels, e.g. 80+80 and 160 sharing the 3688 * on incompatible channels, e.g. 80+80 and 160 sharing the
@@ -3681,13 +3694,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3681 /* don't downgrade for 5 and 10 MHz channels, though. */ 3694 /* don't downgrade for 5 and 10 MHz channels, though. */
3682 if (chandef.width == NL80211_CHAN_WIDTH_5 || 3695 if (chandef.width == NL80211_CHAN_WIDTH_5 ||
3683 chandef.width == NL80211_CHAN_WIDTH_10) 3696 chandef.width == NL80211_CHAN_WIDTH_10)
3684 return ret; 3697 goto out;
3685 3698
3686 while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { 3699 while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
3687 ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); 3700 ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);
3688 ret = ieee80211_vif_use_channel(sdata, &chandef, 3701 ret = ieee80211_vif_use_channel(sdata, &chandef,
3689 IEEE80211_CHANCTX_SHARED); 3702 IEEE80211_CHANCTX_SHARED);
3690 } 3703 }
3704 out:
3705 mutex_unlock(&local->mtx);
3691 return ret; 3706 return ret;
3692} 3707}
3693 3708
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 656648b9b9d3..ed93504d24b8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2315,9 +2315,14 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
2315 struct ieee80211_sub_if_data *sdata; 2315 struct ieee80211_sub_if_data *sdata;
2316 struct cfg80211_chan_def chandef; 2316 struct cfg80211_chan_def chandef;
2317 2317
2318 mutex_lock(&local->mtx);
2318 mutex_lock(&local->iflist_mtx); 2319 mutex_lock(&local->iflist_mtx);
2319 list_for_each_entry(sdata, &local->interfaces, list) { 2320 list_for_each_entry(sdata, &local->interfaces, list) {
2320 cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); 2321 /* it might be waiting for the local->mtx, but then
2322 * by the time it gets it, sdata->wdev.cac_started
2323 * will no longer be true
2324 */
2325 cancel_delayed_work(&sdata->dfs_cac_timer_work);
2321 2326
2322 if (sdata->wdev.cac_started) { 2327 if (sdata->wdev.cac_started) {
2323 chandef = sdata->vif.bss_conf.chandef; 2328 chandef = sdata->vif.bss_conf.chandef;
@@ -2329,6 +2334,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
2329 } 2334 }
2330 } 2335 }
2331 mutex_unlock(&local->iflist_mtx); 2336 mutex_unlock(&local->iflist_mtx);
2337 mutex_unlock(&local->mtx);
2332} 2338}
2333 2339
2334void ieee80211_dfs_radar_detected_work(struct work_struct *work) 2340void ieee80211_dfs_radar_detected_work(struct work_struct *work)