Skip to content

Commit

Permalink
cfg80211/mac80211: move interface counting for combination check to m…
Browse files Browse the repository at this point in the history
…ac80211

Move the counting part of the interface combination check from
cfg80211 to mac80211.

This is needed to simplify locking when the driver has to perform a
combination check by itself (eg. with channel-switch).

Signed-off-by: Luciano Coelho <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
  • Loading branch information
lucacoelho authored and jmberg-intel committed Apr 9, 2014
1 parent 2beb6da commit 73de86a
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 80 deletions.
2 changes: 0 additions & 2 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,6 @@ struct cfg80211_acl_data {
* @p2p_opp_ps: P2P opportunistic PS
* @acl: ACL configuration used by the drivers which has support for
* MAC address based access control
* @radar_required: set if radar detection is required
*/
struct cfg80211_ap_settings {
struct cfg80211_chan_def chandef;
Expand All @@ -680,7 +679,6 @@ struct cfg80211_ap_settings {
u8 p2p_ctwindow;
bool p2p_opp_ps;
const struct cfg80211_acl_data *acl;
bool radar_required;
};

/**
Expand Down
2 changes: 0 additions & 2 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->needed_rx_chains = sdata->local->rx_chains;

mutex_lock(&local->mtx);
sdata->radar_required = params->radar_required;
err = ieee80211_vif_use_channel(sdata, &params->chandef,
IEEE80211_CHANCTX_SHARED);
mutex_unlock(&local->mtx);
Expand Down Expand Up @@ -2930,7 +2929,6 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
/* whatever, but channel contexts should not complain about that one */
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = local->rx_chains;
sdata->radar_required = true;

err = ieee80211_vif_use_channel(sdata, chandef,
IEEE80211_CHANCTX_SHARED);
Expand Down
17 changes: 17 additions & 0 deletions net/mac80211/chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,13 +519,30 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *ctx;
u8 radar_detect_width = 0;
int ret;

lockdep_assert_held(&local->mtx);

WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));

mutex_lock(&local->chanctx_mtx);

ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
chandef,
sdata->wdev.iftype);
if (ret < 0)
goto out;
if (ret > 0)
radar_detect_width = BIT(chandef->width);

sdata->radar_required = ret;

ret = ieee80211_check_combinations(sdata, chandef, mode,
radar_detect_width);
if (ret < 0)
goto out;

__ieee80211_vif_release_channel(sdata);

ctx = ieee80211_find_chanctx(local, chandef, mode);
Expand Down
4 changes: 4 additions & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1805,6 +1805,10 @@ int ieee80211_cs_headroom(struct ieee80211_local *local,
enum nl80211_iftype iftype);
void ieee80211_recalc_dtim(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode chanmode,
u8 radar_detect);

#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
Expand Down
72 changes: 72 additions & 0 deletions net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2797,3 +2797,75 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,

ps->dtim_count = dtim_count;
}

int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode chanmode,
u8 radar_detect)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *sdata_iter;
enum nl80211_iftype iftype = sdata->wdev.iftype;
int num[NUM_NL80211_IFTYPES];
struct ieee80211_chanctx *ctx;
int num_different_channels = 1;
int total = 1;

lockdep_assert_held(&local->chanctx_mtx);

if (WARN_ON(hweight32(radar_detect) > 1))
return -EINVAL;

if (WARN_ON(chanmode == IEEE80211_CHANCTX_SHARED && !chandef->chan))
return -EINVAL;

if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
return -EINVAL;

/* Always allow software iftypes */
if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
if (radar_detect)
return -EINVAL;
return 0;
}

memset(num, 0, sizeof(num));

if (iftype != NL80211_IFTYPE_UNSPECIFIED)
num[iftype] = 1;

list_for_each_entry(ctx, &local->chanctx_list, list) {
if (ctx->conf.radar_enabled)
radar_detect |= BIT(ctx->conf.def.width);
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
num_different_channels++;
continue;
}
if ((chanmode == IEEE80211_CHANCTX_SHARED) &&
cfg80211_chandef_compatible(chandef,
&ctx->conf.def))
continue;
num_different_channels++;
}

list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
struct wireless_dev *wdev_iter;

wdev_iter = &sdata_iter->wdev;

if (sdata_iter == sdata ||
rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
continue;

num[wdev_iter->iftype]++;
total++;
}

if (total == 1 && !radar_detect)
return 0;

return cfg80211_check_combinations(local->hw.wiphy,
num_different_channels,
radar_detect, num);
}
13 changes: 3 additions & 10 deletions net/wireless/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_iftype iftype)
{
/* TODO: For this function, we'll probably need to keep some
* kind of interface combination check in cfg80211...
*/
return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
CHAN_MODE_UNDEFINED, 0);
}
Expand All @@ -431,16 +434,6 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
return cfg80211_can_change_interface(rdev, NULL, iftype);
}

static inline int
cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
enum cfg80211_chan_mode chanmode)
{
return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
chan, chanmode, 0);
}

static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
{
unsigned long end = jiffies;
Expand Down
4 changes: 4 additions & 0 deletions net/wireless/ibss.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
radar_detect_width = BIT(params->chandef.width);
}

/* TODO: We need to check the combinations at this point, we
* probably must move this call down to join_ibss() in
* mac80211.
*/
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
check_chan,
(params->channel_fixed &&
Expand Down
28 changes: 0 additions & 28 deletions net/wireless/mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
const struct mesh_config *conf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
u8 radar_detect_width = 0;
int err;

BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
Expand Down Expand Up @@ -179,22 +178,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
NL80211_IFTYPE_MESH_POINT))
return -EINVAL;

err = cfg80211_chandef_dfs_required(wdev->wiphy,
&setup->chandef,
NL80211_IFTYPE_MESH_POINT);
if (err < 0)
return err;

if (err > 0)
radar_detect_width = BIT(setup->chandef.width);

err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
setup->chandef.chan,
CHAN_MODE_SHARED,
radar_detect_width);
if (err)
return err;

err = rdev_join_mesh(rdev, dev, conf, setup);
if (!err) {
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
Expand Down Expand Up @@ -240,17 +223,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
if (!netif_running(wdev->netdev))
return -ENETDOWN;

/* cfg80211_can_use_chan() calls
* cfg80211_can_use_iftype_chan() with no radar
* detection, so if we're trying to use a radar
* channel here, something is wrong.
*/
WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR);
err = cfg80211_can_use_chan(rdev, wdev, chandef->chan,
CHAN_MODE_SHARED);
if (err)
return err;

err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
chandef->chan);
if (!err)
Expand Down
14 changes: 1 addition & 13 deletions net/wireless/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
if (!req.bss)
return -ENOENT;

err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
CHAN_MODE_SHARED);
if (err)
goto out;

err = rdev_auth(rdev, dev, &req);

out:
cfg80211_put_bss(&rdev->wiphy, req.bss);
return err;
}
Expand Down Expand Up @@ -306,16 +300,10 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
if (!req->bss)
return -ENOENT;

err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
if (err)
goto out;

err = rdev_assoc(rdev, dev, req);
if (!err)
cfg80211_hold_bss(bss_from_pub(req->bss));

out:
if (err)
else
cfg80211_put_bss(&rdev->wiphy, req->bss);

return err;
Expand Down
29 changes: 4 additions & 25 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -3155,7 +3155,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_ap_settings params;
int err;
u8 radar_detect_width = 0;

if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
Expand Down Expand Up @@ -3275,24 +3274,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
wdev->iftype))
return -EINVAL;

err = cfg80211_chandef_dfs_required(wdev->wiphy,
&params.chandef,
NL80211_IFTYPE_AP);
if (err < 0)
return err;

if (err > 0) {
params.radar_required = true;
radar_detect_width = BIT(params.chandef.width);
}

err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
params.chandef.chan,
CHAN_MODE_SHARED,
radar_detect_width);
if (err)
return err;

if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
params.acl = parse_acl_data(&rdev->wiphy, info);
if (IS_ERR(params.acl))
Expand Down Expand Up @@ -5823,12 +5804,6 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
if (!rdev->ops->start_radar_detection)
return -EOPNOTSUPP;

err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
chandef.chan, CHAN_MODE_SHARED,
BIT(chandef.width));
if (err)
return err;

cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
if (WARN_ON(!cac_time_ms))
cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
Expand Down Expand Up @@ -5957,6 +5932,10 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
params.radar_required = true;
}

/* TODO: I left this here for now. With channel switch, the
* verification is a bit more complicated, because we only do
* it later when the channel switch really happens.
*/
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
params.chandef.chan,
CHAN_MODE_SHARED,
Expand Down
5 changes: 5 additions & 0 deletions net/wireless/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,11 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,

num[iftype] = 1;

/* TODO: We'll probably not need this anymore, since this
* should only be called with CHAN_MODE_UNDEFINED. There are
* still a couple of pending calls where other chanmodes are
* used, but we should get rid of them.
*/
switch (chanmode) {
case CHAN_MODE_UNDEFINED:
break;
Expand Down

0 comments on commit 73de86a

Please sign in to comment.