• 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 #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);
bytes2hex(const char * data,int bytes,char * str)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 }
hex2byte(char hex)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 }
trim_bin_str_value(const char ** str)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 }
hex2bytes(const char * str,int len,char * data)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 }
reverse_bin(char * bin,int size)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 ////////////////////////////////////////////////////////////////////////////////////////////////////////
btif_config_save_file(const char * file_name)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 }
btif_config_load_file(const char * file_name)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 //////////////////////////////////////////////////////////////////////////////////////////////////////////
parse_sections(const char * section_name,const XMLElement * section)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 }
add_ele(XMLDocument * xml,XMLElement * p,int index,const char * name_tag,const char * value_type=NULL)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 }
enum_config(void * user_data,const char * section_name,const char * key_name,const char * value_name,const char * value,int bytes,int type)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 
type_str2int(const char * type)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 }
type_int2str(int type)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 
create_ele_name(int index,char * element,int len)374 static inline void create_ele_name(int index, char* element, int len)
375 {
376     snprintf(element, len, "N%d", index);
377 }
validate_ele_name(const char * key)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 }
open_file_map(const char * pathname,const char ** map,int * size)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 }
close_file_map(int fd,const char * map,int size)417 static void close_file_map(int fd, const char* map, int size)
418 {
419     munmap((void*)map, size);
420     close(fd);
421 }
read_file_line(const char * map,int start_pos,int size,int * line_size)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 }
find_value_line(const char * map,int size,const char * key,int * value_size)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 }
read_line_word(const char * line,int start_pos,int line_size,char * word,int * word_size,bool lower_case=false)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 }
is_valid_bd_addr(const char * addr)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 }
load_bluez_cfg_value(const char * adapter_path,const char * file_name)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 
load_bluez_adapter_info(char * adapter_path,int size)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 }
upcase_addr(const char * laddr,char * uaddr,int size)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 
parse_hid_attribute(const char * str,int line_size,int len)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 
parse_bluez_hid_sdp_records(const char * adapter_path,const char * bd_addr)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 
load_bluez_dev_value(const char * adapter_path,const char * bd_addr,const char * file_name,const char * cfg_value_name,int type)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 }
bz2bd_linkkeytype(int type)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 }
load_bluez_linkkeys(const char * adapter_path)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