wifi: cfg80211/mac80211: implement dot11ExtendedRegInfoSupport

Implement dot11ExtendedRegInfoSupport to advertise non-AP station
regulatory power capability as part of regulatory connectivity
element in (Re)Association request frames so that AP can achieve
maximum client connectivity. Control field which was interpreted
using value of 3-bits B5 to B3, now uses value of 4-bits B6 to B3 to
interpret the type of AP. Hence update IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO
to parse 4-bits control field. If older AP still updates only 3-bits
value of control field, station can still interpret the value as per
section E.2.7 of IEEE 802.11 REVme D7.0 and support the appropriate
AP type.

Also update IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP as the value of
standard power AP is changed to 8 instead of 4 so that AP can support both
LPI AP and SP AP to maximize the connectivity with stations. For backward
compatibility, keeping value 4 as old AP by limiting it to SP AP only.

Signed-off-by: Somashekhar Puttagangaiah <somashekhar.puttagangaiah@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250609213232.90cdef116aad.I85da390fbee59355e3855691933e6a5e55c47ac4@changeid
[fix kernel-doc]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Somashekhar Puttagangaiah
2025-06-09 21:35:26 +03:00
committed by Johannes Berg
parent a9681efa1b
commit a11ec0dc92
5 changed files with 89 additions and 6 deletions

View File

@@ -2837,11 +2837,12 @@ static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len)
#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000
#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000
#define IEEE80211_6GHZ_CTRL_REG_LPI_AP 0
#define IEEE80211_6GHZ_CTRL_REG_SP_AP 1
#define IEEE80211_6GHZ_CTRL_REG_VLP_AP 2
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP 3
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP 4
#define IEEE80211_6GHZ_CTRL_REG_LPI_AP 0
#define IEEE80211_6GHZ_CTRL_REG_SP_AP 1
#define IEEE80211_6GHZ_CTRL_REG_VLP_AP 2
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP 3
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD 4
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP 8
/**
* struct ieee80211_he_6ghz_oper - HE 6 GHz operation Information field
@@ -2859,13 +2860,31 @@ struct ieee80211_he_6ghz_oper {
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ 2
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ 3
#define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4
#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x38
#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x78
u8 control;
u8 ccfs0;
u8 ccfs1;
u8 minrate;
} __packed;
/**
* enum ieee80211_reg_conn_bits - represents Regulatory connectivity field bits.
*
* This enumeration defines bit flags used to represent regulatory connectivity
* field bits.
*
* @IEEE80211_REG_CONN_LPI_VALID: Indicates whether the LPI bit is valid.
* @IEEE80211_REG_CONN_LPI_VALUE: Represents the value of the LPI bit.
* @IEEE80211_REG_CONN_SP_VALID: Indicates whether the SP bit is valid.
* @IEEE80211_REG_CONN_SP_VALUE: Represents the value of the SP bit.
*/
enum ieee80211_reg_conn_bits {
IEEE80211_REG_CONN_LPI_VALID = BIT(0),
IEEE80211_REG_CONN_LPI_VALUE = BIT(1),
IEEE80211_REG_CONN_SP_VALID = BIT(2),
IEEE80211_REG_CONN_SP_VALUE = BIT(3),
};
/* transmit power interpretation type of transmit power envelope element */
enum ieee80211_tx_power_intrpt_type {
IEEE80211_TPE_LOCAL_EIRP,
@@ -3847,6 +3866,7 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_FILS_PUBLIC_KEY = 12,
WLAN_EID_EXT_FILS_NONCE = 13,
WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14,
WLAN_EID_EXT_DH_PARAMETER = 32,
WLAN_EID_EXT_HE_CAPABILITY = 35,
WLAN_EID_EXT_HE_OPERATION = 36,
WLAN_EID_EXT_UORA = 37,
@@ -3870,6 +3890,8 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_EHT_CAPABILITY = 108,
WLAN_EID_EXT_TID_TO_LINK_MAPPING = 109,
WLAN_EID_EXT_BANDWIDTH_INDICATION = 135,
WLAN_EID_EXT_KNOWN_STA_IDENTIFCATION = 136,
WLAN_EID_EXT_NON_AP_STA_REG_CON = 137,
};
/* Action category code */

View File

@@ -2642,6 +2642,8 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata,
const struct ieee80211_supported_band *sband,
const struct ieee80211_conn_settings *conn);
int ieee80211_put_reg_conn(struct sk_buff *skb,
enum ieee80211_channel_flags flags);
/* channel management */
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,

View File

@@ -1641,6 +1641,30 @@ static size_t ieee80211_add_before_he_elems(struct sk_buff *skb,
return noffset;
}
static size_t ieee80211_add_before_reg_conn(struct sk_buff *skb,
const u8 *elems, size_t elems_len,
size_t offset)
{
static const u8 before_reg_conn[] = {
/*
* no need to list the ones split off before HE
* or generated here
*/
WLAN_EID_EXTENSION, WLAN_EID_EXT_DH_PARAMETER,
WLAN_EID_EXTENSION, WLAN_EID_EXT_KNOWN_STA_IDENTIFCATION,
};
size_t noffset;
if (!elems_len)
return offset;
noffset = ieee80211_ie_split(elems, elems_len, before_reg_conn,
ARRAY_SIZE(before_reg_conn), offset);
skb_put_data(skb, elems + offset, noffset - offset);
return noffset;
}
#define PRESENT_ELEMS_MAX 8
#define PRESENT_ELEM_EXT_OFFS 0x100
@@ -1801,6 +1825,22 @@ ieee80211_add_link_elems(struct ieee80211_sub_if_data *sdata,
ieee80211_put_he_6ghz_cap(skb, sdata, smps_mode);
}
/*
* if present, add any custom IEs that go before regulatory
* connectivity element
*/
offset = ieee80211_add_before_reg_conn(skb, extra_elems,
extra_elems_len, offset);
if (sband->band == NL80211_BAND_6GHZ) {
/*
* as per Section E.2.7 of IEEE 802.11 REVme D7.0, non-AP STA
* capable of operating on the 6 GHz band shall transmit
* regulatory connectivity element.
*/
ieee80211_put_reg_conn(skb, chan->flags);
}
/*
* careful - need to know about all the present elems before
* calling ieee80211_assoc_add_ml_elem(), so add this one if
@@ -5931,6 +5971,7 @@ ieee80211_ap_power_type(u8 control)
return IEEE80211_REG_LPI_AP;
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
return IEEE80211_REG_SP_AP;
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
return IEEE80211_REG_VLP_AP;

View File

@@ -2556,6 +2556,23 @@ int ieee80211_put_he_cap(struct sk_buff *skb,
return 0;
}
int ieee80211_put_reg_conn(struct sk_buff *skb,
enum ieee80211_channel_flags flags)
{
u8 reg_conn = IEEE80211_REG_CONN_LPI_VALID |
IEEE80211_REG_CONN_LPI_VALUE |
IEEE80211_REG_CONN_SP_VALID;
if (!(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT))
reg_conn |= IEEE80211_REG_CONN_SP_VALUE;
skb_put_u8(skb, WLAN_EID_EXTENSION);
skb_put_u8(skb, 1 + sizeof(reg_conn));
skb_put_u8(skb, WLAN_EID_EXT_NON_AP_STA_REG_CON);
skb_put_u8(skb, reg_conn);
return 0;
}
int ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode)

View File

@@ -2231,6 +2231,7 @@ cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len)
return IEEE80211_REG_LPI_AP;
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
return IEEE80211_REG_SP_AP;
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
return IEEE80211_REG_VLP_AP;