1 /*
2  * Copyright 2019 HIMSA II K/S - www.himsa.com.
3  * Represented by EHIMA - www.ehima.com
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 #include "ble_scanner_hci_interface.h"
19 
20 #include <base/functional/bind.h>
21 #include <bluetooth/log.h>
22 
23 #include "hci/controller_interface.h"
24 #include "main/shim/entry.h"
25 #include "stack/include/bt_types.h"
26 #include "stack/include/btm_client_interface.h"
27 #include "stack/include/hcimsgs.h"
28 #include "types/raw_address.h"
29 
30 using namespace bluetooth;
31 
32 namespace {
33 BleScannerHciInterface* instance = nullptr;
34 
status_callback(base::Callback<void (uint8_t)> cb,uint8_t * data,uint16_t len)35 static void status_callback(base::Callback<void(uint8_t)> cb, uint8_t* data, uint16_t len) {
36   uint8_t status;
37 
38   log::assert_that(len == 1, "Received bad response length: {}", len);
39   STREAM_TO_UINT8(status, data);
40 
41   cb.Run(status);
42 }
43 
status_handle_callback(base::Callback<void (uint8_t,uint16_t)> cb,uint8_t * data,uint16_t len)44 static void status_handle_callback(base::Callback<void(uint8_t, uint16_t)> cb, uint8_t* data,
45                                    uint16_t len) {
46   uint8_t status;
47   uint16_t handle = HCI_INVALID_HANDLE;
48 
49   log::assert_that((len > 0) && (len < 4), "Received bad response length: {}", len);
50   uint8_t* pp = data;
51   STREAM_TO_UINT8(status, pp);
52 
53   if (status == HCI_SUCCESS) {
54     log::assert_that(len == 3, "Received bad response length: {}", len);
55 
56     STREAM_TO_UINT16(handle, pp);
57     handle = handle & 0x0EFF;
58 
59   } else {
60     log::verbose("hci response error code: {}", int{status});
61   }
62   cb.Run(status, handle);
63 }
64 
65 /**
66  * BleScannerHciInterface allows the caller to sync to a periodic advertising
67  * train and receive periodic advertising data events through a registered
68  * observer's callbacks. It also provides a synchronisation transfer API,
69  * including in-controller allow list support. The right feature-complete
70  * interface implementation is chosen during the init phase based on the
71  * controller's list of supported features.
72  */
73 class BleScannerImplBase : public BleScannerHciInterface {
74 public:
SetScanEventObserver(ScanEventObserver * observer)75   void SetScanEventObserver(ScanEventObserver* observer) override {
76     // TODO: Support multiple observers if ever needed.
77     scan_event_observer = observer;
78   }
79 
PeriodicScanStart(uint8_t options,uint8_t set_id,uint8_t adv_addr_type,const RawAddress & adv_addr,uint16_t skip_num,uint16_t sync_timeout,uint8_t sync_cte_type)80   void PeriodicScanStart(uint8_t options, uint8_t set_id, uint8_t adv_addr_type,
81                          const RawAddress& adv_addr, uint16_t skip_num, uint16_t sync_timeout,
82                          uint8_t sync_cte_type) override {
83     btsnd_hcic_ble_periodic_advertising_create_sync(options, set_id, adv_addr_type, adv_addr,
84                                                     skip_num, sync_timeout, sync_cte_type);
85   }
86 
PeriodicScanCancelStart(status_cb command_complete)87   void PeriodicScanCancelStart(status_cb command_complete) override {
88     btsnd_hcic_ble_periodic_advertising_create_sync_cancel(
89             base::Bind(&status_callback, std::move(command_complete)));
90   }
91 
PeriodicScanTerminate(uint16_t sync_handle,status_cb command_complete)92   void PeriodicScanTerminate(uint16_t sync_handle, status_cb command_complete) override {
93     btsnd_hcic_ble_periodic_advertising_terminate_sync(
94             sync_handle, base::Bind(&status_callback, std::move(command_complete)));
95   }
96 
PeriodicScanResultEvtEnable(uint16_t sync_handle,bool enable,status_cb command_complete)97   void PeriodicScanResultEvtEnable(uint16_t sync_handle, bool enable,
98                                    status_cb command_complete) override {
99     btsnd_hcic_ble_set_periodic_advertising_receive_enable(
100             sync_handle, enable, base::Bind(&status_callback, std::move(command_complete)));
101   }
102 
PeriodicAdvertiserListGetSize(BleScannerHciInterface::list_size_cb command_complete)103   void PeriodicAdvertiserListGetSize(
104           BleScannerHciInterface::list_size_cb command_complete) override {
105     command_complete.Run(bluetooth::shim::GetController()->GetLePeriodicAdvertiserListSize());
106   }
107 
PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type,RawAddress & adv_addr,uint8_t set_id,status_cb command_complete)108   void PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type, RawAddress& adv_addr, uint8_t set_id,
109                                        status_cb command_complete) override {
110     btsnd_hci_ble_add_device_to_periodic_advertiser_list(
111             adv_addr_type, adv_addr, set_id,
112             base::Bind(&status_callback, std::move(command_complete)));
113   }
114 
PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type,RawAddress & adv_addr,uint8_t set_id,status_cb command_complete)115   void PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type, RawAddress& adv_addr,
116                                           uint8_t set_id, status_cb command_complete) override {
117     btsnd_hci_ble_remove_device_from_periodic_advertiser_list(
118             adv_addr_type, adv_addr, set_id,
119             base::Bind(&status_callback, std::move(command_complete)));
120   }
121 
PeriodicAdvertiserListClear(status_cb command_complete)122   void PeriodicAdvertiserListClear(status_cb command_complete) override {
123     btsnd_hci_ble_clear_periodic_advertiser_list(
124             base::Bind(&status_callback, std::move(command_complete)));
125   }
126 
PeriodicAdvSyncTransfer(const RawAddress & bd_addr,uint16_t service_data,uint16_t sync_handle,BleScannerHciInterface::handle_cb command_complete)127   void PeriodicAdvSyncTransfer(const RawAddress& bd_addr, uint16_t service_data,
128                                uint16_t sync_handle,
129                                BleScannerHciInterface::handle_cb command_complete) override {
130     uint16_t acl_handle =
131             get_btm_client_interface().peer.BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
132 
133     if (acl_handle == HCI_INVALID_HANDLE) {
134       log::error("Wrong mode: no LE link exist or LE not supported");
135       return;
136     }
137 
138     btsnd_hcic_ble_periodic_advertising_sync_transfer(
139             acl_handle, service_data, sync_handle,
140             base::Bind(&status_handle_callback, std::move(command_complete)));
141   }
142 
PeriodicAdvSetInfoTransfer(const RawAddress & bd_addr,uint16_t service_data,uint8_t adv_handle,handle_cb command_complete)143   void PeriodicAdvSetInfoTransfer(const RawAddress& bd_addr, uint16_t service_data,
144                                   uint8_t adv_handle, handle_cb command_complete) override {
145     uint16_t acl_handle =
146             get_btm_client_interface().peer.BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
147 
148     if (acl_handle == HCI_INVALID_HANDLE) {
149       log::error("Wrong mode: no LE link exist or LE not supported");
150       return;
151     }
152 
153     btsnd_hcic_ble_periodic_advertising_set_info_transfer(
154             acl_handle, service_data, adv_handle,
155             base::Bind(&status_handle_callback, std::move(command_complete)));
156   }
157 
SetPeriodicAdvSyncTransferParams(const RawAddress & bd_addr,uint8_t mode,uint16_t skip,uint16_t sync_timeout,uint8_t cte_type,bool set_defaults,status_cb command_complete)158   void SetPeriodicAdvSyncTransferParams(const RawAddress& bd_addr, uint8_t mode, uint16_t skip,
159                                         uint16_t sync_timeout, uint8_t cte_type, bool set_defaults,
160                                         status_cb command_complete) override {
161     uint16_t acl_handle =
162             get_btm_client_interface().peer.BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
163 
164     if (acl_handle == HCI_INVALID_HANDLE) {
165       log::error("Wrong mode: no LE link exist or LE not supported");
166       return;
167     }
168 
169     if (set_defaults) {
170       btsnd_hcic_ble_set_default_periodic_advertising_sync_transfer_params(
171               acl_handle, mode, skip, sync_timeout, cte_type,
172               base::Bind(&status_callback, std::move(command_complete)));
173     } else {
174       btsnd_hcic_ble_set_periodic_advertising_sync_transfer_params(
175               acl_handle, mode, skip, sync_timeout, cte_type,
176               base::Bind(&status_callback, std::move(command_complete)));
177     }
178   }
179 
OnPeriodicAdvSyncEstablished(uint8_t status,uint16_t sync_handle,uint8_t adv_sid,uint8_t adv_addr_type,RawAddress adv_addr,uint8_t adv_phy,uint16_t adv_interval,uint8_t adv_clock_accuracy)180   void OnPeriodicAdvSyncEstablished(uint8_t status, uint16_t sync_handle, uint8_t adv_sid,
181                                     uint8_t adv_addr_type, RawAddress adv_addr, uint8_t adv_phy,
182                                     uint16_t adv_interval, uint8_t adv_clock_accuracy) {
183     if (scan_event_observer) {
184       scan_event_observer->OnPeriodicScanEstablished(status, sync_handle, adv_sid, adv_addr_type,
185                                                      adv_addr, adv_phy, adv_interval,
186                                                      adv_clock_accuracy);
187     }
188   }
189 
OnPeriodicScanResult(uint16_t sync_handle,uint8_t tx_power,int8_t rssi,uint8_t cte_type,uint8_t pkt_data_status,uint8_t pkt_data_len,const uint8_t * p_pkt_data)190   void OnPeriodicScanResult(uint16_t sync_handle, uint8_t tx_power, int8_t rssi, uint8_t cte_type,
191                             uint8_t pkt_data_status, uint8_t pkt_data_len,
192                             const uint8_t* p_pkt_data) {
193     // The observer should handle the caching and reassembly of the fragmented
194     // packet.
195     if (scan_event_observer) {
196       scan_event_observer->OnPeriodicScanResult(sync_handle, tx_power, rssi, cte_type,
197                                                 pkt_data_status, pkt_data_len, p_pkt_data);
198     }
199   }
200 
OnPeriodicSyncLost(uint16_t sync_handle)201   void OnPeriodicSyncLost(uint16_t sync_handle) {
202     if (scan_event_observer) {
203       scan_event_observer->OnPeriodicScanLost(sync_handle);
204     }
205   }
206 
207 private:
208   ScanEventObserver* scan_event_observer = nullptr;
209 };
210 
211 class BleScannerListImpl : public virtual BleScannerImplBase {
PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type,RawAddress & adv_addr,uint8_t set_id,status_cb command_complete)212   void PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type, RawAddress& adv_addr, uint8_t set_id,
213                                        status_cb command_complete) override {
214     btsnd_hci_ble_add_device_to_periodic_advertiser_list(
215             adv_addr_type, adv_addr, set_id,
216             base::Bind(&status_callback, std::move(command_complete)));
217   }
218 
PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type,RawAddress & adv_addr,uint8_t set_id,status_cb command_complete)219   void PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type, RawAddress& adv_addr,
220                                           uint8_t set_id, status_cb command_complete) override {
221     btsnd_hci_ble_remove_device_from_periodic_advertiser_list(
222             adv_addr_type, adv_addr, set_id,
223             base::Bind(&status_callback, std::move(command_complete)));
224   }
225 
PeriodicAdvertiserListClear(status_cb command_complete)226   void PeriodicAdvertiserListClear(status_cb command_complete) override {
227     btsnd_hci_ble_clear_periodic_advertiser_list(
228             base::Bind(&status_callback, std::move(command_complete)));
229   }
230 };
231 
232 class BleScannerSyncTransferImpl : public virtual BleScannerImplBase {
PeriodicAdvSyncTransfer(const RawAddress & bd_addr,uint16_t service_data,uint16_t sync_handle,BleScannerHciInterface::handle_cb command_complete)233   void PeriodicAdvSyncTransfer(const RawAddress& bd_addr, uint16_t service_data,
234                                uint16_t sync_handle,
235                                BleScannerHciInterface::handle_cb command_complete) override {
236     uint16_t acl_handle =
237             get_btm_client_interface().peer.BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
238 
239     if (acl_handle == HCI_INVALID_HANDLE) {
240       log::error("Wrong mode: no LE link exist or LE not supported");
241       return;
242     }
243 
244     btsnd_hcic_ble_periodic_advertising_sync_transfer(
245             acl_handle, service_data, sync_handle,
246             base::Bind(&status_handle_callback, std::move(command_complete)));
247   }
248 
PeriodicAdvSetInfoTransfer(const RawAddress & bd_addr,uint16_t service_data,uint8_t adv_handle,handle_cb command_complete)249   void PeriodicAdvSetInfoTransfer(const RawAddress& bd_addr, uint16_t service_data,
250                                   uint8_t adv_handle, handle_cb command_complete) override {
251     uint16_t acl_handle =
252             get_btm_client_interface().peer.BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
253 
254     if (acl_handle == HCI_INVALID_HANDLE) {
255       log::error("Wrong mode: no LE link exist or LE not supported");
256       return;
257     }
258 
259     btsnd_hcic_ble_periodic_advertising_set_info_transfer(
260             acl_handle, service_data, adv_handle,
261             base::Bind(&status_handle_callback, std::move(command_complete)));
262   }
263 
SetPeriodicAdvSyncTransferParams(const RawAddress & bd_addr,uint8_t mode,uint16_t skip,uint16_t sync_timeout,uint8_t cte_type,bool set_defaults,status_cb command_complete)264   void SetPeriodicAdvSyncTransferParams(const RawAddress& bd_addr, uint8_t mode, uint16_t skip,
265                                         uint16_t sync_timeout, uint8_t cte_type, bool set_defaults,
266                                         status_cb command_complete) override {
267     uint16_t acl_handle =
268             get_btm_client_interface().peer.BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
269 
270     if (acl_handle == HCI_INVALID_HANDLE) {
271       log::error("Wrong mode: no LE link exist or LE not supported");
272       return;
273     }
274 
275     if (set_defaults) {
276       btsnd_hcic_ble_set_default_periodic_advertising_sync_transfer_params(
277               acl_handle, mode, skip, sync_timeout, cte_type,
278               base::Bind(&status_callback, std::move(command_complete)));
279     } else {
280       btsnd_hcic_ble_set_periodic_advertising_sync_transfer_params(
281               acl_handle, mode, skip, sync_timeout, cte_type,
282               base::Bind(&status_callback, std::move(command_complete)));
283     }
284   }
285 };
286 
287 class BleScannerCompleteImpl : public BleScannerListImpl, public BleScannerSyncTransferImpl {
288   // Not much to do here :)
289 };
290 
291 }  // namespace
292 
Initialize()293 void BleScannerHciInterface::Initialize() {
294   log::assert_that(instance == nullptr, "Was already initialized.");
295 
296   if ((bluetooth::shim::GetController()->GetLePeriodicAdvertiserListSize()) &&
297       (bluetooth::shim::GetController()->SupportsBlePeriodicAdvertisingSyncTransferSender())) {
298     log::info("Advertiser list in controller can be used");
299     log::info("Periodic Adv Sync Transfer Sender role is supported");
300     instance = new BleScannerCompleteImpl();
301   } else if (bluetooth::shim::GetController()->SupportsBlePeriodicAdvertisingSyncTransferSender()) {
302     log::info("Periodic Adv Sync Transfer Sender role is supported");
303     instance = new BleScannerSyncTransferImpl();
304   } else if (bluetooth::shim::GetController()->GetLePeriodicAdvertiserListSize()) {
305     log::info("Periodic Adv Sync Transfer Recipient role is supported");
306     instance = new BleScannerListImpl();
307   }
308   // TODO: Implement periodic adv. sync. recipient role if ever needed.
309 }
310 
Get()311 BleScannerHciInterface* BleScannerHciInterface::Get() { return instance; }
312 
CleanUp()313 void BleScannerHciInterface::CleanUp() {
314   delete instance;
315   instance = nullptr;
316 }
317