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