blob: 2e76ba2fbedcb764fc5ac7f57fca7441439e4b89 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
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"
43extern "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
Hemant Gupta8cd229d2013-10-25 22:00:07 +053059#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
The Android Open Source Project5738f832012-12-12 16:00:35 -080094using namespace tinyxml2;
95struct 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
108static int type_str2int(const char* type);
109static const char* type_int2str(int type);
110static inline void create_ele_name(int index, char* element, int len);
111static inline int validate_ele_name(const char* key);
112static int parse_sections(const char* section_name, const XMLElement* section);
113static void enum_config(void* user_data, const char* section, const char* key, const char* name,
114 const char* value, int bytes, int type);
115static 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}
127static 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}
137static 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}
150static 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}
176static 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////////////////////////////////////////////////////////////////////////////////////////////////////////
186int 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}
200int 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//////////////////////////////////////////////////////////////////////////////////////////////////////////
226static 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);
Amit Goel85a35032014-07-31 20:14:27 -0700246 int type = BTIF_CFG_TYPE_INVALID;
247 if(value_type)
248 {
249 type = type_str2int((const char*)value_type);
250 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800251 if(value_name && *value_name && type != BTIF_CFG_TYPE_INVALID)
252 {
253 const char* value_str = value->GetText() ? value->GetText() : "";
254 //debug("value_name:%s, value_str:%s, value_type:%s, type:%x",
255 // value_name, value_str, value_type, type);
256 if(type & BTIF_CFG_TYPE_STR)
257 btif_config_set_str(section_name, key_name, value_name, value_str);
258 else if(type & BTIF_CFG_TYPE_INT)
259 {
Sai Aitharajue8a3e7f2015-02-06 09:20:32 +0530260 if(value_str && *value_str)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800261 {
262 int v = atoi(value_str);
263 btif_config_set_int(section_name, key_name, value_name, v);
264 }
265 }
266 else if(type & BTIF_CFG_TYPE_BIN)
267 {
268 int len = trim_bin_str_value(&value_str);
269 if(len > 0 && len % 2 == 0)
270 {
271 char *bin = (char*)alloca(len / 2);
272 if(hex2bytes(value_str, len, bin))
273 btif_config_set(section_name, key_name, value_name, bin, len/2, BTIF_CFG_TYPE_BIN);
274 }
275 }
276 else error("Unsupported value:%s, type:%s not loaded", value_name, value_type);
277 }
278 }
279 }
280 }
281 }
282 //debug("out");
283 return TRUE;
284}
285static inline XMLElement* add_ele(XMLDocument* xml, XMLElement* p, int index,
286 const char* name_tag, const char* value_type = NULL)
287{
288 //debug("in, tag:%s", name_tag);
289 char ele_name[128] = {0};
290 create_ele_name(index, ele_name, sizeof(ele_name));
291 XMLElement* ele = xml->NewElement(ele_name);
292 //debug("ele name:%s, tag:%s, index:%d, value type:%s", ele_name, name_tag, index, value_type);
293 ele->SetAttribute(BLUEDROID_NAME_TAG, name_tag);
294 if(value_type && *value_type)
295 ele->SetAttribute(BLUEDROID_VALUE_TYPE, value_type);
296 p->InsertEndChild(ele);
297 //debug("out, tag:%s", name_tag);
298 return ele;
299}
300static void enum_config(void* user_data, const char* section_name, const char* key_name, const char* value_name,
301 const char* value, int bytes, int type)
302{
303 enum_user_data& d = *(enum_user_data*)user_data;
Amit Goel85a35032014-07-31 20:14:27 -0700304 XMLElement * root_elem = d.xml->RootElement();
The Android Open Source Project5738f832012-12-12 16:00:35 -0800305 //debug("in, key:%s, value:%s", key_name, value_name);
306 //debug("section name:%s, key name:%s, value name:%s, value type:%s",
307 // section_name, key_name, value_name, type_int2str(type));
308 if(type & BTIF_CFG_TYPE_VOLATILE)
309 return; //skip any volatile value
Amit Goel85a35032014-07-31 20:14:27 -0700310 if( (d.sn != section_name) && (root_elem != NULL) )
The Android Open Source Project5738f832012-12-12 16:00:35 -0800311 {
312 d.sn = section_name;
Rajshekar Eashwarappa1f857eb2015-03-15 00:58:59 +0530313 //Commenting in 5.1 bring-up
314 //if(d.xml->RootElement())
315 // d.se = add_ele(d.xml, d.xml->RootElement(), ++d.si, section_name);
Amit Goel85a35032014-07-31 20:14:27 -0700316 d.se = add_ele(d.xml, root_elem, ++d.si, section_name);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800317 d.ki = 0;
318 }
319 if(d.kn != key_name)
320 {
321 d.kn = key_name;
322 d.ke = add_ele(d.xml, d.se, ++d.ki, key_name);
323 d.vi = 0;
324 }
325 if(d.vn != value_name)
326 {
327 if(type & BTIF_CFG_TYPE_STR)
328 {
329 d.vn = value_name;
330 d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
331 d.ve->InsertFirstChild(d.xml->NewText(value));
332 }
333 else if(type & BTIF_CFG_TYPE_INT)
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[64] = {0};
338 snprintf(value_str, sizeof(value_str), "%d", *(int*)value);
339 d.ve->InsertFirstChild(d.xml->NewText(value_str));
340 }
341 else if(type & BTIF_CFG_TYPE_BIN)
342 {
343 d.vn = value_name;
344 d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
345 char* value_str = (char*)alloca(bytes*2 + 1);
346 bytes2hex(value, bytes, value_str);
347 d.ve->InsertFirstChild(d.xml->NewText(value_str));
348 }
349 else error("unsupported config value name:%s, type:%s not saved", d.vn, type_int2str(type));
350 }
351 //debug("out, key:%s, value:%s", key_name, value_name);
352}
353
354static int type_str2int(const char* type)
355{
Amit Goel85a35032014-07-31 20:14:27 -0700356 if(type == NULL || *type == 0 || strcmp(type, "string") == 0)
Sai Aitharajue8a3e7f2015-02-06 09:20:32 +0530357 return BTIF_CFG_TYPE_STR;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800358 if(strcmp(type, "int") == 0)
359 return BTIF_CFG_TYPE_INT;
360 if(strcmp(type, "binary") == 0)
361 return BTIF_CFG_TYPE_BIN;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800362 error("unknown value type:%s", type);
363 return BTIF_CFG_TYPE_INVALID;
364}
365static const char* type_int2str(int type)
366{
367 switch(type)
368 {
369 case BTIF_CFG_TYPE_INT:
370 return "int";
371 case BTIF_CFG_TYPE_BIN:
372 return "binary";
373 case BTIF_CFG_TYPE_STR:
374 return "string";
375 default:
376 error("unknown type:%d", type);
377 break;
378 }
379 return NULL;
380}
381
382static inline void create_ele_name(int index, char* element, int len)
383{
384 snprintf(element, len, "N%d", index);
385}
386static inline int validate_ele_name(const char* key)
387{
388 //must be 'N' followed with numbers
389 if(key && *key == 'N' && *++key)
390 {
391 while(*key)
392 {
393 if(*key < '0' || *key > '9')
394 return FALSE;
395 ++key;
396 }
397 return TRUE;
398 }
399 return FALSE;
400}
401static int open_file_map(const char *pathname, const char**map, int* size)
402{
403 struct stat st;
404 st.st_size = 0;
405 int fd;
406 //debug("in");
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700407 if((fd = TEMP_FAILURE_RETRY(open(pathname, O_RDONLY))) >= 0)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800408 {
409 //debug("fd:%d", fd);
410 if(fstat(fd, &st) == 0 && st.st_size)
411 {
412 *size = st.st_size;
413 *map = (const char*)mmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0);
414 if(*map && *map != MAP_FAILED)
415 {
416 //debug("out map:%p, size:%d", *map, *size);
417 return fd;
418 }
419 }
420 close(fd);
421 }
422 //debug("out, failed");
423 return -1;
424}
425static void close_file_map(int fd, const char* map, int size)
426{
427 munmap((void*)map, size);
428 close(fd);
429}
430static int read_file_line(const char* map, int start_pos, int size, int* line_size)
431{
432 *line_size = 0;
433 //debug("in, start pos:%d, size:%d", start_pos, size);
434 int i;
435 for(i = start_pos; i < size; i++)
436 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800437 if(map[i] == '\r' || map[i] == '\n')
438 break;
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800439 ++*line_size;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800440 }
441 //debug("out, ret:%d, start pos:%d, size:%d, line_size:%d", i, start_pos, size, *line_size);
442 return i + 1;
443}
444static const char* find_value_line(const char* map, int size, const char *key, int* value_size)
445{
446 int key_len = strlen(key);
447 int i;
448 for(i = 0; i < size; i++)
449 {
450 if(map[i] == *key)
451 {
452 if(i + key_len + 1 > size)
453 return NULL;
454 if(memcmp(map + i, key, key_len) == 0)
455 {
456 read_file_line(map, i + key_len + 1, size, value_size);
457 if(*value_size)
458 return map + i + key_len + 1;
459 break;
460 }
461 }
462 }
463 return NULL;
464}
465static int read_line_word(const char* line, int start_pos, int line_size, char* word, int *word_size, bool lower_case = false)
466{
467 int i;
468 //skip space
469 //debug("in, line start_pos:%d, line_size:%d", start_pos, line_size);
470 for(i = start_pos; i < line_size; i++)
471 {
472 //debug("skip space loop, line[%d]:%c", i, line[i]);
473 if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n')
474 break;
475 }
476 *word_size = 0;
477 for(; i < line_size; i++)
478 {
479 //debug("add word loop, line[%d]:%c", i, line[i]);
480 if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n')
481 {
482 ++*word_size;
483 if(lower_case && 'A' <= line[i] && line[i] <= 'Z')
484 *word++ = 'a' - 'A' + line[i];
485 else
486 *word++ = line[i];
487 }
488 else break;
489 }
490 *word = 0;
491 //debug("out, ret:%d, word:%s, word_size:%d, line start_pos:%d, line_size:%d",
492 // i, word, *word_size, start_pos, line_size);
493 return i;
494}
495static int is_valid_bd_addr(const char* addr)
496{
497 int len = strlen(addr);
498 //debug("addr: %s, len:%d", addr, len);
499 return len == 17 && addr[2] == ':' && addr[5] == ':' && addr[14] == ':';
500}
501static int load_bluez_cfg_value(const char* adapter_path, const char* file_name)
502{
503 //debug("in");
504
505 const char* map = NULL;
506 int size = 0;
507 int ret = FALSE;
508 char path[256];
509 snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name);
510 int fd = open_file_map(path, &map, &size);
511 //debug("in, path:%s, fd:%d, size:%d", path, fd, size);
512 if(fd < 0 || size == 0)
513 {
514 error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
515 //debug("out");
Kim Schulz2a2701c2013-09-16 15:59:33 +0200516 if (fd >= 0)
517 close(fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800518 return FALSE;
519 }
520 //get local bt device name from bluez config
521 int line_size = 0;
522 const char *value_line = find_value_line(map, size, "name", &line_size);
523 if(value_line && line_size > 0)
524 {
525 char value[line_size + 1];
526 memcpy(value, value_line, line_size);
527 value[line_size] = 0;
528 //debug("import local bt dev names:%s", value);
529 btif_config_set_str("Local", "Adapter", "Name", value);
530 ret = TRUE;
531 }
532
533 close_file_map(fd, map, size);
534 //debug("out, ret:%d", ret);
535 return ret;
536}
537
538int load_bluez_adapter_info(char* adapter_path, int size)
539{
540 struct dirent *dptr;
541 DIR *dirp;
542 int ret = FALSE;
543 if((dirp = opendir(BLUEZ_PATH)) != NULL)
544 {
545 while((dptr = readdir(dirp)) != NULL)
546 {
547 //debug("readdir: %s",dptr->d_name);
548 if(is_valid_bd_addr(dptr->d_name))
549 {
550 snprintf(adapter_path, size, "%s%s", BLUEZ_PATH, dptr->d_name);
551 btif_config_set_str("Local", "Adapter", "Address", dptr->d_name);
552 load_bluez_cfg_value(adapter_path, BLUEZ_CONFIG);
553 ret = TRUE;
554 break;
555 }
556 }
557 closedir(dirp);
558 }
559 return ret;
560}
561static inline void upcase_addr(const char* laddr, char* uaddr, int size)
562{
563 int i;
564 for(i = 0; i < size && laddr[i]; i++)
565 uaddr[i] = ('a' <= laddr[i] && laddr[i] <= 'z') ?
566 laddr[i] - ('a' - 'A') : laddr[i];
567 uaddr[i] = 0;
568}
Hemant Gupta8cd229d2013-10-25 22:00:07 +0530569
570static int parse_hid_attribute(const char *str, int line_size, int len)
571{
572 if (len == 0 || line_size == 0 || str == NULL || (len%2))
573 return 0;
574
575 char hex_string[len + 1], hex_bytes[len/2];
576 memcpy(hex_string, str - 1, len);
577 hex_string[len] = 0;
578 hex2bytes(hex_string, len, hex_bytes);
579 if (len == 2)
580 return hex_bytes[0];
581 else if (len == 4)
582 return hex_bytes[0] << 8 | hex_bytes[1];
583 else return 0;
584}
585
586static int parse_bluez_hid_sdp_records(const char* adapter_path, const char* bd_addr)
587{
588 //debug("in");
589 char addr[32];
590 char pattern_to_search[50];
591 upcase_addr(bd_addr, addr, sizeof(addr));
592
593 const char* map = NULL;
594 int size = 0;
595 int ret = FALSE;
596 char path[256];
597 snprintf(path, sizeof(path), "%s/%s", adapter_path, BLUEZ_SDP);
598 int fd = open_file_map(path, &map, &size);
599 //debug("in, path:%s, addr:%s, fd:%d, size:%d", path, addr, fd, size);
600 if(fd < 0 || size == 0)
601 {
602 error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
603 //debug("out");
604 return FALSE;
605 }
606 int line_size = 0;
607 snprintf(pattern_to_search, sizeof(pattern_to_search), "%s#00010000", addr);
608 const char *value_line = find_value_line(map, size, pattern_to_search, &line_size);
609 int dev_sub_class = 0;
610 int app_id = 0;
611 int countrycode = 0;
612 int product = 0;
613 int vendor = 0;
614 int product_ver = 0;
615 int attr_mask = 0;
616 int ssr_max_lat = 0;
617 int ssr_min_timeout = 0;
618 int rep_desc_len = 0;
619 if(value_line && line_size)
620 {
621 char hid_sdp[line_size + 2];
622 memcpy(hid_sdp, value_line - 1, line_size);
623 hid_sdp[line_size + 1] = 0;
624 //debug("addr:%s, hid_sdp:%s", bd_addr, hid_sdp);
625 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SUB_CLASS, &line_size);
626 dev_sub_class = parse_hid_attribute(value_line, line_size, 2);
627 if(dev_sub_class)
628 {
629 if ((dev_sub_class & 0x80) == 0x80)
630 app_id = HID_APP_ID_MOUSE;
631 else
632 app_id = HID_APP_ID_KYB;
633 //debug("dev_sub_class:%d", dev_sub_class);
634 }
635 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_COUNTRY_CODE, &line_size);
636 countrycode = parse_hid_attribute(value_line, line_size, 2);
637 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_VIRTUAL_CABLE, &line_size);
638 if(parse_hid_attribute(value_line, line_size, 2))
639 {
640 attr_mask |= HID_ATTR_MASK_VIRTUAL_CABLE;
641 //debug("attr_mask after Virtual Unplug:%04x", attr_mask);
642 }
643 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_RECON_INNITIATE, &line_size);
644 if(parse_hid_attribute(value_line, line_size, 2))
645 {
646 attr_mask |= HID_ATTR_MASK_RECONN_INIT;
647 //debug("attr_mask after Reconnect Initiate:%04x", attr_mask);
648 }
649 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_REP_DSC_1, &line_size);
650 if(value_line && line_size)
651 {
652 char rep_desc[line_size + 1], rd[line_size/2 + 1];
653 char rep_dsc_len[5], rd_len[2];
654 memcpy(rep_dsc_len, value_line - 1, 4);
655 rep_dsc_len[4] = 0;
656 hex2bytes(rep_dsc_len, 4, rd_len);
657 rep_desc_len = (rd_len[0] << 8 | rd_len[1]) - (HID_RPT_DSCR_HDR_LEN_1 - 2);
658 //debug("rep_desc_len:%d", rep_desc_len);
659 memcpy(rep_desc, value_line - 1 + (HID_RPT_DSCR_HDR_LEN_1 * 2), rep_desc_len * 2);
660 rep_desc[rep_desc_len * 2] = 0;
661 hex2bytes(rep_desc, rep_desc_len* 2, rd);
662 if (rep_desc_len)
663 {
664 //debug("rep_desc:%s", rep_desc);
665 btif_config_set("Remote", bd_addr, "HidDescriptor", rd, rep_desc_len,
666 BTIF_CFG_TYPE_BIN);
667 }
668 }
669 else
670 {
671 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_REP_DSC_2, &line_size);
672 if(value_line && line_size)
673 {
674 char rep_dsc_len[3], rd_len[1];
675 memcpy(rep_dsc_len, value_line - 1, 2);
676 rep_dsc_len[2] = 0;
677 hex2bytes(rep_dsc_len, 2, rd_len);
678 rep_desc_len = rd_len[0] - (HID_RPT_DSCR_HDR_LEN_2 - 1);
679 //debug("rep_desc_len:%d", rep_desc_len);
680 char rep_desc[(rep_desc_len * 2) + 1], rd[rep_desc_len + 1];
681 memcpy(rep_desc, value_line - 1 + (HID_RPT_DSCR_HDR_LEN_2 * 2), rep_desc_len * 2);
682 rep_desc[rep_desc_len * 2] = 0;
683 hex2bytes(rep_desc, rep_desc_len * 2, rd);
684 if (rep_desc_len)
685 {
686 //debug("rep_desc:%s", rep_desc);
687 btif_config_set("Remote", bd_addr, "HidDescriptor", rd, rep_desc_len,
688 BTIF_CFG_TYPE_BIN);
689 }
690 }
691 }
692 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SDP_DISABLE, &line_size);
693 if(parse_hid_attribute(value_line, line_size, 2))
694 {
695 attr_mask |= HID_ATTR_MASK_SDP_DISABLE;
696 //debug("attr_mask after SDP Disable:%04x", attr_mask);
697 }
698 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_BAT_POWER, &line_size);
699 if(parse_hid_attribute(value_line, line_size, 2))
700 {
701 attr_mask |= HID_ATTR_MASK_BATTERY_POWER;
702 //debug("attr_mask after Battery Powered:%04x", attr_mask);
703 }
704 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_REM_WAKE, &line_size);
705 if(parse_hid_attribute(value_line, line_size, 2))
706 {
707 attr_mask |= HID_ATTR_MASK_REMOTE_WAKE;
708 //debug("attr_mask after Remote Wake:%04x", attr_mask);
709 }
710 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_NORM_CONN, &line_size);
711 if(parse_hid_attribute(value_line, line_size, 2))
712 {
713 attr_mask |= HID_ATTR_MASK_NORMALLY_CONNECTABLE;
714 //debug("attr_mask after Normally Conenctable:%04x", attr_mask);
715 }
716 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SUP_TIME, &line_size);
717 if(value_line && line_size)
718 attr_mask |= HID_ATTR_MASK_SUP_TOUT_AVLBL;
719 //debug("attr_mask after Supervision Timeout:%04x", attr_mask);
720 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SSR_MAX_LAT, &line_size);
721 ssr_max_lat = parse_hid_attribute(value_line, line_size, 4);
722 if(!ssr_max_lat)
723 ssr_max_lat = HID_SSR_PARAM_INVALID;
724 value_line = find_value_line(hid_sdp, strlen(hid_sdp), HID_SSR_MIN_TIM, &line_size);
725 ssr_min_timeout = parse_hid_attribute(value_line, line_size, 4);
726 if(!ssr_min_timeout)
727 ssr_min_timeout = HID_SSR_PARAM_INVALID;
728 snprintf(pattern_to_search, sizeof(pattern_to_search), "%s#00010001", addr);
729 value_line = find_value_line(map, size, pattern_to_search, &line_size);
730 if(value_line && line_size)
731 {
732 char did_sdp[line_size + 2];
733 memcpy(did_sdp, value_line - 1, line_size + 1);
734 did_sdp[line_size + 1] = 0;
735 //debug("addr:%s, did_sdp:%s", bd_addr, did_sdp);
736 value_line = find_value_line(did_sdp, strlen(did_sdp), HID_VENDOR_ID, &line_size);
737 vendor = parse_hid_attribute(value_line, line_size, 4);
738 value_line = find_value_line(did_sdp, strlen(did_sdp), HID_PRODUCT_ID, &line_size);
739 product = parse_hid_attribute(value_line, line_size, 4);
740 value_line = find_value_line(did_sdp, strlen(did_sdp), HID_PRODUCT_VERSION, &line_size);
741 product_ver = parse_hid_attribute(value_line, line_size, 4);
742 }
743 }
744 btif_config_set_int("Remote", bd_addr, "HidAttrMask", attr_mask);
745 btif_config_set_int("Remote", bd_addr, "HidSubClass", dev_sub_class);
746 btif_config_set_int("Remote", bd_addr, "HidAppId", app_id);
747 btif_config_set_int("Remote", bd_addr, "HidVendorId", vendor);
748 btif_config_set_int("Remote", bd_addr, "HidProductId", product);
749 btif_config_set_int("Remote", bd_addr, "HidVersion", product_ver);
750 btif_config_set_int("Remote", bd_addr, "HidCountryCode", countrycode);
751 btif_config_set_int("Remote", bd_addr, "HidSSRMinTimeout", ssr_min_timeout);
752 btif_config_set_int("Remote", bd_addr, "HidSSRMaxLatency", ssr_max_lat);
753 //debug("HidSubClass: %02x, app_id = %d, vendor = %04x, product = %04x, product_ver = %04x"
754 // "countrycode = %02x, ssr_min_timeout = %04x, ssr_max_lat = %04x",
755 // HidSubClass, app_id, vendor, product, product_ver, countrycode, ssr_min_timeout,
756 // ssr_max_lat);
757 close_file_map(fd, map, size);
758 ret = TRUE;
759 //debug("out, ret:%d", ret);
760 return ret;
761}
762
The Android Open Source Project5738f832012-12-12 16:00:35 -0800763static int load_bluez_dev_value(const char* adapter_path, const char* bd_addr,
764 const char* file_name, const char* cfg_value_name, int type)
765{
766 //debug("in");
767 char addr[32];
768 upcase_addr(bd_addr, addr, sizeof(addr));
769
770 const char* map = NULL;
771 int size = 0;
772 int ret = FALSE;
773 char path[256];
774 snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name);
775 int fd = open_file_map(path, &map, &size);
776 //debug("in, path:%s, addr:%s, fd:%d, size:%d", path, addr, fd, size);
777 if(fd < 0 || size == 0)
778 {
779 error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
780 //debug("out");
Kim Schulz2a2701c2013-09-16 15:59:33 +0200781 if (fd >= 0)
782 close(fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800783 return FALSE;
784 }
785 int line_size = 0;
786 const char *value_line = find_value_line(map, size, addr, &line_size);
787 if(value_line && line_size)
788 {
789 char line[line_size + 1];
790 memcpy(line, value_line, line_size);
791 line[line_size] = 0;
792 //debug("addr:%s, Names:%s", bd_addr, line);
793 if(type == BTIF_CFG_TYPE_STR)
794 btif_config_set_str("Remote", bd_addr, cfg_value_name, line);
795 else if(type == BTIF_CFG_TYPE_INT)
796 {
797 int v = strtol(line, NULL, 16);
Hemant Gupta8cd229d2013-10-25 22:00:07 +0530798 //parse sdp record in case remote device is hid
The Android Open Source Project5738f832012-12-12 16:00:35 -0800799 if(strcmp(file_name, BLUEZ_CLASSES) == 0)
800 {
801 switch((v & 0x1f00) >> 8)
802 {
803 case 0x5: //hid device
Hemant Gupta8cd229d2013-10-25 22:00:07 +0530804 info("parsing sdp for hid device %s", bd_addr);
805 parse_bluez_hid_sdp_records(adapter_path, bd_addr);
806 break;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800807 }
808 }
809 btif_config_set_int("Remote", bd_addr, cfg_value_name, v);
810 }
811 ret = TRUE;
812 }
813 close_file_map(fd, map, size);
814 //debug("out, ret:%d", ret);
815 return ret;
816}
817static inline int bz2bd_linkkeytype(int type)
818{
819#if 1
820 return type;
821#else
822 int table[5] = {0, 0, 0, 0, 0};
823 if(0 <= type && type < (int)(sizeof(table)/sizeof(int)))
824 return table[type];
825 return 0;
826#endif
827}
828int load_bluez_linkkeys(const char* adapter_path)
829{
830 const char* map = NULL;
831 int size = 0;
832 int ret = FALSE;
833 char path[256];
834 //debug("in");
835 snprintf(path, sizeof(path), "%s/%s", adapter_path, BLUEZ_LINKKEY);
836 int fd = open_file_map(path, &map, &size);
837 if(fd < 0 || size == 0)
838 {
839 error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
840 //debug("out");
Kim Schulz2a2701c2013-09-16 15:59:33 +0200841 if (fd >= 0)
842 close(fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800843 return FALSE;
844 }
845 int pos = 0;
846 //debug("path:%s, size:%d", path, size);
847 while(pos < size)
848 {
849 int line_size = 0;
850 int next_pos = read_file_line(map, pos, size, &line_size);
851 //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size);
852 if(line_size)
853 {
854 const char* line = map + pos;
855 char addr[line_size + 1];
856 int word_pos = 0;
857 int addr_size = 0;
858 word_pos = read_line_word(line, word_pos, line_size, addr, &addr_size, true);
859 //debug("read_line_word addr:%s, addr_size:%d", addr, addr_size);
860 if(*addr)
861 {
862 char value[line_size + 1];
863 int value_size = 0;
864 //read link key
865 word_pos = read_line_word(line, word_pos, line_size, value, &value_size);
866 //debug("read_line_word linkkey:%s, size:%d", value, value_size);
867 if(*value)
868 {
869 int linkkey_size = value_size / 2;
870 char linkkey[linkkey_size];
871 if(hex2bytes(value, value_size, linkkey))
872 { //read link key type
873 //bluez save the linkkey in reversed order
874 reverse_bin(linkkey, linkkey_size);
875 word_pos = read_line_word(line, word_pos,
876 line_size, value, &value_size);
877 if(*value)
878 {
879 if(load_bluez_dev_value(adapter_path, addr,
Amit Goel19cedbb2014-05-21 15:58:04 -0700880 BLUEZ_CLASSES, "DevClass", BTIF_CFG_TYPE_INT) ||
The Android Open Source Project5738f832012-12-12 16:00:35 -0800881 load_bluez_dev_value(adapter_path, addr,
Amit Goel19cedbb2014-05-21 15:58:04 -0700882 BLUEZ_NAMES, "Name", BTIF_CFG_TYPE_STR) ||
The Android Open Source Project5738f832012-12-12 16:00:35 -0800883 load_bluez_dev_value(adapter_path, addr,
Amit Goel19cedbb2014-05-21 15:58:04 -0700884 BLUEZ_TYPES, "DevType", BTIF_CFG_TYPE_INT) ||
The Android Open Source Project5738f832012-12-12 16:00:35 -0800885 load_bluez_dev_value(adapter_path, addr,
886 BLUEZ_PROFILES, "Service", BTIF_CFG_TYPE_STR))
887 {
888 load_bluez_dev_value(adapter_path, addr,
889 BLUEZ_ALIASES, "Aliase", BTIF_CFG_TYPE_STR);
890 int key_type = bz2bd_linkkeytype(atoi(value));
891
892 //read pin len
893 word_pos = read_line_word(line, word_pos, line_size, value, &value_size);
894 if(*value)
895 {
896 int pin_len = atoi(value);
897 ret = TRUE;
898 btif_config_set("Remote", addr, "LinkKey", linkkey,
899 linkkey_size, BTIF_CFG_TYPE_BIN);
900 //dump_bin("import bluez linkkey", linkkey, linkkey_size);
901 btif_config_set_int("Remote", addr, "LinkKeyType", key_type);
902 btif_config_set_int("Remote", addr, "PinLength", pin_len);
903 }
904 }
905 }
906 }
907 }
908 }
909 }
910 //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size);
911 pos = next_pos;
912 }
913 close_file_map(fd, map, size);
914 //debug("out, ret:%d", ret);
915 return ret;
916}
917