Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 121820
b: refs/heads/master
c: 9c96477
h: refs/heads/master
v: v3
  • Loading branch information
Luis R. Rodriguez authored and John W. Linville committed Nov 10, 2008
1 parent 22e4667 commit fcf3a00
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 9 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d71aaf6053e380996e40c9ecfe39a8dced52694c
refs/heads/master: 9c96477d10763d4314012425ecc8a3cff9e60ea9
166 changes: 158 additions & 8 deletions trunk/net/wireless/reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct regulatory_request {
struct wiphy *wiphy;
enum reg_set_by initiator;
char alpha2[2];
bool intersect;
};

static struct regulatory_request *last_request;
Expand Down Expand Up @@ -359,6 +360,143 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
return 0;
}

/* Helper for regdom_intersect(), this does the real
* mathematical intersection fun */
static int reg_rules_intersect(
const struct ieee80211_reg_rule *rule1,
const struct ieee80211_reg_rule *rule2,
struct ieee80211_reg_rule *intersected_rule)
{
const struct ieee80211_freq_range *freq_range1, *freq_range2;
struct ieee80211_freq_range *freq_range;
const struct ieee80211_power_rule *power_rule1, *power_rule2;
struct ieee80211_power_rule *power_rule;
u32 freq_diff;

freq_range1 = &rule1->freq_range;
freq_range2 = &rule2->freq_range;
freq_range = &intersected_rule->freq_range;

power_rule1 = &rule1->power_rule;
power_rule2 = &rule2->power_rule;
power_rule = &intersected_rule->power_rule;

freq_range->start_freq_khz = max(freq_range1->start_freq_khz,
freq_range2->start_freq_khz);
freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
freq_range2->end_freq_khz);
freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
freq_range2->max_bandwidth_khz);

freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
if (freq_range->max_bandwidth_khz > freq_diff)
freq_range->max_bandwidth_khz = freq_diff;

power_rule->max_eirp = min(power_rule1->max_eirp,
power_rule2->max_eirp);
power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
power_rule2->max_antenna_gain);

intersected_rule->flags = (rule1->flags | rule2->flags);

if (!is_valid_reg_rule(intersected_rule))
return -EINVAL;

return 0;
}

/**
* regdom_intersect - do the intersection between two regulatory domains
* @rd1: first regulatory domain
* @rd2: second regulatory domain
*
* Use this function to get the intersection between two regulatory domains.
* Once completed we will mark the alpha2 for the rd as intersected, "98",
* as no one single alpha2 can represent this regulatory domain.
*
* Returns a pointer to the regulatory domain structure which will hold the
* resulting intersection of rules between rd1 and rd2. We will
* kzalloc() this structure for you.
*/
static struct ieee80211_regdomain *regdom_intersect(
const struct ieee80211_regdomain *rd1,
const struct ieee80211_regdomain *rd2)
{
int r, size_of_regd;
unsigned int x, y;
unsigned int num_rules = 0, rule_idx = 0;
const struct ieee80211_reg_rule *rule1, *rule2;
struct ieee80211_reg_rule *intersected_rule;
struct ieee80211_regdomain *rd;
/* This is just a dummy holder to help us count */
struct ieee80211_reg_rule irule;

/* Uses the stack temporarily for counter arithmetic */
intersected_rule = &irule;

memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule));

if (!rd1 || !rd2)
return NULL;

/* First we get a count of the rules we'll need, then we actually
* build them. This is to so we can malloc() and free() a
* regdomain once. The reason we use reg_rules_intersect() here
* is it will return -EINVAL if the rule computed makes no sense.
* All rules that do check out OK are valid. */

for (x = 0; x < rd1->n_reg_rules; x++) {
rule1 = &rd1->reg_rules[x];
for (y = 0; y < rd2->n_reg_rules; y++) {
rule2 = &rd2->reg_rules[y];
if (!reg_rules_intersect(rule1, rule2,
intersected_rule))
num_rules++;
memset(intersected_rule, 0,
sizeof(struct ieee80211_reg_rule));
}
}

if (!num_rules)
return NULL;

size_of_regd = sizeof(struct ieee80211_regdomain) +
((num_rules + 1) * sizeof(struct ieee80211_reg_rule));

rd = kzalloc(size_of_regd, GFP_KERNEL);
if (!rd)
return NULL;

for (x = 0; x < rd1->n_reg_rules; x++) {
rule1 = &rd1->reg_rules[x];
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(rule1, rule2,
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;
}

rd->n_reg_rules = num_rules;
rd->alpha2[0] = '9';
rd->alpha2[1] = '8';

return rd;
}

/* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
* want to just have the channel structure use these */
static u32 map_regdom_flags(u32 rd_flags)
Expand Down Expand Up @@ -468,6 +606,10 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
}
}

/* Return value which can be used by ignore_request() to indicate
* it has been determined we should intersect two regulatory domains */
#define REG_INTERSECT 1

/* This has the logic which determines when a new request
* should be ignored. */
static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
Expand Down Expand Up @@ -517,14 +659,8 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
return -EALREADY;
return 0;
case REGDOM_SET_BY_USER:
/*
* If the user wants to override the AP's hint, we may
* need to follow both and use the intersection. For now,
* reject any such attempt (but we don't support country
* IEs right now anyway.)
*/
if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
return -EOPNOTSUPP;
return REG_INTERSECT;
return 0;
}

Expand All @@ -536,10 +672,14 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
const char *alpha2)
{
struct regulatory_request *request;
bool intersect = false;
int r = 0;

r = ignore_request(wiphy, set_by, alpha2);
if (r)

if (r == REG_INTERSECT)
intersect = true;
else if (r)
return r;

switch (set_by) {
Expand All @@ -556,6 +696,7 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
request->alpha2[1] = alpha2[1];
request->initiator = set_by;
request->wiphy = wiphy;
request->intersect = intersect;

kfree(last_request);
last_request = request;
Expand Down Expand Up @@ -648,6 +789,7 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd)
/* Takes ownership of rd only if it doesn't fail */
static int __set_regdom(const struct ieee80211_regdomain *rd)
{
const struct ieee80211_regdomain *intersected_rd = NULL;
/* Some basic sanity checks first */

if (is_world_regdom(rd->alpha2)) {
Expand Down Expand Up @@ -697,6 +839,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
return -EOPNOTSUPP;
}

if (unlikely(last_request->intersect)) {
intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
if (!intersected_rd)
return -EINVAL;
kfree(rd);
rd = intersected_rd;
}

/* Tada! */
cfg80211_regdomain = rd;

Expand Down

0 comments on commit fcf3a00

Please sign in to comment.