wifi: rtw89: wow: enable TKIP related feature

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
This commit is contained in:
Chih-Kang Chang 2025-09-15 14:54:34 +08:00 committed by Ping-Ke Shih
parent 8e72c3a625
commit 533e60e1ca
4 changed files with 74 additions and 18 deletions

View 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];

View 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) |

View 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;

View 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)