From 4baf140d250c696aa15b2694fe9fa824ae73159f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 5 Feb 2019 14:05:49 +0100 Subject: [PATCH] Implement the BLE handshaking The BLE communication sends a handshake packet containing a passphrase based on the serial number of the device. Sadly, we can't actually read the serial number from the device until after this handshake has successfully completed, which makes it a bit of a chicken-and-egg problem from a communication standpoint. However, the serial number is also exposed in the bluetooth device name the device advertizes, which is the reason for the newly added DC_IOCTL_BLE_GET_NAME ioctl. Thanks to Janice McLaughlin for pointing out the logic of this magic handshake. Based-on-code-by: Linus Torvalds --- src/oceanic_atom2.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 682fec9..e897259 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -22,6 +22,8 @@ #include // memcpy #include // malloc, free +#include + #include "oceanic_atom2.h" #include "oceanic_common.h" #include "context-private.h" @@ -46,6 +48,7 @@ #define CMD_INIT 0xA8 #define CMD_VERSION 0x84 +#define CMD_HANDSHAKE 0xE5 #define CMD_READ1 0xB1 #define CMD_READ8 0xB4 #define CMD_READ16 0xB8 @@ -766,6 +769,65 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm return DC_STATUS_SUCCESS; } +/* + * The BLE communication sends a handshake packet that seems + * to be a passphrase based on the BLE name of the device + * (more specifically the serial number encoded in the name). + * + * The packet format is: + * 0xe5 + * < 8 bytes of passphrase > + * one-byte checksum of the passphrase. + */ +static dc_status_t +oceanic_atom2_ble_handshake(oceanic_atom2_device_t *device) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_device_t *abstract = (dc_device_t *) device; + + // Retrieve the bluetooth device name. + // The format of the name is something like 'FQ001124', where the + // two first letters are the ASCII representation of the model + // number (e.g. 'FQ' or 0x4651 for the i770R), and the six digits + // are the serial number. + char name[8 + 1] = {0}; + rc = dc_iostream_ioctl (device->iostream, DC_IOCTL_BLE_GET_NAME, name, sizeof(name)); + if (rc != DC_STATUS_SUCCESS) { + if (rc == DC_STATUS_UNSUPPORTED) { + // Allow skipping the handshake if no name. But the download + // will likely fail. + WARNING (abstract->context, "Bluetooth device name unavailable."); + return DC_STATUS_SUCCESS; + } else { + return rc; + } + } + + // Force a null terminated string. + name[sizeof(name) - 1] = 0; + + // Check the minimum length. + if (strlen (name) < 8) { + ERROR (abstract->context, "Bluetooth device name too short."); + return DC_STATUS_IO; + } + + // Turn ASCII numbers into just raw byte values. + unsigned char handshake[10] = {CMD_HANDSHAKE}; + for (unsigned int i = 0; i < 6; i++) { + handshake[i + 1] = name[i + 2] - '0'; + } + + // Add simple checksum. + handshake[9] = checksum_add_uint8 (handshake + 1, 8, 0x00); + + // Send the command to the dive computer. + rc = oceanic_atom2_transfer (device, handshake, sizeof(handshake), ACK, NULL, 0, 0); + if (rc != DC_STATUS_SUCCESS) + return rc; + + return DC_STATUS_SUCCESS; +} dc_status_t oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model) @@ -857,6 +919,13 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream goto error_free; } + if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) { + status = oceanic_atom2_ble_handshake(device); + if (status != DC_STATUS_SUCCESS) { + goto error_free; + } + } + // Override the base class values. if (OCEANIC_COMMON_MATCH (device->base.version, aeris_f10_version)) { device->base.layout = &aeris_f10_layout;