]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: ath12k: install pairwise key first
authorBaochen Qiang <quic_bqiang@quicinc.com>
Fri, 23 May 2025 03:49:02 +0000 (11:49 +0800)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Mon, 23 Jun 2025 14:28:33 +0000 (07:28 -0700)
As station, WCN7850 firmware requires pairwise key to be installed before
group key. Currently host does not care about this, so it is up to kernel
or userspace to decide which one will be installed first. In case above
requirement is not met, WCN7850 firmware's EAPOL station machine is messed
up, and finally connection fails [1].

Reorder key install for station interface in that case: this is done by
caching group key first; Later when pairwise key arrives, both can be
installed in required order.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00217-QCAHKSWPL_SILICONZ-1

Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218733
Link: https://lore.kernel.org/all/AS8P190MB12051DDBD84CD88E71C40AD7873F2@AS8P190MB1205.EURP190.PROD.OUTLOOK.COM
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250523-ath12k-unicast-key-first-v1-2-f53c3880e6d8@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/wmi.h

index cf10c62d4751af225229903ffa1c3bb495e59ee2..0c1a6df7a02e7d269e47dc214099f274ff0761a5 100644 (file)
@@ -345,6 +345,10 @@ struct ath12k_link_vif {
        bool is_sta_assoc_link;
 
        struct ath12k_reg_tpc_power_info reg_tpc_info;
+
+       bool group_key_valid;
+       struct wmi_vdev_install_key_arg group_key;
+       bool pairwise_key_done;
 };
 
 struct ath12k_vif {
index 18c42b714ef37bb49f1112454fae2cf118268ac6..8a1b0c5599783808fed2f962bcdf3e6e9c5a258e 100644 (file)
@@ -4829,14 +4829,13 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif,
                .key_len = key->keylen,
                .key_data = key->key,
                .key_flags = flags,
+               .ieee80211_key_cipher = key->cipher,
                .macaddr = macaddr,
        };
        struct ath12k_vif *ahvif = arvif->ahvif;
 
        lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
 
-       reinit_completion(&ar->install_key_done);
-
        if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
                return 0;
 
@@ -4845,7 +4844,7 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif,
                /* arg.key_cipher = WMI_CIPHER_NONE; */
                arg.key_len = 0;
                arg.key_data = NULL;
-               goto install;
+               goto check_order;
        }
 
        switch (key->cipher) {
@@ -4873,19 +4872,82 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif,
                key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV |
                              IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
 
+check_order:
+       if (ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
+           arg.key_flags == WMI_KEY_GROUP) {
+               if (cmd == SET_KEY) {
+                       if (arvif->pairwise_key_done) {
+                               ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+                                          "vdev %u pairwise key done, go install group key\n",
+                                          arg.vdev_id);
+                               goto install;
+                       } else {
+                               /* WCN7850 firmware requires pairwise key to be installed
+                                * before group key. In case group key comes first, cache
+                                * it and return. Will revisit it once pairwise key gets
+                                * installed.
+                                */
+                               arvif->group_key = arg;
+                               arvif->group_key_valid = true;
+                               ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+                                          "vdev %u group key before pairwise key, cache and skip\n",
+                                          arg.vdev_id);
+
+                               ret = 0;
+                               goto out;
+                       }
+               } else {
+                       arvif->group_key_valid = false;
+               }
+       }
+
 install:
-       ret = ath12k_wmi_vdev_install_key(arvif->ar, &arg);
+       reinit_completion(&ar->install_key_done);
 
+       ret = ath12k_wmi_vdev_install_key(arvif->ar, &arg);
        if (ret)
                return ret;
 
        if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ))
                return -ETIMEDOUT;
 
-       if (ether_addr_equal(macaddr, arvif->bssid))
-               ahvif->key_cipher = key->cipher;
+       if (ether_addr_equal(arg.macaddr, arvif->bssid))
+               ahvif->key_cipher = arg.ieee80211_key_cipher;
+
+       if (ar->install_key_status) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
+           arg.key_flags == WMI_KEY_PAIRWISE) {
+               if (cmd == SET_KEY) {
+                       arvif->pairwise_key_done = true;
+                       if (arvif->group_key_valid) {
+                               /* Install cached GTK */
+                               arvif->group_key_valid = false;
+                               arg = arvif->group_key;
+                               ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+                                          "vdev %u pairwise key done, group key ready, go install\n",
+                                          arg.vdev_id);
+                               goto install;
+                       }
+               } else {
+                       arvif->pairwise_key_done = false;
+               }
+       }
+
+out:
+       if (ret) {
+               /* In case of failure userspace may not do DISABLE_KEY
+                * but triggers re-connection directly, so manually reset
+                * status here.
+                */
+               arvif->group_key_valid = false;
+               arvif->pairwise_key_done = false;
+       }
 
-       return ar->install_key_status ? -EINVAL : 0;
+       return ret;
 }
 
 static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif,
index 117150220b997bf03fe2ea882f899208ffc4b046..8627154f1680fabb75d646e27a353a0b45733f08 100644 (file)
@@ -3760,6 +3760,7 @@ struct wmi_vdev_install_key_arg {
        u32 key_idx;
        u32 key_flags;
        u32 key_cipher;
+       u32 ieee80211_key_cipher;
        u32 key_len;
        u32 key_txmic_len;
        u32 key_rxmic_len;