USB Protocol: Difference between revisions

From Hackspire
Jump to navigation Jump to search
(Acknowledgment and data checksum)
Line 8: Line 8:
We will call ''host'' the participant of the communication which is the USB host, i.e. the computer for a transfer between a computer and a TI-Nspire. <span style="color: IndianRed">The host of a transfer between two TI-Nspires is probably also the USB host, determined with the Host Negotiation Protocol of [http://en.wikipedia.org/wiki/USB_OTG USB On-The-Go]</span>. The communication model of the TI-Nspire seems to allow multiple devices to communicate simultaneously with the same host, through not yet released [http://www.ti-nspire.com/tools/nspire/resources/connect_class.html USB hubs], similar to [http://education.ti.com/educationportal/sites/US/productDetail/us_ti_navigator.html TI-Navigator] available for former calculator models. The TI-Nspire and the computer thus have each a dynamically assigned ''address'' used to identify the source and destination of a packet. A message sent from a source host/device to a destination host/device will be called a ''packet'' in the rest of this documentation. It is actually a protocol packet which may be transparently split into several USB packets by the USB device and host stacks if its length is greater or equal than the maximum USB packet size supported by the TI-Nspire (64 bytes).
We will call ''host'' the participant of the communication which is the USB host, i.e. the computer for a transfer between a computer and a TI-Nspire. <span style="color: IndianRed">The host of a transfer between two TI-Nspires is probably also the USB host, determined with the Host Negotiation Protocol of [http://en.wikipedia.org/wiki/USB_OTG USB On-The-Go]</span>. The communication model of the TI-Nspire seems to allow multiple devices to communicate simultaneously with the same host, through not yet released [http://www.ti-nspire.com/tools/nspire/resources/connect_class.html USB hubs], similar to [http://education.ti.com/educationportal/sites/US/productDetail/us_ti_navigator.html TI-Navigator] available for former calculator models. The TI-Nspire and the computer thus have each a dynamically assigned ''address'' used to identify the source and destination of a packet. A message sent from a source host/device to a destination host/device will be called a ''packet'' in the rest of this documentation. It is actually a protocol packet which may be transparently split into several USB packets by the USB device and host stacks if its length is greater or equal than the maximum USB packet size supported by the TI-Nspire (64 bytes).


Packets are exchanged between ''services'' of the host and the device. A service is a software module which produce and interpret a subset of packet types. A service is identified by a two bytes identifier. Each packet contains both the source and destination service identifiers. A service of a participant sending a packet choose the target service it wants to talk with. Service ids are similar to TCP ports, except that multiple source and destination services are used during the same session (more specifically for acknowledgement) as we will see.
Packets are exchanged between ''services'' of the host and the device. A service is a software module which produce and interpret a subset of packet types. A service is identified by a two bytes identifier. Each packet contains both the source and destination service identifiers. A service of a participant sending a packet choose the target service it wants to talk with. Service ids are similar to TCP ports, except that multiple source and destination services are used during the same session (more specifically for acknowledgment) as we will see.
 
We will use further in the documentation notations of the form: <tt>100.0:8001->100.1:4060</tt> where 100.0 is here the source address, 8001 the source service, 100.1 the destination address and 4060 the destination service.


Once a device has been declared to the host, transfers are initiated by the host and have this form (each line represents a packet):
Once a device has been declared to the host, transfers are initiated by the host and have this form (each line represents a packet):
Line 28: Line 30:
*<tt>DC DC</tt>: checksum of the data part
*<tt>DC DC</tt>: checksum of the data part
*<tt>SZ</tt>: size of the data part
*<tt>SZ</tt>: size of the data part
*<tt>AK</tt>: used for acknowledgment packets
*<tt>AK</tt>: used for acknowledgment packets, 00 for other packets.
*<tt>SQ</tt>: sequence number
*<tt>SQ</tt>: sequence number
*<tt>CK</tt>: checksum of the header: the sum of the preceding bytes modulo 256
*<tt>CK</tt>: checksum of the header: the sum of the preceding bytes modulo 256
Line 37: Line 39:


===Acknowledgment===
===Acknowledgment===
Whether send by the host or a device, an acknowledgment packet always have '''0x00FF''' as source service id. The destination service id must be the source service id of the previously received packet the participant acknowledges. The sequence number must be the same as the one of the packet acknowledged. The field <tt>AK</tt> of the header must contain '''0x0A'''. The 2 byte-long data part must contain the destination service id of the packet acknowledged (i.e. a local service id). Here is an example of an acknowledgment packet sent by a TI-Nspire to a computer:
64.1:00FF->64.0:8001 AK=0A SQ=02
data part: 40 60
Here the device acknowledges the reception of a packet sent by the service 8001 of the host, which had 02 as sequence number, and was sent to the service 4060 of the TI-Nspire.


===Data part checksum===
===Data part checksum===
 
The 2 byte-long checksum is more or less a CRC checksum. The checksum is 00 00 if there is no data part in the packet. Here is a Python implementation of its generation:
def checksum(data):
    acc = 0
    for byte in data:
        first = (ord(byte) << 8) | acc >> 8
        acc = acc & 0xFF
          second = (((acc & 0xF) << 4) ^ acc) << 8
        third = second >> 5
        acc = third >> 7
        acc = (acc ^ first ^ second ^ third) & 0xFFFF
    return acc
# A few examples
assert checksum('\x00\xFF') == 0xFF00
assert checksum('\x05\x00\x00') == 0x57AD
assert checksum('\x20\x00\x00\x00\x00\x00\x00\x00\x05\x01\x00') == 0xA095
===Data part===
===Data part===
The format and interpretation of the data part depends on the source and destination services for the packet. Multiple-bytes integers that appear in the data part are in big endian (most significant byte first). Strings are terminated by a null byte.
The format and interpretation of the data part depends on the source and destination services for the packet. Multiple-bytes integers that appear in the data part (for example sizes are service identifiers) are in big endian (most significant byte first). Strings are terminated with a null byte.


==TODO==
==TODO==
*Move USB descriptors here
*Move the section on USB descriptors here
*Find the differences between PC/TI-Nspire transfers and TI-Nspire/TI-Nspire transfers.
*Find the differences between PC/TI-Nspire transfers and TI-Nspire/TI-Nspire transfers.

Revision as of 15:31, 26 August 2007

This article describes the protocol used for USB communication between the computer and the TI-Nspire. It has been documented from TI's official linking software Computer Link Software, an analysis of USB captures of data traffic, and results of tests with a custom host implementation. This documentation may be used to build a full-featured third-party implementation of the computer program, to use features provided by the link not available from Computer Link Software's GUI, to indirectly gather additional information on the TI-Nspire hardware and software, and to discover exploitable flaws of the TI-Nspire OS's implementation of the protocol.

The documentation is currently incomplete, sometimes vague or too restrictive, and may be wrong on some points. Feel free to contribute to its enhancement and refinement. Information based on assumptions which needs to be confirmed by a host implementation is formatted in indian red. Once enough tests have been made to validate or correct these parts, please edit them and remove the highlighting.

The descriptions of the packets of the protocol let sometimes appear hard-coded value, for which it is not clear whether the corresponding field is constant or may vary under certain conditions. You may edit these descriptions to document additional logic found for them. Limit cases have not all been tested: most of the time the TI-Nspire's implementation of the protocol handles them and make use of error codes. These error codes have not all been documented yet.

Overview

We will call host the participant of the communication which is the USB host, i.e. the computer for a transfer between a computer and a TI-Nspire. The host of a transfer between two TI-Nspires is probably also the USB host, determined with the Host Negotiation Protocol of USB On-The-Go. The communication model of the TI-Nspire seems to allow multiple devices to communicate simultaneously with the same host, through not yet released USB hubs, similar to TI-Navigator available for former calculator models. The TI-Nspire and the computer thus have each a dynamically assigned address used to identify the source and destination of a packet. A message sent from a source host/device to a destination host/device will be called a packet in the rest of this documentation. It is actually a protocol packet which may be transparently split into several USB packets by the USB device and host stacks if its length is greater or equal than the maximum USB packet size supported by the TI-Nspire (64 bytes).

Packets are exchanged between services of the host and the device. A service is a software module which produce and interpret a subset of packet types. A service is identified by a two bytes identifier. Each packet contains both the source and destination service identifiers. A service of a participant sending a packet choose the target service it wants to talk with. Service ids are similar to TCP ports, except that multiple source and destination services are used during the same session (more specifically for acknowledgment) as we will see.

We will use further in the documentation notations of the form: 100.0:8001->100.1:4060 where 100.0 is here the source address, 8001 the source service, 100.1 the destination address and 4060 the destination service.

Once a device has been declared to the host, transfers are initiated by the host and have this form (each line represents a packet):

Host: Request
Device: ACK (acknowledgment)
Device: Response
Host: ACK (acknowledgment)

What could be called a "functional request" (for example "transfer a file") may use serveral exchanges of this type. The host and the device have stateful sessions and can keep track of the current state between these exchanges (for example when listing the content of a directory, which requires one pair of request/response for each file, the device keeps track of the current file).

Packet format

Packets send by a host or a device have the same format. A packet has a 16 bytes header and may have an optional data part of variable length. A packet is at most 270 bytes long, so the data part is at most 254 bytes long.

54 FD SA SA SS SS DA DA DS DS DC DC SZ AK SQ CK [data part]

The different fields of the header part are:

  • 54 FD: constant
  • SA SA: source address
  • SS SS: source service id
  • DA DA: destination address
  • DS DS: destination service id
  • DC DC: checksum of the data part
  • SZ: size of the data part
  • AK: used for acknowledgment packets, 00 for other packets.
  • SQ: sequence number
  • CK: checksum of the header: the sum of the preceding bytes modulo 256

Here is additional information for the fields not obvious and not described before.

Sequence number

Sequence numbers are solely used for proper acknowledgment of packets. Each participant manages itself the generation of the sequence numbers for the packets it sends (a communication between a computer and a TI-Nspire brings into play two sequences). Each packet (except acknowledgment packets, see further, and except in the case of an overflow) has it own sequence number. The number is incremented each time a packet is sent (do they really need to be consecutive?). The generation is common for all the services of a participant, i.e. two consecutive packets sent by/to different services will have consecutive sequence numbers. The sequence number is reinitialized to 1 after a connection reset (does the host really have to make it start from 1?). The sequence number which follows 255 is 1, 0 is never used (is there really a reason for this are does it still work with 0?).

Acknowledgment

Whether send by the host or a device, an acknowledgment packet always have 0x00FF as source service id. The destination service id must be the source service id of the previously received packet the participant acknowledges. The sequence number must be the same as the one of the packet acknowledged. The field AK of the header must contain 0x0A. The 2 byte-long data part must contain the destination service id of the packet acknowledged (i.e. a local service id). Here is an example of an acknowledgment packet sent by a TI-Nspire to a computer:

64.1:00FF->64.0:8001 AK=0A SQ=02 
data part: 40 60

Here the device acknowledges the reception of a packet sent by the service 8001 of the host, which had 02 as sequence number, and was sent to the service 4060 of the TI-Nspire.

Data part checksum

The 2 byte-long checksum is more or less a CRC checksum. The checksum is 00 00 if there is no data part in the packet. Here is a Python implementation of its generation:

def checksum(data):
    acc = 0
    for byte in data:
        first = (ord(byte) << 8) | acc >> 8
        acc = acc & 0xFF
         second = (((acc & 0xF) << 4) ^ acc) << 8
       third = second >> 5
        acc = third >> 7
        acc = (acc ^ first ^ second ^ third) & 0xFFFF
    return acc

# A few examples
assert checksum('\x00\xFF') == 0xFF00
assert checksum('\x05\x00\x00') == 0x57AD
assert checksum('\x20\x00\x00\x00\x00\x00\x00\x00\x05\x01\x00') == 0xA095

Data part

The format and interpretation of the data part depends on the source and destination services for the packet. Multiple-bytes integers that appear in the data part (for example sizes are service identifiers) are in big endian (most significant byte first). Strings are terminated with a null byte.

TODO

  • Move the section on USB descriptors here
  • Find the differences between PC/TI-Nspire transfers and TI-Nspire/TI-Nspire transfers.