From 08a57ce724bfd6ce6532b5cbcf703b568b1b1ef2 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 29 Dec 2010 21:42:23 +0100 Subject: [PATCH] Validate the logbook pointers immediately after downloading. The Aeris Elite T3 appears to update the global logbook pointer incorrectly when overwriting old dives. As a result there can be logbook entries pointing to profile data that has already been overwritten with newer dives, and those cause problems when calculating the total amount of bytes in the profile ringbuffer. As a workaround we validate the logbook pointers immediately after downloading. At this early stage we can check manually for ringbuffer overflows without having to rely on the values stored in the data. --- src/oceanic_common.c | 50 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/oceanic_common.c b/src/oceanic_common.c index 1048a0b..f83763d 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -288,6 +288,10 @@ oceanic_common_device_foreach (device_t *abstract, dive_callback_t callback, voi // Error status for delayed errors. device_status_t status = DEVICE_STATUS_SUCCESS; + // Keep track of the previous dive. + unsigned int remaining = layout->rb_profile_end - layout->rb_profile_begin; + unsigned int previous = 0; + // The logbook ringbuffer is read backwards to retrieve the most recent // entries first. If an already downloaded entry is identified (by means // of its fingerprint), the transfer is aborted immediately to reduce @@ -385,6 +389,31 @@ oceanic_common_device_foreach (device_t *abstract, dive_callback_t callback, voi break; } + // Get the profile pointers. + unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, PAGESIZE, layout); + unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + PAGESIZE; + + // Make sure the profiles are continuous. + if (previous && rb_entry_end != previous) { + WARNING ("Profiles are not continuous."); + status = DEVICE_STATUS_ERROR; + begin = current + PAGESIZE / 2; + abort = 1; + break; + } + + // Make sure the profile size is valid. + if (rb_entry_size > remaining) { + WARNING ("Unexpected profile size."); + status = DEVICE_STATUS_ERROR; + begin = current + PAGESIZE / 2; + abort = 1; + break; + } + + remaining -= rb_entry_size; + previous = rb_entry_first; + // Compare the fingerprint to identify previously downloaded entries. if (memcmp (logbooks + current, device->fingerprint, PAGESIZE / 2) == 0) { begin = current + PAGESIZE / 2; @@ -425,11 +454,11 @@ oceanic_common_device_foreach (device_t *abstract, dive_callback_t callback, voi // When using multipage reads, the last packet can contain data from more // than one dive. Therefore, the remaining data of this package (and its // size) needs to be preserved for the next dive. - unsigned int remaining = rb_profile_size; unsigned int available = 0; // Keep track of the previous dive. - unsigned int previous = rb_profile_end; + remaining = rb_profile_size; + previous = rb_profile_end; // Traverse the logbook ringbuffer backwards to retrieve the most recent // dives first. The logbook ringbuffer is linearized at this point, so @@ -445,25 +474,8 @@ oceanic_common_device_foreach (device_t *abstract, dive_callback_t callback, voi // Get the profile pointers. unsigned int rb_entry_first = get_profile_first (logbooks + current, layout); unsigned int rb_entry_last = get_profile_last (logbooks + current, layout); - unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, PAGESIZE, layout); unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + PAGESIZE; - // Make sure the profiles are continuous. - if (rb_entry_end != previous) { - WARNING ("Profiles are not continuous."); - free (logbooks); - free (profiles); - return DEVICE_STATUS_ERROR; - } - - // Make sure the profile size is valid. - if (rb_entry_size > remaining) { - WARNING ("Unexpected profile size."); - free (logbooks); - free (profiles); - return DEVICE_STATUS_ERROR; - } - // Read the profile data. unsigned int nbytes = available; while (nbytes < rb_entry_size) {