mirror of
https://github.com/google/pebble.git
synced 2025-03-25 04:49:06 +00:00
553 lines
23 KiB
C
553 lines
23 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "services/common/shared_prf_storage/shared_prf_storage.h"
|
|
#include "services/common/shared_prf_storage/v3_sprf/shared_prf_storage_private.h"
|
|
#include "flash_region/flash_region.h"
|
|
#include "drivers/flash.h"
|
|
#include "util/size.h"
|
|
|
|
#include <bluetooth/sm_types.h>
|
|
#include <btutil/sm_util.h>
|
|
#include <os/mutex.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "clar.h"
|
|
|
|
// Fakes
|
|
//////////////////////////////////////////////////////////
|
|
#include "fake_spi_flash.h"
|
|
#include "stubs_pbl_malloc.h"
|
|
#include "stubs_passert.h"
|
|
#include "stubs_logging.h"
|
|
|
|
// Externs
|
|
//////////////////////////////////////////////////////////
|
|
extern uint32_t shared_prf_storage_get_valid_page_number(void);
|
|
extern void shared_prf_storage_set_valid_page_number(uint32_t page_num);
|
|
|
|
// Defines
|
|
//////////////////////////////////////////////////////////
|
|
#define SPRF_REGION_SIZE (FLASH_REGION_SHARED_PRF_STORAGE_END - \
|
|
FLASH_REGION_SHARED_PRF_STORAGE_BEGIN)
|
|
#define SPRF_NUM_PAGES (SPRF_REGION_SIZE / sizeof(SharedPRFData))
|
|
|
|
#define SPRF_PAGE_FLASH_OFFSET(idx) (FLASH_REGION_SHARED_PRF_STORAGE_BEGIN + \
|
|
(idx * sizeof(SharedPRFData)))
|
|
|
|
// Stubs
|
|
//////////////////////////////////////////////////////////
|
|
static bool s_mutex_locked;
|
|
PebbleMutex * mutex_create(void) {
|
|
return NULL;
|
|
}
|
|
|
|
void mutex_lock(PebbleMutex * handle) {
|
|
cl_assert_equal_b(s_mutex_locked, false);
|
|
s_mutex_locked = true;
|
|
}
|
|
|
|
void mutex_unlock(PebbleMutex * handle) {
|
|
cl_assert_equal_b(s_mutex_locked, true);
|
|
s_mutex_locked = false;
|
|
}
|
|
|
|
static const char DEVICE_NAME[BT_DEVICE_NAME_BUFFER_SIZE] = "ABCDEFGHIJKLMNOPQRS";
|
|
static const char *PAIRING_NAME = "Blah123";
|
|
static const BTDeviceAddress DEVICE_ADDR = {.octets = {0x88, 0x99, 0xaa, 0xbb, 0x00, 0x11}};
|
|
|
|
static const SMPairingInfo PAIRING_INFO = (const SMPairingInfo) {
|
|
.local_encryption_info = {
|
|
.ediv = 123,
|
|
.ltk = (const SMLongTermKey) {
|
|
.data = {
|
|
0x44, 0x55, 0x66, 0x77, 0x00, 0x11, 0x22, 0x33,
|
|
0xcc, 0xdd, 0xee, 0xff, 0x88, 0x99, 0xaa, 0xbb,
|
|
},
|
|
},
|
|
.rand = 0x11223344,
|
|
},
|
|
|
|
.remote_encryption_info = {
|
|
.ltk = (const SMLongTermKey) {
|
|
.data = {
|
|
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
|
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
|
|
},
|
|
},
|
|
.rand = 0x11223344,
|
|
.ediv = 9876,
|
|
},
|
|
|
|
.irk = (const SMIdentityResolvingKey) {
|
|
.data = {
|
|
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
|
|
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
|
},
|
|
},
|
|
.identity = (const BTDeviceInternal) {
|
|
.opaque.opaque_64 = 0x1122334455667788,
|
|
},
|
|
|
|
.csrk = {
|
|
.data = {
|
|
0xcc, 0xdd, 0xee, 0xff, 0x88, 0x99, 0xaa, 0xbb,
|
|
0x44, 0x55, 0x66, 0x77, 0x00, 0x11, 0x22, 0x33,
|
|
},
|
|
},
|
|
|
|
.is_local_encryption_info_valid = true,
|
|
.is_remote_encryption_info_valid = true,
|
|
.is_remote_identity_info_valid = true,
|
|
.is_remote_signing_info_valid = true,
|
|
.is_mitm_protection_enabled = true,
|
|
};
|
|
|
|
// Helpers
|
|
///////////////////////////////////////////////////////////
|
|
static void prv_fill_flash_random_data(void) {
|
|
uint8_t *buf = kernel_malloc_check(SPRF_REGION_SIZE);
|
|
fake_spi_flash_erase();
|
|
memset(buf, 0x17, SPRF_REGION_SIZE);
|
|
flash_write_bytes(buf, FLASH_REGION_SHARED_PRF_STORAGE_BEGIN, SPRF_REGION_SIZE);
|
|
kernel_free(buf);
|
|
}
|
|
|
|
static void prv_assert_mutexes_unlocked(void) {
|
|
cl_assert_equal_b(s_mutex_locked, false);
|
|
}
|
|
|
|
// Tests
|
|
///////////////////////////////////////////////////////////
|
|
void test_shared_prf_storage_v3__initialize(void) {
|
|
fake_spi_flash_init(FLASH_REGION_SHARED_PRF_STORAGE_BEGIN,
|
|
SPRF_REGION_SIZE);
|
|
shared_prf_storage_init();
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__cleanup(void) {
|
|
fake_spi_flash_cleanup();
|
|
prv_assert_mutexes_unlocked();
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__init_all_zeros(void) {
|
|
uint8_t *flash_buf = kernel_zalloc(SPRF_REGION_SIZE);
|
|
flash_write_bytes(flash_buf, FLASH_REGION_SHARED_PRF_STORAGE_BEGIN, SPRF_REGION_SIZE);
|
|
shared_prf_storage_init();
|
|
shared_prf_storage_set_getting_started_complete(true);
|
|
cl_assert_equal_b(shared_prf_storage_get_getting_started_complete(), true);
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__find_first_valid_sector(void) {
|
|
SharedPRFData data;
|
|
|
|
// These are the pages that this test will place a valid header. It will write invalid pages
|
|
// before the valid one.
|
|
uint8_t page_idx[] = {0, 1, SPRF_NUM_PAGES / 2, SPRF_NUM_PAGES - 1};
|
|
|
|
for (uint32_t i = 0; i < ARRAY_LENGTH(page_idx); i++) {
|
|
fake_spi_flash_erase();
|
|
|
|
// Invalidate all entries before it to simulate logging style
|
|
for (uint32_t j = 0; j < page_idx[i]; j++) {
|
|
SprfMagic inv_magic = SprfMagic_InvalidatedEntry;
|
|
flash_write_bytes((uint8_t *) &inv_magic, SPRF_PAGE_FLASH_OFFSET(j), sizeof(inv_magic));
|
|
}
|
|
|
|
// Write the valid page
|
|
flash_read_bytes((uint8_t *) &data, SPRF_PAGE_FLASH_OFFSET(page_idx[i]), sizeof(data));
|
|
data.magic = SprfMagic_ValidEntry;
|
|
flash_write_bytes((uint8_t *) &data, SPRF_PAGE_FLASH_OFFSET(page_idx[i]), sizeof(data));
|
|
|
|
// Call init and see if it found the valid page
|
|
shared_prf_storage_init();
|
|
uint32_t desired_page_idx = page_idx[i];
|
|
if (page_idx[i] > SPRF_MAX_NUM_PAGES_MULT(SPRF_NUM_PAGES)) {
|
|
desired_page_idx = 0;
|
|
}
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), desired_page_idx);
|
|
}
|
|
|
|
// Erase the entire region and test that it picks the first empty page
|
|
fake_spi_flash_erase();
|
|
shared_prf_storage_init();
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
|
|
// Test that it sees all pages are invalid, rewrites everything, and picks the first empty page
|
|
prv_fill_flash_random_data();
|
|
shared_prf_storage_init();
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__wipe_all(void) {
|
|
SMPairingInfo sm_pairing_info;
|
|
memset(&sm_pairing_info, 0xaa, sizeof(sm_pairing_info));
|
|
sm_pairing_info.is_local_encryption_info_valid = true;
|
|
sm_pairing_info.is_remote_signing_info_valid = true;
|
|
sm_pairing_info.is_remote_identity_info_valid = true;
|
|
shared_prf_storage_store_ble_pairing_data(&sm_pairing_info, PAIRING_NAME,
|
|
false /* requires_address_pinning */, 0 /* flags */);
|
|
cl_assert_equal_b(shared_prf_storage_get_ble_pairing_data(NULL, NULL, NULL, NULL), true);
|
|
shared_prf_storage_wipe_all();
|
|
|
|
cl_assert_equal_b(shared_prf_storage_get_ble_pairing_data(NULL, NULL, NULL, NULL), false);
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__getting_started_complete(void) {
|
|
shared_prf_storage_wipe_all();
|
|
cl_assert_equal_b(shared_prf_storage_get_getting_started_complete(), false);
|
|
shared_prf_storage_set_getting_started_complete(true);
|
|
cl_assert_equal_b(shared_prf_storage_get_getting_started_complete(), true);
|
|
shared_prf_storage_wipe_all();
|
|
cl_assert_equal_b(shared_prf_storage_get_getting_started_complete(), false);
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__ble_pairing(void) {
|
|
shared_prf_storage_wipe_all();
|
|
cl_assert_equal_b(shared_prf_storage_get_ble_pairing_data(NULL, NULL, NULL, NULL), false);
|
|
|
|
shared_prf_storage_store_ble_pairing_data(&PAIRING_INFO, DEVICE_NAME,
|
|
false /* requires_address_pinning */, 0 /* flags */);
|
|
|
|
char name_out[BT_DEVICE_NAME_BUFFER_SIZE];
|
|
memset(name_out, 0, sizeof(name_out));
|
|
SMPairingInfo pairing_info_out = {};
|
|
bool requires_address_pinning_out = true;
|
|
uint8_t flags = 0;
|
|
cl_assert_equal_b(shared_prf_storage_get_ble_pairing_data(&pairing_info_out, name_out,
|
|
&requires_address_pinning_out,
|
|
&flags), true);
|
|
cl_assert_equal_b(requires_address_pinning_out, false);
|
|
cl_assert_equal_i(flags, 0);
|
|
cl_assert_equal_i(strcmp(DEVICE_NAME, name_out), 0);
|
|
cl_assert_equal_b(PAIRING_INFO.is_mitm_protection_enabled,
|
|
pairing_info_out.is_mitm_protection_enabled);
|
|
cl_assert_equal_b(PAIRING_INFO.is_remote_signing_info_valid,
|
|
pairing_info_out.is_remote_signing_info_valid);
|
|
cl_assert_equal_b(PAIRING_INFO.is_remote_identity_info_valid,
|
|
pairing_info_out.is_remote_identity_info_valid);
|
|
cl_assert_equal_b(PAIRING_INFO.is_remote_encryption_info_valid,
|
|
pairing_info_out.is_remote_encryption_info_valid);
|
|
cl_assert_equal_b(PAIRING_INFO.is_local_encryption_info_valid,
|
|
pairing_info_out.is_local_encryption_info_valid);
|
|
cl_assert_equal_i(PAIRING_INFO.local_encryption_info.ediv,
|
|
pairing_info_out.local_encryption_info.ediv);
|
|
cl_assert_equal_i(PAIRING_INFO.local_encryption_info.div,
|
|
pairing_info_out.local_encryption_info.div);
|
|
cl_assert_equal_i(PAIRING_INFO.identity.opaque.opaque_64,
|
|
pairing_info_out.identity.opaque.opaque_64);
|
|
cl_assert_equal_i(PAIRING_INFO.remote_encryption_info.rand,
|
|
pairing_info_out.remote_encryption_info.rand);
|
|
cl_assert_equal_i(PAIRING_INFO.remote_encryption_info.ediv,
|
|
pairing_info_out.remote_encryption_info.ediv);
|
|
cl_assert_equal_i(memcmp(&PAIRING_INFO.remote_encryption_info.ltk,
|
|
&pairing_info_out.remote_encryption_info.ltk, sizeof(SMLongTermKey)), 0);
|
|
cl_assert_equal_i(memcmp(&PAIRING_INFO.irk, &pairing_info_out.irk,
|
|
sizeof(SMIdentityResolvingKey)), 0);
|
|
cl_assert_equal_i(memcmp(&PAIRING_INFO.csrk, &pairing_info_out.csrk,
|
|
sizeof(SM128BitKey)), 0);
|
|
|
|
shared_prf_storage_erase_ble_pairing_data();
|
|
cl_assert_equal_b(shared_prf_storage_get_ble_pairing_data(NULL, NULL, NULL, NULL), false);
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__root_keys(void) {
|
|
shared_prf_storage_wipe_all();
|
|
|
|
cl_assert_equal_b(shared_prf_storage_get_root_key(SMRootKeyTypeIdentity, NULL), false);
|
|
cl_assert_equal_b(shared_prf_storage_get_root_key(SMRootKeyTypeEncryption, NULL), false);
|
|
|
|
SM128BitKey keys[2];
|
|
for (int i = 0; i < sizeof(keys); ++i) {
|
|
((uint8_t *) keys)[i] = i;
|
|
}
|
|
|
|
shared_prf_storage_set_root_keys(keys);
|
|
|
|
SM128BitKey keys_out[2];
|
|
for (SMRootKeyType key_type = 0; key_type < SMRootKeyTypeNum; ++key_type) {
|
|
cl_assert_equal_b(shared_prf_storage_get_root_key(key_type, &keys_out[key_type]), true);
|
|
// It's a byte array inside, so memcmp should be OK to use:
|
|
cl_assert_equal_i(memcmp(&keys[key_type], &keys_out[key_type], sizeof(keys[0])), 0);
|
|
}
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__local_device_name(void) {
|
|
cl_assert_equal_b(shared_prf_storage_get_local_device_name(NULL, 0), false);
|
|
|
|
shared_prf_storage_set_local_device_name(DEVICE_NAME);
|
|
|
|
char device_name_out[BT_DEVICE_NAME_BUFFER_SIZE];
|
|
cl_assert_equal_b(shared_prf_storage_get_local_device_name(device_name_out,
|
|
sizeof(device_name_out)), true);
|
|
cl_assert_equal_s(DEVICE_NAME, device_name_out);
|
|
}
|
|
|
|
// Test that setting a local_name to NULL will rewrite the field with 0xFF and allow it to
|
|
// be rewritten without causing a new page to be written
|
|
void test_shared_prf_storage_v3__local_device_name_NULL_new_erased_field(void) {
|
|
shared_prf_storage_set_local_device_name(DEVICE_NAME);
|
|
|
|
char device_name_out[BT_DEVICE_NAME_BUFFER_SIZE];
|
|
cl_assert_equal_b(shared_prf_storage_get_local_device_name(device_name_out,
|
|
sizeof(device_name_out)), true);
|
|
cl_assert_equal_s(DEVICE_NAME, device_name_out);
|
|
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
shared_prf_storage_set_local_device_name(NULL);
|
|
cl_assert_equal_b(shared_prf_storage_get_local_device_name(device_name_out,
|
|
sizeof(device_name_out)), false);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 1);
|
|
shared_prf_storage_set_local_device_name(DEVICE_NAME);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 1);
|
|
}
|
|
|
|
// Test that setting and retrieving a pinned address works.
|
|
void test_shared_prf_storage_v3__pinned_address(void) {
|
|
shared_prf_storage_set_ble_pinned_address(&DEVICE_ADDR);
|
|
BTDeviceAddress addr_buf;
|
|
bool rv = shared_prf_storage_get_ble_pinned_address(&addr_buf);
|
|
cl_assert_equal_b(rv, true);
|
|
cl_assert_equal_m(&DEVICE_ADDR, &addr_buf, sizeof(DEVICE_ADDR));
|
|
|
|
shared_prf_storage_set_ble_pinned_address(&DEVICE_ADDR);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
|
|
shared_prf_storage_set_ble_pinned_address(NULL);
|
|
rv = shared_prf_storage_get_ble_pinned_address(NULL);
|
|
cl_assert_equal_b(rv, false);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 1);
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__rewrite_pages_and_wrap_around(void) {
|
|
bool toggle = false;
|
|
|
|
shared_prf_storage_wipe_all();
|
|
|
|
// Make sure to wrap around a few times and confirm that works
|
|
for (uint32_t iter = 0; iter < 3; iter++) {
|
|
toggle = false;
|
|
// Iterate through all possible pages and keep writing new data, confirm it's the right data.
|
|
for (uint32_t i = 0; i < SPRF_NUM_PAGES; i++) {
|
|
shared_prf_storage_set_getting_started_complete(toggle);
|
|
cl_assert_equal_b(shared_prf_storage_get_getting_started_complete(), toggle);
|
|
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), i);
|
|
|
|
toggle = !toggle;
|
|
}
|
|
}
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__save_all_data_confirm_all_data_correct(void) {
|
|
const bool GETTING_STARTED_COMPLETE = true;
|
|
|
|
shared_prf_storage_store_ble_pairing_data(&PAIRING_INFO, DEVICE_NAME,
|
|
true /* requires_address_pinning */, 0xff /* flags */);
|
|
shared_prf_storage_set_getting_started_complete(GETTING_STARTED_COMPLETE);
|
|
shared_prf_storage_set_local_device_name(DEVICE_NAME);
|
|
|
|
char device_name_out[BT_DEVICE_NAME_BUFFER_SIZE];
|
|
|
|
// Check pairing info
|
|
SMPairingInfo pairing_info_out;
|
|
bool requires_address_pinning = false;
|
|
uint8_t flags = 0;
|
|
shared_prf_storage_get_ble_pairing_data(&pairing_info_out, device_name_out,
|
|
&requires_address_pinning,
|
|
&flags);
|
|
cl_assert_equal_b(requires_address_pinning, true);
|
|
cl_assert_equal_i(flags, 0xff);
|
|
cl_assert_equal_b(sm_is_pairing_info_equal_identity(&PAIRING_INFO, &pairing_info_out), true);
|
|
cl_assert_equal_s(device_name_out, DEVICE_NAME);
|
|
|
|
// Check getting started
|
|
cl_assert_equal_b(shared_prf_storage_get_getting_started_complete(), GETTING_STARTED_COMPLETE);
|
|
|
|
// Check local_name
|
|
cl_assert_equal_b(shared_prf_storage_get_local_device_name(device_name_out,
|
|
sizeof(device_name_out)), true);
|
|
cl_assert_equal_s(DEVICE_NAME, device_name_out);
|
|
}
|
|
|
|
void test_shared_prf_storage_v3__write_in_loop_getting_started_confirm_data_still_intact(void) {
|
|
bool GETTING_STARTED_COMPLETE = true;
|
|
|
|
shared_prf_storage_store_ble_pairing_data(&PAIRING_INFO, DEVICE_NAME,
|
|
true /* requires_address_pinning */, 0xff /* flags */);
|
|
shared_prf_storage_set_getting_started_complete(GETTING_STARTED_COMPLETE);
|
|
shared_prf_storage_set_local_device_name(DEVICE_NAME);
|
|
|
|
for (uint32_t i = 0; i < 50; i++) {
|
|
GETTING_STARTED_COMPLETE = !GETTING_STARTED_COMPLETE;
|
|
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), i % SPRF_NUM_PAGES);
|
|
shared_prf_storage_set_getting_started_complete(GETTING_STARTED_COMPLETE);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), (i + 1) % SPRF_NUM_PAGES);
|
|
}
|
|
|
|
// Check if our old information is still in tact after looping and rewriting a ton of times
|
|
|
|
char device_name_out[BT_DEVICE_NAME_BUFFER_SIZE];
|
|
|
|
// Check pairing info
|
|
SMPairingInfo pairing_info_out;
|
|
bool requires_address_pinning = false;
|
|
uint8_t flags = 0;
|
|
|
|
shared_prf_storage_get_ble_pairing_data(&pairing_info_out, device_name_out,
|
|
&requires_address_pinning,
|
|
&flags);
|
|
cl_assert_equal_b(requires_address_pinning, true);
|
|
cl_assert_equal_i(flags, 0xff);
|
|
cl_assert_equal_b(sm_is_pairing_info_equal_identity(&PAIRING_INFO, &pairing_info_out), true);
|
|
cl_assert_equal_s(device_name_out, DEVICE_NAME);
|
|
|
|
// Check local_name
|
|
cl_assert_equal_b(shared_prf_storage_get_local_device_name(device_name_out,
|
|
sizeof(device_name_out)), true);
|
|
cl_assert_equal_s(DEVICE_NAME, device_name_out);
|
|
}
|
|
|
|
// Sets the getting started field, then corrupts the getting_started crc
|
|
void test_shared_prf_storage_v3__handle_currupt_field_same(void) {
|
|
bool GETTING_STARTED_COMPLETE = true;
|
|
shared_prf_storage_set_getting_started_complete(GETTING_STARTED_COMPLETE);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
|
|
SharedPRFData data;
|
|
flash_read_bytes((uint8_t *)&data,
|
|
SPRF_PAGE_FLASH_OFFSET(shared_prf_storage_get_valid_page_number()),
|
|
sizeof(data));
|
|
cl_assert(data.getting_started.crc != 0xFFFFFFFF);
|
|
|
|
uint32_t new_crc = 0;
|
|
flash_write_bytes((uint8_t *)&new_crc,
|
|
SPRF_PAGE_FLASH_OFFSET(shared_prf_storage_get_valid_page_number())
|
|
+ offsetof(SharedPRFData, getting_started)
|
|
+ offsetof(SprfGettingStarted, crc),
|
|
sizeof(new_crc));
|
|
|
|
// Confirm new CRC was written
|
|
flash_read_bytes((uint8_t *)&data,
|
|
SPRF_PAGE_FLASH_OFFSET(shared_prf_storage_get_valid_page_number()),
|
|
sizeof(data));
|
|
cl_assert_equal_i(data.getting_started.crc, new_crc);
|
|
|
|
// Should be corrupt, so it should return false
|
|
cl_assert_equal_b(shared_prf_storage_get_getting_started_complete(), false);
|
|
// Should have moved to the next page
|
|
cl_assert_equal_b(shared_prf_storage_get_valid_page_number(), 1);
|
|
|
|
// Let's do it again, but move the valid page to index NUM_PAGES - 1 so we force a wrap around
|
|
fake_spi_flash_erase();
|
|
shared_prf_storage_set_valid_page_number(SPRF_NUM_PAGES - 1);
|
|
shared_prf_storage_set_getting_started_complete(GETTING_STARTED_COMPLETE);
|
|
flash_write_bytes((uint8_t *)&new_crc,
|
|
SPRF_PAGE_FLASH_OFFSET(shared_prf_storage_get_valid_page_number())
|
|
+ offsetof(SharedPRFData, getting_started)
|
|
+ offsetof(SprfGettingStarted, crc),
|
|
sizeof(new_crc));
|
|
// Should be corrupt, so it should return false
|
|
cl_assert_equal_b(shared_prf_storage_get_getting_started_complete(), false);
|
|
// Should have moved to the next page, which is ZERO since we had to wrap around.
|
|
cl_assert_equal_b(shared_prf_storage_get_valid_page_number(), 0);
|
|
}
|
|
|
|
// Sets the getting started field, then corrupts the ble_pairing_data crc
|
|
// This tests that when setting a value, all fields in the struct must be valid.
|
|
void test_shared_prf_storage_v3__handle_currupt_field_during_setting(void) {
|
|
bool GETTING_STARTED_COMPLETE = true;
|
|
shared_prf_storage_set_getting_started_complete(GETTING_STARTED_COMPLETE);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
|
|
SharedPRFData data;
|
|
flash_read_bytes((uint8_t *)&data,
|
|
SPRF_PAGE_FLASH_OFFSET(shared_prf_storage_get_valid_page_number()),
|
|
sizeof(data));
|
|
cl_assert(data.getting_started.crc != 0xFFFFFFFF);
|
|
|
|
uint32_t new_crc = 0;
|
|
flash_write_bytes((uint8_t *)&new_crc,
|
|
SPRF_PAGE_FLASH_OFFSET(shared_prf_storage_get_valid_page_number())
|
|
+ offsetof(SharedPRFData, ble_pairing_data)
|
|
+ offsetof(SprfBlePairingData, crc),
|
|
sizeof(new_crc));
|
|
|
|
// Confirm new CRC was written
|
|
flash_read_bytes((uint8_t *)&data,
|
|
SPRF_PAGE_FLASH_OFFSET(shared_prf_storage_get_valid_page_number()),
|
|
sizeof(data));
|
|
cl_assert_equal_i(data.ble_pairing_data.crc, new_crc);
|
|
|
|
// Should be corrupt, so after a 'set', the page number should increment even though we are
|
|
// setting the same value
|
|
shared_prf_storage_set_getting_started_complete(true);
|
|
// Should have moved to the next page
|
|
cl_assert_equal_b(shared_prf_storage_get_valid_page_number(), 1);
|
|
}
|
|
|
|
// Test that when we write the ble_data and the ble_name separately, a page rewrite isn't triggered
|
|
void test_shared_prf_storage_v3__write_ble_data_and_ble_name_separately(void) {
|
|
shared_prf_storage_store_ble_pairing_data(&PAIRING_INFO, NULL,
|
|
true /* requires_address_pinning */,
|
|
true /* auto_accept_re_pairing */);
|
|
shared_prf_storage_store_ble_pairing_data(&PAIRING_INFO, DEVICE_NAME,
|
|
true /* requires_address_pinning */,
|
|
true /* auto_accept_re_pairing */);
|
|
// confirm we wrote to the same "Page"
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
}
|
|
|
|
// Test that when deleting the ble_data, both the data and name are deleted.
|
|
// Test that when rewriting the ble_data, the same page is used (since they were previously
|
|
// marked with 0xFF's
|
|
void test_shared_prf_storage_v3__write_ble_data_name_delete_rewrite(void) {
|
|
shared_prf_storage_store_ble_pairing_data(&PAIRING_INFO, DEVICE_NAME,
|
|
true /* requires_address_pinning */,
|
|
true /* auto_accept_re_pairing */);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
shared_prf_storage_erase_ble_pairing_data();
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 2);
|
|
|
|
char device_name_out[BT_DEVICE_NAME_BUFFER_SIZE];
|
|
SMPairingInfo pairing_info_out;
|
|
const bool rv = shared_prf_storage_get_ble_pairing_data(&pairing_info_out, device_name_out, NULL,
|
|
NULL);
|
|
cl_assert_equal_b(rv, false);
|
|
|
|
shared_prf_storage_store_ble_pairing_data(&PAIRING_INFO, DEVICE_NAME,
|
|
true /* requires_address_pinning */,
|
|
true /* auto_accept_re_pairing */);
|
|
// It should detect the fields were already blank in the current page so the index should not
|
|
// increment
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 2);
|
|
}
|
|
|
|
// Test that if we try to write the same data, the system does not force a rewrite of the page
|
|
void test_shared_prf_storage_v3__write_repeated_data_same_page(void) {
|
|
shared_prf_storage_set_getting_started_complete(false);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
shared_prf_storage_set_getting_started_complete(false);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 0);
|
|
shared_prf_storage_set_getting_started_complete(true);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 1);
|
|
shared_prf_storage_set_getting_started_complete(true);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 1);
|
|
shared_prf_storage_set_getting_started_complete(false);
|
|
cl_assert_equal_i(shared_prf_storage_get_valid_page_number(), 2);
|
|
}
|