From ffa9e0aa3c6535ba4876b495f8fb9856474f9c4a Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 3 Mar 2020 19:58:55 +0100 Subject: [PATCH] Ignore excess bytes in the BLE version packet For the Oceanic Pro Plus X and the Aqualung i770R, downloading over BLE often fails because the version packet contains one or more unexpected bytes. For a successful download, the correct structure for the version packet is as follows: 5A 4F4345414E4F43582031432030303032 C6 That's the start byte, the payload "OCEANOCX 1C 0002" and the checksum. For all the failed packets, there are one or more bytes extra present between the payload and the checksum: 5A 4F4345414E4F43582031432030303032 9F02 67 5A 4F4345414E4F43582031432030303032 3603 FF 5A 4F4345414E4F43582031432030303032 64 2A 5A 4F4345414E4F43582031432030303032 9202 5A 5A 4F4345414E4F43582031432030303032 08 CE 5A 4F4345414E4F43582031432030303032 2C01 F3 The amount of extra bytes, and their content appears to be pretty random. The strangest part is that the checksum of the packet is actually correct and includes those extra bytes! As workaround, accept extra bytes in the BLE packet, verify the checksum as usual, and finally strip the excess bytes and only pass the actual content to the next layer. To avoid false positives, the workaround is limited to packets with a payload and checksum, and only enabled for the two affected models. --- src/oceanic_atom2.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 342cb9e..9183b0a 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -65,6 +65,7 @@ typedef struct oceanic_atom2_device_t { dc_iostream_t *iostream; unsigned int sequence; unsigned int delay; + unsigned int extra; unsigned int bigpage; unsigned char cache[256]; unsigned int cached_page; @@ -590,7 +591,7 @@ oceanic_atom2_ble_write (oceanic_atom2_device_t *device, const unsigned char dat } static dc_status_t -oceanic_atom2_ble_read (oceanic_atom2_device_t *device, unsigned char data[], unsigned int size) +oceanic_atom2_ble_read (oceanic_atom2_device_t *device, unsigned char data[], unsigned int size, unsigned int *actual) { dc_status_t rc = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; @@ -656,11 +657,15 @@ oceanic_atom2_ble_read (oceanic_atom2_device_t *device, unsigned char data[], un } // Verify the expected number of bytes. - if (nbytes != size) { + if (nbytes > size) { ERROR (abstract->context, "Unexpected number of bytes received (%u %u).", nbytes, size); return DC_STATUS_PROTOCOL; } + if (actual) { + *actual = nbytes; + } + return DC_STATUS_SUCCESS; } @@ -699,8 +704,13 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman // Receive the answer of the dive computer. unsigned char packet[1 + MAXPACKET + 2]; + unsigned int nbytes = 1 + asize + crc_size; if (transport == DC_TRANSPORT_BLE) { - status = oceanic_atom2_ble_read (device, packet, 1 + asize + crc_size); + // Accept excess bytes for some models. + if (asize && device->extra) { + nbytes = 1 + MAXPACKET + crc_size; + } + status = oceanic_atom2_ble_read (device, packet, nbytes, &nbytes); } else { status = dc_iostream_read (device->iostream, packet, 1 + asize + crc_size, NULL); } @@ -709,6 +719,14 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman return status; } + // Verify the number of bytes. + if (nbytes < 1 + asize + crc_size) { + ERROR (abstract->context, "Unexpected number of bytes received (%u %u).", nbytes, 1 + asize + crc_size); + return DC_STATUS_PROTOCOL; + } + + nbytes -= 1 + crc_size; + // Verify the ACK byte of the answer. if (packet[0] != ack) { ERROR (abstract->context, "Unexpected answer start byte(s)."); @@ -719,11 +737,11 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman // Verify the checksum of the answer. unsigned short crc, ccrc; if (crc_size == 2) { - crc = array_uint16_le (packet + 1 + asize); - ccrc = checksum_add_uint16 (packet + 1, asize, 0x0000); + crc = array_uint16_le (packet + 1 + nbytes); + ccrc = checksum_add_uint16 (packet + 1, nbytes, 0x0000); } else { - crc = packet[1 + asize]; - ccrc = checksum_add_uint8 (packet + 1, asize, 0x00); + crc = packet[1 + nbytes]; + ccrc = checksum_add_uint8 (packet + 1, nbytes, 0x00); } if (crc != ccrc) { ERROR (abstract->context, "Unexpected answer checksum."); @@ -733,6 +751,10 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman memcpy (answer, packet + 1, asize); } + if (nbytes > asize) { + WARNING (abstract->context, "Ignored %u excess byte(s).", nbytes - asize); + } + device->sequence++; return DC_STATUS_SUCCESS; @@ -852,6 +874,7 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream // Set the default values. device->iostream = iostream; device->delay = 0; + device->extra = model == PROPLUSX || model == I770R; device->sequence = 0; device->bigpage = 1; // no big pages device->cached_page = INVALID;