]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
cfg80211: validate wmm rule when setting
authorStanislaw Gruszka <sgruszka@redhat.com>
Wed, 22 Aug 2018 11:52:22 +0000 (13:52 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 5 Sep 2018 08:16:59 +0000 (10:16 +0200)
Add validation check for wmm rule when copy rules from fwdb and print
error when rule is invalid.

Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/reg.c

index 7046d922867a380543190cc58475c20471e66188..56be68a27bb96a84492555a6fe67830674757e08 100644 (file)
@@ -847,22 +847,36 @@ static bool valid_regdb(const u8 *data, unsigned int size)
        return true;
 }
 
-static void set_wmm_rule(struct ieee80211_reg_rule *rrule,
-                        struct fwdb_wmm_rule *wmm)
-{
-       struct ieee80211_wmm_rule *rule = &rrule->wmm_rule;
-       unsigned int i;
+static void set_wmm_rule(const struct fwdb_header *db,
+                        const struct fwdb_country *country,
+                        const struct fwdb_rule *rule,
+                        struct ieee80211_reg_rule *rrule)
+{
+       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++) {
-               rule->client[i].cw_min =
+               wmm_rule->client[i].cw_min =
                        ecw2cw((wmm->client[i].ecw & 0xf0) >> 4);
-               rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
-               rule->client[i].aifsn =  wmm->client[i].aifsn;
-               rule->client[i].cot = 1000 * be16_to_cpu(wmm->client[i].cot);
-               rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
-               rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
-               rule->ap[i].aifsn = wmm->ap[i].aifsn;
-               rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
+               wmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
+               wmm_rule->client[i].aifsn =  wmm->client[i].aifsn;
+               wmm_rule->client[i].cot =
+                       1000 * be16_to_cpu(wmm->client[i].cot);
+               wmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
+               wmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
+               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;
@@ -870,7 +884,7 @@ static void set_wmm_rule(struct ieee80211_reg_rule *rrule,
 
 static int __regdb_query_wmm(const struct fwdb_header *db,
                             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;
        struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
@@ -879,18 +893,14 @@ static int __regdb_query_wmm(const struct fwdb_header *db,
        for (i = 0; i < coll->n_rules; i++) {
                __be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
                unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
-               struct fwdb_rule *rrule = (void *)((u8 *)db + rule_ptr);
-               struct fwdb_wmm_rule *wmm;
-               unsigned int wmm_ptr;
+               struct fwdb_rule *rule = (void *)((u8 *)db + rule_ptr);
 
-               if (rrule->len < offsetofend(struct fwdb_rule, wmm_ptr))
+               if (rule->len < offsetofend(struct fwdb_rule, wmm_ptr))
                        continue;
 
-               if (freq >= KHZ_TO_MHZ(be32_to_cpu(rrule->start)) &&
-                   freq <= KHZ_TO_MHZ(be32_to_cpu(rrule->end))) {
-                       wmm_ptr = be16_to_cpu(rrule->wmm_ptr) << 2;
-                       wmm = (void *)((u8 *)db + wmm_ptr);
-                       set_wmm_rule(rule, wmm);
+               if (freq >= KHZ_TO_MHZ(be32_to_cpu(rule->start)) &&
+                   freq <= KHZ_TO_MHZ(be32_to_cpu(rule->end))) {
+                       set_wmm_rule(db, country, rule, rrule);
                        return 0;
                }
        }
@@ -972,12 +982,8 @@ static int regdb_query_country(const struct fwdb_header *db,
                if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout))
                        rrule->dfs_cac_ms =
                                1000 * be16_to_cpu(rule->cac_timeout);
-               if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) {
-                       u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
-                       struct fwdb_wmm_rule *wmm = (void *)((u8 *)db + wmm_ptr);
-
-                       set_wmm_rule(rrule, wmm);
-               }
+               if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr))
+                       set_wmm_rule(db, country, rule, rrule);
        }
 
        return reg_schedule_apply(regdom);