From ea08eeccae9297f7aabd2ef7f0c2517ac4549acc Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:18:26 +0000
Subject: [PATCH] write in 30M
---
kernel/net/wireless/reg.c | 524 ++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 401 insertions(+), 123 deletions(-)
diff --git a/kernel/net/wireless/reg.c b/kernel/net/wireless/reg.c
index c7825b9..9029726 100644
--- a/kernel/net/wireless/reg.c
+++ b/kernel/net/wireless/reg.c
@@ -5,7 +5,7 @@
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2017 Intel Deutschland GmbH
- * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018 - 2019 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -131,7 +131,8 @@
/* Used to track the userspace process controlling the indoor setting */
static u32 reg_is_indoor_portid;
-static void restore_regulatory_settings(bool reset_user);
+static void restore_regulatory_settings(bool reset_user, bool cached);
+static void print_regdomain(const struct ieee80211_regdomain *rd);
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{
@@ -263,6 +264,7 @@
static char *ieee80211_regdom = "00";
static char user_alpha2[2];
+static const struct ieee80211_regdomain *cfg80211_user_regdom;
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
@@ -425,14 +427,10 @@
reg_copy_regd(const struct ieee80211_regdomain *src_regd)
{
struct ieee80211_regdomain *regd;
- int size_of_regd;
unsigned int i;
- size_of_regd =
- sizeof(struct ieee80211_regdomain) +
- src_regd->n_reg_rules * sizeof(struct ieee80211_reg_rule);
-
- regd = kzalloc(size_of_regd, GFP_KERNEL);
+ regd = kzalloc(struct_size(regd, reg_rules, src_regd->n_reg_rules),
+ GFP_KERNEL);
if (!regd)
return ERR_PTR(-ENOMEM);
@@ -443,6 +441,15 @@
sizeof(struct ieee80211_reg_rule));
return regd;
+}
+
+static void cfg80211_save_user_regdom(const struct ieee80211_regdomain *rd)
+{
+ ASSERT_RTNL();
+
+ if (!IS_ERR(cfg80211_user_regdom))
+ kfree(cfg80211_user_regdom);
+ cfg80211_user_regdom = reg_copy_regd(rd);
}
struct reg_regdb_apply_request {
@@ -510,7 +517,7 @@
pr_debug("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
rtnl_lock();
reg_crda_timeouts++;
- restore_regulatory_settings(true);
+ restore_regulatory_settings(true, false);
rtnl_unlock();
}
@@ -780,6 +787,8 @@
return 0;
}
+MODULE_FIRMWARE("regulatory.db.p7s");
+
static bool regdb_has_valid_signature(const u8 *data, unsigned int size)
{
const struct firmware *sig;
@@ -937,12 +946,10 @@
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
struct ieee80211_regdomain *regdom;
- unsigned int size_of_regd, i;
+ unsigned int i;
- size_of_regd = sizeof(struct ieee80211_regdomain) +
- coll->n_rules * sizeof(struct ieee80211_reg_rule);
-
- regdom = kzalloc(size_of_regd, GFP_KERNEL);
+ regdom = kzalloc(struct_size(regdom, reg_rules, coll->n_rules),
+ GFP_KERNEL);
if (!regdom)
return -ENOMEM;
@@ -1024,8 +1031,13 @@
}
rtnl_lock();
- if (WARN_ON(regdb && !IS_ERR(regdb))) {
- /* just restore and free new db */
+ if (regdb && !IS_ERR(regdb)) {
+ /* negative case - a bug
+ * positive case - can happen due to race in case of multiple cb's in
+ * queue, due to usage of asynchronous callback
+ *
+ * Either case, just restore and free new db.
+ */
} else if (set_error) {
regdb = ERR_PTR(set_error);
} else if (fw) {
@@ -1039,7 +1051,7 @@
}
if (restore)
- restore_regulatory_settings(true);
+ restore_regulatory_settings(true, false);
rtnl_unlock();
@@ -1048,8 +1060,12 @@
release_firmware(fw);
}
+MODULE_FIRMWARE("regulatory.db");
+
static int query_regdb_file(const char *alpha2)
{
+ int err;
+
ASSERT_RTNL();
if (regdb)
@@ -1059,9 +1075,13 @@
if (!alpha2)
return -ENOMEM;
- return request_firmware_nowait(THIS_MODULE, true, "regulatory.db",
- ®_pdev->dev, GFP_KERNEL,
- (void *)alpha2, regdb_fw_cb);
+ err = request_firmware_nowait(THIS_MODULE, true, "regulatory.db",
+ ®_pdev->dev, GFP_KERNEL,
+ (void *)alpha2, regdb_fw_cb);
+ if (err)
+ kfree(alpha2);
+
+ return err;
}
int reg_reload_regdb(void)
@@ -1473,7 +1493,7 @@
regdom_intersect(const struct ieee80211_regdomain *rd1,
const struct ieee80211_regdomain *rd2)
{
- int r, size_of_regd;
+ int r;
unsigned int x, y;
unsigned int num_rules = 0;
const struct ieee80211_reg_rule *rule1, *rule2;
@@ -1504,10 +1524,7 @@
if (!num_rules)
return NULL;
- size_of_regd = sizeof(struct ieee80211_regdomain) +
- num_rules * sizeof(struct ieee80211_reg_rule);
-
- rd = kzalloc(size_of_regd, GFP_KERNEL);
+ rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
if (!rd)
return NULL;
@@ -1562,6 +1579,8 @@
channel_flags |= IEEE80211_CHAN_NO_80MHZ;
if (rd_flags & NL80211_RRF_NO_160MHZ)
channel_flags |= IEEE80211_CHAN_NO_160MHZ;
+ if (rd_flags & NL80211_RRF_NO_HE)
+ channel_flags |= IEEE80211_CHAN_NO_HE;
return channel_flags;
}
@@ -1585,7 +1604,7 @@
/*
* We only need to know if one frequency rule was
- * was in center_freq's band, that's enough, so lets
+ * in center_freq's band, that's enough, so let's
* not overwrite it once found
*/
if (!band_rule_found)
@@ -1607,10 +1626,12 @@
__freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
{
const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
- const struct ieee80211_reg_rule *reg_rule = NULL;
+ const u32 bws[] = {0, 1, 2, 4, 5, 8, 10, 16, 20};
+ const struct ieee80211_reg_rule *reg_rule;
+ int i = ARRAY_SIZE(bws) - 1;
u32 bw;
- for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
+ for (bw = MHZ_TO_KHZ(bws[i]); bw >= min_bw; bw = MHZ_TO_KHZ(bws[i--])) {
reg_rule = freq_reg_info_regd(center_freq, regd, bw);
if (!IS_ERR(reg_rule))
return reg_rule;
@@ -1622,7 +1643,9 @@
const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
u32 center_freq)
{
- return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(20));
+ u32 min_bw = center_freq < MHZ_TO_KHZ(1000) ? 1 : 20;
+
+ return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(min_bw));
}
EXPORT_SYMBOL(freq_reg_info);
@@ -1649,88 +1672,92 @@
const struct ieee80211_channel *chan)
{
const struct ieee80211_freq_range *freq_range = NULL;
- u32 max_bandwidth_khz, bw_flags = 0;
+ u32 max_bandwidth_khz, center_freq_khz, bw_flags = 0;
+ bool is_s1g = chan->band == NL80211_BAND_S1GHZ;
freq_range = ®_rule->freq_range;
max_bandwidth_khz = freq_range->max_bandwidth_khz;
+ center_freq_khz = ieee80211_channel_to_khz(chan);
/* Check if auto calculation requested */
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
/* If we get a reg_rule we can assume that at least 5Mhz fit */
if (!cfg80211_does_bw_fit_range(freq_range,
- MHZ_TO_KHZ(chan->center_freq),
+ center_freq_khz,
MHZ_TO_KHZ(10)))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (!cfg80211_does_bw_fit_range(freq_range,
- MHZ_TO_KHZ(chan->center_freq),
+ center_freq_khz,
MHZ_TO_KHZ(20)))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
- if (max_bandwidth_khz < MHZ_TO_KHZ(10))
- bw_flags |= IEEE80211_CHAN_NO_10MHZ;
- if (max_bandwidth_khz < MHZ_TO_KHZ(20))
- bw_flags |= IEEE80211_CHAN_NO_20MHZ;
- if (max_bandwidth_khz < MHZ_TO_KHZ(40))
- bw_flags |= IEEE80211_CHAN_NO_HT40;
- if (max_bandwidth_khz < MHZ_TO_KHZ(80))
- bw_flags |= IEEE80211_CHAN_NO_80MHZ;
- if (max_bandwidth_khz < MHZ_TO_KHZ(160))
- bw_flags |= IEEE80211_CHAN_NO_160MHZ;
+ if (is_s1g) {
+ /* S1G is strict about non overlapping channels. We can
+ * calculate which bandwidth is allowed per channel by finding
+ * the largest bandwidth which cleanly divides the freq_range.
+ */
+ int edge_offset;
+ int ch_bw = max_bandwidth_khz;
+
+ while (ch_bw) {
+ edge_offset = (center_freq_khz - ch_bw / 2) -
+ freq_range->start_freq_khz;
+ if (edge_offset % ch_bw == 0) {
+ switch (KHZ_TO_MHZ(ch_bw)) {
+ case 1:
+ bw_flags |= IEEE80211_CHAN_1MHZ;
+ break;
+ case 2:
+ bw_flags |= IEEE80211_CHAN_2MHZ;
+ break;
+ case 4:
+ bw_flags |= IEEE80211_CHAN_4MHZ;
+ break;
+ case 8:
+ bw_flags |= IEEE80211_CHAN_8MHZ;
+ break;
+ case 16:
+ bw_flags |= IEEE80211_CHAN_16MHZ;
+ break;
+ default:
+ /* If we got here, no bandwidths fit on
+ * this frequency, ie. band edge.
+ */
+ bw_flags |= IEEE80211_CHAN_DISABLED;
+ break;
+ }
+ break;
+ }
+ ch_bw /= 2;
+ }
+ } else {
+ if (max_bandwidth_khz < MHZ_TO_KHZ(10))
+ bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(20))
+ bw_flags |= IEEE80211_CHAN_NO_20MHZ;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(40))
+ bw_flags |= IEEE80211_CHAN_NO_HT40;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(80))
+ bw_flags |= IEEE80211_CHAN_NO_80MHZ;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(160))
+ bw_flags |= IEEE80211_CHAN_NO_160MHZ;
+ }
return bw_flags;
}
-/*
- * Note that right now we assume the desired channel bandwidth
- * is always 20 MHz for each individual channel (HT40 uses 20 MHz
- * per channel, the primary and the extension channel).
- */
-static void handle_channel(struct wiphy *wiphy,
- enum nl80211_reg_initiator initiator,
- struct ieee80211_channel *chan)
+static void handle_channel_single_rule(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator,
+ struct ieee80211_channel *chan,
+ u32 flags,
+ struct regulatory_request *lr,
+ struct wiphy *request_wiphy,
+ const struct ieee80211_reg_rule *reg_rule)
{
- u32 flags, bw_flags = 0;
- const struct ieee80211_reg_rule *reg_rule = NULL;
+ u32 bw_flags = 0;
const struct ieee80211_power_rule *power_rule = NULL;
- struct wiphy *request_wiphy = NULL;
- struct regulatory_request *lr = get_last_request();
const struct ieee80211_regdomain *regd;
-
- request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
-
- flags = chan->orig_flags;
-
- reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
- if (IS_ERR(reg_rule)) {
- /*
- * We will disable all channels that do not match our
- * received regulatory rule unless the hint is coming
- * from a Country IE and the Country IE had no information
- * about a band. The IEEE 802.11 spec allows for an AP
- * to send only a subset of the regulatory rules allowed,
- * so an AP in the US that only supports 2.4 GHz may only send
- * a country IE with information for the 2.4 GHz band
- * while 5 GHz is still supported.
- */
- if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
- PTR_ERR(reg_rule) == -ERANGE)
- return;
-
- if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
- request_wiphy && request_wiphy == wiphy &&
- request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
- pr_debug("Disabling freq %d MHz for good\n",
- chan->center_freq);
- chan->orig_flags |= IEEE80211_CHAN_DISABLED;
- chan->flags = chan->orig_flags;
- } else {
- pr_debug("Disabling freq %d MHz\n",
- chan->center_freq);
- chan->flags |= IEEE80211_CHAN_DISABLED;
- }
- return;
- }
regd = reg_get_regdomain(wiphy);
@@ -1791,6 +1818,204 @@
chan->max_reg_power);
} else
chan->max_power = chan->max_reg_power;
+}
+
+static void handle_channel_adjacent_rules(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator,
+ struct ieee80211_channel *chan,
+ u32 flags,
+ struct regulatory_request *lr,
+ struct wiphy *request_wiphy,
+ const struct ieee80211_reg_rule *rrule1,
+ const struct ieee80211_reg_rule *rrule2,
+ struct ieee80211_freq_range *comb_range)
+{
+ u32 bw_flags1 = 0;
+ u32 bw_flags2 = 0;
+ const struct ieee80211_power_rule *power_rule1 = NULL;
+ const struct ieee80211_power_rule *power_rule2 = NULL;
+ const struct ieee80211_regdomain *regd;
+
+ regd = reg_get_regdomain(wiphy);
+
+ power_rule1 = &rrule1->power_rule;
+ power_rule2 = &rrule2->power_rule;
+ bw_flags1 = reg_rule_to_chan_bw_flags(regd, rrule1, chan);
+ bw_flags2 = reg_rule_to_chan_bw_flags(regd, rrule2, chan);
+
+ if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+ request_wiphy && request_wiphy == wiphy &&
+ request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
+ /* This guarantees the driver's requested regulatory domain
+ * will always be used as a base for further regulatory
+ * settings
+ */
+ chan->flags =
+ map_regdom_flags(rrule1->flags) |
+ map_regdom_flags(rrule2->flags) |
+ bw_flags1 |
+ bw_flags2;
+ chan->orig_flags = chan->flags;
+ chan->max_antenna_gain =
+ min_t(int, MBI_TO_DBI(power_rule1->max_antenna_gain),
+ MBI_TO_DBI(power_rule2->max_antenna_gain));
+ chan->orig_mag = chan->max_antenna_gain;
+ chan->max_reg_power =
+ min_t(int, MBM_TO_DBM(power_rule1->max_eirp),
+ MBM_TO_DBM(power_rule2->max_eirp));
+ chan->max_power = chan->max_reg_power;
+ chan->orig_mpwr = chan->max_reg_power;
+
+ if (chan->flags & IEEE80211_CHAN_RADAR) {
+ chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
+ if (rrule1->dfs_cac_ms || rrule2->dfs_cac_ms)
+ chan->dfs_cac_ms = max_t(unsigned int,
+ rrule1->dfs_cac_ms,
+ rrule2->dfs_cac_ms);
+ }
+
+ return;
+ }
+
+ chan->dfs_state = NL80211_DFS_USABLE;
+ chan->dfs_state_entered = jiffies;
+
+ chan->beacon_found = false;
+ chan->flags = flags | bw_flags1 | bw_flags2 |
+ map_regdom_flags(rrule1->flags) |
+ map_regdom_flags(rrule2->flags);
+
+ /* reg_rule_to_chan_bw_flags may forbids 10 and forbids 20 MHz
+ * (otherwise no adj. rule case), recheck therefore
+ */
+ if (cfg80211_does_bw_fit_range(comb_range,
+ ieee80211_channel_to_khz(chan),
+ MHZ_TO_KHZ(10)))
+ chan->flags &= ~IEEE80211_CHAN_NO_10MHZ;
+ if (cfg80211_does_bw_fit_range(comb_range,
+ ieee80211_channel_to_khz(chan),
+ MHZ_TO_KHZ(20)))
+ chan->flags &= ~IEEE80211_CHAN_NO_20MHZ;
+
+ chan->max_antenna_gain =
+ min_t(int, chan->orig_mag,
+ min_t(int,
+ MBI_TO_DBI(power_rule1->max_antenna_gain),
+ MBI_TO_DBI(power_rule2->max_antenna_gain)));
+ chan->max_reg_power = min_t(int,
+ MBM_TO_DBM(power_rule1->max_eirp),
+ MBM_TO_DBM(power_rule2->max_eirp));
+
+ if (chan->flags & IEEE80211_CHAN_RADAR) {
+ if (rrule1->dfs_cac_ms || rrule2->dfs_cac_ms)
+ chan->dfs_cac_ms = max_t(unsigned int,
+ rrule1->dfs_cac_ms,
+ rrule2->dfs_cac_ms);
+ else
+ chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
+ }
+
+ if (chan->orig_mpwr) {
+ /* Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
+ * will always follow the passed country IE power settings.
+ */
+ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+ wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER)
+ chan->max_power = chan->max_reg_power;
+ else
+ chan->max_power = min(chan->orig_mpwr,
+ chan->max_reg_power);
+ } else {
+ chan->max_power = chan->max_reg_power;
+ }
+}
+
+/* Note that right now we assume the desired channel bandwidth
+ * is always 20 MHz for each individual channel (HT40 uses 20 MHz
+ * per channel, the primary and the extension channel).
+ */
+static void handle_channel(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator,
+ struct ieee80211_channel *chan)
+{
+ const u32 orig_chan_freq = ieee80211_channel_to_khz(chan);
+ struct regulatory_request *lr = get_last_request();
+ struct wiphy *request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
+ const struct ieee80211_reg_rule *rrule = NULL;
+ const struct ieee80211_reg_rule *rrule1 = NULL;
+ const struct ieee80211_reg_rule *rrule2 = NULL;
+
+ u32 flags = chan->orig_flags;
+
+ rrule = freq_reg_info(wiphy, orig_chan_freq);
+ if (IS_ERR(rrule)) {
+ /* check for adjacent match, therefore get rules for
+ * chan - 20 MHz and chan + 20 MHz and test
+ * if reg rules are adjacent
+ */
+ rrule1 = freq_reg_info(wiphy,
+ orig_chan_freq - MHZ_TO_KHZ(20));
+ rrule2 = freq_reg_info(wiphy,
+ orig_chan_freq + MHZ_TO_KHZ(20));
+ if (!IS_ERR(rrule1) && !IS_ERR(rrule2)) {
+ struct ieee80211_freq_range comb_range;
+
+ if (rrule1->freq_range.end_freq_khz !=
+ rrule2->freq_range.start_freq_khz)
+ goto disable_chan;
+
+ comb_range.start_freq_khz =
+ rrule1->freq_range.start_freq_khz;
+ comb_range.end_freq_khz =
+ rrule2->freq_range.end_freq_khz;
+ comb_range.max_bandwidth_khz =
+ min_t(u32,
+ rrule1->freq_range.max_bandwidth_khz,
+ rrule2->freq_range.max_bandwidth_khz);
+
+ if (!cfg80211_does_bw_fit_range(&comb_range,
+ orig_chan_freq,
+ MHZ_TO_KHZ(20)))
+ goto disable_chan;
+
+ handle_channel_adjacent_rules(wiphy, initiator, chan,
+ flags, lr, request_wiphy,
+ rrule1, rrule2,
+ &comb_range);
+ return;
+ }
+
+disable_chan:
+ /* We will disable all channels that do not match our
+ * received regulatory rule unless the hint is coming
+ * from a Country IE and the Country IE had no information
+ * about a band. The IEEE 802.11 spec allows for an AP
+ * to send only a subset of the regulatory rules allowed,
+ * so an AP in the US that only supports 2.4 GHz may only send
+ * a country IE with information for the 2.4 GHz band
+ * while 5 GHz is still supported.
+ */
+ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+ PTR_ERR(rrule) == -ERANGE)
+ return;
+
+ if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+ request_wiphy && request_wiphy == wiphy &&
+ request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
+ pr_debug("Disabling freq %d.%03d MHz for good\n",
+ chan->center_freq, chan->freq_offset);
+ chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+ chan->flags = chan->orig_flags;
+ } else {
+ pr_debug("Disabling freq %d.%03d MHz\n",
+ chan->center_freq, chan->freq_offset);
+ chan->flags |= IEEE80211_CHAN_DISABLED;
+ }
+ return;
+ }
+
+ handle_channel_single_rule(wiphy, initiator, chan, flags, lr,
+ request_wiphy, rrule);
}
static void handle_band(struct wiphy *wiphy,
@@ -1927,7 +2152,7 @@
sband = wiphy->bands[reg_beacon->chan.band];
chan = &sband->channels[chan_idx];
- if (likely(chan->center_freq != reg_beacon->chan.center_freq))
+ if (likely(!ieee80211_channel_equal(chan, ®_beacon->chan)))
return;
if (chan->beacon_found)
@@ -2260,18 +2485,18 @@
u32 bw_flags = 0;
const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
- u32 bw;
+ u32 bw, center_freq_khz;
+ center_freq_khz = ieee80211_channel_to_khz(chan);
for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
- reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq),
- regd, bw);
+ reg_rule = freq_reg_info_regd(center_freq_khz, regd, bw);
if (!IS_ERR(reg_rule))
break;
}
if (IS_ERR_OR_NULL(reg_rule)) {
- pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
- chan->center_freq);
+ pr_debug("Disabling freq %d.%03d MHz as custom regd has no rule that fits it\n",
+ chan->center_freq, chan->freq_offset);
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
chan->flags |= IEEE80211_CHAN_DISABLED;
} else {
@@ -2374,7 +2599,7 @@
/**
* reg_process_hint_core - process core regulatory requests
- * @pending_request: a pending core regulatory request
+ * @core_request: a pending core regulatory request
*
* The wireless subsystem can use this function to process
* a regulatory request issued by the regulatory core.
@@ -2483,6 +2708,7 @@
/**
* reg_process_hint_driver - process driver regulatory requests
+ * @wiphy: the wireless device for the regulatory request
* @driver_request: a pending driver regulatory request
*
* The wireless subsystem can use this function to process
@@ -2583,6 +2809,7 @@
/**
* reg_process_hint_country_ie - process regulatory requests from country IEs
+ * @wiphy: the wireless device for the regulatory request
* @country_ie_request: a regulatory request from a country IE
*
* The wireless subsystem can use this function to process
@@ -2770,9 +2997,7 @@
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
wiphy = &rdev->wiphy;
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
- request->initiator == NL80211_REGDOM_SET_BY_USER &&
- request->user_reg_hint_type ==
- NL80211_USER_REG_HINT_CELL_BASE)
+ request->initiator == NL80211_REGDOM_SET_BY_USER)
reg_call_notifier(wiphy, request);
}
}
@@ -3160,10 +3385,10 @@
* - send a user regulatory hint if applicable
*
* Device drivers that send a regulatory hint for a specific country
- * keep their own regulatory domain on wiphy->regd so that does does
+ * keep their own regulatory domain on wiphy->regd so that does
* not need to be remembered.
*/
-static void restore_regulatory_settings(bool reset_user)
+static void restore_regulatory_settings(bool reset_user, bool cached)
{
char alpha2[2];
char world_alpha2[2];
@@ -3222,15 +3447,41 @@
restore_custom_reg_settings(&rdev->wiphy);
}
- regulatory_hint_core(world_alpha2);
+ if (cached && (!is_an_alpha2(alpha2) ||
+ !IS_ERR_OR_NULL(cfg80211_user_regdom))) {
+ reset_regdomains(false, cfg80211_world_regdom);
+ update_all_wiphy_regulatory(NL80211_REGDOM_SET_BY_CORE);
+ print_regdomain(get_cfg80211_regdom());
+ nl80211_send_reg_change_event(&core_request_world);
+ reg_set_request_processed();
- /*
- * This restores the ieee80211_regdom module parameter
- * preference or the last user requested regulatory
- * settings, user regulatory settings takes precedence.
- */
- if (is_an_alpha2(alpha2))
- regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER);
+ if (is_an_alpha2(alpha2) &&
+ !regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER)) {
+ struct regulatory_request *ureq;
+
+ spin_lock(®_requests_lock);
+ ureq = list_last_entry(®_requests_list,
+ struct regulatory_request,
+ list);
+ list_del(&ureq->list);
+ spin_unlock(®_requests_lock);
+
+ notify_self_managed_wiphys(ureq);
+ reg_update_last_request(ureq);
+ set_regdom(reg_copy_regd(cfg80211_user_regdom),
+ REGD_SOURCE_CACHED);
+ }
+ } else {
+ regulatory_hint_core(world_alpha2);
+
+ /*
+ * This restores the ieee80211_regdom module parameter
+ * preference or the last user requested regulatory
+ * settings, user regulatory settings takes precedence.
+ */
+ if (is_an_alpha2(alpha2))
+ regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER);
+ }
spin_lock(®_requests_lock);
list_splice_tail_init(&tmp_reg_req_list, ®_requests_list);
@@ -3290,10 +3541,10 @@
}
pr_debug("All devices are disconnected, going to restore regulatory settings\n");
- restore_regulatory_settings(false);
+ restore_regulatory_settings(false, true);
}
-static bool freq_is_chan_12_13_14(u16 freq)
+static bool freq_is_chan_12_13_14(u32 freq)
{
if (freq == ieee80211_channel_to_frequency(12, NL80211_BAND_2GHZ) ||
freq == ieee80211_channel_to_frequency(13, NL80211_BAND_2GHZ) ||
@@ -3307,8 +3558,8 @@
struct reg_beacon *pending_beacon;
list_for_each_entry(pending_beacon, ®_pending_beacons, list)
- if (beacon_chan->center_freq ==
- pending_beacon->chan.center_freq)
+ if (ieee80211_channel_equal(beacon_chan,
+ &pending_beacon->chan))
return true;
return false;
}
@@ -3337,9 +3588,10 @@
if (!reg_beacon)
return -ENOMEM;
- pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
- beacon_chan->center_freq,
- ieee80211_frequency_to_channel(beacon_chan->center_freq),
+ pr_debug("Found new beacon on frequency: %d.%03d MHz (Ch %d) on %s\n",
+ beacon_chan->center_freq, beacon_chan->freq_offset,
+ ieee80211_freq_khz_to_channel(
+ ieee80211_channel_to_khz(beacon_chan)),
wiphy_name(wiphy));
memcpy(®_beacon->chan, beacon_chan,
@@ -3607,6 +3859,9 @@
bool user_reset = false;
int r;
+ if (IS_ERR_OR_NULL(rd))
+ return -ENODATA;
+
if (!reg_is_valid_request(rd->alpha2)) {
kfree(rd);
return -EINVAL;
@@ -3623,6 +3878,7 @@
r = reg_set_rd_core(rd);
break;
case NL80211_REGDOM_SET_BY_USER:
+ cfg80211_save_user_regdom(rd);
r = reg_set_rd_user(rd, lr);
user_reset = true;
break;
@@ -3645,7 +3901,7 @@
break;
default:
/* Back to world regulatory in case of errors */
- restore_regulatory_settings(user_reset);
+ restore_regulatory_settings(user_reset, false);
}
kfree(rd);
@@ -3744,10 +4000,9 @@
/*
* The last request may have been received before this
* registration call. Call the driver notifier if
- * initiator is USER and user type is CELL_BASE.
+ * initiator is USER.
*/
- if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
- lr->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE)
+ if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
reg_call_notifier(wiphy, lr);
}
@@ -3756,6 +4011,7 @@
wiphy_update_regulatory(wiphy, lr->initiator);
wiphy_all_share_dfs_chan_state(wiphy);
+ reg_process_self_managed_hints();
}
void wiphy_regulatory_deregister(struct wiphy *wiphy)
@@ -3782,8 +4038,9 @@
}
/*
- * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for
- * UNII band definitions
+ * See FCC notices for UNII band definitions
+ * 5GHz: https://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii
+ * 6GHz: https://www.fcc.gov/document/fcc-proposes-more-spectrum-unlicensed-use-0
*/
int cfg80211_get_unii(int freq)
{
@@ -3806,6 +4063,22 @@
/* UNII-3 */
if (freq > 5725 && freq <= 5825)
return 4;
+
+ /* UNII-5 */
+ if (freq > 5925 && freq <= 6425)
+ return 5;
+
+ /* UNII-6 */
+ if (freq > 6425 && freq <= 6525)
+ return 6;
+
+ /* UNII-7 */
+ if (freq > 6525 && freq <= 6875)
+ return 7;
+
+ /* UNII-8 */
+ if (freq > 6875 && freq <= 7125)
+ return 8;
return -EINVAL;
}
@@ -3842,6 +4115,7 @@
return pre_cac_allowed;
}
+EXPORT_SYMBOL(regulatory_pre_cac_allowed);
static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev)
{
@@ -3911,8 +4185,10 @@
return -EINVAL;
err = load_builtin_regdb_keys();
- if (err)
+ if (err) {
+ platform_device_unregister(reg_pdev);
return err;
+ }
/* We always try to get an update for the static regdomain */
err = regulatory_hint_core(cfg80211_world_regdom->alpha2);
@@ -4002,6 +4278,8 @@
if (!IS_ERR_OR_NULL(regdb))
kfree(regdb);
+ if (!IS_ERR_OR_NULL(cfg80211_user_regdom))
+ kfree(cfg80211_user_regdom);
free_regdb_keyring();
}
--
Gitblit v1.6.2