# Copyright (c) 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.
"""
DES_02 Descriptors Validation 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
"""
import common
from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors
from autotest_lib.client.cros.cellular.mbim_compliance import usb_descriptors
from autotest_lib.client.cros.cellular.mbim_compliance.sequences \
import get_descriptors_sequence
from autotest_lib.client.cros.cellular.mbim_compliance.tests import des_test
from autotest_lib.client.cros.cellular.mbim_compliance import test_context
class DES_02_Test(des_test.DesTest):
""" Implement the DES_2 Descriptors Validation for MBIM Only Functions. """
def run_internal(self):
""" Run the DES_02 test. """
# Precondition.
descriptors = get_descriptors_sequence.GetDescriptorsSequence(
self.test_context).run()
device = self.test_context.device
if not device:
mbim_errors.log_and_raise(mbim_errors.MBIMComplianceFrameworkError,
'Device not found')
# Test step 1
# Get MBIM communication interface.
interfaces = usb_descriptors.filter_descriptors(
usb_descriptors.InterfaceDescriptor, descriptors)
mbim_communication_interfaces = (
self.filter_interface_descriptors(
interfaces, self.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 = self.filter_interface_descriptors(
interfaces, self.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 = self.filter_interface_descriptors(
interfaces, self.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 self.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')
# Update |test_context| with mbim function settings.
if self.test_context.device_type == test_context.DEVICE_TYPE_NCM_MBIM:
mbim_errors.log_and_raise(mbim_errors.MBIMComplianceFrameworkError,
'A device can only be either a MBIM'
'device or a NCM/MBIM device.')
self.test_context.device_type = test_context.DEVICE_TYPE_MBIM
self.test_context.mbim_communication_interface = (
mbim_communication_interface)
self.test_context.no_data_data_interface = no_data_data_interface
self.test_context.mbim_data_interface = mbim_data_interface
self.test_context.mbim_functional = mbim_descriptor
self.test_context.interrupt_endpoint = interrupt_endpoint_descriptor
# End of run_internal().