1e25b4a2fSMatthias Ringwald /*
2e25b4a2fSMatthias Ringwald * Copyright (C) 2016 BlueKitchen GmbH
3e25b4a2fSMatthias Ringwald *
4e25b4a2fSMatthias Ringwald * Redistribution and use in source and binary forms, with or without
5e25b4a2fSMatthias Ringwald * modification, are permitted provided that the following conditions
6e25b4a2fSMatthias Ringwald * are met:
7e25b4a2fSMatthias Ringwald *
8e25b4a2fSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
9e25b4a2fSMatthias Ringwald * notice, this list of conditions and the following disclaimer.
10e25b4a2fSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
11e25b4a2fSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
12e25b4a2fSMatthias Ringwald * documentation and/or other materials provided with the distribution.
13e25b4a2fSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
14e25b4a2fSMatthias Ringwald * contributors may be used to endorse or promote products derived
15e25b4a2fSMatthias Ringwald * from this software without specific prior written permission.
16e25b4a2fSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
17e25b4a2fSMatthias Ringwald * personal benefit and not for any commercial purpose or for
18e25b4a2fSMatthias Ringwald * monetary gain.
19e25b4a2fSMatthias Ringwald *
20e25b4a2fSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21e25b4a2fSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22e25b4a2fSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*2fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*2fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25e25b4a2fSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26e25b4a2fSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27e25b4a2fSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28e25b4a2fSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29e25b4a2fSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30e25b4a2fSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31e25b4a2fSMatthias Ringwald * SUCH DAMAGE.
32e25b4a2fSMatthias Ringwald *
33e25b4a2fSMatthias Ringwald * Please inquire about commercial licensing options at
34e25b4a2fSMatthias Ringwald * [email protected]
35e25b4a2fSMatthias Ringwald *
36e25b4a2fSMatthias Ringwald */
37e25b4a2fSMatthias Ringwald
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_link_key_db_wiced_dct.c"
39e25b4a2fSMatthias Ringwald
40e25b4a2fSMatthias Ringwald /*
41e25b4a2fSMatthias Ringwald * btstack_link_key_db_wiced_dct.c
42e25b4a2fSMatthias Ringwald *
43e25b4a2fSMatthias Ringwald * Persistent Link Key implemenetation for WICED using DCT mechanism
44e25b4a2fSMatthias Ringwald */
45e25b4a2fSMatthias Ringwald
46e25b4a2fSMatthias Ringwald #include "classic/btstack_link_key_db.h"
47e25b4a2fSMatthias Ringwald
48e25b4a2fSMatthias Ringwald #include "stdint.h"
49e25b4a2fSMatthias Ringwald #include "string.h"
50e25b4a2fSMatthias Ringwald #include "btstack_debug.h"
51e25b4a2fSMatthias Ringwald #include "btstack_util.h"
52e25b4a2fSMatthias Ringwald
53e25b4a2fSMatthias Ringwald #include "wiced.h"
54e25b4a2fSMatthias Ringwald
55e25b4a2fSMatthias Ringwald // Link Key Magic
56e25b4a2fSMatthias Ringwald #define LINK_KEY_MAGIC ((uint32_t) 'B' << 24 | 'T' << 16 | 'L' << 8 | 'K')
57e25b4a2fSMatthias Ringwald
58e25b4a2fSMatthias Ringwald typedef struct link_key_nvm {
59e25b4a2fSMatthias Ringwald uint32_t magic;
60e25b4a2fSMatthias Ringwald uint32_t seq_nr; // used for "last recently stored" eviction strategy
61e25b4a2fSMatthias Ringwald bd_addr_t bd_addr;
62e25b4a2fSMatthias Ringwald link_key_t link_key;
63e25b4a2fSMatthias Ringwald link_key_type_t link_key_type;
64e25b4a2fSMatthias Ringwald } link_key_nvm_t;
65e25b4a2fSMatthias Ringwald
66e25b4a2fSMatthias Ringwald static char link_key_to_str_buffer[LINK_KEY_STR_LEN+1]; // 11223344556677889900112233445566\0
link_key_to_str(link_key_t link_key)67e25b4a2fSMatthias Ringwald static char *link_key_to_str(link_key_t link_key){
68e25b4a2fSMatthias Ringwald char * p = link_key_to_str_buffer;
69e25b4a2fSMatthias Ringwald int i;
70e25b4a2fSMatthias Ringwald for (i = 0; i < LINK_KEY_LEN ; i++) {
71e25b4a2fSMatthias Ringwald *p++ = char_for_nibble((link_key[i] >> 4) & 0x0F);
72e25b4a2fSMatthias Ringwald *p++ = char_for_nibble((link_key[i] >> 0) & 0x0F);
73e25b4a2fSMatthias Ringwald }
74e25b4a2fSMatthias Ringwald *p = 0;
75e25b4a2fSMatthias Ringwald return (char *) link_key_to_str_buffer;
76e25b4a2fSMatthias Ringwald }
77e25b4a2fSMatthias Ringwald
link_key_db_init(void)78e25b4a2fSMatthias Ringwald static void link_key_db_init(void){
79e25b4a2fSMatthias Ringwald log_info("Link Key DB initialized for DCT\n");
80e25b4a2fSMatthias Ringwald }
81e25b4a2fSMatthias Ringwald
link_key_db_close(void)82e25b4a2fSMatthias Ringwald static void link_key_db_close(void){
83e25b4a2fSMatthias Ringwald }
84e25b4a2fSMatthias Ringwald
85e25b4a2fSMatthias Ringwald // @return valid
link_key_read(int index,link_key_nvm_t * out_entry)86e25b4a2fSMatthias Ringwald static int link_key_read(int index, link_key_nvm_t * out_entry){
87e25b4a2fSMatthias Ringwald
88e25b4a2fSMatthias Ringwald // calculate address
89e25b4a2fSMatthias Ringwald uint32_t address = index * sizeof(link_key_nvm_t);
90e25b4a2fSMatthias Ringwald
91e25b4a2fSMatthias Ringwald // read lock
92e25b4a2fSMatthias Ringwald link_key_nvm_t * entry;
93e25b4a2fSMatthias Ringwald wiced_dct_read_lock((void*) &entry, WICED_FALSE, DCT_APP_SECTION, address, sizeof(link_key_nvm_t));
94e25b4a2fSMatthias Ringwald
95e25b4a2fSMatthias Ringwald if (entry->magic == LINK_KEY_MAGIC){
96e25b4a2fSMatthias Ringwald memcpy(out_entry, entry, sizeof(link_key_nvm_t));
97e25b4a2fSMatthias Ringwald } else {
98e25b4a2fSMatthias Ringwald memset(out_entry, 0, sizeof(link_key_nvm_t));
99e25b4a2fSMatthias Ringwald }
100e25b4a2fSMatthias Ringwald
101e25b4a2fSMatthias Ringwald // read unlock
102e25b4a2fSMatthias Ringwald wiced_dct_read_unlock((void*) entry, WICED_FALSE);
103e25b4a2fSMatthias Ringwald
104e25b4a2fSMatthias Ringwald return out_entry->magic == LINK_KEY_MAGIC;
105e25b4a2fSMatthias Ringwald }
106e25b4a2fSMatthias Ringwald
link_key_write(int index,link_key_nvm_t * entry)107e25b4a2fSMatthias Ringwald static void link_key_write(int index, link_key_nvm_t * entry){
108e25b4a2fSMatthias Ringwald // calculate address
109e25b4a2fSMatthias Ringwald uint32_t address = index * sizeof(link_key_nvm_t);
110e25b4a2fSMatthias Ringwald // write block
111e25b4a2fSMatthias Ringwald wiced_dct_write((void*)entry, DCT_APP_SECTION, address, sizeof(link_key_nvm_t));
112e25b4a2fSMatthias Ringwald }
113e25b4a2fSMatthias Ringwald
114e25b4a2fSMatthias Ringwald // returns entry index or -1
link_key_find_entry_for_address(bd_addr_t address)115e25b4a2fSMatthias Ringwald static int link_key_find_entry_for_address(bd_addr_t address){
116e25b4a2fSMatthias Ringwald link_key_nvm_t item;
117e25b4a2fSMatthias Ringwald int i;
118e25b4a2fSMatthias Ringwald for (i=0;i<NVM_NUM_LINK_KEYS;i++){
119e25b4a2fSMatthias Ringwald link_key_read(i, &item);
120e25b4a2fSMatthias Ringwald if (item.magic != LINK_KEY_MAGIC) continue;
121e25b4a2fSMatthias Ringwald if (memcmp(address, &item.bd_addr, 6) != 0) continue;
122e25b4a2fSMatthias Ringwald return i;
123e25b4a2fSMatthias Ringwald }
124e25b4a2fSMatthias Ringwald return -1;
125e25b4a2fSMatthias Ringwald }
126e25b4a2fSMatthias Ringwald
127e25b4a2fSMatthias Ringwald // returns index
link_key_find_free_entry(void)128e25b4a2fSMatthias Ringwald static int link_key_find_free_entry(void){
129e25b4a2fSMatthias Ringwald link_key_nvm_t item;
130e25b4a2fSMatthias Ringwald int i;
131e25b4a2fSMatthias Ringwald uint32_t seq_nr = 0;
132e25b4a2fSMatthias Ringwald int lowest_index = -1;
133e25b4a2fSMatthias Ringwald for (i=0;i<NVM_NUM_LINK_KEYS;i++){
134e25b4a2fSMatthias Ringwald link_key_read(i, &item);
135e25b4a2fSMatthias Ringwald if (item.magic != LINK_KEY_MAGIC) return i;
136e25b4a2fSMatthias Ringwald if ((lowest_index < 0) || (item.seq_nr < seq_nr)){
137e25b4a2fSMatthias Ringwald lowest_index = i;
138e25b4a2fSMatthias Ringwald seq_nr= item.seq_nr;
139e25b4a2fSMatthias Ringwald }
140e25b4a2fSMatthias Ringwald }
141e25b4a2fSMatthias Ringwald return lowest_index;
142e25b4a2fSMatthias Ringwald }
143e25b4a2fSMatthias Ringwald
link_key_highest_seq_nr(void)144e25b4a2fSMatthias Ringwald static uint32_t link_key_highest_seq_nr(void){
145e25b4a2fSMatthias Ringwald link_key_nvm_t item;
146e25b4a2fSMatthias Ringwald int i;
147e25b4a2fSMatthias Ringwald uint32_t seq_nr = 0;
148e25b4a2fSMatthias Ringwald for (i=0;i<NVM_NUM_LINK_KEYS;i++){
149e25b4a2fSMatthias Ringwald link_key_read(i, &item);
150e25b4a2fSMatthias Ringwald if (item.magic != LINK_KEY_MAGIC) continue;
151e25b4a2fSMatthias Ringwald if (item.seq_nr < seq_nr) continue;
152e25b4a2fSMatthias Ringwald seq_nr = item.seq_nr;
153e25b4a2fSMatthias Ringwald }
154e25b4a2fSMatthias Ringwald return seq_nr;
155e25b4a2fSMatthias Ringwald }
156e25b4a2fSMatthias Ringwald
157e25b4a2fSMatthias Ringwald // returns 1 if found
link_key_db_get_link_key(bd_addr_t bd_addr,link_key_t link_key,link_key_type_t * link_key_type)158e25b4a2fSMatthias Ringwald static int link_key_db_get_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * link_key_type) {
159e25b4a2fSMatthias Ringwald int index = link_key_find_entry_for_address(bd_addr);
160e25b4a2fSMatthias Ringwald if (index < 0) {
161e25b4a2fSMatthias Ringwald log_info("link_key_db_get_link_key for %s -> not found\n", bd_addr_to_str(bd_addr));
162e25b4a2fSMatthias Ringwald return 0;
163e25b4a2fSMatthias Ringwald }
164e25b4a2fSMatthias Ringwald link_key_nvm_t item;
165e25b4a2fSMatthias Ringwald link_key_read(index, &item);
166e25b4a2fSMatthias Ringwald memcpy(link_key, item.link_key, LINK_KEY_LEN);
167e25b4a2fSMatthias Ringwald if (link_key_type) {
168e25b4a2fSMatthias Ringwald *link_key_type = item.link_key_type;
169e25b4a2fSMatthias Ringwald }
170e25b4a2fSMatthias Ringwald log_info("link_key_db_get_link_key for %s -> found %s\n", bd_addr_to_str(bd_addr), link_key_to_str(link_key));
171e25b4a2fSMatthias Ringwald return 1;
172e25b4a2fSMatthias Ringwald }
173e25b4a2fSMatthias Ringwald
link_key_db_delete_link_key(bd_addr_t bd_addr)174e25b4a2fSMatthias Ringwald static void link_key_db_delete_link_key(bd_addr_t bd_addr){
175e25b4a2fSMatthias Ringwald int index = link_key_find_entry_for_address(bd_addr);
176e25b4a2fSMatthias Ringwald if (index < 0) return;
177e25b4a2fSMatthias Ringwald
178e25b4a2fSMatthias Ringwald link_key_nvm_t item;
179e25b4a2fSMatthias Ringwald memset(&item, 0, sizeof(item));
180e25b4a2fSMatthias Ringwald link_key_write(index, &item);
181e25b4a2fSMatthias Ringwald }
182e25b4a2fSMatthias Ringwald
183e25b4a2fSMatthias Ringwald
link_key_db_put_link_key(bd_addr_t bd_addr,link_key_t link_key,link_key_type_t link_key_type)184e25b4a2fSMatthias Ringwald static void link_key_db_put_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t link_key_type){
185e25b4a2fSMatthias Ringwald // check for existing record
186e25b4a2fSMatthias Ringwald int index = link_key_find_entry_for_address(bd_addr);
187e25b4a2fSMatthias Ringwald
188e25b4a2fSMatthias Ringwald // if not found, use new entry
189e25b4a2fSMatthias Ringwald if (index < 0) {
190e25b4a2fSMatthias Ringwald index = link_key_find_free_entry();
191e25b4a2fSMatthias Ringwald }
192e25b4a2fSMatthias Ringwald
193e25b4a2fSMatthias Ringwald log_info("link_key_db_put_link_key for %s - key %s - at index %u\n", bd_addr_to_str(bd_addr), link_key_to_str(link_key), index);
194e25b4a2fSMatthias Ringwald
195e25b4a2fSMatthias Ringwald link_key_nvm_t item;
196e25b4a2fSMatthias Ringwald item.magic = LINK_KEY_MAGIC;
197e25b4a2fSMatthias Ringwald item.seq_nr = link_key_highest_seq_nr() + 1;
198e25b4a2fSMatthias Ringwald memcpy(item.bd_addr, bd_addr, sizeof(bd_addr_t));
199e25b4a2fSMatthias Ringwald memcpy(item.link_key, link_key, LINK_KEY_LEN);
200e25b4a2fSMatthias Ringwald item.link_key_type = link_key_type;
201e25b4a2fSMatthias Ringwald link_key_write(index, &item);
202e25b4a2fSMatthias Ringwald }
203e25b4a2fSMatthias Ringwald
link_key_db_set_local_bd_addr(bd_addr_t bd_addr)204e25b4a2fSMatthias Ringwald static void link_key_db_set_local_bd_addr(bd_addr_t bd_addr){
205e25b4a2fSMatthias Ringwald }
206e25b4a2fSMatthias Ringwald
link_key_db_tlv_iterator_init(btstack_link_key_iterator_t * it)207c4023defSMatthias Ringwald static int link_key_db_tlv_iterator_init(btstack_link_key_iterator_t * it){
208c4023defSMatthias Ringwald it->context = (void*) 0;
209c4023defSMatthias Ringwald return 1;
210c4023defSMatthias Ringwald }
211c4023defSMatthias Ringwald
link_key_db_tlv_iterator_get_next(btstack_link_key_iterator_t * it,bd_addr_t bd_addr,link_key_t link_key,link_key_type_t * link_key_type)212c4023defSMatthias Ringwald static int link_key_db_tlv_iterator_get_next(btstack_link_key_iterator_t * it, bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * link_key_type){
213c4023defSMatthias Ringwald uintptr_t i = (uintptr_t) it->context;
214c4023defSMatthias Ringwald int found = 0;
215c4023defSMatthias Ringwald while (i<NVM_NUM_LINK_KEYS){
216c4023defSMatthias Ringwald link_key_nvm_t item;
217c4023defSMatthias Ringwald link_key_read(i++, &item);
218c4023defSMatthias Ringwald if (item.magic != LINK_KEY_MAGIC) continue;
219c4023defSMatthias Ringwald
220c4023defSMatthias Ringwald memcpy(bd_addr, item.bd_addr, 6);
221c4023defSMatthias Ringwald memcpy(link_key, item.link_key, 16);
222c4023defSMatthias Ringwald *link_key_type = item.link_key_type;
223c4023defSMatthias Ringwald found = 1;
224c4023defSMatthias Ringwald break;
225c4023defSMatthias Ringwald }
226c4023defSMatthias Ringwald it->context = (void*) i;
227c4023defSMatthias Ringwald return found;
228c4023defSMatthias Ringwald }
229c4023defSMatthias Ringwald
link_key_db_tlv_iterator_done(btstack_link_key_iterator_t * it)230c4023defSMatthias Ringwald static void link_key_db_tlv_iterator_done(btstack_link_key_iterator_t * it){
231c4023defSMatthias Ringwald UNUSED(it);
232c4023defSMatthias Ringwald }
233c4023defSMatthias Ringwald
234e25b4a2fSMatthias Ringwald const btstack_link_key_db_t btstack_link_key_db_wiced_dct = {
235e25b4a2fSMatthias Ringwald link_key_db_init,
236e25b4a2fSMatthias Ringwald link_key_db_set_local_bd_addr,
237e25b4a2fSMatthias Ringwald link_key_db_close,
238e25b4a2fSMatthias Ringwald link_key_db_get_link_key,
239e25b4a2fSMatthias Ringwald link_key_db_put_link_key,
240e25b4a2fSMatthias Ringwald link_key_db_delete_link_key,
241c4023defSMatthias Ringwald link_key_db_tlv_iterator_init,
242c4023defSMatthias Ringwald link_key_db_tlv_iterator_get_next,
243c4023defSMatthias Ringwald link_key_db_tlv_iterator_done,
244e25b4a2fSMatthias Ringwald };
245e25b4a2fSMatthias Ringwald
246e25b4a2fSMatthias Ringwald // custom function
btstack_link_key_db_wiced_dct_delete_all(void)247e25b4a2fSMatthias Ringwald void btstack_link_key_db_wiced_dct_delete_all(void){
248e25b4a2fSMatthias Ringwald int i;
249e25b4a2fSMatthias Ringwald link_key_nvm_t entry;
250e25b4a2fSMatthias Ringwald memset(&entry, 0, sizeof(link_key_nvm_t));
251e25b4a2fSMatthias Ringwald for (i=0;i<NVM_NUM_LINK_KEYS;i++){
252e25b4a2fSMatthias Ringwald link_key_write(i, &entry);
253e25b4a2fSMatthias Ringwald }
254e25b4a2fSMatthias Ringwald }
255e25b4a2fSMatthias Ringwald
btstack_link_key_db_wiced_dct_get_storage_size(void)25685447f54SMatthias Ringwald int btstack_link_key_db_wiced_dct_get_storage_size(void){
25785447f54SMatthias Ringwald return NVM_NUM_LINK_KEYS * sizeof(link_key_nvm_t);
25885447f54SMatthias Ringwald }
25985447f54SMatthias Ringwald
btstack_link_key_db_wiced_dct_instance(void)260e25b4a2fSMatthias Ringwald const btstack_link_key_db_t * btstack_link_key_db_wiced_dct_instance(void){
261e25b4a2fSMatthias Ringwald return &btstack_link_key_db_wiced_dct;
262e25b4a2fSMatthias Ringwald }
263