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