From: Chih-Kang Chang <gary.chang@xxxxxxxxxxx> When creating EAPOL_KEY, SA_QUERY and ARP_RSP packet offload, we need to append security header offset for different cipher as required by the firmware. Only 8852A, 8852B, 8852BT and 8851B need it. Signed-off-by: Chih-Kang Chang <gary.chang@xxxxxxxxxxx> Signed-off-by: Ping-Ke Shih <pkshih@xxxxxxxxxxx> --- drivers/net/wireless/realtek/rtw89/fw.c | 67 +++++++++++++++--------- drivers/net/wireless/realtek/rtw89/wow.c | 22 +++++--- drivers/net/wireless/realtek/rtw89/wow.h | 30 +++++++++++ 3 files changed, 85 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 23204b2706c9..3c666fd0f8ed 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -13,22 +13,20 @@ #include "ps.h" #include "reg.h" #include "util.h" +#include "wow.h" struct rtw89_eapol_2_of_2 { - struct ieee80211_hdr_3addr hdr; u8 gtkbody[14]; u8 key_des_ver; u8 rsvd[92]; -} __packed __aligned(2); +} __packed; struct rtw89_sa_query { - struct ieee80211_hdr_3addr hdr; u8 category; u8 action; -} __packed __aligned(2); +} __packed; struct rtw89_arp_rsp { - struct ieee80211_hdr_3addr addr; u8 llc_hdr[sizeof(rfc1042_header)]; __be16 llc_type; struct arphdr arp_hdr; @@ -36,7 +34,7 @@ struct rtw89_arp_rsp { __be32 sender_ip; u8 target_hw[ETH_ALEN]; __be32 target_ip; -} __packed __aligned(2); +} __packed; static const u8 mss_signature[] = {0x4D, 0x53, 0x53, 0x4B, 0x50, 0x4F, 0x4F, 0x4C}; @@ -2197,8 +2195,10 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, 0x8E, 0x01, 0x03, 0x00, 0x5F, 0x02, 0x03}; struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_eapol_2_of_2 *eapol_pkt; + struct ieee80211_hdr_3addr *hdr; struct sk_buff *skb; u8 key_des_ver; @@ -2211,17 +2211,21 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, else key_des_ver = 0; - skb = dev_alloc_skb(sizeof(*eapol_pkt)); + skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*eapol_pkt)); if (!skb) return NULL; + hdr = skb_put_zero(skb, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_FCTL_TODS | + IEEE80211_FCTL_PROTECTED); + ether_addr_copy(hdr->addr1, bss_conf->bssid); + ether_addr_copy(hdr->addr2, vif->addr); + ether_addr_copy(hdr->addr3, bss_conf->bssid); + + skb_put_zero(skb, sec_hdr_len); + eapol_pkt = skb_put_zero(skb, sizeof(*eapol_pkt)); - eapol_pkt->hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_FCTL_TODS | - IEEE80211_FCTL_PROTECTED); - ether_addr_copy(eapol_pkt->hdr.addr1, bss_conf->bssid); - ether_addr_copy(eapol_pkt->hdr.addr2, vif->addr); - ether_addr_copy(eapol_pkt->hdr.addr3, bss_conf->bssid); memcpy(eapol_pkt->gtkbody, gtkbody, sizeof(gtkbody)); eapol_pkt->key_des_ver = key_des_ver; @@ -2233,20 +2237,26 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, { struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); + struct ieee80211_hdr_3addr *hdr; struct rtw89_sa_query *sa_query; struct sk_buff *skb; - skb = dev_alloc_skb(sizeof(*sa_query)); + skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*sa_query)); if (!skb) return NULL; + hdr = skb_put_zero(skb, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION | + IEEE80211_FCTL_PROTECTED); + ether_addr_copy(hdr->addr1, bss_conf->bssid); + ether_addr_copy(hdr->addr2, vif->addr); + ether_addr_copy(hdr->addr3, bss_conf->bssid); + + skb_put_zero(skb, sec_hdr_len); + sa_query = skb_put_zero(skb, sizeof(*sa_query)); - sa_query->hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ACTION | - IEEE80211_FCTL_PROTECTED); - ether_addr_copy(sa_query->hdr.addr1, bss_conf->bssid); - ether_addr_copy(sa_query->hdr.addr2, vif->addr); - ether_addr_copy(sa_query->hdr.addr3, bss_conf->bssid); sa_query->category = WLAN_CATEGORY_SA_QUERY; sa_query->action = WLAN_ACTION_SA_QUERY_RESPONSE; @@ -2256,17 +2266,19 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { + u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct ieee80211_hdr_3addr *hdr; struct rtw89_arp_rsp *arp_skb; struct arphdr *arp_hdr; struct sk_buff *skb; __le16 fc; - skb = dev_alloc_skb(sizeof(struct rtw89_arp_rsp)); + skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*arp_skb)); if (!skb) return NULL; - arp_skb = skb_put_zero(skb, sizeof(*arp_skb)); + hdr = skb_put_zero(skb, sizeof(*hdr)); if (rtw_wow->ptk_alg) fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS | @@ -2274,11 +2286,14 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, else fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS); - arp_skb->addr.frame_control = fc; - ether_addr_copy(arp_skb->addr.addr1, rtwvif->bssid); - ether_addr_copy(arp_skb->addr.addr2, rtwvif->mac_addr); - ether_addr_copy(arp_skb->addr.addr3, rtwvif->bssid); + hdr->frame_control = fc; + ether_addr_copy(hdr->addr1, rtwvif->bssid); + ether_addr_copy(hdr->addr2, rtwvif->mac_addr); + ether_addr_copy(hdr->addr3, rtwvif->bssid); + + skb_put_zero(skb, sec_hdr_len); + arp_skb = skb_put_zero(skb, sizeof(*arp_skb)); memcpy(arp_skb->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); arp_skb->llc_type = htons(ETH_P_ARP); diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index fa61484c3839..df22a53b8f41 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -27,17 +27,23 @@ void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) rtw_wow->akm = rsn_ie->akm_cipher_suite.type; } +#define RTW89_CIPHER_INFO_DEF(cipher) \ + {WLAN_CIPHER_SUITE_ ## cipher, .fw_alg = RTW89_WOW_FW_ALG_ ## cipher, \ + .len = WLAN_KEY_LEN_ ## cipher} + static const struct rtw89_cipher_info rtw89_cipher_info_defs[] = { - {WLAN_CIPHER_SUITE_WEP40, .fw_alg = 1, .len = WLAN_KEY_LEN_WEP40,}, - {WLAN_CIPHER_SUITE_WEP104, .fw_alg = 2, .len = WLAN_KEY_LEN_WEP104,}, - {WLAN_CIPHER_SUITE_TKIP, .fw_alg = 3, .len = WLAN_KEY_LEN_TKIP,}, - {WLAN_CIPHER_SUITE_CCMP, .fw_alg = 6, .len = WLAN_KEY_LEN_CCMP,}, - {WLAN_CIPHER_SUITE_GCMP, .fw_alg = 8, .len = WLAN_KEY_LEN_GCMP,}, - {WLAN_CIPHER_SUITE_CCMP_256, .fw_alg = 7, .len = WLAN_KEY_LEN_CCMP_256,}, - {WLAN_CIPHER_SUITE_GCMP_256, .fw_alg = 23, .len = WLAN_KEY_LEN_GCMP_256,}, - {WLAN_CIPHER_SUITE_AES_CMAC, .fw_alg = 32, .len = WLAN_KEY_LEN_AES_CMAC,}, + RTW89_CIPHER_INFO_DEF(WEP40), + RTW89_CIPHER_INFO_DEF(WEP104), + RTW89_CIPHER_INFO_DEF(TKIP), + RTW89_CIPHER_INFO_DEF(CCMP), + RTW89_CIPHER_INFO_DEF(GCMP), + RTW89_CIPHER_INFO_DEF(CCMP_256), + RTW89_CIPHER_INFO_DEF(GCMP_256), + RTW89_CIPHER_INFO_DEF(AES_CMAC), }; +#undef RTW89_CIPHER_INFO_DEF + static const struct rtw89_cipher_info *rtw89_cipher_alg_recognize(u32 cipher) { diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index e595aee0196d..0d90add0e88d 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -35,6 +35,17 @@ enum rtw89_wake_reason { RTW89_WOW_RSN_RX_NLO = 0x55, }; +enum rtw89_fw_alg { + RTW89_WOW_FW_ALG_WEP40 = 0x1, + RTW89_WOW_FW_ALG_WEP104 = 0x2, + RTW89_WOW_FW_ALG_TKIP = 0x3, + RTW89_WOW_FW_ALG_CCMP = 0x6, + RTW89_WOW_FW_ALG_CCMP_256 = 0x7, + RTW89_WOW_FW_ALG_GCMP = 0x8, + RTW89_WOW_FW_ALG_GCMP_256 = 0x9, + RTW89_WOW_FW_ALG_AES_CMAC = 0xa, +}; + struct rtw89_cipher_suite { u8 oui[3]; u8 type; @@ -64,6 +75,25 @@ struct rtw89_set_key_info_iter_data { bool error; }; +static inline int rtw89_wow_get_sec_hdr_len(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + + if (!(rtwdev->chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev))) + return 0; + + switch (rtw_wow->ptk_alg) { + case RTW89_WOW_FW_ALG_WEP40: + return 4; + case RTW89_WOW_FW_ALG_TKIP: + case RTW89_WOW_FW_ALG_CCMP: + case RTW89_WOW_FW_ALG_GCMP_256: + return 8; + default: + return 0; + } +} + #ifdef CONFIG_PM int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan); int rtw89_wow_resume(struct rtw89_dev *rtwdev); -- 2.25.1