test/flash_tlv: implement btstack_link_key_db_tlv based on btstack_tlv

This commit is contained in:
Matthias Ringwald 2017-06-04 23:09:58 +02:00
parent 6fed001717
commit 25023b006d
9 changed files with 486 additions and 4 deletions

View File

@ -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

2
test/flash_tlv/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
tlv_test
*.pklg

View File

@ -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)

View File

@ -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 <string.h>
#include <stdlib.h>
#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;i<NVM_NUM_LINK_KEYS;i++){
link_key_nvm_t entry;
uint32_t tag = btstack_link_key_db_tag_for_index(i);
int size = self->btstack_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;i<NVM_NUM_LINK_KEYS;i++){
link_key_nvm_t entry;
uint32_t tag = btstack_link_key_db_tag_for_index(i);
int size = self->btstack_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;i<NVM_NUM_LINK_KEYS;i++){
link_key_nvm_t entry;
uint32_t tag = btstack_link_key_db_tag_for_index(i);
int size = self->btstack_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;
}

View File

@ -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

View File

@ -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;

View File

@ -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 <stdint.h>
#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

View File

@ -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 <stdint.h>
#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

View File

@ -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; i<size; i++){
if (expected[i] != actual[i]) {
printf("offset %u wrong\n", i);
printf("expected: "); printf_hexdump(expected, size);
printf("actual: "); printf_hexdump(actual, size);
}
BYTES_EQUAL(expected[i], actual[i]);
}
}
TEST_GROUP(HAL_FLASH_SECTOR){
const hal_flash_sector_t * hal_flash_sector_impl;
hal_flash_sector_memory_t hal_flash_sector_context;
@ -126,6 +143,25 @@ TEST(BSTACK_TLV, TestWriteWriteRead){
CHECK_EQUAL(buffer, data);
}
TEST(BSTACK_TLV, TestWriteABARead){
btstack_tlv_impl = btstack_tlv_flash_sector_init_instance(&btstack_tlv_context, hal_flash_sector_impl, &hal_flash_sector_context);
uint32_t tag_a = 'aaaa';
uint32_t tag_b = 'bbbb';
uint8_t data = 7;
uint8_t buffer = data;
btstack_tlv_impl->store_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);