lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250920132614.277719-6-pchelkin@ispras.ru>
Date: Sat, 20 Sep 2025 16:26:10 +0300
From: Fedor Pchelkin <pchelkin@...ras.ru>
To: Ping-Ke Shih <pkshih@...ltek.com>,
	Bitterblue Smith <rtl8821cerfe2@...il.com>
Cc: Fedor Pchelkin <pchelkin@...ras.ru>,
	Zong-Zhe Yang <kevin_yang@...ltek.com>,
	Po-Hao Huang <phhuang@...ltek.com>,
	linux-wireless@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	lvc-project@...uxtesting.org
Subject: [PATCH rtw-next 5/6] wifi: rtw89: process TX wait skbs for USB via C2H handler

TX wait skbs need to be completed when they are done.  PCIe part does this
inside rtw89_pci_tx_status() during RPP processing.  Other HCIs use a
mechanism based on C2H firmware messages.

Store a sequence number in a TX wait object so that it'll be possible to
identify completed items inside C2H handler.  No need to add the
corresponding skb to the &txcb->tx_ack_queue on USB part.

Found by Linux Verification Center (linuxtesting.org).

Signed-off-by: Fedor Pchelkin <pchelkin@...ras.ru>
---
 drivers/net/wireless/realtek/rtw89/core.c |  6 ++++--
 drivers/net/wireless/realtek/rtw89/core.h | 18 +++++++++++++++++-
 drivers/net/wireless/realtek/rtw89/mac.c  | 11 +++++++++++
 drivers/net/wireless/realtek/rtw89/usb.c  |  9 ++++++++-
 4 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 3e7bd0cedbdf..e76f04736502 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -1161,18 +1161,19 @@ int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *sk
 
 	lockdep_assert_wiphy(rtwdev->hw->wiphy);
 
+	list_add_tail_rcu(&wait->list, &rtwdev->tx_waits);
 	rtw89_core_tx_kick_off(rtwdev, qsel);
 	time_left = wait_for_completion_timeout(&wait->completion,
 						msecs_to_jiffies(timeout));
 
 	if (time_left == 0) {
 		ret = -ETIMEDOUT;
-		list_add_tail(&wait->list, &rtwdev->tx_waits);
 		wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->tx_wait_work,
 					 RTW89_TX_WAIT_WORK_TIMEOUT);
 	} else {
 		if (!wait->tx_done)
 			ret = -EAGAIN;
+		list_del_rcu(&wait->list);
 		rtw89_tx_wait_release(wait);
 	}
 
@@ -1237,11 +1238,12 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
 	tx_req.skb = skb;
 	tx_req.vif = vif;
 	tx_req.sta = sta;
+	tx_req.wait = wait;
 	tx_req.rtwvif_link = rtwvif_link;
 	tx_req.rtwsta_link = rtwsta_link;
 	tx_req.desc_info.sw_mld = sw_mld;
 
-	if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
+	if (wait || (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
 		rtw89_hci_tx_rpt_enable(rtwdev, &tx_req);
 
 	rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true);
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 4e597a5df005..e7948bd0bdf6 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1199,6 +1199,7 @@ struct rtw89_core_tx_request {
 	struct sk_buff *skb;
 	struct ieee80211_vif *vif;
 	struct ieee80211_sta *sta;
+	struct rtw89_tx_wait_info *wait;
 	struct rtw89_vif_link *rtwvif_link;
 	struct rtw89_sta_link *rtwsta_link;
 	struct rtw89_tx_desc_info desc_info;
@@ -3521,6 +3522,7 @@ struct rtw89_tx_wait_info {
 	struct completion completion;
 	struct sk_buff *skb;
 	bool tx_done;
+	u8 sn;
 };
 
 struct rtw89_tx_skb_data {
@@ -6289,7 +6291,7 @@ static inline void rtw89_tx_wait_list_clear(struct rtw89_dev *rtwdev)
 	list_for_each_entry_safe(wait, tmp, &rtwdev->tx_waits, list) {
 		if (!completion_done(&wait->completion))
 			continue;
-		list_del(&wait->list);
+		list_del_rcu(&wait->list);
 		rtw89_tx_wait_release(wait);
 	}
 }
@@ -7392,6 +7394,20 @@ static inline struct sk_buff *rtw89_alloc_skb_for_rx(struct rtw89_dev *rtwdev,
 	return dev_alloc_skb(length);
 }
 
+static inline bool rtw89_core_is_tx_wait(struct rtw89_dev *rtwdev,
+					 struct rtw89_tx_skb_data *skb_data)
+{
+	struct rtw89_tx_wait_info *wait;
+
+	guard(rcu)();
+
+	wait = rcu_dereference(skb_data->wait);
+	if (!wait)
+		return false;
+
+	return true;
+}
+
 static inline bool rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev,
 					       struct rtw89_tx_skb_data *skb_data,
 					       bool tx_done)
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index 831e53aedccc..79409eb4d028 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -5477,6 +5477,7 @@ rtw89_mac_c2h_tx_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
 {
 	u8 sw_define = RTW89_GET_MAC_C2H_TX_RPT_SW_DEFINE(c2h->data);
 	u8 tx_status = RTW89_GET_MAC_C2H_TX_RPT_TX_STATE(c2h->data);
+	struct rtw89_tx_wait_info *wait;
 	struct sk_buff *cur, *tmp;
 	unsigned long flags;
 	u8 *n;
@@ -5485,6 +5486,16 @@ rtw89_mac_c2h_tx_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
 		    "C2H TX RPT: sn %d, tx_status %d\n",
 		    sw_define, tx_status);
 
+	rcu_read_lock();
+	list_for_each_entry_rcu(wait, &rtwdev->tx_waits, list) {
+		if (wait->sn == sw_define) {
+			wait->tx_done = tx_status == RTW89_TX_DONE;
+			complete_all(&wait->completion);
+			break;
+		}
+	}
+	rcu_read_unlock();
+
 	spin_lock_irqsave(&rtwdev->tx_rpt_queue.lock, flags);
 	skb_queue_walk_safe(&rtwdev->tx_rpt_queue, cur, tmp) {
 		n = (u8 *)RTW89_TX_SKB_CB(cur)->hci_priv;
diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
index 98eff955fc96..342c05227191 100644
--- a/drivers/net/wireless/realtek/rtw89/usb.c
+++ b/drivers/net/wireless/realtek/rtw89/usb.c
@@ -191,8 +191,13 @@ static u8 rtw89_usb_get_bulkout_id(u8 ch_dma)
 static void rtw89_usb_ops_tx_rpt_enable(struct rtw89_dev *rtwdev,
 					struct rtw89_core_tx_request *tx_req)
 {
+	struct rtw89_tx_wait_info *wait = tx_req->wait;
+
 	tx_req->desc_info.report = true;
 	tx_req->desc_info.sn = atomic_inc_return(&rtwdev->sn) & 0xF;
+
+	if (wait)
+		wait->sn = tx_req->desc_info.sn;
 }
 
 static void rtw89_usb_write_port_complete(struct urb *urb)
@@ -313,7 +318,9 @@ static void rtw89_usb_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
 		txcb->txch = txch;
 		skb_queue_head_init(&txcb->tx_ack_queue);
 
-		skb_queue_tail(&txcb->tx_ack_queue, skb);
+		/* tx_wait skbs are completed in rtw89_mac_c2h_tx_rpt() */
+		if (!rtw89_core_is_tx_wait(rtwdev, RTW89_TX_SKB_CB(skb)))
+			skb_queue_tail(&txcb->tx_ack_queue, skb);
 
 		ret = rtw89_usb_write_port(rtwdev, txch, skb->data, skb->len,
 					   txcb);
-- 
2.51.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ