|
@@ -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++;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- if (rule_idx != num_rules) {
|
|
|
- kfree(rd);
|
|
|
- return NULL;
|
|
|
+ add_rule(&intersected_rule, rd->reg_rules,
|
|
|
+ &rd->n_reg_rules);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- rd->n_reg_rules = num_rules;
|
|
|
rd->alpha2[0] = '9';
|
|
|
rd->alpha2[1] = '8';
|
|
|
rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,
|