diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-02-08 06:07:44 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-11 12:44:57 -0500 |
commit | 1f4ac5a63f897a480fffd0d5c843b03f02c384a5 (patch) | |
tree | d7ae579e6dff49cfc5c8eca2812fa04faa7246fc /net | |
parent | 757af6fefd53628bcfe75f7fbd302c5d4c02eba5 (diff) |
mac80211: explicitly copy channels to VLANs where needed
Currently the code assigns channel contexts to VLANs
(for use by the TX/RX code) when the AP master gets
its channel context assigned. This works fine, but
in the upcoming radar detection work the VLANs don't
require a channel context (during radar detection)
and assigning one to them anyway causes issues with
locking and also inconsistencies -- a VLAN interface
that is added before radar detection would get the
channel context, while one added during it wouldn't.
Fix these issues moving the channel context copying
to a new explicit operation that will not be used
in the radar detection code.
Acked-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/chan.c | 52 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 |
3 files changed, 38 insertions, 18 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f4f7e7691077..8f6b593a921f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -933,6 +933,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
933 | IEEE80211_CHANCTX_SHARED); | 933 | IEEE80211_CHANCTX_SHARED); |
934 | if (err) | 934 | if (err) |
935 | return err; | 935 | return err; |
936 | ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | ||
936 | 937 | ||
937 | /* | 938 | /* |
938 | * Apply control port protocol, this allows us to | 939 | * Apply control port protocol, this allows us to |
@@ -1047,6 +1048,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1047 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); | 1048 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); |
1048 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | 1049 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); |
1049 | 1050 | ||
1051 | ieee80211_vif_copy_chanctx_to_vlans(sdata, true); | ||
1050 | ieee80211_vif_release_channel(sdata); | 1052 | ieee80211_vif_release_channel(sdata); |
1051 | 1053 | ||
1052 | return 0; | 1054 | return 0; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 1bfe0a8b19d2..b5b50762f03e 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -198,15 +198,6 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
198 | 198 | ||
199 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 199 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
200 | 200 | ||
201 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
202 | struct ieee80211_sub_if_data *vlan; | ||
203 | |||
204 | /* for the VLAN list */ | ||
205 | ASSERT_RTNL(); | ||
206 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
207 | rcu_assign_pointer(vlan->vif.chanctx_conf, NULL); | ||
208 | } | ||
209 | |||
210 | ieee80211_unassign_vif_chanctx(sdata, ctx); | 201 | ieee80211_unassign_vif_chanctx(sdata, ctx); |
211 | if (ctx->refcount == 0) | 202 | if (ctx->refcount == 0) |
212 | ieee80211_free_chanctx(local, ctx); | 203 | ieee80211_free_chanctx(local, ctx); |
@@ -326,15 +317,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
326 | goto out; | 317 | goto out; |
327 | } | 318 | } |
328 | 319 | ||
329 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
330 | struct ieee80211_sub_if_data *vlan; | ||
331 | |||
332 | /* for the VLAN list */ | ||
333 | ASSERT_RTNL(); | ||
334 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
335 | rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf); | ||
336 | } | ||
337 | |||
338 | ieee80211_recalc_smps_chanctx(local, ctx); | 320 | ieee80211_recalc_smps_chanctx(local, ctx); |
339 | out: | 321 | out: |
340 | mutex_unlock(&local->chanctx_mtx); | 322 | mutex_unlock(&local->chanctx_mtx); |
@@ -369,6 +351,40 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) | |||
369 | mutex_unlock(&local->chanctx_mtx); | 351 | mutex_unlock(&local->chanctx_mtx); |
370 | } | 352 | } |
371 | 353 | ||
354 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | ||
355 | bool clear) | ||
356 | { | ||
357 | struct ieee80211_local *local = sdata->local; | ||
358 | struct ieee80211_sub_if_data *vlan; | ||
359 | struct ieee80211_chanctx_conf *conf; | ||
360 | |||
361 | ASSERT_RTNL(); | ||
362 | |||
363 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) | ||
364 | return; | ||
365 | |||
366 | mutex_lock(&local->chanctx_mtx); | ||
367 | |||
368 | /* | ||
369 | * Check that conf exists, even when clearing this function | ||
370 | * must be called with the AP's channel context still there | ||
371 | * as it would otherwise cause VLANs to have an invalid | ||
372 | * channel context pointer for a while, possibly pointing | ||
373 | * to a channel context that has already been freed. | ||
374 | */ | ||
375 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
376 | lockdep_is_held(&local->chanctx_mtx)); | ||
377 | WARN_ON(!conf); | ||
378 | |||
379 | if (clear) | ||
380 | conf = NULL; | ||
381 | |||
382 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
383 | rcu_assign_pointer(vlan->vif.chanctx_conf, conf); | ||
384 | |||
385 | mutex_unlock(&local->chanctx_mtx); | ||
386 | } | ||
387 | |||
372 | void ieee80211_iter_chan_contexts_atomic( | 388 | void ieee80211_iter_chan_contexts_atomic( |
373 | struct ieee80211_hw *hw, | 389 | struct ieee80211_hw *hw, |
374 | void (*iter)(struct ieee80211_hw *hw, | 390 | void (*iter)(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 080cf0942ce7..8e884fcbe79b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1605,6 +1605,8 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
1605 | enum ieee80211_chanctx_mode mode); | 1605 | enum ieee80211_chanctx_mode mode); |
1606 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1606 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
1607 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1607 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
1608 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | ||
1609 | bool clear); | ||
1608 | 1610 | ||
1609 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 1611 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
1610 | struct ieee80211_chanctx *chanctx); | 1612 | struct ieee80211_chanctx *chanctx); |