summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChin-Yen Lee <timlee@realtek.com>2026-06-25 14:15:44 +0800
committerPing-Ke Shih <pkshih@realtek.com>2026-07-03 11:40:14 +0800
commit03a963f4aeda538acad50806e94ef25d95b78743 (patch)
treea2b19464c430bfd115f057a26c44df83babf51d3
parent76edcedda6437647ecd09b4b47593990a003b07a (diff)
downloadlinux-03a963f4aeda538acad50806e94ef25d95b78743.tar.gz
linux-03a963f4aeda538acad50806e94ef25d95b78743.zip
wifi: rtw89: wow: add QoS control field to WoWLAN ARP response for MLO
Some MLO APs expect WoWLAN ARP response frames to be transmitted as QoS data frames and may discard frames that do not contain a QoS Control field. Add a QoS Control field and use the QoS Data subtype when generating WoWLAN ARP responses for MLD vifs. Keep the existing frame format unchanged for non-MLO connections. This allows WoWLAN ARP responses to be accepted by MLO APs while preserving compatibility with legacy APs. Signed-off-by: Chin-Yen Lee <timlee@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20260625061545.44808-10-pkshih@realtek.com
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 44eb71c38580..9d98805835d6 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -2943,6 +2943,7 @@ 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_link *rtwvif_link)
{
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif_link->rtwvif);
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev);
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
@@ -2950,26 +2951,42 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev,
struct rtw89_arp_rsp *arp_skb;
struct arphdr *arp_hdr;
struct sk_buff *skb;
- __le16 fc;
+ bool with_qos;
+ u16 fc;
- skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*arp_skb));
+ with_qos = ieee80211_vif_is_mld(vif);
+
+ rtw89_debug(rtwdev, RTW89_DBG_WOW, "[arp_reply] with qos field: %s\n",
+ str_yes_no(with_qos));
+
+ skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*arp_skb) +
+ (with_qos ? 2 : 0));
if (!skb)
return NULL;
hdr = skb_put_zero(skb, sizeof(*hdr));
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS;
+
if (rtw_wow->ptk_alg)
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS |
- IEEE80211_FCTL_PROTECTED);
+ fc |= IEEE80211_FCTL_PROTECTED;
+
+ if (with_qos)
+ fc |= IEEE80211_STYPE_QOS_DATA;
else
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS);
+ fc |= IEEE80211_STYPE_DATA;
+
+ hdr->frame_control = cpu_to_le16(fc);
- hdr->frame_control = fc;
ether_addr_copy(hdr->addr1, rtwvif_link->bssid);
ether_addr_copy(hdr->addr2, rtwvif_link->mac_addr);
ether_addr_copy(hdr->addr3, rtwvif_link->bssid);
- skb_put_zero(skb, sec_hdr_len);
+ if (with_qos)
+ skb_put_zero(skb, sizeof(__le16));
+
+ if (sec_hdr_len)
+ 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));