Commit 014f5a25 authored by Stanislaw Gruszka's avatar Stanislaw Gruszka Committed by Johannes Berg

cfg80211: validate wmm rule when setting

Add validation check for wmm rule when copy rules from fwdb and print
error when rule is invalid.
Signed-off-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 40b5a0f8
...@@ -847,22 +847,36 @@ static bool valid_regdb(const u8 *data, unsigned int size) ...@@ -847,22 +847,36 @@ static bool valid_regdb(const u8 *data, unsigned int size)
return true; return true;
} }
static void set_wmm_rule(struct ieee80211_reg_rule *rrule, static void set_wmm_rule(const struct fwdb_header *db,
struct fwdb_wmm_rule *wmm) const struct fwdb_country *country,
{ const struct fwdb_rule *rule,
struct ieee80211_wmm_rule *rule = &rrule->wmm_rule; struct ieee80211_reg_rule *rrule)
unsigned int i; {
struct ieee80211_wmm_rule *wmm_rule = &rrule->wmm_rule;
struct fwdb_wmm_rule *wmm;
unsigned int i, wmm_ptr;
wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
wmm = (void *)((u8 *)db + wmm_ptr);
if (!valid_wmm(wmm)) {
pr_err("Invalid regulatory WMM rule %u-%u in domain %c%c\n",
be32_to_cpu(rule->start), be32_to_cpu(rule->end),
country->alpha2[0], country->alpha2[1]);
return;
}
for (i = 0; i < IEEE80211_NUM_ACS; i++) { for (i = 0; i < IEEE80211_NUM_ACS; i++) {
rule->client[i].cw_min = wmm_rule->client[i].cw_min =
ecw2cw((wmm->client[i].ecw & 0xf0) >> 4); ecw2cw((wmm->client[i].ecw & 0xf0) >> 4);
rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f); wmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
rule->client[i].aifsn = wmm->client[i].aifsn; wmm_rule->client[i].aifsn = wmm->client[i].aifsn;
rule->client[i].cot = 1000 * be16_to_cpu(wmm->client[i].cot); wmm_rule->client[i].cot =
rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4); 1000 * be16_to_cpu(wmm->client[i].cot);
rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f); wmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
rule->ap[i].aifsn = wmm->ap[i].aifsn; wmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot); wmm_rule->ap[i].aifsn = wmm->ap[i].aifsn;
wmm_rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
} }
rrule->has_wmm = true; rrule->has_wmm = true;
...@@ -870,7 +884,7 @@ static void set_wmm_rule(struct ieee80211_reg_rule *rrule, ...@@ -870,7 +884,7 @@ static void set_wmm_rule(struct ieee80211_reg_rule *rrule,
static int __regdb_query_wmm(const struct fwdb_header *db, static int __regdb_query_wmm(const struct fwdb_header *db,
const struct fwdb_country *country, int freq, const struct fwdb_country *country, int freq,
struct ieee80211_reg_rule *rule) struct ieee80211_reg_rule *rrule)
{ {
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2; unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
struct fwdb_collection *coll = (void *)((u8 *)db + ptr); struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
...@@ -879,18 +893,14 @@ static int __regdb_query_wmm(const struct fwdb_header *db, ...@@ -879,18 +893,14 @@ static int __regdb_query_wmm(const struct fwdb_header *db,
for (i = 0; i < coll->n_rules; i++) { for (i = 0; i < coll->n_rules; i++) {
__be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2)); __be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2; unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
struct fwdb_rule *rrule = (void *)((u8 *)db + rule_ptr); struct fwdb_rule *rule = (void *)((u8 *)db + rule_ptr);
struct fwdb_wmm_rule *wmm;
unsigned int wmm_ptr;
if (rrule->len < offsetofend(struct fwdb_rule, wmm_ptr)) if (rule->len < offsetofend(struct fwdb_rule, wmm_ptr))
continue; continue;
if (freq >= KHZ_TO_MHZ(be32_to_cpu(rrule->start)) && if (freq >= KHZ_TO_MHZ(be32_to_cpu(rule->start)) &&
freq <= KHZ_TO_MHZ(be32_to_cpu(rrule->end))) { freq <= KHZ_TO_MHZ(be32_to_cpu(rule->end))) {
wmm_ptr = be16_to_cpu(rrule->wmm_ptr) << 2; set_wmm_rule(db, country, rule, rrule);
wmm = (void *)((u8 *)db + wmm_ptr);
set_wmm_rule(rule, wmm);
return 0; return 0;
} }
} }
...@@ -972,12 +982,8 @@ static int regdb_query_country(const struct fwdb_header *db, ...@@ -972,12 +982,8 @@ static int regdb_query_country(const struct fwdb_header *db,
if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout)) if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout))
rrule->dfs_cac_ms = rrule->dfs_cac_ms =
1000 * be16_to_cpu(rule->cac_timeout); 1000 * be16_to_cpu(rule->cac_timeout);
if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) { if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr))
u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2; set_wmm_rule(db, country, rule, rrule);
struct fwdb_wmm_rule *wmm = (void *)((u8 *)db + wmm_ptr);
set_wmm_rule(rrule, wmm);
}
} }
return reg_schedule_apply(regdom); return reg_schedule_apply(regdom);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment