1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <bluetooth/log.h>
19 #include <com_android_bluetooth_flags.h>
20 
21 #include <chrono>
22 #include <memory>
23 #include <utility>
24 
25 #include "common/callback.h"
26 #include "common/init_flags.h"
27 #include "hci/address_with_type.h"
28 #include "hci/event_checkers.h"
29 #include "hci/hci_packets.h"
30 #include "hci/le_scanning_callback.h"
31 #include "hci/le_scanning_interface.h"
32 #include "hci/le_scanning_reassembler.h"
33 #include "hci/uuid.h"
34 #include "module.h"
35 #include "os/alarm.h"
36 #include "os/log.h"
37 
38 namespace bluetooth {
39 namespace hci {
40 
41 constexpr std::chrono::duration kPeriodicSyncTimeout = std::chrono::seconds(5);
42 constexpr int kMaxSyncTransactions = 16;
43 
44 enum PeriodicSyncState : int {
45   PERIODIC_SYNC_STATE_IDLE = 0,
46   PERIODIC_SYNC_STATE_PENDING,
47   PERIODIC_SYNC_STATE_ESTABLISHED,
48 };
49 
50 struct PeriodicSyncTransferStates {
51   int pa_source;
52   int connection_handle;
53   Address addr;
54 };
55 
56 struct PeriodicSyncStates {
57   int request_id;
58   uint8_t advertiser_sid;
59   AddressWithType address_with_type;
60   uint16_t sync_handle;
61   PeriodicSyncState sync_state;
62 };
63 
64 struct PendingPeriodicSyncRequest {
PendingPeriodicSyncRequestPendingPeriodicSyncRequest65   PendingPeriodicSyncRequest(
66       uint8_t advertiser_sid,
67       AddressWithType address_with_type,
68       uint16_t skip,
69       uint16_t sync_timeout,
70       os::Handler* handler)
71       : advertiser_sid(advertiser_sid),
72         address_with_type(std::move(address_with_type)),
73         skip(skip),
74         sync_timeout(sync_timeout),
75         sync_timeout_alarm(handler) {}
76   bool busy = false;
77   uint8_t advertiser_sid;
78   AddressWithType address_with_type;
79   uint16_t skip;
80   uint16_t sync_timeout;
81   os::Alarm sync_timeout_alarm;
82 };
83 
84 class PeriodicSyncManager {
85  public:
PeriodicSyncManager(ScanningCallback * callbacks)86   explicit PeriodicSyncManager(ScanningCallback* callbacks)
87       : le_scanning_interface_(nullptr), handler_(nullptr), callbacks_(callbacks), sync_received_callback_id(0) {}
88 
Init(hci::LeScanningInterface * le_scanning_interface,os::Handler * handler)89   void Init(hci::LeScanningInterface* le_scanning_interface, os::Handler* handler) {
90     le_scanning_interface_ = le_scanning_interface;
91     handler_ = handler;
92   }
93 
SetScanningCallback(ScanningCallback * callbacks)94   void SetScanningCallback(ScanningCallback* callbacks) {
95     callbacks_ = callbacks;
96   }
97 
StartSync(const PeriodicSyncStates & request,uint16_t skip,uint16_t sync_timeout)98   void StartSync(const PeriodicSyncStates& request, uint16_t skip, uint16_t sync_timeout) {
99     if (periodic_syncs_.size() >= kMaxSyncTransactions) {
100       int status = static_cast<int>(ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES);
101       callbacks_->OnPeriodicSyncStarted(
102           request.request_id, status, 0, request.advertiser_sid, request.address_with_type, 0, 0);
103       return;
104     }
105     auto address_type = request.address_with_type.GetAddressType();
106     log::assert_that(
107         (address_type == AddressType::PUBLIC_DEVICE_ADDRESS ||
108          address_type == AddressType::RANDOM_DEVICE_ADDRESS),
109         "Invalid address type {}",
110         AddressTypeText(address_type));
111     periodic_syncs_.emplace_back(request);
112     log::debug("address = {}, sid = {}", request.address_with_type, request.advertiser_sid);
113     pending_sync_requests_.emplace_back(
114         request.advertiser_sid, request.address_with_type, skip, sync_timeout, handler_);
115     HandleNextRequest();
116   }
117 
StopSync(uint16_t handle)118   void StopSync(uint16_t handle) {
119     log::debug("[PSync]: handle = {}", handle);
120     auto periodic_sync = GetEstablishedSyncFromHandle(handle);
121     if (periodic_sync == periodic_syncs_.end()) {
122       log::error("[PSync]: invalid index for handle {}", handle);
123       le_scanning_interface_->EnqueueCommand(
124           hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(handle),
125           handler_->BindOnce(check_complete<LePeriodicAdvertisingTerminateSyncCompleteView>));
126       return;
127     };
128     periodic_syncs_.erase(periodic_sync);
129     le_scanning_interface_->EnqueueCommand(
130         hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(handle),
131         handler_->BindOnce(check_complete<LePeriodicAdvertisingTerminateSyncCompleteView>));
132   }
133 
CancelCreateSync(uint8_t adv_sid,Address address)134   void CancelCreateSync(uint8_t adv_sid, Address address) {
135     log::debug("[PSync]");
136     auto periodic_sync = GetSyncFromAddressAndSid(address, adv_sid);
137     if (periodic_sync == periodic_syncs_.end()) {
138       log::error("[PSync]:Invalid index for sid={}", adv_sid);
139       return;
140     }
141 
142     if (periodic_sync->sync_state == PERIODIC_SYNC_STATE_PENDING) {
143       log::warn("[PSync]: Sync state is pending");
144       le_scanning_interface_->EnqueueCommand(
145           hci::LePeriodicAdvertisingCreateSyncCancelBuilder::Create(),
146           handler_->BindOnceOn(
147               this,
148               &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncCancelStatus<
149                   LePeriodicAdvertisingCreateSyncCancelCompleteView>));
150     } else if (periodic_sync->sync_state == PERIODIC_SYNC_STATE_IDLE) {
151       log::debug("[PSync]: Removing Sync request from queue");
152       CleanUpRequest(adv_sid, address);
153     }
154     periodic_syncs_.erase(periodic_sync);
155   }
156 
TransferSync(const Address & address,uint16_t service_data,uint16_t sync_handle,int pa_source,uint16_t connection_handle)157   void TransferSync(
158       const Address& address, uint16_t service_data, uint16_t sync_handle, int pa_source, uint16_t connection_handle) {
159     if (periodic_sync_transfers_.size() >= kMaxSyncTransactions) {
160       int status = static_cast<int>(ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES);
161       callbacks_->OnPeriodicSyncTransferred(pa_source, status, address);
162       return;
163     }
164 
165     PeriodicSyncTransferStates request{pa_source, connection_handle, address};
166     periodic_sync_transfers_.emplace_back(request);
167     le_scanning_interface_->EnqueueCommand(
168         hci::LePeriodicAdvertisingSyncTransferBuilder::Create(connection_handle, service_data, sync_handle),
169         handler_->BindOnceOn(
170             this,
171             &PeriodicSyncManager::HandlePeriodicAdvertisingSyncTransferComplete<
172                 LePeriodicAdvertisingSyncTransferCompleteView>,
173             connection_handle));
174   }
175 
SyncSetInfo(const Address & address,uint16_t service_data,uint8_t adv_handle,int pa_source,uint16_t connection_handle)176   void SyncSetInfo(
177       const Address& address, uint16_t service_data, uint8_t adv_handle, int pa_source, uint16_t connection_handle) {
178     if (periodic_sync_transfers_.size() >= kMaxSyncTransactions) {
179       int status = static_cast<int>(ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES);
180       callbacks_->OnPeriodicSyncTransferred(pa_source, status, address);
181       return;
182     }
183     PeriodicSyncTransferStates request{pa_source, connection_handle, address};
184     periodic_sync_transfers_.emplace_back(request);
185     le_scanning_interface_->EnqueueCommand(
186         hci::LePeriodicAdvertisingSetInfoTransferBuilder::Create(connection_handle, service_data, adv_handle),
187         handler_->BindOnceOn(
188             this,
189             &PeriodicSyncManager::HandlePeriodicAdvertisingSyncTransferComplete<
190                 LePeriodicAdvertisingSetInfoTransferCompleteView>,
191             connection_handle));
192   }
193 
SyncTxParameters(const Address &,uint8_t mode,uint16_t skip,uint16_t timeout,int reg_id)194   void SyncTxParameters(
195       const Address& /* address */, uint8_t mode, uint16_t skip, uint16_t timeout, int reg_id) {
196     log::debug("[PAST]: mode={}, skip={}, timeout={}", mode, skip, timeout);
197     auto sync_cte_type = static_cast<CteType>(
198         static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOA_CONSTANT_TONE_EXTENSION) |
199         static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOD_CONSTANT_TONE_EXTENSION_WITH_ONE_US_SLOTS) |
200         static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOD_CONSTANT_TONE_EXTENSION_WITH_TWO_US_SLOTS));
201     sync_received_callback_registered_ = true;
202     sync_received_callback_id = reg_id;
203 
204     le_scanning_interface_->EnqueueCommand(
205         hci::LeSetDefaultPeriodicAdvertisingSyncTransferParametersBuilder::Create(
206             static_cast<SyncTransferMode>(mode), skip, timeout, sync_cte_type),
207         handler_->BindOnce(
208             check_complete<LeSetDefaultPeriodicAdvertisingSyncTransferParametersCompleteView>));
209   }
210 
211   template <class View>
HandlePeriodicAdvertisingCreateSyncStatus(CommandStatusView view)212   void HandlePeriodicAdvertisingCreateSyncStatus(CommandStatusView view) {
213     if (!com::android::bluetooth::flags::leaudio_broadcast_assistant_handle_command_statuses()) {
214       return;
215     }
216     log::assert_that(view.IsValid(), "assert failed: view.IsValid()");
217     auto status_view = View::Create(view);
218     log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()");
219     auto status = status_view.GetStatus();
220     if (status != ErrorCode::SUCCESS) {
221       auto& request = pending_sync_requests_.front();
222       request.sync_timeout_alarm.Cancel();
223       log::warn(
224           "Got a Command status {}, status {}, SID={:04X}, bd_addr={}",
225           OpCodeText(view.GetCommandOpCode()),
226           ErrorCodeText(status),
227           request.advertiser_sid,
228           request.address_with_type);
229 
230       uint8_t adv_sid = request.advertiser_sid;
231       AddressWithType address_with_type = request.address_with_type;
232       auto sync = GetSyncFromAddressWithTypeAndSid(address_with_type, adv_sid);
233       callbacks_->OnPeriodicSyncStarted(
234           sync->request_id,
235           (uint8_t)status,
236           0,
237           sync->advertiser_sid,
238           request.address_with_type,
239           0,
240           0);
241       periodic_syncs_.erase(sync);
242       AdvanceRequest();
243     }
244   }
245 
246   template <class View>
HandlePeriodicAdvertisingCreateSyncCancelStatus(CommandCompleteView view)247   void HandlePeriodicAdvertisingCreateSyncCancelStatus(CommandCompleteView view) {
248     if (!com::android::bluetooth::flags::leaudio_broadcast_assistant_handle_command_statuses()) {
249       return;
250     }
251     log::assert_that(view.IsValid(), "assert failed: view.IsValid()");
252     auto status_view = View::Create(view);
253     log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()");
254     auto status = status_view.GetStatus();
255     if (status != ErrorCode::SUCCESS) {
256       auto& request = pending_sync_requests_.front();
257       request.sync_timeout_alarm.Cancel();
258       log::warn(
259           "Got a Command complete {}, status {}, SID={:04X}, bd_addr={}",
260           OpCodeText(view.GetCommandOpCode()),
261           ErrorCodeText(status),
262           request.advertiser_sid,
263           request.address_with_type);
264       AdvanceRequest();
265     }
266   }
267 
268   template <class View>
HandlePeriodicAdvertisingSyncTransferComplete(uint16_t connection_handle,CommandCompleteView view)269   void HandlePeriodicAdvertisingSyncTransferComplete(uint16_t connection_handle, CommandCompleteView view) {
270     log::assert_that(view.IsValid(), "assert failed: view.IsValid()");
271     auto status_view = View::Create(view);
272     log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()");
273     if (status_view.GetStatus() != ErrorCode::SUCCESS) {
274       log::warn(
275           "Got a Command complete {}, status {}, connection_handle {}",
276           OpCodeText(view.GetCommandOpCode()),
277           ErrorCodeText(status_view.GetStatus()),
278           connection_handle);
279     } else {
280       log::debug(
281           "Got a Command complete {}, status {}, connection_handle {}",
282           OpCodeText(view.GetCommandOpCode()),
283           ErrorCodeText(status_view.GetStatus()),
284           connection_handle);
285     }
286 
287     auto periodic_sync_transfer = GetSyncTransferRequestFromConnectionHandle(connection_handle);
288     if (periodic_sync_transfer == periodic_sync_transfers_.end()) {
289       log::error("[PAST]:Invalid, conn_handle {} not found in DB", connection_handle);
290       return;
291     };
292 
293     callbacks_->OnPeriodicSyncTransferred(
294         periodic_sync_transfer->pa_source, (uint16_t)status_view.GetStatus(), periodic_sync_transfer->addr);
295     periodic_sync_transfers_.erase(periodic_sync_transfer);
296   }
297 
HandleLePeriodicAdvertisingSyncEstablished(LePeriodicAdvertisingSyncEstablishedView event_view)298   void HandleLePeriodicAdvertisingSyncEstablished(LePeriodicAdvertisingSyncEstablishedView event_view) {
299     log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()");
300     log::debug(
301         "[PSync]: status={}, sync_handle={}, address={}, s_id={}, address_type={}, adv_phy={}, "
302         "adv_interval={}, clock_acc={}",
303         (uint16_t)event_view.GetStatus(),
304         event_view.GetSyncHandle(),
305         AddressWithType(event_view.GetAdvertiserAddress(), event_view.GetAdvertiserAddressType()),
306         event_view.GetAdvertisingSid(),
307         (uint16_t)event_view.GetAdvertiserAddressType(),
308         (uint16_t)event_view.GetAdvertiserPhy(),
309         event_view.GetPeriodicAdvertisingInterval(),
310         (uint16_t)event_view.GetAdvertiserClockAccuracy());
311 
312     auto pending_sync_request =
313         GetPendingSyncFromAddressAndSid(event_view.GetAdvertiserAddress(), event_view.GetAdvertisingSid());
314     if (pending_sync_request != pending_sync_requests_.end()) {
315       pending_sync_request->sync_timeout_alarm.Cancel();
316     }
317 
318     auto address_with_type = AddressWithType(event_view.GetAdvertiserAddress(), event_view.GetAdvertiserAddressType());
319     auto peer_address_type = address_with_type.GetAddressType();
320     AddressType temp_address_type;
321     switch (peer_address_type) {
322       case AddressType::PUBLIC_DEVICE_ADDRESS:
323       case AddressType::PUBLIC_IDENTITY_ADDRESS:
324         temp_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
325         break;
326       case AddressType::RANDOM_DEVICE_ADDRESS:
327       case AddressType::RANDOM_IDENTITY_ADDRESS:
328         temp_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
329         break;
330     }
331 
332     auto periodic_sync = GetSyncFromAddressWithTypeAndSid(
333         AddressWithType(event_view.GetAdvertiserAddress(), temp_address_type), event_view.GetAdvertisingSid());
334     if (periodic_sync == periodic_syncs_.end()) {
335       log::warn("[PSync]: Invalid address and sid for sync established");
336       if (event_view.GetStatus() == ErrorCode::SUCCESS) {
337         log::warn("Terminate sync");
338         le_scanning_interface_->EnqueueCommand(
339             hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(event_view.GetSyncHandle()),
340             handler_->BindOnce(check_complete<LePeriodicAdvertisingTerminateSyncCompleteView>));
341       }
342       AdvanceRequest();
343       return;
344     }
345     periodic_sync->sync_handle = event_view.GetSyncHandle();
346     periodic_sync->sync_state = PERIODIC_SYNC_STATE_ESTABLISHED;
347     callbacks_->OnPeriodicSyncStarted(
348         periodic_sync->request_id,
349         (uint8_t)event_view.GetStatus(),
350         event_view.GetSyncHandle(),
351         event_view.GetAdvertisingSid(),
352         address_with_type,
353         (uint16_t)event_view.GetAdvertiserPhy(),
354         event_view.GetPeriodicAdvertisingInterval());
355 
356     if (com::android::bluetooth::flags::leaudio_broadcast_feature_support()) {
357       if (event_view.GetStatus() != ErrorCode::SUCCESS) {
358         periodic_syncs_.erase(periodic_sync);
359       }
360     }
361 
362     AdvanceRequest();
363   }
364 
HandleLePeriodicAdvertisingReport(LePeriodicAdvertisingReportView event_view)365   void HandleLePeriodicAdvertisingReport(LePeriodicAdvertisingReportView event_view) {
366     log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()");
367     log::debug(
368         "[PSync]: sync_handle = {}, tx_power = {}, rssi = {},cte_type = {}, data_status = {}, "
369         "data_len = {}",
370         event_view.GetSyncHandle(),
371         event_view.GetTxPower(),
372         event_view.GetRssi(),
373         (uint16_t)event_view.GetCteType(),
374         (uint16_t)event_view.GetDataStatus(),
375         (uint16_t)event_view.GetData().size());
376 
377     uint16_t sync_handle = event_view.GetSyncHandle();
378     auto periodic_sync = GetEstablishedSyncFromHandle(sync_handle);
379     if (periodic_sync == periodic_syncs_.end()) {
380       log::error("[PSync]: index not found for handle {}", sync_handle);
381       return;
382     }
383 
384     auto complete_advertising_data =
385         com::android::bluetooth::flags::le_periodic_scanning_reassembler()
386             ? scanning_reassembler_.ProcessPeriodicAdvertisingReport(
387                   sync_handle, DataStatus(event_view.GetDataStatus()), event_view.GetData())
388             : event_view.GetData();
389     if (!complete_advertising_data.has_value()) {
390       return;
391     }
392 
393     log::debug("{}", "[PSync]: invoking callback");
394     callbacks_->OnPeriodicSyncReport(
395         sync_handle,
396         event_view.GetTxPower(),
397         event_view.GetRssi(),
398         (uint16_t)event_view.GetDataStatus(),
399         complete_advertising_data.value());
400   }
401 
HandleLePeriodicAdvertisingSyncLost(LePeriodicAdvertisingSyncLostView event_view)402   void HandleLePeriodicAdvertisingSyncLost(LePeriodicAdvertisingSyncLostView event_view) {
403     log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()");
404     uint16_t sync_handle = event_view.GetSyncHandle();
405     log::debug("[PSync]: sync_handle = {}", sync_handle);
406     callbacks_->OnPeriodicSyncLost(sync_handle);
407     auto periodic_sync = GetEstablishedSyncFromHandle(sync_handle);
408     if (periodic_sync == periodic_syncs_.end()) {
409       log::error("[PSync]: index not found for handle {}", sync_handle);
410       return;
411     }
412     periodic_syncs_.erase(periodic_sync);
413   }
414 
HandleLePeriodicAdvertisingSyncTransferReceived(LePeriodicAdvertisingSyncTransferReceivedView event_view)415   void HandleLePeriodicAdvertisingSyncTransferReceived(LePeriodicAdvertisingSyncTransferReceivedView event_view) {
416     log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()");
417     uint8_t status = (uint8_t)event_view.GetStatus();
418     uint8_t advertiser_phy = (uint8_t)event_view.GetAdvertiserPhy();
419     log::debug(
420         "[PAST]: status = {}, connection_handle = {}, service_data = {}, sync_handle = {}, adv_sid "
421         "= {}, address_type = {}, address = {}, advertiser_phy = {}, periodic_advertising_interval "
422         "= {}, clock_accuracy = {}",
423         status,
424         event_view.GetConnectionHandle(),
425         event_view.GetServiceData(),
426         event_view.GetSyncHandle(),
427         event_view.GetAdvertisingSid(),
428         (uint8_t)event_view.GetAdvertiserAddressType(),
429         event_view.GetAdvertiserAddress(),
430         advertiser_phy,
431         event_view.GetPeriodicAdvertisingInterval(),
432         (uint8_t)event_view.GetAdvertiserClockAccuracy());
433     if (sync_received_callback_registered_) {
434       callbacks_->OnPeriodicSyncStarted(
435           sync_received_callback_id,
436           status,
437           event_view.GetSyncHandle(),
438           event_view.GetAdvertisingSid(),
439           AddressWithType(event_view.GetAdvertiserAddress(), event_view.GetAdvertiserAddressType()),
440           advertiser_phy,
441           event_view.GetPeriodicAdvertisingInterval());
442     }
443   }
444 
OnStartSyncTimeout()445   void OnStartSyncTimeout() {
446     auto& request = pending_sync_requests_.front();
447     log::warn(
448         "sync timeout SID={:04X}, bd_addr={}", request.advertiser_sid, request.address_with_type);
449     uint8_t adv_sid = request.advertiser_sid;
450     AddressWithType address_with_type = request.address_with_type;
451     auto sync = GetSyncFromAddressWithTypeAndSid(address_with_type, adv_sid);
452     le_scanning_interface_->EnqueueCommand(
453         hci::LePeriodicAdvertisingCreateSyncCancelBuilder::Create(),
454         handler_->BindOnceOn(
455             this,
456             &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncCancelStatus<
457                 LePeriodicAdvertisingCreateSyncCancelCompleteView>));
458     int status = static_cast<int>(ErrorCode::ADVERTISING_TIMEOUT);
459     callbacks_->OnPeriodicSyncStarted(
460         sync->request_id, status, 0, sync->advertiser_sid, request.address_with_type, 0, 0);
461     periodic_syncs_.erase(sync);
462   }
463 
HandleLeBigInfoAdvertisingReport(LeBigInfoAdvertisingReportView event_view)464   void HandleLeBigInfoAdvertisingReport(LeBigInfoAdvertisingReportView event_view) {
465     log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()");
466     log::debug(
467         "[PAST]:sync_handle {}, num_bises = {}, nse = {},iso_interval = {}, bn = {}, pto = {}, irc "
468         "= {}, max_pdu = {} sdu_interval = {}, max_sdu = {}, phy = {}, framing = {}, encryption  = "
469         "{}",
470         event_view.GetSyncHandle(),
471         event_view.GetNumBis(),
472         event_view.GetNse(),
473         event_view.GetIsoInterval(),
474         event_view.GetBn(),
475         event_view.GetPto(),
476         event_view.GetIrc(),
477         event_view.GetMaxPdu(),
478         event_view.GetSduInterval(),
479         event_view.GetMaxSdu(),
480         static_cast<uint32_t>(event_view.GetPhy()),
481         static_cast<uint32_t>(event_view.GetFraming()),
482         static_cast<uint32_t>(event_view.GetEncryption()));
483 
484     uint16_t sync_handle = event_view.GetSyncHandle();
485     auto periodic_sync = GetEstablishedSyncFromHandle(sync_handle);
486     if (periodic_sync == periodic_syncs_.end()) {
487       log::error("[PSync]: index not found for handle {}", sync_handle);
488       return;
489     }
490     log::debug("{}", "[PSync]: invoking callback");
491     callbacks_->OnBigInfoReport(sync_handle, event_view.GetEncryption() == Enable::ENABLED ? true : false);
492   }
493 
494  private:
GetEstablishedSyncFromHandle(uint16_t handle)495   std::list<PeriodicSyncStates>::iterator GetEstablishedSyncFromHandle(uint16_t handle) {
496     for (auto it = periodic_syncs_.begin(); it != periodic_syncs_.end(); it++) {
497       if (it->sync_handle == handle && it->sync_state == PeriodicSyncState::PERIODIC_SYNC_STATE_ESTABLISHED) {
498         return it;
499       }
500     }
501     return periodic_syncs_.end();
502   }
503 
GetSyncFromAddressWithTypeAndSid(const AddressWithType & address_with_type,uint8_t adv_sid)504   std::list<PeriodicSyncStates>::iterator GetSyncFromAddressWithTypeAndSid(
505       const AddressWithType& address_with_type, uint8_t adv_sid) {
506     for (auto it = periodic_syncs_.begin(); it != periodic_syncs_.end(); it++) {
507       if (it->advertiser_sid == adv_sid && it->address_with_type == address_with_type) {
508         return it;
509       }
510     }
511     return periodic_syncs_.end();
512   }
513 
GetSyncFromAddressAndSid(const Address & address,uint8_t adv_sid)514   std::list<PeriodicSyncStates>::iterator GetSyncFromAddressAndSid(const Address& address, uint8_t adv_sid) {
515     for (auto it = periodic_syncs_.begin(); it != periodic_syncs_.end(); it++) {
516       if (it->advertiser_sid == adv_sid && it->address_with_type.GetAddress() == address) {
517         return it;
518       }
519     }
520     return periodic_syncs_.end();
521   }
522 
GetPendingSyncFromAddressAndSid(const Address & address,uint8_t adv_sid)523   std::list<PendingPeriodicSyncRequest>::iterator GetPendingSyncFromAddressAndSid(
524       const Address& address, uint8_t adv_sid) {
525     for (auto it = pending_sync_requests_.begin(); it != pending_sync_requests_.end(); it++) {
526       if (it->advertiser_sid == adv_sid && it->address_with_type.GetAddress() == address) {
527         return it;
528       }
529     }
530     return pending_sync_requests_.end();
531   }
532 
GetSyncTransferRequestFromConnectionHandle(uint16_t connection_handle)533   std::list<PeriodicSyncTransferStates>::iterator GetSyncTransferRequestFromConnectionHandle(
534       uint16_t connection_handle) {
535     for (auto it = periodic_sync_transfers_.begin(); it != periodic_sync_transfers_.end(); it++) {
536       if (it->connection_handle == connection_handle) {
537         return it;
538       }
539     }
540     return periodic_sync_transfers_.end();
541   }
542 
HandleStartSyncRequest(uint8_t sid,const AddressWithType & address_with_type,uint16_t skip,uint16_t timeout)543   void HandleStartSyncRequest(uint8_t sid, const AddressWithType& address_with_type, uint16_t skip, uint16_t timeout) {
544     PeriodicAdvertisingOptions options;
545     auto sync_cte_type =
546         static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOA_CONSTANT_TONE_EXTENSION) |
547         static_cast<uint8_t>(
548             PeriodicSyncCteType::AVOID_AOD_CONSTANT_TONE_EXTENSION_WITH_ONE_US_SLOTS) |
549         static_cast<uint8_t>(
550             PeriodicSyncCteType::AVOID_AOD_CONSTANT_TONE_EXTENSION_WITH_TWO_US_SLOTS);
551     auto sync = GetSyncFromAddressWithTypeAndSid(address_with_type, sid);
552     sync->sync_state = PERIODIC_SYNC_STATE_PENDING;
553     AdvertisingAddressType advertisingAddressType =
554         static_cast<AdvertisingAddressType>(address_with_type.GetAddressType());
555     le_scanning_interface_->EnqueueCommand(
556         hci::LePeriodicAdvertisingCreateSyncBuilder::Create(
557             options,
558             sid,
559             advertisingAddressType,
560             address_with_type.GetAddress(),
561             skip,
562             timeout,
563             sync_cte_type),
564         handler_->BindOnceOn(
565             this,
566             &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncStatus<
567                 LePeriodicAdvertisingCreateSyncStatusView>));
568   }
569 
HandleNextRequest()570   void HandleNextRequest() {
571     if (pending_sync_requests_.empty()) {
572       log::debug("pending_sync_requests_ empty");
573       return;
574     }
575     auto& request = pending_sync_requests_.front();
576     log::info(
577         "executing sync request SID={:04X}, bd_addr={}",
578         request.advertiser_sid,
579         request.address_with_type);
580     if (request.busy) {
581       log::info("Request is already busy");
582       return;
583     }
584     request.busy = true;
585     request.sync_timeout_alarm.Cancel();
586     HandleStartSyncRequest(request.advertiser_sid, request.address_with_type, request.skip, request.sync_timeout);
587     request.sync_timeout_alarm.Schedule(
588         base::BindOnce(&PeriodicSyncManager::OnStartSyncTimeout, base::Unretained(this)), kPeriodicSyncTimeout);
589   }
590 
AdvanceRequest()591   void AdvanceRequest() {
592     log::debug("AdvanceRequest");
593     if (pending_sync_requests_.empty()) {
594       log::debug("pending_sync_requests_ empty");
595       return;
596     }
597     auto it = pending_sync_requests_.begin();
598     pending_sync_requests_.erase(it);
599     HandleNextRequest();
600   }
601 
CleanUpRequest(uint8_t advertiser_sid,Address address)602   void CleanUpRequest(uint8_t advertiser_sid, Address address) {
603     auto it = pending_sync_requests_.begin();
604     while (it != pending_sync_requests_.end()) {
605       if (it->advertiser_sid == advertiser_sid && it->address_with_type.GetAddress() == address) {
606         log::info(
607             "removing connection request SID={:04X}, bd_addr={}, busy={}",
608             it->advertiser_sid,
609             it->address_with_type,
610             it->busy);
611         it = pending_sync_requests_.erase(it);
612       } else {
613         ++it;
614       }
615     }
616   }
617 
618   hci::LeScanningInterface* le_scanning_interface_;
619   os::Handler* handler_;
620   ScanningCallback* callbacks_;
621   std::list<PendingPeriodicSyncRequest> pending_sync_requests_;
622   std::list<PeriodicSyncStates> periodic_syncs_;
623   std::list<PeriodicSyncTransferStates> periodic_sync_transfers_;
624   LeScanningReassembler scanning_reassembler_;
625   bool sync_received_callback_registered_ = false;
626   int sync_received_callback_id{};
627 };
628 
629 }  // namespace hci
630 }  // namespace bluetooth
631