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