| # Copyright 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import common |
| from autotest_lib.client.cros.cellular.mbim_compliance.sequences \ |
| import get_descriptors_sequence |
| from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors |
| from autotest_lib.client.cros.cellular.mbim_compliance \ |
| import mbim_test_base |
| from autotest_lib.client.cros.cellular.mbim_compliance import usb_descriptors |
| |
| |
| class cellular_MbimComplianceDES02(mbim_test_base.MbimTestBase): |
| """ |
| DES_02 Descriptors Validation for MBIM Only Functions |
| |
| This test validates descriptors for MBIM only functions. |
| |
| Reference: |
| [1] Universal Serial Bus Communication Class MBIM Compliance Testing: 26 |
| http://www.usb.org/developers/docs/devclass_docs/MBIM-Compliance-1.0.pdf |
| |
| """ |
| version = 1 |
| |
| def run_internal(self): |
| """ Run the DES_02 test. """ |
| # Precondition. |
| descriptors = get_descriptors_sequence.GetDescriptorsSequence( |
| self.device_context).run() |
| |
| # Test step 1 |
| # Get MBIM communication interface. |
| interfaces = usb_descriptors.filter_descriptors( |
| usb_descriptors.InterfaceDescriptor, descriptors) |
| |
| mbim_communication_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.MBIM_ONLY_COMMUNICATION_INTERFACE)) |
| |
| if not mbim_communication_interfaces: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.3#1') |
| |
| if len(mbim_communication_interfaces) > 1: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'Expected 1 mbim communication interface, got %d.' % ( |
| len(mbim_communication_interfaces))) |
| mbim_communication_interface = mbim_communication_interfaces[0] |
| |
| # Test step 2 |
| # Get header functional descriptor, union functional descriptor, |
| # MBIM functional descriptor and MBIM extended functional |
| # descriptor. |
| mbim_communication_interface_bundle = ( |
| usb_descriptors.get_descriptor_bundle( |
| descriptors, mbim_communication_interface)) |
| |
| header_descriptors = usb_descriptors.filter_descriptors( |
| usb_descriptors.HeaderFunctionalDescriptor, |
| mbim_communication_interface_bundle) |
| union_descriptors = usb_descriptors.filter_descriptors( |
| usb_descriptors.UnionFunctionalDescriptor, |
| mbim_communication_interface_bundle) |
| mbim_descriptors = usb_descriptors.filter_descriptors( |
| usb_descriptors.MBIMFunctionalDescriptor, |
| mbim_communication_interface_bundle) |
| mbim_extended_descriptors = usb_descriptors.filter_descriptors( |
| usb_descriptors.MBIMExtendedFunctionalDescriptor, |
| mbim_communication_interface_bundle) |
| if not(header_descriptors and union_descriptors and mbim_descriptors): |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.3#2') |
| |
| # Test step 3 |
| # Check header functional descriptor. |
| if usb_descriptors.has_distinct_descriptors(header_descriptors): |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'Expected 1 unique header functional descriptor.') |
| header_descriptor = header_descriptors[0] |
| if not(header_descriptor.bDescriptorType == 0x24 and |
| header_descriptor.bDescriptorSubtype == 0x00 and |
| header_descriptor.bLength == 5 and |
| header_descriptor.bcdCDC >= 0x0120): |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'Header functional descriptor: wrong value(s)') |
| |
| # Test step 4 |
| # Check union functional descriptor. |
| if usb_descriptors.has_distinct_descriptors(union_descriptors): |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenerisAssertionError, |
| 'Expected 1 unique union functional descriptor.') |
| union_descriptor = union_descriptors[0] |
| if union_descriptor.index < header_descriptor.index: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.3#3') |
| |
| # Get CDC no data data interface. |
| no_data_data_interfaces = usb_descriptors.filter_interface_descriptors( |
| interfaces, usb_descriptors.MBIM_ONLY_DATA_INTERFACE_NO_DATA) |
| if not no_data_data_interfaces: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.6#4') |
| if len(no_data_data_interfaces) > 1: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'Exactly 1 CDC data interface, got %d.' % ( |
| len(no_data_data_interfaces))) |
| no_data_data_interface = no_data_data_interfaces[0] |
| no_data_data_interface_bundle = usb_descriptors.get_descriptor_bundle( |
| descriptors, no_data_data_interface) |
| data_endpoint_descriptors = ( |
| usb_descriptors.filter_descriptors( |
| usb_descriptors.EndpointDescriptor, |
| no_data_data_interface_bundle)) |
| if data_endpoint_descriptors: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.6#2') |
| |
| # Get MBIM data interface. |
| mbim_data_interfaces = usb_descriptors.filter_interface_descriptors( |
| interfaces, usb_descriptors.MBIM_ONLY_DATA_INTERFACE_MBIM) |
| if not mbim_data_interfaces: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.6#4') |
| if len(mbim_data_interfaces) > 1: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'Expected 1 MBIM data interface, got %d.' % ( |
| len(mbim_data_interfaces))) |
| mbim_data_interface = mbim_data_interfaces[0] |
| |
| # Check if there are two endpoint descriptors. |
| if mbim_data_interface.bNumEndpoints != 2: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.6#3.') |
| |
| mbim_data_interface_bundle = usb_descriptors.get_descriptor_bundle( |
| descriptors, mbim_data_interface) |
| data_endpoint_descriptors = usb_descriptors.filter_descriptors( |
| usb_descriptors.EndpointDescriptor, |
| mbim_data_interface_bundle) |
| |
| # Check the values of fields in endpoint descriptors. |
| # There should be one bulk OUT and one bulk IN. |
| if not usb_descriptors.has_bulk_in_and_bulk_out( |
| data_endpoint_descriptors): |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.6#3') |
| |
| # MBIM cdc data interface should have both no data data interface and |
| # MBIM data interface. Therefore two interface numbers should be |
| # the same. |
| if (no_data_data_interface.bInterfaceNumber != |
| mbim_data_interface.bInterfaceNumber): |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.6#1') |
| |
| # Check the fields of union functional descriptor |
| if not(union_descriptor.bLength == 5 and |
| (union_descriptor.bControlInterface == |
| mbim_communication_interface.bInterfaceNumber) and |
| (union_descriptor.bSubordinateInterface0 == |
| mbim_data_interface.bInterfaceNumber)): |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.3#4') |
| |
| # Test step 5 |
| # Get MBIM functional descriptor. |
| if usb_descriptors.has_distinct_descriptors(mbim_descriptors): |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'Expected 1 unique MBIM functional descriptor.') |
| mbim_descriptor = mbim_descriptors[0] |
| |
| if mbim_descriptor.index < header_descriptor.index: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.3#3') |
| |
| if mbim_descriptor.bLength != 12: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.4#5') |
| |
| if mbim_descriptor.bcdMBIMVersion != 0x0100: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.4#6') |
| |
| if mbim_descriptor.wMaxControlMessage < 64: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.4#1') |
| |
| if mbim_descriptor.bNumberFilters < 16: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.4#2') |
| |
| if mbim_descriptor.bMaxFilterSize > 192: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.4#3') |
| |
| # TODO(mcchou): Most of vendors set wMaxSegmentSize to be less than |
| # 1500, so this assertion is skipped for now. |
| # |
| #if not mbim_descriptor.wMaxSegmentSize >= 2048: |
| # mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| # 'mbim1.0:6.4#4') |
| |
| # Use a byte as the mask to check if D0, D1, D2, D4, D6 and D7 are |
| # zeros. |
| if (mbim_descriptor.bmNetworkCapabilities & 0b11010111) > 0: |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.4#7') |
| |
| # Test step 6 |
| # Get MBIM extended functional descriptor, which is optional. |
| if len(mbim_extended_descriptors) >= 1: |
| if usb_descriptors.has_distinct_descriptors( |
| mbim_extended_descriptors): |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenerisAssertionError, |
| 'Expected 1 unique MBIM extended functional ' |
| 'descriptor.') |
| mbim_extended_descriptor = mbim_extended_descriptors[0] |
| |
| if mbim_extended_descriptor.index < mbim_descriptor.index: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.5#1') |
| |
| if mbim_extended_descriptor.bLength != 8: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.5#2') |
| |
| if mbim_extended_descriptor.bcdMBIMExtendedVersion != 0x0100: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.5#3') |
| |
| if mbim_extended_descriptor.bMaxOutstandingCommandMessages == 0: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.5#4') |
| |
| # Test step 7 |
| # Get the first endpoint for the communication interface. |
| interrupt_endpoint_descriptors = usb_descriptors.filter_descriptors( |
| usb_descriptors.EndpointDescriptor, |
| mbim_communication_interface_bundle) |
| |
| if len(interrupt_endpoint_descriptors) != 1: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'Expected 1 endpoint, got %d.' % ( |
| len(interrupt_endpoint_descriptors))) |
| interrupt_endpoint_descriptor = interrupt_endpoint_descriptors[0] |
| if not (interrupt_endpoint_descriptor.bDescriptorType == 0x05 and |
| interrupt_endpoint_descriptor.bLength == 7 and |
| interrupt_endpoint_descriptor.bEndpointAddress >= 0x80 and |
| interrupt_endpoint_descriptor.bmAttributes == 0x03): |
| mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.3#5') |
| |
| appear_before_functional_descriptors = False |
| if mbim_extended_descriptors: |
| if (mbim_extended_descriptor.index > |
| interrupt_endpoint_descriptor.index): |
| appear_before_functional_descriptors = True |
| else: |
| if (mbim_descriptor.index > interrupt_endpoint_descriptor.index or |
| union_descriptor.index > interrupt_endpoint_descriptor.index): |
| appear_before_functional_descriptors = True |
| if appear_before_functional_descriptors: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'All functional descriptors must appear before endpoint' |
| 'descriptors.') |
| |
| # Test step 8 |
| # Get interface association descriptor. |
| interface_association_descriptors = ( |
| usb_descriptors.filter_descriptors( |
| usb_descriptors.InterfaceAssociationDescriptor, |
| descriptors)) |
| |
| if usb_descriptors.has_distinct_descriptors( |
| interface_association_descriptors): |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceGenericAssertionError, |
| 'Expected 1 interface association descriptor, got %d.' % ( |
| len(interface_association_descriptors))) |
| |
| for association_descriptor in interface_association_descriptors: |
| # Check interface association descriptor if one of the following |
| # condition is met: |
| # 1. bFirstInterface <= bControlInterface < (bFirstInterface + |
| # bInterfaceCount) |
| # 2. bFirstInterface <= bSubordinateInterface0 < ( |
| # bFirstInterface + bInterfaceCount) |
| b_first_interface = association_descriptor.bFirstInterface |
| b_interface_count = association_descriptor.bInterfaceCount |
| b_control_interface = union_descriptor.bControlInterface |
| b_subordinate_interface_0 = ( |
| union_descriptor.bSubordinateInterface0) |
| check_inteface_association_descriptor = False |
| |
| if ((b_first_interface <= b_control_interface < ( |
| b_first_interface + b_interface_count)) or |
| (b_first_interface <= b_subordinate_interface_0 < ( |
| b_first_interface + b_interface_count))): |
| check_interface_association_descriptor = True |
| |
| if not check_interface_association_descriptor: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.1#1') |
| |
| if check_interface_association_descriptor: |
| if not((b_first_interface == b_control_interface or |
| b_first_interface == b_subordinate_interface_0) and |
| (b_interface_count == 2) and |
| (b_subordinate_interface_0 == b_control_interface + 1 or |
| b_subordinate_interface_0 == |
| b_control_interface - 1) and |
| (association_descriptor.bFunctionClass == 0x02) and |
| (association_descriptor.bFunctionSubClass == 0x0E) and |
| (association_descriptor.bFunctionProtocol == 0x00)): |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceAssertionError, |
| 'mbim1.0:6.1#2') |
| |
| # End of run_internal(). |