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