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