Loading system/gd/hci/acl_manager.cc +42 −103 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ #include "hci/acl_manager.h" #include <atomic> #include <future> #include <queue> #include <set> #include <utility> Loading Loading @@ -67,41 +66,29 @@ uint16_t GetL2capPduSize(AclPacketView packet) { } // namespace struct AclManager::acl_connection { acl_connection(AddressWithType address_with_type, os::Handler* handler) : address_with_type_(address_with_type), handler_(handler) {} struct assembler { assembler(AddressWithType address_with_type, AclConnection::QueueDownEnd* down_end, os::Handler* handler) : address_with_type_(address_with_type), down_end_(down_end), handler_(handler) {} AddressWithType address_with_type_; AclConnection::QueueDownEnd* down_end_; os::Handler* handler_; std::unique_ptr<AclConnection::Queue> queue_ = std::make_unique<AclConnection::Queue>(10); bool is_disconnected_ = false; ErrorCode disconnect_reason_; os::Handler* command_complete_handler_ = nullptr; os::Handler* disconnect_handler_ = nullptr; ConnectionManagementCallbacks* command_complete_callbacks_ = nullptr; os::Handler* le_command_complete_handler_ = nullptr; LeConnectionManagementCallbacks* le_command_complete_callbacks_ = nullptr; common::OnceCallback<void(ErrorCode)> on_disconnect_callback_; // For LE Connection parameter update from L2CAP common::OnceCallback<void(ErrorCode)> on_connection_update_complete_callback_; os::Handler* on_connection_update_complete_callback_handler_ = nullptr; PacketViewForRecombination recombination_stage_{std::make_shared<std::vector<uint8_t>>()}; int remaining_sdu_continuation_packet_size_ = 0; std::atomic_bool enqueue_registered_ = false; std::shared_ptr<std::atomic_bool> enqueue_registered_ = std::make_shared<std::atomic_bool>(false); std::queue<packet::PacketView<kLittleEndian>> incoming_queue_; ~acl_connection() { if (enqueue_registered_.exchange(false)) { queue_->GetDownEnd()->UnregisterEnqueue(); ~assembler() { if (enqueue_registered_->exchange(false)) { down_end_->UnregisterEnqueue(); } queue_.reset(); } // Invoked from some external Queue Reactable context std::unique_ptr<packet::PacketView<kLittleEndian>> on_incoming_data_ready() { std::unique_ptr<packet::PacketView<kLittleEndian>> on_le_incoming_data_ready() { auto packet = incoming_queue_.front(); incoming_queue_.pop(); if (incoming_queue_.empty() && enqueue_registered_.exchange(false)) { queue_->GetDownEnd()->UnregisterEnqueue(); if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) { down_end_->UnregisterEnqueue(); } return std::make_unique<PacketView<kLittleEndian>>(packet); } Loading Loading @@ -147,11 +134,30 @@ struct AclManager::acl_connection { } incoming_queue_.push(payload); if (!enqueue_registered_.exchange(true)) { queue_->GetDownEnd()->RegisterEnqueue( handler_, common::Bind(&AclManager::acl_connection::on_incoming_data_ready, common::Unretained(this))); if (!enqueue_registered_->exchange(true)) { down_end_->RegisterEnqueue(handler_, common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this))); } } }; struct AclManager::acl_connection { acl_connection(AddressWithType address_with_type, os::Handler* handler) : queue_(std::make_shared<AclConnection::Queue>(10)), assembler_(address_with_type, queue_->GetDownEnd(), handler), address_with_type_(address_with_type), handler_(handler) {} std::shared_ptr<AclConnection::Queue> queue_; struct assembler assembler_; AddressWithType address_with_type_; os::Handler* handler_; bool is_disconnected_ = false; ErrorCode disconnect_reason_; os::Handler* command_complete_handler_ = nullptr; os::Handler* disconnect_handler_ = nullptr; ConnectionManagementCallbacks* command_complete_callbacks_ = nullptr; common::OnceCallback<void(ErrorCode)> on_disconnect_callback_; ~acl_connection() {} void call_disconnect_callback() { disconnect_handler_->Post(BindOnce(std::move(on_disconnect_callback_), disconnect_reason_)); Loading @@ -160,22 +166,12 @@ struct AclManager::acl_connection { struct AclManager::le_acl_connection { le_acl_connection(AddressWithType address_with_type, os::Handler* handler) : address_with_type_(address_with_type), handler_(handler) {} AddressWithType address_with_type_; : queue_(std::make_shared<AclConnection::Queue>(10)), assembler_(address_with_type, queue_->GetDownEnd(), handler), handler_(handler) {} std::shared_ptr<AclConnection::Queue> queue_; struct assembler assembler_; LeConnectionManagementCallbacks* le_connection_management_callbacks_; os::Handler* handler_; std::shared_ptr<AclConnection::Queue> queue_ = std::make_unique<AclConnection::Queue>(10); PacketViewForRecombination recombination_stage_{std::make_shared<std::vector<uint8_t>>()}; int remaining_sdu_continuation_packet_size_ = 0; std::shared_ptr<std::atomic_bool> enqueue_registered_ = std::make_shared<std::atomic_bool>(false); std::queue<packet::PacketView<kLittleEndian>> incoming_queue_; ~le_acl_connection() { if (enqueue_registered_->exchange(false)) { queue_->GetDownEnd()->UnregisterEnqueue(); } queue_.reset(); } AclConnection::QueueDownEnd* GetDownEnd() { return queue_->GetDownEnd(); Loading @@ -184,63 +180,6 @@ struct AclManager::le_acl_connection { void SetLeConnectionManagementCallbacks(LeConnectionManagementCallbacks* callbacks) { le_connection_management_callbacks_ = callbacks; } // Invoked from some external Queue Reactable context std::unique_ptr<packet::PacketView<kLittleEndian>> on_le_incoming_data_ready() { auto packet = incoming_queue_.front(); incoming_queue_.pop(); if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) { queue_->GetDownEnd()->UnregisterEnqueue(); } return std::make_unique<PacketView<kLittleEndian>>(packet); } void on_incoming_packet(AclPacketView packet) { // TODO: What happens if the connection is stalled and fills up? PacketView<kLittleEndian> payload = packet.GetPayload(); auto payload_size = payload.size(); auto packet_boundary_flag = packet.GetPacketBoundaryFlag(); if (packet_boundary_flag == PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) { LOG_ERROR("Controller is not allowed to send FIRST_NON_AUTOMATICALLY_FLUSHABLE to host except loopback mode"); return; } if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) { if (remaining_sdu_continuation_packet_size_ < payload_size) { LOG_WARN("Remote sent unexpected L2CAP PDU. Drop the entire L2CAP PDU"); recombination_stage_ = PacketViewForRecombination(std::make_shared<std::vector<uint8_t>>()); remaining_sdu_continuation_packet_size_ = 0; return; } remaining_sdu_continuation_packet_size_ -= payload_size; recombination_stage_.AppendPacketView(payload); if (remaining_sdu_continuation_packet_size_ != 0) { return; } else { payload = recombination_stage_; recombination_stage_ = PacketViewForRecombination(std::make_shared<std::vector<uint8_t>>()); } } else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) { if (recombination_stage_.size() > 0) { LOG_ERROR("Controller sent a starting packet without finishing previous packet. Drop previous one."); } auto l2cap_pdu_size = GetL2capPduSize(packet); remaining_sdu_continuation_packet_size_ = l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize); if (remaining_sdu_continuation_packet_size_ > 0) { recombination_stage_ = payload; return; } } if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) { LOG_ERROR("Dropping packet due to congestion from remote:%s", address_with_type_.ToString().c_str()); return; } incoming_queue_.push(payload); if (!enqueue_registered_->exchange(true)) { queue_->GetDownEnd()->RegisterEnqueue( handler_, common::Bind(&AclManager::le_acl_connection::on_le_incoming_data_ready, common::Unretained(this))); } } }; class LeAclConnectionTracker : public LeConnectionManagementCallbacks { Loading Loading @@ -431,14 +370,14 @@ struct AclManager::impl : public security::ISecurityManagerListener { } auto connection_pair = acl_connections_.find(handle); if (connection_pair != acl_connections_.end()) { connection_pair->second.on_incoming_packet(*packet); connection_pair->second.assembler_.on_incoming_packet(*packet); } else { auto le_connection_pair = le_acl_connections_.find(handle); if (le_connection_pair == le_acl_connections_.end()) { LOG_INFO("Dropping packet of size %zu to unknown connection 0x%0hx", packet->size(), handle); return; } le_connection_pair->second.on_incoming_packet(*packet); le_connection_pair->second.assembler_.on_incoming_packet(*packet); } } Loading Loading @@ -514,7 +453,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { std::move(connection_proxy))); hci_layer_->GetHciHandler()->Post( common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), RoundRobinScheduler::ConnectionType::LE, handle, connection.queue_->GetDownEnd())); RoundRobinScheduler::ConnectionType::LE, handle, connection.queue_)); } void on_le_enhanced_connection_complete(LeMetaEventView packet) { Loading Loading @@ -543,7 +482,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { auto& connection = check_and_get_le_connection(handle); hci_layer_->GetHciHandler()->Post( common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), RoundRobinScheduler::ConnectionType::LE, handle, connection.queue_->GetDownEnd())); RoundRobinScheduler::ConnectionType::LE, handle, connection.queue_)); auto role = connection_complete.GetRole(); auto do_disconnect = common::BindOnce(&impl::handle_disconnect, common::Unretained(this), handle); std::unique_ptr<LeAclConnection> connection_proxy( Loading Loading @@ -574,7 +513,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { auto& connection = check_and_get_connection(handle); hci_layer_->GetHciHandler()->Post(common::BindOnce( &RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), RoundRobinScheduler::ConnectionType::CLASSIC, handle, check_and_get_connection(handle).queue_->GetDownEnd())); RoundRobinScheduler::ConnectionType::CLASSIC, handle, check_and_get_connection(handle).queue_)); std::unique_ptr<ClassicAclConnection> connection_proxy( new ClassicAclConnection(&acl_manager_, connection.queue_->GetUpEnd(), acl_connection_interface_, handle, address, Role::MASTER /* TODO: Did we connect? */)); Loading system/gd/hci/round_robin_scheduler.cc +6 −6 Original line number Diff line number Diff line Loading @@ -40,8 +40,8 @@ RoundRobinScheduler::~RoundRobinScheduler() { } void RoundRobinScheduler::Register(ConnectionType connection_type, uint16_t handle, AclConnection::QueueDownEnd* queue_down_end) { acl_queue_handler acl_queue_handler = {connection_type, queue_down_end, false, 0, false}; std::shared_ptr<AclConnection::Queue> queue) { acl_queue_handler acl_queue_handler = {connection_type, std::move(queue), false, 0, false}; acl_queue_handlers_.insert(std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler)); if (fragments_to_send_.size() == 0) { start_round_robin(); Loading @@ -53,7 +53,7 @@ void RoundRobinScheduler::Unregister(uint16_t handle) { auto acl_queue_handler = acl_queue_handlers_.find(handle)->second; if (acl_queue_handler.dequeue_is_registered_) { acl_queue_handler.dequeue_is_registered_ = false; acl_queue_handler.queue_down_end_->UnregisterDequeue(); acl_queue_handler.queue_->GetDownEnd()->UnregisterDequeue(); } acl_queue_handlers_.erase(handle); starting_point_ = acl_queue_handlers_.begin(); Loading Loading @@ -101,7 +101,7 @@ void RoundRobinScheduler::start_round_robin() { le_acl_packet_credits_ == 0 && acl_queue_handler->second.connection_type_ == ConnectionType::LE; if (!acl_queue_handler->second.dequeue_is_registered_ && !classic_buffer_full && !le_buffer_full) { acl_queue_handler->second.dequeue_is_registered_ = true; acl_queue_handler->second.queue_down_end_->RegisterDequeue( acl_queue_handler->second.queue_->GetDownEnd()->RegisterDequeue( handler_, common::Bind(&RoundRobinScheduler::buffer_packet, common::Unretained(this), acl_queue_handler)); } acl_queue_handler = std::next(acl_queue_handler); Loading @@ -117,7 +117,7 @@ void RoundRobinScheduler::buffer_packet(std::map<uint16_t, acl_queue_handler>::i BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT; // Wrap packet and enqueue it uint16_t handle = acl_queue_handler->first; auto packet = acl_queue_handler->second.queue_down_end_->TryDequeue(); auto packet = acl_queue_handler->second.queue_->GetDownEnd()->TryDequeue(); ASSERT(packet != nullptr); ConnectionType connection_type = acl_queue_handler->second.connection_type_; Loading Loading @@ -148,7 +148,7 @@ void RoundRobinScheduler::unregister_all_connections() { acl_queue_handler = std::next(acl_queue_handler)) { if (acl_queue_handler->second.dequeue_is_registered_) { acl_queue_handler->second.dequeue_is_registered_ = false; acl_queue_handler->second.queue_down_end_->UnregisterDequeue(); acl_queue_handler->second.queue_->GetDownEnd()->UnregisterDequeue(); } } } Loading system/gd/hci/round_robin_scheduler.h +2 −2 Original line number Diff line number Diff line Loading @@ -37,13 +37,13 @@ class RoundRobinScheduler { struct acl_queue_handler { ConnectionType connection_type_; AclConnection::QueueDownEnd* queue_down_end_; std::shared_ptr<AclConnection::Queue> queue_; bool dequeue_is_registered_ = false; uint16_t number_of_sent_packets_ = 0; // Track credits bool is_disconnected_ = false; }; void Register(ConnectionType connection_type, uint16_t handle, AclConnection::QueueDownEnd* queue_down_end); void Register(ConnectionType connection_type, uint16_t handle, std::shared_ptr<AclConnection::Queue> queue); void Unregister(uint16_t handle); void SetDisconnect(uint16_t handle); uint16_t GetCredits(); Loading system/gd/hci/round_robin_scheduler_test.cc +35 −43 Original line number Diff line number Diff line Loading @@ -15,9 +15,12 @@ */ #include "hci/round_robin_scheduler.h" #include <gtest/gtest.h> #include "common/bidi_queue.h" #include "common/callback.h" #include "hci/acl_manager.h" #include "hci/controller.h" #include "hci/hci_packets.h" #include "os/handler.h" Loading Loading @@ -172,20 +175,18 @@ TEST_F(RoundRobinSchedulerTest, startup_teardown) {} TEST_F(RoundRobinSchedulerTest, register_unregister_connection) { uint16_t handle = 0x01; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{10}; round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue.GetDownEnd()); auto connection_queue = std::make_shared<AclConnection::Queue>(10); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); round_robin_scheduler_->Unregister(handle); } TEST_F(RoundRobinSchedulerTest, buffer_packet) { uint16_t handle = 0x01; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{10}; AclConnection::QueueDownEnd* queue_down_end = connection_queue.GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue_down_end); auto connection_queue = std::make_shared<AclConnection::Queue>(10); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); SetPacketFuture(2); AclConnection::QueueUpEnd* queue_up_end = connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); std::vector<uint8_t> packet1 = {0x01, 0x02, 0x03}; std::vector<uint8_t> packet2 = {0x04, 0x05, 0x06}; EnqueueAclUpEnd(queue_up_end, packet1); Loading @@ -202,17 +203,15 @@ TEST_F(RoundRobinSchedulerTest, buffer_packet) { TEST_F(RoundRobinSchedulerTest, buffer_packet_from_two_connections) { uint16_t handle = 0x01; uint16_t le_handle = 0x02; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> le_connection_queue{10}; auto connection_queue = std::make_shared<AclConnection::Queue>(10); auto le_connection_queue = std::make_shared<AclConnection::Queue>(10); AclConnection::QueueDownEnd* queue_down_end = connection_queue.GetDownEnd(); AclConnection::QueueDownEnd* le_queue_down_end = le_connection_queue.GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue_down_end); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_queue_down_end); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue); SetPacketFuture(2); AclConnection::QueueUpEnd* queue_up_end = connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd(); std::vector<uint8_t> packet = {0x01, 0x02, 0x03}; std::vector<uint8_t> le_packet = {0x04, 0x05, 0x06}; EnqueueAclUpEnd(le_queue_up_end, le_packet); Loading @@ -230,12 +229,11 @@ TEST_F(RoundRobinSchedulerTest, buffer_packet_from_two_connections) { TEST_F(RoundRobinSchedulerTest, do_not_register_when_credits_is_zero) { uint16_t handle = 0x01; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{15}; AclConnection::QueueDownEnd* queue_down_end = connection_queue.GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue_down_end); auto connection_queue = std::make_shared<AclConnection::Queue>(15); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); SetPacketFuture(10); AclConnection::QueueUpEnd* queue_up_end = connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); for (uint8_t i = 0; i < 15; i++) { std::vector<uint8_t> packet = {0x01, 0x02, 0x03, i}; EnqueueAclUpEnd(queue_up_end, packet); Loading Loading @@ -273,25 +271,21 @@ TEST_F(RoundRobinSchedulerTest, buffer_packet_intervally) { uint16_t handle2 = 0x02; uint16_t le_handle1 = 0x03; uint16_t le_handle2 = 0x04; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue1{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue2{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> le_connection_queue1{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> le_connection_queue2{10}; AclConnection::QueueDownEnd* queue_down_end1 = connection_queue1.GetDownEnd(); AclConnection::QueueDownEnd* queue_down_end2 = connection_queue2.GetDownEnd(); AclConnection::QueueDownEnd* le_queue_down_end1 = le_connection_queue1.GetDownEnd(); AclConnection::QueueDownEnd* le_queue_down_end2 = le_connection_queue2.GetDownEnd(); auto connection_queue1 = std::make_shared<AclConnection::Queue>(10); auto connection_queue2 = std::make_shared<AclConnection::Queue>(10); auto le_connection_queue1 = std::make_shared<AclConnection::Queue>(10); auto le_connection_queue2 = std::make_shared<AclConnection::Queue>(10); SetPacketFuture(18); AclConnection::QueueUpEnd* queue_up_end1 = connection_queue1.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end2 = connection_queue2.GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end1 = le_connection_queue1.GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end2 = le_connection_queue2.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end1 = connection_queue1->GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end2 = connection_queue2->GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end1 = le_connection_queue1->GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end2 = le_connection_queue2->GetUpEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle1, queue_down_end1); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle2, queue_down_end2); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle1, le_queue_down_end1); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle2, le_queue_down_end2); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle1, connection_queue1); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle2, connection_queue2); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle1, le_connection_queue1); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle2, le_connection_queue2); std::vector<uint8_t> packet = {0x01, 0x02, 0x03}; EnqueueAclUpEnd(queue_up_end1, packet); Loading Loading @@ -333,17 +327,15 @@ TEST_F(RoundRobinSchedulerTest, buffer_packet_intervally) { TEST_F(RoundRobinSchedulerTest, send_fragments_without_interval) { uint16_t handle = 0x01; uint16_t le_handle = 0x02; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> le_connection_queue{10}; auto connection_queue = std::make_shared<AclConnection::Queue>(10); auto le_connection_queue = std::make_shared<AclConnection::Queue>(10); AclConnection::QueueDownEnd* queue_down_end = connection_queue.GetDownEnd(); AclConnection::QueueDownEnd* le_queue_down_end = le_connection_queue.GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue_down_end); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_queue_down_end); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue); SetPacketFuture(5); AclConnection::QueueUpEnd* queue_up_end = connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd(); std::vector<uint8_t> packet(controller_->hci_mtu_, 0xff); std::vector<uint8_t> packet_part1(controller_->hci_mtu_, 0xff); std::vector<uint8_t> packet_part2 = {0x03, 0x02, 0x01}; Loading Loading
system/gd/hci/acl_manager.cc +42 −103 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ #include "hci/acl_manager.h" #include <atomic> #include <future> #include <queue> #include <set> #include <utility> Loading Loading @@ -67,41 +66,29 @@ uint16_t GetL2capPduSize(AclPacketView packet) { } // namespace struct AclManager::acl_connection { acl_connection(AddressWithType address_with_type, os::Handler* handler) : address_with_type_(address_with_type), handler_(handler) {} struct assembler { assembler(AddressWithType address_with_type, AclConnection::QueueDownEnd* down_end, os::Handler* handler) : address_with_type_(address_with_type), down_end_(down_end), handler_(handler) {} AddressWithType address_with_type_; AclConnection::QueueDownEnd* down_end_; os::Handler* handler_; std::unique_ptr<AclConnection::Queue> queue_ = std::make_unique<AclConnection::Queue>(10); bool is_disconnected_ = false; ErrorCode disconnect_reason_; os::Handler* command_complete_handler_ = nullptr; os::Handler* disconnect_handler_ = nullptr; ConnectionManagementCallbacks* command_complete_callbacks_ = nullptr; os::Handler* le_command_complete_handler_ = nullptr; LeConnectionManagementCallbacks* le_command_complete_callbacks_ = nullptr; common::OnceCallback<void(ErrorCode)> on_disconnect_callback_; // For LE Connection parameter update from L2CAP common::OnceCallback<void(ErrorCode)> on_connection_update_complete_callback_; os::Handler* on_connection_update_complete_callback_handler_ = nullptr; PacketViewForRecombination recombination_stage_{std::make_shared<std::vector<uint8_t>>()}; int remaining_sdu_continuation_packet_size_ = 0; std::atomic_bool enqueue_registered_ = false; std::shared_ptr<std::atomic_bool> enqueue_registered_ = std::make_shared<std::atomic_bool>(false); std::queue<packet::PacketView<kLittleEndian>> incoming_queue_; ~acl_connection() { if (enqueue_registered_.exchange(false)) { queue_->GetDownEnd()->UnregisterEnqueue(); ~assembler() { if (enqueue_registered_->exchange(false)) { down_end_->UnregisterEnqueue(); } queue_.reset(); } // Invoked from some external Queue Reactable context std::unique_ptr<packet::PacketView<kLittleEndian>> on_incoming_data_ready() { std::unique_ptr<packet::PacketView<kLittleEndian>> on_le_incoming_data_ready() { auto packet = incoming_queue_.front(); incoming_queue_.pop(); if (incoming_queue_.empty() && enqueue_registered_.exchange(false)) { queue_->GetDownEnd()->UnregisterEnqueue(); if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) { down_end_->UnregisterEnqueue(); } return std::make_unique<PacketView<kLittleEndian>>(packet); } Loading Loading @@ -147,11 +134,30 @@ struct AclManager::acl_connection { } incoming_queue_.push(payload); if (!enqueue_registered_.exchange(true)) { queue_->GetDownEnd()->RegisterEnqueue( handler_, common::Bind(&AclManager::acl_connection::on_incoming_data_ready, common::Unretained(this))); if (!enqueue_registered_->exchange(true)) { down_end_->RegisterEnqueue(handler_, common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this))); } } }; struct AclManager::acl_connection { acl_connection(AddressWithType address_with_type, os::Handler* handler) : queue_(std::make_shared<AclConnection::Queue>(10)), assembler_(address_with_type, queue_->GetDownEnd(), handler), address_with_type_(address_with_type), handler_(handler) {} std::shared_ptr<AclConnection::Queue> queue_; struct assembler assembler_; AddressWithType address_with_type_; os::Handler* handler_; bool is_disconnected_ = false; ErrorCode disconnect_reason_; os::Handler* command_complete_handler_ = nullptr; os::Handler* disconnect_handler_ = nullptr; ConnectionManagementCallbacks* command_complete_callbacks_ = nullptr; common::OnceCallback<void(ErrorCode)> on_disconnect_callback_; ~acl_connection() {} void call_disconnect_callback() { disconnect_handler_->Post(BindOnce(std::move(on_disconnect_callback_), disconnect_reason_)); Loading @@ -160,22 +166,12 @@ struct AclManager::acl_connection { struct AclManager::le_acl_connection { le_acl_connection(AddressWithType address_with_type, os::Handler* handler) : address_with_type_(address_with_type), handler_(handler) {} AddressWithType address_with_type_; : queue_(std::make_shared<AclConnection::Queue>(10)), assembler_(address_with_type, queue_->GetDownEnd(), handler), handler_(handler) {} std::shared_ptr<AclConnection::Queue> queue_; struct assembler assembler_; LeConnectionManagementCallbacks* le_connection_management_callbacks_; os::Handler* handler_; std::shared_ptr<AclConnection::Queue> queue_ = std::make_unique<AclConnection::Queue>(10); PacketViewForRecombination recombination_stage_{std::make_shared<std::vector<uint8_t>>()}; int remaining_sdu_continuation_packet_size_ = 0; std::shared_ptr<std::atomic_bool> enqueue_registered_ = std::make_shared<std::atomic_bool>(false); std::queue<packet::PacketView<kLittleEndian>> incoming_queue_; ~le_acl_connection() { if (enqueue_registered_->exchange(false)) { queue_->GetDownEnd()->UnregisterEnqueue(); } queue_.reset(); } AclConnection::QueueDownEnd* GetDownEnd() { return queue_->GetDownEnd(); Loading @@ -184,63 +180,6 @@ struct AclManager::le_acl_connection { void SetLeConnectionManagementCallbacks(LeConnectionManagementCallbacks* callbacks) { le_connection_management_callbacks_ = callbacks; } // Invoked from some external Queue Reactable context std::unique_ptr<packet::PacketView<kLittleEndian>> on_le_incoming_data_ready() { auto packet = incoming_queue_.front(); incoming_queue_.pop(); if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) { queue_->GetDownEnd()->UnregisterEnqueue(); } return std::make_unique<PacketView<kLittleEndian>>(packet); } void on_incoming_packet(AclPacketView packet) { // TODO: What happens if the connection is stalled and fills up? PacketView<kLittleEndian> payload = packet.GetPayload(); auto payload_size = payload.size(); auto packet_boundary_flag = packet.GetPacketBoundaryFlag(); if (packet_boundary_flag == PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) { LOG_ERROR("Controller is not allowed to send FIRST_NON_AUTOMATICALLY_FLUSHABLE to host except loopback mode"); return; } if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) { if (remaining_sdu_continuation_packet_size_ < payload_size) { LOG_WARN("Remote sent unexpected L2CAP PDU. Drop the entire L2CAP PDU"); recombination_stage_ = PacketViewForRecombination(std::make_shared<std::vector<uint8_t>>()); remaining_sdu_continuation_packet_size_ = 0; return; } remaining_sdu_continuation_packet_size_ -= payload_size; recombination_stage_.AppendPacketView(payload); if (remaining_sdu_continuation_packet_size_ != 0) { return; } else { payload = recombination_stage_; recombination_stage_ = PacketViewForRecombination(std::make_shared<std::vector<uint8_t>>()); } } else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) { if (recombination_stage_.size() > 0) { LOG_ERROR("Controller sent a starting packet without finishing previous packet. Drop previous one."); } auto l2cap_pdu_size = GetL2capPduSize(packet); remaining_sdu_continuation_packet_size_ = l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize); if (remaining_sdu_continuation_packet_size_ > 0) { recombination_stage_ = payload; return; } } if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) { LOG_ERROR("Dropping packet due to congestion from remote:%s", address_with_type_.ToString().c_str()); return; } incoming_queue_.push(payload); if (!enqueue_registered_->exchange(true)) { queue_->GetDownEnd()->RegisterEnqueue( handler_, common::Bind(&AclManager::le_acl_connection::on_le_incoming_data_ready, common::Unretained(this))); } } }; class LeAclConnectionTracker : public LeConnectionManagementCallbacks { Loading Loading @@ -431,14 +370,14 @@ struct AclManager::impl : public security::ISecurityManagerListener { } auto connection_pair = acl_connections_.find(handle); if (connection_pair != acl_connections_.end()) { connection_pair->second.on_incoming_packet(*packet); connection_pair->second.assembler_.on_incoming_packet(*packet); } else { auto le_connection_pair = le_acl_connections_.find(handle); if (le_connection_pair == le_acl_connections_.end()) { LOG_INFO("Dropping packet of size %zu to unknown connection 0x%0hx", packet->size(), handle); return; } le_connection_pair->second.on_incoming_packet(*packet); le_connection_pair->second.assembler_.on_incoming_packet(*packet); } } Loading Loading @@ -514,7 +453,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { std::move(connection_proxy))); hci_layer_->GetHciHandler()->Post( common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), RoundRobinScheduler::ConnectionType::LE, handle, connection.queue_->GetDownEnd())); RoundRobinScheduler::ConnectionType::LE, handle, connection.queue_)); } void on_le_enhanced_connection_complete(LeMetaEventView packet) { Loading Loading @@ -543,7 +482,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { auto& connection = check_and_get_le_connection(handle); hci_layer_->GetHciHandler()->Post( common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), RoundRobinScheduler::ConnectionType::LE, handle, connection.queue_->GetDownEnd())); RoundRobinScheduler::ConnectionType::LE, handle, connection.queue_)); auto role = connection_complete.GetRole(); auto do_disconnect = common::BindOnce(&impl::handle_disconnect, common::Unretained(this), handle); std::unique_ptr<LeAclConnection> connection_proxy( Loading Loading @@ -574,7 +513,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { auto& connection = check_and_get_connection(handle); hci_layer_->GetHciHandler()->Post(common::BindOnce( &RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), RoundRobinScheduler::ConnectionType::CLASSIC, handle, check_and_get_connection(handle).queue_->GetDownEnd())); RoundRobinScheduler::ConnectionType::CLASSIC, handle, check_and_get_connection(handle).queue_)); std::unique_ptr<ClassicAclConnection> connection_proxy( new ClassicAclConnection(&acl_manager_, connection.queue_->GetUpEnd(), acl_connection_interface_, handle, address, Role::MASTER /* TODO: Did we connect? */)); Loading
system/gd/hci/round_robin_scheduler.cc +6 −6 Original line number Diff line number Diff line Loading @@ -40,8 +40,8 @@ RoundRobinScheduler::~RoundRobinScheduler() { } void RoundRobinScheduler::Register(ConnectionType connection_type, uint16_t handle, AclConnection::QueueDownEnd* queue_down_end) { acl_queue_handler acl_queue_handler = {connection_type, queue_down_end, false, 0, false}; std::shared_ptr<AclConnection::Queue> queue) { acl_queue_handler acl_queue_handler = {connection_type, std::move(queue), false, 0, false}; acl_queue_handlers_.insert(std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler)); if (fragments_to_send_.size() == 0) { start_round_robin(); Loading @@ -53,7 +53,7 @@ void RoundRobinScheduler::Unregister(uint16_t handle) { auto acl_queue_handler = acl_queue_handlers_.find(handle)->second; if (acl_queue_handler.dequeue_is_registered_) { acl_queue_handler.dequeue_is_registered_ = false; acl_queue_handler.queue_down_end_->UnregisterDequeue(); acl_queue_handler.queue_->GetDownEnd()->UnregisterDequeue(); } acl_queue_handlers_.erase(handle); starting_point_ = acl_queue_handlers_.begin(); Loading Loading @@ -101,7 +101,7 @@ void RoundRobinScheduler::start_round_robin() { le_acl_packet_credits_ == 0 && acl_queue_handler->second.connection_type_ == ConnectionType::LE; if (!acl_queue_handler->second.dequeue_is_registered_ && !classic_buffer_full && !le_buffer_full) { acl_queue_handler->second.dequeue_is_registered_ = true; acl_queue_handler->second.queue_down_end_->RegisterDequeue( acl_queue_handler->second.queue_->GetDownEnd()->RegisterDequeue( handler_, common::Bind(&RoundRobinScheduler::buffer_packet, common::Unretained(this), acl_queue_handler)); } acl_queue_handler = std::next(acl_queue_handler); Loading @@ -117,7 +117,7 @@ void RoundRobinScheduler::buffer_packet(std::map<uint16_t, acl_queue_handler>::i BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT; // Wrap packet and enqueue it uint16_t handle = acl_queue_handler->first; auto packet = acl_queue_handler->second.queue_down_end_->TryDequeue(); auto packet = acl_queue_handler->second.queue_->GetDownEnd()->TryDequeue(); ASSERT(packet != nullptr); ConnectionType connection_type = acl_queue_handler->second.connection_type_; Loading Loading @@ -148,7 +148,7 @@ void RoundRobinScheduler::unregister_all_connections() { acl_queue_handler = std::next(acl_queue_handler)) { if (acl_queue_handler->second.dequeue_is_registered_) { acl_queue_handler->second.dequeue_is_registered_ = false; acl_queue_handler->second.queue_down_end_->UnregisterDequeue(); acl_queue_handler->second.queue_->GetDownEnd()->UnregisterDequeue(); } } } Loading
system/gd/hci/round_robin_scheduler.h +2 −2 Original line number Diff line number Diff line Loading @@ -37,13 +37,13 @@ class RoundRobinScheduler { struct acl_queue_handler { ConnectionType connection_type_; AclConnection::QueueDownEnd* queue_down_end_; std::shared_ptr<AclConnection::Queue> queue_; bool dequeue_is_registered_ = false; uint16_t number_of_sent_packets_ = 0; // Track credits bool is_disconnected_ = false; }; void Register(ConnectionType connection_type, uint16_t handle, AclConnection::QueueDownEnd* queue_down_end); void Register(ConnectionType connection_type, uint16_t handle, std::shared_ptr<AclConnection::Queue> queue); void Unregister(uint16_t handle); void SetDisconnect(uint16_t handle); uint16_t GetCredits(); Loading
system/gd/hci/round_robin_scheduler_test.cc +35 −43 Original line number Diff line number Diff line Loading @@ -15,9 +15,12 @@ */ #include "hci/round_robin_scheduler.h" #include <gtest/gtest.h> #include "common/bidi_queue.h" #include "common/callback.h" #include "hci/acl_manager.h" #include "hci/controller.h" #include "hci/hci_packets.h" #include "os/handler.h" Loading Loading @@ -172,20 +175,18 @@ TEST_F(RoundRobinSchedulerTest, startup_teardown) {} TEST_F(RoundRobinSchedulerTest, register_unregister_connection) { uint16_t handle = 0x01; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{10}; round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue.GetDownEnd()); auto connection_queue = std::make_shared<AclConnection::Queue>(10); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); round_robin_scheduler_->Unregister(handle); } TEST_F(RoundRobinSchedulerTest, buffer_packet) { uint16_t handle = 0x01; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{10}; AclConnection::QueueDownEnd* queue_down_end = connection_queue.GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue_down_end); auto connection_queue = std::make_shared<AclConnection::Queue>(10); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); SetPacketFuture(2); AclConnection::QueueUpEnd* queue_up_end = connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); std::vector<uint8_t> packet1 = {0x01, 0x02, 0x03}; std::vector<uint8_t> packet2 = {0x04, 0x05, 0x06}; EnqueueAclUpEnd(queue_up_end, packet1); Loading @@ -202,17 +203,15 @@ TEST_F(RoundRobinSchedulerTest, buffer_packet) { TEST_F(RoundRobinSchedulerTest, buffer_packet_from_two_connections) { uint16_t handle = 0x01; uint16_t le_handle = 0x02; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> le_connection_queue{10}; auto connection_queue = std::make_shared<AclConnection::Queue>(10); auto le_connection_queue = std::make_shared<AclConnection::Queue>(10); AclConnection::QueueDownEnd* queue_down_end = connection_queue.GetDownEnd(); AclConnection::QueueDownEnd* le_queue_down_end = le_connection_queue.GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue_down_end); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_queue_down_end); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue); SetPacketFuture(2); AclConnection::QueueUpEnd* queue_up_end = connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd(); std::vector<uint8_t> packet = {0x01, 0x02, 0x03}; std::vector<uint8_t> le_packet = {0x04, 0x05, 0x06}; EnqueueAclUpEnd(le_queue_up_end, le_packet); Loading @@ -230,12 +229,11 @@ TEST_F(RoundRobinSchedulerTest, buffer_packet_from_two_connections) { TEST_F(RoundRobinSchedulerTest, do_not_register_when_credits_is_zero) { uint16_t handle = 0x01; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{15}; AclConnection::QueueDownEnd* queue_down_end = connection_queue.GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue_down_end); auto connection_queue = std::make_shared<AclConnection::Queue>(15); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); SetPacketFuture(10); AclConnection::QueueUpEnd* queue_up_end = connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); for (uint8_t i = 0; i < 15; i++) { std::vector<uint8_t> packet = {0x01, 0x02, 0x03, i}; EnqueueAclUpEnd(queue_up_end, packet); Loading Loading @@ -273,25 +271,21 @@ TEST_F(RoundRobinSchedulerTest, buffer_packet_intervally) { uint16_t handle2 = 0x02; uint16_t le_handle1 = 0x03; uint16_t le_handle2 = 0x04; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue1{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue2{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> le_connection_queue1{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> le_connection_queue2{10}; AclConnection::QueueDownEnd* queue_down_end1 = connection_queue1.GetDownEnd(); AclConnection::QueueDownEnd* queue_down_end2 = connection_queue2.GetDownEnd(); AclConnection::QueueDownEnd* le_queue_down_end1 = le_connection_queue1.GetDownEnd(); AclConnection::QueueDownEnd* le_queue_down_end2 = le_connection_queue2.GetDownEnd(); auto connection_queue1 = std::make_shared<AclConnection::Queue>(10); auto connection_queue2 = std::make_shared<AclConnection::Queue>(10); auto le_connection_queue1 = std::make_shared<AclConnection::Queue>(10); auto le_connection_queue2 = std::make_shared<AclConnection::Queue>(10); SetPacketFuture(18); AclConnection::QueueUpEnd* queue_up_end1 = connection_queue1.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end2 = connection_queue2.GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end1 = le_connection_queue1.GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end2 = le_connection_queue2.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end1 = connection_queue1->GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end2 = connection_queue2->GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end1 = le_connection_queue1->GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end2 = le_connection_queue2->GetUpEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle1, queue_down_end1); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle2, queue_down_end2); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle1, le_queue_down_end1); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle2, le_queue_down_end2); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle1, connection_queue1); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle2, connection_queue2); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle1, le_connection_queue1); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle2, le_connection_queue2); std::vector<uint8_t> packet = {0x01, 0x02, 0x03}; EnqueueAclUpEnd(queue_up_end1, packet); Loading Loading @@ -333,17 +327,15 @@ TEST_F(RoundRobinSchedulerTest, buffer_packet_intervally) { TEST_F(RoundRobinSchedulerTest, send_fragments_without_interval) { uint16_t handle = 0x01; uint16_t le_handle = 0x02; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> connection_queue{10}; BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> le_connection_queue{10}; auto connection_queue = std::make_shared<AclConnection::Queue>(10); auto le_connection_queue = std::make_shared<AclConnection::Queue>(10); AclConnection::QueueDownEnd* queue_down_end = connection_queue.GetDownEnd(); AclConnection::QueueDownEnd* le_queue_down_end = le_connection_queue.GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue_down_end); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_queue_down_end); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue); SetPacketFuture(5); AclConnection::QueueUpEnd* queue_up_end = connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue.GetUpEnd(); AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd(); std::vector<uint8_t> packet(controller_->hci_mtu_, 0xff); std::vector<uint8_t> packet_part1(controller_->hci_mtu_, 0xff); std::vector<uint8_t> packet_part2 = {0x03, 0x02, 0x01}; Loading