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/bind.h>
21 
22 #include "acl_api.h"
23 #include "btm_api.h"
24 #include "device/include/controller.h"
25 #include "hcidefs.h"
26 #include "hcimsgs.h"
27 
28 #include "osi/include/log.h"
29 
30 namespace {
31 BleScannerHciInterface* instance = nullptr;
32 
status_callback(base::Callback<void (uint8_t)> cb,uint8_t * data,uint16_t len)33 static void status_callback(base::Callback<void(uint8_t)> cb, uint8_t* data,
34                             uint16_t len) {
35   uint8_t status;
36 
37   LOG_ASSERT(len == 1) << "Received bad response length: " << len;
38   STREAM_TO_UINT8(status, data);
39 
40   DVLOG(1) << __func__ << " Received status_cb";
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,
45                                    uint8_t* data, uint16_t len) {
46   uint8_t status;
47   uint16_t handle = HCI_INVALID_HANDLE;
48 
49   LOG_ASSERT((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(len == 3) << "Received bad response length: " << len;
55 
56     STREAM_TO_UINT16(handle, pp);
57     handle = handle & 0x0EFF;
58 
59     DVLOG(1) << __func__ << " Received status_handle_callback";
60   } else {
61     DVLOG(1) << __func__ << " hci response error code: " << int{status};
62   }
63   cb.Run(status, handle);
64 }
65 
66 /**
67  * BleScannerHciInterface allows the caller to sync to a periodic advertising
68  * train and receive periodic advertising data events through a registered
69  * observer's callbacks. It also provides a synchronisation transfer API,
70  * including in-controller allow list support. The right feature-complete
71  * interface implementation is chosen during the init phase based on the
72  * controller's list of supported features.
73  */
74 class BleScannerImplBase : public BleScannerHciInterface {
75  public:
SetScanEventObserver(ScanEventObserver * observer)76   void SetScanEventObserver(ScanEventObserver* observer) override {
77     VLOG(1) << __func__;
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     VLOG(1) << __func__;
87     btsnd_hcic_ble_periodic_advertising_create_sync(
88         options, set_id, adv_addr_type, adv_addr, skip_num, sync_timeout,
89         sync_cte_type);
90   }
91 
PeriodicScanCancelStart(status_cb command_complete)92   void PeriodicScanCancelStart(status_cb command_complete) override {
93     VLOG(1) << __func__;
94     btsnd_hcic_ble_periodic_advertising_create_sync_cancel(
95         base::Bind(&status_callback, std::move(command_complete)));
96   }
97 
PeriodicScanTerminate(uint16_t sync_handle,status_cb command_complete)98   void PeriodicScanTerminate(uint16_t sync_handle,
99                              status_cb command_complete) override {
100     VLOG(1) << __func__;
101     btsnd_hcic_ble_periodic_advertising_terminate_sync(
102         sync_handle, base::Bind(&status_callback, std::move(command_complete)));
103   }
104 
PeriodicScanResultEvtEnable(uint16_t sync_handle,bool enable,status_cb command_complete)105   void PeriodicScanResultEvtEnable(uint16_t sync_handle, bool enable,
106                                    status_cb command_complete) override {
107     VLOG(1) << __func__;
108     btsnd_hcic_ble_set_periodic_advertising_receive_enable(
109         sync_handle, enable,
110         base::Bind(&status_callback, std::move(command_complete)));
111   }
112 
PeriodicAdvertiserListGetSize(BleScannerHciInterface::list_size_cb command_complete)113   void PeriodicAdvertiserListGetSize(
114       BleScannerHciInterface::list_size_cb command_complete) override {
115     VLOG(1) << __func__;
116     command_complete.Run(
117         controller_get_interface()->get_ble_periodic_advertiser_list_size());
118   }
119 
PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type,RawAddress & adv_addr,uint8_t set_id,status_cb command_complete)120   void PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type,
121                                        RawAddress& adv_addr, uint8_t set_id,
122                                        status_cb command_complete) override {
123     VLOG(1) << __func__;
124     btsnd_hci_ble_add_device_to_periodic_advertiser_list(
125         adv_addr_type, adv_addr, set_id,
126         base::Bind(&status_callback, std::move(command_complete)));
127   }
128 
PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type,RawAddress & adv_addr,uint8_t set_id,status_cb command_complete)129   void PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type,
130                                           RawAddress& adv_addr, uint8_t set_id,
131                                           status_cb command_complete) override {
132     VLOG(1) << __func__;
133     btsnd_hci_ble_remove_device_from_periodic_advertiser_list(
134         adv_addr_type, adv_addr, set_id,
135         base::Bind(&status_callback, std::move(command_complete)));
136   }
137 
PeriodicAdvertiserListClear(status_cb command_complete)138   void PeriodicAdvertiserListClear(status_cb command_complete) override {
139     VLOG(1) << __func__;
140     btsnd_hci_ble_clear_periodic_advertiser_list(
141         base::Bind(&status_callback, std::move(command_complete)));
142   };
143 
PeriodicAdvSyncTransfer(const RawAddress & bd_addr,uint16_t service_data,uint16_t sync_handle,BleScannerHciInterface::handle_cb command_complete)144   void PeriodicAdvSyncTransfer(
145       const RawAddress& bd_addr, uint16_t service_data, uint16_t sync_handle,
146       BleScannerHciInterface::handle_cb command_complete) override {
147     VLOG(1) << __func__;
148     uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
149 
150     if (acl_handle == HCI_INVALID_HANDLE) {
151       LOG(ERROR) << __func__
152                  << ": Wrong mode: no LE link exist or LE not supported";
153       return;
154     }
155 
156     btsnd_hcic_ble_periodic_advertising_sync_transfer(
157         acl_handle, service_data, sync_handle,
158         base::Bind(&status_handle_callback, std::move(command_complete)));
159   }
160 
PeriodicAdvSetInfoTransfer(const RawAddress & bd_addr,uint16_t service_data,uint8_t adv_handle,handle_cb command_complete)161   void PeriodicAdvSetInfoTransfer(const RawAddress& bd_addr,
162                                   uint16_t service_data, uint8_t adv_handle,
163                                   handle_cb command_complete) override {
164     VLOG(1) << __func__;
165     uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
166 
167     if (acl_handle == HCI_INVALID_HANDLE) {
168       LOG(ERROR) << __func__
169                  << ": Wrong mode: no LE link exist or LE not supported";
170       return;
171     }
172 
173     btsnd_hcic_ble_periodic_advertising_set_info_transfer(
174         acl_handle, service_data, adv_handle,
175         base::Bind(&status_handle_callback, std::move(command_complete)));
176   }
177 
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)178   void SetPeriodicAdvSyncTransferParams(const RawAddress& bd_addr, uint8_t mode,
179                                         uint16_t skip, uint16_t sync_timeout,
180                                         uint8_t cte_type, bool set_defaults,
181                                         status_cb command_complete) override {
182     VLOG(1) << __func__;
183     uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
184 
185     if (acl_handle == HCI_INVALID_HANDLE) {
186       LOG(ERROR) << __func__
187                  << ": Wrong mode: no LE link exist or LE not supported";
188       return;
189     }
190 
191     if (set_defaults)
192       btsnd_hcic_ble_set_default_periodic_advertising_sync_transfer_params(
193           acl_handle, mode, skip, sync_timeout, cte_type,
194           base::Bind(&status_callback, std::move(command_complete)));
195     else
196       btsnd_hcic_ble_set_periodic_advertising_sync_transfer_params(
197           acl_handle, mode, skip, sync_timeout, cte_type,
198           base::Bind(&status_callback, std::move(command_complete)));
199   }
200 
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)201   void OnPeriodicAdvSyncEstablished(uint8_t status, uint16_t sync_handle,
202                                     uint8_t adv_sid, uint8_t adv_addr_type,
203                                     RawAddress adv_addr, uint8_t adv_phy,
204                                     uint16_t adv_interval,
205                                     uint8_t adv_clock_accuracy) {
206     if (scan_event_observer) {
207       scan_event_observer->OnPeriodicScanEstablished(
208           status, sync_handle, adv_sid, adv_addr_type, adv_addr, adv_phy,
209           adv_interval, adv_clock_accuracy);
210     }
211   }
212 
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,uint8_t * p_pkt_data)213   void OnPeriodicScanResult(uint16_t sync_handle, uint8_t tx_power, int8_t rssi,
214                             uint8_t cte_type, uint8_t pkt_data_status,
215                             uint8_t pkt_data_len, uint8_t* p_pkt_data) {
216     // The observer should handle the caching and reassembly of the fragmented
217     // packet.
218     if (scan_event_observer) {
219       scan_event_observer->OnPeriodicScanResult(sync_handle, tx_power, rssi,
220                                                 cte_type, pkt_data_status,
221                                                 pkt_data_len, p_pkt_data);
222     }
223   }
224 
OnPeriodicSyncLost(uint16_t sync_handle)225   void OnPeriodicSyncLost(uint16_t sync_handle) {
226     if (scan_event_observer)
227       scan_event_observer->OnPeriodicScanLost(sync_handle);
228   }
229 
230  private:
231   ScanEventObserver* scan_event_observer = nullptr;
232 };
233 
234 class BleScannerListImpl : public virtual BleScannerImplBase {
PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type,RawAddress & adv_addr,uint8_t set_id,status_cb command_complete)235   void PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type,
236                                        RawAddress& adv_addr, uint8_t set_id,
237                                        status_cb command_complete) override {
238     VLOG(1) << __func__;
239     btsnd_hci_ble_add_device_to_periodic_advertiser_list(
240         adv_addr_type, adv_addr, set_id,
241         base::Bind(&status_callback, std::move(command_complete)));
242   }
243 
PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type,RawAddress & adv_addr,uint8_t set_id,status_cb command_complete)244   void PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type,
245                                           RawAddress& adv_addr, uint8_t set_id,
246                                           status_cb command_complete) override {
247     VLOG(1) << __func__;
248     btsnd_hci_ble_remove_device_from_periodic_advertiser_list(
249         adv_addr_type, adv_addr, set_id,
250         base::Bind(&status_callback, std::move(command_complete)));
251   }
252 
PeriodicAdvertiserListClear(status_cb command_complete)253   void PeriodicAdvertiserListClear(status_cb command_complete) override {
254     VLOG(1) << __func__;
255     btsnd_hci_ble_clear_periodic_advertiser_list(
256         base::Bind(&status_callback, std::move(command_complete)));
257   };
258 };
259 
260 class BleScannerSyncTransferImpl : public virtual BleScannerImplBase {
PeriodicAdvSyncTransfer(const RawAddress & bd_addr,uint16_t service_data,uint16_t sync_handle,BleScannerHciInterface::handle_cb command_complete)261   void PeriodicAdvSyncTransfer(
262       const RawAddress& bd_addr, uint16_t service_data, uint16_t sync_handle,
263       BleScannerHciInterface::handle_cb command_complete) override {
264     uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
265 
266     if (acl_handle == HCI_INVALID_HANDLE) {
267       LOG(ERROR) << __func__
268                  << ": Wrong mode: no LE link exist or LE not supported";
269       return;
270     }
271 
272     btsnd_hcic_ble_periodic_advertising_sync_transfer(
273         acl_handle, service_data, sync_handle,
274         base::Bind(&status_handle_callback, std::move(command_complete)));
275   }
276 
PeriodicAdvSetInfoTransfer(const RawAddress & bd_addr,uint16_t service_data,uint8_t adv_handle,handle_cb command_complete)277   void PeriodicAdvSetInfoTransfer(const RawAddress& bd_addr,
278                                   uint16_t service_data, uint8_t adv_handle,
279                                   handle_cb command_complete) override {
280     uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
281 
282     if (acl_handle == HCI_INVALID_HANDLE) {
283       LOG(ERROR) << __func__
284                  << ": Wrong mode: no LE link exist or LE not supported";
285       return;
286     }
287 
288     btsnd_hcic_ble_periodic_advertising_set_info_transfer(
289         acl_handle, service_data, adv_handle,
290         base::Bind(&status_handle_callback, std::move(command_complete)));
291   }
292 
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)293   void SetPeriodicAdvSyncTransferParams(const RawAddress& bd_addr, uint8_t mode,
294                                         uint16_t skip, uint16_t sync_timeout,
295                                         uint8_t cte_type, bool set_defaults,
296                                         status_cb command_complete) override {
297     uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
298 
299     if (acl_handle == HCI_INVALID_HANDLE) {
300       LOG(ERROR) << __func__
301                  << ": Wrong mode: no LE link exist or LE not supported";
302       return;
303     }
304 
305     if (set_defaults)
306       btsnd_hcic_ble_set_default_periodic_advertising_sync_transfer_params(
307           acl_handle, mode, skip, sync_timeout, cte_type,
308           base::Bind(&status_callback, std::move(command_complete)));
309     else
310       btsnd_hcic_ble_set_periodic_advertising_sync_transfer_params(
311           acl_handle, mode, skip, sync_timeout, cte_type,
312           base::Bind(&status_callback, std::move(command_complete)));
313   }
314 };
315 
316 class BleScannerCompleteImpl : public BleScannerListImpl,
317                                public BleScannerSyncTransferImpl {
318   // Not much to do here :)
319 };
320 
321 }  // namespace
322 
Initialize()323 void BleScannerHciInterface::Initialize() {
324   VLOG(1) << __func__;
325   LOG_ASSERT(instance == nullptr) << "Was already initialized.";
326 
327   if ((controller_get_interface()->get_ble_periodic_advertiser_list_size()) &&
328       (controller_get_interface()
329            ->supports_ble_periodic_advertising_sync_transfer_sender())) {
330     LOG(INFO) << "Advertiser list in controller can be used";
331     LOG(INFO) << "Periodic Adv Sync Transfer Sender role is supported";
332     instance = new BleScannerCompleteImpl();
333   } else if (controller_get_interface()
334                  ->supports_ble_periodic_advertising_sync_transfer_sender()) {
335     LOG(INFO) << "Periodic Adv Sync Transfer Sender role is supported";
336     instance = new BleScannerSyncTransferImpl();
337   } else if (controller_get_interface()
338                  ->get_ble_periodic_advertiser_list_size()) {
339     LOG(INFO) << "Periodic Adv Sync Transfer Recipient role is supported";
340     instance = new BleScannerListImpl();
341   }
342   // TODO: Implement periodic adv. sync. recipient role if ever needed.
343 }
344 
Get()345 BleScannerHciInterface* BleScannerHciInterface::Get() { return instance; }
346 
CleanUp()347 void BleScannerHciInterface::CleanUp() {
348   VLOG(1) << __func__;
349 
350   delete instance;
351   instance = nullptr;
352 }
353 
btm_ble_process_periodic_adv_sync_est_evt(uint8_t data_len,uint8_t * data)354 void btm_ble_process_periodic_adv_sync_est_evt(uint8_t data_len,
355                                                uint8_t* data) {
356   uint16_t sync_handle, adv_interval;
357   uint8_t status, adv_sid, adv_addr_type, adv_phy, adv_clock_accuracy;
358   RawAddress adv_addr;
359 
360   VLOG(1) << __func__;
361 
362   LOG_ASSERT(data_len == 15)
363       << "Malformed LE Periodic Advertising Sync Est. Event from controller";
364 
365   STREAM_TO_UINT8(status, data);
366   STREAM_TO_UINT16(sync_handle, data);
367   STREAM_TO_UINT8(adv_sid, data);
368   STREAM_TO_UINT8(adv_addr_type, data);
369   STREAM_TO_BDADDR(adv_addr, data);
370   STREAM_TO_UINT8(adv_phy, data);
371   STREAM_TO_UINT16(adv_interval, data);
372   STREAM_TO_UINT8(adv_clock_accuracy, data);
373 
374   if (BleScannerHciInterface::Get()) {
375     static_cast<BleScannerImplBase*>(BleScannerHciInterface::Get())
376         ->OnPeriodicAdvSyncEstablished(status, sync_handle, adv_sid,
377                                        adv_addr_type, adv_addr, adv_phy,
378                                        adv_interval, adv_clock_accuracy);
379   }
380 }
381 
btm_ble_process_periodic_adv_pkt(uint8_t data_len,uint8_t * data)382 void btm_ble_process_periodic_adv_pkt(uint8_t data_len, uint8_t* data) {
383   uint8_t* p = data;
384   uint16_t sync_handle;
385   uint8_t tx_power, cte_type, pkt_data_status, pkt_data_len;
386   int8_t rssi;
387 
388   LOG_ASSERT(data_len >= 7)
389       << "Malformed LE Periodic Advertising Report Event from controller";
390 
391   STREAM_TO_UINT16(sync_handle, p);
392   STREAM_TO_UINT8(tx_power, p);
393   STREAM_TO_INT8(rssi, p);
394   STREAM_TO_UINT8(cte_type, p);
395   STREAM_TO_UINT8(pkt_data_status, p);
396   STREAM_TO_UINT8(pkt_data_len, p);
397 
398   uint8_t* pkt_data = p;
399   p += pkt_data_len;
400 
401   if (p > data + data_len) {
402     LOG(ERROR) << __func__ << " Invalid pkt_data_len: " << int{pkt_data_len};
403     return;
404   }
405 
406   if (rssi >= 21 && rssi <= 126) {
407     LOG(ERROR) << __func__
408                << " bad rssi value in advertising report: " << int{rssi};
409   }
410 
411   if (BleScannerHciInterface::Get()) {
412     static_cast<BleScannerImplBase*>(BleScannerHciInterface::Get())
413         ->OnPeriodicScanResult(sync_handle, tx_power, rssi, cte_type,
414                                pkt_data_status, pkt_data_len, pkt_data);
415   }
416 }
417 
btm_ble_process_periodic_adv_sync_lost_evt(uint8_t data_len,uint8_t * data)418 void btm_ble_process_periodic_adv_sync_lost_evt(uint8_t data_len,
419                                                 uint8_t* data) {
420   uint16_t sync_handle;
421 
422   STREAM_TO_UINT16(sync_handle, data);
423 
424   if (BleScannerHciInterface::Get()) {
425     static_cast<BleScannerImplBase*>(BleScannerHciInterface::Get())
426         ->OnPeriodicSyncLost(sync_handle);
427   }
428 }
429