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__ "btstack_link_key_db_wiced_dct.c" 39 40 /* 41 * btstack_link_key_db_wiced_dct.c 42 * 43 * Persistent Link Key implemenetation for WICED using DCT mechanism 44 */ 45 46 #include "classic/btstack_link_key_db.h" 47 48 #include "stdint.h" 49 #include "string.h" 50 #include "btstack_debug.h" 51 #include "btstack_util.h" 52 53 #include "wiced.h" 54 55 // Link Key Magic 56 #define LINK_KEY_MAGIC ((uint32_t) 'B' << 24 | 'T' << 16 | 'L' << 8 | 'K') 57 58 typedef struct link_key_nvm { 59 uint32_t magic; 60 uint32_t seq_nr; // used for "last recently stored" eviction strategy 61 bd_addr_t bd_addr; 62 link_key_t link_key; 63 link_key_type_t link_key_type; 64 } link_key_nvm_t; 65 66 static char link_key_to_str_buffer[LINK_KEY_STR_LEN+1]; // 11223344556677889900112233445566\0 67 static char *link_key_to_str(link_key_t link_key){ 68 char * p = link_key_to_str_buffer; 69 int i; 70 for (i = 0; i < LINK_KEY_LEN ; i++) { 71 *p++ = char_for_nibble((link_key[i] >> 4) & 0x0F); 72 *p++ = char_for_nibble((link_key[i] >> 0) & 0x0F); 73 } 74 *p = 0; 75 return (char *) link_key_to_str_buffer; 76 } 77 78 static void link_key_db_init(void){ 79 log_info("Link Key DB initialized for DCT\n"); 80 } 81 82 static void link_key_db_close(void){ 83 } 84 85 // @return valid 86 static int link_key_read(int index, link_key_nvm_t * out_entry){ 87 88 // calculate address 89 uint32_t address = index * sizeof(link_key_nvm_t); 90 91 // read lock 92 link_key_nvm_t * entry; 93 wiced_dct_read_lock((void*) &entry, WICED_FALSE, DCT_APP_SECTION, address, sizeof(link_key_nvm_t)); 94 95 if (entry->magic == LINK_KEY_MAGIC){ 96 memcpy(out_entry, entry, sizeof(link_key_nvm_t)); 97 } else { 98 memset(out_entry, 0, sizeof(link_key_nvm_t)); 99 } 100 101 // read unlock 102 wiced_dct_read_unlock((void*) entry, WICED_FALSE); 103 104 return out_entry->magic == LINK_KEY_MAGIC; 105 } 106 107 static void link_key_write(int index, link_key_nvm_t * entry){ 108 // calculate address 109 uint32_t address = index * sizeof(link_key_nvm_t); 110 // write block 111 wiced_dct_write((void*)entry, DCT_APP_SECTION, address, sizeof(link_key_nvm_t)); 112 } 113 114 // returns entry index or -1 115 static int link_key_find_entry_for_address(bd_addr_t address){ 116 link_key_nvm_t item; 117 int i; 118 for (i=0;i<NVM_NUM_LINK_KEYS;i++){ 119 link_key_read(i, &item); 120 if (item.magic != LINK_KEY_MAGIC) continue; 121 if (memcmp(address, &item.bd_addr, 6) != 0) continue; 122 return i; 123 } 124 return -1; 125 } 126 127 // returns index 128 static int link_key_find_free_entry(void){ 129 link_key_nvm_t item; 130 int i; 131 uint32_t seq_nr = 0; 132 int lowest_index = -1; 133 for (i=0;i<NVM_NUM_LINK_KEYS;i++){ 134 link_key_read(i, &item); 135 if (item.magic != LINK_KEY_MAGIC) return i; 136 if ((lowest_index < 0) || (item.seq_nr < seq_nr)){ 137 lowest_index = i; 138 seq_nr= item.seq_nr; 139 } 140 } 141 return lowest_index; 142 } 143 144 static uint32_t link_key_highest_seq_nr(void){ 145 link_key_nvm_t item; 146 int i; 147 uint32_t seq_nr = 0; 148 for (i=0;i<NVM_NUM_LINK_KEYS;i++){ 149 link_key_read(i, &item); 150 if (item.magic != LINK_KEY_MAGIC) continue; 151 if (item.seq_nr < seq_nr) continue; 152 seq_nr = item.seq_nr; 153 } 154 return seq_nr; 155 } 156 157 // returns 1 if found 158 static int link_key_db_get_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * link_key_type) { 159 int index = link_key_find_entry_for_address(bd_addr); 160 if (index < 0) { 161 log_info("link_key_db_get_link_key for %s -> not found\n", bd_addr_to_str(bd_addr)); 162 return 0; 163 } 164 link_key_nvm_t item; 165 link_key_read(index, &item); 166 memcpy(link_key, item.link_key, LINK_KEY_LEN); 167 if (link_key_type) { 168 *link_key_type = item.link_key_type; 169 } 170 log_info("link_key_db_get_link_key for %s -> found %s\n", bd_addr_to_str(bd_addr), link_key_to_str(link_key)); 171 return 1; 172 } 173 174 static void link_key_db_delete_link_key(bd_addr_t bd_addr){ 175 int index = link_key_find_entry_for_address(bd_addr); 176 if (index < 0) return; 177 178 link_key_nvm_t item; 179 memset(&item, 0, sizeof(item)); 180 link_key_write(index, &item); 181 } 182 183 184 static void link_key_db_put_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t link_key_type){ 185 // check for existing record 186 int index = link_key_find_entry_for_address(bd_addr); 187 188 // if not found, use new entry 189 if (index < 0) { 190 index = link_key_find_free_entry(); 191 } 192 193 log_info("link_key_db_put_link_key for %s - key %s - at index %u\n", bd_addr_to_str(bd_addr), link_key_to_str(link_key), index); 194 195 link_key_nvm_t item; 196 item.magic = LINK_KEY_MAGIC; 197 item.seq_nr = link_key_highest_seq_nr() + 1; 198 memcpy(item.bd_addr, bd_addr, sizeof(bd_addr_t)); 199 memcpy(item.link_key, link_key, LINK_KEY_LEN); 200 item.link_key_type = link_key_type; 201 link_key_write(index, &item); 202 } 203 204 static void link_key_db_set_local_bd_addr(bd_addr_t bd_addr){ 205 } 206 207 static int link_key_db_tlv_iterator_init(btstack_link_key_iterator_t * it){ 208 it->context = (void*) 0; 209 return 1; 210 } 211 212 static int link_key_db_tlv_iterator_get_next(btstack_link_key_iterator_t * it, bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * link_key_type){ 213 uintptr_t i = (uintptr_t) it->context; 214 int found = 0; 215 while (i<NVM_NUM_LINK_KEYS){ 216 link_key_nvm_t item; 217 link_key_read(i++, &item); 218 if (item.magic != LINK_KEY_MAGIC) continue; 219 220 memcpy(bd_addr, item.bd_addr, 6); 221 memcpy(link_key, item.link_key, 16); 222 *link_key_type = item.link_key_type; 223 found = 1; 224 break; 225 } 226 it->context = (void*) i; 227 return found; 228 } 229 230 static void link_key_db_tlv_iterator_done(btstack_link_key_iterator_t * it){ 231 UNUSED(it); 232 } 233 234 const btstack_link_key_db_t btstack_link_key_db_wiced_dct = { 235 link_key_db_init, 236 link_key_db_set_local_bd_addr, 237 link_key_db_close, 238 link_key_db_get_link_key, 239 link_key_db_put_link_key, 240 link_key_db_delete_link_key, 241 link_key_db_tlv_iterator_init, 242 link_key_db_tlv_iterator_get_next, 243 link_key_db_tlv_iterator_done, 244 }; 245 246 // custom function 247 void btstack_link_key_db_wiced_dct_delete_all(void){ 248 int i; 249 link_key_nvm_t entry; 250 memset(&entry, 0, sizeof(link_key_nvm_t)); 251 for (i=0;i<NVM_NUM_LINK_KEYS;i++){ 252 link_key_write(i, &entry); 253 } 254 } 255 256 int btstack_link_key_db_wiced_dct_get_storage_size(void){ 257 return NVM_NUM_LINK_KEYS * sizeof(link_key_nvm_t); 258 } 259 260 const btstack_link_key_db_t * btstack_link_key_db_wiced_dct_instance(void){ 261 return &btstack_link_key_db_wiced_dct; 262 } 263