cfg80211: Add API to allow querying regdb for wmm_rule
authorHaim Dreyfuss <haim.dreyfuss@intel.com>
Wed, 28 Mar 2018 10:24:11 +0000 (13:24 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 29 Mar 2018 09:35:17 +0000 (11:35 +0200)
In general regulatory self managed devices maintain their own
regulatory profiles thus it doesn't have to query the regulatory database
on country change.

ETSI has recently introduced a new channel access mechanism for 5GHz
that all wlan devices need to comply with.
These values are stored in the regulatory database.
There are self managed devices which can't maintain these
values on their own. Add API to allow self managed regulatory devices
to query the regulatory database for high band wmm rule.

Signed-off-by: Haim Dreyfuss <haim.dreyfuss@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
[johannes: fix documentation]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
net/wireless/reg.c

index 4341508bc6a465a6aac77930cc3e0fbdf9a61117..bfe174896fcfc80b3322063de96f3aafcc8208e3 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014 Intel Mobile Communications GmbH
  * Copyright 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -4657,6 +4658,33 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
  */
 const char *reg_initiator_name(enum nl80211_reg_initiator initiator);
 
+/**
+ * DOC: Internal regulatory db functions
+ *
+ */
+
+/**
+ * reg_query_regdb_wmm -  Query internal regulatory db for wmm rule
+ * Regulatory self-managed driver can use it to proactively
+ *
+ * @alpha2: the ISO/IEC 3166 alpha2 wmm rule to be queried.
+ * @freq: the freqency(in MHz) to be queried.
+ * @ptr: pointer where the regdb wmm data is to be stored (or %NULL if
+ *     irrelevant). This can be used later for deduplication.
+ * @rule: pointer to store the wmm rule from the regulatory db.
+ *
+ * Self-managed wireless drivers can use this function to  query
+ * the internal regulatory database to check whether the given
+ * ISO/IEC 3166 alpha2 country and freq have wmm rule limitations.
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENODATA.
+ *
+ * Return: 0 on success. -ENODATA.
+ */
+int reg_query_regdb_wmm(char *alpha2, int freq, u32 *ptr,
+                       struct ieee80211_wmm_rule *rule);
+
 /*
  * callbacks for asynchronous cfg80211 methods, notification
  * functions and BSS handling helpers
index e352a0d1c4381e6901a1bde27e07d37873c28f4a..16c7e4ef58207cc781b80ef9bb3242ead81001a0 100644 (file)
@@ -878,6 +878,60 @@ static void set_wmm_rule(struct ieee80211_wmm_rule *rule,
        }
 }
 
+static int __regdb_query_wmm(const struct fwdb_header *db,
+                            const struct fwdb_country *country, int freq,
+                            u32 *dbptr, struct ieee80211_wmm_rule *rule)
+{
+       unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
+       struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
+       int i;
+
+       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;
+
+               if (rrule->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 (dbptr)
+                               *dbptr = wmm_ptr;
+                       return 0;
+               }
+       }
+
+       return -ENODATA;
+}
+
+int reg_query_regdb_wmm(char *alpha2, int freq, u32 *dbptr,
+                       struct ieee80211_wmm_rule *rule)
+{
+       const struct fwdb_header *hdr = regdb;
+       const struct fwdb_country *country;
+
+       if (IS_ERR(regdb))
+               return PTR_ERR(regdb);
+
+       country = &hdr->country[0];
+       while (country->coll_ptr) {
+               if (alpha2_equal(alpha2, country->alpha2))
+                       return __regdb_query_wmm(regdb, country, freq, dbptr,
+                                                rule);
+
+               country++;
+       }
+
+       return -ENODATA;
+}
+EXPORT_SYMBOL(reg_query_regdb_wmm);
+
 struct wmm_ptrs {
        struct ieee80211_wmm_rule *rule;
        u32 ptr;