1# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""
6DES_01 Descriptors Validation for NCM/MBIM Functions
7
8Reference:
9    [1] Universal Serial Bus Communication Class MBIM Compliance Testing: 23
10        http://www.usb.org/developers/docs/devclass_docs/MBIM-Compliance-1.0.pdf
11
12"""
13
14import common
15from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors
16from autotest_lib.client.cros.cellular.mbim_compliance import test_context
17from autotest_lib.client.cros.cellular.mbim_compliance import usb_descriptors
18from autotest_lib.client.cros.cellular.mbim_compliance.sequences \
19        import get_descriptors_sequence
20from autotest_lib.client.cros.cellular.mbim_compliance.tests import des_test
21
22
23class DES_01_Test(des_test.DesTest):
24    """ Implement the DES_01 Descriptors Validation for NCM/MBIM Functions """
25
26    def run_internal(self):
27        """ Run the DES_01 test. """
28        # Precondition.
29        descriptors = get_descriptors_sequence.GetDescriptorsSequence(
30                self.test_context).run()
31        device = self.test_context.device
32        if not device:
33            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceFrameworkError,
34                                      'Device not found')
35        interfaces = usb_descriptors.filter_descriptors(
36                usb_descriptors.InterfaceDescriptor, descriptors)
37
38        # Test step 1
39        # Get ncm communication interface and mbim communication interface.
40        ncm_communication_interfaces = self.filter_interface_descriptors(
41                interfaces, self.NCM_MBIM_COMMUNICATION_INTERFACE_NCM)
42
43        if len(ncm_communication_interfaces) != 1:
44            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
45                                      'mbim1.0:3.2.1#2')
46
47        ncm_communication_interface = ncm_communication_interfaces[0]
48
49        mbim_communication_interfaces = self.filter_interface_descriptors(
50                interfaces, self.NCM_MBIM_COMMUNICATION_INTERFACE_MBIM)
51
52        if len(mbim_communication_interfaces) != 1:
53            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
54                                      'mbim1.0:3.2.1#3')
55
56        mbim_communication_interface = mbim_communication_interfaces[0]
57
58        if (ncm_communication_interface.bInterfaceNumber !=
59            mbim_communication_interface.bInterfaceNumber):
60            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
61                                      'mbim1.0:3.2.1#1')
62
63        # Test step 2
64        if (ncm_communication_interface.index >
65            mbim_communication_interface.index):
66            mbim_errors.log_and_raise(
67                    mbim_errors.MBIMComplianceGenericAssertionError,
68                    'Alternate setting 1 of the interface must appear after'
69                    'alternate setting 0 of the interface.')
70
71        # Test step 3
72        # Get header functional descriptor, union functinoal descriptor,
73        # MBIM functinoal descriptor and MBIM extended functional
74        # descriptor from |ncm_communication_interface|[0].
75        ncm_communication_interface_bundle = (
76                usb_descriptors.get_descriptor_bundle(
77                        descriptors, ncm_communication_interface))
78
79        header_descriptors = usb_descriptors.filter_descriptors(
80                usb_descriptors.HeaderFunctionalDescriptor,
81                ncm_communication_interface_bundle)
82        union_descriptors = usb_descriptors.filter_descriptors(
83                usb_descriptors.UnionFunctionalDescriptor,
84                ncm_communication_interface_bundle)
85        mbim_descriptors = usb_descriptors.filter_descriptors(
86                usb_descriptors.MBIMFunctionalDescriptor,
87                ncm_communication_interface_bundle)
88        mbim_extended_descriptors = usb_descriptors.filter_descriptors(
89                usb_descriptors.MBIMExtendedFunctionalDescriptor,
90                ncm_communication_interface_bundle)
91        if not(header_descriptors and union_descriptors and mbim_descriptors):
92            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
93                                      'mbim1.0:6.3#2')
94
95        # Test step 4
96        # Check header funcional descriptor.
97        if usb_descriptors.has_distinct_descriptors(header_descriptors):
98            mbim_errors.log_and_raise(
99                    mbim_errors.MBIMComplianceGenericAssertionError,
100                    'Expected 1 unique header functional descriptor.')
101        header_descriptor = header_descriptors[0]
102        if not(header_descriptor.bDescriptorType == 0x24 and
103               header_descriptor.bDescriptorSubtype == 0x00 and
104               header_descriptor.bLength == 5 and
105               header_descriptor.bcdCDC >= 0x0120):
106            mbim_errors.log_and_raise(
107                    mbim_errors.MBIMComplianceGenericAssertionError,
108                    'Header functional descriptor: wrong value(s)')
109
110        # Test step 5
111        # Check union functional descriptor.
112        if usb_descriptors.has_distinct_descriptors(union_descriptors):
113            mbim_errors.log_and_raise(
114                    mbim_errors.MBIMComplianceGenericAssertionError,
115                    'Expected 1 unique union functional descriptor.')
116
117        union_descriptor = union_descriptors[0]
118        if union_descriptor.index < header_descriptor.index:
119            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
120                                      'mbim1.0:6.3#3')
121        # Get no data data interface.
122        no_data_data_interfaces = self.filter_interface_descriptors(
123                interfaces, self.NCM_MBIM_DATA_INTERFACE_NO_DATA)
124
125        if len(no_data_data_interfaces) != 1:
126            mbim_errors.log_and_raise(
127                    mbim_errors.MBIMComplianceAssertionError,
128                    'mbim1.0:3.2.2.4#2')
129
130        no_data_data_interface = no_data_data_interfaces[0]
131        no_data_data_interface_bundle = usb_descriptors.get_descriptor_bundle(
132                descriptors, no_data_data_interface)
133        endpoint_descriptors = (
134                usb_descriptors.filter_descriptors(
135                        usb_descriptors.EndpointDescriptor,
136                        no_data_data_interface_bundle))
137
138        if endpoint_descriptors:
139            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
140                                      'mbim1.0:3.2.2.4#4')
141
142        # Get NCM data interface.
143        ncm_data_interfaces = (
144                self.filter_interface_descriptors(
145                        interfaces,
146                        self.NCM_MBIM_DATA_INTERFACE_NCM))
147
148        if len(ncm_data_interfaces) != 1:
149            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
150                                      'mbim1.0:3.2.2.4#2')
151        ncm_data_interface = ncm_data_interfaces[0]
152        if ncm_data_interface.bNumEndpoints != 2:
153            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
154                                      'mbim1.0:3.2.2.4#4')
155        ncm_data_interface_bundle = (
156                usb_descriptors.get_descriptor_bundle(descriptors,
157                                                      ncm_data_interface))
158        endpoint_descriptors = (
159                usb_descriptors.filter_descriptors(
160                        usb_descriptors.EndpointDescriptor,
161                        ncm_data_interface_bundle))
162        # Check endpoint descriptors in |ncm_data_interface_bundle|
163        # There should be one bulk OUT and one bulk IN.
164        if not self.has_bulk_in_and_bulk_out(endpoint_descriptors):
165            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
166                                      'mbim1.0:3.2.2.4#4')
167
168        # Get MBIM data interface.
169        mbim_data_interfaces = self.filter_interface_descriptors(
170                interfaces, self.NCM_MBIM_DATA_INTERFACE_MBIM)
171
172        if len(mbim_data_interfaces) != 1:
173           mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
174                                     'mbim1.0:3.2.2.4#3')
175        mbim_data_interface = mbim_data_interfaces[0]
176        if mbim_data_interface.bNumEndpoints != 2:
177            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
178                                      'mbim1.0:3.2.2.4#4')
179
180        mbim_data_interface_bundle = (
181                usb_descriptors.get_descriptor_bundle(descriptors,
182                                                      mbim_data_interface))
183        endpoint_descriptors = (
184                usb_descriptors.filter_descriptors(
185                        usb_descriptors.EndpointDescriptor,
186                        mbim_data_interface_bundle))
187        # Check endpoint descriptors in |mbim_data_interface_bundle|
188        # alternate setting 2. There should be one bulk OUT and one bulk IN.
189        if not self.has_bulk_in_and_bulk_out(endpoint_descriptors):
190            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
191                                      'mbim1.0:3.2.2.4#4')
192
193        if not(no_data_data_interface.bInterfaceNumber ==
194               ncm_data_interface.bInterfaceNumber ==
195               mbim_data_interface.bInterfaceNumber):
196            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
197                                      'mbim1.0:3.2.2.4#1')
198
199        if not(union_descriptor.bLength == 5 and
200               union_descriptor.bControlInterface == (
201                       ncm_communication_interface.bInterfaceNumber) and
202               union_descriptors.bSubordinateInterface0 == (
203                       no_data_data_interface.bInterfaceNumber)):
204            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
205                                      'mbim1.0:6.3#4')
206        # TODO(mcchou): Continue the remaining test steps.
207
208        # Update |test_context| with NCM/MBIM function settings.
209        if self.test_context.device_type == test_context.DEVICE_TYPE_MBIM:
210            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceFrameworkError,
211                                      'A device can only be either a MBIM'
212                                      'device ro a NCM/MBIM device.')
213        self.test_context.device_type = test_context.DEVICE_TYPE_NCM_MBIM
214        self.test_context.ncm_communication_interface = (
215                ncm_communication_interface)
216        self.test_context.mbim_communication_interface = (
217                mbim_communication_interface)
218        self.test_context.no_data_data_interface = no_data_data_interface
219        self.test_context.ncm_data_interface = ncm_data_interface
220        self.test_context.mbim_data_interface = mbim_data_interface
221    # End of run_internal()
222