[PATCH ath-next] wifi: ath12k: Add EHT capabilities to scan probe frame
Rameshkumar Sundaram
rameshkumar.sundaram at oss.qualcomm.com
Mon Sep 28 10:24:34 PDT 2026
On 9/21/2026 10:01 AM, Gaole Zhang wrote:
> Currently, ath12k does not set the EHT flag in scan channel
> information and does not send WMI_VDEV_SET_IE_CMDID with the EHT
> Capabilities element configuration. As a result, EHT-capable STA
> Probe Requests do not contain the EHT Capabilities element.
>
> Without this element, AP can't identify the STA as EHT-capable
> during active scanning and may omit EHT-related information from its
> Probe Response. This can result in incomplete scan information and
> prevent userspace from correctly determining the AP's EHT capabilities.
>
> Set the EHT scan flag and configure the EHT Capabilities element so
> that ath12k includes it in STA Probe Request frames.
>
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
>
> Signed-off-by: Gaole Zhang <gaole.zhang at oss.qualcomm.com>
> ---
> drivers/net/wireless/ath/ath12k/core.h | 6 ++++
> drivers/net/wireless/ath/ath12k/mac.c | 29 +++++++++++++--
> drivers/net/wireless/ath/ath12k/reg.c | 4 +++
> drivers/net/wireless/ath/ath12k/wmi.c | 50 ++++++++++++++++++++++++++
> drivers/net/wireless/ath/ath12k/wmi.h | 23 +++++++++++-
> 5 files changed, 109 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index a98fc6e0699d..e7373a523dc3 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -1394,6 +1394,12 @@ static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah, u8 radio_idx)
> return &ah->radio[radio_idx];
> }
>
> +static inline bool ath12k_is_11be_enabled(struct ath12k_base *ab)
> +{
> + return test_bit(WMI_TLV_SERVICE_11BE, ab->wmi_ab.svc_map) &&
> + !ath12k_acpi_get_disable_11be(ab);
> +}
> +
> static inline struct ath12k_hw *ath12k_ar_to_ah(struct ath12k *ar)
> {
> return ar->ah;
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index d4116ba0da08..f353af63c5eb 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5602,6 +5602,25 @@ ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar)
> return ATH12K_FIRST_SCAN_LINK;
> }
>
> +static int ath12k_mac_set_scan_eht_cap_ie(struct ath12k *ar,
> + struct ath12k_link_vif *arvif,
> + const u8 *ies, size_t ies_len)
> +{
> + const struct element *eht_cap;
> +
> + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
> +
> + eht_cap = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_CAPABILITY, ies,
> + ies_len);
> + if (!eht_cap || eht_cap->datalen <= 1)
> + return 0;
> +
> + return ath12k_wmi_vdev_set_ie(ar, arvif->vdev_id,
> + WLAN_EID_EXTENSION,
> + eht_cap->data, eht_cap->datalen,
> + WMI_SET_VDEV_IE_BAND_ALL);
> +}
> +
> static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
> struct ieee80211_vif *vif,
> struct ieee80211_scan_request *hw_req,
> @@ -5718,6 +5737,13 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
> goto exit;
> }
> arg->extraie.len = req->ie_len;
> + ret = ath12k_mac_set_scan_eht_cap_ie(ar, arvif, req->ie,
> + req->ie_len);
> + if (ret) {
> + ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
> + "failed to set eht cap ie, ret %d\n", ret);
> + goto exit;
> + }
> }
>
> if (req->n_ssids) {
> @@ -8983,8 +9009,7 @@ static void ath12k_mac_copy_eht_cap(struct ath12k *ar,
>
> memset(eht_cap, 0, sizeof(struct ieee80211_sta_eht_cap));
>
> - if (!(test_bit(WMI_TLV_SERVICE_11BE, ar->ab->wmi_ab.svc_map)) ||
> - ath12k_acpi_get_disable_11be(ar->ab))
> + if (!ath12k_is_11be_enabled(ar->ab))
> return;
>
> eht_cap->has_eht = true;
> diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
> index 89abf2e87ad1..0aba1e74a3e9 100644
> --- a/drivers/net/wireless/ath/ath12k/reg.c
> +++ b/drivers/net/wireless/ath/ath12k/reg.c
> @@ -140,6 +140,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
> enum nl80211_band band;
> int num_channels = 0;
> int i, ret = 0;
> + bool has_eht;
>
> if (ar->ah->state == ATH12K_HW_STATE_RESTARTING)
> return 0;
> @@ -180,6 +181,8 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
>
> ch = arg->channel;
>
> + has_eht = ath12k_is_11be_enabled(ar->ab);
> +
> for (band = 0; band < NUM_NL80211_BANDS; band++) {
> if (!(ar->mac.sbands[band].channels && bands[band]))
> continue;
> @@ -201,6 +204,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
> ch->allow_ht = true;
> ch->allow_vht = true;
> ch->allow_he = true;
> + ch->allow_eht = has_eht;
>
> ch->dfs_set =
> !!(channel->flags & IEEE80211_CHAN_RADAR);
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index a63bbda0219c..5fe7af731a4e 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -2005,6 +2005,54 @@ int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id,
> return ret;
> }
>
> +int ath12k_wmi_vdev_set_ie(struct ath12k *ar, u32 vdev_id, u32 ie_id,
> + const u8 *ie, size_t ie_len, u32 band)
> +{
> + struct ath12k_wmi_pdev *wmi = ar->wmi;
> + struct wmi_vdev_set_ie_cmd *cmd;
> + struct sk_buff *skb;
> + struct wmi_tlv *tlv;
> + size_t aligned_len;
> + int ret, len;
> + void *ptr;
> +
> + aligned_len = roundup(ie_len, sizeof(u32));
> + len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len;
> +
> + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
> + if (!skb)
> + return -ENOMEM;
> +
> + ptr = skb->data;
> + cmd = ptr;
> + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_SET_IE_CMD,
> + sizeof(*cmd));
> + cmd->vdev_id = cpu_to_le32(vdev_id);
> + cmd->ie_id = cpu_to_le32(ie_id);
This appears to be passing only WLAN_EID_EXTENSION.
How does the firmware make use of this IE identifier, and why is this
required only for EHT Capabilities? Are HE Capabilities and other
extension-based IEs handled differently?
Also, this command is sent for every hardware scan request. Does the
firmware use the host-provided IE only for the current scan and then
discard it afterward, or is the IE retained across scans?
It would be helpful to capture these details in the commit message
and/or code comments.
--
Ramesh
More information about the ath12k
mailing list