From 0e1c1b2bbe2898e92d5752b3664903567703c5e4 Mon Sep 17 00:00:00 2001 From: Jacek Kowalski <Jacek@jacekk.info> Date: Fri, 24 Jul 2020 19:11:14 +0000 Subject: [PATCH] ControlVault 3 - initial support --- /dev/null | 189 ----------- cv3.py | 43 ++ traffic_cv2.txt | 0 nfc.py | 76 ++++ traffic_cv3.txt | 529 +++++++++++++++++++++++++++++++ cv2.py | 46 ++ cvcomm.py | 93 +++++ README.md | 16 8 files changed, 796 insertions(+), 196 deletions(-) diff --git a/README.md b/README.md index 83c0e71..bcbdc69 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Enable NFC on Dell ControlVault2 +# Enable NFC on Dell ControlVault2 and ControlVault3 ## Introduction @@ -14,7 +14,7 @@ 1. Clone the repository. 1. Install python3 and python3-usb. -1. Run: `./bcm20795.py on` (use `sudo` if necessary). +1. Run: `./nfc.py on` (use `sudo` if necessary). 1. Run `pcsc_scan` or whatever you prefer. 1. Enjoy! @@ -24,8 +24,9 @@ Currently only the following devices were tested and are known to work: -* `0a5c:5832` -* `0a5c:5834` +* `0a5c:5832` (ControlVault 2), +* `0a5c:5833` (ControlVault 3), +* `0a5c:5834` (ControlVault 2). Firmware update (done during driver installation on Windows) may be required. @@ -36,19 +37,20 @@ * Dell Latitude 7280 * Dell Latitude 7290 * Dell Latitude 7390 +* Dell Latitude 7400 * Dell Latitude E5270 * Dell Latitude E7470 * Dell Latitude E7490 ## How it works? -Python script sends the same sequence of commands the Windows driver does. The traffic was sniffed using USBPcap and Wireshark (kudos to [~jkramarz](https://github.com/jkramarz) for that). +Python script sends the same sequence of commands the Windows driver does. The traffic was sniffed using USBPcap and Wireshark (kudos to [~jkramarz](https://github.com/jkramarz) and [~lgarbarini](https://github.com/lgarbarini) and for that). The data is sent as-is and responses are read, but no error-checking is done. -The semi-annotated traffic dump is available as [traffic.txt](traffic.txt) - feel free to decode it further! +The semi-annotated traffic dumps are available as [traffic_cv2.txt](traffic_cv2.txt) and [traffic_cv3.txt](traffic_cv3.txt) - feel free to decode it further! -The communication protocol is based on NCI (NFC Controller Interface). Unfortunately the specs are not freely available and some proprietary extensions are used. libnfc-nci and kernel sources were used to decode some structs. +The communication protocol is based on NCI (NFC Controller Interface). Unfortunately the specs are not freely available and some proprietary extensions are used. libnfc-nci and kernel sources were used to decode vendor-independent structs. ## References diff --git a/bcm20795.py b/bcm20795.py deleted file mode 100755 index c683016..0000000 --- a/bcm20795.py +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env python3 - -# Enable NFC on Linux (CCID/PCSCD) -# Dell E7470 -# Dell ControlVault2 -# BCM20795 (20795A1) - -import binascii -import logging -import math -import struct -import sys -import time -import usb.core -import usb.util - -SUPPORTED_DEVICES = [ - {'idVendor': 0x0A5C, 'idProduct': 0x5834}, - {'idVendor': 0x0A5C, 'idProduct': 0x5832}, -] - -logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger(__name__) - -def to_hex(val): - return ' '.join([bytes([i]).hex() for i in val]) - -class BcmCommunicator: - def __init__(self, device, bulk_in, bulk_out): - self.logger = logging.getLogger(__name__) - self.device = device - self.bulk_in = bulk_in - self.bulk_out = bulk_out - - def ctrl_transfer(self, *args, **kwargs): - self.logger.debug('Control: {} {}'.format(args, kwargs)) - return self.device.ctrl_transfer(*args, **kwargs) - - def write(self, *args, **kwargs): - return self.bulk_out.write(*args, **kwargs) - - def read(self, *args, **kwargs): - return self.bulk_in.read(*args, **kwargs) - - def send_packet(self, payload): - packet_type = 0x01 - unknown1 = 0x00 - length = len(payload) - - packet = struct.pack('>BBH', packet_type, unknown1, length) + payload - - self.logger.debug('Put: {}'.format(to_hex(packet))) - self.write(packet) - - def recv_packet(self): - packet = self.read(64, timeout=5000).tobytes() - tag = packet[0:2] - if tag != b'\x00\x00': - raise Exception('Unknown tag: {}'.format(tag.hex())) - length = packet[2:4] - length = struct.unpack('>H', length)[0] - - for i in range(0, math.ceil(length/64) - 1): - packet += self.read(64).tobytes() - - self.logger.debug('Got: {}'.format(to_hex(packet))) - return packet[4:] - - def talk(self, exchange): - for packet in exchange: - self.send_packet(bytes.fromhex(packet)) - data = self.recv_packet() - - if data[1] == 0x61: - packet = self.recv_packet() - - @staticmethod - def _dev_match(template, candidate): - for prop, value in template.items(): - if prop not in candidate.__dict__ or candidate.__dict__[prop] != value: - return False - return True - - @classmethod - def _dev_matcher(cls, dev): - for device in SUPPORTED_DEVICES: - if cls._dev_match(device, dev): - return True - return False - - @classmethod - def find(cls): - logger = logging.getLogger(__name__) - logger.info('Looking for BCM device...') - - device = usb.core.find(custom_match=cls._dev_matcher) - if device is None: - raise Exception('Cannot find BCM device - check list of supported devices') - logger.info('Found {:04X}:{:04X}'.format(device.idVendor, device.idProduct)) - - logger.debug('Enumerating interfaces...') - configuration = device.get_active_configuration() - bcm_interface = None - for interface in configuration: - if interface.bInterfaceClass == 0xff and interface.iInterface == 0x08: - if bcm_interface is not None: - raise Exception('More than one vendor-specific interface found!') - bcm_interface = interface - if bcm_interface is None: - raise Exception('Cannot find vendor-specific interface') - logger.debug('Interface found: {}'.format(bcm_interface._str())) - - logger.debug('Enumerating endpoints...') - bulk_in = None - bulk_out = None - for endpoint in bcm_interface: - if endpoint.bmAttributes & usb.util._ENDPOINT_TRANSFER_TYPE_MASK == usb.util.ENDPOINT_TYPE_BULK: - if endpoint.bEndpointAddress & usb.util._ENDPOINT_DIR_MASK == usb.util.ENDPOINT_IN: - if bulk_in is not None: - raise Exception('More than one BULK IN endpoint found!') - bulk_in = endpoint - logger.debug('BULK IN found: {}'.format(bulk_in._str())) - if endpoint.bEndpointAddress & usb.util._ENDPOINT_DIR_MASK == usb.util.ENDPOINT_OUT: - if bulk_out is not None: - raise Exception('More than one BULK OUT endpoint found!') - bulk_out = endpoint - logger.debug('BULK OUT found: {}'.format(bulk_out._str())) - - if bulk_in is None: - raise Exception('BULK IN endpoint not found!') - if bulk_out is None: - raise Exception('BULK OUT endpoint not found!') - - logger.debug('Returning {} object...'.format(cls.__name__)) - return cls(device, bulk_in, bulk_out) - -turn_on_seq1 = [ - "10 2f 04 00", - "10 2f 1d 03 05 90 65", - "10 2f 2d 00", - "10 2f 11 01 f7", - "01 27 fc 0c 08 00 01 00 01 00 00 00 00 00 00 00", -] -turn_on_seq2 = [ - "10 20 00 01 01", - "10 20 01 02 01 00", - "10 20 02 67 01 b9 64 01 00 ff ff 50 00 8b 13 00 10 00 06 00 00 00 00 00 ff 00 00 00 ff 00 00 04 00 00 00 00 03 00 00 00 03 00 0c 00 00 0d 00 00 00 00 00 00 00 00 00 00 33 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 02 53 3b 0f 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00", - "10 20 02 90 0a ca 05 00 00 00 00 2c 80 01 01 b0 05 01 03 03 03 08 b5 03 01 03 ff c9 0d 24 00 00 00 01 00 bb 00 e4 00 0a 01 02 d6 0d 01 02 00 00 00 00 00 01 00 01 5a 00 8a b2 02 e8 03 c8 1e 06 1f 00 0a 00 30 00 04 24 00 1c 00 75 00 77 00 76 00 1c 00 03 00 0a 00 56 01 00 00 40 04 d7 01 07 dd 32 00 00 00 29 16 08 08 06 04 00 00 00 1f 27 0a 6d 20 00 52 20 00 00 00 01 85 00 00 32 1f 00 00 02 0a 16 00 02 55 55 55 55 55 55 55 55 55 55 55 55 55 1e", - "10 20 02 06 01 b7 03 02 00 01", - "10 2f 06 01 01", - "10 20 02 0e 02 51 08 20 79 ff ff ff ff ff ff 58 01 07", - "10 21 00 07 02 04 03 02 05 03 03", - "10 20 02 17 01 29 14 46 66 6d 01 01 11 02 02 07 ff 03 02 00 13 04 01 64 07 01 03", - "10 20 02 1a 02 61 14 46 66 6d 01 01 11 02 02 07 ff 03 02 00 13 04 01 64 07 01 03 60 01 07", - "10 20 02 10 05 30 01 04 31 01 00 32 01 40 38 01 00 50 01 02", - "10 20 02 05 01 00 02 fa 00", - "10 20 02 0b 01 c2 08 01 08 00 04 80 c3 c9 01", - "10 21 03 0d 06 00 01 01 01 02 01 80 01 82 01 06 01", -] - -def turn_on(communicator): - communicator.ctrl_transfer(0x41, 0, 1, 3) - communicator.talk(turn_on_seq1) - communicator.ctrl_transfer(0x41, 1, 0, 3) - communicator.talk(turn_on_seq2) - communicator.ctrl_transfer(0x41, 1, 1, 3) - -def turn_off(communicator): - communicator.ctrl_transfer(0x41, 1, 0, 3) - communicator.ctrl_transfer(0x41, 0, 0, 3) - - - -if __name__ == "__main__": - if len(sys.argv) < 2: - print('Usage: {} [on|off]'.format(sys.argv[0])) - sys.exit(2) - - communicator = BcmCommunicator.find() - if sys.argv[1] == 'on': - logger.info('Turning NFC on...') - turn_on(communicator) - logger.info('NFC should be turned on now!') - elif sys.argv[1] == 'off': - logger.info('Turning NFC off...') - turn_off(communicator) - logger.info('NFC should be turned off now!') - else: - raise Exception('Unknown option: {}'.format(sys.argv[1])) diff --git a/cv2.py b/cv2.py new file mode 100644 index 0000000..975c7d3 --- /dev/null +++ b/cv2.py @@ -0,0 +1,46 @@ +import cvcomm + +class ControlVault2: + NAME = 'Broadcom ControlVault 2' + + turn_on_seq1 = [ + "10 2f 04 00", + "10 2f 1d 03 05 90 65", + "10 2f 2d 00", + "10 2f 11 01 f7", + "01 27 fc 0c 08 00 01 00 01 00 00 00 00 00 00 00", + ] + turn_on_seq2 = [ + "10 20 00 01 01", + "10 20 01 02 01 00", + "10 20 02 67 01 b9 64 01 00 ff ff 50 00 8b 13 00 10 00 06 00 00 00 00 00 ff 00 00 00 ff 00 00 04 00 00 00 00 03 00 00 00 03 00 0c 00 00 0d 00 00 00 00 00 00 00 00 00 00 33 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 02 53 3b 0f 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00", + "10 20 02 90 0a ca 05 00 00 00 00 2c 80 01 01 b0 05 01 03 03 03 08 b5 03 01 03 ff c9 0d 24 00 00 00 01 00 bb 00 e4 00 0a 01 02 d6 0d 01 02 00 00 00 00 00 01 00 01 5a 00 8a b2 02 e8 03 c8 1e 06 1f 00 0a 00 30 00 04 24 00 1c 00 75 00 77 00 76 00 1c 00 03 00 0a 00 56 01 00 00 40 04 d7 01 07 dd 32 00 00 00 29 16 08 08 06 04 00 00 00 1f 27 0a 6d 20 00 52 20 00 00 00 01 85 00 00 32 1f 00 00 02 0a 16 00 02 55 55 55 55 55 55 55 55 55 55 55 55 55 1e", + "10 20 02 06 01 b7 03 02 00 01", + "10 2f 06 01 01", + "10 20 02 0e 02 51 08 20 79 ff ff ff ff ff ff 58 01 07", + "10 21 00 07 02 04 03 02 05 03 03", + "10 20 02 17 01 29 14 46 66 6d 01 01 11 02 02 07 ff 03 02 00 13 04 01 64 07 01 03", + "10 20 02 1a 02 61 14 46 66 6d 01 01 11 02 02 07 ff 03 02 00 13 04 01 64 07 01 03 60 01 07", + "10 20 02 10 05 30 01 04 31 01 00 32 01 40 38 01 00 50 01 02", + "10 20 02 05 01 00 02 fa 00", + "10 20 02 0b 01 c2 08 01 08 00 04 80 c3 c9 01", + "10 21 03 0d 06 00 01 01 01 02 01 80 01 82 01 06 01", + ] + + def __init__(self, device): + self.device = device + self.communicator = cvcomm.ControlVaultCommunicator(device) + + def turn_on(self): + self.communicator.ctrl_transfer(0x41, 0, 1, 3) + self.communicator.talk(self.turn_on_seq1) + self.communicator.ctrl_transfer(0x41, 1, 0, 3) + self.communicator.talk(self.turn_on_seq2) + self.communicator.ctrl_transfer(0x41, 1, 1, 3) + + def turn_off(self): + self.communicator.ctrl_transfer(0x41, 1, 0, 3) + self.communicator.ctrl_transfer(0x41, 0, 0, 3) + + def reset(self): + self.device.reset() diff --git a/cv3.py b/cv3.py new file mode 100644 index 0000000..e010616 --- /dev/null +++ b/cv3.py @@ -0,0 +1,43 @@ +import cvcomm + +class ControlVault3: + NAME = 'Broadcom ControlVault 3' + + turn_on_seq1 = [ + "20 00 01 00", + ] + turn_on_seq2 = [ + "20 00 01 00", + "20 01 00", + "20 03 02 01 52", + "20 02 1f 0a 21 01 00 28 01 00 30 01 04 31 01 03 54 01 06 5b 01 00 60 01 07 80 01 01 81 01 01 82 01 0e", + "21 00 10 05 04 03 02 05 03 03 01 01 01 02 01 01 03 01 01", + "21 01 07 00 01 01 03 00 01 05", + "20 02 09 01 b9 06 01 00 00 0b 00 00", + "20 02 c7 11 18 01 02 2a 01 32 80 01 00 c2 02 03 02 c4 02 00 13 ca 05 00 0f 0d 03 08 cb 01 00 d6 0b 01 01 00 01 12 00 01 00 01 00 01 d8 01 01 de 04 01 00 00 00 e0 07 00 60 93 1c 63 3e 0a e1 02 79 07 e2 2a 48 07 0c 10 00 31 39 39 39 39 39 39 39 39 39 39 41 39 90 90 90 90 3f 90 90 90 88 8a 8c 94 94 28 04 07 00 00 00 00 00 00 00 00 e3 08 17 04 16 0d 10 0c 2b 0b e4 01 37 e5 1e e0 1e 02 12 00 0a 00 10 04 54 54 54 54 2b 52 50 53 4e 20 2d 18 0c 02 07 00 94 70 94 70 20 e6 2d 01 68 00 77 00 8b 00 a7 00 d6 00 22 01 c0 01 9e 58 4c 40 33 26 20 1e 68 00 77 00 8b 00 a7 00 d6 00 22 01 c0 01 5e 58 4c 40 33 2b 26 1e", + "2f 1b 06 08 00 00 01 00 00", + "20 02 2d 04 29 11 46 66 6d 01 01 11 02 02 03 80 03 02 00 01 04 01 64 2a 01 30 61 11 46 66 6d 01 01 11 02 02 03 80 03 02 00 01 04 01 64 62 01 30", + "20 02 0e 04 18 01 01 32 01 40 50 01 02 00 02 2c 01", + "21 03 0d 06 00 01 01 01 02 01 06 01 80 01 82 01", + ] + + def __init__(self, device): + self.device = device + self.communicator = cvcomm.ControlVaultCommunicator(device) + + def turn_on(self): + self.communicator.ctrl_transfer(0x41, 1, 0, 3) + self.communicator.talk(self.turn_on_seq1) + self.communicator.ctrl_transfer(0x41, 1, 1, 3) + self.communicator.ctrl_transfer(0x41, 0, 0, 3) + self.communicator.ctrl_transfer(0x41, 0, 1, 3) + self.communicator.ctrl_transfer(0x41, 1, 0, 3) + self.communicator.talk(self.turn_on_seq2) + self.communicator.ctrl_transfer(0x41, 1, 1, 3) + + def turn_off(self): + self.communicator.ctrl_transfer(0x41, 1, 0, 3) + self.communicator.ctrl_transfer(0x41, 0, 0, 3) + + def reset(self): + self.device.reset() diff --git a/cvcomm.py b/cvcomm.py new file mode 100644 index 0000000..67ad942 --- /dev/null +++ b/cvcomm.py @@ -0,0 +1,93 @@ +import logging +import math +import struct +import usb.util + +def to_hex(val): + return ' '.join([bytes([i]).hex() for i in val]) + +class ControlVaultCommunicator: + def __init__(self, device, spi_master=0x01, spi_slave=0x00, spi_crc=0x00): + self.logger = logging.getLogger(__name__) + self.device = device + self.bulk_in, self.bulk_out = self._find_endpoints() + + self.spi_master = spi_master + self.spi_slave = spi_slave + self.spi_crc = spi_crc + self.spi_slave_prefix = struct.pack('>BB', self.spi_slave, self.spi_crc) + + def ctrl_transfer(self, *args, **kwargs): + self.logger.debug('Control: {} {}'.format(args, kwargs)) + return self.device.ctrl_transfer(*args, **kwargs) + + def write(self, *args, **kwargs): + return self.bulk_out.write(*args, **kwargs) + + def read(self, *args, **kwargs): + return self.bulk_in.read(*args, **kwargs) + + def send_packet(self, payload): + length = len(payload) + packet = struct.pack('>BBH', self.spi_master, self.spi_crc, length) + payload + self.logger.debug('Put: {}'.format(to_hex(packet))) + self.write(packet) + + def recv_packet(self): + packet = self.read(64, timeout=5000).tobytes() + tag = packet[0:2] + if tag != self.spi_slave_prefix: + raise Exception('Unknown tag: {}'.format(tag.hex())) + length = packet[2:4] + length = struct.unpack('>H', length)[0] + + for i in range(0, math.ceil(length/64) - 1): + packet += self.read(64).tobytes() + + self.logger.debug('Got: {}'.format(to_hex(packet))) + return packet[4:] + + def talk(self, exchange): + for packet in exchange: + self.send_packet(bytes.fromhex(packet)) + data = self.recv_packet() + + if data[1] == 0x61: + packet = self.recv_packet() + + def _find_endpoints(self): + self.logger.debug('Enumerating interfaces...') + configuration = self.device.get_active_configuration() + bcm_interface = None + for interface in configuration: + if interface.bInterfaceClass == 0xff and interface.iInterface == 0x08: + if bcm_interface is not None: + raise Exception('More than one vendor-specific interface found!') + bcm_interface = interface + if bcm_interface is None: + raise Exception('Cannot find vendor-specific interface') + self.logger.debug('Interface found: {}'.format(bcm_interface._str())) + + self.logger.debug('Enumerating endpoints...') + bulk_in = None + bulk_out = None + for endpoint in bcm_interface: + if endpoint.bmAttributes & usb.util._ENDPOINT_TRANSFER_TYPE_MASK == usb.util.ENDPOINT_TYPE_BULK: + if endpoint.bEndpointAddress & usb.util._ENDPOINT_DIR_MASK == usb.util.ENDPOINT_IN: + if bulk_in is not None: + raise Exception('More than one BULK IN endpoint found!') + bulk_in = endpoint + self.logger.debug('BULK IN found: {}'.format(bulk_in._str())) + if endpoint.bEndpointAddress & usb.util._ENDPOINT_DIR_MASK == usb.util.ENDPOINT_OUT: + if bulk_out is not None: + raise Exception('More than one BULK OUT endpoint found!') + bulk_out = endpoint + self.logger.debug('BULK OUT found: {}'.format(bulk_out._str())) + + if bulk_in is None: + raise Exception('BULK IN endpoint not found!') + if bulk_out is None: + raise Exception('BULK OUT endpoint not found!') + + self.logger.debug('Endpoint discovery successful.') + return bulk_in, bulk_out diff --git a/nfc.py b/nfc.py new file mode 100755 index 0000000..1d02389 --- /dev/null +++ b/nfc.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 + +import logging +import sys +import usb.core + +class UsbDeviceMatcher: + def __init__(self, properties, handler): + self.properties = properties + self.handler = handler + + def matches(self, candidate): + for prop, value in self.properties.items(): + if prop not in candidate.__dict__ or candidate.__dict__[prop] != value: + return False + return True + +class UsbDeviceFinder: + SUPPORTED_DEVICES = [ + UsbDeviceMatcher({'idVendor': 0x0A5C, 'idProduct': 0x5832}, lambda device: __import__('cv2').ControlVault2(device)), + UsbDeviceMatcher({'idVendor': 0x0A5C, 'idProduct': 0x5833}, lambda device: __import__('cv3').ControlVault3(device)), + UsbDeviceMatcher({'idVendor': 0x0A5C, 'idProduct': 0x5834}, lambda device: __import__('cv2').ControlVault2(device)), + ] + + @classmethod + def _dev_matcher(cls, device): + for matcher in cls.SUPPORTED_DEVICES: + if matcher.matches(device): + return True + return False + + @classmethod + def _cls_matcher(cls, device): + for matcher in cls.SUPPORTED_DEVICES: + if matcher.matches(device): + return matcher.handler(device) + raise Exception('Cannot find handler for device {:04X}:{:04X}'.format(dev.idVendor, dev.idProduct)) + + @classmethod + def find(cls): + logger = logging.getLogger(__name__) + logger.info('Looking for supported device...') + + device = usb.core.find(custom_match=cls._dev_matcher) + if device is None: + raise Exception('Cannot find BCM device - check list of supported devices') + logger.info('Found {:04X}:{:04X}'.format(device.idVendor, device.idProduct)) + + handler = cls._cls_matcher(device) + logger.info('Handler {} ({})'.format(handler.__class__.__name__, handler.NAME)) + return handler + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print('Usage: {} [on|off|reset]'.format(sys.argv[0])) + sys.exit(2) + + logging.basicConfig(level=logging.DEBUG) + logger = logging.getLogger(__name__) + + handler = UsbDeviceFinder.find() + if sys.argv[1] == 'on': + logger.info('Turning NFC on...') + handler.turn_on() + logger.info('NFC should be turned on now!') + elif sys.argv[1] == 'off': + logger.info('Turning NFC off...') + handler.turn_off() + logger.info('NFC should be turned off now!') + elif sys.argv[1] == 'reset': + logger.info('Resetting device...') + handler.reset() + logger.info('NFC device has been reset!') + else: + raise Exception('Unknown option: {}'.format(sys.argv[1])) diff --git a/traffic.txt b/traffic_cv2.txt similarity index 100% rename from traffic.txt rename to traffic_cv2.txt diff --git a/traffic_cv3.txt b/traffic_cv3.txt new file mode 100644 index 0000000..7cc18a0 --- /dev/null +++ b/traffic_cv3.txt @@ -0,0 +1,529 @@ +idVendor 0x0A5C +idProduct 0x5843 + +Interface 4 - Application-Specific +EP 1 IN +EP 1 OUT +EP 5 IN + +Interface 5 - Smart Card +EP 2 IN +EP 2 OUT +EP 6 IN + +Interface 6 - Smart Card +EP 3 IN +EP 3 OUT +EP 7 IN + +Interface 7 - Vendor Specific +EP 4 IN +EP 4 OUT +EP 8 IN + + +Legend: + +> - New outgoing message (beginning) +>> - Message continuation (division for readability) +< - New incoming message (beginning) +<< - Message continuation (division for readability) +# CTRL - Control endpoint communication (bmRequestType, bRequest, wValue, wIndex) + +Communication via Endpoint 4 + +########## +TURNING ON +########## + +# CTRL 0x41 0x01 0x0000 0x0003 + +> 01 00 00 04 + 01 = SPI_MASTER + 00 = NO_CRC + 00 04 = size +>> 20 00 01 00 + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 00 = NCI_MSG_CORE_RESET + 01 = NCI_CORE_PARAM_SIZE_RESET + 00 = NCI_RESET_TYPE_KEEP_CFG + +< 00 00 00 06 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 06 = size +<< 40 00 03 00 10 00 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 00 = NCI_MSG_CORE_RESET + 03 = NCI_CORE_PARAM_SIZE_RESET_RSP + 00 = NCI_STATUS_OK + 10 = NCI_VERSION (1.0) + 00 = NCI_RESET_STATUS_KEPT_CFG + +# CTRL 0x41 0x01 0x0001 0x0003 + +# CTRL 0x41 0x00 0x0000 0x0003 + +# CTRL 0x41 0x00 0x0001 0x0003 + +# CTRL 0x41 0x01 0x0000 0x0003 + +> 01 00 00 04 + 01 = SPI_MASTER + 00 = NO_CRC + 00 04 = size +>> 20 00 01 00 + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 00 = NCI_MSG_CORE_RESET + 01 = NCI_CORE_PARAM_SIZE_RESET + 00 = NCI_RESET_TYPE_KEEP_CFG + +< 00 00 00 06 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 06 = size +<< 40 00 03 00 11 00 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 00 = NCI_MSG_CORE_RESET + 03 = NCI_CORE_PARAM_SIZE_RESET_RSP + 00 = NCI_STATUS_OK + 11 = NCI_VERSION (1.1) + 00 = NCI_RESET_STATUS_KEPT_CFG + +> 01 00 00 03 + 01 = SPI_MASTER + 00 = NO_CRC + 00 03 = size +>> 20 01 00 + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 01 = NCI_MSG_CORE_INIT + 00 = size + +< 00 00 00 1a + 00 = SPI_SLAVE + 00 = NO_CRC + 00 1a = size +<< 40 01 17 00 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 01 = NCI_MSG_CORE_INIT + 17 = size + 00 = NCI_STATUS_OK +<< 03 0e 02 01 + 03 0e 02 01 NFCC_FEATURES + 02 = multiple NFCEEs + 01 = RF_DISCOVER_CMD supported + 08 = AID-based routing supported + 04 = Protocol-based routing supported + 02 = Technology-based routing supported + 02 = Switched-off state supported + 01 = Proprietary parameters +<< 06 00 01 02 03 81 83 + 06 = num_of_ifaces (6) + 00 = NCI_INTERFACE_EE_DIRECT_RF + 01 = NCI_INTERFACE_FRAME + 02 = NCI_INTERFACE_ISO_DEP + 03 = NCI_INTERFACE_NFC_DEP + 81 = Proprietary Interface (81) + 83 = Proprietary Interface (83) + +<< 08 00 04 ff 0f 00 2e 04 10 2b 41 + 08 = num_of_conns_max (8) + 00 04 = num_of_routes_max + ff = size_control_payload_max + 0f 00 = size_large_params_max + 2e = manufacturer_id + 04 10 2b 41 = manufacturer_specific + +> 01 00 00 05 + 01 = SPI_MASTER + 00 = NO_CRC + 00 05 = size +>> 20 03 02 01 52 + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 03 = NCI_MSG_CORE_GET_CONFIG + 02 = num_of_params (2) + 01 = CON_DEVICES_LIMIT + 52 = LF_T3T_MAX + +< 00 00 00 08 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 08 = size +<< 40 03 05 00 01 52 01 10 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 03 = NCI_MSG_CORE_GET_CONFIG + ??? + +> 01 00 00 22 + 01 = SPI_MASTER + 00 = NO_CRC + 00 22 = size +>> 20 02 1f 0a + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 1f = size + 0a = num_of_params (10) +>> 21 01 00 + 21 = PI_BIT_RATE + 01 = size_of_param + 00 = 106 Kbit/s +>> 28 01 00 + 28 = PN_NFC_DEP_SPEED + 01 = size_of_param + 00 = Highest Available Bitrate +>> 30 01 04 + 30 = LA_BIT_FRAME_SDD + 01 = size_of_param + 04 = Bit Frame SDD value to be sent in Byte 1 of SENS_RES +>> 31 01 03 + 31 = LA_PLATFORM_CONFIG + 01 = size_of_param + 03 = Platform Configuration value to be sent in Byte 2 of SENS_RES +>> 54 01 06 + 54 = LF_CON_BITR_F + 01 = size_of_param + 02 = listen for 212 kbps + 04 = listen for 424 kbps +>> 5b 01 00 + 5b = LI_BIT_RATE + 01 = size_of_param + 00 = 106 Kbit/s +>> 60 01 07 + 60 = LN_WT + 01 = size_of_param + 07 = waiting time (7) +>> 80 01 01 + 80 = RF_FIELD_INFO + 01 = size_of_param + 01 = RF_FIELD_INFO_NTF allowed +>> 81 01 01 + 81 = RF_NFCEE_ACTION + 01 = size_of_param + 01 = send RF NFCEE Actions +>> 82 01 0e + 82 = NFCDEP_OP + 01 = size_of_param + 02 = ATTENTION only for error recovery + 04 = don't send msgs without Transport Data Bytes + 08 = chaining uses max number of Transport Data Bytes + +< 00 00 00 05 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 05 = size +<< 40 02 02 00 00 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 02 = size + 00 = NCI_STATUS_OK + 00 = num_of_invalid_params (0) + +> 01 00 00 13 + 01 = SPI_MASTER + 00 = NO_CRC + 00 13 = size +>> 21 00 10 05 + 21 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE + 00 = NCI_MSG_RF_DISCOVER_MAP + 10 = size (16) + 05 = num_mapping_configs +>> 04 03 02 + 04 = NCI_PROTOCOL_ISO_DEP + 03 = NCI_INTERFACE_MODE_POLL_N_LISTEN + 02 = NCI_INTERFACE_ISO_DEP +>> 05 03 03 + 05 = NCI_PROTOCOL_NFC_DEP + 03 = NCI_INTERFACE_MODE_POLL_N_LISTEN + 03 = NCI_INTERFACE_NFC_DEP +>> 01 01 01 + 01 = PROTOCOL_T1T + 01 = NCI_INTERFACE_MODE_POLL + 01 = NCI_INTERFACE_FRAME +>> 02 01 01 + 02 = PROTOCOL_T2T + 01 = NCI_INTERFACE_MODE_POLL + 01 = NCI_INTERFACE_FRAME +>> 03 01 01 + 03 = PROTOCOL_T3T + 01 = NCI_INTERFACE_MODE_POLL + 01 = NCI_INTERFACE_FRAME + +< 00 00 00 04 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 04 = size +<< 61 07 01 00 + 61 = NCI_MTS_NTF | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE + 07 = NCI_MSG_RF_FIELD + 01 = size + 00 = No RF field + +< 00 00 00 04 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 04 = size +<< 41 00 01 00 + 41 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE + 00 = NCI_MSG_RF_DISCOVER_MAP + 01 = NCI_DISCOVER_PARAM_SIZE_RSP + 00 = NCI_STATUS_OK + + +> 01 00 00 0a + 01 = SPI_MASTER + 00 = NO_CRC + 00 0a = size +>> 21 01 07 00 01 01 03 00 01 05 + 21 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE + 01 = NCI_MSG_RF_SET_ROUTING + 07 = size + 00 = last message + 01 = routing_entries (1) + 01 = protocol-based routing + 03 = length (3) + 00 = DH NFCEE ID + 01 = power state (1 - switched on) + 05 = PROTOCOL_NFC_DEP + + +< 00 00 00 04 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 04 = size +<< 41 01 01 00 + 41 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE + 01 = NCI_MSG_RF_SET_ROUTING + 01 = size + 00 = NCI_STATUS_OK + +> 01 00 00 0c + 01 = SPI_MASTER + 00 = NO_CRC + 00 0c = size +>> 20 02 09 01 + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 09 = size + 01 = num_of_params +>> b9 06 01 00 00 0b 00 00 + b9 = Proprietary parameter (b9) + 06 = size_of_param + +< 00 00 00 05 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 05 = size +<< 40 02 02 00 00 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 02 = size + 00 = NCI_STATUS_OK + 00 = num_of_invalid_params (0) + +> 01 00 00 ca + 01 = SPI_MASTER + 00 = NO_CRC + 00 ca = size +>> 20 02 c7 11 + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + c7 = size + 11 = num_of_params (17) +>> 18 01 02 + 18 = PF_BIT_RATE + 01 = size_of_param + 02 = 424 Kbit/s +>> 2a 01 32 + 2a = PN_ATR_REQ_CONFIG + 01 = size_of_param + 30 = 0011b for LLCP + 02 = ? +>> 80 01 00 + 80 = RF_FIELD_INFO + 01 = size_of_param + 00 = RF_FIELD_INFO_NTF not allowed +>> c2 02 03 02 + c2 = Proprietary parameter (c2) + 02 = size_of_param +>> c4 02 00 13 + c4 = Proprietary parameter (c4) + 02 = size_of_param +>> ca 05 00 0f 0d 03 08 + ca = Proprietary parameter (ca) + 05 = size_of_param +>> cb 01 00 + cb = Proprietary parameter (cb) + 01 = size_of_param +>> d6 0b 01 01 00 01 12 00 01 00 01 00 01 + d6 = Proprietary parameter (d6) + 0b = size_of_param +>> d8 01 01 + d8 = Proprietary parameter (d8) + 01 = size_of_param +>> de 04 01 00 00 00 + de = Proprietary parameter (de) + 04 = size_of_param +>> e0 07 00 60 93 1c 63 3e 0a + e0 = Proprietary parameter (e0) + 07 = size_of_param +>> e1 02 79 07 + e1 = Proprietary parameter (e1) + 02 = size_of_param +>> e2 2a 48 07 0c 10 00 31 39 39 39 39 39 39 39 39 39 39 41 39 90 90 90 90 3f 90 90 90 88 8a 8c 94 94 28 04 07 00 00 00 00 00 00 00 00 + e2 = Proprietary parameter (e2) + 2a = size_of_param +>> e3 08 17 04 16 0d 10 0c 2b 0b + e3 = Proprietary parameter (e3) + 08 = size_of_param +>> e4 01 37 + e4 = Proprietary parameter (e4) + 01 = size_of_param +>> e5 1e e0 1e 02 12 00 0a 00 10 04 54 54 54 54 2b 52 50 53 4e 20 2d 18 0c 02 07 00 94 70 94 70 20 + e5 = Proprietary parameter (e5) + 1e = size_of_param +>> e6 2d 01 68 00 77 00 8b 00 a7 00 d6 00 22 01 c0 01 9e 58 4c 40 33 26 20 1e 68 00 77 00 8b 00 a7 00 d6 00 22 01 c0 01 5e 58 4c 40 33 2b 26 1e + e6 = Proprietary parameter (e6) + 2d = size_of_param + +< 00 00 00 05 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 05 = size +<< 40 02 02 00 00 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 02 = size + 00 = NCI_STATUS_OK + 00 = num_of_invalid_params (0) + +> 01 00 00 09 + 01 = SPI_MASTER + 00 = NO_CRC + 00 09 = size +>> 2f 1b 06 08 00 00 01 00 00 + 2f = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_PROP + 1b = Proprietary message (1b) + 06 = size + +< 00 00 00 04 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 04 = size +<< 4f 1b 01 00 + 4f = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_PROP + 1b = Proprietary message (1b) + 01 = size + +> 01 00 00 30 + 01 = SPI_MASTER + 00 = NO_CRC + 00 30 = size +>> 20 02 2d 04 + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 2d = size + 04 = num_of_params (4) +>> 29 11 46 66 6d 01 01 11 02 02 03 80 03 02 00 01 04 01 64 + 29 = PN_ATR_REQ_GEN_BYTES + 11 = size_of_param + General Bytes for ATR_REQ +>> 2a 01 30 + 2a = PN_ATR_REQ_CONFIG + 01 = size_of_param + 30 = 0011b for LLCP +>> 61 11 46 66 6d 01 01 11 02 02 03 80 03 02 00 01 04 01 64 + 61 = LN_ATR_RES_GEN_BYTES + 11 = size_of_param + General Bytes in ATR_RES +>> 62 01 30 + 62 = LN_ATR_RES_CONFIG + 01 = size_of_param + 30 = 0011b for LLCP + +< 00 00 00 05 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 05 = size +<< 40 02 02 00 00 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 02 = size + 00 = NCI_STATUS_OK + 00 = num_of_invalid_params (0) + +> 01 00 00 11 + 01 = SPI_MASTER + 00 = NO_CRC + 00 11 = size +>> 20 02 0e 04 + 20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 0e = size + 04 = num_of_params (4) +>> 18 01 01 + 18 = PF_BIT_RATE + 01 = size_of_param + 01 = 212 Kbit/s +>> 32 01 40 + 32 = LA_SEL_INFO + 01 = size_of_param + 40 = NFC-DEP +>> 50 01 02 + 50 = LF_PROTOCOL_TYPE + 01 = size_of_param + 02 = NFC-DEP +>> 00 02 2c 01 + 00 = TOTAL_DURATION + 02 = size_of_param + 2c 01 = 11 256 ms + +< 00 00 00 05 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 05 = size +<< 40 02 02 00 00 + 40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE + 02 = NCI_MSG_CORE_SET_CONFIG + 02 = size + 00 = NCI_STATUS_OK + 00 = num_of_invalid_params (0) + +> 01 00 00 10 + 01 = SPI_MASTER + 00 = NO_CRC + 00 10 = size +>> 21 03 0d 06 + 21 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE + 03 = NCI_MSG_RF_DISCOVER + 0d = size + 06 = num_of_configs (6) +>> 00 01 + 00 = NFC_A_PASSIVE_POLL_MODE + 01 = every discovery period +>> 01 01 + 01 = NFC_B_PASSIVE_POLL_MODE + 01 = every discovery period +>> 02 01 + 02 = NFC_F_PASSIVE_POLL_MODE + 01 = every discovery period +>> 06 01 + 06 = NFC_15693_PASSIVE_POLL_MODE + 01 = every discovery period +>> 80 01 + 80 = NFC_A_PASSIVE_LISTEN_MODE + 01 = every discovery period +>> 82 01 + 82 = NFC_F_PASSIVE_LISTEN_MODE + 01 = every discovery period + +< 00 00 00 04 + 00 = SPI_SLAVE + 00 = NO_CRC + 00 04 = size +<< 41 03 01 00 + 41 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE + 03 = NCI_MSG_RF_DISCOVER + 01 = size + 00 = STATUS_OK + +# CTRL 0x41 0x01 0x0001 0x0003 -- Gitblit v1.9.1