mirror of https://github.com/ARMmbed/mbed-os.git
Tests: USB: Check ep buffer is released by abort
Validate that endpoint buffer is not used after a transfer has been aborted.pull/9768/head
parent
36d4c355a9
commit
1f8bf46f2e
|
@ -56,6 +56,7 @@ VENDOR_TEST_CTRL_OUT_STATUS_DELAY = 8
|
||||||
VENDOR_TEST_CTRL_IN_SIZES = 9
|
VENDOR_TEST_CTRL_IN_SIZES = 9
|
||||||
VENDOR_TEST_CTRL_OUT_SIZES = 10
|
VENDOR_TEST_CTRL_OUT_SIZES = 10
|
||||||
VENDOR_TEST_READ_START = 11
|
VENDOR_TEST_READ_START = 11
|
||||||
|
VENDOR_TEST_ABORT_BUFF_CHECK = 12
|
||||||
VENDOR_TEST_UNSUPPORTED_REQUEST = 32
|
VENDOR_TEST_UNSUPPORTED_REQUEST = 32
|
||||||
|
|
||||||
REQUEST_GET_STATUS = 0
|
REQUEST_GET_STATUS = 0
|
||||||
|
@ -1062,6 +1063,16 @@ def request_endpoint_read_start(dev, ep):
|
||||||
dev.ctrl_transfer(**ctrl_kwargs)
|
dev.ctrl_transfer(**ctrl_kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def request_abort_buff_check(dev, ep):
|
||||||
|
ctrl_kwargs = {
|
||||||
|
'bmRequestType': build_request_type(CTRL_IN, CTRL_TYPE_VENDOR, CTRL_RECIPIENT_ENDPOINT),
|
||||||
|
'bRequest': VENDOR_TEST_ABORT_BUFF_CHECK,
|
||||||
|
'wValue': 0,
|
||||||
|
'wIndex': ep.bEndpointAddress,
|
||||||
|
'data_or_wLength': 1}
|
||||||
|
return bool(dev.ctrl_transfer(**ctrl_kwargs)[0])
|
||||||
|
|
||||||
|
|
||||||
USB_ERROR_FMT = str('Got {0!r} while testing endpoints '
|
USB_ERROR_FMT = str('Got {0!r} while testing endpoints '
|
||||||
'{1.bEndpointAddress:#04x}({1.wMaxPacketSize:02}) and '
|
'{1.bEndpointAddress:#04x}({1.wMaxPacketSize:02}) and '
|
||||||
'{2.bEndpointAddress:#04x}({2.wMaxPacketSize:02}) with '
|
'{2.bEndpointAddress:#04x}({2.wMaxPacketSize:02}) with '
|
||||||
|
@ -1304,9 +1315,16 @@ def ep_test_abort(dev, log, verbose=False):
|
||||||
Given a USB device with multiple OUT/IN endpoint pairs
|
Given a USB device with multiple OUT/IN endpoint pairs
|
||||||
When a device aborts an in progress data transfer
|
When a device aborts an in progress data transfer
|
||||||
Then no more data is transmitted
|
Then no more data is transmitted
|
||||||
|
and endpoint buffer is correctly released on the device end
|
||||||
"""
|
"""
|
||||||
NUM_PACKETS_UNTIL_ABORT = 2
|
NUM_PACKETS_UNTIL_ABORT = 2
|
||||||
NUM_PACKETS_AFTER_ABORT = 8
|
NUM_PACKETS_AFTER_ABORT = 8
|
||||||
|
|
||||||
|
# If the host ever receives a payload with any byte set to this value,
|
||||||
|
# the device does not handle abort operation correctly. The buffer
|
||||||
|
# passed to aborted operation must not be used after call to abort().
|
||||||
|
FORBIDDEN_PAYLOAD_VALUE = NUM_PACKETS_AFTER_ABORT + 1
|
||||||
|
|
||||||
cfg = dev.get_active_configuration()
|
cfg = dev.get_active_configuration()
|
||||||
for intf in cfg:
|
for intf in cfg:
|
||||||
log('interface {}, alt {} -- '.format(intf.bInterfaceNumber, intf.bAlternateSetting), end='')
|
log('interface {}, alt {} -- '.format(intf.bInterfaceNumber, intf.bAlternateSetting), end='')
|
||||||
|
@ -1336,6 +1354,11 @@ def ep_test_abort(dev, log, verbose=False):
|
||||||
payload_in.extend(packet)
|
payload_in.extend(packet)
|
||||||
except usb.core.USBError as err:
|
except usb.core.USBError as err:
|
||||||
break
|
break
|
||||||
|
if FORBIDDEN_PAYLOAD_VALUE in payload_in:
|
||||||
|
raise_unconditionally(
|
||||||
|
lineno(), 'Endpoint buffer not released when aborting the '
|
||||||
|
'write operation on endpoint {0.bEndpointAddress:#04x}.'
|
||||||
|
.format(ep_in))
|
||||||
if verbose:
|
if verbose:
|
||||||
log('The size of data successfully received from endpoint {0.bEndpointAddress:#04x}: {1} B.'
|
log('The size of data successfully received from endpoint {0.bEndpointAddress:#04x}: {1} B.'
|
||||||
.format(ep_in, len(payload_in)))
|
.format(ep_in, len(payload_in)))
|
||||||
|
@ -1353,13 +1376,24 @@ def ep_test_abort(dev, log, verbose=False):
|
||||||
log('Testing aborting an in progress transfer for OUT endpoints.')
|
log('Testing aborting an in progress transfer for OUT endpoints.')
|
||||||
for ep_out in (bulk_out, interrupt_out):
|
for ep_out in (bulk_out, interrupt_out):
|
||||||
payload_size = (NUM_PACKETS_UNTIL_ABORT + NUM_PACKETS_AFTER_ABORT) * ep_out.wMaxPacketSize
|
payload_size = (NUM_PACKETS_UNTIL_ABORT + NUM_PACKETS_AFTER_ABORT) * ep_out.wMaxPacketSize
|
||||||
payload_out = array.array('B', (0x01 for _ in range(ep_out.wMaxPacketSize)))
|
|
||||||
num_bytes_written = 0
|
num_bytes_written = 0
|
||||||
while num_bytes_written < payload_size:
|
while num_bytes_written < payload_size:
|
||||||
|
payload_out = array.array('B', (num_bytes_written/ep_out.wMaxPacketSize
|
||||||
|
for _ in range(ep_out.wMaxPacketSize)))
|
||||||
try:
|
try:
|
||||||
num_bytes_written += ep_out.write(payload_out)
|
num_bytes_written += ep_out.write(payload_out)
|
||||||
except usb.core.USBError:
|
except usb.core.USBError:
|
||||||
break
|
break
|
||||||
|
try:
|
||||||
|
ep_buff_correct = request_abort_buff_check(dev, ep_out)
|
||||||
|
except (usb.core.USBError, IndexError, TypeError) as err:
|
||||||
|
raise_unconditionally(
|
||||||
|
lineno(), 'Unable to verify endpoint buffer content ({!r}).'.format(err))
|
||||||
|
if not ep_buff_correct:
|
||||||
|
raise_unconditionally(
|
||||||
|
lineno(), 'Endpoint buffer not released when aborting the '
|
||||||
|
'read operation on endpoint {0.bEndpointAddress:#04x}.'
|
||||||
|
.format(ep_out))
|
||||||
if verbose:
|
if verbose:
|
||||||
log('The size of data successfully sent to endpoint {0.bEndpointAddress:#04x}: {1} B.'
|
log('The size of data successfully sent to endpoint {0.bEndpointAddress:#04x}: {1} B.'
|
||||||
.format(ep_out, num_bytes_written))
|
.format(ep_out, num_bytes_written))
|
||||||
|
|
|
@ -24,12 +24,20 @@
|
||||||
|
|
||||||
#define NUM_PACKETS_UNTIL_ABORT 2
|
#define NUM_PACKETS_UNTIL_ABORT 2
|
||||||
#define NUM_PACKETS_AFTER_ABORT 8
|
#define NUM_PACKETS_AFTER_ABORT 8
|
||||||
|
#define EP_ABORT_BUFF_VALUE 0xff
|
||||||
|
|
||||||
#define VENDOR_TEST_CTRL_IN 1
|
/* If the host ever receives a payload with any byte set to this value,
|
||||||
#define VENDOR_TEST_CTRL_OUT 2
|
* the device does not handle abort operation correctly. The buffer
|
||||||
#define VENDOR_TEST_CTRL_IN_SIZES 9
|
* passed to aborted operation must not be used after call to abort().
|
||||||
#define VENDOR_TEST_CTRL_OUT_SIZES 10
|
*/
|
||||||
#define VENDOR_TEST_READ_START 11
|
#define FORBIDDEN_PAYLOAD_VALUE (NUM_PACKETS_AFTER_ABORT + 1)
|
||||||
|
|
||||||
|
#define VENDOR_TEST_CTRL_IN 1
|
||||||
|
#define VENDOR_TEST_CTRL_OUT 2
|
||||||
|
#define VENDOR_TEST_CTRL_IN_SIZES 9
|
||||||
|
#define VENDOR_TEST_CTRL_OUT_SIZES 10
|
||||||
|
#define VENDOR_TEST_READ_START 11
|
||||||
|
#define VENDOR_TEST_ABORT_BUFF_CHECK 12
|
||||||
|
|
||||||
#define EVENT_READY (1 << 0)
|
#define EVENT_READY (1 << 0)
|
||||||
|
|
||||||
|
@ -236,6 +244,12 @@ void USBEndpointTester::callback_request(const setup_packet_t *setup)
|
||||||
case VENDOR_TEST_READ_START:
|
case VENDOR_TEST_READ_START:
|
||||||
result = (_request_read_start(setup)) ? Success : Failure;
|
result = (_request_read_start(setup)) ? Success : Failure;
|
||||||
break;
|
break;
|
||||||
|
case VENDOR_TEST_ABORT_BUFF_CHECK:
|
||||||
|
result = Send;
|
||||||
|
ctrl_buf[0] = _request_abort_buff_check(setup);
|
||||||
|
data = ctrl_buf;
|
||||||
|
size = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
result = PassThrough;
|
result = PassThrough;
|
||||||
break;
|
break;
|
||||||
|
@ -273,20 +287,50 @@ bool USBEndpointTester::_request_read_start(const setup_packet_t *setup)
|
||||||
if (setup->bmRequestType.Recipient != ENDPOINT_RECIPIENT) {
|
if (setup->bmRequestType.Recipient != ENDPOINT_RECIPIENT) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size_t ep_index = NUM_ENDPOINTS + 1;
|
size_t ep_index = NUM_ENDPOINTS;
|
||||||
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
|
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
|
||||||
if (_endpoints[i] == setup->wIndex) {
|
if (_endpoints[i] == setup->wIndex) {
|
||||||
ep_index = i;
|
ep_index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ep_index > NUM_ENDPOINTS) {
|
if (ep_index == NUM_ENDPOINTS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_endpoint_buffs[ep_index] == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
endpoint_abort(_endpoints[ep_index]);
|
endpoint_abort(_endpoints[ep_index]);
|
||||||
return read_start(_endpoints[ep_index], _endpoint_buffs[ep_index], (*_endpoint_configs)[ep_index].max_packet);
|
return read_start(_endpoints[ep_index], _endpoint_buffs[ep_index], (*_endpoint_configs)[ep_index].max_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool USBEndpointTester::_request_abort_buff_check(const setup_packet_t *setup)
|
||||||
|
{
|
||||||
|
assert_locked();
|
||||||
|
if (setup->bmRequestType.Recipient != ENDPOINT_RECIPIENT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t ep_index = NUM_ENDPOINTS;
|
||||||
|
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
|
||||||
|
if (_endpoints[i] == setup->wIndex) {
|
||||||
|
ep_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ep_index == NUM_ENDPOINTS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_endpoint_buffs[ep_index] == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < (*_endpoint_configs)[ep_index].max_packet; i++) {
|
||||||
|
if (_endpoint_buffs[ep_index][i] != EP_ABORT_BUFF_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void USBEndpointTester::callback_request_xfer_done(const setup_packet_t *setup, bool aborted)
|
void USBEndpointTester::callback_request_xfer_done(const setup_packet_t *setup, bool aborted)
|
||||||
{
|
{
|
||||||
if (aborted) {
|
if (aborted) {
|
||||||
|
@ -309,6 +353,9 @@ void USBEndpointTester::callback_request_xfer_done(const setup_packet_t *setup,
|
||||||
case VENDOR_TEST_CTRL_IN_SIZES:
|
case VENDOR_TEST_CTRL_IN_SIZES:
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
|
case VENDOR_TEST_ABORT_BUFF_CHECK:
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
|
@ -723,7 +770,6 @@ void USBEndpointTester::_cb_bulk_out()
|
||||||
{
|
{
|
||||||
_cnt_cb_bulk_out++;
|
_cnt_cb_bulk_out++;
|
||||||
uint32_t rx_size = read_finish(_endpoints[EP_BULK_OUT]);
|
uint32_t rx_size = read_finish(_endpoints[EP_BULK_OUT]);
|
||||||
|
|
||||||
if (_abort_transfer_test == false) {
|
if (_abort_transfer_test == false) {
|
||||||
// Send data back to host using the IN endpoint.
|
// Send data back to host using the IN endpoint.
|
||||||
memset(_endpoint_buffs[EP_BULK_IN], 0, (*_endpoint_configs)[EP_BULK_IN].max_packet);
|
memset(_endpoint_buffs[EP_BULK_IN], 0, (*_endpoint_configs)[EP_BULK_IN].max_packet);
|
||||||
|
@ -732,6 +778,10 @@ void USBEndpointTester::_cb_bulk_out()
|
||||||
} else {
|
} else {
|
||||||
// Abort the transfer if enough data was received.
|
// Abort the transfer if enough data was received.
|
||||||
_num_packets_bulk_out_abort++;
|
_num_packets_bulk_out_abort++;
|
||||||
|
if (_num_packets_bulk_out_abort == NUM_PACKETS_UNTIL_ABORT) {
|
||||||
|
// Set every byte of the buffer to a known value.
|
||||||
|
memset(_endpoint_buffs[EP_BULK_OUT], EP_ABORT_BUFF_VALUE, (*_endpoint_configs)[EP_BULK_OUT].max_packet);
|
||||||
|
}
|
||||||
read_start(_endpoints[EP_BULK_OUT], _endpoint_buffs[EP_BULK_OUT], (*_endpoint_configs)[EP_BULK_OUT].max_packet);
|
read_start(_endpoints[EP_BULK_OUT], _endpoint_buffs[EP_BULK_OUT], (*_endpoint_configs)[EP_BULK_OUT].max_packet);
|
||||||
if (_num_packets_bulk_out_abort == NUM_PACKETS_UNTIL_ABORT) {
|
if (_num_packets_bulk_out_abort == NUM_PACKETS_UNTIL_ABORT) {
|
||||||
endpoint_abort(_endpoints[EP_BULK_OUT]);
|
endpoint_abort(_endpoints[EP_BULK_OUT]);
|
||||||
|
@ -743,7 +793,6 @@ void USBEndpointTester::_cb_bulk_in()
|
||||||
{
|
{
|
||||||
_cnt_cb_bulk_in++;
|
_cnt_cb_bulk_in++;
|
||||||
write_finish(_endpoints[EP_BULK_IN]);
|
write_finish(_endpoints[EP_BULK_IN]);
|
||||||
|
|
||||||
if (_abort_transfer_test == false) {
|
if (_abort_transfer_test == false) {
|
||||||
// Receive more data from the host using the OUT endpoint.
|
// Receive more data from the host using the OUT endpoint.
|
||||||
read_start(_endpoints[EP_BULK_OUT], _endpoint_buffs[EP_BULK_OUT], (*_endpoint_configs)[EP_BULK_OUT].max_packet);
|
read_start(_endpoints[EP_BULK_OUT], _endpoint_buffs[EP_BULK_OUT], (*_endpoint_configs)[EP_BULK_OUT].max_packet);
|
||||||
|
@ -757,6 +806,10 @@ void USBEndpointTester::_cb_bulk_in()
|
||||||
write_start(_endpoints[EP_BULK_IN], _endpoint_buffs[EP_BULK_IN], (*_endpoint_configs)[EP_BULK_IN].max_packet);
|
write_start(_endpoints[EP_BULK_IN], _endpoint_buffs[EP_BULK_IN], (*_endpoint_configs)[EP_BULK_IN].max_packet);
|
||||||
if (_num_packets_bulk_in_abort == NUM_PACKETS_UNTIL_ABORT) {
|
if (_num_packets_bulk_in_abort == NUM_PACKETS_UNTIL_ABORT) {
|
||||||
endpoint_abort(_endpoints[EP_BULK_IN]);
|
endpoint_abort(_endpoints[EP_BULK_IN]);
|
||||||
|
// Verify that buffer given in write_start is not used after the
|
||||||
|
// call to endpoint_abort(), by changing the buffer contents.
|
||||||
|
// The test will fail if the host receives new buffer content.
|
||||||
|
memset(_endpoint_buffs[EP_BULK_IN], FORBIDDEN_PAYLOAD_VALUE, (*_endpoint_configs)[EP_BULK_IN].max_packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -773,6 +826,10 @@ void USBEndpointTester::_cb_int_out()
|
||||||
} else {
|
} else {
|
||||||
// Abort the transfer if enough data was received.
|
// Abort the transfer if enough data was received.
|
||||||
_num_packets_int_out_abort++;
|
_num_packets_int_out_abort++;
|
||||||
|
if (_num_packets_int_out_abort == NUM_PACKETS_UNTIL_ABORT) {
|
||||||
|
// Set every byte of the buffer to a known value.
|
||||||
|
memset(_endpoint_buffs[EP_INT_OUT], EP_ABORT_BUFF_VALUE, (*_endpoint_configs)[EP_INT_OUT].max_packet);
|
||||||
|
}
|
||||||
read_start(_endpoints[EP_INT_OUT], _endpoint_buffs[EP_INT_OUT], (*_endpoint_configs)[EP_INT_OUT].max_packet);
|
read_start(_endpoints[EP_INT_OUT], _endpoint_buffs[EP_INT_OUT], (*_endpoint_configs)[EP_INT_OUT].max_packet);
|
||||||
if (_num_packets_int_out_abort == NUM_PACKETS_UNTIL_ABORT) {
|
if (_num_packets_int_out_abort == NUM_PACKETS_UNTIL_ABORT) {
|
||||||
endpoint_abort(_endpoints[EP_INT_OUT]);
|
endpoint_abort(_endpoints[EP_INT_OUT]);
|
||||||
|
@ -797,6 +854,10 @@ void USBEndpointTester::_cb_int_in()
|
||||||
write_start(_endpoints[EP_INT_IN], _endpoint_buffs[EP_INT_IN], (*_endpoint_configs)[EP_INT_IN].max_packet);
|
write_start(_endpoints[EP_INT_IN], _endpoint_buffs[EP_INT_IN], (*_endpoint_configs)[EP_INT_IN].max_packet);
|
||||||
if (_num_packets_int_in_abort == NUM_PACKETS_UNTIL_ABORT) {
|
if (_num_packets_int_in_abort == NUM_PACKETS_UNTIL_ABORT) {
|
||||||
endpoint_abort(_endpoints[EP_INT_IN]);
|
endpoint_abort(_endpoints[EP_INT_IN]);
|
||||||
|
// Verify that buffer given in write_start is not used after the
|
||||||
|
// call to endpoint_abort(), by changing the buffer contents.
|
||||||
|
// The test will fail if the host receives new buffer content.
|
||||||
|
memset(_endpoint_buffs[EP_INT_IN], FORBIDDEN_PAYLOAD_VALUE, (*_endpoint_configs)[EP_INT_IN].max_packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
const char *get_desc_string(const uint8_t *desc);
|
const char *get_desc_string(const uint8_t *desc);
|
||||||
bool _request_read_start(const setup_packet_t *setup);
|
bool _request_read_start(const setup_packet_t *setup);
|
||||||
|
bool _request_abort_buff_check(const setup_packet_t *setup);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -355,6 +355,7 @@ void ep_test_parallel_transfers_ctrl()
|
||||||
* Given a USB device with multiple OUT/IN endpoint pairs
|
* Given a USB device with multiple OUT/IN endpoint pairs
|
||||||
* When a device aborts an in progress data transfer
|
* When a device aborts an in progress data transfer
|
||||||
* Then no more data is transmitted
|
* Then no more data is transmitted
|
||||||
|
* and endpoint buffer is correctly released on the device end
|
||||||
*/
|
*/
|
||||||
void ep_test_abort()
|
void ep_test_abort()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue