xref: /btstack/platform/wiced/le_device_db_wiced_dct.c (revision 2fca4dad957cd7b88f4657ed51e89c12615dda72)
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__ "le_device_db_wiced_dct.c"
39 
40 /*
41  *  le_device_db_wiced_dct.c
42  *
43  *  Persistent LE Device DB implemenetation for WICED using DCT mechanism
44  */
45 
46 #include "stdint.h"
47 #include "string.h"
48 #include "inttypes.h"
49 
50 #include "wiced.h"
51 
52 #include "ble/le_device_db.h"
53 #include "btstack_link_key_db_wiced_dct.h"	// for size of
54 
55 #include "btstack_debug.h"
56 #include "btstack_util.h"
57 
58 // Link Key Magic
59 #define LE_DEVICE_MAGIC ((uint32_t) 'L' << 24 | 'E' << 16 | 'D' << 8 | 'B')
60 
61 typedef struct le_device_nvm {
62 	uint32_t magic;
63 	uint32_t seq_nr;	// used for "last recently stored" eviction strategy
64 
65     // Identification
66     sm_key_t irk;
67     bd_addr_t addr;
68     uint8_t addr_type;
69 
70     // pairing information
71     uint8_t  key_size;
72     uint8_t  authenticated;
73     uint8_t  authorized;
74     uint8_t  secure_connection;
75 
76     sm_key_t ltk;
77 
78     // Stored pairing information allows to re-establish an enncrypted connection
79     // with a peripheral that doesn't have any persistent memory
80     uint16_t ediv;
81     uint8_t  rand[8];
82 
83 } le_device_nvm_t;
84 
85 static uint32_t start_of_le_device_db;
86 
87 // calculate address
le_device_db_address_for_absolute_index(int abolute_index)88 static int le_device_db_address_for_absolute_index(int abolute_index){
89 	return start_of_le_device_db + abolute_index * sizeof(le_device_nvm_t);
90 }
91 
le_device_db_entry_valid(int absolute_index)92 static int le_device_db_entry_valid(int absolute_index){
93 	// read lock
94 	le_device_nvm_t * entry;
95 	wiced_dct_read_lock((void*) &entry, WICED_FALSE, DCT_APP_SECTION, le_device_db_address_for_absolute_index(absolute_index), sizeof(le_device_nvm_t));
96 	int valid = entry->magic == LE_DEVICE_MAGIC;
97 	// read unlock
98 	wiced_dct_read_unlock((void*) entry, WICED_FALSE);
99 	return valid;
100 }
101 
102 // @return valid
le_device_db_entry_read(int absolute_index,le_device_nvm_t * out_entry)103 static int le_device_db_entry_read(int absolute_index, le_device_nvm_t * out_entry){
104 
105 	// read lock
106 	le_device_nvm_t * entry;
107 	wiced_dct_read_lock((void*) &entry, WICED_FALSE, DCT_APP_SECTION, le_device_db_address_for_absolute_index(absolute_index), sizeof(le_device_nvm_t));
108 
109 	if (entry->magic == LE_DEVICE_MAGIC){
110 		memcpy(out_entry, entry, sizeof(le_device_nvm_t));
111 	} else {
112 		memset(out_entry, 0, sizeof(le_device_nvm_t));
113 	}
114 
115 	// read unlock
116 	wiced_dct_read_unlock((void*) entry, WICED_FALSE);
117 
118 	return out_entry->magic == LE_DEVICE_MAGIC;
119 }
120 
le_device_db_entry_write(int absolute_index,le_device_nvm_t * entry)121 static void le_device_db_entry_write(int absolute_index, le_device_nvm_t * entry){
122 	// write block
123 	wiced_dct_write((void*)entry, DCT_APP_SECTION, le_device_db_address_for_absolute_index(absolute_index), sizeof(le_device_nvm_t));
124 }
125 
le_device_db_highest_seq_nr(void)126 static uint32_t le_device_db_highest_seq_nr(void){
127 	le_device_nvm_t entry;
128 	int i;
129 	uint32_t seq_nr = 0;
130 	for (i=0;i<NVM_NUM_LE_DEVICES;i++){
131 		le_device_db_entry_read(i, &entry);
132 		if (entry.magic != LE_DEVICE_MAGIC) continue;
133 		if (entry.seq_nr < seq_nr) continue;
134 		seq_nr = entry.seq_nr;
135 	}
136 	return seq_nr;
137 }
138 
139 // returns absoulte index
le_device_db_find_free_entry(void)140 static int le_device_db_find_free_entry(void){
141 	le_device_nvm_t entry;
142 	int i;
143 	uint32_t seq_nr = 0;
144 	int lowest_index = -1;
145 	for (i=0;i<NVM_NUM_LE_DEVICES;i++){
146 		le_device_db_entry_read(i, &entry);
147 		if (entry.magic != LE_DEVICE_MAGIC) return i;
148 		if ((lowest_index < 0) || (entry.seq_nr < seq_nr)){
149 			lowest_index = i;
150 			seq_nr= entry.seq_nr;
151 		}
152 	}
153 	return lowest_index;
154 }
155 
156 // returns absolute index
le_device_db_get_absolute_index_for_device_index(int device_index)157 static int le_device_db_get_absolute_index_for_device_index(int device_index){
158     int i;
159     int counter = 0;
160     for (i=0;i<NVM_NUM_LE_DEVICES;i++){
161     	if (le_device_db_entry_valid(i)) {
162     		// found
163     		if (counter == device_index) return i;
164     		counter++;
165     	}
166     }
167     return 0;
168 }
169 
170 // PUBLIC API
171 
le_device_db_wiced_dct_set_start_address(uint32_t start_address)172 void le_device_db_wiced_dct_set_start_address(uint32_t start_address){
173 	log_info("set start address: %"PRIu32, start_address);
174 	start_of_le_device_db = start_address;
175 }
176 
le_device_db_init(void)177 void le_device_db_init(void){
178 }
179 
le_device_db_set_local_bd_addr(bd_addr_t addr)180 void le_device_db_set_local_bd_addr(bd_addr_t addr){
181 	(void) addr;
182 }
183 
184 // @returns number of device in db
le_device_db_count(void)185 int le_device_db_count(void){
186     int i;
187     int counter = 0;
188     for (i=0;i<NVM_NUM_LE_DEVICES;i++){
189     	if (le_device_db_entry_valid(i)) counter++;
190     }
191     return counter;
192 }
193 
le_device_db_max_count(void)194 int le_device_db_max_count(void){
195     return NVM_NUM_LE_DEVICES;
196 }
197 
198 // get device information: addr type and address
le_device_db_info(int device_index,int * addr_type,bd_addr_t addr,sm_key_t irk)199 void le_device_db_info(int device_index, int * addr_type, bd_addr_t addr, sm_key_t irk){
200 	int absolute_index = le_device_db_get_absolute_index_for_device_index(device_index);
201     le_device_nvm_t entry;
202     int valid = le_device_db_entry_read(absolute_index, &entry);
203 
204     // set defaults if not found
205     if (!valid) {
206         memset(&entry, 0, sizeof(le_device_nvm_t));
207         entry.addr_type = BD_ADDR_TYPE_UNKNOWN;
208     }
209 
210     if (addr_type) *addr_type = entry.addr_type;
211     if (addr) memcpy(addr, entry.addr, 6);
212     if (irk) memcpy(irk, entry.irk, 16);
213 }
214 
215 // free device
le_device_db_remove(int device_index)216 void le_device_db_remove(int device_index){
217 	int absolute_index = le_device_db_get_absolute_index_for_device_index(device_index);
218 	le_device_nvm_t entry;
219 	memset(&entry, 0, sizeof(le_device_nvm_t));
220 	le_device_db_entry_write(absolute_index, &entry);
221 }
222 
223 // custom function
le_device_db_wiced_dct_delete_all(void)224 void le_device_db_wiced_dct_delete_all(void){
225 	int i;
226 	le_device_nvm_t entry;
227 	memset(&entry, 0, sizeof(le_device_nvm_t));
228 	for (i=0;i<NVM_NUM_LE_DEVICES;i++){
229 		le_device_db_entry_write(i, &entry);
230 	}
231 }
232 
le_device_db_add(int addr_type,bd_addr_t addr,sm_key_t irk)233 int le_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk){
234     int absolute_index = le_device_db_find_free_entry();
235     uint32_t seq_nr = le_device_db_highest_seq_nr() + 1;
236     log_info("adding type %u - %s, seq nr %u, as #%u", addr_type, bd_addr_to_str(addr), (int) seq_nr, absolute_index);
237     log_info_key("irk", irk);
238 
239 	le_device_nvm_t entry;
240 	memset(&entry, 0, sizeof(le_device_nvm_t));
241 
242     entry.magic     = LE_DEVICE_MAGIC;
243 	entry.seq_nr    = seq_nr;
244     entry.addr_type = addr_type;
245     memcpy(entry.addr, addr, 6);
246     memcpy(entry.irk, irk, 16);
247 
248     le_device_db_entry_write(absolute_index, &entry);
249 
250     return absolute_index;
251 }
252 
le_device_db_encryption_set(int device_index,uint16_t ediv,uint8_t rand[8],sm_key_t ltk,int key_size,int authenticated,int authorized,int secure_connection)253 void le_device_db_encryption_set(int device_index, uint16_t ediv, uint8_t rand[8], sm_key_t ltk, int key_size, int authenticated, int authorized, int secure_connection){
254 
255 	int absolute_index = le_device_db_get_absolute_index_for_device_index(device_index);
256     le_device_nvm_t entry;
257 	le_device_db_entry_read(absolute_index, &entry);
258 
259     log_info("LE Device DB set encryption for %u, ediv x%04x, key size %u, authenticated %u, authorized %u, secure connection %u",
260         device_index, ediv, key_size, authenticated, authorized, secure_connection);
261 
262     entry.ediv = ediv;
263     if (rand) memcpy(entry.rand, rand, 8);
264     if (ltk) memcpy(entry.ltk, ltk, 16);
265     entry.key_size = key_size;
266     entry.authenticated = authenticated;
267     entry.authorized = authorized;
268     entry.secure_connection = secure_connection;
269 
270     le_device_db_entry_write(absolute_index, &entry);
271 }
272 
le_device_db_encryption_get(int device_index,uint16_t * ediv,uint8_t rand[8],sm_key_t ltk,int * key_size,int * authenticated,int * authorized,int * secure_connection)273 void le_device_db_encryption_get(int device_index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk, int * key_size, int * authenticated, int * authorized, int * secure_connection){
274 
275 	int absolute_index = le_device_db_get_absolute_index_for_device_index(device_index);
276     le_device_nvm_t entry;
277 	le_device_db_entry_read(absolute_index, &entry);
278 
279     log_info("LE Device DB encryption for %u, ediv x%04x, keysize %u, authenticated %u, authorized %u, secure connection %u",
280         device_index, entry.ediv, entry.key_size, entry.authenticated, entry.authorized, entry.secure_connection);
281 
282     if (ediv) *ediv = entry.ediv;
283     if (rand) memcpy(rand, entry.rand, 8);
284     if (ltk)  memcpy(ltk, entry.ltk, 16);
285     if (key_size) *key_size = entry.key_size;
286     if (authenticated) *authenticated = entry.authenticated;
287     if (authorized) *authorized = entry.authorized;
288     if (secure_connection) *secure_connection = entry.secure_connection;
289 }
290 
le_device_db_dump(void)291 void le_device_db_dump(void){
292     log_info("dump, devices: %d", le_device_db_count());
293     int i;
294     for (i=0;i<NVM_NUM_LE_DEVICES;i++){
295 	    le_device_nvm_t entry;
296 		int valid = le_device_db_entry_read(i, &entry);
297 
298         if (!valid) continue;
299 
300         log_info("#%u: %u %s", i, entry.addr_type, bd_addr_to_str(entry.addr));
301         log_info_key("ltk", entry.ltk);
302         log_info_key("irk", entry.irk);
303     }
304 }
305 
le_device_db_wiced_dct_get_storage_size(void)306 int le_device_db_wiced_dct_get_storage_size(void){
307 	return NVM_NUM_LE_DEVICES * sizeof(le_device_nvm_t);
308 }
309