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 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 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 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 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 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 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 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 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 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 306 int le_device_db_wiced_dct_get_storage_size(void){ 307 return NVM_NUM_LE_DEVICES * sizeof(le_device_nvm_t); 308 } 309