cfg80211: avoid duplicate entries on regdomain intersection
The regdom intersection code simply tries intersecting each rule of the source with each rule of the target. Since the resulting intersections are not observed as a whole, this can result in multiple overlapping/duplicate entries. Make the rule addition a bit more smarter, by looking for rules that can be contained within other rules, and adding only extended ones. Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
cd2f5dd709
commit
a62a1aed37
|
@ -799,6 +799,57 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* check whether old rule contains new rule */
|
||||
static bool rule_contains(struct ieee80211_reg_rule *r1,
|
||||
struct ieee80211_reg_rule *r2)
|
||||
{
|
||||
/* for simplicity, currently consider only same flags */
|
||||
if (r1->flags != r2->flags)
|
||||
return false;
|
||||
|
||||
/* verify r1 is more restrictive */
|
||||
if ((r1->power_rule.max_antenna_gain >
|
||||
r2->power_rule.max_antenna_gain) ||
|
||||
r1->power_rule.max_eirp > r2->power_rule.max_eirp)
|
||||
return false;
|
||||
|
||||
/* make sure r2's range is contained within r1 */
|
||||
if (r1->freq_range.start_freq_khz > r2->freq_range.start_freq_khz ||
|
||||
r1->freq_range.end_freq_khz < r2->freq_range.end_freq_khz)
|
||||
return false;
|
||||
|
||||
/* and finally verify that r1.max_bw >= r2.max_bw */
|
||||
if (r1->freq_range.max_bandwidth_khz <
|
||||
r2->freq_range.max_bandwidth_khz)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* add or extend current rules. do nothing if rule is already contained */
|
||||
static void add_rule(struct ieee80211_reg_rule *rule,
|
||||
struct ieee80211_reg_rule *reg_rules, u32 *n_rules)
|
||||
{
|
||||
struct ieee80211_reg_rule *tmp_rule;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < *n_rules; i++) {
|
||||
tmp_rule = ®_rules[i];
|
||||
/* rule is already contained - do nothing */
|
||||
if (rule_contains(tmp_rule, rule))
|
||||
return;
|
||||
|
||||
/* extend rule if possible */
|
||||
if (rule_contains(rule, tmp_rule)) {
|
||||
memcpy(tmp_rule, rule, sizeof(*rule));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(®_rules[*n_rules], rule, sizeof(*rule));
|
||||
(*n_rules)++;
|
||||
}
|
||||
|
||||
/**
|
||||
* regdom_intersect - do the intersection between two regulatory domains
|
||||
* @rd1: first regulatory domain
|
||||
|
@ -818,12 +869,10 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
|
|||
{
|
||||
int r, size_of_regd;
|
||||
unsigned int x, y;
|
||||
unsigned int num_rules = 0, rule_idx = 0;
|
||||
unsigned int num_rules = 0;
|
||||
const struct ieee80211_reg_rule *rule1, *rule2;
|
||||
struct ieee80211_reg_rule *intersected_rule;
|
||||
struct ieee80211_reg_rule intersected_rule;
|
||||
struct ieee80211_regdomain *rd;
|
||||
/* This is just a dummy holder to help us count */
|
||||
struct ieee80211_reg_rule dummy_rule;
|
||||
|
||||
if (!rd1 || !rd2)
|
||||
return NULL;
|
||||
|
@ -841,7 +890,7 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
|
|||
for (y = 0; y < rd2->n_reg_rules; y++) {
|
||||
rule2 = &rd2->reg_rules[y];
|
||||
if (!reg_rules_intersect(rd1, rd2, rule1, rule2,
|
||||
&dummy_rule))
|
||||
&intersected_rule))
|
||||
num_rules++;
|
||||
}
|
||||
}
|
||||
|
@ -856,34 +905,24 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
|
|||
if (!rd)
|
||||
return NULL;
|
||||
|
||||
for (x = 0; x < rd1->n_reg_rules && rule_idx < num_rules; x++) {
|
||||
for (x = 0; x < rd1->n_reg_rules; x++) {
|
||||
rule1 = &rd1->reg_rules[x];
|
||||
for (y = 0; y < rd2->n_reg_rules && rule_idx < num_rules; y++) {
|
||||
for (y = 0; y < rd2->n_reg_rules; y++) {
|
||||
rule2 = &rd2->reg_rules[y];
|
||||
/*
|
||||
* This time around instead of using the stack lets
|
||||
* write to the target rule directly saving ourselves
|
||||
* a memcpy()
|
||||
*/
|
||||
intersected_rule = &rd->reg_rules[rule_idx];
|
||||
r = reg_rules_intersect(rd1, rd2, rule1, rule2,
|
||||
intersected_rule);
|
||||
&intersected_rule);
|
||||
/*
|
||||
* No need to memset here the intersected rule here as
|
||||
* we're not using the stack anymore
|
||||
*/
|
||||
if (r)
|
||||
continue;
|
||||
rule_idx++;
|
||||
|
||||
add_rule(&intersected_rule, rd->reg_rules,
|
||||
&rd->n_reg_rules);
|
||||
}
|
||||
}
|
||||
|
||||
if (rule_idx != num_rules) {
|
||||
kfree(rd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rd->n_reg_rules = num_rules;
|
||||
rd->alpha2[0] = '9';
|
||||
rd->alpha2[1] = '8';
|
||||
rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,
|
||||
|
|
Loading…
Reference in New Issue