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