• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <stdio.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/statfs.h>
25 #include <sys/vfs.h>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <limits.h>
29 #include <sys/file.h>
30 #include <sys/mman.h>
31 
32 #include "btif_config.h"
33 #include "btif_config_util.h"
34 #ifndef ANDROID_NDK
35 #define ANDROID_NDK
36 #endif
37 #include "tinyxml2.h"
38 #ifndef FALSE
39 #define TRUE 1
40 #define FALSE 0
41 #endif
42 #define LOG_TAG "btif_config_util"
43 extern "C" {
44 #include "btif_sock_util.h"
45 }
46 #include <stdlib.h>
47 #include <cutils/log.h>
48 #define info(fmt, ...)  ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__,  ## __VA_ARGS__)
49 #define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__,  ## __VA_ARGS__)
50 #define warn(fmt, ...) ALOGW ("## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
51 #define error(fmt, ...) ALOGE ("## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
52 #define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
53 
54 #define BLUEDROID_ROOT "Bluedroid"
55 #define BLUEDROID_NAME_TAG "Tag"
56 #define BLUEDROID_VALUE_TYPE "Type"
57 #define BLUEDROID_TAG_REMOTE_DEVICE "Remote Devices"
58 
59 using namespace tinyxml2;
60 struct enum_user_data
61 {
62     const char* sn; //current section name
63     const char* kn; //current key name
64     const char* vn; //current value name
65     int si, ki, vi;
66     XMLDocument* xml;
67     XMLElement* se;
68     XMLElement* ke;
69     XMLElement* ve;
70 };
71 
72 
73 static int type_str2int(const char* type);
74 static const char* type_int2str(int type);
75 static inline void create_ele_name(int index, char* element, int len);
76 static inline int validate_ele_name(const char* key);
77 static int parse_sections(const char* section_name, const XMLElement* section);
78 static void enum_config(void* user_data, const char* section, const char* key, const char* name,
79                                           const char*  value, int bytes, int type);
bytes2hex(const char * data,int bytes,char * str)80 static inline void bytes2hex(const char* data, int bytes, char* str)
81 {
82     static const char* hex_table = "0123456789abcdef";
83     for(int i = 0; i < bytes; i++)
84     {
85         *str = hex_table[(data[i] >> 4) & 0xf];
86         ++str;
87         *str = hex_table[data[i] & 0xf];
88         ++str;
89     }
90     *str = 0;
91 }
hex2byte(char hex)92 static inline int hex2byte(char hex)
93 {
94     if('0' <= hex && hex <= '9')
95         return hex - '0';
96     if('a' <= hex && hex <= 'z')
97         return hex - 'a' + 0xa;
98     if('A' <= hex && hex <= 'Z')
99         return hex - 'A' + 0xa;
100     return -1;
101 }
trim_bin_str_value(const char ** str)102 static inline int trim_bin_str_value(const char** str)
103 {
104     while(**str == ' ' || **str == '\r' || **str == '\t' || **str == '\n')
105         (*str)++;
106     int len = 0;
107     const char* s = *str;
108     while(*s && *s != ' ' && *s != '\r' && *s != '\t' && *s != '\n')
109     {
110         len++;
111         s++;
112     }
113     return len;
114 }
hex2bytes(const char * str,int len,char * data)115 static inline bool hex2bytes(const char* str, int len, char* data)
116 {
117     if(len % 2)
118     {
119         error("cannot convert odd len hex str: %s, len:%d to binary", str, len);
120         return false;
121     }
122     for(int i = 0; i < len; i+= 2)
123     {
124         int d = hex2byte(str[i]);
125         if(d < 0)
126         {
127             error("cannot convert hex: %s, len:%d to binary", str, len);
128             return false;
129         }
130         *data = (char)(d << 4);
131         d = hex2byte(str[i+1]);
132         if(d < 0)
133         {
134             error("cannot convert hex: %s, len:%d to binary", str, len);
135             return false;
136         }
137         *data++ |= (char)d;
138     }
139     return true;
140 }
reverse_bin(char * bin,int size)141 static inline void reverse_bin(char *bin, int size)
142 {
143     for(int i = 0; i < size /2; i++)
144     {
145         int b = bin[i];
146         bin[i] = bin[size - i - 1];
147         bin[size -i  - 1] = b;
148     }
149 }
150 ////////////////////////////////////////////////////////////////////////////////////////////////////////
btif_config_save_file(const char * file_name)151 int btif_config_save_file(const char* file_name)
152 {
153     debug("in file name:%s", file_name);
154     XMLDocument xml;
155     XMLElement* root = xml.NewElement(BLUEDROID_ROOT);
156     xml.InsertFirstChild(root);
157     int ret = FALSE;
158     enum_user_data data;
159     memset(&data, 0, sizeof(data));
160     data.xml = &xml;
161     if(btif_config_enum(enum_config, &data))
162         ret = xml.SaveFile(file_name) == XML_SUCCESS;
163     return ret;
164 }
btif_config_load_file(const char * file_name)165 int btif_config_load_file(const char* file_name)
166 {
167     //if(access(file_name, 0) != 0)
168     //    return XML_ERROR_FILE_NOT_FOUND;
169     XMLDocument xml;
170     int err = xml.LoadFile(file_name);
171     const XMLElement* root = xml.RootElement();
172     int ret = FALSE;
173     if(err == XML_SUCCESS && root && strcmp(root->Name(), BLUEDROID_ROOT) == 0)
174     {
175         const XMLElement* section;
176         for(section = root->FirstChildElement(); section; section = section->NextSiblingElement())
177         {
178             //debug("section tag:%s", section->Name());
179             if(validate_ele_name(section->Name()))
180             {
181                 const char* section_name = section->Attribute(BLUEDROID_NAME_TAG);
182                 if(section_name && *section_name)
183                     if(parse_sections(section_name, section))
184                         ret = TRUE;
185             }
186         }
187     }
188     return ret;
189 }
190 //////////////////////////////////////////////////////////////////////////////////////////////////////////
parse_sections(const char * section_name,const XMLElement * section)191 static int parse_sections(const char* section_name, const XMLElement* section)
192 {
193     const XMLElement* key;
194     //debug("in");
195     for(key = section->FirstChildElement(); key; key = key->NextSiblingElement())
196     {
197         //debug("key tag:%s", key->Name());
198         if(validate_ele_name(key->Name()))
199         {
200             const char* key_name = key->Attribute(BLUEDROID_NAME_TAG);
201             //debug("key name:%s", key_name);
202             if(key_name && *key_name)
203             {
204                 const XMLElement* value;
205                 for(value = key->FirstChildElement(); value; value = value->NextSiblingElement())
206                 {
207                     const char* value_name = value->Attribute(BLUEDROID_NAME_TAG);
208                     const char* value_type = value->Attribute(BLUEDROID_VALUE_TYPE);
209                     //debug("value ele name:%s, section name:%s, key name:%s, value name:%s, value type:%s",
210                     //        value->Name(), section_name, key_name, value_name, value_type);
211                     int type = type_str2int(value_type);
212                     if(value_name && *value_name && type != BTIF_CFG_TYPE_INVALID)
213                     {
214                         const char* value_str = value->GetText() ? value->GetText() : "";
215                         //debug("value_name:%s, value_str:%s, value_type:%s, type:%x",
216                         //       value_name, value_str, value_type, type);
217                         if(type & BTIF_CFG_TYPE_STR)
218                             btif_config_set_str(section_name, key_name, value_name, value_str);
219                         else if(type & BTIF_CFG_TYPE_INT)
220                         {
221                             if(*value_str)
222                             {
223                                 int v = atoi(value_str);
224                                 btif_config_set_int(section_name, key_name, value_name, v);
225                             }
226                         }
227                         else if(type & BTIF_CFG_TYPE_BIN)
228                         {
229                             int len = trim_bin_str_value(&value_str);
230                             if(len > 0 && len % 2 == 0)
231                             {
232                                 char *bin = (char*)alloca(len / 2);
233                                 if(hex2bytes(value_str, len, bin))
234                                     btif_config_set(section_name, key_name, value_name, bin, len/2, BTIF_CFG_TYPE_BIN);
235                             }
236                         }
237                         else error("Unsupported value:%s, type:%s not loaded", value_name, value_type);
238                     }
239                 }
240             }
241         }
242     }
243     //debug("out");
244     return TRUE;
245 }
add_ele(XMLDocument * xml,XMLElement * p,int index,const char * name_tag,const char * value_type=NULL)246 static inline XMLElement* add_ele(XMLDocument* xml, XMLElement* p, int index,
247                                   const char* name_tag, const char* value_type = NULL)
248 {
249     //debug("in, tag:%s", name_tag);
250     char ele_name[128] = {0};
251     create_ele_name(index, ele_name, sizeof(ele_name));
252     XMLElement* ele = xml->NewElement(ele_name);
253     //debug("ele name:%s, tag:%s, index:%d, value type:%s", ele_name, name_tag, index, value_type);
254     ele->SetAttribute(BLUEDROID_NAME_TAG, name_tag);
255     if(value_type && *value_type)
256         ele->SetAttribute(BLUEDROID_VALUE_TYPE, value_type);
257     p->InsertEndChild(ele);
258     //debug("out, tag:%s", name_tag);
259     return ele;
260 }
enum_config(void * user_data,const char * section_name,const char * key_name,const char * value_name,const char * value,int bytes,int type)261 static void enum_config(void* user_data, const char* section_name, const char* key_name, const char* value_name,
262                         const char*  value, int bytes, int type)
263 {
264     enum_user_data& d = *(enum_user_data*)user_data;
265     //debug("in, key:%s, value:%s", key_name, value_name);
266     //debug("section name:%s, key name:%s, value name:%s, value type:%s",
267     //                      section_name, key_name, value_name, type_int2str(type));
268     if(type & BTIF_CFG_TYPE_VOLATILE)
269         return; //skip any volatile value
270     if(d.sn != section_name)
271     {
272         d.sn = section_name;
273         d.se = add_ele(d.xml, d.xml->RootElement(), ++d.si, section_name);
274         d.ki = 0;
275     }
276     if(d.kn != key_name)
277     {
278         d.kn = key_name;
279         d.ke = add_ele(d.xml, d.se, ++d.ki, key_name);
280         d.vi = 0;
281     }
282     if(d.vn != value_name)
283     {
284         if(type & BTIF_CFG_TYPE_STR)
285         {
286             d.vn = value_name;
287             d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
288             d.ve->InsertFirstChild(d.xml->NewText(value));
289         }
290         else if(type & BTIF_CFG_TYPE_INT)
291         {
292             d.vn = value_name;
293             d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
294             char value_str[64] = {0};
295             snprintf(value_str, sizeof(value_str), "%d", *(int*)value);
296             d.ve->InsertFirstChild(d.xml->NewText(value_str));
297         }
298         else if(type & BTIF_CFG_TYPE_BIN)
299         {
300             d.vn = value_name;
301             d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
302             char* value_str = (char*)alloca(bytes*2 + 1);
303             bytes2hex(value, bytes, value_str);
304             d.ve->InsertFirstChild(d.xml->NewText(value_str));
305         }
306         else error("unsupported config value name:%s, type:%s not saved", d.vn, type_int2str(type));
307     }
308     //debug("out, key:%s, value:%s", key_name, value_name);
309 }
310 
type_str2int(const char * type)311 static int type_str2int(const char* type)
312 {
313     if(strcmp(type, "int") == 0)
314         return BTIF_CFG_TYPE_INT;
315     if(strcmp(type, "binary") == 0)
316         return BTIF_CFG_TYPE_BIN;
317     if(type == 0 || *type == 0 || strcmp(type, "string") == 0)
318         return  BTIF_CFG_TYPE_STR;
319     error("unknown value type:%s", type);
320     return BTIF_CFG_TYPE_INVALID;
321 }
type_int2str(int type)322 static const char* type_int2str(int type)
323 {
324     switch(type)
325     {
326         case BTIF_CFG_TYPE_INT:
327             return "int";
328         case BTIF_CFG_TYPE_BIN:
329             return "binary";
330         case BTIF_CFG_TYPE_STR:
331             return "string";
332         default:
333             error("unknown type:%d", type);
334             break;
335     }
336     return NULL;
337 }
338 
create_ele_name(int index,char * element,int len)339 static inline void create_ele_name(int index, char* element, int len)
340 {
341     snprintf(element, len, "N%d", index);
342 }
validate_ele_name(const char * key)343 static inline int validate_ele_name(const char* key)
344 {
345     //must be 'N' followed with numbers
346     if(key && *key == 'N' && *++key)
347     {
348         while(*key)
349         {
350             if(*key < '0' || *key > '9')
351                 return FALSE;
352             ++key;
353         }
354         return TRUE;
355     }
356     return FALSE;
357 }
open_file_map(const char * pathname,const char ** map,int * size)358 static int open_file_map(const char *pathname, const char**map, int* size)
359 {
360     struct stat st;
361     st.st_size = 0;
362     int fd;
363     //debug("in");
364     if((fd = open(pathname, O_RDONLY)) >= 0)
365     {
366         //debug("fd:%d", fd);
367         if(fstat(fd, &st) == 0 && st.st_size)
368         {
369             *size = st.st_size;
370             *map = (const char*)mmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0);
371             if(*map && *map != MAP_FAILED)
372             {
373                 //debug("out map:%p, size:%d", *map, *size);
374                 return fd;
375             }
376         }
377         close(fd);
378     }
379     //debug("out, failed");
380     return -1;
381 }
close_file_map(int fd,const char * map,int size)382 static void close_file_map(int fd, const char* map, int size)
383 {
384     munmap((void*)map, size);
385     close(fd);
386 }
read_file_line(const char * map,int start_pos,int size,int * line_size)387 static int read_file_line(const char* map, int start_pos, int size, int* line_size)
388 {
389     *line_size = 0;
390     //debug("in, start pos:%d, size:%d", start_pos, size);
391     int i;
392     for(i = start_pos; i < size; i++)
393     {
394         if(map[i] == '\r' || map[i] == '\n')
395             break;
396          ++*line_size;
397     }
398     //debug("out, ret:%d, start pos:%d, size:%d, line_size:%d", i, start_pos, size, *line_size);
399     return i + 1;
400 }
find_value_line(const char * map,int size,const char * key,int * value_size)401 static const char* find_value_line(const char* map, int size, const char *key, int* value_size)
402 {
403     int key_len = strlen(key);
404     int i;
405     for(i = 0; i < size; i++)
406     {
407         if(map[i] == *key)
408         {
409             if(i + key_len + 1 > size)
410                 return NULL;
411             if(memcmp(map + i, key, key_len) == 0)
412             {
413                 read_file_line(map, i + key_len + 1, size, value_size);
414                 if(*value_size)
415                     return map + i + key_len + 1;
416                 break;
417             }
418         }
419     }
420     return NULL;
421 }
read_line_word(const char * line,int start_pos,int line_size,char * word,int * word_size,bool lower_case=false)422 static int read_line_word(const char* line, int start_pos, int line_size, char* word, int *word_size, bool lower_case = false)
423 {
424     int i;
425     //skip space
426     //debug("in, line start_pos:%d, line_size:%d", start_pos, line_size);
427     for(i = start_pos; i < line_size; i++)
428     {
429         //debug("skip space loop, line[%d]:%c", i, line[i]);
430         if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n')
431             break;
432     }
433     *word_size = 0;
434     for(; i < line_size; i++)
435     {
436         //debug("add word loop, line[%d]:%c", i, line[i]);
437         if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n')
438         {
439             ++*word_size;
440             if(lower_case && 'A' <= line[i] && line[i] <= 'Z')
441                 *word++ = 'a' - 'A' + line[i];
442             else
443                 *word++ = line[i];
444         }
445         else break;
446     }
447     *word = 0;
448     //debug("out, ret:%d, word:%s, word_size:%d, line start_pos:%d, line_size:%d",
449     //            i, word, *word_size, start_pos, line_size);
450     return i;
451 }
is_valid_bd_addr(const char * addr)452 static int is_valid_bd_addr(const char* addr)
453 {
454     int len = strlen(addr);
455     //debug("addr: %s, len:%d", addr, len);
456     return len == 17 && addr[2] == ':' && addr[5] == ':' && addr[14] == ':';
457 }
load_bluez_cfg_value(const char * adapter_path,const char * file_name)458 static int load_bluez_cfg_value(const char* adapter_path, const char* file_name)
459 {
460     //debug("in");
461 
462     const char* map = NULL;
463     int size = 0;
464     int ret = FALSE;
465     char path[256];
466     snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name);
467     int fd = open_file_map(path, &map, &size);
468     //debug("in, path:%s, fd:%d, size:%d", path, fd, size);
469     if(fd < 0 || size == 0)
470     {
471         error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
472         //debug("out");
473         return FALSE;
474     }
475     //get local bt device name from bluez config
476     int line_size = 0;
477     const char *value_line = find_value_line(map, size, "name", &line_size);
478     if(value_line && line_size > 0)
479     {
480         char value[line_size + 1];
481         memcpy(value, value_line, line_size);
482         value[line_size] = 0;
483         //debug("import local bt dev names:%s", value);
484         btif_config_set_str("Local", "Adapter", "Name", value);
485         ret = TRUE;
486     }
487 
488     close_file_map(fd, map, size);
489     //debug("out, ret:%d", ret);
490     return ret;
491 }
492 
load_bluez_adapter_info(char * adapter_path,int size)493 int load_bluez_adapter_info(char* adapter_path, int size)
494 {
495     struct dirent *dptr;
496     DIR *dirp;
497     int ret = FALSE;
498     if((dirp = opendir(BLUEZ_PATH)) != NULL)
499     {
500         while((dptr = readdir(dirp)) != NULL)
501         {
502             //debug("readdir: %s",dptr->d_name);
503             if(is_valid_bd_addr(dptr->d_name))
504             {
505                 snprintf(adapter_path, size, "%s%s", BLUEZ_PATH, dptr->d_name);
506                 btif_config_set_str("Local", "Adapter", "Address", dptr->d_name);
507                 load_bluez_cfg_value(adapter_path, BLUEZ_CONFIG);
508                 ret = TRUE;
509                 break;
510             }
511         }
512         closedir(dirp);
513     }
514     return ret;
515 }
upcase_addr(const char * laddr,char * uaddr,int size)516 static inline void upcase_addr(const char* laddr, char* uaddr, int size)
517 {
518     int i;
519     for(i = 0; i < size && laddr[i]; i++)
520         uaddr[i] = ('a' <= laddr[i] && laddr[i] <= 'z') ?
521                         laddr[i] - ('a' - 'A') : laddr[i];
522     uaddr[i] = 0;
523 }
load_bluez_dev_value(const char * adapter_path,const char * bd_addr,const char * file_name,const char * cfg_value_name,int type)524 static int load_bluez_dev_value(const char* adapter_path, const char* bd_addr,
525                                 const char* file_name, const char* cfg_value_name, int type)
526 {
527     //debug("in");
528     char addr[32];
529     upcase_addr(bd_addr, addr, sizeof(addr));
530 
531     const char* map = NULL;
532     int size = 0;
533     int ret = FALSE;
534     char path[256];
535     snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name);
536     int fd = open_file_map(path, &map, &size);
537     //debug("in, path:%s, addr:%s, fd:%d, size:%d", path, addr, fd, size);
538     if(fd < 0 || size == 0)
539     {
540         error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
541         //debug("out");
542         return FALSE;
543     }
544     int line_size = 0;
545     const char *value_line = find_value_line(map, size, addr, &line_size);
546     if(value_line && line_size)
547     {
548         char line[line_size + 1];
549         memcpy(line, value_line, line_size);
550         line[line_size] = 0;
551         //debug("addr:%s, Names:%s", bd_addr, line);
552         if(type == BTIF_CFG_TYPE_STR)
553             btif_config_set_str("Remote", bd_addr, cfg_value_name, line);
554         else if(type == BTIF_CFG_TYPE_INT)
555         {
556             int v = strtol(line, NULL, 16);
557             //filter out unspported devices by its class
558             if(strcmp(file_name, BLUEZ_CLASSES) == 0)
559             {
560                 switch((v & 0x1f00) >> 8)
561                 {
562                     case 0x5: //hid device
563                         error("skip paired hid devices");
564                         close_file_map(fd, map, size);
565                         return FALSE;
566                 }
567             }
568             btif_config_set_int("Remote", bd_addr, cfg_value_name, v);
569         }
570         ret = TRUE;
571     }
572     close_file_map(fd, map, size);
573     //debug("out, ret:%d", ret);
574     return ret;
575 }
bz2bd_linkkeytype(int type)576 static inline int bz2bd_linkkeytype(int type)
577 {
578 #if 1
579     return type;
580 #else
581     int table[5] = {0, 0, 0, 0, 0};
582     if(0 <= type && type < (int)(sizeof(table)/sizeof(int)))
583         return table[type];
584     return 0;
585 #endif
586 }
load_bluez_linkkeys(const char * adapter_path)587 int load_bluez_linkkeys(const char* adapter_path)
588 {
589     const char* map = NULL;
590     int size = 0;
591     int ret = FALSE;
592     char path[256];
593     //debug("in");
594     snprintf(path, sizeof(path), "%s/%s", adapter_path, BLUEZ_LINKKEY);
595     int fd = open_file_map(path, &map, &size);
596     if(fd < 0 || size == 0)
597     {
598         error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
599         //debug("out");
600         return FALSE;
601     }
602     int pos = 0;
603     //debug("path:%s, size:%d", path, size);
604     while(pos < size)
605     {
606         int line_size = 0;
607         int next_pos = read_file_line(map, pos, size, &line_size);
608         //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size);
609         if(line_size)
610         {
611             const char* line = map + pos;
612             char addr[line_size + 1];
613             int word_pos = 0;
614             int addr_size = 0;
615             word_pos = read_line_word(line, word_pos, line_size, addr, &addr_size, true);
616             //debug("read_line_word addr:%s, addr_size:%d", addr, addr_size);
617             if(*addr)
618             {
619                 char value[line_size + 1];
620                 int value_size = 0;
621                 //read link key
622                 word_pos = read_line_word(line, word_pos, line_size, value, &value_size);
623                 //debug("read_line_word linkkey:%s, size:%d", value, value_size);
624                 if(*value)
625                 {
626                     int linkkey_size = value_size / 2;
627                     char linkkey[linkkey_size];
628                     if(hex2bytes(value, value_size, linkkey))
629                     { //read link key type
630                         //bluez save the linkkey in reversed order
631                         reverse_bin(linkkey, linkkey_size);
632                         word_pos = read_line_word(line, word_pos,
633                                                     line_size, value, &value_size);
634                         if(*value)
635                         {
636                             if(load_bluez_dev_value(adapter_path, addr,
637                                                 BLUEZ_CLASSES, "DevClass", BTIF_CFG_TYPE_INT) &&
638                                load_bluez_dev_value(adapter_path, addr,
639                                                 BLUEZ_NAMES, "Name", BTIF_CFG_TYPE_STR) &&
640                                load_bluez_dev_value(adapter_path, addr,
641                                                 BLUEZ_TYPES, "DevType", BTIF_CFG_TYPE_INT) &&
642                                load_bluez_dev_value(adapter_path, addr,
643                                                 BLUEZ_PROFILES, "Service", BTIF_CFG_TYPE_STR))
644                             {
645                                 load_bluez_dev_value(adapter_path, addr,
646                                                 BLUEZ_ALIASES, "Aliase", BTIF_CFG_TYPE_STR);
647                                 int key_type = bz2bd_linkkeytype(atoi(value));
648 
649                                 //read pin len
650                                 word_pos = read_line_word(line, word_pos, line_size, value, &value_size);
651                                 if(*value)
652                                 {
653                                     int pin_len = atoi(value);
654                                     ret = TRUE;
655                                     btif_config_set("Remote", addr, "LinkKey", linkkey,
656                                                                     linkkey_size, BTIF_CFG_TYPE_BIN);
657                                     //dump_bin("import bluez linkkey", linkkey, linkkey_size);
658                                     btif_config_set_int("Remote", addr, "LinkKeyType", key_type);
659                                     btif_config_set_int("Remote", addr, "PinLength", pin_len);
660                                 }
661                             }
662                         }
663                     }
664                 }
665             }
666         }
667         //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size);
668         pos = next_pos;
669     }
670     close_file_map(fd, map, size);
671     //debug("out, ret:%d", ret);
672     return ret;
673 }
674 
675