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