mac80211: fix channel context suspend/reconfig handling
Sujith reported warnings with suspend/resume due to channel contexts. When I looked into it, I realised that the code was completely broken as it unassigned the channel contexts when suspending, which actually means they are destroyed. Eliad Peller then pointed out that we also need to remove the channel contexts from the driver. When I looked into this, I also noticed that the code isn't handling the virtual monitor interface correctly (if it exists.) Fix this by calling just the driver methods (if they are implemented) instead of using the channel context management code. Also add reconfiguration for the virtual monitor interface. Reported-by: Sujith Manoharan <sujith@msujith.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
4988456862
commit
fe5f255930
|
@ -33,6 +33,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||||
struct ieee80211_local *local = hw_to_local(hw);
|
struct ieee80211_local *local = hw_to_local(hw);
|
||||||
struct ieee80211_sub_if_data *sdata;
|
struct ieee80211_sub_if_data *sdata;
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
|
struct ieee80211_chanctx *ctx;
|
||||||
|
|
||||||
if (!local->open_count)
|
if (!local->open_count)
|
||||||
goto suspend;
|
goto suspend;
|
||||||
|
@ -139,14 +140,51 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||||
rcu_access_pointer(sdata->u.ap.beacon))
|
rcu_access_pointer(sdata->u.ap.beacon))
|
||||||
drv_stop_ap(local, sdata);
|
drv_stop_ap(local, sdata);
|
||||||
|
|
||||||
/* the interface is leaving the channel and is removed */
|
if (local->use_chanctx) {
|
||||||
ieee80211_vif_release_channel(sdata);
|
struct ieee80211_chanctx_conf *conf;
|
||||||
|
|
||||||
|
mutex_lock(&local->chanctx_mtx);
|
||||||
|
conf = rcu_dereference_protected(
|
||||||
|
sdata->vif.chanctx_conf,
|
||||||
|
lockdep_is_held(&local->chanctx_mtx));
|
||||||
|
if (conf) {
|
||||||
|
ctx = container_of(conf,
|
||||||
|
struct ieee80211_chanctx,
|
||||||
|
conf);
|
||||||
|
drv_unassign_vif_chanctx(local, sdata, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&local->chanctx_mtx);
|
||||||
|
}
|
||||||
drv_remove_interface(local, sdata);
|
drv_remove_interface(local, sdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
sdata = rtnl_dereference(local->monitor_sdata);
|
sdata = rtnl_dereference(local->monitor_sdata);
|
||||||
if (sdata)
|
if (sdata) {
|
||||||
|
if (local->use_chanctx) {
|
||||||
|
struct ieee80211_chanctx_conf *conf;
|
||||||
|
|
||||||
|
mutex_lock(&local->chanctx_mtx);
|
||||||
|
conf = rcu_dereference_protected(
|
||||||
|
sdata->vif.chanctx_conf,
|
||||||
|
lockdep_is_held(&local->chanctx_mtx));
|
||||||
|
if (conf) {
|
||||||
|
ctx = container_of(conf,
|
||||||
|
struct ieee80211_chanctx,
|
||||||
|
conf);
|
||||||
|
drv_unassign_vif_chanctx(local, sdata, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&local->chanctx_mtx);
|
||||||
|
}
|
||||||
|
|
||||||
drv_remove_interface(local, sdata);
|
drv_remove_interface(local, sdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&local->chanctx_mtx);
|
||||||
|
list_for_each_entry(ctx, &local->chanctx_list, list)
|
||||||
|
drv_remove_chanctx(local, ctx);
|
||||||
|
mutex_unlock(&local->chanctx_mtx);
|
||||||
|
|
||||||
/* stop hardware - this must stop RX */
|
/* stop hardware - this must stop RX */
|
||||||
if (local->open_count)
|
if (local->open_count)
|
||||||
|
|
|
@ -1441,6 +1441,21 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||||
mutex_unlock(&local->chanctx_mtx);
|
mutex_unlock(&local->chanctx_mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdata = rtnl_dereference(local->monitor_sdata);
|
||||||
|
if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) {
|
||||||
|
struct ieee80211_chanctx_conf *ctx_conf;
|
||||||
|
|
||||||
|
mutex_lock(&local->chanctx_mtx);
|
||||||
|
ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||||
|
lockdep_is_held(&local->chanctx_mtx));
|
||||||
|
if (ctx_conf) {
|
||||||
|
ctx = container_of(ctx_conf, struct ieee80211_chanctx,
|
||||||
|
conf);
|
||||||
|
drv_assign_vif_chanctx(local, sdata, ctx);
|
||||||
|
}
|
||||||
|
mutex_unlock(&local->chanctx_mtx);
|
||||||
|
}
|
||||||
|
|
||||||
/* add STAs back */
|
/* add STAs back */
|
||||||
mutex_lock(&local->sta_mtx);
|
mutex_lock(&local->sta_mtx);
|
||||||
list_for_each_entry(sta, &local->sta_list, list) {
|
list_for_each_entry(sta, &local->sta_list, list) {
|
||||||
|
|
Loading…
Reference in New Issue