1 /******************************************************************************
2 *
3 * Copyright (C) 2009-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /************************************************************************************
20 *
21 * Filename: btif_config.c
22 *
23 * Description: Stores the local BT adapter and remote device properties in
24 * NVRAM storage, typically as xml file in the
25 * mobile's filesystem
26 *
27 *
28 ***********************************************************************************/
29 #include <stdlib.h>
30 #include <time.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <dirent.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/mman.h>
41 #include <stdlib.h>
42 #include <private/android_filesystem_config.h>
43
44 #define LOG_TAG "btif_config"
45
46 #include <hardware/bluetooth.h>
47 #include "data_types.h"
48 #include "bd.h"
49 #include "btif_api.h"
50 #include "btif_config.h"
51 #include "btif_config_util.h"
52 #include "btif_sock_thread.h"
53 #include "btif_sock_util.h"
54 #include "btif_util.h"
55
56 //#define UNIT_TEST
57 #define CFG_PATH "/data/misc/bluedroid/"
58 #define CFG_FILE_NAME "bt_config"
59 #define CFG_FILE_EXT ".xml"
60 #define CFG_FILE_EXT_OLD ".old"
61 #define CFG_FILE_EXT_NEW ".new"
62 #define CFG_GROW_SIZE (10*sizeof(cfg_node))
63 #define GET_CHILD_MAX_COUNT(node) (short)((int)(node)->bytes / sizeof(cfg_node))
64 #define GET_CHILD_COUNT(p) (short)((int)(p)->used / sizeof(cfg_node))
65 #define ADD_CHILD_COUNT(p, c) (p)->used += (short)((c)*sizeof(cfg_node))
66 #define DEC_CHILD_COUNT(p, c) (p)->used -= (short)((c)*sizeof(cfg_node))
67 #define GET_NODE_COUNT(bytes) (bytes / sizeof(cfg_node))
68 #define GET_NODE_BYTES(c) (c * sizeof(cfg_node))
69 #define MAX_NODE_BYTES 32000
70 #define CFG_CMD_SAVE 1
71
72 #ifndef FALSE
73 #define TRUE 1
74 #define FALSE 0
75 #endif
76 typedef struct cfg_node_s
77 {
78 const char* name;
79 union
80 {
81 struct cfg_node_s* child;
82 char* value;
83 };
84 short bytes;
85 short type;
86 short used;
87 short flag;
88 } cfg_node;
89
90 static pthread_mutex_t slot_lock;
91 static int pth = -1; //poll thread handle
92 static cfg_node root;
93 static int cached_change;
94 static int save_cmds_queued;
95 static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
96 static inline short alloc_node(cfg_node* p, short grow);
97 static inline void free_node(cfg_node* p);
98 static inline short find_inode(const cfg_node* p, const char* name);
99 static cfg_node* find_node(const char* section, const char* key, const char* name);
100 static int remove_node(const char* section, const char* key, const char* name);
101 static int remove_filter_node(const char* section, const char* filter[], int filter_count, int max_allowed);
102 static inline cfg_node* find_free_node(cfg_node* p);
103 static int set_node(const char* section, const char* key, const char* name,
104 const char* value, short bytes, short type);
105 static int save_cfg();
106 static void load_cfg();
107 static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
108 #ifdef UNIT_TEST
109 static void cfg_test_load();
110 static void cfg_test_write();
111 static void cfg_test_read();
112 #endif
113 #define MY_LOG_LEVEL appl_trace_level
114 #define MY_LOG_LAYER TRACE_LAYER_NONE | TRACE_ORG_APPL
115
dump_node(const char * title,const cfg_node * p)116 static inline void dump_node(const char* title, const cfg_node* p)
117 {
118 if(p) {
119 bdld("%s, p->name:%s, child/value:%p, bytes:%d",
120 title, p->name, p->child, p->bytes);
121 bdld("p->used:%d, type:%x, p->flag:%d",
122 p->used, p->type, p->flag);
123 } else bdld("%s is NULL", title);
124 }
125
126 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
btif_config_init()127 int btif_config_init()
128 {
129 static int initialized;
130 bdld("in initialized:%d", initialized);
131 if(!initialized)
132 {
133 initialized = 1;
134 struct stat st;
135 if(stat(CFG_PATH, &st) != 0)
136 bdle("%s does not exist, need provision", CFG_PATH);
137 btsock_thread_init();
138 init_slot_lock(&slot_lock);
139 lock_slot(&slot_lock);
140 root.name = "Bluedroid";
141 alloc_node(&root, CFG_GROW_SIZE);
142 dump_node("root", &root);
143 pth = btsock_thread_create(NULL, cfg_cmd_callback);
144 load_cfg();
145 unlock_slot(&slot_lock);
146 #ifdef UNIT_TEST
147 cfg_test_write();
148 //cfg_test_read();
149 exit(0);
150 #endif
151 }
152 return pth >= 0;
153 }
btif_config_get_int(const char * section,const char * key,const char * name,int * value)154 int btif_config_get_int(const char* section, const char* key, const char* name, int* value)
155 {
156 int size = sizeof(*value);
157 int type = BTIF_CFG_TYPE_INT;
158 return btif_config_get(section, key, name, (char*)value, &size, &type);
159 }
btif_config_set_int(const char * section,const char * key,const char * name,int value)160 int btif_config_set_int(const char* section, const char* key, const char* name, int value)
161 {
162 return btif_config_set(section, key, name, (char*)&value, sizeof(value), BTIF_CFG_TYPE_INT);
163 }
btif_config_get_str(const char * section,const char * key,const char * name,char * value,int * size)164 int btif_config_get_str(const char* section, const char* key, const char* name, char* value, int* size)
165 {
166 int type = BTIF_CFG_TYPE_STR;
167 if(value)
168 *value = 0;
169 return btif_config_get(section, key, name, value, size, &type);
170 }
btif_config_set_str(const char * section,const char * key,const char * name,const char * value)171 int btif_config_set_str(const char* section, const char* key, const char* name, const char* value)
172 {
173 value = value ? value : "";
174 return btif_config_set(section, key, name, value, strlen(value) + 1, BTIF_CFG_TYPE_STR);
175 }
btif_config_exist(const char * section,const char * key,const char * name)176 int btif_config_exist(const char* section, const char* key, const char* name)
177 {
178 int ret = FALSE;
179 if(section && *section && key && *key)
180 {
181 lock_slot(&slot_lock);
182 ret = find_node(section, key, name) != NULL;
183 unlock_slot(&slot_lock);
184 }
185 return ret;
186 }
btif_config_get(const char * section,const char * key,const char * name,char * value,int * bytes,int * type)187 int btif_config_get(const char* section, const char* key, const char* name, char* value, int* bytes, int* type)
188 {
189 int ret = FALSE;
190 bdla(section && *section && key && *key && name && *name && bytes && type);
191 bdld("section:%s, key:%s, name:%s, value:%p, bytes:%d, type:%d",
192 section, key, name, value, *bytes, *type);
193 if(section && *section && key && *key && name && *name && bytes && type)
194 {
195 lock_slot(&slot_lock);
196 const cfg_node* node = find_node(section, key, name);
197 dump_node("found node", node);
198 if(node)
199 {
200 if(*type == node->type && value && *bytes >= node->used)
201 {
202 if(node->used > 0)
203 memcpy(value, node->value, node->used);
204 ret = TRUE;
205 }
206 *type = node->type;
207 *bytes = node->used;
208 if(ret != TRUE)
209 {
210 if(*type != node->type)
211 bdle("value:%s, wrong type:%d, need to be type: %d",
212 name, *type, node->type);
213 if(value && *bytes < node->used)
214 bdle("value:%s, not enough size: %d bytes, need %d bytes",
215 name, node->used, *bytes);
216 }
217 }
218 unlock_slot(&slot_lock);
219 }
220 return ret;
221 }
btif_config_set(const char * section,const char * key,const char * name,const char * value,int bytes,int type)222 int btif_config_set(const char* section, const char* key, const char* name, const char* value, int bytes, int type)
223 {
224 int ret = FALSE;
225 bdla(section && *section && key && *key && name && *name);
226 bdla(bytes < MAX_NODE_BYTES);
227 if(section && *section && key && *key && name && *name && bytes < MAX_NODE_BYTES)
228 {
229 lock_slot(&slot_lock);
230 ret = set_node(section, key, name, value, (short)bytes, (short)type);
231 if(ret && !(type & BTIF_CFG_TYPE_VOLATILE))
232 cached_change++;
233 unlock_slot(&slot_lock);
234 }
235 return ret;
236 }
btif_config_remove(const char * section,const char * key,const char * name)237 int btif_config_remove(const char* section, const char* key, const char* name)
238 {
239 bdla(section && *section && key && *key);
240 bdld("section:%s, key:%s, name:%s", section, key, name);
241 int ret = FALSE;
242 if(section && *section && key && *key)
243 {
244 lock_slot(&slot_lock);
245 ret = remove_node(section, key, name);
246 if(ret)
247 cached_change++;
248 unlock_slot(&slot_lock);
249 }
250 return ret;
251 }
252
btif_config_filter_remove(const char * section,const char * filter[],int filter_count,int max_allowed)253 int btif_config_filter_remove(const char* section, const char* filter[], int filter_count, int max_allowed)
254 {
255 bdla(section && *section && max_allowed > 0);
256 bdld("section:%s, filter:%s, filter count:%d, max allowed:%d",
257 section, filter[0], filter_count, max_allowed);
258 int ret = FALSE;
259 if(section && *section && max_allowed > 0)
260 {
261 lock_slot(&slot_lock);
262 ret = remove_filter_node(section, filter, filter_count, max_allowed);
263 if(ret)
264 cached_change++;
265 unlock_slot(&slot_lock);
266 }
267 return ret;
268 }
269 typedef struct {
270 short si;
271 short ki;
272 short vi;
273 short reserved;
274 } cfg_node_pos;
btif_config_next_key(short pos,const char * section,char * name,int * bytes)275 short btif_config_next_key(short pos, const char* section, char * name, int* bytes)
276 {
277 int next = -1;
278 lock_slot(&slot_lock);
279 short si = find_inode(&root, section);
280 if(si >= 0)
281 {
282 const cfg_node* section_node = &root.child[si];
283 next = find_next_node(section_node, pos, name, bytes);
284 }
285 unlock_slot(&slot_lock);
286 return next;
287 }
btif_config_next_value(short pos,const char * section,const char * key,char * name,int * bytes)288 short btif_config_next_value(short pos, const char* section, const char* key, char* name, int* bytes)
289 {
290 int next = -1;
291 lock_slot(&slot_lock);
292 short si = find_inode(&root, section);
293 if(si >= 0)
294 {
295 const cfg_node* section_node = &root.child[si];
296 short ki = find_inode(section_node, key);
297 if(ki >= 0)
298 {
299 const cfg_node* key_node = §ion_node->child[ki];
300 next = find_next_node(key_node, pos, name, bytes);
301 }
302 }
303 unlock_slot(&slot_lock);
304 return next;
305 }
btif_config_enum(btif_config_enum_callback cb,void * user_data)306 int btif_config_enum(btif_config_enum_callback cb, void* user_data)
307 {
308 bdla(cb);
309 if(!cb)
310 return FALSE;
311 lock_slot(&slot_lock);
312 int si, ki, vi;
313 cfg_node *section_node, *key_node, *value_node;
314 for(si = 0; si < GET_CHILD_COUNT(&root); si++)
315 {
316 section_node = &root.child[si];
317 if(section_node->name && *section_node->name)
318 {
319 for(ki = 0; ki < GET_CHILD_COUNT(section_node); ki++)
320 {
321 key_node = §ion_node->child[ki];
322 if(key_node->name && *key_node->name)
323 {
324 for(vi = 0; vi < GET_CHILD_COUNT(key_node); vi++)
325 {
326 value_node = &key_node->child[vi];
327 if(value_node->name && *value_node->name)
328 {
329 cb(user_data, section_node->name, key_node->name, value_node->name,
330 value_node->value, value_node->used, value_node->type);
331 }
332 }
333 }
334 }
335 }
336 }
337 unlock_slot(&slot_lock);
338 return TRUE;
339 }
btif_config_save()340 int btif_config_save()
341 {
342 int post_cmd = 0;
343 lock_slot(&slot_lock);
344 bdld("save_cmds_queued:%d, cached_change:%d", save_cmds_queued, cached_change);
345 if((save_cmds_queued == 0) && (cached_change > 0))
346 {
347 post_cmd = 1;
348 save_cmds_queued++;
349 bdld("post_cmd set to 1, save_cmds_queued:%d", save_cmds_queued);
350 }
351 unlock_slot(&slot_lock);
352 /* don't hold lock when invoking send or else a deadlock could
353 * occur when the socket thread tries to do the actual saving.
354 */
355 if (post_cmd)
356 btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
357
358 return TRUE;
359 }
btif_config_flush()360 void btif_config_flush()
361 {
362 lock_slot(&slot_lock);
363 if(cached_change > 0)
364 save_cfg();
365 unlock_slot(&slot_lock);
366 }
367
368 /*******************************************************************************
369 * Device information
370 *******************************************************************************/
btif_get_device_type(const BD_ADDR bd_addr,int * p_device_type)371 BOOLEAN btif_get_device_type(const BD_ADDR bd_addr, int *p_device_type)
372 {
373 if (p_device_type == NULL)
374 return FALSE;
375
376 bt_bdaddr_t bda;
377 bdcpy(bda.address, bd_addr);
378
379 char bd_addr_str[18] = {0};
380 bd2str(&bda, &bd_addr_str);
381
382 if (!btif_config_get_int("Remote", bd_addr_str, "DevType", p_device_type))
383 return FALSE;
384
385 ALOGD("%s: Device [%s] type %d", __FUNCTION__, bd_addr_str, *p_device_type);
386 return TRUE;
387 }
388
btif_get_address_type(const BD_ADDR bd_addr,int * p_addr_type)389 BOOLEAN btif_get_address_type(const BD_ADDR bd_addr, int *p_addr_type)
390 {
391 if (p_addr_type == NULL)
392 return FALSE;
393
394 bt_bdaddr_t bda;
395 bdcpy(bda.address, bd_addr);
396
397 char bd_addr_str[18] = {0};
398 bd2str(&bda, &bd_addr_str);
399
400 if (!btif_config_get_int("Remote", bd_addr_str, "AddrType", p_addr_type))
401 return FALSE;
402
403 ALOGD("%s: Device [%s] address type %d", __FUNCTION__, bd_addr_str, *p_addr_type);
404 return TRUE;
405 }
406
407 /////////////////////////////////////////////////////////////////////////////////////////////
alloc_node(cfg_node * p,short grow)408 static inline short alloc_node(cfg_node* p, short grow)
409 {
410 int new_bytes = p->bytes + grow;
411 if(grow > 0 && new_bytes < MAX_NODE_BYTES)
412 {
413 char* value = (char*)realloc(p->value, new_bytes);
414 if(value)
415 {
416 short old_bytes = p->bytes;
417 //clear to zero
418 memset(value + old_bytes, 0, grow);
419 p->bytes = old_bytes + grow;
420 p->value = value;
421 return old_bytes;//return the previous size
422 }
423 else bdle("realloc failed, old_bytes:%d, grow:%d, total:%d", p->bytes, grow, p->bytes + grow);
424 }
425 return -1;
426 }
free_node(cfg_node * p)427 static inline void free_node(cfg_node* p)
428 {
429 if(p)
430 {
431 if(p->child)
432 {
433 free(p->child);
434 p->child = NULL;
435 }
436 if(p->name)
437 {
438 free((void*)p->name);
439 p->name = 0;
440 }
441 p->used = p->bytes = p->flag = p->type = 0;
442 }
443 }
find_inode(const cfg_node * p,const char * name)444 static inline short find_inode(const cfg_node* p, const char* name)
445 {
446 if(p && p->child && name && *name)
447 {
448 int i;
449 int count = GET_CHILD_COUNT(p);
450 //bdld("parent name:%s, child name:%s, child count:%d", p->name, name, count);
451 for(i = 0; i < count; i++)
452 {
453 if(p->child[i].name && *p->child[i].name &&
454 strcmp(p->child[i].name, name) == 0)
455 {
456 return (short)i;
457 }
458 }
459 }
460 return -1;
461 }
find_free_node(cfg_node * p)462 static inline cfg_node* find_free_node(cfg_node* p)
463 {
464 if(p && p->child)
465 {
466 int count = GET_CHILD_COUNT(p);
467 if(count < GET_CHILD_MAX_COUNT(p))
468 return p->child + count;
469 }
470 return NULL;
471 }
find_add_node(cfg_node * p,const char * name)472 static cfg_node* find_add_node(cfg_node* p, const char* name)
473 {
474 int i = -1;
475 cfg_node* node = NULL;
476 if((i = find_inode(p, name)) < 0)
477 {
478 if(!(node = find_free_node(p)))
479 {
480 int old_size = alloc_node(p, CFG_GROW_SIZE);
481 if(old_size >= 0)
482 {
483 i = GET_NODE_COUNT(old_size);
484 node = &p->child[i];
485 ADD_CHILD_COUNT(p, 1);
486 }
487 } else ADD_CHILD_COUNT(p, 1);
488 }
489 else node = &p->child[i];
490 if(node && (!node->name))
491 node->name = strdup(name);
492 return node;
493 }
set_node(const char * section,const char * key,const char * name,const char * value,short bytes,short type)494 static int set_node(const char* section, const char* key, const char* name,
495 const char* value, short bytes, short type)
496 {
497 int si = -1, ki = -1, vi = -1;
498 cfg_node* section_node = NULL;
499 if((section_node = find_add_node(&root, section)))
500 {
501 cfg_node* key_node;
502 if((key_node = find_add_node(section_node, key)))
503 {
504 cfg_node* value_node;
505 if((value_node = find_add_node(key_node, name)))
506 {
507 if(value_node->bytes < bytes)
508 {
509 if(value_node->value)
510 free(value_node->value);
511 value_node->value = (char*)malloc(bytes);
512 if(value_node->value)
513 value_node->bytes = bytes;
514 else
515 {
516 bdle("not enough memory!");
517 value_node->bytes = 0;
518 return FALSE;
519 }
520 }
521 if(value_node->value && value != NULL && bytes > 0)
522 memcpy(value_node->value, value, bytes);
523 value_node->type = type;
524 value_node->used = bytes;
525 return TRUE;
526 }
527 }
528 }
529 return FALSE;
530 }
find_node(const char * section,const char * key,const char * name)531 static cfg_node* find_node(const char* section, const char* key, const char* name)
532 {
533 int si = -1, ki = -1, vi = -1;
534 if((si = find_inode(&root, section)) >= 0)
535 {
536 cfg_node* section_node = &root.child[si];
537 if(key)
538 {
539 if((ki = find_inode(section_node, key)) >= 0)
540 {
541 cfg_node* key_node = §ion_node->child[ki];
542 if(name)
543 {
544 if((vi = find_inode(key_node, name)) >= 0)
545 {
546 return &key_node->child[vi];
547 }
548 return NULL;
549 }
550 return key_node;
551 }
552 return NULL;
553 }
554 return section_node;
555 }
556 return NULL;
557 }
find_next_node(const cfg_node * p,short start,char * name,int * bytes)558 static short find_next_node(const cfg_node* p, short start, char* name, int* bytes)
559 {
560 bdla(0 <= start && start < GET_CHILD_COUNT(p));
561 bdld("in, start:%d, child count:%d, max count:%d", start, GET_CHILD_COUNT(p), GET_CHILD_MAX_COUNT(p));
562 short next = -1;
563 if(name) *name = 0;
564 if(0 <= start && start < GET_CHILD_COUNT(p))
565 {
566 int i;
567 for(i = start; i < GET_CHILD_COUNT(p); i++)
568 {
569 cfg_node* child = &p->child[i];
570 if(child->name)
571 {
572 int name_bytes = strlen(child->name) + 1;
573 if(name && bytes && *bytes >= name_bytes)
574 {
575 memcpy(name, child->name, name_bytes);
576 if(i + 1 < GET_CHILD_COUNT(p))
577 next = (short)(i + 1);
578 *bytes = name_bytes;
579 }
580 else if(bytes)
581 {
582 *bytes = name_bytes;
583 }
584 break;
585 }
586 }
587 }
588 return next;
589 }
free_child(cfg_node * p,int ichild,int count)590 static void free_child(cfg_node* p, int ichild, int count)
591 {
592 int child_count = GET_CHILD_COUNT(p);
593 bdla(p && ichild + count <= child_count && count > 0);
594 int icount = ichild + count;
595 icount = icount <= child_count ? icount : child_count;
596 int i;
597 for(i = ichild; i < icount; i++)
598 free_node(p->child + i);
599 if(i < child_count)
600 {
601 int mv_count = child_count - i;
602 memmove(p->child + ichild, p->child + i, GET_NODE_BYTES(mv_count));
603 //cleanup the buffer of already moved children
604 memset(p->child + i, 0, GET_NODE_BYTES(mv_count));
605 }
606 DEC_CHILD_COUNT(p, i - ichild);
607 }
remove_node(const char * section,const char * key,const char * name)608 static int remove_node(const char* section, const char* key, const char* name)
609 {
610 short si = -1, ki = -1, vi = -1;
611 if((si = find_inode(&root, section)) >= 0)
612 {
613 cfg_node* section_node = &root.child[si];
614 if((ki = find_inode(section_node, key)) >= 0)
615 {
616 cfg_node* key_node = §ion_node->child[ki];
617 if(name == NULL)
618 {
619 int count = GET_CHILD_COUNT(key_node);
620 int i;
621 free_child(key_node, 0, count);
622 free_child(section_node, ki, 1);
623 return TRUE;
624 }
625 else if((vi = find_inode(key_node, name)) >= 0)
626 {
627 free_child(key_node, vi, 1);
628 return TRUE;
629 }
630 }
631 }
632 return FALSE;
633 }
find_first_empty(cfg_node * p,int start,int count)634 static inline int find_first_empty(cfg_node*p, int start, int count)
635 {
636 int i;
637 for(i = start; i < count; i++)
638 {
639 if(p->child[i].name == NULL)
640 return i;
641 }
642 return -1;
643 }
find_first_occupy(cfg_node * p,int start,int count)644 static inline int find_first_occupy(cfg_node*p, int start, int count)
645 {
646 int i;
647 for(i = start; i < count; i++)
648 if(p->child[i].name)
649 return i;
650 return -1;
651 }
652
pack_child(cfg_node * p)653 static void pack_child(cfg_node* p)
654 {
655 int child_count = GET_CHILD_COUNT(p);
656 int occupy = 1;
657 int empty = 0;
658 int i;
659 for(;;)
660 {
661 empty = find_first_empty(p, empty, child_count);
662 if(empty >= 0)
663 {
664 if(occupy <= empty)
665 occupy = empty + 1;
666 occupy = find_first_occupy(p, occupy, child_count);
667 bdla(occupy != 0);
668 if(occupy > 0)
669 {//move
670 p->child[empty] = p->child[occupy];
671 memset(&p->child[occupy], 0, sizeof(cfg_node));
672 empty++;
673 occupy++;
674 }
675 else break;
676 }
677 else break;
678 }
679 }
value_in_filter(cfg_node * key,const char * filter[],int filter_count)680 static inline int value_in_filter(cfg_node* key, const char* filter[], int filter_count)
681 {
682 int i, j;
683 int child_count = GET_CHILD_COUNT(key);
684 for(i = 0; i < child_count; i++)
685 {
686 if(key->child[i].name && *key->child[i].name)
687 {
688 for(j = 0; j < filter_count; j++)
689 if(strcmp(filter[j], key->child[i].name) == 0)
690 return TRUE;
691 }
692 }
693 return FALSE;
694 }
remove_filter_node(const char * section,const char * filter[],int filter_count,int max_allowed)695 static int remove_filter_node(const char* section, const char* filter[], int filter_count, int max_allowed)
696 {
697 int si = -1;
698 if((si = find_inode(&root, section)) < 0)
699 {
700 bdle("cannot find section:%s", section);
701 return FALSE;
702 }
703 cfg_node* s = &root.child[si];
704 int child_count = GET_CHILD_COUNT(s);
705 bdld("section:%s, curr child count:%d, filter count:%d", section, child_count, filter_count);
706 if(child_count < max_allowed)
707 return FALSE;
708 //remove until half of max allowance left
709 int total_rm = child_count - max_allowed / 2;
710 int rm_count = 0;
711 int i;
712 for(i = 0; i < child_count; i++)
713 {
714 if(!value_in_filter(&s->child[i], filter, filter_count))
715 {
716 free_child(&s->child[i], 0, GET_CHILD_COUNT(&s->child[i]));
717 free_node(&s->child[i]);
718 rm_count++;
719 if(rm_count >= total_rm)
720 break;
721 }
722 }
723 if(rm_count)
724 {
725 pack_child(s);
726 DEC_CHILD_COUNT(s, rm_count);
727 return TRUE;
728 }
729 return FALSE;
730 }
731
save_cfg()732 static int save_cfg()
733 {
734 const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
735 const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
736 const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
737 int ret = FALSE;
738 if(access(file_name_old, F_OK) == 0)
739 unlink(file_name_old);
740 if(access(file_name_new, F_OK) == 0)
741 unlink(file_name_new);
742 if(btif_config_save_file(file_name_new))
743 {
744 cached_change = 0;
745 chown(file_name_new, -1, AID_NET_BT_STACK);
746 chmod(file_name_new, 0660);
747 rename(file_name, file_name_old);
748 rename(file_name_new, file_name);
749 ret = TRUE;
750 }
751 else bdle("btif_config_save_file failed");
752 return ret;
753 }
754
load_bluez_cfg()755 static int load_bluez_cfg()
756 {
757 char adapter_path[256];
758 if(load_bluez_adapter_info(adapter_path, sizeof(adapter_path)))
759 {
760 if(load_bluez_linkkeys(adapter_path))
761 return TRUE;
762 }
763 return FALSE;
764 }
remove_bluez_cfg()765 static void remove_bluez_cfg()
766 {
767 rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
768 }
clean_newline_char()769 static void clean_newline_char()
770 {
771 char kname[128], vname[128];
772 short kpos = 0;
773 int kname_size, vname_size;
774 vname[0] = 0;
775 vname_size = sizeof(vname);
776 //bdld("removing newline at the end of the adapter and device name");
777 if(btif_config_get_str("Local", "Adapter", "Name", vname, &vname_size) &&
778 vname_size > 2)
779 {
780 if(vname[vname_size - 2] == '\n')
781 {
782 bdld("remove newline at the end of the adapter name:%s", vname);
783 vname[vname_size - 2] = 0;
784 btif_config_set_str("Local", "Adapter", "Name", vname);
785 }
786 }
787 do
788 {
789 kname_size = sizeof(kname);
790 kname[0] = 0;
791 kpos = btif_config_next_key(kpos, "Remote", kname, &kname_size);
792 //bdld("Remote device:%s, size:%d", kname, kname_size);
793 vname_size = sizeof(vname);
794 vname[0] = 0;
795 if(btif_config_get_str("Remote", kname, "Name", vname, &vname_size) &&
796 vname_size > 2)
797 {
798 bdld("remote device name:%s", vname);
799 if(vname[vname_size - 2] == '\n')
800 {
801 bdld("remove newline at the end of the device name:%s", vname);
802 vname[vname_size - 2] = 0;
803 btif_config_set_str("Remote", kname, "Name", vname);
804 }
805 }
806 } while(kpos != -1);
807 }
load_cfg()808 static void load_cfg()
809 {
810 const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
811 const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
812 const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
813 if(!btif_config_load_file(file_name))
814 {
815 unlink(file_name);
816 if(!btif_config_load_file(file_name_old))
817 {
818 unlink(file_name_old);
819 if(load_bluez_cfg() && save_cfg())
820 remove_bluez_cfg();
821 }
822 }
823 int bluez_migration_done = 0;
824 btif_config_get_int("Local", "Adapter", "BluezMigrationDone", &bluez_migration_done);
825 if(!bluez_migration_done)
826 {
827 //clean the new line char at the end of the device name. Caused by bluez config import bug
828 clean_newline_char();
829 btif_config_set_int("Local", "Adapter", "BluezMigrationDone", 1);
830 btif_config_save();
831 }
832 }
cfg_cmd_callback(int cmd_fd,int type,int size,uint32_t user_id)833 static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id)
834 {
835 UNUSED(cmd_fd);
836 UNUSED(size);
837 UNUSED(user_id);
838
839 switch(type)
840 {
841 case CFG_CMD_SAVE:
842 {
843 int i;
844 int last_cached_change;
845
846 // grab lock while accessing cached_change.
847 lock_slot(&slot_lock);
848 bdla(save_cmds_queued > 0);
849 save_cmds_queued--;
850 last_cached_change = cached_change;
851 //hold the file saving until no more change in last 3 seconds.
852 bdld("wait until no more changes in short time, cached change:%d", cached_change);
853 for(i = 0; i < 100; i ++) //5 minutes max waiting
854 {
855 // don't sleep if there is nothing to do
856 if(cached_change == 0)
857 break;
858 // release lock during sleep
859 unlock_slot(&slot_lock);
860 sleep(3);
861 lock_slot(&slot_lock);
862 if(last_cached_change == cached_change)
863 break;
864 last_cached_change = cached_change;
865 }
866 bdld("writing the bt_config.xml now, cached change:%d", cached_change);
867 if(cached_change > 0)
868 save_cfg();
869 unlock_slot(&slot_lock);
870 break;
871 }
872 }
873 }
874 #ifdef UNIT_TEST
cfg_test_load()875 static void cfg_test_load()
876 {
877 load_cfg();
878 char kname[128], vname[128];
879 short kpos, vpos;
880 int kname_size, vname_size;
881 bdld("list all remote devices values:");
882 kname_size = sizeof(kname);
883 kname[0] = 0;
884 kpos = 0;
885 do
886 {
887 kpos = btif_config_next_key(kpos, "Remote Devices", kname, &kname_size);
888 bdld("Remote devices:%s, size:%d", kname, kname_size);
889 vpos = 0;
890 vname[0] = 0;
891 vname_size = sizeof(vname);
892 while((vpos = btif_config_next_value(vpos, "Remote Devices", kname, vname, &vname_size)) != -1)
893 {
894 char v[128] = {0};
895 int vtype = BTIF_CFG_TYPE_STR;
896 int vsize = sizeof(v);
897 int ret = btif_config_get("Remote Devices", kname, vname, v, &vsize, &vtype);
898 bdld("btif_config_get return:%d, Remote devices:%s, value name:%s, value:%s, value size:%d, type:0x%x",
899 ret, kname, vname, v, vsize, vtype);
900
901 vname[0] = 0;
902 vname_size = sizeof(vname);
903 }
904 kname[0] = 0;
905 kname_size = sizeof(kname);
906 } while(kpos != -1);
907 }
cfg_test_write()908 static void cfg_test_write()
909 {
910 int i;
911
912 char key[128];
913 const char* section = "Remote";
914 char link_key[64];
915 for(i = 0; i < (int)sizeof(link_key); i++)
916 link_key[i] = i;
917 bdld("[start write testing");
918 if(btif_config_exist("test", "test cfg", "write"))
919 return;
920 btif_config_set_int("test", "test cfg", "write", 1);
921 for(i = 0; i < 50; i++)
922 {
923 if(i % 3 == 0)
924 sprintf(key, "Remote paired %d", i);
925 else sprintf(key, "Remote %d", i);
926 link_key[0] = i;
927 btif_config_set_str(section, key, "class", "smart phone");
928 if(i % 3 == 0)
929 {
930 if(i % 6 == 0)
931 btif_config_set(section, key, "LinkKey", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
932 else btif_config_set(section, key, "LE_KEY_LCSRK", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
933 }
934 btif_config_set_int(section, key, "count", i);
935 if(!btif_config_exist(section, key, "time stamp"))
936 btif_config_set_int(section, key, "time stamp", time(NULL));
937 }
938 static const char* exclude_filter[] =
939 {"LinkKey", "LE_KEY_PENC", "LE_KEY_PID", "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"};
940 const int max_allowed_remote_device = 40;
941 btif_config_filter_remove("Remote", exclude_filter, sizeof(exclude_filter)/sizeof(char*),
942 max_allowed_remote_device);
943 bdld("]end write testing");
944 btif_config_flush();
945 }
cfg_test_read()946 static void cfg_test_read()
947 {
948 //debug("in");
949 char class[128] = {0};
950 char link_key[128] = {0};
951 int size, type;
952 char key[128];
953 const char* section;
954 int ret, i;
955 for(i = 0; i < 100; i++)
956 {
957 sprintf(key, "00:22:5F:97:56:%02d", i);
958 section = "Remote";
959 size = sizeof(class);
960 ret = btif_config_get_str(section, key, "class", class, &size);
961 bdld("btif_config_get_str return:%d, Remote devices:%s, class:%s", ret, key, class);
962
963 size = sizeof(link_key);
964 type = BTIF_CFG_TYPE_BIN;
965 ret = btif_config_get(section, key, "link keys", link_key, &size, &type);
966 //debug("btif_config_get return:%d, Remote devices:%s, link key:%x, %x",
967 // ret, key, *(int *)link_key, *((int *)link_key + 1));
968
969 int timeout;
970 ret = btif_config_get_int(section, key, "connect time out", &timeout);
971 //debug("btif_config_get_int return:%d, Remote devices:%s, connect time out:%d", ret, key, timeout);
972 }
973
974 // debug("testing btif_config_remove");
975 size = sizeof(class);
976 type = BTIF_CFG_TYPE_STR;
977 btif_config_set("Remote", "00:22:5F:97:56:04", "Class Delete", class, strlen(class) + 1, BTIF_CFG_TYPE_STR);
978
979 btif_config_get("Remote", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
980 // debug("Remote devices, 00:22:5F:97:56:04 Class Delete:%s", class);
981 btif_config_remove("Remote", "00:22:5F:97:56:04", "Class Delete");
982
983 size = sizeof(class);
984 type = BTIF_CFG_TYPE_STR;
985 ret = btif_config_get("Remote", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
986 // debug("after removed, btif_config_get ret:%d, Remote devices, 00:22:5F:97:56:04 Class Delete:%s", ret, class);
987 // debug("out");
988 }
989
990
991 #endif
992