Home | History | Annotate | Download | only in src
      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);
     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 }
     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 }
    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 }
    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 }
    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 ////////////////////////////////////////////////////////////////////////////////////////////////////////
    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 }
    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 //////////////////////////////////////////////////////////////////////////////////////////////////////////
    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 }
    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 }
    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 
    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 }
    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 
    339 static inline void create_ele_name(int index, char* element, int len)
    340 {
    341     snprintf(element, len, "N%d", index);
    342 }
    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 }
    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 }
    382 static void close_file_map(int fd, const char* map, int size)
    383 {
    384     munmap((void*)map, size);
    385     close(fd);
    386 }
    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          ++*line_size;
    395         if(map[i] == '\r' || map[i] == '\n')
    396             break;
    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 }
    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 }
    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 }
    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 }
    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 
    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 }
    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 }
    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 }
    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 }
    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