From f8ce1d5060145c49e11d7ba28c42e0e10c002fd5 Mon Sep 17 00:00:00 2001 From: Henri Chataing Date: Fri, 17 Oct 2025 13:18:49 -0700 Subject: [PATCH 1/2] Sync with aosp main Synchronized to tools/rootcanal commit fc1283d0d8bb5bf7939d870cf62cd59346c697db Changelist: - LeController: Remove Br-Edr specific methods and fields - BrEdrController: Remove LE specific methods and fields - model/controller: Specialize the implementation of dual HCI commands - model/controller: Specialize implementations of IncomingPacket - Fix a problem with older version of C++ building acl_connection_handler - model/controller: Clone LinkLayerController - DualModeController: Split the link layer controller - AclConnectionHandler: Allocate connection handles in ranges by type - AclConnectionHandle: Cleanup GetScoHandle - model/controller: Apply clang-format - LeAclConnection: Track connection parameters - LinkLayerController: Fix use-after-free on LeAclConnection reference - Silently disconnect all established connections on Reset - AclConnectionHandler: Implement separate LeAclConnection type - AclConnectionHandler: Remove helper GetAddressSafe - AclConnectionHandler: Remove remaining connection helpers - LinkLayerController: Replace calls to GetHandleOnlyAddress - AclConnectionHandler: Remove helpers to get address by handle - LinkLayerController: Specialize ReadRemoteVersionInformation, HandleAcl - LinkLayerController: Specialize SendLeCommandToRemove, ReadRssi - LinkLayerController: Harden calls to HasHandle, GetAclConnection - LinkLayerController: Restructure Disconnect() to process connections by type - LinkLayerController: Add connection parameter for LL commands - AclConnection: Add const handle member - LinkLayerController: Harden the implementation of IncomingLeConnectComplete - LinkLayerController: Split IncomingPacket according to phy type - Move the page scan substate information to link layer controller - Remove pass-through getters from AclConnectionHandler - Remove unused AclConnectionHandler getters - RootCanal: Remove pending LE-ACL connection handling from AclConnectionHandler --- BUILD | 18 +- model/controller/acl_connection.cc | 13 +- model/controller/acl_connection.h | 44 +- model/controller/acl_connection_handler.cc | 322 +-- model/controller/acl_connection_handler.h | 92 +- model/controller/bredr_controller.cc | 1980 +++++++++++++ model/controller/bredr_controller.h | 484 ++++ model/controller/connection_handle.h | 76 + model/controller/controller_properties.cc | 220 +- model/controller/dual_mode_controller.cc | 441 +-- model/controller/dual_mode_controller.h | 6 +- model/controller/ffi.cc | 6 +- model/controller/le_acl_connection.cc | 67 + model/controller/le_acl_connection.h | 110 + model/controller/le_advertiser.cc | 52 +- ...k_layer_controller.cc => le_controller.cc} | 2451 +++-------------- ...ink_layer_controller.h => le_controller.h} | 305 +- model/controller/vendor_commands/le_apcf.cc | 56 +- model/devices/hci_device.cc | 4 +- packets/BUILD | 4 +- .../{bredr_bb.pdl => bredr_bb_packets.pdl} | 0 rust/Cargo.toml | 1 - rust/build.rs | 4 +- test/LL/CIS/PER/BV_01_C.py | 3 +- test/LL/CON_/CEN/BV_41_C.py | 8 +- test/LL/CON_/CEN/BV_43_C.py | 8 +- test/LL/CON_/PER/BV_40_C.py | 8 +- test/LL/CON_/PER/BV_42_C.py | 8 +- test/LL/DDI/ADV/BV_06_C.py | 8 +- test/LL/DDI/ADV/BV_07_C.py | 8 +- test/LL/DDI/ADV/BV_09_C.py | 39 +- test/LL/DDI/ADV/BV_11_C.py | 8 +- test/LL/DDI/ADV/BV_19_C.py | 8 +- test/LMP/LIH/BV_01_C.py | 16 +- test/LMP/LIH/BV_02_C.py | 19 +- test/LMP/LIH/BV_142_C.py | 16 +- test/LMP/LIH/BV_143_C.py | 16 +- test/LMP/LIH/BV_144_C.py | 8 +- test/LMP/LIH/BV_149_C.py | 16 +- test/LMP/LIH/BV_78_C.py | 8 +- test/LMP/LIH/BV_79_C.py | 8 +- test/LMP/page_collision.py | 8 +- ...e_add_device_to_filter_accept_list_test.cc | 4 +- ...device_to_periodic_advertiser_list_test.cc | 4 +- .../le_add_device_to_resolving_list_test.cc | 4 +- .../le/le_clear_filter_accept_list_test.cc | 4 +- .../le_clear_periodic_advertiser_list_test.cc | 4 +- .../le/le_clear_resolving_list_test.cc | 4 +- .../le/le_create_connection_cancel_test.cc | 4 +- .../le/le_create_connection_test.cc | 4 +- .../le/le_extended_create_connection_test.cc | 4 +- ...dic_advertising_create_sync_cancel_test.cc | 4 +- ...e_periodic_advertising_create_sync_test.cc | 4 +- ...ove_device_from_filter_accept_list_test.cc | 4 +- ...vice_from_periodic_advertiser_list_test.cc | 4 +- ..._remove_device_from_resolving_list_test.cc | 4 +- .../le/le_scanning_filter_duplicates_test.cc | 4 +- .../le_set_address_resolution_enable_test.cc | 4 +- .../le/le_set_advertising_enable_test.cc | 4 +- .../le/le_set_advertising_parameters_test.cc | 4 +- .../le_set_extended_advertising_data_test.cc | 4 +- ...le_set_extended_advertising_enable_test.cc | 4 +- ...et_extended_advertising_parameters_test.cc | 4 +- .../le/le_set_extended_scan_enable_test.cc | 4 +- .../le_set_extended_scan_parameters_test.cc | 4 +- ...le_set_extended_scan_response_data_test.cc | 4 +- .../le_set_periodic_advertising_data_test.cc | 4 +- ...le_set_periodic_advertising_enable_test.cc | 4 +- ...et_periodic_advertising_parameters_test.cc | 4 +- .../le/le_set_random_address_test.cc | 4 +- test/controller/le/le_set_scan_enable_test.cc | 4 +- .../le/le_set_scan_parameters_test.cc | 4 +- test/controller/le/rpa_generation_test.cc | 6 +- test/controller/le/test_helpers.h | 2 +- 74 files changed, 3994 insertions(+), 3111 deletions(-) create mode 100644 model/controller/bredr_controller.cc create mode 100644 model/controller/bredr_controller.h create mode 100644 model/controller/connection_handle.h create mode 100644 model/controller/le_acl_connection.cc create mode 100644 model/controller/le_acl_connection.h rename model/controller/{link_layer_controller.cc => le_controller.cc} (65%) rename model/controller/{link_layer_controller.h => le_controller.h} (74%) rename packets/{bredr_bb.pdl => bredr_bb_packets.pdl} (100%) diff --git a/BUILD b/BUILD index be0631f..df20047 100644 --- a/BUILD +++ b/BUILD @@ -48,14 +48,19 @@ cc_binary( "model/controller/acl_connection.h", "model/controller/acl_connection_handler.cc", "model/controller/acl_connection_handler.h", + "model/controller/bredr_controller.cc", + "model/controller/bredr_controller.h", + "model/controller/connection_handle.h", "model/controller/controller_properties.cc", "model/controller/controller_properties.h", "model/controller/dual_mode_controller.cc", "model/controller/dual_mode_controller.h", + "model/controller/le_acl_connection.cc", + "model/controller/le_acl_connection.h", "model/controller/le_advertiser.cc", "model/controller/le_advertiser.h", - "model/controller/link_layer_controller.cc", - "model/controller/link_layer_controller.h", + "model/controller/le_controller.cc", + "model/controller/le_controller.h", "model/controller/sco_connection.cc", "model/controller/sco_connection.h", "model/controller/vendor_commands/csr.h", @@ -117,14 +122,19 @@ cc_binary( "model/controller/acl_connection.h", "model/controller/acl_connection_handler.cc", "model/controller/acl_connection_handler.h", + "model/controller/bredr_controller.cc", + "model/controller/bredr_controller.h", + "model/controller/connection_handle.h", "model/controller/controller_properties.cc", "model/controller/controller_properties.h", "model/controller/dual_mode_controller.cc", "model/controller/dual_mode_controller.h", + "model/controller/le_acl_connection.cc", + "model/controller/le_acl_connection.h", "model/controller/le_advertiser.cc", "model/controller/le_advertiser.h", - "model/controller/link_layer_controller.cc", - "model/controller/link_layer_controller.h", + "model/controller/le_controller.cc", + "model/controller/le_controller.h", "model/controller/sco_connection.cc", "model/controller/sco_connection.h", "model/controller/vendor_commands/csr.h", diff --git a/model/controller/acl_connection.cc b/model/controller/acl_connection.cc index 3cb4172..71148b9 100644 --- a/model/controller/acl_connection.cc +++ b/model/controller/acl_connection.cc @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Android Open Source Project + * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,16 +20,13 @@ #include #include "packets/hci_packets.h" -#include "phy.h" namespace rootcanal { -AclConnection::AclConnection(AddressWithType address, AddressWithType own_address, - AddressWithType resolved_address, Phy::Type phy_type, +AclConnection::AclConnection(uint16_t handle, Address address, Address own_address, bluetooth::hci::Role role) - : address_(address), - own_address_(own_address), - resolved_address_(resolved_address), - type_(phy_type), + : handle(handle), + address(address), + own_address(own_address), role_(role), last_packet_timestamp_(std::chrono::steady_clock::now()), timeout_(std::chrono::seconds(3)) {} diff --git a/model/controller/acl_connection.h b/model/controller/acl_connection.h index 793f9e8..67e366c 100644 --- a/model/controller/acl_connection.h +++ b/model/controller/acl_connection.h @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Android Open Source Project + * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,13 +19,12 @@ #include #include -#include "hci/address_with_type.h" +#include "hci/address.h" #include "packets/hci_packets.h" -#include "phy.h" namespace rootcanal { -using ::bluetooth::hci::AddressWithType; +using bluetooth::hci::Address; enum AclConnectionState { kActiveMode, @@ -33,19 +32,15 @@ enum AclConnectionState { kSniffMode, }; -// Model the connection of a device to the controller. -class AclConnection { +// Model the BR/EDR connection of a device to the controller. +class AclConnection final { public: - AclConnection(AddressWithType address, AddressWithType own_address, - AddressWithType resolved_address, Phy::Type phy_type, bluetooth::hci::Role role); + const uint16_t handle; + const Address address; + const Address own_address; - virtual ~AclConnection() = default; - - Phy::Type GetPhyType() const { return type_; } - - AddressWithType GetAddress() const { return address_; } - AddressWithType GetOwnAddress() const { return own_address_; } - AddressWithType GetResolvedAddress() const { return resolved_address_; } + AclConnection(uint16_t handle, Address address, Address own_address, bluetooth::hci::Role role); + ~AclConnection() = default; void Encrypt(); bool IsEncrypted() const; @@ -70,21 +65,7 @@ class AclConnection { bool IsNearExpiring() const; bool HasExpired() const; - // LE-ACL state. - void InitiatePhyUpdate() { initiated_phy_update_ = true; } - void PhyUpdateComplete() { initiated_phy_update_ = false; } - bool InitiatedPhyUpdate() const { return initiated_phy_update_; } - bluetooth::hci::PhyType GetTxPhy() const { return tx_phy_; } - bluetooth::hci::PhyType GetRxPhy() const { return rx_phy_; } - void SetTxPhy(bluetooth::hci::PhyType phy) { tx_phy_ = phy; } - void SetRxPhy(bluetooth::hci::PhyType phy) { rx_phy_ = phy; } - private: - AddressWithType address_; - AddressWithType own_address_; - AddressWithType resolved_address_; - Phy::Type type_{Phy::Type::BR_EDR}; - // Reports the RSSI measured for the last packet received on // this connection. int8_t rssi_{0}; @@ -96,11 +77,6 @@ class AclConnection { bluetooth::hci::Role role_{bluetooth::hci::Role::CENTRAL}; std::chrono::steady_clock::time_point last_packet_timestamp_; std::chrono::steady_clock::duration timeout_; - - // LE-ACL state. - bluetooth::hci::PhyType tx_phy_{bluetooth::hci::PhyType::LE_1M}; - bluetooth::hci::PhyType rx_phy_{bluetooth::hci::PhyType::LE_1M}; - bool initiated_phy_update_{false}; }; } // namespace rootcanal diff --git a/model/controller/acl_connection_handler.cc b/model/controller/acl_connection_handler.cc index bdcd1f7..65bc303 100644 --- a/model/controller/acl_connection_handler.cc +++ b/model/controller/acl_connection_handler.cc @@ -27,140 +27,77 @@ #include "hci/address_with_type.h" #include "log.h" #include "model/controller/acl_connection.h" +#include "model/controller/le_acl_connection.h" #include "model/controller/sco_connection.h" #include "packets/hci_packets.h" -#include "phy.h" namespace rootcanal { using ::bluetooth::hci::Address; -using ::bluetooth::hci::AddressType; using ::bluetooth::hci::AddressWithType; -void AclConnectionHandler::Reset(std::function stopStream) { - // Leave no dangling periodic task. - for (auto& [_, sco_connection] : sco_connections_) { - sco_connection.StopStream(stopStream); +template +static uint16_t GetUnusedHandle(std::unordered_map const& connections, + uint16_t range_start, uint16_t range_end, uint16_t& last) { + while (connections.find(last) != connections.end()) { + if (++last > range_end) { + last = range_start; + } } - sco_connections_.clear(); - acl_connections_.clear(); -} - -bool AclConnectionHandler::HasHandle(uint16_t handle) const { - return acl_connections_.count(handle) != 0; -} - -bool AclConnectionHandler::HasScoHandle(uint16_t handle) const { - return sco_connections_.count(handle) != 0; -} - -uint16_t AclConnectionHandler::GetUnusedHandle() { - // Keep a reserved range of handles for CIS connections implemented - // in the rust module. - while (HasHandle(last_handle_) || HasScoHandle(last_handle_) || - (last_handle_ >= kCisHandleRangeStart && last_handle_ < kCisHandleRangeEnd)) { - last_handle_ = (last_handle_ + 1) % kReservedHandle; + uint16_t unused_handle = last; + if (++last > range_end) { + last = range_start; } - uint16_t unused_handle = last_handle_; - last_handle_ = (last_handle_ + 1) % kReservedHandle; + return unused_handle; } -bool AclConnectionHandler::CreatePendingConnection(Address addr, bool authenticate_on_connect, - bool allow_role_switch) { - if (classic_connection_pending_ || GetAclConnectionHandle(addr).has_value()) { - return false; +void AclConnectionHandler::Reset(std::function stopStream) { + // Leave no dangling periodic task. + for (auto& [_, sco_connection] : sco_connections_) { + sco_connection.StopStream(stopStream); } - classic_connection_pending_ = true; - pending_connection_address_ = addr; - authenticate_pending_classic_connection_ = authenticate_on_connect; - pending_classic_connection_allow_role_switch_ = allow_role_switch; - return true; -} -bool AclConnectionHandler::HasPendingConnection(Address addr) const { - return classic_connection_pending_ && pending_connection_address_ == addr; -} - -bool AclConnectionHandler::AuthenticatePendingConnection() const { - return authenticate_pending_classic_connection_; -} + sco_connections_.clear(); + acl_connections_.clear(); + le_acl_connections_.clear(); -bool AclConnectionHandler::CancelPendingConnection(Address addr) { - if (!classic_connection_pending_ || pending_connection_address_ != addr) { - return false; - } - classic_connection_pending_ = false; - pending_connection_address_ = Address::kEmpty; - pending_le_connection_resolved_address_ = AddressWithType(); - return true; + last_acl_handle_ = ConnectionHandle::kAclRangeStart; + last_sco_handle_ = ConnectionHandle::kScoRangeStart; + last_le_acl_handle_ = ConnectionHandle::kLeAclRangeStart; } -bool AclConnectionHandler::CreatePendingLeConnection(AddressWithType peer, - AddressWithType resolved_peer, - AddressWithType local_address) { - for (auto pair : acl_connections_) { - auto connection = std::get(pair); - if (connection.GetAddress() == peer || connection.GetResolvedAddress() == resolved_peer) { - INFO("{}: {} is already connected", __func__, peer); - if (connection.GetResolvedAddress() == resolved_peer) { - INFO("{}: allowing a second connection with {}", __func__, resolved_peer); - } else { - return false; - } - } - } - if (le_connection_pending_) { - INFO("{}: connection already pending", __func__); - return false; - } - le_connection_pending_ = true; - pending_le_connection_address_ = peer; - pending_le_connection_own_address_ = local_address; - pending_le_connection_resolved_address_ = resolved_peer; - return true; +bool AclConnectionHandler::HasAclHandle(uint16_t handle) const { + return acl_connections_.count(handle) != 0; } -bool AclConnectionHandler::HasPendingLeConnection(AddressWithType addr) const { - return le_connection_pending_ && pending_le_connection_address_ == addr; +bool AclConnectionHandler::HasLeAclHandle(uint16_t handle) const { + return le_acl_connections_.count(handle) != 0; } -bool AclConnectionHandler::CancelPendingLeConnection(AddressWithType addr) { - if (!le_connection_pending_ || pending_le_connection_address_ != addr) { - return false; - } - le_connection_pending_ = false; - pending_le_connection_address_ = - AddressWithType{Address::kEmpty, AddressType::PUBLIC_DEVICE_ADDRESS}; - pending_le_connection_resolved_address_ = - AddressWithType{Address::kEmpty, AddressType::PUBLIC_DEVICE_ADDRESS}; - return true; +bool AclConnectionHandler::HasScoHandle(uint16_t handle) const { + return sco_connections_.count(handle) != 0; } -uint16_t AclConnectionHandler::CreateConnection(Address addr, Address own_addr, bool pending) { - if (!pending || CancelPendingConnection(addr)) { - uint16_t handle = GetUnusedHandle(); - acl_connections_.emplace( - handle, - AclConnection{AddressWithType{addr, AddressType::PUBLIC_DEVICE_ADDRESS}, - AddressWithType{own_addr, AddressType::PUBLIC_DEVICE_ADDRESS}, - AddressWithType(), Phy::Type::BR_EDR, bluetooth::hci::Role::CENTRAL}); - return handle; - } - return kReservedHandle; +uint16_t AclConnectionHandler::CreateConnection(Address addr, Address own_addr) { + uint16_t handle = GetUnusedHandle(acl_connections_, ConnectionHandle::kAclRangeStart, + ConnectionHandle::kAclRangeEnd, last_acl_handle_); + acl_connections_.emplace(handle, + AclConnection{handle, addr, own_addr, bluetooth::hci::Role::CENTRAL}); + return handle; } -uint16_t AclConnectionHandler::CreateLeConnection(AddressWithType addr, AddressWithType own_addr, - bluetooth::hci::Role role) { - AddressWithType resolved_peer = pending_le_connection_resolved_address_; - if (CancelPendingLeConnection(addr)) { - uint16_t handle = GetUnusedHandle(); - acl_connections_.emplace( - handle, AclConnection{addr, own_addr, resolved_peer, Phy::Type::LOW_ENERGY, role}); - return handle; - } - return kReservedHandle; +uint16_t AclConnectionHandler::CreateLeConnection(AddressWithType addr, + AddressWithType resolved_peer, + AddressWithType own_addr, + bluetooth::hci::Role role, + LeAclConnectionParameters connection_parameters) { + uint16_t handle = GetUnusedHandle(le_acl_connections_, ConnectionHandle::kLeAclRangeStart, + ConnectionHandle::kLeAclRangeEnd, last_le_acl_handle_); + le_acl_connections_.emplace(handle, LeAclConnection{handle, addr, own_addr, resolved_peer, role, + connection_parameters}); + return handle; } bool AclConnectionHandler::Disconnect(uint16_t handle, std::function stopStream) { @@ -169,40 +106,46 @@ bool AclConnectionHandler::Disconnect(uint16_t handle, std::function(pair).GetAddress() == addr) { - return std::get<0>(pair); +std::optional AclConnectionHandler::GetAclConnectionHandle( + bluetooth::hci::Address bd_addr) const { + for (auto const& [handle, connection] : acl_connections_) { + if (connection.address == bd_addr) { + return handle; } } - return kReservedHandle; + return {}; } -uint16_t AclConnectionHandler::GetHandleOnlyAddress(bluetooth::hci::Address addr) const { - for (auto pair : acl_connections_) { - if (std::get(pair).GetAddress().GetAddress() == addr) { - return std::get<0>(pair); +std::optional AclConnectionHandler::GetLeAclConnectionHandle( + bluetooth::hci::Address local_address, bluetooth::hci::Address remote_address) const { + for (auto const& [handle, connection] : le_acl_connections_) { + if (connection.address.GetAddress() == remote_address && + connection.own_address.GetAddress() == local_address) { + return handle; } } - return kReservedHandle; + return {}; } -std::optional AclConnectionHandler::GetAclConnectionHandle( - bluetooth::hci::Address bd_addr) const { - for (auto const& [handle, connection] : acl_connections_) { - if (connection.GetAddress().GetAddress() == bd_addr && - connection.GetPhyType() == Phy::Type::BR_EDR) { +std::optional AclConnectionHandler::GetScoConnectionHandle( + bluetooth::hci::Address addr) const { + for (auto const& [handle, connection] : sco_connections_) { + if (connection.GetAddress() == addr) { return handle; } } @@ -210,18 +153,13 @@ std::optional AclConnectionHandler::GetAclConnectionHandle( } AclConnection& AclConnectionHandler::GetAclConnection(uint16_t handle) { - ASSERT_LOG(HasHandle(handle), "Unknown handle %d", handle); + ASSERT_LOG(HasAclHandle(handle), "Unknown handle %d", handle); return acl_connections_.at(handle); } -AddressWithType AclConnectionHandler::GetAddress(uint16_t handle) const { - ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle); - return acl_connections_.at(handle).GetAddress(); -} - -std::optional AclConnectionHandler::GetAddressSafe(uint16_t handle) const { - return HasHandle(handle) ? acl_connections_.at(handle).GetAddress() - : std::optional(); +LeAclConnection& AclConnectionHandler::GetLeAclConnection(uint16_t handle) { + ASSERT_LOG(HasLeAclHandle(handle), "Unknown handle %d", handle); + return le_acl_connections_.at(handle); } Address AclConnectionHandler::GetScoAddress(uint16_t handle) const { @@ -229,68 +167,12 @@ Address AclConnectionHandler::GetScoAddress(uint16_t handle) const { return sco_connections_.at(handle).GetAddress(); } -AddressWithType AclConnectionHandler::GetOwnAddress(uint16_t handle) const { - ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle); - return acl_connections_.at(handle).GetOwnAddress(); -} - -AddressWithType AclConnectionHandler::GetResolvedAddress(uint16_t handle) const { - ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle); - return acl_connections_.at(handle).GetResolvedAddress(); -} - -void AclConnectionHandler::Encrypt(uint16_t handle) { - if (!HasHandle(handle)) { - return; - } - acl_connections_.at(handle).Encrypt(); -} - -bool AclConnectionHandler::IsEncrypted(uint16_t handle) const { - if (!HasHandle(handle)) { - return false; - } - return acl_connections_.at(handle).IsEncrypted(); -} - -void AclConnectionHandler::SetRssi(uint16_t handle, int8_t rssi) { - if (HasHandle(handle)) { - acl_connections_.at(handle).SetRssi(rssi); - } -} - -int8_t AclConnectionHandler::GetRssi(uint16_t handle) const { - return HasHandle(handle) ? acl_connections_.at(handle).GetRssi() : 0; -} - -Phy::Type AclConnectionHandler::GetPhyType(uint16_t handle) const { - if (!HasHandle(handle)) { - return Phy::Type::BR_EDR; - } - return acl_connections_.at(handle).GetPhyType(); -} - -uint16_t AclConnectionHandler::GetAclLinkPolicySettings(uint16_t handle) const { - return acl_connections_.at(handle).GetLinkPolicySettings(); -} - -void AclConnectionHandler::SetAclLinkPolicySettings(uint16_t handle, uint16_t settings) { - acl_connections_.at(handle).SetLinkPolicySettings(settings); -} - -bluetooth::hci::Role AclConnectionHandler::GetAclRole(uint16_t handle) const { - return acl_connections_.at(handle).GetRole(); -} - -void AclConnectionHandler::SetAclRole(uint16_t handle, bluetooth::hci::Role role) { - acl_connections_.at(handle).SetRole(role); -} - void AclConnectionHandler::CreateScoConnection(bluetooth::hci::Address addr, ScoConnectionParameters const& parameters, ScoState state, ScoDatapath datapath, bool legacy) { - uint16_t sco_handle = GetUnusedHandle(); - sco_connections_.emplace(sco_handle, ScoConnection(addr, parameters, state, datapath, legacy)); + uint16_t handle = GetUnusedHandle(sco_connections_, ConnectionHandle::kScoRangeStart, + ConnectionHandle::kScoRangeEnd, last_sco_handle_); + sco_connections_.emplace(handle, ScoConnection(addr, parameters, state, datapath, legacy)); } bool AclConnectionHandler::HasPendingScoConnection(bluetooth::hci::Address addr) const { @@ -362,15 +244,6 @@ bool AclConnectionHandler::AcceptPendingScoConnection(bluetooth::hci::Address ad return false; } -uint16_t AclConnectionHandler::GetScoHandle(bluetooth::hci::Address addr) const { - for (const auto& pair : sco_connections_) { - if (std::get(pair).GetAddress() == addr) { - return std::get<0>(pair); - } - } - return kReservedHandle; -} - ScoConnectionParameters AclConnectionHandler::GetScoConnectionParameters( bluetooth::hci::Address addr) const { for (const auto& pair : sco_connections_) { @@ -390,39 +263,28 @@ ScoLinkParameters AclConnectionHandler::GetScoLinkParameters(bluetooth::hci::Add return {}; } -std::vector AclConnectionHandler::GetAclHandles() const { - std::vector keys(acl_connections_.size()); - - for (const auto& pair : acl_connections_) { - keys.push_back(pair.first); +std::vector AclConnectionHandler::GetScoHandles() const { + std::vector handles; + for (auto const& [handle, _] : sco_connections_) { + handles.push_back(handle); } - return keys; -} - -void AclConnectionHandler::ResetLinkTimer(uint16_t handle) { - acl_connections_.at(handle).ResetLinkTimer(); -} - -std::chrono::steady_clock::duration AclConnectionHandler::TimeUntilLinkNearExpiring( - uint16_t handle) const { - return acl_connections_.at(handle).TimeUntilNearExpiring(); -} - -bool AclConnectionHandler::IsLinkNearExpiring(uint16_t handle) const { - return acl_connections_.at(handle).IsNearExpiring(); -} - -std::chrono::steady_clock::duration AclConnectionHandler::TimeUntilLinkExpired( - uint16_t handle) const { - return acl_connections_.at(handle).TimeUntilExpired(); + return handles; } -bool AclConnectionHandler::HasLinkExpired(uint16_t handle) const { - return acl_connections_.at(handle).HasExpired(); +std::vector AclConnectionHandler::GetAclHandles() const { + std::vector handles; + for (auto const& [handle, _] : acl_connections_) { + handles.push_back(handle); + } + return handles; } -bool AclConnectionHandler::IsRoleSwitchAllowedForPendingConnection() const { - return pending_classic_connection_allow_role_switch_; +std::vector AclConnectionHandler::GetLeAclHandles() const { + std::vector handles; + for (auto const& [handle, _] : le_acl_connections_) { + handles.push_back(handle); + } + return handles; } } // namespace rootcanal diff --git a/model/controller/acl_connection_handler.h b/model/controller/acl_connection_handler.h index b25181b..c3bafa0 100644 --- a/model/controller/acl_connection_handler.h +++ b/model/controller/acl_connection_handler.h @@ -26,18 +26,17 @@ #include "hci/address.h" #include "hci/address_with_type.h" #include "model/controller/acl_connection.h" +#include "model/controller/connection_handle.h" +#include "model/controller/le_acl_connection.h" #include "model/controller/sco_connection.h" #include "packets/hci_packets.h" -#include "phy.h" namespace rootcanal { -static constexpr uint16_t kReservedHandle = 0xF00; -static constexpr uint16_t kCisHandleRangeStart = 0xE00; -static constexpr uint16_t kCisHandleRangeEnd = 0xEFE; class AclConnectionHandler { public: AclConnectionHandler() = default; + AclConnectionHandler& operator=(AclConnectionHandler const&) = delete; virtual ~AclConnectionHandler() = default; using TaskId = uint32_t; @@ -46,12 +45,6 @@ class AclConnectionHandler { // SCO connections. void Reset(std::function stopStream); - bool CreatePendingConnection(bluetooth::hci::Address addr, bool authenticate_on_connect, - bool allow_role_switch); - bool HasPendingConnection(bluetooth::hci::Address addr) const; - bool CancelPendingConnection(bluetooth::hci::Address addr); - bool AuthenticatePendingConnection() const; - bool HasPendingScoConnection(bluetooth::hci::Address addr) const; ScoState GetScoConnectionState(bluetooth::hci::Address addr) const; bool IsLegacyScoConnection(bluetooth::hci::Address addr) const; @@ -63,83 +56,56 @@ class AclConnectionHandler { bool AcceptPendingScoConnection(bluetooth::hci::Address addr, ScoConnectionParameters const& parameters, std::function startStream); - uint16_t GetScoHandle(bluetooth::hci::Address addr) const; ScoConnectionParameters GetScoConnectionParameters(bluetooth::hci::Address addr) const; ScoLinkParameters GetScoLinkParameters(bluetooth::hci::Address addr) const; - bool CreatePendingLeConnection(bluetooth::hci::AddressWithType peer, - bluetooth::hci::AddressWithType resolved_peer, - bluetooth::hci::AddressWithType local_address); - bool HasPendingLeConnection(bluetooth::hci::AddressWithType addr) const; - bool CancelPendingLeConnection(bluetooth::hci::AddressWithType addr); - - // \p pending is true if the connection is expected to be - // in pending state. - uint16_t CreateConnection(bluetooth::hci::Address addr, bluetooth::hci::Address own_addr, - bool pending = true); + uint16_t CreateConnection(bluetooth::hci::Address addr, bluetooth::hci::Address own_addr); uint16_t CreateLeConnection(bluetooth::hci::AddressWithType addr, - bluetooth::hci::AddressWithType own_addr, bluetooth::hci::Role role); + bluetooth::hci::AddressWithType resolved_addr, + bluetooth::hci::AddressWithType own_addr, bluetooth::hci::Role role, + LeAclConnectionParameters connection_parameters); + bool Disconnect(uint16_t handle, std::function stopStream); - bool HasHandle(uint16_t handle) const; + + bool HasAclHandle(uint16_t handle) const; + bool HasLeAclHandle(uint16_t handle) const; bool HasScoHandle(uint16_t handle) const; // Return the connection handle for a classic ACL connection only. // \p bd_addr is the peer address. std::optional GetAclConnectionHandle(bluetooth::hci::Address bd_addr) const; - uint16_t GetHandle(bluetooth::hci::AddressWithType addr) const; - uint16_t GetHandleOnlyAddress(bluetooth::hci::Address addr) const; - bluetooth::hci::AddressWithType GetAddress(uint16_t handle) const; - std::optional GetAddressSafe(uint16_t handle) const; + // Return the connection handle for a LE ACL connection identified with + // local and remote addresses. + std::optional GetLeAclConnectionHandle(bluetooth::hci::Address local_address, + bluetooth::hci::Address remote_address) const; + + // Return the connection handle for a classic SCO connection identified + // with the peer address \p bd_addr. + std::optional GetScoConnectionHandle(bluetooth::hci::Address bd_addr) const; + bluetooth::hci::Address GetScoAddress(uint16_t handle) const; - bluetooth::hci::AddressWithType GetOwnAddress(uint16_t handle) const; - bluetooth::hci::AddressWithType GetResolvedAddress(uint16_t handle) const; // Return the AclConnection for the selected connection handle, asserts // if the handle is not currently used. AclConnection& GetAclConnection(uint16_t handle); - void Encrypt(uint16_t handle); - bool IsEncrypted(uint16_t handle) const; - - void SetRssi(uint16_t handle, int8_t rssi); - int8_t GetRssi(uint16_t handle) const; - - Phy::Type GetPhyType(uint16_t handle) const; - - uint16_t GetAclLinkPolicySettings(uint16_t handle) const; - void SetAclLinkPolicySettings(uint16_t handle, uint16_t settings); - - bluetooth::hci::Role GetAclRole(uint16_t handle) const; - void SetAclRole(uint16_t handle, bluetooth::hci::Role role); + // Return the AclConnection for the selected connection handle, asserts + // if the handle is not currently used. + LeAclConnection& GetLeAclConnection(uint16_t handle); + std::vector GetScoHandles() const; std::vector GetAclHandles() const; - - void ResetLinkTimer(uint16_t handle); - std::chrono::steady_clock::duration TimeUntilLinkNearExpiring(uint16_t handle) const; - bool IsLinkNearExpiring(uint16_t handle) const; - std::chrono::steady_clock::duration TimeUntilLinkExpired(uint16_t handle) const; - bool HasLinkExpired(uint16_t handle) const; - bool IsRoleSwitchAllowedForPendingConnection() const; + std::vector GetLeAclHandles() const; private: std::unordered_map acl_connections_; + std::unordered_map le_acl_connections_; std::unordered_map sco_connections_; - bool classic_connection_pending_{false}; - bluetooth::hci::Address pending_connection_address_{bluetooth::hci::Address::kEmpty}; - bool authenticate_pending_classic_connection_{false}; - bool pending_classic_connection_allow_role_switch_{false}; - bool le_connection_pending_{false}; - bluetooth::hci::AddressWithType pending_le_connection_address_{ - bluetooth::hci::Address::kEmpty, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS}; - bluetooth::hci::AddressWithType pending_le_connection_own_address_{ - bluetooth::hci::Address::kEmpty, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS}; - bluetooth::hci::AddressWithType pending_le_connection_resolved_address_{ - bluetooth::hci::Address::kEmpty, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS}; - - uint16_t GetUnusedHandle(); - uint16_t last_handle_{kReservedHandle - 2}; + uint16_t last_acl_handle_{ConnectionHandle::kAclRangeStart}; + uint16_t last_sco_handle_{ConnectionHandle::kScoRangeStart}; + uint16_t last_le_acl_handle_{ConnectionHandle::kLeAclRangeStart}; }; } // namespace rootcanal diff --git a/model/controller/bredr_controller.cc b/model/controller/bredr_controller.cc new file mode 100644 index 0000000..6397e1a --- /dev/null +++ b/model/controller/bredr_controller.cc @@ -0,0 +1,1980 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "model/controller/bredr_controller.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crypto/crypto.h" +#include "hci/address.h" +#include "hci/address_with_type.h" +#include "log.h" +#include "model/controller/acl_connection.h" +#include "model/controller/acl_connection_handler.h" +#include "model/controller/controller_properties.h" +#include "model/controller/le_acl_connection.h" +#include "model/controller/le_advertiser.h" +#include "model/controller/sco_connection.h" +#include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" +#include "phy.h" +#include "rust/include/rootcanal_rs.h" + +using namespace std::chrono; +using bluetooth::hci::Address; + +using namespace model::packets; +using namespace std::literals; + +using TaskId = rootcanal::BrEdrController::TaskId; + +namespace rootcanal { + +constexpr milliseconds kNoDelayMs(0); +constexpr milliseconds kPageInterval(1000); + +const Address& BrEdrController::GetAddress() const { return address_; } + +bool BrEdrController::IsEventUnmasked(EventCode event) const { + uint8_t evt = static_cast(event); + + if (evt <= 64) { + uint64_t bit = UINT64_C(1) << (evt - 1); + return (event_mask_ & bit) != 0; + } else { + evt -= 64; + uint64_t bit = UINT64_C(1) << (evt - 1); + return (event_mask_page_2_ & bit) != 0; + } +} + +// ============================================================================= +// BR/EDR Commands +// ============================================================================= + +// HCI Read Rssi command (Vol 4, Part E § 7.5.4). +ErrorCode BrEdrController::ReadRssi(uint16_t connection_handle, int8_t* rssi) { + if (connections_.HasAclHandle(connection_handle)) { + *rssi = connections_.GetAclConnection(connection_handle).GetRssi(); + return ErrorCode::SUCCESS; + } + + // Not documented: If the connection handle is not found, the Controller + // shall return the error code Unknown Connection Identifier (0x02). + INFO(id_, "unknown connection identifier"); + return ErrorCode::UNKNOWN_CONNECTION; +} + +void BrEdrController::SetSecureSimplePairingSupport(bool enable) { + uint64_t bit = 0x1; + secure_simple_pairing_host_support_ = enable; + if (enable) { + host_supported_features_ |= bit; + } else { + host_supported_features_ &= ~bit; + } +} + +void BrEdrController::SetLeHostSupport(bool enable) { + // TODO: Vol 2, Part C § 3.5 Feature requirements. + // (65) LE Supported (Host) implies + // (38) LE Supported (Controller) + uint64_t bit = 0x2; + le_host_support_ = enable; + if (enable) { + host_supported_features_ |= bit; + } else { + host_supported_features_ &= ~bit; + } +} + +void BrEdrController::SetSecureConnectionsSupport(bool enable) { + // TODO: Vol 2, Part C § 3.5 Feature requirements. + // (67) Secure Connections (Host Support) implies + // (64) Secure Simple Pairing (Host Support) and + // (136) Secure Connections (Controller Support) + uint64_t bit = 0x8; + secure_connections_host_support_ = enable; + if (enable) { + host_supported_features_ |= bit; + } else { + host_supported_features_ &= ~bit; + } +} + +void BrEdrController::SetLocalName(std::array const& local_name) { + std::copy(local_name.begin(), local_name.end(), local_name_.begin()); +} + +void BrEdrController::SetLocalName(std::vector const& local_name) { + ASSERT(local_name.size() <= local_name_.size()); + local_name_.fill(0); + std::copy(local_name.begin(), local_name.end(), local_name_.begin()); +} + +void BrEdrController::SetExtendedInquiryResponse( + std::array const& extended_inquiry_response) { + extended_inquiry_response_ = extended_inquiry_response; +} + +void BrEdrController::SetExtendedInquiryResponse( + std::vector const& extended_inquiry_response) { + ASSERT(extended_inquiry_response.size() <= extended_inquiry_response_.size()); + extended_inquiry_response_.fill(0); + std::copy(extended_inquiry_response.begin(), extended_inquiry_response.end(), + extended_inquiry_response_.begin()); +} + +BrEdrController::BrEdrController(const Address& address, const ControllerProperties& properties, + uint32_t id) + : id_(id), address_(address), properties_(properties), lm_(nullptr, link_manager_destroy) { + controller_ops_ = { + .user_pointer = this, + .get_handle = + [](void* user, const uint8_t (*address)[6]) { + auto controller = static_cast(user); + + // Returns the connection handle but only for established + // BR-EDR connections. + return controller->connections_.GetAclConnectionHandle(Address(*address)) + .value_or(-1); + }, + + .get_address = + [](void* user, uint16_t handle, uint8_t (*result)[6]) { + auto controller = static_cast(user); + Address address = {}; + + if (controller->connections_.HasAclHandle(handle)) { + address = controller->connections_.GetAclConnection(handle).address; + } else if (controller->connections_.HasLeAclHandle(handle)) { + address = controller->connections_.GetLeAclConnection(handle) + .address.GetAddress(); + } + + std::copy(address.data(), address.data() + 6, + reinterpret_cast(result)); + }, + + .get_extended_features = + [](void* user, uint8_t features_page) { + auto controller = static_cast(user); + return controller->GetLmpFeatures(features_page); + }, + + .send_hci_event = + [](void* user, const uint8_t* data, uintptr_t len) { + auto controller = static_cast(user); + + auto event_code = static_cast(data[0]); + controller->send_event_(bluetooth::hci::EventBuilder::Create( + event_code, std::vector(data + 2, data + len))); + }, + + .send_lmp_packet = + [](void* user, const uint8_t (*to)[6], const uint8_t* data, uintptr_t len) { + auto controller = static_cast(user); + + Address source = controller->GetAddress(); + Address dest(*to); + + controller->SendLinkLayerPacket(model::packets::LmpBuilder::Create( + source, dest, std::vector(data, data + len))); + }}; + + lm_.reset(link_manager_create(controller_ops_)); +} + +BrEdrController::~BrEdrController() {} + +void BrEdrController::SendLinkLayerPacket( + std::unique_ptr packet, int8_t tx_power) { + std::shared_ptr shared_packet = std::move(packet); + ScheduleTask(kNoDelayMs, [this, shared_packet, tx_power]() { + send_to_remote_(shared_packet, Phy::Type::BR_EDR, tx_power); + }); +} + +ErrorCode BrEdrController::SendCommandToRemoteByAddress(OpCode opcode, pdl::packet::slice args, + const Address& own_address, + const Address& peer_address) { + switch (opcode) { + case (OpCode::REMOTE_NAME_REQUEST): + // LMP features get requested with remote name requests. + SendLinkLayerPacket( + model::packets::ReadRemoteLmpFeaturesBuilder::Create(own_address, peer_address)); + SendLinkLayerPacket( + model::packets::RemoteNameRequestBuilder::Create(own_address, peer_address)); + break; + case (OpCode::READ_REMOTE_SUPPORTED_FEATURES): + SendLinkLayerPacket(model::packets::ReadRemoteSupportedFeaturesBuilder::Create(own_address, + peer_address)); + break; + case (OpCode::READ_REMOTE_EXTENDED_FEATURES): { + pdl::packet::slice page_number_slice = args.subrange(5, 1); + uint8_t page_number = page_number_slice.read_le(); + SendLinkLayerPacket(model::packets::ReadRemoteExtendedFeaturesBuilder::Create( + own_address, peer_address, page_number)); + } break; + case (OpCode::READ_CLOCK_OFFSET): + SendLinkLayerPacket( + model::packets::ReadClockOffsetBuilder::Create(own_address, peer_address)); + break; + default: + INFO(id_, "Dropping unhandled command 0x{:04x}", static_cast(opcode)); + return ErrorCode::UNKNOWN_HCI_COMMAND; + } + + return ErrorCode::SUCCESS; +} + +ErrorCode BrEdrController::SendCommandToRemoteByHandle(OpCode opcode, pdl::packet::slice args, + uint16_t handle) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + auto const& connection = connections_.GetAclConnection(handle); + return SendCommandToRemoteByAddress(opcode, args, connection.own_address, connection.address); +} + +ErrorCode BrEdrController::SendScoToRemote(bluetooth::hci::ScoView sco_packet) { + uint16_t handle = sco_packet.GetHandle(); + if (!connections_.HasScoHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + // TODO: SCO flow control + Address source = GetAddress(); + Address destination = connections_.GetScoAddress(handle); + + auto sco_data = sco_packet.GetData(); + std::vector sco_data_bytes(sco_data.begin(), sco_data.end()); + + SendLinkLayerPacket( + model::packets::ScoBuilder::Create(source, destination, std::move(sco_data_bytes))); + return ErrorCode::SUCCESS; +} + +void BrEdrController::IncomingPacket(model::packets::LinkLayerPacketView incoming, int8_t rssi) { + ASSERT(incoming.IsValid()); + auto destination_address = incoming.GetDestinationAddress(); + auto source_address = incoming.GetSourceAddress(); + + // Accept broadcasts to address 00:00:00:00:00:00 but otherwise ignore the incoming + // packet if the destination address is not the local public address. + if (destination_address != Address::kEmpty && destination_address != address_) { + DEBUG(id_, "[LM] {} | Dropping {} packet not addressed to me {}->{}", address_, + PacketTypeText(incoming.GetType()), source_address, destination_address); + return; + } + + // Update link timeout for established ACL connections. + auto connection_handle = connections_.GetAclConnectionHandle(source_address); + if (connection_handle.has_value()) { + connections_.GetAclConnection(*connection_handle).ResetLinkTimer(); + } + + switch (incoming.GetType()) { + case model::packets::PacketType::ACL: + IncomingAclPacket(incoming, rssi); + break; + case model::packets::PacketType::SCO: + IncomingScoPacket(incoming); + break; + case model::packets::PacketType::DISCONNECT: + IncomingDisconnectPacket(incoming); + break; + case model::packets::PacketType::LMP: + IncomingLmpPacket(incoming); + break; + case model::packets::PacketType::INQUIRY: + IncomingInquiryPacket(incoming, rssi); + break; + case model::packets::PacketType::INQUIRY_RESPONSE: + IncomingInquiryResponsePacket(incoming); + break; + case model::packets::PacketType::PAGE: + IncomingPagePacket(incoming); + break; + case model::packets::PacketType::PAGE_RESPONSE: + IncomingPageResponsePacket(incoming); + break; + case model::packets::PacketType::PAGE_REJECT: + IncomingPageRejectPacket(incoming); + break; + case model::packets::PacketType::REMOTE_NAME_REQUEST: + IncomingRemoteNameRequest(incoming); + break; + case model::packets::PacketType::REMOTE_NAME_REQUEST_RESPONSE: + IncomingRemoteNameRequestResponse(incoming); + break; + case model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES: + IncomingReadRemoteSupportedFeatures(incoming); + break; + case model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES_RESPONSE: + IncomingReadRemoteSupportedFeaturesResponse(incoming); + break; + case model::packets::PacketType::READ_REMOTE_LMP_FEATURES: + IncomingReadRemoteLmpFeatures(incoming); + break; + case model::packets::PacketType::READ_REMOTE_LMP_FEATURES_RESPONSE: + IncomingReadRemoteLmpFeaturesResponse(incoming); + break; + case model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES: + IncomingReadRemoteExtendedFeatures(incoming); + break; + case model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES_RESPONSE: + IncomingReadRemoteExtendedFeaturesResponse(incoming); + break; + case model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION: + IncomingReadRemoteVersion(incoming); + break; + case model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION_RESPONSE: + IncomingReadRemoteVersionResponse(incoming); + break; + case model::packets::PacketType::READ_CLOCK_OFFSET: + IncomingReadClockOffset(incoming); + break; + case model::packets::PacketType::READ_CLOCK_OFFSET_RESPONSE: + IncomingReadClockOffsetResponse(incoming); + break; + case model::packets::PacketType::SCO_CONNECTION_REQUEST: + IncomingScoConnectionRequest(incoming); + break; + case model::packets::PacketType::SCO_CONNECTION_RESPONSE: + IncomingScoConnectionResponse(incoming); + break; + case model::packets::PacketType::SCO_DISCONNECT: + IncomingScoDisconnect(incoming); + break; + case model::packets::PacketType::PING_REQUEST: + IncomingPingRequest(incoming); + break; + case model::packets::PacketType::PING_RESPONSE: + // ping responses require no action + break; + case model::packets::PacketType::ROLE_SWITCH_REQUEST: + IncomingRoleSwitchRequest(incoming); + break; + case model::packets::PacketType::ROLE_SWITCH_RESPONSE: + IncomingRoleSwitchResponse(incoming); + break; + default: + WARNING(id_, "Dropping unhandled packet of type {}", + model::packets::PacketTypeText(incoming.GetType())); + } +} + +void BrEdrController::IncomingAclPacket(model::packets::LinkLayerPacketView incoming, int8_t rssi) { + auto acl = model::packets::AclView::Create(incoming); + ASSERT(acl.IsValid()); + + auto acl_data = acl.GetData(); + auto packet_boundary_flag = bluetooth::hci::PacketBoundaryFlag(acl.GetPacketBoundaryFlag()); + auto broadcast_flag = bluetooth::hci::BroadcastFlag(acl.GetBroadcastFlag()); + + if (packet_boundary_flag == + bluetooth::hci::PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) { + packet_boundary_flag = bluetooth::hci::PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; + } + + INFO(id_, "ACL Packet [{}] {} -> {}", acl_data.size(), incoming.GetSourceAddress(), + incoming.GetDestinationAddress()); + + auto connection_handle = connections_.GetAclConnectionHandle(incoming.GetSourceAddress()); + if (!connection_handle.has_value()) { + INFO(id_, "Dropping packet since connection does not exist"); + return; + } + + // Update the RSSI for the local ACL connection. + auto& connection = connections_.GetAclConnection(*connection_handle); + connection.SetRssi(rssi); + + send_acl_(bluetooth::hci::AclBuilder::Create( + *connection_handle, packet_boundary_flag, broadcast_flag, + std::vector(acl_data.begin(), acl_data.end()))); +} + +void BrEdrController::IncomingScoPacket(model::packets::LinkLayerPacketView incoming) { + Address source = incoming.GetSourceAddress(); + auto sco_handle = connections_.GetScoConnectionHandle(source); + if (!sco_handle.has_value()) { + INFO(id_, "Spurious SCO packet from {}", source); + return; + } + + auto sco = model::packets::ScoView::Create(incoming); + ASSERT(sco.IsValid()); + auto sco_data = sco.GetPayload(); + std::vector sco_data_bytes(sco_data.begin(), sco_data.end()); + + INFO(id_, "Sco Packet [{}] {} -> {}", static_cast(sco_data_bytes.size()), + incoming.GetSourceAddress(), incoming.GetDestinationAddress()); + + send_sco_(bluetooth::hci::ScoBuilder::Create( + *sco_handle, bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED, sco_data_bytes)); +} + +void BrEdrController::IncomingRemoteNameRequest(model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::RemoteNameRequestView::Create(incoming); + ASSERT(view.IsValid()); + + SendLinkLayerPacket(model::packets::RemoteNameRequestResponseBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), local_name_)); +} + +void BrEdrController::IncomingRemoteNameRequestResponse( + model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::RemoteNameRequestResponseView::Create(incoming); + ASSERT(view.IsValid()); + + if (IsEventUnmasked(EventCode::REMOTE_NAME_REQUEST_COMPLETE)) { + send_event_(bluetooth::hci::RemoteNameRequestCompleteBuilder::Create( + ErrorCode::SUCCESS, incoming.GetSourceAddress(), view.GetName())); + } +} + +void BrEdrController::IncomingReadRemoteLmpFeatures(model::packets::LinkLayerPacketView incoming) { + SendLinkLayerPacket(model::packets::ReadRemoteLmpFeaturesResponseBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), host_supported_features_)); +} + +void BrEdrController::IncomingReadRemoteLmpFeaturesResponse( + model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::ReadRemoteLmpFeaturesResponseView::Create(incoming); + ASSERT(view.IsValid()); + if (IsEventUnmasked(EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION)) { + send_event_(bluetooth::hci::RemoteHostSupportedFeaturesNotificationBuilder::Create( + incoming.GetSourceAddress(), view.GetFeatures())); + } +} + +void BrEdrController::IncomingReadRemoteSupportedFeatures( + model::packets::LinkLayerPacketView incoming) { + SendLinkLayerPacket(model::packets::ReadRemoteSupportedFeaturesResponseBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), + properties_.lmp_features[0])); +} + +void BrEdrController::IncomingReadRemoteSupportedFeaturesResponse( + model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::ReadRemoteSupportedFeaturesResponseView::Create(incoming); + ASSERT(view.IsValid()); + Address source = incoming.GetSourceAddress(); + auto handle = connections_.GetAclConnectionHandle(source); + if (!handle.has_value()) { + INFO(id_, "Discarding response from a disconnected device {}", source); + return; + } + if (IsEventUnmasked(EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE)) { + send_event_(bluetooth::hci::ReadRemoteSupportedFeaturesCompleteBuilder::Create( + ErrorCode::SUCCESS, *handle, view.GetFeatures())); + } +} + +void BrEdrController::IncomingReadRemoteExtendedFeatures( + model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::ReadRemoteExtendedFeaturesView::Create(incoming); + ASSERT(view.IsValid()); + uint8_t page_number = view.GetPageNumber(); + uint8_t error_code = static_cast(ErrorCode::SUCCESS); + if (page_number >= properties_.lmp_features.size()) { + error_code = static_cast(ErrorCode::INVALID_LMP_OR_LL_PARAMETERS); + } + SendLinkLayerPacket(model::packets::ReadRemoteExtendedFeaturesResponseBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), error_code, page_number, + GetMaxLmpFeaturesPageNumber(), GetLmpFeatures(page_number))); +} + +void BrEdrController::IncomingReadRemoteExtendedFeaturesResponse( + model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::ReadRemoteExtendedFeaturesResponseView::Create(incoming); + ASSERT(view.IsValid()); + Address source = incoming.GetSourceAddress(); + auto handle = connections_.GetAclConnectionHandle(source); + if (!handle.has_value()) { + INFO(id_, "Discarding response from a disconnected device {}", source); + return; + } + if (IsEventUnmasked(EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE)) { + send_event_(bluetooth::hci::ReadRemoteExtendedFeaturesCompleteBuilder::Create( + static_cast(view.GetStatus()), *handle, view.GetPageNumber(), + view.GetMaxPageNumber(), view.GetFeatures())); + } +} + +void BrEdrController::IncomingReadRemoteVersion(model::packets::LinkLayerPacketView incoming) { + SendLinkLayerPacket(model::packets::ReadRemoteVersionInformationResponseBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), + static_cast(properties_.lmp_version), + static_cast(properties_.lmp_subversion), properties_.company_identifier)); +} + +void BrEdrController::IncomingReadRemoteVersionResponse( + model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::ReadRemoteVersionInformationResponseView::Create(incoming); + ASSERT(view.IsValid()); + Address source = incoming.GetSourceAddress(); + + auto handle = connections_.GetAclConnectionHandle(source); + + if (!handle.has_value()) { + INFO(id_, "Discarding response from a disconnected device {}", source); + return; + } + + if (IsEventUnmasked(EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE)) { + send_event_(bluetooth::hci::ReadRemoteVersionInformationCompleteBuilder::Create( + ErrorCode::SUCCESS, *handle, view.GetLmpVersion(), view.GetManufacturerName(), + view.GetLmpSubversion())); + } +} + +void BrEdrController::IncomingReadClockOffset(model::packets::LinkLayerPacketView incoming) { + SendLinkLayerPacket(model::packets::ReadClockOffsetResponseBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), GetClockOffset())); +} + +void BrEdrController::IncomingReadClockOffsetResponse( + model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::ReadClockOffsetResponseView::Create(incoming); + ASSERT(view.IsValid()); + Address source = incoming.GetSourceAddress(); + auto handle = connections_.GetAclConnectionHandle(source); + if (!handle.has_value()) { + INFO(id_, "Discarding response from a disconnected device {}", source); + return; + } + if (IsEventUnmasked(EventCode::READ_CLOCK_OFFSET_COMPLETE)) { + send_event_(bluetooth::hci::ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, *handle, + view.GetOffset())); + } +} + +void BrEdrController::IncomingDisconnectPacket(model::packets::LinkLayerPacketView incoming) { + INFO(id_, "Disconnect Packet"); + + auto disconnect = model::packets::DisconnectView::Create(incoming); + ASSERT(disconnect.IsValid()); + + Address peer = incoming.GetSourceAddress(); + auto handle = connections_.GetAclConnectionHandle(peer); + if (!handle.has_value()) { + INFO(id_, "Discarding disconnect from a disconnected device {}", peer); + return; + } + + ASSERT_LOG(connections_.Disconnect(*handle, + [this](TaskId task_id) { CancelScheduledTask(task_id); }), + "GetHandle() returned invalid handle 0x{:x}", *handle); + + uint8_t reason = disconnect.GetReason(); + ASSERT(link_manager_remove_link(lm_.get(), reinterpret_cast(peer.data()))); + SendDisconnectionCompleteEvent(*handle, ErrorCode(reason)); +} + +void BrEdrController::IncomingInquiryPacket(model::packets::LinkLayerPacketView incoming, + uint8_t rssi) { + if (!inquiry_scan_enable_) { + return; + } + + auto inquiry = model::packets::InquiryView::Create(incoming); + ASSERT(inquiry.IsValid()); + + Address peer = incoming.GetSourceAddress(); + uint8_t lap = inquiry.GetLap(); + + // Filter out inquiry packets with IAC not present in the + // list Current_IAC_LAP. + if (std::none_of(current_iac_lap_list_.cbegin(), current_iac_lap_list_.cend(), + [lap](auto iac_lap) { return iac_lap.lap_ == lap; })) { + return; + } + + switch (inquiry.GetInquiryType()) { + case (model::packets::InquiryType::STANDARD): { + SendLinkLayerPacket(model::packets::InquiryResponseBuilder::Create( + GetAddress(), peer, static_cast(GetPageScanRepetitionMode()), + class_of_device_, GetClockOffset())); + } break; + case (model::packets::InquiryType::RSSI): { + SendLinkLayerPacket(model::packets::InquiryResponseWithRssiBuilder::Create( + GetAddress(), peer, static_cast(GetPageScanRepetitionMode()), + class_of_device_, GetClockOffset(), rssi)); + } break; + case (model::packets::InquiryType::EXTENDED): { + SendLinkLayerPacket(model::packets::ExtendedInquiryResponseBuilder::Create( + GetAddress(), peer, static_cast(GetPageScanRepetitionMode()), + class_of_device_, GetClockOffset(), rssi, extended_inquiry_response_)); + } break; + default: + WARNING(id_, "Unhandled Incoming Inquiry of type {}", static_cast(inquiry.GetType())); + return; + } + // TODO: Send an Inquiry Response Notification Event 7.7.74 +} + +void BrEdrController::IncomingInquiryResponsePacket(model::packets::LinkLayerPacketView incoming) { + auto basic_inquiry_response = model::packets::BasicInquiryResponseView::Create(incoming); + ASSERT(basic_inquiry_response.IsValid()); + std::vector eir; + + switch (basic_inquiry_response.GetInquiryType()) { + case (model::packets::InquiryType::STANDARD): { + // TODO: Support multiple inquiries in the same packet. + auto inquiry_response = model::packets::InquiryResponseView::Create(basic_inquiry_response); + ASSERT(inquiry_response.IsValid()); + + auto page_scan_repetition_mode = + (bluetooth::hci::PageScanRepetitionMode)inquiry_response.GetPageScanRepetitionMode(); + + std::vector responses; + responses.emplace_back(); + responses.back().bd_addr_ = inquiry_response.GetSourceAddress(); + responses.back().page_scan_repetition_mode_ = page_scan_repetition_mode; + responses.back().class_of_device_ = inquiry_response.GetClassOfDevice(); + responses.back().clock_offset_ = inquiry_response.GetClockOffset(); + if (IsEventUnmasked(EventCode::INQUIRY_RESULT)) { + send_event_(bluetooth::hci::InquiryResultBuilder::Create(responses)); + } + } break; + + case (model::packets::InquiryType::RSSI): { + auto inquiry_response = + model::packets::InquiryResponseWithRssiView::Create(basic_inquiry_response); + ASSERT(inquiry_response.IsValid()); + + auto page_scan_repetition_mode = + (bluetooth::hci::PageScanRepetitionMode)inquiry_response.GetPageScanRepetitionMode(); + + std::vector responses; + responses.emplace_back(); + responses.back().address_ = inquiry_response.GetSourceAddress(); + responses.back().page_scan_repetition_mode_ = page_scan_repetition_mode; + responses.back().class_of_device_ = inquiry_response.GetClassOfDevice(); + responses.back().clock_offset_ = inquiry_response.GetClockOffset(); + responses.back().rssi_ = inquiry_response.GetRssi(); + if (IsEventUnmasked(EventCode::INQUIRY_RESULT_WITH_RSSI)) { + send_event_(bluetooth::hci::InquiryResultWithRssiBuilder::Create(responses)); + } + } break; + + case (model::packets::InquiryType::EXTENDED): { + auto inquiry_response = + model::packets::ExtendedInquiryResponseView::Create(basic_inquiry_response); + ASSERT(inquiry_response.IsValid()); + + send_event_(bluetooth::hci::ExtendedInquiryResultBuilder::Create( + inquiry_response.GetSourceAddress(), + static_cast( + inquiry_response.GetPageScanRepetitionMode()), + inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), + inquiry_response.GetRssi(), inquiry_response.GetExtendedInquiryResponse())); + } break; + + default: + WARNING(id_, "Unhandled Incoming Inquiry Response of type {}", + static_cast(basic_inquiry_response.GetInquiryType())); + } +} + +void BrEdrController::IncomingScoConnectionRequest(model::packets::LinkLayerPacketView incoming) { + Address address = incoming.GetSourceAddress(); + auto request = model::packets::ScoConnectionRequestView::Create(incoming); + ASSERT(request.IsValid()); + + INFO(id_, "Received eSCO connection request from {}", address); + + // Automatically reject if connection request was already sent + // from the current device. + if (connections_.HasPendingScoConnection(address)) { + INFO(id_, + "Rejecting eSCO connection request from {}, " + "an eSCO connection already exist with this device", + address); + + SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( + GetAddress(), address, (uint8_t)ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED, 0, 0, + 0, 0, 0, 0)); + return; + } + + // Create local connection context. + ScoConnectionParameters connection_parameters = { + request.GetTransmitBandwidth(), request.GetReceiveBandwidth(), + request.GetMaxLatency(), request.GetVoiceSetting(), + request.GetRetransmissionEffort(), request.GetPacketType()}; + + bool extended = connection_parameters.IsExtended(); + connections_.CreateScoConnection(address, connection_parameters, + extended ? ScoState::SCO_STATE_SENT_ESCO_CONNECTION_REQUEST + : ScoState::SCO_STATE_SENT_SCO_CONNECTION_REQUEST, + ScoDatapath::NORMAL); + + // Send connection request event and wait for Accept or Reject command. + send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( + address, request.GetClassOfDevice(), + extended ? bluetooth::hci::ConnectionRequestLinkType::ESCO + : bluetooth::hci::ConnectionRequestLinkType::SCO)); +} + +void BrEdrController::IncomingScoConnectionResponse(model::packets::LinkLayerPacketView incoming) { + Address address = incoming.GetSourceAddress(); + auto response = model::packets::ScoConnectionResponseView::Create(incoming); + ASSERT(response.IsValid()); + auto status = ErrorCode(response.GetStatus()); + auto sco_connection_handle = connections_.GetScoConnectionHandle(address); + bool is_legacy = connections_.IsLegacyScoConnection(address); + + if (!sco_connection_handle.has_value()) { + INFO(id_, "Received spurious eSCO connection response from {}", address); + return; + } + + INFO(id_, "Received eSCO connection response with status 0x{:02x} from {}", + static_cast(status), incoming.GetSourceAddress()); + + if (status == ErrorCode::SUCCESS) { + bool extended = response.GetExtended(); + ScoLinkParameters link_parameters = { + response.GetTransmissionInterval(), + response.GetRetransmissionWindow(), + response.GetRxPacketLength(), + response.GetTxPacketLength(), + response.GetAirMode(), + extended, + }; + + connections_.AcceptPendingScoConnection(address, link_parameters, [this, address] { + return BrEdrController::StartScoStream(address); + }); + + if (is_legacy) { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode::SUCCESS, *sco_connection_handle, address, bluetooth::hci::LinkType::SCO, + bluetooth::hci::Enable::DISABLED)); + } else { + send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( + ErrorCode::SUCCESS, *sco_connection_handle, address, + extended ? bluetooth::hci::ScoLinkType::ESCO : bluetooth::hci::ScoLinkType::SCO, + extended ? response.GetTransmissionInterval() : 0, + extended ? response.GetRetransmissionWindow() : 0, + extended ? response.GetRxPacketLength() : 0, + extended ? response.GetTxPacketLength() : 0, + bluetooth::hci::ScoAirMode(response.GetAirMode()))); + } + } else { + connections_.CancelPendingScoConnection(address); + if (is_legacy) { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + status, 0, address, bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED)); + } else { + ScoConnectionParameters connection_parameters = + connections_.GetScoConnectionParameters(address); + send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( + status, 0, address, + connection_parameters.IsExtended() ? bluetooth::hci::ScoLinkType::ESCO + : bluetooth::hci::ScoLinkType::SCO, + 0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT)); + } + } +} + +void BrEdrController::IncomingScoDisconnect(model::packets::LinkLayerPacketView incoming) { + Address address = incoming.GetSourceAddress(); + auto request = model::packets::ScoDisconnectView::Create(incoming); + ASSERT(request.IsValid()); + auto reason = request.GetReason(); + auto handle = connections_.GetScoConnectionHandle(address); + + INFO(id_, + "Received eSCO disconnection request with" + " reason 0x{:02x} from {}", + static_cast(reason), incoming.GetSourceAddress()); + + if (handle.has_value()) { + connections_.Disconnect(*handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }); + SendDisconnectionCompleteEvent(*handle, ErrorCode(reason)); + } +} + +void BrEdrController::IncomingLmpPacket(model::packets::LinkLayerPacketView incoming) { + Address address = incoming.GetSourceAddress(); + auto request = model::packets::LmpView::Create(incoming); + ASSERT(request.IsValid()); + auto payload = request.GetPayload(); + auto packet = std::vector(payload.begin(), payload.end()); + + ASSERT(link_manager_ingest_lmp(lm_.get(), reinterpret_cast(address.data()), + packet.data(), packet.size())); +} + +void BrEdrController::HandleAcl(bluetooth::hci::AclView acl) { + uint16_t connection_handle = acl.GetHandle(); + auto pb_flag = acl.GetPacketBoundaryFlag(); + auto bc_flag = acl.GetBroadcastFlag(); + + // TODO: Support Broadcast_Flag value of BR/EDR broadcast. + if (bc_flag != bluetooth::hci::BroadcastFlag::POINT_TO_POINT) { + FATAL("Received ACL HCI packet with Broadcast_flag set to unsupported value {}", + static_cast(bc_flag)); + } + + if (connections_.HasAclHandle(connection_handle)) { + // Classic ACL connection. + auto& connection = connections_.GetAclConnection(connection_handle); + auto acl_payload = acl.GetPayload(); + auto acl_packet = model::packets::AclBuilder::Create( + connection.own_address, connection.address, static_cast(pb_flag), + static_cast(bc_flag), std::vector(acl_payload.begin(), acl_payload.end())); + SendLinkLayerPacket(std::move(acl_packet)); + + } else { + // ACL HCI packets received with an unknown or invalid Connection Handle + // are silently dropped. + DEBUG("Received ACL HCI packet with invalid ACL connection handle 0x{:x}", connection_handle); + } + + // Send immediate acknowledgment for the ACL packet. + // We don't really have a transmission queue in the controller. + ScheduleTask(kNoDelayMs, [this, connection_handle]() { + send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create( + {bluetooth::hci::CompletedPackets(connection_handle, 1)})); + }); +} + +void BrEdrController::IncomingPagePacket(model::packets::LinkLayerPacketView incoming) { + if (!page_scan_enable_) { + return; + } + + auto bd_addr = incoming.GetSourceAddress(); + auto page = model::packets::PageView::Create(incoming); + ASSERT(page.IsValid()); + + // [HCI] 7.3.3 Set Event Filter command + // If the Auto_Accept_Flag is off and the Host has masked the + // HCI_Connection_Request event, the Controller shall reject the + // connection attempt. + if (!IsEventUnmasked(EventCode::CONNECTION_REQUEST)) { + INFO(id_, + "rejecting connection request from {} because the HCI_Connection_Request" + " event is masked by the Host", + bd_addr); + SendLinkLayerPacket(model::packets::PageRejectBuilder::Create( + GetAddress(), bd_addr, static_cast(ErrorCode::CONNECTION_TIMEOUT))); + return; + } + + // Cannot establish two BR-EDR connections with the same peer. + if (connections_.GetAclConnectionHandle(bd_addr).has_value()) { + return; + } + + // Cannot establish multiple connections simultaneously. + if (page_scan_.has_value()) { + INFO(id_, "ignoring connection request from {}, already connecting to {}", bd_addr, + page_scan_->bd_addr); + return; + } + + INFO(id_, "processing connection request from {}", bd_addr); + + page_scan_ = PageScan{ + .bd_addr = bd_addr, + .authentication_required = authentication_enable_ == AuthenticationEnable::REQUIRED, + .allow_role_switch = page.GetAllowRoleSwitch(), + }; + + send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( + bd_addr, page.GetClassOfDevice(), bluetooth::hci::ConnectionRequestLinkType::ACL)); +} + +void BrEdrController::IncomingPageRejectPacket(model::packets::LinkLayerPacketView incoming) { + auto bd_addr = incoming.GetSourceAddress(); + auto reject = model::packets::PageRejectView::Create(incoming); + ASSERT(reject.IsValid()); + + if (!page_.has_value() || page_->bd_addr != bd_addr) { + INFO(id_, + "ignoring Page Reject packet received when not in Page state," + " or paging to a different address"); + return; + } + + INFO(id_, "Received Page Reject packet from {}", bd_addr); + page_ = {}; + + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + static_cast(reject.GetReason()), 0, bd_addr, bluetooth::hci::LinkType::ACL, + bluetooth::hci::Enable::DISABLED)); + } +} + +void BrEdrController::IncomingPageResponsePacket(model::packets::LinkLayerPacketView incoming) { + auto bd_addr = incoming.GetSourceAddress(); + auto response = model::packets::PageResponseView::Create(incoming); + ASSERT(response.IsValid()); + + if (!page_.has_value() || page_->bd_addr != bd_addr) { + INFO(id_, + "ignoring Page Response packet received when not in Page state," + " or paging to a different address"); + return; + } + + INFO(id_, "Received Page Response packet from {}", bd_addr); + + uint16_t connection_handle = connections_.CreateConnection(bd_addr, GetAddress()); + + bluetooth::hci::Role role = page_->allow_role_switch && response.GetTryRoleSwitch() + ? bluetooth::hci::Role::PERIPHERAL + : bluetooth::hci::Role::CENTRAL; + + AclConnection& connection = connections_.GetAclConnection(connection_handle); + CheckExpiringConnection(connection_handle); + connection.SetLinkPolicySettings(default_link_policy_settings_); + connection.SetRole(role); + page_ = {}; + + ASSERT(link_manager_add_link(lm_.get(), reinterpret_cast(bd_addr.data()))); + + // Role change event before connection complete generates an HCI Role Change + // event on the initiator side if accepted; the event is sent before the + // HCI Connection Complete event. + if (role == bluetooth::hci::Role::PERIPHERAL && IsEventUnmasked(EventCode::ROLE_CHANGE)) { + send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, bd_addr, role)); + } + + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode::SUCCESS, connection_handle, bd_addr, bluetooth::hci::LinkType::ACL, + bluetooth::hci::Enable::DISABLED)); + } +} + +void BrEdrController::Tick() { + RunPendingTasks(); + Paging(); + + if (inquiry_timer_task_id_ != kInvalidTaskId) { + Inquiry(); + } + link_manager_tick(lm_.get()); +} + +void BrEdrController::Close() { + DisconnectAll(ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF); +} + +void BrEdrController::RegisterEventChannel( + const std::function)>& send_event) { + send_event_ = send_event; +} + +void BrEdrController::RegisterAclChannel( + const std::function)>& send_acl) { + send_acl_ = send_acl; +} + +void BrEdrController::RegisterScoChannel( + const std::function)>& send_sco) { + send_sco_ = send_sco; +} + +void BrEdrController::RegisterRemoteChannel( + const std::function, Phy::Type, + int8_t)>& send_to_remote) { + send_to_remote_ = send_to_remote; +} + +void BrEdrController::ForwardToLm(bluetooth::hci::CommandView command) { + auto packet = command.bytes().bytes(); + ASSERT(link_manager_ingest_hci(lm_.get(), packet.data(), packet.size())); +} + +std::vector const& BrEdrController::ReadCurrentIacLap() const { + return current_iac_lap_list_; +} + +void BrEdrController::WriteCurrentIacLap(std::vector iac_lap) { + current_iac_lap_list_.swap(iac_lap); + + // If Num_Current_IAC is greater than Num_Supported_IAC then only the first + // Num_Supported_IAC shall be stored in the Controller + if (current_iac_lap_list_.size() > properties_.num_supported_iac) { + current_iac_lap_list_.resize(properties_.num_supported_iac); + } +} + +ErrorCode BrEdrController::AcceptConnectionRequest(const Address& bd_addr, bool try_role_switch) { + if (page_scan_.has_value() && page_scan_->bd_addr == bd_addr) { + INFO(id_, "Accepting connection request from {}", bd_addr); + ScheduleTask(kNoDelayMs, [this, bd_addr, try_role_switch]() { + INFO(id_, "Accepted connection from {}", bd_addr); + MakePeripheralConnection(bd_addr, try_role_switch); + }); + + return ErrorCode::SUCCESS; + } + + // The HCI command Accept Connection may be used to accept incoming SCO + // connection requests. + if (connections_.HasPendingScoConnection(bd_addr)) { + ErrorCode status = ErrorCode::SUCCESS; + uint16_t sco_handle = *connections_.GetScoConnectionHandle(bd_addr); + ScoLinkParameters link_parameters = {}; + ScoConnectionParameters connection_parameters = + connections_.GetScoConnectionParameters(bd_addr); + + if (!connections_.AcceptPendingScoConnection(bd_addr, connection_parameters, [this, bd_addr] { + return BrEdrController::StartScoStream(bd_addr); + })) { + connections_.CancelPendingScoConnection(bd_addr); + status = ErrorCode::SCO_INTERVAL_REJECTED; // TODO: proper status code + sco_handle = 0; + } else { + link_parameters = connections_.GetScoLinkParameters(bd_addr); + } + + // Send eSCO connection response to peer. + SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( + GetAddress(), bd_addr, (uint8_t)status, link_parameters.transmission_interval, + link_parameters.retransmission_window, link_parameters.rx_packet_length, + link_parameters.tx_packet_length, link_parameters.air_mode, link_parameters.extended)); + + // Schedule HCI Connection Complete event. + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { + ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr]() { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode(status), sco_handle, bd_addr, bluetooth::hci::LinkType::SCO, + bluetooth::hci::Enable::DISABLED)); + }); + } + + return ErrorCode::SUCCESS; + } + + INFO(id_, "No pending connection for {}", bd_addr); + return ErrorCode::UNKNOWN_CONNECTION; +} + +void BrEdrController::MakePeripheralConnection(const Address& bd_addr, bool try_role_switch) { + uint16_t connection_handle = connections_.CreateConnection(bd_addr, GetAddress()); + + bluetooth::hci::Role role = try_role_switch && page_scan_->allow_role_switch + ? bluetooth::hci::Role::CENTRAL + : bluetooth::hci::Role::PERIPHERAL; + + AclConnection& connection = connections_.GetAclConnection(connection_handle); + CheckExpiringConnection(connection_handle); + connection.SetLinkPolicySettings(default_link_policy_settings_); + connection.SetRole(role); + + ASSERT(link_manager_add_link(lm_.get(), reinterpret_cast(bd_addr.data()))); + + // Role change event before connection complete generates an HCI Role Change + // event on the acceptor side if accepted; the event is sent before the + // HCI Connection Complete event. + if (role == bluetooth::hci::Role::CENTRAL && IsEventUnmasked(EventCode::ROLE_CHANGE)) { + INFO(id_, "Role at connection setup accepted"); + send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, bd_addr, role)); + } + + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode::SUCCESS, connection_handle, bd_addr, bluetooth::hci::LinkType::ACL, + bluetooth::hci::Enable::DISABLED)); + } + + // If the current Host was initiating a connection to the same bd_addr, + // send a connection complete event for the pending Create Connection + // command and cancel the paging. + if (page_.has_value() && page_->bd_addr == bd_addr) { + // TODO: the core specification is very unclear as to what behavior + // is expected when two connections are established simultaneously. + // This implementation considers that a unique HCI Connection Complete + // event is expected for both the HCI Create Connection and HCI Accept + // Connection Request commands. + page_ = {}; + } + + // Reset the page scan state. + page_scan_ = {}; + + INFO(id_, "Sending page response to {}", bd_addr.ToString()); + SendLinkLayerPacket( + model::packets::PageResponseBuilder::Create(GetAddress(), bd_addr, try_role_switch)); +} + +ErrorCode BrEdrController::RejectConnectionRequest(const Address& addr, uint8_t reason) { + if (!page_scan_.has_value() || page_scan_->bd_addr != addr) { + INFO(id_, "No pending connection for {}", addr); + return ErrorCode::UNKNOWN_CONNECTION; + } + + ScheduleTask(kNoDelayMs, [this, addr, reason]() { RejectPeripheralConnection(addr, reason); }); + + return ErrorCode::SUCCESS; +} + +void BrEdrController::RejectPeripheralConnection(const Address& addr, uint8_t reason) { + INFO(id_, "Sending page reject to {} (reason 0x{:02x})", addr, reason); + SendLinkLayerPacket(model::packets::PageRejectBuilder::Create(GetAddress(), addr, reason)); + + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + static_cast(reason), 0xeff, addr, bluetooth::hci::LinkType::ACL, + bluetooth::hci::Enable::DISABLED)); + } +} + +ErrorCode BrEdrController::CreateConnection(const Address& bd_addr, uint16_t /* packet_type */, + uint8_t /* page_scan_mode */, + uint16_t /* clock_offset */, + uint8_t allow_role_switch) { + // RootCanal only accepts one pending outgoing connection at any time. + if (page_.has_value()) { + INFO(id_, "Create Connection command is already pending"); + return ErrorCode::COMMAND_DISALLOWED; + } + + // Reject the command if a connection already exists + // for the selected peer address. + if (connections_.GetAclConnectionHandle(bd_addr).has_value()) { + INFO(id_, "Connection with {} already exists", bd_addr); + return ErrorCode::CONNECTION_ALREADY_EXISTS; + } + + // Reject the command if a pending connection already exists + // for the selected peer address. + if (page_scan_.has_value() && page_scan_->bd_addr == bd_addr) { + INFO(id_, "Connection with {} is already being established", bd_addr); + return ErrorCode::CONNECTION_ALREADY_EXISTS; + } + + auto now = std::chrono::steady_clock::now(); + page_ = Page{ + .bd_addr = bd_addr, + .allow_role_switch = allow_role_switch, + .next_page_event = now + kPageInterval, + .page_timeout = now + slots(page_timeout_), + }; + + return ErrorCode::SUCCESS; +} + +ErrorCode BrEdrController::CreateConnectionCancel(const Address& bd_addr) { + // If the HCI_Create_Connection_Cancel command is sent to the Controller + // without a preceding HCI_Create_Connection command to the same device, + // the BR/EDR Controller shall return an HCI_Command_Complete event with + // the error code Unknown Connection Identifier (0x02) + if (!page_.has_value() || page_->bd_addr != bd_addr) { + INFO(id_, "no pending connection to {}", bd_addr.ToString()); + return ErrorCode::UNKNOWN_CONNECTION; + } + + // The HCI_Connection_Complete event for the corresponding HCI_Create_- + // Connection command shall always be sent. The HCI_Connection_Complete + // event shall be sent after the HCI_Command_Complete event for the + // HCI_Create_Connection_Cancel command. If the cancellation was successful, + // the HCI_Connection_Complete event will be generated with the error code + // Unknown Connection Identifier (0x02). + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { + ScheduleTask(kNoDelayMs, [this, bd_addr]() { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, 0, bd_addr, bluetooth::hci::LinkType::ACL, + bluetooth::hci::Enable::DISABLED)); + }); + } + + page_ = {}; + return ErrorCode::SUCCESS; +} + +void BrEdrController::SendDisconnectionCompleteEvent(uint16_t handle, ErrorCode reason) { + if (IsEventUnmasked(EventCode::DISCONNECTION_COMPLETE)) { + ScheduleTask(kNoDelayMs, [this, handle, reason]() { + send_event_(bluetooth::hci::DisconnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, + reason)); + }); + } +} + +ErrorCode BrEdrController::Disconnect(uint16_t handle, ErrorCode host_reason, + ErrorCode controller_reason) { + if (connections_.HasScoHandle(handle)) { + const Address remote = connections_.GetScoAddress(handle); + INFO(id_, "Disconnecting eSCO connection with {}", remote); + + SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create( + GetAddress(), remote, static_cast(host_reason))); + + connections_.Disconnect(handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }); + SendDisconnectionCompleteEvent(handle, controller_reason); + return ErrorCode::SUCCESS; + } + + if (connections_.HasAclHandle(handle)) { + auto connection = connections_.GetAclConnection(handle); + auto address = connection.address; + INFO(id_, "Disconnecting ACL connection with {}", connection.address); + + auto sco_handle = connections_.GetScoConnectionHandle(connection.address); + if (sco_handle.has_value()) { + SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create( + connection.own_address, connection.address, static_cast(host_reason))); + + connections_.Disconnect(*sco_handle, + [this](TaskId task_id) { CancelScheduledTask(task_id); }); + SendDisconnectionCompleteEvent(*sco_handle, controller_reason); + } + + SendLinkLayerPacket(model::packets::DisconnectBuilder::Create( + connection.own_address, connection.address, static_cast(host_reason))); + + connections_.Disconnect(handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }); + SendDisconnectionCompleteEvent(handle, controller_reason); + + ASSERT(link_manager_remove_link(lm_.get(), reinterpret_cast(address.data()))); + return ErrorCode::SUCCESS; + } + + return ErrorCode::UNKNOWN_CONNECTION; +} + +ErrorCode BrEdrController::ReadRemoteVersionInformation(uint16_t connection_handle) { + if (connections_.HasAclHandle(connection_handle)) { + auto const& connection = connections_.GetAclConnection(connection_handle); + SendLinkLayerPacket(model::packets::ReadRemoteVersionInformationBuilder::Create( + connection.own_address, connection.address)); + return ErrorCode::SUCCESS; + } + + return ErrorCode::UNKNOWN_CONNECTION; +} + +ErrorCode BrEdrController::ChangeConnectionPacketType(uint16_t handle, uint16_t types) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + ScheduleTask(kNoDelayMs, [this, handle, types]() { + if (IsEventUnmasked(EventCode::CONNECTION_PACKET_TYPE_CHANGED)) { + send_event_(bluetooth::hci::ConnectionPacketTypeChangedBuilder::Create(ErrorCode::SUCCESS, + handle, types)); + } + }); + + return ErrorCode::SUCCESS; +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +ErrorCode BrEdrController::ChangeConnectionLinkKey(uint16_t handle) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + // TODO: implement real logic + return ErrorCode::COMMAND_DISALLOWED; +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +ErrorCode BrEdrController::CentralLinkKey(uint8_t /* key_flag */) { + // TODO: implement real logic + return ErrorCode::COMMAND_DISALLOWED; +} + +ErrorCode BrEdrController::HoldMode(uint16_t handle, uint16_t hold_mode_max_interval, + uint16_t hold_mode_min_interval) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + if (hold_mode_max_interval < hold_mode_min_interval) { + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + } + + // TODO: implement real logic + return ErrorCode::COMMAND_DISALLOWED; +} + +ErrorCode BrEdrController::SniffMode(uint16_t handle, uint16_t sniff_max_interval, + uint16_t sniff_min_interval, uint16_t sniff_attempt, + uint16_t sniff_timeout) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + if (sniff_max_interval < sniff_min_interval || sniff_attempt < 0x0001 || sniff_attempt > 0x7FFF || + sniff_timeout > 0x7FFF) { + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + } + + // TODO: implement real logic + return ErrorCode::COMMAND_DISALLOWED; +} + +ErrorCode BrEdrController::ExitSniffMode(uint16_t handle) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + // TODO: implement real logic + return ErrorCode::COMMAND_DISALLOWED; +} + +ErrorCode BrEdrController::QosSetup(uint16_t handle, uint8_t service_type, + uint32_t /* token_rate */, uint32_t /* peak_bandwidth */, + uint32_t /* latency */, uint32_t /* delay_variation */) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + if (service_type > 0x02) { + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + } + + // TODO: implement real logic + return ErrorCode::COMMAND_DISALLOWED; +} + +ErrorCode BrEdrController::RoleDiscovery(uint16_t handle, bluetooth::hci::Role* role) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + *role = connections_.GetAclConnection(handle).GetRole(); + return ErrorCode::SUCCESS; +} + +ErrorCode BrEdrController::SwitchRole(Address bd_addr, bluetooth::hci::Role role) { + // The BD_ADDR command parameter indicates for which connection + // the role switch is to be performed and shall specify a BR/EDR Controller + // for which a connection already exists. + auto connection_handle = connections_.GetAclConnectionHandle(bd_addr); + if (!connection_handle.has_value()) { + INFO(id_, "unknown connection address {}", bd_addr); + return ErrorCode::UNKNOWN_CONNECTION; + } + + AclConnection& connection = connections_.GetAclConnection(*connection_handle); + + // If there is an (e)SCO connection between the local device and the device + // identified by the BD_ADDR parameter, an attempt to perform a role switch + // shall be rejected by the local device. + if (connections_.GetScoConnectionHandle(bd_addr).has_value()) { + INFO(id_, + "role switch rejected because an Sco link is opened with" + " the target device"); + return ErrorCode::COMMAND_DISALLOWED; + } + + // If the connection between the local device and the device identified by the + // BD_ADDR parameter is placed in Sniff mode, an attempt to perform a role + // switch shall be rejected by the local device. + if (connection.GetMode() == AclConnectionState::kSniffMode) { + INFO(id_, "role switch rejected because the acl connection is in sniff mode"); + return ErrorCode::COMMAND_DISALLOWED; + } + + if (role != connection.GetRole()) { + SendLinkLayerPacket(model::packets::RoleSwitchRequestBuilder::Create(GetAddress(), bd_addr)); + } else if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { + // Note: the status is Success only if the role change procedure was + // actually performed, otherwise the status is >0. + ScheduleTask(kNoDelayMs, [this, bd_addr, role]() { + send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::ROLE_SWITCH_FAILED, bd_addr, + role)); + }); + } + + return ErrorCode::SUCCESS; +} + +void BrEdrController::IncomingRoleSwitchRequest(model::packets::LinkLayerPacketView incoming) { + auto bd_addr = incoming.GetSourceAddress(); + auto connection_handle = connections_.GetAclConnectionHandle(bd_addr); + auto switch_req = model::packets::RoleSwitchRequestView::Create(incoming); + ASSERT(switch_req.IsValid()); + + if (!connection_handle.has_value()) { + INFO(id_, "ignoring Switch Request received on unknown connection"); + return; + } + + AclConnection& connection = connections_.GetAclConnection(*connection_handle); + + if (!connection.IsRoleSwitchEnabled()) { + INFO(id_, "role switch disabled by local link policy settings"); + SendLinkLayerPacket(model::packets::RoleSwitchResponseBuilder::Create( + GetAddress(), bd_addr, static_cast(ErrorCode::ROLE_CHANGE_NOT_ALLOWED))); + } else { + INFO(id_, "role switch request accepted by local device"); + SendLinkLayerPacket(model::packets::RoleSwitchResponseBuilder::Create( + GetAddress(), bd_addr, static_cast(ErrorCode::SUCCESS))); + + bluetooth::hci::Role new_role = connection.GetRole() == bluetooth::hci::Role::CENTRAL + ? bluetooth::hci::Role::PERIPHERAL + : bluetooth::hci::Role::CENTRAL; + + connection.SetRole(new_role); + + if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { + ScheduleTask(kNoDelayMs, [this, bd_addr, new_role]() { + send_event_( + bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, bd_addr, new_role)); + }); + } + } +} + +void BrEdrController::IncomingRoleSwitchResponse(model::packets::LinkLayerPacketView incoming) { + auto bd_addr = incoming.GetSourceAddress(); + auto connection_handle = connections_.GetAclConnectionHandle(bd_addr); + auto switch_rsp = model::packets::RoleSwitchResponseView::Create(incoming); + ASSERT(switch_rsp.IsValid()); + + if (!connection_handle.has_value()) { + INFO(id_, "ignoring Switch Response received on unknown connection"); + return; + } + + AclConnection& connection = connections_.GetAclConnection(*connection_handle); + ErrorCode status = ErrorCode(switch_rsp.GetStatus()); + bluetooth::hci::Role new_role = status != ErrorCode::SUCCESS ? connection.GetRole() + : connection.GetRole() == bluetooth::hci::Role::CENTRAL + ? bluetooth::hci::Role::PERIPHERAL + : bluetooth::hci::Role::CENTRAL; + + connection.SetRole(new_role); + + if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { + ScheduleTask(kNoDelayMs, [this, status, bd_addr, new_role]() { + send_event_(bluetooth::hci::RoleChangeBuilder::Create(status, bd_addr, new_role)); + }); + } +} + +ErrorCode BrEdrController::ReadLinkPolicySettings(uint16_t handle, uint16_t* settings) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + *settings = connections_.GetAclConnection(handle).GetLinkPolicySettings(); + return ErrorCode::SUCCESS; +} + +ErrorCode BrEdrController::WriteLinkPolicySettings(uint16_t handle, uint16_t settings) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + if (settings > 7 /* Sniff + Hold + Role switch */) { + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + } + + connections_.GetAclConnection(handle).SetLinkPolicySettings(settings); + return ErrorCode::SUCCESS; +} + +ErrorCode BrEdrController::WriteDefaultLinkPolicySettings(uint16_t settings) { + if (settings > 7 /* Sniff + Hold + Role switch */) { + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + } + + default_link_policy_settings_ = settings; + return ErrorCode::SUCCESS; +} + +uint16_t BrEdrController::ReadDefaultLinkPolicySettings() const { + return default_link_policy_settings_; +} + +void BrEdrController::ReadLocalOobData() { + std::array c_array({'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '0', '0', '0', '0', '0', + '0', static_cast((oob_id_ % 0x10000) >> 8), + static_cast(oob_id_ % 0x100)}); + + std::array r_array({'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '0', '0', '0', '0', '0', + '0', static_cast((oob_id_ % 0x10000) >> 8), + static_cast(oob_id_ % 0x100)}); + + send_event_(bluetooth::hci::ReadLocalOobDataCompleteBuilder::Create(1, ErrorCode::SUCCESS, + c_array, r_array)); + oob_id_ += 1; +} + +void BrEdrController::ReadLocalOobExtendedData() { + std::array c_192_array({'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '1', '9', '2', '0', + '0', '0', static_cast((oob_id_ % 0x10000) >> 8), + static_cast(oob_id_ % 0x100)}); + + std::array r_192_array({'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '1', '9', '2', '0', + '0', '0', static_cast((oob_id_ % 0x10000) >> 8), + static_cast(oob_id_ % 0x100)}); + + std::array c_256_array({'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '2', '5', '6', '0', + '0', '0', static_cast((oob_id_ % 0x10000) >> 8), + static_cast(oob_id_ % 0x100)}); + + std::array r_256_array({'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '2', '5', '6', '0', + '0', '0', static_cast((oob_id_ % 0x10000) >> 8), + static_cast(oob_id_ % 0x100)}); + + send_event_(bluetooth::hci::ReadLocalOobExtendedDataCompleteBuilder::Create( + 1, ErrorCode::SUCCESS, c_192_array, r_192_array, c_256_array, r_256_array)); + oob_id_ += 1; +} + +ErrorCode BrEdrController::FlowSpecification(uint16_t handle, uint8_t flow_direction, + uint8_t service_type, uint32_t /* token_rate */, + uint32_t /* token_bucket_size */, + uint32_t /* peak_bandwidth */, + uint32_t /* access_latency */) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + if (flow_direction > 0x01 || service_type > 0x02) { + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + } + + // TODO: implement real logic + return ErrorCode::COMMAND_DISALLOWED; +} + +ErrorCode BrEdrController::WriteLinkSupervisionTimeout(uint16_t handle, uint16_t /* timeout */) { + if (!connections_.HasAclHandle(handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + return ErrorCode::SUCCESS; +} + +bool BrEdrController::HasAclConnection(uint16_t connection_handle) { + return connections_.HasAclHandle(connection_handle); +} + +void BrEdrController::DisconnectAll(ErrorCode reason) { + for (auto connection_handle : connections_.GetScoHandles()) { + SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create( + GetAddress(), connections_.GetScoAddress(connection_handle), + static_cast(reason))); + } + for (auto connection_handle : connections_.GetAclHandles()) { + auto const& connection = connections_.GetAclConnection(connection_handle); + SendLinkLayerPacket(model::packets::DisconnectBuilder::Create( + connection.own_address, connection.address, static_cast(reason))); + } +} + +void BrEdrController::Reset() { + // Explicitly Disconnect all existing links on reset. + // No Disconnection Complete event should be generated from the link + // disconnections, as only the HCI Command Complete event is expected for the + // HCI Reset command. + DisconnectAll(ErrorCode::REMOTE_USER_TERMINATED_CONNECTION); + + // DisconnectAll does not close the local connection contexts. + connections_.Reset([this](TaskId task_id) { CancelScheduledTask(task_id); }); + + host_supported_features_ = 0; + le_host_support_ = false; + secure_simple_pairing_host_support_ = false; + secure_connections_host_support_ = false; + page_scan_enable_ = false; + inquiry_scan_enable_ = false; + inquiry_scan_interval_ = 0x1000; + inquiry_scan_window_ = 0x0012; + page_timeout_ = 0x2000; + connection_accept_timeout_ = 0x1FA0; + page_scan_interval_ = 0x0800; + page_scan_window_ = 0x0012; + voice_setting_ = 0x0060; + authentication_enable_ = AuthenticationEnable::NOT_REQUIRED; + default_link_policy_settings_ = 0x0000; + sco_flow_control_enable_ = false; + local_name_.fill(0); + extended_inquiry_response_.fill(0); + class_of_device_ = 0; + min_encryption_key_size_ = 16; + event_mask_ = 0x00001fffffffffff; + event_mask_page_2_ = 0x0; + page_scan_repetition_mode_ = PageScanRepetitionMode::R0; + oob_id_ = 1; + key_id_ = 1; + last_inquiry_ = steady_clock::now(); + inquiry_mode_ = InquiryType::STANDARD; + inquiry_lap_ = 0; + inquiry_max_responses_ = 0; + + bluetooth::hci::Lap general_iac; + general_iac.lap_ = 0x33; // 0x9E8B33 + current_iac_lap_list_.clear(); + current_iac_lap_list_.emplace_back(general_iac); + + page_ = {}; + page_scan_ = {}; + + if (inquiry_timer_task_id_ != kInvalidTaskId) { + CancelScheduledTask(inquiry_timer_task_id_); + inquiry_timer_task_id_ = kInvalidTaskId; + } + + lm_.reset(link_manager_create(controller_ops_)); +} + +/// Drive the logic for the Page controller substate. +void BrEdrController::Paging() { + auto now = std::chrono::steady_clock::now(); + + if (page_.has_value() && now >= page_->page_timeout) { + INFO("page timeout triggered for connection with {}", page_->bd_addr.ToString()); + + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode::PAGE_TIMEOUT, 0, page_->bd_addr, bluetooth::hci::LinkType::ACL, + bluetooth::hci::Enable::DISABLED)); + + page_ = {}; + return; + } + + // Send a Page packet to the peer when a paging interval has passed. + // Paging is suppressed while a pending connection with the same peer is + // being established (i.e. two hosts initiated a connection simultaneously). + if (page_.has_value() && now >= page_->next_page_event && + !(page_scan_.has_value() && page_scan_->bd_addr == page_->bd_addr)) { + SendLinkLayerPacket(model::packets::PageBuilder::Create( + GetAddress(), page_->bd_addr, class_of_device_, page_->allow_role_switch)); + page_->next_page_event = now + kPageInterval; + } +} + +void BrEdrController::StartInquiry(milliseconds timeout) { + inquiry_timer_task_id_ = + ScheduleTask(milliseconds(timeout), [this]() { BrEdrController::InquiryTimeout(); }); +} + +void BrEdrController::InquiryCancel() { + ASSERT(inquiry_timer_task_id_ != kInvalidTaskId); + CancelScheduledTask(inquiry_timer_task_id_); + inquiry_timer_task_id_ = kInvalidTaskId; +} + +void BrEdrController::InquiryTimeout() { + if (inquiry_timer_task_id_ != kInvalidTaskId) { + inquiry_timer_task_id_ = kInvalidTaskId; + if (IsEventUnmasked(EventCode::INQUIRY_COMPLETE)) { + send_event_(bluetooth::hci::InquiryCompleteBuilder::Create(ErrorCode::SUCCESS)); + } + } +} + +void BrEdrController::SetInquiryMode(uint8_t mode) { + inquiry_mode_ = static_cast(mode); +} + +void BrEdrController::SetInquiryLAP(uint64_t lap) { inquiry_lap_ = lap; } + +void BrEdrController::SetInquiryMaxResponses(uint8_t max) { inquiry_max_responses_ = max; } + +void BrEdrController::Inquiry() { + steady_clock::time_point now = steady_clock::now(); + if (duration_cast(now - last_inquiry_) < milliseconds(2000)) { + return; + } + + SendLinkLayerPacket(model::packets::InquiryBuilder::Create(GetAddress(), Address::kEmpty, + inquiry_mode_, inquiry_lap_)); + last_inquiry_ = now; +} + +void BrEdrController::SetInquiryScanEnable(bool enable) { inquiry_scan_enable_ = enable; } + +void BrEdrController::SetPageScanEnable(bool enable) { page_scan_enable_ = enable; } + +void BrEdrController::SetPageTimeout(uint16_t page_timeout) { page_timeout_ = page_timeout; } + +ErrorCode BrEdrController::AddScoConnection(uint16_t connection_handle, uint16_t packet_type, + ScoDatapath datapath) { + if (!connections_.HasAclHandle(connection_handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + auto const& connection = connections_.GetAclConnection(connection_handle); + if (connections_.HasPendingScoConnection(connection.address)) { + return ErrorCode::COMMAND_DISALLOWED; + } + + INFO(id_, "Creating SCO connection with {}", connection.address); + + // Save connection parameters. + ScoConnectionParameters connection_parameters = { + 8000, + 8000, + 0xffff, + 0x60 /* 16bit CVSD */, + (uint8_t)bluetooth::hci::RetransmissionEffort::NO_RETRANSMISSION, + (uint16_t)((uint16_t)((packet_type >> 5) & 0x7U) | + (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_2_EV3_ALLOWED | + (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_3_EV3_ALLOWED | + (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_2_EV5_ALLOWED | + (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_3_EV5_ALLOWED)}; + connections_.CreateScoConnection(connection.address, connection_parameters, SCO_STATE_PENDING, + datapath, true); + + // Send SCO connection request to peer. + SendLinkLayerPacket(model::packets::ScoConnectionRequestBuilder::Create( + GetAddress(), connection.address, connection_parameters.transmit_bandwidth, + connection_parameters.receive_bandwidth, connection_parameters.max_latency, + connection_parameters.voice_setting, connection_parameters.retransmission_effort, + connection_parameters.packet_type, class_of_device_)); + return ErrorCode::SUCCESS; +} + +ErrorCode BrEdrController::SetupSynchronousConnection(uint16_t connection_handle, + uint32_t transmit_bandwidth, + uint32_t receive_bandwidth, + uint16_t max_latency, uint16_t voice_setting, + uint8_t retransmission_effort, + uint16_t packet_types, ScoDatapath datapath) { + if (!connections_.HasAclHandle(connection_handle)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + auto const& connection = connections_.GetAclConnection(connection_handle); + if (connections_.HasPendingScoConnection(connection.address)) { + // This command may be used to modify an exising eSCO link. + // Skip for now. TODO: should return an event + // HCI_Synchronous_Connection_Changed on both sides. + return ErrorCode::COMMAND_DISALLOWED; + } + + INFO(id_, "Creating eSCO connection with {}", connection.address); + + // Save connection parameters. + ScoConnectionParameters connection_parameters = {transmit_bandwidth, receive_bandwidth, + max_latency, voice_setting, + retransmission_effort, packet_types}; + connections_.CreateScoConnection(connection.address, connection_parameters, SCO_STATE_PENDING, + datapath); + + // Send eSCO connection request to peer. + SendLinkLayerPacket(model::packets::ScoConnectionRequestBuilder::Create( + GetAddress(), connection.address, transmit_bandwidth, receive_bandwidth, max_latency, + voice_setting, retransmission_effort, packet_types, class_of_device_)); + return ErrorCode::SUCCESS; +} + +ErrorCode BrEdrController::AcceptSynchronousConnection(Address bd_addr, uint32_t transmit_bandwidth, + uint32_t receive_bandwidth, + uint16_t max_latency, uint16_t voice_setting, + uint8_t retransmission_effort, + uint16_t packet_types) { + INFO(id_, "Accepting eSCO connection request from {}", bd_addr); + + if (!connections_.HasPendingScoConnection(bd_addr)) { + INFO(id_, "No pending eSCO connection for {}", bd_addr); + return ErrorCode::COMMAND_DISALLOWED; + } + + ErrorCode status = ErrorCode::SUCCESS; + uint16_t sco_handle = *connections_.GetScoConnectionHandle(bd_addr); + ScoLinkParameters link_parameters = {}; + ScoConnectionParameters connection_parameters = {transmit_bandwidth, receive_bandwidth, + max_latency, voice_setting, + retransmission_effort, packet_types}; + + if (!connections_.AcceptPendingScoConnection(bd_addr, connection_parameters, [this, bd_addr] { + return BrEdrController::StartScoStream(bd_addr); + })) { + connections_.CancelPendingScoConnection(bd_addr); + status = ErrorCode::STATUS_UNKNOWN; // TODO: proper status code + sco_handle = 0; + } else { + link_parameters = connections_.GetScoLinkParameters(bd_addr); + } + + // Send eSCO connection response to peer. + SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( + GetAddress(), bd_addr, (uint8_t)status, link_parameters.transmission_interval, + link_parameters.retransmission_window, link_parameters.rx_packet_length, + link_parameters.tx_packet_length, link_parameters.air_mode, link_parameters.extended)); + + // Schedule HCI Synchronous Connection Complete event. + ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr, link_parameters]() { + send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( + ErrorCode(status), sco_handle, bd_addr, + link_parameters.extended ? bluetooth::hci::ScoLinkType::ESCO + : bluetooth::hci::ScoLinkType::SCO, + link_parameters.extended ? link_parameters.transmission_interval : 0, + link_parameters.extended ? link_parameters.retransmission_window : 0, + link_parameters.extended ? link_parameters.rx_packet_length : 0, + link_parameters.extended ? link_parameters.tx_packet_length : 0, + bluetooth::hci::ScoAirMode(link_parameters.air_mode))); + }); + + return ErrorCode::SUCCESS; +} + +ErrorCode BrEdrController::RejectSynchronousConnection(Address bd_addr, uint16_t reason) { + INFO(id_, "Rejecting eSCO connection request from {}", bd_addr); + + if (reason == (uint8_t)ErrorCode::SUCCESS) { + reason = (uint8_t)ErrorCode::REMOTE_USER_TERMINATED_CONNECTION; + } + if (!connections_.HasPendingScoConnection(bd_addr)) { + return ErrorCode::COMMAND_DISALLOWED; + } + + connections_.CancelPendingScoConnection(bd_addr); + + // Send eSCO connection response to peer. + SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( + GetAddress(), bd_addr, reason, 0, 0, 0, 0, 0, 0)); + + // Schedule HCI Synchronous Connection Complete event. + ScheduleTask(kNoDelayMs, [this, reason, bd_addr]() { + send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( + ErrorCode(reason), 0, bd_addr, bluetooth::hci::ScoLinkType::ESCO, 0, 0, 0, 0, + bluetooth::hci::ScoAirMode::TRANSPARENT)); + }); + + return ErrorCode::SUCCESS; +} + +void BrEdrController::CheckExpiringConnection(uint16_t handle) { + if (!connections_.HasAclHandle(handle)) { + return; + } + + auto& connection = connections_.GetAclConnection(handle); + + if (connection.HasExpired()) { + Disconnect(handle, ErrorCode::CONNECTION_TIMEOUT, ErrorCode::CONNECTION_TIMEOUT); + return; + } + + if (connection.IsNearExpiring()) { + SendLinkLayerPacket( + model::packets::PingRequestBuilder::Create(connection.own_address, connection.address)); + ScheduleTask(std::chrono::duration_cast(connection.TimeUntilExpired()), + [this, handle] { CheckExpiringConnection(handle); }); + return; + } + + ScheduleTask(std::chrono::duration_cast(connection.TimeUntilNearExpiring()), + [this, handle] { CheckExpiringConnection(handle); }); +} + +void BrEdrController::IncomingPingRequest(model::packets::LinkLayerPacketView incoming) { + auto view = model::packets::PingRequestView::Create(incoming); + ASSERT(view.IsValid()); + SendLinkLayerPacket(model::packets::PingResponseBuilder::Create(incoming.GetDestinationAddress(), + incoming.GetSourceAddress())); +} + +TaskId BrEdrController::StartScoStream(Address address) { + auto sco_handle = connections_.GetScoConnectionHandle(address); + ASSERT(sco_handle.has_value()); + + auto sco_builder = bluetooth::hci::ScoBuilder::Create( + *sco_handle, PacketStatusFlag::CORRECTLY_RECEIVED, {0, 0, 0, 0, 0}); + + auto sco_bytes = sco_builder->SerializeToBytes(); + auto sco_view = bluetooth::hci::ScoView::Create( + pdl::packet::slice(std::make_shared>(std::move(sco_bytes)))); + ASSERT(sco_view.IsValid()); + + return SchedulePeriodicTask(0ms, 20ms, [this, address, sco_view]() { + INFO(id_, "SCO sending..."); + SendScoToRemote(sco_view); + }); +} + +TaskId BrEdrController::NextTaskId() { + TaskId task_id = task_counter_++; + while (task_id == kInvalidTaskId || + std::any_of(task_queue_.begin(), task_queue_.end(), + [=](Task const& task) { return task.task_id == task_id; })) { + task_id = task_counter_++; + } + return task_id; +} + +TaskId BrEdrController::ScheduleTask(std::chrono::milliseconds delay, TaskCallback task_callback) { + TaskId task_id = NextTaskId(); + task_queue_.emplace(std::chrono::steady_clock::now() + delay, std::move(task_callback), task_id); + return task_id; +} + +TaskId BrEdrController::SchedulePeriodicTask(std::chrono::milliseconds delay, + std::chrono::milliseconds period, + TaskCallback task_callback) { + TaskId task_id = NextTaskId(); + task_queue_.emplace(std::chrono::steady_clock::now() + delay, period, std::move(task_callback), + task_id); + return task_id; +} + +void BrEdrController::CancelScheduledTask(TaskId task_id) { + auto it = task_queue_.cbegin(); + for (; it != task_queue_.cend(); it++) { + if (it->task_id == task_id) { + task_queue_.erase(it); + return; + } + } +} + +void BrEdrController::RunPendingTasks() { + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + while (!task_queue_.empty()) { + auto it = task_queue_.begin(); + if (it->time > now) { + break; + } + + Task task = *it; + task_queue_.erase(it); + task.callback(); + + // Re-insert periodic tasks after updating the + // time by the period. + if (task.periodic) { + task.time = now + task.period; + task_queue_.insert(task); + } + } +} + +} // namespace rootcanal diff --git a/model/controller/bredr_controller.h b/model/controller/bredr_controller.h new file mode 100644 index 0000000..36abee3 --- /dev/null +++ b/model/controller/bredr_controller.h @@ -0,0 +1,484 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hci/address.h" +#include "hci/address_with_type.h" +#include "model/controller/acl_connection_handler.h" +#include "model/controller/controller_properties.h" +#include "model/controller/le_advertiser.h" +#include "model/controller/sco_connection.h" +#include "model/controller/vendor_commands/le_apcf.h" +#include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" +#include "phy.h" +#include "rust/include/rootcanal_rs.h" + +namespace rootcanal { + +using ::bluetooth::hci::Address; +using ::bluetooth::hci::AddressType; +using ::bluetooth::hci::AuthenticationEnable; +using ::bluetooth::hci::ErrorCode; +using ::bluetooth::hci::FilterAcceptListAddressType; +using ::bluetooth::hci::OpCode; +using ::bluetooth::hci::PageScanRepetitionMode; +using rootcanal::apcf::ApcfScanner; + +class BrEdrController { +public: + static constexpr size_t kIrkSize = 16; + static constexpr size_t kLtkSize = 16; + static constexpr size_t kLocalNameSize = 248; + static constexpr size_t kExtendedInquiryResponseSize = 240; + + // Unique instance identifier. + const uint32_t id_; + + BrEdrController(const Address& address, const ControllerProperties& properties, uint32_t id = 0); + ~BrEdrController(); + + ErrorCode SendCommandToRemoteByAddress(OpCode opcode, pdl::packet::slice args, + const Address& own_address, const Address& peer_address); + ErrorCode SendCommandToRemoteByHandle(OpCode opcode, pdl::packet::slice args, uint16_t handle); + ErrorCode SendScoToRemote(bluetooth::hci::ScoView sco_packet); + + void ForwardToLm(bluetooth::hci::CommandView command); + + std::vector const& ReadCurrentIacLap() const; + void WriteCurrentIacLap(std::vector iac_lap); + + ErrorCode AcceptConnectionRequest(const Address& addr, bool try_role_switch); + void MakePeripheralConnection(const Address& addr, bool try_role_switch); + ErrorCode RejectConnectionRequest(const Address& addr, uint8_t reason); + void RejectPeripheralConnection(const Address& addr, uint8_t reason); + + // HCI command Create Connection (Vol 4, Part E § 7.1.5). + ErrorCode CreateConnection(const Address& bd_addr, uint16_t packet_type, uint8_t page_scan_mode, + uint16_t clock_offset, uint8_t allow_role_switch); + + // HCI command Disconnect (Vol 4, Part E § 7.1.6). + // \p host_reason is taken from the Disconnect command, and sent over + // to the remote as disconnect error. \p controller_reason is the code + // used in the DisconnectionComplete event. + ErrorCode Disconnect( + uint16_t handle, ErrorCode host_reason, + ErrorCode controller_reason = ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST); + + // HCI command Create Connection Cancel (Vol 4, Part E § 7.1.7). + ErrorCode CreateConnectionCancel(const Address& bd_addr); + + // HCI command Read Remote Version Information (Vol 4, Part E § 7.1.23). + ErrorCode ReadRemoteVersionInformation(uint16_t connection_handle); + + // Internal task scheduler. + // This scheduler is driven by the tick function only, + // hence the precision of the scheduler is within a tick period. + class Task; + using TaskId = uint32_t; + using TaskCallback = std::function; + static constexpr TaskId kInvalidTaskId = 0; + + /// Schedule a task to be executed \p delay ms in the future. + TaskId ScheduleTask(std::chrono::milliseconds delay, TaskCallback task_callback); + + /// Schedule a task to be executed every \p period ms starting + /// \p delay ms in the future. Note that the task will be executed + /// at most once per \ref Tick() invocation, hence the period + /// cannot be lower than the \ref Tick() period. + TaskId SchedulePeriodicTask(std::chrono::milliseconds delay, std::chrono::milliseconds period, + TaskCallback task_callback); + + /// Cancel the selected task. + void CancelScheduledTask(TaskId task_id); + + // Execute tasks that are pending at the current time. + void RunPendingTasks(); + +private: + void SendDisconnectionCompleteEvent(uint16_t handle, ErrorCode reason); + +public: + const Address& GetAddress() const; + + void IncomingPacket(model::packets::LinkLayerPacketView incoming, int8_t rssi); + + void Tick(); + void Close(); + + /// Send disconnection events for all connected links, with the provided + /// reason. Does not remove the local connection contexts. + void DisconnectAll(ErrorCode reason); + + // Set the callbacks for sending packets to the HCI. + void RegisterEventChannel( + const std::function)>& send_event); + + void RegisterAclChannel( + const std::function)>& send_acl); + + void RegisterScoChannel( + const std::function)>& send_sco); + + void RegisterRemoteChannel( + const std::function, + Phy::Type, int8_t)>& send_to_remote); + + void Reset(); + void Paging(); + + void StartInquiry(std::chrono::milliseconds timeout); + void InquiryCancel(); + void InquiryTimeout(); + void SetInquiryMode(uint8_t mode); + void SetInquiryLAP(uint64_t lap); + void SetInquiryMaxResponses(uint8_t max); + void Inquiry(); + + bool GetInquiryScanEnable() const { return inquiry_scan_enable_; } + void SetInquiryScanEnable(bool enable); + + bool GetPageScanEnable() const { return page_scan_enable_; } + void SetPageScanEnable(bool enable); + + uint16_t GetPageTimeout() const { return page_timeout_; } + void SetPageTimeout(uint16_t page_timeout); + + ErrorCode ChangeConnectionPacketType(uint16_t handle, uint16_t types); + ErrorCode ChangeConnectionLinkKey(uint16_t handle); + ErrorCode CentralLinkKey(uint8_t key_flag); + ErrorCode HoldMode(uint16_t handle, uint16_t hold_mode_max_interval, + uint16_t hold_mode_min_interval); + ErrorCode SniffMode(uint16_t handle, uint16_t sniff_max_interval, uint16_t sniff_min_interval, + uint16_t sniff_attempt, uint16_t sniff_timeout); + ErrorCode ExitSniffMode(uint16_t handle); + ErrorCode QosSetup(uint16_t handle, uint8_t service_type, uint32_t token_rate, + uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation); + ErrorCode RoleDiscovery(uint16_t handle, bluetooth::hci::Role* role); + ErrorCode SwitchRole(Address bd_addr, bluetooth::hci::Role role); + ErrorCode ReadLinkPolicySettings(uint16_t handle, uint16_t* settings); + ErrorCode WriteLinkPolicySettings(uint16_t handle, uint16_t settings); + ErrorCode FlowSpecification(uint16_t handle, uint8_t flow_direction, uint8_t service_type, + uint32_t token_rate, uint32_t token_bucket_size, + uint32_t peak_bandwidth, uint32_t access_latency); + ErrorCode WriteLinkSupervisionTimeout(uint16_t handle, uint16_t timeout); + ErrorCode WriteDefaultLinkPolicySettings(uint16_t settings); + void CheckExpiringConnection(uint16_t handle); + uint16_t ReadDefaultLinkPolicySettings() const; + + void ReadLocalOobData(); + void ReadLocalOobExtendedData(); + + ErrorCode AddScoConnection(uint16_t connection_handle, uint16_t packet_type, + ScoDatapath datapath); + ErrorCode SetupSynchronousConnection(uint16_t connection_handle, uint32_t transmit_bandwidth, + uint32_t receive_bandwidth, uint16_t max_latency, + uint16_t voice_setting, uint8_t retransmission_effort, + uint16_t packet_types, ScoDatapath datapath); + ErrorCode AcceptSynchronousConnection(Address bd_addr, uint32_t transmit_bandwidth, + uint32_t receive_bandwidth, uint16_t max_latency, + uint16_t voice_setting, uint8_t retransmission_effort, + uint16_t packet_types); + ErrorCode RejectSynchronousConnection(Address bd_addr, uint16_t reason); + + // Returns true if the specified ACL connection handle is valid. + bool HasAclConnection(uint16_t connection_handle); + + void HandleAcl(bluetooth::hci::AclView acl); + + // BR/EDR Commands + + // HCI Read Rssi command (Vol 4, Part E § 7.5.4). + ErrorCode ReadRssi(uint16_t connection_handle, int8_t* rssi); + +protected: + void SendLinkLayerPacket(std::unique_ptr packet, + int8_t tx_power = 0); + + void IncomingAclPacket(model::packets::LinkLayerPacketView incoming, int8_t rssi); + void IncomingScoPacket(model::packets::LinkLayerPacketView incoming); + void IncomingDisconnectPacket(model::packets::LinkLayerPacketView incoming); + void IncomingEncryptConnection(model::packets::LinkLayerPacketView incoming); + void IncomingEncryptConnectionResponse(model::packets::LinkLayerPacketView incoming); + void IncomingInquiryPacket(model::packets::LinkLayerPacketView incoming, uint8_t rssi); + void IncomingInquiryResponsePacket(model::packets::LinkLayerPacketView incoming); + void IncomingLmpPacket(model::packets::LinkLayerPacketView incoming); + void IncomingPagePacket(model::packets::LinkLayerPacketView incoming); + void IncomingPageRejectPacket(model::packets::LinkLayerPacketView incoming); + void IncomingPageResponsePacket(model::packets::LinkLayerPacketView incoming); + void IncomingReadRemoteLmpFeatures(model::packets::LinkLayerPacketView incoming); + void IncomingReadRemoteLmpFeaturesResponse(model::packets::LinkLayerPacketView incoming); + void IncomingReadRemoteSupportedFeatures(model::packets::LinkLayerPacketView incoming); + void IncomingReadRemoteSupportedFeaturesResponse(model::packets::LinkLayerPacketView incoming); + void IncomingReadRemoteExtendedFeatures(model::packets::LinkLayerPacketView incoming); + void IncomingReadRemoteExtendedFeaturesResponse(model::packets::LinkLayerPacketView incoming); + void IncomingReadRemoteVersion(model::packets::LinkLayerPacketView incoming); + void IncomingReadRemoteVersionResponse(model::packets::LinkLayerPacketView incoming); + void IncomingReadClockOffset(model::packets::LinkLayerPacketView incoming); + void IncomingReadClockOffsetResponse(model::packets::LinkLayerPacketView incoming); + void IncomingRemoteNameRequest(model::packets::LinkLayerPacketView incoming); + void IncomingRemoteNameRequestResponse(model::packets::LinkLayerPacketView incoming); + + void IncomingScoConnectionRequest(model::packets::LinkLayerPacketView incoming); + void IncomingScoConnectionResponse(model::packets::LinkLayerPacketView incoming); + void IncomingScoDisconnect(model::packets::LinkLayerPacketView incoming); + + void IncomingPingRequest(model::packets::LinkLayerPacketView incoming); + void IncomingRoleSwitchRequest(model::packets::LinkLayerPacketView incoming); + void IncomingRoleSwitchResponse(model::packets::LinkLayerPacketView incoming); + +public: + bool IsEventUnmasked(bluetooth::hci::EventCode event) const; + + // TODO + // The Clock Offset should be specific to an ACL connection. + // Returning a proper value is not that important. + // NOLINTNEXTLINE(readability-convert-member-functions-to-static) + uint32_t GetClockOffset() const { return 0; } + + // TODO + // The Page Scan Repetition Mode should be specific to an ACL connection or + // a paging session. + PageScanRepetitionMode GetPageScanRepetitionMode() const { return page_scan_repetition_mode_; } + + // TODO + // The Encryption Key Size should be specific to an ACL connection. + uint8_t GetEncryptionKeySize() const { return 16; } + void SetMinEncryptionKeySize(uint8_t min_encryption_key_size) { + min_encryption_key_size_ = min_encryption_key_size; + } + + bool GetScoFlowControlEnable() const { return sco_flow_control_enable_; } + + AuthenticationEnable GetAuthenticationEnable() { return authentication_enable_; } + + std::array const& GetLocalName() { return local_name_; } + + uint16_t GetConnectionAcceptTimeout() const { return connection_accept_timeout_; } + + uint16_t GetVoiceSetting() const { return voice_setting_; } + uint32_t GetClassOfDevice() const { return class_of_device_; } + + uint8_t GetMaxLmpFeaturesPageNumber() { return properties_.lmp_features.size() - 1; } + + uint64_t GetLmpFeatures(uint8_t page_number = 0) { + return page_number == 1 ? host_supported_features_ : properties_.lmp_features[page_number]; + } + + void SetLocalName(std::vector const& local_name); + void SetLocalName(std::array const& local_name); + + void SetExtendedInquiryResponse(std::array const& extended_inquiry_response); + void SetExtendedInquiryResponse(std::vector const& extended_inquiry_response); + + void SetClassOfDevice(uint32_t class_of_device) { class_of_device_ = class_of_device; } + + void SetAuthenticationEnable(AuthenticationEnable enable) { authentication_enable_ = enable; } + + void SetScoFlowControlEnable(bool enable) { sco_flow_control_enable_ = enable; } + void SetVoiceSetting(uint16_t voice_setting) { voice_setting_ = voice_setting; } + void SetEventMask(uint64_t event_mask) { event_mask_ = event_mask; } + void SetEventMaskPage2(uint64_t event_mask) { event_mask_page_2_ = event_mask; } + + void SetLeHostSupport(bool enable); + void SetSecureSimplePairingSupport(bool enable); + void SetSecureConnectionsSupport(bool enable); + + void SetConnectionAcceptTimeout(uint16_t timeout) { connection_accept_timeout_ = timeout; } + + TaskId StartScoStream(Address address); + +private: + const Address& address_; + const ControllerProperties& properties_; + + // Host Supported Features (Vol 2, Part C § 3.3 Feature Mask Definition). + // Page 1 of the LMP feature mask. + uint64_t host_supported_features_{0}; + bool le_host_support_{false}; + bool secure_simple_pairing_host_support_{false}; + bool secure_connections_host_support_{false}; + + // HCI configuration parameters. + // + // Provide the current HCI Configuration Parameters as defined in section + // Vol 4, Part E § 6 of the core specification. + + // Scan Enable (Vol 4, Part E § 6.1). + bool page_scan_enable_{false}; + bool inquiry_scan_enable_{false}; + + // Inquiry Scan Interval and Window + // (Vol 4, Part E § 6.2, 6.3). + uint16_t inquiry_scan_interval_{0x1000}; + uint16_t inquiry_scan_window_{0x0012}; + + // Page Timeout (Vol 4, Part E § 6.6). + uint16_t page_timeout_{0x2000}; + + // Connection Accept Timeout (Vol 4, Part E § 6.7). + uint16_t connection_accept_timeout_{0x1FA0}; + + // Page Scan Interval and Window + // (Vol 4, Part E § 6.8, 6.9). + uint16_t page_scan_interval_{0x0800}; + uint16_t page_scan_window_{0x0012}; + + // Voice Setting (Vol 4, Part E § 6.12). + uint16_t voice_setting_{0x0060}; + + // Authentication Enable (Vol 4, Part E § 6.16). + AuthenticationEnable authentication_enable_{AuthenticationEnable::NOT_REQUIRED}; + + // Default Link Policy Settings (Vol 4, Part E § 6.18). + uint8_t default_link_policy_settings_{0x0000}; + + // Synchronous Flow Control Enable (Vol 4, Part E § 6.22). + bool sco_flow_control_enable_{false}; + + // Local Name (Vol 4, Part E § 6.23). + std::array local_name_{}; + + // Extended Inquiry Response (Vol 4, Part E § 6.24). + std::array extended_inquiry_response_{}; + + // Class of Device (Vol 4, Part E § 6.26). + uint32_t class_of_device_{0}; + + // Other configuration parameters. + + // Current IAC LAP (Vol 4, Part E § 7.3.44). + std::vector current_iac_lap_list_{}; + + // Min Encryption Key Size (Vol 4, Part E § 7.3.102). + uint8_t min_encryption_key_size_{16}; + + // Event Mask (Vol 4, Part E § 7.3.1) and + // Event Mask Page 2 (Vol 4, Part E § 7.3.69) and + // LE Event Mask (Vol 4, Part E § 7.8.1). + uint64_t event_mask_{0x00001fffffffffff}; + uint64_t event_mask_page_2_{0x0}; + + // Resolvable Private Address Timeout (Vol 4, Part E § 7.8.45). + std::chrono::seconds resolvable_private_address_timeout_{0x0384}; + + // Page Scan Repetition Mode (Vol 2 Part B § 8.3.1 Page Scan substate). + // The Page Scan Repetition Mode depends on the selected Page Scan Interval. + PageScanRepetitionMode page_scan_repetition_mode_{PageScanRepetitionMode::R0}; + + AclConnectionHandler connections_; + + // Callbacks to send packets back to the HCI. + std::function)> send_acl_; + std::function)> send_event_; + std::function)> send_sco_; + + // Callback to send packets to remote devices. + std::function, Phy::Type phy_type, + int8_t tx_power)> + send_to_remote_; + + uint32_t oob_id_{1}; + uint32_t key_id_{1}; + + // Rust state. + std::unique_ptr lm_; + struct ControllerOps controller_ops_; + + // Classic state. + struct Page { + Address bd_addr; + uint8_t allow_role_switch; + std::chrono::steady_clock::time_point next_page_event{}; + std::chrono::steady_clock::time_point page_timeout{}; + }; + + // Page substate. + // RootCanal will allow only one page request running at the same time. + std::optional page_; + + struct PageScan { + Address bd_addr; + bool authentication_required; + uint8_t allow_role_switch; + }; + + // Page scan substate. + // Set when page scan is enabled and a valid page request is received. + // Holds the state for the connection being established. + std::optional page_scan_; + + std::chrono::steady_clock::time_point last_inquiry_; + model::packets::InquiryType inquiry_mode_{model::packets::InquiryType::STANDARD}; + TaskId inquiry_timer_task_id_ = kInvalidTaskId; + uint64_t inquiry_lap_{}; + uint8_t inquiry_max_responses_{}; + +public: + // Type of scheduled tasks. + class Task { + public: + Task(std::chrono::steady_clock::time_point time, std::chrono::milliseconds period, + TaskCallback callback, TaskId task_id) + : time(time), + periodic(true), + period(period), + callback(std::move(callback)), + task_id(task_id) {} + + Task(std::chrono::steady_clock::time_point time, TaskCallback callback, TaskId task_id) + : time(time), periodic(false), callback(std::move(callback)), task_id(task_id) {} + + // Operators needed to be in a collection + bool operator<(const Task& another) const { + return std::make_pair(time, task_id) < std::make_pair(another.time, another.task_id); + } + + // These fields should no longer be public if the class ever becomes + // public or gets more complex + std::chrono::steady_clock::time_point time; + const bool periodic; + std::chrono::milliseconds period{}; + TaskCallback callback; + TaskId task_id; + }; + +private: + // List currently pending tasks. + std::set task_queue_{}; + TaskId task_counter_{0}; + + // Return the next valid unused task identifier. + TaskId NextTaskId(); +}; + +} // namespace rootcanal diff --git a/model/controller/connection_handle.h b/model/controller/connection_handle.h new file mode 100644 index 0000000..b40a7b3 --- /dev/null +++ b/model/controller/connection_handle.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace rootcanal { + +/// Core Specification Volume 4 Part E § 5.3.1. Controller handles +/// +/// Connection_Handles, Sync_Handles, Advertising_Handles, and BIG_Handles are Controller Handles +/// used to identify logical channels between the Host and the Controller. +/// +/// Connection_Handles are assigned by the Controller when a new logical transport is created or +/// reserved and reported to the Host in one of the following events: +/// - Connection Complete, +/// - Synchronous Connection Complete, +/// - LE Connection Complete, +/// - LE Enhanced Connection Complete, +/// - LE CIS Request, +/// - LE Create BIG Complete, +/// - LE BIG Sync Established, or Command Complete events following the LE Set CIG Parameters +/// command. +/// All connection handles that are assigned by the Controller shall be derived from the same +/// number space. + +enum ConnectionHandle : uint16_t { + kAclRangeStart = 0x000, + kAclRangeEnd = 0x0FF, + kScoRangeStart = 0x100, + kScoRangeEnd = 0x1FF, + kLeAclRangeStart = 0x200, + kLeAclRangeEnd = 0x2FF, + kCisRangeStart = 0xE00, + kCisRangeEnd = 0xEFF, +}; + +[[maybe_unused]] +static bool IsAclConnectionHandle(uint16_t connection_handle) { + return connection_handle >= ConnectionHandle::kAclRangeStart && + connection_handle <= ConnectionHandle::kAclRangeEnd; +} + +[[maybe_unused]] +static bool IsScoConnectionHandle(uint16_t connection_handle) { + return connection_handle >= ConnectionHandle::kScoRangeStart && + connection_handle <= ConnectionHandle::kScoRangeEnd; +} + +[[maybe_unused]] +static bool IsLeAclConnectionHandle(uint16_t connection_handle) { + return connection_handle >= ConnectionHandle::kLeAclRangeStart && + connection_handle <= ConnectionHandle::kLeAclRangeEnd; +} + +[[maybe_unused]] +static bool IsCisConnectionHandle(uint16_t connection_handle) { + return connection_handle >= ConnectionHandle::kCisRangeStart && + connection_handle <= ConnectionHandle::kCisRangeEnd; +} + +} // namespace rootcanal diff --git a/model/controller/controller_properties.cc b/model/controller/controller_properties.cc index 62240f4..8387444 100644 --- a/model/controller/controller_properties.cc +++ b/model/controller/controller_properties.cc @@ -129,25 +129,40 @@ static constexpr uint64_t LlFeatures() { static std::array SupportedCommands() { OpCodeIndex supported_commands[] = { // LINK_CONTROL - OpCodeIndex::INQUIRY, OpCodeIndex::INQUIRY_CANCEL, + OpCodeIndex::INQUIRY, + OpCodeIndex::INQUIRY_CANCEL, // OpCodeIndex::PERIODIC_INQUIRY_MODE, // OpCodeIndex::EXIT_PERIODIC_INQUIRY_MODE, - OpCodeIndex::CREATE_CONNECTION, OpCodeIndex::DISCONNECT, OpCodeIndex::ADD_SCO_CONNECTION, - OpCodeIndex::CREATE_CONNECTION_CANCEL, OpCodeIndex::ACCEPT_CONNECTION_REQUEST, - OpCodeIndex::REJECT_CONNECTION_REQUEST, OpCodeIndex::LINK_KEY_REQUEST_REPLY, - OpCodeIndex::LINK_KEY_REQUEST_NEGATIVE_REPLY, OpCodeIndex::PIN_CODE_REQUEST_REPLY, - OpCodeIndex::PIN_CODE_REQUEST_NEGATIVE_REPLY, OpCodeIndex::CHANGE_CONNECTION_PACKET_TYPE, - OpCodeIndex::AUTHENTICATION_REQUESTED, OpCodeIndex::SET_CONNECTION_ENCRYPTION, - OpCodeIndex::CHANGE_CONNECTION_LINK_KEY, OpCodeIndex::CENTRAL_LINK_KEY, + OpCodeIndex::CREATE_CONNECTION, + OpCodeIndex::DISCONNECT, + OpCodeIndex::ADD_SCO_CONNECTION, + OpCodeIndex::CREATE_CONNECTION_CANCEL, + OpCodeIndex::ACCEPT_CONNECTION_REQUEST, + OpCodeIndex::REJECT_CONNECTION_REQUEST, + OpCodeIndex::LINK_KEY_REQUEST_REPLY, + OpCodeIndex::LINK_KEY_REQUEST_NEGATIVE_REPLY, + OpCodeIndex::PIN_CODE_REQUEST_REPLY, + OpCodeIndex::PIN_CODE_REQUEST_NEGATIVE_REPLY, + OpCodeIndex::CHANGE_CONNECTION_PACKET_TYPE, + OpCodeIndex::AUTHENTICATION_REQUESTED, + OpCodeIndex::SET_CONNECTION_ENCRYPTION, + OpCodeIndex::CHANGE_CONNECTION_LINK_KEY, + OpCodeIndex::CENTRAL_LINK_KEY, OpCodeIndex::REMOTE_NAME_REQUEST, // OpCodeIndex::REMOTE_NAME_REQUEST_CANCEL, - OpCodeIndex::READ_REMOTE_SUPPORTED_FEATURES, OpCodeIndex::READ_REMOTE_EXTENDED_FEATURES, - OpCodeIndex::READ_REMOTE_VERSION_INFORMATION, OpCodeIndex::READ_CLOCK_OFFSET, - OpCodeIndex::READ_LMP_HANDLE, OpCodeIndex::SETUP_SYNCHRONOUS_CONNECTION, - OpCodeIndex::ACCEPT_SYNCHRONOUS_CONNECTION, OpCodeIndex::REJECT_SYNCHRONOUS_CONNECTION, - OpCodeIndex::IO_CAPABILITY_REQUEST_REPLY, OpCodeIndex::USER_CONFIRMATION_REQUEST_REPLY, + OpCodeIndex::READ_REMOTE_SUPPORTED_FEATURES, + OpCodeIndex::READ_REMOTE_EXTENDED_FEATURES, + OpCodeIndex::READ_REMOTE_VERSION_INFORMATION, + OpCodeIndex::READ_CLOCK_OFFSET, + OpCodeIndex::READ_LMP_HANDLE, + OpCodeIndex::SETUP_SYNCHRONOUS_CONNECTION, + OpCodeIndex::ACCEPT_SYNCHRONOUS_CONNECTION, + OpCodeIndex::REJECT_SYNCHRONOUS_CONNECTION, + OpCodeIndex::IO_CAPABILITY_REQUEST_REPLY, + OpCodeIndex::USER_CONFIRMATION_REQUEST_REPLY, OpCodeIndex::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, - OpCodeIndex::USER_PASSKEY_REQUEST_REPLY, OpCodeIndex::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, + OpCodeIndex::USER_PASSKEY_REQUEST_REPLY, + OpCodeIndex::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, OpCodeIndex::REMOTE_OOB_DATA_REQUEST_REPLY, OpCodeIndex::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, OpCodeIndex::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, @@ -162,57 +177,90 @@ static std::array SupportedCommands() { OpCodeIndex::REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY, // LINK_POLICY - OpCodeIndex::HOLD_MODE, OpCodeIndex::SNIFF_MODE, OpCodeIndex::EXIT_SNIFF_MODE, - OpCodeIndex::QOS_SETUP, OpCodeIndex::ROLE_DISCOVERY, OpCodeIndex::SWITCH_ROLE, - OpCodeIndex::READ_LINK_POLICY_SETTINGS, OpCodeIndex::WRITE_LINK_POLICY_SETTINGS, + OpCodeIndex::HOLD_MODE, + OpCodeIndex::SNIFF_MODE, + OpCodeIndex::EXIT_SNIFF_MODE, + OpCodeIndex::QOS_SETUP, + OpCodeIndex::ROLE_DISCOVERY, + OpCodeIndex::SWITCH_ROLE, + OpCodeIndex::READ_LINK_POLICY_SETTINGS, + OpCodeIndex::WRITE_LINK_POLICY_SETTINGS, OpCodeIndex::READ_DEFAULT_LINK_POLICY_SETTINGS, - OpCodeIndex::WRITE_DEFAULT_LINK_POLICY_SETTINGS, OpCodeIndex::FLOW_SPECIFICATION, + OpCodeIndex::WRITE_DEFAULT_LINK_POLICY_SETTINGS, + OpCodeIndex::FLOW_SPECIFICATION, OpCodeIndex::SNIFF_SUBRATING, // CONTROLLER_AND_BASEBAND - OpCodeIndex::SET_EVENT_MASK, OpCodeIndex::RESET, OpCodeIndex::SET_EVENT_FILTER, + OpCodeIndex::SET_EVENT_MASK, + OpCodeIndex::RESET, + OpCodeIndex::SET_EVENT_FILTER, OpCodeIndex::FLUSH, // OpCodeIndex::READ_PIN_TYPE, // OpCodeIndex::WRITE_PIN_TYPE, // OpCodeIndex::READ_STORED_LINK_KEY, // OpCodeIndex::WRITE_STORED_LINK_KEY, - OpCodeIndex::DELETE_STORED_LINK_KEY, OpCodeIndex::WRITE_LOCAL_NAME, - OpCodeIndex::READ_LOCAL_NAME, OpCodeIndex::READ_CONNECTION_ACCEPT_TIMEOUT, - OpCodeIndex::WRITE_CONNECTION_ACCEPT_TIMEOUT, OpCodeIndex::READ_PAGE_TIMEOUT, - OpCodeIndex::WRITE_PAGE_TIMEOUT, OpCodeIndex::READ_SCAN_ENABLE, - OpCodeIndex::WRITE_SCAN_ENABLE, OpCodeIndex::READ_PAGE_SCAN_ACTIVITY, - OpCodeIndex::WRITE_PAGE_SCAN_ACTIVITY, OpCodeIndex::READ_INQUIRY_SCAN_ACTIVITY, - OpCodeIndex::WRITE_INQUIRY_SCAN_ACTIVITY, OpCodeIndex::READ_AUTHENTICATION_ENABLE, - OpCodeIndex::WRITE_AUTHENTICATION_ENABLE, OpCodeIndex::READ_CLASS_OF_DEVICE, - OpCodeIndex::WRITE_CLASS_OF_DEVICE, OpCodeIndex::READ_VOICE_SETTING, - OpCodeIndex::WRITE_VOICE_SETTING, OpCodeIndex::READ_AUTOMATIC_FLUSH_TIMEOUT, + OpCodeIndex::DELETE_STORED_LINK_KEY, + OpCodeIndex::WRITE_LOCAL_NAME, + OpCodeIndex::READ_LOCAL_NAME, + OpCodeIndex::READ_CONNECTION_ACCEPT_TIMEOUT, + OpCodeIndex::WRITE_CONNECTION_ACCEPT_TIMEOUT, + OpCodeIndex::READ_PAGE_TIMEOUT, + OpCodeIndex::WRITE_PAGE_TIMEOUT, + OpCodeIndex::READ_SCAN_ENABLE, + OpCodeIndex::WRITE_SCAN_ENABLE, + OpCodeIndex::READ_PAGE_SCAN_ACTIVITY, + OpCodeIndex::WRITE_PAGE_SCAN_ACTIVITY, + OpCodeIndex::READ_INQUIRY_SCAN_ACTIVITY, + OpCodeIndex::WRITE_INQUIRY_SCAN_ACTIVITY, + OpCodeIndex::READ_AUTHENTICATION_ENABLE, + OpCodeIndex::WRITE_AUTHENTICATION_ENABLE, + OpCodeIndex::READ_CLASS_OF_DEVICE, + OpCodeIndex::WRITE_CLASS_OF_DEVICE, + OpCodeIndex::READ_VOICE_SETTING, + OpCodeIndex::WRITE_VOICE_SETTING, + OpCodeIndex::READ_AUTOMATIC_FLUSH_TIMEOUT, OpCodeIndex::WRITE_AUTOMATIC_FLUSH_TIMEOUT, // OpCodeIndex::READ_NUM_BROADCAST_RETRANSMITS, // OpCodeIndex::WRITE_NUM_BROADCAST_RETRANSMITS, - OpCodeIndex::READ_HOLD_MODE_ACTIVITY, OpCodeIndex::WRITE_HOLD_MODE_ACTIVITY, - OpCodeIndex::READ_TRANSMIT_POWER_LEVEL, OpCodeIndex::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE, + OpCodeIndex::READ_HOLD_MODE_ACTIVITY, + OpCodeIndex::WRITE_HOLD_MODE_ACTIVITY, + OpCodeIndex::READ_TRANSMIT_POWER_LEVEL, + OpCodeIndex::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE, OpCodeIndex::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE, - OpCodeIndex::SET_CONTROLLER_TO_HOST_FLOW_CONTROL, OpCodeIndex::HOST_BUFFER_SIZE, - OpCodeIndex::HOST_NUMBER_OF_COMPLETED_PACKETS, OpCodeIndex::READ_LINK_SUPERVISION_TIMEOUT, - OpCodeIndex::WRITE_LINK_SUPERVISION_TIMEOUT, OpCodeIndex::READ_NUMBER_OF_SUPPORTED_IAC, - OpCodeIndex::READ_CURRENT_IAC_LAP, OpCodeIndex::WRITE_CURRENT_IAC_LAP, - OpCodeIndex::SET_AFH_HOST_CHANNEL_CLASSIFICATION, OpCodeIndex::READ_INQUIRY_SCAN_TYPE, - OpCodeIndex::WRITE_INQUIRY_SCAN_TYPE, OpCodeIndex::READ_INQUIRY_MODE, - OpCodeIndex::WRITE_INQUIRY_MODE, OpCodeIndex::READ_PAGE_SCAN_TYPE, - OpCodeIndex::WRITE_PAGE_SCAN_TYPE, OpCodeIndex::READ_AFH_CHANNEL_ASSESSMENT_MODE, + OpCodeIndex::SET_CONTROLLER_TO_HOST_FLOW_CONTROL, + OpCodeIndex::HOST_BUFFER_SIZE, + OpCodeIndex::HOST_NUMBER_OF_COMPLETED_PACKETS, + OpCodeIndex::READ_LINK_SUPERVISION_TIMEOUT, + OpCodeIndex::WRITE_LINK_SUPERVISION_TIMEOUT, + OpCodeIndex::READ_NUMBER_OF_SUPPORTED_IAC, + OpCodeIndex::READ_CURRENT_IAC_LAP, + OpCodeIndex::WRITE_CURRENT_IAC_LAP, + OpCodeIndex::SET_AFH_HOST_CHANNEL_CLASSIFICATION, + OpCodeIndex::READ_INQUIRY_SCAN_TYPE, + OpCodeIndex::WRITE_INQUIRY_SCAN_TYPE, + OpCodeIndex::READ_INQUIRY_MODE, + OpCodeIndex::WRITE_INQUIRY_MODE, + OpCodeIndex::READ_PAGE_SCAN_TYPE, + OpCodeIndex::WRITE_PAGE_SCAN_TYPE, + OpCodeIndex::READ_AFH_CHANNEL_ASSESSMENT_MODE, OpCodeIndex::WRITE_AFH_CHANNEL_ASSESSMENT_MODE, - OpCodeIndex::READ_EXTENDED_INQUIRY_RESPONSE, OpCodeIndex::WRITE_EXTENDED_INQUIRY_RESPONSE, - OpCodeIndex::REFRESH_ENCRYPTION_KEY, OpCodeIndex::READ_SIMPLE_PAIRING_MODE, - OpCodeIndex::WRITE_SIMPLE_PAIRING_MODE, OpCodeIndex::READ_LOCAL_OOB_DATA, + OpCodeIndex::READ_EXTENDED_INQUIRY_RESPONSE, + OpCodeIndex::WRITE_EXTENDED_INQUIRY_RESPONSE, + OpCodeIndex::REFRESH_ENCRYPTION_KEY, + OpCodeIndex::READ_SIMPLE_PAIRING_MODE, + OpCodeIndex::WRITE_SIMPLE_PAIRING_MODE, + OpCodeIndex::READ_LOCAL_OOB_DATA, OpCodeIndex::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL, OpCodeIndex::WRITE_INQUIRY_TRANSMIT_POWER_LEVEL, // OpCodeIndex::READ_DEFAULT_ERRONEOUS_DATA_REPORTING, // OpCodeIndex::WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING, - OpCodeIndex::ENHANCED_FLUSH, OpCodeIndex::SEND_KEYPRESS_NOTIFICATION, + OpCodeIndex::ENHANCED_FLUSH, + OpCodeIndex::SEND_KEYPRESS_NOTIFICATION, OpCodeIndex::SET_EVENT_MASK_PAGE_2, // OpCodeIndex::READ_FLOW_CONTROL_MODE, // OpCodeIndex::WRITE_FLOW_CONTROL_MODE, - OpCodeIndex::READ_ENHANCED_TRANSMIT_POWER_LEVEL, OpCodeIndex::READ_LE_HOST_SUPPORT, + OpCodeIndex::READ_ENHANCED_TRANSMIT_POWER_LEVEL, + OpCodeIndex::READ_LE_HOST_SUPPORT, OpCodeIndex::WRITE_LE_HOST_SUPPORT, // OpCodeIndex::SET_MWS_CHANNEL_PARAMETERS, // OpCodeIndex::SET_EXTERNAL_FRAME_CONFIGURATION, @@ -239,8 +287,10 @@ static std::array SupportedCommands() { // OpCodeIndex::SET_MIN_ENCRYPTION_KEY_SIZE, // INFORMATIONAL_PARAMETERS - OpCodeIndex::READ_LOCAL_VERSION_INFORMATION, OpCodeIndex::READ_LOCAL_SUPPORTED_FEATURES, - OpCodeIndex::READ_LOCAL_EXTENDED_FEATURES, OpCodeIndex::READ_BUFFER_SIZE, + OpCodeIndex::READ_LOCAL_VERSION_INFORMATION, + OpCodeIndex::READ_LOCAL_SUPPORTED_FEATURES, + OpCodeIndex::READ_LOCAL_EXTENDED_FEATURES, + OpCodeIndex::READ_BUFFER_SIZE, OpCodeIndex::READ_BD_ADDR, // OpCodeIndex::READ_DATA_BLOCK_SIZE, OpCodeIndex::READ_LOCAL_SUPPORTED_CODECS_V1, @@ -250,39 +300,54 @@ static std::array SupportedCommands() { // OpCodeIndex::READ_LOCAL_SUPPORTED_CONTROLLER_DELAY, // STATUS_PARAMETERS - OpCodeIndex::READ_FAILED_CONTACT_COUNTER, OpCodeIndex::RESET_FAILED_CONTACT_COUNTER, + OpCodeIndex::READ_FAILED_CONTACT_COUNTER, + OpCodeIndex::RESET_FAILED_CONTACT_COUNTER, // OpCodeIndex::READ_LINK_QUALITY, - OpCodeIndex::READ_RSSI, OpCodeIndex::READ_AFH_CHANNEL_MAP, + OpCodeIndex::READ_RSSI, + OpCodeIndex::READ_AFH_CHANNEL_MAP, // OpCodeIndex::READ_CLOCK, OpCodeIndex::READ_ENCRYPTION_KEY_SIZE, // OpCodeIndex::GET_MWS_TRANSPORT_LAYER_CONFIGURATION, // OpCodeIndex::SET_TRIGGERED_CLOCK_CAPTURE, // TESTING - OpCodeIndex::READ_LOOPBACK_MODE, OpCodeIndex::WRITE_LOOPBACK_MODE, + OpCodeIndex::READ_LOOPBACK_MODE, + OpCodeIndex::WRITE_LOOPBACK_MODE, OpCodeIndex::ENABLE_IMPLEMENTATION_UNDER_TEST_MODE, OpCodeIndex::WRITE_SIMPLE_PAIRING_DEBUG_MODE, OpCodeIndex::WRITE_SECURE_CONNECTIONS_TEST_MODE, // LE_CONTROLLER - OpCodeIndex::LE_SET_EVENT_MASK, OpCodeIndex::LE_READ_BUFFER_SIZE_V1, - OpCodeIndex::LE_READ_LOCAL_SUPPORTED_FEATURES_PAGE_0, OpCodeIndex::LE_SET_RANDOM_ADDRESS, + OpCodeIndex::LE_SET_EVENT_MASK, + OpCodeIndex::LE_READ_BUFFER_SIZE_V1, + OpCodeIndex::LE_READ_LOCAL_SUPPORTED_FEATURES_PAGE_0, + OpCodeIndex::LE_SET_RANDOM_ADDRESS, OpCodeIndex::LE_SET_ADVERTISING_PARAMETERS, OpCodeIndex::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER, - OpCodeIndex::LE_SET_ADVERTISING_DATA, OpCodeIndex::LE_SET_SCAN_RESPONSE_DATA, - OpCodeIndex::LE_SET_ADVERTISING_ENABLE, OpCodeIndex::LE_SET_SCAN_PARAMETERS, - OpCodeIndex::LE_SET_SCAN_ENABLE, OpCodeIndex::LE_CREATE_CONNECTION, - OpCodeIndex::LE_CREATE_CONNECTION_CANCEL, OpCodeIndex::LE_READ_FILTER_ACCEPT_LIST_SIZE, + OpCodeIndex::LE_SET_ADVERTISING_DATA, + OpCodeIndex::LE_SET_SCAN_RESPONSE_DATA, + OpCodeIndex::LE_SET_ADVERTISING_ENABLE, + OpCodeIndex::LE_SET_SCAN_PARAMETERS, + OpCodeIndex::LE_SET_SCAN_ENABLE, + OpCodeIndex::LE_CREATE_CONNECTION, + OpCodeIndex::LE_CREATE_CONNECTION_CANCEL, + OpCodeIndex::LE_READ_FILTER_ACCEPT_LIST_SIZE, OpCodeIndex::LE_CLEAR_FILTER_ACCEPT_LIST, OpCodeIndex::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST, - OpCodeIndex::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST, OpCodeIndex::LE_CONNECTION_UPDATE, - OpCodeIndex::LE_SET_HOST_CHANNEL_CLASSIFICATION, OpCodeIndex::LE_READ_CHANNEL_MAP, - OpCodeIndex::LE_READ_REMOTE_FEATURES_PAGE_0, OpCodeIndex::LE_ENCRYPT, - OpCodeIndex::LE_RAND, OpCodeIndex::LE_START_ENCRYPTION, + OpCodeIndex::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST, + OpCodeIndex::LE_CONNECTION_UPDATE, + OpCodeIndex::LE_SET_HOST_CHANNEL_CLASSIFICATION, + OpCodeIndex::LE_READ_CHANNEL_MAP, + OpCodeIndex::LE_READ_REMOTE_FEATURES_PAGE_0, + OpCodeIndex::LE_ENCRYPT, + OpCodeIndex::LE_RAND, + OpCodeIndex::LE_START_ENCRYPTION, OpCodeIndex::LE_LONG_TERM_KEY_REQUEST_REPLY, OpCodeIndex::LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY, - OpCodeIndex::LE_READ_SUPPORTED_STATES, OpCodeIndex::LE_RECEIVER_TEST_V1, - OpCodeIndex::LE_TRANSMITTER_TEST_V1, OpCodeIndex::LE_TEST_END, + OpCodeIndex::LE_READ_SUPPORTED_STATES, + OpCodeIndex::LE_RECEIVER_TEST_V1, + OpCodeIndex::LE_TRANSMITTER_TEST_V1, + OpCodeIndex::LE_TEST_END, OpCodeIndex::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY, OpCodeIndex::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY, OpCodeIndex::LE_SET_DATA_LENGTH, @@ -291,13 +356,17 @@ static std::array SupportedCommands() { OpCodeIndex::LE_READ_LOCAL_P_256_PUBLIC_KEY, // OpCodeIndex::LE_GENERATE_DHKEY_V1, OpCodeIndex::LE_ADD_DEVICE_TO_RESOLVING_LIST, - OpCodeIndex::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST, OpCodeIndex::LE_CLEAR_RESOLVING_LIST, - OpCodeIndex::LE_READ_RESOLVING_LIST_SIZE, OpCodeIndex::LE_READ_PEER_RESOLVABLE_ADDRESS, + OpCodeIndex::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST, + OpCodeIndex::LE_CLEAR_RESOLVING_LIST, + OpCodeIndex::LE_READ_RESOLVING_LIST_SIZE, + OpCodeIndex::LE_READ_PEER_RESOLVABLE_ADDRESS, OpCodeIndex::LE_READ_LOCAL_RESOLVABLE_ADDRESS, OpCodeIndex::LE_SET_ADDRESS_RESOLUTION_ENABLE, OpCodeIndex::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT, - OpCodeIndex::LE_READ_MAXIMUM_DATA_LENGTH, OpCodeIndex::LE_READ_PHY, - OpCodeIndex::LE_SET_DEFAULT_PHY, OpCodeIndex::LE_SET_PHY, + OpCodeIndex::LE_READ_MAXIMUM_DATA_LENGTH, + OpCodeIndex::LE_READ_PHY, + OpCodeIndex::LE_SET_DEFAULT_PHY, + OpCodeIndex::LE_SET_PHY, // OpCodeIndex::LE_RECEIVER_TEST_V2, // OpCodeIndex::LE_TRANSMITTER_TEST_V2, OpCodeIndex::LE_SET_ADVERTISING_SET_RANDOM_ADDRESS, @@ -307,11 +376,13 @@ static std::array SupportedCommands() { OpCodeIndex::LE_SET_EXTENDED_ADVERTISING_ENABLE, OpCodeIndex::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH, OpCodeIndex::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS, - OpCodeIndex::LE_REMOVE_ADVERTISING_SET, OpCodeIndex::LE_CLEAR_ADVERTISING_SETS, + OpCodeIndex::LE_REMOVE_ADVERTISING_SET, + OpCodeIndex::LE_CLEAR_ADVERTISING_SETS, OpCodeIndex::LE_SET_PERIODIC_ADVERTISING_PARAMETERS_V1, OpCodeIndex::LE_SET_PERIODIC_ADVERTISING_DATA, OpCodeIndex::LE_SET_PERIODIC_ADVERTISING_ENABLE, - OpCodeIndex::LE_SET_EXTENDED_SCAN_PARAMETERS, OpCodeIndex::LE_SET_EXTENDED_SCAN_ENABLE, + OpCodeIndex::LE_SET_EXTENDED_SCAN_PARAMETERS, + OpCodeIndex::LE_SET_EXTENDED_SCAN_ENABLE, OpCodeIndex::LE_EXTENDED_CREATE_CONNECTION_V1, OpCodeIndex::LE_PERIODIC_ADVERTISING_CREATE_SYNC, OpCodeIndex::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL, @@ -322,7 +393,8 @@ static std::array SupportedCommands() { OpCodeIndex::LE_READ_PERIODIC_ADVERTISER_LIST_SIZE, // OpCodeIndex::LE_READ_TRANSMIT_POWER, OpCodeIndex::LE_READ_RF_PATH_COMPENSATION_POWER, - OpCodeIndex::LE_WRITE_RF_PATH_COMPENSATION_POWER, OpCodeIndex::LE_SET_PRIVACY_MODE, + OpCodeIndex::LE_WRITE_RF_PATH_COMPENSATION_POWER, + OpCodeIndex::LE_SET_PRIVACY_MODE, // OpCodeIndex::LE_RECEIVER_TEST_V3, // OpCodeIndex::LE_TRANSMITTER_TEST_V3, // OpCodeIndex::LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS, @@ -342,15 +414,19 @@ static std::array SupportedCommands() { // OpCodeIndex::LE_MODIFY_SLEEP_CLOCK_ACCURACY, OpCodeIndex::LE_READ_BUFFER_SIZE_V2, // OpCodeIndex::LE_READ_ISO_TX_SYNC, - OpCodeIndex::LE_SET_CIG_PARAMETERS, OpCodeIndex::LE_SET_CIG_PARAMETERS_TEST, - OpCodeIndex::LE_CREATE_CIS, OpCodeIndex::LE_REMOVE_CIG, - OpCodeIndex::LE_ACCEPT_CIS_REQUEST, OpCodeIndex::LE_REJECT_CIS_REQUEST, + OpCodeIndex::LE_SET_CIG_PARAMETERS, + OpCodeIndex::LE_SET_CIG_PARAMETERS_TEST, + OpCodeIndex::LE_CREATE_CIS, + OpCodeIndex::LE_REMOVE_CIG, + OpCodeIndex::LE_ACCEPT_CIS_REQUEST, + OpCodeIndex::LE_REJECT_CIS_REQUEST, // OpCodeIndex::LE_CREATE_BIG, // OpCodeIndex::LE_CREATE_BIG_TEST, // OpCodeIndex::LE_TERMINATE_BIG, // OpCodeIndex::LE_BIG_CREATE_SYNC, // OpCodeIndex::LE_BIG_TERMINATE_SYNC, - OpCodeIndex::LE_REQUEST_PEER_SCA, OpCodeIndex::LE_SETUP_ISO_DATA_PATH, + OpCodeIndex::LE_REQUEST_PEER_SCA, + OpCodeIndex::LE_SETUP_ISO_DATA_PATH, OpCodeIndex::LE_REMOVE_ISO_DATA_PATH, // OpCodeIndex::LE_ISO_TRANSMIT_TEST, // OpCodeIndex::LE_ISO_RECEIVE_TEST, diff --git a/model/controller/dual_mode_controller.cc b/model/controller/dual_mode_controller.cc index 4642840..71fa169 100644 --- a/model/controller/dual_mode_controller.cc +++ b/model/controller/dual_mode_controller.cc @@ -74,14 +74,25 @@ void DualModeController::SetProperties(ControllerProperties properties) { std::string DualModeController::GetTypeString() const { return "Simulated Bluetooth Controller"; } void DualModeController::ReceiveLinkLayerPacket(model::packets::LinkLayerPacketView incoming, - Phy::Type /*type*/, int8_t rssi) { - link_layer_controller_.IncomingPacket(incoming, rssi); + Phy::Type type, int8_t rssi) { + switch (type) { + case Phy::Type::BR_EDR: + bredr_controller_.IncomingPacket(incoming, rssi); + break; + case Phy::Type::LOW_ENERGY: + le_controller_.IncomingPacket(incoming, rssi); + break; + } } -void DualModeController::Tick() { link_layer_controller_.Tick(); } +void DualModeController::Tick() { + bredr_controller_.Tick(); + le_controller_.Tick(); +} void DualModeController::Close() { - link_layer_controller_.Close(); + bredr_controller_.Close(); + le_controller_.Close(); Device::Close(); } @@ -103,43 +114,56 @@ DualModeController::DualModeController(ControllerProperties properties) invalid_packet_handler_ = [](uint32_t, InvalidPacketReason, std::string message, std::vector const&) { FATAL("{}", message); }; - link_layer_controller_.RegisterRemoteChannel( + bredr_controller_.RegisterRemoteChannel( + [this](std::shared_ptr packet, Phy::Type phy_type, + int8_t tx_power) { this->SendLinkLayerPacket(packet, phy_type, tx_power); }); + le_controller_.RegisterRemoteChannel( [this](std::shared_ptr packet, Phy::Type phy_type, int8_t tx_power) { this->SendLinkLayerPacket(packet, phy_type, tx_power); }); } void DualModeController::ForwardToLm(CommandView command) { DEBUG(id_, "<< [LM] {}", bluetooth::hci::OpCodeText(command.GetOpCode())); - link_layer_controller_.ForwardToLm(command); + bredr_controller_.ForwardToLm(command); } void DualModeController::ForwardToLl(CommandView command) { DEBUG(id_, "<< [LL] {}", bluetooth::hci::OpCodeText(command.GetOpCode())); - link_layer_controller_.ForwardToLl(command); + le_controller_.ForwardToLl(command); } void DualModeController::HandleAcl(std::shared_ptr> packet) { auto acl_packet = bluetooth::hci::AclView::Create(pdl::packet::slice(packet)); CHECK_PACKET_VIEW(acl_packet); + uint16_t connection_handle = acl_packet.GetHandle(); if (loopback_mode_ == LoopbackMode::ENABLE_LOCAL) { - uint16_t handle = acl_packet.GetHandle(); - std::vector payload(acl_packet.GetPayload()); - send_acl_(bluetooth::hci::AclBuilder::Create(handle, acl_packet.GetPacketBoundaryFlag(), - acl_packet.GetBroadcastFlag(), - std::move(payload))); + send_acl_(bluetooth::hci::AclBuilder::Create( + connection_handle, acl_packet.GetPacketBoundaryFlag(), acl_packet.GetBroadcastFlag(), + std::move(payload))); std::vector completed_packets; bluetooth::hci::CompletedPackets cp; - cp.connection_handle_ = handle; + cp.connection_handle_ = connection_handle; cp.host_num_of_completed_packets_ = 1; completed_packets.push_back(cp); send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create(completed_packets)); return; } - link_layer_controller_.HandleAcl(acl_packet); + if (IsAclConnectionHandle(connection_handle)) { + return bredr_controller_.HandleAcl(acl_packet); + } + + if (IsLeAclConnectionHandle(connection_handle)) { + return le_controller_.HandleAcl(acl_packet); + } + + // The packet connection handle is not the ranges of valid ACL connection handles. + // Send HCI Number of Completed Packets now to return the credit. + send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create( + {bluetooth::hci::CompletedPackets(connection_handle, 1)})); } void DualModeController::HandleSco(std::shared_ptr> packet) { @@ -157,19 +181,19 @@ void DualModeController::HandleSco(std::shared_ptr> packet) cp.connection_handle_ = handle; cp.host_num_of_completed_packets_ = 1; completed_packets.push_back(cp); - if (link_layer_controller_.GetScoFlowControlEnable()) { + if (bredr_controller_.GetScoFlowControlEnable()) { send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create(completed_packets)); } return; } - link_layer_controller_.SendScoToRemote(sco_packet); + bredr_controller_.SendScoToRemote(sco_packet); } void DualModeController::HandleIso(std::shared_ptr> packet) { auto iso = bluetooth::hci::IsoView::Create(pdl::packet::slice(packet)); CHECK_PACKET_VIEW(iso); - link_layer_controller_.HandleIso(iso); + le_controller_.HandleIso(iso); } void DualModeController::HandleCommand(std::shared_ptr> packet) { @@ -252,7 +276,8 @@ void DualModeController::RegisterEventChannel( event->Serialize(*bytes); send_event(bytes); }; - link_layer_controller_.RegisterEventChannel(send_event_); + bredr_controller_.RegisterEventChannel(send_event_); + le_controller_.RegisterEventChannel(send_event_); } void DualModeController::RegisterAclChannel( @@ -262,7 +287,8 @@ void DualModeController::RegisterAclChannel( acl_data->Serialize(*bytes); send_acl(bytes); }; - link_layer_controller_.RegisterAclChannel(send_acl_); + bredr_controller_.RegisterAclChannel(send_acl_); + le_controller_.RegisterAclChannel(send_acl_); } void DualModeController::RegisterScoChannel( @@ -272,7 +298,7 @@ void DualModeController::RegisterScoChannel( sco_data->Serialize(*bytes); send_sco(bytes); }; - link_layer_controller_.RegisterScoChannel(send_sco_); + bredr_controller_.RegisterScoChannel(send_sco_); } void DualModeController::RegisterIsoChannel( @@ -282,7 +308,7 @@ void DualModeController::RegisterIsoChannel( iso_data->Serialize(*bytes); send_iso(bytes); }; - link_layer_controller_.RegisterIsoChannel(send_iso_); + le_controller_.RegisterIsoChannel(send_iso_); } void DualModeController::Reset(CommandView command) { @@ -291,7 +317,8 @@ void DualModeController::Reset(CommandView command) { DEBUG(id_, "<< Reset"); - link_layer_controller_.Reset(); + bredr_controller_.Reset(); + le_controller_.Reset(); loopback_mode_ = LoopbackMode::NO_LOOPBACK; controller_reset_ = true; @@ -316,7 +343,7 @@ void DualModeController::ReadFailedContactCounter(CommandView command) { uint16_t connection_handle = command_view.GetConnectionHandle(); uint16_t failed_contact_counter = 0; - ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) + ErrorCode status = bredr_controller_.HasAclConnection(connection_handle) ? ErrorCode::SUCCESS : ErrorCode::UNKNOWN_CONNECTION; @@ -335,7 +362,7 @@ void DualModeController::ResetFailedContactCounter(CommandView command) { DEBUG(id_, "<< Reset Failed Contact Counter"); DEBUG(id_, " connection_handle=0x{:x}", connection_handle); - ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) + ErrorCode status = bredr_controller_.HasAclConnection(connection_handle) ? ErrorCode::SUCCESS : ErrorCode::UNKNOWN_CONNECTION; @@ -353,7 +380,11 @@ void DualModeController::ReadRssi(CommandView command) { DEBUG(id_, "<< Read RSSI"); DEBUG(id_, " connection_handle=0x{:x}", connection_handle); - ErrorCode status = link_layer_controller_.ReadRssi(connection_handle, &rssi); + ErrorCode status = IsAclConnectionHandle(connection_handle) + ? bredr_controller_.ReadRssi(connection_handle, &rssi) + : IsLeAclConnectionHandle(connection_handle) + ? le_controller_.ReadRssi(connection_handle, &rssi) + : ErrorCode::UNKNOWN_CONNECTION; send_event_(bluetooth::hci::ReadRssiCompleteBuilder::Create(kNumCommandPackets, status, connection_handle, rssi)); } @@ -367,7 +398,7 @@ void DualModeController::ReadEncryptionKeySize(CommandView command) { send_event_(bluetooth::hci::ReadEncryptionKeySizeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, command_view.GetConnectionHandle(), - link_layer_controller_.GetEncryptionKeySize())); + bredr_controller_.GetEncryptionKeySize())); } void DualModeController::HostBufferSize(CommandView command) { @@ -401,12 +432,16 @@ void DualModeController::ReadRemoteVersionInformation(CommandView command) { auto command_view = bluetooth::hci::ReadRemoteVersionInformationView::Create(command); CHECK_PACKET_VIEW(command_view); + uint16_t connection_handle = command_view.GetConnectionHandle(); + DEBUG(id_, "<< Read Remote Version Information"); - DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); - auto status = link_layer_controller_.SendCommandToRemoteByHandle( - OpCode::READ_REMOTE_VERSION_INFORMATION, command.bytes(), - command_view.GetConnectionHandle()); + auto status = IsAclConnectionHandle(connection_handle) + ? bredr_controller_.ReadRemoteVersionInformation(connection_handle) + : IsLeAclConnectionHandle(connection_handle) + ? le_controller_.ReadRemoteVersionInformation(connection_handle) + : ErrorCode::UNKNOWN_CONNECTION; send_event_(bluetooth::hci::ReadRemoteVersionInformationStatusBuilder::Create( status, kNumCommandPackets)); @@ -439,7 +474,7 @@ void DualModeController::ReadLocalSupportedFeatures(CommandView command) { DEBUG(id_, "<< Read Local Supported Features"); send_event_(bluetooth::hci::ReadLocalSupportedFeaturesCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, link_layer_controller_.GetLmpFeatures())); + kNumCommandPackets, ErrorCode::SUCCESS, bredr_controller_.GetLmpFeatures())); } void DualModeController::ReadLocalSupportedCodecsV1(CommandView command) { @@ -463,8 +498,8 @@ void DualModeController::ReadLocalExtendedFeatures(CommandView command) { send_event_(bluetooth::hci::ReadLocalExtendedFeaturesCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, page_number, - link_layer_controller_.GetMaxLmpFeaturesPageNumber(), - link_layer_controller_.GetLmpFeatures(page_number))); + bredr_controller_.GetMaxLmpFeaturesPageNumber(), + bredr_controller_.GetLmpFeatures(page_number))); } void DualModeController::ReadRemoteExtendedFeatures(CommandView command) { @@ -475,9 +510,9 @@ void DualModeController::ReadRemoteExtendedFeatures(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); DEBUG(id_, " page_number={}", command_view.GetPageNumber()); - auto status = link_layer_controller_.SendCommandToRemoteByHandle( - OpCode::READ_REMOTE_EXTENDED_FEATURES, command_view.bytes(), - command_view.GetConnectionHandle()); + auto status = bredr_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_EXTENDED_FEATURES, + command_view.bytes(), + command_view.GetConnectionHandle()); send_event_(bluetooth::hci::ReadRemoteExtendedFeaturesStatusBuilder::Create(status, kNumCommandPackets)); @@ -491,7 +526,7 @@ void DualModeController::SwitchRole(CommandView command) { DEBUG(id_, " bd_addr={}", command_view.GetBdAddr()); DEBUG(id_, " role={}", bluetooth::hci::RoleText(command_view.GetRole())); - auto status = link_layer_controller_.SwitchRole(command_view.GetBdAddr(), command_view.GetRole()); + auto status = bredr_controller_.SwitchRole(command_view.GetBdAddr(), command_view.GetRole()); send_event_(bluetooth::hci::SwitchRoleStatusBuilder::Create(status, kNumCommandPackets)); } @@ -503,7 +538,7 @@ void DualModeController::ReadRemoteSupportedFeatures(CommandView command) { DEBUG(id_, "<< Read Remote Supported Features"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - auto status = link_layer_controller_.SendCommandToRemoteByHandle( + auto status = bredr_controller_.SendCommandToRemoteByHandle( OpCode::READ_REMOTE_SUPPORTED_FEATURES, command_view.bytes(), command_view.GetConnectionHandle()); @@ -520,8 +555,8 @@ void DualModeController::ReadClockOffset(CommandView command) { uint16_t handle = command_view.GetConnectionHandle(); - auto status = link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_CLOCK_OFFSET, - command_view.bytes(), handle); + auto status = bredr_controller_.SendCommandToRemoteByHandle(OpCode::READ_CLOCK_OFFSET, + command_view.bytes(), handle); send_event_(bluetooth::hci::ReadClockOffsetStatusBuilder::Create(status, kNumCommandPackets)); } @@ -536,7 +571,7 @@ void DualModeController::AddScoConnection(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); - auto status = link_layer_controller_.AddScoConnection( + auto status = bredr_controller_.AddScoConnection( command_view.GetConnectionHandle(), command_view.GetPacketType(), ScoDatapath::NORMAL); send_event_(bluetooth::hci::AddScoConnectionStatusBuilder::Create(status, kNumCommandPackets)); @@ -550,7 +585,7 @@ void DualModeController::SetupSynchronousConnection(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); - auto status = link_layer_controller_.SetupSynchronousConnection( + auto status = bredr_controller_.SetupSynchronousConnection( command_view.GetConnectionHandle(), command_view.GetTransmitBandwidth(), command_view.GetReceiveBandwidth(), command_view.GetMaxLatency(), command_view.GetVoiceSetting(), @@ -569,7 +604,7 @@ void DualModeController::AcceptSynchronousConnection(CommandView command) { DEBUG(id_, " bd_addr={}", command_view.GetBdAddr()); DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); - auto status = link_layer_controller_.AcceptSynchronousConnection( + auto status = bredr_controller_.AcceptSynchronousConnection( command_view.GetBdAddr(), command_view.GetTransmitBandwidth(), command_view.GetReceiveBandwidth(), command_view.GetMaxLatency(), command_view.GetVoiceSetting(), @@ -702,9 +737,9 @@ void DualModeController::EnhancedSetupSynchronousConnection(CommandView command) } if (status == ErrorCode::SUCCESS) { - status = link_layer_controller_.SetupSynchronousConnection( + status = bredr_controller_.SetupSynchronousConnection( command_view.GetConnectionHandle(), transmit_bandwidth, receive_bandwidth, - command_view.GetMaxLatency(), link_layer_controller_.GetVoiceSetting(), + command_view.GetMaxLatency(), bredr_controller_.GetVoiceSetting(), static_cast(command_view.GetRetransmissionEffort()), command_view.GetPacketType(), datapath); } @@ -834,9 +869,9 @@ void DualModeController::EnhancedAcceptSynchronousConnection(CommandView command } if (status == ErrorCode::SUCCESS) { - status = link_layer_controller_.AcceptSynchronousConnection( + status = bredr_controller_.AcceptSynchronousConnection( command_view.GetBdAddr(), transmit_bandwidth, receive_bandwidth, - command_view.GetMaxLatency(), link_layer_controller_.GetVoiceSetting(), + command_view.GetMaxLatency(), bredr_controller_.GetVoiceSetting(), static_cast(command_view.GetRetransmissionEffort()), command_view.GetPacketType()); } @@ -853,8 +888,8 @@ void DualModeController::RejectSynchronousConnection(CommandView command) { DEBUG(id_, " bd_addr={}", command_view.GetBdAddr()); DEBUG(id_, " reason={}", bluetooth::hci::RejectConnectionReasonText(command_view.GetReason())); - auto status = link_layer_controller_.RejectSynchronousConnection( - command_view.GetBdAddr(), (uint16_t)command_view.GetReason()); + auto status = bredr_controller_.RejectSynchronousConnection(command_view.GetBdAddr(), + (uint16_t)command_view.GetReason()); send_event_(bluetooth::hci::RejectSynchronousConnectionStatusBuilder::Create(status, kNumCommandPackets)); @@ -885,7 +920,7 @@ void DualModeController::EnhancedFlush(CommandView command) { // TODO: When adding a queue of ACL packets. // Send the Enhanced Flush Complete event after discarding // all L2CAP packets identified by the Packet Type. - if (link_layer_controller_.IsEventUnmasked(bluetooth::hci::EventCode::ENHANCED_FLUSH_COMPLETE)) { + if (bredr_controller_.IsEventUnmasked(bluetooth::hci::EventCode::ENHANCED_FLUSH_COMPLETE)) { send_event_(bluetooth::hci::EnhancedFlushCompleteBuilder::Create(handle)); } } @@ -897,7 +932,8 @@ void DualModeController::SetEventMaskPage2(CommandView command) { DEBUG(id_, "<< Set Event Mask Page 2"); DEBUG(id_, " event_mask_page_2=0x{:x}", command_view.GetEventMaskPage2()); - link_layer_controller_.SetEventMaskPage2(command_view.GetEventMaskPage2()); + bredr_controller_.SetEventMaskPage2(command_view.GetEventMaskPage2()); + le_controller_.SetEventMaskPage2(command_view.GetEventMaskPage2()); send_event_(bluetooth::hci::SetEventMaskPage2CompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -907,7 +943,7 @@ void DualModeController::ReadLocalOobData(CommandView command) { DEBUG(id_, "<< Read Local Oob Data"); - link_layer_controller_.ReadLocalOobData(); + bredr_controller_.ReadLocalOobData(); } void DualModeController::ReadLocalOobExtendedData(CommandView command) { @@ -915,7 +951,7 @@ void DualModeController::ReadLocalOobExtendedData(CommandView command) { DEBUG(id_, "<< Read Local Oob Extended Data"); - link_layer_controller_.ReadLocalOobExtendedData(); + bredr_controller_.ReadLocalOobExtendedData(); } void DualModeController::SetMinEncryptionKeySize(CommandView command) { @@ -925,7 +961,7 @@ void DualModeController::SetMinEncryptionKeySize(CommandView command) { DEBUG(id_, "<< Set Min Encryption Key Size"); DEBUG(id_, " min_encryption_key_size={}", command_view.GetMinEncryptionKeySize()); - link_layer_controller_.SetMinEncryptionKeySize(command_view.GetMinEncryptionKeySize()); + bredr_controller_.SetMinEncryptionKeySize(command_view.GetMinEncryptionKeySize()); send_event_(bluetooth::hci::SetMinEncryptionKeySizeCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -939,7 +975,7 @@ void DualModeController::WriteSimplePairingMode(CommandView command) { command_view.GetSimplePairingMode() == bluetooth::hci::Enable::ENABLED); auto enabled = command_view.GetSimplePairingMode() == bluetooth::hci::Enable::ENABLED; - link_layer_controller_.SetSecureSimplePairingSupport(enabled); + bredr_controller_.SetSecureSimplePairingSupport(enabled); send_event_(bluetooth::hci::WriteSimplePairingModeCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -955,7 +991,7 @@ void DualModeController::ChangeConnectionPacketType(CommandView command) { uint16_t handle = command_view.GetConnectionHandle(); uint16_t packet_type = static_cast(command_view.GetPacketType()); - auto status = link_layer_controller_.ChangeConnectionPacketType(handle, packet_type); + auto status = bredr_controller_.ChangeConnectionPacketType(handle, packet_type); send_event_(bluetooth::hci::ChangeConnectionPacketTypeStatusBuilder::Create(status, kNumCommandPackets)); } @@ -969,7 +1005,7 @@ void DualModeController::WriteLeHostSupport(CommandView command) { command_view.GetLeSupportedHost() == bluetooth::hci::Enable::ENABLED); auto le_support = command_view.GetLeSupportedHost() == bluetooth::hci::Enable::ENABLED; - link_layer_controller_.SetLeHostSupport(le_support); + bredr_controller_.SetLeHostSupport(le_support); send_event_(bluetooth::hci::WriteLeHostSupportCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -982,8 +1018,8 @@ void DualModeController::WriteSecureConnectionsHostSupport(CommandView command) DEBUG(id_, " secure_connections_host_support={}", command_view.GetSecureConnectionsHostSupport() == bluetooth::hci::Enable::ENABLED); - link_layer_controller_.SetSecureConnectionsSupport( - command_view.GetSecureConnectionsHostSupport() == bluetooth::hci::Enable::ENABLED); + bredr_controller_.SetSecureConnectionsSupport(command_view.GetSecureConnectionsHostSupport() == + bluetooth::hci::Enable::ENABLED); send_event_(bluetooth::hci::WriteSecureConnectionsHostSupportCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -995,7 +1031,8 @@ void DualModeController::SetEventMask(CommandView command) { DEBUG(id_, "<< Set Event Mask"); DEBUG(id_, " event_mask=0x{:x}", command_view.GetEventMask()); - link_layer_controller_.SetEventMask(command_view.GetEventMask()); + bredr_controller_.SetEventMask(command_view.GetEventMask()); + le_controller_.SetEventMask(command_view.GetEventMask()); send_event_(bluetooth::hci::SetEventMaskCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1018,7 +1055,7 @@ void DualModeController::WriteInquiryMode(CommandView command) { DEBUG(id_, "<< Write Inquiry Mode"); DEBUG(id_, " inquiry_mode={}", bluetooth::hci::InquiryModeText(command_view.GetInquiryMode())); - link_layer_controller_.SetInquiryMode(static_cast(command_view.GetInquiryMode())); + bredr_controller_.SetInquiryMode(static_cast(command_view.GetInquiryMode())); send_event_(bluetooth::hci::WriteInquiryModeCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1077,7 +1114,7 @@ void DualModeController::ChangeConnectionLinkKey(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); uint16_t handle = command_view.GetConnectionHandle(); - auto status = link_layer_controller_.ChangeConnectionLinkKey(handle); + auto status = bredr_controller_.ChangeConnectionLinkKey(handle); send_event_( bluetooth::hci::ChangeConnectionLinkKeyStatusBuilder::Create(status, kNumCommandPackets)); @@ -1091,7 +1128,7 @@ void DualModeController::CentralLinkKey(CommandView command) { DEBUG(id_, " key_flag={}", bluetooth::hci::KeyFlagText(command_view.GetKeyFlag())); uint8_t key_flag = static_cast(command_view.GetKeyFlag()); - auto status = link_layer_controller_.CentralLinkKey(key_flag); + auto status = bredr_controller_.CentralLinkKey(key_flag); send_event_(bluetooth::hci::CentralLinkKeyStatusBuilder::Create(status, kNumCommandPackets)); } @@ -1104,7 +1141,7 @@ void DualModeController::WriteAuthenticationEnable(CommandView command) { DEBUG(id_, " authentication_enable={}", bluetooth::hci::AuthenticationEnableText(command_view.GetAuthenticationEnable())); - link_layer_controller_.SetAuthenticationEnable(command_view.GetAuthenticationEnable()); + bredr_controller_.SetAuthenticationEnable(command_view.GetAuthenticationEnable()); send_event_(bluetooth::hci::WriteAuthenticationEnableCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1118,7 +1155,7 @@ void DualModeController::ReadAuthenticationEnable(CommandView command) { send_event_(bluetooth::hci::ReadAuthenticationEnableCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, static_cast( - link_layer_controller_.GetAuthenticationEnable()))); + bredr_controller_.GetAuthenticationEnable()))); } void DualModeController::ReadClassOfDevice(CommandView command) { @@ -1128,7 +1165,7 @@ void DualModeController::ReadClassOfDevice(CommandView command) { DEBUG(id_, "<< Read Class of Device"); send_event_(bluetooth::hci::ReadClassOfDeviceCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, link_layer_controller_.GetClassOfDevice())); + kNumCommandPackets, ErrorCode::SUCCESS, bredr_controller_.GetClassOfDevice())); } void DualModeController::WriteClassOfDevice(CommandView command) { @@ -1138,7 +1175,7 @@ void DualModeController::WriteClassOfDevice(CommandView command) { DEBUG(id_, "<< Write Class of Device"); DEBUG(id_, " class_of_device=0x{:x}", command_view.GetClassOfDevice()); - link_layer_controller_.SetClassOfDevice(command_view.GetClassOfDevice()); + bredr_controller_.SetClassOfDevice(command_view.GetClassOfDevice()); send_event_(bluetooth::hci::WriteClassOfDeviceCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1149,7 +1186,7 @@ void DualModeController::ReadPageTimeout(CommandView command) { DEBUG(id_, "<< Read Page Timeout"); - uint16_t page_timeout = link_layer_controller_.GetPageTimeout(); + uint16_t page_timeout = bredr_controller_.GetPageTimeout(); send_event_(bluetooth::hci::ReadPageTimeoutCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, page_timeout)); } @@ -1161,7 +1198,7 @@ void DualModeController::WritePageTimeout(CommandView command) { DEBUG(id_, "<< Write Page Timeout"); DEBUG(id_, " page_timeout={}", command_view.GetPageTimeout()); - link_layer_controller_.SetPageTimeout(command_view.GetPageTimeout()); + bredr_controller_.SetPageTimeout(command_view.GetPageTimeout()); send_event_(bluetooth::hci::WritePageTimeoutCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1176,8 +1213,7 @@ void DualModeController::HoldMode(CommandView command) { DEBUG(id_, "<< Hold Mode"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - auto status = - link_layer_controller_.HoldMode(handle, hold_mode_max_interval, hold_mode_min_interval); + auto status = bredr_controller_.HoldMode(handle, hold_mode_max_interval, hold_mode_min_interval); send_event_(bluetooth::hci::HoldModeStatusBuilder::Create(status, kNumCommandPackets)); } @@ -1194,8 +1230,8 @@ void DualModeController::SniffMode(CommandView command) { DEBUG(id_, "<< Sniff Mode"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - auto status = link_layer_controller_.SniffMode(handle, sniff_max_interval, sniff_min_interval, - sniff_attempt, sniff_timeout); + auto status = bredr_controller_.SniffMode(handle, sniff_max_interval, sniff_min_interval, + sniff_attempt, sniff_timeout); send_event_(bluetooth::hci::SniffModeStatusBuilder::Create(status, kNumCommandPackets)); } @@ -1207,7 +1243,7 @@ void DualModeController::ExitSniffMode(CommandView command) { DEBUG(id_, "<< Exit Sniff Mode"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - auto status = link_layer_controller_.ExitSniffMode(command_view.GetConnectionHandle()); + auto status = bredr_controller_.ExitSniffMode(command_view.GetConnectionHandle()); send_event_(bluetooth::hci::ExitSniffModeStatusBuilder::Create(status, kNumCommandPackets)); } @@ -1225,8 +1261,8 @@ void DualModeController::QosSetup(CommandView command) { DEBUG(id_, "<< Qos Setup"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - auto status = link_layer_controller_.QosSetup(handle, service_type, token_rate, peak_bandwidth, - latency, delay_variation); + auto status = bredr_controller_.QosSetup(handle, service_type, token_rate, peak_bandwidth, + latency, delay_variation); send_event_(bluetooth::hci::QosSetupStatusBuilder::Create(status, kNumCommandPackets)); } @@ -1240,7 +1276,7 @@ void DualModeController::RoleDiscovery(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", handle); auto role = bluetooth::hci::Role::CENTRAL; - auto status = link_layer_controller_.RoleDiscovery(handle, &role); + auto status = bredr_controller_.RoleDiscovery(handle, &role); send_event_(bluetooth::hci::RoleDiscoveryCompleteBuilder::Create(kNumCommandPackets, status, handle, role)); @@ -1252,7 +1288,7 @@ void DualModeController::ReadDefaultLinkPolicySettings(CommandView command) { DEBUG(id_, "<< Read Default Link Policy Settings"); - uint16_t settings = link_layer_controller_.ReadDefaultLinkPolicySettings(); + uint16_t settings = bredr_controller_.ReadDefaultLinkPolicySettings(); send_event_(bluetooth::hci::ReadDefaultLinkPolicySettingsCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, settings)); } @@ -1264,7 +1300,7 @@ void DualModeController::WriteDefaultLinkPolicySettings(CommandView command) { DEBUG(id_, "<< Write Default Link Policy Settings"); DEBUG(id_, " default_link_policy_settings=0x{:x}", command_view.GetDefaultLinkPolicySettings()); - ErrorCode status = link_layer_controller_.WriteDefaultLinkPolicySettings( + ErrorCode status = bredr_controller_.WriteDefaultLinkPolicySettings( command_view.GetDefaultLinkPolicySettings()); send_event_(bluetooth::hci::WriteDefaultLinkPolicySettingsCompleteBuilder::Create( kNumCommandPackets, status)); @@ -1296,9 +1332,9 @@ void DualModeController::FlowSpecification(CommandView command) { DEBUG(id_, "<< Flow Specification"); DEBUG(id_, " connection_handle=0x{:x}", handle); - auto status = link_layer_controller_.FlowSpecification(handle, flow_direction, service_type, - token_rate, token_bucket_size, - peak_bandwidth, access_latency); + auto status = + bredr_controller_.FlowSpecification(handle, flow_direction, service_type, token_rate, + token_bucket_size, peak_bandwidth, access_latency); send_event_(bluetooth::hci::FlowSpecificationStatusBuilder::Create(status, kNumCommandPackets)); } @@ -1312,7 +1348,7 @@ void DualModeController::ReadLinkPolicySettings(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", handle); uint16_t settings = 0; - auto status = link_layer_controller_.ReadLinkPolicySettings(handle, &settings); + auto status = bredr_controller_.ReadLinkPolicySettings(handle, &settings); send_event_(bluetooth::hci::ReadLinkPolicySettingsCompleteBuilder::Create( kNumCommandPackets, status, handle, settings)); @@ -1328,7 +1364,7 @@ void DualModeController::WriteLinkPolicySettings(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", handle); DEBUG(id_, " link_policy_settings=0x{:x}", settings); - auto status = link_layer_controller_.WriteLinkPolicySettings(handle, settings); + auto status = bredr_controller_.WriteLinkPolicySettings(handle, settings); send_event_(bluetooth::hci::WriteLinkPolicySettingsCompleteBuilder::Create(kNumCommandPackets, status, handle)); @@ -1344,7 +1380,7 @@ void DualModeController::WriteLinkSupervisionTimeout(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", handle); DEBUG(id_, " link_supervision_timeout={}", timeout); - auto status = link_layer_controller_.WriteLinkSupervisionTimeout(handle, timeout); + auto status = bredr_controller_.WriteLinkSupervisionTimeout(handle, timeout); send_event_(bluetooth::hci::WriteLinkSupervisionTimeoutCompleteBuilder::Create(kNumCommandPackets, status, handle)); } @@ -1356,7 +1392,7 @@ void DualModeController::ReadLocalName(CommandView command) { DEBUG(id_, "<< Read Local Name"); send_event_(bluetooth::hci::ReadLocalNameCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, link_layer_controller_.GetLocalName())); + kNumCommandPackets, ErrorCode::SUCCESS, bredr_controller_.GetLocalName())); } void DualModeController::WriteLocalName(CommandView command) { @@ -1365,7 +1401,7 @@ void DualModeController::WriteLocalName(CommandView command) { DEBUG(id_, "<< Write Local Name"); - link_layer_controller_.SetLocalName(command_view.GetLocalName()); + bredr_controller_.SetLocalName(command_view.GetLocalName()); send_event_(bluetooth::hci::WriteLocalNameCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1376,7 +1412,7 @@ void DualModeController::WriteExtendedInquiryResponse(CommandView command) { DEBUG(id_, "<< Write Extended Inquiry Response"); - link_layer_controller_.SetExtendedInquiryResponse(command_view.GetExtendedInquiryResponse()); + bredr_controller_.SetExtendedInquiryResponse(command_view.GetExtendedInquiryResponse()); send_event_(bluetooth::hci::WriteExtendedInquiryResponseCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1403,7 +1439,7 @@ void DualModeController::ReadVoiceSetting(CommandView command) { DEBUG(id_, "<< Read Voice Setting"); send_event_(bluetooth::hci::ReadVoiceSettingCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, link_layer_controller_.GetVoiceSetting())); + kNumCommandPackets, ErrorCode::SUCCESS, bredr_controller_.GetVoiceSetting())); } void DualModeController::WriteVoiceSetting(CommandView command) { @@ -1413,7 +1449,7 @@ void DualModeController::WriteVoiceSetting(CommandView command) { DEBUG(id_, "<< Write Voice Setting"); DEBUG(id_, " voice_setting=0x{:x}", command_view.GetVoiceSetting()); - link_layer_controller_.SetVoiceSetting(command_view.GetVoiceSetting()); + bredr_controller_.SetVoiceSetting(command_view.GetVoiceSetting()); send_event_(bluetooth::hci::WriteVoiceSettingCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); @@ -1436,7 +1472,7 @@ void DualModeController::ReadCurrentIacLap(CommandView command) { DEBUG(id_, "<< Read Current Iac Lap"); send_event_(bluetooth::hci::ReadCurrentIacLapCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, link_layer_controller_.ReadCurrentIacLap())); + kNumCommandPackets, ErrorCode::SUCCESS, bredr_controller_.ReadCurrentIacLap())); } void DualModeController::WriteCurrentIacLap(CommandView command) { @@ -1445,7 +1481,7 @@ void DualModeController::WriteCurrentIacLap(CommandView command) { DEBUG(id_, "<< Write Current Iac Lap"); - link_layer_controller_.WriteCurrentIacLap(command_view.GetLapsToWrite()); + bredr_controller_.WriteCurrentIacLap(command_view.GetLapsToWrite()); send_event_(bluetooth::hci::WriteCurrentIacLapCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1500,8 +1536,8 @@ void DualModeController::ReadScanEnable(CommandView command) { DEBUG(id_, "<< Read Scan Enable"); - bool inquiry_scan = link_layer_controller_.GetInquiryScanEnable(); - bool page_scan = link_layer_controller_.GetPageScanEnable(); + bool inquiry_scan = bredr_controller_.GetInquiryScanEnable(); + bool page_scan = bredr_controller_.GetPageScanEnable(); bluetooth::hci::ScanEnable scan_enable = inquiry_scan && page_scan ? bluetooth::hci::ScanEnable::INQUIRY_AND_PAGE_SCAN @@ -1525,8 +1561,8 @@ void DualModeController::WriteScanEnable(CommandView command) { DEBUG(id_, "<< Write Scan Enable"); DEBUG(id_, " scan_enable={}", bluetooth::hci::ScanEnableText(scan_enable)); - link_layer_controller_.SetInquiryScanEnable(inquiry_scan); - link_layer_controller_.SetPageScanEnable(page_scan); + bredr_controller_.SetInquiryScanEnable(inquiry_scan); + bredr_controller_.SetPageScanEnable(page_scan); send_event_(bluetooth::hci::WriteScanEnableCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1539,7 +1575,7 @@ void DualModeController::ReadTransmitPowerLevel(CommandView command) { DEBUG(id_, "<< Read Transmit Power Level"); DEBUG(id_, " connection_handle=0x{:x}", connection_handle); - ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) + ErrorCode status = bredr_controller_.HasAclConnection(connection_handle) ? ErrorCode::SUCCESS : ErrorCode::UNKNOWN_CONNECTION; @@ -1555,7 +1591,7 @@ void DualModeController::ReadEnhancedTransmitPowerLevel(CommandView command) { DEBUG(id_, "<< Read Enhanced Transmit Power Level"); DEBUG(id_, " connection_handle=0x{:x}", connection_handle); - ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) + ErrorCode status = bredr_controller_.HasAclConnection(connection_handle) ? ErrorCode::SUCCESS : ErrorCode::UNKNOWN_CONNECTION; @@ -1571,7 +1607,7 @@ void DualModeController::ReadSynchronousFlowControlEnable(CommandView command) { DEBUG(id_, "<< Read Synchronous Flow Control Enable"); auto enabled = bluetooth::hci::Enable::DISABLED; - if (link_layer_controller_.GetScoFlowControlEnable()) { + if (bredr_controller_.GetScoFlowControlEnable()) { enabled = bluetooth::hci::Enable::ENABLED; } send_event_(bluetooth::hci::ReadSynchronousFlowControlEnableCompleteBuilder::Create( @@ -1586,7 +1622,7 @@ void DualModeController::WriteSynchronousFlowControlEnable(CommandView command) DEBUG(id_, "<< Write Synchronous Flow Control Enable"); DEBUG(id_, " enable={}", enabled); - link_layer_controller_.SetScoFlowControlEnable(enabled); + bredr_controller_.SetScoFlowControlEnable(enabled); send_event_(bluetooth::hci::WriteSynchronousFlowControlEnableCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1621,9 +1657,9 @@ void DualModeController::Inquiry(CommandView command) { ErrorCode::INVALID_HCI_COMMAND_PARAMETERS, kNumCommandPackets)); return; } - link_layer_controller_.SetInquiryLAP(command_view.GetLap().lap_); - link_layer_controller_.SetInquiryMaxResponses(max_responses); - link_layer_controller_.StartInquiry(std::chrono::milliseconds(length * 1280)); + bredr_controller_.SetInquiryLAP(command_view.GetLap().lap_); + bredr_controller_.SetInquiryMaxResponses(max_responses); + bredr_controller_.StartInquiry(std::chrono::milliseconds(length * 1280)); send_event_(bluetooth::hci::InquiryStatusBuilder::Create(ErrorCode::SUCCESS, kNumCommandPackets)); } @@ -1634,7 +1670,7 @@ void DualModeController::InquiryCancel(CommandView command) { DEBUG(id_, "<< Inquiry Cancel"); - link_layer_controller_.InquiryCancel(); + bredr_controller_.InquiryCancel(); send_event_(bluetooth::hci::InquiryCancelCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1650,7 +1686,7 @@ void DualModeController::AcceptConnectionRequest(CommandView command) { DEBUG(id_, " bd_addr={}", bd_addr); DEBUG(id_, " try_role_switch={}", try_role_switch); - auto status = link_layer_controller_.AcceptConnectionRequest(bd_addr, try_role_switch); + auto status = bredr_controller_.AcceptConnectionRequest(bd_addr, try_role_switch); send_event_( bluetooth::hci::AcceptConnectionRequestStatusBuilder::Create(status, kNumCommandPackets)); } @@ -1665,8 +1701,7 @@ void DualModeController::RejectConnectionRequest(CommandView command) { DEBUG(id_, " bd_addr={}", bd_addr); DEBUG(id_, " reason={}", bluetooth::hci::RejectConnectionReasonText(reason)); - auto status = - link_layer_controller_.RejectConnectionRequest(bd_addr, static_cast(reason)); + auto status = bredr_controller_.RejectConnectionRequest(bd_addr, static_cast(reason)); send_event_( bluetooth::hci::RejectConnectionRequestStatusBuilder::Create(status, kNumCommandPackets)); } @@ -1689,7 +1724,7 @@ void DualModeController::RemoteNameRequest(CommandView command) { DEBUG(id_, "<< Remote Name Request"); DEBUG(id_, " bd_addr={}", bd_addr); - auto status = link_layer_controller_.SendCommandToRemoteByAddress( + auto status = bredr_controller_.SendCommandToRemoteByAddress( OpCode::REMOTE_NAME_REQUEST, command_view.bytes(), GetAddress(), bd_addr); send_event_(bluetooth::hci::RemoteNameRequestStatusBuilder::Create(status, kNumCommandPackets)); @@ -1702,7 +1737,7 @@ void DualModeController::LeSetEventMask(CommandView command) { DEBUG(id_, "<< LE Set Event Mask"); DEBUG(id_, " le_event_mask=0x{:x}", command_view.GetLeEventMask()); - link_layer_controller_.SetLeEventMask(command_view.GetLeEventMask()); + le_controller_.SetLeEventMask(command_view.GetLeEventMask()); send_event_(bluetooth::hci::LeSetEventMaskCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1727,7 +1762,7 @@ void DualModeController::LeRequestPeerSca(CommandView command) { // return the error code Unsupported Remote Feature (0x1A). // TODO - if (link_layer_controller_.HasAclConnection(connection_handle)) { + if (le_controller_.HasLeAclConnection(connection_handle)) { send_event_(bluetooth::hci::LeRequestPeerScaStatusBuilder::Create(ErrorCode::SUCCESS, kNumCommandPackets)); send_event_(bluetooth::hci::LeRequestPeerScaCompleteBuilder::Create( @@ -1748,7 +1783,7 @@ void DualModeController::LeSetHostFeatureV1(CommandView command) { DEBUG(id_, " bit_number={}", bit_number); DEBUG(id_, " bit_value={}", bit_value); - ErrorCode status = link_layer_controller_.LeSetHostFeature(bit_number, bit_value); + ErrorCode status = le_controller_.LeSetHostFeature(bit_number, bit_value); send_event_( bluetooth::hci::LeSetHostFeatureV1CompleteBuilder::Create(kNumCommandPackets, status)); } @@ -1792,7 +1827,7 @@ void DualModeController::LeSetAddressResolutionEnable(CommandView command) { DEBUG(id_, " address_resolution_enable={}", command_view.GetAddressResolutionEnable() == bluetooth::hci::Enable::ENABLED); - ErrorCode status = link_layer_controller_.LeSetAddressResolutionEnable( + ErrorCode status = le_controller_.LeSetAddressResolutionEnable( command_view.GetAddressResolutionEnable() == bluetooth::hci::Enable::ENABLED); send_event_(bluetooth::hci::LeSetAddressResolutionEnableCompleteBuilder::Create( kNumCommandPackets, status)); @@ -1805,7 +1840,7 @@ void DualModeController::LeSetResolvablePrivateAddressTimeout(CommandView comman DEBUG(id_, "<< LE Set Resolvable Private Address Timeout"); ErrorCode status = - link_layer_controller_.LeSetResolvablePrivateAddressTimeout(command_view.GetRpaTimeout()); + le_controller_.LeSetResolvablePrivateAddressTimeout(command_view.GetRpaTimeout()); send_event_(bluetooth::hci::LeSetResolvablePrivateAddressTimeoutCompleteBuilder::Create( kNumCommandPackets, status)); } @@ -1816,7 +1851,7 @@ void DualModeController::LeReadLocalSupportedFeaturesPage0(CommandView command) DEBUG(id_, "<< LE Read Local Supported Features Page 0"); - uint64_t le_features = link_layer_controller_.GetLeSupportedFeatures(); + uint64_t le_features = le_controller_.GetLeSupportedFeatures(); send_event_(bluetooth::hci::LeReadLocalSupportedFeaturesPage0CompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, le_features)); } @@ -1828,7 +1863,7 @@ void DualModeController::LeSetRandomAddress(CommandView command) { DEBUG(id_, "<< LE Set Random Address"); DEBUG(id_, " random_address={}", command_view.GetRandomAddress()); - ErrorCode status = link_layer_controller_.LeSetRandomAddress(command_view.GetRandomAddress()); + ErrorCode status = le_controller_.LeSetRandomAddress(command_view.GetRandomAddress()); send_event_( bluetooth::hci::LeSetRandomAddressCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -1839,7 +1874,7 @@ void DualModeController::LeSetAdvertisingParameters(CommandView command) { DEBUG(id_, "<< LE Set Advertising Parameters"); - ErrorCode status = link_layer_controller_.LeSetAdvertisingParameters( + ErrorCode status = le_controller_.LeSetAdvertisingParameters( command_view.GetAdvertisingIntervalMin(), command_view.GetAdvertisingIntervalMax(), command_view.GetAdvertisingType(), command_view.GetOwnAddressType(), command_view.GetPeerAddressType(), command_view.GetPeerAddress(), @@ -1865,7 +1900,7 @@ void DualModeController::LeSetAdvertisingData(CommandView command) { DEBUG(id_, "<< LE Set Advertising Data"); - ErrorCode status = link_layer_controller_.LeSetAdvertisingData(command_view.GetAdvertisingData()); + ErrorCode status = le_controller_.LeSetAdvertisingData(command_view.GetAdvertisingData()); send_event_( bluetooth::hci::LeSetAdvertisingDataCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -1876,8 +1911,7 @@ void DualModeController::LeSetScanResponseData(CommandView command) { DEBUG(id_, "<< LE Set Scan Response Data"); - ErrorCode status = - link_layer_controller_.LeSetScanResponseData(command_view.GetAdvertisingData()); + ErrorCode status = le_controller_.LeSetScanResponseData(command_view.GetAdvertisingData()); send_event_( bluetooth::hci::LeSetScanResponseDataCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -1890,8 +1924,8 @@ void DualModeController::LeSetAdvertisingEnable(CommandView command) { DEBUG(id_, " advertising_enable={}", command_view.GetAdvertisingEnable() == bluetooth::hci::Enable::ENABLED); - ErrorCode status = link_layer_controller_.LeSetAdvertisingEnable( - command_view.GetAdvertisingEnable() == bluetooth::hci::Enable::ENABLED); + ErrorCode status = le_controller_.LeSetAdvertisingEnable(command_view.GetAdvertisingEnable() == + bluetooth::hci::Enable::ENABLED); send_event_(bluetooth::hci::LeSetAdvertisingEnableCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -1902,7 +1936,7 @@ void DualModeController::LeSetScanParameters(CommandView command) { DEBUG(id_, "<< LE Set Scan Parameters"); - ErrorCode status = link_layer_controller_.LeSetScanParameters( + ErrorCode status = le_controller_.LeSetScanParameters( command_view.GetLeScanType(), command_view.GetLeScanInterval(), command_view.GetLeScanWindow(), command_view.GetOwnAddressType(), command_view.GetScanningFilterPolicy()); @@ -1918,7 +1952,7 @@ void DualModeController::LeSetScanEnable(CommandView command) { DEBUG(id_, " scan_enable={}", command_view.GetLeScanEnable() == bluetooth::hci::Enable::ENABLED); - ErrorCode status = link_layer_controller_.LeSetScanEnable( + ErrorCode status = le_controller_.LeSetScanEnable( command_view.GetLeScanEnable() == bluetooth::hci::Enable::ENABLED, command_view.GetFilterDuplicates() == bluetooth::hci::Enable::ENABLED); send_event_(bluetooth::hci::LeSetScanEnableCompleteBuilder::Create(kNumCommandPackets, status)); @@ -1937,7 +1971,7 @@ void DualModeController::LeCreateConnection(CommandView command) { DEBUG(id_, " initiator_filter_policy={}", bluetooth::hci::InitiatorFilterPolicyText(command_view.GetInitiatorFilterPolicy())); - ErrorCode status = link_layer_controller_.LeCreateConnection( + ErrorCode status = le_controller_.LeCreateConnection( command_view.GetLeScanInterval(), command_view.GetLeScanWindow(), command_view.GetInitiatorFilterPolicy(), AddressWithType{ @@ -1957,7 +1991,7 @@ void DualModeController::LeCreateConnectionCancel(CommandView command) { DEBUG(id_, "<< LE Create Connection Cancel"); - ErrorCode status = link_layer_controller_.LeCreateConnectionCancel(); + ErrorCode status = le_controller_.LeCreateConnectionCancel(); send_event_(bluetooth::hci::LeCreateConnectionCancelCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -1969,7 +2003,7 @@ void DualModeController::LeConnectionUpdate(CommandView command) { DEBUG(id_, "<< LE Connection Update"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - ErrorCode status = link_layer_controller_.LeConnectionUpdate( + ErrorCode status = le_controller_.LeConnectionUpdate( command_view.GetConnectionHandle(), command_view.GetConnectionIntervalMin(), command_view.GetConnectionIntervalMax(), command_view.GetMaxLatency(), command_view.GetSupervisionTimeout()); @@ -1995,8 +2029,8 @@ void DualModeController::CreateConnection(CommandView command) { command_view.GetAllowRoleSwitch() == bluetooth::hci::CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH); - auto status = link_layer_controller_.CreateConnection(bd_addr, packet_type, page_scan_mode, - clock_offset, allow_role_switch); + auto status = bredr_controller_.CreateConnection(bd_addr, packet_type, page_scan_mode, + clock_offset, allow_role_switch); send_event_(bluetooth::hci::CreateConnectionStatusBuilder::Create(status, kNumCommandPackets)); } @@ -2009,7 +2043,7 @@ void DualModeController::CreateConnectionCancel(CommandView command) { DEBUG(id_, "<< Create Connection Cancel"); DEBUG(id_, " bd_addr={}", address); - auto status = link_layer_controller_.CreateConnectionCancel(address); + auto status = bredr_controller_.CreateConnectionCancel(address); send_event_(bluetooth::hci::CreateConnectionCancelCompleteBuilder::Create(kNumCommandPackets, status, address)); @@ -2019,18 +2053,22 @@ void DualModeController::Disconnect(CommandView command) { auto command_view = bluetooth::hci::DisconnectView::Create(command); CHECK_PACKET_VIEW(command_view); uint16_t connection_handle = command_view.GetConnectionHandle(); + ErrorCode reason = ErrorCode(command_view.GetReason()); DEBUG(id_, "<< Disconnect"); DEBUG(id_, " connection_handle=0x{:x}", connection_handle); - if (connection_handle >= kCisHandleRangeStart && connection_handle < kCisHandleRangeEnd) { - link_layer_controller_.ForwardToLl(command); - } else { - auto status = link_layer_controller_.Disconnect(connection_handle, - ErrorCode(command_view.GetReason())); - - send_event_(bluetooth::hci::DisconnectStatusBuilder::Create(status, kNumCommandPackets)); + if (IsCisConnectionHandle(connection_handle)) { + return le_controller_.ForwardToLl(command); } + + auto status = IsAclConnectionHandle(connection_handle) || IsScoConnectionHandle(connection_handle) + ? bredr_controller_.Disconnect(connection_handle, reason) + : IsLeAclConnectionHandle(connection_handle) + ? le_controller_.Disconnect(connection_handle, reason) + : ErrorCode::UNKNOWN_CONNECTION; + + send_event_(bluetooth::hci::DisconnectStatusBuilder::Create(status, kNumCommandPackets)); } void DualModeController::LeReadFilterAcceptListSize(CommandView command) { @@ -2049,7 +2087,7 @@ void DualModeController::LeClearFilterAcceptList(CommandView command) { DEBUG(id_, "<< LE Clear Filter Accept List"); - ErrorCode status = link_layer_controller_.LeClearFilterAcceptList(); + ErrorCode status = le_controller_.LeClearFilterAcceptList(); send_event_(bluetooth::hci::LeClearFilterAcceptListCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -2063,8 +2101,8 @@ void DualModeController::LeAddDeviceToFilterAcceptList(CommandView command) { DEBUG(id_, " address_type={}", bluetooth::hci::FilterAcceptListAddressTypeText(command_view.GetAddressType())); - ErrorCode status = link_layer_controller_.LeAddDeviceToFilterAcceptList( - command_view.GetAddressType(), command_view.GetAddress()); + ErrorCode status = le_controller_.LeAddDeviceToFilterAcceptList(command_view.GetAddressType(), + command_view.GetAddress()); send_event_(bluetooth::hci::LeAddDeviceToFilterAcceptListCompleteBuilder::Create( kNumCommandPackets, status)); } @@ -2078,7 +2116,7 @@ void DualModeController::LeRemoveDeviceFromFilterAcceptList(CommandView command) DEBUG(id_, " address_type={}", bluetooth::hci::FilterAcceptListAddressTypeText(command_view.GetAddressType())); - ErrorCode status = link_layer_controller_.LeRemoveDeviceFromFilterAcceptList( + ErrorCode status = le_controller_.LeRemoveDeviceFromFilterAcceptList( command_view.GetAddressType(), command_view.GetAddress()); send_event_(bluetooth::hci::LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create( kNumCommandPackets, status)); @@ -2090,7 +2128,7 @@ void DualModeController::LeClearResolvingList(CommandView command) { DEBUG(id_, "<< LE Clear Resolving List"); - ErrorCode status = link_layer_controller_.LeClearResolvingList(); + ErrorCode status = le_controller_.LeClearResolvingList(); send_event_( bluetooth::hci::LeClearResolvingListCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -2115,7 +2153,7 @@ void DualModeController::LeReadPeerResolvableAddress(CommandView command) { bluetooth::hci::PeerAddressTypeText(command_view.GetPeerIdentityAddressType())); Address peer_resolvable_address; - ErrorCode status = link_layer_controller_.LeReadPeerResolvableAddress( + ErrorCode status = le_controller_.LeReadPeerResolvableAddress( command_view.GetPeerIdentityAddressType(), command_view.GetPeerIdentityAddress(), &peer_resolvable_address); send_event_(bluetooth::hci::LeReadPeerResolvableAddressCompleteBuilder::Create( @@ -2132,7 +2170,7 @@ void DualModeController::LeReadLocalResolvableAddress(CommandView command) { bluetooth::hci::PeerAddressTypeText(command_view.GetPeerIdentityAddressType())); Address local_resolvable_address; - ErrorCode status = link_layer_controller_.LeReadLocalResolvableAddress( + ErrorCode status = le_controller_.LeReadLocalResolvableAddress( command_view.GetPeerIdentityAddressType(), command_view.GetPeerIdentityAddress(), &local_resolvable_address); send_event_(bluetooth::hci::LeReadLocalResolvableAddressCompleteBuilder::Create( @@ -2164,7 +2202,7 @@ void DualModeController::LeReadPhy(CommandView command) { bluetooth::hci::PhyType tx_phy{}; bluetooth::hci::PhyType rx_phy{}; - ErrorCode status = link_layer_controller_.LeReadPhy(connection_handle, &tx_phy, &rx_phy); + ErrorCode status = le_controller_.LeReadPhy(connection_handle, &tx_phy, &rx_phy); send_event_(bluetooth::hci::LeReadPhyCompleteBuilder::Create(kNumCommandPackets, status, connection_handle, tx_phy, rx_phy)); } @@ -2175,10 +2213,10 @@ void DualModeController::LeSetDefaultPhy(CommandView command) { DEBUG(id_, "<< LE Set Default Phy"); - ErrorCode status = link_layer_controller_.LeSetDefaultPhy( - command_view.GetAllPhysNoTransmitPreference(), - command_view.GetAllPhysNoReceivePreference(), command_view.GetTxPhys(), - command_view.GetRxPhys()); + ErrorCode status = + le_controller_.LeSetDefaultPhy(command_view.GetAllPhysNoTransmitPreference(), + command_view.GetAllPhysNoReceivePreference(), + command_view.GetTxPhys(), command_view.GetRxPhys()); send_event_(bluetooth::hci::LeSetDefaultPhyCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -2189,7 +2227,7 @@ void DualModeController::LeSetPhy(CommandView command) { DEBUG(id_, "<< LE Set Phy"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - ErrorCode status = link_layer_controller_.LeSetPhy( + ErrorCode status = le_controller_.LeSetPhy( command_view.GetConnectionHandle(), command_view.GetAllPhysNoTransmitPreference(), command_view.GetAllPhysNoReceivePreference(), command_view.GetTxPhys(), command_view.GetRxPhys(), command_view.GetPhyOptions()); @@ -2203,7 +2241,7 @@ void DualModeController::LeSetDataLength(CommandView command) { DEBUG(id_, "<< LE Set Data Length"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - ErrorCode status = link_layer_controller_.LeSetDataLength( + ErrorCode status = le_controller_.LeSetDataLength( command_view.GetConnectionHandle(), command_view.GetTxOctets(), command_view.GetTxTime()); send_event_(bluetooth::hci::LeSetDataLengthCompleteBuilder::Create( kNumCommandPackets, status, command_view.GetConnectionHandle())); @@ -2216,9 +2254,8 @@ void DualModeController::LeReadSuggestedDefaultDataLength(CommandView command) { DEBUG(id_, "<< LE Read Suggested Default Data Length"); send_event_(bluetooth::hci::LeReadSuggestedDefaultDataLengthCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, - link_layer_controller_.GetLeSuggestedMaxTxOctets(), - link_layer_controller_.GetLeSuggestedMaxTxTime())); + kNumCommandPackets, ErrorCode::SUCCESS, le_controller_.GetLeSuggestedMaxTxOctets(), + le_controller_.GetLeSuggestedMaxTxTime())); } void DualModeController::LeWriteSuggestedDefaultDataLength(CommandView command) { @@ -2233,8 +2270,8 @@ void DualModeController::LeWriteSuggestedDefaultDataLength(CommandView command) if (max_tx_octets > 0xFB || max_tx_octets < 0x1B || max_tx_time < 0x148 || max_tx_time > 0x4290) { status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } else { - link_layer_controller_.SetLeSuggestedMaxTxOctets(max_tx_octets); - link_layer_controller_.SetLeSuggestedMaxTxTime(max_tx_time); + le_controller_.SetLeSuggestedMaxTxOctets(max_tx_octets); + le_controller_.SetLeSuggestedMaxTxTime(max_tx_time); } send_event_(bluetooth::hci::LeWriteSuggestedDefaultDataLengthCompleteBuilder::Create( @@ -2331,7 +2368,7 @@ void DualModeController::LeAddDeviceToResolvingList(CommandView command) { DEBUG(id_, " peer_identity_address_type={}", bluetooth::hci::PeerAddressTypeText(command_view.GetPeerIdentityAddressType())); - ErrorCode status = link_layer_controller_.LeAddDeviceToResolvingList( + ErrorCode status = le_controller_.LeAddDeviceToResolvingList( command_view.GetPeerIdentityAddressType(), command_view.GetPeerIdentityAddress(), command_view.GetPeerIrk(), command_view.GetLocalIrk()); send_event_(bluetooth::hci::LeAddDeviceToResolvingListCompleteBuilder::Create(kNumCommandPackets, @@ -2347,7 +2384,7 @@ void DualModeController::LeRemoveDeviceFromResolvingList(CommandView command) { DEBUG(id_, " peer_identity_address_type={}", bluetooth::hci::PeerAddressTypeText(command_view.GetPeerIdentityAddressType())); - ErrorCode status = link_layer_controller_.LeRemoveDeviceFromResolvingList( + ErrorCode status = le_controller_.LeRemoveDeviceFromResolvingList( command_view.GetPeerIdentityAddressType(), command_view.GetPeerIdentityAddress()); send_event_(bluetooth::hci::LeRemoveDeviceFromResolvingListCompleteBuilder::Create( kNumCommandPackets, status)); @@ -2360,7 +2397,7 @@ void DualModeController::LeSetPeriodicAdvertisingParametersV1(CommandView comman DEBUG(id_, "<< LE Set Periodic Advertising Parameters V1"); DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); - ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingParameters( + ErrorCode status = le_controller_.LeSetPeriodicAdvertisingParameters( command_view.GetAdvertisingHandle(), command_view.GetPeriodicAdvertisingIntervalMin(), command_view.GetPeriodicAdvertisingIntervalMax(), command_view.GetIncludeTxPower()); send_event_(bluetooth::hci::LeSetPeriodicAdvertisingParametersV1CompleteBuilder::Create( @@ -2374,7 +2411,7 @@ void DualModeController::LeSetPeriodicAdvertisingData(CommandView command) { DEBUG(id_, "<< LE Set Periodic Advertising Data"); DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); - ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingData( + ErrorCode status = le_controller_.LeSetPeriodicAdvertisingData( command_view.GetAdvertisingHandle(), command_view.GetOperation(), command_view.GetAdvertisingData()); send_event_(bluetooth::hci::LeSetPeriodicAdvertisingDataCompleteBuilder::Create( @@ -2389,7 +2426,7 @@ void DualModeController::LeSetPeriodicAdvertisingEnable(CommandView command) { DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); DEBUG(id_, " enable={}", command_view.GetEnable() != 0); - ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingEnable( + ErrorCode status = le_controller_.LeSetPeriodicAdvertisingEnable( command_view.GetEnable(), command_view.GetIncludeAdi(), command_view.GetAdvertisingHandle()); send_event_(bluetooth::hci::LeSetPeriodicAdvertisingEnableCompleteBuilder::Create( @@ -2405,7 +2442,7 @@ void DualModeController::LePeriodicAdvertisingCreateSync(CommandView command) { DEBUG(id_, " advertiser_address_type={}", bluetooth::hci::AdvertiserAddressTypeText(command_view.GetAdvertiserAddressType())); - ErrorCode status = link_layer_controller_.LePeriodicAdvertisingCreateSync( + ErrorCode status = le_controller_.LePeriodicAdvertisingCreateSync( command_view.GetOptions(), command_view.GetAdvertisingSid(), command_view.GetAdvertiserAddressType(), command_view.GetAdvertiserAddress(), command_view.GetSkip(), command_view.GetSyncTimeout(), command_view.GetSyncCteType()); @@ -2419,7 +2456,7 @@ void DualModeController::LePeriodicAdvertisingCreateSyncCancel(CommandView comma DEBUG(id_, "<< LE Periodic Advertising Create Sync Cancel"); - ErrorCode status = link_layer_controller_.LePeriodicAdvertisingCreateSyncCancel(); + ErrorCode status = le_controller_.LePeriodicAdvertisingCreateSyncCancel(); send_event_(bluetooth::hci::LePeriodicAdvertisingCreateSyncCancelCompleteBuilder::Create( kNumCommandPackets, status)); } @@ -2432,7 +2469,7 @@ void DualModeController::LePeriodicAdvertisingTerminateSync(CommandView command) DEBUG(id_, " sync_handle=0x{:x}", command_view.GetSyncHandle()); ErrorCode status = - link_layer_controller_.LePeriodicAdvertisingTerminateSync(command_view.GetSyncHandle()); + le_controller_.LePeriodicAdvertisingTerminateSync(command_view.GetSyncHandle()); send_event_(bluetooth::hci::LePeriodicAdvertisingTerminateSyncCompleteBuilder::Create( kNumCommandPackets, status)); } @@ -2446,7 +2483,7 @@ void DualModeController::LeAddDeviceToPeriodicAdvertiserList(CommandView command DEBUG(id_, " advertiser_address_type={}", bluetooth::hci::AdvertiserAddressTypeText(command_view.GetAdvertiserAddressType())); - ErrorCode status = link_layer_controller_.LeAddDeviceToPeriodicAdvertiserList( + ErrorCode status = le_controller_.LeAddDeviceToPeriodicAdvertiserList( command_view.GetAdvertiserAddressType(), command_view.GetAdvertiserAddress(), command_view.GetAdvertisingSid()); send_event_(bluetooth::hci::LeAddDeviceToPeriodicAdvertiserListCompleteBuilder::Create( @@ -2462,7 +2499,7 @@ void DualModeController::LeRemoveDeviceFromPeriodicAdvertiserList(CommandView co DEBUG(id_, " advertiser_address_type={}", bluetooth::hci::AdvertiserAddressTypeText(command_view.GetAdvertiserAddressType())); - ErrorCode status = link_layer_controller_.LeRemoveDeviceFromPeriodicAdvertiserList( + ErrorCode status = le_controller_.LeRemoveDeviceFromPeriodicAdvertiserList( command_view.GetAdvertiserAddressType(), command_view.GetAdvertiserAddress(), command_view.GetAdvertisingSid()); send_event_(bluetooth::hci::LeRemoveDeviceFromPeriodicAdvertiserListCompleteBuilder::Create( @@ -2475,7 +2512,7 @@ void DualModeController::LeClearPeriodicAdvertiserList(CommandView command) { DEBUG(id_, "<< LE Clear Periodic Advertiser List"); - ErrorCode status = link_layer_controller_.LeClearPeriodicAdvertiserList(); + ErrorCode status = le_controller_.LeClearPeriodicAdvertiserList(); send_event_(bluetooth::hci::LeClearPeriodicAdvertiserListCompleteBuilder::Create( kNumCommandPackets, status)); } @@ -2496,7 +2533,7 @@ void DualModeController::LeSetExtendedScanParameters(CommandView command) { DEBUG(id_, "<< LE Set Extended Scan Parameters"); - ErrorCode status = link_layer_controller_.LeSetExtendedScanParameters( + ErrorCode status = le_controller_.LeSetExtendedScanParameters( command_view.GetOwnAddressType(), command_view.GetScanningFilterPolicy(), command_view.GetScanningPhys(), command_view.GetScanningPhyParameters()); send_event_(bluetooth::hci::LeSetExtendedScanParametersCompleteBuilder::Create(kNumCommandPackets, @@ -2510,7 +2547,7 @@ void DualModeController::LeSetExtendedScanEnable(CommandView command) { DEBUG(id_, "<< LE Set Extended Scan Enable"); DEBUG(id_, " enable={}", command_view.GetEnable() == bluetooth::hci::Enable::ENABLED); - ErrorCode status = link_layer_controller_.LeSetExtendedScanEnable( + ErrorCode status = le_controller_.LeSetExtendedScanEnable( command_view.GetEnable() == bluetooth::hci::Enable::ENABLED, command_view.GetFilterDuplicates(), command_view.GetDuration(), command_view.GetPeriod()); send_event_(bluetooth::hci::LeSetExtendedScanEnableCompleteBuilder::Create(kNumCommandPackets, @@ -2539,7 +2576,7 @@ void DualModeController::LeExtendedCreateConnectionV1(CommandView command) { break; } - ErrorCode status = link_layer_controller_.LeExtendedCreateConnection( + ErrorCode status = le_controller_.LeExtendedCreateConnection( command_view.GetInitiatorFilterPolicy(), command_view.GetOwnAddressType(), AddressWithType{ command_view.GetPeerAddress(), @@ -2560,9 +2597,9 @@ void DualModeController::LeSetPrivacyMode(CommandView command) { bluetooth::hci::PeerAddressTypeText(command_view.GetPeerIdentityAddressType())); DEBUG(id_, " privacy_mode={}", bluetooth::hci::PrivacyModeText(command_view.GetPrivacyMode())); - ErrorCode status = link_layer_controller_.LeSetPrivacyMode( - command_view.GetPeerIdentityAddressType(), command_view.GetPeerIdentityAddress(), - command_view.GetPrivacyMode()); + ErrorCode status = le_controller_.LeSetPrivacyMode(command_view.GetPeerIdentityAddressType(), + command_view.GetPeerIdentityAddress(), + command_view.GetPrivacyMode()); send_event_(bluetooth::hci::LeSetPrivacyModeCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -2574,8 +2611,7 @@ void DualModeController::LeReadRemoteFeaturesPage0(CommandView command) { DEBUG(id_, "<< LE Read Remote Features Page 0"); DEBUG(id_, " connection_handle=0x{:x}", handle); - auto status = link_layer_controller_.SendCommandToRemoteByHandle( - OpCode::LE_READ_REMOTE_FEATURES_PAGE_0, command_view.bytes(), handle); + auto status = le_controller_.LeReadRemoteFeaturesPage0(handle); send_event_(bluetooth::hci::LeReadRemoteFeaturesPage0StatusBuilder::Create(status, kNumCommandPackets)); @@ -2621,7 +2657,7 @@ void DualModeController::LeRemoteConnectionParameterRequestReply(CommandView com DEBUG(id_, "<< LE Remote Connection Parameters Request Reply"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - auto status = link_layer_controller_.LeRemoteConnectionParameterRequestReply( + auto status = le_controller_.LeRemoteConnectionParameterRequestReply( command_view.GetConnectionHandle(), command_view.GetIntervalMin(), command_view.GetIntervalMax(), command_view.GetTimeout(), command_view.GetLatency(), command_view.GetMinimumCeLength(), command_view.GetMaximumCeLength()); @@ -2637,7 +2673,7 @@ void DualModeController::LeRemoteConnectionParameterRequestNegativeReply(Command DEBUG(id_, "<< LE Remote Connection Parameters Request Negative Reply"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - auto status = link_layer_controller_.LeRemoteConnectionParameterRequestNegativeReply( + auto status = le_controller_.LeRemoteConnectionParameterRequestNegativeReply( command_view.GetConnectionHandle(), command_view.GetReason()); send_event_( bluetooth::hci::LeRemoteConnectionParameterRequestNegativeReplyCompleteBuilder::Create( @@ -2694,8 +2730,8 @@ void DualModeController::LeApcf(CommandView command) { DEBUG(id_, "<< LE APCF Enable"); DEBUG(id_, " enable={}", bluetooth::hci::EnableText(subcommand_view.GetApcfEnable())); - ErrorCode status = link_layer_controller_.LeApcfEnable(subcommand_view.GetApcfEnable() == - bluetooth::hci::Enable::ENABLED); + ErrorCode status = le_controller_.LeApcfEnable(subcommand_view.GetApcfEnable() == + bluetooth::hci::Enable::ENABLED); send_event_(bluetooth::hci::LeApcfEnableCompleteBuilder::Create( kNumCommandPackets, status, subcommand_view.GetApcfEnable())); break; @@ -2715,7 +2751,7 @@ void DualModeController::LeApcf(CommandView command) { auto subsubcommand_view = bluetooth::hci::LeApcfAddFilteringParametersView::Create(subcommand_view); CHECK_PACKET_VIEW(subcommand_view); - status = link_layer_controller_.LeApcfAddFilteringParameters( + status = le_controller_.LeApcfAddFilteringParameters( subsubcommand_view.GetApcfFilterIndex(), subsubcommand_view.GetApcfFeatureSelection(), subsubcommand_view.GetApcfListLogicType(), @@ -2730,7 +2766,7 @@ void DualModeController::LeApcf(CommandView command) { auto subsubcommand_view = bluetooth::hci::LeApcfDeleteFilteringParametersView::Create(subcommand_view); CHECK_PACKET_VIEW(subcommand_view); - status = link_layer_controller_.LeApcfDeleteFilteringParameters( + status = le_controller_.LeApcfDeleteFilteringParameters( subsubcommand_view.GetApcfFilterIndex(), &apcf_available_spaces); break; } @@ -2738,7 +2774,7 @@ void DualModeController::LeApcf(CommandView command) { auto subsubcommand_view = bluetooth::hci::LeApcfClearFilteringParametersView::Create(subcommand_view); CHECK_PACKET_VIEW(subcommand_view); - status = link_layer_controller_.LeApcfClearFilteringParameters(&apcf_available_spaces); + status = le_controller_.LeApcfClearFilteringParameters(&apcf_available_spaces); break; } default: @@ -2766,7 +2802,7 @@ void DualModeController::LeApcf(CommandView command) { auto subsubcommand_view = bluetooth::hci::LeApcfAddBroadcasterAddressView::Create(subcommand_view); CHECK_PACKET_VIEW(subcommand_view); - status = link_layer_controller_.LeApcfBroadcasterAddress( + status = le_controller_.LeApcfBroadcasterAddress( bluetooth::hci::ApcfAction::ADD, subsubcommand_view.GetApcfFilterIndex(), subsubcommand_view.GetApcfBroadcasterAddress(), subsubcommand_view.GetApcfApplicationAddressType(), &apcf_available_spaces); @@ -2776,7 +2812,7 @@ void DualModeController::LeApcf(CommandView command) { auto subsubcommand_view = bluetooth::hci::LeApcfDeleteBroadcasterAddressView::Create(subcommand_view); CHECK_PACKET_VIEW(subcommand_view); - status = link_layer_controller_.LeApcfBroadcasterAddress( + status = le_controller_.LeApcfBroadcasterAddress( bluetooth::hci::ApcfAction::DELETE, subsubcommand_view.GetApcfFilterIndex(), subsubcommand_view.GetApcfBroadcasterAddress(), subsubcommand_view.GetApcfApplicationAddressType(), &apcf_available_spaces); @@ -2786,7 +2822,7 @@ void DualModeController::LeApcf(CommandView command) { auto subsubcommand_view = bluetooth::hci::LeApcfClearBroadcasterAddressView::Create(subcommand_view); CHECK_PACKET_VIEW(subcommand_view); - status = link_layer_controller_.LeApcfBroadcasterAddress( + status = le_controller_.LeApcfBroadcasterAddress( bluetooth::hci::ApcfAction::CLEAR, subsubcommand_view.GetApcfFilterIndex(), Address(), bluetooth::hci::ApcfApplicationAddressType::NOT_APPLICABLE, &apcf_available_spaces); @@ -2810,7 +2846,7 @@ void DualModeController::LeApcf(CommandView command) { DEBUG(id_, " action={}", bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); uint8_t apcf_available_spaces = 0; - ErrorCode status = link_layer_controller_.LeApcfServiceUuid( + ErrorCode status = le_controller_.LeApcfServiceUuid( subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), subcommand_view.GetAcpfUuidData(), &apcf_available_spaces); send_event_(bluetooth::hci::LeApcfServiceUuidCompleteBuilder::Create( @@ -2826,7 +2862,7 @@ void DualModeController::LeApcf(CommandView command) { DEBUG(id_, " action={}", bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); uint8_t apcf_available_spaces = 0; - ErrorCode status = link_layer_controller_.LeApcfServiceSolicitationUuid( + ErrorCode status = le_controller_.LeApcfServiceSolicitationUuid( subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), subcommand_view.GetAcpfUuidData(), &apcf_available_spaces); send_event_(bluetooth::hci::LeApcfServiceSolicitationUuidCompleteBuilder::Create( @@ -2841,7 +2877,7 @@ void DualModeController::LeApcf(CommandView command) { DEBUG(id_, " action={}", bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); uint8_t apcf_available_spaces = 0; - ErrorCode status = link_layer_controller_.LeApcfLocalName( + ErrorCode status = le_controller_.LeApcfLocalName( subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), subcommand_view.GetApcfLocalName(), &apcf_available_spaces); send_event_(bluetooth::hci::LeApcfLocalNameCompleteBuilder::Create( @@ -2856,7 +2892,7 @@ void DualModeController::LeApcf(CommandView command) { DEBUG(id_, " action={}", bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); uint8_t apcf_available_spaces = 0; - ErrorCode status = link_layer_controller_.LeApcfManufacturerData( + ErrorCode status = le_controller_.LeApcfManufacturerData( subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), subcommand_view.GetApcfManufacturerData(), &apcf_available_spaces); send_event_(bluetooth::hci::LeApcfManufacturerDataCompleteBuilder::Create( @@ -2871,7 +2907,7 @@ void DualModeController::LeApcf(CommandView command) { DEBUG(id_, " action={}", bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); uint8_t apcf_available_spaces = 0; - ErrorCode status = link_layer_controller_.LeApcfServiceData( + ErrorCode status = le_controller_.LeApcfServiceData( subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), subcommand_view.GetApcfServiceData(), &apcf_available_spaces); send_event_(bluetooth::hci::LeApcfServiceDataCompleteBuilder::Create( @@ -2899,7 +2935,7 @@ void DualModeController::LeApcf(CommandView command) { DEBUG(id_, " action={}", bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); uint8_t apcf_available_spaces = 0; - ErrorCode status = link_layer_controller_.LeApcfAdTypeFilter( + ErrorCode status = le_controller_.LeApcfAdTypeFilter( subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), subcommand_view.GetApcfAdType(), subcommand_view.GetApcfAdData(), subcommand_view.GetApcfAdDataMask(), &apcf_available_spaces); @@ -3126,7 +3162,7 @@ void DualModeController::LeSetAdvertisingSetRandomAddress(CommandView command) { DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); DEBUG(id_, " random_address={}", command_view.GetRandomAddress()); - ErrorCode status = link_layer_controller_.LeSetAdvertisingSetRandomAddress( + ErrorCode status = le_controller_.LeSetAdvertisingSetRandomAddress( command_view.GetAdvertisingHandle(), command_view.GetRandomAddress()); send_event_(bluetooth::hci::LeSetAdvertisingSetRandomAddressCompleteBuilder::Create( kNumCommandPackets, status)); @@ -3139,7 +3175,7 @@ void DualModeController::LeSetExtendedAdvertisingParametersV1(CommandView comman DEBUG(id_, "<< LE Set Extended Advertising Parameters V1"); DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); - ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingParameters( + ErrorCode status = le_controller_.LeSetExtendedAdvertisingParameters( command_view.GetAdvertisingHandle(), command_view.GetAdvertisingEventProperties(), command_view.GetPrimaryAdvertisingIntervalMin(), command_view.GetPrimaryAdvertisingIntervalMax(), @@ -3162,7 +3198,7 @@ void DualModeController::LeSetExtendedAdvertisingData(CommandView command) { DEBUG(id_, "<< LE Set Extended Advertising Data"); DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); - ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingData( + ErrorCode status = le_controller_.LeSetExtendedAdvertisingData( command_view.GetAdvertisingHandle(), command_view.GetOperation(), command_view.GetFragmentPreference(), command_view.GetAdvertisingData()); send_event_(bluetooth::hci::LeSetExtendedAdvertisingDataCompleteBuilder::Create( @@ -3176,7 +3212,7 @@ void DualModeController::LeSetExtendedScanResponseData(CommandView command) { DEBUG(id_, "<< LE Set Extended Scan Response Data"); DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); - ErrorCode status = link_layer_controller_.LeSetExtendedScanResponseData( + ErrorCode status = le_controller_.LeSetExtendedScanResponseData( command_view.GetAdvertisingHandle(), command_view.GetOperation(), command_view.GetFragmentPreference(), command_view.GetScanResponseData()); send_event_(bluetooth::hci::LeSetExtendedScanResponseDataCompleteBuilder::Create( @@ -3193,7 +3229,7 @@ void DualModeController::LeSetExtendedAdvertisingEnable(CommandView command) { DEBUG(id_, " advertising_handle={}", set.advertising_handle_); } - ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingEnable( + ErrorCode status = le_controller_.LeSetExtendedAdvertisingEnable( command_view.GetEnable() == bluetooth::hci::Enable::ENABLED, command_view.GetEnabledSets()); send_event_(bluetooth::hci::LeSetExtendedAdvertisingEnableCompleteBuilder::Create( @@ -3227,7 +3263,7 @@ void DualModeController::LeRemoveAdvertisingSet(CommandView command) { DEBUG(id_, "<< LE Remove Advertising Set"); DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); - auto status = link_layer_controller_.LeRemoveAdvertisingSet(command_view.GetAdvertisingHandle()); + auto status = le_controller_.LeRemoveAdvertisingSet(command_view.GetAdvertisingHandle()); send_event_(bluetooth::hci::LeRemoveAdvertisingSetCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -3238,7 +3274,7 @@ void DualModeController::LeClearAdvertisingSets(CommandView command) { DEBUG(id_, "<< LE Clear Advertising Sets"); - auto status = link_layer_controller_.LeClearAdvertisingSets(); + auto status = le_controller_.LeClearAdvertisingSets(); send_event_(bluetooth::hci::LeClearAdvertisingSetsCompleteBuilder::Create(kNumCommandPackets, status)); } @@ -3250,7 +3286,7 @@ void DualModeController::LeStartEncryption(CommandView command) { DEBUG(id_, "<< LE Start Encryption"); DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); - ErrorCode status = link_layer_controller_.LeEnableEncryption( + ErrorCode status = le_controller_.LeEnableEncryption( command_view.GetConnectionHandle(), command_view.GetRand(), command_view.GetEdiv(), command_view.GetLtk()); @@ -3266,7 +3302,7 @@ void DualModeController::LeLongTermKeyRequestReply(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", handle); ErrorCode status = - link_layer_controller_.LeLongTermKeyRequestReply(handle, command_view.GetLongTermKey()); + le_controller_.LeLongTermKeyRequestReply(handle, command_view.GetLongTermKey()); send_event_(bluetooth::hci::LeLongTermKeyRequestReplyCompleteBuilder::Create(kNumCommandPackets, status, handle)); @@ -3280,7 +3316,7 @@ void DualModeController::LeLongTermKeyRequestNegativeReply(CommandView command) DEBUG(id_, "<< LE Long Term Key Request Negative Reply"); DEBUG(id_, " connection_handle=0x{:x}", handle); - ErrorCode status = link_layer_controller_.LeLongTermKeyRequestNegativeReply(handle); + ErrorCode status = le_controller_.LeLongTermKeyRequestNegativeReply(handle); send_event_(bluetooth::hci::LeLongTermKeyRequestNegativeReplyCompleteBuilder::Create( kNumCommandPackets, status, handle)); @@ -3293,8 +3329,7 @@ void DualModeController::ReadConnectionAcceptTimeout(CommandView command) { DEBUG(id_, "<< Read Connection Accept Timeout"); send_event_(bluetooth::hci::ReadConnectionAcceptTimeoutCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, - link_layer_controller_.GetConnectionAcceptTimeout())); + kNumCommandPackets, ErrorCode::SUCCESS, bredr_controller_.GetConnectionAcceptTimeout())); } void DualModeController::WriteConnectionAcceptTimeout(CommandView command) { @@ -3303,7 +3338,7 @@ void DualModeController::WriteConnectionAcceptTimeout(CommandView command) { DEBUG(id_, "<< Write Connection Accept Timeout"); - link_layer_controller_.SetConnectionAcceptTimeout(command_view.GetConnAcceptTimeout()); + bredr_controller_.SetConnectionAcceptTimeout(command_view.GetConnAcceptTimeout()); send_event_(bluetooth::hci::WriteConnectionAcceptTimeoutCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); diff --git a/model/controller/dual_mode_controller.h b/model/controller/dual_mode_controller.h index d56273b..78c5fc6 100644 --- a/model/controller/dual_mode_controller.h +++ b/model/controller/dual_mode_controller.h @@ -27,8 +27,9 @@ #include #include "hci/address.h" +#include "model/controller/bredr_controller.h" #include "model/controller/controller_properties.h" -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "model/controller/vendor_commands/csr.h" #include "model/devices/device.h" #include "packets/hci_packets.h" @@ -550,7 +551,8 @@ class DualModeController : public Device { ControllerProperties properties_; // Link Layer state. - LinkLayerController link_layer_controller_{address_, properties_, id_}; + BrEdrController bredr_controller_{address_, properties_, id_}; + LeController le_controller_{address_, properties_, id_}; private: // Send a HCI_Command_Complete event for the specified op_code with diff --git a/model/controller/ffi.cc b/model/controller/ffi.cc index d9b1325..4a5e666 100644 --- a/model/controller/ffi.cc +++ b/model/controller/ffi.cc @@ -130,9 +130,9 @@ __attribute__((visibility("default"))) void ffi_controller_tick(void* controller __attribute__((visibility("default"))) void ffi_generate_rpa(uint8_t const irk_[16], uint8_t rpa[6]) { - std::array irk; - memcpy(irk.data(), irk_, LinkLayerController::kIrkSize); - Address address = LinkLayerController::generate_rpa(irk); + std::array irk; + memcpy(irk.data(), irk_, LeController::kIrkSize); + Address address = LeController::generate_rpa(irk); memcpy(rpa, address.data(), Address::kLength); } diff --git a/model/controller/le_acl_connection.cc b/model/controller/le_acl_connection.cc new file mode 100644 index 0000000..8a707a2 --- /dev/null +++ b/model/controller/le_acl_connection.cc @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "model/controller/le_acl_connection.h" + +#include +#include + +#include "packets/hci_packets.h" + +namespace rootcanal { + +LeAclConnection::LeAclConnection(uint16_t handle, AddressWithType address, + AddressWithType own_address, AddressWithType resolved_address, + bluetooth::hci::Role role, + LeAclConnectionParameters connection_parameters) + : handle(handle), + address(address), + own_address(own_address), + resolved_address(resolved_address), + role(role), + parameters(connection_parameters), + last_packet_timestamp_(std::chrono::steady_clock::now()), + timeout_(std::chrono::seconds(3)) {} + +void LeAclConnection::Encrypt() { encrypted_ = true; } + +bool LeAclConnection::IsEncrypted() const { return encrypted_; } + +int8_t LeAclConnection::GetRssi() const { return rssi_; } + +void LeAclConnection::SetRssi(int8_t rssi) { rssi_ = rssi; } + +void LeAclConnection::ResetLinkTimer() { + last_packet_timestamp_ = std::chrono::steady_clock::now(); +} + +std::chrono::steady_clock::duration LeAclConnection::TimeUntilNearExpiring() const { + return (last_packet_timestamp_ + timeout_ / 2) - std::chrono::steady_clock::now(); +} + +bool LeAclConnection::IsNearExpiring() const { + return TimeUntilNearExpiring() < std::chrono::steady_clock::duration::zero(); +} + +std::chrono::steady_clock::duration LeAclConnection::TimeUntilExpired() const { + return (last_packet_timestamp_ + timeout_) - std::chrono::steady_clock::now(); +} + +bool LeAclConnection::HasExpired() const { + return TimeUntilExpired() < std::chrono::steady_clock::duration::zero(); +} + +} // namespace rootcanal diff --git a/model/controller/le_acl_connection.h b/model/controller/le_acl_connection.h new file mode 100644 index 0000000..3f8973e --- /dev/null +++ b/model/controller/le_acl_connection.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "hci/address_with_type.h" +#include "packets/hci_packets.h" + +namespace rootcanal { + +using bluetooth::hci::AddressWithType; + +/// Link specification. +/// Records the configuration of the LE-ACL connection. +/// +/// Volume 6 Part B § 4.5.1. Connection events. +/// The timing of connection events is determined by the following parameters: +/// connection interval (connInterval), subrate base event (connSubrateBaseEvent), +/// subrate factor (connSubrateFactor), continuation number (connContinuationNumber), +/// and Peripheral latency (connPeripheralLatency). +struct LeAclConnectionParameters { + // The connInterval shall be a multiple of 1.25 ms in the range 7.5 ms to 4.0 s. + uint16_t conn_interval{}; + uint16_t conn_subrate_factor{1}; + uint16_t conn_continuation_number{0}; + + // The connPeripheralLatency parameter defines the number of consecutive subrated + // connection events that the Peripheral is not required to listen for the Central. + // connPeripheralLatency shall be an integer such that + // connSubrateFactor × (connPeripheralLatency + 1) is less than or equal to 500 and + // connInterval × connSubrateFactor × (connPeripheralLatency + 1) is less than half + // connSupervisionTimeout. + uint16_t conn_peripheral_latency{0}; + + // Volume 6 Part B § 4.5.2. Supervision timeout. + // Supervision timeout for the LE Link. The connSupervisionTimeout shall be a + // multiple of 10 ms. + uint16_t conn_supervision_timeout{}; +}; + +// Model the LE connection of a device to the controller. +class LeAclConnection final { +public: + const uint16_t handle; + const AddressWithType address; + const AddressWithType own_address; + const AddressWithType resolved_address; + const bluetooth::hci::Role role; + + LeAclConnectionParameters parameters; + + LeAclConnection(uint16_t handle, AddressWithType address, AddressWithType own_address, + AddressWithType resolved_address, bluetooth::hci::Role role, + LeAclConnectionParameters parameters); + ~LeAclConnection() = default; + + void Encrypt(); + bool IsEncrypted() const; + + int8_t GetRssi() const; + void SetRssi(int8_t rssi); + + std::chrono::steady_clock::duration TimeUntilNearExpiring() const; + std::chrono::steady_clock::duration TimeUntilExpired() const; + void ResetLinkTimer(); + bool IsNearExpiring() const; + bool HasExpired() const; + + // LE-ACL state. + void InitiatePhyUpdate() { initiated_phy_update_ = true; } + void PhyUpdateComplete() { initiated_phy_update_ = false; } + bool InitiatedPhyUpdate() const { return initiated_phy_update_; } + bluetooth::hci::PhyType GetTxPhy() const { return tx_phy_; } + bluetooth::hci::PhyType GetRxPhy() const { return rx_phy_; } + void SetTxPhy(bluetooth::hci::PhyType phy) { tx_phy_ = phy; } + void SetRxPhy(bluetooth::hci::PhyType phy) { rx_phy_ = phy; } + +private: + // Reports the RSSI measured for the last packet received on + // this connection. + int8_t rssi_{0}; + + // State variables + bool encrypted_{false}; + std::chrono::steady_clock::time_point last_packet_timestamp_; + std::chrono::steady_clock::duration timeout_; + + // LE-ACL state. + bluetooth::hci::PhyType tx_phy_{bluetooth::hci::PhyType::LE_1M}; + bluetooth::hci::PhyType rx_phy_{bluetooth::hci::PhyType::LE_1M}; + bool initiated_phy_update_{false}; +}; + +} // namespace rootcanal diff --git a/model/controller/le_advertiser.cc b/model/controller/le_advertiser.cc index bb2ba4b..076b497 100644 --- a/model/controller/le_advertiser.cc +++ b/model/controller/le_advertiser.cc @@ -26,7 +26,7 @@ #include "hci/address_with_type.h" #include "log.h" -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "packets/hci_packets.h" #include "packets/link_layer_packets.h" @@ -61,7 +61,7 @@ const uint16_t max_extended_advertising_pdu_size = 1650; // ============================================================================= // HCI command LE_Set_Advertising_Parameters (Vol 4, Part E § 7.8.5). -ErrorCode LinkLayerController::LeSetAdvertisingParameters( +ErrorCode LeController::LeSetAdvertisingParameters( uint16_t advertising_interval_min, uint16_t advertising_interval_max, AdvertisingType advertising_type, OwnAddressType own_address_type, PeerAddressType peer_address_type, Address peer_address, uint8_t advertising_channel_map, @@ -143,7 +143,7 @@ ErrorCode LinkLayerController::LeSetAdvertisingParameters( } // HCI command LE_Set_Advertising_Data (Vol 4, Part E § 7.8.7). -ErrorCode LinkLayerController::LeSetAdvertisingData(const std::vector& advertising_data) { +ErrorCode LeController::LeSetAdvertisingData(const std::vector& advertising_data) { // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { @@ -158,8 +158,7 @@ ErrorCode LinkLayerController::LeSetAdvertisingData(const std::vector& } // HCI command LE_Set_Scan_Response_Data (Vol 4, Part E § 7.8.8). -ErrorCode LinkLayerController::LeSetScanResponseData( - const std::vector& scan_response_data) { +ErrorCode LeController::LeSetScanResponseData(const std::vector& scan_response_data) { // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { @@ -174,7 +173,7 @@ ErrorCode LinkLayerController::LeSetScanResponseData( } // HCI command LE_Advertising_Enable (Vol 4, Part E § 7.8.9). -ErrorCode LinkLayerController::LeSetAdvertisingEnable(bool advertising_enable) { +ErrorCode LeController::LeSetAdvertisingEnable(bool advertising_enable) { // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { @@ -285,8 +284,8 @@ ErrorCode LinkLayerController::LeSetAdvertisingEnable(bool advertising_enable) { // ============================================================================= // HCI command LE_Set_Advertising_Set_Random_Address (Vol 4, Part E § 7.8.52). -ErrorCode LinkLayerController::LeSetAdvertisingSetRandomAddress(uint8_t advertising_handle, - Address random_address) { +ErrorCode LeController::LeSetAdvertisingSetRandomAddress(uint8_t advertising_handle, + Address random_address) { // If the advertising set corresponding to the Advertising_Handle parameter // does not exist, then the Controller shall return the error code // Unknown Advertising Identifier (0x42). @@ -313,7 +312,7 @@ ErrorCode LinkLayerController::LeSetAdvertisingSetRandomAddress(uint8_t advertis } // HCI command LE_Set_Extended_Advertising_Parameters (Vol 4, Part E § 7.8.53). -ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( +ErrorCode LeController::LeSetExtendedAdvertisingParameters( uint8_t advertising_handle, AdvertisingEventProperties advertising_event_properties, uint16_t primary_advertising_interval_min, uint16_t primary_advertising_interval_max, uint8_t primary_advertising_channel_map, OwnAddressType own_address_type, @@ -570,9 +569,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( } // HCI command LE_Set_Extended_Advertising_Data (Vol 4, Part E § 7.8.54). -ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( - uint8_t advertising_handle, Operation operation, FragmentPreference fragment_preference, - const std::vector& advertising_data) { +ErrorCode LeController::LeSetExtendedAdvertisingData(uint8_t advertising_handle, + Operation operation, + FragmentPreference fragment_preference, + const std::vector& advertising_data) { // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { @@ -743,7 +743,7 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( } // HCI command LE_Set_Extended_Scan_Response_Data (Vol 4, Part E § 7.8.55). -ErrorCode LinkLayerController::LeSetExtendedScanResponseData( +ErrorCode LeController::LeSetExtendedScanResponseData( uint8_t advertising_handle, Operation operation, FragmentPreference fragment_preference, const std::vector& scan_response_data) { // Extended advertising commands are disallowed when legacy advertising @@ -906,7 +906,7 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( } // HCI command LE_Set_Extended_Advertising_Enable (Vol 4, Part E § 7.8.56). -ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( +ErrorCode LeController::LeSetExtendedAdvertisingEnable( bool enable, const std::vector& sets) { // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. @@ -1123,7 +1123,7 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( } // HCI command LE_Remove_Advertising_Set (Vol 4, Part E § 7.8.59). -ErrorCode LinkLayerController::LeRemoveAdvertisingSet(uint8_t advertising_handle) { +ErrorCode LeController::LeRemoveAdvertisingSet(uint8_t advertising_handle) { // If the advertising set corresponding to the Advertising_Handle parameter // does not exist, then the Controller shall return the error code // Unknown Advertising Identifier (0x42). @@ -1148,7 +1148,7 @@ ErrorCode LinkLayerController::LeRemoveAdvertisingSet(uint8_t advertising_handle } // HCI command LE_Clear_Advertising_Sets (Vol 4, Part E § 7.8.60). -ErrorCode LinkLayerController::LeClearAdvertisingSets() { +ErrorCode LeController::LeClearAdvertisingSets() { // If advertising or periodic advertising is enabled on any advertising set, // then the Controller shall return the error code Command Disallowed (0x0C). for (auto& advertiser : extended_advertisers_) { @@ -1196,9 +1196,9 @@ uint16_t ExtendedAdvertiser::GetMaxAdvertisingDataLength( // length is 254. Extended payload header fields eat into the // available space. max_advertising_data_length = 254; - max_advertising_data_length -= 6; // AdvA - max_advertising_data_length -= 2; // ADI - max_advertising_data_length -= 6 * properties.directed_; // TargetA + max_advertising_data_length -= 6; // AdvA + max_advertising_data_length -= 2; // ADI + max_advertising_data_length -= 6 * properties.directed_; // TargetA max_advertising_data_length -= 1 * properties.include_tx_power_; // TxPower // TODO(pedantic): configure the ACAD field in order to leave the least // amount of AdvData space to the user (191). @@ -1263,7 +1263,7 @@ uint16_t ExtendedAdvertiser::GetRawAdvertisingEventProperties( // ============================================================================= // HCI LE Set Periodic Advertising Parameters command (Vol 4, Part E § 7.8.61). -ErrorCode LinkLayerController::LeSetPeriodicAdvertisingParameters( +ErrorCode LeController::LeSetPeriodicAdvertisingParameters( uint8_t advertising_handle, uint16_t periodic_advertising_interval_min, uint16_t periodic_advertising_interval_max, bool /*include_tx_power*/) { // The Advertising_Handle parameter identifies the advertising set whose @@ -1338,9 +1338,9 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingParameters( } // HCI LE Set Periodic Advertising Data command (Vol 4, Part E § 7.8.62). -ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( - uint8_t advertising_handle, bluetooth::hci::Operation operation, - const std::vector& advertising_data) { +ErrorCode LeController::LeSetPeriodicAdvertisingData(uint8_t advertising_handle, + bluetooth::hci::Operation operation, + const std::vector& advertising_data) { // If the advertising set corresponding to the Advertising_Handle parameter // does not exist, then the Controller shall return the error code // Unknown Advertising Identifier (0x42). @@ -1463,8 +1463,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( } // HCI LE Set Periodic Advertising Enable command (Vol 4, Part E § 7.8.63). -ErrorCode LinkLayerController::LeSetPeriodicAdvertisingEnable(bool enable, bool include_adi, - uint8_t advertising_handle) { +ErrorCode LeController::LeSetPeriodicAdvertisingEnable(bool enable, bool include_adi, + uint8_t advertising_handle) { // If the advertising set corresponding to the Advertising_Handle parameter // does not exist, the Controller shall return the error code Unknown // Advertising Identifier (0x42). @@ -1557,7 +1557,7 @@ uint16_t ExtendedAdvertiser::GetMaxPeriodicAdvertisingDataLength( // Advertising Routines // ============================================================================= -void LinkLayerController::LeAdvertising() { +void LeController::LeAdvertising() { chrono::time_point now = std::chrono::steady_clock::now(); // Legacy Advertising Timeout diff --git a/model/controller/link_layer_controller.cc b/model/controller/le_controller.cc similarity index 65% rename from model/controller/link_layer_controller.cc rename to model/controller/le_controller.cc index def4304..c6da6a5 100644 --- a/model/controller/link_layer_controller.cc +++ b/model/controller/le_controller.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include @@ -37,6 +37,7 @@ #include "model/controller/acl_connection.h" #include "model/controller/acl_connection_handler.h" #include "model/controller/controller_properties.h" +#include "model/controller/le_acl_connection.h" #include "model/controller/le_advertiser.h" #include "model/controller/sco_connection.h" #include "packets/hci_packets.h" @@ -54,15 +55,14 @@ using bluetooth::hci::SubeventCode; using namespace model::packets; using namespace std::literals; -using TaskId = rootcanal::LinkLayerController::TaskId; +using TaskId = rootcanal::LeController::TaskId; namespace rootcanal { constexpr milliseconds kScanRequestTimeout(200); constexpr milliseconds kNoDelayMs(0); -constexpr milliseconds kPageInterval(1000); -const Address& LinkLayerController::GetAddress() const { return address_; } +const Address& LeController::GetAddress() const { return address_; } AddressWithType PeerDeviceAddress(Address address, PeerAddressType peer_address_type) { switch (peer_address_type) { @@ -82,7 +82,7 @@ AddressWithType PeerIdentityAddress(Address address, PeerAddressType peer_addres } } -bool LinkLayerController::IsEventUnmasked(EventCode event) const { +bool LeController::IsEventUnmasked(EventCode event) const { uint8_t evt = static_cast(event); if (evt <= 64) { @@ -95,12 +95,12 @@ bool LinkLayerController::IsEventUnmasked(EventCode event) const { } } -bool LinkLayerController::IsLeEventUnmasked(SubeventCode subevent) const { +bool LeController::IsLeEventUnmasked(SubeventCode subevent) const { uint64_t bit = UINT64_C(1) << (static_cast(subevent) - 1); return IsEventUnmasked(EventCode::LE_META_EVENT) && (le_event_mask_ & bit) != 0; } -bool LinkLayerController::FilterAcceptListBusy() { +bool LeController::FilterAcceptListBusy() { // Filter Accept List cannot be modified when // • any advertising filter policy uses the Filter Accept List and // advertising is enabled, @@ -139,8 +139,8 @@ bool LinkLayerController::FilterAcceptListBusy() { return false; } -bool LinkLayerController::LeFilterAcceptListContainsDevice(FilterAcceptListAddressType address_type, - Address address) { +bool LeController::LeFilterAcceptListContainsDevice(FilterAcceptListAddressType address_type, + Address address) { for (auto const& entry : le_filter_accept_list_) { if (entry.address_type == address_type && (address_type == FilterAcceptListAddressType::ANONYMOUS_ADVERTISERS || @@ -152,7 +152,7 @@ bool LinkLayerController::LeFilterAcceptListContainsDevice(FilterAcceptListAddre return false; } -bool LinkLayerController::LePeriodicAdvertiserListContainsDevice( +bool LeController::LePeriodicAdvertiserListContainsDevice( bluetooth::hci::AdvertiserAddressType advertiser_address_type, Address advertiser_address, uint8_t advertising_sid) { for (auto const& entry : le_periodic_advertiser_list_) { @@ -166,7 +166,7 @@ bool LinkLayerController::LePeriodicAdvertiserListContainsDevice( return false; } -bool LinkLayerController::LeFilterAcceptListContainsDevice(AddressWithType address) { +bool LeController::LeFilterAcceptListContainsDevice(AddressWithType address) { FilterAcceptListAddressType address_type; switch (address.GetAddressType()) { case AddressType::PUBLIC_DEVICE_ADDRESS: @@ -182,7 +182,7 @@ bool LinkLayerController::LeFilterAcceptListContainsDevice(AddressWithType addre return LeFilterAcceptListContainsDevice(address_type, address.GetAddress()); } -bool LinkLayerController::ResolvingListBusy() { +bool LeController::ResolvingListBusy() { // The resolving list cannot be modified when // • Advertising (other than periodic advertising) is enabled, if (legacy_advertiser_.IsEnabled()) { @@ -209,7 +209,7 @@ bool LinkLayerController::ResolvingListBusy() { return false; } -std::optional LinkLayerController::ResolvePrivateAddress(AddressWithType address) { +std::optional LeController::ResolvePrivateAddress(AddressWithType address) { if (!address.IsRpa()) { return address; } @@ -231,7 +231,7 @@ std::optional LinkLayerController::ResolvePrivateAddress(Addres return {}; } -bool LinkLayerController::ResolveTargetA(AddressWithType target_a, AddressWithType adv_a) { +bool LeController::ResolveTargetA(AddressWithType target_a, AddressWithType adv_a) { if (!le_resolving_list_enabled_) { return false; } @@ -246,7 +246,7 @@ bool LinkLayerController::ResolveTargetA(AddressWithType target_a, AddressWithTy return false; } -bool LinkLayerController::ValidateTargetA(AddressWithType target_a, AddressWithType adv_a) { +bool LeController::ValidateTargetA(AddressWithType target_a, AddressWithType adv_a) { if (IsLocalPublicOrRandomAddress(target_a)) { return true; } @@ -256,12 +256,12 @@ bool LinkLayerController::ValidateTargetA(AddressWithType target_a, AddressWithT return false; } -std::optional LinkLayerController::GenerateResolvablePrivateAddress( +std::optional LeController::GenerateResolvablePrivateAddress( AddressWithType address, IrkSelection irk) { for (auto& entry : le_resolving_list_) { if (address.GetAddress() == entry.peer_identity_address && address.ToPeerAddressType() == entry.peer_identity_address_type) { - std::array const& used_irk = + std::array const& used_irk = irk == IrkSelection::Local ? entry.local_irk : entry.peer_irk; Address local_resolvable_address = generate_rpa(used_irk); @@ -283,16 +283,16 @@ std::optional LinkLayerController::GenerateResolvablePrivateAdd // ============================================================================= // HCI Read Rssi command (Vol 4, Part E § 7.5.4). -ErrorCode LinkLayerController::ReadRssi(uint16_t connection_handle, int8_t* rssi) { - // Not documented: If the connection handle is not found, the Controller - // shall return the error code Unknown Connection Identifier (0x02). - if (!connections_.HasHandle(connection_handle)) { - INFO(id_, "unknown connection identifier"); - return ErrorCode::UNKNOWN_CONNECTION; +ErrorCode LeController::ReadRssi(uint16_t connection_handle, int8_t* rssi) { + if (connections_.HasLeAclHandle(connection_handle)) { + *rssi = connections_.GetLeAclConnection(connection_handle).GetRssi(); + return ErrorCode::SUCCESS; } - *rssi = connections_.GetRssi(connection_handle); - return ErrorCode::SUCCESS; + // Not documented: If the connection handle is not found, the Controller + // shall return the error code Unknown Connection Identifier (0x02). + INFO(id_, "unknown connection identifier"); + return ErrorCode::UNKNOWN_CONNECTION; } // ============================================================================= @@ -300,7 +300,7 @@ ErrorCode LinkLayerController::ReadRssi(uint16_t connection_handle, int8_t* rssi // ============================================================================= // HCI LE Set Random Address command (Vol 4, Part E § 7.8.4). -ErrorCode LinkLayerController::LeSetRandomAddress(Address random_address) { +ErrorCode LeController::LeSetRandomAddress(Address random_address) { // If the Host issues this command when any of advertising (created using // legacy advertising commands), scanning, or initiating are enabled, // the Controller shall return the error code Command Disallowed (0x0C). @@ -319,7 +319,7 @@ ErrorCode LinkLayerController::LeSetRandomAddress(Address random_address) { } // HCI LE Set Host Feature command (Vol 4, Part E § 7.8.45). -ErrorCode LinkLayerController::LeSetResolvablePrivateAddressTimeout(uint16_t rpa_timeout) { +ErrorCode LeController::LeSetResolvablePrivateAddressTimeout(uint16_t rpa_timeout) { // Note: no documented status code for this case. if (rpa_timeout < 0x1 || rpa_timeout > 0x0e10) { INFO(id_, @@ -334,26 +334,24 @@ ErrorCode LinkLayerController::LeSetResolvablePrivateAddressTimeout(uint16_t rpa } // HCI LE Read Phy command (Vol 4, Part E § 7.8.47). -ErrorCode LinkLayerController::LeReadPhy(uint16_t connection_handle, - bluetooth::hci::PhyType* tx_phy, - bluetooth::hci::PhyType* rx_phy) { +ErrorCode LeController::LeReadPhy(uint16_t connection_handle, bluetooth::hci::PhyType* tx_phy, + bluetooth::hci::PhyType* rx_phy) { // Note: no documented status code for this case. - if (!connections_.HasHandle(connection_handle) || - connections_.GetPhyType(connection_handle) != Phy::Type::LOW_ENERGY) { + if (!connections_.HasLeAclHandle(connection_handle)) { INFO(id_, "unknown or invalid connection handle"); return ErrorCode::UNKNOWN_CONNECTION; } - AclConnection const& connection = connections_.GetAclConnection(connection_handle); + LeAclConnection const& connection = connections_.GetLeAclConnection(connection_handle); *tx_phy = connection.GetTxPhy(); *rx_phy = connection.GetRxPhy(); return ErrorCode::SUCCESS; } // HCI LE Set Default Phy command (Vol 4, Part E § 7.8.48). -ErrorCode LinkLayerController::LeSetDefaultPhy(bool all_phys_no_transmit_preference, - bool all_phys_no_receive_preference, uint8_t tx_phys, - uint8_t rx_phys) { +ErrorCode LeController::LeSetDefaultPhy(bool all_phys_no_transmit_preference, + bool all_phys_no_receive_preference, uint8_t tx_phys, + uint8_t rx_phys) { uint8_t supported_phys = properties_.LeSupportedPhys(); // If the All_PHYs parameter specifies that the Host has no preference, @@ -397,20 +395,19 @@ ErrorCode LinkLayerController::LeSetDefaultPhy(bool all_phys_no_transmit_prefere } // HCI LE Set Phy command (Vol 4, Part E § 7.8.49). -ErrorCode LinkLayerController::LeSetPhy(uint16_t connection_handle, - bool all_phys_no_transmit_preference, - bool all_phys_no_receive_preference, uint8_t tx_phys, - uint8_t rx_phys, - bluetooth::hci::PhyOptions /*phy_options*/) { +ErrorCode LeController::LeSetPhy(uint16_t connection_handle, bool all_phys_no_transmit_preference, + bool all_phys_no_receive_preference, uint8_t tx_phys, + uint8_t rx_phys, bluetooth::hci::PhyOptions /*phy_options*/) { uint8_t supported_phys = properties_.LeSupportedPhys(); // Note: no documented status code for this case. - if (!connections_.HasHandle(connection_handle) || - connections_.GetPhyType(connection_handle) != Phy::Type::LOW_ENERGY) { + if (!connections_.HasLeAclHandle(connection_handle)) { INFO(id_, "unknown or invalid connection handle"); return ErrorCode::UNKNOWN_CONNECTION; } + auto& connection = connections_.GetLeAclConnection(connection_handle); + // If the All_PHYs parameter specifies that the Host has no preference, // the TX_PHYs parameter shall be ignored; otherwise at least one bit shall // be set to 1. @@ -450,10 +447,9 @@ ErrorCode LinkLayerController::LeSetPhy(uint16_t connection_handle, // or both PHY changes or when the Controller determines that neither PHY // will change immediately. SendLeLinkLayerPacket(model::packets::LlPhyReqBuilder::Create( - connections_.GetOwnAddress(connection_handle).GetAddress(), - connections_.GetAddress(connection_handle).GetAddress(), tx_phys, rx_phys)); + connection.own_address.GetAddress(), connection.address.GetAddress(), tx_phys, rx_phys)); - connections_.GetAclConnection(connection_handle).InitiatePhyUpdate(); + connection.InitiatePhyUpdate(); requested_tx_phys_ = tx_phys; requested_rx_phys_ = rx_phys; return ErrorCode::SUCCESS; @@ -476,20 +472,12 @@ static uint8_t indicate_phy(bluetooth::hci::PhyType selected, bluetooth::hci::Ph : 0x1; } -void LinkLayerController::IncomingLlPhyReq(model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLlPhyReq(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming) { auto phy_req = model::packets::LlPhyReqView::Create(incoming); ASSERT(phy_req.IsValid()); - uint16_t connection_handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); - - if (connection_handle == kReservedHandle) { - INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), - incoming.GetSourceAddress()); - return; - } - - AclConnection& connection = connections_.GetAclConnection(connection_handle); - if (connection.GetRole() == bluetooth::hci::Role::PERIPHERAL) { + if (connection.role == bluetooth::hci::Role::PERIPHERAL) { // Peripheral receives the request: respond with local phy preferences // in LL_PHY_RSP pdu. SendLeLinkLayerPacket(model::packets::LlPhyRspBuilder::Create( @@ -524,7 +512,7 @@ void LinkLayerController::IncomingLlPhyReq(model::packets::LinkLayerPacketView i if ((phy_c_to_p != connection.GetTxPhy() || phy_p_to_c != connection.GetRxPhy()) && IsLeEventUnmasked(SubeventCode::LE_PHY_UPDATE_COMPLETE)) { send_event_(bluetooth::hci::LePhyUpdateCompleteBuilder::Create( - ErrorCode::SUCCESS, connection_handle, phy_c_to_p, phy_p_to_c)); + ErrorCode::SUCCESS, connection.handle, phy_c_to_p, phy_p_to_c)); } // Update local state. @@ -533,19 +521,11 @@ void LinkLayerController::IncomingLlPhyReq(model::packets::LinkLayerPacketView i } } -void LinkLayerController::IncomingLlPhyRsp(model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLlPhyRsp(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming) { auto phy_rsp = model::packets::LlPhyRspView::Create(incoming); ASSERT(phy_rsp.IsValid()); - uint16_t connection_handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); - - if (connection_handle == kReservedHandle) { - INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), - incoming.GetSourceAddress()); - return; - } - - AclConnection& connection = connections_.GetAclConnection(connection_handle); - ASSERT(connection.GetRole() == bluetooth::hci::Role::CENTRAL); + ASSERT(connection.role == bluetooth::hci::Role::CENTRAL); // Intersect phy preferences with local preferences. uint8_t tx_phys = phy_rsp.GetRxPhys() & requested_tx_phys_; @@ -571,7 +551,7 @@ void LinkLayerController::IncomingLlPhyRsp(model::packets::LinkLayerPacketView i // (initiator in this case). if (IsLeEventUnmasked(SubeventCode::LE_PHY_UPDATE_COMPLETE)) { send_event_(bluetooth::hci::LePhyUpdateCompleteBuilder::Create( - ErrorCode::SUCCESS, connection_handle, phy_c_to_p, phy_p_to_c)); + ErrorCode::SUCCESS, connection.handle, phy_c_to_p, phy_p_to_c)); } // Update local state. @@ -580,19 +560,11 @@ void LinkLayerController::IncomingLlPhyRsp(model::packets::LinkLayerPacketView i connection.SetRxPhy(phy_p_to_c); } -void LinkLayerController::IncomingLlPhyUpdateInd(model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLlPhyUpdateInd(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming) { auto phy_update_ind = model::packets::LlPhyUpdateIndView::Create(incoming); ASSERT(phy_update_ind.IsValid()); - uint16_t connection_handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); - - if (connection_handle == kReservedHandle) { - INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), - incoming.GetSourceAddress()); - return; - } - - AclConnection& connection = connections_.GetAclConnection(connection_handle); - ASSERT(connection.GetRole() == bluetooth::hci::Role::PERIPHERAL); + ASSERT(connection.role == bluetooth::hci::Role::PERIPHERAL); bluetooth::hci::PhyType tx_phy = select_phy(phy_update_ind.GetPhyPToC(), connection.GetTxPhy()); bluetooth::hci::PhyType rx_phy = select_phy(phy_update_ind.GetPhyCToP(), connection.GetRxPhy()); @@ -604,7 +576,7 @@ void LinkLayerController::IncomingLlPhyUpdateInd(model::packets::LinkLayerPacket (tx_phy != connection.GetTxPhy() || rx_phy != connection.GetRxPhy() || connection.InitiatedPhyUpdate())) { send_event_(bluetooth::hci::LePhyUpdateCompleteBuilder::Create( - ErrorCode::SUCCESS, connection_handle, tx_phy, rx_phy)); + ErrorCode::SUCCESS, connection.handle, tx_phy, rx_phy)); } connection.PhyUpdateComplete(); @@ -613,11 +585,10 @@ void LinkLayerController::IncomingLlPhyUpdateInd(model::packets::LinkLayerPacket } // HCI LE Set Data Length (Vol 4, Part E § 7.8.33). -ErrorCode LinkLayerController::LeSetDataLength(uint16_t connection_handle, uint16_t tx_octets, - uint16_t tx_time) { +ErrorCode LeController::LeSetDataLength(uint16_t connection_handle, uint16_t tx_octets, + uint16_t tx_time) { // Note: no documented status code for this case. - if (!connections_.HasHandle(connection_handle) || - connections_.GetPhyType(connection_handle) != Phy::Type::LOW_ENERGY) { + if (!connections_.HasLeAclHandle(connection_handle)) { INFO(id_, "unknown or invalid connection handle"); return ErrorCode::UNKNOWN_CONNECTION; } @@ -645,7 +616,7 @@ ErrorCode LinkLayerController::LeSetDataLength(uint16_t connection_handle, uint1 } // HCI LE Set Host Feature command (Vol 4, Part E § 7.8.115). -ErrorCode LinkLayerController::LeSetHostFeature(uint8_t bit_number, uint8_t bit_value) { +ErrorCode LeController::LeSetHostFeature(uint8_t bit_number, uint8_t bit_value) { if (bit_number >= 64 || bit_value > 1) { return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -659,7 +630,7 @@ ErrorCode LinkLayerController::LeSetHostFeature(uint8_t bit_number, uint8_t bit_ // If the Host issues this command while the Controller has a connection to // another device, the Controller shall return the error code // Command Disallowed (0x0C). - if (HasAclConnection()) { + if (!connections_.GetLeAclHandles().empty()) { return ErrorCode::COMMAND_DISALLOWED; } @@ -690,9 +661,10 @@ ErrorCode LinkLayerController::LeSetHostFeature(uint8_t bit_number, uint8_t bit_ // ============================================================================= // HCI command LE_Add_Device_To_Resolving_List (Vol 4, Part E § 7.8.38). -ErrorCode LinkLayerController::LeAddDeviceToResolvingList( - PeerAddressType peer_identity_address_type, Address peer_identity_address, - std::array peer_irk, std::array local_irk) { +ErrorCode LeController::LeAddDeviceToResolvingList(PeerAddressType peer_identity_address_type, + Address peer_identity_address, + std::array peer_irk, + std::array local_irk) { // This command shall not be used when address resolution is enabled in the // Controller and: // • Advertising (other than periodic advertising) is enabled, @@ -737,8 +709,8 @@ ErrorCode LinkLayerController::LeAddDeviceToResolvingList( } // HCI command LE_Remove_Device_From_Resolving_List (Vol 4, Part E § 7.8.39). -ErrorCode LinkLayerController::LeRemoveDeviceFromResolvingList( - PeerAddressType peer_identity_address_type, Address peer_identity_address) { +ErrorCode LeController::LeRemoveDeviceFromResolvingList(PeerAddressType peer_identity_address_type, + Address peer_identity_address) { // This command shall not be used when address resolution is enabled in the // Controller and: // • Advertising (other than periodic advertising) is enabled, @@ -768,7 +740,7 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromResolvingList( } // HCI command LE_Clear_Resolving_List (Vol 4, Part E § 7.8.40). -ErrorCode LinkLayerController::LeClearResolvingList() { +ErrorCode LeController::LeClearResolvingList() { // This command shall not be used when address resolution is enabled in the // Controller and: // • Advertising (other than periodic advertising) is enabled, @@ -787,9 +759,9 @@ ErrorCode LinkLayerController::LeClearResolvingList() { } // HCI command LE_Read_Peer_Resolvable_Address (Vol 4, Part E § 7.8.42). -ErrorCode LinkLayerController::LeReadPeerResolvableAddress( - PeerAddressType peer_identity_address_type, Address peer_identity_address, - Address* peer_resolvable_address) { +ErrorCode LeController::LeReadPeerResolvableAddress(PeerAddressType peer_identity_address_type, + Address peer_identity_address, + Address* peer_resolvable_address) { for (auto const& entry : le_resolving_list_) { if (entry.peer_identity_address_type == peer_identity_address_type && entry.peer_identity_address == peer_identity_address && @@ -811,9 +783,9 @@ ErrorCode LinkLayerController::LeReadPeerResolvableAddress( } // HCI command LE_Read_Local_Resolvable_Address (Vol 4, Part E § 7.8.43). -ErrorCode LinkLayerController::LeReadLocalResolvableAddress( - PeerAddressType peer_identity_address_type, Address peer_identity_address, - Address* local_resolvable_address) { +ErrorCode LeController::LeReadLocalResolvableAddress(PeerAddressType peer_identity_address_type, + Address peer_identity_address, + Address* local_resolvable_address) { for (auto const& entry : le_resolving_list_) { if (entry.peer_identity_address_type == peer_identity_address_type && entry.peer_identity_address == peer_identity_address && @@ -835,7 +807,7 @@ ErrorCode LinkLayerController::LeReadLocalResolvableAddress( } // HCI command LE_Set_Address_Resolution_Enable (Vol 4, Part E § 7.8.44). -ErrorCode LinkLayerController::LeSetAddressResolutionEnable(bool enable) { +ErrorCode LeController::LeSetAddressResolutionEnable(bool enable) { // This command shall not be used when: // • Advertising (other than periodic advertising) is enabled, // • Scanning is enabled, or @@ -853,9 +825,9 @@ ErrorCode LinkLayerController::LeSetAddressResolutionEnable(bool enable) { } // HCI command LE_Set_Privacy_Mode (Vol 4, Part E § 7.8.77). -ErrorCode LinkLayerController::LeSetPrivacyMode(PeerAddressType peer_identity_address_type, - Address peer_identity_address, - bluetooth::hci::PrivacyMode privacy_mode) { +ErrorCode LeController::LeSetPrivacyMode(PeerAddressType peer_identity_address_type, + Address peer_identity_address, + bluetooth::hci::PrivacyMode privacy_mode) { // This command shall not be used when address resolution is enabled in the // Controller and: // • Advertising (other than periodic advertising) is enabled, @@ -888,7 +860,7 @@ ErrorCode LinkLayerController::LeSetPrivacyMode(PeerAddressType peer_identity_ad // ============================================================================= // HCI command LE_Clear_Filter_Accept_List (Vol 4, Part E § 7.8.15). -ErrorCode LinkLayerController::LeClearFilterAcceptList() { +ErrorCode LeController::LeClearFilterAcceptList() { // This command shall not be used when: // • any advertising filter policy uses the Filter Accept List and // advertising is enabled, @@ -909,8 +881,8 @@ ErrorCode LinkLayerController::LeClearFilterAcceptList() { } // HCI command LE_Add_Device_To_Filter_Accept_List (Vol 4, Part E § 7.8.16). -ErrorCode LinkLayerController::LeAddDeviceToFilterAcceptList( - FilterAcceptListAddressType address_type, Address address) { +ErrorCode LeController::LeAddDeviceToFilterAcceptList(FilterAcceptListAddressType address_type, + Address address) { // This command shall not be used when: // • any advertising filter policy uses the Filter Accept List and // advertising is enabled, @@ -940,8 +912,8 @@ ErrorCode LinkLayerController::LeAddDeviceToFilterAcceptList( // HCI command LE_Remove_Device_From_Filter_Accept_List (Vol 4, Part E // § 7.8.17). -ErrorCode LinkLayerController::LeRemoveDeviceFromFilterAcceptList( - FilterAcceptListAddressType address_type, Address address) { +ErrorCode LeController::LeRemoveDeviceFromFilterAcceptList(FilterAcceptListAddressType address_type, + Address address) { // This command shall not be used when: // • any advertising filter policy uses the Filter Accept List and // advertising is enabled, @@ -978,7 +950,7 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromFilterAcceptList( // HCI LE Add Device To Periodic Advertiser List command (Vol 4, Part E // § 7.8.70). -ErrorCode LinkLayerController::LeAddDeviceToPeriodicAdvertiserList( +ErrorCode LeController::LeAddDeviceToPeriodicAdvertiserList( bluetooth::hci::AdvertiserAddressType advertiser_address_type, Address advertiser_address, uint8_t advertising_sid) { // If the Host issues this command when an HCI_LE_Periodic_Advertising_- @@ -1015,7 +987,7 @@ ErrorCode LinkLayerController::LeAddDeviceToPeriodicAdvertiserList( // HCI LE Remove Device From Periodic Advertiser List command // (Vol 4, Part E § 7.8.71). -ErrorCode LinkLayerController::LeRemoveDeviceFromPeriodicAdvertiserList( +ErrorCode LeController::LeRemoveDeviceFromPeriodicAdvertiserList( bluetooth::hci::AdvertiserAddressType advertiser_address_type, Address advertiser_address, uint8_t advertising_sid) { // If this command is used when an HCI_LE_Periodic_Advertising_Create_Sync @@ -1043,7 +1015,7 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromPeriodicAdvertiserList( } // HCI LE Clear Periodic Advertiser List command (Vol 4, Part E § 7.8.72). -ErrorCode LinkLayerController::LeClearPeriodicAdvertiserList() { +ErrorCode LeController::LeClearPeriodicAdvertiserList() { // If this command is used when an HCI_LE_Periodic_Advertising_Create_Sync // command is pending, the Controller shall return the error code Command // Disallowed (0x0C). @@ -1061,7 +1033,7 @@ ErrorCode LinkLayerController::LeClearPeriodicAdvertiserList() { // ============================================================================= // HCI LE Periodic Advertising Create Sync command (Vol 4, Part E § 7.8.67). -ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSync( +ErrorCode LeController::LePeriodicAdvertisingCreateSync( bluetooth::hci::PeriodicAdvertisingOptions options, uint8_t advertising_sid, bluetooth::hci::AdvertiserAddressType advertiser_address_type, Address advertiser_address, uint16_t /*skip*/, uint16_t sync_timeout, uint8_t sync_cte_type) { @@ -1144,7 +1116,7 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSync( // HCI LE Periodic Advertising Create Sync Cancel command (Vol 4, Part E // § 7.8.68). -ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSyncCancel() { +ErrorCode LeController::LePeriodicAdvertisingCreateSyncCancel() { // If the Host issues this command while no HCI_LE_Periodic_Advertising_- // Create_Sync command is pending, the Controller shall return the error code // Command Disallowed (0x0C). @@ -1172,7 +1144,7 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSyncCancel() { // HCI LE Periodic Advertising Terminate Sync command (Vol 4, Part E // § 7.8.69). -ErrorCode LinkLayerController::LePeriodicAdvertisingTerminateSync(uint16_t sync_handle) { +ErrorCode LeController::LePeriodicAdvertisingTerminateSync(uint16_t sync_handle) { // If the periodic advertising train corresponding to the Sync_Handle // parameter does not exist, then the Controller shall return the error // code Unknown Advertising Identifier (0x42). @@ -1190,7 +1162,7 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingTerminateSync(uint16_t sync_ // ============================================================================= // HCI command LE_Set_Scan_Parameters (Vol 4, Part E § 7.8.10). -ErrorCode LinkLayerController::LeSetScanParameters( +ErrorCode LeController::LeSetScanParameters( bluetooth::hci::LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window, bluetooth::hci::OwnAddressType own_address_type, bluetooth::hci::LeScanningFilterPolicy scanning_filter_policy) { @@ -1241,7 +1213,7 @@ ErrorCode LinkLayerController::LeSetScanParameters( } // HCI command LE_Set_Scan_Enable (Vol 4, Part E § 7.8.11). -ErrorCode LinkLayerController::LeSetScanEnable(bool enable, bool filter_duplicates) { +ErrorCode LeController::LeSetScanEnable(bool enable, bool filter_duplicates) { // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { @@ -1293,7 +1265,7 @@ ErrorCode LinkLayerController::LeSetScanEnable(bool enable, bool filter_duplicat // ============================================================================= // HCI command LE_Set_Extended_Scan_Parameters (Vol 4, Part E § 7.8.64). -ErrorCode LinkLayerController::LeSetExtendedScanParameters( +ErrorCode LeController::LeSetExtendedScanParameters( bluetooth::hci::OwnAddressType own_address_type, bluetooth::hci::LeScanningFilterPolicy scanning_filter_policy, uint8_t scanning_phys, std::vector scanning_phy_parameters) { @@ -1395,9 +1367,9 @@ ErrorCode LinkLayerController::LeSetExtendedScanParameters( } // HCI command LE_Set_Extended_Scan_Enable (Vol 4, Part E § 7.8.65). -ErrorCode LinkLayerController::LeSetExtendedScanEnable( - bool enable, bluetooth::hci::FilterDuplicates filter_duplicates, uint16_t duration, - uint16_t period) { +ErrorCode LeController::LeSetExtendedScanEnable(bool enable, + bluetooth::hci::FilterDuplicates filter_duplicates, + uint16_t duration, uint16_t period) { // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { @@ -1489,7 +1461,7 @@ ErrorCode LinkLayerController::LeSetExtendedScanEnable( // ============================================================================= // HCI LE Create Connection command (Vol 4, Part E § 7.8.12). -ErrorCode LinkLayerController::LeCreateConnection( +ErrorCode LeController::LeCreateConnection( uint16_t scan_interval, uint16_t scan_window, bluetooth::hci::InitiatorFilterPolicy initiator_filter_policy, AddressWithType peer_address, bluetooth::hci::OwnAddressType own_address_type, uint16_t connection_interval_min, @@ -1642,7 +1614,7 @@ ErrorCode LinkLayerController::LeCreateConnection( } // HCI LE Create Connection Cancel command (Vol 4, Part E § 7.8.12). -ErrorCode LinkLayerController::LeCreateConnectionCancel() { +ErrorCode LeController::LeCreateConnectionCancel() { // If no HCI_LE_Create_Connection or HCI_LE_Extended_Create_Connection // command is pending, then the Controller shall return the error code // Command Disallowed (0x0C). @@ -1679,7 +1651,7 @@ ErrorCode LinkLayerController::LeCreateConnectionCancel() { // ============================================================================= // HCI LE Extended Create Connection command (Vol 4, Part E § 7.8.66). -ErrorCode LinkLayerController::LeExtendedCreateConnection( +ErrorCode LeController::LeExtendedCreateConnection( bluetooth::hci::InitiatorFilterPolicy initiator_filter_policy, bluetooth::hci::OwnAddressType own_address_type, AddressWithType peer_address, uint8_t initiating_phys, @@ -1903,7 +1875,7 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( return ErrorCode::SUCCESS; } -void LinkLayerController::SetSecureSimplePairingSupport(bool enable) { +void LeController::SetSecureSimplePairingSupport(bool enable) { uint64_t bit = 0x1; secure_simple_pairing_host_support_ = enable; if (enable) { @@ -1913,7 +1885,7 @@ void LinkLayerController::SetSecureSimplePairingSupport(bool enable) { } } -void LinkLayerController::SetLeHostSupport(bool enable) { +void LeController::SetLeHostSupport(bool enable) { // TODO: Vol 2, Part C § 3.5 Feature requirements. // (65) LE Supported (Host) implies // (38) LE Supported (Controller) @@ -1926,7 +1898,7 @@ void LinkLayerController::SetLeHostSupport(bool enable) { } } -void LinkLayerController::SetSecureConnectionsSupport(bool enable) { +void LeController::SetSecureConnectionsSupport(bool enable) { // TODO: Vol 2, Part C § 3.5 Feature requirements. // (67) Secure Connections (Host Support) implies // (64) Secure Simple Pairing (Host Support) and @@ -1940,36 +1912,9 @@ void LinkLayerController::SetSecureConnectionsSupport(bool enable) { } } -void LinkLayerController::SetLocalName(std::array const& local_name) { - std::copy(local_name.begin(), local_name.end(), local_name_.begin()); -} - -void LinkLayerController::SetLocalName(std::vector const& local_name) { - ASSERT(local_name.size() <= local_name_.size()); - local_name_.fill(0); - std::copy(local_name.begin(), local_name.end(), local_name_.begin()); -} - -void LinkLayerController::SetExtendedInquiryResponse( - std::array const& extended_inquiry_response) { - extended_inquiry_response_ = extended_inquiry_response; -} - -void LinkLayerController::SetExtendedInquiryResponse( - std::vector const& extended_inquiry_response) { - ASSERT(extended_inquiry_response.size() <= extended_inquiry_response_.size()); - extended_inquiry_response_.fill(0); - std::copy(extended_inquiry_response.begin(), extended_inquiry_response.end(), - extended_inquiry_response_.begin()); -} - -LinkLayerController::LinkLayerController(const Address& address, - const ControllerProperties& properties, uint32_t id) - : id_(id), - address_(address), - properties_(properties), - lm_(nullptr, link_manager_destroy), - ll_(nullptr, link_layer_destroy) { +LeController::LeController(const Address& address, const ControllerProperties& properties, + uint32_t id) + : id_(id), address_(address), properties_(properties), ll_(nullptr, link_layer_destroy) { if (properties_.quirks.has_default_random_address) { WARNING(id_, "Configuring a default random address for this controller"); random_address_ = Address{0xba, 0xdb, 0xad, 0xba, 0xdb, 0xad}; @@ -1978,89 +1923,77 @@ LinkLayerController::LinkLayerController(const Address& address, controller_ops_ = { .user_pointer = this, .get_handle = - [](void* user, const uint8_t(*address)[6]) { - auto controller = static_cast(user); + [](void* user, const uint8_t (*address)[6]) { + auto controller = static_cast(user); - return controller->connections_.GetHandleOnlyAddress(Address(*address)); + // Returns the connection handle but only for established + // BR-EDR connections. + return controller->connections_.GetAclConnectionHandle(Address(*address)) + .value_or(-1); }, .get_address = - [](void* user, uint16_t handle, uint8_t(*result)[6]) { - auto controller = static_cast(user); + [](void* user, uint16_t handle, uint8_t (*result)[6]) { + auto controller = static_cast(user); + Address address = {}; + + if (controller->connections_.HasLeAclHandle(handle)) { + address = controller->connections_.GetLeAclConnection(handle) + .address.GetAddress(); + } - auto address_opt = controller->connections_.GetAddressSafe(handle); - Address address = address_opt.has_value() ? address_opt.value().GetAddress() - : Address::kEmpty; std::copy(address.data(), address.data() + 6, reinterpret_cast(result)); }, - .get_extended_features = - [](void* user, uint8_t features_page) { - auto controller = static_cast(user); - return controller->GetLmpFeatures(features_page); - }, - .get_le_features = [](void* user) { - auto controller = static_cast(user); + auto controller = static_cast(user); return controller->GetLeSupportedFeatures(); }, .get_le_event_mask = [](void* user) { - auto controller = static_cast(user); + auto controller = static_cast(user); return controller->le_event_mask_; }, .send_hci_event = [](void* user, const uint8_t* data, uintptr_t len) { - auto controller = static_cast(user); + auto controller = static_cast(user); auto event_code = static_cast(data[0]); controller->send_event_(bluetooth::hci::EventBuilder::Create( event_code, std::vector(data + 2, data + len))); }, - .send_lmp_packet = - [](void* user, const uint8_t(*to)[6], const uint8_t* data, uintptr_t len) { - auto controller = static_cast(user); - - Address source = controller->GetAddress(); - Address dest(*to); - - controller->SendLinkLayerPacket(model::packets::LmpBuilder::Create( - source, dest, std::vector(data, data + len))); - }, - .send_llcp_packet = [](void* user, uint16_t acl_connection_handle, const uint8_t* data, uintptr_t len) { - auto controller = static_cast(user); + auto controller = static_cast(user); - if (!controller->connections_.HasHandle(acl_connection_handle)) { + if (!controller->connections_.HasLeAclHandle(acl_connection_handle)) { ERROR("Dropping LLCP packet sent for unknown connection handle " "0x{:x}", acl_connection_handle); return; } - AclConnection const& connection = - controller->connections_.GetAclConnection(acl_connection_handle); - Address source = connection.GetOwnAddress().GetAddress(); - Address destination = connection.GetAddress().GetAddress(); + LeAclConnection const& connection = + controller->connections_.GetLeAclConnection(acl_connection_handle); + Address source = connection.own_address.GetAddress(); + Address destination = connection.address.GetAddress(); - controller->SendLinkLayerPacket(model::packets::LlcpBuilder::Create( + controller->SendLeLinkLayerPacket(model::packets::LlcpBuilder::Create( source, destination, std::vector(data, data + len))); }}; - lm_.reset(link_manager_create(controller_ops_)); ll_.reset(link_layer_create(controller_ops_)); } -LinkLayerController::~LinkLayerController() {} +LeController::~LeController() {} -void LinkLayerController::SendLeLinkLayerPacket( +void LeController::SendLeLinkLayerPacket( std::unique_ptr packet, int8_t tx_power) { std::shared_ptr shared_packet = std::move(packet); ScheduleTask(kNoDelayMs, [this, shared_packet, tx_power]() { @@ -2068,294 +2001,110 @@ void LinkLayerController::SendLeLinkLayerPacket( }); } -void LinkLayerController::SendLinkLayerPacket( - std::unique_ptr packet, int8_t tx_power) { - std::shared_ptr shared_packet = std::move(packet); - ScheduleTask(kNoDelayMs, [this, shared_packet, tx_power]() { - send_to_remote_(shared_packet, Phy::Type::BR_EDR, tx_power); - }); -} - -ErrorCode LinkLayerController::SendLeCommandToRemoteByAddress(OpCode opcode, - const Address& own_address, - const Address& peer_address) { - switch (opcode) { - case (OpCode::LE_READ_REMOTE_FEATURES_PAGE_0): - SendLeLinkLayerPacket( - model::packets::LeReadRemoteFeaturesBuilder::Create(own_address, peer_address)); - break; - default: - INFO(id_, "Dropping unhandled command 0x{:04x}", static_cast(opcode)); - return ErrorCode::UNKNOWN_HCI_COMMAND; - } - - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::SendCommandToRemoteByAddress(OpCode opcode, pdl::packet::slice args, - const Address& own_address, - const Address& peer_address) { - switch (opcode) { - case (OpCode::REMOTE_NAME_REQUEST): - // LMP features get requested with remote name requests. - SendLinkLayerPacket( - model::packets::ReadRemoteLmpFeaturesBuilder::Create(own_address, peer_address)); - SendLinkLayerPacket( - model::packets::RemoteNameRequestBuilder::Create(own_address, peer_address)); - break; - case (OpCode::READ_REMOTE_SUPPORTED_FEATURES): - SendLinkLayerPacket(model::packets::ReadRemoteSupportedFeaturesBuilder::Create(own_address, - peer_address)); - break; - case (OpCode::READ_REMOTE_EXTENDED_FEATURES): { - pdl::packet::slice page_number_slice = args.subrange(5, 1); - uint8_t page_number = page_number_slice.read_le(); - SendLinkLayerPacket(model::packets::ReadRemoteExtendedFeaturesBuilder::Create( - own_address, peer_address, page_number)); - } break; - case (OpCode::READ_REMOTE_VERSION_INFORMATION): - SendLinkLayerPacket(model::packets::ReadRemoteVersionInformationBuilder::Create( - own_address, peer_address)); - break; - case (OpCode::READ_CLOCK_OFFSET): - SendLinkLayerPacket( - model::packets::ReadClockOffsetBuilder::Create(own_address, peer_address)); - break; - default: - INFO(id_, "Dropping unhandled command 0x{:04x}", static_cast(opcode)); - return ErrorCode::UNKNOWN_HCI_COMMAND; - } - - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::SendCommandToRemoteByHandle(OpCode opcode, pdl::packet::slice args, - uint16_t handle) { - if (!connections_.HasHandle(handle)) { +ErrorCode LeController::LeReadRemoteFeaturesPage0(uint16_t connection_handle) { + if (!connections_.HasLeAclHandle(connection_handle)) { return ErrorCode::UNKNOWN_CONNECTION; } - switch (opcode) { - case (OpCode::LE_READ_REMOTE_FEATURES_PAGE_0): - return SendLeCommandToRemoteByAddress(opcode, connections_.GetOwnAddress(handle).GetAddress(), - connections_.GetAddress(handle).GetAddress()); - default: - return SendCommandToRemoteByAddress(opcode, args, - connections_.GetOwnAddress(handle).GetAddress(), - connections_.GetAddress(handle).GetAddress()); - } -} - -ErrorCode LinkLayerController::SendScoToRemote(bluetooth::hci::ScoView sco_packet) { - uint16_t handle = sco_packet.GetHandle(); - if (!connections_.HasScoHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - // TODO: SCO flow control - Address source = GetAddress(); - Address destination = connections_.GetScoAddress(handle); - - auto sco_data = sco_packet.GetData(); - std::vector sco_data_bytes(sco_data.begin(), sco_data.end()); + auto const& connection = connections_.GetLeAclConnection(connection_handle); + SendLeLinkLayerPacket(model::packets::LeReadRemoteFeaturesBuilder::Create( + connection.own_address.GetAddress(), connection.address.GetAddress())); - SendLinkLayerPacket( - model::packets::ScoBuilder::Create(source, destination, std::move(sco_data_bytes))); return ErrorCode::SUCCESS; } -void LinkLayerController::IncomingPacket(model::packets::LinkLayerPacketView incoming, - int8_t rssi) { +void LeController::IncomingPacket(model::packets::LinkLayerPacketView incoming, int8_t rssi) { ASSERT(incoming.IsValid()); auto destination_address = incoming.GetDestinationAddress(); + auto source_address = incoming.GetSourceAddress(); - // Match broadcasts - bool address_matches = (destination_address == Address::kEmpty); - - // Address match is performed in specific handlers for these PDU types. + // Handle connection-less packet types. + // Whether the packet needs to be handled by this controller instance is decided + // by the current controller state. switch (incoming.GetType()) { case model::packets::PacketType::LE_SCAN: + return IncomingLeScanPacket(incoming); case model::packets::PacketType::LE_SCAN_RESPONSE: + return IncomingLeScanResponsePacket(incoming, rssi); case model::packets::PacketType::LE_LEGACY_ADVERTISING_PDU: + return IncomingLeLegacyAdvertisingPdu(incoming, rssi); case model::packets::PacketType::LE_EXTENDED_ADVERTISING_PDU: + return IncomingLeExtendedAdvertisingPdu(incoming, rssi); + case model::packets::PacketType::LE_PERIODIC_ADVERTISING_PDU: + return IncomingLePeriodicAdvertisingPdu(incoming, rssi); case model::packets::PacketType::LE_CONNECT: - address_matches = true; - break; + return IncomingLeConnectPacket(incoming); + case model::packets::PacketType::LE_CONNECT_COMPLETE: + return IncomingLeConnectCompletePacket(incoming); default: break; } - // Check public address - if (destination_address == address_ || destination_address == random_address_) { - address_matches = true; - } - - // Check current connection address - if (destination_address == initiator_.initiating_address) { - address_matches = true; - } - - // Check connection addresses - auto source_address = incoming.GetSourceAddress(); - auto handle = connections_.GetHandleOnlyAddress(source_address); - if (handle != kReservedHandle) { - if (connections_.GetOwnAddress(handle).GetAddress() == destination_address) { - address_matches = true; - - // Update link timeout for valid ACL connections - connections_.ResetLinkTimer(handle); - } - } - - // Drop packets not addressed to me - if (!address_matches) { - INFO(id_, "{} | Dropping packet not addressed to me {}->{} (type 0x{:x})", address_, - source_address, destination_address, static_cast(incoming.GetType())); + // Verify the existence of an LE-ACL connection with the proper source and + // destination addresses. + auto connection_handle = + connections_.GetLeAclConnectionHandle(destination_address, source_address); + if (!connection_handle.has_value()) { + DEBUG(id_, "[LL] {} | Dropping {} packet not addressed to me {}->{}", address_, + PacketTypeText(incoming.GetType()), source_address, destination_address); return; } + // Update link timeout for valid ACL connections + auto& connection = connections_.GetLeAclConnection(*connection_handle); + connection.ResetLinkTimer(); + switch (incoming.GetType()) { case model::packets::PacketType::ACL: - IncomingAclPacket(incoming, rssi); - break; - case model::packets::PacketType::SCO: - IncomingScoPacket(incoming); + IncomingLeAclPacket(connection, incoming, rssi); break; case model::packets::PacketType::LE_CONNECTED_ISOCHRONOUS_PDU: IncomingLeConnectedIsochronousPdu(incoming); break; case model::packets::PacketType::DISCONNECT: - IncomingDisconnectPacket(incoming); - break; - case model::packets::PacketType::LMP: - IncomingLmpPacket(incoming); + IncomingLeDisconnectPacket(connection, incoming); break; case model::packets::PacketType::LLCP: IncomingLlcpPacket(incoming); break; - case model::packets::PacketType::INQUIRY: - if (inquiry_scan_enable_) { - IncomingInquiryPacket(incoming, rssi); - } - break; - case model::packets::PacketType::INQUIRY_RESPONSE: - IncomingInquiryResponsePacket(incoming); - break; - case model::packets::PacketType::LE_LEGACY_ADVERTISING_PDU: - IncomingLeLegacyAdvertisingPdu(incoming, rssi); - return; - case model::packets::PacketType::LE_EXTENDED_ADVERTISING_PDU: - IncomingLeExtendedAdvertisingPdu(incoming, rssi); - return; - case model::packets::PacketType::LE_PERIODIC_ADVERTISING_PDU: - IncomingLePeriodicAdvertisingPdu(incoming, rssi); - return; - case model::packets::PacketType::LE_CONNECT: - IncomingLeConnectPacket(incoming); - break; - case model::packets::PacketType::LE_CONNECT_COMPLETE: - IncomingLeConnectCompletePacket(incoming); - break; case model::packets::PacketType::LE_CONNECTION_PARAMETER_REQUEST: - IncomingLeConnectionParameterRequest(incoming); + IncomingLeConnectionParameterRequest(connection, incoming); break; case model::packets::PacketType::LE_CONNECTION_PARAMETER_UPDATE: - IncomingLeConnectionParameterUpdate(incoming); + IncomingLeConnectionParameterUpdate(connection, incoming); break; case model::packets::PacketType::LE_ENCRYPT_CONNECTION: - IncomingLeEncryptConnection(incoming); + IncomingLeEncryptConnection(connection, incoming); break; case model::packets::PacketType::LE_ENCRYPT_CONNECTION_RESPONSE: - IncomingLeEncryptConnectionResponse(incoming); + IncomingLeEncryptConnectionResponse(connection, incoming); break; case (model::packets::PacketType::LE_READ_REMOTE_FEATURES): - IncomingLeReadRemoteFeatures(incoming); + IncomingLeReadRemoteFeatures(connection, incoming); break; case (model::packets::PacketType::LE_READ_REMOTE_FEATURES_RESPONSE): - IncomingLeReadRemoteFeaturesResponse(incoming); - break; - case model::packets::PacketType::LE_SCAN: - IncomingLeScanPacket(incoming); - break; - case model::packets::PacketType::LE_SCAN_RESPONSE: - IncomingLeScanResponsePacket(incoming, rssi); - break; - case model::packets::PacketType::PAGE: - if (page_scan_enable_) { - IncomingPagePacket(incoming); - } - break; - case model::packets::PacketType::PAGE_RESPONSE: - IncomingPageResponsePacket(incoming); - break; - case model::packets::PacketType::PAGE_REJECT: - IncomingPageRejectPacket(incoming); - break; - case (model::packets::PacketType::REMOTE_NAME_REQUEST): - IncomingRemoteNameRequest(incoming); - break; - case (model::packets::PacketType::REMOTE_NAME_REQUEST_RESPONSE): - IncomingRemoteNameRequestResponse(incoming); + IncomingLeReadRemoteFeaturesResponse(connection, incoming); break; - case (model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES): - IncomingReadRemoteSupportedFeatures(incoming); - break; - case (model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES_RESPONSE): - IncomingReadRemoteSupportedFeaturesResponse(incoming); - break; - case (model::packets::PacketType::READ_REMOTE_LMP_FEATURES): - IncomingReadRemoteLmpFeatures(incoming); - break; - case (model::packets::PacketType::READ_REMOTE_LMP_FEATURES_RESPONSE): - IncomingReadRemoteLmpFeaturesResponse(incoming); - break; - case (model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES): - IncomingReadRemoteExtendedFeatures(incoming); - break; - case (model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES_RESPONSE): - IncomingReadRemoteExtendedFeaturesResponse(incoming); - break; - case (model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION): + case model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION: IncomingReadRemoteVersion(incoming); break; - case (model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION_RESPONSE): + case model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION_RESPONSE: IncomingReadRemoteVersionResponse(incoming); break; - case (model::packets::PacketType::READ_CLOCK_OFFSET): - IncomingReadClockOffset(incoming); - break; - case (model::packets::PacketType::READ_CLOCK_OFFSET_RESPONSE): - IncomingReadClockOffsetResponse(incoming); - break; - case model::packets::PacketType::SCO_CONNECTION_REQUEST: - IncomingScoConnectionRequest(incoming); - break; - case model::packets::PacketType::SCO_CONNECTION_RESPONSE: - IncomingScoConnectionResponse(incoming); - break; - case model::packets::PacketType::SCO_DISCONNECT: - IncomingScoDisconnect(incoming); - break; case model::packets::PacketType::PING_REQUEST: IncomingPingRequest(incoming); break; case model::packets::PacketType::PING_RESPONSE: // ping responses require no action break; - case model::packets::PacketType::ROLE_SWITCH_REQUEST: - IncomingRoleSwitchRequest(incoming); - break; - case model::packets::PacketType::ROLE_SWITCH_RESPONSE: - IncomingRoleSwitchResponse(incoming); - break; case model::packets::PacketType::LL_PHY_REQ: - IncomingLlPhyReq(incoming); + IncomingLlPhyReq(connection, incoming); break; case model::packets::PacketType::LL_PHY_RSP: - IncomingLlPhyRsp(incoming); + IncomingLlPhyRsp(connection, incoming); break; case model::packets::PacketType::LL_PHY_UPDATE_IND: - IncomingLlPhyUpdateInd(incoming); + IncomingLlPhyUpdateInd(connection, incoming); break; default: WARNING(id_, "Dropping unhandled packet of type {}", @@ -2363,8 +2112,8 @@ void LinkLayerController::IncomingPacket(model::packets::LinkLayerPacketView inc } } -void LinkLayerController::IncomingAclPacket(model::packets::LinkLayerPacketView incoming, - int8_t rssi) { +void LeController::IncomingLeAclPacket(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming, int8_t rssi) { auto acl = model::packets::AclView::Create(incoming); ASSERT(acl.IsValid()); @@ -2377,308 +2126,64 @@ void LinkLayerController::IncomingAclPacket(model::packets::LinkLayerPacketView packet_boundary_flag = bluetooth::hci::PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; } - INFO(id_, "Acl Packet [{}] {} -> {}", acl_data.size(), incoming.GetSourceAddress(), + INFO(id_, "LE-ACL Packet [{}] {} -> {}", acl_data.size(), incoming.GetSourceAddress(), incoming.GetDestinationAddress()); - uint16_t connection_handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); - if (connection_handle == kReservedHandle) { - INFO(id_, "Dropping packet since connection does not exist"); - return; - } - // Update the RSSI for the local ACL connection. - connections_.SetRssi(connection_handle, rssi); + connection.SetRssi(rssi); send_acl_(bluetooth::hci::AclBuilder::Create( - connection_handle, packet_boundary_flag, broadcast_flag, + connection.handle, packet_boundary_flag, broadcast_flag, std::vector(acl_data.begin(), acl_data.end()))); } -void LinkLayerController::IncomingScoPacket(model::packets::LinkLayerPacketView incoming) { - Address source = incoming.GetSourceAddress(); - uint16_t sco_handle = connections_.GetScoHandle(source); - if (!connections_.HasScoHandle(sco_handle)) { - INFO(id_, "Spurious SCO packet from {}", source); - return; - } - - auto sco = model::packets::ScoView::Create(incoming); - ASSERT(sco.IsValid()); - auto sco_data = sco.GetPayload(); - std::vector sco_data_bytes(sco_data.begin(), sco_data.end()); - - INFO(id_, "Sco Packet [{}] {} -> {}", static_cast(sco_data_bytes.size()), - incoming.GetSourceAddress(), incoming.GetDestinationAddress()); - - send_sco_(bluetooth::hci::ScoBuilder::Create( - sco_handle, bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED, sco_data_bytes)); -} - -void LinkLayerController::IncomingRemoteNameRequest(model::packets::LinkLayerPacketView incoming) { - auto view = model::packets::RemoteNameRequestView::Create(incoming); - ASSERT(view.IsValid()); - - SendLinkLayerPacket(model::packets::RemoteNameRequestResponseBuilder::Create( - incoming.GetDestinationAddress(), incoming.GetSourceAddress(), local_name_)); -} - -void LinkLayerController::IncomingRemoteNameRequestResponse( - model::packets::LinkLayerPacketView incoming) { - auto view = model::packets::RemoteNameRequestResponseView::Create(incoming); - ASSERT(view.IsValid()); - - if (IsEventUnmasked(EventCode::REMOTE_NAME_REQUEST_COMPLETE)) { - send_event_(bluetooth::hci::RemoteNameRequestCompleteBuilder::Create( - ErrorCode::SUCCESS, incoming.GetSourceAddress(), view.GetName())); - } -} - -void LinkLayerController::IncomingReadRemoteLmpFeatures( - model::packets::LinkLayerPacketView incoming) { - SendLinkLayerPacket(model::packets::ReadRemoteLmpFeaturesResponseBuilder::Create( - incoming.GetDestinationAddress(), incoming.GetSourceAddress(), host_supported_features_)); -} - -void LinkLayerController::IncomingReadRemoteLmpFeaturesResponse( - model::packets::LinkLayerPacketView incoming) { - auto view = model::packets::ReadRemoteLmpFeaturesResponseView::Create(incoming); - ASSERT(view.IsValid()); - if (IsEventUnmasked(EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION)) { - send_event_(bluetooth::hci::RemoteHostSupportedFeaturesNotificationBuilder::Create( - incoming.GetSourceAddress(), view.GetFeatures())); - } -} - -void LinkLayerController::IncomingReadRemoteSupportedFeatures( - model::packets::LinkLayerPacketView incoming) { - SendLinkLayerPacket(model::packets::ReadRemoteSupportedFeaturesResponseBuilder::Create( - incoming.GetDestinationAddress(), incoming.GetSourceAddress(), - properties_.lmp_features[0])); -} - -void LinkLayerController::IncomingReadRemoteSupportedFeaturesResponse( - model::packets::LinkLayerPacketView incoming) { - auto view = model::packets::ReadRemoteSupportedFeaturesResponseView::Create(incoming); - ASSERT(view.IsValid()); - Address source = incoming.GetSourceAddress(); - uint16_t handle = connections_.GetHandleOnlyAddress(source); - if (handle == kReservedHandle) { - INFO(id_, "Discarding response from a disconnected device {}", source); - return; - } - if (IsEventUnmasked(EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE)) { - send_event_(bluetooth::hci::ReadRemoteSupportedFeaturesCompleteBuilder::Create( - ErrorCode::SUCCESS, handle, view.GetFeatures())); - } -} - -void LinkLayerController::IncomingReadRemoteExtendedFeatures( - model::packets::LinkLayerPacketView incoming) { - auto view = model::packets::ReadRemoteExtendedFeaturesView::Create(incoming); - ASSERT(view.IsValid()); - uint8_t page_number = view.GetPageNumber(); - uint8_t error_code = static_cast(ErrorCode::SUCCESS); - if (page_number >= properties_.lmp_features.size()) { - error_code = static_cast(ErrorCode::INVALID_LMP_OR_LL_PARAMETERS); - } - SendLinkLayerPacket(model::packets::ReadRemoteExtendedFeaturesResponseBuilder::Create( - incoming.GetDestinationAddress(), incoming.GetSourceAddress(), error_code, page_number, - GetMaxLmpFeaturesPageNumber(), GetLmpFeatures(page_number))); -} - -void LinkLayerController::IncomingReadRemoteExtendedFeaturesResponse( - model::packets::LinkLayerPacketView incoming) { - auto view = model::packets::ReadRemoteExtendedFeaturesResponseView::Create(incoming); - ASSERT(view.IsValid()); - Address source = incoming.GetSourceAddress(); - uint16_t handle = connections_.GetHandleOnlyAddress(source); - if (handle == kReservedHandle) { - INFO(id_, "Discarding response from a disconnected device {}", source); - return; - } - if (IsEventUnmasked(EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE)) { - send_event_(bluetooth::hci::ReadRemoteExtendedFeaturesCompleteBuilder::Create( - static_cast(view.GetStatus()), handle, view.GetPageNumber(), - view.GetMaxPageNumber(), view.GetFeatures())); - } -} - -void LinkLayerController::IncomingReadRemoteVersion(model::packets::LinkLayerPacketView incoming) { - SendLinkLayerPacket(model::packets::ReadRemoteVersionInformationResponseBuilder::Create( +void LeController::IncomingReadRemoteVersion(model::packets::LinkLayerPacketView incoming) { + SendLeLinkLayerPacket(model::packets::ReadRemoteVersionInformationResponseBuilder::Create( incoming.GetDestinationAddress(), incoming.GetSourceAddress(), static_cast(properties_.lmp_version), static_cast(properties_.lmp_subversion), properties_.company_identifier)); } -void LinkLayerController::IncomingReadRemoteVersionResponse( - model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingReadRemoteVersionResponse(model::packets::LinkLayerPacketView incoming) { auto view = model::packets::ReadRemoteVersionInformationResponseView::Create(incoming); ASSERT(view.IsValid()); Address source = incoming.GetSourceAddress(); - uint16_t handle = connections_.GetHandleOnlyAddress(source); - if (handle == kReservedHandle) { + Address destination = incoming.GetDestinationAddress(); + + auto handle = connections_.GetLeAclConnectionHandle(destination, source); + + if (!handle.has_value()) { INFO(id_, "Discarding response from a disconnected device {}", source); return; } + if (IsEventUnmasked(EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE)) { send_event_(bluetooth::hci::ReadRemoteVersionInformationCompleteBuilder::Create( - ErrorCode::SUCCESS, handle, view.GetLmpVersion(), view.GetManufacturerName(), + ErrorCode::SUCCESS, *handle, view.GetLmpVersion(), view.GetManufacturerName(), view.GetLmpSubversion())); } } -void LinkLayerController::IncomingReadClockOffset(model::packets::LinkLayerPacketView incoming) { - SendLinkLayerPacket(model::packets::ReadClockOffsetResponseBuilder::Create( - incoming.GetDestinationAddress(), incoming.GetSourceAddress(), GetClockOffset())); -} - -void LinkLayerController::IncomingReadClockOffsetResponse( - model::packets::LinkLayerPacketView incoming) { - auto view = model::packets::ReadClockOffsetResponseView::Create(incoming); - ASSERT(view.IsValid()); - Address source = incoming.GetSourceAddress(); - uint16_t handle = connections_.GetHandleOnlyAddress(source); - if (handle == kReservedHandle) { - INFO(id_, "Discarding response from a disconnected device {}", source); - return; - } - if (IsEventUnmasked(EventCode::READ_CLOCK_OFFSET_COMPLETE)) { - send_event_(bluetooth::hci::ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, handle, - view.GetOffset())); - } -} - -void LinkLayerController::IncomingDisconnectPacket(model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLeDisconnectPacket(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming) { INFO(id_, "Disconnect Packet"); auto disconnect = model::packets::DisconnectView::Create(incoming); ASSERT(disconnect.IsValid()); - Address peer = incoming.GetSourceAddress(); - uint16_t handle = connections_.GetHandleOnlyAddress(peer); - if (handle == kReservedHandle) { - INFO(id_, "Discarding disconnect from a disconnected device {}", peer); - return; - } - auto is_br_edr = connections_.GetPhyType(handle) == Phy::Type::BR_EDR; - ASSERT_LOG( - connections_.Disconnect(handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }), - "GetHandle() returned invalid handle 0x{:x}", handle); + // /!\ The connection reference becomes invalid after it is removed from the + // connection handler. + uint16_t connection_handle = connection.handle; + ASSERT_LOG(connections_.Disconnect(connection_handle, + [this](TaskId task_id) { CancelScheduledTask(task_id); }), + "GetHandle() returned invalid handle 0x{:x}", connection_handle); uint8_t reason = disconnect.GetReason(); - if (is_br_edr) { - ASSERT(link_manager_remove_link(lm_.get(), reinterpret_cast(peer.data()))); - } else { - // Will optionally notify CIS disconnections. - ASSERT(link_layer_remove_link(ll_.get(), handle, reason)); - } - - SendDisconnectionCompleteEvent(handle, ErrorCode(reason)); -} - -void LinkLayerController::IncomingInquiryPacket(model::packets::LinkLayerPacketView incoming, - uint8_t rssi) { - auto inquiry = model::packets::InquiryView::Create(incoming); - ASSERT(inquiry.IsValid()); - - Address peer = incoming.GetSourceAddress(); - uint8_t lap = inquiry.GetLap(); - - // Filter out inquiry packets with IAC not present in the - // list Current_IAC_LAP. - if (std::none_of(current_iac_lap_list_.cbegin(), current_iac_lap_list_.cend(), - [lap](auto iac_lap) { return iac_lap.lap_ == lap; })) { - return; - } - - switch (inquiry.GetInquiryType()) { - case (model::packets::InquiryType::STANDARD): { - SendLinkLayerPacket(model::packets::InquiryResponseBuilder::Create( - GetAddress(), peer, static_cast(GetPageScanRepetitionMode()), - class_of_device_, GetClockOffset())); - } break; - case (model::packets::InquiryType::RSSI): { - SendLinkLayerPacket(model::packets::InquiryResponseWithRssiBuilder::Create( - GetAddress(), peer, static_cast(GetPageScanRepetitionMode()), - class_of_device_, GetClockOffset(), rssi)); - } break; - case (model::packets::InquiryType::EXTENDED): { - SendLinkLayerPacket(model::packets::ExtendedInquiryResponseBuilder::Create( - GetAddress(), peer, static_cast(GetPageScanRepetitionMode()), - class_of_device_, GetClockOffset(), rssi, extended_inquiry_response_)); - } break; - default: - WARNING(id_, "Unhandled Incoming Inquiry of type {}", static_cast(inquiry.GetType())); - return; - } - // TODO: Send an Inquiry Response Notification Event 7.7.74 -} - -void LinkLayerController::IncomingInquiryResponsePacket( - model::packets::LinkLayerPacketView incoming) { - auto basic_inquiry_response = model::packets::BasicInquiryResponseView::Create(incoming); - ASSERT(basic_inquiry_response.IsValid()); - std::vector eir; - - switch (basic_inquiry_response.GetInquiryType()) { - case (model::packets::InquiryType::STANDARD): { - // TODO: Support multiple inquiries in the same packet. - auto inquiry_response = model::packets::InquiryResponseView::Create(basic_inquiry_response); - ASSERT(inquiry_response.IsValid()); - - auto page_scan_repetition_mode = - (bluetooth::hci::PageScanRepetitionMode)inquiry_response.GetPageScanRepetitionMode(); - - std::vector responses; - responses.emplace_back(); - responses.back().bd_addr_ = inquiry_response.GetSourceAddress(); - responses.back().page_scan_repetition_mode_ = page_scan_repetition_mode; - responses.back().class_of_device_ = inquiry_response.GetClassOfDevice(); - responses.back().clock_offset_ = inquiry_response.GetClockOffset(); - if (IsEventUnmasked(EventCode::INQUIRY_RESULT)) { - send_event_(bluetooth::hci::InquiryResultBuilder::Create(responses)); - } - } break; - - case (model::packets::InquiryType::RSSI): { - auto inquiry_response = - model::packets::InquiryResponseWithRssiView::Create(basic_inquiry_response); - ASSERT(inquiry_response.IsValid()); - - auto page_scan_repetition_mode = - (bluetooth::hci::PageScanRepetitionMode)inquiry_response.GetPageScanRepetitionMode(); - - std::vector responses; - responses.emplace_back(); - responses.back().address_ = inquiry_response.GetSourceAddress(); - responses.back().page_scan_repetition_mode_ = page_scan_repetition_mode; - responses.back().class_of_device_ = inquiry_response.GetClassOfDevice(); - responses.back().clock_offset_ = inquiry_response.GetClockOffset(); - responses.back().rssi_ = inquiry_response.GetRssi(); - if (IsEventUnmasked(EventCode::INQUIRY_RESULT_WITH_RSSI)) { - send_event_(bluetooth::hci::InquiryResultWithRssiBuilder::Create(responses)); - } - } break; - - case (model::packets::InquiryType::EXTENDED): { - auto inquiry_response = - model::packets::ExtendedInquiryResponseView::Create(basic_inquiry_response); - ASSERT(inquiry_response.IsValid()); - - send_event_(bluetooth::hci::ExtendedInquiryResultBuilder::Create( - inquiry_response.GetSourceAddress(), - static_cast( - inquiry_response.GetPageScanRepetitionMode()), - inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), - inquiry_response.GetRssi(), inquiry_response.GetExtendedInquiryResponse())); - } break; - - default: - WARNING(id_, "Unhandled Incoming Inquiry Response of type {}", - static_cast(basic_inquiry_response.GetInquiryType())); - } + // Will optionally notify CIS disconnections. + ASSERT(link_layer_remove_link(ll_.get(), connection_handle, reason)); + SendDisconnectionCompleteEvent(connection_handle, ErrorCode(reason)); } -Address LinkLayerController::generate_rpa(std::array irk) { +Address LeController::generate_rpa(std::array irk) { // most significant bit, bit7, bit6 is 01 to be resolvable random // Bits of the random part of prand shall not be all 1 or all 0 std::array prand; @@ -2710,12 +2215,12 @@ Address LinkLayerController::generate_rpa(std::array irk) { +bool LeController::irk_is_zero(std::array irk) { return std::all_of(irk.begin(), irk.end(), [](uint8_t b) { return b == 0; }); } // Handle legacy advertising PDUs while in the Scanning state. -void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( +void LeController::ScanIncomingLeLegacyAdvertisingPdu( model::packets::LeLegacyAdvertisingPduView& pdu, uint8_t rssi) { if (!scanner_.IsEnabled()) { return; @@ -2997,7 +2502,7 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( } } -void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( +void LeController::ConnectIncomingLeLegacyAdvertisingPdu( model::packets::LeLegacyAdvertisingPduView& pdu) { if (!initiator_.IsEnabled()) { return; @@ -3121,14 +2626,6 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( break; } - if (!connections_.CreatePendingLeConnection(advertising_address, - resolved_advertising_address != advertising_address - ? resolved_advertising_address - : AddressWithType{}, - initiating_address)) { - WARNING(id_, "CreatePendingLeConnection failed for connection to {}", advertising_address); - } - initiator_.pending_connect_request = advertising_address; initiator_.initiating_address = initiating_address.GetAddress(); @@ -3149,8 +2646,8 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( initiator_.le_1m_phy.supervision_timeout)); } -void LinkLayerController::IncomingLeLegacyAdvertisingPdu( - model::packets::LinkLayerPacketView incoming, uint8_t rssi) { +void LeController::IncomingLeLegacyAdvertisingPdu(model::packets::LinkLayerPacketView incoming, + uint8_t rssi) { auto pdu = model::packets::LeLegacyAdvertisingPduView::Create(incoming); ASSERT(pdu.IsValid()); @@ -3159,7 +2656,7 @@ void LinkLayerController::IncomingLeLegacyAdvertisingPdu( } // Handle legacy advertising PDUs while in the Scanning state. -void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( +void LeController::ScanIncomingLeExtendedAdvertisingPdu( model::packets::LeExtendedAdvertisingPduView& pdu, uint8_t rssi) { if (!scanner_.IsEnabled()) { return; @@ -3421,7 +2918,7 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( } } -void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( +void LeController::ConnectIncomingLeExtendedAdvertisingPdu( model::packets::LeExtendedAdvertisingPduView& pdu) { if (!initiator_.IsEnabled()) { return; @@ -3542,14 +3039,6 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( break; } - if (!connections_.CreatePendingLeConnection(advertising_address, - resolved_advertising_address != advertising_address - ? resolved_advertising_address - : AddressWithType{}, - initiating_address)) { - WARNING(id_, "CreatePendingLeConnection failed for connection to {}", advertising_address); - } - initiator_.pending_connect_request = advertising_address; initiator_.initiating_address = initiating_address.GetAddress(); @@ -3570,8 +3059,8 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( initiator_.le_1m_phy.supervision_timeout)); } -void LinkLayerController::IncomingLeExtendedAdvertisingPdu( - model::packets::LinkLayerPacketView incoming, uint8_t rssi) { +void LeController::IncomingLeExtendedAdvertisingPdu(model::packets::LinkLayerPacketView incoming, + uint8_t rssi) { auto pdu = model::packets::LeExtendedAdvertisingPduView::Create(incoming); ASSERT(pdu.IsValid()); @@ -3579,8 +3068,8 @@ void LinkLayerController::IncomingLeExtendedAdvertisingPdu( ConnectIncomingLeExtendedAdvertisingPdu(pdu); } -void LinkLayerController::IncomingLePeriodicAdvertisingPdu( - model::packets::LinkLayerPacketView incoming, uint8_t rssi) { +void LeController::IncomingLePeriodicAdvertisingPdu(model::packets::LinkLayerPacketView incoming, + uint8_t rssi) { auto pdu = model::packets::LePeriodicAdvertisingPduView::Create(incoming); ASSERT(pdu.IsValid()); @@ -3720,150 +3209,24 @@ void LinkLayerController::IncomingLePeriodicAdvertisingPdu( } } -void LinkLayerController::IncomingScoConnectionRequest( - model::packets::LinkLayerPacketView incoming) { - Address address = incoming.GetSourceAddress(); - auto request = model::packets::ScoConnectionRequestView::Create(incoming); - ASSERT(request.IsValid()); - - INFO(id_, "Received eSCO connection request from {}", address); - - // Automatically reject if connection request was already sent - // from the current device. - if (connections_.HasPendingScoConnection(address)) { - INFO(id_, - "Rejecting eSCO connection request from {}, " - "an eSCO connection already exist with this device", - address); - - SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( - GetAddress(), address, (uint8_t)ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED, 0, 0, - 0, 0, 0, 0)); - return; - } - - // Create local connection context. - ScoConnectionParameters connection_parameters = { - request.GetTransmitBandwidth(), request.GetReceiveBandwidth(), - request.GetMaxLatency(), request.GetVoiceSetting(), - request.GetRetransmissionEffort(), request.GetPacketType()}; - - bool extended = connection_parameters.IsExtended(); - connections_.CreateScoConnection(address, connection_parameters, - extended ? ScoState::SCO_STATE_SENT_ESCO_CONNECTION_REQUEST - : ScoState::SCO_STATE_SENT_SCO_CONNECTION_REQUEST, - ScoDatapath::NORMAL); - - // Send connection request event and wait for Accept or Reject command. - send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( - address, request.GetClassOfDevice(), - extended ? bluetooth::hci::ConnectionRequestLinkType::ESCO - : bluetooth::hci::ConnectionRequestLinkType::SCO)); -} - -void LinkLayerController::IncomingScoConnectionResponse( - model::packets::LinkLayerPacketView incoming) { - Address address = incoming.GetSourceAddress(); - auto response = model::packets::ScoConnectionResponseView::Create(incoming); - ASSERT(response.IsValid()); - auto status = ErrorCode(response.GetStatus()); - bool is_legacy = connections_.IsLegacyScoConnection(address); - - INFO(id_, "Received eSCO connection response with status 0x{:02x} from {}", - static_cast(status), incoming.GetSourceAddress()); - - if (status == ErrorCode::SUCCESS) { - bool extended = response.GetExtended(); - ScoLinkParameters link_parameters = { - response.GetTransmissionInterval(), - response.GetRetransmissionWindow(), - response.GetRxPacketLength(), - response.GetTxPacketLength(), - response.GetAirMode(), - extended, - }; - - connections_.AcceptPendingScoConnection(address, link_parameters, [this, address] { - return LinkLayerController::StartScoStream(address); - }); - - if (is_legacy) { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode::SUCCESS, connections_.GetScoHandle(address), address, - bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED)); - } else { - send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( - ErrorCode::SUCCESS, connections_.GetScoHandle(address), address, - extended ? bluetooth::hci::ScoLinkType::ESCO : bluetooth::hci::ScoLinkType::SCO, - extended ? response.GetTransmissionInterval() : 0, - extended ? response.GetRetransmissionWindow() : 0, - extended ? response.GetRxPacketLength() : 0, - extended ? response.GetTxPacketLength() : 0, - bluetooth::hci::ScoAirMode(response.GetAirMode()))); - } - } else { - connections_.CancelPendingScoConnection(address); - if (is_legacy) { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - status, 0, address, bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED)); - } else { - ScoConnectionParameters connection_parameters = - connections_.GetScoConnectionParameters(address); - send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( - status, 0, address, - connection_parameters.IsExtended() ? bluetooth::hci::ScoLinkType::ESCO - : bluetooth::hci::ScoLinkType::SCO, - 0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT)); - } - } -} - -void LinkLayerController::IncomingScoDisconnect(model::packets::LinkLayerPacketView incoming) { - Address address = incoming.GetSourceAddress(); - auto request = model::packets::ScoDisconnectView::Create(incoming); - ASSERT(request.IsValid()); - auto reason = request.GetReason(); - uint16_t handle = connections_.GetScoHandle(address); - - INFO(id_, - "Received eSCO disconnection request with" - " reason 0x{:02x} from {}", - static_cast(reason), incoming.GetSourceAddress()); - - if (handle != kReservedHandle) { - connections_.Disconnect(handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }); - SendDisconnectionCompleteEvent(handle, ErrorCode(reason)); - } -} - -void LinkLayerController::IncomingLmpPacket(model::packets::LinkLayerPacketView incoming) { - Address address = incoming.GetSourceAddress(); - auto request = model::packets::LmpView::Create(incoming); - ASSERT(request.IsValid()); - auto payload = request.GetPayload(); - auto packet = std::vector(payload.begin(), payload.end()); - - ASSERT(link_manager_ingest_lmp(lm_.get(), reinterpret_cast(address.data()), - packet.data(), packet.size())); -} - -void LinkLayerController::IncomingLlcpPacket(model::packets::LinkLayerPacketView incoming) { - Address address = incoming.GetSourceAddress(); +void LeController::IncomingLlcpPacket(model::packets::LinkLayerPacketView incoming) { + Address source = incoming.GetSourceAddress(); + Address destination = incoming.GetDestinationAddress(); auto request = model::packets::LlcpView::Create(incoming); ASSERT(request.IsValid()); auto payload = request.GetPayload(); auto packet = std::vector(payload.begin(), payload.end()); - uint16_t acl_connection_handle = connections_.GetHandleOnlyAddress(address); + auto acl_connection_handle = connections_.GetLeAclConnectionHandle(destination, source); - if (acl_connection_handle == kReservedHandle) { + if (!acl_connection_handle.has_value()) { INFO(id_, "Dropping LLCP packet since connection does not exist"); return; } - ASSERT(link_layer_ingest_llcp(ll_.get(), acl_connection_handle, packet.data(), packet.size())); + ASSERT(link_layer_ingest_llcp(ll_.get(), *acl_connection_handle, packet.data(), packet.size())); } -void LinkLayerController::IncomingLeConnectedIsochronousPdu(LinkLayerPacketView incoming) { +void LeController::IncomingLeConnectedIsochronousPdu(LinkLayerPacketView incoming) { auto pdu = model::packets::LeConnectedIsochronousPduView::Create(incoming); ASSERT(pdu.IsValid()); auto data = pdu.GetData(); @@ -3903,7 +3266,7 @@ void LinkLayerController::IncomingLeConnectedIsochronousPdu(LinkLayerPacketView } while (remaining_size > 0); } -void LinkLayerController::HandleAcl(bluetooth::hci::AclView acl) { +void LeController::HandleAcl(bluetooth::hci::AclView acl) { uint16_t connection_handle = acl.GetHandle(); auto pb_flag = acl.GetPacketBoundaryFlag(); auto bc_flag = acl.GetBroadcastFlag(); @@ -3914,42 +3277,31 @@ void LinkLayerController::HandleAcl(bluetooth::hci::AclView acl) { static_cast(bc_flag)); } - // ACL HCI packets received with an unknown or invalid Connection Handle are - // immediately acknowledged and silently dropped. - if (!connections_.HasHandle(connection_handle)) { - DEBUG("Received ACL HCI packet with invalid ACL connection handle 0x{:x}", connection_handle); - ScheduleTask(kNoDelayMs, [this, connection_handle]() { - send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create( - {bluetooth::hci::CompletedPackets(connection_handle, 1)})); - }); - return; - } - - AddressWithType source = connections_.GetOwnAddress(connection_handle); - AddressWithType destination = connections_.GetAddress(connection_handle); - Phy::Type phy = connections_.GetPhyType(connection_handle); + if (connections_.HasLeAclHandle(connection_handle)) { + // LE-ACL connection. + auto& connection = connections_.GetLeAclConnection(connection_handle); + auto acl_payload = acl.GetPayload(); + auto acl_packet = model::packets::AclBuilder::Create( + connection.own_address.GetAddress(), connection.address.GetAddress(), + static_cast(pb_flag), static_cast(bc_flag), + std::vector(acl_payload.begin(), acl_payload.end())); + SendLeLinkLayerPacket(std::move(acl_packet)); - auto acl_payload = acl.GetPayload(); - auto acl_packet = model::packets::AclBuilder::Create( - source.GetAddress(), destination.GetAddress(), static_cast(pb_flag), - static_cast(bc_flag), std::vector(acl_payload.begin(), acl_payload.end())); - - switch (phy) { - case Phy::Type::BR_EDR: - SendLinkLayerPacket(std::move(acl_packet)); - break; - case Phy::Type::LOW_ENERGY: - SendLeLinkLayerPacket(std::move(acl_packet)); - break; + } else { + // ACL HCI packets received with an unknown or invalid Connection Handle + // are silently dropped. + DEBUG("Received ACL HCI packet with invalid ACL connection handle 0x{:x}", connection_handle); } + // Send immediate acknowledgment for the ACL packet. + // We don't really have a transmission queue in the controller. ScheduleTask(kNoDelayMs, [this, connection_handle]() { send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create( {bluetooth::hci::CompletedPackets(connection_handle, 1)})); }); } -void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) { +void LeController::HandleIso(bluetooth::hci::IsoView iso) { uint16_t cis_connection_handle = iso.GetConnectionHandle(); auto pb_flag = iso.GetPbFlag(); auto ts_flag = iso.GetTsFlag(); @@ -3982,7 +3334,7 @@ void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) { uint8_t cig_id = 0; uint8_t cis_id = 0; - uint16_t acl_connection_handle = kReservedHandle; + uint16_t acl_connection_handle = -1; uint16_t packet_sequence_number = 0; uint16_t max_sdu_length = 0; @@ -3992,6 +3344,11 @@ void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) { return; } + if (!connections_.HasLeAclHandle(acl_connection_handle)) { + ERROR(id_, "Invalid LE-ACL connection handle returned from ISO manager"); + return; + } + if (pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT || pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU) { iso_sdu_.clear(); @@ -4029,28 +3386,33 @@ void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) { return; } + auto const& connection = connections_.GetLeAclConnection(acl_connection_handle); SendLeLinkLayerPacket(model::packets::LeConnectedIsochronousPduBuilder::Create( - address_, connections_.GetAddress(acl_connection_handle).GetAddress(), cig_id, cis_id, + connection.own_address.GetAddress(), connection.address.GetAddress(), cig_id, cis_id, packet_sequence_number, std::move(iso_sdu_))); } } -uint16_t LinkLayerController::HandleLeConnection( - AddressWithType address, AddressWithType own_address, bluetooth::hci::Role role, - uint16_t connection_interval, uint16_t connection_latency, uint16_t supervision_timeout, - bool send_le_channel_selection_algorithm_event) { +uint16_t LeController::HandleLeConnection(AddressWithType address, AddressWithType resolved_address, + AddressWithType own_address, bluetooth::hci::Role role, + uint16_t connection_interval, uint16_t connection_latency, + uint16_t supervision_timeout, + bool send_le_channel_selection_algorithm_event) { // Note: the HCI_LE_Connection_Complete event is not sent if the // HCI_LE_Enhanced_Connection_Complete event (see Section 7.7.65.10) is // unmasked. - uint16_t handle = connections_.CreateLeConnection(address, own_address, role); - if (handle == kReservedHandle) { - WARNING(id_, "No pending connection for connection from {}", address); - return kReservedHandle; - } + INFO(id_, "Creating LE connection with peer {}|{} and local address {}", address, + resolved_address, own_address); + uint16_t handle = connections_.CreateLeConnection( + address, resolved_address, own_address, role, + LeAclConnectionParameters{.conn_interval = connection_interval, + .conn_subrate_factor = 1, + .conn_peripheral_latency = connection_latency, + .conn_supervision_timeout = supervision_timeout}); if (IsLeEventUnmasked(SubeventCode::LE_ENHANCED_CONNECTION_COMPLETE_V1)) { - AddressWithType peer_resolved_address = connections_.GetResolvedAddress(handle); + AddressWithType peer_resolved_address = resolved_address; Address peer_resolvable_private_address; Address connection_address = address.GetAddress(); AddressType peer_address_type = address.GetAddressType(); @@ -4078,7 +3440,7 @@ uint16_t LinkLayerController::HandleLeConnection( // Update the link layer with the new link. ASSERT(link_layer_add_link(ll_.get(), handle, - reinterpret_cast(address.GetAddress().data()), + reinterpret_cast(address.GetAddress().data()), static_cast(role))); // Note: the HCI_LE_Connection_Complete event is immediately followed by @@ -4099,7 +3461,7 @@ uint16_t LinkLayerController::HandleLeConnection( } // Handle CONNECT_IND PDUs for the legacy advertiser. -bool LinkLayerController::ProcessIncomingLegacyConnectRequest( +bool LeController::ProcessIncomingLegacyConnectRequest( model::packets::LeConnectView const& connect_ind) { if (!legacy_advertiser_.IsEnabled()) { return false; @@ -4179,20 +3541,12 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest( "address {}", resolved_initiating_address); - if (!connections_.CreatePendingLeConnection(initiating_address, - resolved_initiating_address != initiating_address - ? resolved_initiating_address - : AddressWithType{}, - advertising_address)) { - WARNING(id_, "CreatePendingLeConnection failed for connection from {}", - initiating_address.GetAddress()); - return false; - } - - (void)HandleLeConnection(initiating_address, advertising_address, - bluetooth::hci::Role::PERIPHERAL, connect_ind.GetConnInterval(), - connect_ind.GetConnPeripheralLatency(), - connect_ind.GetConnSupervisionTimeout(), false); + (void)HandleLeConnection( + initiating_address, + resolved_initiating_address != initiating_address ? resolved_initiating_address + : AddressWithType{}, + advertising_address, bluetooth::hci::Role::PERIPHERAL, connect_ind.GetConnInterval(), + connect_ind.GetConnPeripheralLatency(), connect_ind.GetConnSupervisionTimeout(), false); SendLeLinkLayerPacket(model::packets::LeConnectCompleteBuilder::Create( advertising_address.GetAddress(), initiating_address.GetAddress(), @@ -4206,7 +3560,7 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest( } // Handle CONNECT_IND PDUs for the selected extended advertiser. -bool LinkLayerController::ProcessIncomingExtendedConnectRequest( +bool LeController::ProcessIncomingExtendedConnectRequest( ExtendedAdvertiser& advertiser, model::packets::LeConnectView const& connect_ind) { if (!advertiser.IsEnabled()) { return false; @@ -4287,22 +3641,14 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest( "address {}", advertiser.advertising_handle, resolved_initiating_address); - if (!connections_.CreatePendingLeConnection(initiating_address, - resolved_initiating_address != initiating_address - ? resolved_initiating_address - : AddressWithType{}, - advertising_address)) { - WARNING(id_, "CreatePendingLeConnection failed for connection from {}", - initiating_address.GetAddress()); - return false; - } - advertiser.Disable(); uint16_t connection_handle = HandleLeConnection( - initiating_address, advertising_address, bluetooth::hci::Role::PERIPHERAL, - connect_ind.GetConnInterval(), connect_ind.GetConnPeripheralLatency(), - connect_ind.GetConnSupervisionTimeout(), false); + initiating_address, + resolved_initiating_address != initiating_address ? resolved_initiating_address + : AddressWithType{}, + advertising_address, bluetooth::hci::Role::PERIPHERAL, connect_ind.GetConnInterval(), + connect_ind.GetConnPeripheralLatency(), connect_ind.GetConnSupervisionTimeout(), false); SendLeLinkLayerPacket(model::packets::LeConnectCompleteBuilder::Create( advertising_address.GetAddress(), initiating_address.GetAddress(), @@ -4326,7 +3672,7 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest( return true; } -void LinkLayerController::IncomingLeConnectPacket(model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLeConnectPacket(model::packets::LinkLayerPacketView incoming) { model::packets::LeConnectView connect = model::packets::LeConnectView::Create(incoming); ASSERT(connect.IsValid()); @@ -4341,19 +3687,33 @@ void LinkLayerController::IncomingLeConnectPacket(model::packets::LinkLayerPacke } } -void LinkLayerController::IncomingLeConnectCompletePacket( - model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLeConnectCompletePacket(model::packets::LinkLayerPacketView incoming) { auto complete = model::packets::LeConnectCompleteView::Create(incoming); ASSERT(complete.IsValid()); + AddressWithType initiating_address{ + incoming.GetDestinationAddress(), + static_cast(complete.GetInitiatingAddressType())}; AddressWithType advertising_address{ incoming.GetSourceAddress(), static_cast(complete.GetAdvertisingAddressType())}; + if (initiator_.pending_connect_request != advertising_address && + initiator_.initiating_address != initiating_address.GetAddress()) { + INFO(id_, "Ignoring unexpected LE Connect complete response {} -> {}", advertising_address, + initiating_address); + return; + } + INFO(id_, "Received LE Connect complete response with advertising address {}", advertising_address); - HandleLeConnection(advertising_address, + AddressWithType resolved_advertising_address = + advertising_address.IsRpa() + ? ResolvePrivateAddress(advertising_address).value_or(AddressWithType{}) + : AddressWithType{}; + + HandleLeConnection(advertising_address, resolved_advertising_address, AddressWithType(incoming.GetDestinationAddress(), static_cast( complete.GetInitiatingAddressType())), @@ -4365,21 +3725,15 @@ void LinkLayerController::IncomingLeConnectCompletePacket( initiator_.Disable(); } -void LinkLayerController::IncomingLeConnectionParameterRequest( - model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLeConnectionParameterRequest( + LeAclConnection& connection, model::packets::LinkLayerPacketView incoming) { auto request = model::packets::LeConnectionParameterRequestView::Create(incoming); ASSERT(request.IsValid()); - Address peer = incoming.GetSourceAddress(); - uint16_t handle = connections_.GetHandleOnlyAddress(peer); - if (handle == kReservedHandle) { - INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), peer); - return; - } if (IsLeEventUnmasked(SubeventCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST)) { send_event_(bluetooth::hci::LeRemoteConnectionParameterRequestBuilder::Create( - handle, request.GetIntervalMin(), request.GetIntervalMax(), request.GetLatency(), - request.GetTimeout())); + connection.handle, request.GetIntervalMin(), request.GetIntervalMax(), + request.GetLatency(), request.GetTimeout())); } else { // If the request is being indicated to the Host and the event to the Host // is masked, then the Link Layer shall issue an LL_REJECT_EXT_IND PDU with @@ -4390,54 +3744,38 @@ void LinkLayerController::IncomingLeConnectionParameterRequest( } } -void LinkLayerController::IncomingLeConnectionParameterUpdate( - model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLeConnectionParameterUpdate( + LeAclConnection& connection, model::packets::LinkLayerPacketView incoming) { auto update = model::packets::LeConnectionParameterUpdateView::Create(incoming); ASSERT(update.IsValid()); - Address peer = incoming.GetSourceAddress(); - uint16_t handle = connections_.GetHandleOnlyAddress(peer); - if (handle == kReservedHandle) { - INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), peer); - return; - } + if (IsLeEventUnmasked(SubeventCode::LE_CONNECTION_UPDATE_COMPLETE)) { send_event_(bluetooth::hci::LeConnectionUpdateCompleteBuilder::Create( - static_cast(update.GetStatus()), handle, update.GetInterval(), + static_cast(update.GetStatus()), connection.handle, update.GetInterval(), update.GetLatency(), update.GetTimeout())); } } -void LinkLayerController::IncomingLeEncryptConnection( - model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLeEncryptConnection(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming) { INFO(id_, "IncomingLeEncryptConnection"); - Address peer = incoming.GetSourceAddress(); - uint16_t handle = connections_.GetHandleOnlyAddress(peer); - if (handle == kReservedHandle) { - INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), peer); - return; - } auto le_encrypt = model::packets::LeEncryptConnectionView::Create(incoming); ASSERT(le_encrypt.IsValid()); // TODO: Save keys to check if (IsEventUnmasked(EventCode::LE_META_EVENT)) { - send_event_(bluetooth::hci::LeLongTermKeyRequestBuilder::Create(handle, le_encrypt.GetRand(), - le_encrypt.GetEdiv())); + send_event_(bluetooth::hci::LeLongTermKeyRequestBuilder::Create( + connection.handle, le_encrypt.GetRand(), le_encrypt.GetEdiv())); } } -void LinkLayerController::IncomingLeEncryptConnectionResponse( - model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLeEncryptConnectionResponse( + LeAclConnection& connection, model::packets::LinkLayerPacketView incoming) { INFO(id_, "IncomingLeEncryptConnectionResponse"); // TODO: Check keys - uint16_t handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); - if (handle == kReservedHandle) { - INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), - incoming.GetSourceAddress()); - return; - } + ErrorCode status = ErrorCode::SUCCESS; auto response = model::packets::LeEncryptConnectionResponseView::Create(incoming); ASSERT(response.IsValid()); @@ -4449,59 +3787,48 @@ void LinkLayerController::IncomingLeEncryptConnectionResponse( success = false; } - if (connections_.IsEncrypted(handle)) { + if (connection.IsEncrypted()) { if (IsEventUnmasked(EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE)) { - send_event_(bluetooth::hci::EncryptionKeyRefreshCompleteBuilder::Create(status, handle)); + send_event_(bluetooth::hci::EncryptionKeyRefreshCompleteBuilder::Create(status, + connection.handle)); } } else if (success) { - connections_.Encrypt(handle); + connection.Encrypt(); if (IsEventUnmasked(EventCode::ENCRYPTION_CHANGE)) { send_event_(bluetooth::hci::EncryptionChangeBuilder::Create( - status, handle, bluetooth::hci::EncryptionEnabled::ON)); + status, connection.handle, bluetooth::hci::EncryptionEnabled::ON)); } } else { if (IsEventUnmasked(EventCode::ENCRYPTION_CHANGE)) { send_event_(bluetooth::hci::EncryptionChangeBuilder::Create( - status, handle, bluetooth::hci::EncryptionEnabled::OFF)); + status, connection.handle, bluetooth::hci::EncryptionEnabled::OFF)); } } } -void LinkLayerController::IncomingLeReadRemoteFeatures( - model::packets::LinkLayerPacketView incoming) { - uint16_t handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); +void LeController::IncomingLeReadRemoteFeatures(LeAclConnection& /*connection*/, + model::packets::LinkLayerPacketView incoming) { ErrorCode status = ErrorCode::SUCCESS; - if (handle == kReservedHandle) { - WARNING(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), - incoming.GetSourceAddress()); - } SendLeLinkLayerPacket(model::packets::LeReadRemoteFeaturesResponseBuilder::Create( incoming.GetDestinationAddress(), incoming.GetSourceAddress(), GetLeSupportedFeatures(), static_cast(status))); } -void LinkLayerController::IncomingLeReadRemoteFeaturesResponse( - model::packets::LinkLayerPacketView incoming) { - uint16_t handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); - ErrorCode status = ErrorCode::SUCCESS; +void LeController::IncomingLeReadRemoteFeaturesResponse( + LeAclConnection& connection, model::packets::LinkLayerPacketView incoming) { auto response = model::packets::LeReadRemoteFeaturesResponseView::Create(incoming); ASSERT(response.IsValid()); - if (handle == kReservedHandle) { - INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), - incoming.GetSourceAddress()); - status = ErrorCode::UNKNOWN_CONNECTION; - } else { - status = static_cast(response.GetStatus()); - } + ErrorCode status = static_cast(response.GetStatus()); + if (IsEventUnmasked(EventCode::LE_META_EVENT)) { send_event_(bluetooth::hci::LeReadRemoteFeaturesPage0CompleteBuilder::Create( - status, handle, response.GetFeatures())); + status, connection.handle, response.GetFeatures())); } } -void LinkLayerController::ProcessIncomingLegacyScanRequest( - AddressWithType scanning_address, AddressWithType resolved_scanning_address, - AddressWithType advertising_address) { +void LeController::ProcessIncomingLegacyScanRequest(AddressWithType scanning_address, + AddressWithType resolved_scanning_address, + AddressWithType advertising_address) { // Check if the advertising addresses matches the legacy // advertising address. if (!legacy_advertiser_.IsEnabled()) { @@ -4558,9 +3885,10 @@ void LinkLayerController::ProcessIncomingLegacyScanRequest( properties_.le_advertising_physical_channel_tx_power); } -void LinkLayerController::ProcessIncomingExtendedScanRequest( - ExtendedAdvertiser const& advertiser, AddressWithType scanning_address, - AddressWithType resolved_scanning_address, AddressWithType advertising_address) { +void LeController::ProcessIncomingExtendedScanRequest(ExtendedAdvertiser const& advertiser, + AddressWithType scanning_address, + AddressWithType resolved_scanning_address, + AddressWithType advertising_address) { // Check if the advertising addresses matches the legacy // advertising address. if (!advertiser.IsEnabled()) { @@ -4628,7 +3956,7 @@ void LinkLayerController::ProcessIncomingExtendedScanRequest( advertiser.advertising_tx_power); } -void LinkLayerController::IncomingLeScanPacket(model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingLeScanPacket(model::packets::LinkLayerPacketView incoming) { auto scan_request = model::packets::LeScanView::Create(incoming); ASSERT(scan_request.IsValid()); @@ -4662,8 +3990,8 @@ void LinkLayerController::IncomingLeScanPacket(model::packets::LinkLayerPacketVi } } -void LinkLayerController::IncomingLeScanResponsePacket(model::packets::LinkLayerPacketView incoming, - uint8_t rssi) { +void LeController::IncomingLeScanResponsePacket(model::packets::LinkLayerPacketView incoming, + uint8_t rssi) { auto scan_response = model::packets::LeScanResponseView::Create(incoming); ASSERT(scan_response.IsValid()); @@ -4768,7 +4096,7 @@ void LinkLayerController::IncomingLeScanResponsePacket(model::packets::LinkLayer } } -void LinkLayerController::LeScanning() { +void LeController::LeScanning() { if (!scanner_.IsEnabled()) { return; } @@ -4820,7 +4148,7 @@ void LinkLayerController::LeScanning() { } } -void LinkLayerController::LeSynchronization() { +void LeController::LeSynchronization() { std::vector removed_sync_handles; for (auto& [_, sync] : synchronized_) { if (sync.timeout > std::chrono::steady_clock::now()) { @@ -4837,361 +4165,43 @@ void LinkLayerController::LeSynchronization() { } } -void LinkLayerController::IncomingPagePacket(model::packets::LinkLayerPacketView incoming) { - auto bd_addr = incoming.GetSourceAddress(); - auto page = model::packets::PageView::Create(incoming); - ASSERT(page.IsValid()); - - // [HCI] 7.3.3 Set Event Filter command - // If the Auto_Accept_Flag is off and the Host has masked the - // HCI_Connection_Request event, the Controller shall reject the - // connection attempt. - if (!IsEventUnmasked(EventCode::CONNECTION_REQUEST)) { - INFO(id_, - "rejecting connection request from {} because the HCI_Connection_Request" - " event is masked by the Host", - bd_addr); - SendLinkLayerPacket(model::packets::PageRejectBuilder::Create( - GetAddress(), bd_addr, static_cast(ErrorCode::CONNECTION_TIMEOUT))); - return; - } - - // Cannot establish two BR-EDR connections with the same peer. - if (connections_.GetAclConnectionHandle(bd_addr).has_value()) { - return; - } - - bool allow_role_switch = page.GetAllowRoleSwitch(); - if (!connections_.CreatePendingConnection( - bd_addr, authentication_enable_ == AuthenticationEnable::REQUIRED, - allow_role_switch)) { - // Will be triggered when multiple hosts are paging simultaneously; - // only one connection will be accepted. - WARNING(id_, "Failed to create a pending connection for {}", bd_addr); - return; - } - - send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( - bd_addr, page.GetClassOfDevice(), bluetooth::hci::ConnectionRequestLinkType::ACL)); -} - -void LinkLayerController::IncomingPageRejectPacket(model::packets::LinkLayerPacketView incoming) { - auto bd_addr = incoming.GetSourceAddress(); - auto reject = model::packets::PageRejectView::Create(incoming); - ASSERT(reject.IsValid()); - - if (!page_.has_value() || page_->bd_addr != bd_addr) { - INFO(id_, - "ignoring Page Reject packet received when not in Page state," - " or paging to a different address"); - return; - } - - INFO(id_, "Received Page Reject packet from {}", bd_addr); - page_ = {}; - - if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - static_cast(reject.GetReason()), 0, bd_addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); - } -} - -void LinkLayerController::IncomingPageResponsePacket(model::packets::LinkLayerPacketView incoming) { - auto bd_addr = incoming.GetSourceAddress(); - auto response = model::packets::PageResponseView::Create(incoming); - ASSERT(response.IsValid()); - - if (!page_.has_value() || page_->bd_addr != bd_addr) { - INFO(id_, - "ignoring Page Response packet received when not in Page state," - " or paging to a different address"); - return; - } - - INFO(id_, "Received Page Response packet from {}", bd_addr); - - uint16_t connection_handle = connections_.CreateConnection(bd_addr, GetAddress(), false); - ASSERT(connection_handle != kReservedHandle); - - bluetooth::hci::Role role = page_->allow_role_switch && response.GetTryRoleSwitch() - ? bluetooth::hci::Role::PERIPHERAL - : bluetooth::hci::Role::CENTRAL; - - AclConnection& connection = connections_.GetAclConnection(connection_handle); - CheckExpiringConnection(connection_handle); - connection.SetLinkPolicySettings(default_link_policy_settings_); - connection.SetRole(role); - page_ = {}; - - ASSERT(link_manager_add_link(lm_.get(), reinterpret_cast(bd_addr.data()))); - - // Role change event before connection complete generates an HCI Role Change - // event on the initiator side if accepted; the event is sent before the - // HCI Connection Complete event. - if (role == bluetooth::hci::Role::PERIPHERAL && IsEventUnmasked(EventCode::ROLE_CHANGE)) { - send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, bd_addr, role)); - } - - if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode::SUCCESS, connection_handle, bd_addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); - } -} - -void LinkLayerController::Tick() { +void LeController::Tick() { RunPendingTasks(); - Paging(); - - if (inquiry_timer_task_id_ != kInvalidTaskId) { - Inquiry(); - } LeAdvertising(); LeScanning(); - link_manager_tick(lm_.get()); } -void LinkLayerController::Close() { - for (auto handle : connections_.GetAclHandles()) { - Disconnect(handle, ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF, - ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF); - } +void LeController::Close() { + DisconnectAll(ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF); } -void LinkLayerController::RegisterEventChannel( +void LeController::RegisterEventChannel( const std::function)>& send_event) { send_event_ = send_event; } -void LinkLayerController::RegisterAclChannel( +void LeController::RegisterAclChannel( const std::function)>& send_acl) { send_acl_ = send_acl; } -void LinkLayerController::RegisterScoChannel( - const std::function)>& send_sco) { - send_sco_ = send_sco; -} - -void LinkLayerController::RegisterIsoChannel( +void LeController::RegisterIsoChannel( const std::function)>& send_iso) { send_iso_ = send_iso; } -void LinkLayerController::RegisterRemoteChannel( +void LeController::RegisterRemoteChannel( const std::function, Phy::Type, int8_t)>& send_to_remote) { send_to_remote_ = send_to_remote; } -void LinkLayerController::ForwardToLm(bluetooth::hci::CommandView command) { - auto packet = command.bytes().bytes(); - ASSERT(link_manager_ingest_hci(lm_.get(), packet.data(), packet.size())); -} - -void LinkLayerController::ForwardToLl(bluetooth::hci::CommandView command) { +void LeController::ForwardToLl(bluetooth::hci::CommandView command) { auto packet = command.bytes().bytes(); ASSERT(link_layer_ingest_hci(ll_.get(), packet.data(), packet.size())); } -std::vector const& LinkLayerController::ReadCurrentIacLap() const { - return current_iac_lap_list_; -} - -void LinkLayerController::WriteCurrentIacLap(std::vector iac_lap) { - current_iac_lap_list_.swap(iac_lap); - - // If Num_Current_IAC is greater than Num_Supported_IAC then only the first - // Num_Supported_IAC shall be stored in the Controller - if (current_iac_lap_list_.size() > properties_.num_supported_iac) { - current_iac_lap_list_.resize(properties_.num_supported_iac); - } -} - -ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr, - bool try_role_switch) { - if (connections_.HasPendingConnection(bd_addr)) { - INFO(id_, "Accepting connection request from {}", bd_addr); - ScheduleTask(kNoDelayMs, [this, bd_addr, try_role_switch]() { - INFO(id_, "Accepted connection from {}", bd_addr); - MakePeripheralConnection(bd_addr, try_role_switch); - }); - - return ErrorCode::SUCCESS; - } - - // The HCI command Accept Connection may be used to accept incoming SCO - // connection requests. - if (connections_.HasPendingScoConnection(bd_addr)) { - ErrorCode status = ErrorCode::SUCCESS; - uint16_t sco_handle = 0; - ScoLinkParameters link_parameters = {}; - ScoConnectionParameters connection_parameters = - connections_.GetScoConnectionParameters(bd_addr); - - if (!connections_.AcceptPendingScoConnection(bd_addr, connection_parameters, [this, bd_addr] { - return LinkLayerController::StartScoStream(bd_addr); - })) { - connections_.CancelPendingScoConnection(bd_addr); - status = ErrorCode::SCO_INTERVAL_REJECTED; // TODO: proper status code - } else { - sco_handle = connections_.GetScoHandle(bd_addr); - link_parameters = connections_.GetScoLinkParameters(bd_addr); - } - - // Send eSCO connection response to peer. - SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( - GetAddress(), bd_addr, (uint8_t)status, link_parameters.transmission_interval, - link_parameters.retransmission_window, link_parameters.rx_packet_length, - link_parameters.tx_packet_length, link_parameters.air_mode, link_parameters.extended)); - - // Schedule HCI Connection Complete event. - if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { - ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr]() { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode(status), sco_handle, bd_addr, bluetooth::hci::LinkType::SCO, - bluetooth::hci::Enable::DISABLED)); - }); - } - - return ErrorCode::SUCCESS; - } - - INFO(id_, "No pending connection for {}", bd_addr); - return ErrorCode::UNKNOWN_CONNECTION; -} - -void LinkLayerController::MakePeripheralConnection(const Address& bd_addr, bool try_role_switch) { - uint16_t connection_handle = connections_.CreateConnection(bd_addr, GetAddress()); - if (connection_handle == kReservedHandle) { - INFO(id_, "CreateConnection failed"); - return; - } - - bluetooth::hci::Role role = - try_role_switch && connections_.IsRoleSwitchAllowedForPendingConnection() - ? bluetooth::hci::Role::CENTRAL - : bluetooth::hci::Role::PERIPHERAL; - - AclConnection& connection = connections_.GetAclConnection(connection_handle); - CheckExpiringConnection(connection_handle); - connection.SetLinkPolicySettings(default_link_policy_settings_); - connection.SetRole(role); - - ASSERT(link_manager_add_link(lm_.get(), reinterpret_cast(bd_addr.data()))); - - // Role change event before connection complete generates an HCI Role Change - // event on the acceptor side if accepted; the event is sent before the - // HCI Connection Complete event. - if (role == bluetooth::hci::Role::CENTRAL && IsEventUnmasked(EventCode::ROLE_CHANGE)) { - INFO(id_, "Role at connection setup accepted"); - send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, bd_addr, role)); - } - - if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode::SUCCESS, connection_handle, bd_addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); - } - - // If the current Host was initiating a connection to the same bd_addr, - // send a connection complete event for the pending Create Connection - // command and cancel the paging. - if (page_.has_value() && page_->bd_addr == bd_addr) { - // TODO: the core specification is very unclear as to what behavior - // is expected when two connections are established simultaneously. - // This implementation considers that a unique HCI Connection Complete - // event is expected for both the HCI Create Connection and HCI Accept - // Connection Request commands. - page_ = {}; - } - - INFO(id_, "Sending page response to {}", bd_addr.ToString()); - SendLinkLayerPacket( - model::packets::PageResponseBuilder::Create(GetAddress(), bd_addr, try_role_switch)); -} - -ErrorCode LinkLayerController::RejectConnectionRequest(const Address& addr, uint8_t reason) { - if (!connections_.HasPendingConnection(addr)) { - INFO(id_, "No pending connection for {}", addr); - return ErrorCode::UNKNOWN_CONNECTION; - } - - ScheduleTask(kNoDelayMs, [this, addr, reason]() { RejectPeripheralConnection(addr, reason); }); - - return ErrorCode::SUCCESS; -} - -void LinkLayerController::RejectPeripheralConnection(const Address& addr, uint8_t reason) { - INFO(id_, "Sending page reject to {} (reason 0x{:02x})", addr, reason); - SendLinkLayerPacket(model::packets::PageRejectBuilder::Create(GetAddress(), addr, reason)); - - if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - static_cast(reason), 0xeff, addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); - } -} - -ErrorCode LinkLayerController::CreateConnection(const Address& bd_addr, uint16_t /* packet_type */, - uint8_t /* page_scan_mode */, - uint16_t /* clock_offset */, - uint8_t allow_role_switch) { - // RootCanal only accepts one pending outgoing connection at any time. - if (page_.has_value()) { - INFO(id_, "Create Connection command is already pending"); - return ErrorCode::COMMAND_DISALLOWED; - } - - // Reject the command if a connection or pending connection already exists - // for the selected peer address. - if (connections_.HasPendingConnection(bd_addr) || - connections_.GetAclConnectionHandle(bd_addr).has_value()) { - INFO(id_, "Connection with {} already exists", bd_addr.ToString()); - return ErrorCode::CONNECTION_ALREADY_EXISTS; - } - - auto now = std::chrono::steady_clock::now(); - page_ = Page{ - .bd_addr = bd_addr, - .allow_role_switch = allow_role_switch, - .next_page_event = now + kPageInterval, - .page_timeout = now + slots(page_timeout_), - }; - - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::CreateConnectionCancel(const Address& bd_addr) { - // If the HCI_Create_Connection_Cancel command is sent to the Controller - // without a preceding HCI_Create_Connection command to the same device, - // the BR/EDR Controller shall return an HCI_Command_Complete event with - // the error code Unknown Connection Identifier (0x02) - if (!page_.has_value() || page_->bd_addr != bd_addr) { - INFO(id_, "no pending connection to {}", bd_addr.ToString()); - return ErrorCode::UNKNOWN_CONNECTION; - } - - // The HCI_Connection_Complete event for the corresponding HCI_Create_- - // Connection command shall always be sent. The HCI_Connection_Complete - // event shall be sent after the HCI_Command_Complete event for the - // HCI_Create_Connection_Cancel command. If the cancellation was successful, - // the HCI_Connection_Complete event will be generated with the error code - // Unknown Connection Identifier (0x02). - if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { - ScheduleTask(kNoDelayMs, [this, bd_addr]() { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode::UNKNOWN_CONNECTION, 0, bd_addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); - }); - } - - page_ = {}; - return ErrorCode::SUCCESS; -} - -void LinkLayerController::SendDisconnectionCompleteEvent(uint16_t handle, ErrorCode reason) { +void LeController::SendDisconnectionCompleteEvent(uint16_t handle, ErrorCode reason) { if (IsEventUnmasked(EventCode::DISCONNECTION_COMPLETE)) { ScheduleTask(kNoDelayMs, [this, handle, reason]() { send_event_(bluetooth::hci::DisconnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, @@ -5200,364 +4210,47 @@ void LinkLayerController::SendDisconnectionCompleteEvent(uint16_t handle, ErrorC } } -ErrorCode LinkLayerController::Disconnect(uint16_t handle, ErrorCode host_reason, - ErrorCode controller_reason) { - if (connections_.HasScoHandle(handle)) { - const Address remote = connections_.GetScoAddress(handle); - INFO(id_, "Disconnecting eSCO connection with {}", remote); +ErrorCode LeController::Disconnect(uint16_t handle, ErrorCode host_reason, + ErrorCode controller_reason) { + if (connections_.HasLeAclHandle(handle)) { + auto connection = connections_.GetLeAclConnection(handle); + INFO(id_, "Disconnecting LE-ACL connection with {}", connection.address); - SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create( - GetAddress(), remote, static_cast(host_reason))); + SendLeLinkLayerPacket(model::packets::DisconnectBuilder::Create( + connection.own_address.GetAddress(), connection.address.GetAddress(), + static_cast(host_reason))); connections_.Disconnect(handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }); SendDisconnectionCompleteEvent(handle, controller_reason); - return ErrorCode::SUCCESS; - } - - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - const AddressWithType remote = connections_.GetAddress(handle); - auto is_br_edr = connections_.GetPhyType(handle) == Phy::Type::BR_EDR; - if (is_br_edr) { - INFO(id_, "Disconnecting ACL connection with {}", remote); - - uint16_t sco_handle = connections_.GetScoHandle(remote.GetAddress()); - if (sco_handle != kReservedHandle) { - SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create( - GetAddress(), remote.GetAddress(), static_cast(host_reason))); - - connections_.Disconnect(sco_handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }); - SendDisconnectionCompleteEvent(sco_handle, controller_reason); - } - - SendLinkLayerPacket(model::packets::DisconnectBuilder::Create( - GetAddress(), remote.GetAddress(), static_cast(host_reason))); - } else { - INFO(id_, "Disconnecting LE connection with {}", remote); - - SendLeLinkLayerPacket(model::packets::DisconnectBuilder::Create( - connections_.GetOwnAddress(handle).GetAddress(), remote.GetAddress(), - static_cast(host_reason))); - } - - connections_.Disconnect(handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }); - SendDisconnectionCompleteEvent(handle, controller_reason); - if (is_br_edr) { - ASSERT(link_manager_remove_link(lm_.get(), - reinterpret_cast(remote.GetAddress().data()))); - } else { ASSERT(link_layer_remove_link(ll_.get(), handle, static_cast(controller_reason))); + return ErrorCode::SUCCESS; } - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::ChangeConnectionPacketType(uint16_t handle, uint16_t types) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - ScheduleTask(kNoDelayMs, [this, handle, types]() { - if (IsEventUnmasked(EventCode::CONNECTION_PACKET_TYPE_CHANGED)) { - send_event_(bluetooth::hci::ConnectionPacketTypeChangedBuilder::Create(ErrorCode::SUCCESS, - handle, types)); - } - }); - - return ErrorCode::SUCCESS; -} - -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -ErrorCode LinkLayerController::ChangeConnectionLinkKey(uint16_t handle) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - // TODO: implement real logic - return ErrorCode::COMMAND_DISALLOWED; -} - -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -ErrorCode LinkLayerController::CentralLinkKey(uint8_t /* key_flag */) { - // TODO: implement real logic - return ErrorCode::COMMAND_DISALLOWED; -} - -ErrorCode LinkLayerController::HoldMode(uint16_t handle, uint16_t hold_mode_max_interval, - uint16_t hold_mode_min_interval) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - if (hold_mode_max_interval < hold_mode_min_interval) { - return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; - } - - // TODO: implement real logic - return ErrorCode::COMMAND_DISALLOWED; -} - -ErrorCode LinkLayerController::SniffMode(uint16_t handle, uint16_t sniff_max_interval, - uint16_t sniff_min_interval, uint16_t sniff_attempt, - uint16_t sniff_timeout) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - if (sniff_max_interval < sniff_min_interval || sniff_attempt < 0x0001 || sniff_attempt > 0x7FFF || - sniff_timeout > 0x7FFF) { - return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; - } - - // TODO: implement real logic - return ErrorCode::COMMAND_DISALLOWED; -} - -ErrorCode LinkLayerController::ExitSniffMode(uint16_t handle) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - // TODO: implement real logic - return ErrorCode::COMMAND_DISALLOWED; -} - -ErrorCode LinkLayerController::QosSetup(uint16_t handle, uint8_t service_type, - uint32_t /* token_rate */, uint32_t /* peak_bandwidth */, - uint32_t /* latency */, uint32_t /* delay_variation */) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - if (service_type > 0x02) { - return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; - } - - // TODO: implement real logic - return ErrorCode::COMMAND_DISALLOWED; -} - -ErrorCode LinkLayerController::RoleDiscovery(uint16_t handle, bluetooth::hci::Role* role) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - *role = connections_.GetAclRole(handle); - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::SwitchRole(Address bd_addr, bluetooth::hci::Role role) { - // The BD_ADDR command parameter indicates for which connection - // the role switch is to be performed and shall specify a BR/EDR Controller - // for which a connection already exists. - uint16_t connection_handle = connections_.GetHandleOnlyAddress(bd_addr); - if (connection_handle == kReservedHandle) { - INFO(id_, "unknown connection address {}", bd_addr); - return ErrorCode::UNKNOWN_CONNECTION; - } - - AclConnection& connection = connections_.GetAclConnection(connection_handle); - - // If there is an (e)SCO connection between the local device and the device - // identified by the BD_ADDR parameter, an attempt to perform a role switch - // shall be rejected by the local device. - if (connections_.GetScoHandle(bd_addr) != kReservedHandle) { - INFO(id_, - "role switch rejected because an Sco link is opened with" - " the target device"); - return ErrorCode::COMMAND_DISALLOWED; - } - - // If the connection between the local device and the device identified by the - // BD_ADDR parameter is placed in Sniff mode, an attempt to perform a role - // switch shall be rejected by the local device. - if (connection.GetMode() == AclConnectionState::kSniffMode) { - INFO(id_, "role switch rejected because the acl connection is in sniff mode"); - return ErrorCode::COMMAND_DISALLOWED; - } - - if (role != connection.GetRole()) { - SendLinkLayerPacket(model::packets::RoleSwitchRequestBuilder::Create(GetAddress(), bd_addr)); - } else if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { - // Note: the status is Success only if the role change procedure was - // actually performed, otherwise the status is >0. - ScheduleTask(kNoDelayMs, [this, bd_addr, role]() { - send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::ROLE_SWITCH_FAILED, bd_addr, - role)); - }); - } - - return ErrorCode::SUCCESS; -} - -void LinkLayerController::IncomingRoleSwitchRequest(model::packets::LinkLayerPacketView incoming) { - auto bd_addr = incoming.GetSourceAddress(); - auto connection_handle = connections_.GetHandleOnlyAddress(bd_addr); - auto switch_req = model::packets::RoleSwitchRequestView::Create(incoming); - ASSERT(switch_req.IsValid()); - - if (connection_handle == kReservedHandle) { - INFO(id_, "ignoring Switch Request received on unknown connection"); - return; - } - - AclConnection& connection = connections_.GetAclConnection(connection_handle); - - if (!connection.IsRoleSwitchEnabled()) { - INFO(id_, "role switch disabled by local link policy settings"); - SendLinkLayerPacket(model::packets::RoleSwitchResponseBuilder::Create( - GetAddress(), bd_addr, static_cast(ErrorCode::ROLE_CHANGE_NOT_ALLOWED))); - } else { - INFO(id_, "role switch request accepted by local device"); - SendLinkLayerPacket(model::packets::RoleSwitchResponseBuilder::Create( - GetAddress(), bd_addr, static_cast(ErrorCode::SUCCESS))); - - bluetooth::hci::Role new_role = connection.GetRole() == bluetooth::hci::Role::CENTRAL - ? bluetooth::hci::Role::PERIPHERAL - : bluetooth::hci::Role::CENTRAL; - - connection.SetRole(new_role); - - if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { - ScheduleTask(kNoDelayMs, [this, bd_addr, new_role]() { - send_event_( - bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, bd_addr, new_role)); - }); - } - } -} - -void LinkLayerController::IncomingRoleSwitchResponse(model::packets::LinkLayerPacketView incoming) { - auto bd_addr = incoming.GetSourceAddress(); - auto connection_handle = connections_.GetHandleOnlyAddress(bd_addr); - auto switch_rsp = model::packets::RoleSwitchResponseView::Create(incoming); - ASSERT(switch_rsp.IsValid()); - - if (connection_handle == kReservedHandle) { - INFO(id_, "ignoring Switch Response received on unknown connection"); - return; - } - - AclConnection& connection = connections_.GetAclConnection(connection_handle); - ErrorCode status = ErrorCode(switch_rsp.GetStatus()); - bluetooth::hci::Role new_role = status != ErrorCode::SUCCESS ? connection.GetRole() - : connection.GetRole() == bluetooth::hci::Role::CENTRAL - ? bluetooth::hci::Role::PERIPHERAL - : bluetooth::hci::Role::CENTRAL; - - connection.SetRole(new_role); - - if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { - ScheduleTask(kNoDelayMs, [this, status, bd_addr, new_role]() { - send_event_(bluetooth::hci::RoleChangeBuilder::Create(status, bd_addr, new_role)); - }); - } -} - -ErrorCode LinkLayerController::ReadLinkPolicySettings(uint16_t handle, uint16_t* settings) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - *settings = connections_.GetAclLinkPolicySettings(handle); - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::WriteLinkPolicySettings(uint16_t handle, uint16_t settings) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - if (settings > 7 /* Sniff + Hold + Role switch */) { - return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; - } - connections_.SetAclLinkPolicySettings(handle, settings); - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::WriteDefaultLinkPolicySettings(uint16_t settings) { - if (settings > 7 /* Sniff + Hold + Role switch */) { - return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; - } - - default_link_policy_settings_ = settings; - return ErrorCode::SUCCESS; -} - -uint16_t LinkLayerController::ReadDefaultLinkPolicySettings() const { - return default_link_policy_settings_; -} - -void LinkLayerController::ReadLocalOobData() { - std::array c_array({'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '0', '0', '0', '0', '0', - '0', static_cast((oob_id_ % 0x10000) >> 8), - static_cast(oob_id_ % 0x100)}); - - std::array r_array({'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '0', '0', '0', '0', '0', - '0', static_cast((oob_id_ % 0x10000) >> 8), - static_cast(oob_id_ % 0x100)}); - send_event_(bluetooth::hci::ReadLocalOobDataCompleteBuilder::Create(1, ErrorCode::SUCCESS, - c_array, r_array)); - oob_id_ += 1; -} - -void LinkLayerController::ReadLocalOobExtendedData() { - std::array c_192_array({'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '1', '9', '2', '0', - '0', '0', static_cast((oob_id_ % 0x10000) >> 8), - static_cast(oob_id_ % 0x100)}); - - std::array r_192_array({'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '1', '9', '2', '0', - '0', '0', static_cast((oob_id_ % 0x10000) >> 8), - static_cast(oob_id_ % 0x100)}); - - std::array c_256_array({'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '2', '5', '6', '0', - '0', '0', static_cast((oob_id_ % 0x10000) >> 8), - static_cast(oob_id_ % 0x100)}); - - std::array r_256_array({'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '2', '5', '6', '0', - '0', '0', static_cast((oob_id_ % 0x10000) >> 8), - static_cast(oob_id_ % 0x100)}); - - send_event_(bluetooth::hci::ReadLocalOobExtendedDataCompleteBuilder::Create( - 1, ErrorCode::SUCCESS, c_192_array, r_192_array, c_256_array, r_256_array)); - oob_id_ += 1; + return ErrorCode::UNKNOWN_CONNECTION; } -ErrorCode LinkLayerController::FlowSpecification(uint16_t handle, uint8_t flow_direction, - uint8_t service_type, uint32_t /* token_rate */, - uint32_t /* token_bucket_size */, - uint32_t /* peak_bandwidth */, - uint32_t /* access_latency */) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - if (flow_direction > 0x01 || service_type > 0x02) { - return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; +ErrorCode LeController::ReadRemoteVersionInformation(uint16_t connection_handle) { + if (connections_.HasLeAclHandle(connection_handle)) { + auto const& connection = connections_.GetLeAclConnection(connection_handle); + SendLeLinkLayerPacket(model::packets::ReadRemoteVersionInformationBuilder::Create( + connection.own_address.GetAddress(), connection.address.GetAddress())); + return ErrorCode::SUCCESS; } - // TODO: implement real logic - return ErrorCode::COMMAND_DISALLOWED; -} - -ErrorCode LinkLayerController::WriteLinkSupervisionTimeout(uint16_t handle, - uint16_t /* timeout */) { - if (!connections_.HasHandle(handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - return ErrorCode::SUCCESS; + return ErrorCode::UNKNOWN_CONNECTION; } -void LinkLayerController::LeConnectionUpdateComplete(uint16_t handle, uint16_t interval_min, - uint16_t interval_max, uint16_t latency, - uint16_t supervision_timeout) { +void LeController::LeConnectionUpdateComplete(uint16_t handle, uint16_t interval_min, + uint16_t interval_max, uint16_t latency, + uint16_t supervision_timeout) { ErrorCode status = ErrorCode::SUCCESS; - if (!connections_.HasHandle(handle)) { + if (!connections_.HasLeAclHandle(handle)) { status = ErrorCode::UNKNOWN_CONNECTION; } + auto const& connection = connections_.GetLeAclConnection(handle); + if (interval_min < 6 || interval_max > 0xC80 || interval_min > interval_max || interval_max < interval_min || latency > 0x1F3 || supervision_timeout < 0xA || supervision_timeout > 0xC80 || @@ -5569,9 +4262,8 @@ void LinkLayerController::LeConnectionUpdateComplete(uint16_t handle, uint16_t i uint16_t interval = (interval_min + interval_max) / 2; SendLeLinkLayerPacket(LeConnectionParameterUpdateBuilder::Create( - connections_.GetOwnAddress(handle).GetAddress(), - connections_.GetAddress(handle).GetAddress(), static_cast(ErrorCode::SUCCESS), - interval, latency, supervision_timeout)); + connection.own_address.GetAddress(), connection.address.GetAddress(), + static_cast(ErrorCode::SUCCESS), interval, latency, supervision_timeout)); if (IsLeEventUnmasked(SubeventCode::LE_CONNECTION_UPDATE_COMPLETE)) { send_event_(bluetooth::hci::LeConnectionUpdateCompleteBuilder::Create( @@ -5579,22 +4271,21 @@ void LinkLayerController::LeConnectionUpdateComplete(uint16_t handle, uint16_t i } } -ErrorCode LinkLayerController::LeConnectionUpdate(uint16_t handle, uint16_t interval_min, - uint16_t interval_max, uint16_t latency, - uint16_t supervision_timeout) { - if (!connections_.HasHandle(handle)) { +ErrorCode LeController::LeConnectionUpdate(uint16_t handle, uint16_t interval_min, + uint16_t interval_max, uint16_t latency, + uint16_t supervision_timeout) { + if (!connections_.HasLeAclHandle(handle)) { return ErrorCode::UNKNOWN_CONNECTION; } - bluetooth::hci::Role role = connections_.GetAclRole(handle); + auto& connection = connections_.GetLeAclConnection(handle); - if (role == bluetooth::hci::Role::CENTRAL) { + if (connection.role == bluetooth::hci::Role::CENTRAL) { // As Central, it is allowed to directly send // LL_CONNECTION_PARAM_UPDATE_IND to update the parameters. SendLeLinkLayerPacket(LeConnectionParameterUpdateBuilder::Create( - connections_.GetOwnAddress(handle).GetAddress(), - connections_.GetAddress(handle).GetAddress(), static_cast(ErrorCode::SUCCESS), - interval_max, latency, supervision_timeout)); + connection.own_address.GetAddress(), connection.address.GetAddress(), + static_cast(ErrorCode::SUCCESS), interval_max, latency, supervision_timeout)); if (IsLeEventUnmasked(SubeventCode::LE_CONNECTION_UPDATE_COMPLETE)) { send_event_(bluetooth::hci::LeConnectionUpdateCompleteBuilder::Create( @@ -5604,18 +4295,17 @@ ErrorCode LinkLayerController::LeConnectionUpdate(uint16_t handle, uint16_t inte // Send LL_CONNECTION_PARAM_REQ and wait for LL_CONNECTION_PARAM_RSP // in return. SendLeLinkLayerPacket(LeConnectionParameterRequestBuilder::Create( - connections_.GetOwnAddress(handle).GetAddress(), - connections_.GetAddress(handle).GetAddress(), interval_min, interval_max, latency, - supervision_timeout)); + connection.own_address.GetAddress(), connection.address.GetAddress(), interval_min, + interval_max, latency, supervision_timeout)); } return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::LeRemoteConnectionParameterRequestReply( +ErrorCode LeController::LeRemoteConnectionParameterRequestReply( uint16_t connection_handle, uint16_t interval_min, uint16_t interval_max, uint16_t timeout, uint16_t latency, uint16_t minimum_ce_length, uint16_t maximum_ce_length) { - if (!connections_.HasHandle(connection_handle)) { + if (!connections_.HasLeAclHandle(connection_handle)) { return ErrorCode::UNKNOWN_CONNECTION; } @@ -5630,45 +4320,42 @@ ErrorCode LinkLayerController::LeRemoteConnectionParameterRequestReply( return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::LeRemoteConnectionParameterRequestNegativeReply( +ErrorCode LeController::LeRemoteConnectionParameterRequestNegativeReply( uint16_t connection_handle, bluetooth::hci::ErrorCode reason) { - if (!connections_.HasHandle(connection_handle)) { + if (!connections_.HasLeAclHandle(connection_handle)) { return ErrorCode::UNKNOWN_CONNECTION; } + auto const& connection = connections_.GetLeAclConnection(connection_handle); uint16_t interval = 0; uint16_t latency = 0; uint16_t timeout = 0; SendLeLinkLayerPacket(LeConnectionParameterUpdateBuilder::Create( - connections_.GetOwnAddress(connection_handle).GetAddress(), - connections_.GetAddress(connection_handle).GetAddress(), static_cast(reason), - interval, latency, timeout)); + connection.own_address.GetAddress(), connection.address.GetAddress(), + static_cast(reason), interval, latency, timeout)); return ErrorCode::SUCCESS; } -bool LinkLayerController::HasAclConnection() { return !connections_.GetAclHandles().empty(); } - -bool LinkLayerController::HasAclConnection(uint16_t connection_handle) { - return connections_.HasHandle(connection_handle); +bool LeController::HasLeAclConnection(uint16_t connection_handle) { + return connections_.HasLeAclHandle(connection_handle); } -void LinkLayerController::HandleLeEnableEncryption(uint16_t handle, std::array rand, - uint16_t ediv, - std::array ltk) { +void LeController::HandleLeEnableEncryption(uint16_t handle, std::array rand, + uint16_t ediv, std::array ltk) { // TODO: Check keys // TODO: Block ACL traffic or at least guard against it - if (!connections_.HasHandle(handle)) { + if (!connections_.HasLeAclHandle(handle)) { return; } + + auto const& connection = connections_.GetLeAclConnection(handle); SendLeLinkLayerPacket(model::packets::LeEncryptConnectionBuilder::Create( - connections_.GetOwnAddress(handle).GetAddress(), - connections_.GetAddress(handle).GetAddress(), rand, ediv, ltk)); + connection.own_address.GetAddress(), connection.address.GetAddress(), rand, ediv, ltk)); } -ErrorCode LinkLayerController::LeEnableEncryption(uint16_t handle, std::array rand, - uint16_t ediv, - std::array ltk) { - if (!connections_.HasHandle(handle)) { +ErrorCode LeController::LeEnableEncryption(uint16_t handle, std::array rand, + uint16_t ediv, std::array ltk) { + if (!connections_.HasLeAclHandle(handle)) { INFO(id_, "Unknown handle 0x{:04x}", handle); return ErrorCode::UNKNOWN_CONNECTION; } @@ -5679,21 +4366,23 @@ ErrorCode LinkLayerController::LeEnableEncryption(uint16_t handle, std::array ltk) { - if (!connections_.HasHandle(handle)) { +ErrorCode LeController::LeLongTermKeyRequestReply(uint16_t handle, + std::array ltk) { + if (!connections_.HasLeAclHandle(handle)) { INFO(id_, "Unknown handle {:04x}", handle); return ErrorCode::UNKNOWN_CONNECTION; } + auto& connection = connections_.GetLeAclConnection(handle); + // TODO: Check keys - if (connections_.IsEncrypted(handle)) { + if (connection.IsEncrypted()) { if (IsEventUnmasked(EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE)) { send_event_(bluetooth::hci::EncryptionKeyRefreshCompleteBuilder::Create(ErrorCode::SUCCESS, handle)); } } else { - connections_.Encrypt(handle); + connection.Encrypt(); if (IsEventUnmasked(EventCode::ENCRYPTION_CHANGE_V2)) { send_event_(bluetooth::hci::EncryptionChangeV2Builder::Create( ErrorCode::SUCCESS, handle, bluetooth::hci::EncryptionEnabled::ON, @@ -5704,26 +4393,44 @@ ErrorCode LinkLayerController::LeLongTermKeyRequestReply(uint16_t handle, } } SendLeLinkLayerPacket(model::packets::LeEncryptConnectionResponseBuilder::Create( - connections_.GetOwnAddress(handle).GetAddress(), - connections_.GetAddress(handle).GetAddress(), std::array(), uint16_t(), ltk)); + connection.own_address.GetAddress(), connection.address.GetAddress(), + std::array(), uint16_t(), ltk)); return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::LeLongTermKeyRequestNegativeReply(uint16_t handle) { - if (!connections_.HasHandle(handle)) { +ErrorCode LeController::LeLongTermKeyRequestNegativeReply(uint16_t handle) { + if (!connections_.HasLeAclHandle(handle)) { INFO(id_, "Unknown handle {:04x}", handle); return ErrorCode::UNKNOWN_CONNECTION; } + auto const& connection = connections_.GetLeAclConnection(handle); SendLeLinkLayerPacket(model::packets::LeEncryptConnectionResponseBuilder::Create( - connections_.GetOwnAddress(handle).GetAddress(), - connections_.GetAddress(handle).GetAddress(), std::array(), uint16_t(), - std::array())); + connection.own_address.GetAddress(), connection.address.GetAddress(), + std::array(), uint16_t(), std::array())); return ErrorCode::SUCCESS; } -void LinkLayerController::Reset() { +void LeController::DisconnectAll(ErrorCode reason) { + for (auto connection_handle : connections_.GetLeAclHandles()) { + auto const& connection = connections_.GetLeAclConnection(connection_handle); + SendLeLinkLayerPacket(model::packets::DisconnectBuilder::Create( + connection.own_address.GetAddress(), connection.address.GetAddress(), + static_cast(reason))); + } +} + +void LeController::Reset() { + // Explicitly Disconnect all existing links on reset. + // No Disconnection Complete event should be generated from the link + // disconnections, as only the HCI Command Complete event is expected for the + // HCI Reset command. + DisconnectAll(ErrorCode::REMOTE_USER_TERMINATED_CONNECTION); + + // DisconnectAll does not close the local connection contexts. + connections_.Reset([this](TaskId task_id) { CancelScheduledTask(task_id); }); + host_supported_features_ = 0; le_host_support_ = false; secure_simple_pairing_host_support_ = false; @@ -5732,32 +4439,12 @@ void LinkLayerController::Reset() { connected_isochronous_stream_host_support_ = false; connection_subrating_host_support_ = false; random_address_ = Address::kEmpty; - page_scan_enable_ = false; - inquiry_scan_enable_ = false; - inquiry_scan_interval_ = 0x1000; - inquiry_scan_window_ = 0x0012; - page_timeout_ = 0x2000; - connection_accept_timeout_ = 0x1FA0; - page_scan_interval_ = 0x0800; - page_scan_window_ = 0x0012; - voice_setting_ = 0x0060; - authentication_enable_ = AuthenticationEnable::NOT_REQUIRED; - default_link_policy_settings_ = 0x0000; - sco_flow_control_enable_ = false; - local_name_.fill(0); - extended_inquiry_response_.fill(0); - class_of_device_ = 0; - min_encryption_key_size_ = 16; event_mask_ = 0x00001fffffffffff; event_mask_page_2_ = 0x0; le_event_mask_ = 0x01f; le_suggested_max_tx_octets_ = 0x001b; le_suggested_max_tx_time_ = 0x0148; resolvable_private_address_timeout_ = std::chrono::seconds(0x0384); - page_scan_repetition_mode_ = PageScanRepetitionMode::R0; - connections_ = AclConnectionHandler(); - oob_id_ = 1; - key_id_ = 1; le_periodic_advertiser_list_.clear(); le_filter_accept_list_.clear(); le_resolving_list_.clear(); @@ -5771,295 +4458,44 @@ void LinkLayerController::Reset() { initiator_ = Initiator{}; synchronizing_ = {}; synchronized_ = {}; - last_inquiry_ = steady_clock::now(); - inquiry_mode_ = InquiryType::STANDARD; - inquiry_lap_ = 0; - inquiry_max_responses_ = 0; default_tx_phys_ = properties_.LeSupportedPhys(); default_rx_phys_ = properties_.LeSupportedPhys(); - bluetooth::hci::Lap general_iac; - general_iac.lap_ = 0x33; // 0x9E8B33 - current_iac_lap_list_.clear(); - current_iac_lap_list_.emplace_back(general_iac); - - page_ = {}; - - if (inquiry_timer_task_id_ != kInvalidTaskId) { - CancelScheduledTask(inquiry_timer_task_id_); - inquiry_timer_task_id_ = kInvalidTaskId; - } - - lm_.reset(link_manager_create(controller_ops_)); ll_.reset(link_layer_create(controller_ops_)); } -/// Drive the logic for the Page controller substate. -void LinkLayerController::Paging() { - auto now = std::chrono::steady_clock::now(); - - if (page_.has_value() && now >= page_->page_timeout) { - INFO("page timeout triggered for connection with {}", page_->bd_addr.ToString()); - - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode::PAGE_TIMEOUT, 0, page_->bd_addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); - - page_ = {}; +void LeController::CheckExpiringConnection(uint16_t handle) { + if (!connections_.HasAclHandle(handle)) { return; } - // Send a Page packet to the peer when a paging interval has passed. - // Paging is suppressed while a pending connection with the same peer is - // being established (i.e. two hosts initiated a connection simultaneously). - if (page_.has_value() && now >= page_->next_page_event && - !connections_.HasPendingConnection(page_->bd_addr)) { - SendLinkLayerPacket(model::packets::PageBuilder::Create( - GetAddress(), page_->bd_addr, class_of_device_, page_->allow_role_switch)); - page_->next_page_event = now + kPageInterval; - } -} + auto& connection = connections_.GetAclConnection(handle); -void LinkLayerController::StartInquiry(milliseconds timeout) { - inquiry_timer_task_id_ = - ScheduleTask(milliseconds(timeout), [this]() { LinkLayerController::InquiryTimeout(); }); -} - -void LinkLayerController::InquiryCancel() { - ASSERT(inquiry_timer_task_id_ != kInvalidTaskId); - CancelScheduledTask(inquiry_timer_task_id_); - inquiry_timer_task_id_ = kInvalidTaskId; -} - -void LinkLayerController::InquiryTimeout() { - if (inquiry_timer_task_id_ != kInvalidTaskId) { - inquiry_timer_task_id_ = kInvalidTaskId; - if (IsEventUnmasked(EventCode::INQUIRY_COMPLETE)) { - send_event_(bluetooth::hci::InquiryCompleteBuilder::Create(ErrorCode::SUCCESS)); - } - } -} - -void LinkLayerController::SetInquiryMode(uint8_t mode) { - inquiry_mode_ = static_cast(mode); -} - -void LinkLayerController::SetInquiryLAP(uint64_t lap) { inquiry_lap_ = lap; } - -void LinkLayerController::SetInquiryMaxResponses(uint8_t max) { inquiry_max_responses_ = max; } - -void LinkLayerController::Inquiry() { - steady_clock::time_point now = steady_clock::now(); - if (duration_cast(now - last_inquiry_) < milliseconds(2000)) { - return; - } - - SendLinkLayerPacket(model::packets::InquiryBuilder::Create(GetAddress(), Address::kEmpty, - inquiry_mode_, inquiry_lap_)); - last_inquiry_ = now; -} - -void LinkLayerController::SetInquiryScanEnable(bool enable) { inquiry_scan_enable_ = enable; } - -void LinkLayerController::SetPageScanEnable(bool enable) { page_scan_enable_ = enable; } - -void LinkLayerController::SetPageTimeout(uint16_t page_timeout) { page_timeout_ = page_timeout; } - -ErrorCode LinkLayerController::AddScoConnection(uint16_t connection_handle, uint16_t packet_type, - ScoDatapath datapath) { - if (!connections_.HasHandle(connection_handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - Address bd_addr = connections_.GetAddress(connection_handle).GetAddress(); - if (connections_.HasPendingScoConnection(bd_addr)) { - return ErrorCode::COMMAND_DISALLOWED; - } - - INFO(id_, "Creating SCO connection with {}", bd_addr); - - // Save connection parameters. - ScoConnectionParameters connection_parameters = { - 8000, - 8000, - 0xffff, - 0x60 /* 16bit CVSD */, - (uint8_t)bluetooth::hci::RetransmissionEffort::NO_RETRANSMISSION, - (uint16_t)((uint16_t)((packet_type >> 5) & 0x7U) | - (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_2_EV3_ALLOWED | - (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_3_EV3_ALLOWED | - (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_2_EV5_ALLOWED | - (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_3_EV5_ALLOWED)}; - connections_.CreateScoConnection(connections_.GetAddress(connection_handle).GetAddress(), - connection_parameters, SCO_STATE_PENDING, datapath, true); - - // Send SCO connection request to peer. - SendLinkLayerPacket(model::packets::ScoConnectionRequestBuilder::Create( - GetAddress(), bd_addr, connection_parameters.transmit_bandwidth, - connection_parameters.receive_bandwidth, connection_parameters.max_latency, - connection_parameters.voice_setting, connection_parameters.retransmission_effort, - connection_parameters.packet_type, class_of_device_)); - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::SetupSynchronousConnection( - uint16_t connection_handle, uint32_t transmit_bandwidth, uint32_t receive_bandwidth, - uint16_t max_latency, uint16_t voice_setting, uint8_t retransmission_effort, - uint16_t packet_types, ScoDatapath datapath) { - if (!connections_.HasHandle(connection_handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - - Address bd_addr = connections_.GetAddress(connection_handle).GetAddress(); - if (connections_.HasPendingScoConnection(bd_addr)) { - // This command may be used to modify an exising eSCO link. - // Skip for now. TODO: should return an event - // HCI_Synchronous_Connection_Changed on both sides. - return ErrorCode::COMMAND_DISALLOWED; - } - - INFO(id_, "Creating eSCO connection with {}", bd_addr); - - // Save connection parameters. - ScoConnectionParameters connection_parameters = {transmit_bandwidth, receive_bandwidth, - max_latency, voice_setting, - retransmission_effort, packet_types}; - connections_.CreateScoConnection(connections_.GetAddress(connection_handle).GetAddress(), - connection_parameters, SCO_STATE_PENDING, datapath); - - // Send eSCO connection request to peer. - SendLinkLayerPacket(model::packets::ScoConnectionRequestBuilder::Create( - GetAddress(), bd_addr, transmit_bandwidth, receive_bandwidth, max_latency, voice_setting, - retransmission_effort, packet_types, class_of_device_)); - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::AcceptSynchronousConnection( - Address bd_addr, uint32_t transmit_bandwidth, uint32_t receive_bandwidth, - uint16_t max_latency, uint16_t voice_setting, uint8_t retransmission_effort, - uint16_t packet_types) { - INFO(id_, "Accepting eSCO connection request from {}", bd_addr); - - if (!connections_.HasPendingScoConnection(bd_addr)) { - INFO(id_, "No pending eSCO connection for {}", bd_addr); - return ErrorCode::COMMAND_DISALLOWED; - } - - ErrorCode status = ErrorCode::SUCCESS; - uint16_t sco_handle = 0; - ScoLinkParameters link_parameters = {}; - ScoConnectionParameters connection_parameters = {transmit_bandwidth, receive_bandwidth, - max_latency, voice_setting, - retransmission_effort, packet_types}; - - if (!connections_.AcceptPendingScoConnection(bd_addr, connection_parameters, [this, bd_addr] { - return LinkLayerController::StartScoStream(bd_addr); - })) { - connections_.CancelPendingScoConnection(bd_addr); - status = ErrorCode::STATUS_UNKNOWN; // TODO: proper status code - } else { - sco_handle = connections_.GetScoHandle(bd_addr); - link_parameters = connections_.GetScoLinkParameters(bd_addr); - } - - // Send eSCO connection response to peer. - SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( - GetAddress(), bd_addr, (uint8_t)status, link_parameters.transmission_interval, - link_parameters.retransmission_window, link_parameters.rx_packet_length, - link_parameters.tx_packet_length, link_parameters.air_mode, link_parameters.extended)); - - // Schedule HCI Synchronous Connection Complete event. - ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr, link_parameters]() { - send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( - ErrorCode(status), sco_handle, bd_addr, - link_parameters.extended ? bluetooth::hci::ScoLinkType::ESCO - : bluetooth::hci::ScoLinkType::SCO, - link_parameters.extended ? link_parameters.transmission_interval : 0, - link_parameters.extended ? link_parameters.retransmission_window : 0, - link_parameters.extended ? link_parameters.rx_packet_length : 0, - link_parameters.extended ? link_parameters.tx_packet_length : 0, - bluetooth::hci::ScoAirMode(link_parameters.air_mode))); - }); - - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::RejectSynchronousConnection(Address bd_addr, uint16_t reason) { - INFO(id_, "Rejecting eSCO connection request from {}", bd_addr); - - if (reason == (uint8_t)ErrorCode::SUCCESS) { - reason = (uint8_t)ErrorCode::REMOTE_USER_TERMINATED_CONNECTION; - } - if (!connections_.HasPendingScoConnection(bd_addr)) { - return ErrorCode::COMMAND_DISALLOWED; - } - - connections_.CancelPendingScoConnection(bd_addr); - - // Send eSCO connection response to peer. - SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( - GetAddress(), bd_addr, reason, 0, 0, 0, 0, 0, 0)); - - // Schedule HCI Synchronous Connection Complete event. - ScheduleTask(kNoDelayMs, [this, reason, bd_addr]() { - send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( - ErrorCode(reason), 0, bd_addr, bluetooth::hci::ScoLinkType::ESCO, 0, 0, 0, 0, - bluetooth::hci::ScoAirMode::TRANSPARENT)); - }); - - return ErrorCode::SUCCESS; -} - -void LinkLayerController::CheckExpiringConnection(uint16_t handle) { - if (!connections_.HasHandle(handle)) { - return; - } - - if (connections_.HasLinkExpired(handle)) { + if (connection.HasExpired()) { Disconnect(handle, ErrorCode::CONNECTION_TIMEOUT, ErrorCode::CONNECTION_TIMEOUT); return; } - if (connections_.IsLinkNearExpiring(handle)) { - AddressWithType my_address = connections_.GetOwnAddress(handle); - AddressWithType destination = connections_.GetAddress(handle); - SendLinkLayerPacket(model::packets::PingRequestBuilder::Create(my_address.GetAddress(), - destination.GetAddress())); - ScheduleTask( - std::chrono::duration_cast(connections_.TimeUntilLinkExpired(handle)), - [this, handle] { CheckExpiringConnection(handle); }); + if (connection.IsNearExpiring()) { + SendLeLinkLayerPacket( + model::packets::PingRequestBuilder::Create(connection.own_address, connection.address)); + ScheduleTask(std::chrono::duration_cast(connection.TimeUntilExpired()), + [this, handle] { CheckExpiringConnection(handle); }); return; } - ScheduleTask( - std::chrono::duration_cast(connections_.TimeUntilLinkNearExpiring(handle)), - [this, handle] { CheckExpiringConnection(handle); }); + ScheduleTask(std::chrono::duration_cast(connection.TimeUntilNearExpiring()), + [this, handle] { CheckExpiringConnection(handle); }); } -void LinkLayerController::IncomingPingRequest(model::packets::LinkLayerPacketView incoming) { +void LeController::IncomingPingRequest(model::packets::LinkLayerPacketView incoming) { auto view = model::packets::PingRequestView::Create(incoming); ASSERT(view.IsValid()); - SendLinkLayerPacket(model::packets::PingResponseBuilder::Create(incoming.GetDestinationAddress(), - incoming.GetSourceAddress())); -} - -TaskId LinkLayerController::StartScoStream(Address address) { - auto sco_builder = - bluetooth::hci::ScoBuilder::Create(connections_.GetScoHandle(address), - PacketStatusFlag::CORRECTLY_RECEIVED, {0, 0, 0, 0, 0}); - - auto sco_bytes = sco_builder->SerializeToBytes(); - auto sco_view = bluetooth::hci::ScoView::Create( - pdl::packet::slice(std::make_shared>(std::move(sco_bytes)))); - ASSERT(sco_view.IsValid()); - - return SchedulePeriodicTask(0ms, 20ms, [this, address, sco_view]() { - INFO(id_, "SCO sending..."); - SendScoToRemote(sco_view); - }); + SendLeLinkLayerPacket(model::packets::PingResponseBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress())); } -TaskId LinkLayerController::NextTaskId() { +TaskId LeController::NextTaskId() { TaskId task_id = task_counter_++; while (task_id == kInvalidTaskId || std::any_of(task_queue_.begin(), task_queue_.end(), @@ -6069,23 +4505,22 @@ TaskId LinkLayerController::NextTaskId() { return task_id; } -TaskId LinkLayerController::ScheduleTask(std::chrono::milliseconds delay, - TaskCallback task_callback) { +TaskId LeController::ScheduleTask(std::chrono::milliseconds delay, TaskCallback task_callback) { TaskId task_id = NextTaskId(); task_queue_.emplace(std::chrono::steady_clock::now() + delay, std::move(task_callback), task_id); return task_id; } -TaskId LinkLayerController::SchedulePeriodicTask(std::chrono::milliseconds delay, - std::chrono::milliseconds period, - TaskCallback task_callback) { +TaskId LeController::SchedulePeriodicTask(std::chrono::milliseconds delay, + std::chrono::milliseconds period, + TaskCallback task_callback) { TaskId task_id = NextTaskId(); task_queue_.emplace(std::chrono::steady_clock::now() + delay, period, std::move(task_callback), task_id); return task_id; } -void LinkLayerController::CancelScheduledTask(TaskId task_id) { +void LeController::CancelScheduledTask(TaskId task_id) { auto it = task_queue_.cbegin(); for (; it != task_queue_.cend(); it++) { if (it->task_id == task_id) { @@ -6095,7 +4530,7 @@ void LinkLayerController::CancelScheduledTask(TaskId task_id) { } } -void LinkLayerController::RunPendingTasks() { +void LeController::RunPendingTasks() { std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); while (!task_queue_.empty()) { auto it = task_queue_.begin(); diff --git a/model/controller/link_layer_controller.h b/model/controller/le_controller.h similarity index 74% rename from model/controller/link_layer_controller.h rename to model/controller/le_controller.h index 91330a3..bedc7e3 100644 --- a/model/controller/link_layer_controller.h +++ b/model/controller/le_controller.h @@ -60,48 +60,25 @@ AddressWithType PeerDeviceAddress(Address address, PeerAddressType peer_address_ // address. AddressWithType PeerIdentityAddress(Address address, PeerAddressType peer_address_type); -class LinkLayerController { +class LeController { public: static constexpr size_t kIrkSize = 16; static constexpr size_t kLtkSize = 16; - static constexpr size_t kLocalNameSize = 248; - static constexpr size_t kExtendedInquiryResponseSize = 240; // Unique instance identifier. const uint32_t id_; // Generate a resolvable private address using the specified IRK. - static Address generate_rpa(std::array irk); + static Address generate_rpa(std::array irk); // Return true if the input IRK is all 0s. - static bool irk_is_zero(std::array irk); + static bool irk_is_zero(std::array irk); - LinkLayerController(const Address& address, const ControllerProperties& properties, - uint32_t id = 0); - ~LinkLayerController(); + LeController(const Address& address, const ControllerProperties& properties, uint32_t id = 0); + ~LeController(); - ErrorCode SendCommandToRemoteByAddress(OpCode opcode, pdl::packet::slice args, - const Address& own_address, const Address& peer_address); - ErrorCode SendLeCommandToRemoteByAddress(OpCode opcode, const Address& own_address, - const Address& peer_address); - ErrorCode SendCommandToRemoteByHandle(OpCode opcode, pdl::packet::slice args, uint16_t handle); - ErrorCode SendScoToRemote(bluetooth::hci::ScoView sco_packet); - - void ForwardToLm(bluetooth::hci::CommandView command); void ForwardToLl(bluetooth::hci::CommandView command); - std::vector const& ReadCurrentIacLap() const; - void WriteCurrentIacLap(std::vector iac_lap); - - ErrorCode AcceptConnectionRequest(const Address& addr, bool try_role_switch); - void MakePeripheralConnection(const Address& addr, bool try_role_switch); - ErrorCode RejectConnectionRequest(const Address& addr, uint8_t reason); - void RejectPeripheralConnection(const Address& addr, uint8_t reason); - - // HCI command Create Connection (Vol 4, Part E § 7.1.5). - ErrorCode CreateConnection(const Address& bd_addr, uint16_t packet_type, uint8_t page_scan_mode, - uint16_t clock_offset, uint8_t allow_role_switch); - // HCI command Disconnect (Vol 4, Part E § 7.1.6). // \p host_reason is taken from the Disconnect command, and sent over // to the remote as disconnect error. \p controller_reason is the code @@ -110,8 +87,8 @@ class LinkLayerController { uint16_t handle, ErrorCode host_reason, ErrorCode controller_reason = ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST); - // HCI command Create Connection Cancel (Vol 4, Part E § 7.1.7). - ErrorCode CreateConnectionCancel(const Address& bd_addr); + // HCI command Read Remote Version Information (Vol 4, Part E § 7.1.23). + ErrorCode ReadRemoteVersionInformation(uint16_t connection_handle); // Internal task scheduler. // This scheduler is driven by the tick function only, @@ -146,9 +123,12 @@ class LinkLayerController { void IncomingPacket(model::packets::LinkLayerPacketView incoming, int8_t rssi); void Tick(); - void Close(); + /// Send disconnection events for all connected links, with the provided + /// reason. Does not remove the local connection contexts. + void DisconnectAll(ErrorCode reason); + // Set the callbacks for sending packets to the HCI. void RegisterEventChannel( const std::function)>& send_event); @@ -156,9 +136,6 @@ class LinkLayerController { void RegisterAclChannel( const std::function)>& send_acl); - void RegisterScoChannel( - const std::function)>& send_sco); - void RegisterIsoChannel( const std::function)>& send_iso); @@ -168,7 +145,8 @@ class LinkLayerController { void Reset(); - void Paging(); + void CheckExpiringConnection(uint16_t handle); + void LeAdvertising(); void LeScanning(); void LeSynchronization(); @@ -184,9 +162,10 @@ class LinkLayerController { uint16_t maximum_ce_length); ErrorCode LeRemoteConnectionParameterRequestNegativeReply(uint16_t connection_handle, bluetooth::hci::ErrorCode reason); - uint16_t HandleLeConnection(AddressWithType addr, AddressWithType own_addr, - bluetooth::hci::Role role, uint16_t connection_interval, - uint16_t connection_latency, uint16_t supervision_timeout, + uint16_t HandleLeConnection(AddressWithType addr, AddressWithType resolved_addr, + AddressWithType own_addr, bluetooth::hci::Role role, + uint16_t connection_interval, uint16_t connection_latency, + uint16_t supervision_timeout, bool send_le_channel_selection_algorithm_event); bool ResolvingListBusy(); @@ -252,75 +231,17 @@ class LinkLayerController { uint8_t LeReadNumberOfSupportedAdvertisingSets(); - // Classic - void StartInquiry(std::chrono::milliseconds timeout); - void InquiryCancel(); - void InquiryTimeout(); - void SetInquiryMode(uint8_t mode); - void SetInquiryLAP(uint64_t lap); - void SetInquiryMaxResponses(uint8_t max); - void Inquiry(); - - bool GetInquiryScanEnable() const { return inquiry_scan_enable_; } - void SetInquiryScanEnable(bool enable); - - bool GetPageScanEnable() const { return page_scan_enable_; } - void SetPageScanEnable(bool enable); - - uint16_t GetPageTimeout() const { return page_timeout_; } - void SetPageTimeout(uint16_t page_timeout); - - ErrorCode ChangeConnectionPacketType(uint16_t handle, uint16_t types); - ErrorCode ChangeConnectionLinkKey(uint16_t handle); - ErrorCode CentralLinkKey(uint8_t key_flag); - ErrorCode HoldMode(uint16_t handle, uint16_t hold_mode_max_interval, - uint16_t hold_mode_min_interval); - ErrorCode SniffMode(uint16_t handle, uint16_t sniff_max_interval, uint16_t sniff_min_interval, - uint16_t sniff_attempt, uint16_t sniff_timeout); - ErrorCode ExitSniffMode(uint16_t handle); - ErrorCode QosSetup(uint16_t handle, uint8_t service_type, uint32_t token_rate, - uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation); - ErrorCode RoleDiscovery(uint16_t handle, bluetooth::hci::Role* role); - ErrorCode SwitchRole(Address bd_addr, bluetooth::hci::Role role); - ErrorCode ReadLinkPolicySettings(uint16_t handle, uint16_t* settings); - ErrorCode WriteLinkPolicySettings(uint16_t handle, uint16_t settings); - ErrorCode FlowSpecification(uint16_t handle, uint8_t flow_direction, uint8_t service_type, - uint32_t token_rate, uint32_t token_bucket_size, - uint32_t peak_bandwidth, uint32_t access_latency); - ErrorCode WriteLinkSupervisionTimeout(uint16_t handle, uint16_t timeout); - ErrorCode WriteDefaultLinkPolicySettings(uint16_t settings); - void CheckExpiringConnection(uint16_t handle); - uint16_t ReadDefaultLinkPolicySettings() const; - - void ReadLocalOobData(); - void ReadLocalOobExtendedData(); - - ErrorCode AddScoConnection(uint16_t connection_handle, uint16_t packet_type, - ScoDatapath datapath); - ErrorCode SetupSynchronousConnection(uint16_t connection_handle, uint32_t transmit_bandwidth, - uint32_t receive_bandwidth, uint16_t max_latency, - uint16_t voice_setting, uint8_t retransmission_effort, - uint16_t packet_types, ScoDatapath datapath); - ErrorCode AcceptSynchronousConnection(Address bd_addr, uint32_t transmit_bandwidth, - uint32_t receive_bandwidth, uint16_t max_latency, - uint16_t voice_setting, uint8_t retransmission_effort, - uint16_t packet_types); - ErrorCode RejectSynchronousConnection(Address bd_addr, uint16_t reason); - - // Returns true if any ACL connection exists. - bool HasAclConnection(); // Returns true if the specified ACL connection handle is valid. - bool HasAclConnection(uint16_t connection_handle); + bool HasLeAclConnection(uint16_t connection_handle); void HandleAcl(bluetooth::hci::AclView acl); void HandleIso(bluetooth::hci::IsoView iso); - // BR/EDR Commands - // HCI Read Rssi command (Vol 4, Part E § 7.5.4). ErrorCode ReadRssi(uint16_t connection_handle, int8_t* rssi); - // LE Commands + // HCI LE Read Remote Features (Vol 4, Part E § 7.8.21). + ErrorCode LeReadRemoteFeaturesPage0(uint16_t connection_handle); // HCI LE Set Random Address command (Vol 4, Part E § 7.8.4). ErrorCode LeSetRandomAddress(Address random_address); @@ -600,19 +521,13 @@ class LinkLayerController { uint8_t* apcf_available_spaces); protected: - void SendLinkLayerPacket(std::unique_ptr packet, - int8_t tx_power = 0); void SendLeLinkLayerPacket(std::unique_ptr packet, int8_t tx_power = 0); - void IncomingAclPacket(model::packets::LinkLayerPacketView incoming, int8_t rssi); - void IncomingScoPacket(model::packets::LinkLayerPacketView incoming); - void IncomingDisconnectPacket(model::packets::LinkLayerPacketView incoming); - void IncomingEncryptConnection(model::packets::LinkLayerPacketView incoming); - void IncomingEncryptConnectionResponse(model::packets::LinkLayerPacketView incoming); - void IncomingInquiryPacket(model::packets::LinkLayerPacketView incoming, uint8_t rssi); - void IncomingInquiryResponsePacket(model::packets::LinkLayerPacketView incoming); - void IncomingLmpPacket(model::packets::LinkLayerPacketView incoming); + void IncomingLeAclPacket(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming, int8_t rssi); + void IncomingLeDisconnectPacket(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming); void IncomingLlcpPacket(model::packets::LinkLayerPacketView incoming); void IncomingLeConnectedIsochronousPdu(model::packets::LinkLayerPacketView incoming); @@ -629,12 +544,18 @@ class LinkLayerController { void IncomingLeConnectPacket(model::packets::LinkLayerPacketView incoming); void IncomingLeConnectCompletePacket(model::packets::LinkLayerPacketView incoming); - void IncomingLeConnectionParameterRequest(model::packets::LinkLayerPacketView incoming); - void IncomingLeConnectionParameterUpdate(model::packets::LinkLayerPacketView incoming); - void IncomingLeEncryptConnection(model::packets::LinkLayerPacketView incoming); - void IncomingLeEncryptConnectionResponse(model::packets::LinkLayerPacketView incoming); - void IncomingLeReadRemoteFeatures(model::packets::LinkLayerPacketView incoming); - void IncomingLeReadRemoteFeaturesResponse(model::packets::LinkLayerPacketView incoming); + void IncomingLeConnectionParameterRequest(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming); + void IncomingLeConnectionParameterUpdate(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming); + void IncomingLeEncryptConnection(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming); + void IncomingLeEncryptConnectionResponse(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming); + void IncomingLeReadRemoteFeatures(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming); + void IncomingLeReadRemoteFeaturesResponse(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming); void ProcessIncomingLegacyScanRequest(AddressWithType scanning_address, AddressWithType resolved_scanning_address, @@ -651,91 +572,25 @@ class LinkLayerController { void IncomingLeScanPacket(model::packets::LinkLayerPacketView incoming); void IncomingLeScanResponsePacket(model::packets::LinkLayerPacketView incoming, uint8_t rssi); - void IncomingPagePacket(model::packets::LinkLayerPacketView incoming); - void IncomingPageRejectPacket(model::packets::LinkLayerPacketView incoming); - void IncomingPageResponsePacket(model::packets::LinkLayerPacketView incoming); - void IncomingReadRemoteLmpFeatures(model::packets::LinkLayerPacketView incoming); - void IncomingReadRemoteLmpFeaturesResponse(model::packets::LinkLayerPacketView incoming); - void IncomingReadRemoteSupportedFeatures(model::packets::LinkLayerPacketView incoming); - void IncomingReadRemoteSupportedFeaturesResponse(model::packets::LinkLayerPacketView incoming); - void IncomingReadRemoteExtendedFeatures(model::packets::LinkLayerPacketView incoming); - void IncomingReadRemoteExtendedFeaturesResponse(model::packets::LinkLayerPacketView incoming); void IncomingReadRemoteVersion(model::packets::LinkLayerPacketView incoming); void IncomingReadRemoteVersionResponse(model::packets::LinkLayerPacketView incoming); - void IncomingReadClockOffset(model::packets::LinkLayerPacketView incoming); - void IncomingReadClockOffsetResponse(model::packets::LinkLayerPacketView incoming); - void IncomingRemoteNameRequest(model::packets::LinkLayerPacketView incoming); - void IncomingRemoteNameRequestResponse(model::packets::LinkLayerPacketView incoming); - - void IncomingScoConnectionRequest(model::packets::LinkLayerPacketView incoming); - void IncomingScoConnectionResponse(model::packets::LinkLayerPacketView incoming); - void IncomingScoDisconnect(model::packets::LinkLayerPacketView incoming); void IncomingPingRequest(model::packets::LinkLayerPacketView incoming); - void IncomingRoleSwitchRequest(model::packets::LinkLayerPacketView incoming); - void IncomingRoleSwitchResponse(model::packets::LinkLayerPacketView incoming); - void IncomingLlPhyReq(model::packets::LinkLayerPacketView incoming); - void IncomingLlPhyRsp(model::packets::LinkLayerPacketView incoming); - void IncomingLlPhyUpdateInd(model::packets::LinkLayerPacketView incoming); + void IncomingLlPhyReq(LeAclConnection& connection, model::packets::LinkLayerPacketView incoming); + void IncomingLlPhyRsp(LeAclConnection& connection, model::packets::LinkLayerPacketView incoming); + void IncomingLlPhyUpdateInd(LeAclConnection& connection, + model::packets::LinkLayerPacketView incoming); public: bool IsEventUnmasked(bluetooth::hci::EventCode event) const; bool IsLeEventUnmasked(bluetooth::hci::SubeventCode subevent) const; - // TODO - // The Clock Offset should be specific to an ACL connection. - // Returning a proper value is not that important. - // NOLINTNEXTLINE(readability-convert-member-functions-to-static) - uint32_t GetClockOffset() const { return 0; } - - // TODO - // The Page Scan Repetition Mode should be specific to an ACL connection or - // a paging session. - PageScanRepetitionMode GetPageScanRepetitionMode() const { return page_scan_repetition_mode_; } - - // TODO - // The Encryption Key Size should be specific to an ACL connection. - uint8_t GetEncryptionKeySize() const { return 16; } - void SetMinEncryptionKeySize(uint8_t min_encryption_key_size) { - min_encryption_key_size_ = min_encryption_key_size; - } - - bool GetScoFlowControlEnable() const { return sco_flow_control_enable_; } - - AuthenticationEnable GetAuthenticationEnable() { return authentication_enable_; } - - std::array const& GetLocalName() { return local_name_; } - uint64_t GetLeSupportedFeatures() const { return properties_.le_features | le_host_supported_features_; } - uint16_t GetConnectionAcceptTimeout() const { return connection_accept_timeout_; } - - uint16_t GetVoiceSetting() const { return voice_setting_; } - uint32_t GetClassOfDevice() const { return class_of_device_; } - - uint8_t GetMaxLmpFeaturesPageNumber() { return properties_.lmp_features.size() - 1; } - - uint64_t GetLmpFeatures(uint8_t page_number = 0) { - return page_number == 1 ? host_supported_features_ : properties_.lmp_features[page_number]; - } - - void SetLocalName(std::vector const& local_name); - void SetLocalName(std::array const& local_name); - - void SetExtendedInquiryResponse(std::array const& extended_inquiry_response); - void SetExtendedInquiryResponse(std::vector const& extended_inquiry_response); - - void SetClassOfDevice(uint32_t class_of_device) { class_of_device_ = class_of_device; } - - void SetAuthenticationEnable(AuthenticationEnable enable) { authentication_enable_ = enable; } - - void SetScoFlowControlEnable(bool enable) { sco_flow_control_enable_ = enable; } - void SetVoiceSetting(uint16_t voice_setting) { voice_setting_ = voice_setting; } void SetEventMask(uint64_t event_mask) { event_mask_ = event_mask; } - void SetEventMaskPage2(uint64_t event_mask) { event_mask_page_2_ = event_mask; } void SetLeEventMask(uint64_t le_event_mask) { le_event_mask_ = le_event_mask; } @@ -743,8 +598,6 @@ class LinkLayerController { void SetSecureSimplePairingSupport(bool enable); void SetSecureConnectionsSupport(bool enable); - void SetConnectionAcceptTimeout(uint16_t timeout) { connection_accept_timeout_ = timeout; } - bool LegacyAdvertising() const { return legacy_advertising_in_use_; } bool ExtendedAdvertising() const { return extended_advertising_in_use_; } @@ -772,8 +625,6 @@ class LinkLayerController { } void SetLeSuggestedMaxTxTime(uint16_t max_tx_time) { le_suggested_max_tx_time_ = max_tx_time; } - TaskId StartScoStream(Address address); - private: const Address& address_; const ControllerProperties& properties_; @@ -799,55 +650,6 @@ class LinkLayerController { // Provide the current HCI Configuration Parameters as defined in section // Vol 4, Part E § 6 of the core specification. - // Scan Enable (Vol 4, Part E § 6.1). - bool page_scan_enable_{false}; - bool inquiry_scan_enable_{false}; - - // Inquiry Scan Interval and Window - // (Vol 4, Part E § 6.2, 6.3). - uint16_t inquiry_scan_interval_{0x1000}; - uint16_t inquiry_scan_window_{0x0012}; - - // Page Timeout (Vol 4, Part E § 6.6). - uint16_t page_timeout_{0x2000}; - - // Connection Accept Timeout (Vol 4, Part E § 6.7). - uint16_t connection_accept_timeout_{0x1FA0}; - - // Page Scan Interval and Window - // (Vol 4, Part E § 6.8, 6.9). - uint16_t page_scan_interval_{0x0800}; - uint16_t page_scan_window_{0x0012}; - - // Voice Setting (Vol 4, Part E § 6.12). - uint16_t voice_setting_{0x0060}; - - // Authentication Enable (Vol 4, Part E § 6.16). - AuthenticationEnable authentication_enable_{AuthenticationEnable::NOT_REQUIRED}; - - // Default Link Policy Settings (Vol 4, Part E § 6.18). - uint8_t default_link_policy_settings_{0x0000}; - - // Synchronous Flow Control Enable (Vol 4, Part E § 6.22). - bool sco_flow_control_enable_{false}; - - // Local Name (Vol 4, Part E § 6.23). - std::array local_name_{}; - - // Extended Inquiry Response (Vol 4, Part E § 6.24). - std::array extended_inquiry_response_{}; - - // Class of Device (Vol 4, Part E § 6.26). - uint32_t class_of_device_{0}; - - // Other configuration parameters. - - // Current IAC LAP (Vol 4, Part E § 7.3.44). - std::vector current_iac_lap_list_{}; - - // Min Encryption Key Size (Vol 4, Part E § 7.3.102). - uint8_t min_encryption_key_size_{16}; - // Event Mask (Vol 4, Part E § 7.3.1) and // Event Mask Page 2 (Vol 4, Part E § 7.3.69) and // LE Event Mask (Vol 4, Part E § 7.8.1). @@ -862,16 +664,11 @@ class LinkLayerController { // Resolvable Private Address Timeout (Vol 4, Part E § 7.8.45). std::chrono::seconds resolvable_private_address_timeout_{0x0384}; - // Page Scan Repetition Mode (Vol 2 Part B § 8.3.1 Page Scan substate). - // The Page Scan Repetition Mode depends on the selected Page Scan Interval. - PageScanRepetitionMode page_scan_repetition_mode_{PageScanRepetitionMode::R0}; - AclConnectionHandler connections_; // Callbacks to send packets back to the HCI. std::function)> send_acl_; std::function)> send_event_; - std::function)> send_sco_; std::function)> send_iso_; // Callback to send packets to remote devices. @@ -879,9 +676,6 @@ class LinkLayerController { int8_t tx_power)> send_to_remote_; - uint32_t oob_id_{1}; - uint32_t key_id_{1}; - struct FilterAcceptListEntry { FilterAcceptListAddressType address_type; Address address; @@ -1057,28 +851,9 @@ class LinkLayerController { std::vector iso_sdu_{}; // Rust state. - std::unique_ptr lm_; std::unique_ptr ll_; struct ControllerOps controller_ops_; - // Classic state. - struct Page { - Address bd_addr; - uint8_t allow_role_switch; - std::chrono::steady_clock::time_point next_page_event{}; - std::chrono::steady_clock::time_point page_timeout{}; - }; - - // Page substate. - // RootCanal will allow only one page request running at the same time. - std::optional page_; - - std::chrono::steady_clock::time_point last_inquiry_; - model::packets::InquiryType inquiry_mode_{model::packets::InquiryType::STANDARD}; - TaskId inquiry_timer_task_id_ = kInvalidTaskId; - uint64_t inquiry_lap_{}; - uint8_t inquiry_max_responses_{}; - public: // Type of scheduled tasks. class Task { diff --git a/model/controller/vendor_commands/le_apcf.cc b/model/controller/vendor_commands/le_apcf.cc index e4a774e..3aefe1a 100644 --- a/model/controller/vendor_commands/le_apcf.cc +++ b/model/controller/vendor_commands/le_apcf.cc @@ -20,7 +20,7 @@ #include #include "log.h" -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "packets/hci_packets.h" #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -136,12 +136,12 @@ namespace rootcanal { using bluetooth::hci::ApcfAction; -ErrorCode LinkLayerController::LeApcfEnable(bool apcf_enable) { +ErrorCode LeController::LeApcfEnable(bool apcf_enable) { apcf_scanner_.enable = apcf_enable; return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::LeApcfAddFilteringParameters( +ErrorCode LeController::LeApcfAddFilteringParameters( uint8_t apcf_filter_index, uint16_t apcf_feature_selection, uint16_t apcf_list_logic_type, uint8_t apcf_filter_logic_type, uint8_t rssi_high_thresh, bluetooth::hci::DeliveryMode delivery_mode, uint16_t onfound_timeout, @@ -177,8 +177,8 @@ ErrorCode LinkLayerController::LeApcfAddFilteringParameters( return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::LeApcfDeleteFilteringParameters(uint8_t apcf_filter_index, - uint8_t* apcf_available_spaces) { +ErrorCode LeController::LeApcfDeleteFilteringParameters(uint8_t apcf_filter_index, + uint8_t* apcf_available_spaces) { *apcf_available_spaces = properties_.le_apcf_filter_list_size - apcf_scanner_.filters.size(); if (!apcf_scanner_.HasFilterIndex(apcf_filter_index)) { @@ -196,13 +196,13 @@ ErrorCode LinkLayerController::LeApcfDeleteFilteringParameters(uint8_t apcf_filt return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::LeApcfClearFilteringParameters(uint8_t* apcf_available_spaces) { +ErrorCode LeController::LeApcfClearFilteringParameters(uint8_t* apcf_available_spaces) { apcf_scanner_.Clear(); *apcf_available_spaces = properties_.le_apcf_filter_list_size; return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::LeApcfBroadcasterAddress( +ErrorCode LeController::LeApcfBroadcasterAddress( ApcfAction apcf_action, uint8_t apcf_filter_index, bluetooth::hci::Address apcf_broadcaster_address, bluetooth::hci::ApcfApplicationAddressType apcf_application_address_type, @@ -222,9 +222,9 @@ ErrorCode LinkLayerController::LeApcfBroadcasterAddress( return status; } -ErrorCode LinkLayerController::LeApcfServiceUuid(ApcfAction apcf_action, uint8_t apcf_filter_index, - std::vector apcf_uuid_data, - uint8_t* apcf_available_spaces) { +ErrorCode LeController::LeApcfServiceUuid(ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_uuid_data, + uint8_t* apcf_available_spaces) { size_t uuid_data_size = apcf_uuid_data.size() / 2; std::vector uuid_data(std::begin(apcf_uuid_data), std::begin(apcf_uuid_data) + uuid_data_size); @@ -246,10 +246,10 @@ ErrorCode LinkLayerController::LeApcfServiceUuid(ApcfAction apcf_action, uint8_t return status; } -ErrorCode LinkLayerController::LeApcfServiceSolicitationUuid(ApcfAction apcf_action, - uint8_t apcf_filter_index, - std::vector apcf_uuid_data, - uint8_t* apcf_available_spaces) { +ErrorCode LeController::LeApcfServiceSolicitationUuid(ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector apcf_uuid_data, + uint8_t* apcf_available_spaces) { size_t uuid_data_size = apcf_uuid_data.size() / 2; std::vector uuid_data(std::begin(apcf_uuid_data), std::begin(apcf_uuid_data) + uuid_data_size); @@ -271,9 +271,9 @@ ErrorCode LinkLayerController::LeApcfServiceSolicitationUuid(ApcfAction apcf_act return status; } -ErrorCode LinkLayerController::LeApcfLocalName(ApcfAction apcf_action, uint8_t apcf_filter_index, - std::vector apcf_local_name, - uint8_t* apcf_available_spaces) { +ErrorCode LeController::LeApcfLocalName(ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_local_name, + uint8_t* apcf_available_spaces) { size_t local_name_size = apcf_local_name.size() / 2; std::vector local_name(std::begin(apcf_local_name), std::begin(apcf_local_name) + local_name_size); @@ -295,10 +295,9 @@ ErrorCode LinkLayerController::LeApcfLocalName(ApcfAction apcf_action, uint8_t a return status; } -ErrorCode LinkLayerController::LeApcfManufacturerData(ApcfAction apcf_action, - uint8_t apcf_filter_index, - std::vector apcf_manufacturer_data, - uint8_t* apcf_available_spaces) { +ErrorCode LeController::LeApcfManufacturerData(ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_manufacturer_data, + uint8_t* apcf_available_spaces) { size_t manufacturer_data_size = apcf_manufacturer_data.size() / 2; std::vector manufacturer_data( std::begin(apcf_manufacturer_data), @@ -322,9 +321,9 @@ ErrorCode LinkLayerController::LeApcfManufacturerData(ApcfAction apcf_action, return status; } -ErrorCode LinkLayerController::LeApcfServiceData(ApcfAction apcf_action, uint8_t apcf_filter_index, - std::vector apcf_service_data, - uint8_t* apcf_available_spaces) { +ErrorCode LeController::LeApcfServiceData(ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_service_data, + uint8_t* apcf_available_spaces) { size_t service_data_size = apcf_service_data.size() / 2; std::vector service_data(std::begin(apcf_service_data), std::begin(apcf_service_data) + service_data_size); @@ -346,11 +345,10 @@ ErrorCode LinkLayerController::LeApcfServiceData(ApcfAction apcf_action, uint8_t return status; } -ErrorCode LinkLayerController::LeApcfAdTypeFilter(ApcfAction apcf_action, uint8_t apcf_filter_index, - uint8_t apcf_ad_type, - std::vector apcf_ad_data, - std::vector apcf_ad_data_mask, - uint8_t* apcf_available_spaces) { +ErrorCode LeController::LeApcfAdTypeFilter(ApcfAction apcf_action, uint8_t apcf_filter_index, + uint8_t apcf_ad_type, std::vector apcf_ad_data, + std::vector apcf_ad_data_mask, + uint8_t* apcf_available_spaces) { ErrorCode status = apcf_scanner_.UpdateFilterList( apcf_scanner_.ad_type_filters, properties_.le_apcf_ad_type_filter_list_size, apcf_action, rootcanal::apcf::AdTypeFilter{ diff --git a/model/devices/hci_device.cc b/model/devices/hci_device.cc index 5597fd0..e2cf6e2 100644 --- a/model/devices/hci_device.cc +++ b/model/devices/hci_device.cc @@ -31,7 +31,7 @@ namespace rootcanal { HciDevice::HciDevice(std::shared_ptr transport, ControllerProperties const& properties) : DualModeController(ControllerProperties(properties)), transport_(transport) { - link_layer_controller_.SetLocalName(std::vector({ + bredr_controller_.SetLocalName(std::vector({ 'g', 'D', 'e', @@ -44,7 +44,7 @@ HciDevice::HciDevice(std::shared_ptr transport, 'C', 'I', })); - link_layer_controller_.SetExtendedInquiryResponse(std::vector({ + bredr_controller_.SetExtendedInquiryResponse(std::vector({ 12, // Length 9, // Type: Device Name 'g', diff --git a/packets/BUILD b/packets/BUILD index 58285d6..2b03dae 100644 --- a/packets/BUILD +++ b/packets/BUILD @@ -14,9 +14,9 @@ genrule( genrule( name = "bredr_bb_packets_json", - cmd = "pdlc $(location bredr_bb.pdl) > $(location bredr_bb_packets.json)", + cmd = "pdlc $(location bredr_bb_packets.pdl) > $(location bredr_bb_packets.json)", outs = ["bredr_bb_packets.json"], - srcs = ["bredr_bb.pdl"], + srcs = ["bredr_bb_packets.pdl"], ) genrule( diff --git a/packets/bredr_bb.pdl b/packets/bredr_bb_packets.pdl similarity index 100% rename from packets/bredr_bb.pdl rename to packets/bredr_bb_packets.pdl diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 2acf506..526ad5b 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -29,7 +29,6 @@ num-derive = "0.3.3" num-integer = "0.1.45" num-traits = "0.2.14" paste = "1.0.4" -pdl-derive = "0.4.2" pdl-runtime = "0.4.2" pin-utils = "0.1.0" rand = "0.8.3" diff --git a/rust/build.rs b/rust/build.rs index 72236db..fce18a9 100644 --- a/rust/build.rs +++ b/rust/build.rs @@ -42,5 +42,7 @@ fn generate_module(in_file: &Path) { .expect("PDL parse failed"); let analyzed_file = pdl_compiler::analyzer::analyze(&parsed_file).expect("PDL analysis failed"); let rust_source = pdl_compiler::backends::rust::generate(&sources, &analyzed_file, &[]); - out_file.write_all(rust_source.as_bytes()).expect("Could not write to output file"); + out_file + .write_all(rust_source.as_bytes()) + .expect("Could not write to output file"); } diff --git a/test/LL/CIS/PER/BV_01_C.py b/test/LL/CIS/PER/BV_01_C.py index 69e3be0..8da4475 100644 --- a/test/LL/CIS/PER/BV_01_C.py +++ b/test/LL/CIS/PER/BV_01_C.py @@ -177,7 +177,8 @@ async def test(self): # 10. The Lower Tester sends data packets to the IUT. iso_sdu = [random.randint(1, 251) for n in range(self.Max_SDU_C_TO_P)] controller.send_ll( - ll.LeConnectedIsochronousPdu(source_address=controller.address, + ll.LeConnectedIsochronousPdu(source_address=peer_address, + destination_address=controller.address, cig_id=cig_id, cis_id=cis_id, sequence_number=42, diff --git a/test/LL/CON_/CEN/BV_41_C.py b/test/LL/CON_/CEN/BV_41_C.py index dc7c541..cb1486c 100644 --- a/test/LL/CON_/CEN/BV_41_C.py +++ b/test/LL/CON_/CEN/BV_41_C.py @@ -36,7 +36,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') # Prelude: Establish an ACL connection as central with the IUT. @@ -89,10 +89,10 @@ async def test(self): conn_peripheral_latency=0x6, conn_supervision_timeout=0xc80)) - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, role=hci.Role.CENTRAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, @@ -101,6 +101,8 @@ async def test(self): supervision_timeout=0xc80, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + acl_connection_handle = evt.connection_handle + await self.expect_evt( hci.LeChannelSelectionAlgorithm( connection_handle=acl_connection_handle, diff --git a/test/LL/CON_/CEN/BV_43_C.py b/test/LL/CON_/CEN/BV_43_C.py index c875286..8898dfe 100644 --- a/test/LL/CON_/CEN/BV_43_C.py +++ b/test/LL/CON_/CEN/BV_43_C.py @@ -33,7 +33,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') # Prelude: Establish an ACL connection as central with the IUT. @@ -86,10 +86,10 @@ async def test(self): conn_peripheral_latency=0x6, conn_supervision_timeout=0xc80)) - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, role=hci.Role.CENTRAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, @@ -98,6 +98,8 @@ async def test(self): supervision_timeout=0xc80, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + acl_connection_handle = evt.connection_handle + await self.expect_evt( hci.LeChannelSelectionAlgorithm( connection_handle=acl_connection_handle, diff --git a/test/LL/CON_/PER/BV_40_C.py b/test/LL/CON_/PER/BV_40_C.py index c29c6dd..8ca1fba 100644 --- a/test/LL/CON_/PER/BV_40_C.py +++ b/test/LL/CON_/PER/BV_40_C.py @@ -36,7 +36,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') # Prelude: Establish an ACL connection as central with the IUT. @@ -74,10 +74,10 @@ async def test(self): conn_peripheral_latency=0x200, conn_supervision_timeout=0x200)) - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, @@ -86,6 +86,8 @@ async def test(self): supervision_timeout=0x200, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + acl_connection_handle = evt.connection_handle + test_rounds = [ TestRound(0x00, 0x01, 0x03, 0x02, 0x00), TestRound(0x00, 0x02, 0x05, 0x01, 0x02), diff --git a/test/LL/CON_/PER/BV_42_C.py b/test/LL/CON_/PER/BV_42_C.py index 6b76726..95b9aaa 100644 --- a/test/LL/CON_/PER/BV_42_C.py +++ b/test/LL/CON_/PER/BV_42_C.py @@ -36,7 +36,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') # Prelude: Establish an ACL connection as central with the IUT. @@ -74,10 +74,10 @@ async def test(self): conn_peripheral_latency=0x200, conn_supervision_timeout=0x200)) - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, @@ -86,6 +86,8 @@ async def test(self): supervision_timeout=0x200, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + acl_connection_handle = evt.connection_handle + # 1. Upper Tester sends an HCI_LE_Set_PHY command to the IUT with the ALL_PHYS fields set to a # value of 0x03. Upper Tester receives an HCI_Command_Status event indicating success in # response. diff --git a/test/LL/DDI/ADV/BV_06_C.py b/test/LL/DDI/ADV/BV_06_C.py index 17aa480..6998467 100644 --- a/test/LL/DDI/ADV/BV_06_C.py +++ b/test/LL/DDI/ADV/BV_06_C.py @@ -38,7 +38,7 @@ async def test(self): controller.address.address[2], controller.address.address[3], controller.address.address[4], controller.address.address[5] ]) - connection_handle = 0xefe + connection_handle = None # 1. Upper Tester enables undirected advertising in the IUT using all supported advertising channels # and a selected advertising interval between the minimum and maximum advertising intervals. @@ -94,10 +94,10 @@ async def test(self): # 6. Upper Tester receives an HCI_LE_Connection_Complete event from the IUT including the # parameters sent to the IUT in step 4. - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=connection_handle, + connection_handle=self.Any, role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, @@ -106,6 +106,8 @@ async def test(self): supervision_timeout=LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + connection_handle = evt.connection_handle + # 7. The Upper Tester sends an HCI_Disconnect command to the IUT with the Connection_Handle # and receives a successful HCI_Command_Status event in return. controller.send_cmd( diff --git a/test/LL/DDI/ADV/BV_07_C.py b/test/LL/DDI/ADV/BV_07_C.py index df2a52a..0c7d498 100644 --- a/test/LL/DDI/ADV/BV_07_C.py +++ b/test/LL/DDI/ADV/BV_07_C.py @@ -33,7 +33,7 @@ async def test(self): LL_advertiser_Adv_Channel_Map = 0x7 controller = self.controller peer_address = Address('aa:bb:cc:dd:ee:ff') - connection_handle = 0xefe + connection_handle = None # 1. Upper Tester enables undirected advertising in the IUT using all supported advertising channels, # a selected advertising interval between the minimum and maximum advertising intervals, and @@ -124,10 +124,10 @@ async def test(self): # 9. Upper Tester receives an HCI_LE_Connection_Complete event from the IUT including the # parameters sent to the IUT. - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=connection_handle, + connection_handle=self.Any, role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, @@ -136,5 +136,7 @@ async def test(self): supervision_timeout=LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + connection_handle = evt.connection_handle + # 10. Peripheral Connection Terminated (connection interval, Peripheral latency, timeout, channel map, # un-encrypted, connection handle from step 9). diff --git a/test/LL/DDI/ADV/BV_09_C.py b/test/LL/DDI/ADV/BV_09_C.py index 34e15a2..f82aff4 100644 --- a/test/LL/DDI/ADV/BV_09_C.py +++ b/test/LL/DDI/ADV/BV_09_C.py @@ -84,8 +84,7 @@ async def test(self): # 3. Lower Tester address type is set to Public Address type. await self.steps_4_14(peer_address=public_peer_address, - peer_address_type=ll.AddressType.PUBLIC, - connection_handle=0xefe) + peer_address_type=ll.AddressType.PUBLIC) # 15. Upper Tester enables undirected advertising in the IUT using public address type, all supported # advertising channels and filtering policy set to ‘Allow Scan Request from Filter Accept List, Allow @@ -98,8 +97,7 @@ async def test(self): # 16. Lower Tester address type is set to Random Address type. # 17. Repeat steps 4–14. await self.steps_4_14(peer_address=random_peer_address, - peer_address_type=ll.AddressType.RANDOM, - connection_handle=0xeff) + peer_address_type=ll.AddressType.RANDOM) # 18. Upper Tester enables undirected advertising in the IUT using public address type, all supported # advertising channels and filtering policy set to ‘Allow Scan Request from Any, Allow Connect @@ -125,8 +123,7 @@ async def test(self): # 19. Lower Tester address type is set to Public Address type. # 20. Repeat steps 4–14. await self.steps_4_14(peer_address=public_peer_address, - peer_address_type=ll.AddressType.PUBLIC, - connection_handle=0x000) + peer_address_type=ll.AddressType.PUBLIC) # 21. Upper Tester enables undirected advertising in the IUT using public address type, all supported # advertising channels and filtering policy set to ‘Allow Scan Request from Any, Allow Connect @@ -139,8 +136,7 @@ async def test(self): # 22. Lower Tester address type is set to Random Address type. # 23. Repeat steps 4–14. await self.steps_4_14(peer_address=random_peer_address, - peer_address_type=ll.AddressType.RANDOM, - connection_handle=0x001) + peer_address_type=ll.AddressType.RANDOM) # 24. Upper Tester enables undirected advertising in the IUT using all supported advertising channels, # minimum advertising interval and filtering policy set to ‘Allow Scan Request from Any, Allow @@ -164,8 +160,7 @@ async def test(self): hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) await self.steps_24_29(peer_address=public_peer_address, - peer_address_type=ll.AddressType.PUBLIC, - connection_handle=0x002) + peer_address_type=ll.AddressType.PUBLIC) # 30. Repeat steps 24–29, except that in step 25, configure Lower Tester to use a device address not # on the IUT’s Filter Accept List as the address parameter of the CONNECT_IND PDU; the address @@ -177,8 +172,7 @@ async def test(self): hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) await self.steps_24_29(peer_address=invalid_peer_address, - peer_address_type=ll.AddressType.PUBLIC, - connection_handle=0x003) + peer_address_type=ll.AddressType.PUBLIC) # 31. Repeat steps 24–29, except that in step 25, configure Lower Tester to use a device address not # on the IUT’s Filter Accept List as the address parameter of the CONNECT_IND PDU; the address @@ -225,12 +219,10 @@ async def test(self): # 36. Repeat steps 25–29. await self.steps_24_29(peer_address=public_peer_address, - peer_address_type=ll.AddressType.PUBLIC, - connection_handle=0x004) + peer_address_type=ll.AddressType.PUBLIC) # Subroutine for steps 4-14. - async def steps_4_14(self, peer_address: Address, peer_address_type: ll.AddressType, - connection_handle: int): + async def steps_4_14(self, peer_address: Address, peer_address_type: ll.AddressType): # 4. Configure Lower Tester to monitor the advertising and connection procedures of the IUT and # send a CONNECT_IND packet on the selected supported advertising channel (defined as an # IXIT) in response to connectable advertisements. The initiator’s address in the CONNECT_IND @@ -323,10 +315,10 @@ async def steps_4_14(self, peer_address: Address, peer_address_type: ll.AddressT # 13. Upper Tester receives an HCI_LE_Connection_Complete event from the IUT including the # parameters sent to the IUT. - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=connection_handle, + connection_handle=self.Any, role=hci.Role.PERIPHERAL, peer_address_type=(hci.AddressType.PUBLIC_DEVICE_ADDRESS if peer_address_type == ll.AddressType.PUBLIC else @@ -337,6 +329,8 @@ async def steps_4_14(self, peer_address: Address, peer_address_type: ll.AddressT supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + connection_handle = evt.connection_handle + # 14. Peripheral Connection Terminated (connection interval, Peripheral latency, timeout, channel map, # un-encrypted, connection handle). controller.send_ll( @@ -350,8 +344,7 @@ async def steps_4_14(self, peer_address: Address, peer_address_type: ll.AddressT reason=hci.ErrorCode.REMOTE_USER_TERMINATED_CONNECTION)) # Subroutine for steps 24-29. - async def steps_24_29(self, peer_address: Address, peer_address_type: ll.AddressType, - connection_handle: int): + async def steps_24_29(self, peer_address: Address, peer_address_type: ll.AddressType): # 25. Configure Lower Tester to monitor the advertising and connection procedures of the IUT and # send a CONNECT_IND packet on the first supported advertising channel in response to # connectable advertisements. The initiator’s address in the CONNECT_IND PDU shall be an @@ -396,10 +389,10 @@ async def steps_24_29(self, peer_address: Address, peer_address_type: ll.Address # 29. Upper Tester receives an HCI_LE_Connection_Complete event from the IUT including the # parameters sent to the IUT in step 25 and as postamble: Peripheral Connection Terminated # (connection interval, Peripheral latency, timeout, channel map, un-encrypted, connection handle). - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=connection_handle, + connection_handle=self.Any, role=hci.Role.PERIPHERAL, peer_address_type=(hci.AddressType.PUBLIC_DEVICE_ADDRESS if peer_address_type == ll.AddressType.PUBLIC else @@ -410,6 +403,8 @@ async def steps_24_29(self, peer_address: Address, peer_address_type: ll.Address supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + connection_handle = evt.connection_handle + controller.send_ll( ll.Disconnect(source_address=peer_address, destination_address=controller.address, diff --git a/test/LL/DDI/ADV/BV_11_C.py b/test/LL/DDI/ADV/BV_11_C.py index a28a426..a4e3c53 100644 --- a/test/LL/DDI/ADV/BV_11_C.py +++ b/test/LL/DDI/ADV/BV_11_C.py @@ -34,7 +34,7 @@ class Test(ControllerTest): async def test(self): controller = self.controller peer_address = Address('aa:bb:cc:dd:ee:ff') - connection_handle = 0xefe + connection_handle = None # 1. Configure Lower Tester to start passive scanning. # 2. Upper Tester enables high duty cycle directed advertising in the IUT using all supported @@ -133,10 +133,10 @@ async def test(self): # 11. Upper Tester receives an HCI_LE_Connection_Complete event from the IUT including the # parameters sent to the IUT in step 8. - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=connection_handle, + connection_handle=self.Any, role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, @@ -145,6 +145,8 @@ async def test(self): supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + connection_handle = evt.connection_handle + # 12. Upper Tester receives an HCI_LE_Disconnection_Complete event from the IUT with the reason # parameter indicating ‘connection failed to be established’, with the connection handle parameter # matching to step 8. diff --git a/test/LL/DDI/ADV/BV_19_C.py b/test/LL/DDI/ADV/BV_19_C.py index c71a98c..e37904a 100644 --- a/test/LL/DDI/ADV/BV_19_C.py +++ b/test/LL/DDI/ADV/BV_19_C.py @@ -33,7 +33,7 @@ class Test(ControllerTest): async def test(self): controller = self.controller public_peer_address = Address('aa:bb:cc:dd:ee:ff') - connection_handle = 0xefe + connection_handle = None # 1. Configure Lower Tester to start scanning and monitor advertising packets from the IUT. # 2. Upper Tester enables low duty cycle directed advertising in the IUT using a selected advertising @@ -109,10 +109,10 @@ async def test(self): # 10. Upper Tester receives an HCI_LE_Connection_Complete event from the IUT including the # parameters sent to the IUT in step 7. - await self.expect_evt( + evt = await self.expect_evt( hci.LeEnhancedConnectionCompleteV1( status=ErrorCode.SUCCESS, - connection_handle=connection_handle, + connection_handle=self.Any, role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=public_peer_address, @@ -121,6 +121,8 @@ async def test(self): supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + connection_handle = evt.connection_handle + # 11. Upper Tester receives an HCI_Disconnection_Complete event from the IUT once the # Establishment Timeout has expired. controller.send_ll( diff --git a/test/LMP/LIH/BV_01_C.py b/test/LMP/LIH/BV_01_C.py index 0413185..9257d8a 100644 --- a/test/LMP/LIH/BV_01_C.py +++ b/test/LMP/LIH/BV_01_C.py @@ -18,7 +18,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -27,7 +27,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) @@ -38,7 +38,8 @@ async def test(self): controller.send_ll( ll.Page(source_address=peer_address, destination_address=controller.address, - allow_role_switch=False)) + allow_role_switch=False), + phy=Phy.BrEdr) await self.expect_evt( hci.ConnectionRequest(bd_addr=peer_address, @@ -56,13 +57,15 @@ async def test(self): destination_address=peer_address, try_role_switch=False)) - await self.expect_evt( + evt = await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) + acl_connection_handle = evt.connection_handle + controller.send_cmd( hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, link_policy_settings=hci.LinkPolicy.ENABLE_ROLE_SWITCH)) @@ -84,7 +87,8 @@ async def test(self): controller.send_ll( ll.RoleSwitchResponse(source_address=peer_address, destination_address=controller.address, - status=ErrorCode.SUCCESS)) + status=ErrorCode.SUCCESS), + phy=Phy.BrEdr) await self.expect_evt( hci.RoleChange(status=ErrorCode.SUCCESS, diff --git a/test/LMP/LIH/BV_02_C.py b/test/LMP/LIH/BV_02_C.py index 398defa..10bbed5 100644 --- a/test/LMP/LIH/BV_02_C.py +++ b/test/LMP/LIH/BV_02_C.py @@ -18,7 +18,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -27,7 +27,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') controller.send_cmd( @@ -47,15 +47,18 @@ async def test(self): controller.send_ll( ll.PageResponse(source_address=peer_address, destination_address=controller.address, - try_role_switch=False)) + try_role_switch=False), + phy=Phy.BrEdr) - await self.expect_evt( + evt = await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) + acl_connection_handle = evt.connection_handle + controller.send_cmd( hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, link_policy_settings=hci.LinkPolicy.ENABLE_ROLE_SWITCH)) @@ -67,7 +70,8 @@ async def test(self): controller.send_ll( ll.RoleSwitchRequest(source_address=peer_address, - destination_address=controller.address)) + destination_address=controller.address), + phy=Phy.BrEdr) await self.expect_ll( ll.RoleSwitchResponse(source_address=controller.address, @@ -81,7 +85,8 @@ async def test(self): controller.send_ll( ll.RoleSwitchRequest(source_address=peer_address, - destination_address=controller.address)) + destination_address=controller.address), + phy=Phy.BrEdr) await self.expect_ll( ll.RoleSwitchResponse(source_address=controller.address, diff --git a/test/LMP/LIH/BV_142_C.py b/test/LMP/LIH/BV_142_C.py index 49dc8a6..ff9a188 100644 --- a/test/LMP/LIH/BV_142_C.py +++ b/test/LMP/LIH/BV_142_C.py @@ -18,7 +18,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -27,7 +27,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') controller.send_cmd( @@ -47,15 +47,18 @@ async def test(self): controller.send_ll( ll.PageResponse(source_address=peer_address, destination_address=controller.address, - try_role_switch=False)) + try_role_switch=False), + phy=Phy.BrEdr) - await self.expect_evt( + evt = await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) + acl_connection_handle = evt.connection_handle + controller.send_cmd( hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, link_policy_settings=0)) @@ -67,7 +70,8 @@ async def test(self): controller.send_ll( ll.RoleSwitchRequest(source_address=peer_address, - destination_address=controller.address)) + destination_address=controller.address), + phy=Phy.BrEdr) await self.expect_ll( ll.RoleSwitchResponse(source_address=controller.address, diff --git a/test/LMP/LIH/BV_143_C.py b/test/LMP/LIH/BV_143_C.py index 5232880..405cd85 100644 --- a/test/LMP/LIH/BV_143_C.py +++ b/test/LMP/LIH/BV_143_C.py @@ -18,7 +18,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -27,7 +27,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) @@ -38,7 +38,8 @@ async def test(self): controller.send_ll( ll.Page(source_address=peer_address, destination_address=controller.address, - allow_role_switch=False)) + allow_role_switch=False), + phy=Phy.BrEdr) await self.expect_evt( hci.ConnectionRequest(bd_addr=peer_address, @@ -56,13 +57,15 @@ async def test(self): destination_address=peer_address, try_role_switch=False)) - await self.expect_evt( + evt = await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) + acl_connection_handle = evt.connection_handle + controller.send_cmd( hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, link_policy_settings=hci.LinkPolicy.ENABLE_ROLE_SWITCH)) @@ -84,7 +87,8 @@ async def test(self): controller.send_ll( ll.RoleSwitchResponse(source_address=peer_address, destination_address=controller.address, - status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED)) + status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED), + phy=Phy.BrEdr) await self.expect_evt( hci.RoleChange(status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED, diff --git a/test/LMP/LIH/BV_144_C.py b/test/LMP/LIH/BV_144_C.py index 2324ce4..669db56 100644 --- a/test/LMP/LIH/BV_144_C.py +++ b/test/LMP/LIH/BV_144_C.py @@ -18,7 +18,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -27,7 +27,6 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe peer_address = Address('11:22:33:44:55:66') controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) @@ -38,7 +37,8 @@ async def test(self): controller.send_ll( ll.Page(source_address=peer_address, destination_address=controller.address, - allow_role_switch=False)) + allow_role_switch=False), + phy=Phy.BrEdr) await self.expect_evt( hci.ConnectionRequest(bd_addr=peer_address, @@ -58,7 +58,7 @@ async def test(self): await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) diff --git a/test/LMP/LIH/BV_149_C.py b/test/LMP/LIH/BV_149_C.py index 6e69241..ed76433 100644 --- a/test/LMP/LIH/BV_149_C.py +++ b/test/LMP/LIH/BV_149_C.py @@ -18,7 +18,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -27,7 +27,7 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe + acl_connection_handle = None peer_address = Address('11:22:33:44:55:66') controller.send_cmd( @@ -47,15 +47,18 @@ async def test(self): controller.send_ll( ll.PageResponse(source_address=peer_address, destination_address=controller.address, - try_role_switch=False)) + try_role_switch=False), + phy=Phy.BrEdr) - await self.expect_evt( + evt = await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) + acl_connection_handle = evt.connection_handle + controller.send_cmd( hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, link_policy_settings=hci.LinkPolicy.ENABLE_ROLE_SWITCH)) @@ -87,7 +90,8 @@ async def test(self): controller.send_ll( ll.RoleSwitchResponse(source_address=peer_address, destination_address=controller.address, - status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED)) + status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED), + phy=Phy.BrEdr) await self.expect_evt( hci.RoleChange(status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED, diff --git a/test/LMP/LIH/BV_78_C.py b/test/LMP/LIH/BV_78_C.py index 8020ab8..066f12c 100644 --- a/test/LMP/LIH/BV_78_C.py +++ b/test/LMP/LIH/BV_78_C.py @@ -18,7 +18,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -27,7 +27,6 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe peer_address = Address('11:22:33:44:55:66') controller.send_cmd( @@ -48,7 +47,8 @@ async def test(self): controller.send_ll( ll.PageResponse(source_address=peer_address, destination_address=controller.address, - try_role_switch=True)) + try_role_switch=True), + phy=Phy.BrEdr) await self.expect_evt( hci.RoleChange(status=ErrorCode.SUCCESS, @@ -57,7 +57,7 @@ async def test(self): await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) diff --git a/test/LMP/LIH/BV_79_C.py b/test/LMP/LIH/BV_79_C.py index b8968a6..22a5bc2 100644 --- a/test/LMP/LIH/BV_79_C.py +++ b/test/LMP/LIH/BV_79_C.py @@ -18,7 +18,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -27,7 +27,6 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe peer_address = Address('11:22:33:44:55:66') controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) @@ -38,7 +37,8 @@ async def test(self): controller.send_ll( ll.Page(source_address=peer_address, destination_address=controller.address, - allow_role_switch=True)) + allow_role_switch=True), + phy=Phy.BrEdr) await self.expect_evt( hci.ConnectionRequest(bd_addr=peer_address, @@ -63,7 +63,7 @@ async def test(self): await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) diff --git a/test/LMP/page_collision.py b/test/LMP/page_collision.py index bceac54..0c2b95c 100644 --- a/test/LMP/page_collision.py +++ b/test/LMP/page_collision.py @@ -4,7 +4,7 @@ import unittest from hci_packets import ErrorCode from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, Phy class Test(ControllerTest): @@ -17,7 +17,6 @@ class Test(ControllerTest): async def test(self): # Test parameters. controller = self.controller - acl_connection_handle = 0xefe peer_address = Address('11:22:33:44:55:66') controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) @@ -44,7 +43,8 @@ async def test(self): controller.send_ll( ll.Page(source_address=peer_address, destination_address=controller.address, - allow_role_switch=False)) + allow_role_switch=False), + phy=Phy.BrEdr) await self.expect_evt( hci.ConnectionRequest(bd_addr=peer_address, @@ -64,7 +64,7 @@ async def test(self): await self.expect_evt( hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, + connection_handle=self.Any, bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) diff --git a/test/controller/le/le_add_device_to_filter_accept_list_test.cc b/test/controller/le/le_add_device_to_filter_accept_list_test.cc index fe5b0c6..ba37f52 100644 --- a/test/controller/le/le_add_device_to_filter_accept_list_test.cc +++ b/test/controller/le/le_add_device_to_filter_accept_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeAddDeviceToFilterAcceptListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeAddDeviceToFilterAcceptListTest, Success) { diff --git a/test/controller/le/le_add_device_to_periodic_advertiser_list_test.cc b/test/controller/le/le_add_device_to_periodic_advertiser_list_test.cc index 94212f8..5ae3ad5 100644 --- a/test/controller/le/le_add_device_to_periodic_advertiser_list_test.cc +++ b/test/controller/le/le_add_device_to_periodic_advertiser_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeAddDeviceToPeriodicAdvertiserListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeAddDeviceToPeriodicAdvertiserListTest, Success) { diff --git a/test/controller/le/le_add_device_to_resolving_list_test.cc b/test/controller/le/le_add_device_to_resolving_list_test.cc index 050a70a..feb76a2 100644 --- a/test/controller/le/le_add_device_to_resolving_list_test.cc +++ b/test/controller/le/le_add_device_to_resolving_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeAddDeviceToResolvingListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeAddDeviceToResolvingListTest, Success) { diff --git a/test/controller/le/le_clear_filter_accept_list_test.cc b/test/controller/le/le_clear_filter_accept_list_test.cc index b7d8fb8..457fd02 100644 --- a/test/controller/le/le_clear_filter_accept_list_test.cc +++ b/test/controller/le/le_clear_filter_accept_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeClearFilterAcceptListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeClearFilterAcceptListTest, Success) { diff --git a/test/controller/le/le_clear_periodic_advertiser_list_test.cc b/test/controller/le/le_clear_periodic_advertiser_list_test.cc index a2e7d50..8d2cd58 100644 --- a/test/controller/le/le_clear_periodic_advertiser_list_test.cc +++ b/test/controller/le/le_clear_periodic_advertiser_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeClearPeriodicAdvertiserListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeClearPeriodicAdvertiserListTest, Success) { diff --git a/test/controller/le/le_clear_resolving_list_test.cc b/test/controller/le/le_clear_resolving_list_test.cc index 98914a5..b5465e9 100644 --- a/test/controller/le/le_clear_resolving_list_test.cc +++ b/test/controller/le/le_clear_resolving_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeClearResolvingListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeClearResolvingListTest, Success) { diff --git a/test/controller/le/le_create_connection_cancel_test.cc b/test/controller/le/le_create_connection_cancel_test.cc index d8d16e8..9797637 100644 --- a/test/controller/le/le_create_connection_cancel_test.cc +++ b/test/controller/le/le_create_connection_cancel_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -31,7 +31,7 @@ class LeCreateConnectionCancelTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeCreateConnectionCancelTest, CancelLegacyConnection) { diff --git a/test/controller/le/le_create_connection_test.cc b/test/controller/le/le_create_connection_test.cc index 866c493..52b4015 100644 --- a/test/controller/le/le_create_connection_test.cc +++ b/test/controller/le/le_create_connection_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LeCreateConnectionTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeCreateConnectionTest, ConnectUsingPublicAddress) { diff --git a/test/controller/le/le_extended_create_connection_test.cc b/test/controller/le/le_extended_create_connection_test.cc index 0728271..6174ccd 100644 --- a/test/controller/le/le_extended_create_connection_test.cc +++ b/test/controller/le/le_extended_create_connection_test.cc @@ -18,7 +18,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -33,7 +33,7 @@ class LeExtendedCreateConnectionTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeExtendedCreateConnectionTest, ConnectUsingPublicAddress) { diff --git a/test/controller/le/le_periodic_advertising_create_sync_cancel_test.cc b/test/controller/le/le_periodic_advertising_create_sync_cancel_test.cc index ad8924c..5b93e70 100644 --- a/test/controller/le/le_periodic_advertising_create_sync_cancel_test.cc +++ b/test/controller/le/le_periodic_advertising_create_sync_cancel_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LePeriodicAdvertisingCreateSyncCancelTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LePeriodicAdvertisingCreateSyncCancelTest, Success) { diff --git a/test/controller/le/le_periodic_advertising_create_sync_test.cc b/test/controller/le/le_periodic_advertising_create_sync_test.cc index 0ee36cd..5c5dab9 100644 --- a/test/controller/le/le_periodic_advertising_create_sync_test.cc +++ b/test/controller/le/le_periodic_advertising_create_sync_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LePeriodicAdvertisingCreateSyncTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LePeriodicAdvertisingCreateSyncTest, CreateUsingPublicAddress) { diff --git a/test/controller/le/le_remove_device_from_filter_accept_list_test.cc b/test/controller/le/le_remove_device_from_filter_accept_list_test.cc index 5a05c59..c774d95 100644 --- a/test/controller/le/le_remove_device_from_filter_accept_list_test.cc +++ b/test/controller/le/le_remove_device_from_filter_accept_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeRemoveDeviceFromFilterAcceptListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeRemoveDeviceFromFilterAcceptListTest, Success) { diff --git a/test/controller/le/le_remove_device_from_periodic_advertiser_list_test.cc b/test/controller/le/le_remove_device_from_periodic_advertiser_list_test.cc index 86edd3c..806932c 100644 --- a/test/controller/le/le_remove_device_from_periodic_advertiser_list_test.cc +++ b/test/controller/le/le_remove_device_from_periodic_advertiser_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeRemoveDeviceFromPeriodicAdvertiserListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeRemoveDeviceFromPeriodicAdvertiserListTest, Success) { diff --git a/test/controller/le/le_remove_device_from_resolving_list_test.cc b/test/controller/le/le_remove_device_from_resolving_list_test.cc index 9676514..713d20a 100644 --- a/test/controller/le/le_remove_device_from_resolving_list_test.cc +++ b/test/controller/le/le_remove_device_from_resolving_list_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeRemoveDeviceFromResolvingListTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeRemoveDeviceFromResolvingListTest, Success) { diff --git a/test/controller/le/le_scanning_filter_duplicates_test.cc b/test/controller/le/le_scanning_filter_duplicates_test.cc index 0c4fbab..1f97424 100644 --- a/test/controller/le/le_scanning_filter_duplicates_test.cc +++ b/test/controller/le/le_scanning_filter_duplicates_test.cc @@ -23,7 +23,7 @@ #include #include "hci/address.h" -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "packets/hci_packets.h" #include "packets/link_layer_packets.h" @@ -138,7 +138,7 @@ class LeScanningFilterDuplicates : public ::testing::Test { protected: Address address_{}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; static unsigned event_listener_called_; private: diff --git a/test/controller/le/le_set_address_resolution_enable_test.cc b/test/controller/le/le_set_address_resolution_enable_test.cc index 00546f4..5459d05 100644 --- a/test/controller/le/le_set_address_resolution_enable_test.cc +++ b/test/controller/le/le_set_address_resolution_enable_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -31,7 +31,7 @@ class LeSetAddressResolutionEnableTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetAddressResolutionEnableTest, Success) { diff --git a/test/controller/le/le_set_advertising_enable_test.cc b/test/controller/le/le_set_advertising_enable_test.cc index 435bdd6..9b1652b 100644 --- a/test/controller/le/le_set_advertising_enable_test.cc +++ b/test/controller/le/le_set_advertising_enable_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LeSetAdvertisingEnableTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetAdvertisingEnableTest, EnableUsingPublicAddress) { diff --git a/test/controller/le/le_set_advertising_parameters_test.cc b/test/controller/le/le_set_advertising_parameters_test.cc index 1bc71fa..9ac340a 100644 --- a/test/controller/le/le_set_advertising_parameters_test.cc +++ b/test/controller/le/le_set_advertising_parameters_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LeSetAdvertisingParametersTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetAdvertisingParametersTest, Success) { diff --git a/test/controller/le/le_set_extended_advertising_data_test.cc b/test/controller/le/le_set_extended_advertising_data_test.cc index 2ffa673..57b5151 100644 --- a/test/controller/le/le_set_extended_advertising_data_test.cc +++ b/test/controller/le/le_set_extended_advertising_data_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeSetExtendedAdvertisingDataTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetExtendedAdvertisingDataTest, Complete) { diff --git a/test/controller/le/le_set_extended_advertising_enable_test.cc b/test/controller/le/le_set_extended_advertising_enable_test.cc index 5addb9c..5473690 100644 --- a/test/controller/le/le_set_extended_advertising_enable_test.cc +++ b/test/controller/le/le_set_extended_advertising_enable_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeSetExtendedAdvertisingEnableTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetExtendedAdvertisingEnableTest, DisableAll) { diff --git a/test/controller/le/le_set_extended_advertising_parameters_test.cc b/test/controller/le/le_set_extended_advertising_parameters_test.cc index 9b89b88..b218282 100644 --- a/test/controller/le/le_set_extended_advertising_parameters_test.cc +++ b/test/controller/le/le_set_extended_advertising_parameters_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -34,7 +34,7 @@ class LeSetExtendedAdvertisingParametersTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetExtendedAdvertisingParametersTest, Success) { diff --git a/test/controller/le/le_set_extended_scan_enable_test.cc b/test/controller/le/le_set_extended_scan_enable_test.cc index 298683a..2b07b57 100644 --- a/test/controller/le/le_set_extended_scan_enable_test.cc +++ b/test/controller/le/le_set_extended_scan_enable_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LeSetExtendedScanEnableTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; static ScanningPhyParameters MakeScanningPhyParameters(LeScanType scan_type, uint16_t scan_interval, diff --git a/test/controller/le/le_set_extended_scan_parameters_test.cc b/test/controller/le/le_set_extended_scan_parameters_test.cc index ecc61e9..fd449b2 100644 --- a/test/controller/le/le_set_extended_scan_parameters_test.cc +++ b/test/controller/le/le_set_extended_scan_parameters_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LeSetExtendedScanParametersTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; static ScanningPhyParameters MakeScanningPhyParameters(LeScanType scan_type, uint16_t scan_interval, diff --git a/test/controller/le/le_set_extended_scan_response_data_test.cc b/test/controller/le/le_set_extended_scan_response_data_test.cc index c53c9f5..6206126 100644 --- a/test/controller/le/le_set_extended_scan_response_data_test.cc +++ b/test/controller/le/le_set_extended_scan_response_data_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -35,7 +35,7 @@ class LeSetExtendedScanResponseDataTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetExtendedScanResponseDataTest, Complete) { diff --git a/test/controller/le/le_set_periodic_advertising_data_test.cc b/test/controller/le/le_set_periodic_advertising_data_test.cc index 90bbc1a..d9c852b 100644 --- a/test/controller/le/le_set_periodic_advertising_data_test.cc +++ b/test/controller/le/le_set_periodic_advertising_data_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -34,7 +34,7 @@ class LeSetPeriodicAdvertisingDataTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetPeriodicAdvertisingDataTest, Complete) { diff --git a/test/controller/le/le_set_periodic_advertising_enable_test.cc b/test/controller/le/le_set_periodic_advertising_enable_test.cc index 09f5cdf..6df3f88 100644 --- a/test/controller/le/le_set_periodic_advertising_enable_test.cc +++ b/test/controller/le/le_set_periodic_advertising_enable_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -31,7 +31,7 @@ class LeSetPeriodicAdvertisingEnableTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetPeriodicAdvertisingEnableTest, Enable) { diff --git a/test/controller/le/le_set_periodic_advertising_parameters_test.cc b/test/controller/le/le_set_periodic_advertising_parameters_test.cc index 301443b..ab882cb 100644 --- a/test/controller/le/le_set_periodic_advertising_parameters_test.cc +++ b/test/controller/le/le_set_periodic_advertising_parameters_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -31,7 +31,7 @@ class LeSetPeriodicAdvertisingParametersTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetPeriodicAdvertisingParametersTest, Success) { diff --git a/test/controller/le/le_set_random_address_test.cc b/test/controller/le/le_set_random_address_test.cc index a92a72d..cf70dad 100644 --- a/test/controller/le/le_set_random_address_test.cc +++ b/test/controller/le/le_set_random_address_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" #include "test_helpers.h" namespace rootcanal { @@ -31,7 +31,7 @@ class LeSetRandomAddressTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetRandomAddressTest, Success) { diff --git a/test/controller/le/le_set_scan_enable_test.cc b/test/controller/le/le_set_scan_enable_test.cc index 08cba64..f9b6d62 100644 --- a/test/controller/le/le_set_scan_enable_test.cc +++ b/test/controller/le/le_set_scan_enable_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LeSetScanEnableTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetScanEnableTest, EnableUsingPublicAddress) { diff --git a/test/controller/le/le_set_scan_parameters_test.cc b/test/controller/le/le_set_scan_parameters_test.cc index 13f693b..a2a93b5 100644 --- a/test/controller/le/le_set_scan_parameters_test.cc +++ b/test/controller/le/le_set_scan_parameters_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -30,7 +30,7 @@ class LeSetScanParametersTest : public ::testing::Test { protected: Address address_{0}; ControllerProperties properties_{}; - LinkLayerController controller_{address_, properties_}; + LeController controller_{address_, properties_}; }; TEST_F(LeSetScanParametersTest, Success) { diff --git a/test/controller/le/rpa_generation_test.cc b/test/controller/le/rpa_generation_test.cc index ab7e7eb..5c1f0d0 100644 --- a/test/controller/le/rpa_generation_test.cc +++ b/test/controller/le/rpa_generation_test.cc @@ -16,7 +16,7 @@ #include -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" namespace rootcanal { @@ -29,11 +29,11 @@ class RpaGenerationTest : public ::testing::Test { }; TEST_F(RpaGenerationTest, Test) { - std::array irk = { + std::array irk = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, }; - AddressWithType rpa{rootcanal::LinkLayerController::generate_rpa(irk), + AddressWithType rpa{rootcanal::LeController::generate_rpa(irk), AddressType::RANDOM_DEVICE_ADDRESS}; ASSERT_TRUE(rpa.IsRpa()); diff --git a/test/controller/le/test_helpers.h b/test/controller/le/test_helpers.h index 78978f7..e5b16c5 100644 --- a/test/controller/le/test_helpers.h +++ b/test/controller/le/test_helpers.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "model/controller/link_layer_controller.h" +#include "model/controller/le_controller.h" enum : unsigned { CONNECTABLE = 0x1, From af6dbae208f0f7bf1deb0d97224235a64679dfdb Mon Sep 17 00:00:00 2001 From: Henri Chataing Date: Tue, 21 Oct 2025 11:41:18 -0700 Subject: [PATCH 2/2] Add rustfmt.toml configuration file --- rust/src/ffi.rs | 5 +- rust/src/llcp/iso.rs | 54 ++++++++++++++----- rust/src/llcp/manager.rs | 9 ++-- rust/src/lmp/manager.rs | 20 +++++-- rust/src/lmp/procedure/authentication.rs | 14 +++-- rust/src/lmp/procedure/encryption.rs | 4 +- rust/src/lmp/procedure/features.rs | 6 ++- .../lmp/procedure/secure_simple_pairing.rs | 17 +++--- rust/src/lmp/test/context.rs | 14 +++-- rustfmt.toml | 5 ++ 10 files changed, 111 insertions(+), 37 deletions(-) create mode 100644 rustfmt.toml diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs index 8c9eb0c..3349ff1 100644 --- a/rust/src/ffi.rs +++ b/rust/src/ffi.rs @@ -240,7 +240,10 @@ pub unsafe extern "C" fn link_layer_add_link( let mut ll = ManuallyDrop::new(unsafe { Rc::from_raw(ll) }); let ll = Rc::get_mut(&mut ll).unwrap(); let role = hci::Role::try_from(role).unwrap_or(hci::Role::Peripheral); - unsafe { ll.add_link(handle, hci::Address::from(&*peer_address), role).is_ok() } + unsafe { + ll.add_link(handle, hci::Address::from(&*peer_address), role) + .is_ok() + } } /// Unregister a link with a peer inside the link layer diff --git a/rust/src/llcp/iso.rs b/rust/src/llcp/iso.rs index db440f0..9e59267 100644 --- a/rust/src/llcp/iso.rs +++ b/rust/src/llcp/iso.rs @@ -144,7 +144,9 @@ impl CisParameters { let bn_p_to_c: u8 = cis_config .bn_p_to_c .unwrap_or_else(|| cis_config.max_sdu_p_to_c.div_ceil(251).try_into().unwrap()); - let nse = cis_config.nse.unwrap_or(std::cmp::max(bn_c_to_p, bn_p_to_c)); + let nse = cis_config + .nse + .unwrap_or(std::cmp::max(bn_c_to_p, bn_p_to_c)); let max_pdu_c_to_p = cis_config.max_pdu_c_to_p.unwrap_or(251); let max_pdu_p_to_c = cis_config.max_pdu_p_to_c.unwrap_or(251); let sub_interval = (cig_config.iso_interval as u32 * 1250) / nse as u32; @@ -381,7 +383,9 @@ impl IsoManager { // Returns the first unused handle in the range 0xe00..0xefe. fn new_cis_connection_handle(&self) -> u16 { - (0xe00..0xefe).find(|handle| !self.cis_connections.contains_key(handle)).unwrap() + (0xe00..0xefe) + .find(|handle| !self.cis_connections.contains_key(handle)) + .unwrap() } // Insert a new CIS connection, optionally allocating an handle for the @@ -424,7 +428,8 @@ impl IsoManager { acl_connection_handle: u16, packet: P, ) { - self.ops.send_llcp_packet(acl_connection_handle, &packet.encode_to_vec().unwrap()) + self.ops + .send_llcp_packet(acl_connection_handle, &packet.encode_to_vec().unwrap()) } fn get_le_features(&self) -> u64 { @@ -467,7 +472,10 @@ impl IsoManager { /// Start the next CIS connection request, if any. fn deque_cis_connection_request(&mut self) { if let Some(request) = self.cis_connection_requests.pop() { - let cis_config = self.cis_config.get(&(request.cig_id, request.cis_id)).unwrap(); + let cis_config = self + .cis_config + .get(&(request.cig_id, request.cis_id)) + .unwrap(); let cig_config = self.cig_config.get(&request.cig_id).unwrap(); let parameters = CisParameters::new(cig_config, cis_config); @@ -498,7 +506,10 @@ impl IsoManager { }, ); - let cis = self.cis_connections.get_mut(&request.cis_connection_handle).unwrap(); + let cis = self + .cis_connections + .get_mut(&request.cis_connection_handle) + .unwrap(); cis.acl_connection_handle = Some(request.acl_connection_handle); cis.state = CisState::PendingRsp; cis.parameters = Some(parameters); @@ -524,7 +535,12 @@ impl IsoManager { // If the Host issues this command when the CIG is not in the configurable // state, the Controller shall return the error code // Command Disallowed (0x0C). - if !self.cig_config.get(&cig_id).map(|cig| cig.configurable).unwrap_or(true) { + if !self + .cig_config + .get(&cig_id) + .map(|cig| cig.configurable) + .unwrap_or(true) + { println!("CIG ({}) is no longer in the configurable state", cig_id); return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); } @@ -713,7 +729,12 @@ impl IsoManager { // If the Host issues this command when the CIG is not in the configurable // state, the Controller shall return the error code // Command Disallowed (0x0C). - if !self.cig_config.get(&cig_id).map(|cig| cig.configurable).unwrap_or(true) { + if !self + .cig_config + .get(&cig_id) + .map(|cig| cig.configurable) + .unwrap_or(true) + { println!("CIG ({}) is no longer in the configurable state", cig_id); return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); } @@ -1394,7 +1415,10 @@ impl IsoManager { }); if let Some(cis_connection_handle) = cis_connection_handle { - let cis = self.cis_connections.get_mut(&cis_connection_handle).unwrap(); + let cis = self + .cis_connections + .get_mut(&cis_connection_handle) + .unwrap(); cis.state = CisState::Configuration; cis.parameters = None; self.send_hci_event(hci::LeCisEstablishedV1 { @@ -1430,12 +1454,14 @@ impl IsoManager { }); if let Some(cis_connection_handle) = cis_connection_handle { - self.cis_connections.entry(cis_connection_handle).and_modify(|cis| { - cis.state = CisState::Connected; - let parameters = cis.parameters.as_mut().unwrap(); - parameters.cig_sync_delay = packet.cig_sync_delay(); - parameters.cis_sync_delay = packet.cis_sync_delay(); - }); + self.cis_connections + .entry(cis_connection_handle) + .and_modify(|cis| { + cis.state = CisState::Connected; + let parameters = cis.parameters.as_mut().unwrap(); + parameters.cig_sync_delay = packet.cig_sync_delay(); + parameters.cis_sync_delay = packet.cis_sync_delay(); + }); let cis = self.cis_connections.get(&cis_connection_handle).unwrap(); let parameters = cis.parameters.as_ref().unwrap(); self.send_hci_event(hci::LeCisEstablishedV1 { diff --git a/rust/src/llcp/manager.rs b/rust/src/llcp/manager.rs index 5d78a03..70bef50 100644 --- a/rust/src/llcp/manager.rs +++ b/rust/src/llcp/manager.rs @@ -60,7 +60,8 @@ impl LinkLayer { return Err(LinkLayerError::LinkAlreadyExists); } - self.links.insert(acl_connection_handle, Link { acl_connection_handle, role }); + self.links + .insert(acl_connection_handle, Link { acl_connection_handle, role }); self.iso.add_acl_connection(acl_connection_handle, role); Ok(()) } @@ -76,7 +77,8 @@ impl LinkLayer { let reason = hci::ErrorCode::try_from(reason) .unwrap_or(hci::ErrorCode::RemoteUserTerminatedConnection); - self.iso.remove_acl_connection(acl_connection_handle, reason); + self.iso + .remove_acl_connection(acl_connection_handle, reason); Ok(()) } @@ -124,7 +126,8 @@ impl LinkLayer { } pub fn get_cis_connection_handle(&self, cig_id: u8, cis_id: u8) -> Option { - self.iso.get_cis_connection_handle(|cis| cis.cig_id == cig_id && cis.cis_id == cis_id) + self.iso + .get_cis_connection_handle(|cis| cis.cig_id == cig_id && cis.cis_id == cis_id) } pub fn get_cis(&self, cis_connection_handle: u16) -> Option<&iso::Cis> { diff --git a/rust/src/lmp/manager.rs b/rust/src/lmp/manager.rs index d1d4bdc..6b0a844 100644 --- a/rust/src/lmp/manager.rs +++ b/rust/src/lmp/manager.rs @@ -69,7 +69,9 @@ impl Link { fn poll_lmp_packet>(&self) -> Poll

{ let mut queue = self.lmp.borrow_mut(); - let packet = queue.front().and_then(|packet| packet.clone().try_into().ok()); + let packet = queue + .front() + .and_then(|packet| packet.clone().try_into().ok()); if let Some(packet) = packet { queue.pop_front(); @@ -250,7 +252,10 @@ impl LinkManager { } pub fn add_link(self: &Rc, peer: hci::Address) -> Result<(), LinkManagerError> { - let index = self.links.iter().position(|link| link.peer.get().is_empty()); + let index = self + .links + .iter() + .position(|link| link.peer.get().is_empty()); if let Some(index) = index { self.links[index].peer.set(peer); @@ -283,7 +288,12 @@ impl LinkManager { pub fn tick(&self) { let waker = noop_waker(); - for procedures in self.procedures.borrow_mut().iter_mut().filter_map(Option::as_mut) { + for procedures in self + .procedures + .borrow_mut() + .iter_mut() + .filter_map(Option::as_mut) + { let _ = procedures.as_mut().poll(&mut Context::from_waker(&waker)); } } @@ -323,7 +333,9 @@ impl procedure::Context for LinkContext { fn send_lmp_packet + pdl_runtime::Packet>(&self, packet: P) { if let Some(manager) = self.manager.upgrade() { - manager.ops.send_lmp_packet(self.peer_address(), &packet.encode_to_vec().unwrap()) + manager + .ops + .send_lmp_packet(self.peer_address(), &packet.encode_to_vec().unwrap()) } } diff --git a/rust/src/lmp/procedure/authentication.rs b/rust/src/lmp/procedure/authentication.rs index 25a92bb..1fad106 100644 --- a/rust/src/lmp/procedure/authentication.rs +++ b/rust/src/lmp/procedure/authentication.rs @@ -27,19 +27,27 @@ pub async fn send_challenge( let random_number = [0; 16]; ctx.send_lmp_packet(lmp::AuRand { transaction_id, random_number }); - match ctx.receive_lmp_packet::>().await { + match ctx + .receive_lmp_packet::>() + .await + { Either::Left(_response) => Ok(()), Either::Right(_) => Err(()), } } pub async fn receive_challenge(ctx: &impl Context, _link_key: [u8; 16]) { - let _random_number = *ctx.receive_lmp_packet::().await.random_number(); + let _random_number = *ctx + .receive_lmp_packet::() + .await + .random_number(); ctx.send_lmp_packet(lmp::Sres { transaction_id: 0, authentication_rsp: [0; 4] }); } pub async fn initiate(ctx: &impl Context) { - let _ = ctx.receive_hci_command::().await; + let _ = ctx + .receive_hci_command::() + .await; ctx.send_hci_event(hci::AuthenticationRequestedStatus { num_hci_command_packets, status: hci::ErrorCode::Success, diff --git a/rust/src/lmp/procedure/encryption.rs b/rust/src/lmp/procedure/encryption.rs index 7be8d0b..fbb2359 100644 --- a/rust/src/lmp/procedure/encryption.rs +++ b/rust/src/lmp/procedure/encryption.rs @@ -24,7 +24,9 @@ use hci::LMPFeaturesPage2Bits::SecureConnectionsControllerSupport; pub async fn initiate(ctx: &impl Context) { // TODO: handle turn off - let _ = ctx.receive_hci_command::().await; + let _ = ctx + .receive_hci_command::() + .await; ctx.send_hci_event(hci::SetConnectionEncryptionStatus { num_hci_command_packets, status: hci::ErrorCode::Success, diff --git a/rust/src/lmp/procedure/features.rs b/rust/src/lmp/procedure/features.rs index 8468bea..643c585 100644 --- a/rust/src/lmp/procedure/features.rs +++ b/rust/src/lmp/procedure/features.rs @@ -25,7 +25,11 @@ pub async fn initiate(ctx: &impl Context, features_page: u8) -> u64 { extended_features: ctx.extended_features(features_page).to_le_bytes(), }); - u64::from_le_bytes(*ctx.receive_lmp_packet::().await.extended_features()) + u64::from_le_bytes( + *ctx.receive_lmp_packet::() + .await + .extended_features(), + ) } pub async fn respond(ctx: &impl Context) { diff --git a/rust/src/lmp/procedure/secure_simple_pairing.rs b/rust/src/lmp/procedure/secure_simple_pairing.rs index 1b66d39..1fe6475 100644 --- a/rust/src/lmp/procedure/secure_simple_pairing.rs +++ b/rust/src/lmp/procedure/secure_simple_pairing.rs @@ -114,8 +114,11 @@ async fn send_public_key(ctx: &impl Context, transaction_id: u8, public_key: Pub } async fn receive_public_key(ctx: &impl Context, transaction_id: u8) -> PublicKey { - let key_size: usize = - ctx.receive_lmp_packet::().await.payload_length().into(); + let key_size: usize = ctx + .receive_lmp_packet::() + .await + .payload_length() + .into(); let mut key = PublicKey::new(key_size).unwrap(); ctx.send_lmp_packet(lmp::Accepted { @@ -162,8 +165,9 @@ async fn receive_commitment(ctx: &impl Context, confirm: Option().await; // TODO: check pairing number diff --git a/rust/src/lmp/test/context.rs b/rust/src/lmp/test/context.rs index 44e2a72..fc82c64 100644 --- a/rust/src/lmp/test/context.rs +++ b/rust/src/lmp/test/context.rs @@ -65,8 +65,11 @@ impl TestContext { impl Context for TestContext { fn poll_hci_command>(&self) -> Poll { - let command = - self.hci_commands.borrow().front().and_then(|command| command.clone().try_into().ok()); + let command = self + .hci_commands + .borrow() + .front() + .and_then(|command| command.clone().try_into().ok()); if let Some(command) = command { self.hci_commands.borrow_mut().pop_front(); @@ -77,8 +80,11 @@ impl Context for TestContext { } fn poll_lmp_packet>(&self) -> Poll

{ - let packet = - self.in_lmp_packets.borrow().front().and_then(|packet| packet.clone().try_into().ok()); + let packet = self + .in_lmp_packets + .borrow() + .front() + .and_then(|packet| packet.clone().try_into().ok()); if let Some(packet) = packet { self.in_lmp_packets.borrow_mut().pop_front(); diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..8b0fa57 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,5 @@ +edition = "2021" +newline_style = "Unix" +chain_width = 60 +use_small_heuristics = "Max" +imports_granularity = "Module"