1 /******************************************************************************
2 *
3 * Copyright 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 <unordered_map>
27
28 #include "bt_types.h"
29 #include "btm_int.h"
30 #include "btu.h"
31 #include "device/include/controller.h"
32 #include "hcimsgs.h"
33 #include "l2c_int.h"
34
35 extern void btm_send_hci_create_connection(
36 uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
37 uint8_t addr_type_peer, const RawAddress& bda_peer, uint8_t addr_type_own,
38 uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
39 uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
40 uint8_t phy);
41 extern void btm_ble_create_conn_cancel();
42 void wl_remove_complete(uint8_t* p_data, uint16_t /* evt_len */);
43
44 // Unfortunately (for now?) we have to maintain a copy of the device whitelist
45 // on the host to determine if a device is pending to be connected or not. This
46 // controls whether the host should keep trying to scan for whitelisted
47 // peripherals or not.
48 // TODO: Move all of this to controller/le/background_list or similar?
49 struct BackgroundConnection {
50 RawAddress address;
51 uint8_t addr_type;
52 bool in_controller_wl;
53 uint8_t addr_type_in_wl;
54 bool pending_removal;
55 };
56
57 struct BgConnHash {
operator ()BgConnHash58 std::size_t operator()(const RawAddress& x) const {
59 const uint8_t* a = x.address;
60 return a[0] ^ (a[1] << 8) ^ (a[2] << 16) ^ (a[3] << 24) ^ a[4] ^
61 (a[5] << 8);
62 }
63 };
64
65 static std::unordered_map<RawAddress, BackgroundConnection, BgConnHash>
66 background_connections;
67
background_connection_add(uint8_t addr_type,const RawAddress & address)68 static void background_connection_add(uint8_t addr_type,
69 const RawAddress& address) {
70 auto map_iter = background_connections.find(address);
71 if (map_iter == background_connections.end()) {
72 background_connections[address] =
73 BackgroundConnection{address, addr_type, false, 0, false};
74 } else {
75 BackgroundConnection* connection = &map_iter->second;
76 if (addr_type != connection->addr_type) {
77 LOG(INFO) << __func__ << " Addr type mismatch " << address;
78 btsnd_hcic_ble_remove_from_white_list(
79 connection->addr_type_in_wl, connection->address,
80 base::Bind(&wl_remove_complete));
81 connection->addr_type = addr_type;
82 connection->in_controller_wl = false;
83 }
84 connection->pending_removal = false;
85 }
86 }
87
background_connection_remove(const RawAddress & address)88 static void background_connection_remove(const RawAddress& address) {
89 auto map_iter = background_connections.find(address);
90 if (map_iter != background_connections.end()) {
91 if (map_iter->second.in_controller_wl) {
92 map_iter->second.pending_removal = true;
93 } else {
94 background_connections.erase(map_iter);
95 }
96 }
97 }
98
background_connections_clear()99 static void background_connections_clear() { background_connections.clear(); }
100
background_connections_pending()101 static bool background_connections_pending() {
102 for (auto& map_el : background_connections) {
103 BackgroundConnection* connection = &map_el.second;
104 if (connection->pending_removal) continue;
105 const bool connected =
106 BTM_IsAclConnectionUp(connection->address, BT_TRANSPORT_LE);
107 if (!connected) {
108 return true;
109 }
110 }
111 return false;
112 }
113
background_connections_count()114 static int background_connections_count() {
115 int count = 0;
116 for (auto& map_el : background_connections) {
117 if (!map_el.second.pending_removal) ++count;
118 }
119 return count;
120 }
121
122 /*******************************************************************************
123 *
124 * Function btm_update_scanner_filter_policy
125 *
126 * Description This function updates the filter policy of scanner
127 ******************************************************************************/
btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy)128 void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) {
129 tBTM_BLE_INQ_CB* p_inq = &btm_cb.ble_ctr_cb.inq_var;
130
131 uint32_t scan_interval =
132 !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
133 uint32_t scan_window =
134 !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
135
136 BTM_TRACE_EVENT("%s", __func__);
137
138 p_inq->sfp = scan_policy;
139 p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE
140 ? BTM_BLE_SCAN_MODE_ACTI
141 : p_inq->scan_type;
142
143 btm_send_hci_set_scan_params(
144 p_inq->scan_type, (uint16_t)scan_interval, (uint16_t)scan_window,
145 btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, scan_policy);
146 }
147
148 /*******************************************************************************
149 *
150 * Function btm_ble_bgconn_cancel_if_disconnected
151 *
152 * Description If a device has been disconnected, it must be re-added to
153 * the white list. If needed, this function cancels a pending
154 * initiate command in order to trigger restart of the initiate
155 * command which in turn updates the white list.
156 *
157 * Parameters bd_addr: updated device
158 *
159 ******************************************************************************/
btm_ble_bgconn_cancel_if_disconnected(const RawAddress & bd_addr)160 void btm_ble_bgconn_cancel_if_disconnected(const RawAddress& bd_addr) {
161 if (btm_ble_get_conn_st() != BLE_CONNECTING) return;
162
163 auto map_it = background_connections.find(bd_addr);
164 if (map_it != background_connections.end()) {
165 BackgroundConnection* connection = &map_it->second;
166 if (!connection->in_controller_wl && !connection->pending_removal &&
167 !BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) {
168 btm_ble_stop_auto_conn();
169 }
170 }
171 }
172
BTM_BackgroundConnectAddressKnown(const RawAddress & address)173 bool BTM_BackgroundConnectAddressKnown(const RawAddress& address) {
174 tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address);
175
176 // not a known device, or a classic device, we assume public address
177 if (p_dev_rec == NULL || (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == 0)
178 return true;
179
180 // bonded device with identity address known
181 if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
182 return true;
183 }
184
185 // Public address, Random Static, or Random Non-Resolvable Address known
186 if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC ||
187 !BTM_BLE_IS_RESOLVE_BDA(address)) {
188 return true;
189 }
190
191 // Only Resolvable Private Address (RPA) is known, we don't allow it into
192 // the background connection procedure.
193 return false;
194 }
195
196 /*******************************************************************************
197 *
198 * Function btm_add_dev_to_controller
199 *
200 * Description This function load the device into controller white list
201 ******************************************************************************/
btm_add_dev_to_controller(bool to_add,const RawAddress & bd_addr)202 bool btm_add_dev_to_controller(bool to_add, const RawAddress& bd_addr) {
203 tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
204
205 if (p_dev_rec != NULL && p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) {
206 if (to_add) {
207 if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
208 background_connection_add(p_dev_rec->ble.identity_addr_type,
209 p_dev_rec->ble.identity_addr);
210 } else {
211 background_connection_add(p_dev_rec->ble.ble_addr_type, bd_addr);
212
213 if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM &&
214 BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
215 LOG(INFO) << __func__ << " addig RPA into white list";
216 }
217 }
218
219 p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
220 } else {
221 if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
222 background_connection_remove(p_dev_rec->ble.identity_addr);
223 } else {
224 background_connection_remove(bd_addr);
225
226 if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM &&
227 BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
228 LOG(INFO) << __func__ << " removing RPA from white list";
229 }
230 }
231
232 p_dev_rec->ble.in_controller_list &= ~BTM_WHITE_LIST_BIT;
233 }
234 } else {
235 /* not a known device, i.e. attempt to connect to device never seen before
236 */
237 if (to_add)
238 background_connection_add(BLE_ADDR_PUBLIC, bd_addr);
239 else
240 background_connection_remove(bd_addr);
241 }
242
243 return true;
244 }
245
246 /** White list add complete */
wl_add_complete(uint8_t * p_data,uint16_t)247 void wl_add_complete(uint8_t* p_data, uint16_t /* evt_len */) {
248 uint8_t status;
249 STREAM_TO_UINT8(status, p_data);
250 VLOG(2) << __func__ << ": status=" << loghex(status);
251 }
252
253 /** White list element remove complete */
wl_remove_complete(uint8_t * p_data,uint16_t)254 void wl_remove_complete(uint8_t* p_data, uint16_t /* evt_len */) {
255 uint8_t status;
256 STREAM_TO_UINT8(status, p_data);
257 VLOG(2) << __func__ << ": status=" << loghex(status);
258 }
259
260 /*******************************************************************************
261 *
262 * Function btm_execute_wl_dev_operation
263 *
264 * Description execute the pending whitelist device operation (loading or
265 * removing)
266 ******************************************************************************/
btm_execute_wl_dev_operation(void)267 bool btm_execute_wl_dev_operation(void) {
268 // handle removals first to avoid filling up controller's white list
269 for (auto map_it = background_connections.begin();
270 map_it != background_connections.end();) {
271 BackgroundConnection* connection = &map_it->second;
272 if (connection->pending_removal) {
273 btsnd_hcic_ble_remove_from_white_list(
274 connection->addr_type_in_wl, connection->address,
275 base::BindOnce(&wl_remove_complete));
276 map_it = background_connections.erase(map_it);
277 } else
278 ++map_it;
279 }
280 for (auto& map_el : background_connections) {
281 BackgroundConnection* connection = &map_el.second;
282 const bool connected =
283 BTM_IsAclConnectionUp(connection->address, BT_TRANSPORT_LE);
284 if (!connection->in_controller_wl && !connected) {
285 btsnd_hcic_ble_add_white_list(connection->addr_type, connection->address,
286 base::BindOnce(&wl_add_complete));
287 connection->in_controller_wl = true;
288 connection->addr_type_in_wl = connection->addr_type;
289 } else if (connection->in_controller_wl && connected) {
290 /* Bluetooth Core 4.2 as well as ESR08 disallows more than one
291 connection between two LE addresses. Not all controllers handle this
292 correctly, therefore we must make sure connected devices are not in
293 the white list when bg connection attempt is active. */
294 btsnd_hcic_ble_remove_from_white_list(
295 connection->addr_type_in_wl, connection->address,
296 base::BindOnce(&wl_remove_complete));
297 connection->in_controller_wl = false;
298 }
299 }
300 return true;
301 }
302
303 /*******************************************************************************
304 *
305 * Function btm_ble_white_list_init
306 *
307 * Description Initialize white list size
308 *
309 ******************************************************************************/
btm_ble_white_list_init(uint8_t white_list_size)310 void btm_ble_white_list_init(uint8_t white_list_size) {
311 BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
312 }
313
BTM_GetWhiteListSize()314 uint8_t BTM_GetWhiteListSize() {
315 const controller_t* controller = controller_get_interface();
316 if (!controller->supports_ble()) {
317 return 0;
318 }
319 return controller->get_ble_white_list_size();
320 }
321
BTM_SetLeConnectionModeToFast()322 bool BTM_SetLeConnectionModeToFast() {
323 VLOG(2) << __func__;
324 tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
325 if ((p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF &&
326 p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ||
327 (p_cb->scan_int == BTM_BLE_SCAN_SLOW_INT_1 &&
328 p_cb->scan_win == BTM_BLE_SCAN_SLOW_WIN_1)) {
329 p_cb->scan_int = BTM_BLE_SCAN_FAST_INT;
330 p_cb->scan_win = BTM_BLE_SCAN_FAST_WIN;
331 return true;
332 }
333 return false;
334 }
335
BTM_SetLeConnectionModeToSlow()336 void BTM_SetLeConnectionModeToSlow() {
337 VLOG(2) << __func__;
338 tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
339 if ((p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF &&
340 p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ||
341 (p_cb->scan_int == BTM_BLE_SCAN_FAST_INT &&
342 p_cb->scan_win == BTM_BLE_SCAN_FAST_WIN)) {
343 p_cb->scan_int = BTM_BLE_SCAN_SLOW_INT_1;
344 p_cb->scan_win = BTM_BLE_SCAN_SLOW_WIN_1;
345 }
346 }
347
348 /** This function is to start auto connection procedure */
btm_ble_start_auto_conn()349 bool btm_ble_start_auto_conn() {
350 tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
351
352 BTM_TRACE_EVENT("%s", __func__);
353
354 uint16_t scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
355 ? BTM_BLE_SCAN_SLOW_INT_1
356 : p_cb->scan_int;
357 uint16_t scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
358 ? BTM_BLE_SCAN_SLOW_WIN_1
359 : p_cb->scan_win;
360 uint8_t own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
361 uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
362
363 uint8_t phy = PHY_LE_1M;
364 if (controller_get_interface()->supports_ble_2m_phy()) phy |= PHY_LE_2M;
365 if (controller_get_interface()->supports_ble_coded_phy()) phy |= PHY_LE_CODED;
366
367 if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) {
368 LOG(INFO) << "initate background connection fail, topology limitation";
369 return false;
370 }
371
372 if (btm_ble_get_conn_st() != BLE_CONN_IDLE ||
373 !background_connections_pending() || !l2cu_can_allocate_lcb()) {
374 return false;
375 }
376
377 p_cb->wl_state |= BTM_BLE_WL_INIT;
378
379 btm_execute_wl_dev_operation();
380
381 #if (BLE_PRIVACY_SPT == TRUE)
382 btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT);
383 if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE &&
384 controller_get_interface()->supports_ble_privacy()) {
385 own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
386 peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
387 }
388 #endif
389
390 btm_send_hci_create_connection(
391 scan_int, /* uint16_t scan_int */
392 scan_win, /* uint16_t scan_win */
393 0x01, /* uint8_t white_list */
394 peer_addr_type, /* uint8_t addr_type_peer */
395 RawAddress::kEmpty, /* BD_ADDR bda_peer */
396 own_addr_type, /* uint8_t addr_type_own */
397 BTM_BLE_CONN_INT_MIN_DEF, /* uint16_t conn_int_min */
398 BTM_BLE_CONN_INT_MAX_DEF, /* uint16_t conn_int_max */
399 BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* uint16_t conn_latency */
400 BTM_BLE_CONN_TIMEOUT_DEF, /* uint16_t conn_timeout */
401 0, /* uint16_t min_len */
402 0, /* uint16_t max_len */
403 phy);
404 return true;
405 }
406
407 /** This function is to stop auto connection procedure */
btm_ble_stop_auto_conn()408 bool btm_ble_stop_auto_conn() {
409 BTM_TRACE_EVENT("%s", __func__);
410
411 if (btm_ble_get_conn_st() != BLE_CONNECTING) {
412 BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop",
413 btm_ble_get_conn_st());
414 return false;
415 }
416
417 btm_ble_create_conn_cancel();
418
419 btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_INIT;
420 return true;
421 }
422
423 /*******************************************************************************
424 *
425 * Function btm_ble_suspend_bg_conn
426 *
427 * Description This function is to suspend an active background connection
428 * procedure.
429 *
430 * Parameters none.
431 *
432 * Returns none.
433 *
434 ******************************************************************************/
btm_ble_suspend_bg_conn(void)435 bool btm_ble_suspend_bg_conn(void) {
436 BTM_TRACE_EVENT("%s", __func__);
437 return btm_ble_stop_auto_conn();
438 }
439
440 /*******************************************************************************
441 *
442 * Function btm_ble_resume_bg_conn
443 *
444 * Description This function is to resume a background auto connection
445 * procedure.
446 *
447 * Parameters none.
448 *
449 * Returns none.
450 *
451 ******************************************************************************/
btm_ble_resume_bg_conn(void)452 bool btm_ble_resume_bg_conn(void) { return btm_ble_start_auto_conn(); }
453
454 /** Adds the device into white list. Returns false if white list is full and
455 * device can't be added, true otherwise. */
BTM_WhiteListAdd(const RawAddress & address)456 bool BTM_WhiteListAdd(const RawAddress& address) {
457 VLOG(1) << __func__ << ": " << address;
458
459 if (background_connections_count() ==
460 controller_get_interface()->get_ble_white_list_size()) {
461 BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
462 return false;
463 }
464
465 if (btm_cb.ble_ctr_cb.wl_state & BTM_BLE_WL_INIT) {
466 btm_ble_stop_auto_conn();
467 }
468 btm_add_dev_to_controller(true, address);
469 btm_ble_resume_bg_conn();
470 return true;
471 }
472
473 /** Removes the device from white list */
BTM_WhiteListRemove(const RawAddress & address)474 void BTM_WhiteListRemove(const RawAddress& address) {
475 VLOG(1) << __func__ << ": " << address;
476 if (btm_cb.ble_ctr_cb.wl_state & BTM_BLE_WL_INIT) {
477 btm_ble_stop_auto_conn();
478 }
479 btm_add_dev_to_controller(false, address);
480 btm_ble_resume_bg_conn();
481 }
482
483 /** clear white list complete */
wl_clear_complete(uint8_t * p_data,uint16_t)484 void wl_clear_complete(uint8_t* p_data, uint16_t /* evt_len */) {
485 uint8_t status;
486 STREAM_TO_UINT8(status, p_data);
487 VLOG(2) << __func__ << ": status=" << loghex(status);
488 }
489
490 /** Clear the whitelist, end any pending whitelist connections */
BTM_WhiteListClear()491 void BTM_WhiteListClear() {
492 VLOG(1) << __func__;
493 if (!controller_get_interface()->supports_ble()) return;
494 btm_ble_stop_auto_conn();
495 btsnd_hcic_ble_clear_white_list(base::BindOnce(&wl_clear_complete));
496 background_connections_clear();
497 }
498