Skip to content

Commit 6086e1f

Browse files
Filip Jagodzinskic1728p9
authored andcommitted
Tests: USB: Check ep buffer is released by abort
Validate that endpoint buffer is not used after a transfer has been aborted.
1 parent ef66111 commit 6086e1f

File tree

4 files changed

+107
-10
lines changed

4 files changed

+107
-10
lines changed

TESTS/host_tests/pyusb_basic.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def get_interface(dev, interface, alternate=0):
5656
VENDOR_TEST_CTRL_IN_SIZES = 9
5757
VENDOR_TEST_CTRL_OUT_SIZES = 10
5858
VENDOR_TEST_READ_START = 11
59+
VENDOR_TEST_ABORT_BUFF_CHECK = 12
5960
VENDOR_TEST_UNSUPPORTED_REQUEST = 32
6061

6162
REQUEST_GET_STATUS = 0
@@ -1062,6 +1063,16 @@ def request_endpoint_read_start(dev, ep):
10621063
dev.ctrl_transfer(**ctrl_kwargs)
10631064

10641065

1066+
def request_abort_buff_check(dev, ep):
1067+
ctrl_kwargs = {
1068+
'bmRequestType': build_request_type(CTRL_IN, CTRL_TYPE_VENDOR, CTRL_RECIPIENT_ENDPOINT),
1069+
'bRequest': VENDOR_TEST_ABORT_BUFF_CHECK,
1070+
'wValue': 0,
1071+
'wIndex': ep.bEndpointAddress,
1072+
'data_or_wLength': 1}
1073+
return bool(dev.ctrl_transfer(**ctrl_kwargs)[0])
1074+
1075+
10651076
USB_ERROR_FMT = str('Got {0!r} while testing endpoints '
10661077
'{1.bEndpointAddress:#04x}({1.wMaxPacketSize:02}) and '
10671078
'{2.bEndpointAddress:#04x}({2.wMaxPacketSize:02}) with '
@@ -1304,9 +1315,16 @@ def ep_test_abort(dev, log, verbose=False):
13041315
Given a USB device with multiple OUT/IN endpoint pairs
13051316
When a device aborts an in progress data transfer
13061317
Then no more data is transmitted
1318+
and endpoint buffer is correctly released on the device end
13071319
"""
13081320
NUM_PACKETS_UNTIL_ABORT = 2
13091321
NUM_PACKETS_AFTER_ABORT = 8
1322+
1323+
# If the host ever receives a payload with any byte set to this value,
1324+
# the device does not handle abort operation correctly. The buffer
1325+
# passed to aborted operation must not be used after call to abort().
1326+
FORBIDDEN_PAYLOAD_VALUE = NUM_PACKETS_AFTER_ABORT + 1
1327+
13101328
cfg = dev.get_active_configuration()
13111329
for intf in cfg:
13121330
log('interface {}, alt {} -- '.format(intf.bInterfaceNumber, intf.bAlternateSetting), end='')
@@ -1336,6 +1354,11 @@ def ep_test_abort(dev, log, verbose=False):
13361354
payload_in.extend(packet)
13371355
except usb.core.USBError as err:
13381356
break
1357+
if FORBIDDEN_PAYLOAD_VALUE in payload_in:
1358+
raise_unconditionally(
1359+
lineno(), 'Endpoint buffer not released when aborting the '
1360+
'write operation on endpoint {0.bEndpointAddress:#04x}.'
1361+
.format(ep_in))
13391362
if verbose:
13401363
log('The size of data successfully received from endpoint {0.bEndpointAddress:#04x}: {1} B.'
13411364
.format(ep_in, len(payload_in)))
@@ -1353,13 +1376,24 @@ def ep_test_abort(dev, log, verbose=False):
13531376
log('Testing aborting an in progress transfer for OUT endpoints.')
13541377
for ep_out in (bulk_out, interrupt_out):
13551378
payload_size = (NUM_PACKETS_UNTIL_ABORT + NUM_PACKETS_AFTER_ABORT) * ep_out.wMaxPacketSize
1356-
payload_out = array.array('B', (0x01 for _ in range(ep_out.wMaxPacketSize)))
13571379
num_bytes_written = 0
13581380
while num_bytes_written < payload_size:
1381+
payload_out = array.array('B', (num_bytes_written/ep_out.wMaxPacketSize
1382+
for _ in range(ep_out.wMaxPacketSize)))
13591383
try:
13601384
num_bytes_written += ep_out.write(payload_out)
13611385
except usb.core.USBError:
13621386
break
1387+
try:
1388+
ep_buff_correct = request_abort_buff_check(dev, ep_out)
1389+
except (usb.core.USBError, IndexError, TypeError) as err:
1390+
raise_unconditionally(
1391+
lineno(), 'Unable to verify endpoint buffer content ({!r}).'.format(err))
1392+
if not ep_buff_correct:
1393+
raise_unconditionally(
1394+
lineno(), 'Endpoint buffer not released when aborting the '
1395+
'read operation on endpoint {0.bEndpointAddress:#04x}.'
1396+
.format(ep_out))
13631397
if verbose:
13641398
log('The size of data successfully sent to endpoint {0.bEndpointAddress:#04x}: {1} B.'
13651399
.format(ep_out, num_bytes_written))

TESTS/usb_device/basic/USBEndpointTester.cpp

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,20 @@
2424

2525
#define NUM_PACKETS_UNTIL_ABORT 2
2626
#define NUM_PACKETS_AFTER_ABORT 8
27+
#define EP_ABORT_BUFF_VALUE 0xff
2728

28-
#define VENDOR_TEST_CTRL_IN 1
29-
#define VENDOR_TEST_CTRL_OUT 2
30-
#define VENDOR_TEST_CTRL_IN_SIZES 9
31-
#define VENDOR_TEST_CTRL_OUT_SIZES 10
32-
#define VENDOR_TEST_READ_START 11
29+
/* If the host ever receives a payload with any byte set to this value,
30+
* the device does not handle abort operation correctly. The buffer
31+
* passed to aborted operation must not be used after call to abort().
32+
*/
33+
#define FORBIDDEN_PAYLOAD_VALUE (NUM_PACKETS_AFTER_ABORT + 1)
34+
35+
#define VENDOR_TEST_CTRL_IN 1
36+
#define VENDOR_TEST_CTRL_OUT 2
37+
#define VENDOR_TEST_CTRL_IN_SIZES 9
38+
#define VENDOR_TEST_CTRL_OUT_SIZES 10
39+
#define VENDOR_TEST_READ_START 11
40+
#define VENDOR_TEST_ABORT_BUFF_CHECK 12
3341

3442
#define EVENT_READY (1 << 0)
3543

@@ -236,6 +244,12 @@ void USBEndpointTester::callback_request(const setup_packet_t *setup)
236244
case VENDOR_TEST_READ_START:
237245
result = (_request_read_start(setup)) ? Success : Failure;
238246
break;
247+
case VENDOR_TEST_ABORT_BUFF_CHECK:
248+
result = Send;
249+
ctrl_buf[0] = _request_abort_buff_check(setup);
250+
data = ctrl_buf;
251+
size = 1;
252+
break;
239253
default:
240254
result = PassThrough;
241255
break;
@@ -273,20 +287,50 @@ bool USBEndpointTester::_request_read_start(const setup_packet_t *setup)
273287
if (setup->bmRequestType.Recipient != ENDPOINT_RECIPIENT) {
274288
return false;
275289
}
276-
size_t ep_index = NUM_ENDPOINTS + 1;
290+
size_t ep_index = NUM_ENDPOINTS;
277291
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
278292
if (_endpoints[i] == setup->wIndex) {
279293
ep_index = i;
280294
break;
281295
}
282296
}
283-
if (ep_index > NUM_ENDPOINTS) {
297+
if (ep_index == NUM_ENDPOINTS) {
298+
return false;
299+
}
300+
if (_endpoint_buffs[ep_index] == NULL) {
284301
return false;
285302
}
286303
endpoint_abort(_endpoints[ep_index]);
287304
return read_start(_endpoints[ep_index], _endpoint_buffs[ep_index], (*_endpoint_configs)[ep_index].max_packet);
288305
}
289306

307+
bool USBEndpointTester::_request_abort_buff_check(const setup_packet_t *setup)
308+
{
309+
assert_locked();
310+
if (setup->bmRequestType.Recipient != ENDPOINT_RECIPIENT) {
311+
return false;
312+
}
313+
size_t ep_index = NUM_ENDPOINTS;
314+
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
315+
if (_endpoints[i] == setup->wIndex) {
316+
ep_index = i;
317+
break;
318+
}
319+
}
320+
if (ep_index == NUM_ENDPOINTS) {
321+
return false;
322+
}
323+
if (_endpoint_buffs[ep_index] == NULL) {
324+
return false;
325+
}
326+
for (size_t i = 0; i < (*_endpoint_configs)[ep_index].max_packet; i++) {
327+
if (_endpoint_buffs[ep_index][i] != EP_ABORT_BUFF_VALUE) {
328+
return false;
329+
}
330+
}
331+
return true;
332+
}
333+
290334
void USBEndpointTester::callback_request_xfer_done(const setup_packet_t *setup, bool aborted)
291335
{
292336
if (aborted) {
@@ -309,6 +353,9 @@ void USBEndpointTester::callback_request_xfer_done(const setup_packet_t *setup,
309353
case VENDOR_TEST_CTRL_IN_SIZES:
310354
result = true;
311355
break;
356+
case VENDOR_TEST_ABORT_BUFF_CHECK:
357+
result = true;
358+
break;
312359
default:
313360
result = false;
314361
break;
@@ -723,7 +770,6 @@ void USBEndpointTester::_cb_bulk_out()
723770
{
724771
_cnt_cb_bulk_out++;
725772
uint32_t rx_size = read_finish(_endpoints[EP_BULK_OUT]);
726-
727773
if (_abort_transfer_test == false) {
728774
// Send data back to host using the IN endpoint.
729775
memset(_endpoint_buffs[EP_BULK_IN], 0, (*_endpoint_configs)[EP_BULK_IN].max_packet);
@@ -732,6 +778,10 @@ void USBEndpointTester::_cb_bulk_out()
732778
} else {
733779
// Abort the transfer if enough data was received.
734780
_num_packets_bulk_out_abort++;
781+
if (_num_packets_bulk_out_abort == NUM_PACKETS_UNTIL_ABORT) {
782+
// Set every byte of the buffer to a known value.
783+
memset(_endpoint_buffs[EP_BULK_OUT], EP_ABORT_BUFF_VALUE, (*_endpoint_configs)[EP_BULK_OUT].max_packet);
784+
}
735785
read_start(_endpoints[EP_BULK_OUT], _endpoint_buffs[EP_BULK_OUT], (*_endpoint_configs)[EP_BULK_OUT].max_packet);
736786
if (_num_packets_bulk_out_abort == NUM_PACKETS_UNTIL_ABORT) {
737787
endpoint_abort(_endpoints[EP_BULK_OUT]);
@@ -743,7 +793,6 @@ void USBEndpointTester::_cb_bulk_in()
743793
{
744794
_cnt_cb_bulk_in++;
745795
write_finish(_endpoints[EP_BULK_IN]);
746-
747796
if (_abort_transfer_test == false) {
748797
// Receive more data from the host using the OUT endpoint.
749798
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()
757806
write_start(_endpoints[EP_BULK_IN], _endpoint_buffs[EP_BULK_IN], (*_endpoint_configs)[EP_BULK_IN].max_packet);
758807
if (_num_packets_bulk_in_abort == NUM_PACKETS_UNTIL_ABORT) {
759808
endpoint_abort(_endpoints[EP_BULK_IN]);
809+
// Verify that buffer given in write_start is not used after the
810+
// call to endpoint_abort(), by changing the buffer contents.
811+
// The test will fail if the host receives new buffer content.
812+
memset(_endpoint_buffs[EP_BULK_IN], FORBIDDEN_PAYLOAD_VALUE, (*_endpoint_configs)[EP_BULK_IN].max_packet);
760813
}
761814
}
762815
}
@@ -773,6 +826,10 @@ void USBEndpointTester::_cb_int_out()
773826
} else {
774827
// Abort the transfer if enough data was received.
775828
_num_packets_int_out_abort++;
829+
if (_num_packets_int_out_abort == NUM_PACKETS_UNTIL_ABORT) {
830+
// Set every byte of the buffer to a known value.
831+
memset(_endpoint_buffs[EP_INT_OUT], EP_ABORT_BUFF_VALUE, (*_endpoint_configs)[EP_INT_OUT].max_packet);
832+
}
776833
read_start(_endpoints[EP_INT_OUT], _endpoint_buffs[EP_INT_OUT], (*_endpoint_configs)[EP_INT_OUT].max_packet);
777834
if (_num_packets_int_out_abort == NUM_PACKETS_UNTIL_ABORT) {
778835
endpoint_abort(_endpoints[EP_INT_OUT]);
@@ -797,6 +854,10 @@ void USBEndpointTester::_cb_int_in()
797854
write_start(_endpoints[EP_INT_IN], _endpoint_buffs[EP_INT_IN], (*_endpoint_configs)[EP_INT_IN].max_packet);
798855
if (_num_packets_int_in_abort == NUM_PACKETS_UNTIL_ABORT) {
799856
endpoint_abort(_endpoints[EP_INT_IN]);
857+
// Verify that buffer given in write_start is not used after the
858+
// call to endpoint_abort(), by changing the buffer contents.
859+
// The test will fail if the host receives new buffer content.
860+
memset(_endpoint_buffs[EP_INT_IN], FORBIDDEN_PAYLOAD_VALUE, (*_endpoint_configs)[EP_INT_IN].max_packet);
800861
}
801862
}
802863
}

TESTS/usb_device/basic/USBEndpointTester.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class USBEndpointTester: public USBDevice {
104104
private:
105105
const char *get_desc_string(const uint8_t *desc);
106106
bool _request_read_start(const setup_packet_t *setup);
107+
bool _request_abort_buff_check(const setup_packet_t *setup);
107108
};
108109

109110
#endif

TESTS/usb_device/basic/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ void ep_test_parallel_transfers_ctrl()
355355
* Given a USB device with multiple OUT/IN endpoint pairs
356356
* When a device aborts an in progress data transfer
357357
* Then no more data is transmitted
358+
* and endpoint buffer is correctly released on the device end
358359
*/
359360
void ep_test_abort()
360361
{

0 commit comments

Comments
 (0)