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