[PATCH 2/4] wifi: ath11k: support beacon protection
From: Andrei-Alexandru Bleortu
Date: Sat Oct 03 2026 - 12:00:22 EST
Firmware with WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT protects the
beacons it transmits with the BIGTK. Advertise
NL80211_EXT_FEATURE_BEACON_PROTECTION when the service is present,
install the BIGTK (key index 6/7) in hardware with the BIP ciphers, and
set the beacon protection bit of the beacon template command when the
beacon's Extended Capabilities, or those of a nontransmitted BSSID
profile in it, enable it. The IGTK (index 4/5) stays in software, which
protects the management frames mac80211 sends.
This follows the ath12k change that added the same support, commit
"wifi: ath12k: allow beacon protection keys to be installed in hardware".
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.9.0.1-02146-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ5018 hw1.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
Assisted-by: LLM
Signed-off-by: Andrei-Alexandru Bleortu <me@xxxxxxxxxxxx>
---
drivers/net/wireless/ath/ath11k/core.h | 1 +
drivers/net/wireless/ath/ath11k/mac.c | 61 +++++++++++++++++++++++---
drivers/net/wireless/ath/ath11k/wmi.c | 2 +
drivers/net/wireless/ath/ath11k/wmi.h | 5 ++-
4 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index a0d725923..31eee25c0 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -408,6 +408,7 @@ struct ath11k_vif {
int txpower;
bool rsnie_present;
bool wpaie_present;
+ bool beacon_prot;
bool bcca_zero_sent;
bool do_not_send_tmpl;
struct ath11k_arp_ns_offload arp_ns_offload;
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index c1fa42edd..57cc6dbdd 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -1495,6 +1495,44 @@ static int ath11k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui,
return 0;
}
+static bool ath11k_mac_ext_capa_bcn_prot(const struct element *ext_capa)
+{
+ return ext_capa && ext_capa->datalen >= 11 &&
+ (ext_capa->data[10] & WLAN_EXT_CAPA11_BCN_PROTECT);
+}
+
+/* Beacon protection covers the whole beacon, so enable it when the
+ * transmitted BSS or any nontransmitted profile in it advertises it.
+ */
+static bool ath11k_mac_bcn_prot_enabled(struct sk_buff *bcn)
+{
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data;
+ const u8 *ies = mgmt->u.beacon.variable;
+ int ies_len = skb_tail_pointer(bcn) - ies;
+ const struct element *elem, *profile;
+
+ if (ath11k_mac_ext_capa_bcn_prot(cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
+ ies, ies_len)))
+ return true;
+
+ for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ies, ies_len) {
+ if (elem->datalen < 1)
+ continue;
+
+ for_each_element(profile, elem->data + 1, elem->datalen - 1) {
+ if (profile->id != 0)
+ continue;
+
+ if (ath11k_mac_ext_capa_bcn_prot(cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
+ profile->data,
+ profile->datalen)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
static int ath11k_mac_set_vif_params(struct ath11k_vif *arvif,
struct sk_buff *bcn)
{
@@ -1598,6 +1636,7 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif,
params |= ((!i ? 1 : 0) << WMI_EMA_FIRST_TMPL_SHIFT);
params |= ((i + 1 == beacons->cnt ? 1 : 0) << WMI_EMA_LAST_TMPL_SHIFT);
+ tx_arvif->beacon_prot = ath11k_mac_bcn_prot_enabled(beacons->bcn[i].skb);
ret = ath11k_wmi_bcn_tmpl(tx_arvif->ar, tx_arvif->vdev_id,
&beacons->bcn[i].offs,
beacons->bcn[i].skb, params);
@@ -1651,6 +1690,7 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif,
goto free;
}
+ arvif->beacon_prot = ath11k_mac_bcn_prot_enabled(bcn);
ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, 0);
if (ret)
ath11k_warn(ab, "failed to submit beacon template command: %d\n",
@@ -4412,6 +4452,14 @@ static int ath11k_install_key(struct ath11k_vif *arvif,
arg.key_cipher = WMI_CIPHER_AES_GCM;
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ arg.key_cipher = WMI_CIPHER_AES_CMAC;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ arg.key_cipher = WMI_CIPHER_AES_GMAC;
+ break;
default:
ath11k_warn(ar->ab, "cipher %d is not supported\n", key->cipher);
return -EOPNOTSUPP;
@@ -4523,11 +4571,10 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
int ret = 0;
u32 flags = 0;
- /* BIP needs to be done in software */
- if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
- key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
- key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
- key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
+ /* The IGTK protects management frames, which are done in software;
+ * only the BIGTK (index 6/7) goes to the firmware, which signs beacons.
+ */
+ if (key->keyidx == 4 || key->keyidx == 5)
return 1;
if (test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
@@ -10633,6 +10680,10 @@ static int __ath11k_mac_register(struct ath11k *ar)
wiphy_ext_feature_set(ar->hw->wiphy,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
+ if (test_bit(WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT, ar->ab->wmi_ab.svc_map))
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION);
+
ar->hw->wiphy->mbssid_max_interfaces = TARGET_NUM_VDEVS(ab);
ar->hw->wiphy->ema_max_profile_periodicity = TARGET_EMA_MAX_PROFILE_PERIOD;
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 08fd6795e..2c3e14a65 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -1811,6 +1811,8 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id,
cmd->buf_len = bcn->len;
cmd->mbssid_ie_offset = offs->mbssid_off;
cmd->ema_params = ema_params;
+ if (arvif->beacon_prot)
+ cmd->feature_enable_bitmap |= WMI_BCN_TMPL_BEACON_PROTECTION_EN;
ptr = skb->data + sizeof(*cmd);
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index b2dade051..ae8b4cc08 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -2128,6 +2128,7 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213,
WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
WMI_TLV_SERVICE_EXT2_MSG = 220,
+ WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT = 244,
WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT = 246,
WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249,
WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253,
@@ -3628,6 +3629,8 @@ struct ath11k_wmi_p2p_noa_info {
#define WMI_EMA_FIRST_TMPL_SHIFT 16
#define WMI_EMA_LAST_TMPL_SHIFT 24
+#define WMI_BCN_TMPL_BEACON_PROTECTION_EN BIT(0)
+
struct wmi_bcn_tmpl_cmd {
u32 tlv_header;
u32 vdev_id;
@@ -5237,7 +5240,7 @@ enum wmi_ap_ps_peer_param {
#define DISABLE_SIFS_RESPONSE_TRIGGER 0
-#define WMI_MAX_KEY_INDEX 3
+#define WMI_MAX_KEY_INDEX 7
#define WMI_MAX_KEY_LEN 32
#define WMI_KEY_PAIRWISE 0x00