1 /******************************************************************************
2  *
3  *  Copyright 2018 The Android Open Source Project
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 "connection_manager.h"
20 
21 #include <base/functional/bind.h>
22 #include <base/functional/callback.h>
23 #include <base/location.h>
24 #include <bluetooth/log.h>
25 
26 #include <map>
27 #include <memory>
28 #include <set>
29 
30 #include "internal_include/bt_trace.h"
31 #include "main/shim/le_scanning_manager.h"
32 #include "os/log.h"
33 #include "osi/include/alarm.h"
34 #include "stack/btm/btm_ble_bgconn.h"
35 #include "stack/include/advertise_data_parser.h"
36 #include "stack/include/bt_types.h"
37 #include "stack/include/btm_ble_api.h"
38 #include "stack/include/btm_log_history.h"
39 #include "stack/include/main_thread.h"
40 #include "types/raw_address.h"
41 
42 #define DIRECT_CONNECT_TIMEOUT (30 * 1000) /* 30 seconds */
43 
44 using namespace bluetooth;
45 
46 constexpr char kBtmLogTag[] = "TA";
47 
48 struct closure_data {
49   base::OnceClosure user_task;
50   base::Location posted_from;
51 };
52 
alarm_closure_cb(void * p)53 static void alarm_closure_cb(void* p) {
54   closure_data* data = (closure_data*)p;
55   log::verbose("executing timer scheduled at {}", data->posted_from.ToString());
56   std::move(data->user_task).Run();
57   delete data;
58 }
59 
60 // Periodic alarms are not supported, because we clean up data in callback
alarm_set_closure(const base::Location & posted_from,alarm_t * alarm,uint64_t interval_ms,base::OnceClosure user_task)61 void alarm_set_closure(const base::Location& posted_from, alarm_t* alarm,
62                        uint64_t interval_ms, base::OnceClosure user_task) {
63   closure_data* data = new closure_data;
64   data->posted_from = posted_from;
65   data->user_task = std::move(user_task);
66   log::verbose("scheduling timer {}", data->posted_from.ToString());
67   alarm_set_on_mloop(alarm, interval_ms, alarm_closure_cb, data);
68 }
69 
70 using unique_alarm_ptr = std::unique_ptr<alarm_t, decltype(&alarm_free)>;
71 
72 namespace connection_manager {
73 
74 struct tAPPS_CONNECTING {
75   // ids of clients doing background connection to given device
76   std::set<tAPP_ID> doing_bg_conn;
77   std::set<tAPP_ID> doing_targeted_announcements_conn;
78   bool is_in_accept_list;
79 
80   // Apps trying to do direct connection.
81   std::map<tAPP_ID, unique_alarm_ptr> doing_direct_conn;
82 };
83 
84 namespace {
85 // Maps address to apps trying to connect to it
86 std::map<RawAddress, tAPPS_CONNECTING> bgconn_dev;
87 
num_of_targeted_announcements_users(void)88 int num_of_targeted_announcements_users(void) {
89   return std::count_if(
90       bgconn_dev.begin(), bgconn_dev.end(), [](const auto& pair) {
91         return (!pair.second.is_in_accept_list &&
92                 !pair.second.doing_targeted_announcements_conn.empty());
93       });
94 }
95 
is_anyone_interested_to_use_accept_list(const std::map<RawAddress,tAPPS_CONNECTING>::iterator it)96 bool is_anyone_interested_to_use_accept_list(
97     const std::map<RawAddress, tAPPS_CONNECTING>::iterator it) {
98   if (!it->second.doing_targeted_announcements_conn.empty()) {
99     return (!it->second.doing_direct_conn.empty());
100   }
101   return (!it->second.doing_bg_conn.empty() ||
102           !it->second.doing_direct_conn.empty());
103 }
104 
is_anyone_connecting(const std::map<RawAddress,tAPPS_CONNECTING>::iterator it)105 bool is_anyone_connecting(
106     const std::map<RawAddress, tAPPS_CONNECTING>::iterator it) {
107   return (!it->second.doing_bg_conn.empty() ||
108           !it->second.doing_direct_conn.empty() ||
109           !it->second.doing_targeted_announcements_conn.empty());
110 }
111 
112 }  // namespace
113 
114 /** background connection device from the list. Returns pointer to the device
115  * record, or nullptr if not found */
get_apps_connecting_to(const RawAddress & address)116 std::set<tAPP_ID> get_apps_connecting_to(const RawAddress& address) {
117   log::debug("address={}", address);
118   auto it = bgconn_dev.find(address);
119   return (it != bgconn_dev.end()) ? it->second.doing_bg_conn
120                                   : std::set<tAPP_ID>();
121 }
122 
IsTargetedAnnouncement(const uint8_t * p_eir,uint16_t eir_len)123 bool IsTargetedAnnouncement(const uint8_t* p_eir, uint16_t eir_len) {
124   const uint8_t* p_service_data = p_eir;
125   uint8_t service_data_len = 0;
126 
127   while ((p_service_data = AdvertiseDataParser::GetFieldByType(
128               p_service_data + service_data_len,
129               eir_len - (p_service_data - p_eir) - service_data_len,
130               BTM_BLE_AD_TYPE_SERVICE_DATA_TYPE, &service_data_len))) {
131     uint16_t uuid;
132     uint8_t announcement_type;
133     const uint8_t* p_tmp = p_service_data;
134 
135     if (service_data_len < 3) {
136       continue;
137     }
138 
139     STREAM_TO_UINT16(uuid, p_tmp);
140     log::debug("Found UUID 0x{:04x}", uuid);
141 
142     if (uuid != 0x184E && uuid != 0x1853) {
143       continue;
144     }
145 
146     STREAM_TO_UINT8(announcement_type, p_tmp);
147     log::debug("Found announcement_type 0x{:02x}", announcement_type);
148     if (announcement_type == 0x01) {
149       return true;
150     }
151   }
152   return false;
153 }
154 
155 static void schedule_direct_connect_add(uint8_t app_id,
156                                         const RawAddress& address);
157 
target_announcement_observe_results_cb(tBTM_INQ_RESULTS * p_inq,const uint8_t * p_eir,uint16_t eir_len)158 static void target_announcement_observe_results_cb(tBTM_INQ_RESULTS* p_inq,
159                                                    const uint8_t* p_eir,
160                                                    uint16_t eir_len) {
161   auto addr = p_inq->remote_bd_addr;
162   auto it = bgconn_dev.find(addr);
163   if (it == bgconn_dev.end() ||
164       it->second.doing_targeted_announcements_conn.empty()) {
165     return;
166   }
167 
168   if (!IsTargetedAnnouncement(p_eir, eir_len)) {
169     log::debug("Not a targeted announcement for device {}", addr);
170     return;
171   }
172 
173   log::info("Found targeted announcement for device {}", addr);
174 
175   if (it->second.is_in_accept_list) {
176     log::info("Device {} is already connecting", addr);
177     return;
178   }
179 
180   if (BTM_GetHCIConnHandle(addr, BT_TRANSPORT_LE) != 0xFFFF) {
181     log::debug("Device {} already connected", addr);
182     return;
183   }
184 
185   BTM_LogHistory(kBtmLogTag, addr, "Found TA from");
186 
187   /* Take fist app_id and use it for direct_connect */
188   auto app_id = *(it->second.doing_targeted_announcements_conn.begin());
189 
190   /* If scan is ongoing lets stop it */
191   do_in_main_thread(FROM_HERE,
192                     base::BindOnce(schedule_direct_connect_add, app_id, addr));
193 }
194 
target_announcements_filtering_set(bool enable)195 void target_announcements_filtering_set(bool enable) {
196   log::debug("enable {}", enable);
197   BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty,
198                  (enable ? "Start filtering" : "Stop filtering"));
199 
200   /* Safe to call as if there is no support for filtering, this call will be
201    * ignored. */
202   bluetooth::shim::set_target_announcements_filter(enable);
203   BTM_BleTargetAnnouncementObserve(enable,
204                                    target_announcement_observe_results_cb);
205 }
206 
207 /** Add a device to the background connection list for targeted announcements.
208  * Returns
209  *   true if device added to the list, or already in list,
210  *   false otherwise
211  */
background_connect_targeted_announcement_add(tAPP_ID app_id,const RawAddress & address)212 bool background_connect_targeted_announcement_add(tAPP_ID app_id,
213                                                   const RawAddress& address) {
214   log::info("app_id={}, address={}", static_cast<int>(app_id), address);
215 
216   bool disable_accept_list = false;
217 
218   auto it = bgconn_dev.find(address);
219   if (it != bgconn_dev.end()) {
220     // check if filtering already enabled
221     if (it->second.doing_targeted_announcements_conn.count(app_id)) {
222       log::info(
223           "app_id={}, already doing targeted announcement filtering to "
224           "address={}",
225           static_cast<int>(app_id), address);
226       return true;
227     }
228 
229     bool targeted_filtering_enabled =
230         !it->second.doing_targeted_announcements_conn.empty();
231 
232     // Check if connecting
233     if (!it->second.doing_direct_conn.empty()) {
234       log::info("app_id={}, address={}, already in direct connection",
235                 static_cast<int>(app_id), address);
236 
237     } else if (!targeted_filtering_enabled &&
238                !it->second.doing_bg_conn.empty()) {
239       // device is already in the acceptlist so we would have to remove it
240       log::info(
241           "already doing background connection to address={}. Need to disable "
242           "it.",
243           address);
244       disable_accept_list = true;
245     }
246   }
247 
248   if (disable_accept_list) {
249     BTM_AcceptlistRemove(address);
250     bgconn_dev[address].is_in_accept_list = false;
251   }
252 
253   bgconn_dev[address].doing_targeted_announcements_conn.insert(app_id);
254   if (bgconn_dev[address].doing_targeted_announcements_conn.size() == 1) {
255     BTM_LogHistory(kBtmLogTag, address, "Allow connection from");
256   }
257 
258   if (num_of_targeted_announcements_users() == 1) {
259     target_announcements_filtering_set(true);
260   }
261 
262   return true;
263 }
264 
265 /** Add a device from the background connection list.  Returns true if device
266  * added to the list, or already in list, false otherwise */
background_connect_add(uint8_t app_id,const RawAddress & address)267 bool background_connect_add(uint8_t app_id, const RawAddress& address) {
268   log::debug("app_id={}, address={}", static_cast<int>(app_id), address);
269   auto it = bgconn_dev.find(address);
270   bool in_acceptlist = false;
271   bool is_targeted_announcement_enabled = false;
272   if (it != bgconn_dev.end()) {
273     // device already in the acceptlist, just add interested app to the list
274     if (it->second.doing_bg_conn.count(app_id)) {
275       log::debug("app_id={}, already doing background connection to address={}",
276                  static_cast<int>(app_id), address);
277       return true;
278     }
279 
280     // Already in acceptlist ?
281     if (it->second.is_in_accept_list) {
282       log::debug("app_id={}, address={}, already in accept list",
283                  static_cast<int>(app_id), address);
284       in_acceptlist = true;
285     } else {
286       is_targeted_announcement_enabled =
287           !it->second.doing_targeted_announcements_conn.empty();
288     }
289   }
290 
291   if (!in_acceptlist) {
292     // the device is not in the acceptlist
293     if (is_targeted_announcement_enabled) {
294       log::debug("Targeted announcement enabled, do not add to AcceptList");
295     } else {
296       if (!BTM_AcceptlistAdd(address)) {
297         log::warn("Failed to add device {} to accept list for app {}", address,
298                   static_cast<int>(app_id));
299         return false;
300       }
301       bgconn_dev[address].is_in_accept_list = true;
302     }
303   }
304 
305   // create entry for address, and insert app_id.
306   // new tAPPS_CONNECTING will be default constructed if not exist
307   bgconn_dev[address].doing_bg_conn.insert(app_id);
308   return true;
309 }
310 
311 /** Removes all registrations for connection for given device.
312  * Returns true if anything was removed, false otherwise */
remove_unconditional(const RawAddress & address)313 bool remove_unconditional(const RawAddress& address) {
314   log::debug("address={}", address);
315   auto it = bgconn_dev.find(address);
316   if (it == bgconn_dev.end()) {
317     log::warn("address {} is not found", address);
318     return false;
319   }
320 
321   BTM_AcceptlistRemove(address);
322   bgconn_dev.erase(it);
323   return true;
324 }
325 
326 /** Remove device from the background connection device list or listening to
327  * advertising list.  Returns true if device was on the list and was
328  * successfully removed */
background_connect_remove(uint8_t app_id,const RawAddress & address)329 bool background_connect_remove(uint8_t app_id, const RawAddress& address) {
330   log::debug("app_id={}, address={}", static_cast<int>(app_id), address);
331   auto it = bgconn_dev.find(address);
332   if (it == bgconn_dev.end()) {
333     log::warn("address {} is not found", address);
334     return false;
335   }
336 
337   bool accept_list_enabled = it->second.is_in_accept_list;
338   auto num_of_targeted_announcements_before_remove =
339       it->second.doing_targeted_announcements_conn.size();
340 
341   bool removed_from_bg_conn = (it->second.doing_bg_conn.erase(app_id) > 0);
342   bool removed_from_ta =
343       (it->second.doing_targeted_announcements_conn.erase(app_id) > 0);
344   if (!removed_from_bg_conn && !removed_from_ta) {
345     log::warn("Failed to remove background connection app {} for address {}",
346               static_cast<int>(app_id), address);
347     return false;
348   }
349 
350   if (removed_from_ta &&
351       it->second.doing_targeted_announcements_conn.size() == 0) {
352     BTM_LogHistory(kBtmLogTag, address, "Ignore connection from");
353   }
354 
355   if (is_anyone_connecting(it)) {
356     log::debug("some device is still connecting, app_id={}, address={}",
357                static_cast<int>(app_id), address);
358     /* Check which method should be used now.*/
359     if (!accept_list_enabled) {
360       /* Accept list was not used */
361       if (!it->second.doing_targeted_announcements_conn.empty()) {
362         /* Keep using filtering */
363         log::debug("Keep using target announcement filtering");
364       } else if (!it->second.doing_bg_conn.empty()) {
365         if (!BTM_AcceptlistAdd(address)) {
366           log::warn("Could not re add device to accept list");
367         } else {
368           bgconn_dev[address].is_in_accept_list = true;
369         }
370       }
371     }
372     return true;
373   }
374 
375   bgconn_dev.erase(it);
376 
377   // no more apps interested - remove from accept list and delete record
378   if (accept_list_enabled) {
379     BTM_AcceptlistRemove(address);
380     return true;
381   }
382 
383   if ((num_of_targeted_announcements_before_remove > 0) &&
384       num_of_targeted_announcements_users() == 0) {
385     target_announcements_filtering_set(true);
386   }
387 
388   return true;
389 }
390 
is_background_connection(const RawAddress & address)391 bool is_background_connection(const RawAddress& address) {
392   return bgconn_dev.find(address) != bgconn_dev.end();
393 }
394 
395 /** deregister all related background connetion device. */
on_app_deregistered(uint8_t app_id)396 void on_app_deregistered(uint8_t app_id) {
397   log::debug("app_id={}", static_cast<int>(app_id));
398   auto it = bgconn_dev.begin();
399   auto end = bgconn_dev.end();
400   /* update the BG conn device list */
401   while (it != end) {
402     it->second.doing_bg_conn.erase(app_id);
403 
404     it->second.doing_direct_conn.erase(app_id);
405 
406     if (is_anyone_connecting(it)) {
407       it++;
408       continue;
409     }
410 
411     BTM_AcceptlistRemove(it->first);
412     it = bgconn_dev.erase(it);
413   }
414 }
415 
remove_all_clients_with_pending_connections(const RawAddress & address)416 static void remove_all_clients_with_pending_connections(
417     const RawAddress& address) {
418   log::debug("address={}", address);
419   auto it = bgconn_dev.find(address);
420   while (it != bgconn_dev.end() && !it->second.doing_direct_conn.empty()) {
421     uint8_t app_id = it->second.doing_direct_conn.begin()->first;
422     direct_connect_remove(app_id, address);
423     it = bgconn_dev.find(address);
424   }
425 }
426 
on_connection_complete(const RawAddress & address)427 void on_connection_complete(const RawAddress& address) {
428   log::info("Le connection completed to device:{}", address);
429 
430   remove_all_clients_with_pending_connections(address);
431 }
432 
on_connection_timed_out_from_shim(const RawAddress & address)433 void on_connection_timed_out_from_shim(const RawAddress& address) {
434   log::info("Connection failed {}", address);
435   on_connection_timed_out(0x00, address);
436 }
437 
438 /** Reset bg device list. If called after controller reset, set |after_reset|
439  * to true, as there is no need to wipe controller acceptlist in this case. */
reset(bool after_reset)440 void reset(bool after_reset) {
441   bgconn_dev.clear();
442   if (!after_reset) {
443     target_announcements_filtering_set(false);
444     BTM_AcceptlistClear();
445   }
446 }
447 
wl_direct_connect_timeout_cb(uint8_t app_id,const RawAddress & address)448 void wl_direct_connect_timeout_cb(uint8_t app_id, const RawAddress& address) {
449   log::debug("app_id={}, address={}", static_cast<int>(app_id), address);
450   on_connection_timed_out(app_id, address);
451 
452   // TODO: this would free the timer, from within the timer callback, which is
453   // bad.
454   direct_connect_remove(app_id, address, true);
455 }
456 
457 /** Add a device to the direct connection list. Returns true if device
458  * added to the list, false otherwise */
direct_connect_add(uint8_t app_id,const RawAddress & address)459 bool direct_connect_add(uint8_t app_id, const RawAddress& address) {
460   log::debug("app_id={}, address={}", static_cast<int>(app_id), address);
461   bool in_acceptlist = false;
462   auto it = bgconn_dev.find(address);
463   if (it != bgconn_dev.end()) {
464     // app already trying to connect to this particular device
465     if (it->second.doing_direct_conn.count(app_id)) {
466       log::info("direct connect attempt from app_id=0x{:x} already in progress",
467                 app_id);
468       return false;
469     }
470 
471     // are we already in the acceptlist ?
472     if (it->second.is_in_accept_list) {
473       log::warn("Background connection attempt already in progress app_id={:x}",
474                 app_id);
475       in_acceptlist = true;
476     }
477   }
478 
479   if (!in_acceptlist) {
480     if (!BTM_AcceptlistAdd(address, true)) {
481       // if we can't add to acceptlist, turn parameters back to slow.
482       log::warn("Unable to add le device to acceptlist");
483       return false;
484     }
485     bgconn_dev[address].is_in_accept_list = true;
486   }
487 
488   // Setup a timer
489   alarm_t* timeout = alarm_new("wl_conn_params_30s");
490   alarm_set_closure(
491       FROM_HERE, timeout, DIRECT_CONNECT_TIMEOUT,
492       base::BindOnce(&wl_direct_connect_timeout_cb, app_id, address));
493 
494   bgconn_dev[address].doing_direct_conn.emplace(
495       app_id, unique_alarm_ptr(timeout, &alarm_free));
496 
497   return true;
498 }
499 
schedule_direct_connect_add(uint8_t app_id,const RawAddress & address)500 static void schedule_direct_connect_add(uint8_t app_id,
501                                         const RawAddress& address) {
502   direct_connect_add(app_id, address);
503 }
504 
direct_connect_remove(uint8_t app_id,const RawAddress & address,bool connection_timeout)505 bool direct_connect_remove(uint8_t app_id, const RawAddress& address,
506                            bool connection_timeout) {
507   log::debug("app_id={}, address={}", static_cast<int>(app_id), address);
508   auto it = bgconn_dev.find(address);
509   if (it == bgconn_dev.end()) {
510     log::warn("Unable to find background connection to remove peer:{}",
511               address);
512     return false;
513   }
514 
515   auto app_it = it->second.doing_direct_conn.find(app_id);
516   if (app_it == it->second.doing_direct_conn.end()) {
517     log::warn("Unable to find direct connection to remove peer:{}", address);
518     return false;
519   }
520 
521   /* Let see if the device was connected due to Target Announcements.*/
522   bool is_targeted_announcement_enabled =
523       !it->second.doing_targeted_announcements_conn.empty();
524 
525   // this will free the alarm
526   it->second.doing_direct_conn.erase(app_it);
527 
528   if (is_anyone_interested_to_use_accept_list(it)) {
529     if (connection_timeout) {
530       /* In such case we need to add device back to allow list because,
531        * when connection timeout out, the lower layer removes device from
532        * the allow list.
533        */
534       if (!BTM_AcceptlistAdd(address)) {
535         log::warn(
536             "Failed to re-add device {} to accept list after connection "
537             "timeout",
538             address);
539       }
540     }
541     return true;
542   }
543 
544   // no more apps interested - remove from acceptlist
545   BTM_AcceptlistRemove(address);
546 
547   if (!is_targeted_announcement_enabled) {
548     bgconn_dev.erase(it);
549   } else {
550     it->second.is_in_accept_list = false;
551   }
552 
553   return true;
554 }
555 
dump(int fd)556 void dump(int fd) {
557   dprintf(fd, "\nconnection_manager state:\n");
558   if (bgconn_dev.empty()) {
559     dprintf(fd, "\tno Low Energy connection attempts\n");
560     return;
561   }
562 
563   dprintf(fd, "\tdevices attempting connection: %d", (int)bgconn_dev.size());
564   for (const auto& entry : bgconn_dev) {
565     // TODO: confirm whether we need to replace this
566     dprintf(fd, "\n\t * %s: ", ADDRESS_TO_LOGGABLE_CSTR(entry.first));
567 
568     if (!entry.second.doing_direct_conn.empty()) {
569       dprintf(fd, "\n\t\tapps doing direct connect: ");
570       for (const auto& id : entry.second.doing_direct_conn) {
571         dprintf(fd, "%d, ", id.first);
572       }
573     }
574 
575     if (!entry.second.doing_bg_conn.empty()) {
576       dprintf(fd, "\n\t\tapps doing background connect: ");
577       for (const auto& id : entry.second.doing_bg_conn) {
578         dprintf(fd, "%d, ", id);
579       }
580     }
581     if (!entry.second.doing_targeted_announcements_conn.empty()) {
582       dprintf(fd, "\n\t\tapps doing cap announcement connect: ");
583       for (const auto& id : entry.second.doing_targeted_announcements_conn) {
584         dprintf(fd, "%d, ", id);
585       }
586     }
587     dprintf(fd, "\n\t\t is in the allow list: %s",
588             entry.second.is_in_accept_list ? "true" : "false");
589   }
590   dprintf(fd, "\n");
591 }
592 
593 }  // namespace connection_manager
594