• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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