USBLL: Do not reassemble across STALL handshake

When device responds with STALL, the host will clear the halt using
ClearFeature(ENDPOINT_HALT) request. The request always results in data
toggle being reinitialized to DATA0. Because USBLL dissector does not
track all control transfers, it is unaware of the expected data toggle
change and thus would treat next DATA0 packet as retransmission if the
last data packet before STALL was DATA0.

USB transfer never spans across STALL, i.e. data packet after STALL
cannot be retransmission nor continuation of any earlier transfer.

Avoid continuing reassembly after a STALL by clearing active transfer
information from endpoint info on every STALL handshake.
This commit is contained in:
Tomasz Moń 2023-02-08 14:47:49 +01:00
parent 8dfe8737c5
commit 58a80312cb
No known key found for this signature in database
GPG Key ID: 397DFEBE343AD96F
1 changed files with 54 additions and 0 deletions

View File

@ -933,6 +933,45 @@ static gboolean usbll_is_data_from_host(usbll_state_t state)
}
}
static gboolean usbll_is_endpoint_stall(usbll_state_t state)
{
switch (state)
{
case STATE_IN_STALL:
case STATE_OUT_STALL:
case STATE_PING_STALL:
case STATE_CSPLIT_CONTROL_OUT_STALL:
case STATE_CSPLIT_CONTROL_IN_STALL:
case STATE_CSPLIT_BULK_OUT_STALL:
case STATE_CSPLIT_BULK_IN_STALL:
case STATE_CSPLIT_INTERRUPT_OUT_STALL:
case STATE_CSPLIT_INTERRUPT_IN_STALL:
return TRUE;
default:
return FALSE;
}
}
static gboolean usbll_is_stalled_data_from_host(usbll_state_t state)
{
switch (state)
{
case STATE_OUT_STALL:
case STATE_PING_STALL:
case STATE_CSPLIT_CONTROL_OUT_STALL:
case STATE_CSPLIT_BULK_OUT_STALL:
case STATE_CSPLIT_INTERRUPT_OUT_STALL:
return TRUE;
case STATE_IN_STALL:
case STATE_CSPLIT_CONTROL_IN_STALL:
case STATE_CSPLIT_BULK_IN_STALL:
case STATE_CSPLIT_INTERRUPT_IN_STALL:
return FALSE;
default:
DISSECTOR_ASSERT_NOT_REACHED();
}
}
static usb_speed_t usbll_get_data_transaction_speed(usbll_data_t *data)
{
switch (data->transaction_state)
@ -2060,6 +2099,21 @@ dissect_usbll_handshake(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *t
DISSECTOR_ASSERT(data->prev->transaction != NULL);
data->transaction = data->prev->transaction;
}
if (usbll_is_endpoint_stall(data->transaction_state))
{
usbll_endpoint_info_t *ep_info;
gboolean from_host;
from_host = usbll_is_stalled_data_from_host(data->transaction_state);
ep_info = usbll_get_endpoint_info(pinfo, data->transaction->address, data->transaction->endpoint, from_host);
ep_info->last_data_pid = 0;
ep_info->active_transfer_key = 0;
ep_info->transfer_offset = 0;
ep_info->last_data_len = 0;
ep_info->requested_transfer_length = 0;
}
}
return offset;