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 "btif_api.h"
48#include "btif_config.h"
49#include "btif_config_util.h"
50#include "btif_sock_thread.h"
51#include "btif_sock_util.h"
52
53#define asrt(s) if(!(s)) BTIF_TRACE_ERROR3 ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
54//#define UNIT_TEST
55#define CFG_PATH "/data/misc/bluedroid/"
56#define CFG_FILE_NAME "bt_config"
57#define CFG_FILE_EXT ".xml"
58#define CFG_FILE_EXT_OLD ".old"
59#define CFG_FILE_EXT_NEW ".new"
60#define CFG_GROW_SIZE (10*sizeof(cfg_node))
61#define GET_CHILD_MAX_COUNT(node) (short)((int)(node)->bytes / sizeof(cfg_node))
62#define IS_EMPTY(node) ((node)->name == NULL)
63#define GET_NODE_COUNT(bytes) (bytes / sizeof(cfg_node))
64#define MAX_NODE_BYTES 32000
65#define MAX_CACHED_COUNT 150
66#define CFG_CMD_SAVE 1
67
68#ifndef FALSE
69#define TRUE 1
70#define FALSE 0
71#endif
72typedef struct cfg_node_s
73{
74    const char* name;
75    union
76    {
77        struct cfg_node_s* child;
78        char* value;
79    };
80    short bytes;
81    short type;
82    short used;
83    short flag;
84} cfg_node;
85
86static pthread_mutex_t slot_lock;
87static int pth = -1; //poll thread handle
88static cfg_node root;
89static int cached_change;
90static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
91static inline short alloc_node(cfg_node* p, short grow);
92static inline void free_node(cfg_node* p);
93static inline void free_inode(cfg_node* p, int child);
94static inline short find_inode(const cfg_node* p, const char* name);
95static cfg_node* find_node(const char* section, const char* key, const char* name);
96static int remove_node(const char* section, const char* key, const char* name);
97static inline cfg_node* find_free_node(cfg_node* p);
98static int set_node(const char* section, const char* key, const char* name,
99                        const char* value, short bytes, short type);
100static int save_cfg();
101static void load_cfg();
102static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
103static int create_dir(const char* path);
104#ifdef UNIT_TEST
105static void cfg_test_load();
106static void cfg_test_write();
107static void cfg_test_read();
108#endif
109static inline void dump_node(const char* title, const cfg_node* p)
110{
111    if(p) {
112        BTIF_TRACE_DEBUG4("%s, p->name:%s, child/value:%p, bytes:%d",
113                          title, p->name, p->child, p->bytes);
114        BTIF_TRACE_DEBUG3("p->used:%d, type:%x, p->flag:%d",
115                          p->used, p->type, p->flag);
116    } else BTIF_TRACE_DEBUG1("%s is NULL", title);
117}
118////////////////////////////////////////////////////////////////////////////////////////////////////////////
119int btif_config_init()
120{
121    static int initialized;
122    BTIF_TRACE_DEBUG1("in initialized:%d", initialized);
123    if(!initialized)
124    {
125        initialized = 1;
126        struct stat st;
127        if(stat(CFG_PATH, &st) != 0)
128            BTIF_TRACE_ERROR1("%s does not exist, need provision", CFG_PATH);
129        btsock_thread_init();
130        init_slot_lock(&slot_lock);
131        lock_slot(&slot_lock);
132        root.name = "Bluedroid";
133        alloc_node(&root, CFG_GROW_SIZE);
134        dump_node("root", &root);
135        pth = btsock_thread_create(NULL, cfg_cmd_callback);
136        load_cfg();
137        unlock_slot(&slot_lock);
138        #ifdef UNIT_TEST
139            //cfg_test_load();
140            cfg_test_write();
141            cfg_test_read();
142        #endif
143    }
144    return pth >= 0;
145}
146int btif_config_get_int(const char* section, const char* key, const char* name, int* value)
147{
148    int size = sizeof(*value);
149    int type = BTIF_CFG_TYPE_INT;
150    return btif_config_get(section, key, name, (char*)value, &size, &type);
151}
152int btif_config_set_int(const char* section, const char* key, const char* name, int value)
153{
154    return btif_config_set(section, key, name, (char*)&value, sizeof(value), BTIF_CFG_TYPE_INT);
155}
156int btif_config_get_str(const char* section, const char* key, const char* name, char* value, int* size)
157{
158    int type = BTIF_CFG_TYPE_STR;
159    if(value)
160        *value = 0;
161    return btif_config_get(section, key, name, value, size, &type);
162}
163int btif_config_set_str(const char* section, const char* key, const char* name, const char* value)
164{
165   value = value ? value : "";
166   return btif_config_set(section, key, name, value, strlen(value) + 1, BTIF_CFG_TYPE_STR);
167}
168int btif_config_exist(const char* section, const char* key, const char* name)
169{
170    int ret = FALSE;
171    if(section && *section && key && *key)
172    {
173        lock_slot(&slot_lock);
174        ret = find_node(section, key, name) != NULL;
175        unlock_slot(&slot_lock);
176    }
177    return ret;
178}
179int btif_config_get(const char* section, const char* key, const char* name, char* value, int* bytes, int* type)
180{
181    int ret = FALSE;
182    asrt(section && *section && key && *key && name && *name && bytes && type);
183    //debug("section:%s, key:%s, name:%s, value:%p, bytes:%d, type:%d",
184    //            section, key, name, value, *bytes, *type);
185    if(section && *section && key && *key && name && *name && bytes && type)
186    {
187        lock_slot(&slot_lock);
188        const cfg_node* node = find_node(section, key, name);
189        dump_node("found node", node);
190        if(node)
191        {
192            if(*type == node->type && value && *bytes >= node->used)
193            {
194                if(node->used > 0)
195                    memcpy(value, node->value, node->used);
196                ret = TRUE;
197            }
198            *type = node->type;
199            *bytes = node->used;
200            if(ret != TRUE)
201            {
202                if(*type != node->type)
203                    BTIF_TRACE_ERROR3("value:%s, wrong type:%d, need to be type: %d",
204                                      name, *type, node->type);
205                if(value && *bytes < node->used)
206                    BTIF_TRACE_ERROR3("value:%s, not enough size: %d bytes, need %d bytes",
207                                      name, node->used, *bytes);
208            }
209        }
210        unlock_slot(&slot_lock);
211    }
212    //debug("out");
213    return ret;
214}
215int btif_config_set(const char* section, const char* key, const char* name, const char*  value, int bytes, int type)
216{
217    int ret = FALSE;
218    asrt(section && *section && key && *key && name && *name);
219    asrt(bytes < MAX_NODE_BYTES);
220    if(section && *section && key && *key && name && *name && bytes < MAX_NODE_BYTES)
221    {
222        lock_slot(&slot_lock);
223        ret = set_node(section, key, name, value, (short)bytes, (short)type);
224        if(ret && !(type & BTIF_CFG_TYPE_VOLATILE) && ++cached_change > MAX_CACHED_COUNT)
225        {
226            cached_change = 0;
227            btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
228        }
229
230        unlock_slot(&slot_lock);
231    }
232    return ret;
233}
234int btif_config_remove(const char* section, const char* key, const char* name)
235{
236    asrt(section && *section && key && *key);
237    int ret = FALSE;
238    if(section && *section && key && *key)
239    {
240         lock_slot(&slot_lock);
241         ret = remove_node(section, key, name);
242         if(ret)
243            cached_change++;
244         unlock_slot(&slot_lock);
245    }
246    return ret;
247}
248typedef struct {
249    short si;
250    short ki;
251    short vi;
252    short reserved;
253} cfg_node_pos;
254short btif_config_next_key(short pos, const char* section, char * name, int* bytes)
255{
256    int next = -1;
257    lock_slot(&slot_lock);
258    short si = find_inode(&root, section);
259    if(si >= 0)
260    {
261        const cfg_node* section_node = &root.child[si];
262        next = find_next_node(section_node, pos, name, bytes);
263    }
264    unlock_slot(&slot_lock);
265    return next;
266}
267short btif_config_next_value(short pos, const char* section, const char* key, char* name, int* bytes)
268{
269    int next = -1;
270    lock_slot(&slot_lock);
271    short si = find_inode(&root, section);
272    if(si >= 0)
273    {
274        const cfg_node* section_node = &root.child[si];
275        short ki = find_inode(section_node, key);
276        if(ki >= 0)
277        {
278            const cfg_node* key_node = &section_node->child[ki];
279            next = find_next_node(key_node, pos, name, bytes);
280        }
281    }
282    unlock_slot(&slot_lock);
283    return next;
284}
285int btif_config_enum(btif_config_enum_callback cb, void* user_data)
286{
287    asrt(cb);
288    if(!cb)
289        return FALSE;
290    lock_slot(&slot_lock);
291    int si, ki, vi;
292    cfg_node *section_node, *key_node, *value_node;
293    for(si = 0; si < GET_CHILD_MAX_COUNT(&root); si++)
294    {
295        section_node = &root.child[si];
296        if(section_node->name && *section_node->name)
297        {
298            for(ki = 0; ki < GET_CHILD_MAX_COUNT(section_node); ki++)
299            {
300                key_node = &section_node->child[ki];
301                if(key_node->name && *key_node->name)
302                {
303                    for(vi = 0; vi < GET_CHILD_MAX_COUNT(key_node); vi++)
304                    {
305                        value_node = &key_node->child[vi];
306                        if(value_node->name && *value_node->name)
307                        {
308                            cb(user_data, section_node->name, key_node->name, value_node->name,
309                                            value_node->value, value_node->used, value_node->type);
310                        }
311                    }
312                }
313            }
314        }
315    }
316    unlock_slot(&slot_lock);
317    return TRUE;
318}
319int btif_config_save()
320{
321    lock_slot(&slot_lock);
322    if(cached_change > 0)
323    {
324        cached_change = 0;
325        btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
326    }
327    unlock_slot(&slot_lock);
328    return TRUE;
329}
330void btif_config_flush()
331{
332    lock_slot(&slot_lock);
333    if(cached_change > 0)
334        save_cfg();
335    unlock_slot(&slot_lock);
336}
337/////////////////////////////////////////////////////////////////////////////////////////////
338static inline short alloc_node(cfg_node* p, short grow)
339{
340    int new_bytes = p->bytes + grow;
341    //debug("in, bytes:%d, new bytes:%d, grow:%d", p->bytes, new_bytes, grow);
342    if(grow > 0 && new_bytes < MAX_NODE_BYTES)
343    {
344        char* value = (char*)realloc(p->value, new_bytes);
345        if(value)
346        {
347            short old_bytes = p->bytes;
348            //clear to zero
349            memset(value + old_bytes, 0, grow);
350            p->bytes = old_bytes + grow;
351            p->value = value;
352            //debug("out");
353            return old_bytes;//return the previous size
354        }
355        else BTIF_TRACE_ERROR3("realloc failed, old_bytes:%d, grow:%d, total:%d", p->bytes, grow,  p->bytes + grow);
356    }
357    //debug("out, alloc failed");
358    return -1;
359}
360static inline void free_node(cfg_node* p)
361{
362    if(p)
363    {
364        if(p->child)
365        {
366            free(p->child);
367            p->child = NULL;
368        }
369        if(p->name)
370        {
371            free((void*)p->name);
372            p->name = 0;
373        }
374        p->used = p->bytes = p->flag = p->type = 0;
375    }
376}
377static inline short find_inode(const cfg_node* p, const char* name)
378{
379    //debug("in");
380    if(p && p->child && name && *name)
381    {
382        int i;
383        int count = GET_CHILD_MAX_COUNT(p);
384        //debug("child name:%s, child max count:%d", name, count);
385        for(i = 0; i < count; i++)
386        {
387            if(p->child[i].name && *p->child[i].name &&
388                strcmp(p->child[i].name, name) == 0)
389            {
390                  //debug("out found child index:%d", i);
391                  return (short)i;
392            }
393        }
394    }
395    //debug("out, child name: %s not found", name);
396    return -1;
397}
398static inline cfg_node* find_free_node(cfg_node* p)
399{
400    if(p && p->child)
401    {
402        int i;
403        int count = GET_CHILD_MAX_COUNT(p);
404        //debug("p->name:%s, max child count:%d", p->name, count);
405        for(i = 0; i < count; i++)
406        {
407            if(IS_EMPTY(p->child + i))
408                return p->child + i;
409        }
410    }
411    return NULL;
412}
413static cfg_node* find_add_node(cfg_node* p, const char* name)
414{
415    int i = -1;
416    cfg_node* node = NULL;
417    //debug("in, p->name:%s, p->bytes:%d, adding child:%s", p->name, p->bytes, name);
418    if((i = find_inode(p, name)) < 0)
419    {
420        if(!(node = find_free_node(p)))
421        {
422            int old_size = alloc_node(p, CFG_GROW_SIZE);
423            if(old_size >= 0)
424            {
425                i = GET_NODE_COUNT(old_size);
426                node = &p->child[i];
427            }
428        }
429    }
430    else node = &p->child[i];
431    if(!node->name)
432        node->name = strdup(name);
433    //debug("out");
434    return node;
435}
436static int set_node(const char* section, const char* key, const char* name,
437                    const char* value, short bytes, short type)
438{
439    int si = -1, ki = -1, vi = -1;
440    cfg_node* section_node = NULL;
441    //debug("in");
442    //dump_node("root", &root);
443    if((section_node = find_add_node(&root, section)))
444    {
445        //dump_node("section node", section_node);
446        cfg_node* key_node;
447        if((key_node = find_add_node(section_node, key)))
448        {
449            //dump_node("key node", key_node);
450            cfg_node* value_node;
451            if((value_node = find_add_node(key_node, name)))
452            {
453                //dump_node("value node", value_node);
454                if(value_node->bytes < bytes)
455                {
456                    if(value_node->value)
457                        free(value_node->value);
458                    value_node->value = (char*)malloc(bytes);
459                    if(value_node->value)
460                        value_node->bytes = bytes;
461                    else
462                    {
463                        BTIF_TRACE_ERROR0("not enough memory!");
464                        value_node->bytes = 0;
465                        return FALSE;
466                    }
467                }
468                if(value_node->value && value != NULL && bytes > 0)
469                    memcpy(value_node->value, value, bytes);
470                value_node->type = type;
471                value_node->used = bytes;
472                //dump_node("changed value node", value_node);
473                return TRUE;
474            }
475        }
476    }
477    return FALSE;
478}
479static cfg_node* find_node(const char* section, const char* key, const char* name)
480{
481    int si = -1, ki = -1, vi = -1;
482    if((si = find_inode(&root, section)) >= 0)
483    {
484        cfg_node* section_node = &root.child[si];
485        if(key)
486        {
487            //dump_node("found section node", section_node);
488            if((ki = find_inode(section_node, key)) >= 0)
489            {
490                cfg_node* key_node = &section_node->child[ki];
491                //dump_node("found key node", key_node);
492                if(name)
493                {
494                    if((vi = find_inode(key_node, name)) >= 0)
495                    {
496                        //dump_node("found value node", &key_node->child[vi]);
497                        return &key_node->child[vi];
498                    }
499                    //debug("value node:%s not found", name);
500                    return NULL;
501                }
502                return key_node;
503            }
504            //debug("key node:%s not found", key);
505            return NULL;
506        }
507        return section_node;
508    }
509    //debug("section node:%s not found", section);
510    return NULL;
511}
512static short find_next_node(const cfg_node* p, short start, char* name, int* bytes)
513{
514    asrt(0 <= start && start < GET_CHILD_MAX_COUNT(p));
515    //debug("in, start:%d, max child count:%d", start, GET_CHILD_MAX_COUNT(p));
516    //dump_node("find_next_node, parent", p);
517    short next = -1;
518    if(name) *name = 0;
519    if(0 <= start && start < GET_CHILD_MAX_COUNT(p))
520    {
521        int i;
522        for(i = start; i < GET_CHILD_MAX_COUNT(p); i++)
523        {
524            cfg_node* child = &p->child[i];
525            if(child->name)
526            {
527                int name_bytes = strlen(child->name) + 1;
528                if(name && bytes && *bytes >= name_bytes)
529                {
530                    memcpy(name, child->name, name_bytes);
531                    if(i + 1 < GET_CHILD_MAX_COUNT(p))
532                        next = (short)(i + 1);
533                    *bytes = name_bytes;
534                }
535                else if(bytes)
536                {
537                    //debug("not enough room to copy the name, size in:%d, size needed:%d", *bytes, name_bytes);
538                    *bytes = name_bytes;
539                }
540                break;
541            }
542        }
543    }
544    return next;
545}
546static int remove_node(const char* section, const char* key, const char* name)
547{
548    short  si = -1, ki = -1, vi = -1;
549    if((si = find_inode(&root, section)) >= 0)
550    {
551        cfg_node* section_node = &root.child[si];
552        if((ki = find_inode(section_node, key)) >= 0)
553        {
554            cfg_node* key_node = &section_node->child[ki];
555            if(name == NULL)
556            {
557                int count = GET_CHILD_MAX_COUNT(key_node);
558                int i;
559                for(i = 0; i < count; i++)
560                    free_node(&key_node->child[i]);
561                free_node(key_node);
562                return TRUE;
563            }
564            else if((vi = find_inode(key_node, name)) >= 0)
565            {
566                //debug("remove value:%s", key_node->child[vi].name);
567                free_node(&key_node->child[vi]);
568                return TRUE;
569            }
570        }
571    }
572    return FALSE;
573}
574static int save_cfg()
575{
576    const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
577    const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
578    const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
579    int ret = FALSE;
580    if(access(file_name_old,  F_OK) == 0)
581        unlink(file_name_old);
582    if(access(file_name_new, F_OK) == 0)
583        unlink(file_name_new);
584   if(btif_config_save_file(file_name_new))
585    {
586        cached_change = 0;
587        chown(file_name_new, -1, AID_NET_BT_STACK);
588        chmod(file_name_new, 0660);
589        rename(file_name, file_name_old);
590        rename(file_name_new, file_name);
591        ret = TRUE;
592    }
593    else BTIF_TRACE_ERROR0("btif_config_save_file failed");
594    return ret;
595}
596
597static int load_bluez_cfg()
598{
599    char adapter_path[256];
600    if(load_bluez_adapter_info(adapter_path, sizeof(adapter_path)))
601    {
602        if(load_bluez_linkkeys(adapter_path))
603            return TRUE;
604    }
605    return FALSE;
606}
607static void remove_bluez_cfg()
608{
609    rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
610}
611static void clean_newline_char()
612{
613    char kname[128], vname[128];
614    short kpos = 0;
615    int kname_size, vname_size;
616    vname[0] = 0;
617    vname_size = sizeof(vname);
618    //BTIF_TRACE_DEBUG0("removing newline at the end of the adapter and device name");
619    if(btif_config_get_str("Local", "Adapter", "Name", vname, &vname_size) &&
620        vname_size > 2)
621    {
622        if(vname[vname_size - 2] == '\n')
623        {
624            BTIF_TRACE_DEBUG1("remove newline at the end of the adapter name:%s", vname);
625            vname[vname_size - 2] = 0;
626            btif_config_set_str("Local", "Adapter", "Name", vname);
627        }
628    }
629    do
630    {
631        kname_size = sizeof(kname);
632        kname[0] = 0;
633        kpos = btif_config_next_key(kpos, "Remote", kname, &kname_size);
634        //BTIF_TRACE_DEBUG2("Remote device:%s, size:%d", kname, kname_size);
635        vname_size = sizeof(vname);
636        vname[0] = 0;
637        if(btif_config_get_str("Remote", kname, "Name", vname, &vname_size) &&
638            vname_size > 2)
639        {
640            BTIF_TRACE_DEBUG1("remote device name:%s", vname);
641            if(vname[vname_size - 2] == '\n')
642            {
643                BTIF_TRACE_DEBUG1("remove newline at the end of the device name:%s", vname);
644                vname[vname_size - 2] = 0;
645                btif_config_set_str("Remote", kname, "Name", vname);
646            }
647        }
648     } while(kpos != -1);
649}
650static void load_cfg()
651{
652    const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
653    const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
654    const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
655    if(!btif_config_load_file(file_name))
656    {
657        unlink(file_name);
658        if(!btif_config_load_file(file_name_old))
659        {
660            unlink(file_name_old);
661            if(load_bluez_cfg() && save_cfg())
662                remove_bluez_cfg();
663        }
664    }
665    int bluez_migration_done = 0;
666    btif_config_get_int("Local", "Adapter", "BluezMigrationDone", &bluez_migration_done);
667    if(!bluez_migration_done)
668    {
669        //clean the new line char at the end of the device name. Caused by bluez config import bug
670        clean_newline_char();
671        btif_config_set_int("Local", "Adapter", "BluezMigrationDone", 1);
672        btif_config_save();
673    }
674}
675static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id)
676{
677  //BTIF_TRACE_DEBUG2("cmd type:%d, size:%d", type, size);
678    switch(type)
679    {
680        case CFG_CMD_SAVE:
681            lock_slot(&slot_lock);
682            save_cfg();
683            unlock_slot(&slot_lock);
684            break;
685    }
686}
687#ifdef UNIT_TEST
688static void cfg_test_load()
689{
690    load_cfg();
691    char kname[128], vname[128];
692    short kpos, vpos;
693    int kname_size, vname_size;
694    BTIF_TRACE_DEBUG0("list all remote devices values:");
695    kname_size = sizeof(kname);
696    kname[0] = 0;
697    kpos = 0;
698    do
699    {
700        kpos = btif_config_next_key(kpos, "Remote Devices", kname, &kname_size);
701        BTIF_TRACE_DEBUG2("Remote devices:%s, size:%d", kname, kname_size);
702        vpos = 0;
703        vname[0] = 0;
704        vname_size = sizeof(vname);
705        while((vpos = btif_config_next_value(vpos, "Remote Devices", kname, vname, &vname_size)) != -1)
706        {
707            char v[128] = {0};
708            int vtype = BTIF_CFG_TYPE_STR;
709            int vsize = sizeof(v);
710            int ret = btif_config_get("Remote Devices", kname, vname, v, &vsize, &vtype);
711            BTIF_TRACE_DEBUG6("btif_config_get return:%d, Remote devices:%s, value name:%s, value:%s, value size:%d, type:0x%x",
712                              ret, kname, vname, v, vsize, vtype);
713
714            vname[0] = 0;
715            vname_size = sizeof(vname);
716        }
717        kname[0] = 0;
718        kname_size = sizeof(kname);
719    } while(kpos != -1);
720}
721static void cfg_test_write()
722{
723    int i;
724
725    char key[128];
726    const char* section;
727    char link_key[64];
728    for(i = 0; i < (int)sizeof(link_key); i++)
729        link_key[i] = i;
730    for(i = 0; i < 100; i++)
731    {
732        sprintf(key, "00:22:5F:97:56:%02d", i);
733        link_key[0] = i;
734        section = "Remote Devices";
735        btif_config_set_str(section, key, "class", "smart phone");
736        btif_config_set(section, key, "link keys", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
737        btif_config_set_int(section, key, "connect time out", i);
738    }
739    btif_config_save();
740}
741static void cfg_test_read()
742{
743    //debug("in");
744    char class[128] = {0};
745    char link_key[128] = {0};
746    int size, type;
747    char key[128];
748    const char* section;
749    int ret, i;
750    for(i = 0; i < 100; i++)
751    {
752        sprintf(key, "00:22:5F:97:56:%02d", i);
753        section = "Remote Devices";
754        size = sizeof(class);
755        ret = btif_config_get_str(section, key, "class", class, &size);
756        BTIF_TRACE_DEBUG3("btif_config_get_str return:%d, Remote devices:%s, class:%s", ret, key, class);
757
758        size = sizeof(link_key);
759        type = BTIF_CFG_TYPE_BIN;
760        ret = btif_config_get(section, key, "link keys", link_key, &size, &type);
761        //debug("btif_config_get return:%d, Remote devices:%s, link key:%x, %x",
762        //            ret, key, *(int *)link_key, *((int *)link_key + 1));
763
764        int timeout;
765        ret = btif_config_get_int(section, key, "connect time out", &timeout);
766        //debug("btif_config_get_int return:%d, Remote devices:%s, connect time out:%d", ret, key, timeout);
767    }
768
769    // debug("testing btif_config_remove");
770    size = sizeof(class);
771    type = BTIF_CFG_TYPE_STR;
772    btif_config_set("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, strlen(class) + 1, BTIF_CFG_TYPE_STR);
773
774    btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
775    // debug("Remote devices, 00:22:5F:97:56:04 Class Delete:%s", class);
776    btif_config_remove("Remote Devices", "00:22:5F:97:56:04", "Class Delete");
777
778    size = sizeof(class);
779    type = BTIF_CFG_TYPE_STR;
780    ret = btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
781    // debug("after removed, btif_config_get ret:%d, Remote devices, 00:22:5F:97:56:04 Class Delete:%s", ret, class);
782    // debug("out");
783}
784#endif
785