mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-30 01:52:51 +00:00
565 lines
20 KiB
Diff
565 lines
20 KiB
Diff
From 404211da041eef5ddfc52515048b04c70ef8579c Mon Sep 17 00:00:00 2001
|
|
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
|
Date: Thu, 21 Oct 2021 12:51:38 +0530
|
|
Subject: [PATCH] hostapd: add support for 6GHz operation
|
|
|
|
6 GHz gives users ability to select the AP mode from LPI, SP and
|
|
VLP modes. This mode needs to be passed on to the cfg80211
|
|
for further processing during AP bring up. Also, the regulatory
|
|
rules received by hostapd contains psd values for 6G rules.
|
|
Hostapd needs to store these values in order to later advertise
|
|
it in the tx power element in the beacon.
|
|
|
|
This patch adds the support to send the user configured 6g power
|
|
type during set_channel command and as well to get and store the
|
|
psd values from reg rules which will be later on used in tpe
|
|
advertisement during beacon formation.
|
|
|
|
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
|
---
|
|
src/ap/ap_drv_ops.c | 9 ++++++---
|
|
src/ap/beacon.c | 9 +++++++--
|
|
src/ap/dfs.c | 6 ++++--
|
|
src/ap/hostapd.c | 2 +-
|
|
src/ap/ieee802_11.c | 13 ++++++++++++-
|
|
src/ap/ieee802_11_he.c | 10 ++++++++--
|
|
src/common/hw_features_common.c | 4 +++-
|
|
src/common/hw_features_common.h | 2 +-
|
|
src/common/ieee802_11_defs.h | 14 ++++++++++++++
|
|
src/drivers/driver.h | 20 +++++++++++++++++++-
|
|
src/drivers/driver_hostap.c | 3 ++-
|
|
src/drivers/driver_nl80211.c | 15 ++++++++++++++-
|
|
src/drivers/driver_nl80211.h | 2 +-
|
|
src/drivers/driver_nl80211_capa.c | 28 +++++++++++++++++++++++-----
|
|
src/drivers/driver_nl80211_event.c | 2 +-
|
|
src/drivers/nl80211_copy.h | 19 +++++++++++++++++++
|
|
wpa_supplicant/driver_i.h | 2 +-
|
|
wpa_supplicant/mesh.c | 2 +-
|
|
wpa_supplicant/wpa_supplicant.c | 2 +-
|
|
19 files changed, 138 insertions(+), 26 deletions(-)
|
|
|
|
--- a/src/ap/ap_drv_ops.c
|
|
+++ b/src/ap/ap_drv_ops.c
|
|
@@ -563,7 +563,8 @@ int hostapd_set_freq(struct hostapd_data
|
|
center_segment0, center_segment1,
|
|
cmode ? cmode->vht_capab : 0,
|
|
cmode ?
|
|
- &cmode->he_capab[IEEE80211_MODE_AP] : NULL))
|
|
+ &cmode->he_capab[IEEE80211_MODE_AP] : NULL,
|
|
+ hapd->iconf->he_6ghz_reg_pwr_type))
|
|
return -1;
|
|
|
|
if (hapd->driver == NULL)
|
|
@@ -636,7 +637,8 @@ hostapd_get_hw_feature_data(struct hosta
|
|
hapd->driver->get_hw_feature_data == NULL)
|
|
return NULL;
|
|
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
|
|
- flags, dfs_domain);
|
|
+ flags, dfs_domain,
|
|
+ hapd->iconf->he_6ghz_reg_pwr_type);
|
|
}
|
|
|
|
|
|
@@ -836,7 +838,8 @@ int hostapd_start_dfs_cac(struct hostapd
|
|
oper_chwidth, center_segment0,
|
|
center_segment1,
|
|
cmode->vht_capab,
|
|
- &cmode->he_capab[IEEE80211_MODE_AP])) {
|
|
+ &cmode->he_capab[IEEE80211_MODE_AP],
|
|
+ hapd->iconf->he_6ghz_reg_pwr_type)) {
|
|
wpa_printf(MSG_ERROR, "Can't set freq params");
|
|
return -1;
|
|
}
|
|
--- a/src/ap/beacon.c
|
|
+++ b/src/ap/beacon.c
|
|
@@ -1571,7 +1571,11 @@ int ieee802_11_build_ap_params(struct ho
|
|
if (is_6ghz_op_class(hapd->iconf->op_class)) {
|
|
tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) +
|
|
3 + sizeof(struct ieee80211_he_6ghz_band_cap);
|
|
- /* Additional TX Power envelope for subordinate client */
|
|
+ /* Additional TX Power envelope for subordinate client
|
|
+ * Currently as per the spec, only AP LP mode should send
|
|
+ * the tpe for subordinate client. SP mode should not and
|
|
+ * no standard set yet for VLP mode.
|
|
+ */
|
|
if (hostapd_get_he_6ghz_reg_pwr_type(hapd->iconf) ==
|
|
AP_TYPE_6GHZ_INDOOR_AP)
|
|
tail_len += 4;
|
|
@@ -2012,7 +2016,8 @@ static int __ieee802_11_set_beacon(struc
|
|
hostapd_get_oper_centr_freq_seg0_idx(iconf),
|
|
hostapd_get_oper_centr_freq_seg1_idx(iconf),
|
|
cmode->vht_capab,
|
|
- &cmode->he_capab[IEEE80211_MODE_AP]) == 0)
|
|
+ &cmode->he_capab[IEEE80211_MODE_AP],
|
|
+ iconf->he_6ghz_reg_pwr_type) == 0)
|
|
params.freq = &freq;
|
|
|
|
res = hostapd_drv_set_ap(hapd, ¶ms);
|
|
--- a/src/ap/dfs.c
|
|
+++ b/src/ap/dfs.c
|
|
@@ -1086,7 +1086,8 @@ static int hostapd_dfs_testmode_set_beac
|
|
vht_oper_centr_freq_seg0_idx,
|
|
vht_oper_centr_freq_seg1_idx,
|
|
iface->current_mode->vht_capab,
|
|
- &iface->current_mode->he_capab[IEEE80211_MODE_AP]);
|
|
+ &iface->current_mode->he_capab[IEEE80211_MODE_AP],
|
|
+ hapd->iconf->he_6ghz_reg_pwr_type);
|
|
|
|
if (err) {
|
|
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
|
|
@@ -1227,7 +1228,8 @@ static int hostapd_dfs_start_channel_swi
|
|
oper_centr_freq_seg0_idx,
|
|
oper_centr_freq_seg1_idx,
|
|
cmode->vht_capab,
|
|
- &cmode->he_capab[ieee80211_mode]);
|
|
+ &cmode->he_capab[ieee80211_mode],
|
|
+ iface->conf->he_6ghz_reg_pwr_type);
|
|
|
|
if (err) {
|
|
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
|
|
--- a/src/ap/hostapd.c
|
|
+++ b/src/ap/hostapd.c
|
|
@@ -3503,7 +3503,7 @@ static int hostapd_change_config_freq(st
|
|
hostapd_get_oper_centr_freq_seg1_idx(conf),
|
|
conf->vht_capab,
|
|
mode ? &mode->he_capab[IEEE80211_MODE_AP] :
|
|
- NULL))
|
|
+ NULL, hapd->iconf->he_6ghz_reg_pwr_type))
|
|
return -1;
|
|
|
|
switch (params->bandwidth) {
|
|
--- a/src/ap/ieee802_11.c
|
|
+++ b/src/ap/ieee802_11.c
|
|
@@ -6927,6 +6927,8 @@ u8 * hostapd_eid_txpower_envelope(struct
|
|
int dfs, i;
|
|
u8 channel, tx_pwr_count, local_pwr_constraint;
|
|
u8 tx_pwr, tx_pwr_intrpn, tx_pwr_cat, ap_type;
|
|
+ s8 psd;
|
|
+
|
|
int max_tx_power;
|
|
|
|
if (!mode)
|
|
@@ -6963,15 +6965,24 @@ u8 * hostapd_eid_txpower_envelope(struct
|
|
*/
|
|
if (ap_type == AP_TYPE_6GHZ_INDOOR_AP) {
|
|
tx_pwr_cat = REG_SUBORDINATE_CLIENT;
|
|
- /* TODO: extract psd limits from channel data */
|
|
+ psd = mode->psd_values[NL80211_REG_SUBORDINATE_CLIENT_LPI + ap_type];
|
|
+#ifdef REG_DOM_SUPPORT_TX_POWER
|
|
+ tx_pwr = psd * 2;
|
|
+#else
|
|
tx_pwr = (hostapd_get_6g_tx_power(hapd, ap_type, tx_pwr_cat) * 2);
|
|
+#endif /* REG_DOM_SUPPORT_TX_POWER */
|
|
eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
|
|
tx_pwr_cat, tx_pwr);
|
|
}
|
|
|
|
/* Default Tx Power envelope for Global Operating class */
|
|
tx_pwr_cat = REG_DEFAULT_CLIENT;
|
|
+ psd = mode->psd_values[NL80211_REG_REGULAR_CLIENT_LPI + ap_type];
|
|
+#ifdef REG_DOM_SUPPORT_TX_POWER
|
|
+ tx_pwr = psd * 2;
|
|
+#else
|
|
tx_pwr = (hostapd_get_6g_tx_power(hapd, ap_type, tx_pwr_cat) * 2);
|
|
+#endif /* REG_DOM_SUPPORT_TX_POWER */
|
|
eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn, tx_pwr_cat, tx_pwr);
|
|
|
|
return eid;
|
|
--- a/src/ap/ieee802_11_he.c
|
|
+++ b/src/ap/ieee802_11_he.c
|
|
@@ -235,10 +235,16 @@ u8 * hostapd_eid_he_operation(struct hos
|
|
* - 1 (Standard Power Access Point)
|
|
* - Reserved in 5GHz and 2Ghz bands
|
|
*/
|
|
+
|
|
+ u8 ap_type = hostapd_get_he_6ghz_reg_pwr_type(hapd->iconf);
|
|
+
|
|
if (seg1)
|
|
- *pos++ = 3;
|
|
+ *pos++ = 3 | (IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO &
|
|
+ (ap_type << IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO_LSB));
|
|
else
|
|
- *pos++ = center_idx_to_bw_6ghz(seg0);
|
|
+ *pos++ = center_idx_to_bw_6ghz(seg0) |
|
|
+ (IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO &
|
|
+ (ap_type << IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO_LSB));
|
|
|
|
/* Channel Center Freq Seg0/Seg1 */
|
|
if (hapd->iconf->he_oper_chwidth == 2) {
|
|
--- a/src/common/hw_features_common.c
|
|
+++ b/src/common/hw_features_common.c
|
|
@@ -403,7 +403,7 @@ int hostapd_set_freq_params(struct hosta
|
|
int sec_channel_offset,
|
|
int oper_chwidth, int center_segment0,
|
|
int center_segment1, u32 vht_caps,
|
|
- struct he_capabilities *he_cap)
|
|
+ struct he_capabilities *he_cap, u8 reg_6g_pwr_mode)
|
|
{
|
|
if (!he_cap)
|
|
he_enabled = 0;
|
|
@@ -486,6 +486,8 @@ int hostapd_set_freq_params(struct hosta
|
|
data->ht_enabled = 0;
|
|
data->vht_enabled = 0;
|
|
|
|
+ /* Append 6G reg power info */
|
|
+ data->he_6ghz_reg_pwr_type = reg_6g_pwr_mode;
|
|
return 0;
|
|
}
|
|
|
|
--- a/src/common/hw_features_common.h
|
|
+++ b/src/common/hw_features_common.h
|
|
@@ -44,7 +44,7 @@ int hostapd_set_freq_params(struct hosta
|
|
int sec_channel_offset,
|
|
int oper_chwidth, int center_segment0,
|
|
int center_segment1, u32 vht_caps,
|
|
- struct he_capabilities *he_caps);
|
|
+ struct he_capabilities *he_caps, u8 reg_6g_pwr_mode);
|
|
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
|
|
int disabled);
|
|
int ieee80211ac_cap_check(u32 hw, u32 conf);
|
|
--- a/src/common/ieee802_11_defs.h
|
|
+++ b/src/common/ieee802_11_defs.h
|
|
@@ -1963,6 +1963,17 @@ enum reg_6g_client_type {
|
|
|
|
/* same Max Tx Pwr for all 20MHz bands */
|
|
#define DEFAULT_MAX_TX_POWER_COUNT_6G 0
|
|
+
|
|
+/*
|
|
+ * REG_DOM_SUPPORT_TX_POWER - regulatory domain
|
|
+ * supports tx power values or not.
|
|
+ *
|
|
+ * If this macro is undefined, tx-power macros will be used to
|
|
+ * get the tx-power, otherwise psd values from regulatory domain
|
|
+ * will be taken
|
|
+ */
|
|
+#define REG_DOM_SUPPORT_TX_POWER 1
|
|
+
|
|
/*
|
|
* These tx-power macros are present till the 6G regdomains are defined to
|
|
* support tx-power values for various client types.
|
|
@@ -2350,6 +2361,9 @@ struct ieee80211_spatial_reuse {
|
|
#define HE_OPERATION_BSS_COLOR_OFFSET 24
|
|
#define HE_OPERATION_BSS_COLOR_MAX 64
|
|
|
|
+#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x38
|
|
+#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO_LSB 3
|
|
+
|
|
/* Spatial Reuse defines */
|
|
#define SPATIAL_REUSE_SRP_DISALLOWED BIT(0)
|
|
#define SPATIAL_REUSE_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1)
|
|
--- a/src/drivers/driver.h
|
|
+++ b/src/drivers/driver.h
|
|
@@ -299,6 +299,12 @@ struct hostapd_hw_modes {
|
|
* for IEEE 802.11ay EDMG configuration.
|
|
*/
|
|
struct ieee80211_edmg_config edmg;
|
|
+
|
|
+ /**
|
|
+ * This array is used to store the psd value of each power mode
|
|
+ * supported in 6G band.
|
|
+ */
|
|
+ s8 psd_values[NL80211_REG_NUM_POWER_MODES];
|
|
};
|
|
|
|
|
|
@@ -777,6 +783,17 @@ struct hostapd_freq_params {
|
|
* for IEEE 802.11ay EDMG configuration.
|
|
*/
|
|
struct ieee80211_edmg_config edmg;
|
|
+
|
|
+ /**
|
|
+ * he_6ghz_reg_pwr_type - 6G regulatory power mode
|
|
+ * Since many operation related to channel for 6G depends on the
|
|
+ * power mode, this parameter is added here.
|
|
+ *
|
|
+ * 0 - LPI_AP
|
|
+ * 1 - SP_AP
|
|
+ * 2 - VLP_AP
|
|
+ */
|
|
+ u8 he_6ghz_reg_pwr_type;
|
|
};
|
|
|
|
/**
|
|
@@ -2938,12 +2955,13 @@ struct wpa_driver_ops {
|
|
* @num_modes: Variable for returning the number of returned modes
|
|
* flags: Variable for returning hardware feature flags
|
|
* @dfs: Variable for returning DFS region (HOSTAPD_DFS_REGION_*)
|
|
+ * @pwr_mode: Variable required for processing the support data for 6G
|
|
* Returns: Pointer to allocated hardware data on success or %NULL on
|
|
* failure. Caller is responsible for freeing this.
|
|
*/
|
|
struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
|
|
u16 *num_modes,
|
|
- u16 *flags, u8 *dfs);
|
|
+ u16 *flags, u8 *dfs, u8 pwr_mode);
|
|
|
|
/**
|
|
* send_mlme - Send management frame from MLME
|
|
--- a/src/drivers/driver_hostap.c
|
|
+++ b/src/drivers/driver_hostap.c
|
|
@@ -1099,7 +1099,8 @@ static int hostap_sta_disassoc(void *pri
|
|
|
|
static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
|
|
u16 *num_modes,
|
|
- u16 *flags, u8 *dfs)
|
|
+ u16 *flags, u8 *dfs,
|
|
+ u8 pwr_mode)
|
|
{
|
|
struct hostapd_hw_modes *mode;
|
|
int i, clen, rlen;
|
|
--- a/src/drivers/driver_nl80211.c
|
|
+++ b/src/drivers/driver_nl80211.c
|
|
@@ -5038,6 +5038,19 @@ static int nl80211_set_channel(struct i8
|
|
return -1;
|
|
}
|
|
|
|
+#ifdef CONFIG_IEEE80211AX
|
|
+ if (freq->freq && is_6ghz_freq(freq->freq)) {
|
|
+ wpa_printf(MSG_DEBUG, "%s: 6g_reg_pwr_mode=%d",
|
|
+ __func__, freq->he_6ghz_reg_pwr_type);
|
|
+ if (nla_put_u8(msg, NL80211_ATTR_6G_REG_POWER_MODE,
|
|
+ freq->he_6ghz_reg_pwr_type)) {
|
|
+ wpa_printf(MSG_ERROR,
|
|
+ "%s: Failed to put 6g_reg_pwr_mode", __func__);
|
|
+ nlmsg_free(msg);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+#endif /* CONFIG_IEEE80211AX */
|
|
ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
|
|
if (ret == 0) {
|
|
bss->freq = freq->freq;
|
|
@@ -8303,7 +8316,7 @@ static int wpa_driver_nl80211_send_actio
|
|
int i;
|
|
|
|
modes = nl80211_get_hw_feature_data(bss, &num_modes,
|
|
- &flags, &dfs_domain);
|
|
+ &flags, &dfs_domain, 0);
|
|
if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
|
|
ieee80211_is_dfs(bss->freq, modes, num_modes))
|
|
offchanok = 0;
|
|
--- a/src/drivers/driver_nl80211.h
|
|
+++ b/src/drivers/driver_nl80211.h
|
|
@@ -285,7 +285,7 @@ int nl80211_send_monitor(struct wpa_driv
|
|
int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv);
|
|
struct hostapd_hw_modes *
|
|
nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
|
|
- u8 *dfs_domain);
|
|
+ u8 *dfs_domain, u8 pwr_mode);
|
|
|
|
int process_global_event(struct nl_msg *msg, void *arg);
|
|
int process_bss_event(struct nl_msg *msg, void *arg);
|
|
--- a/src/drivers/driver_nl80211_capa.c
|
|
+++ b/src/drivers/driver_nl80211_capa.c
|
|
@@ -1454,6 +1454,7 @@ struct phy_info_arg {
|
|
int last_mode, last_chan_idx;
|
|
int failed;
|
|
u8 dfs_domain;
|
|
+ u8 pwr_mode;
|
|
};
|
|
|
|
static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
|
|
@@ -2102,7 +2103,9 @@ static void nl80211_set_ht40_mode_sec(st
|
|
|
|
|
|
static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
|
|
- struct phy_info_arg *results)
|
|
+ struct phy_info_arg *results,
|
|
+ u8 config_pwr_mode, u8 pwr_mode,
|
|
+ s8 psd)
|
|
{
|
|
u16 m;
|
|
|
|
@@ -2112,10 +2115,16 @@ static void nl80211_reg_rule_max_eirp(u3
|
|
|
|
for (c = 0; c < mode->num_channels; c++) {
|
|
struct hostapd_channel_data *chan = &mode->channels[c];
|
|
+
|
|
+ if (is_6ghz_freq(chan->freq) && config_pwr_mode != pwr_mode)
|
|
+ continue;
|
|
+
|
|
if ((u32) chan->freq - 10 >= start &&
|
|
(u32) chan->freq + 10 <= end)
|
|
chan->max_tx_power = max_eirp;
|
|
}
|
|
+ /* Update the psd rules */
|
|
+ mode->psd_values[pwr_mode] = psd;
|
|
}
|
|
}
|
|
|
|
@@ -2288,6 +2297,7 @@ static int nl80211_get_reg(struct nl_msg
|
|
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
|
|
};
|
|
|
|
+ u8 config_pwr_mode = results->pwr_mode;
|
|
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
|
genlmsg_attrlen(gnlh, 0), NULL);
|
|
if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
|
|
@@ -2312,6 +2322,8 @@ static int nl80211_get_reg(struct nl_msg
|
|
nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
|
|
{
|
|
u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
|
|
+ u8 pwr_mode = 0;
|
|
+ s8 psd = 0;
|
|
nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
|
|
nla_data(nl_rule), nla_len(nl_rule), reg_policy);
|
|
if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
|
|
@@ -2325,9 +2337,13 @@ static int nl80211_get_reg(struct nl_msg
|
|
max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
|
|
if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
|
|
flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
|
|
+ if (tb_rule[NL80211_ATTR_REG_POWER_MODE])
|
|
+ pwr_mode = nla_get_u8(tb_rule[NL80211_ATTR_REG_POWER_MODE]);
|
|
+ if (tb_rule[NL80211_ATTR_POWER_RULE_PSD])
|
|
+ psd = (s8) nla_get_u8(tb_rule[NL80211_ATTR_POWER_RULE_PSD]);
|
|
|
|
- wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
|
|
- start, end, max_bw, max_eirp,
|
|
+ wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm pwr_mode: %u psd: %d%s%s%s%s%s%s%s%s",
|
|
+ start, end, max_bw, max_eirp, pwr_mode, psd,
|
|
flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
|
|
flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
|
|
flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
|
|
@@ -2341,7 +2357,8 @@ static int nl80211_get_reg(struct nl_msg
|
|
nl80211_reg_rule_ht40(start, end, results);
|
|
if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
|
|
nl80211_reg_rule_max_eirp(start, end, max_eirp,
|
|
- results);
|
|
+ results, config_pwr_mode,
|
|
+ pwr_mode, psd);
|
|
}
|
|
|
|
nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
|
|
@@ -2441,7 +2458,7 @@ static void nl80211_dump_chan_list(struc
|
|
|
|
struct hostapd_hw_modes *
|
|
nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
|
|
- u8 *dfs_domain)
|
|
+ u8 *dfs_domain, u8 pwr_mode)
|
|
{
|
|
u32 feat;
|
|
struct i802_bss *bss = priv;
|
|
@@ -2454,6 +2471,7 @@ nl80211_get_hw_feature_data(void *priv,
|
|
.last_mode = -1,
|
|
.failed = 0,
|
|
.dfs_domain = 0,
|
|
+ .pwr_mode = pwr_mode
|
|
};
|
|
|
|
*num_modes = 0;
|
|
--- a/src/drivers/driver_nl80211_event.c
|
|
+++ b/src/drivers/driver_nl80211_event.c
|
|
@@ -1919,7 +1919,7 @@ static unsigned int chan_to_freq(struct
|
|
int i;
|
|
|
|
modes = nl80211_get_hw_feature_data(drv->first_bss, &num_modes,
|
|
- &flags, &dfs_domain);
|
|
+ &flags, &dfs_domain, 0);
|
|
if (!modes) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"nl80211: Fetching hardware mode failed");
|
|
--- a/src/drivers/nl80211_copy.h
|
|
+++ b/src/drivers/nl80211_copy.h
|
|
@@ -3127,6 +3127,8 @@ enum nl80211_attrs {
|
|
|
|
NL80211_ATTR_BEACON_TX_MODE,
|
|
|
|
+ NL80211_ATTR_6G_REG_POWER_MODE,
|
|
+
|
|
/* add attributes here, update the policy in nl80211.c */
|
|
|
|
__NL80211_ATTR_AFTER_LAST,
|
|
@@ -3791,6 +3797,20 @@ enum nl80211_band_attr {
|
|
|
|
#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
|
|
|
|
+enum nl80211_regulatory_power_modes {
|
|
+ NL80211_REG_AP_LPI,
|
|
+ NL80211_REG_AP_SP,
|
|
+ NL80211_REG_AP_VLP,
|
|
+ NL80211_REG_REGULAR_CLIENT_LPI,
|
|
+ NL80211_REG_REGULAR_CLIENT_SP,
|
|
+ NL80211_REG_REGULAR_CLIENT_VLP,
|
|
+ NL80211_REG_SUBORDINATE_CLIENT_LPI,
|
|
+ NL80211_REG_SUBORDINATE_CLIENT_SP,
|
|
+ NL80211_REG_SUBORDINATE_CLIENT_VLP,
|
|
+
|
|
+ NL80211_REG_NUM_POWER_MODES,
|
|
+};
|
|
+
|
|
/**
|
|
* enum nl80211_wmm_rule - regulatory wmm rule
|
|
*
|
|
@@ -4015,6 +4035,9 @@ 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_ATTR_REG_POWER_MODE: the regulatory power mode for 6G rules
|
|
* @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
|
|
* currently defined
|
|
* @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
|
|
@@ -4032,6 +4055,10 @@ enum nl80211_reg_rule_attr {
|
|
|
|
NL80211_ATTR_DFS_CAC_TIME,
|
|
|
|
+ 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
|
|
--- a/wpa_supplicant/driver_i.h
|
|
+++ b/wpa_supplicant/driver_i.h
|
|
@@ -305,7 +305,7 @@ wpa_drv_get_hw_feature_data(struct wpa_s
|
|
if (wpa_s->driver->get_hw_feature_data)
|
|
return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv,
|
|
num_modes, flags,
|
|
- dfs_domain);
|
|
+ dfs_domain, 0);
|
|
return NULL;
|
|
}
|
|
|
|
--- a/wpa_supplicant/mesh.c
|
|
+++ b/wpa_supplicant/mesh.c
|
|
@@ -231,7 +231,7 @@ static int wpas_mesh_update_freq_params(
|
|
hostapd_get_oper_centr_freq_seg0_idx(ifmsh->conf),
|
|
hostapd_get_oper_centr_freq_seg1_idx(ifmsh->conf),
|
|
ifmsh->conf->vht_capab,
|
|
- he_capab)) {
|
|
+ he_capab, ifmsh->conf->he_6ghz_reg_pwr_type)) {
|
|
wpa_printf(MSG_ERROR, "Error updating mesh frequency params");
|
|
wpa_supplicant_mesh_deinit(wpa_s, true);
|
|
return -1;
|
|
--- a/wpa_supplicant/wpa_supplicant.c
|
|
+++ b/wpa_supplicant/wpa_supplicant.c
|
|
@@ -2788,7 +2788,7 @@ skip_to_6ghz:
|
|
vht_freq.vht_enabled, vht_freq.he_enabled,
|
|
freq->sec_channel_offset,
|
|
chwidth, seg0, seg1, vht_caps,
|
|
- &mode->he_capab[ieee80211_mode]) != 0)
|
|
+ &mode->he_capab[ieee80211_mode], 0) != 0)
|
|
return;
|
|
|
|
*freq = vht_freq;
|
|
--- a/hostapd/config_file.c
|
|
+++ b/hostapd/config_file.c
|
|
@@ -3510,6 +3510,15 @@ static int hostapd_config_fill(struct ho
|
|
}
|
|
} else if (os_strcmp(buf, "he_6ghz_reg_pwr_type") == 0) {
|
|
conf->he_6ghz_reg_pwr_type = atoi(pos);
|
|
+ if (conf->he_6ghz_reg_pwr_type > AP_TYPE_6GHZ_VERY_LOW_POWER_AP ||
|
|
+ conf->he_6ghz_reg_pwr_type < AP_TYPE_6GHZ_INDOOR_AP) {
|
|
+ wpa_printf(MSG_ERROR,
|
|
+ "Line %d: Invalid 6ghz regulatory power type('%s') "
|
|
+ "[min: %d and max: %d]",
|
|
+ line, pos, AP_TYPE_6GHZ_INDOOR_AP,
|
|
+ AP_TYPE_6GHZ_VERY_LOW_POWER_AP);
|
|
+ return 1;
|
|
+ }
|
|
} else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
|
|
conf->he_oper_chwidth = atoi(pos);
|
|
} else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
|