diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index eea7028a46a7..e7ac24603892 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -913,24 +913,30 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) return 0; - mutex_lock(&local->mtx); if (local->use_chanctx) { sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata) { + sdata_lock(sdata); + mutex_lock(&local->mtx); ieee80211_link_release_channel(&sdata->deflink); ret = ieee80211_link_use_channel(&sdata->deflink, chandef, IEEE80211_CHANCTX_EXCLUSIVE); + mutex_unlock(&local->mtx); + sdata_unlock(sdata); } - } else if (local->open_count == local->monitors) { - local->_oper_chandef = *chandef; - ieee80211_hw_config(local, 0); + } else { + mutex_lock(&local->mtx); + if (local->open_count == local->monitors) { + local->_oper_chandef = *chandef; + ieee80211_hw_config(local, 0); + } + mutex_unlock(&local->mtx); } if (ret == 0) local->monitor_chandef = *chandef; - mutex_unlock(&local->mtx); return ret; } diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 9518acf9643b..be586bc0b5b7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1133,6 +1133,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) snprintf(sdata->name, IFNAMSIZ, "%s-monitor", wiphy_name(local->hw.wiphy)); sdata->wdev.iftype = NL80211_IFTYPE_MONITOR; + mutex_init(&sdata->wdev.mtx); ieee80211_sdata_init(local, sdata); @@ -1157,16 +1158,19 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) rcu_assign_pointer(local->monitor_sdata, sdata); mutex_unlock(&local->iflist_mtx); + sdata_lock(sdata); mutex_lock(&local->mtx); ret = ieee80211_link_use_channel(&sdata->deflink, &local->monitor_chandef, IEEE80211_CHANCTX_EXCLUSIVE); mutex_unlock(&local->mtx); + sdata_unlock(sdata); if (ret) { mutex_lock(&local->iflist_mtx); RCU_INIT_POINTER(local->monitor_sdata, NULL); mutex_unlock(&local->iflist_mtx); synchronize_net(); drv_remove_interface(local, sdata); + mutex_destroy(&sdata->wdev.mtx); kfree(sdata); return ret; } @@ -1202,12 +1206,15 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) synchronize_net(); + sdata_lock(sdata); mutex_lock(&local->mtx); ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&local->mtx); + sdata_unlock(sdata); drv_remove_interface(local, sdata); + mutex_destroy(&sdata->wdev.mtx); kfree(sdata); }