Merge "cfg80211: validate beacon int as part of iface combinations"

This commit is contained in:
Linux Build Service Account 2016-11-24 06:13:18 -08:00 committed by Gerrit - the friendly Code Review server
commit aff86d3b4f
2 changed files with 63 additions and 46 deletions

View file

@ -796,19 +796,15 @@ struct cfg80211_csa_settings {
* @iftype_num: array with the number of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
* @beacon_int_gcd: a value specifying GCD of all beaconing interfaces,
* the GCD of a single value is considered the value itself, so for
* a single interface this should be set to that interface's beacon
* interval
* @beacon_int_different: a flag indicating whether or not all beacon
* intervals (of beaconing interfaces) are different or not.
* @new_beacon_int: set this to the beacon interval of a new interface
* that's not operating yet, if such is to be checked as part of
* the verification
*/
struct iface_combination_params {
int num_different_channels;
u8 radar_detect;
int iftype_num[NUM_NL80211_IFTYPES];
u32 beacon_int_gcd;
bool beacon_int_different;
u32 new_beacon_int;
};
/**

View file

@ -13,6 +13,7 @@
#include <net/dsfield.h>
#include <linux/if_vlan.h>
#include <linux/mpls.h>
#include <linux/gcd.h>
#include "core.h"
#include "rdev-ops.h"
@ -1482,47 +1483,53 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
}
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
u32 *beacon_int_gcd,
bool *beacon_int_different)
{
struct wireless_dev *wdev;
*beacon_int_gcd = 0;
*beacon_int_different = false;
list_for_each_entry(wdev, &wiphy->wdev_list, list) {
if (!wdev->beacon_interval)
continue;
if (!*beacon_int_gcd) {
*beacon_int_gcd = wdev->beacon_interval;
continue;
}
if (wdev->beacon_interval == *beacon_int_gcd)
continue;
*beacon_int_different = true;
*beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
}
if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {
if (*beacon_int_gcd)
*beacon_int_different = true;
*beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int);
}
}
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, u32 beacon_int)
{
struct wireless_dev *wdev;
struct iface_combination_params params = {
.beacon_int_gcd = beacon_int, /* GCD(n) = n */
};
/*
* This is just a basic pre-condition check; if interface combinations
* are possible the driver must already be checking those with a call
* to cfg80211_check_combinations(), in which case we'll validate more
* through the cfg80211_calculate_bi_data() call and code in
* cfg80211_iter_combinations().
*/
if (beacon_int < 10 || beacon_int > 10000)
return -EINVAL;
params.iftype_num[iftype] = 1;
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->beacon_interval)
continue;
params.iftype_num[wdev->iftype]++;
}
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
u32 bi_prev = wdev->beacon_interval;
if (!wdev->beacon_interval)
continue;
/* slight optimisation - skip identical BIs */
if (wdev->beacon_interval == beacon_int)
continue;
params.beacon_int_different = true;
/* Get the GCD */
while (bi_prev != 0) {
u32 tmp_bi = bi_prev;
bi_prev = params.beacon_int_gcd % bi_prev;
params.beacon_int_gcd = tmp_bi;
}
}
return cfg80211_check_combinations(&rdev->wiphy, &params);
return 0;
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
@ -1536,6 +1543,21 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
int i, j, iftype;
int num_interfaces = 0;
u32 used_iftypes = 0;
u32 beacon_int_gcd;
bool beacon_int_different;
/*
* This is a bit strange, since the iteration used to rely only on
* the data given by the driver, but here it now relies on context,
* in form of the currently operating interfaces.
* This is OK for all current users, and saves us from having to
* push the GCD calculations into all the drivers.
* In the future, this should probably rely more on data that's in
* cfg80211 already - the only thing not would appear to be any new
* interfaces (while being brought up) and channel/radar data.
*/
cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
&beacon_int_gcd, &beacon_int_different);
if (params->radar_detect) {
rcu_read_lock();
@ -1598,12 +1620,11 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
if (params->beacon_int_gcd) {
if (beacon_int_gcd) {
if (c->beacon_int_min_gcd &&
params->beacon_int_gcd < c->beacon_int_min_gcd)
beacon_int_gcd < c->beacon_int_min_gcd)
goto cont;
if (!c->beacon_int_min_gcd &&
params->beacon_int_different)
if (!c->beacon_int_min_gcd && beacon_int_different)
goto cont;
}