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