def _setup_mock_subprocess(self): """ Setup long-term expectations on the mocked out subprocess. These expectations are only met when |self._channel.close| is called in |tearDown|. """ self._subprocess_mox = mox.Mox() mock_process = self._subprocess_mox.CreateMock(multiprocessing.Process) mock_process(target=mox.IgnoreArg(), args=mox.IgnoreArg()).AndReturn(mock_process) mock_process.start() # Each API call into MBIMChannel results in an aliveness ping to the # subprocess. # Finally, when |self._channel| is destructed, it will attempt to # terminate the |mock_process|, with increasingly drastic actions. mock_process.is_alive().MultipleTimes().AndReturn(True) mock_process.join(mox.IgnoreArg()) mock_process.is_alive().AndReturn(True) mock_process.terminate() self._subprocess_mox.ReplayAll() self._channel = mbim_channel.MBIMChannel( self._device, self._interface_number, self._interrupt_endpoint_address, self._in_buffer_size, mock_process)
def run_internal(self): """ Run the MBIM_CID_DEVICE_CAPS Sequence. """ # Step 1 # Send MBIM_COMMAND_MSG. device_context = self.device_context descriptor_cache = device_context.descriptor_cache command_message = mbim_command_message.MBIMDeviceCapsQuery() packets = mbim_message_request.generate_request_packets( command_message, device_context.max_control_transfer_size) channel = mbim_channel.MBIMChannel( device_context._device, descriptor_cache.mbim_communication_interface.bInterfaceNumber, descriptor_cache.interrupt_endpoint.bEndpointAddress, device_context.max_control_transfer_size) response_packets = channel.bidirectional_transaction(*packets) channel.close() # Step 2 response_message = mbim_message_response.parse_response_packets( response_packets) # Step 3 is_message_valid = isinstance(response_message, mbim_command_message.MBIMDeviceCapsInfo) if ((not is_message_valid) or (response_message.message_type != mbim_constants.MBIM_COMMAND_DONE) or (response_message.status_codes != mbim_constants.MBIM_STATUS_SUCCESS)): mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.4.3') return command_message, response_message
def run_internal(self): """ Run the MBIM Close Sequence. """ # Step 1 # Send MBIM_CLOSE_MSG to the device. close_message = mbim_message_request.MBIMClose() device_context = self.device_context descriptor_cache = device_context.descriptor_cache packets = mbim_message_request.generate_request_packets( close_message, device_context.max_control_transfer_size) channel = mbim_channel.MBIMChannel( device_context._device, descriptor_cache.mbim_communication_interface.bInterfaceNumber, descriptor_cache.interrupt_endpoint.bEndpointAddress, device_context.max_control_transfer_size) # Step 2 response_packets = channel.bidirectional_transaction(*packets) channel.close() response_message = mbim_message_response.parse_response_packets( response_packets) # Step 3 if response_message.transaction_id != close_message.transaction_id: mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.4.2#1') if response_message.status_codes != mbim_constants.MBIM_STATUS_SUCCESS: mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.4.2#2') return close_message, response_message
def run_internal(self): """ Run CM_05 test. """ # Precondition mbim_open_generic_sequence.MBIMOpenGenericSequence( self.test_context).run() caps_command_message = mbim_control.MBIMCommandMessage( device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes, cid=mbim_constants.MBIM_CID_DEVICE_CAPS, command_type=mbim_constants.COMMAND_TYPE_QUERY, information_buffer_length=0) caps_packets = caps_command_message.generate_packets() services_command_message = mbim_control.MBIMCommandMessage( device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes, cid=mbim_constants.MBIM_CID_DEVICE_SERVICES, command_type=mbim_constants.COMMAND_TYPE_QUERY, information_buffer_length=0) services_packets = services_command_message.generate_packets() self.caps_transaction_id = caps_command_message.transaction_id self.services_transaction_id = services_command_message.transaction_id self.channel = mbim_channel.MBIMChannel( { 'idVendor': self.test_context.id_vendor, 'idProduct': self.test_context.id_product }, self.test_context.mbim_communication_interface.bInterfaceNumber, self.test_context.interrupt_endpoint.bEndpointAddress, self.test_context.mbim_functional.wMaxControlMessage) # Step 1 self.channel.unidirectional_transaction(*caps_packets) # Step 2 self.channel.unidirectional_transaction(*services_packets) utils.poll_for_condition( self._get_response_packets, timeout=5, exception=mbim_errors.MBIMComplianceChannelError( 'Failed to retrieve the response packets to specific ' 'control messages.')) self.channel.close() caps_response_message = mbim_control.parse_response_packets( self.caps_response_packet) services_response_message = mbim_control.parse_response_packets( self.services_response_packet) # Step 3 if not ((caps_response_message.transaction_id == caps_command_message.transaction_id) and (caps_response_message.device_service_id == caps_command_message.device_service_id) and caps_response_message.cid == caps_command_message.cid and (services_command_message.transaction_id == services_response_message.transaction_id) and (services_command_message.device_service_id == services_response_message.device_service_id) and services_command_message.cid == services_response_message.cid): mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:8.1.2#2')
def run_internal(self): """ Run CM_13 test. """ # Precondition mbim_open_generic_sequence.MBIMOpenGenericSequence( self.test_context).run() connect_sequence.ConnectSequence(self.test_context).run() mbim_close_sequence.MBIMCloseSequence(self.test_context).run() mbim_open_generic_sequence.MBIMOpenGenericSequence( self.test_context).run() # Step 1 connect_info_structure = mbim_data.MBIMConnectInfoStructure( session_id=0, activation_state=0, voice_call_state=0, ip_type=0, context_type=mbim_constants.MBIM_CONTEXT_TYPE_NONE.bytes, nw_error=0) command_message = mbim_control.MBIMCommandMessage( message_length=84, total_fragments=1, current_fragment=0, device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes, cid=mbim_constants.MBIM_CID_CONNECT, command_type=mbim_constants.COMMAND_TYPE_QUERY, information_buffer_length=36, information_buffer=connect_info_structure.pack()) packets = command_message.generate_packets() channel = mbim_channel.MBIMChannel( {'idVendor': self.test_context.id_vendor, 'idProduct': self.test_context.id_product}, self.test_context.mbim_communication_interface.bInterfaceNumber, self.test_context.interrupt_endpoint.bEndpointAddress, self.test_context.mbim_functional.wMaxControlMessage) response_packets = channel.bidirectional_transaction(*packets) channel.close() # Step 2 response_message = mbim_control.parse_response_packets(response_packets) # Step 3 if (response_message.status_codes != mbim_constants.MBIM_STATUS_CONTEXT_NOT_ACTIVATED): mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.3.2#3')
def run_internal(self): """ Run CM_08 test. """ # Precondition descriptors = get_descriptors_sequence.GetDescriptorsSequence( self.device_context).run() self.device_context.update_descriptor_cache(descriptors) mbim_open_generic_sequence.MBIMOpenGenericSequence( self.device_context).run() # Step 1 device_context = self.device_context descriptor_cache = device_context.descriptor_cache command_message = mbim_message_request.MBIMCommand( device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes, cid=mbim_constants.MBIM_CID_RADIO_STATE, command_type=mbim_constants.COMMAND_TYPE_SET, information_buffer_length=4, payload_buffer=array.array('B', struct.pack('I', 2))) packets = mbim_message_request.generate_request_packets( command_message, device_context.max_control_transfer_size) channel = mbim_channel.MBIMChannel( device_context._device, descriptor_cache.mbim_communication_interface.bInterfaceNumber, descriptor_cache.interrupt_endpoint.bEndpointAddress, device_context.max_control_transfer_size) response_packets = channel.bidirectional_transaction(*packets) channel.close() # Step 2 response_message = mbim_message_response.parse_response_packets( response_packets) # Step 3 if ((response_message.message_type != mbim_constants.MBIM_COMMAND_DONE) or (response_message.status_codes == mbim_constants.MBIM_STATUS_SUCCESS) or response_message.information_buffer_length != 0): mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.4.5#3')
def run_internal(self): """ Run CM_08 test. """ # Precondition mbim_open_generic_sequence.MBIMOpenGenericSequence( self.test_context).run() # Step 1 command_message = mbim_control.MBIMCommandMessage( message_length=52, total_fragments=1, current_fragment=0, device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes, cid=mbim_constants.MBIM_CID_RADIO_STATE, command_type=mbim_constants.COMMAND_TYPE_SET, information_buffer_length=4, information_buffer=array.array('B', struct.pack('I', 2))) packets = command_message.generate_packets() channel = mbim_channel.MBIMChannel( { 'idVendor': self.test_context.id_vendor, 'idProduct': self.test_context.id_product }, self.test_context.mbim_communication_interface.bInterfaceNumber, self.test_context.interrupt_endpoint.bEndpointAddress, self.test_context.mbim_functional.wMaxControlMessage) response_packets = channel.bidirectional_transaction(*packets) channel.close() # Step 2 response_message = mbim_control.parse_response_packets( response_packets) # Step 3 if ((response_message.message_type != mbim_constants.MBIM_COMMAND_DONE) or (response_message.status_codes == mbim_constants.MBIM_STATUS_SUCCESS) or response_message.information_buffer_length != 0): mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.4.5#3')
def run_internal(self): """ Run CM_07 test. """ # Precondition descriptors = get_descriptors_sequence.GetDescriptorsSequence( self.device_context).run() self.device_context.update_descriptor_cache(descriptors) mbim_open_generic_sequence.MBIMOpenGenericSequence( self.device_context).run() # Step 1 # 255 is an unsupported CID. device_context = self.device_context descriptor_cache = device_context.descriptor_cache command_message = mbim_message_request.MBIMCommand( device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes, cid=255, command_type=mbim_constants.COMMAND_TYPE_QUERY, information_buffer_length=0) packets = mbim_message_request.generate_request_packets( command_message, device_context.max_control_transfer_size) channel = mbim_channel.MBIMChannel( device_context._device, descriptor_cache.mbim_communication_interface.bInterfaceNumber, descriptor_cache.interrupt_endpoint.bEndpointAddress, device_context.max_control_transfer_size) response_packets = channel.bidirectional_transaction(*packets) channel.close() # Step 2 response_message = mbim_message_response.parse_response_packets( response_packets) # Step 3 if (response_message.message_type != mbim_constants.MBIM_COMMAND_DONE or (response_message.status_codes != mbim_constants.MBIM_STATUS_NO_DEVICE_SUPPORT)): mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.4.5#2')
def run_internal(self): """ Run CM_07 test. """ # Precondition mbim_open_generic_sequence.MBIMOpenGenericSequence( self.test_context).run() # Step 1 # 255 is an unsupported CID. command_message = mbim_control.MBIMCommandMessage( message_length=48, total_fragments=1, current_fragment=0, device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes, cid=255, command_type=mbim_constants.COMMAND_TYPE_QUERY, information_buffer_length=0) packets = command_message.generate_packets() channel = mbim_channel.MBIMChannel( { 'idVendor': self.test_context.id_vendor, 'idProduct': self.test_context.id_product }, self.test_context.mbim_communication_interface.bInterfaceNumber, self.test_context.interrupt_endpoint.bEndpointAddress, self.test_context.mbim_functional.wMaxControlMessage) response_packets = channel.bidirectional_transaction(*packets) channel.close() # Step 2 response_message = mbim_control.parse_response_packets( response_packets) # Step 3 if (response_message.message_type != mbim_constants.MBIM_COMMAND_DONE or (response_message.status_codes != mbim_constants.MBIM_STATUS_NO_DEVICE_SUPPORT)): mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.4.5#2')
def run_internal(self, introduce_error_in_access_offset=False, introduce_error_in_packets_order=None, raise_exception_on_failure=True): """ Run the Connect Sequence. Once the command message is sent, there should be at least one notification received apart from the command done message. @param introduce_error_in_access_offset: Whether to introduce an error in the access_string offset or not. @param introduce_error_in_packets_order: Whether to introduce an error in the order of packets sent or not. It's a user provided list of packet sequence numbers to reorder, repeat or remove packets generated for connect before sending it to the device. @param raise_exception_on_failure: Whether to raise an exception or not. @returns tuple of (command_message, response_message, notifications): command_message: The command message sent to device. |command_message| is a MBIMCommandMessage object. response_message: The response to the |command_message|. |response_message| is a MBIMCommandDoneMessage object. notifications: The list of notifications message sent from the modem to the host. |notifications| is a list of |MBIMIndicateStatusMessage| objects. """ # Step 1 # Send MBIM_COMMAND_MSG. context_type = mbim_constants.MBIM_CONTEXT_TYPE_INTERNET.bytes data_buffer = array.array('B', 'loopback'.encode('utf-16le')) information_buffer_length = ( mbim_command_message.MBIMSetConnect.get_struct_len()) information_buffer_length += len(data_buffer) device_context = self.device_context descriptor_cache = device_context.descriptor_cache if introduce_error_in_access_offset: access_string_offset = 0 else: access_string_offset = 60 command_message = (mbim_command_message.MBIMSetConnect( session_id=0, activation_command=1, access_string_offset=access_string_offset, access_string_size=16, user_name_offset=0, user_name_size=0, password_offset=0, password_size=0, compression=0, auth_protocol=0, ip_type=1, context_type=context_type, information_buffer_length=information_buffer_length, payload_buffer=data_buffer)) packets = mbim_message_request.generate_request_packets( command_message, device_context.max_control_transfer_size) channel = mbim_channel.MBIMChannel( device_context._device, descriptor_cache.mbim_communication_interface.bInterfaceNumber, descriptor_cache.interrupt_endpoint.bEndpointAddress, device_context.max_control_transfer_size) if introduce_error_in_packets_order is not None: packets = [packets[i] for i in introduce_error_in_packets_order] response_packets = channel.bidirectional_transaction(*packets) notifications_packets = channel.get_outstanding_packets() channel.close() # Step 2 response_message = mbim_message_response.parse_response_packets( response_packets) notifications = [] for notification_packets in notifications_packets: notifications.append( mbim_message_response.parse_response_packets( notification_packets)) # Step 3 if (response_message.message_type != mbim_constants.MBIM_COMMAND_DONE or response_message.status_codes != mbim_constants.MBIM_STATUS_SUCCESS): if raise_exception_on_failure: mbim_errors.log_and_raise( mbim_errors.MBIMComplianceSequenceError, 'Connect sequence failed.') return command_message, response_message, notifications
def run_internal(self, max_control_transfer_size=None, ntb_format=mbim_constants.NTB_FORMAT_32): """ Run the MBIM Open Generic Sequence. @param max_control_transfer_size: Sets the max_control_transfer parameter in the open message sent to the device and the size of control buffers sent to the device. @param ntb_format: Sets the NTB type to 16 bit vs 32 bit. This will only be set on devices which support both 32 bit NTB and 16 bit NTB. @returns tuple of (command_message, response_message): command_message: The command message sent to device. |command_message| is a MBIMCommandMessage object. response_message: The response to the |command_message|. |response_message| is a MBIMCommandDoneMessage object. """ # Step 1 and 2 device_context = self.device_context device_type = device_context.device_type mbim_communication_interface = ( device_context.descriptor_cache.mbim_communication_interface) ncm_communication_interface = ( device_context.descriptor_cache.ncm_communication_interface) no_data_data_interface = ( device_context.descriptor_cache.no_data_data_interface) ncm_data_interface = ( device_context.descriptor_cache.ncm_data_interface) mbim_data_interface = ( device_context.descriptor_cache.mbim_data_interface) mbim_functional_descriptor = ( device_context.descriptor_cache.mbim_functional) interrupt_endpoint = ( device_context.descriptor_cache.interrupt_endpoint) descriptor_cache = device_context.descriptor_cache communication_interface_number = ( mbim_communication_interface.bInterfaceNumber) data_interface_number = mbim_data_interface.bInterfaceNumber # Step 3 # Set alternate setting to be 0 for MBIM only data interface and # NCM/MBIM data interface. self.detach_kernel_driver_if_active(data_interface_number) self.set_alternate_setting(data_interface_number, 0) # Step 4 # Set alternate setting to be 1 for MBIM communication interface of # NCM/MBIM function. if device_type == mbim_device_context.DEVICE_TYPE_NCM_MBIM: self.set_alternate_setting(communication_interface_number, 1) # Step 5 # Send a RESET_FUNCTION(0x05) request to reset communication interface. self.reset_function(communication_interface_number) # Step 6 # Send GetNtbParameters() request to communication interface. ntb_parameters = self.get_ntb_parameters( mbim_communication_interface.bInterfaceNumber) # Step 7 # Send SetNtbFormat() request to communication interface. # Bit 1 of |bmNtbForatsSupported| indicates whether the device # supports 32-bit NTBs. if (ntb_parameters.bmNtbFormatsSupported >> 1) & 1: self.set_ntb_format(communication_interface_number, ntb_format) # Step 8 # Send SetNtbInputSize() request to communication interface. self.set_ntb_input_size(communication_interface_number, ntb_parameters.dwNtbInMaxSize) # Step 9 # Send SetMaxDatagramSize() request to communication interface. # Bit 3 determines whether the device can process SetMaxDatagramSize() # and GetMaxDatagramSize() requests. if (mbim_functional_descriptor.bmNetworkCapabilities >> 3) & 1: self.set_max_datagram_size(communication_interface_number) # Step 10 if device_type == mbim_device_context.DEVICE_TYPE_MBIM: alternate_setting = 1 else: alternate_setting = 2 self.set_alternate_setting(data_interface_number, alternate_setting) # Step 11 and 12 # Send MBIM_OPEN_MSG request and receive the response. interrupt_endpoint_address = interrupt_endpoint.bEndpointAddress # If |max_control_transfer_size| is not explicitly set by the test, # we'll revert to using the |wMaxControlMessage| advertized by the # device in the MBIM functional descriptor. if not max_control_transfer_size: max_control_transfer_size = ( mbim_functional_descriptor.wMaxControlMessage) open_message = mbim_message_request.MBIMOpen( max_control_transfer=max_control_transfer_size) packets = mbim_message_request.generate_request_packets( open_message, max_control_transfer_size) channel = mbim_channel.MBIMChannel(device_context._device, communication_interface_number, interrupt_endpoint_address, max_control_transfer_size) response_packets = channel.bidirectional_transaction(*packets) channel.close() # Step 13 # Verify if MBIM_OPEN_MSG request succeeds. response_message = mbim_message_response.parse_response_packets( response_packets) if response_message.transaction_id != open_message.transaction_id: mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:9.4.1#1') if response_message.status_codes != mbim_constants.MBIM_STATUS_SUCCESS: mbim_errors.log_and_raise(mbim_errors.MBIMComplianceSequenceError, 'mbim1.0:9.4.1#2') # Store data/control transfer parameters in the device context so that # it can be used in any further control/data transfers. device_context.max_control_transfer_size = max_control_transfer_size device_context.current_ntb_format = self.get_ntb_format( communication_interface_number) device_context.max_in_data_transfer_size = ( ntb_parameters.dwNtbInMaxSize) device_context.max_out_data_transfer_size = ( ntb_parameters.dwNtbOutMaxSize) device_context.out_data_transfer_divisor = ( ntb_parameters.wNdpOutDivisor) device_context.out_data_transfer_payload_remainder = ( ntb_parameters.wNdpOutPayloadRemainder) device_context.out_data_transfer_ndp_alignment = ( ntb_parameters.wNdpOutAlignment) return open_message, response_message
def run_internal(self): """ Run CM_05 test. """ # Precondition descriptors = get_descriptors_sequence.GetDescriptorsSequence( self.device_context).run() self.device_context.update_descriptor_cache(descriptors) mbim_open_generic_sequence.MBIMOpenGenericSequence( self.device_context).run() device_context = self.device_context descriptor_cache = device_context.descriptor_cache self.channel = mbim_channel.MBIMChannel( device_context._device, descriptor_cache.mbim_communication_interface.bInterfaceNumber, descriptor_cache.interrupt_endpoint.bEndpointAddress, device_context.max_control_transfer_size) # Step 1 caps_command_message = mbim_command_message.MBIMDeviceCapsQuery() caps_packets = mbim_message_request.generate_request_packets( caps_command_message, device_context.max_control_transfer_size) self.caps_transaction_id = caps_command_message.transaction_id self.channel.unidirectional_transaction(*caps_packets) # Step 2 services_command_message = ( mbim_command_message.MBIMDeviceServicesQuery()) services_packets = mbim_message_request.generate_request_packets( services_command_message, device_context.max_control_transfer_size) self.services_transaction_id = services_command_message.transaction_id self.channel.unidirectional_transaction(*services_packets) # Step 3 utils.poll_for_condition( self._get_response_packets, timeout=5, exception=mbim_errors.MBIMComplianceChannelError( 'Failed to retrieve the response packets to specific ' 'control messages.')) self.channel.close() caps_response_message = self.caps_response services_response_message = self.services_response is_caps_message_valid = isinstance( caps_response_message, mbim_command_message.MBIMDeviceCapsInfo) is_services_message_valid = isinstance( services_response_message, mbim_command_message.MBIMDeviceServicesInfo) if not ((is_caps_message_valid and is_services_message_valid) and (caps_response_message.transaction_id == caps_command_message.transaction_id) and (caps_response_message.device_service_id == caps_command_message.device_service_id) and caps_response_message.cid == caps_command_message.cid and (services_command_message.transaction_id == services_response_message.transaction_id) and (services_command_message.device_service_id == services_response_message.device_service_id) and services_command_message.cid == services_response_message.cid): mbim_errors.log_and_raise(mbim_errors.MBIMComplianceAssertionError, 'mbim1.0:8.1.2#2')