1 /****************************************************************************** 2 * 3 * Copyright (C) 1999-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 /****************************************************************************** 20 * 21 * This file contains functions for BLE whitelist operation. 22 * 23 ******************************************************************************/ 24 25 #include <base/logging.h> 26 #include <string.h> 27 #include <unordered_map> 28 29 #include "bt_types.h" 30 #include "bt_utils.h" 31 #include "btm_int.h" 32 #include "btu.h" 33 #include "device/include/controller.h" 34 #include "hcimsgs.h" 35 #include "l2c_int.h" 36 #include "osi/include/allocator.h" 37 #include "osi/include/osi.h" 38 39 #ifndef BTM_BLE_SCAN_PARAM_TOUT 40 #define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */ 41 #endif 42 43 static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state); 44 static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state); 45 46 // Unfortunately (for now?) we have to maintain a copy of the device whitelist 47 // on the host to determine if a device is pending to be connected or not. This 48 // controls whether the host should keep trying to scan for whitelisted 49 // peripherals or not. 50 // TODO: Move all of this to controller/le/background_list or similar? 51 typedef struct background_connection_t { 52 RawAddress address; 53 uint8_t addr_type; 54 55 bool in_controller_wl; 56 uint8_t addr_type_in_wl; 57 58 bool pending_removal; 59 } background_connection_t; 60 61 struct BgConnHash { 62 bool operator()(const RawAddress& x) const { 63 const uint8_t* a = x.address; 64 return a[0] ^ (a[1] << 8) ^ (a[2] << 16) ^ (a[3] << 24) ^ a[4] ^ 65 (a[5] << 8); 66 } 67 }; 68 69 static std::unordered_map<RawAddress, background_connection_t, BgConnHash> 70 background_connections; 71 72 static void background_connection_add(uint8_t addr_type, 73 const RawAddress& address) { 74 auto map_iter = background_connections.find(address); 75 if (map_iter == background_connections.end()) { 76 background_connections[address] = 77 background_connection_t{address, addr_type, false, 0, false}; 78 } else { 79 background_connection_t* connection = &map_iter->second; 80 connection->addr_type = addr_type; 81 connection->pending_removal = false; 82 } 83 } 84 85 static void background_connection_remove(const RawAddress& address) { 86 auto map_iter = background_connections.find(address); 87 if (map_iter != background_connections.end()) { 88 if (map_iter->second.in_controller_wl) { 89 map_iter->second.pending_removal = true; 90 } else { 91 background_connections.erase(map_iter); 92 } 93 } 94 } 95 96 static void background_connections_clear() { background_connections.clear(); } 97 98 static bool background_connections_pending() { 99 for (auto& map_el : background_connections) { 100 background_connection_t* connection = &map_el.second; 101 if (connection->pending_removal) continue; 102 const bool connected = 103 BTM_IsAclConnectionUp(connection->address, BT_TRANSPORT_LE); 104 if (!connected) { 105 return true; 106 } 107 } 108 return false; 109 } 110 111 static int background_connections_count() { 112 int count = 0; 113 for (auto& map_el : background_connections) { 114 if (!map_el.second.pending_removal) ++count; 115 } 116 return count; 117 } 118 119 /******************************************************************************* 120 * 121 * Function btm_update_scanner_filter_policy 122 * 123 * Description This function updates the filter policy of scanner 124 ******************************************************************************/ 125 void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) { 126 tBTM_BLE_INQ_CB* p_inq = &btm_cb.ble_ctr_cb.inq_var; 127 128 uint32_t scan_interval = 129 !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval; 130 uint32_t scan_window = 131 !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window; 132 133 BTM_TRACE_EVENT("%s", __func__); 134 135 p_inq->sfp = scan_policy; 136 p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE 137 ? BTM_BLE_SCAN_MODE_ACTI 138 : p_inq->scan_type; 139 140 btm_send_hci_set_scan_params( 141 p_inq->scan_type, (uint16_t)scan_interval, (uint16_t)scan_window, 142 btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, scan_policy); 143 } 144 145 /******************************************************************************* 146 * 147 * Function btm_ble_bgconn_cancel_if_disconnected 148 * 149 * Description If a device has been disconnected, it must be re-added to 150 * the white list. If needed, this function cancels a pending 151 * initiate command in order to trigger restart of the initiate 152 * command which in turn updates the white list. 153 * 154 * Parameters bd_addr: updated device 155 * 156 ******************************************************************************/ 157 void btm_ble_bgconn_cancel_if_disconnected(const RawAddress& bd_addr) { 158 if (btm_cb.ble_ctr_cb.conn_state != BLE_BG_CONN) return; 159 160 auto map_it = background_connections.find(bd_addr); 161 if (map_it != background_connections.end()) { 162 background_connection_t* connection = &map_it->second; 163 if (!connection->in_controller_wl && !connection->pending_removal && 164 !BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) { 165 btm_ble_start_auto_conn(false); 166 } 167 } 168 } 169 170 /******************************************************************************* 171 * 172 * Function btm_add_dev_to_controller 173 * 174 * Description This function load the device into controller white list 175 ******************************************************************************/ 176 bool btm_add_dev_to_controller(bool to_add, const RawAddress& bd_addr) { 177 tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); 178 bool started = false; 179 180 if (p_dev_rec != NULL && p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) { 181 if (to_add) { 182 if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || 183 !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) { 184 background_connection_add(p_dev_rec->ble.ble_addr_type, bd_addr); 185 started = true; 186 p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT; 187 } else if (p_dev_rec->ble.static_addr != bd_addr && 188 !p_dev_rec->ble.static_addr.IsEmpty()) { 189 background_connection_add(p_dev_rec->ble.static_addr_type, 190 p_dev_rec->ble.static_addr); 191 started = true; 192 p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT; 193 } 194 } else { 195 if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || 196 !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) { 197 background_connection_remove(bd_addr); 198 started = true; 199 } 200 201 if (!p_dev_rec->ble.static_addr.IsEmpty() && 202 p_dev_rec->ble.static_addr != bd_addr) { 203 background_connection_remove(p_dev_rec->ble.static_addr); 204 started = true; 205 } 206 207 p_dev_rec->ble.in_controller_list &= ~BTM_WHITE_LIST_BIT; 208 } 209 } else { 210 /* not a known device, i.e. attempt to connect to device never seen before 211 */ 212 uint8_t addr_type = 213 BTM_IS_PUBLIC_BDA(bd_addr) ? BLE_ADDR_PUBLIC : BLE_ADDR_RANDOM; 214 started = true; 215 if (to_add) 216 background_connection_add(addr_type, bd_addr); 217 else 218 background_connection_remove(bd_addr); 219 } 220 221 return started; 222 } 223 /******************************************************************************* 224 * 225 * Function btm_execute_wl_dev_operation 226 * 227 * Description execute the pending whitelist device operation (loading or 228 * removing) 229 ******************************************************************************/ 230 bool btm_execute_wl_dev_operation(void) { 231 // handle removals first to avoid filling up controller's white list 232 for (auto map_it = background_connections.begin(); 233 map_it != background_connections.end();) { 234 background_connection_t* connection = &map_it->second; 235 if (connection->pending_removal) { 236 btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl, 237 connection->address); 238 map_it = background_connections.erase(map_it); 239 } else 240 ++map_it; 241 } 242 for (auto& map_el : background_connections) { 243 background_connection_t* connection = &map_el.second; 244 const bool connected = 245 BTM_IsAclConnectionUp(connection->address, BT_TRANSPORT_LE); 246 if (!connection->in_controller_wl && !connected) { 247 btsnd_hcic_ble_add_white_list(connection->addr_type, connection->address); 248 connection->in_controller_wl = true; 249 connection->addr_type_in_wl = connection->addr_type; 250 } else if (connection->in_controller_wl && connected) { 251 /* Bluetooth Core 4.2 as well as ESR08 disallows more than one 252 connection between two LE addresses. Not all controllers handle this 253 correctly, therefore we must make sure connected devices are not in 254 the white list when bg connection attempt is active. */ 255 btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl, 256 connection->address); 257 connection->in_controller_wl = false; 258 } 259 } 260 return true; 261 } 262 263 /******************************************************************************* 264 * 265 * Function btm_update_dev_to_white_list 266 * 267 * Description This function adds or removes a device into/from 268 * the white list. 269 * 270 ******************************************************************************/ 271 bool btm_update_dev_to_white_list(bool to_add, const RawAddress& bd_addr) { 272 tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb; 273 274 if (to_add && 275 background_connections_count() == 276 controller_get_interface()->get_ble_white_list_size()) { 277 BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__); 278 return false; 279 } 280 281 btm_suspend_wl_activity(p_cb->wl_state); 282 btm_add_dev_to_controller(to_add, bd_addr); 283 btm_resume_wl_activity(p_cb->wl_state); 284 return true; 285 } 286 287 /******************************************************************************* 288 * 289 * Function btm_ble_clear_white_list 290 * 291 * Description This function clears the white list. 292 * 293 ******************************************************************************/ 294 void btm_ble_clear_white_list(void) { 295 BTM_TRACE_EVENT("btm_ble_clear_white_list"); 296 btsnd_hcic_ble_clear_white_list(); 297 background_connections_clear(); 298 } 299 300 /******************************************************************************* 301 * 302 * Function btm_ble_clear_white_list_complete 303 * 304 * Description Indicates white list cleared. 305 * 306 ******************************************************************************/ 307 void btm_ble_clear_white_list_complete(uint8_t* p_data, 308 UNUSED_ATTR uint16_t evt_len) { 309 uint8_t status; 310 311 STREAM_TO_UINT8(status, p_data); 312 BTM_TRACE_EVENT("%s status=%d", __func__, status); 313 } 314 315 /******************************************************************************* 316 * 317 * Function btm_ble_white_list_init 318 * 319 * Description Initialize white list size 320 * 321 ******************************************************************************/ 322 void btm_ble_white_list_init(uint8_t white_list_size) { 323 BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size); 324 } 325 326 /******************************************************************************* 327 * 328 * Function btm_ble_add_2_white_list_complete 329 * 330 * Description White list element added 331 * 332 ******************************************************************************/ 333 void btm_ble_add_2_white_list_complete(uint8_t status) { 334 BTM_TRACE_EVENT("%s status=%d", __func__, status); 335 } 336 337 /******************************************************************************* 338 * 339 * Function btm_ble_remove_from_white_list_complete 340 * 341 * Description White list element removal complete 342 * 343 ******************************************************************************/ 344 void btm_ble_remove_from_white_list_complete(uint8_t* p, 345 UNUSED_ATTR uint16_t evt_len) { 346 BTM_TRACE_EVENT("%s status=%d", __func__, *p); 347 } 348 349 void btm_send_hci_create_connection( 350 uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy, 351 uint8_t addr_type_peer, const RawAddress& bda_peer, uint8_t addr_type_own, 352 uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency, 353 uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len, 354 uint8_t initiating_phys) { 355 if (controller_get_interface()->supports_ble_extended_advertising()) { 356 EXT_CONN_PHY_CFG phy_cfg[3]; // maximum three phys 357 358 int phy_cnt = 359 std::bitset<std::numeric_limits<uint8_t>::digits>(initiating_phys) 360 .count(); 361 362 LOG_ASSERT(phy_cnt < 3) << "More than three phys provided"; 363 // TODO(jpawlowski): tune parameters for different transports 364 for (int i = 0; i < phy_cnt; i++) { 365 phy_cfg[i].scan_int = scan_int; 366 phy_cfg[i].scan_win = scan_win; 367 phy_cfg[i].conn_int_min = conn_int_min; 368 phy_cfg[i].conn_int_max = conn_int_max; 369 phy_cfg[i].conn_latency = conn_latency; 370 phy_cfg[i].sup_timeout = conn_timeout; 371 phy_cfg[i].min_ce_len = min_ce_len; 372 phy_cfg[i].max_ce_len = max_ce_len; 373 } 374 375 addr_type_peer &= ~BLE_ADDR_TYPE_ID_BIT; 376 btsnd_hcic_ble_ext_create_conn(init_filter_policy, addr_type_own, 377 addr_type_peer, bda_peer, initiating_phys, 378 phy_cfg); 379 } else { 380 btsnd_hcic_ble_create_ll_conn(scan_int, scan_win, init_filter_policy, 381 addr_type_peer, bda_peer, addr_type_own, 382 conn_int_min, conn_int_max, conn_latency, 383 conn_timeout, min_ce_len, max_ce_len); 384 } 385 } 386 387 /******************************************************************************* 388 * 389 * Function btm_ble_start_auto_conn 390 * 391 * Description This function is to start/stop auto connection procedure. 392 * 393 * Parameters start: true to start; false to stop. 394 * 395 * Returns void 396 * 397 ******************************************************************************/ 398 bool btm_ble_start_auto_conn(bool start) { 399 tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb; 400 bool exec = true; 401 uint16_t scan_int; 402 uint16_t scan_win; 403 uint8_t own_addr_type = p_cb->addr_mgnt_cb.own_addr_type; 404 uint8_t peer_addr_type = BLE_ADDR_PUBLIC; 405 406 uint8_t phy = PHY_LE_1M; 407 if (controller_get_interface()->supports_ble_2m_phy()) phy |= PHY_LE_2M; 408 if (controller_get_interface()->supports_ble_coded_phy()) phy |= PHY_LE_CODED; 409 410 BTM_TRACE_EVENT("%s start=%d", __func__, start); 411 412 if (start) { 413 if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending() && 414 btm_ble_topology_check(BTM_BLE_STATE_INIT) && l2cu_can_allocate_lcb()) { 415 p_cb->wl_state |= BTM_BLE_WL_INIT; 416 417 btm_execute_wl_dev_operation(); 418 419 #if (BLE_PRIVACY_SPT == TRUE) 420 btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT); 421 #endif 422 scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) 423 ? BTM_BLE_SCAN_SLOW_INT_1 424 : p_cb->scan_int; 425 scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) 426 ? BTM_BLE_SCAN_SLOW_WIN_1 427 : p_cb->scan_win; 428 429 #if (BLE_PRIVACY_SPT == TRUE) 430 if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE && 431 controller_get_interface()->supports_ble_privacy()) { 432 own_addr_type |= BLE_ADDR_TYPE_ID_BIT; 433 peer_addr_type |= BLE_ADDR_TYPE_ID_BIT; 434 } 435 #endif 436 437 btm_send_hci_create_connection( 438 scan_int, /* uint16_t scan_int */ 439 scan_win, /* uint16_t scan_win */ 440 0x01, /* uint8_t white_list */ 441 peer_addr_type, /* uint8_t addr_type_peer */ 442 RawAddress::kEmpty, /* BD_ADDR bda_peer */ 443 own_addr_type, /* uint8_t addr_type_own */ 444 BTM_BLE_CONN_INT_MIN_DEF, /* uint16_t conn_int_min */ 445 BTM_BLE_CONN_INT_MAX_DEF, /* uint16_t conn_int_max */ 446 BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* uint16_t conn_latency */ 447 BTM_BLE_CONN_TIMEOUT_DEF, /* uint16_t conn_timeout */ 448 0, /* uint16_t min_len */ 449 0, /* uint16_t max_len */ 450 phy); 451 btm_ble_set_conn_st(BLE_BG_CONN); 452 } else { 453 exec = false; 454 } 455 } else { 456 if (p_cb->conn_state == BLE_BG_CONN) { 457 btsnd_hcic_ble_create_conn_cancel(); 458 btm_ble_set_conn_st(BLE_CONN_CANCEL); 459 p_cb->wl_state &= ~BTM_BLE_WL_INIT; 460 } else { 461 BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop", 462 p_cb->conn_state); 463 exec = false; 464 } 465 } 466 return exec; 467 } 468 469 /******************************************************************************* 470 * 471 * Function btm_ble_suspend_bg_conn 472 * 473 * Description This function is to suspend an active background connection 474 * procedure. 475 * 476 * Parameters none. 477 * 478 * Returns none. 479 * 480 ******************************************************************************/ 481 bool btm_ble_suspend_bg_conn(void) { 482 BTM_TRACE_EVENT("%s", __func__); 483 484 if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO) 485 return btm_ble_start_auto_conn(false); 486 487 return false; 488 } 489 /******************************************************************************* 490 * 491 * Function btm_suspend_wl_activity 492 * 493 * Description This function is to suspend white list related activity 494 * 495 * Returns none. 496 * 497 ******************************************************************************/ 498 static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state) { 499 if (wl_state & BTM_BLE_WL_INIT) { 500 btm_ble_start_auto_conn(false); 501 } 502 } 503 /******************************************************************************* 504 * 505 * Function btm_resume_wl_activity 506 * 507 * Description This function is to resume white list related activity 508 * 509 * Returns none. 510 * 511 ******************************************************************************/ 512 static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) { 513 btm_ble_resume_bg_conn(); 514 } 515 /******************************************************************************* 516 * 517 * Function btm_ble_resume_bg_conn 518 * 519 * Description This function is to resume a background auto connection 520 * procedure. 521 * 522 * Parameters none. 523 * 524 * Returns none. 525 * 526 ******************************************************************************/ 527 bool btm_ble_resume_bg_conn(void) { 528 tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb; 529 if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) { 530 return btm_ble_start_auto_conn(true); 531 } 532 533 return false; 534 } 535 /******************************************************************************* 536 * 537 * Function btm_ble_get_conn_st 538 * 539 * Description This function get BLE connection state 540 * 541 * Returns connection state 542 * 543 ******************************************************************************/ 544 tBTM_BLE_CONN_ST btm_ble_get_conn_st(void) { 545 return btm_cb.ble_ctr_cb.conn_state; 546 } 547 /******************************************************************************* 548 * 549 * Function btm_ble_set_conn_st 550 * 551 * Description This function set BLE connection state 552 * 553 * Returns None. 554 * 555 ******************************************************************************/ 556 void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st) { 557 btm_cb.ble_ctr_cb.conn_state = new_st; 558 559 if (new_st == BLE_BG_CONN || new_st == BLE_DIR_CONN) 560 btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT); 561 else 562 btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT); 563 } 564 565 /******************************************************************************* 566 * 567 * Function btm_ble_enqueue_direct_conn_req 568 * 569 * Description This function enqueue the direct connection request 570 * 571 * Returns None. 572 * 573 ******************************************************************************/ 574 void btm_ble_enqueue_direct_conn_req(void* p_param) { 575 tBTM_BLE_CONN_REQ* p = 576 (tBTM_BLE_CONN_REQ*)osi_malloc(sizeof(tBTM_BLE_CONN_REQ)); 577 578 p->p_param = p_param; 579 580 fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p); 581 } 582 /******************************************************************************* 583 * 584 * Function btm_ble_dequeue_direct_conn_req 585 * 586 * Description This function dequeues the direct connection request 587 * 588 * Returns None. 589 * 590 ******************************************************************************/ 591 void btm_ble_dequeue_direct_conn_req(const RawAddress& rem_bda) { 592 if (fixed_queue_is_empty(btm_cb.ble_ctr_cb.conn_pending_q)) return; 593 594 list_t* list = fixed_queue_get_list(btm_cb.ble_ctr_cb.conn_pending_q); 595 for (const list_node_t* node = list_begin(list); node != list_end(list); 596 node = list_next(node)) { 597 tBTM_BLE_CONN_REQ* p_req = (tBTM_BLE_CONN_REQ*)list_node(node); 598 tL2C_LCB* p_lcb = (tL2C_LCB*)p_req->p_param; 599 if ((p_lcb == NULL) || (!p_lcb->in_use)) { 600 continue; 601 } 602 // If BD address matches 603 if (rem_bda == p_lcb->remote_bd_addr) { 604 fixed_queue_try_remove_from_queue(btm_cb.ble_ctr_cb.conn_pending_q, 605 p_req); 606 l2cu_release_lcb((tL2C_LCB*)p_req->p_param); 607 osi_free((void*)p_req); 608 break; 609 } 610 } 611 } 612 /******************************************************************************* 613 * 614 * Function btm_send_pending_direct_conn 615 * 616 * Description This function send the pending direct connection request in 617 * queue 618 * 619 * Returns true if started, false otherwise 620 * 621 ******************************************************************************/ 622 bool btm_send_pending_direct_conn(void) { 623 tBTM_BLE_CONN_REQ* p_req; 624 bool rt = false; 625 626 p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_try_dequeue( 627 btm_cb.ble_ctr_cb.conn_pending_q); 628 if (p_req != NULL) { 629 tL2C_LCB* p_lcb = (tL2C_LCB*)(p_req->p_param); 630 /* Ignore entries that might have been released while queued. */ 631 if (p_lcb->in_use) rt = l2cble_init_direct_conn(p_lcb); 632 osi_free(p_req); 633 } 634 635 return rt; 636 } 637