Detect dives with invalid profile data

The OSTC3 stores the dive headers and profile data in two separate
memory areas. There is a header area with fixed positions and a profile
area which is used as a ring buffer. Each dive header stores the
position of the profile data in the ring buffer.

Now, once there are more dive headers then room for the profiles, the
oldest profiles (but not the headers) are overwritten with new data.
Because the dive headers are not updated when their profile data gets
overwritten, they will now point to data that is no longer available.
The internal logbook detects this situation and does not display the
profile. But during the download, there is no such check, and the OSTC
will send invalid profile data.

This invalid profile data should be dropped on the receiver side.
Unfortunately implementing the exact same check as is done by the OSTC
itself isn't possible, because the OSTC doesn't send the 6 byte internal
header on which the check is based. As a workaround, the two byte
end-of-profile marker and the length field in the profile header is used
to detect overwritten profiles.
This commit is contained in:
Jef Driesen 2017-11-23 21:39:53 +01:00
parent f98f5eba5f
commit 76187c550a
2 changed files with 32 additions and 0 deletions

View File

@ -727,6 +727,11 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
if (firmware < 93)
length -= 3;
}
if (length < RB_LOGBOOK_SIZE_FULL) {
ERROR (abstract->context, "Invalid profile length (%u bytes).", length);
free (header);
return DC_STATUS_DATAFORMAT;
}
// Check the fingerprint data.
if (memcmp (header + offset + logbook->fingerprint, device->fingerprint, sizeof (device->fingerprint)) == 0)
@ -789,6 +794,26 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
return rc;
}
// Detect invalid profile data.
unsigned int delta = device->hardware == OSTC4 ? 3 : 0;
if (length < RB_LOGBOOK_SIZE_FULL + 2 ||
profile[length - 2] != 0xFD || profile[length - 1] != 0xFD) {
// A valid profile should have at least a correct 2 byte
// end-of-profile marker.
WARNING (abstract->context, "Invalid profile end marker detected!");
length = RB_LOGBOOK_SIZE_FULL;
} else if (length == RB_LOGBOOK_SIZE_FULL + 2) {
// A profile containing only the 2 byte end-of-profile
// marker is considered a valid empty profile.
} else if (length < RB_LOGBOOK_SIZE_FULL + 5 + 2 ||
array_uint24_le (profile + RB_LOGBOOK_SIZE_FULL) + delta != array_uint24_le (profile + 9)) {
// If there is more data available, then there should be a
// valid profile header containing a length matching the
// length in the dive header.
WARNING (abstract->context, "Invalid profile header detected.");
length = RB_LOGBOOK_SIZE_FULL;
}
if (callback && !callback (profile, length, profile + 12, sizeof (device->fingerprint), userdata))
break;
}

View File

@ -569,6 +569,13 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
unsigned int header = parser->header;
const hw_ostc_layout_t *layout = parser->layout;
// Exit if no profile data available.
if (size == header || (size == header + 2 &&
data[header] == 0xFD && data[header + 1] == 0xFD)) {
parser->cached = PROFILE;
return DC_STATUS_SUCCESS;
}
// Check the header length.
if (version == 0x23 || version == 0x24) {
if (size < header + 5) {