aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-11-19 16:19:08 -0500
committerJohannes Berg <johannes.berg@intel.com>2012-11-20 04:33:05 -0500
commitfe5f255930af02ef3c3e0d00545b674e7e9d0cfb (patch)
treeaf684af4360e88d1f4630627b731dfaf671a3411 /net
parent49884568628db47a1f8c1f596c6ab3b8db81b73c (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/pm.c44
-rw-r--r--net/mac80211/util.c15
2 files changed, 56 insertions, 3 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 0f1c434638bc..79a48f37d409 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -33,6 +33,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
33 struct ieee80211_local *local = hw_to_local(hw); 33 struct ieee80211_local *local = hw_to_local(hw);
34 struct ieee80211_sub_if_data *sdata; 34 struct ieee80211_sub_if_data *sdata;
35 struct sta_info *sta; 35 struct sta_info *sta;
36 struct ieee80211_chanctx *ctx;
36 37
37 if (!local->open_count) 38 if (!local->open_count)
38 goto suspend; 39 goto suspend;
@@ -139,14 +140,51 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
139 rcu_access_pointer(sdata->u.ap.beacon)) 140 rcu_access_pointer(sdata->u.ap.beacon))
140 drv_stop_ap(local, sdata); 141 drv_stop_ap(local, sdata);
141 142
142 /* the interface is leaving the channel and is removed */ 143 if (local->use_chanctx) {
143 ieee80211_vif_release_channel(sdata); 144 struct ieee80211_chanctx_conf *conf;
145
146 mutex_lock(&local->chanctx_mtx);
147 conf = rcu_dereference_protected(
148 sdata->vif.chanctx_conf,
149 lockdep_is_held(&local->chanctx_mtx));
150 if (conf) {
151 ctx = container_of(conf,
152 struct ieee80211_chanctx,
153 conf);
154 drv_unassign_vif_chanctx(local, sdata, ctx);
155 }
156
157 mutex_unlock(&local->chanctx_mtx);
158 }
144 drv_remove_interface(local, sdata); 159 drv_remove_interface(local, sdata);
145 } 160 }
146 161
147 sdata = rtnl_dereference(local->monitor_sdata); 162 sdata = rtnl_dereference(local->monitor_sdata);
148 if (sdata) 163 if (sdata) {
164 if (local->use_chanctx) {
165 struct ieee80211_chanctx_conf *conf;
166
167 mutex_lock(&local->chanctx_mtx);
168 conf = rcu_dereference_protected(
169 sdata->vif.chanctx_conf,
170 lockdep_is_held(&local->chanctx_mtx));
171 if (conf) {
172 ctx = container_of(conf,
173 struct ieee80211_chanctx,
174 conf);
175 drv_unassign_vif_chanctx(local, sdata, ctx);
176 }
177
178 mutex_unlock(&local->chanctx_mtx);
179 }
180
149 drv_remove_interface(local, sdata); 181 drv_remove_interface(local, sdata);
182 }
183
184 mutex_lock(&local->chanctx_mtx);
185 list_for_each_entry(ctx, &local->chanctx_list, list)
186 drv_remove_chanctx(local, ctx);
187 mutex_unlock(&local->chanctx_mtx);
150 188
151 /* stop hardware - this must stop RX */ 189 /* stop hardware - this must stop RX */
152 if (local->open_count) 190 if (local->open_count)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7fb55bf6561e..2f08a7e09b7e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1441,6 +1441,21 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1441 mutex_unlock(&local->chanctx_mtx); 1441 mutex_unlock(&local->chanctx_mtx);
1442 } 1442 }
1443 1443
1444 sdata = rtnl_dereference(local->monitor_sdata);
1445 if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) {
1446 struct ieee80211_chanctx_conf *ctx_conf;
1447
1448 mutex_lock(&local->chanctx_mtx);
1449 ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
1450 lockdep_is_held(&local->chanctx_mtx));
1451 if (ctx_conf) {
1452 ctx = container_of(ctx_conf, struct ieee80211_chanctx,
1453 conf);
1454 drv_assign_vif_chanctx(local, sdata, ctx);
1455 }
1456 mutex_unlock(&local->chanctx_mtx);
1457 }
1458
1444 /* add STAs back */ 1459 /* add STAs back */
1445 mutex_lock(&local->sta_mtx); 1460 mutex_lock(&local->sta_mtx);
1446 list_for_each_entry(sta, &local->sta_list, list) { 1461 list_for_each_entry(sta, &local->sta_list, list) {