xref: /btstack/platform/wiced/le_device_db_wiced_dct.c (revision 82c9843e67930118ee91effaf3bfc78a59bb5b9a)
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     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
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 
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
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 
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 
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
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
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 
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 
177 void le_device_db_init(void){
178 }
179 
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
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 
194 int le_device_db_max_count(void){
195     return NVM_NUM_LE_DEVICES;
196 }
197 
198 // get device information: addr type and address
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 	le_device_db_entry_read(absolute_index, &entry);
203     if (addr_type) *addr_type = entry.addr_type;
204     if (addr) memcpy(addr, entry.addr, 6);
205     if (irk) memcpy(irk, entry.irk, 16);
206 }
207 
208 // free device
209 void le_device_db_remove(int device_index){
210 	int absolute_index = le_device_db_get_absolute_index_for_device_index(device_index);
211 	le_device_nvm_t entry;
212 	memset(&entry, 0, sizeof(le_device_nvm_t));
213 	le_device_db_entry_write(absolute_index, &entry);
214 }
215 
216 // custom function
217 void le_device_db_wiced_dct_delete_all(void){
218 	int i;
219 	le_device_nvm_t entry;
220 	memset(&entry, 0, sizeof(le_device_nvm_t));
221 	for (i=0;i<NVM_NUM_LE_DEVICES;i++){
222 		le_device_db_entry_write(i, &entry);
223 	}
224 }
225 
226 int le_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk){
227     int absolute_index = le_device_db_find_free_entry();
228     uint32_t seq_nr = le_device_db_highest_seq_nr() + 1;
229     log_info("adding type %u - %s, seq nr %u, as #%u", addr_type, bd_addr_to_str(addr), (int) seq_nr, absolute_index);
230     log_info_key("irk", irk);
231 
232 	le_device_nvm_t entry;
233 	memset(&entry, 0, sizeof(le_device_nvm_t));
234 
235     entry.magic     = LE_DEVICE_MAGIC;
236 	entry.seq_nr    = seq_nr;
237     entry.addr_type = addr_type;
238     memcpy(entry.addr, addr, 6);
239     memcpy(entry.irk, irk, 16);
240 
241     le_device_db_entry_write(absolute_index, &entry);
242 
243     return absolute_index;
244 }
245 
246 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){
247 
248 	int absolute_index = le_device_db_get_absolute_index_for_device_index(device_index);
249     le_device_nvm_t entry;
250 	le_device_db_entry_read(absolute_index, &entry);
251 
252     log_info("set encryption for #%u, ediv 0x%04x, key size %u, authenticated %u, authorized %u",
253     	absolute_index, ediv, key_size, authenticated, authorized);
254 
255     entry.ediv = ediv;
256     if (rand) memcpy(entry.rand, rand, 8);
257     if (ltk) memcpy(entry.ltk, ltk, 16);
258     entry.key_size = key_size;
259     entry.authenticated = authenticated;
260     entry.authorized = authorized;
261 
262     le_device_db_entry_write(absolute_index, &entry);
263 }
264 
265 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){
266 
267 	int absolute_index = le_device_db_get_absolute_index_for_device_index(device_index);
268     le_device_nvm_t entry;
269 	le_device_db_entry_read(absolute_index, &entry);
270 
271     log_info("encryption for #%u, ediv x%04x, keysize %u, authenticated %u, authorized %u",
272         absolute_index, entry.ediv, entry.key_size, entry.authenticated, entry.authorized);
273 
274     if (ediv) *ediv = entry.ediv;
275     if (rand) memcpy(rand, entry.rand, 8);
276     if (ltk)  memcpy(ltk, entry.ltk, 16);
277     if (key_size) *key_size = entry.key_size;
278     if (authenticated) *authenticated = entry.authenticated;
279     if (authorized) *authorized = entry.authorized;
280 }
281 
282 void le_device_db_dump(void){
283     log_info("dump, devices: %d", le_device_db_count());
284     int i;
285     for (i=0;i<NVM_NUM_LE_DEVICES;i++){
286 	    le_device_nvm_t entry;
287 		int valid = le_device_db_entry_read(i, &entry);
288 
289         if (!valid) continue;
290 
291         log_info("#%u: %u %s", i, entry.addr_type, bd_addr_to_str(entry.addr));
292         log_info_key("ltk", entry.ltk);
293         log_info_key("irk", entry.irk);
294     }
295 }
296 
297 int le_device_db_wiced_dct_get_storage_size(void){
298 	return NVM_NUM_LE_DEVICES * sizeof(le_device_nvm_t);
299 }
300