Merge "cfg80211: support virtual interfaces with different beacon intervals"

This commit is contained in:
Linux Build Service Account 2016-11-02 14:41:39 -07:00 committed by Gerrit - the friendly Code Review server
commit 875dca44ef
5 changed files with 67 additions and 10 deletions

View file

@ -796,11 +796,19 @@ 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.
*/
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;
};
/**
@ -2894,6 +2902,12 @@ struct ieee80211_iface_limit {
* only in special cases.
* @radar_detect_widths: bitmap of channel widths supported for radar detection
* @radar_detect_regions: bitmap of regions supported for radar detection
* @beacon_int_min_gcd: This interface combination supports different
* beacon intervals.
* = 0 - all beacon intervals for different interface must be same.
* > 0 - any beacon interval for the interface part of this combination AND
* *GCD* of all beacon intervals from beaconing interfaces of this
* combination must be greater or equal to this value.
*
* With this structure the driver can describe which interface
* combinations it supports concurrently.
@ -2952,6 +2966,7 @@ struct ieee80211_iface_combination {
bool beacon_int_infra_match;
u8 radar_detect_widths;
u8 radar_detect_regions;
u32 beacon_int_min_gcd;
};
struct ieee80211_txrx_stypes {

View file

@ -4101,6 +4101,9 @@ enum nl80211_iface_limit_attrs {
* of supported channel widths for radar detection.
* @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap
* of supported regulatory regions for radar detection.
* @NL80211_IFACE_COMB_BI_MIN_GCD: u32 attribute specifying the minimum GCD of
* different beacon intervals supported by all the interface combinations
* in this group (if not present, all beacon intervals be identical).
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
@ -4108,8 +4111,8 @@ enum nl80211_iface_limit_attrs {
* limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
* => allows an AP and a STA that must match BIs
*
* numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
* => allows 8 of AP/GO
* numbers = [ #{AP, P2P-GO} <= 8 ], BI min gcd, channels = 1, max = 8,
* => allows 8 of AP/GO that can have BI gcd >= min gcd
*
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2
* => allows two STAs on different channels
@ -4135,6 +4138,7 @@ enum nl80211_if_combination_attrs {
NL80211_IFACE_COMB_NUM_CHANNELS,
NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
NL80211_IFACE_COMB_BI_MIN_GCD,
/* keep last */
NUM_NL80211_IFACE_COMB,

View file

@ -466,7 +466,7 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
u32 *mask);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
u32 beacon_int);
enum nl80211_iftype iftype, u32 beacon_int);
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);

View file

@ -1003,6 +1003,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
c->radar_detect_regions)))
goto nla_put_failure;
if (c->beacon_int_min_gcd &&
nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
c->beacon_int_min_gcd))
goto nla_put_failure;
nla_nest_end(msg, nl_combi);
}
@ -3656,7 +3660,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
params.dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
params.beacon_interval);
if (err)
return err;

View file

@ -1483,24 +1483,46 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
u32 beacon_int)
enum nl80211_iftype iftype, u32 beacon_int)
{
struct wireless_dev *wdev;
int res = 0;
struct iface_combination_params params = {
.beacon_int_gcd = beacon_int, /* GCD(n) = n */
};
if (!beacon_int)
return -EINVAL;
params.iftype_num[iftype] = 1;
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (!wdev->beacon_interval)
continue;
if (wdev->beacon_interval != beacon_int) {
res = -EINVAL;
break;
params.iftype_num[wdev->iftype]++;
}
list_for_each_entry(wdev, &rdev->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 res;
return cfg80211_check_combinations(&rdev->wiphy, &params);
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
@ -1576,6 +1598,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
if (params->beacon_int_gcd) {
if (c->beacon_int_min_gcd &&
params->beacon_int_gcd < c->beacon_int_min_gcd) {
kfree(limits);
return -EINVAL;
}
if (!c->beacon_int_min_gcd &&
params->beacon_int_different)
goto cont;
}
/* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/