diff --git a/test/btstack_config.h b/test/btstack_config.h index f0a9c805a..d2f87a180 100644 --- a/test/btstack_config.h +++ b/test/btstack_config.h @@ -29,4 +29,6 @@ #define HCI_INCOMING_PRE_BUFFER_SIZE 4 #define MAX_NR_LE_DEVICE_DB_ENTRIES 4 +#define NVM_NUM_LINK_KEYS 2 + #endif diff --git a/test/flash_tlv/.gitignore b/test/flash_tlv/.gitignore new file mode 100644 index 000000000..24855859c --- /dev/null +++ b/test/flash_tlv/.gitignore @@ -0,0 +1,2 @@ +tlv_test +*.pklg diff --git a/test/flash_tlv/Makefile b/test/flash_tlv/Makefile index c29b9ba99..5a9579a5d 100644 --- a/test/flash_tlv/Makefile +++ b/test/flash_tlv/Makefile @@ -5,10 +5,11 @@ POSIX_ROOT= ${BTSTACK_ROOT}/platform/posix CPPUTEST_HOME = ${BTSTACK_ROOT}/test/cpputest COMMON = \ - hal_flash_sector_memory.c \ + btstack_link_key_db_tlv.c \ btstack_tlv_flash_sector.c \ - hci_dump.c \ btstack_util.c \ + hal_flash_sector_memory.c \ + hci_dump.c \ COMMON_OBJ = $(COMMON:.c=.o) diff --git a/test/flash_tlv/btstack_link_key_db_tlv.c b/test/flash_tlv/btstack_link_key_db_tlv.c new file mode 100644 index 000000000..958cf9d68 --- /dev/null +++ b/test/flash_tlv/btstack_link_key_db_tlv.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +#include +#include + +#include "btstack_link_key_db_tlv.h" + +#include "btstack_debug.h" +#include "btstack_util.h" +#include "classic/core.h" + +// NVM_NUM_LINK_KEYS defines number of stored link keys + +typedef struct { + const btstack_tlv_t * btstack_tlv_impl; + void * btstack_tlv_context; +} btstack_link_key_db_tlv_h; + +typedef struct link_key_nvm { + uint32_t seq_nr; // used for "least recently stored" eviction strategy + bd_addr_t bd_addr; + link_key_t link_key; + link_key_type_t link_key_type; +} link_key_nvm_t; // sizeof(link_key_nvm_t) = 27 bytes + +static btstack_link_key_db_tlv_h singleton; +static btstack_link_key_db_tlv_h * self = &singleton; + +static uint32_t btstack_link_key_db_tag_for_index(uint8_t index){ + return ('B' << 24) | ('T' << 16) | ('L' << 8) | index; +} + +// Device info +static void btstack_link_key_db_tlv_open(void){ +} + +static void btstack_link_key_db_tlv_set_bd_addr(bd_addr_t bd_addr){ + (void)bd_addr; +} + +static void btstack_link_key_db_tlv_close(void){ +} + +static int btstack_link_key_db_tlv_get_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * link_key_type) { + int i; + for (i=0;ibtstack_tlv_impl->get_tag(self->btstack_tlv_context, tag, (uint8_t*) &entry, sizeof(entry)); + if (size == 0) continue; + log_info("tag %x, addr %s", tag, bd_addr_to_str(entry.bd_addr)); + if (memcmp(bd_addr, entry.bd_addr, 6)) continue; + // found, pass back + memcpy(link_key, entry.link_key, 16); + *link_key_type = entry.link_key_type; + return 1; + } + return 0; +} + +static void btstack_link_key_db_tlv_delete_link_key(bd_addr_t bd_addr){ + int i; + for (i=0;ibtstack_tlv_impl->get_tag(self->btstack_tlv_context, tag, (uint8_t*) &entry, sizeof(entry)); + if (size == 0) continue; + if (memcmp(bd_addr, entry.bd_addr, 6)) continue; + // found, delete tag + self->btstack_tlv_impl->delete_tag(self->btstack_tlv_context, tag); + break; + } +} + +static void btstack_link_key_db_tlv_put_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t link_key_type){ + int i; + uint32_t highest_seq_nr = 0; + uint32_t lowest_seq_nr = 0; + uint32_t tag_for_lowest_seq_nr = 0; + uint32_t tag_for_addr = 0; + uint32_t tag_for_empty = 0; + + for (i=0;ibtstack_tlv_impl->get_tag(self->btstack_tlv_context, tag, (uint8_t*) &entry, sizeof(entry)); + // empty/deleted tag + if (size == 0) { + tag_for_empty = tag; + continue; + } + // found addr? + if (memcmp(bd_addr, entry.bd_addr, 6) == 0){ + tag_for_addr = tag; + } + // update highest seq nr + if (entry.seq_nr > highest_seq_nr){ + highest_seq_nr = entry.seq_nr; + } + // find entry with lowest seq nr + if ((tag_for_lowest_seq_nr == 0) || (entry.seq_nr < lowest_seq_nr)){ + tag_for_lowest_seq_nr = tag; + lowest_seq_nr = entry.seq_nr; + } + } + + log_info("tag_for_addr %x, tag_for_empy %x, tag_for_lowest_seq_nr %x", tag_for_addr, tag_for_empty, tag_for_lowest_seq_nr); + + uint32_t tag_to_use = 0; + if (tag_for_addr){ + tag_to_use = tag_for_addr; + } else if (tag_for_empty){ + tag_to_use = tag_for_empty; + } else if (tag_for_lowest_seq_nr){ + tag_to_use = tag_for_lowest_seq_nr; + } else { + // should not happen + return; + } + + log_info("store with tag %x", tag_to_use); + + link_key_nvm_t entry; + + memcpy(entry.bd_addr, bd_addr, 6); + memcpy(entry.link_key, link_key, 16); + entry.link_key_type = link_key_type; + entry.seq_nr = highest_seq_nr + 1; + + self->btstack_tlv_impl->store_tag(self->btstack_tlv_context, tag_to_use, (uint8_t*) &entry, sizeof(entry)); +} + +const btstack_link_key_db_t btstack_link_key_db_tlv = { + btstack_link_key_db_tlv_open, + btstack_link_key_db_tlv_set_bd_addr, + btstack_link_key_db_tlv_close, + btstack_link_key_db_tlv_get_link_key, + btstack_link_key_db_tlv_put_link_key, + btstack_link_key_db_tlv_delete_link_key, +}; + +const btstack_link_key_db_t * btstack_link_key_db_tlv_get_instance(const btstack_tlv_t * btstack_tlv_impl, void * btstack_tlv_context){ + self->btstack_tlv_impl = btstack_tlv_impl; + self->btstack_tlv_context = btstack_tlv_context; + return &btstack_link_key_db_tlv; +} + + diff --git a/test/flash_tlv/btstack_link_key_db_tlv.h b/test/flash_tlv/btstack_link_key_db_tlv.h new file mode 100644 index 000000000..0e08c3215 --- /dev/null +++ b/test/flash_tlv/btstack_link_key_db_tlv.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/** + * interface to provide link key storage via BTstack's TLV storage + */ + +#ifndef __BTSTACK_LINK_KEY_DB_TLV_H +#define __BTSTACK_LINK_KEY_DB_TLV_H + +#include "btstack_tlv.h" +#include "classic/btstack_link_key_db.h" + +#if defined __cplusplus +extern "C" { +#endif + +/* API_START */ + +/** + * Init Link Key DB using TLV + * @param btstack_tlv_impl of btstack_tlv interface + * @Param btstack_tlv_context of btstack_tlv_interface + */ +const btstack_link_key_db_t * btstack_link_key_db_tlv_get_instance(const btstack_tlv_t * btstack_tlv_impl, void * btstack_tlv_context); + +/* API_END */ + +#if defined __cplusplus +} +#endif + +#endif // __BTSTACK_LINK_KEY_DB_TLV_H diff --git a/test/flash_tlv/btstack_tlv_flash_sector.c b/test/flash_tlv/btstack_tlv_flash_sector.c index 317e9d1d7..94a9b890a 100644 --- a/test/flash_tlv/btstack_tlv_flash_sector.c +++ b/test/flash_tlv/btstack_tlv_flash_sector.c @@ -74,11 +74,16 @@ static void btstack_tlv_flash_sector_iterator_init(btstack_tlv_flash_sector_t * static int btstack_tlv_flash_sector_iterator_has_next(btstack_tlv_flash_sector_t * self, tlv_iterator_t * it){ if (it->tag == 0xffffffff) return 0; - return it->offset + 8 + it->len < self->hal_flash_sector_impl->get_size(self->hal_flash_sector_context); + return 1; } static void tlv_iterator_fetch_next(btstack_tlv_flash_sector_t * self, tlv_iterator_t * it){ it->offset += 8 + it->len; + if (it->offset >= self->hal_flash_sector_impl->get_size(self->hal_flash_sector_context)) { + it->tag = 0xffffffff; + it->len = 0; + return; + } btstack_tlv_flash_sector_iterator_fetch_tag_len(self, it); } @@ -190,6 +195,7 @@ static int btstack_tlv_flash_sector_get_tag(void * context, uint32_t tag, uint8_ tlv_iterator_t it; btstack_tlv_flash_sector_iterator_init(self, &it, self->current_bank); while (btstack_tlv_flash_sector_iterator_has_next(self, &it)){ + log_info("Offset %u, tag %x", it.offset, it.tag); if (it.tag == tag){ log_info("Found tag '%x' at position %u", tag, it.offset); tag_index = it.offset; diff --git a/test/flash_tlv/btstack_tlv_flash_sector.h b/test/flash_tlv/btstack_tlv_flash_sector.h new file mode 100644 index 000000000..e9a105292 --- /dev/null +++ b/test/flash_tlv/btstack_tlv_flash_sector.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * btstack_tlv_flash_sector.h + * + * Implementation for BTstack's Tag Value Length Persistent Storage implementations + * using hal_flash_sector storage + */ + +#ifndef __BTSTACK_TLV_FLASH_SECTOR_H +#define __BTSTACK_TLV_FLASH_SECTOR_H + +#include +#include "btstack_tlv.h" + +#if defined __cplusplus +extern "C" { +#endif + +typedef struct { + const hal_flash_sector_t * hal_flash_sector_impl; + void * hal_flash_sector_context; + int current_bank; + int write_offset; +} btstack_tlv_flash_sector_t; + +/** + * Init Tag Length Value Store + * @param context btstack_tlv_flash_sector_t + * @param hal_flash_sector_impl of hal_flash_sector interface + * @Param hal_flash_sector_context of hal_flash_sector_interface + */ +const btstack_tlv_t * btstack_tlv_flash_sector_init_instance(btstack_tlv_flash_sector_t * context, const hal_flash_sector_t * hal_flash_sector_impl, void * hal_flash_sector_context); + +#if defined __cplusplus +} +#endif +#endif // __BTSTACK_TLV_FLASH_SECTOR_H diff --git a/test/flash_tlv/btstack_link_key_db_flash_sector.c b/test/flash_tlv/hal_flash_sector_memory.h similarity index 67% rename from test/flash_tlv/btstack_link_key_db_flash_sector.c rename to test/flash_tlv/hal_flash_sector_memory.h index 4e01a87f1..1a6affdab 100644 --- a/test/flash_tlv/btstack_link_key_db_flash_sector.c +++ b/test/flash_tlv/hal_flash_sector_memory.h @@ -29,5 +29,40 @@ * */ -#include "btstack_flash_sector.h" +/* + * hal_flash_sector.h + * + * HAL abstraction for Flash memory that can be written anywhere + * after being erased implemented with memory + */ +#ifndef __HAL_FLASH_SECTOR_MEMORY_H +#define __HAL_FLASH_SECTOR_MEMORY_H + +#include +#include "hal_flash_sector.h" + +#if defined __cplusplus +extern "C" { +#endif + +// private +typedef struct { + uint32_t bank_size; + uint8_t * banks[2]; +} hal_flash_sector_memory_t; + +// public + +/** + * Init instance + * @param context hal_flash_sector_memory_t + * @param storage to use + * @param size of storage + */ +const hal_flash_sector_t * hal_flash_sector_memory_init_instance(hal_flash_sector_memory_t * context, uint8_t * storage, uint32_t storage_size); + +#if defined __cplusplus +} +#endif +#endif // __HAL_FLASH_SECTOR_MEMORY_H diff --git a/test/flash_tlv/tlv_test.c b/test/flash_tlv/tlv_test.c index fa58064c8..813b98108 100644 --- a/test/flash_tlv/tlv_test.c +++ b/test/flash_tlv/tlv_test.c @@ -7,10 +7,27 @@ #include "btstack_tlv.h" #include "btstack_tlv_flash_sector.h" #include "hci_dump.h" +#include "classic/btstack_link_key_db.h" +#include "btstack_link_key_db_tlv.h" +#include "btstack_util.h" +#include "btstack_config.h" +#include "btstack_debug.h" #define HAL_FLASH_SECTOR_MEMORY_STORAGE_SIZE 256 static uint8_t hal_flash_sector_memory_storage[HAL_FLASH_SECTOR_MEMORY_STORAGE_SIZE]; +static void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){ + int i; + for (i=0; istore_tag(&btstack_tlv_context, tag_a, &buffer, 1); + data++; + buffer = data; + btstack_tlv_impl->store_tag(&btstack_tlv_context, tag_b, &buffer, 1); + data++; + buffer = data; + btstack_tlv_impl->store_tag(&btstack_tlv_context, tag_a, &buffer, 1); + int size = btstack_tlv_impl->get_tag(&btstack_tlv_context, tag_a, NULL, 0); + CHECK_EQUAL(size, 1); + btstack_tlv_impl->get_tag(&btstack_tlv_context, tag_a, &buffer, 1); + CHECK_EQUAL(buffer, data); +} + TEST(BSTACK_TLV, TestWriteDeleteRead){ btstack_tlv_impl = btstack_tlv_flash_sector_init_instance(&btstack_tlv_context, hal_flash_sector_impl, &hal_flash_sector_context); uint32_t tag = 'abcd'; @@ -191,6 +227,89 @@ TEST(BSTACK_TLV, TestMigrate2){ CHECK_EQUAL(buffer[0], data2[0]); } +// + +TEST_GROUP(LINK_KEY_DB){ + const hal_flash_sector_t * hal_flash_sector_impl; + hal_flash_sector_memory_t hal_flash_sector_context; + + const btstack_tlv_t * btstack_tlv_impl; + btstack_tlv_flash_sector_t btstack_tlv_context; + + const btstack_link_key_db_t * btstack_link_key_db; + + bd_addr_t addr1, addr2, addr3; + link_key_t link_key1, link_key2; + link_key_type_t link_key_type; + + void setup(void){ + // hal_flash_sector + hal_flash_sector_impl = hal_flash_sector_memory_init_instance(&hal_flash_sector_context, hal_flash_sector_memory_storage, HAL_FLASH_SECTOR_MEMORY_STORAGE_SIZE); + hal_flash_sector_impl->erase(&hal_flash_sector_context, 0); + hal_flash_sector_impl->erase(&hal_flash_sector_context, 1); + // btstack_tlv + btstack_tlv_impl = btstack_tlv_flash_sector_init_instance(&btstack_tlv_context, hal_flash_sector_impl, &hal_flash_sector_context); + // btstack_link_key_db + btstack_link_key_db = btstack_link_key_db_tlv_get_instance(btstack_tlv_impl, &btstack_tlv_context); + + bd_addr_t addr_1 = {0x00, 0x01, 0x02, 0x03, 0x04, 0x01 }; + bd_addr_t addr_2 = {0x00, 0x01, 0x02, 0x03, 0x04, 0x02 }; + bd_addr_t addr_3 = {0x00, 0x01, 0x02, 0x03, 0x04, 0x03 }; + bd_addr_copy(addr1, addr_1); + bd_addr_copy(addr2, addr_2); + bd_addr_copy(addr3, addr_3); + for (int i=0;i<16;i++) { + link_key1[i] = 'a'+i; + link_key2[i] = 'A'+i; + } + link_key_type = COMBINATION_KEY; + } +}; + +TEST(LINK_KEY_DB, SinglePutGetDeleteKey){ + + link_key_t test_link_key; + link_key_type_t test_link_key_type; + + btstack_link_key_db->delete_link_key(addr1); + CHECK(btstack_link_key_db->get_link_key(addr1, test_link_key, &test_link_key_type) == 0); + + btstack_link_key_db->put_link_key(addr1, link_key1, link_key_type); + CHECK(btstack_link_key_db->get_link_key(addr1, test_link_key, &test_link_key_type) == 1); + CHECK_EQUAL_ARRAY(link_key1, test_link_key, 16); + + btstack_link_key_db->delete_link_key(addr1); + CHECK(btstack_link_key_db->get_link_key(addr1, test_link_key, &test_link_key_type) == 0); +} + +TEST(LINK_KEY_DB, UpdateKey){ + link_key_t test_link_key; + link_key_type_t test_link_key_type; + + btstack_link_key_db->put_link_key(addr1, link_key1, link_key_type); + btstack_link_key_db->put_link_key(addr1, link_key2, link_key_type); + CHECK(btstack_link_key_db->get_link_key(addr1, test_link_key, &test_link_key_type) == 1); + CHECK_EQUAL_ARRAY(link_key2, test_link_key, 16); +} + +TEST(LINK_KEY_DB, NumKeys){ + CHECK(NVM_NUM_LINK_KEYS == 2); +} + +TEST(LINK_KEY_DB, KeyReplacement){ + link_key_t test_link_key; + link_key_type_t test_link_key_type; + + btstack_link_key_db->put_link_key(addr1, link_key1, link_key_type); + btstack_link_key_db->put_link_key(addr2, link_key1, link_key_type); + btstack_link_key_db->put_link_key(addr3, link_key1, link_key_type); + + CHECK(btstack_link_key_db->get_link_key(addr3, test_link_key, &test_link_key_type) == 1); + CHECK(btstack_link_key_db->get_link_key(addr2, test_link_key, &test_link_key_type) == 1); + CHECK(btstack_link_key_db->get_link_key(addr1, test_link_key, &test_link_key_type) == 0); + CHECK_EQUAL_ARRAY(link_key1, test_link_key, 16); +} + int main (int argc, const char * argv[]){ hci_dump_open("tlv_test.pklg", HCI_DUMP_PACKETLOGGER); return CommandLineTestRunner::RunAllTests(argc, argv);