| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| import traceback |
| |
| import common |
| from autotest_lib.client.common_lib import error |
| |
| |
| class MBIMComplianceError(error.TestFail): |
| """ Base class for all errors overtly raised in the suite. """ |
| pass |
| |
| |
| class MBIMComplianceFrameworkError(MBIMComplianceError): |
| """ |
| Errors raised by any of the framework code. |
| |
| These errors are raised by code that is not part of a test / sequence / |
| assertion. |
| |
| """ |
| pass |
| |
| |
| class MBIMComplianceChannelError(MBIMComplianceError): |
| """ Errors raised in the MBIM communication channel. """ |
| pass |
| |
| |
| class MBIMComplianceControlMessageError(MBIMComplianceError): |
| """ Errors raised in the MBIM control module. """ |
| pass |
| |
| |
| class MBIMComplianceDataTransferError(MBIMComplianceError): |
| """ Errors raised in the MBIM data transfer module. """ |
| pass |
| |
| |
| class MBIMComplianceNtbError(MBIMComplianceError): |
| """ Errors raised in the MBIM NTB module. """ |
| pass |
| |
| |
| class MBIMComplianceTestError(MBIMComplianceError): |
| """ Errors raised by compliance suite tests. """ |
| pass |
| |
| |
| class MBIMComplianceSequenceError(MBIMComplianceError): |
| """ Errors raised by compliance suite sequences. """ |
| pass |
| |
| |
| class MBIMComplianceAssertionError(MBIMComplianceError): |
| """ Errors raised by compliance suite assertions. """ |
| |
| MBIM_ASSERTIONS = { |
| # This key should not be used directly. |
| # Raise |MBIMComplianceGenericAssertionError| instead. |
| 'no_code': '', |
| |
| # Assertion group: 3.x.x#x |
| 'mbim1.0:3.2.1#1': 'Functions that implement both NCM 1.0 and MBIM ' |
| 'shall provide two alternate settings for the ' |
| 'Communication Interface.', |
| 'mbim1.0:3.2.1#2': 'For alternate setting 0 of the Communication ' |
| 'Interface of an NCM/MBIM function: interface, ' |
| 'functional and endpoint descriptors shall be ' |
| 'constructed according to the rules given in ' |
| '[USBNCM10].', |
| 'mbim1.0:3.2.1#3': 'For alternate setting 1 of the Communication ' |
| 'Interface of an NCM/MBIM function: interface, ' |
| 'functional and endpoint descriptors shall be ' |
| 'constructed according to the rules given in ' |
| '[MBIM 1.0] section 6.', |
| 'mbim1.0:3.2.1#4': 'When alternate setting 0 of the Communiation' |
| 'Interface of an NCM/MBIM function is selected, ' |
| 'the function shall operator according to the ' |
| 'NCM rules given in [USBNCM10].', |
| 'mbim1.0:3.2.1#5': 'When alternate setting 1 of the Communiation' |
| 'Interface of an NCM/MBIM function is selected, ' |
| 'the function shall operator according to the ' |
| 'MBIM rules given in [MBIM1.0].', |
| 'mbim1.0:3.2.2.1#1': 'If an Interface Association Descriptor is ' |
| 'used to form an NCM/MBIM function, its ' |
| 'interface class, subclass, and protocol ' |
| 'codes shall match those given in alternate ' |
| 'setting 0 of the Communication Interface. ', |
| 'mbim1.0:3.2.2.4#1': 'Functions that implement both NCM 1.0 and ' |
| 'MBIM (an "NCM/MBIM function") shall provide ' |
| 'three alternate settings for the Data ' |
| 'Interface.', |
| 'mbim1.0:3.2.2.4#2': 'For an NCM/MBIM function, the Data Interface ' |
| 'descriptors for alternate settings 0 and 1 ' |
| 'must have bInterfaceSubClass == 00h, and ' |
| 'bInterfaceProtocol == 01h.', |
| 'mbim1.0:3.2.2.4#3': 'For an NCM/MBIM function, the Data Interface ' |
| 'descriptor for alternate setting 2 must have ' |
| 'bInterfaceSubClass == 00h, and ' |
| 'bInterfaceProtocol == 02h.', |
| 'mbim1.0:3.2.2.4#4': 'For an NCM/MBIM function there must be no ' |
| 'endpoints for alternate setting 0 of the ' |
| 'Data Interface. For each of the other two ' |
| 'alternate settings (1 and 2) there must be ' |
| 'exactly two endpoints: one Bulk IN and one ' |
| 'Bulk OUT.', |
| |
| # Assertion group: 6.x#x |
| 'mbim1.0:6.1#1': 'If an Interface Association Descriptor (IAD) is ' |
| 'provided for the MBIM function, the IAD and the ' |
| 'mandatory CDC Union Functional Descriptor ' |
| 'specified for the MBIM function shall group ' |
| 'together the same interfaces.', |
| 'mbim1.0:6.1#2': 'If an Interface Association Descriptor (IAD) is ' |
| 'provided for the MBIM only function, its ' |
| 'interface class, subclass, and protocol codes ' |
| 'shall match those given in the Communication ' |
| 'Interface descriptor.', |
| 'mbim1.0:6.3#1': 'The descriptor for alternate setting 0 of the ' |
| 'Communication Interface of an MBIM only function ' |
| 'shall have bInterfaceClass == 02h, ' |
| 'bInterfaceSubClass == 0Eh, and ' |
| 'bInterfaceProtocol == 00h.', |
| 'mbim1.0:6.3#2': 'MBIM Communication Interface description shall ' |
| 'include the following functional descriptors: ' |
| 'CDC Header Functional Descriptor, CDC Union ' |
| 'Functional Descriptor, and MBIM Functional ' |
| 'Descriptor. Refer to Table 6.2 of [USBMBIM10].', |
| 'mbim1.0:6.3#3': 'CDC Header Functional Descriptor shall appear ' |
| 'before CDC Union Functional Descriptor and ' |
| 'before MBIM Functional Descriptor.', |
| 'mbim1.0:6.3#4': 'CDC Union Functional Descriptor for an MBIM ' |
| 'function shall group together the MBIM ' |
| 'Communication Interface and the MBIM Data ' |
| 'Interface.', |
| 'mbim1.0:6.3#5': 'The class-specific descriptors must be followed ' |
| 'by an Interrupt IN endpoint descriptor.', |
| 'mbim1.0:6.4#1': 'Field wMaxControlMessage of MBIM Functional ' |
| 'Descriptor must not be smaller than 64.', |
| 'mbim1.0:6.4#2': 'Field bNumberFilters of MBIM Functional ' |
| 'Descriptor must not be smaller than 16.', |
| 'mbim1.0:6.4#3': 'Field bMaxFilterSize of MBIM Functional ' |
| 'Descriptor must not exceed 192.', |
| 'mbim1.0:6.4#4': 'Field wMaxSegmentSize of MBIM Functional ' |
| 'Descriptor must not be smaller than 2048.', |
| 'mbim1.0:6.4#5': 'Field bFunctionLength of MBIM Functional ' |
| 'Descriptor must be 12 representing the size of ' |
| 'the descriptor.', |
| 'mbim1.0:6.4#6': 'Field bcdMBIMVersion of MBIM Functional ' |
| 'Descriptor must be 0x0100 in little endian ' |
| 'format.', |
| 'mbim1.0:6.4#7': 'Field bmNetworkCapabilities of MBIM Functional ' |
| 'Descriptor should have the following bits set to ' |
| 'zero: D0, D1, D2, D4, D6 and D7.', |
| 'mbim1.0:6.5#1': 'If MBIM Extended Functional Descriptor is ' |
| 'provided, it must appear after MBIM Functional ' |
| 'Descriptor.', |
| 'mbim1.0:6.5#2': 'Field bFunctionLength of MBIM Extended ' |
| 'Functional Descriptor must be 8 representing the ' |
| 'size of the descriptor.', |
| 'mbim1.0:6.5#3': 'Field bcdMBIMEFDVersion of MBIM Extended ' |
| 'Functional Descriptor must be 0x0100 in little ' |
| 'endian format.', |
| 'mbim1.0:6.5#4': 'Field bMaxOutstandingCommandMessages of MBIM ' |
| 'Extended Functional Descriptor shall be greater ' |
| 'than 0.', |
| 'mbim1.0:6.6#1': 'The Data Interface for an MBIM only function ' |
| 'shall provide two alternate settings.', |
| 'mbim1.0:6.6#2': 'The first alternate setting for the Data ' |
| 'Interface of an MBIM only function (the default ' |
| 'interface setting, alternate setting 0) shall ' |
| 'include no endpoints.', |
| 'mbim1.0:6.6#3': 'The second alternate setting for the Data ' |
| 'Interface of an MBIM only function (alternate ' |
| 'setting 1) is used for normal operation, and ' |
| 'shall include one Bulk IN endpoint and one Bulk ' |
| 'OUT endpoint.', |
| 'mbim1.0:6.6#4': 'For an MBIM only function the Data Interface ' |
| 'descriptors for alternate settings 0 and 1 must ' |
| 'have bInterfaceSubClass == 00h, and ' |
| 'bInterfaceProtocol == 02h. Refer to Table 6.4 of ' |
| '[USBMBIM10].', |
| |
| # Assertion Groups: 7.x.x#x |
| 'mbim1.0:7#1': 'To distinguish among the data streams, the last ' |
| 'character of the dwSignature in the NDP16 header ' |
| 'shall be coded with the index SessionId specified' |
| ' by the host in the MBIM_CID_CONNECT. The first ' |
| 'three symbols are encoded as ASCII characters in ' |
| 'little-endian form plus a last byte in HEX ' |
| '(binary) format: "IPS"<SessionId>.', |
| 'mbim1.0:7#3': 'To distinguish among the data streams, the last ' |
| 'character of the dwSignature in the NDP32 header ' |
| 'shall be coded with the index SessionId specified' |
| ' by the host in the MBIM_CID_CONNECT. The first ' |
| 'three symbols are encoded as ASCII characters in ' |
| 'little-endian form plus a last byte in HEX ' |
| '(binary) format: "ips"<SessionId>.', |
| |
| # Assertion Groups: 8.x.x#x |
| 'mbim1.0:8.1.2#2': 'The function must use a separate ' |
| 'GET_ENCAPSULATED_RESPONSE transfer for each ' |
| 'control message it has to send to the host.', |
| 'mbim1.0:8.1.2#3': 'The function must send a RESPONSE_AVAILABLE ' |
| 'notification for each available fragment of ' |
| 'ENCAPSULATED_RESPONSE to be read from the ' |
| 'default pipe.', |
| |
| # Assertion Groups: 9.x#x, 9.x.x and 9.x.x#x |
| 'mbim1.0:9.1#1': 'For notifications, the TransactionId must be ' |
| 'set to 0 by the function.', |
| 'mbim1.0:9.1#2': 'MessageLength in MBIM_MESSAGE_HEADER must be >=' |
| ' 0x0C.', |
| 'mbim1.0:9.2': 'Function should fragment responses based on ' |
| 'MaxControlTransfer value from MBIM_OPEN_MSG.', |
| 'mbim1.0:9.3.1#1': 'In case MBIM_OPEN_MSG message is sent to a ' |
| 'function that is already opened, the function ' |
| 'shall interpret this as that the host and the ' |
| 'function are out of synchronization. The ' |
| 'function shall then perform the actions ' |
| 'dictated by the MBIM_CLOSE_MSG before it ' |
| 'performs the actions dictated by this ' |
| 'command.The function shall not send the ' |
| 'MBIM_CLOSE_DONE when the transition to the ' |
| 'Closed state has been completed. Only the ' |
| ' MBIM_OPEN_DONE message is sent upon ' |
| 'successful completion of this message.', |
| 'mbim1.0:9.3.2#1': 'Between the host\'s sending MBIM_CLOSE_MSG ' |
| 'message and the function\'s completing the ' |
| 'request (acknowledged with MBIM_CLOSE_DONE), ' |
| 'the function shall ignore any MBIM control ' |
| 'messages it receives on the control plane or ' |
| 'the data on the bulk pipes.', |
| 'mbim1.0:9.3.2#2': 'The function shall not send any MBIM control ' |
| 'messages on the control plane or data on the ' |
| 'bulk pipes after completing ' |
| 'MBIM_CLOSE_MSG message (acknowledging it with ' |
| 'the MBIM_CLOSE_DONE message) with one ' |
| 'exception and that is MBIM_ERROR_NOT_OPENED.', |
| 'mbim1.0:9.3.2#3': 'On MBIM_CLOSE_MSG, any active context between ' |
| 'the function and the host shall be terminated ', |
| 'mbim1.0:9.3.4#2': 'An MBIM_FUNCTION_ERROR_MSG shall not make use ' |
| 'of a DataBuffer, so it cannot send any data ' |
| 'payload.', |
| 'mbim1.0:9.3.4#3': 'MBIM_ERROR_FRAGMENT_OUT_OF_SEQUENCE shall be ' |
| 'sent by the function if it detects a fragmented' |
| ' message out of sequence.', |
| 'mbim1.0:9.3.4.2#2': 'For MBIM_ERROR_FRAGMENT_OUT_OF_SEQUENCE, the' |
| ' TransactionId of the responding message must ' |
| 'match the TransactionId in the faulty ' |
| 'fragmented sequence.', |
| 'mbim1.0:9.3.4.2#3': 'In case of an out of a sequence error, the ' |
| 'function shall discard all the packets with ' |
| 'the same TransactionId as the faulty message ' |
| 'sequence.', |
| 'mbim1.0:9.3.4.2#4': 'If the function gets one more message that ' |
| 'is out of order for the same TransactionId, it ' |
| 'shall send a new error message with the same ' |
| 'TransactionId once more.', |
| 'mbim1.0:9.4.1#1': 'The function shall respond to the ' |
| 'MBIM_OPEN_MSG message with an MBIM_OPEN_DONE ' |
| 'message in which the TransactionId must match ' |
| 'the TransactionId in the MBIM_OPEN_MSG.', |
| 'mbim1.0:9.4.1#2': 'The Status field of MBIM_OPEN_DONE shall be ' |
| 'set to MBIM_STATUS_SUCCESS if the function ' |
| 'initialized successfully.', |
| 'mbim1.0:9.4.2#1': 'The function shall respond to the ' |
| 'MBIM_CLOSE_MSG message with an ' |
| 'MBIM_CLOSE_DONE message in which the ' |
| 'TransactionId must match the TransactionId in ' |
| 'the MBIM_CLOSE_MSG.', |
| 'mbim1.0:9.4.2#2': 'The Status field of MBIM_CLOSE_DONE shall ' |
| 'always be set to MBIM_STATUS_SUCCESS.', |
| 'mbim1.0:9.4.3': 'The function shall respond to ' |
| 'the MBIM_COMMAND_MSG message with an ' |
| 'MBIM_COMMAND_DONE message in which the ' |
| 'TransactionId must match the TransactionId in ' |
| 'the MBIM_COMMAND_MSG.', |
| 'mbim1.0:9.4.5#1': 'If the CID is successful, the function shall ' |
| 'set the Status field to MBIM_STATUS_SUCCESS ' |
| 'in the MBIM_COMMAND_DONE.', |
| 'mbim1.0:9.4.5#2': 'If the function does not implement the CID, ' |
| 'then the function shall fail the request with ' |
| 'MBIM_STATUS_NO_DEVICE_SUPPORT.', |
| 'mbim1.0:9.4.5#3': 'If the Status field returned to the host is ' |
| 'not equal to MBIM_STATUS_SUCCESS, the function ' |
| 'must set the Information BufferLength to 0, ' |
| 'indicating an empty InformationBuffer except ' |
| 'the following CIDs: MBIM_CID_REGISTER_STATE, ' |
| 'MBIM_CID_PACKET_SERVICE, MBIM_CID_CONNECT, ' |
| 'MBIM_CID_SERVICE_ACTIVATION.', |
| 'mbim1.0:9.5#1': 'Function should transmit fragmented message to ' |
| 'host without intermixing fragments from other ' |
| 'messages.', |
| 'mbim1.0:10.3#2': 'The function shall reject incoming messages ' |
| 'that dont follow the rules for variable-length' |
| ' encoding by setting ' |
| 'MBIM_STATUS_INVALID_PARAMETERS as the status ' |
| 'code in the MBIM_COMMAND_DONE message.', |
| 'mbim1.0:10.5.1.3#1': 'Functions that support CDMA must specify ' |
| 'MBIMCtrlCapsCdmaMobileIP or ' |
| 'MBIMCtrlCapsCdmaSimpleIP or both flags to ' |
| 'inform the host about the type of IP that the ' |
| 'function supports.', |
| |
| # NCM Assertion group: 3.x.x#x |
| 'ncm1.0:3.2.1#1': 'The first four bytes in NTH16 shall be ' |
| '0x484D434E in little-endian format ("NCMH").', |
| 'ncm1.0:3.2.1#2': 'wHeaderLength value in NTH16 shall be 0x000C.', |
| 'ncm1.0:3.2.1#3': 'wSequence in NTH16 shall be set to zero by the ' |
| 'function in the first NTB transferred after ' |
| 'every "function reset" event.', |
| 'ncm1.0:3.2.1#4': 'wSequence value in NTH16 shall be incremented ' |
| 'for every NTB subsequent transfer.', |
| 'ncm1.0:3.2.1#5': 'NTB size (IN) shall not exceed dwNtbInMaxSize.', |
| 'ncm1.0:3.2.1#6': 'wNdpIndex value in NTH16 must be a multiple of ' |
| '4, and must be >= 0x000C, in little endian.', |
| 'ncm1.0:3.2.2#1': 'The first four bytes in NTH32 shall be ' |
| '0x686D636E in little-endian format ("ncmh").', |
| 'ncm1.0:3.2.2#2': 'wHeaderLength value in NTH32 shall be 0x0010.', |
| 'ncm1.0:3.2.2#3': 'wSequence in NTH32 shall be set to zero by the ' |
| 'function in the first NTB transferred after ' |
| 'every "function reset" event.', |
| 'ncm1.0:3.2.2#4': 'wSequence value in NTH32 shall be incremented ' |
| 'for every NTB subsequent transfer.', |
| 'ncm1.0:3.2.2#5': 'NTB size (IN) shall not exceed dwNtbInMaxSize.', |
| 'ncm1.0:3.2.2#6': 'dwNdpIndex value in NTH32 must be a multiple of' |
| ' 4, and must be >= 0x0010, in little endian.', |
| 'ncm1.0:3.3.1#1': 'wLength value in the NDP16 must be a multiple ' |
| 'of 4, and must be at least 16d (0x0010).', |
| 'ncm1.0:3.3.1#2': 'wDatagramIndex[0] value in NDP16 must be >= ' |
| '0x000C (because it must point past the NTH16).', |
| 'ncm1.0:3.3.1#3': 'wDatagramLength[0] value in NDP16 must be >= ' |
| '20d if datagram payload is IPv4 and >= 40d if ' |
| 'datagram payload is IPv6.', |
| 'ncm1.0:3.3.1#4': 'wDatagramIndex[(wLength-8)/4 - 1] value in ' |
| 'NDP16 must be zero.', |
| 'ncm1.0:3.3.1#5': 'wDatagramLength[(wLength-8)/4 - 1] value in ' |
| 'NDP16 must be zero.', |
| 'ncm1.0:3.3.2#1': 'wLength value in the NDP32 must be a multiple ' |
| 'of 8, and must be at least 16d (0x0020).', |
| 'ncm1.0:3.3.2#2': 'dwDatagramIndex[0] value in NDP32 must be >= ' |
| '0x0010 (because it must point past the NTH32).', |
| 'ncm1.0:3.3.2#3': 'dwDatagramLength[0] value in NDP32 must be >= ' |
| '20d if datagram payload is IPv4 and >= 40d if ' |
| 'datagram payload is IPv6.', |
| 'ncm1.0:3.3.2#4': 'dwDatagramIndex[(wLength-8)/4 - 1] value in ' |
| 'NDP32 must be zero.', |
| 'ncm1.0:3.3.2#5': 'dwDatagramLength[(wLength-8)/4 - 1] value in ' |
| 'NDP32 must be zero.', |
| } |
| |
| def __init__(self, assertion_id, error_string=None): |
| """ |
| @param assertion_id: A str that must be a key in the MBIM_ASSERTIONS map |
| defined in this class. |
| @param error_string: An optional str to be appended to the error |
| description. |
| |
| For example, |
| MBIMComplianceAssertionError('mbim1.0:3.2.1#1') |
| raises an error associated with assertion [MBIM 1.0]-3.2.1#1 |
| |
| """ |
| if assertion_id not in self.MBIM_ASSERTIONS: |
| log_and_raise(MBIMComplianceFrameworkError, |
| 'Unknown assertion id "%s"' % assertion_id) |
| |
| message = '[%s]: %s' % (assertion_id, |
| self.MBIM_ASSERTIONS[assertion_id]) |
| if error_string: |
| message += ': %s' % error_string |
| |
| super(MBIMComplianceAssertionError, self).__init__(message) |
| |
| |
| class MBIMComplianceGenericAssertionError(MBIMComplianceAssertionError): |
| """ Assertion errors that don't map directly to an MBIM assertion. """ |
| def __init__(self, error_string): |
| """ |
| @param error_string: A description of the error. |
| """ |
| super(MBIMComplianceGenericAssertionError, self).__init__( |
| 'no_code', |
| error_string) |
| |
| |
| def log_and_raise(error_class, *args): |
| """ |
| Log and raise an error. |
| |
| This function should be used to raise all errors. |
| |
| @param error_class: An Exception subclass to raise. |
| @param *args: Arguments to be passed to the error class constructor. |
| @raises: |error_class|. |
| |
| """ |
| error_object = error_class(*args) |
| logging.error(error_object) |
| trace = traceback.format_stack() |
| # Get rid of the current frame from trace |
| trace = trace[:len(trace)-1] |
| logging.error('Traceback:\n' + ''.join(trace)) |
| raise error_object |