]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: rtw89: wow: enable TKIP related feature
authorChih-Kang Chang <gary.chang@realtek.com>
Mon, 15 Sep 2025 06:54:34 +0000 (14:54 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Thu, 18 Sep 2025 01:21:31 +0000 (09:21 +0800)
For chips that supports TKIP HW encryption and decryption, enable TKIP
cipher for WoWLAN feature. Additionally, the TX MIC KEY and RX MIC KEY is
opposite in FW. Therefore, reverse the MIC KEY direction in H2C format,
and also reverse it from AOAC report before reporting to mac80211.

Signed-off-by: Chih-Kang Chang <gary.chang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250915065434.39324-1-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/wow.c
drivers/net/wireless/realtek/rtw89/wow.h

index 8408d5d8d42d4c6b2242d0340a5e8c8ce8e5ef13..3d4ad2ffb75cbbe8efbba1779e12277730fef693 100644 (file)
@@ -5771,8 +5771,8 @@ struct rtw89_wow_gtk_info {
        u8 kck[32];
        u8 kek[32];
        u8 tk1[16];
-       u8 txmickey[8];
        u8 rxmickey[8];
+       u8 txmickey[8];
        __le32 igtk_keyid;
        __le64 ipn;
        u8 igtk[2][32];
index 2273dae8434ab2dd7a1c6fba82caf7a4ef24e579..ab904a7def1b448224178914c33238a4652fba35 100644 (file)
@@ -8726,9 +8726,10 @@ int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev,
                        goto fail;
        }
 
-       /* not support TKIP yet */
        h2c->w0 = le32_encode_bits(enable, RTW89_H2C_WOW_GTK_OFLD_W0_EN) |
-                 le32_encode_bits(0, RTW89_H2C_WOW_GTK_OFLD_W0_TKIP_EN) |
+                 le32_encode_bits(!!memchr_inv(gtk_info->txmickey, 0,
+                                               sizeof(gtk_info->txmickey)),
+                                  RTW89_H2C_WOW_GTK_OFLD_W0_TKIP_EN) |
                  le32_encode_bits(gtk_info->igtk_keyid ? 1 : 0,
                                   RTW89_H2C_WOW_GTK_OFLD_W0_IEEE80211W_EN) |
                  le32_encode_bits(macid, RTW89_H2C_WOW_GTK_OFLD_W0_MAC_ID) |
index 5bb7c1a42f1dec5a2b4a47f6388150aadf95c8cc..5faa51ad896a26a0c17e4080a8ab49e77553024f 100644 (file)
@@ -99,13 +99,26 @@ static int rtw89_rx_pn_to_iv(struct rtw89_dev *rtwdev,
 
        ieee80211_get_key_rx_seq(key, 0, &seq);
 
-       /* seq.ccmp.pn[] is BE order array */
-       pn = u64_encode_bits(seq.ccmp.pn[0], RTW89_KEY_PN_5) |
-            u64_encode_bits(seq.ccmp.pn[1], RTW89_KEY_PN_4) |
-            u64_encode_bits(seq.ccmp.pn[2], RTW89_KEY_PN_3) |
-            u64_encode_bits(seq.ccmp.pn[3], RTW89_KEY_PN_2) |
-            u64_encode_bits(seq.ccmp.pn[4], RTW89_KEY_PN_1) |
-            u64_encode_bits(seq.ccmp.pn[5], RTW89_KEY_PN_0);
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               pn = u64_encode_bits(seq.tkip.iv32, RTW89_KEY_TKIP_PN_IV32) |
+                    u64_encode_bits(seq.tkip.iv16, RTW89_KEY_TKIP_PN_IV16);
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+       case WLAN_CIPHER_SUITE_GCMP:
+       case WLAN_CIPHER_SUITE_CCMP_256:
+       case WLAN_CIPHER_SUITE_GCMP_256:
+               /* seq.ccmp.pn[] is BE order array */
+               pn = u64_encode_bits(seq.ccmp.pn[0], RTW89_KEY_PN_5) |
+                    u64_encode_bits(seq.ccmp.pn[1], RTW89_KEY_PN_4) |
+                    u64_encode_bits(seq.ccmp.pn[2], RTW89_KEY_PN_3) |
+                    u64_encode_bits(seq.ccmp.pn[3], RTW89_KEY_PN_2) |
+                    u64_encode_bits(seq.ccmp.pn[4], RTW89_KEY_PN_1) |
+                    u64_encode_bits(seq.ccmp.pn[5], RTW89_KEY_PN_0);
+               break;
+       default:
+               return -EINVAL;
+       }
 
        err = _pn_to_iv(rtwdev, key, iv, pn, key->keyidx);
        if (err)
@@ -177,13 +190,26 @@ static int rtw89_rx_iv_to_pn(struct rtw89_dev *rtwdev,
        if (err)
                return err;
 
-       /* seq.ccmp.pn[] is BE order array */
-       seq.ccmp.pn[0] = u64_get_bits(pn, RTW89_KEY_PN_5);
-       seq.ccmp.pn[1] = u64_get_bits(pn, RTW89_KEY_PN_4);
-       seq.ccmp.pn[2] = u64_get_bits(pn, RTW89_KEY_PN_3);
-       seq.ccmp.pn[3] = u64_get_bits(pn, RTW89_KEY_PN_2);
-       seq.ccmp.pn[4] = u64_get_bits(pn, RTW89_KEY_PN_1);
-       seq.ccmp.pn[5] = u64_get_bits(pn, RTW89_KEY_PN_0);
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               seq.tkip.iv32 = u64_get_bits(pn, RTW89_KEY_TKIP_PN_IV32);
+               seq.tkip.iv16 = u64_get_bits(pn, RTW89_KEY_TKIP_PN_IV16);
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+       case WLAN_CIPHER_SUITE_GCMP:
+       case WLAN_CIPHER_SUITE_CCMP_256:
+       case WLAN_CIPHER_SUITE_GCMP_256:
+               /* seq.ccmp.pn[] is BE order array */
+               seq.ccmp.pn[0] = u64_get_bits(pn, RTW89_KEY_PN_5);
+               seq.ccmp.pn[1] = u64_get_bits(pn, RTW89_KEY_PN_4);
+               seq.ccmp.pn[2] = u64_get_bits(pn, RTW89_KEY_PN_3);
+               seq.ccmp.pn[3] = u64_get_bits(pn, RTW89_KEY_PN_2);
+               seq.ccmp.pn[4] = u64_get_bits(pn, RTW89_KEY_PN_1);
+               seq.ccmp.pn[5] = u64_get_bits(pn, RTW89_KEY_PN_0);
+               break;
+       default:
+               return -EINVAL;
+       }
 
        ieee80211_set_key_rx_seq(key, 0, &seq);
        rtw89_debug(rtwdev, RTW89_DBG_WOW, "%s key %d iv-%*ph to pn-%*ph\n",
@@ -285,6 +311,11 @@ static void rtw89_wow_get_key_info_iter(struct ieee80211_hw *hw,
 
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
+               if (sta)
+                       memcpy(gtk_info->txmickey,
+                              key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
+                              sizeof(gtk_info->txmickey));
+               fallthrough;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_GCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
@@ -348,10 +379,27 @@ static void rtw89_wow_set_key_info_iter(struct ieee80211_hw *hw,
        struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt;
        struct rtw89_set_key_info_iter_data *iter_data = data;
        bool update_tx_key_info = iter_data->rx_ready;
+       u8 tmp[RTW89_MIC_KEY_LEN];
        int ret;
 
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
+               /*
+                * TX MIC KEY and RX MIC KEY is oppsite in FW,
+                * need to swap it before sending to mac80211.
+                */
+               if (!sta && update_tx_key_info && aoac_rpt->rekey_ok &&
+                   !iter_data->tkip_gtk_swapped) {
+                       memcpy(tmp, &aoac_rpt->gtk[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+                              RTW89_MIC_KEY_LEN);
+                       memcpy(&aoac_rpt->gtk[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+                              &aoac_rpt->gtk[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+                              RTW89_MIC_KEY_LEN);
+                       memcpy(&aoac_rpt->gtk[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+                              tmp, RTW89_MIC_KEY_LEN);
+                       iter_data->tkip_gtk_swapped = true;
+               }
+               fallthrough;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_GCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
@@ -642,7 +690,8 @@ static void rtw89_wow_update_key_info(struct rtw89_dev *rtwdev, bool rx_ready)
        struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
        struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt;
        struct rtw89_set_key_info_iter_data data = {.error = false,
-                                                   .rx_ready = rx_ready};
+                                                   .rx_ready = rx_ready,
+                                                   .tkip_gtk_swapped = false};
        struct ieee80211_bss_conf *bss_conf;
        struct ieee80211_key_conf *key;
 
index 6606528d31c7de58c7c8af6fc0d0cc6d3df1e17e..d2ba6cebc2a6b002043fad0275e0768f9c72b9f0 100644 (file)
@@ -5,6 +5,9 @@
 #ifndef __RTW89_WOW_H__
 #define __RTW89_WOW_H__
 
+#define RTW89_KEY_TKIP_PN_IV16 GENMASK_ULL(15, 0)
+#define RTW89_KEY_TKIP_PN_IV32 GENMASK_ULL(47, 16)
+
 #define RTW89_KEY_PN_0 GENMASK_ULL(7, 0)
 #define RTW89_KEY_PN_1 GENMASK_ULL(15, 8)
 #define RTW89_KEY_PN_2 GENMASK_ULL(23, 16)
@@ -25,6 +28,8 @@
 #define RTW89_WOW_SYMBOL_CHK_PTK BIT(0)
 #define RTW89_WOW_SYMBOL_CHK_GTK BIT(1)
 
+#define RTW89_MIC_KEY_LEN 8
+
 enum rtw89_wake_reason {
        RTW89_WOW_RSN_RX_PTK_REKEY = 0x1,
        RTW89_WOW_RSN_RX_GTK_REKEY = 0x2,
@@ -73,6 +78,7 @@ struct rtw89_set_key_info_iter_data {
        u32 igtk_cipher;
        bool rx_ready;
        bool error;
+       bool tkip_gtk_swapped;
 };
 
 static inline int rtw89_wow_get_sec_hdr_len(struct rtw89_dev *rtwdev)