Skip to content

Commit

Permalink
mac80211: explicitly copy channels to VLANs where needed
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg committed Feb 11, 2013
1 parent 757af6f commit 1f4ac5a
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 18 deletions.
2 changes: 2 additions & 0 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_CHANCTX_SHARED);
if (err)
return err;
ieee80211_vif_copy_chanctx_to_vlans(sdata, false);

/*
* Apply control port protocol, this allows us to
Expand Down Expand Up @@ -1047,6 +1048,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
skb_queue_purge(&sdata->u.ap.ps.bc_buf);

ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
ieee80211_vif_release_channel(sdata);

return 0;
Expand Down
52 changes: 34 additions & 18 deletions net/mac80211/chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,6 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)

ctx = container_of(conf, struct ieee80211_chanctx, conf);

if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan;

/* for the VLAN list */
ASSERT_RTNL();
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
rcu_assign_pointer(vlan->vif.chanctx_conf, NULL);
}

ieee80211_unassign_vif_chanctx(sdata, ctx);
if (ctx->refcount == 0)
ieee80211_free_chanctx(local, ctx);
Expand Down Expand Up @@ -326,15 +317,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
goto out;
}

if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan;

/* for the VLAN list */
ASSERT_RTNL();
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf);
}

ieee80211_recalc_smps_chanctx(local, ctx);
out:
mutex_unlock(&local->chanctx_mtx);
Expand Down Expand Up @@ -369,6 +351,40 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&local->chanctx_mtx);
}

void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
bool clear)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *vlan;
struct ieee80211_chanctx_conf *conf;

ASSERT_RTNL();

if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
return;

mutex_lock(&local->chanctx_mtx);

/*
* Check that conf exists, even when clearing this function
* must be called with the AP's channel context still there
* as it would otherwise cause VLANs to have an invalid
* channel context pointer for a while, possibly pointing
* to a channel context that has already been freed.
*/
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
WARN_ON(!conf);

if (clear)
conf = NULL;

list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
rcu_assign_pointer(vlan->vif.chanctx_conf, conf);

mutex_unlock(&local->chanctx_mtx);
}

void ieee80211_iter_chan_contexts_atomic(
struct ieee80211_hw *hw,
void (*iter)(struct ieee80211_hw *hw,
Expand Down
2 changes: 2 additions & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,8 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
enum ieee80211_chanctx_mode mode);
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
bool clear);

void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
Expand Down

0 comments on commit 1f4ac5a

Please sign in to comment.