[PATCH] usb: gadget: dummy_hcd: fix data corruption with queued requests

From: Sebastian Urban

Date: Sun Mar 15 2026 - 05:03:44 EST


The transfer() function in dummy_hcd iterates over all queued gadget
requests for a given endpoint via list_for_each_entry(). When the
per-frame bandwidth budget is exhausted mid-request, leaving a
partially-transferred gadget request, the loop continues to the next
queued request instead of stopping. This breaks data ordering in the
URB transfer buffer.

Two consequences:

1. Data corruption: bytes from subsequent requests are written into
the URB buffer ahead of the remaining bytes from the incomplete
request. On the next timer tick the incomplete request resumes,
appending its remaining data after the out-of-order bytes.

2. Premature URB completion: if the next request is a ZLP or shorter
than the remaining host buffer, it triggers the is_short path and
completes the URB before all data has been transferred.

Fix this by breaking out of the loop when the current request has
remaining data (req->req.actual < req->req.length). The request
resumes on the next timer tick, preserving data ordering.

Signed-off-by: Sebastian Urban <surban@xxxxxxxxxx>
---
drivers/usb/gadget/udc/dummy_hcd.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 1cefca660..0eead4a85 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -1534,6 +1534,12 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
/* rescan to continue with any other queued i/o */
if (rescan)
goto top;
+
+ /* request not fully transferred; stop iterating to
+ * preserve data ordering across queued requests.
+ */
+ if (req->req.actual < req->req.length)
+ break;
}
return sent;
}
--
2.53.0