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