Skip to content

Commit

Permalink
cfg80211: refactor cfg80211_can_use_iftype_chan()
Browse files Browse the repository at this point in the history
Separate the code that counts the interface types and channels from
the code that check the interface combinations.  The new function that
checks for combinations is exported so it can be called by the
drivers.

This is done in preparation for moving the interface combinations
checks out of cfg80211.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
lucacoelho authored and jmberg-intel committed Apr 9, 2014
1 parent c8866e5 commit cb2d956
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 56 deletions.
1 change: 1 addition & 0 deletions Documentation/DocBook/80211.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
!Finclude/net/cfg80211.h wdev_priv
!Finclude/net/cfg80211.h ieee80211_iface_limit
!Finclude/net/cfg80211.h ieee80211_iface_combination
!Finclude/net/cfg80211.h cfg80211_check_combinations
</chapter>
<chapter>
<title>Actions and configuration</title>
Expand Down
22 changes: 22 additions & 0 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -4692,6 +4692,28 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);
*/
unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);

/**
* cfg80211_check_combinations - check interface combinations
*
* @wiphy: the wiphy
* @num_different_channels: the number of different channels we want
* to use for verification
* @radar_detect: a bitmap where each bit corresponds to a channel
* width where radar detection is needed, as in the definition of
* &struct ieee80211_iface_combination.@radar_detect_widths
* @iftype_num: array with the numbers of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
*
* This function can be called by the driver to check whether a
* combination of interfaces and their types are allowed according to
* the interface combinations.
*/
int cfg80211_check_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES]);

/* Logging, debugging and troubleshooting/diagnostic helpers. */

/* wiphy_printk helpers, similar to dev_printk */
Expand Down
129 changes: 73 additions & 56 deletions net/wireless/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,76 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
return res;
}

int cfg80211_check_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES])
{
int i, j, iftype;
int num_interfaces = 0;
u32 used_iftypes = 0;

for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
num_interfaces += iftype_num[iftype];
if (iftype_num[iftype] > 0 &&
!(wiphy->software_iftypes & BIT(iftype)))
used_iftypes |= BIT(iftype);
}

for (i = 0; i < wiphy->n_iface_combinations; i++) {
const struct ieee80211_iface_combination *c;
struct ieee80211_iface_limit *limits;
u32 all_iftypes = 0;

c = &wiphy->iface_combinations[i];

if (num_interfaces > c->max_interfaces)
continue;
if (num_different_channels > c->num_different_channels)
continue;

limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
GFP_KERNEL);
if (!limits)
return -ENOMEM;

for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
if (wiphy->software_iftypes & BIT(iftype))
continue;
for (j = 0; j < c->n_limits; j++) {
all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype)))
continue;
if (limits[j].max < iftype_num[iftype])
goto cont;
limits[j].max -= iftype_num[iftype];
}
}

if (radar_detect && !(c->radar_detect_widths & radar_detect))
goto cont;

/* Finally check that all iftypes that we're currently
* using are actually part of this combination. If they
* aren't then we can't use this combination and have
* to continue to the next.
*/
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;

/* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
kfree(limits);
return 0;
cont:
kfree(limits);
}

return -EBUSY;
}
EXPORT_SYMBOL(cfg80211_check_combinations);

int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_iftype iftype,
Expand All @@ -1276,15 +1346,14 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
u8 radar_detect)
{
struct wireless_dev *wdev_iter;
u32 used_iftypes = BIT(iftype);
int num[NUM_NL80211_IFTYPES];
struct ieee80211_channel
*used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
struct ieee80211_channel *ch;
enum cfg80211_chan_mode chmode;
int num_different_channels = 0;
int total = 1;
int i, j;
int i;

ASSERT_RTNL();

Expand Down Expand Up @@ -1369,65 +1438,13 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,

num[wdev_iter->iftype]++;
total++;
used_iftypes |= BIT(wdev_iter->iftype);
}

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

for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
const struct ieee80211_iface_combination *c;
struct ieee80211_iface_limit *limits;
u32 all_iftypes = 0;

c = &rdev->wiphy.iface_combinations[i];

if (total > c->max_interfaces)
continue;
if (num_different_channels > c->num_different_channels)
continue;

limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
GFP_KERNEL);
if (!limits)
return -ENOMEM;

for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
if (rdev->wiphy.software_iftypes & BIT(iftype))
continue;
for (j = 0; j < c->n_limits; j++) {
all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype)))
continue;
if (limits[j].max < num[iftype])
goto cont;
limits[j].max -= num[iftype];
}
}

if (radar_detect && !(c->radar_detect_widths & radar_detect))
goto cont;

/*
* Finally check that all iftypes that we're currently
* using are actually part of this combination. If they
* aren't then we can't use this combination and have
* to continue to the next.
*/
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;

/*
* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
kfree(limits);
return 0;
cont:
kfree(limits);
}

return -EBUSY;
return cfg80211_check_combinations(&rdev->wiphy, num_different_channels,
radar_detect, num);
}

int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
Expand Down

0 comments on commit cb2d956

Please sign in to comment.