1# Copyright 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 5import common 6from autotest_lib.client.cros.cellular.mbim_compliance.sequences \ 7 import get_descriptors_sequence 8from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors 9from autotest_lib.client.cros.cellular.mbim_compliance \ 10 import mbim_test_base 11from autotest_lib.client.cros.cellular.mbim_compliance import usb_descriptors 12 13 14class cellular_MbimComplianceDES02(mbim_test_base.MbimTestBase): 15 """ 16 DES_02 Descriptors Validation for MBIM Only Functions 17 18 This test validates descriptors for MBIM only functions. 19 20 Reference: 21 [1] Universal Serial Bus Communication Class MBIM Compliance Testing: 26 22 http://www.usb.org/developers/docs/devclass_docs/MBIM-Compliance-1.0.pdf 23 24 """ 25 version = 1 26 27 def run_internal(self): 28 """ Run the DES_02 test. """ 29 # Precondition. 30 descriptors = get_descriptors_sequence.GetDescriptorsSequence( 31 self.device_context).run() 32 33 # Test step 1 34 # Get MBIM communication interface. 35 interfaces = usb_descriptors.filter_descriptors( 36 usb_descriptors.InterfaceDescriptor, descriptors) 37 38 mbim_communication_interfaces = ( 39 usb_descriptors.filter_interface_descriptors( 40 interfaces, 41 usb_descriptors.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 = usb_descriptors.filter_interface_descriptors( 106 interfaces, usb_descriptors.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 = usb_descriptors.filter_interface_descriptors( 128 interfaces, usb_descriptors.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 usb_descriptors.has_bulk_in_and_bulk_out( 153 data_endpoint_descriptors): 154 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 155 'mbim1.0:6.6#3') 156 157 # MBIM cdc data interface should have both no data data interface and 158 # MBIM data interface. Therefore two interface numbers should be 159 # the same. 160 if (no_data_data_interface.bInterfaceNumber != 161 mbim_data_interface.bInterfaceNumber): 162 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 163 'mbim1.0:6.6#1') 164 165 # Check the fields of union functional descriptor 166 if not(union_descriptor.bLength == 5 and 167 (union_descriptor.bControlInterface == 168 mbim_communication_interface.bInterfaceNumber) and 169 (union_descriptor.bSubordinateInterface0 == 170 mbim_data_interface.bInterfaceNumber)): 171 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 172 'mbim1.0:6.3#4') 173 174 # Test step 5 175 # Get MBIM functional descriptor. 176 if usb_descriptors.has_distinct_descriptors(mbim_descriptors): 177 mbim_errors.log_and_raise( 178 mbim_errors.MBIMComplianceGenericAssertionError, 179 'Expected 1 unique MBIM functional descriptor.') 180 mbim_descriptor = mbim_descriptors[0] 181 182 if mbim_descriptor.index < header_descriptor.index: 183 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 184 'mbim1.0:6.3#3') 185 186 if mbim_descriptor.bLength != 12: 187 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 188 'mbim1.0:6.4#5') 189 190 if mbim_descriptor.bcdMBIMVersion != 0x0100: 191 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 192 'mbim1.0:6.4#6') 193 194 if mbim_descriptor.wMaxControlMessage < 64: 195 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 196 'mbim1.0:6.4#1') 197 198 if mbim_descriptor.bNumberFilters < 16: 199 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 200 'mbim1.0:6.4#2') 201 202 if mbim_descriptor.bMaxFilterSize > 192: 203 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 204 'mbim1.0:6.4#3') 205 206 # TODO(mcchou): Most of vendors set wMaxSegmentSize to be less than 207 # 1500, so this assertion is skipped for now. 208 # 209 #if not mbim_descriptor.wMaxSegmentSize >= 2048: 210 # mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 211 # 'mbim1.0:6.4#4') 212 213 # Use a byte as the mask to check if D0, D1, D2, D4, D6 and D7 are 214 # zeros. 215 if (mbim_descriptor.bmNetworkCapabilities & 0b11010111) > 0: 216 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 217 'mbim1.0:6.4#7') 218 219 # Test step 6 220 # Get MBIM extended functional descriptor, which is optional. 221 if len(mbim_extended_descriptors) >= 1: 222 if usb_descriptors.has_distinct_descriptors( 223 mbim_extended_descriptors): 224 mbim_errors.log_and_raise( 225 mbim_errors.MBIMComplianceGenerisAssertionError, 226 'Expected 1 unique MBIM extended functional ' 227 'descriptor.') 228 mbim_extended_descriptor = mbim_extended_descriptors[0] 229 230 if mbim_extended_descriptor.index < mbim_descriptor.index: 231 mbim_errors.log_and_raise( 232 mbim_errors.MBIMComplianceAssertionError, 233 'mbim1.0:6.5#1') 234 235 if mbim_extended_descriptor.bLength != 8: 236 mbim_errors.log_and_raise( 237 mbim_errors.MBIMComplianceAssertionError, 238 'mbim1.0:6.5#2') 239 240 if mbim_extended_descriptor.bcdMBIMExtendedVersion != 0x0100: 241 mbim_errors.log_and_raise( 242 mbim_errors.MBIMComplianceAssertionError, 243 'mbim1.0:6.5#3') 244 245 if mbim_extended_descriptor.bMaxOutstandingCommandMessages == 0: 246 mbim_errors.log_and_raise( 247 mbim_errors.MBIMComplianceAssertionError, 248 'mbim1.0:6.5#4') 249 250 # Test step 7 251 # Get the first endpoint for the communication interface. 252 interrupt_endpoint_descriptors = usb_descriptors.filter_descriptors( 253 usb_descriptors.EndpointDescriptor, 254 mbim_communication_interface_bundle) 255 256 if len(interrupt_endpoint_descriptors) != 1: 257 mbim_errors.log_and_raise( 258 mbim_errors.MBIMComplianceGenericAssertionError, 259 'Expected 1 endpoint, got %d.' % ( 260 len(interrupt_endpoint_descriptors))) 261 interrupt_endpoint_descriptor = interrupt_endpoint_descriptors[0] 262 if not (interrupt_endpoint_descriptor.bDescriptorType == 0x05 and 263 interrupt_endpoint_descriptor.bLength == 7 and 264 interrupt_endpoint_descriptor.bEndpointAddress >= 0x80 and 265 interrupt_endpoint_descriptor.bmAttributes == 0x03): 266 mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 267 'mbim1.0:6.3#5') 268 269 appear_before_functional_descriptors = False 270 if mbim_extended_descriptors: 271 if (mbim_extended_descriptor.index > 272 interrupt_endpoint_descriptor.index): 273 appear_before_functional_descriptors = True 274 else: 275 if (mbim_descriptor.index > interrupt_endpoint_descriptor.index or 276 union_descriptor.index > interrupt_endpoint_descriptor.index): 277 appear_before_functional_descriptors = True 278 if appear_before_functional_descriptors: 279 mbim_errors.log_and_raise( 280 mbim_errors.MBIMComplianceGenericAssertionError, 281 'All functional descriptors must appear before endpoint' 282 'descriptors.') 283 284 # Test step 8 285 # Get interface association descriptor. 286 interface_association_descriptors = ( 287 usb_descriptors.filter_descriptors( 288 usb_descriptors.InterfaceAssociationDescriptor, 289 descriptors)) 290 291 if usb_descriptors.has_distinct_descriptors( 292 interface_association_descriptors): 293 mbim_errors.log_and_raise( 294 mbim_errors.MBIMComplianceGenericAssertionError, 295 'Expected 1 interface association descriptor, got %d.' % ( 296 len(interface_association_descriptors))) 297 298 for association_descriptor in interface_association_descriptors: 299 # Check interface association descriptor if one of the following 300 # condition is met: 301 # 1. bFirstInterface <= bControlInterface < (bFirstInterface + 302 # bInterfaceCount) 303 # 2. bFirstInterface <= bSubordinateInterface0 < ( 304 # bFirstInterface + bInterfaceCount) 305 b_first_interface = association_descriptor.bFirstInterface 306 b_interface_count = association_descriptor.bInterfaceCount 307 b_control_interface = union_descriptor.bControlInterface 308 b_subordinate_interface_0 = ( 309 union_descriptor.bSubordinateInterface0) 310 check_inteface_association_descriptor = False 311 312 if ((b_first_interface <= b_control_interface < ( 313 b_first_interface + b_interface_count)) or 314 (b_first_interface <= b_subordinate_interface_0 < ( 315 b_first_interface + b_interface_count))): 316 check_interface_association_descriptor = True 317 318 if not check_interface_association_descriptor: 319 mbim_errors.log_and_raise( 320 mbim_errors.MBIMComplianceAssertionError, 321 'mbim1.0:6.1#1') 322 323 if check_interface_association_descriptor: 324 if not((b_first_interface == b_control_interface or 325 b_first_interface == b_subordinate_interface_0) and 326 (b_interface_count == 2) and 327 (b_subordinate_interface_0 == b_control_interface + 1 or 328 b_subordinate_interface_0 == 329 b_control_interface - 1) and 330 (association_descriptor.bFunctionClass == 0x02) and 331 (association_descriptor.bFunctionSubClass == 0x0E) and 332 (association_descriptor.bFunctionProtocol == 0x00)): 333 mbim_errors.log_and_raise( 334 mbim_errors.MBIMComplianceAssertionError, 335 'mbim1.0:6.1#2') 336 337 # End of run_internal(). 338