#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;
__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};
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;
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;
{
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;
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 |
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);
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)
{
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;
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);