6 GHz introduces various power modes of operation. Currently, based
on the power mode, channel's Power Spectral Density (PSD) value,
Regulatory power value, as well as channel disabled flag can change.
For single interface, current implementation works just fine. But for
multi-interfaces, for example AP-STA concurrency, two different channel
context needs to be maintained. This is because, STA power mode also
depends on the AP's power mode it is going to associate with. Hence,
PSD value, regulatory power value and channel disabled flag might vary.
In this case, same channel context cannot be used for both AP and STA.
Therefore, to support multiple channel space for each power mode, the
6 GHz channels needs a separate storage space in data structure
ieee80211_supported_band. Because of this, the existing APIs to get the
channel/frequency from frequency/channel will not work for 6 GHz band.
Add support to store all possible 6 GHz channel pools according to the
power mode as well as add API support for getting channel/frequency info
from the new struct ieee80211_6ghz_channel.
Why different channel pools and not array of varying member in the same channel?:
--------------------------------------------------------------------------------
Let (A) be the implementation of having separate channel
pools based on power mode:
[...]
struct ieee80211_6ghz_channel {
struct ieee80211_channel *channels;
int num_channels;
};
struct ieee80211_supported_band {
/* Other members */
struct ieee80211_6ghz_channel[MAX_POWER_MODE];
/* Other members */
}
[...]
After updating the regulatory rules, in case of (A), all the channels
stored in the struct ieee80211_6ghz_channel will have its desired
value based on the power mode.
Let the alternate implementation be (B) which maintains array of such variables
which can vary based on power mode:
[...]
struct ieee80211_channel {
/* Other members*/
u32 flags[MAX_POWER_MODE];
int max_reg_power[MAX_POWER_MODE];
s8 psd[MAX_POWER_MODE];
/* Other members*/
}
[...]
After updating the regulatory rules in case of (B), for 6 GHz sband channels,
all the values based on the power mode are stored in array for each channel.
During 6 GHz interface bring up, power mode will be known and in
method (A), accordingly the corresponding ieee80211_channel will
be selected from the pool. With this, all its members are having
the desired value stored in them just like any other ieee80211_channel.
For method B, ieee80211_channel will be selected, but its members are
having array of possible values. Even though configured power mode is
known, still, the members dont have the exact required value.
Now, as per the code flow, a pointer for the configured channel
is stored in chandef and thats parsed to extract the required information
like flags, power, frequency information, etc.
If current implementation (A) is followed then the subsequent functions
using the set ieee80211_channel will need not be modified since the exact
required values based on the power mode is applied to its members
already and everything will fall in its place.
But if method (B) is used, then in all subsequent functions using the
configured ieee80211_channel, condition check on power mode and then
accordingly using the appropriate values from the array needs to be
implemented at each single place.
Hence, method (B) would require code changes at a lot of places leading to
more possiblity of errors to come in.
Also, currently only flags, power and PSD value is changing based on
power mode. If later on any new member or exisiting member is varyed
then with method (A), less code changes will be required since altering
the ieee80211_channel struct would do. But if method (B) is used then
apart from altering ieee80211_channel struct, all functions using
ieee80211_channels needs to be modified accordingly to fecth this new varying
member from correct power mode index.
Aditya Kumar Singh (8):
wifi: mac80211: rework on 6 GHz power type definition
wifi: mac80211: add combined power type definition for 6 GHz
wifi: cfg80211: add NL command to set 6 GHz power mode
wifi: mac80211: add support for 6 GHz channels and regulatory
wifi: cfg80211: rework nl80211_parse_chandef for 6 GHz
wifi: cfg80211: save 6 GHz power mode of the regulatory rules
wifi: cfg80211: fix chandef identical logic for 6 GHz chandefs
wifi: mac80211: use proper API to fetch 6 GHz channel
Wen Gong (1):
wifi: cfg80211: save Power Spectral Density (PSD) of the regulatory
rule
---
v3: - resolved sta mode association issue and AP-STA concurrency bring up
* added patch 8 to handle concurrent AP-STA bring up on 6 GHz
* added patch 9 to handle bss assoc in 6 GHz
- no other changes in patches 1-7 from v2.
v2: addressed v1 review comments.
* moved variables to link specific w.r.t MLO
* rebased on latest ToT
* added "wifi:" tag in commit title.
---
include/linux/ieee80211.h | 33 +++---
include/net/cfg80211.h | 111 ++++++++++++++++++--
include/net/regulatory.h | 2 +
include/uapi/linux/nl80211.h | 61 +++++++++++
net/mac80211/cfg.c | 41 ++++++++
net/mac80211/ieee80211_i.h | 3 +
net/mac80211/mlme.c | 14 ++-
net/mac80211/scan.c | 15 ++-
net/mac80211/util.c | 40 ++++++-
net/wireless/ap.c | 2 +
net/wireless/nl80211.c | 196 ++++++++++++++++++++++++++++++-----
net/wireless/nl80211.h | 3 +-
net/wireless/pmsr.c | 8 +-
net/wireless/rdev-ops.h | 21 ++++
net/wireless/reg.c | 61 +++++++++--
net/wireless/sme.c | 2 +
net/wireless/trace.h | 34 ++++++
net/wireless/util.c | 87 ++++++++++++++++
18 files changed, 671 insertions(+), 63 deletions(-)
base-commit: 4eca8cbf7ba83c3291b5841905ce64584036b1ff
--
2.17.1
6 GHz regulatory domain introduces different modes for 6 GHz AP
operation - Low Power Indoor(LPI), Standard Power(SP) and Very Low
Power(VLP). 6 GHz non-AP STAs could be operated as either Regular
or Subordinate clients. We have separate definitions of AP and
client.
However, IEEE80211_REG_UNSET_* is not a defined power type.
Also due to IEEE80211_REG_UNSET_*, it is difficult to use
_MAX to size arrays.
Move IEEE80211_REG_UNSET_* to last after *_MAX for both AP and
client power mode enums.
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
include/linux/ieee80211.h | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 2463bdd2a382..24d4b5ef3de2 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2173,41 +2173,48 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
unsigned int max_vht_nss);
/**
- * enum ieee80211_ap_reg_power - regulatory power for a Access Point
+ * enum ieee80211_ap_reg_power - regulatory power for an Access Point
*
- * @IEEE80211_REG_UNSET_AP: Access Point has no regulatory power mode
* @IEEE80211_REG_LPI: Indoor Access Point
- * @IEEE80211_REG_SP: Standard power Access Point
- * @IEEE80211_REG_VLP: Very low power Access Point
- * @IEEE80211_REG_AP_POWER_AFTER_LAST: internal
+ * @IEEE80211_REG_SP: Standard Power Access Point
+ * @IEEE80211_REG_VLP: Very Low Power Access Point
+ * @__IEEE80211_REG_AP_POWER_AFTER_LAST: internal use
* @IEEE80211_REG_AP_POWER_MAX: maximum value
+ * @IEEE80211_REG_UNSET_AP: Access Point has no regulatory power
+ * mode.
*/
enum ieee80211_ap_reg_power {
- IEEE80211_REG_UNSET_AP,
IEEE80211_REG_LPI_AP,
IEEE80211_REG_SP_AP,
IEEE80211_REG_VLP_AP,
- IEEE80211_REG_AP_POWER_AFTER_LAST,
+
+ /* keep last */
+ __IEEE80211_REG_AP_POWER_AFTER_LAST,
IEEE80211_REG_AP_POWER_MAX =
- IEEE80211_REG_AP_POWER_AFTER_LAST - 1,
+ __IEEE80211_REG_AP_POWER_AFTER_LAST - 1,
+ /* always last in order to use _MAX to size arrays */
+ IEEE80211_REG_UNSET_AP = 0xFF,
};
/**
* enum ieee80211_client_reg_power - regulatory power for a client
*
- * @IEEE80211_REG_UNSET_CLIENT: Client has no regulatory power mode
* @IEEE80211_REG_DEFAULT_CLIENT: Default Client
* @IEEE80211_REG_SUBORDINATE_CLIENT: Subordinate Client
- * @IEEE80211_REG_CLIENT_POWER_AFTER_LAST: internal
+ * @__IEEE80211_REG_CLIENT_POWER_AFTER_LAST: internal use
* @IEEE80211_REG_CLIENT_POWER_MAX: maximum value
+ * @IEEE80211_REG_UNSET_CLIENT: Client has no regulatory power mode
*/
enum ieee80211_client_reg_power {
- IEEE80211_REG_UNSET_CLIENT,
IEEE80211_REG_DEFAULT_CLIENT,
IEEE80211_REG_SUBORDINATE_CLIENT,
- IEEE80211_REG_CLIENT_POWER_AFTER_LAST,
+
+ /* keep last */
+ __IEEE80211_REG_CLIENT_POWER_AFTER_LAST,
IEEE80211_REG_CLIENT_POWER_MAX =
- IEEE80211_REG_CLIENT_POWER_AFTER_LAST - 1,
+ __IEEE80211_REG_CLIENT_POWER_AFTER_LAST - 1,
+ /* always last in order to use _MAX to size arrays */
+ IEEE80211_REG_UNSET_CLIENT = 0XFF,
};
/* 802.11ax HE MAC capabilities */
--
2.17.1
From: Wen Gong <[email protected]>
6 GHz regulatory domains introduces Power Spectral Density (PSD).
The PSD value of the regulatory rule should be taken into effect
for the ieee80211_channels falling into that particular regulatory
rule. Save the values in the channel which has PSD value and add
nl80211 attributes accordingly to handle it.
Signed-off-by: Wen Gong <[email protected]>
Co-developed-by: Aditya Kumar Singh <[email protected]>
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
include/net/cfg80211.h | 5 +++++
include/net/regulatory.h | 1 +
include/uapi/linux/nl80211.h | 9 +++++++++
net/wireless/nl80211.c | 18 ++++++++++++++++++
net/wireless/reg.c | 17 +++++++++++++++++
5 files changed, 50 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7cebba1c4135..d64481d8d871 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -115,6 +115,8 @@ struct wiphy;
* This may be due to the driver or due to regulatory bandwidth
* restrictions.
* @IEEE80211_CHAN_NO_EHT: EHT operation is not permitted on this channel.
+ * @IEEE80211_CHAN_PSD: power spectral density (in dBm)
+ * on this channel
*/
enum ieee80211_channel_flags {
IEEE80211_CHAN_DISABLED = 1<<0,
@@ -138,6 +140,7 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_16MHZ = 1<<18,
IEEE80211_CHAN_NO_320MHZ = 1<<19,
IEEE80211_CHAN_NO_EHT = 1<<20,
+ IEEE80211_CHAN_PSD = 1<<21,
};
#define IEEE80211_CHAN_NO_HT40 \
@@ -171,6 +174,7 @@ enum ieee80211_channel_flags {
* on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
+ * @psd: power spectral density (in dBm)
*/
struct ieee80211_channel {
enum nl80211_band band;
@@ -187,6 +191,7 @@ struct ieee80211_channel {
enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered;
unsigned int dfs_cac_ms;
+ s8 psd;
};
/**
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index 896191f420d5..c2bf0b39fd1e 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -224,6 +224,7 @@ struct ieee80211_reg_rule {
u32 flags;
u32 dfs_cac_ms;
bool has_wmm;
+ s8 psd;
};
struct ieee80211_regdomain {
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9a0ac0363f1f..844d2000b4e1 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4167,6 +4167,8 @@ enum nl80211_wmm_rule {
* as the primary or any of the secondary channels isn't possible
* @NL80211_FREQUENCY_ATTR_NO_EHT: EHT operation is not allowed on this channel
* in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PSD: power spectral density (in dBm)
+ * is allowed on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -4205,6 +4207,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_16MHZ,
NL80211_FREQUENCY_ATTR_NO_320MHZ,
NL80211_FREQUENCY_ATTR_NO_EHT,
+ NL80211_FREQUENCY_ATTR_PSD,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -4305,6 +4308,8 @@ enum nl80211_reg_type {
* a given frequency range. The value is in mBm (100 * dBm).
* @NL80211_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
* If not present or 0 default CAC time will be used.
+ * @NL80211_ATTR_POWER_RULE_PSD: power spectral density (in dBm).
+ * This could be negative.
* @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
* currently defined
* @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
@@ -4322,6 +4327,8 @@ enum nl80211_reg_rule_attr {
NL80211_ATTR_DFS_CAC_TIME,
+ NL80211_ATTR_POWER_RULE_PSD,
+
/* keep last */
__NL80211_REG_RULE_ATTR_AFTER_LAST,
NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
@@ -4404,6 +4411,7 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
* @NL80211_RRF_NO_HE: HE operation not allowed
* @NL80211_RRF_NO_320MHZ: 320MHz operation not allowed
+ * @NL80211_RRF_PSD: channels has power spectral density value
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -4423,6 +4431,7 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_NO_160MHZ = 1<<16,
NL80211_RRF_NO_HE = 1<<17,
NL80211_RRF_NO_320MHZ = 1<<18,
+ NL80211_RRF_PSD = 1<<19,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0a31b1d2845d..1e8fe560078f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1106,6 +1106,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_OFFSET, chan->freq_offset))
goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_PSD) &&
+ nla_put_s8(msg, NL80211_FREQUENCY_ATTR_PSD, chan->psd))
+ goto nla_put_failure;
+
if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
goto nla_put_failure;
@@ -8456,6 +8460,11 @@ static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
reg_rule->dfs_cac_ms))
goto nla_put_failure;
+ if ((reg_rule->flags & NL80211_RRF_PSD) &&
+ nla_put_s8(msg, NL80211_ATTR_POWER_RULE_PSD,
+ reg_rule->psd))
+ goto nla_put_failure;
+
nla_nest_end(msg, nl_reg_rule);
}
@@ -8629,6 +8638,7 @@ static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] =
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
[NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_PSD] = { .type = NLA_S8 },
};
static int parse_reg_rule(struct nlattr *tb[],
@@ -8650,6 +8660,14 @@ static int parse_reg_rule(struct nlattr *tb[],
reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
+ if (reg_rule->flags & NL80211_RRF_PSD) {
+ if (!tb[NL80211_ATTR_POWER_RULE_PSD])
+ return -EINVAL;
+
+ reg_rule->psd =
+ nla_get_s8(tb[NL80211_ATTR_POWER_RULE_PSD]);
+ }
+
freq_range->start_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
freq_range->end_freq_khz =
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 0d40d6af7e10..452e0085ed2c 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1587,6 +1587,8 @@ static u32 map_regdom_flags(u32 rd_flags)
channel_flags |= IEEE80211_CHAN_NO_HE;
if (rd_flags & NL80211_RRF_NO_320MHZ)
channel_flags |= IEEE80211_CHAN_NO_320MHZ;
+ if (rd_flags & NL80211_RRF_PSD)
+ channel_flags |= IEEE80211_CHAN_PSD;
return channel_flags;
}
@@ -1793,6 +1795,9 @@ static void handle_channel_single_rule(struct wiphy *wiphy,
chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
}
+ if (chan->flags & IEEE80211_CHAN_PSD)
+ chan->psd = reg_rule->psd;
+
return;
}
@@ -1813,6 +1818,9 @@ static void handle_channel_single_rule(struct wiphy *wiphy,
chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
}
+ if (chan->flags & IEEE80211_CHAN_PSD)
+ chan->psd = reg_rule->psd;
+
if (chan->orig_mpwr) {
/*
* Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
@@ -1882,6 +1890,12 @@ static void handle_channel_adjacent_rules(struct wiphy *wiphy,
rrule2->dfs_cac_ms);
}
+ if ((rrule1->flags & NL80211_RRF_PSD) &&
+ (rrule2->flags & NL80211_RRF_PSD))
+ chan->psd = min_t(s8, rrule1->psd, rrule2->psd);
+ else
+ chan->flags &= ~NL80211_RRF_PSD;
+
return;
}
@@ -2572,6 +2586,9 @@ static void handle_channel_custom(struct wiphy *wiphy,
chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
}
+ if (chan->flags & IEEE80211_CHAN_PSD)
+ chan->psd = reg_rule->psd;
+
chan->max_power = chan->max_reg_power;
}
--
2.17.1
6 GHz regulatory domain introduces different power modes for 6 GHz AP
operation - Low Power Indoor(LPI), Standard Power(SP) and Very Low
Power(VLP). 6 GHz STAs could be operated as either Regular or
Subordinate clients. We have separate definitions of AP and client.
However, during concurrency (multi-interfaces), it would be
difficult to keep different enum containers for different interface
types in order to track its power mode.
Add new combined power type definition for 6 GHz interfaces. Also add
support to convert existing AP/Client Power type to this new combined
power type enum.
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
include/net/cfg80211.h | 19 ++++++++++++
include/uapi/linux/nl80211.h | 38 +++++++++++++++++++++++
net/wireless/util.c | 60 ++++++++++++++++++++++++++++++++++++
3 files changed, 117 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d64481d8d871..7bc9ff9c3f36 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6065,6 +6065,25 @@ ieee80211_frequency_to_channel(int freq)
struct ieee80211_channel *
ieee80211_get_channel_khz(struct wiphy *wiphy, u32 freq);
+/**
+ * ieee80211_ap_reg_power_to_reg_power_mode - convert AP specific 6 GHz power
+ * type into combined 6 GHz power type
+ * @ap_type: AP's power mode
+ * Return: Power mode as referenced in &enum nl80211_regulatory_power_modes
+ */
+enum nl80211_regulatory_power_modes
+ieee80211_ap_reg_power_to_reg_power_mode(enum ieee80211_ap_reg_power ap_type);
+
+/**
+ * ieee80211_client_reg_power_to_reg_power_mode - convert Client specific 6 GHz
+ * power type into combined 6 GHz power type
+ * @client_type: Client's power mode
+ * @ap_type: AP's power mode to which this client is associating
+ * Return: Power mode as referenced in &enum nl80211_regulatory_power_modes
+ */
+enum nl80211_regulatory_power_modes
+ieee80211_client_reg_power_to_reg_power_mode(enum ieee80211_client_reg_power client_type,
+ enum ieee80211_ap_reg_power ap_type);
/**
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 844d2000b4e1..eddccd491fc9 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4075,6 +4075,44 @@ enum nl80211_band_attr {
#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+/**
+ * enum nl80211_regulatory_power_modes - 6 GHz regulatory power
+ * modes
+ * @NL80211_REG_PWR_MODE_AP_SP: Low Power Indoor (Access Point)
+ * @NL80211_REG_PWR_MODE_AP_SP: Standard Power (Access Point)
+ * @NL80211_REG_PWR_MODE_AP_VLP: Very Low Power (Access Point)
+ * @NL80211_REG_PWR_MODE_REGULAR_CLIENT_LPI: Low Power Indoor (Regular
+ * or Default Client)
+ * @NL80211_REG_PWR_MODE_REGULAR_CLIENT_SP: Standard Power (Regular
+ * or Default Client)
+ * @NL80211_REG_PWR_MODE_REGULAR_CLIENT_VLP: Very Low Power (Regular
+ * or Default Client)
+ * @NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_LPI: Low Power Indoor
+ * (Subordinate Client)
+ * @NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_SP: Standard Power
+ * (Subordinate Client)
+ * @NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_VLP: Very Low Power
+ * (Subordinate Client)
+ * @__NL80211_REG_PWR_MODE_LAST: Internal use
+ * @NL80211_REG_PWR_MODE_MAX: Max supported number of power
+ * modes
+ */
+enum nl80211_regulatory_power_modes {
+ NL80211_REG_PWR_MODE_AP_LPI,
+ NL80211_REG_PWR_MODE_AP_SP,
+ NL80211_REG_PWR_MODE_AP_VLP,
+ NL80211_REG_PWR_MODE_REGULAR_CLIENT_LPI,
+ NL80211_REG_PWR_MODE_REGULAR_CLIENT_SP,
+ NL80211_REG_PWR_MODE_REGULAR_CLIENT_VLP,
+ NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_LPI,
+ NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_SP,
+ NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_VLP,
+
+ /* keep last */
+ __NL80211_REG_PWR_MODE_LAST,
+ NL80211_REG_PWR_MODE_MAX = __NL80211_REG_PWR_MODE_LAST,
+};
+
/**
* enum nl80211_wmm_rule - regulatory wmm rule
*
diff --git a/net/wireless/util.c b/net/wireless/util.c
index d1a89e82ead0..56a23e5797f4 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -190,6 +190,66 @@ struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
}
EXPORT_SYMBOL(ieee80211_get_channel_khz);
+enum nl80211_regulatory_power_modes
+ieee80211_ap_reg_power_to_reg_power_mode(enum ieee80211_ap_reg_power ap_type)
+{
+ switch (ap_type) {
+ case IEEE80211_REG_LPI_AP:
+ return NL80211_REG_PWR_MODE_AP_LPI;
+ case IEEE80211_REG_SP_AP:
+ return NL80211_REG_PWR_MODE_AP_SP;
+ case IEEE80211_REG_VLP_AP:
+ return NL80211_REG_PWR_MODE_AP_VLP;
+ default:
+ return NL80211_REG_PWR_MODE_MAX;
+ }
+}
+EXPORT_SYMBOL(ieee80211_ap_reg_power_to_reg_power_mode);
+
+/* ieee80211_client_reg_power_to_reg_power_mode: Accepts the individual power type of
+ * a 6 GHz client and power type of AP to which the client is associating and returns
+ * the final combined power mode as enumerated in &enum nl80211_regulatory_power_modes.
+ *
+ * Unlike AP, for client there is no direct mapping because final power mode of
+ * operation of client is dependent upon the power type of AP.
+ * For example -
+ * If client is a Regular client and AP is Low Power Indoor then combined power mode
+ * will be Regular Low Power Indoor where as if AP is Standard Power, then it will be
+ * Regular Standard Power Mode.
+ */
+enum nl80211_regulatory_power_modes
+ieee80211_client_reg_power_to_reg_power_mode(enum ieee80211_client_reg_power client_type,
+ enum ieee80211_ap_reg_power ap_type)
+{
+ switch (client_type) {
+ case IEEE80211_REG_DEFAULT_CLIENT:
+ switch (ap_type) {
+ case IEEE80211_REG_LPI_AP:
+ return NL80211_REG_PWR_MODE_REGULAR_CLIENT_LPI;
+ case IEEE80211_REG_SP_AP:
+ return NL80211_REG_PWR_MODE_REGULAR_CLIENT_SP;
+ case IEEE80211_REG_VLP_AP:
+ return NL80211_REG_PWR_MODE_REGULAR_CLIENT_VLP;
+ default:
+ return NL80211_REG_PWR_MODE_MAX;
+ }
+ case IEEE80211_REG_SUBORDINATE_CLIENT:
+ switch (ap_type) {
+ case IEEE80211_REG_LPI_AP:
+ return NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_LPI;
+ case IEEE80211_REG_SP_AP:
+ return NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_SP;
+ case IEEE80211_REG_VLP_AP:
+ return NL80211_REG_PWR_MODE_SUBORDINATE_CLIENT_VLP;
+ default:
+ return NL80211_REG_PWR_MODE_MAX;
+ }
+ default:
+ return NL80211_REG_PWR_MODE_MAX;
+ }
+}
+EXPORT_SYMBOL(ieee80211_client_reg_power_to_reg_power_mode);
+
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
{
int i, want;
--
2.17.1
6 GHz introduces various power modes for access points and for clients.
When user configures these power modes, currently cfg80211 does not
have support to store the configured power mode.
Add support to store the 6 GHz configured power mode in the structure
wireless_dev via a new NL command - NL80211_CMD_SET_6GHZ_POWER_MODE.
The above command uses a new NL attributes to set power mode for AP
and client interfaces - NL80211_ATTR_6GHZ_REG_POWER_MODE.
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
include/net/cfg80211.h | 6 +++-
include/uapi/linux/nl80211.h | 10 ++++++
net/wireless/ap.c | 2 ++
net/wireless/nl80211.c | 66 +++++++++++++++++++++++++++++++++++-
net/wireless/sme.c | 2 ++
5 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7bc9ff9c3f36..d8d78141bab6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5805,7 +5805,8 @@ static inline void wiphy_unlock(struct wiphy *wiphy)
* @unprot_beacon_reported: (private) timestamp of last
* unprotected beacon report
* @links: array of %IEEE80211_MLD_MAX_NUM_LINKS elements containing @addr
- * @ap and @client for each link
+ * @ap and @client for each link. If link is 6 GHz link then uses
+ * @reg_6ghz_pwr_configured as well.
* @valid_links: bitmap describing what elements of @links are valid
*/
struct wireless_dev {
@@ -5914,11 +5915,14 @@ struct wireless_dev {
struct {
unsigned int beacon_interval;
struct cfg80211_chan_def chandef;
+ enum ieee80211_ap_reg_power power_mode_6ghz;
} ap;
struct {
struct cfg80211_internal_bss *current_bss;
+ enum ieee80211_client_reg_power power_mode_6ghz;
} client;
};
+ bool reg_6ghz_pwr_configured;
} links[IEEE80211_MLD_MAX_NUM_LINKS];
u16 valid_links;
};
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index eddccd491fc9..bff81489fa8a 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1309,6 +1309,8 @@
* The number of peers that HW timestamping can be enabled for concurrently
* is indicated by %NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS.
*
+ * @NL80211_CMD_SET_6GHZ_POWER_MODE: Set 6 GHz power mode for the interface
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1562,6 +1564,8 @@ enum nl80211_commands {
NL80211_CMD_SET_HW_TIMESTAMP,
+ NL80211_CMD_SET_6GHZ_POWER_MODE,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2786,6 +2790,10 @@ enum nl80211_commands {
* bit corresponds to the lowest 20 MHz channel. Each bit set to 1
* indicates that the sub-channel is punctured. Higher 16 bits are
* reserved.
+ * @NL80211_ATTR_6GHZ_REG_POWER_MODE: Regulatory power mode for 6 GHz operation.
+ * This can be used for both AP and clients. Values are defined in
+ * &enum ieee80211_ap_reg_power and &enum ieee80211_client_reg_power.
+ * Therefore, iftype should be taken into consideration. u8 value.
*
* @NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS: Maximum number of peers that HW
* timestamping can be enabled for concurrently (u16), a wiphy attribute.
@@ -3328,6 +3336,8 @@ enum nl80211_attrs {
NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
NL80211_ATTR_HW_TIMESTAMP_ENABLED,
+ NL80211_ATTR_6GHZ_REG_POWER_MODE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/ap.c b/net/wireless/ap.c
index 0962770303b2..b8e2d9466434 100644
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -30,6 +30,8 @@ static int ___cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
if (!wdev->links[link_id].ap.beacon_interval)
return -ENOENT;
+ wdev->links[link_id].reg_6ghz_pwr_configured = false;
+
err = rdev_stop_ap(rdev, dev, link_id);
if (!err) {
wdev->conn_owner_nlportid = 0;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1e8fe560078f..36cb4574145c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -809,6 +809,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS] = { .type = NLA_U16 },
[NL80211_ATTR_HW_TIMESTAMP_ENABLED] = { .type = NLA_FLAG },
+ [NL80211_ATTR_6GHZ_REG_POWER_MODE] = { .type = NLA_U8 },
};
/* policy for the key attributes */
@@ -16213,6 +16214,61 @@ static int nl80211_set_hw_timestamp(struct sk_buff *skb,
return rdev_set_hw_timestamp(rdev, dev, &hwts);
}
+static bool nl80211_6ghz_power_mode_is_valid(enum nl80211_iftype iftype,
+ u8 power_mode)
+{
+ /* For APs, referenced from enum ieee80211_ap_reg_power, and
+ * For clients, referenced from enum ieee80211_client_reg_power
+ */
+ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ return ((power_mode >= IEEE80211_REG_LPI_AP) &&
+ (power_mode <= IEEE80211_REG_AP_POWER_MAX));
+ case NL80211_IFTYPE_STATION:
+ return ((power_mode >= IEEE80211_REG_DEFAULT_CLIENT) &&
+ (power_mode <= IEEE80211_REG_CLIENT_POWER_MAX));
+ default:
+ return false;
+ }
+}
+
+static int nl80211_set_6ghz_power_mode(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct net_device *netdev = info->user_ptr[1];
+ struct wireless_dev *wdev = netdev->ieee80211_ptr;
+ enum nl80211_iftype iftype = wdev->iftype;
+ unsigned int link_id = nl80211_link_id(info->attrs);
+ u8 power_mode;
+
+ if (iftype != NL80211_IFTYPE_AP &&
+ iftype != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_6GHZ_REG_POWER_MODE])
+ return -EINVAL;
+
+ power_mode = nla_get_u8(info->attrs[NL80211_ATTR_6GHZ_REG_POWER_MODE]);
+ if (!nl80211_6ghz_power_mode_is_valid(iftype, power_mode))
+ return -EINVAL;
+
+ wdev_lock(wdev);
+ if (wdev->links[link_id].reg_6ghz_pwr_configured) {
+ wdev_unlock(wdev);
+ return -EALREADY;
+ }
+
+ if (iftype == NL80211_IFTYPE_AP)
+ wdev->links[link_id].ap.power_mode_6ghz = power_mode;
+ else
+ wdev->links[link_id].client.power_mode_6ghz = power_mode;
+
+ wdev->links[link_id].reg_6ghz_pwr_configured = true;
+
+ wdev_unlock(wdev);
+ return 0;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -17393,6 +17449,14 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
},
+ {
+ .cmd = NL80211_CMD_SET_6GHZ_POWER_MODE,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .doit = nl80211_set_6ghz_power_mode,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_MLO_VALID_LINK_ID),
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
@@ -17409,7 +17473,7 @@ static struct genl_family nl80211_fam __ro_after_init = {
.n_ops = ARRAY_SIZE(nl80211_ops),
.small_ops = nl80211_small_ops,
.n_small_ops = ARRAY_SIZE(nl80211_small_ops),
- .resv_start_op = NL80211_CMD_REMOVE_LINK_STA + 1,
+ .resv_start_op = NL80211_CMD_SET_6GHZ_POWER_MODE + 1,
.mcgrps = nl80211_mcgrps,
.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
.parallel_ops = true,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 28ce13840a88..5ccc371fdfaf 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1558,6 +1558,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
if (!wdev->connected)
wdev->u.client.ssid_len = 0;
+ wdev->links[0].reg_6ghz_pwr_configured = false;
+
return err;
}
--
2.17.1
6 GHz introduces various power modes of operation. Currently, based
on the power mode, channel's Power Spectral Density (PSD) value as
well as channel disabled flag can change. For single interface,
current implementation works just fine. But for multi-interfaces, for
example AP-STA concurrency, two different channel context needs to be
maintained. This is because, STA power mode also depends on the AP's
power mode it is going to associate with. Hence, PSD value and channel
disabled flag might vary. In this case, same channel context cannot be
used for both AP and STA.
Therefore, to support multiple channel space for each power mode, the
6 GHz channels needs a separate storage space in struct
ieee80211_supported_band. Because of this, the existing APIs to get the
channel/freq from freq/channel will not work for 6 GHz band.
Add support to store all possible 6 GHz channel pools according to the
power mode as well as add API support for getting chan/freq info from
the new struct ieee80211_channel_6ghz.
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
include/net/cfg80211.h | 31 ++++++++++++++++++++++++++++
include/net/regulatory.h | 1 +
net/mac80211/util.c | 40 +++++++++++++++++++++++++++++++++++-
net/wireless/reg.c | 44 ++++++++++++++++++++++++++++++++--------
net/wireless/util.c | 27 ++++++++++++++++++++++++
5 files changed, 134 insertions(+), 9 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d8d78141bab6..fa2c0551e3da 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -512,6 +512,21 @@ struct ieee80211_sta_s1g_cap {
u8 nss_mcs[5];
};
+/**
+ * struct ieee80211_channel_6ghz - 6 GHz channel definitions
+ *
+ * This structure defines all the channels supported by the
+ * 6 GHz band.
+ *
+ * @channels: Array of channels the hardware can operate with
+ * in 6 GHz band.
+ * @n_channels: Number of channels in @channels
+ */
+struct ieee80211_channel_6ghz {
+ struct ieee80211_channel *channels;
+ int n_channels;
+};
+
/**
* struct ieee80211_supported_band - frequency band definition
*
@@ -520,6 +535,7 @@ struct ieee80211_sta_s1g_cap {
*
* @channels: Array of channels the hardware can operate with
* in this band.
+ * @channels_6ghz: Array of 6 GHz channels the hardware can operate with
* @band: the band this structure represents
* @n_channels: Number of channels in @channels
* @bitrates: Array of bitrates the hardware can operate with
@@ -539,6 +555,8 @@ struct ieee80211_sta_s1g_cap {
*/
struct ieee80211_supported_band {
struct ieee80211_channel *channels;
+ struct ieee80211_channel_6ghz
+ *channels_6ghz[NL80211_REG_PWR_MODE_MAX];
struct ieee80211_rate *bitrates;
enum nl80211_band band;
int n_channels;
@@ -6101,6 +6119,19 @@ ieee80211_get_channel(struct wiphy *wiphy, int freq)
return ieee80211_get_channel_khz(wiphy, MHZ_TO_KHZ(freq));
}
+/**
+ * ieee80211_get_6ghz_channel_khz - get channel struct from wiphy for specified
+ * frequency in 6 GHz band
+ *
+ * @wiphy: the struct wiphy to get the channel for
+ * @freq: the center frequency (in KHz) of the channel
+ * @power_mode: the power mode in which freq is to be operated
+ * Return: The channel struct from @wiphy at @freq.
+ */
+struct ieee80211_channel *
+ieee80211_get_6ghz_channel_khz(struct wiphy *wiphy, u32 freq,
+ enum nl80211_regulatory_power_modes power_mode);
+
/**
* cfg80211_channel_is_psc - Check if the channel is a 6 GHz PSC
* @chan: control channel to check
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index c2bf0b39fd1e..93402ccf366c 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -221,6 +221,7 @@ struct ieee80211_reg_rule {
struct ieee80211_freq_range freq_range;
struct ieee80211_power_rule power_rule;
struct ieee80211_wmm_rule wmm_rule;
+ enum nl80211_regulatory_power_modes power_mode;
u32 flags;
u32 dfs_cac_ms;
bool has_wmm;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 1a28fe5cb614..9ddbc02571c1 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3676,6 +3676,9 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
bool support_80_80, support_160, support_320;
u8 he_phy_cap, eht_phy_cap;
u32 freq;
+ enum ieee80211_ap_reg_power reg_6ghz_power_beacon, reg_6ghz_ap_power;
+ enum ieee80211_client_reg_power reg_6ghz_client_power;
+ enum nl80211_regulatory_power_modes reg_6ghz_power_final;
if (chandef->chan->band != NL80211_BAND_6GHZ)
return true;
@@ -3718,6 +3721,39 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
return false;
}
+ /* 6 GHz Power mode present in the beacon */
+ reg_6ghz_power_beacon = u8_get_bits(he_6ghz_oper->control,
+ IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO);
+ switch (reg_6ghz_power_beacon) {
+ case IEEE80211_REG_LPI_AP:
+ case IEEE80211_REG_SP_AP:
+ case IEEE80211_REG_VLP_AP:
+ break;
+ default:
+ sdata_info(sdata,
+ "Invalid Regulatory Info subfield in HE 6 GHz operation, expect issues\n");
+ return false;
+ }
+
+ /* For AP/AP_VLAN/MESH_POINT interfaces, the 6 GHz power mode depends on the
+ * mode configured by user (LPI/SP/VLP). For other interfaces (for ex STA)
+ * mode depends on the power mode present in beacon as well as power mode
+ * configured by the user for that interface
+ */
+ if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_AP_VLAN ||
+ iftype == NL80211_IFTYPE_MESH_POINT) {
+ reg_6ghz_ap_power =
+ sdata->wdev.links[bss_conf->link_id].ap.power_mode_6ghz;
+ reg_6ghz_power_final =
+ ieee80211_ap_reg_power_to_reg_power_mode(reg_6ghz_ap_power);
+ } else {
+ reg_6ghz_client_power =
+ sdata->wdev.links[bss_conf->link_id].client.power_mode_6ghz;
+ reg_6ghz_power_final =
+ ieee80211_client_reg_power_to_reg_power_mode(reg_6ghz_client_power,
+ reg_6ghz_power_beacon);
+ }
+
/*
* The EHT operation IE does not contain the primary channel so the
* primary channel frequency should be taken from the 6 GHz operation
@@ -3725,7 +3761,9 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
*/
freq = ieee80211_channel_to_frequency(he_6ghz_oper->primary,
NL80211_BAND_6GHZ);
- he_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq);
+ he_chandef.chan = ieee80211_get_6ghz_channel_khz(sdata->local->hw.wiphy,
+ MHZ_TO_KHZ(freq),
+ reg_6ghz_power_final);
switch (u8_get_bits(he_6ghz_oper->control,
IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 452e0085ed2c..c5bf3c9abdb1 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1594,7 +1594,8 @@ static u32 map_regdom_flags(u32 rd_flags)
static const struct ieee80211_reg_rule *
freq_reg_info_regd(u32 center_freq,
- const struct ieee80211_regdomain *regd, u32 bw)
+ const struct ieee80211_regdomain *regd, u32 bw,
+ enum nl80211_regulatory_power_modes power_mode)
{
int i;
bool band_rule_found = false;
@@ -1608,7 +1609,12 @@ freq_reg_info_regd(u32 center_freq,
const struct ieee80211_freq_range *fr = NULL;
rr = ®d->reg_rules[i];
- fr = &rr->freq_range;
+
+ if (rr->power_mode == power_mode)
+ fr = &rr->freq_range;
+
+ if (!fr)
+ continue;
/*
* We only need to know if one frequency rule was
@@ -1640,7 +1646,8 @@ __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
u32 bw;
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);
+ reg_rule = freq_reg_info_regd(center_freq, regd, bw,
+ NL80211_REG_PWR_MODE_AP_LPI);
if (!IS_ERR(reg_rule))
return reg_rule;
}
@@ -2292,7 +2299,8 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy,
if (regd) {
const struct ieee80211_reg_rule *reg_rule =
freq_reg_info_regd(MHZ_TO_KHZ(channel->center_freq),
- regd, MHZ_TO_KHZ(20));
+ regd, MHZ_TO_KHZ(20),
+ NL80211_REG_PWR_MODE_AP_LPI);
if (!IS_ERR(reg_rule))
flags = reg_rule->flags;
@@ -2535,7 +2543,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
static void handle_channel_custom(struct wiphy *wiphy,
struct ieee80211_channel *chan,
const struct ieee80211_regdomain *regd,
- u32 min_bw)
+ u32 min_bw,
+ enum nl80211_regulatory_power_modes power_mode)
{
u32 bw_flags = 0;
const struct ieee80211_reg_rule *reg_rule = NULL;
@@ -2544,7 +2553,7 @@ static void handle_channel_custom(struct wiphy *wiphy,
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(center_freq_khz, regd, bw);
+ reg_rule = freq_reg_info_regd(center_freq_khz, regd, bw, power_mode);
if (!IS_ERR(reg_rule))
break;
}
@@ -2596,11 +2605,29 @@ static void handle_band_custom(struct wiphy *wiphy,
struct ieee80211_supported_band *sband,
const struct ieee80211_regdomain *regd)
{
- unsigned int i;
+ unsigned int i, j;
+ bool channels_6ghz_present = false;
if (!sband)
return;
+ if (sband->band == NL80211_BAND_6GHZ) {
+ for (i = 0; i < NL80211_REG_PWR_MODE_MAX; i++) {
+ if (!sband->channels_6ghz[i])
+ continue;
+
+ channels_6ghz_present = true;
+
+ for (j = 0; j < sband->channels_6ghz[i]->n_channels; j++)
+ handle_channel_custom(wiphy,
+ &sband->channels_6ghz[i]->channels[j],
+ regd, MHZ_TO_KHZ(20), i);
+ }
+
+ if (channels_6ghz_present)
+ return;
+ }
+
/*
* We currently assume that you always want at least 20 MHz,
* otherwise channel 12 might get enabled if this rule is
@@ -2608,7 +2635,8 @@ static void handle_band_custom(struct wiphy *wiphy,
*/
for (i = 0; i < sband->n_channels; i++)
handle_channel_custom(wiphy, &sband->channels[i], regd,
- MHZ_TO_KHZ(20));
+ MHZ_TO_KHZ(20),
+ NL80211_REG_PWR_MODE_AP_LPI);
}
/* Used by drivers prior to wiphy registration */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 56a23e5797f4..266ce51b2f7b 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -165,6 +165,33 @@ int ieee80211_freq_khz_to_channel(u32 freq)
}
EXPORT_SYMBOL(ieee80211_freq_khz_to_channel);
+struct ieee80211_channel
+*ieee80211_get_6ghz_channel_khz(struct wiphy *wiphy, u32 freq,
+ enum nl80211_regulatory_power_modes power_mode)
+{
+ struct ieee80211_supported_band *sband;
+ int i;
+ struct ieee80211_channel *chan;
+
+ sband = wiphy->bands[NL80211_BAND_6GHZ];
+
+ if (!sband || power_mode >= NL80211_REG_PWR_MODE_MAX)
+ return NULL;
+
+ if (!sband->channels_6ghz[power_mode])
+ return ieee80211_get_channel_khz(wiphy, freq);
+
+ for (i = 0; i < sband->channels_6ghz[power_mode]->n_channels; i++) {
+ chan = &sband->channels_6ghz[power_mode]->channels[i];
+
+ if (ieee80211_channel_to_khz(chan) == freq)
+ return chan;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(ieee80211_get_6ghz_channel_khz);
+
struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
u32 freq)
{
--
2.17.1
Currently, nl80211_parse_chandef function just selects a
channel based on the control frequency provided. However,
for 6 GHz, power mode also needs to be considered since
6 GHz has got multiple channel pools based on the power
mode.
Modify logic to consider power mode as well for 6 GHz
interface and accordingly select the channel for the
given control frequency.
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
include/net/cfg80211.h | 9 ++++++
net/mac80211/cfg.c | 41 +++++++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 3 ++
net/wireless/nl80211.c | 57 ++++++++++++++++++++++++++------------
net/wireless/nl80211.h | 3 +-
net/wireless/pmsr.c | 8 ++++--
net/wireless/rdev-ops.h | 21 ++++++++++++++
net/wireless/trace.h | 34 +++++++++++++++++++++++
8 files changed, 155 insertions(+), 21 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index fa2c0551e3da..0120a520c58e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -512,6 +512,10 @@ struct ieee80211_sta_s1g_cap {
u8 nss_mcs[5];
};
+#define is_6ghz_freq_khz(freq) \
+ (freq >= MHZ_TO_KHZ(5945) && freq <= MHZ_TO_KHZ(7125))
+#define is_6ghz_freq(freq) is_6ghz_freq_khz(MHZ_TO_KHZ(freq))
+
/**
* struct ieee80211_channel_6ghz - 6 GHz channel definitions
*
@@ -4367,6 +4371,8 @@ struct mgmt_frame_regs {
* @del_link_station: Remove a link of a station.
*
* @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
+ *
+ * @get_6ghz_power_mode: Get the 6 GHz power mode for the given interface.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4722,6 +4728,9 @@ struct cfg80211_ops {
struct link_station_del_parameters *params);
int (*set_hw_timestamp)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_set_hw_timestamp *hwts);
+ int (*get_6ghz_power_mode)(struct wireless_dev *wdev,
+ unsigned int link_id,
+ enum nl80211_regulatory_power_modes *power_mode);
};
/*
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 760ad934f9e1..9af1e31bdc91 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -4947,6 +4947,46 @@ static int ieee80211_set_hw_timestamp(struct wiphy *wiphy,
return local->ops->set_hw_timestamp(&local->hw, &sdata->vif, hwts);
}
+int
+ieee80211_get_6ghz_power_mode(struct wireless_dev *wdev,
+ unsigned int link_id,
+ enum nl80211_regulatory_power_modes *power_mode_6ghz)
+{
+ enum nl80211_iftype iftype;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_vif vif;
+ enum ieee80211_ap_reg_power power_mode_6ghz_ap;
+ enum ieee80211_client_reg_power power_mode_6ghz_client;
+
+ if (!wdev)
+ return -EINVAL;
+
+ iftype = wdev->iftype;
+
+ /* For APs, 6 GHz power mode is taken from the user configured
+ * value. However, for clients, power mode is also dependent
+ * upon the APs power mode to which this client has associated.
+ * Hence for client, need to take power mode of associated AP,
+ * which is present in beacon data.
+ */
+ if (iftype == NL80211_IFTYPE_AP) {
+ power_mode_6ghz_ap = wdev->links[link_id].ap.power_mode_6ghz;
+ *power_mode_6ghz =
+ ieee80211_ap_reg_power_to_reg_power_mode(power_mode_6ghz_ap);
+ } else if (iftype == NL80211_IFTYPE_STATION) {
+ sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ vif = sdata->vif;
+ power_mode_6ghz_client = wdev->links[link_id].client.power_mode_6ghz;
+ *power_mode_6ghz =
+ ieee80211_client_reg_power_to_reg_power_mode(power_mode_6ghz_client,
+ vif.bss_conf.power_type);
+ } else {
+ *power_mode_6ghz = NL80211_REG_PWR_MODE_AP_LPI;
+ }
+
+ return 0;
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -5058,4 +5098,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.mod_link_station = ieee80211_mod_link_station,
.del_link_station = ieee80211_del_link_station,
.set_hw_timestamp = ieee80211_set_hw_timestamp,
+ .get_6ghz_power_mode = ieee80211_get_6ghz_power_mode,
};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3d4edc25a69e..1a82fc9c0f1f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2572,4 +2572,7 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_eht_cap_elem *eht_cap_ie_elem,
u8 eht_cap_len,
struct link_sta_info *link_sta);
+int ieee80211_get_6ghz_power_mode(struct wireless_dev *wdev,
+ unsigned int link_id,
+ enum nl80211_regulatory_power_modes *power_mode_6ghz);
#endif /* IEEE80211_I_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 36cb4574145c..042035f26e9f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3208,10 +3208,13 @@ static int nl80211_parse_punct_bitmap(struct cfg80211_registered_device *rdev,
int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
struct genl_info *info,
- struct cfg80211_chan_def *chandef)
+ struct cfg80211_chan_def *chandef,
+ struct wireless_dev *wdev)
{
struct netlink_ext_ack *extack = info->extack;
struct nlattr **attrs = info->attrs;
+ enum nl80211_regulatory_power_modes power_mode_6ghz;
+ unsigned int link_id = nl80211_link_id(info->attrs);
u32 control_freq;
if (!attrs[NL80211_ATTR_WIPHY_FREQ]) {
@@ -3227,7 +3230,23 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
memset(chandef, 0, sizeof(*chandef));
- chandef->chan = ieee80211_get_channel_khz(&rdev->wiphy, control_freq);
+
+ if (is_6ghz_freq_khz(control_freq)) {
+ if (!wdev)
+ return -EINVAL;
+
+ power_mode_6ghz = rdev_get_6ghz_power_mode(rdev, wdev, link_id);
+
+ if (power_mode_6ghz >= NL80211_REG_PWR_MODE_MAX)
+ return -EINVAL;
+
+ chandef->chan = ieee80211_get_6ghz_channel_khz(&rdev->wiphy,
+ control_freq,
+ power_mode_6ghz);
+ } else {
+ chandef->chan = ieee80211_get_channel_khz(&rdev->wiphy, control_freq);
+ }
+
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = KHZ_TO_MHZ(control_freq);
chandef->freq1_offset = control_freq % 1000;
@@ -3358,7 +3377,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
link_id = 0;
}
- result = nl80211_parse_chandef(rdev, info, &chandef);
+ result = nl80211_parse_chandef(rdev, info, &chandef, wdev);
if (result)
return result;
@@ -5976,7 +5995,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- err = nl80211_parse_chandef(rdev, info, ¶ms->chandef);
+ err = nl80211_parse_chandef(rdev, info, ¶ms->chandef,
+ wdev);
if (err)
goto out;
} else if (wdev->valid_links) {
@@ -9865,7 +9885,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
if (dfs_region == NL80211_DFS_UNSET)
goto unlock;
- err = nl80211_parse_chandef(rdev, info, &chandef);
+ err = nl80211_parse_chandef(rdev, info, &chandef, wdev);
if (err)
goto unlock;
@@ -9945,7 +9965,7 @@ static int nl80211_notify_radar_detection(struct sk_buff *skb,
return -EINVAL;
}
- err = nl80211_parse_chandef(rdev, info, &chandef);
+ err = nl80211_parse_chandef(rdev, info, &chandef, wdev);
if (err) {
GENL_SET_ERR_MSG(info, "Unable to extract chandef info");
return err;
@@ -10143,7 +10163,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
}
skip_beacons:
- err = nl80211_parse_chandef(rdev, info, ¶ms.chandef);
+ err = nl80211_parse_chandef(rdev, info, ¶ms.chandef, wdev);
if (err)
goto free;
@@ -11236,6 +11256,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_ibss_params ibss;
struct wiphy *wiphy;
struct cfg80211_cached_keys *connkeys = NULL;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
int err;
memset(&ibss, 0, sizeof(ibss));
@@ -11258,7 +11279,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->join_ibss)
return -EOPNOTSUPP;
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+ if (wdev->iftype != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
wiphy = &rdev->wiphy;
@@ -11277,7 +11298,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
- err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
+ err = nl80211_parse_chandef(rdev, info, &ibss.chandef, wdev);
if (err)
return err;
@@ -11376,13 +11397,13 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.userspace_handles_dfs =
nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
- wdev_lock(dev->ieee80211_ptr);
+ wdev_lock(wdev);
err = __cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
if (err)
kfree_sensitive(connkeys);
else if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
- dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
- wdev_unlock(dev->ieee80211_ptr);
+ wdev->conn_owner_nlportid = info->snd_portid;
+ wdev_unlock(wdev);
return err;
}
@@ -12248,7 +12269,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
duration > rdev->wiphy.max_remain_on_channel_duration)
return -EINVAL;
- err = nl80211_parse_chandef(rdev, info, &chandef);
+ err = nl80211_parse_chandef(rdev, info, &chandef, wdev);
if (err)
return err;
@@ -12470,7 +12491,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
*/
chandef.chan = NULL;
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- err = nl80211_parse_chandef(rdev, info, &chandef);
+ err = nl80211_parse_chandef(rdev, info, &chandef, wdev);
if (err)
return err;
}
@@ -12879,7 +12900,8 @@ static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
struct ocb_setup setup = {};
int err;
- err = nl80211_parse_chandef(rdev, info, &setup.chandef);
+ err = nl80211_parse_chandef(rdev, info, &setup.chandef,
+ dev->ieee80211_ptr);
if (err)
return err;
@@ -12954,7 +12976,8 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
cfg.auto_open_plinks = false;
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- err = nl80211_parse_chandef(rdev, info, &setup.chandef);
+ err = nl80211_parse_chandef(rdev, info, &setup.chandef,
+ dev->ieee80211_ptr);
if (err)
return err;
} else {
@@ -15291,7 +15314,7 @@ static int nl80211_tdls_channel_switch(struct sk_buff *skb,
!info->attrs[NL80211_ATTR_OPER_CLASS])
return -EINVAL;
- err = nl80211_parse_chandef(rdev, info, &chandef);
+ err = nl80211_parse_chandef(rdev, info, &chandef, wdev);
if (err)
return err;
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 0278d817bb02..24966630ba27 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -24,7 +24,8 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
struct genl_info *info,
- struct cfg80211_chan_def *chandef);
+ struct cfg80211_chan_def *chandef,
+ struct wireless_dev *wdev);
int nl80211_parse_random_mac(struct nlattr **attrs,
u8 *mac_addr, u8 *mac_addr_mask);
diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c
index 2bc647720cda..501b8af547e1 100644
--- a/net/wireless/pmsr.c
+++ b/net/wireless/pmsr.c
@@ -184,7 +184,8 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
struct nlattr *peer,
struct cfg80211_pmsr_request_peer *out,
- struct genl_info *info)
+ struct genl_info *info,
+ struct wireless_dev *wdev)
{
struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1];
@@ -213,7 +214,7 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
if (err)
return err;
- err = nl80211_parse_chandef(rdev, info, &out->chandef);
+ err = nl80211_parse_chandef(rdev, info, &out->chandef, wdev);
if (err)
return err;
@@ -316,7 +317,8 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
idx = 0;
nla_for_each_nested(peer, peers, rem) {
/* NB: this reuses info->attrs, but we no longer need it */
- err = pmsr_parse_peer(rdev, peer, &req->peers[idx], info);
+ err = pmsr_parse_peer(rdev, peer, &req->peers[idx], info,
+ wdev);
if (err)
goto out_err;
idx++;
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 2e497cf26ef2..b2c8b92789cd 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1511,4 +1511,25 @@ rdev_set_hw_timestamp(struct cfg80211_registered_device *rdev,
return ret;
}
+
+static inline enum nl80211_regulatory_power_modes
+rdev_get_6ghz_power_mode(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ unsigned int link_id)
+{
+ enum nl80211_regulatory_power_modes power_mode_6ghz;
+ int ret;
+
+ if (!rdev->ops->get_6ghz_power_mode)
+ return NL80211_REG_PWR_MODE_MAX;
+
+ trace_rdev_get_6ghz_power_mode(&rdev->wiphy, wdev, link_id);
+ ret = rdev->ops->get_6ghz_power_mode(wdev, link_id, &power_mode_6ghz);
+ trace_rdev_return_6ghz_power_mode(wdev, ret, power_mode_6ghz);
+
+ if (ret)
+ return NL80211_REG_PWR_MODE_MAX;
+
+ return power_mode_6ghz;
+}
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 716a1fa70069..f9595f86fc08 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3946,6 +3946,40 @@ TRACE_EVENT(rdev_set_hw_timestamp,
__entry->enable)
);
+TRACE_EVENT(rdev_get_6ghz_power_mode,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ unsigned int link_id),
+ TP_ARGS(wiphy, wdev, link_id),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ __field(u32, link_id)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ __entry->link_id = params->link_id;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %u",
+ WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id)
+);
+
+TRACE_EVENT(rdev_return_6ghz_power_mode,
+ TP_PROTO(struct wireless_dev *wdev, int ret, u8 power_mode),
+ TP_ARGS(wdev, ret, power_mode),
+ TP_STRUCT__entry(
+ WDEV_ENTRY
+ __field(u8, ret)
+ __field(u8, power_mode)
+ ),
+ TP_fast_assign(
+ WDEV_ASSIGN;
+ __entry->ret = ret;
+ __entry->power_mode = power_mode;
+ ),
+ TP_printk(WDEV_PR_FMT ", ret: %d, power_mode: %d",
+ WDEV_PR_ARG, __entry->ret, __entry->power_mode)
+);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--
2.17.1
Currently, two chandefs are identical if they point to the same
ieee80211_channel as well as other members of the chandef are same.
However, with 6 GHz regulatory power modes changes, now 6 GHz channel
can be picked from different channel pool and hence there can be a
scenario where chandefs are actually idenatical but the channels are
from a different pool (for example - AP-STA concurrency case).
In this situation, the above logic will fail.
Hence, for 6 GHz, instead of comparing the pointers, members inside
ieee80211_channel can be compared and if they are same along with above
condition then chandef can be assumed to be identical.
Fix the same for 6 GHz channel comparison.
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
include/net/cfg80211.h | 41 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 36 insertions(+), 5 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0120a520c58e..2f11b2451efe 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -903,6 +903,31 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
struct ieee80211_channel *channel,
enum nl80211_channel_type chantype);
+/**
+ * cfg80211_6ghz_channel_identical - check if two 6 GHz channel definitions are
+ * identical
+ * @channel1: first channel definition
+ * @channel2: second channel definition
+ *
+ * Return: %true if the channels are identical except for the flags and power
+ * related settings, %false otherwise.
+ */
+static inline bool
+cfg80211_6ghz_channel_identical(struct ieee80211_channel *channel1,
+ struct ieee80211_channel *channel2)
+{
+ if (!channel1 || !channel2)
+ return false;
+
+ if (channel1->band == channel2->band &&
+ channel1->band != NL80211_BAND_6GHZ)
+ return false;
+
+ return (channel1->band == channel2->band &&
+ channel1->center_freq == channel2->center_freq &&
+ channel1->freq_offset == channel2->freq_offset);
+}
+
/**
* cfg80211_chandef_identical - check if two channel definitions are identical
* @chandef1: first channel definition
@@ -915,11 +940,17 @@ static inline bool
cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
const struct cfg80211_chan_def *chandef2)
{
- return (chandef1->chan == chandef2->chan &&
- chandef1->width == chandef2->width &&
- chandef1->center_freq1 == chandef2->center_freq1 &&
- chandef1->freq1_offset == chandef2->freq1_offset &&
- chandef1->center_freq2 == chandef2->center_freq2);
+ bool same_chan = chandef1->chan == chandef2->chan;
+ bool same_chand_def_prop = chandef1->width == chandef2->width &&
+ chandef1->center_freq1 == chandef2->center_freq1 &&
+ chandef1->freq1_offset == chandef2->freq1_offset &&
+ chandef1->center_freq2 == chandef2->center_freq2;
+
+ if (!same_chan)
+ same_chan = cfg80211_6ghz_channel_identical(chandef1->chan,
+ chandef2->chan);
+
+ return (same_chan && same_chand_def_prop);
}
/**
--
2.17.1
Commit "wifi: mac80211: add support for 6 GHz channels and regulatory" adds
different channel pools for different power modes for 6 GHz channels.
Currently, during MLME and association BSS handling, channel is fetched
from older API ieee80211_get_channel_khz which will not consider the power
mode for 6 GHz. Hence use proper API ieee80211_get_6ghz_channel_khz to fetch
the 6 GHz channel.
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
net/mac80211/mlme.c | 14 ++++++++++++--
net/mac80211/scan.c | 15 +++++++++++++--
net/wireless/nl80211.c | 35 ++++++++++++++++++++++++++---------
3 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e13a0354c397..7fc3f4af8202 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5361,11 +5361,21 @@ static void ieee80211_rx_bss_info(struct ieee80211_link_data *link,
struct ieee80211_local *local = sdata->local;
struct ieee80211_bss *bss;
struct ieee80211_channel *channel;
+ u32 rx_freq_khz = ieee80211_rx_status_to_khz(rx_status);
+ enum nl80211_regulatory_power_modes power_mode_6ghz;
sdata_assert_lock(sdata);
- channel = ieee80211_get_channel_khz(local->hw.wiphy,
- ieee80211_rx_status_to_khz(rx_status));
+ if (is_6ghz_freq_khz(rx_freq_khz)) {
+ ieee80211_get_6ghz_power_mode(&sdata->wdev, 0,
+ &power_mode_6ghz);
+ channel = ieee80211_get_6ghz_channel_khz(local->hw.wiphy,
+ rx_freq_khz,
+ power_mode_6ghz);
+ } else {
+ channel = ieee80211_get_channel_khz(local->hw.wiphy,
+ rx_freq_khz);
+ }
if (!channel)
return;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 32fa8aca7005..bd5f73b06856 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -261,6 +261,8 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
struct ieee80211_channel *channel;
size_t min_hdr_len = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
+ u32 rx_freq_khz = ieee80211_rx_status_to_khz(rx_status);
+ enum nl80211_regulatory_power_modes power_mode_6ghz;
if (!ieee80211_is_probe_resp(mgmt->frame_control) &&
!ieee80211_is_beacon(mgmt->frame_control) &&
@@ -319,8 +321,17 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
return;
}
- channel = ieee80211_get_channel_khz(local->hw.wiphy,
- ieee80211_rx_status_to_khz(rx_status));
+ if (is_6ghz_freq_khz(rx_freq_khz)) {
+ ieee80211_get_6ghz_power_mode(sdata1 ? &sdata1->wdev : &sdata2->wdev,
+ 0, &power_mode_6ghz);
+
+ channel = ieee80211_get_6ghz_channel_khz(local->hw.wiphy,
+ rx_freq_khz,
+ power_mode_6ghz);
+ } else {
+ channel = ieee80211_get_channel_khz(local->hw.wiphy,
+ rx_freq_khz);
+ }
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cdb26aac24d1..8d97a3e58015 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1574,12 +1574,26 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
return 0;
}
-static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
+static struct ieee80211_channel *nl80211_get_valid_chan(struct wireless_dev *wdev,
+ unsigned int link_id,
u32 freq)
{
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct ieee80211_channel *chan;
+ enum nl80211_regulatory_power_modes power_mode_6ghz;
+
+ if (is_6ghz_freq_khz(freq)) {
+ power_mode_6ghz = rdev_get_6ghz_power_mode(rdev, wdev, link_id);
+
+ if (power_mode_6ghz >= NL80211_REG_PWR_MODE_MAX)
+ return NULL;
+
+ chan = ieee80211_get_6ghz_channel_khz(wiphy, freq, power_mode_6ghz);
+ } else {
+ chan = ieee80211_get_channel_khz(wiphy, freq);
+ }
- chan = ieee80211_get_channel_khz(wiphy, freq);
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
return NULL;
return chan;
@@ -10652,7 +10666,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
freq +=
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
- chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
+ chan = nl80211_get_valid_chan(dev->ieee80211_ptr, 0, freq);
if (!chan)
return -EINVAL;
@@ -10861,6 +10875,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
}
static struct cfg80211_bss *nl80211_assoc_bss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ unsigned int link_id,
const u8 *ssid, int ssid_len,
struct nlattr **attrs,
const u8 **bssid_out)
@@ -10879,7 +10895,7 @@ static struct cfg80211_bss *nl80211_assoc_bss(struct cfg80211_registered_device
if (attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
freq += nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
- chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
+ chan = nl80211_get_valid_chan(dev->ieee80211_ptr, link_id, freq);
if (!chan)
return ERR_PTR(-EINVAL);
@@ -11062,8 +11078,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
goto free;
}
req.links[link_id].bss =
- nl80211_assoc_bss(rdev, ssid, ssid_len, attrs,
- &bssid);
+ nl80211_assoc_bss(rdev, dev, link_id, ssid, ssid_len,
+ attrs, &bssid);
if (IS_ERR(req.links[link_id].bss)) {
err = PTR_ERR(req.links[link_id].bss);
req.links[link_id].bss = NULL;
@@ -11114,7 +11130,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
if (req.link_id >= 0)
return -EINVAL;
- req.bss = nl80211_assoc_bss(rdev, ssid, ssid_len, info->attrs,
+ req.bss = nl80211_assoc_bss(rdev, dev, 0, ssid, ssid_len, info->attrs,
&bssid);
if (IS_ERR(req.bss))
return PTR_ERR(req.bss);
@@ -11813,13 +11829,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
if (freq) {
- connect.channel = nl80211_get_valid_chan(wiphy, freq);
+ connect.channel = nl80211_get_valid_chan(dev->ieee80211_ptr, 0, freq);
if (!connect.channel)
return -EINVAL;
} else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
freq = MHZ_TO_KHZ(freq);
- connect.channel_hint = nl80211_get_valid_chan(wiphy, freq);
+ connect.channel_hint = nl80211_get_valid_chan(dev->ieee80211_ptr, 0,
+ freq);
if (!connect.channel_hint)
return -EINVAL;
}
--
2.17.1
Currently when user space demands the reg rules via NL80211_CMD_GET_REG
command, along with Power Spectral Denity (PSD) values, power mode
needs to be advertised since in 6 GHz AP beacon, Tx power envelope
should have PSD info as well which can be opted based on the power
mode. Similarly, via NL80211_CMD_SET_REG command, user space can try
to set regulatory rules and cfg80211 needs to store the incoming power
mode for the rule.
Add support for 6 GHz power mode advertisement in
NL80211_CMD_GET_REG command and saving 6 GHz power mode for reg rules
via NL80211_CMD_SET_REG command.
Signed-off-by: Aditya Kumar Singh <[email protected]>
---
include/uapi/linux/nl80211.h | 4 ++++
net/wireless/nl80211.c | 20 ++++++++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index bff81489fa8a..aa0fcf98aab1 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4358,6 +4358,8 @@ enum nl80211_reg_type {
* If not present or 0 default CAC time will be used.
* @NL80211_ATTR_POWER_RULE_PSD: power spectral density (in dBm).
* This could be negative.
+ * @NL80211_ATTR_REG_POWER_MODE: the regulatory power mode for 6 GHz rules.
+ * Referenced from &enum nl80211_regulatory_power_modes
* @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
* currently defined
* @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
@@ -4377,6 +4379,8 @@ enum nl80211_reg_rule_attr {
NL80211_ATTR_POWER_RULE_PSD,
+ NL80211_ATTR_REG_POWER_MODE,
+
/* keep last */
__NL80211_REG_RULE_ATTR_AFTER_LAST,
NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 042035f26e9f..cdb26aac24d1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8481,6 +8481,13 @@ static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
reg_rule->dfs_cac_ms))
goto nla_put_failure;
+ /* Put power mode as well if its a 6 GHz reg rule */
+ if (freq_range->start_freq_khz >= MHZ_TO_KHZ(5925) &&
+ freq_range->end_freq_khz <= MHZ_TO_KHZ(7125) &&
+ nla_put_u8(msg, NL80211_ATTR_REG_POWER_MODE,
+ reg_rule->power_mode))
+ goto nla_put_failure;
+
if ((reg_rule->flags & NL80211_RRF_PSD) &&
nla_put_s8(msg, NL80211_ATTR_POWER_RULE_PSD,
reg_rule->psd))
@@ -8660,6 +8667,10 @@ static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] =
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
[NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_PSD] = { .type = NLA_S8 },
+ [NL80211_ATTR_REG_POWER_MODE] =
+ NLA_POLICY_RANGE(NLA_U8,
+ NL80211_REG_PWR_MODE_AP_LPI,
+ NL80211_REG_PWR_MODE_MAX - 1),
};
static int parse_reg_rule(struct nlattr *tb[],
@@ -8707,6 +8718,15 @@ static int parse_reg_rule(struct nlattr *tb[],
reg_rule->dfs_cac_ms =
nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
+ if (freq_range->start_freq_khz >= MHZ_TO_KHZ(5925) &&
+ freq_range->end_freq_khz <= MHZ_TO_KHZ(7125)) {
+ if (!tb[NL80211_ATTR_REG_POWER_MODE])
+ return -EINVAL;
+
+ reg_rule->power_mode =
+ nla_get_u8(tb[NL80211_ATTR_REG_POWER_MODE]);
+ }
+
return 0;
}
--
2.17.1
Aditya Kumar Singh <[email protected]> writes:
> Commit "wifi: mac80211: add support for 6 GHz channels and regulatory" adds
> different channel pools for different power modes for 6 GHz channels.
As that patch is not applied yet I would do s/Commit/Patch/, but no need
to resend just because of this.
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
On 3/15/2023 18:58, Aditya Kumar Singh wrote:
> 6 GHz introduces various power modes of operation. Currently, based
> on the power mode, channel's Power Spectral Density (PSD) value,
> Regulatory power value, as well as channel disabled flag can change.
> For single interface, current implementation works just fine. But for
> multi-interfaces, for example AP-STA concurrency, two different channel
> context needs to be maintained. This is because, STA power mode also
> depends on the AP's power mode it is going to associate with. Hence,
> PSD value, regulatory power value and channel disabled flag might vary.
> In this case, same channel context cannot be used for both AP and STA.
>
> Therefore, to support multiple channel space for each power mode, the
> 6 GHz channels needs a separate storage space in data structure
> ieee80211_supported_band. Because of this, the existing APIs to get the
> channel/frequency from frequency/channel will not work for 6 GHz band.
>
> Add support to store all possible 6 GHz channel pools according to the
> power mode as well as add API support for getting channel/frequency info
> from the new struct ieee80211_6ghz_channel.
>
>
[..]
>
Hi Johannes,
Could you review this series and provide your comments please?
Aditya
Hi Johannes,
Could you give comments for these v3 patches?
On 3/15/2023 9:28 PM, Aditya Kumar Singh wrote:
...
Hi Johannes,
Kindly Reminder. Could you give comments for these v3 patches?
On 6/9/2023 1:41 PM, Wen Gong wrote:
> Hi Johannes,
>
> Could you give comments for these v3 patches?
>
> On 3/15/2023 9:28 PM, Aditya Kumar Singh wrote:
> ...
Wen Gong <[email protected]> writes:
> Hi Johannes,
>
> Kindly Reminder. Could you give comments for these v3 patches?
>
> On 6/9/2023 1:41 PM, Wen Gong wrote:
>> Hi Johannes,
>>
>> Could you give comments for these v3 patches?
Please stop spamming the lists like this, it's simply rude. And check
our summer schedule:
https://lore.kernel.org/all/[email protected]/
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Hi,
So ... yeah. I shied away from even reviewing this because it's such a
messy topic and we've had so many threads about this. Sorry about that.
On Wed, 2023-03-15 at 18:58 +0530, Aditya Kumar Singh wrote:
> 6 GHz introduces various power modes of operation. Currently, based
> on the power mode, channel's Power Spectral Density (PSD) value,
> Regulatory power value, as well as channel disabled flag can change.
> For single interface, current implementation works just fine. But for
> multi-interfaces, for example AP-STA concurrency, two different channel
> context needs to be maintained. This is because, STA power mode also
> depends on the AP's power mode it is going to associate with. Hence,
> PSD value, regulatory power value and channel disabled flag might vary.
> In this case, same channel context cannot be used for both AP and STA.
>
> Therefore, to support multiple channel space for each power mode, the
> 6 GHz channels needs a separate storage space in data structure
> ieee80211_supported_band. Because of this, the existing APIs to get the
> channel/frequency from frequency/channel will not work for 6 GHz band.
>
> Add support to store all possible 6 GHz channel pools according to the
> power mode as well as add API support for getting channel/frequency info
> from the new struct ieee80211_6ghz_channel.
>
>
> Why different channel pools and not array of varying member in the same channel?:
I really don't understand.
Why do you even need to set *from userspace* the power mode for a
client? That ... doesn't make that much sense?
I mean, you're explaining here the mechanics, which is all fine, but
what's the "theory of operation"? Yes, I get that 6 GHz spectrum use
introduced power modes, but why do we even need to handle it this way?
None of this or the patches actually introduce any rationale?
Also, I'll note that the patch subjects with "cfg80211" or "mac80211"
are _really_ unclear. Sometimes you have "cfg80211" patches that mostly
change mac80211, etc. It'd make reviewing easier if you actually did
limit cfg80211 patches to touching cfg80211 only (with the exception of
necessary API updates, of course), and mac80211 patches to implementing
the new cfg80211 APIs. The first patch is probably neither, you can mark
it as ieee80211.
And then trivial things like - don't introduce a bug only to fix it in
the next patch! I mean, really?
I _still_ don't like "(A)" operation with different channel pointers -
you talk about introducing bugs with (B) but at least those would be
bugs in the new parts; (A) is almost certainly introducing bugs in
existing code that compares pointers and you never even know about it.
Also, related to that, is kind of a fundamental question - should we
really think that two *channels* are different because you use different
(TX) power control/scheme on them? That seems a bit strange, and you've
not gotten into that at all, from a semantic POV, only from a code POV.
I actually currently don't think that makes sense, but convince me
otherwise?
For a chandef, _maybe_? But also see the discussion around puncturing,
I'm not sure that's actually the right solution either.
johannes
On Wed, 2023-03-15 at 18:58 +0530, Aditya Kumar Singh wrote:
>
> + {
> + .cmd = NL80211_CMD_SET_6GHZ_POWER_MODE,
> + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> + .doit = nl80211_set_6ghz_power_mode,
> + .flags = GENL_UNS_ADMIN_PERM,
> + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV |
> + NL80211_FLAG_MLO_VALID_LINK_ID),
> + },
Why is this even a new command, rather than a parameter to start AP or
similar?
Why do we even set it in client mode from userspace?
> static struct genl_family nl80211_fam __ro_after_init = {
> @@ -17409,7 +17473,7 @@ static struct genl_family nl80211_fam __ro_after_init = {
> .n_ops = ARRAY_SIZE(nl80211_ops),
> .small_ops = nl80211_small_ops,
> .n_small_ops = ARRAY_SIZE(nl80211_small_ops),
> - .resv_start_op = NL80211_CMD_REMOVE_LINK_STA + 1,
> + .resv_start_op = NL80211_CMD_SET_6GHZ_POWER_MODE + 1,
>
Obviously, this should not be done.
But in any case, I don't think there's a lot of value in doing a
detailed review of the code if we haven't gotten a good grasp of the
semantics that you want.
johannes
On 8/30/23 13:11, Johannes Berg wrote:
> On Wed, 2023-08-30 at 10:35 +0530, Aditya Kumar Singh wrote:
>> On 8/29/23 23:21, Johannes Berg wrote:
>>> On Wed, 2023-03-15 at 18:58 +0530, Aditya Kumar Singh wrote:
>>>>
>>>> + {
>>>> + .cmd = NL80211_CMD_SET_6GHZ_POWER_MODE,
>>>> + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
>>>> + .doit = nl80211_set_6ghz_power_mode,
>>>> + .flags = GENL_UNS_ADMIN_PERM,
>>>> + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV |
>>>> + NL80211_FLAG_MLO_VALID_LINK_ID),
>>>> + },
>>>
>>> Why is this even a new command, rather than a parameter to start AP or
>>> similar?
>>>
>> A new command was introduced because to give user space a knob to change
>> power mode as and when required. Let's suppose AFC response has not yet
>> arrived, AP could be started in Low Power mode. Now once AFC rules are
>> applied (not going in detail here how that will happen) and user space
>> knows about it, it can send command to switch to Standard Power Mode right?
>
> At least for AP that could also be a beacon update, like most other
> operational parameters. You have to update the beacon _anyway_ since you
> indicate in the beacon what you're doing.
Yeah this option can be explored too. Thanks for the suggestion.
>
> So that by itself doesn't really introduce the requirement to have a
> separate command.
Yes I see your point. Let me re-work on this aspect as well.
>
>>> Why do we even set it in client mode from userspace?
>
> And you didn't comment on this - what userspace do you expect to use it
> in client mode? I can see hostapd in AP mode, I guess, but in client
> mode I don't see how this could be used? Anyway you're tied to what the
> AP is doing, no?
Yes, as you saw already replied to the similar question in the cover
letter. Will reply to the last question here in that thread it self (to
keep client related discussion in same place).
>
>>>> static struct genl_family nl80211_fam __ro_after_init = {
>>>> @@ -17409,7 +17473,7 @@ static struct genl_family nl80211_fam __ro_after_init = {
>>>> .n_ops = ARRAY_SIZE(nl80211_ops),
>>>> .small_ops = nl80211_small_ops,
>>>> .n_small_ops = ARRAY_SIZE(nl80211_small_ops),
>>>> - .resv_start_op = NL80211_CMD_REMOVE_LINK_STA + 1,
>>>> + .resv_start_op = NL80211_CMD_SET_6GHZ_POWER_MODE + 1,
>>>>
>>>
>>> Obviously, this should not be done.
>> If this hunk is not there, the command was not going through. Upon
>> digging further found out that the number of commands declared in the
>> array and the count provided here has some relation. And that too with
>> the last element added. Since a new element was added, modified it
>> accordingly.
>
> No no, that wasn't a discussion. I'm telling you, this is wrong, and I
> will not apply a patch that does this. If you needed it, you did
> something wrong in userspace.
Oh okay. Fine, let me check again.
>
> johannes
On Wed, 2023-09-13 at 18:35 +0800, Wen Gong wrote:
>
> This patch "[PATCH v3 2/9] wifi: cfg80211: save Power Spectral Density
> (PSD) of the regulatory rule" does not have relation with concurrency.
> Because it only add a field "s8 psd" into struct ieee80211_reg_rule
> and ieee80211_channel. The psd value is same with other field such as
> max_reg_power.
>
> max_reg_power is also different value for AP and station mode in db.txt
> here:
> for example:
> "country TW: DFS-FCC" and "country US: DFS-FCC"
> # 5.15 ~ 5.25 GHz: 30 dBm for master mode, 23 dBm for clients
> https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git/tree/db.txt#n1785
>
> So could you merge the "[PATCH v3 2/9] wifi: cfg80211: save Power Spectral
> Density (PSD) of the regulatory rule" firstly?
Well, arguing with the regdb is kind of a bad thing because it reminds
me that nobody ever cares about it anymore ... maybe we should just give
up on it?
I mean, clearly, if you actually cared your patch here would come with
additions to the regdb format (which aren't even that hard now) which
then the wireless-regdb could actually use rather than the comment,
right?
So really all you've achieved right now is again reminding me how little
you really care about upstream?
johannes
On Wed, 2023-03-15 at 18:58 +0530, Aditya Kumar Singh wrote:
> @@ -8650,6 +8660,14 @@ static int parse_reg_rule(struct nlattr *tb[],
>
> reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
>
> + if (reg_rule->flags & NL80211_RRF_PSD) {
> + if (!tb[NL80211_ATTR_POWER_RULE_PSD])
> + return -EINVAL;
> +
> + reg_rule->psd =
> + nla_get_s8(tb[NL80211_ATTR_POWER_RULE_PSD]);
> + }
Wait ... I'm not sure why we've been adding stuff to this recently, but
anyway, this part should only be used by CRDA which is deprecated
anyway?
So I'd say we shouldn't touch any of the code under #ifdef
CONFIG_CFG80211_CRDA_SUPPORT any more since CRDA will not continue to
developed with any updates here.
johannes
On 8/30/2023 1:50 AM, Johannes Berg wrote:
[...]
> johannes
This patch "[PATCH v3 2/9] wifi: cfg80211: save Power Spectral Density
(PSD) of the regulatory rule" does not have relation with concurrency.
Because it only add a field "s8 psd" into struct ieee80211_reg_rule
and ieee80211_channel. The psd value is same with other field such as
max_reg_power.
max_reg_power is also different value for AP and station mode in db.txt
here:
for example:
"country TW: DFS-FCC" and "country US: DFS-FCC"
# 5.15 ~ 5.25 GHz: 30 dBm for master mode, 23 dBm for clients
https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git/tree/db.txt#n1785
So could you merge the "[PATCH v3 2/9] wifi: cfg80211: save Power Spectral
Density (PSD) of the regulatory rule" firstly?
On 9/13/2023 7:55 AM, Johannes Berg wrote:
> So really all you've achieved right now is again reminding me how little
> you really care about upstream?
I have to step in here. As someone who worked many years on the
out-of-tree Android drivers I understand where you're coming from. But
attitudes change, and my transition to the upstream team is a reflection
of that. I believe everyone from Qualcomm currently contributing to
nl/cfg/mac80211 are doing so in support of upstream ath11k/12k drivers.
There are a multitude of patches that you'll get to see once the
precursor work is out of the way.
I'd prefer to stick to technical discussions :)
Wen,
Can you update your patch to better describe WHY your change is needed?
/jeff
On 9/14/2023 11:15 AM, Jeff Johnson wrote:
> On 9/13/2023 7:58 AM, Johannes Berg wrote:
>> So I'd say we shouldn't touch any of the code under #ifdef
>> CONFIG_CFG80211_CRDA_SUPPORT any more since CRDA will not continue to
>> developed with any updates here.
>
> On a related note, what will happen to ongoing wireless-regdb support
> now that Seth has stepped down as maintainer? Have enough vendors
> moved to self-managed such that regdb is obsolete?
currently ath10k chips are not self-managed.
On Thu, 2023-09-14 at 11:45 +0800, Wen Gong wrote:
> On 9/13/2023 10:58 PM, Johannes Berg wrote:
> > On Wed, 2023-03-15 at 18:58 +0530, Aditya Kumar Singh wrote:
> >
> > > @@ -8650,6 +8660,14 @@ static int parse_reg_rule(struct nlattr *tb[],
> > >
> > > reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
> > >
> > > + if (reg_rule->flags & NL80211_RRF_PSD) {
> > > + if (!tb[NL80211_ATTR_POWER_RULE_PSD])
> > > + return -EINVAL;
> > > +
> > > + reg_rule->psd =
> > > + nla_get_s8(tb[NL80211_ATTR_POWER_RULE_PSD]);
> > > + }
> > Wait ... I'm not sure why we've been adding stuff to this recently, but
> > anyway, this part should only be used by CRDA which is deprecated
> > anyway?
> >
> > So I'd say we shouldn't touch any of the code under #ifdef
> > CONFIG_CFG80211_CRDA_SUPPORT any more since CRDA will not continue to
> > developed with any updates here.
> >
> > johannes
> Oh, I will remove the change in parse_reg_rule() in next version, because
> you asked me to add change in 2
> functions(nl80211_put_regdom()/nl80211_msg_put_channel())
> below, but I added change in one more function(parse_reg_rule()).
>
Yes, we should have visibility on the output - but I don't think we ever
expect the input to carry it this way via nl80211 since that's long
deprecated in favour of the kernel loading it as a 'firmware' file.
johannes
On 9/13/2023 10:58 PM, Johannes Berg wrote:
> On Wed, 2023-03-15 at 18:58 +0530, Aditya Kumar Singh wrote:
>
>> @@ -8650,6 +8660,14 @@ static int parse_reg_rule(struct nlattr *tb[],
>>
>> reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
>>
>> + if (reg_rule->flags & NL80211_RRF_PSD) {
>> + if (!tb[NL80211_ATTR_POWER_RULE_PSD])
>> + return -EINVAL;
>> +
>> + reg_rule->psd =
>> + nla_get_s8(tb[NL80211_ATTR_POWER_RULE_PSD]);
>> + }
> Wait ... I'm not sure why we've been adding stuff to this recently, but
> anyway, this part should only be used by CRDA which is deprecated
> anyway?
>
> So I'd say we shouldn't touch any of the code under #ifdef
> CONFIG_CFG80211_CRDA_SUPPORT any more since CRDA will not continue to
> developed with any updates here.
>
> johannes
Oh, I will remove the change in parse_reg_rule() in next version, because
you asked me to add change in 2
functions(nl80211_put_regdom()/nl80211_msg_put_channel())
below, but I added change in one more function(parse_reg_rule()).
https://lore.kernel.org/linux-wireless/[email protected]/
On 9/13/2023 7:58 AM, Johannes Berg wrote:
> So I'd say we shouldn't touch any of the code under #ifdef
> CONFIG_CFG80211_CRDA_SUPPORT any more since CRDA will not continue to
> developed with any updates here.
On a related note, what will happen to ongoing wireless-regdb support
now that Seth has stepped down as maintainer? Have enough vendors moved
to self-managed such that regdb is obsolete?
On Thu, Sep 14, 2023 at 11:15 AM Jeff Johnson <[email protected]> wrote:
>
> On 9/13/2023 7:58 AM, Johannes Berg wrote:
> > So I'd say we shouldn't touch any of the code under #ifdef
> > CONFIG_CFG80211_CRDA_SUPPORT any more since CRDA will not continue to
> > developed with any updates here.
>
> On a related note, what will happen to ongoing wireless-regdb support
> now that Seth has stepped down as maintainer? Have enough vendors moved
> to self-managed such that regdb is obsolete?
I've picked up maintainership for wireless-regdb.
ChenYu
Chen-Yu Tsai <[email protected]> writes:
> On Thu, Sep 14, 2023 at 11:15 AM Jeff Johnson <[email protected]> wrote:
>>
>> On 9/13/2023 7:58 AM, Johannes Berg wrote:
>> > So I'd say we shouldn't touch any of the code under #ifdef
>> > CONFIG_CFG80211_CRDA_SUPPORT any more since CRDA will not continue to
>> > developed with any updates here.
>>
>> On a related note, what will happen to ongoing wireless-regdb support
>> now that Seth has stepped down as maintainer? Have enough vendors moved
>> to self-managed such that regdb is obsolete?
>
> I've picked up maintainership for wireless-regdb.
Chen-Yu, sorry that I haven't been able to comment anything earlier but
I want to thank you for taking the role. And big thanks to Seth for
maintaining regdb for all these years!
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches