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 #define HID_SUB_CLASS      "020208"
     60 #define HID_COUNTRY_CODE      "020308"
     61 #define HID_VIRTUAL_CABLE      "020428"
     62 #define HID_RECON_INNITIATE      "020528"
     63 #define HID_REP_DSC_1      "020636"
     64 #define HID_REP_DSC_2      "020635"
     65 #define HID_SDP_DISABLE      "020828"
     66 #define HID_BAT_POWER      "020928"
     67 #define HID_REM_WAKE      "020A28"
     68 #define HID_SUP_TIME      "020C09"
     69 #define HID_NORM_CONN      "020D28"
     70 #define HID_SSR_MAX_LAT      "020F09"
     71 #define HID_SSR_MIN_TIM      "021009"
     72 #define HID_VENDOR_ID      "020109"
     73 #define HID_PRODUCT_ID      "020209"
     74 #define HID_PRODUCT_VERSION      "020309"
     75 #define HID_APP_ID_MOUSE      1
     76 #define HID_APP_ID_KYB      2
     77 #define HID_PAIRED_DEV_PRIORITY      100
     78 #define HID_SSR_PARAM_INVALID    0xffff
     79 #define HID_RPT_DSCR_HDR_LEN_1    10
     80 #define HID_RPT_DSCR_HDR_LEN_2    7
     81 
     82 /* Hid Atribute Mask */
     83 #define HID_ATTR_MASK_VIRTUAL_CABLE        0x0001
     84 #define HID_ATTR_MASK_NORMALLY_CONNECTABLE 0x0002
     85 #define HID_ATTR_MASK_RECONN_INIT          0x0004
     86 #define HID_ATTR_MASK_SDP_DISABLE          0x0008
     87 #define HID_ATTR_MASK_BATTERY_POWER        0x0010
     88 #define HID_ATTR_MASK_REMOTE_WAKE          0x0020
     89 #define HID_ATTR_MASK_SUP_TOUT_AVLBL       0x0040
     90 #define HID_ATTR_MASK_SSR_MAX_LATENCY      0x0080
     91 #define HID_ATTR_MASK_SSR_MIN_TOUT         0x0100
     92 #define HID_ATTR_MASK_SEC_REQUIRED         0x8000
     93 
     94 using namespace tinyxml2;
     95 struct enum_user_data
     96 {
     97     const char* sn; //current section name
     98     const char* kn; //current key name
     99     const char* vn; //current value name
    100     int si, ki, vi;
    101     XMLDocument* xml;
    102     XMLElement* se;
    103     XMLElement* ke;
    104     XMLElement* ve;
    105 };
    106 
    107 
    108 static int type_str2int(const char* type);
    109 static const char* type_int2str(int type);
    110 static inline void create_ele_name(int index, char* element, int len);
    111 static inline int validate_ele_name(const char* key);
    112 static int parse_sections(const char* section_name, const XMLElement* section);
    113 static void enum_config(void* user_data, const char* section, const char* key, const char* name,
    114                                           const char*  value, int bytes, int type);
    115 static inline void bytes2hex(const char* data, int bytes, char* str)
    116 {
    117     static const char* hex_table = "0123456789abcdef";
    118     for(int i = 0; i < bytes; i++)
    119     {
    120         *str = hex_table[(data[i] >> 4) & 0xf];
    121         ++str;
    122         *str = hex_table[data[i] & 0xf];
    123         ++str;
    124     }
    125     *str = 0;
    126 }
    127 static inline int hex2byte(char hex)
    128 {
    129     if('0' <= hex && hex <= '9')
    130         return hex - '0';
    131     if('a' <= hex && hex <= 'z')
    132         return hex - 'a' + 0xa;
    133     if('A' <= hex && hex <= 'Z')
    134         return hex - 'A' + 0xa;
    135     return -1;
    136 }
    137 static inline int trim_bin_str_value(const char** str)
    138 {
    139     while(**str == ' ' || **str == '\r' || **str == '\t' || **str == '\n')
    140         (*str)++;
    141     int len = 0;
    142     const char* s = *str;
    143     while(*s && *s != ' ' && *s != '\r' && *s != '\t' && *s != '\n')
    144     {
    145         len++;
    146         s++;
    147     }
    148     return len;
    149 }
    150 static inline bool hex2bytes(const char* str, int len, char* data)
    151 {
    152     if(len % 2)
    153     {
    154         error("cannot convert odd len hex str: %s, len:%d to binary", str, len);
    155         return false;
    156     }
    157     for(int i = 0; i < len; i+= 2)
    158     {
    159         int d = hex2byte(str[i]);
    160         if(d < 0)
    161         {
    162             error("cannot convert hex: %s, len:%d to binary", str, len);
    163             return false;
    164         }
    165         *data = (char)(d << 4);
    166         d = hex2byte(str[i+1]);
    167         if(d < 0)
    168         {
    169             error("cannot convert hex: %s, len:%d to binary", str, len);
    170             return false;
    171         }
    172         *data++ |= (char)d;
    173     }
    174     return true;
    175 }
    176 static inline void reverse_bin(char *bin, int size)
    177 {
    178     for(int i = 0; i < size /2; i++)
    179     {
    180         int b = bin[i];
    181         bin[i] = bin[size - i - 1];
    182         bin[size -i  - 1] = b;
    183     }
    184 }
    185 ////////////////////////////////////////////////////////////////////////////////////////////////////////
    186 int btif_config_save_file(const char* file_name)
    187 {
    188     debug("in file name:%s", file_name);
    189     XMLDocument xml;
    190     XMLElement* root = xml.NewElement(BLUEDROID_ROOT);
    191     xml.InsertFirstChild(root);
    192     int ret = FALSE;
    193     enum_user_data data;
    194     memset(&data, 0, sizeof(data));
    195     data.xml = &xml;
    196     if(btif_config_enum(enum_config, &data))
    197         ret = xml.SaveFile(file_name) == XML_SUCCESS;
    198     return ret;
    199 }
    200 int btif_config_load_file(const char* file_name)
    201 {
    202     //if(access(file_name, 0) != 0)
    203     //    return XML_ERROR_FILE_NOT_FOUND;
    204     XMLDocument xml;
    205     int err = xml.LoadFile(file_name);
    206     const XMLElement* root = xml.RootElement();
    207     int ret = FALSE;
    208     if(err == XML_SUCCESS && root && strcmp(root->Name(), BLUEDROID_ROOT) == 0)
    209     {
    210         const XMLElement* section;
    211         for(section = root->FirstChildElement(); section; section = section->NextSiblingElement())
    212         {
    213             //debug("section tag:%s", section->Name());
    214             if(validate_ele_name(section->Name()))
    215             {
    216                 const char* section_name = section->Attribute(BLUEDROID_NAME_TAG);
    217                 if(section_name && *section_name)
    218                     if(parse_sections(section_name, section))
    219                         ret = TRUE;
    220             }
    221         }
    222     }
    223     return ret;
    224 }
    225 //////////////////////////////////////////////////////////////////////////////////////////////////////////
    226 static int parse_sections(const char* section_name, const XMLElement* section)
    227 {
    228     const XMLElement* key;
    229     //debug("in");
    230     for(key = section->FirstChildElement(); key; key = key->NextSiblingElement())
    231     {
    232         //debug("key tag:%s", key->Name());
    233         if(validate_ele_name(key->Name()))
    234         {
    235             const char* key_name = key->Attribute(BLUEDROID_NAME_TAG);
    236             //debug("key name:%s", key_name);
    237             if(key_name && *key_name)
    238             {
    239                 const XMLElement* value;
    240                 for(value = key->FirstChildElement(); value; value = value->NextSiblingElement())
    241                 {
    242                     const char* value_name = value->Attribute(BLUEDROID_NAME_TAG);
    243                     const char* value_type = value->Attribute(BLUEDROID_VALUE_TYPE);
    244                     //debug("value ele name:%s, section name:%s, key name:%s, value name:%s, value type:%s",
    245                     //        value->Name(), section_name, key_name, value_name, value_type);
    246                     int type = type_str2int(value_type);
    247                     if(value_name && *value_name && type != BTIF_CFG_TYPE_INVALID)
    248                     {
    249                         const char* value_str = value->GetText() ? value->GetText() : "";
    250                         //debug("value_name:%s, value_str:%s, value_type:%s, type:%x",
    251                         //       value_name, value_str, value_type, type);
    252                         if(type & BTIF_CFG_TYPE_STR)
    253                             btif_config_set_str(section_name, key_name, value_name, value_str);
    254                         else if(type & BTIF_CFG_TYPE_INT)
    255                         {
    256                             if(*value_str)
    257                             {
    258                                 int v = atoi(value_str);
    259                                 btif_config_set_int(section_name, key_name, value_name, v);
    260                             }
    261                         }
    262                         else if(type & BTIF_CFG_TYPE_BIN)
    263                         {
    264                             int len = trim_bin_str_value(&value_str);
    265                             if(len > 0 && len % 2 == 0)
    266                             {
    267                                 char *bin = (char*)alloca(len / 2);
    268                                 if(hex2bytes(value_str, len, bin))
    269                                     btif_config_set(section_name, key_name, value_name, bin, len/2, BTIF_CFG_TYPE_BIN);
    270                             }
    271                         }
    272                         else error("Unsupported value:%s, type:%s not loaded", value_name, value_type);
    273                     }
    274                 }
    275             }
    276         }
    277     }
    278     //debug("out");
    279     return TRUE;
    280 }
    281 static inline XMLElement* add_ele(XMLDocument* xml, XMLElement* p, int index,
    282                                   const char* name_tag, const char* value_type = NULL)
    283 {
    284     //debug("in, tag:%s", name_tag);
    285     char ele_name[128] = {0};
    286     create_ele_name(index, ele_name, sizeof(ele_name));
    287     XMLElement* ele = xml->NewElement(ele_name);
    288     //debug("ele name:%s, tag:%s, index:%d, value type:%s", ele_name, name_tag, index, value_type);
    289     ele->SetAttribute(BLUEDROID_NAME_TAG, name_tag);
    290     if(value_type && *value_type)
    291         ele->SetAttribute(BLUEDROID_VALUE_TYPE, value_type);
    292     p->InsertEndChild(ele);
    293     //debug("out, tag:%s", name_tag);
    294     return ele;
    295 }
    296 static void enum_config(void* user_data, const char* section_name, const char* key_name, const char* value_name,
    297                         const char*  value, int bytes, int type)
    298 {
    299     enum_user_data& d = *(enum_user_data*)user_data;
    300     //debug("in, key:%s, value:%s", key_name, value_name);
    301     //debug("section name:%s, key name:%s, value name:%s, value type:%s",
    302     //                      section_name, key_name, value_name, type_int2str(type));
    303     if(type & BTIF_CFG_TYPE_VOLATILE)
    304         return; //skip any volatile value
    305     if(d.sn != section_name)
    306     {
    307         d.sn = section_name;
    308         d.se = add_ele(d.xml, d.xml->RootElement(), ++d.si, section_name);
    309         d.ki = 0;
    310     }
    311     if(d.kn != key_name)
    312     {
    313         d.kn = key_name;
    314         d.ke = add_ele(d.xml, d.se, ++d.ki, key_name);
    315         d.vi = 0;
    316     }
    317     if(d.vn != value_name)
    318     {
    319         if(type & BTIF_CFG_TYPE_STR)
    320         {
    321             d.vn = value_name;
    322             d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
    323             d.ve->InsertFirstChild(d.xml->NewText(value));
    324         }
    325         else if(type & BTIF_CFG_TYPE_INT)
    326         {
    327             d.vn = value_name;
    328             d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
    329             char value_str[64] = {0};
    330             snprintf(value_str, sizeof(value_str), "%d", *(int*)value);
    331             d.ve->InsertFirstChild(d.xml->NewText(value_str));
    332         }
    333         else if(type & BTIF_CFG_TYPE_BIN)
    334         {
    335             d.vn = value_name;
    336             d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
    337             char* value_str = (char*)alloca(bytes*2 + 1);
    338             bytes2hex(value, bytes, value_str);
    339             d.ve->InsertFirstChild(d.xml->NewText(value_str));
    340         }
    341         else error("unsupported config value name:%s, type:%s not saved", d.vn, type_int2str(type));
    342     }
    343     //debug("out, key:%s, value:%s", key_name, value_name);
    344 }
    345 
    346 static int type_str2int(const char* type)
    347 {
    348     if(strcmp(type, "int") == 0)
    349         return BTIF_CFG_TYPE_INT;
    350     if(strcmp(type, "binary") == 0)
    351         return BTIF_CFG_TYPE_BIN;
    352     if(type == 0 || *type == 0 || strcmp(type, "string") == 0)
    353         return  BTIF_CFG_TYPE_STR;
    354     error("unknown value type:%s", type);
    355     return BTIF_CFG_TYPE_INVALID;
    356 }
    357 static const char* type_int2str(int type)
    358 {
    359     switch(type)
    360     {
    361         case BTIF_CFG_TYPE_INT:
    362             return "int";
    363         case BTIF_CFG_TYPE_BIN:
    364             return "binary";
    365         case BTIF_CFG_TYPE_STR:
    366             return "string";
    367         default:
    368             error("unknown type:%d", type);
    369             break;
    370     }
    371     return NULL;
    372 }
    373 
    374 static inline void create_ele_name(int index, char* element, int len)
    375 {
    376     snprintf(element, len, "N%d", index);
    377 }
    378 static inline int validate_ele_name(const char* key)
    379 {
    380     //must be 'N' followed with numbers
    381     if(key && *key == 'N' && *++key)
    382     {
    383         while(*key)
    384         {
    385             if(*key < '0' || *key > '9')
    386                 return FALSE;
    387             ++key;
    388         }
    389         return TRUE;
    390     }
    391     return FALSE;
    392 }
    393 static int open_file_map(const char *pathname, const char**map, int* size)
    394 {
    395     struct stat st;
    396     st.st_size = 0;
    397     int fd;
    398     //debug("in");
    399     if((fd = open(pathname, O_RDONLY)) >= 0)
    400     {
    401         //debug("fd:%d", fd);
    402         if(fstat(fd, &st) == 0 && st.st_size)
    403         {
    404             *size = st.st_size;
    405             *map = (const char*)mmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0);
    406             if(*map && *map != MAP_FAILED)
    407             {
    408                 //debug("out map:%p, size:%d", *map, *size);
    409                 return fd;
    410             }
    411         }
    412         close(fd);
    413     }
    414     //debug("out, failed");
    415     return -1;
    416 }
    417 static void close_file_map(int fd, const char* map, int size)
    418 {
    419     munmap((void*)map, size);
    420     close(fd);
    421 }
    422 static int read_file_line(const char* map, int start_pos, int size, int* line_size)
    423 {
    424     *line_size = 0;
    425     //debug("in, start pos:%d, size:%d", start_pos, size);
    426     int i;
    427     for(i = start_pos; i < size; i++)
    428     {
    429         if(map[i] == '\r' || map[i] == '\n')
    430             break;
    431          ++*line_size;
    432     }
    433     //debug("out, ret:%d, start pos:%d, size:%d, line_size:%d", i, start_pos, size, *line_size);
    434     return i + 1;
    435 }
    436 static const char* find_value_line(const char* map, int size, const char *key, int* value_size)
    437 {
    438     int key_len = strlen(key);
    439     int i;
    440     for(i = 0; i < size; i++)
    441     {
    442         if(map[i] == *key)
    443         {
    444             if(i + key_len + 1 > size)
    445                 return NULL;
    446             if(memcmp(map + i, key, key_len) == 0)
    447             {
    448                 read_file_line(map, i + key_len + 1, size, value_size);
    449                 if(*value_size)
    450                     return map + i + key_len + 1;
    451                 break;
    452             }
    453         }
    454     }
    455     return NULL;
    456 }
    457 static int read_line_word(const char* line, int start_pos, int line_size, char* word, int *word_size, bool lower_case = false)
    458 {
    459     int i;
    460     //skip space
    461     //debug("in, line start_pos:%d, line_size:%d", start_pos, line_size);
    462     for(i = start_pos; i < line_size; i++)
    463     {
    464         //debug("skip space loop, line[%d]:%c", i, line[i]);
    465         if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n')
    466             break;
    467     }
    468     *word_size = 0;
    469     for(; i < line_size; i++)
    470     {
    471         //debug("add word loop, line[%d]:%c", i, line[i]);
    472         if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n')
    473         {
    474             ++*word_size;
    475             if(lower_case && 'A' <= line[i] && line[i] <= 'Z')
    476                 *word++ = 'a' - 'A' + line[i];
    477             else
    478                 *word++ = line[i];
    479         }
    480         else break;
    481     }
    482     *word = 0;
    483     //debug("out, ret:%d, word:%s, word_size:%d, line start_pos:%d, line_size:%d",
    484     //            i, word, *word_size, start_pos, line_size);
    485     return i;
    486 }
    487 static int is_valid_bd_addr(const char* addr)
    488 {
    489     int len = strlen(addr);
    490     //debug("addr: %s, len:%d", addr, len);
    491     return len == 17 && addr[2] == ':' && addr[5] == ':' && addr[14] == ':';
    492 }
    493 static int load_bluez_cfg_value(const char* adapter_path, const char* file_name)
    494 {
    495     //debug("in");
    496 
    497     const char* map = NULL;
    498     int size = 0;
    499     int ret = FALSE;
    500     char path[256];
    501     snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name);
    502     int fd = open_file_map(path, &map, &size);
    503     //debug("in, path:%s, fd:%d, size:%d", path, fd, size);
    504     if(fd < 0 || size == 0)
    505     {
    506         error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
    507         //debug("out");
    508         if (fd >= 0)
    509             close(fd);
    510         return FALSE;
    511     }
    512     //get local bt device name from bluez config
    513     int line_size = 0;
    514     const char *value_line = find_value_line(map, size, "name", &line_size);
    515     if(value_line && line_size > 0)
    516     {
    517         char value[line_size + 1];
    518         memcpy(value, value_line, line_size);
    519         value[line_size] = 0;
    520         //debug("import local bt dev names:%s", value);
    521         btif_config_set_str("Local", "Adapter", "Name", value);
    522         ret = TRUE;
    523     }
    524 
    525     close_file_map(fd, map, size);
    526     //debug("out, ret:%d", ret);
    527     return ret;
    528 }
    529 
    530 int load_bluez_adapter_info(char* adapter_path, int size)
    531 {
    532     struct dirent *dptr;
    533     DIR *dirp;
    534     int ret = FALSE;
    535     if((dirp = opendir(BLUEZ_PATH)) != NULL)
    536     {
    537         while((dptr = readdir(dirp)) != NULL)
    538         {
    539             //debug("readdir: %s",dptr->d_name);
    540             if(is_valid_bd_addr(dptr->d_name))
    541             {
    542                 snprintf(adapter_path, size, "%s%s", BLUEZ_PATH, dptr->d_name);
    543                 btif_config_set_str("Local", "Adapter", "Address", dptr->d_name);
    544                 load_bluez_cfg_value(adapter_path, BLUEZ_CONFIG);
    545                 ret = TRUE;
    546                 break;
    547             }
    548         }
    549         closedir(dirp);
    550     }
    551     return ret;
    552 }
    553 static inline void upcase_addr(const char* laddr, char* uaddr, int size)
    554 {
    555     int i;
    556     for(i = 0; i < size && laddr[i]; i++)
    557         uaddr[i] = ('a' <= laddr[i] && laddr[i] <= 'z') ?
    558                         laddr[i] - ('a' - 'A') : laddr[i];
    559     uaddr[i] = 0;
    560 }
    561 
    562 static int parse_hid_attribute(const char *str, int line_size, int len)
    563 {
    564     if (len == 0 || line_size == 0 || str == NULL || (len%2))
    565         return 0;
    566 
    567     char hex_string[len + 1], hex_bytes[len/2];
    568     memcpy(hex_string, str - 1, len);
    569     hex_string[len] = 0;
    570     hex2bytes(hex_string, len, hex_bytes);
    571     if (len == 2)
    572         return hex_bytes[0];
    573     else if (len == 4)
    574         return hex_bytes[0] << 8 | hex_bytes[1];
    575     else return 0;
    576 }
    577 
    578 static int parse_bluez_hid_sdp_records(const char* adapter_path, const char* bd_addr)
    579 {
    580     //debug("in");
    581     char addr[32];
    582     char pattern_to_search[50];
    583     upcase_addr(bd_addr, addr, sizeof(addr));
    584 
    585     const char* map = NULL;
    586     int size = 0;
    587     int ret = FALSE;
    588     char path[256];
    589     snprintf(path, sizeof(path), "%s/%s", adapter_path, BLUEZ_SDP);
    590     int fd = open_file_map(path, &map, &size);
    591     //debug("in, path:%s, addr:%s, fd:%d, size:%d", path, addr, fd, size);
    592     if(fd < 0 || size == 0)
    593     {
    594         error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
    595         //debug("out");
    596         return FALSE;
    597     }
    598     int line_size = 0;
    599     snprintf(pattern_to_search, sizeof(pattern_to_search), "%s#00010000", addr);
    600     const char *value_line = find_value_line(map, size, pattern_to_search, &line_size);
    601     int dev_sub_class = 0;
    602     int app_id = 0;
    603     int countrycode = 0;
    604     int product = 0;
    605     int vendor = 0;
    606     int product_ver = 0;
    607     int attr_mask = 0;
    608     int ssr_max_lat = 0;
    609     int ssr_min_timeout = 0;
    610     int rep_desc_len = 0;
    611     if(value_line && line_size)
    612     {
    613         char hid_sdp[line_size + 2];
    614         memcpy(hid_sdp, value_line - 1, line_size);
    615         hid_sdp[line_size + 1] = 0;
    616         //debug("addr:%s, hid_sdp:%s", bd_addr, hid_sdp);
    617         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SUB_CLASS, &line_size);
    618         dev_sub_class = parse_hid_attribute(value_line, line_size, 2);
    619         if(dev_sub_class)
    620         {
    621             if ((dev_sub_class & 0x80) == 0x80)
    622                 app_id = HID_APP_ID_MOUSE;
    623             else
    624                 app_id = HID_APP_ID_KYB;
    625             //debug("dev_sub_class:%d", dev_sub_class);
    626         }
    627         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_COUNTRY_CODE, &line_size);
    628         countrycode = parse_hid_attribute(value_line, line_size, 2);
    629         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_VIRTUAL_CABLE, &line_size);
    630         if(parse_hid_attribute(value_line, line_size, 2))
    631         {
    632             attr_mask |= HID_ATTR_MASK_VIRTUAL_CABLE;
    633             //debug("attr_mask after Virtual Unplug:%04x", attr_mask);
    634         }
    635         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_RECON_INNITIATE, &line_size);
    636         if(parse_hid_attribute(value_line, line_size, 2))
    637         {
    638             attr_mask |= HID_ATTR_MASK_RECONN_INIT;
    639             //debug("attr_mask after Reconnect Initiate:%04x", attr_mask);
    640         }
    641         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_REP_DSC_1, &line_size);
    642         if(value_line && line_size)
    643         {
    644             char rep_desc[line_size + 1], rd[line_size/2 + 1];
    645             char rep_dsc_len[5], rd_len[2];
    646             memcpy(rep_dsc_len, value_line - 1, 4);
    647             rep_dsc_len[4] = 0;
    648             hex2bytes(rep_dsc_len, 4, rd_len);
    649             rep_desc_len = (rd_len[0] << 8 | rd_len[1]) - (HID_RPT_DSCR_HDR_LEN_1 - 2);
    650             //debug("rep_desc_len:%d", rep_desc_len);
    651             memcpy(rep_desc, value_line - 1 + (HID_RPT_DSCR_HDR_LEN_1 * 2), rep_desc_len * 2);
    652             rep_desc[rep_desc_len * 2] = 0;
    653             hex2bytes(rep_desc, rep_desc_len* 2, rd);
    654             if (rep_desc_len)
    655             {
    656                 //debug("rep_desc:%s", rep_desc);
    657                 btif_config_set("Remote", bd_addr, "HidDescriptor", rd, rep_desc_len,
    658                         BTIF_CFG_TYPE_BIN);
    659             }
    660         }
    661         else
    662         {
    663             value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_REP_DSC_2, &line_size);
    664             if(value_line && line_size)
    665             {
    666                 char rep_dsc_len[3], rd_len[1];
    667                 memcpy(rep_dsc_len, value_line - 1, 2);
    668                 rep_dsc_len[2] = 0;
    669                 hex2bytes(rep_dsc_len, 2, rd_len);
    670                 rep_desc_len = rd_len[0] - (HID_RPT_DSCR_HDR_LEN_2 - 1);
    671                 //debug("rep_desc_len:%d", rep_desc_len);
    672                 char rep_desc[(rep_desc_len * 2) + 1], rd[rep_desc_len + 1];
    673                 memcpy(rep_desc, value_line - 1 + (HID_RPT_DSCR_HDR_LEN_2 * 2), rep_desc_len * 2);
    674                 rep_desc[rep_desc_len * 2] = 0;
    675                 hex2bytes(rep_desc, rep_desc_len * 2, rd);
    676                 if (rep_desc_len)
    677                 {
    678                     //debug("rep_desc:%s", rep_desc);
    679                     btif_config_set("Remote", bd_addr, "HidDescriptor", rd, rep_desc_len,
    680                             BTIF_CFG_TYPE_BIN);
    681                 }
    682             }
    683         }
    684         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SDP_DISABLE, &line_size);
    685         if(parse_hid_attribute(value_line, line_size, 2))
    686         {
    687             attr_mask |= HID_ATTR_MASK_SDP_DISABLE;
    688             //debug("attr_mask after SDP Disable:%04x", attr_mask);
    689         }
    690         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_BAT_POWER, &line_size);
    691         if(parse_hid_attribute(value_line, line_size, 2))
    692         {
    693             attr_mask |= HID_ATTR_MASK_BATTERY_POWER;
    694             //debug("attr_mask after Battery Powered:%04x", attr_mask);
    695         }
    696         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_REM_WAKE, &line_size);
    697         if(parse_hid_attribute(value_line, line_size, 2))
    698         {
    699             attr_mask |= HID_ATTR_MASK_REMOTE_WAKE;
    700             //debug("attr_mask after Remote Wake:%04x", attr_mask);
    701         }
    702         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_NORM_CONN, &line_size);
    703         if(parse_hid_attribute(value_line, line_size, 2))
    704         {
    705             attr_mask |= HID_ATTR_MASK_NORMALLY_CONNECTABLE;
    706             //debug("attr_mask after Normally Conenctable:%04x", attr_mask);
    707         }
    708         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SUP_TIME, &line_size);
    709         if(value_line && line_size)
    710             attr_mask |= HID_ATTR_MASK_SUP_TOUT_AVLBL;
    711         //debug("attr_mask after Supervision Timeout:%04x", attr_mask);
    712         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SSR_MAX_LAT, &line_size);
    713         ssr_max_lat = parse_hid_attribute(value_line, line_size, 4);
    714         if(!ssr_max_lat)
    715             ssr_max_lat = HID_SSR_PARAM_INVALID;
    716         value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SSR_MIN_TIM, &line_size);
    717         ssr_min_timeout = parse_hid_attribute(value_line, line_size, 4);
    718         if(!ssr_min_timeout)
    719             ssr_min_timeout = HID_SSR_PARAM_INVALID;
    720         snprintf(pattern_to_search, sizeof(pattern_to_search), "%s#00010001", addr);
    721         value_line = find_value_line(map, size, pattern_to_search, &line_size);
    722         if(value_line && line_size)
    723         {
    724             char did_sdp[line_size + 2];
    725             memcpy(did_sdp, value_line - 1, line_size + 1);
    726             did_sdp[line_size + 1] = 0;
    727             //debug("addr:%s, did_sdp:%s", bd_addr, did_sdp);
    728             value_line = find_value_line(did_sdp, strlen(did_sdp), HID_VENDOR_ID, &line_size);
    729             vendor = parse_hid_attribute(value_line, line_size, 4);
    730             value_line = find_value_line(did_sdp, strlen(did_sdp), HID_PRODUCT_ID, &line_size);
    731             product = parse_hid_attribute(value_line, line_size, 4);
    732             value_line = find_value_line(did_sdp, strlen(did_sdp), HID_PRODUCT_VERSION, &line_size);
    733             product_ver = parse_hid_attribute(value_line, line_size, 4);
    734          }
    735     }
    736     btif_config_set_int("Remote", bd_addr, "HidAttrMask", attr_mask);
    737     btif_config_set_int("Remote", bd_addr, "HidSubClass", dev_sub_class);
    738     btif_config_set_int("Remote", bd_addr, "HidAppId", app_id);
    739     btif_config_set_int("Remote", bd_addr, "HidVendorId", vendor);
    740     btif_config_set_int("Remote", bd_addr, "HidProductId", product);
    741     btif_config_set_int("Remote", bd_addr, "HidVersion", product_ver);
    742     btif_config_set_int("Remote", bd_addr, "HidCountryCode", countrycode);
    743     btif_config_set_int("Remote", bd_addr, "HidSSRMinTimeout", ssr_min_timeout);
    744     btif_config_set_int("Remote", bd_addr, "HidSSRMaxLatency", ssr_max_lat);
    745     //debug("HidSubClass: %02x, app_id = %d, vendor = %04x, product = %04x, product_ver = %04x"
    746     //    "countrycode = %02x, ssr_min_timeout = %04x, ssr_max_lat = %04x",
    747     //    HidSubClass, app_id, vendor, product, product_ver, countrycode, ssr_min_timeout,
    748     //    ssr_max_lat);
    749     close_file_map(fd, map, size);
    750     ret = TRUE;
    751     //debug("out, ret:%d", ret);
    752     return ret;
    753 }
    754 
    755 static int load_bluez_dev_value(const char* adapter_path, const char* bd_addr,
    756                                 const char* file_name, const char* cfg_value_name, int type)
    757 {
    758     //debug("in");
    759     char addr[32];
    760     upcase_addr(bd_addr, addr, sizeof(addr));
    761 
    762     const char* map = NULL;
    763     int size = 0;
    764     int ret = FALSE;
    765     char path[256];
    766     snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name);
    767     int fd = open_file_map(path, &map, &size);
    768     //debug("in, path:%s, addr:%s, fd:%d, size:%d", path, addr, fd, size);
    769     if(fd < 0 || size == 0)
    770     {
    771         error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
    772         //debug("out");
    773         if (fd >= 0)
    774             close(fd);
    775         return FALSE;
    776     }
    777     int line_size = 0;
    778     const char *value_line = find_value_line(map, size, addr, &line_size);
    779     if(value_line && line_size)
    780     {
    781         char line[line_size + 1];
    782         memcpy(line, value_line, line_size);
    783         line[line_size] = 0;
    784         //debug("addr:%s, Names:%s", bd_addr, line);
    785         if(type == BTIF_CFG_TYPE_STR)
    786             btif_config_set_str("Remote", bd_addr, cfg_value_name, line);
    787         else if(type == BTIF_CFG_TYPE_INT)
    788         {
    789             int v = strtol(line, NULL, 16);
    790             //parse sdp record in case remote device is hid
    791             if(strcmp(file_name, BLUEZ_CLASSES) == 0)
    792             {
    793                 switch((v & 0x1f00) >> 8)
    794                 {
    795                     case 0x5: //hid device
    796                         info("parsing sdp for hid device %s", bd_addr);
    797                         parse_bluez_hid_sdp_records(adapter_path, bd_addr);
    798                         break;
    799                 }
    800             }
    801             btif_config_set_int("Remote", bd_addr, cfg_value_name, v);
    802         }
    803         ret = TRUE;
    804     }
    805     close_file_map(fd, map, size);
    806     //debug("out, ret:%d", ret);
    807     return ret;
    808 }
    809 static inline int bz2bd_linkkeytype(int type)
    810 {
    811 #if 1
    812     return type;
    813 #else
    814     int table[5] = {0, 0, 0, 0, 0};
    815     if(0 <= type && type < (int)(sizeof(table)/sizeof(int)))
    816         return table[type];
    817     return 0;
    818 #endif
    819 }
    820 int load_bluez_linkkeys(const char* adapter_path)
    821 {
    822     const char* map = NULL;
    823     int size = 0;
    824     int ret = FALSE;
    825     char path[256];
    826     //debug("in");
    827     snprintf(path, sizeof(path), "%s/%s", adapter_path, BLUEZ_LINKKEY);
    828     int fd = open_file_map(path, &map, &size);
    829     if(fd < 0 || size == 0)
    830     {
    831         error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
    832         //debug("out");
    833         if (fd >= 0)
    834             close(fd);
    835         return FALSE;
    836     }
    837     int pos = 0;
    838     //debug("path:%s, size:%d", path, size);
    839     while(pos < size)
    840     {
    841         int line_size = 0;
    842         int next_pos = read_file_line(map, pos, size, &line_size);
    843         //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size);
    844         if(line_size)
    845         {
    846             const char* line = map + pos;
    847             char addr[line_size + 1];
    848             int word_pos = 0;
    849             int addr_size = 0;
    850             word_pos = read_line_word(line, word_pos, line_size, addr, &addr_size, true);
    851             //debug("read_line_word addr:%s, addr_size:%d", addr, addr_size);
    852             if(*addr)
    853             {
    854                 char value[line_size + 1];
    855                 int value_size = 0;
    856                 //read link key
    857                 word_pos = read_line_word(line, word_pos, line_size, value, &value_size);
    858                 //debug("read_line_word linkkey:%s, size:%d", value, value_size);
    859                 if(*value)
    860                 {
    861                     int linkkey_size = value_size / 2;
    862                     char linkkey[linkkey_size];
    863                     if(hex2bytes(value, value_size, linkkey))
    864                     { //read link key type
    865                         //bluez save the linkkey in reversed order
    866                         reverse_bin(linkkey, linkkey_size);
    867                         word_pos = read_line_word(line, word_pos,
    868                                                     line_size, value, &value_size);
    869                         if(*value)
    870                         {
    871                             if(load_bluez_dev_value(adapter_path, addr,
    872                                                 BLUEZ_CLASSES, "DevClass", BTIF_CFG_TYPE_INT) &&
    873                                load_bluez_dev_value(adapter_path, addr,
    874                                                 BLUEZ_NAMES, "Name", BTIF_CFG_TYPE_STR) &&
    875                                load_bluez_dev_value(adapter_path, addr,
    876                                                 BLUEZ_TYPES, "DevType", BTIF_CFG_TYPE_INT) &&
    877                                load_bluez_dev_value(adapter_path, addr,
    878                                                 BLUEZ_PROFILES, "Service", BTIF_CFG_TYPE_STR))
    879                             {
    880                                 load_bluez_dev_value(adapter_path, addr,
    881                                                 BLUEZ_ALIASES, "Aliase", BTIF_CFG_TYPE_STR);
    882                                 int key_type = bz2bd_linkkeytype(atoi(value));
    883 
    884                                 //read pin len
    885                                 word_pos = read_line_word(line, word_pos, line_size, value, &value_size);
    886                                 if(*value)
    887                                 {
    888                                     int pin_len = atoi(value);
    889                                     ret = TRUE;
    890                                     btif_config_set("Remote", addr, "LinkKey", linkkey,
    891                                                                     linkkey_size, BTIF_CFG_TYPE_BIN);
    892                                     //dump_bin("import bluez linkkey", linkkey, linkkey_size);
    893                                     btif_config_set_int("Remote", addr, "LinkKeyType", key_type);
    894                                     btif_config_set_int("Remote", addr, "PinLength", pin_len);
    895                                 }
    896                             }
    897                         }
    898                     }
    899                 }
    900             }
    901         }
    902         //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size);
    903         pos = next_pos;
    904     }
    905     close_file_map(fd, map, size);
    906     //debug("out, ret:%d", ret);
    907     return ret;
    908 }
    909 
    910