1caed94dfSMatthias Ringwald /*
2caed94dfSMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH
3caed94dfSMatthias Ringwald *
4caed94dfSMatthias Ringwald * Redistribution and use in source and binary forms, with or without
5caed94dfSMatthias Ringwald * modification, are permitted provided that the following conditions
6caed94dfSMatthias Ringwald * are met:
7caed94dfSMatthias Ringwald *
8caed94dfSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
9caed94dfSMatthias Ringwald * notice, this list of conditions and the following disclaimer.
10caed94dfSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
11caed94dfSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
12caed94dfSMatthias Ringwald * documentation and/or other materials provided with the distribution.
13caed94dfSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
14caed94dfSMatthias Ringwald * contributors may be used to endorse or promote products derived
15caed94dfSMatthias Ringwald * from this software without specific prior written permission.
16caed94dfSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
17caed94dfSMatthias Ringwald * personal benefit and not for any commercial purpose or for
18caed94dfSMatthias Ringwald * monetary gain.
19caed94dfSMatthias Ringwald *
20caed94dfSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21caed94dfSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22caed94dfSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25caed94dfSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26caed94dfSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27caed94dfSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28caed94dfSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29caed94dfSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30caed94dfSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31caed94dfSMatthias Ringwald * SUCH DAMAGE.
32caed94dfSMatthias Ringwald *
33caed94dfSMatthias Ringwald * Please inquire about commercial licensing options at
34caed94dfSMatthias Ringwald * [email protected]
35caed94dfSMatthias Ringwald *
36caed94dfSMatthias Ringwald */
37caed94dfSMatthias Ringwald
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_link_key_db_fs.c"
39ab2c6ae4SMatthias Ringwald
40caed94dfSMatthias Ringwald #include <string.h>
41caed94dfSMatthias Ringwald #include <stdlib.h>
42caed94dfSMatthias Ringwald #include <stdio.h>
43caed94dfSMatthias Ringwald #include <unistd.h>
44caed94dfSMatthias Ringwald
45d08566fbSMatthias Ringwald #include "tinydir.h"
46d08566fbSMatthias Ringwald
47fd19b115SMatthias Ringwald #include "btstack_config.h"
48caed94dfSMatthias Ringwald #include "btstack_link_key_db_fs.h"
49caed94dfSMatthias Ringwald #include "btstack_debug.h"
50caed94dfSMatthias Ringwald #include "btstack_util.h"
51caed94dfSMatthias Ringwald
52fd19b115SMatthias Ringwald // allow to pre-set LINK_KEY_PATH from btstack_config.h
53fd19b115SMatthias Ringwald #ifndef LINK_KEY_PATH
549419a14fSMatthias Ringwald #ifdef _WIN32
559419a14fSMatthias Ringwald #define LINK_KEY_PATH ""
569419a14fSMatthias Ringwald #else
57caed94dfSMatthias Ringwald #define LINK_KEY_PATH "/tmp/"
589419a14fSMatthias Ringwald #endif
59fd19b115SMatthias Ringwald #endif
60fd19b115SMatthias Ringwald
611624665aSMatthias Ringwald #define LINK_KEY_PREFIX "btstack_at_"
621624665aSMatthias Ringwald #define LINK_KEY_FOR "_link_key_for_"
631624665aSMatthias Ringwald #define LINK_KEY_SUFFIX ".txt"
641624665aSMatthias Ringwald #define LINK_KEY_STRING_LEN 17
65caed94dfSMatthias Ringwald
661624665aSMatthias Ringwald static bd_addr_t local_addr;
67d08566fbSMatthias Ringwald // note: sizeof for string literals works at compile time while strlen only works with some optimizations turned on. sizeof includes the \0
6818906008SMatthias Ringwald static char keypath[sizeof(LINK_KEY_PATH) + sizeof(LINK_KEY_PREFIX) + LINK_KEY_STRING_LEN + sizeof(LINK_KEY_FOR) + LINK_KEY_STRING_LEN + sizeof(LINK_KEY_SUFFIX) + 1];
69caed94dfSMatthias Ringwald
bd_addr_to_dash_str(bd_addr_t addr)70caed94dfSMatthias Ringwald static char * bd_addr_to_dash_str(bd_addr_t addr){
71924bf9b8SMatthias Ringwald return bd_addr_to_str_with_delimiter(addr, '-');
72caed94dfSMatthias Ringwald }
73caed94dfSMatthias Ringwald
741624665aSMatthias Ringwald static char link_key_to_str_buffer[LINK_KEY_STR_LEN+1]; // 11223344556677889900112233445566\0
link_key_to_str(link_key_t link_key)7558044c39SMatthias Ringwald static char *link_key_to_str(link_key_t link_key){
761624665aSMatthias Ringwald char * p = link_key_to_str_buffer;
771624665aSMatthias Ringwald int i;
781624665aSMatthias Ringwald for (i = 0; i < LINK_KEY_LEN ; i++) {
791624665aSMatthias Ringwald *p++ = char_for_nibble((link_key[i] >> 4) & 0x0F);
801624665aSMatthias Ringwald *p++ = char_for_nibble((link_key[i] >> 0) & 0x0F);
811624665aSMatthias Ringwald }
821624665aSMatthias Ringwald *p = 0;
831624665aSMatthias Ringwald return (char *) link_key_to_str_buffer;
841624665aSMatthias Ringwald }
851624665aSMatthias Ringwald
861624665aSMatthias Ringwald static char link_key_type_to_str_buffer[2];
link_key_type_to_str(link_key_type_t link_key)8758044c39SMatthias Ringwald static char *link_key_type_to_str(link_key_type_t link_key){
88*d5bacf30SMatthias Ringwald btstack_snprintf_assert_complete(link_key_type_to_str_buffer, sizeof(link_key_type_to_str_buffer), "%d", link_key);
891624665aSMatthias Ringwald return (char *) link_key_type_to_str_buffer;
901624665aSMatthias Ringwald }
911624665aSMatthias Ringwald
sscanf_link_key(char * addr_string,link_key_t link_key)9258044c39SMatthias Ringwald static int sscanf_link_key(char * addr_string, link_key_t link_key){
931624665aSMatthias Ringwald unsigned int buffer[LINK_KEY_LEN];
941624665aSMatthias Ringwald
951624665aSMatthias Ringwald // reset result buffer
961624665aSMatthias Ringwald memset(&buffer, 0, sizeof(buffer));
971624665aSMatthias Ringwald
981624665aSMatthias Ringwald // parse
991624665aSMatthias Ringwald int result = sscanf( (char *) addr_string, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1001624665aSMatthias Ringwald &buffer[0], &buffer[1], &buffer[2], &buffer[3],
1011624665aSMatthias Ringwald &buffer[4], &buffer[5], &buffer[6], &buffer[7],
1021624665aSMatthias Ringwald &buffer[8], &buffer[9], &buffer[10], &buffer[11],
1031624665aSMatthias Ringwald &buffer[12], &buffer[13], &buffer[14], &buffer[15] );
1041624665aSMatthias Ringwald
1051624665aSMatthias Ringwald if (result != LINK_KEY_LEN) return 0;
1061624665aSMatthias Ringwald
1071624665aSMatthias Ringwald // store
1081624665aSMatthias Ringwald int i;
1091624665aSMatthias Ringwald uint8_t *p = (uint8_t *) link_key;
1101624665aSMatthias Ringwald for (i=0; i<LINK_KEY_LEN; i++ ) {
1111624665aSMatthias Ringwald *p++ = (uint8_t) buffer[i];
1121624665aSMatthias Ringwald }
1131624665aSMatthias Ringwald return 1;
1141624665aSMatthias Ringwald }
1151624665aSMatthias Ringwald
set_path(bd_addr_t bd_addr)116caed94dfSMatthias Ringwald static void set_path(bd_addr_t bd_addr){
117caed94dfSMatthias Ringwald strcpy(keypath, LINK_KEY_PATH);
118caed94dfSMatthias Ringwald strcat(keypath, LINK_KEY_PREFIX);
1191624665aSMatthias Ringwald strcat(keypath, bd_addr_to_dash_str(local_addr));
1201624665aSMatthias Ringwald strcat(keypath, LINK_KEY_FOR);
121caed94dfSMatthias Ringwald strcat(keypath, bd_addr_to_dash_str(bd_addr));
1221624665aSMatthias Ringwald strcat(keypath, LINK_KEY_SUFFIX);
123caed94dfSMatthias Ringwald }
124caed94dfSMatthias Ringwald
125caed94dfSMatthias Ringwald // Device info
db_open(void)126caed94dfSMatthias Ringwald static void db_open(void){
127caed94dfSMatthias Ringwald }
128caed94dfSMatthias Ringwald
db_set_local_bd_addr(bd_addr_t bd_addr)1291624665aSMatthias Ringwald static void db_set_local_bd_addr(bd_addr_t bd_addr){
1301624665aSMatthias Ringwald memcpy(local_addr, bd_addr, 6);
1311624665aSMatthias Ringwald }
1321624665aSMatthias Ringwald
db_close(void)133caed94dfSMatthias Ringwald static void db_close(void){
134caed94dfSMatthias Ringwald }
135caed94dfSMatthias Ringwald
put_link_key(bd_addr_t bd_addr,link_key_t link_key,link_key_type_t link_key_type)136caed94dfSMatthias Ringwald static void put_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t link_key_type){
137caed94dfSMatthias Ringwald set_path(bd_addr);
138caed94dfSMatthias Ringwald char * link_key_str = link_key_to_str(link_key);
139caed94dfSMatthias Ringwald char * link_key_type_str = link_key_type_to_str(link_key_type);
140caed94dfSMatthias Ringwald
141caed94dfSMatthias Ringwald FILE * wFile = fopen(keypath,"w+");
1428300a979SBjoern Hartmann if (wFile == NULL){
1438300a979SBjoern Hartmann log_error("failed to create file");
1448300a979SBjoern Hartmann return;
1458300a979SBjoern Hartmann }
146caed94dfSMatthias Ringwald fwrite(link_key_str, strlen(link_key_str), 1, wFile);
147caed94dfSMatthias Ringwald fwrite(link_key_type_str, strlen(link_key_type_str), 1, wFile);
148caed94dfSMatthias Ringwald fclose(wFile);
149caed94dfSMatthias Ringwald }
150caed94dfSMatthias Ringwald
read_link_key(const char * path,link_key_t link_key,link_key_type_t * link_key_type)151d08566fbSMatthias Ringwald static int read_link_key(const char * path, link_key_t link_key, link_key_type_t * link_key_type){
152d08566fbSMatthias Ringwald if (access(path, R_OK)) return 0;
153caed94dfSMatthias Ringwald
154caed94dfSMatthias Ringwald char link_key_str[LINK_KEY_STR_LEN + 1];
155caed94dfSMatthias Ringwald char link_key_type_str[2];
156caed94dfSMatthias Ringwald
157d08566fbSMatthias Ringwald FILE * rFile = fopen(path,"r+");
1588300a979SBjoern Hartmann if (rFile == NULL) return 0;
159caed94dfSMatthias Ringwald size_t objects_read = fread(link_key_str, LINK_KEY_STR_LEN, 1, rFile );
160caed94dfSMatthias Ringwald if (objects_read == 1){
161caed94dfSMatthias Ringwald link_key_str[LINK_KEY_STR_LEN] = 0;
162caed94dfSMatthias Ringwald log_info("Found link key %s\n", link_key_str);
163caed94dfSMatthias Ringwald objects_read = fread(link_key_type_str, 1, 1, rFile );
164caed94dfSMatthias Ringwald }
165caed94dfSMatthias Ringwald fclose(rFile);
166caed94dfSMatthias Ringwald
167caed94dfSMatthias Ringwald if (objects_read != 1) return 0;
168caed94dfSMatthias Ringwald link_key_type_str[1] = 0;
169caed94dfSMatthias Ringwald log_info("Found link key type %s\n", link_key_type_str);
170caed94dfSMatthias Ringwald
171caed94dfSMatthias Ringwald int scan_result = sscanf_link_key(link_key_str, link_key);
172caed94dfSMatthias Ringwald if (scan_result == 0 ) return 0;
173caed94dfSMatthias Ringwald
174caed94dfSMatthias Ringwald int link_key_type_buffer;
175caed94dfSMatthias Ringwald scan_result = sscanf( (char *) link_key_type_str, "%d", &link_key_type_buffer);
176caed94dfSMatthias Ringwald if (scan_result == 0 ) return 0;
177caed94dfSMatthias Ringwald *link_key_type = (link_key_type_t) link_key_type_buffer;
178caed94dfSMatthias Ringwald return 1;
179caed94dfSMatthias Ringwald }
180caed94dfSMatthias Ringwald
get_link_key(bd_addr_t bd_addr,link_key_t link_key,link_key_type_t * link_key_type)181d08566fbSMatthias Ringwald static int get_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * link_key_type) {
182d08566fbSMatthias Ringwald set_path(bd_addr);
183d08566fbSMatthias Ringwald return read_link_key(keypath, link_key, link_key_type);
184d08566fbSMatthias Ringwald }
185d08566fbSMatthias Ringwald
delete_link_key(bd_addr_t bd_addr)186caed94dfSMatthias Ringwald static void delete_link_key(bd_addr_t bd_addr){
187caed94dfSMatthias Ringwald set_path(bd_addr);
188caed94dfSMatthias Ringwald if (access(keypath, R_OK)) return;
189caed94dfSMatthias Ringwald if(remove(keypath) != 0){
190caed94dfSMatthias Ringwald log_error("File %s could not be deleted.\n", keypath);
191caed94dfSMatthias Ringwald }
192caed94dfSMatthias Ringwald }
193caed94dfSMatthias Ringwald
iterator_init(btstack_link_key_iterator_t * it)194d08566fbSMatthias Ringwald static int iterator_init(btstack_link_key_iterator_t * it){
195d622dcd0SMatthias Ringwald tinydir_dir * dir = (tinydir_dir *) malloc(sizeof(tinydir_dir));
196d08566fbSMatthias Ringwald if (!dir) return 0;
197d08566fbSMatthias Ringwald it->context = dir;
198d08566fbSMatthias Ringwald tinydir_open(dir, LINK_KEY_PATH);
199d08566fbSMatthias Ringwald return 1;
200d08566fbSMatthias Ringwald }
201d08566fbSMatthias Ringwald
iterator_get_next(btstack_link_key_iterator_t * it,bd_addr_t bd_addr,link_key_t link_key,link_key_type_t * type)202d08566fbSMatthias Ringwald static int iterator_get_next(btstack_link_key_iterator_t * it, bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * type){
203d08566fbSMatthias Ringwald (void)bd_addr;
204d08566fbSMatthias Ringwald (void)link_key;
205d08566fbSMatthias Ringwald UNUSED(type);
206d08566fbSMatthias Ringwald tinydir_dir * dir = (tinydir_dir*) it->context;
207d08566fbSMatthias Ringwald
208d08566fbSMatthias Ringwald // construct prefix
209d08566fbSMatthias Ringwald strcpy(keypath, LINK_KEY_PREFIX);
210d08566fbSMatthias Ringwald strcat(keypath, bd_addr_to_dash_str(local_addr));
211d08566fbSMatthias Ringwald strcat(keypath, LINK_KEY_FOR);
212d08566fbSMatthias Ringwald
213d08566fbSMatthias Ringwald while (dir->has_next) {
214d08566fbSMatthias Ringwald tinydir_file file;
215d08566fbSMatthias Ringwald tinydir_readfile(dir, &file);
216d08566fbSMatthias Ringwald tinydir_next(dir);
217d08566fbSMatthias Ringwald // compare
218d08566fbSMatthias Ringwald if (strncmp(keypath, file.name, strlen(keypath)) == 0){
219d08566fbSMatthias Ringwald // parse bd_addr
220d08566fbSMatthias Ringwald const int addr_offset = sizeof(LINK_KEY_PREFIX) + LINK_KEY_STRING_LEN + sizeof(LINK_KEY_FOR) - 2; // -1 for each sizeof
221d08566fbSMatthias Ringwald sscanf_bd_addr(&file.name[addr_offset], bd_addr);
222d08566fbSMatthias Ringwald // path found, read file
223d08566fbSMatthias Ringwald strcpy(keypath, LINK_KEY_PATH);
224d08566fbSMatthias Ringwald strcat(keypath, file.name);
225d08566fbSMatthias Ringwald read_link_key(keypath, link_key, type);
226d08566fbSMatthias Ringwald return 1;
227d08566fbSMatthias Ringwald }
228d08566fbSMatthias Ringwald }
229d08566fbSMatthias Ringwald return 0;
230d08566fbSMatthias Ringwald }
231d08566fbSMatthias Ringwald
iterator_done(btstack_link_key_iterator_t * it)232d08566fbSMatthias Ringwald static void iterator_done(btstack_link_key_iterator_t * it){
233d08566fbSMatthias Ringwald tinydir_close((tinydir_dir*)it->context);
234d08566fbSMatthias Ringwald free(it->context);
235d08566fbSMatthias Ringwald it->context = NULL;
236d08566fbSMatthias Ringwald }
237d08566fbSMatthias Ringwald
23858044c39SMatthias Ringwald static const btstack_link_key_db_t btstack_link_key_db_fs = {
2391624665aSMatthias Ringwald &db_open,
2401624665aSMatthias Ringwald &db_set_local_bd_addr,
2411624665aSMatthias Ringwald &db_close,
2421624665aSMatthias Ringwald &get_link_key,
2431624665aSMatthias Ringwald &put_link_key,
2441624665aSMatthias Ringwald &delete_link_key,
245d08566fbSMatthias Ringwald &iterator_init,
246d08566fbSMatthias Ringwald &iterator_get_next,
247d08566fbSMatthias Ringwald &iterator_done,
248caed94dfSMatthias Ringwald };
249caed94dfSMatthias Ringwald
btstack_link_key_db_fs_instance(void)250caed94dfSMatthias Ringwald const btstack_link_key_db_t * btstack_link_key_db_fs_instance(void){
251caed94dfSMatthias Ringwald return &btstack_link_key_db_fs;
252caed94dfSMatthias Ringwald }
253caed94dfSMatthias Ringwald
254caed94dfSMatthias Ringwald
255