tests: gadget0: Added testing for Microsoft OS descriptor retrieval and invalid request handling

This commit is contained in:
dragonmux
2022-08-17 21:41:26 +01:00
committed by Piotr Esden-Tempski
parent 2f1d5e38ab
commit de48ffd543

View File

@@ -47,6 +47,18 @@ DESC_TYPE_DEVICE_CAPABILITY = 0x10
DEVCAP_TYPE_PLATFORM = 5
MICROSOFT_OS_GET_DESCRIPTOR_SET = 7
MICROSOFT_OS_SET_HEADER = 0
MICROSOFT_OS_SUBSET_HEADER_CONFIGURATION = 1
MICROSOFT_OS_SUBSET_HEADER_FUNCTION = 2
MICROSOFT_OS_FEATURE_COMPATIBLE_ID = 3
MICROSOFT_OS_FEATURE_REG_PROPERTY = 4
MICROSOFT_OS_FEATURE_MIN_RESUME_TIME = 5
MICROSOFT_OS_FEATURE_MODEL_ID = 6
MICROSOFT_OS_FEATURE_CCGP_DEVICE = 7
MICROSOFT_OS_FEATURE_VENDOR_REVISION = 8
MICROSOFT_WINDOWS_VERSION_WINBLUE = 0x06030000
class find_by_serial(object):
@@ -575,6 +587,97 @@ class TestBOSDescriptor(unittest.TestCase):
self.assertEqual(e.errno, 32)
class TestMicrosoftOSDescriptors(unittest.TestCase):
"""
Make sure the Microsoft OS descriptor handling works per
https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-os-2-0-descriptors-specification
"""
def setUp(self):
self.dev : usb.core.Device = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
def tearDown(self):
uu.dispose_resources(self.dev)
def get_microsoft_os_descriptor(self, *, vendor_id, byte_count) -> bytes:
return self.dev.ctrl_transfer(
bmRequestType=uu.build_request_type(uu.CTRL_IN, uu.CTRL_TYPE_VENDOR, uu.CTRL_RECIPIENT_DEVICE),
bRequest=vendor_id,
wValue=0,
wIndex=MICROSOFT_OS_GET_DESCRIPTOR_SET,
data_or_wLength=byte_count
).tobytes()
@staticmethod
def read_le16(data : bytes):
return data[0] | (data[1] << 8)
@staticmethod
def read_le32(data : bytes):
return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24)
def test_partial_request(self):
# This is the Vendor Code from the BOS above (descriptor_set_info[6])
descriptor_set = self.get_microsoft_os_descriptor(vendor_id=1, byte_count=10)
self.assertEqual(len(descriptor_set), 10)
# Check that the set descriptor returned is valid
self.assertEqual(self.read_le16(descriptor_set[0:2]), 10)
self.assertEqual(self.read_le16(descriptor_set[2:4]), MICROSOFT_OS_SET_HEADER)
self.assertEqual(self.read_le32(descriptor_set[4:8]), MICROSOFT_WINDOWS_VERSION_WINBLUE)
self.assertEqual(self.read_le16(descriptor_set[8:10]), 46)
def test_complete_request(self):
# This is the Vendor Code from the BOS above (descriptor_set_info[6])
descriptor_set = self.get_microsoft_os_descriptor(vendor_id=1, byte_count=46)
self.assertEqual(len(descriptor_set), 46)
# Check that the set descriptor returned is valid
self.assertEqual(self.read_le16(descriptor_set[0:2]), 10)
self.assertEqual(self.read_le16(descriptor_set[2:4]), MICROSOFT_OS_SET_HEADER)
self.assertEqual(self.read_le32(descriptor_set[4:8]), MICROSOFT_WINDOWS_VERSION_WINBLUE)
self.assertEqual(self.read_le16(descriptor_set[8:10]), 46)
# Check that the config subset descriptor returned is valid
config_subset = descriptor_set[10:]
self.assertEqual(self.read_le16(config_subset[0:2]), 8)
self.assertEqual(self.read_le16(config_subset[2:4]), MICROSOFT_OS_SUBSET_HEADER_CONFIGURATION)
self.assertEqual(config_subset[4], 1) # bConfigurationValue
self.assertEqual(config_subset[5], 0)
self.assertEqual(self.read_le16(config_subset[6:8]), 36)
# Check that the function subset descriptor returned is valid
function_subset = config_subset[8:]
self.assertEqual(self.read_le16(function_subset[0:2]), 8)
self.assertEqual(self.read_le16(function_subset[2:4]), MICROSOFT_OS_SUBSET_HEADER_FUNCTION)
self.assertEqual(function_subset[4], 0) # bFirstInterface
self.assertEqual(function_subset[5], 0)
self.assertEqual(self.read_le16(function_subset[6:8]), 28)
# Check that the feature descriptor is a Compatible ID descriptor and valid
feature = function_subset[8:]
self.assertEqual(self.read_le16(feature[0:2]), 20)
self.assertEqual(self.read_le16(feature[2:4]), MICROSOFT_OS_FEATURE_COMPATIBLE_ID)
self.assertEqual(feature[4:12], b'WINUSB\x00\x00')
self.assertEqual(feature[12:20], b'\x00' * 8)
def test_invalid_request(self):
try:
self.get_microsoft_os_descriptor(vendor_id=0, byte_count=10)
self.fail("get_microsoft_os_descriptor() for an invalid descriptor set request suceeded")
except usb.core.USBError as e:
# Make sure we got a pipe error (EP0 STALL)
# Why libusb returns stalls as this and makes them fatal is.. a subject for a different place..
self.assertEqual(e.errno, 32)
try:
self.get_microsoft_os_descriptor(vendor_id=2, byte_count=0)
self.fail("get_microsoft_os_descriptor() for an invalid descriptor set request suceeded")
except usb.core.USBError as e:
# Make sure we got a pipe error (EP0 STALL)
# Why libusb returns stalls as this and makes them fatal is.. a subject for a different place..
self.assertEqual(e.errno, 32)
def run_ci_test(dut):
# Avoids the import for non-CI users!
import xmlrunner