wifi: mac80211: parse enhanced critical updates field

For association and link reconfiguration response, parse
and store the enhanced BSS parameter change counter out
of the enhanced critical updates field in the multi-link
common info or per-STA profile. These are required for
UHR connections.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260714134154.adb9fc29252d.I625580fbadbbf4a1440d88d3675586477f1a3263@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2026-07-14 13:43:17 +03:00
parent 40918ce98b
commit c4b825b50c
3 changed files with 134 additions and 2 deletions

View File

@ -481,6 +481,7 @@ struct ieee80211_multi_link_elem {
#define IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP 0x0100
#define IEEE80211_MLC_BASIC_PRES_MLD_ID 0x0200
#define IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP 0x0400
#define IEEE80211_MLC_BASIC_PRES_ENH_CRIT_UPD 0x0800
#define IEEE80211_MED_SYNC_DELAY_DURATION 0x00ff
#define IEEE80211_MED_SYNC_DELAY_SYNC_OFDM_ED_THRESH 0x0f00
@ -809,6 +810,49 @@ static inline u16 ieee80211_mle_get_ext_mld_capa_op(const u8 *data)
return get_unaligned_le16(common);
}
/**
* ieee80211_mle_get_enh_crit_upd_info - returns the enhanced critical
* updates information
* @data: pointer to the multi-link element
* Return: the enhanced critical updates information field, or %NULL
*
* The element is assumed to be of the correct type (BASIC) and big enough,
* this must be checked using ieee80211_mle_type_ok().
*/
static inline const struct ieee80211_enh_crit_upd *
ieee80211_mle_get_enh_crit_upd_info(const u8 *data)
{
const struct ieee80211_multi_link_elem *mle = (const void *)data;
u16 control = le16_to_cpu(mle->control);
const u8 *common = mle->variable;
/*
* common points now at the beginning of
* ieee80211_mle_basic_common_info
*/
common += sizeof(struct ieee80211_mle_basic_common_info);
if (!(control & IEEE80211_MLC_BASIC_PRES_ENH_CRIT_UPD))
return NULL;
if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID)
common += 1;
if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)
common += 1;
if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)
common += 2;
if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA)
common += 2;
if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)
common += 2;
if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID)
common += 1;
if (control & IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP)
common += 2;
return (const void *)common;
}
/**
* ieee80211_mle_get_mld_id - returns the MLD ID
* @data: pointer to the multi-link element
@ -883,6 +927,8 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
common += 1;
if (control & IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP)
common += 2;
if (control & IEEE80211_MLC_BASIC_PRES_ENH_CRIT_UPD)
common += 1;
break;
case IEEE80211_ML_CONTROL_TYPE_PREQ:
common += sizeof(struct ieee80211_mle_preq_common_info);
@ -959,6 +1005,8 @@ enum ieee80211_mle_subelems {
#define IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT 0x0200
#define IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE 0x0400
#define IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT 0x0800
#define IEEE80211_MLE_STA_CONTROL_ENH_CRIT_UPD_PRESENT 0x1000
#define IEEE80211_MLE_STA_CONTROL_AP_CONDUCTED_TX_PWR_PRESENT 0x2000
struct ieee80211_mle_per_sta_profile {
__le16 control;
@ -1004,6 +1052,12 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data,
if (control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT)
info_len += 1;
if (control & IEEE80211_MLE_STA_CONTROL_ENH_CRIT_UPD_PRESENT)
info_len += 1;
if (control & IEEE80211_MLE_STA_CONTROL_AP_CONDUCTED_TX_PWR_PRESENT)
info_len += 1;
return prof->sta_info_len >= info_len &&
fixed + prof->sta_info_len - 1 <= len;
}
@ -1044,6 +1098,44 @@ ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(const struct ieee80211_mle_per_sta
return *pos;
}
/**
* ieee80211_mle_basic_sta_prof_enh_crit_upd - get per-STA profile enhanced
* critical updates field
* @prof: the per-STA profile, having been checked with
* ieee80211_mle_basic_sta_prof_size_ok() for the correct length
*
* Return: The enhanced critical updates field if present, %NULL otherwise.
*/
static inline const struct ieee80211_enh_crit_upd *
ieee80211_mle_basic_sta_prof_enh_crit_upd(const struct ieee80211_mle_per_sta_profile *prof)
{
u16 control = le16_to_cpu(prof->control);
const u8 *pos = prof->variable;
if (!(control & IEEE80211_MLE_STA_CONTROL_ENH_CRIT_UPD_PRESENT))
return NULL;
if (control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT)
pos += 6;
if (control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT)
pos += 2;
if (control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT)
pos += 8;
if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT)
pos += 2;
if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE &&
control & IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT) {
if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE)
pos += 2;
else
pos += 1;
}
if (control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT)
pos += 1;
return (const void *)pos;
}
#define IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID 0x000f
#define IEEE80211_MLE_STA_RECONF_CONTROL_COMPLETE_PROFILE 0x0010
#define IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT 0x0020

View File

@ -790,6 +790,10 @@ struct ieee80211_bss_npca_params {
* be updated to 1, even if bss_param_ch_cnt didn't change. This allows
* the link to know that it heard the latest value from its own beacon
* (as opposed to hearing its value from another link's beacon).
* @enh_bss_param_ch_cnt: In BSS-mode, the enhanced BSS parameters change
* counter. See @bss_param_ch_cnt, it works the same way.
* @enh_bss_param_ch_cnt_link_id: In BSS-mode, the link_id for the enhanced
* BSS parameter change counter, see @bss_param_ch_cnt_link_id.
* @s1g_long_beacon_period: number of beacon intervals between each long
* beacon transmission.
* @npca: NPCA parameters
@ -894,6 +898,8 @@ struct ieee80211_bss_conf {
u8 bss_param_ch_cnt;
u8 bss_param_ch_cnt_link_id;
u8 enh_bss_param_ch_cnt;
u8 enh_bss_param_ch_cnt_link_id;
u8 s1g_long_beacon_period;

View File

@ -5931,11 +5931,28 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(elems->prof);
bss_conf->bss_param_ch_cnt = bss_param_ch_cnt;
bss_conf->bss_param_ch_cnt_link_id = link_id;
if (link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_UHR) {
const struct ieee80211_enh_crit_upd *enh_crit_upd;
enh_crit_upd = ieee80211_mle_basic_sta_prof_enh_crit_upd(elems->prof);
if (!enh_crit_upd) {
link_info(link,
"per-STA profile missing enhanced critical updates\n");
ret = false;
goto out;
}
bss_conf->enh_bss_param_ch_cnt =
u8_get_bits(enh_crit_upd->v,
IEEE80211_ENH_CRIT_UPD_EBPCC);
bss_conf->enh_bss_param_ch_cnt_link_id = link_id;
}
}
if (link_id == assoc_data->assoc_link_id && elems->ml_basic) {
int bss_param_ch_cnt =
ieee80211_mle_get_bss_param_ch_cnt((const void *)elems->ml_basic);
const void *mle = (const void *)elems->ml_basic;
int bss_param_ch_cnt = ieee80211_mle_get_bss_param_ch_cnt(mle);
if (bss_param_ch_cnt < 0) {
sdata_info(sdata,
@ -5945,6 +5962,23 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
}
bss_conf->bss_param_ch_cnt = bss_param_ch_cnt;
bss_conf->bss_param_ch_cnt_link_id = link_id;
if (link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_UHR) {
const struct ieee80211_enh_crit_upd *enh_crit_upd;
enh_crit_upd = ieee80211_mle_get_enh_crit_upd_info(mle);
if (!enh_crit_upd) {
link_info(link,
"No enhanced critical updates in assoc response\n");
ret = false;
goto out;
}
bss_conf->enh_bss_param_ch_cnt =
u8_get_bits(enh_crit_upd->v,
IEEE80211_ENH_CRIT_UPD_EBPCC);
bss_conf->enh_bss_param_ch_cnt_link_id = link_id;
}
}
if (!is_s1g && !elems->supp_rates) {