diff options
| author | hathach <[email protected]> | 2026-06-15 22:50:01 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-06-15 22:50:01 +0700 |
| commit | f1080e158aeec31faee0f3371d2d5c6f624dd4f4 (patch) | |
| tree | 0d683d2e879023be03dd707cc34a0a6ad1680ed9 | |
| parent | 3d9468152c44148c6881fb3f30ff3dae91a09b68 (diff) | |
dcd/musb: harden EP0 DATA_OUT against short packet and host overrun
Mirror the IN-side short-packet fix on the OUT drain: end the data
stage (-> STATUS_IN) when wLength is received OR a short OUT packet
(count0 < CFG_TUD_ENDPOINT0_SIZE) signals the host's end-of-data, not
only when remain_wlength hits exactly 0. Also clamp the
remain_wlength subtraction so a host that overruns wLength can't
underflow it and strand the transfer.
Without this, a control-OUT whose host sends fewer bytes than wLength
left pipe0 in DATA_OUT; usbd then armed STATUS IN and tripped the
split's TU_ASSERT(!dir_in). Found by /code-review; conformant hosts
send exactly wLength so HIL was already green.
Verified: HIL pass on ek_tm4c123gxl and max32666fthr (13/13 each).
Co-Authored-By: Claude Fable 5 <[email protected]>
| -rw-r--r-- | src/portable/mentor/musb/dcd_musb.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index 5c2b80cf6..0a2df3e71 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -566,12 +566,13 @@ static void process_ep0_isr(uint8_t rhport) { if (count0) { TU_ASSERT(pipe0->buf, ); tu_hwfifo_read(&musb_regs->fifo[0], pipe0->buf, count0, NULL); - pipe0->remain_wlength -= count0; + pipe0->remain_wlength -= tu_min16(count0, pipe0->remain_wlength); // clamp: host may overrun } // RXRDY stays set until the next edpt0_xfer arm acks it (NAK flow control): // edpt0_xfer(DATA OUT) for a mid-stream packet, edpt0_xfer(STATUS IN) for the last. pipe0->rxrdy_consumed = true; - if (pipe0->remain_wlength == 0) { + // Last packet: wLength received, or a short packet (host's end-of-data). + if (pipe0->remain_wlength == 0 || count0 < CFG_TUD_ENDPOINT0_SIZE) { pipe0->state = PIPE0_STATE_STATUS_IN; } dcd_event_xfer_complete(rhport, TU_EP0_OUT, count0, XFER_RESULT_SUCCESS, true); |
