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