This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 5059638c547 drivers/net: fix ABBA deadlock in netdev_upper_txavail
under forwarding
5059638c547 is described below
commit 5059638c5477f68e3584f27e6b70e8964a8d5f54
Author: Sarthak Pandey <[email protected]>
AuthorDate: Mon Oct 12 20:46:33 2026 +0530
drivers/net: fix ABBA deadlock in netdev_upper_txavail under forwarding
In full-duplex forwarding / NAT scenarios between two network devices
(e.g. wlan0 and wlan1 in SoftAP + Station mode), both netdev RX worker
threads could deadlock (ABBA):
- Thread netdev-wlan0 holds netdev_lock(wlan0) during RX poll. When
forwarding a packet to wlan1, it invokes netdev_txnotify_dev(wlan1),
which calls wlan1->d_txavail(). netdev_upper_txavail() was directly
calling netdev_upper_txavail_work(), which synchronously acquires
netdev_lock(wlan1).
- Concurrently, thread netdev-wlan1 holds netdev_lock(wlan1) during
RX poll and forwards a packet to wlan0, trying to synchronously
acquire netdev_lock(wlan0).
This resulted in a cross-deadlock where both RX workers waited
indefinitely on each other's device lock.
Fix this by checking upper->lower->rxtype in netdev_upper_txavail(). If
rxtype is not NETDEV_RX_DIRECT, delegate via netdev_upper_queue_work(dev)
to wake the target device's worker thread asynchronously without
holding peer device locks synchronously.
Fixes: #20619
Signed-off-by: Sarthak Pandey <[email protected]>
---
drivers/net/netdev_upperhalf.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/drivers/net/netdev_upperhalf.c b/drivers/net/netdev_upperhalf.c
index 7bb5bdaf00d..31939590c1d 100644
--- a/drivers/net/netdev_upperhalf.c
+++ b/drivers/net/netdev_upperhalf.c
@@ -929,7 +929,28 @@ static inline void netdev_upper_queue_work(FAR struct
net_driver_s *dev)
static int netdev_upper_txavail(FAR struct net_driver_s *dev)
{
- netdev_upper_txavail_work(dev->d_private);
+ FAR struct netdev_upperhalf_s *upper = dev->d_private;
+
+ if (upper->lower->rxtype == NETDEV_RX_DIRECT)
+ {
+ netdev_upper_txavail_work(upper);
+ }
+ else if (nxrmutex_trylock(&dev->d_lock) >= 0)
+ {
+ /* Lock free or held by us: transmit now so txq can't overflow.
+ * Drop the extra reference of the recursive lock.
+ */
+
+ netdev_upper_txavail_work(upper);
+ nxrmutex_unlock(&dev->d_lock);
+ }
+ else
+ {
+ /* Locked by another thread: don't wait (ABBA when forwarding) */
+
+ netdev_upper_queue_work(dev);
+ }
+
return OK;
}