Difference between revisions of "Ir:USER"

From 3dbrew
Jump to navigation Jump to search
(Redirected page to IR Services#IR Service "ir:USER")
 
Line 1: Line 1:
#REDIRECT [[IR Services#IR Service "ir:USER"]]
+
This service was added with [[2.0.0-2]]. It employs a custom packet format with obfuscation and error detection.
 +
 
 +
= Command set =
 +
When sending data, SendIrnop is used when the size is <=0xFC, otherwise SendIrnopLarge is used.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Command Header
 +
!  Available since system version
 +
!  Description
 +
|-
 +
| 0x00010182
 +
| [[2.0.0-2]]
 +
| InitializeIrnop
 +
|-
 +
| 0x00020000
 +
| [[2.0.0-2]]
 +
| FinalizeIrnop
 +
|-
 +
| 0x00030000
 +
| [[2.0.0-2]]
 +
| ClearReceiveBuffer
 +
|-
 +
| 0x00040000
 +
| [[2.0.0-2]]
 +
| ClearSendBuffer
 +
|-
 +
| 0x0005....
 +
| [[2.0.0-2]]
 +
| WaitConnection
 +
|-
 +
| 0x00060040
 +
| [[2.0.0-2]]
 +
| RequireConnection (u8 input)
 +
|-
 +
| 0x0007....
 +
| [[2.0.0-2]]
 +
| AutoConnection
 +
|-
 +
| 0x0008....
 +
| [[2.0.0-2]]
 +
| AnyConnection
 +
|-
 +
| 0x00090000
 +
| [[2.0.0-2]]
 +
| Disconnect
 +
|-
 +
| 0x000A0000
 +
| [[2.0.0-2]]
 +
| GetReceiveEvent (writes event handle to cmdreply[3])
 +
|-
 +
| 0x000B0000
 +
| [[2.0.0-2]]
 +
| GetSendEvent (writes event handle to cmdreply[3])
 +
|-
 +
| 0x000C0000
 +
| [[2.0.0-2]]
 +
| GetConnectionStatusEvent (writes event handle to cmdreply[3])
 +
|-
 +
| 0x000D0042
 +
| [[2.0.0-2]]
 +
| SendIrnop (u32 size, ((Size<<14) <nowiki>|</nowiki> 2), inbufptr)
 +
|-
 +
| 0x000E0042
 +
| [[2.0.0-2]]
 +
| SendIrnopLarge (u32 size, ((Size<<8) <nowiki>|</nowiki> 10), inbufptr)
 +
|-
 +
| 0x000F....
 +
| [[2.0.0-2]]
 +
| ReceiveIrnop
 +
|-
 +
| 0x0010....
 +
| [[2.0.0-2]]
 +
| ReceiveIrnopLarge
 +
|-
 +
| 0x0011....
 +
| [[2.0.0-2]]
 +
| GetLatestReceiveErrorResult
 +
|-
 +
| 0x0012....
 +
| [[2.0.0-2]]
 +
| GetLatestSendErrorResult
 +
|-
 +
| 0x0013....
 +
| [[2.0.0-2]]
 +
| GetConnectionStatus
 +
|-
 +
| 0x0014....
 +
| [[2.0.0-2]]
 +
| GetTryingToConnectStatus
 +
|-
 +
| 0x0015....
 +
| [[2.0.0-2]]
 +
| GetReceiveSizeFreeAndUsed
 +
|-
 +
| 0x0016....
 +
| [[2.0.0-2]]
 +
| GetSendSizeFreeAndUsed
 +
|-
 +
| 0x0017....
 +
| [[2.2.0-X]]
 +
| GetConnectionRole
 +
|-
 +
| 0x00180182
 +
| [[2.2.0-X]]
 +
| InitializeIrnopShared (u32, u32, u32, u32, u32, u8, 0, handle)
 +
|-
 +
| 0x00190040
 +
| [[2.2.0-X]]
 +
| ReleaseReceivedData (32bit_value input)
 +
|-
 +
| 0x001A0040
 +
| [[2.2.0-X]]
 +
| SetOwnMachineId (u8 input)
 +
|}
 +
 
 +
= Protocol description =
 +
Packets are sent using IrDA-SIR, with a 8N1 encoding (eight data bits, one stop bit, without parity). Each one is formed by a 2-byte header, a varint with the payload size, an obfuscated payload, and trailing error detection byte.
 +
 
 +
== Packet header ==
 +
The packet header is fixed and consists in a synchronization byte (0xA5), followed by a unused (possibly RFU) zero byte. After these two hardcoded bytes, there's a varint representing the payload size, which may use one byte or two, depending on the how big the payload is.
 +
 
 +
* For payloads with less than 64 bytes, the third byte represents the payload size.
 +
* For packets with up to 16383 bytes, the size is split in two bytes, with the third byte being the upper 6 bits of the payload size, OR'd with 0x40, and the fourth being the lower eight bits of the payload size
 +
 
 +
For packets with less than 64 bytes:
 +
{| class="wikitable" border="1"
 +
! Sync
 +
! RFU
 +
! Size
 +
|-
 +
| 0xA5
 +
| 0x00
 +
| size
 +
|}
 +
 
 +
For packets with up to 16383 bytes:
 +
{| class="wikitable" border="1"
 +
! Sync
 +
! RFU
 +
! Size (1)
 +
! Size (2)
 +
|-
 +
| 0xA5
 +
| 0x00
 +
| (size >> 8) <nowiki>|</nowiki> 0x40
 +
| size & 0xFF
 +
|}
 +
 
 +
In C:
 +
<nowiki>uint8_t * setPacketHeader(uint8_t * buffer, size_t payloadSize) {
 +
assert(payloadSize < 16384);
 +
 
 +
buffer[0] = 0xA5;
 +
buffer[1] = 0x00;
 +
 
 +
if (payloadSize < 64) {
 +
buffer[2] = payloadSize;
 +
buffer += 3;
 +
} else {
 +
buffer[2] = 0x40 | (payloadSize >> 8);
 +
buffer[3] = payloadSize;
 +
buffer += 4;
 +
}
 +
 
 +
return buffer;
 +
}</nowiki>
 +
 
 +
== Payload ==
 +
The payload is obfuscated using a XOR-based encryption. In C:
 +
<nowiki>void payloadObfuscate(const void * voidplain, void * voidcipher, size_t size) {
 +
uint16_t * plain = (uint16_t *) voidplain;
 +
uint16_t * cipher = (uint16_t *) voidcipher;
 +
size_t halfCount = size / sizeof(uint16_t);
 +
 
 +
uint16_t xorval = htobe16(0xE963);
 +
size_t i;
 +
 
 +
for (i = 0; i < halfCount; i++) {
 +
xorval ^= plain[i];
 +
cipher[i] = xorval;
 +
}
 +
}
 +
 
 +
void payloadDeobfuscate(const void * voidcipher, void * voidplain, size_t size) {
 +
uint16_t * cipher = (uint16_t *) voidcipher;
 +
uint16_t * plain = (uint16_t *) voidplain;
 +
size_t halfCount = size / sizeof(uint16_t);
 +
 
 +
if (halfCount) {
 +
size_t i;
 +
for (i = halfCount - 1; i > 0; i--) {
 +
plain[i] = cipher[i] ^ cipher[i - 1];
 +
}
 +
 
 +
plain[0] = cipher[0] ^ htobe16(0xE963);
 +
}
 +
}</nowiki>
 +
 
 +
== Error detection ==
 +
The trailing error detection byte is calculated using [[CRC-8-CCITT]] <b>over the whole packet</b> (both the header and the payload)

Revision as of 10:48, 16 April 2015

This service was added with 2.0.0-2. It employs a custom packet format with obfuscation and error detection.

Command set

When sending data, SendIrnop is used when the size is <=0xFC, otherwise SendIrnopLarge is used.

Command Header Available since system version Description
0x00010182 2.0.0-2 InitializeIrnop
0x00020000 2.0.0-2 FinalizeIrnop
0x00030000 2.0.0-2 ClearReceiveBuffer
0x00040000 2.0.0-2 ClearSendBuffer
0x0005.... 2.0.0-2 WaitConnection
0x00060040 2.0.0-2 RequireConnection (u8 input)
0x0007.... 2.0.0-2 AutoConnection
0x0008.... 2.0.0-2 AnyConnection
0x00090000 2.0.0-2 Disconnect
0x000A0000 2.0.0-2 GetReceiveEvent (writes event handle to cmdreply[3])
0x000B0000 2.0.0-2 GetSendEvent (writes event handle to cmdreply[3])
0x000C0000 2.0.0-2 GetConnectionStatusEvent (writes event handle to cmdreply[3])
0x000D0042 2.0.0-2 SendIrnop (u32 size, ((Size<<14) | 2), inbufptr)
0x000E0042 2.0.0-2 SendIrnopLarge (u32 size, ((Size<<8) | 10), inbufptr)
0x000F.... 2.0.0-2 ReceiveIrnop
0x0010.... 2.0.0-2 ReceiveIrnopLarge
0x0011.... 2.0.0-2 GetLatestReceiveErrorResult
0x0012.... 2.0.0-2 GetLatestSendErrorResult
0x0013.... 2.0.0-2 GetConnectionStatus
0x0014.... 2.0.0-2 GetTryingToConnectStatus
0x0015.... 2.0.0-2 GetReceiveSizeFreeAndUsed
0x0016.... 2.0.0-2 GetSendSizeFreeAndUsed
0x0017.... 2.2.0-X GetConnectionRole
0x00180182 2.2.0-X InitializeIrnopShared (u32, u32, u32, u32, u32, u8, 0, handle)
0x00190040 2.2.0-X ReleaseReceivedData (32bit_value input)
0x001A0040 2.2.0-X SetOwnMachineId (u8 input)

Protocol description

Packets are sent using IrDA-SIR, with a 8N1 encoding (eight data bits, one stop bit, without parity). Each one is formed by a 2-byte header, a varint with the payload size, an obfuscated payload, and trailing error detection byte.

Packet header

The packet header is fixed and consists in a synchronization byte (0xA5), followed by a unused (possibly RFU) zero byte. After these two hardcoded bytes, there's a varint representing the payload size, which may use one byte or two, depending on the how big the payload is.

  • For payloads with less than 64 bytes, the third byte represents the payload size.
  • For packets with up to 16383 bytes, the size is split in two bytes, with the third byte being the upper 6 bits of the payload size, OR'd with 0x40, and the fourth being the lower eight bits of the payload size

For packets with less than 64 bytes:

Sync RFU Size
0xA5 0x00 size

For packets with up to 16383 bytes:

Sync RFU Size (1) Size (2)
0xA5 0x00 (size >> 8) | 0x40 size & 0xFF

In C:

uint8_t * setPacketHeader(uint8_t * buffer, size_t payloadSize) {
	assert(payloadSize < 16384);

	buffer[0] = 0xA5;
	buffer[1] = 0x00;

	if (payloadSize < 64) {
		buffer[2] = payloadSize;
		buffer += 3;
	} else {
		buffer[2] = 0x40 | (payloadSize >> 8);
		buffer[3] = payloadSize;
		buffer += 4;
	}

	return buffer;
}

Payload

The payload is obfuscated using a XOR-based encryption. In C:

void payloadObfuscate(const void * voidplain, void * voidcipher, size_t size) {
	uint16_t * plain = (uint16_t *) voidplain;
	uint16_t * cipher = (uint16_t *) voidcipher;
	size_t halfCount = size / sizeof(uint16_t);

	uint16_t xorval = htobe16(0xE963);
	size_t i;

	for (i = 0; i < halfCount; i++) {
		xorval ^= plain[i];
		cipher[i] = xorval;
	}
}

void payloadDeobfuscate(const void * voidcipher, void * voidplain, size_t size) {
	uint16_t * cipher = (uint16_t *) voidcipher;
	uint16_t * plain = (uint16_t *) voidplain;
	size_t halfCount = size / sizeof(uint16_t);

	if (halfCount) {
		size_t i;
		for (i = halfCount - 1; i > 0; i--) {
			plain[i] = cipher[i] ^ cipher[i - 1];
		}

		plain[0] = cipher[0] ^ htobe16(0xE963);
	}
}

Error detection

The trailing error detection byte is calculated using CRC-8-CCITT over the whole packet (both the header and the payload)