• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_02 Descriptors Validation for MBIM Only Functions
7
8Reference:
9    [1] Universal Serial Bus Communication Class MBIM Compliance Testing: 26
10        http://www.usb.org/developers/docs/devclass_docs/MBIM-Compliance-1.0.pdf
11"""
12
13import common
14from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors
15from autotest_lib.client.cros.cellular.mbim_compliance import usb_descriptors
16from autotest_lib.client.cros.cellular.mbim_compliance.sequences \
17        import get_descriptors_sequence
18from autotest_lib.client.cros.cellular.mbim_compliance.tests import des_test
19from autotest_lib.client.cros.cellular.mbim_compliance import test_context
20
21class DES_02_Test(des_test.DesTest):
22    """ Implement the DES_2 Descriptors Validation for MBIM Only Functions. """
23
24    def run_internal(self):
25        """ Run the DES_02 test. """
26        # Precondition.
27        descriptors = get_descriptors_sequence.GetDescriptorsSequence(
28                self.test_context).run()
29        device = self.test_context.device
30        if not device:
31            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceFrameworkError,
32                                      'Device not found')
33
34        # Test step 1
35        # Get MBIM communication interface.
36        interfaces = usb_descriptors.filter_descriptors(
37                             usb_descriptors.InterfaceDescriptor, descriptors)
38
39        mbim_communication_interfaces = (
40                self.filter_interface_descriptors(
41                        interfaces, self.MBIM_ONLY_COMMUNICATION_INTERFACE))
42
43        if not mbim_communication_interfaces:
44            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
45                                      'mbim1.0:6.3#1')
46
47        if len(mbim_communication_interfaces) > 1:
48            mbim_errors.log_and_raise(
49                    mbim_errors.MBIMComplianceGenericAssertionError,
50                    'Expected 1 mbim communication interface, got %d.' % (
51                            len(mbim_communication_interfaces)))
52        mbim_communication_interface = mbim_communication_interfaces[0]
53
54        # Test step 2
55        # Get header functional descriptor, union functional descriptor,
56        # MBIM functional descriptor and MBIM extended functional
57        # descriptor.
58        mbim_communication_interface_bundle = (
59                usb_descriptors.get_descriptor_bundle(
60                        descriptors, mbim_communication_interface))
61
62        header_descriptors = usb_descriptors.filter_descriptors(
63                usb_descriptors.HeaderFunctionalDescriptor,
64                mbim_communication_interface_bundle)
65        union_descriptors = usb_descriptors.filter_descriptors(
66                usb_descriptors.UnionFunctionalDescriptor,
67                mbim_communication_interface_bundle)
68        mbim_descriptors = usb_descriptors.filter_descriptors(
69                usb_descriptors.MBIMFunctionalDescriptor,
70                mbim_communication_interface_bundle)
71        mbim_extended_descriptors = usb_descriptors.filter_descriptors(
72                usb_descriptors.MBIMExtendedFunctionalDescriptor,
73                mbim_communication_interface_bundle)
74        if not(header_descriptors and union_descriptors and mbim_descriptors):
75            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
76                                      'mbim1.0:6.3#2')
77
78        # Test step 3
79        # Check header functional descriptor.
80        if usb_descriptors.has_distinct_descriptors(header_descriptors):
81            mbim_errors.log_and_raise(
82                    mbim_errors.MBIMComplianceGenericAssertionError,
83                    'Expected 1 unique header functional descriptor.')
84        header_descriptor = header_descriptors[0]
85        if not(header_descriptor.bDescriptorType == 0x24 and
86               header_descriptor.bDescriptorSubtype == 0x00 and
87               header_descriptor.bLength == 5 and
88               header_descriptor.bcdCDC >= 0x0120):
89            mbim_errors.log_and_raise(
90                mbim_errors.MBIMComplianceGenericAssertionError,
91                    'Header functional descriptor: wrong value(s)')
92
93        # Test step 4
94        # Check union functional descriptor.
95        if usb_descriptors.has_distinct_descriptors(union_descriptors):
96            mbim_errors.log_and_raise(
97                    mbim_errors.MBIMComplianceGenerisAssertionError,
98                    'Expected 1 unique union functional descriptor.')
99        union_descriptor = union_descriptors[0]
100        if union_descriptor.index < header_descriptor.index:
101            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
102                                      'mbim1.0:6.3#3')
103
104        # Get CDC no data data interface.
105        no_data_data_interfaces = self.filter_interface_descriptors(
106                interfaces, self.MBIM_ONLY_DATA_INTERFACE_NO_DATA)
107        if not no_data_data_interfaces:
108            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
109                                      'mbim1.0:6.6#4')
110        if len(no_data_data_interfaces) > 1:
111            mbim_errors.log_and_raise(
112                    mbim_errors.MBIMComplianceGenericAssertionError,
113                    'Exactly 1 CDC data interface, got %d.' % (
114                            len(no_data_data_interfaces)))
115        no_data_data_interface = no_data_data_interfaces[0]
116        no_data_data_interface_bundle = usb_descriptors.get_descriptor_bundle(
117                descriptors, no_data_data_interface)
118        data_endpoint_descriptors = (
119                usb_descriptors.filter_descriptors(
120                        usb_descriptors.EndpointDescriptor,
121                        no_data_data_interface_bundle))
122        if data_endpoint_descriptors:
123            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
124                                      'mbim1.0:6.6#2')
125
126        # Get MBIM data interface.
127        mbim_data_interfaces = self.filter_interface_descriptors(
128                interfaces, self.MBIM_ONLY_DATA_INTERFACE_MBIM)
129        if not mbim_data_interfaces:
130            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
131                                      'mbim1.0:6.6#4')
132        if len(mbim_data_interfaces) > 1:
133            mbim_errors.log_and_raise(
134                    mbim_errors.MBIMComplianceGenericAssertionError,
135                    'Expected 1 MBIM data interface, got %d.' % (
136                            len(mbim_data_interfaces)))
137        mbim_data_interface = mbim_data_interfaces[0]
138
139        # Check if there are two endpoint descriptors.
140        if mbim_data_interface.bNumEndpoints != 2:
141            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
142                                      'mbim1.0:6.6#3.')
143
144        mbim_data_interface_bundle = usb_descriptors.get_descriptor_bundle(
145                descriptors, mbim_data_interface)
146        data_endpoint_descriptors = usb_descriptors.filter_descriptors(
147                usb_descriptors.EndpointDescriptor,
148                mbim_data_interface_bundle)
149
150        # Check the values of fields in endpoint descriptors.
151        # There should be one bulk OUT and one bulk IN.
152        if not self.has_bulk_in_and_bulk_out(data_endpoint_descriptors):
153            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
154                                      'mbim1.0:6.6#3')
155
156        # MBIM cdc data interface should have both no data data interface and
157        # MBIM data interface. Therefore two interface numbers should be
158        # the same.
159        if (no_data_data_interface.bInterfaceNumber !=
160            mbim_data_interface.bInterfaceNumber):
161            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
162                                      'mbim1.0:6.6#1')
163
164        # Check the fields of union functional descriptor
165        if not(union_descriptor.bLength == 5 and
166               (union_descriptor.bControlInterface ==
167                mbim_communication_interface.bInterfaceNumber) and
168               (union_descriptor.bSubordinateInterface0 ==
169                mbim_data_interface.bInterfaceNumber)):
170            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
171                                      'mbim1.0:6.3#4')
172
173        # Test step 5
174        # Get MBIM functional descriptor.
175        if usb_descriptors.has_distinct_descriptors(mbim_descriptors):
176            mbim_errors.log_and_raise(
177                    mbim_errors.MBIMComplianceGenericAssertionError,
178                    'Expected 1 unique MBIM functional descriptor.')
179        mbim_descriptor = mbim_descriptors[0]
180
181        if mbim_descriptor.index < header_descriptor.index:
182            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
183                                      'mbim1.0:6.3#3')
184
185        if mbim_descriptor.bLength != 12:
186            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
187                                      'mbim1.0:6.4#5')
188
189        if mbim_descriptor.bcdMBIMVersion != 0x0100:
190            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
191                                      'mbim1.0:6.4#6')
192
193        if mbim_descriptor.wMaxControlMessage < 64:
194            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
195                                      'mbim1.0:6.4#1')
196
197        if mbim_descriptor.bNumberFilters < 16:
198            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
199                                      'mbim1.0:6.4#2')
200
201        if mbim_descriptor.bMaxFilterSize > 192:
202            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
203                                      'mbim1.0:6.4#3')
204
205        # TODO(mcchou): Most of vendors set wMaxSegmentSize to be less than
206        # 1500, so this assertion is skipped for now.
207        #
208        #if not mbim_descriptor.wMaxSegmentSize >= 2048:
209        #    mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
210        #                              'mbim1.0:6.4#4')
211
212        # Use a byte as the mask to check if D0, D1, D2, D4, D6 and D7 are
213        # zeros.
214        if (mbim_descriptor.bmNetworkCapabilities & 0b11010111) > 0:
215            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
216                                      'mbim1.0:6.4#7')
217
218        # Test step 6
219        # Get MBIM extended functional descriptor, which is optional.
220        if len(mbim_extended_descriptors) >= 1:
221            if usb_descriptors.has_distinct_descriptors(
222                    mbim_extended_descriptors):
223                mbim_errors.log_and_raise(
224                        mbim_errors.MBIMComplianceGenerisAssertionError,
225                        'Expected 1 unique MBIM extended functional '
226                        'descriptor.')
227            mbim_extended_descriptor = mbim_extended_descriptors[0]
228
229            if mbim_extended_descriptor.index < mbim_descriptor.index:
230                mbim_errors.log_and_raise(
231                        mbim_errors.MBIMComplianceAssertionError,
232                        'mbim1.0:6.5#1')
233
234            if mbim_extended_descriptor.bLength != 8:
235                mbim_errors.log_and_raise(
236                        mbim_errors.MBIMComplianceAssertionError,
237                        'mbim1.0:6.5#2')
238
239            if mbim_extended_descriptor.bcdMBIMExtendedVersion != 0x0100:
240                mbim_errors.log_and_raise(
241                        mbim_errors.MBIMComplianceAssertionError,
242                        'mbim1.0:6.5#3')
243
244            if mbim_extended_descriptor.bMaxOutstandingCommandMessages == 0:
245                mbim_errors.log_and_raise(
246                        mbim_errors.MBIMComplianceAssertionError,
247                        'mbim1.0:6.5#4')
248
249        # Test step 7
250        # Get the first endpoint for the communication interface.
251        interrupt_endpoint_descriptors = usb_descriptors.filter_descriptors(
252                usb_descriptors.EndpointDescriptor,
253                mbim_communication_interface_bundle)
254
255        if len(interrupt_endpoint_descriptors) != 1:
256            mbim_errors.log_and_raise(
257                    mbim_errors.MBIMComplianceGenericAssertionError,
258                    'Expected 1 endpoint, got %d.' % (
259                            len(interrupt_endpoint_descriptors)))
260        interrupt_endpoint_descriptor = interrupt_endpoint_descriptors[0]
261        if not (interrupt_endpoint_descriptor.bDescriptorType == 0x05 and
262                interrupt_endpoint_descriptor.bLength == 7 and
263                interrupt_endpoint_descriptor.bEndpointAddress >= 0x80 and
264                interrupt_endpoint_descriptor.bmAttributes == 0x03):
265            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError,
266                                      'mbim1.0:6.3#5')
267
268        appear_before_functional_descriptors = False
269        if mbim_extended_descriptors:
270            if (mbim_extended_descriptor.index >
271                interrupt_endpoint_descriptor.index):
272                appear_before_functional_descriptors = True
273        else:
274            if (mbim_descriptor.index > interrupt_endpoint_descriptor.index or
275                union_descriptor.index > interrupt_endpoint_descriptor.index):
276                appear_before_functional_descriptors = True
277        if appear_before_functional_descriptors:
278            mbim_errors.log_and_raise(
279                    mbim_errors.MBIMComplianceGenericAssertionError,
280                    'All functional descriptors must appear before endpoint'
281                    'descriptors.')
282
283        # Test step 8
284        # Get interface association descriptor.
285        interface_association_descriptors = (
286                usb_descriptors.filter_descriptors(
287                        usb_descriptors.InterfaceAssociationDescriptor,
288                        descriptors))
289
290        if usb_descriptors.has_distinct_descriptors(
291                interface_association_descriptors):
292            mbim_errors.log_and_raise(
293                    mbim_errors.MBIMComplianceGenericAssertionError,
294                    'Expected 1 interface association descriptor, got %d.' % (
295                            len(interface_association_descriptors)))
296
297        for association_descriptor in interface_association_descriptors:
298            # Check interface association descriptor if one of the following
299            # condition is met:
300            # 1. bFirstInterface <= bControlInterface < (bFirstInterface +
301            #                                            bInterfaceCount)
302            # 2. bFirstInterface <= bSubordinateInterface0 < (
303            #            bFirstInterface + bInterfaceCount)
304            b_first_interface = association_descriptor.bFirstInterface
305            b_interface_count = association_descriptor.bInterfaceCount
306            b_control_interface = union_descriptor.bControlInterface
307            b_subordinate_interface_0 = (
308                    union_descriptor.bSubordinateInterface0)
309            check_inteface_association_descriptor = False
310
311            if ((b_first_interface <= b_control_interface < (
312                         b_first_interface + b_interface_count)) or
313                (b_first_interface <= b_subordinate_interface_0 < (
314                         b_first_interface + b_interface_count))):
315                check_interface_association_descriptor = True
316
317            if not check_interface_association_descriptor:
318                mbim_errors.log_and_raise(
319                        mbim_errors.MBIMComplianceAssertionError,
320                        'mbim1.0:6.1#1')
321
322            if check_interface_association_descriptor:
323                if not((b_first_interface == b_control_interface or
324                        b_first_interface == b_subordinate_interface_0) and
325                       (b_interface_count == 2) and
326                       (b_subordinate_interface_0 == b_control_interface + 1 or
327                        b_subordinate_interface_0 ==
328                        b_control_interface - 1) and
329                       (association_descriptor.bFunctionClass == 0x02) and
330                       (association_descriptor.bFunctionSubClass == 0x0E) and
331                       (association_descriptor.bFunctionProtocol == 0x00)):
332                    mbim_errors.log_and_raise(
333                            mbim_errors.MBIMComplianceAssertionError,
334                            'mbim1.0:6.1#2')
335
336        # Update |test_context| with mbim function settings.
337        if self.test_context.device_type == test_context.DEVICE_TYPE_NCM_MBIM:
338            mbim_errors.log_and_raise(mbim_errors.MBIMComplianceFrameworkError,
339                                      'A device can only be either a MBIM'
340                                      'device or a NCM/MBIM device.')
341        self.test_context.device_type = test_context.DEVICE_TYPE_MBIM
342        self.test_context.mbim_communication_interface = (
343                mbim_communication_interface)
344        self.test_context.no_data_data_interface = no_data_data_interface
345        self.test_context.mbim_data_interface = mbim_data_interface
346        self.test_context.mbim_functional = mbim_descriptor
347        self.test_context.interrupt_endpoint = interrupt_endpoint_descriptor
348    # End of run_internal().
349