mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-06 07:47:32 +00:00
usb: bound the wait for the host to collect a STALL
AT91F_USB_SendStall spun on STALLSENT with no exit. That bit only arrives once the host polls the endpoint and takes the handshake, so a host that vanishes in between wedges the device. It was the last unbounded wait in the file without an escape. Exit on RXSETUP (host abandoned the request and sent a new SETUP), on ENDBUSRES, or on a spin count, reusing the 0x1FFF that usb_read already uses. usb_check() is not usable here: it calls back into AT91F_CDC_Enumerate, which is what calls this. Do not test RXSUSP. Nothing writes it back to UDP_ICR, so it latches on the first bus idle and stays set, which makes the guard fire on every stall and stops the STALL from ever being delivered. The second wait is bounded too, since leaving the first one early can let the host set STALLSENT after the clear. Also ISOERROR -> STALLSENT. Same bit 3, but only one of those names is true on a control endpoint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fcb61153f8
commit
89305b2f8b
@@ -704,10 +704,41 @@ void AT91F_USB_SendZlp(AT91PS_UDP pudp) {
|
||||
//* \brief Stall the control endpoint
|
||||
//*----------------------------------------------------------------------------
|
||||
void AT91F_USB_SendStall(AT91PS_UDP pudp) {
|
||||
|
||||
UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL);
|
||||
while (!(pudp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR)) {};
|
||||
UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));
|
||||
while (pudp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)) {};
|
||||
|
||||
// STALLSENT only arrives once the host polls the endpoint and takes the
|
||||
// handshake, so every way the host can fail to do that needs an exit.
|
||||
// usb_check() is not one of them, it calls back into AT91F_CDC_Enumerate().
|
||||
uint16_t time_out = 0;
|
||||
while (!(pudp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_STALLSENT)) {
|
||||
|
||||
// host dropped this request and started another one
|
||||
if (pudp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) {
|
||||
break;
|
||||
}
|
||||
|
||||
// bus reset. Not RXSUSP: nothing in this driver writes it back to
|
||||
// UDP_ICR, so once the bus first idles it stays latched for good.
|
||||
if (pudp->UDP_ISR & AT91C_UDP_ENDBUSRES) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (time_out++ == 0x1FFF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, (AT91C_UDP_FORCESTALL | AT91C_UDP_STALLSENT));
|
||||
|
||||
// leaving the loop above early can let the host set STALLSENT after the
|
||||
// clear, so this wait is bounded too
|
||||
time_out = 0;
|
||||
while (pudp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_STALLSENT)) {
|
||||
if (time_out++ == 0x1FFF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user