[PATCH rtw-next v5 07/10] wifi: rtw89: send injected control frames through the management path

From: Enver Ikromov

Date: Fri Nov 13 2026 - 18:56:36 EST


rtw89_core_get_tx_type() classifies every frame that is neither a
management nor a null-data frame as data. Injected control frames
such as a 10-byte ACK or 16-byte RTS therefore go through
rtw89_core_tx_update_data_info(), which derives a TID and data queue
from skb->priority and enables AMPDU/QoS related descriptor fields
that make no sense for them.

Classify injected non-data frames as management frames. Frames
generated by mac80211 itself, such as BlockAckReq, are not affected.

In addition, rtw89_core_tx_update_desc_info() reads hdr->seq_ctrl at
offset 22 for every frame. Control frames have no sequence control
field and are shorter than 24 bytes, so only read hdr->seq_ctrl from
non-control frames whose linear header is long enough to carry it.

Signed-off-by: Enver Ikromov <owner@xxxxxxxxxxxxxx>
---
drivers/net/wireless/realtek/rtw89/core.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 54605f7..7003c24 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -637,12 +637,21 @@ static enum rtw89_core_tx_type
rtw89_core_get_tx_type(struct rtw89_dev *rtwdev,
struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (void *)skb->data;
__le16 fc = hdr->frame_control;

if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc))
return RTW89_CORE_TX_TYPE_MGMT;

+ /* Injected control frames have no QoS/TID and no data payload, so
+ * send them through the management path. Control frames built by
+ * mac80211 itself (e.g. BlockAckReq) keep using the data path.
+ */
+ if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED) &&
+ !ieee80211_is_data(fc))
+ return RTW89_CORE_TX_TYPE_MGMT;
+
return RTW89_CORE_TX_TYPE_DATA;
}

@@ -1299,7 +1308,7 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
enum btc_pkt_type pkt_type;
bool upd_wlan_hdr = false;
bool is_bmc;
- u16 seq;
+ u16 seq = 0;

desc_info->pkt_size = skb->len;

@@ -1315,7 +1324,10 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
else if (tx_req->vif)
desc_info->mlo = ieee80211_vif_is_mld(tx_req->vif);

- seq = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+ /* control frames (e.g. 10-byte ACK/CTS) have no sequence control */
+ if (!ieee80211_is_ctl(hdr->frame_control) &&
+ skb_headlen(skb) >= sizeof(struct ieee80211_hdr_3addr))
+ seq = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
addr_cam = rtw89_get_addr_cam_of(tx_req->rtwvif_link,
tx_req->rtwsta_link);
if (addr_cam->valid && desc_info->mlo)
--
2.56.0.windows.4