diff --git a/.github/workflows/avatar.yml b/.github/workflows/avatar.yml index 42f8416..7f1a8f9 100644 --- a/.github/workflows/avatar.yml +++ b/.github/workflows/avatar.yml @@ -37,7 +37,7 @@ jobs: python -m pip install pandora-avatar - name: Rootcanal run: | - cargo install pdl-compiler --version 0.2.0 + cargo install pdl-compiler --version 0.2.2 bazel build :rootcanal - name: Test run: | diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f7280ea..51a2059 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ jobs: - name: Install dependencies run: | - cargo install pdl-compiler --version 0.2.0 + cargo install pdl-compiler --version 0.2.2 - name: Build run: | @@ -65,7 +65,7 @@ jobs: - name: Install dependencies run: | - cargo install pdl-compiler --version 0.2.0 + cargo install pdl-compiler --version 0.2.2 python3 -m pip install hatch - name: Set VERSION diff --git a/BUILD b/BUILD index 5427101..8778677 100644 --- a/BUILD +++ b/BUILD @@ -147,6 +147,8 @@ cc_library( "model/controller/sco_connection.cc", "model/controller/sco_connection.h", "model/controller/vendor_commands/csr.h", + "model/controller/vendor_commands/le_apcf.cc", + "model/controller/vendor_commands/le_apcf.h", "model/devices/baseband_sniffer.cc", "model/devices/baseband_sniffer.h", "model/devices/beacon.cc", @@ -214,6 +216,7 @@ cc_library( ], defines = [ "NDEBUG", + "_GNU_SOURCE", ], includes = [ "include", @@ -261,6 +264,8 @@ cc_binary( "model/controller/sco_connection.cc", "model/controller/sco_connection.h", "model/controller/vendor_commands/csr.h", + "model/controller/vendor_commands/le_apcf.cc", + "model/controller/vendor_commands/le_apcf.h", "model/controller/ffi.cc", "model/controller/ffi.h", "model/devices/device.cc", @@ -279,6 +284,7 @@ cc_binary( ], defines = [ "NDEBUG", + "_GNU_SOURCE", ], includes = [ "include", diff --git a/BUILD.fmtlib b/BUILD.fmtlib index 9777083..d237183 100644 --- a/BUILD.fmtlib +++ b/BUILD.fmtlib @@ -11,10 +11,8 @@ cc_library( "include/fmt/compile.h", "include/fmt/core.h", "include/fmt/format.h", - "include/fmt/locale.h", "include/fmt/os.h", "include/fmt/ostream.h", - "include/fmt/posix.h", "include/fmt/printf.h", "include/fmt/ranges.h", ], diff --git a/desktop/test_environment.cc b/desktop/test_environment.cc index 10a1661..59e093b 100644 --- a/desktop/test_environment.cc +++ b/desktop/test_environment.cc @@ -14,22 +14,36 @@ // limitations under the License. // -#include "test_environment.h" +#include "desktop/test_environment.h" #include -#include // for exists -#include // for remove_extent_t -#include // for move -#include // for vector - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hci/pcap_filter.h" #include "log.h" +#include "model/controller/controller_properties.h" #include "model/devices/baseband_sniffer.h" -#include "model/devices/link_layer_socket_device.h" // for LinkLayerSocketDevice -#include "model/hci/hci_sniffer.h" // for HciSniffer -#include "model/hci/hci_socket_transport.h" // for HciSocketTransport -#include "net/async_data_channel.h" // for AsyncDataChannel -#include "net/async_data_channel_connector.h" // for AsyncDataChannelConnector +#include "model/devices/device.h" +#include "model/devices/hci_device.h" +#include "model/devices/link_layer_socket_device.h" +#include "model/hci/hci_sniffer.h" +#include "model/hci/hci_socket_transport.h" +#include "model/setup/async_manager.h" +#include "model/setup/test_channel_transport.h" +#include "net/async_data_channel.h" +#include "net/async_data_channel_connector.h" +#include "phy.h" +#include "rootcanal/configuration.pb.h" namespace rootcanal { diff --git a/desktop/test_environment.h b/desktop/test_environment.h index 3f47ba0..5947d07 100644 --- a/desktop/test_environment.h +++ b/desktop/test_environment.h @@ -16,17 +16,19 @@ #pragma once -#include // for milliseconds -#include // for __base, function -#include // for promise -#include // for shared_ptr, make_... -#include // for string - -#include "model/setup/async_manager.h" // for AsyncTaskId, Asyn... -#include "model/setup/test_channel_transport.h" // for TestChannelTransport -#include "model/setup/test_command_handler.h" // for TestCommandHandler -#include "model/setup/test_model.h" // for TestModel -#include "net/async_data_channel_server.h" // for AsyncDataChannelS... +#include +#include +#include +#include +#include +#include + +#include "model/controller/controller_properties.h" +#include "model/setup/async_manager.h" +#include "model/setup/test_channel_transport.h" +#include "model/setup/test_command_handler.h" +#include "model/setup/test_model.h" +#include "net/async_data_channel_server.h" namespace android::net { class AsyncDataChannel; diff --git a/include/hci/address.h b/include/hci/address.h index a46653a..18b38ee 100644 --- a/include/hci/address.h +++ b/include/hci/address.h @@ -16,18 +16,20 @@ #pragma once +#include #include #include +#include #include +#include #include #include #include #include #include -namespace bluetooth { -namespace hci { +namespace bluetooth::hci { class Address final : public pdl::packet::Builder { public: @@ -88,8 +90,7 @@ inline std::ostream& operator<<(std::ostream& os, const Address& a) { return os; } -} // namespace hci -} // namespace bluetooth +} // namespace bluetooth::hci namespace std { template <> @@ -104,3 +105,43 @@ struct hash { } }; } // namespace std + +template <> +struct fmt::formatter { + // Presentation format: 'x' - lowercase, 'X' - uppercase. + char presentation = 'x'; + + // Parses format specifications of the form ['x' | 'X']. + constexpr auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { + // Parse the presentation format and store it in the formatter: + auto it = ctx.begin(); + auto end = ctx.end(); + if (it != end && (*it == 'x' || *it == 'X')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + throw_format_error("invalid format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + // Formats the address a using the parsed format specification (presentation) + // stored in this formatter. + auto format(const bluetooth::hci::Address& a, format_context& ctx) const + -> format_context::iterator { + return presentation == 'x' + ? fmt::format_to(ctx.out(), + "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + a.address[5], a.address[4], a.address[3], + a.address[2], a.address[1], a.address[0]) + : fmt::format_to(ctx.out(), + "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + a.address[5], a.address[4], a.address[3], + a.address[2], a.address[1], a.address[0]); + } +}; diff --git a/include/hci/address_with_type.h b/include/hci/address_with_type.h index 51ddfd9..65c4223 100644 --- a/include/hci/address_with_type.h +++ b/include/hci/address_with_type.h @@ -16,6 +16,13 @@ #pragma once +#include + +#include +#include +#include +#include +#include #include #include #include @@ -24,8 +31,7 @@ #include "hci/address.h" #include "packets/hci_packets.h" -namespace bluetooth { -namespace hci { +namespace bluetooth::hci { class AddressWithType final { public: @@ -118,8 +124,7 @@ inline std::ostream& operator<<(std::ostream& os, const AddressWithType& a) { return os; } -} // namespace hci -} // namespace bluetooth +} // namespace bluetooth::hci namespace std { template <> @@ -134,3 +139,38 @@ struct hash { } }; } // namespace std + +template <> +struct fmt::formatter { + // Presentation format: 'x' - lowercase, 'X' - uppercase. + char presentation = 'x'; + + // Parses format specifications of the form ['x' | 'X']. + constexpr auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { + // Parse the presentation format and store it in the formatter: + auto it = ctx.begin(); + auto end = ctx.end(); + if (it != end && (*it == 'x' || *it == 'X')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + throw_format_error("invalid format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + // Formats the address a using the parsed format specification (presentation) + // stored in this formatter. + auto format(const bluetooth::hci::AddressWithType& a, + format_context& ctx) const -> format_context::iterator { + auto out = presentation == 'x' + ? fmt::format_to(ctx.out(), "{:x}", a.GetAddress()) + : fmt::format_to(ctx.out(), "{:X}", a.GetAddress()); + return fmt::format_to(out, "[{}]", AddressTypeText(a.GetAddressType())); + } +}; diff --git a/include/hci/pcap_filter.h b/include/hci/pcap_filter.h index 6fadfaa..1731ce8 100644 --- a/include/hci/pcap_filter.h +++ b/include/hci/pcap_filter.h @@ -16,7 +16,11 @@ #pragma once -#include +#include +#include +#include +#include +#include #include "packets/hci_packets.h" diff --git a/include/log.h b/include/log.h index a9482a9..130800a 100644 --- a/include/log.h +++ b/include/log.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include diff --git a/include/phy.h b/include/phy.h index 1fa8274..1e82c15 100644 --- a/include/phy.h +++ b/include/phy.h @@ -25,4 +25,5 @@ class Phy { BR_EDR, }; }; + } // namespace rootcanal diff --git a/lib/crypto/crypto.cc b/lib/crypto/crypto.cc index 44ed796..560416d 100644 --- a/lib/crypto/crypto.cc +++ b/lib/crypto/crypto.cc @@ -19,7 +19,6 @@ #include #include -#include namespace rootcanal::crypto { diff --git a/lib/hci/address.cc b/lib/hci/address.cc index 690a1b4..3f9103c 100644 --- a/lib/hci/address.cc +++ b/lib/hci/address.cc @@ -16,18 +16,23 @@ #include "hci/address.h" -#include +#include #include +#include #include #include +#include +#include #include +#include +#include +#include #include +#include +#include -#include "hci/address_with_type.h" - -namespace bluetooth { -namespace hci { +namespace bluetooth::hci { const Address Address::kAny{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; const Address Address::kEmpty{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -123,86 +128,10 @@ bool Address::FromString(const std::string& from, Address& to) { size_t Address::FromOctets(const uint8_t* from) { std::copy(from, from + kLength, data()); return kLength; -}; +} bool Address::IsValidAddress(const std::string& address) { return Address::FromString(address).has_value(); } -} // namespace hci -} // namespace bluetooth - -template <> -struct fmt::formatter { - // Presentation format: 'x' - lowercase, 'X' - uppercase. - char presentation = 'x'; - - // Parses format specifications of the form ['x' | 'X']. - constexpr auto parse(format_parse_context& ctx) - -> format_parse_context::iterator { - // Parse the presentation format and store it in the formatter: - auto it = ctx.begin(); - auto end = ctx.end(); - if (it != end && (*it == 'x' || *it == 'X')) { - presentation = *it++; - } - - // Check if reached the end of the range: - if (it != end && *it != '}') { - ctx.on_error("invalid format"); - } - - // Return an iterator past the end of the parsed range: - return it; - } - - // Formats the address a using the parsed format specification (presentation) - // stored in this formatter. - auto format(const bluetooth::hci::Address& a, format_context& ctx) const - -> format_context::iterator { - return presentation == 'x' - ? fmt::format_to(ctx.out(), - "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - a.address[5], a.address[4], a.address[3], - a.address[2], a.address[1], a.address[0]) - : fmt::format_to(ctx.out(), - "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", - a.address[5], a.address[4], a.address[3], - a.address[2], a.address[1], a.address[0]); - } -}; - -template <> -struct fmt::formatter { - // Presentation format: 'x' - lowercase, 'X' - uppercase. - char presentation = 'x'; - - // Parses format specifications of the form ['x' | 'X']. - constexpr auto parse(format_parse_context& ctx) - -> format_parse_context::iterator { - // Parse the presentation format and store it in the formatter: - auto it = ctx.begin(); - auto end = ctx.end(); - if (it != end && (*it == 'x' || *it == 'X')) { - presentation = *it++; - } - - // Check if reached the end of the range: - if (it != end && *it != '}') { - ctx.on_error("invalid format"); - } - - // Return an iterator past the end of the parsed range: - return it; - } - - // Formats the address a using the parsed format specification (presentation) - // stored in this formatter. - auto format(const bluetooth::hci::AddressWithType& a, - format_context& ctx) const -> format_context::iterator { - auto out = presentation == 'x' - ? fmt::format_to(ctx.out(), "{:x}", a.GetAddress()) - : fmt::format_to(ctx.out(), "{:X}", a.GetAddress()); - return fmt::format_to(out, "[{}]", AddressTypeText(a.GetAddressType())); - } -}; +} // namespace bluetooth::hci diff --git a/lib/hci/pcap_filter.cc b/lib/hci/pcap_filter.cc index b8012fe..4a05da0 100644 --- a/lib/hci/pcap_filter.cc +++ b/lib/hci/pcap_filter.cc @@ -14,7 +14,19 @@ * limitations under the License. */ -#include +#include "hci/pcap_filter.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "log.h" #include "packets/hci_packets.h" diff --git a/lib/log.cc b/lib/log.cc index 9884651..9c78b16 100644 --- a/lib/log.cc +++ b/lib/log.cc @@ -17,11 +17,14 @@ #include "log.h" #include +#include #include +#include #include +#include +#include #include -#include #include namespace rootcanal::log { @@ -59,7 +62,7 @@ void VLog(Verbosity verb, char const* file, int line, auto now = std::chrono::system_clock::now(); auto now_ms = std::chrono::time_point_cast(now); auto now_t = std::chrono::system_clock::to_time_t(now); - char time_str[19]; //"mm-dd_HH:MM:SS.mmm\0" is 19 byte long + char time_str[19]; // "mm-dd_HH:MM:SS.mmm\0" is 19 byte long auto n = std::strftime(time_str, sizeof(time_str), "%m-%d %H:%M:%S", std::localtime(&now_t)); snprintf(time_str + n, sizeof(time_str) - n, ".%03u", diff --git a/model/controller/acl_connection.cc b/model/controller/acl_connection.cc index 926e373..33e4c36 100644 --- a/model/controller/acl_connection.cc +++ b/model/controller/acl_connection.cc @@ -14,7 +14,13 @@ * limitations under the License. */ -#include "acl_connection.h" +#include "model/controller/acl_connection.h" + +#include +#include + +#include "packets/hci_packets.h" +#include "phy.h" namespace rootcanal { AclConnection::AclConnection(AddressWithType address, @@ -27,17 +33,17 @@ AclConnection::AclConnection(AddressWithType address, type_(phy_type), role_(role), last_packet_timestamp_(std::chrono::steady_clock::now()), - timeout_(std::chrono::seconds(1)) {} + timeout_(std::chrono::seconds(3)) {} -void AclConnection::Encrypt() { encrypted_ = true; }; +void AclConnection::Encrypt() { encrypted_ = true; } -bool AclConnection::IsEncrypted() const { return encrypted_; }; +bool AclConnection::IsEncrypted() const { return encrypted_; } void AclConnection::SetLinkPolicySettings(uint16_t settings) { link_policy_settings_ = settings; } -bluetooth::hci::Role AclConnection::GetRole() const { return role_; }; +bluetooth::hci::Role AclConnection::GetRole() const { return role_; } void AclConnection::SetRole(bluetooth::hci::Role role) { role_ = role; } diff --git a/model/controller/acl_connection.h b/model/controller/acl_connection.h index 7945ef0..86ba951 100644 --- a/model/controller/acl_connection.h +++ b/model/controller/acl_connection.h @@ -20,6 +20,7 @@ #include #include "hci/address_with_type.h" +#include "packets/hci_packets.h" #include "phy.h" namespace rootcanal { diff --git a/model/controller/acl_connection_handler.cc b/model/controller/acl_connection_handler.cc index 7fa3a77..656c495 100644 --- a/model/controller/acl_connection_handler.cc +++ b/model/controller/acl_connection_handler.cc @@ -14,11 +14,22 @@ * limitations under the License. */ -#include "acl_connection_handler.h" +#include "model/controller/acl_connection_handler.h" + +#include +#include +#include +#include +#include +#include #include "hci/address.h" +#include "hci/address_with_type.h" #include "log.h" +#include "model/controller/acl_connection.h" +#include "model/controller/sco_connection.h" #include "packets/hci_packets.h" +#include "phy.h" namespace rootcanal { @@ -274,7 +285,7 @@ Phy::Type AclConnectionHandler::GetPhyType(uint16_t handle) const { uint16_t AclConnectionHandler::GetAclLinkPolicySettings(uint16_t handle) const { return acl_connections_.at(handle).GetLinkPolicySettings(); -}; +} void AclConnectionHandler::SetAclLinkPolicySettings(uint16_t handle, uint16_t settings) { @@ -283,7 +294,7 @@ void AclConnectionHandler::SetAclLinkPolicySettings(uint16_t handle, 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) { @@ -404,7 +415,7 @@ ScoLinkParameters AclConnectionHandler::GetScoLinkParameters( } std::vector AclConnectionHandler::GetAclHandles() const { - std::vector keys; + std::vector keys(acl_connections_.size()); for (const auto& pair : acl_connections_) { keys.push_back(pair.first); diff --git a/model/controller/acl_connection_handler.h b/model/controller/acl_connection_handler.h index 8669bcf..146cc47 100644 --- a/model/controller/acl_connection_handler.h +++ b/model/controller/acl_connection_handler.h @@ -18,14 +18,17 @@ #include #include -#include +#include +#include #include +#include -#include "acl_connection.h" #include "hci/address.h" #include "hci/address_with_type.h" +#include "model/controller/acl_connection.h" +#include "model/controller/sco_connection.h" +#include "packets/hci_packets.h" #include "phy.h" -#include "sco_connection.h" namespace rootcanal { static constexpr uint16_t kReservedHandle = 0xF00; diff --git a/model/controller/controller_properties.cc b/model/controller/controller_properties.cc index f269e97..4919887 100644 --- a/model/controller/controller_properties.cc +++ b/model/controller/controller_properties.cc @@ -14,16 +14,16 @@ * limitations under the License. */ -#include "controller_properties.h" +#include "model/controller/controller_properties.h" -#include -#include - -#include -#include -#include +#include +#include +#include +#include #include "log.h" +#include "packets/hci_packets.h" +#include "rootcanal/configuration.pb.h" namespace rootcanal { using namespace bluetooth::hci; @@ -477,7 +477,7 @@ bool ControllerProperties::CheckSupportedFeatures() const { lmp_page_0_reserved_bits = UINT64_C(0x7884000401000100); lmp_page_2_reserved_bits = UINT64_C(0xfffffffffffff080); break; - }; + } if ((lmp_page_0_reserved_bits & lmp_features[0]) != 0) { INFO( @@ -1876,7 +1876,7 @@ ControllerProperties::ControllerProperties( case ControllerPreset::CSR_RCK_PTS_DONGLE: // Configuration extracted with the helper script controller_info.py - vendor_csr = true; + supports_csr_vendor_command = true; br_supported = true; le_supported = true; hci_version = bluetooth::hci::HciVersion::V_4_2; @@ -1970,7 +1970,11 @@ ControllerProperties::ControllerProperties( // Apply selected vendor features. if (config.has_vendor()) { if (config.vendor().has_csr()) { - vendor_csr = config.vendor().csr(); + supports_csr_vendor_command = config.vendor().csr(); + } + if (config.vendor().has_android()) { + supports_le_get_vendor_capabilities_command = config.vendor().android(); + supports_le_apcf_vendor_command = config.vendor().android(); } } diff --git a/model/controller/controller_properties.h b/model/controller/controller_properties.h index 8ec3cdd..0a153f1 100644 --- a/model/controller/controller_properties.h +++ b/model/controller/controller_properties.h @@ -18,11 +18,8 @@ #include #include -#include -#include #include -#include "hci/address.h" #include "packets/hci_packets.h" #include "rootcanal/configuration.pb.h" @@ -67,6 +64,8 @@ struct ControllerProperties { ControllerProperties(ControllerProperties&&) = default; ~ControllerProperties() = default; + ControllerProperties& operator=(ControllerProperties const&) = default; + // Perform a bitwise and operation on the supported commands mask; // the default bit setting is either loaded from the configuration // file or all 1s. @@ -102,6 +101,8 @@ struct ControllerProperties { // Vendor Supported Commands. bool supports_le_get_vendor_capabilities_command{true}; + bool supports_csr_vendor_command{true}; + bool supports_le_apcf_vendor_command{true}; // Local Supported Features (Vol 4, Part E § 7.4.3) and // Local Extended Features (Vol 4, Part E § 7.4.3). @@ -154,12 +155,17 @@ struct ControllerProperties { // LE Periodic Advertiser List Size (Vol 4, Part E § 7.8.73). uint8_t le_periodic_advertiser_list_size{8}; - // Vendor Information. - // Provide parameters returned by vendor specific commands. - std::vector le_vendor_capabilities{}; - - // Enable the support for the CSR vendor command. - bool vendor_csr{true}; + // Android Vendor Capabilities. + // https://source.android.com/docs/core/connect/bluetooth/hci_requirements#vendor-specific-capabilities + uint8_t le_apcf_filter_list_size{16}; + uint8_t le_apcf_num_of_tracked_advertisers{16}; + uint8_t le_apcf_broadcaster_address_filter_list_size{16}; + uint8_t le_apcf_service_uuid_filter_list_size{16}; + uint8_t le_apcf_service_solicitation_uuid_filter_list_size{16}; + uint8_t le_apcf_local_name_filter_list_size{16}; + uint8_t le_apcf_manufacturer_data_filter_list_size{16}; + uint8_t le_apcf_service_data_filter_list_size{16}; + uint8_t le_apcf_ad_type_filter_list_size{16}; bool SupportsLMPFeature(bluetooth::hci::LMPFeaturesPage0Bits bit) const { return (lmp_features[0] & static_cast(bit)) != 0; diff --git a/model/controller/dual_mode_controller.cc b/model/controller/dual_mode_controller.cc index c2b182b..6b029f2 100644 --- a/model/controller/dual_mode_controller.cc +++ b/model/controller/dual_mode_controller.cc @@ -14,18 +14,34 @@ * limitations under the License. */ -#include "dual_mode_controller.h" +#include "model/controller/dual_mode_controller.h" + +#include #include +#include +#include #include +#include +#include +#include +#include #include "crypto/crypto.h" +#include "hci/address_with_type.h" #include "log.h" +#include "model/controller/acl_connection_handler.h" +#include "model/controller/controller_properties.h" +#include "model/controller/sco_connection.h" +#include "model/controller/vendor_commands/csr.h" +#include "model/devices/device.h" +#include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" +#include "phy.h" using bluetooth::hci::ErrorCode; using bluetooth::hci::LoopbackMode; using bluetooth::hci::OpCode; -using std::vector; namespace rootcanal { constexpr uint16_t kNumCommandPackets = 0x01; @@ -33,6 +49,14 @@ constexpr uint16_t kLeMaximumDataLength = 64; constexpr uint16_t kLeMaximumDataTime = 0x148; constexpr uint8_t kTransmitPowerLevel = -20; +constexpr bool kLeApcfTransportDiscoveryDataFilterSupported = true; +constexpr bool kLeApcfAdTypeFilterSupported = true; + +void DualModeController::SetProperties(ControllerProperties properties) { + WARNING(id_, "updating the device properties!"); + properties_ = std::move(properties); +} + // Device methods. std::string DualModeController::GetTypeString() const { return "Simulated Bluetooth Controller"; @@ -73,10 +97,12 @@ DualModeController::DualModeController(ControllerProperties properties) } void DualModeController::ForwardToLm(CommandView command) { + DEBUG(id_, "<< [LM] {}", bluetooth::hci::OpCodeText(command.GetOpCode())); link_layer_controller_.ForwardToLm(command); } void DualModeController::ForwardToLl(CommandView command) { + DEBUG(id_, "<< [LL] {}", bluetooth::hci::OpCodeText(command.GetOpCode())); link_layer_controller_.ForwardToLl(command); } @@ -1123,7 +1149,8 @@ void DualModeController::CentralLinkKey(CommandView command) { ASSERT(command_view.IsValid()); DEBUG(id_, "<< Central Link Key"); - DEBUG(id_, " key_flag={}", command_view.GetKeyFlag()); + 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); @@ -1139,7 +1166,8 @@ void DualModeController::WriteAuthenticationEnable(CommandView command) { DEBUG(id_, "<< Write Authentication Enable"); DEBUG(id_, " authentication_enable={}", - command_view.GetAuthenticationEnable()); + bluetooth::hci::AuthenticationEnableText( + command_view.GetAuthenticationEnable())); link_layer_controller_.SetAuthenticationEnable( command_view.GetAuthenticationEnable()); @@ -1678,6 +1706,12 @@ void DualModeController::SetEventFilter(CommandView command) { DEBUG(id_, " filter_type={}", bluetooth::hci::FilterTypeText(command_view.GetFilterType())); +#if 0 + if (command_view.GetFilterType() != bluetooth::hci::FilterType::CLEAR_ALL_FILTERS) { + FATAL("unsupported event filter type"); + } +#endif + send_event_(bluetooth::hci::SetEventFilterCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -2781,19 +2815,25 @@ void DualModeController::LeGetVendorCapabilities(CommandView command) { return; } - std::vector return_parameters = { - static_cast(ErrorCode::SUCCESS)}; - return_parameters.insert(return_parameters.end(), - properties_.le_vendor_capabilities.begin(), - properties_.le_vendor_capabilities.end()); - // Ensure a minimal size for vendor capabilities. - if (return_parameters.size() < 9) { - return_parameters.resize(9); - } - - send_event_(bluetooth::hci::CommandCompleteBuilder::Create( - kNumCommandPackets, OpCode::LE_GET_VENDOR_CAPABILITIES, - std::move(return_parameters))); + DEBUG(id_, "<< LE Get Vendor Capabilities"); + + bluetooth::hci::VendorCapabilities_V_0_98 vendor_capabilities; + vendor_capabilities.total_scan_results_storage_ = 0; + vendor_capabilities.max_irk_list_sz_ = 16; + vendor_capabilities.filtering_support_ = + properties_.supports_le_apcf_vendor_command; + vendor_capabilities.max_filter_ = properties_.le_apcf_filter_list_size; + vendor_capabilities.activity_energy_info_support_ = 0; + vendor_capabilities.total_num_of_advt_tracked_ = + properties_.le_apcf_num_of_tracked_advertisers; + vendor_capabilities.extended_scan_support_ = 0; + vendor_capabilities.debug_logging_supported_ = 0; + vendor_capabilities.a2dp_source_offload_capability_mask_ = 0; + vendor_capabilities.bluetooth_quality_report_support_ = 0; + + send_event_(bluetooth::hci::LeGetVendorCapabilitiesCompleteBuilder::Create( + kNumCommandPackets, ErrorCode::SUCCESS, + vendor_capabilities.SerializeToBytes())); } void DualModeController::LeBatchScan(CommandView command) { @@ -2805,7 +2845,284 @@ void DualModeController::LeBatchScan(CommandView command) { void DualModeController::LeApcf(CommandView command) { auto command_view = bluetooth::hci::LeApcfView::Create(command); ASSERT(command_view.IsValid()); - SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_APCF); + + if (!properties_.supports_le_apcf_vendor_command) { + SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_APCF); + return; + } + + switch (command_view.GetApcfOpcode()) { + case bluetooth::hci::ApcfOpcode::ENABLE: { + auto subcommand_view = + bluetooth::hci::LeApcfEnableView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + 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); + send_event_(bluetooth::hci::LeApcfEnableCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfEnable())); + break; + } + case bluetooth::hci::ApcfOpcode::SET_FILTERING_PARAMETERS: { + auto subcommand_view = + bluetooth::hci::LeApcfSetFilteringParametersView::Create( + command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Set Filtering Parameters"); + DEBUG(id_, " action={}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + + ErrorCode status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + uint8_t apcf_available_spaces = 0; + + switch (subcommand_view.GetApcfAction()) { + case bluetooth::hci::ApcfAction::ADD: { + auto subsubcommand_view = + bluetooth::hci::LeApcfAddFilteringParametersView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfAddFilteringParameters( + subsubcommand_view.GetApcfFilterIndex(), + subsubcommand_view.GetApcfFeatureSelection(), + subsubcommand_view.GetApcfListLogicType(), + subsubcommand_view.GetApcfFilterLogicType(), + subsubcommand_view.GetRssiHighThresh(), + subsubcommand_view.GetDeliveryMode(), + subsubcommand_view.GetOnfoundTimeout(), + subsubcommand_view.GetOnfoundTimeoutCnt(), + subsubcommand_view.GetRssiLowThresh(), + subsubcommand_view.GetOnlostTimeout(), + subsubcommand_view.GetNumOfTrackingEntries(), + &apcf_available_spaces); + break; + } + case bluetooth::hci::ApcfAction::DELETE: { + auto subsubcommand_view = + bluetooth::hci::LeApcfDeleteFilteringParametersView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfDeleteFilteringParameters( + subsubcommand_view.GetApcfFilterIndex(), &apcf_available_spaces); + break; + } + case bluetooth::hci::ApcfAction::CLEAR: { + auto subsubcommand_view = + bluetooth::hci::LeApcfClearFilteringParametersView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfClearFilteringParameters( + &apcf_available_spaces); + break; + } + default: + INFO(id_, "unknown apcf action {}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + break; + } + + send_event_( + bluetooth::hci::LeApcfSetFilteringParametersCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::BROADCASTER_ADDRESS: { + auto subcommand_view = + bluetooth::hci::LeApcfBroadcasterAddressView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Broadcaster Address"); + DEBUG(id_, " action={}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + + ErrorCode status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + uint8_t apcf_available_spaces = 0; + + switch (subcommand_view.GetApcfAction()) { + case bluetooth::hci::ApcfAction::ADD: { + auto subsubcommand_view = + bluetooth::hci::LeApcfAddBroadcasterAddressView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfBroadcasterAddress( + bluetooth::hci::ApcfAction::ADD, + subsubcommand_view.GetApcfFilterIndex(), + subsubcommand_view.GetApcfBroadcasterAddress(), + subsubcommand_view.GetApcfApplicationAddressType(), + &apcf_available_spaces); + break; + } + case bluetooth::hci::ApcfAction::DELETE: { + auto subsubcommand_view = + bluetooth::hci::LeApcfDeleteBroadcasterAddressView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfBroadcasterAddress( + bluetooth::hci::ApcfAction::DELETE, + subsubcommand_view.GetApcfFilterIndex(), + subsubcommand_view.GetApcfBroadcasterAddress(), + subsubcommand_view.GetApcfApplicationAddressType(), + &apcf_available_spaces); + break; + } + case bluetooth::hci::ApcfAction::CLEAR: { + auto subsubcommand_view = + bluetooth::hci::LeApcfClearBroadcasterAddressView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfBroadcasterAddress( + bluetooth::hci::ApcfAction::CLEAR, + subsubcommand_view.GetApcfFilterIndex(), Address(), + bluetooth::hci::ApcfApplicationAddressType::NOT_APPLICABLE, + &apcf_available_spaces); + break; + } + default: + INFO(id_, "unknown apcf action {}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + break; + } + + send_event_( + bluetooth::hci::LeApcfBroadcasterAddressCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::SERVICE_UUID: { + auto subcommand_view = + bluetooth::hci::LeApcfServiceUuidView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Service UUID"); + DEBUG(id_, " action={}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfServiceUuid( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetAcpfUuidData(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfServiceUuidCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::SERVICE_SOLICITATION_UUID: { + auto subcommand_view = + bluetooth::hci::LeApcfServiceSolicitationUuidView::Create( + command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Service Solicitation UUID"); + DEBUG(id_, " action={}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfServiceSolicitationUuid( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetAcpfUuidData(), &apcf_available_spaces); + send_event_( + bluetooth::hci::LeApcfServiceSolicitationUuidCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::LOCAL_NAME: { + auto subcommand_view = + bluetooth::hci::LeApcfLocalNameView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Local Name"); + DEBUG(id_, " action={}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfLocalName( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetApcfLocalName(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfLocalNameCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::MANUFACTURER_DATA: { + auto subcommand_view = + bluetooth::hci::LeApcfManufacturerDataView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Manufacturer Data"); + DEBUG(id_, " action={}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfManufacturerData( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetApcfManufacturerData(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfManufacturerDataCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::SERVICE_DATA: { + auto subcommand_view = + bluetooth::hci::LeApcfServiceDataView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Service Data"); + DEBUG(id_, " action={}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfServiceData( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetApcfServiceData(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfServiceDataCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::AD_TYPE_FILTER: { + auto subcommand_view = + bluetooth::hci::LeApcfAdTypeFilterView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF AD Type Filter"); + DEBUG(id_, " action={}", + bluetooth::hci::ApcfActionText(subcommand_view.GetApcfAction())); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfAdTypeFilter( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetApcfAdType(), subcommand_view.GetApcfAdData(), + subcommand_view.GetApcfAdDataMask(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfAdTypeFilterCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::READ_EXTENDED_FEATURES: { + auto subcommand_view = + bluetooth::hci::LeApcfReadExtendedFeaturesView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Read Extended Features"); + + send_event_( + bluetooth::hci::LeApcfReadExtendedFeaturesCompleteBuilder::Create( + kNumCommandPackets, ErrorCode::SUCCESS, + kLeApcfTransportDiscoveryDataFilterSupported, + kLeApcfAdTypeFilterSupported)); + break; + } + default: + FATAL(id_, "unknown APCF opcode {}", + static_cast(command_view.GetApcfOpcode())); + } } void DualModeController::LeGetControllerActivityEnergyInfo( @@ -2839,7 +3156,7 @@ void DualModeController::GetControllerDebugInfo(CommandView command) { // Implement the command specific to the CSR controller // used specifically by the PTS tool to pass certification tests. void DualModeController::CsrVendorCommand(CommandView command) { - if (!properties_.vendor_csr) { + if (!properties_.supports_csr_vendor_command) { SendCommandCompleteUnknownOpCodeEvent(OpCode(CSR_VENDOR)); return; } @@ -2954,14 +3271,16 @@ void DualModeController::CsrReadVarid(CsrVarid varid, break; default: - INFO(id_, "Unsupported read of CSR varid 0x{:04x}", varid); + INFO(id_, "Unsupported read of CSR varid 0x{:04x}", + static_cast(varid)); break; } } void DualModeController::CsrWriteVarid( CsrVarid varid, std::vector const& /*value*/) const { - INFO(id_, "Unsupported write of CSR varid 0x{:04x}", varid); + INFO(id_, "Unsupported write of CSR varid 0x{:04x}", + static_cast(varid)); } void DualModeController::CsrReadPskey(CsrPskey pskey, @@ -2985,7 +3304,8 @@ void DualModeController::CsrReadPskey(CsrPskey pskey, break; default: - INFO(id_, "Unsupported read of CSR pskey 0x{:04x}", pskey); + INFO(id_, "Unsupported read of CSR pskey 0x{:04x}", + static_cast(pskey)); break; } } @@ -3004,7 +3324,8 @@ void DualModeController::CsrWritePskey(CsrPskey pskey, break; default: - INFO(id_, "Unsupported write of CSR pskey 0x{:04x}", pskey); + INFO(id_, "Unsupported write of CSR pskey 0x{:04x}", + static_cast(pskey)); break; } } @@ -3254,7 +3575,8 @@ void DualModeController::WriteLoopbackMode(CommandView command) { ASSERT(command_view.IsValid()); DEBUG(id_, "<< Write Loopback Mode"); - DEBUG(id_, " loopback_mode={}", command_view.GetLoopbackMode()); + DEBUG(id_, " loopback_mode={}", + bluetooth::hci::LoopbackModeText(command_view.GetLoopbackMode())); loopback_mode_ = command_view.GetLoopbackMode(); // ACL channel diff --git a/model/controller/dual_mode_controller.h b/model/controller/dual_mode_controller.h index 0ab8d90..3f56acc 100644 --- a/model/controller/dual_mode_controller.h +++ b/model/controller/dual_mode_controller.h @@ -19,18 +19,21 @@ #include #include +#include #include #include #include #include #include -#include "controller_properties.h" #include "hci/address.h" -#include "link_layer_controller.h" +#include "model/controller/controller_properties.h" +#include "model/controller/link_layer_controller.h" #include "model/controller/vendor_commands/csr.h" #include "model/devices/device.h" #include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { @@ -57,6 +60,9 @@ class DualModeController : public Device { DualModeController& operator=(const DualModeController&) = delete; + // Overwrite the configuration. + void SetProperties(ControllerProperties properties); + // Device methods. std::string GetTypeString() const override; diff --git a/model/controller/ffi.cc b/model/controller/ffi.cc index 3f17e41..4c6efad 100644 --- a/model/controller/ffi.cc +++ b/model/controller/ffi.cc @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "ffi.h" +#include "model/controller/ffi.h" #include -#include "dual_mode_controller.h" +#include "model/controller/dual_mode_controller.h" using namespace rootcanal; using bluetooth::hci::Address; diff --git a/model/controller/le_advertiser.cc b/model/controller/le_advertiser.cc index 37afe98..865ceeb 100644 --- a/model/controller/le_advertiser.cc +++ b/model/controller/le_advertiser.cc @@ -14,10 +14,21 @@ * limitations under the License. */ -#include "le_advertiser.h" +#include "model/controller/le_advertiser.h" -#include "link_layer_controller.h" +#include +#include +#include +#include +#include +#include +#include + +#include "hci/address_with_type.h" #include "log.h" +#include "model/controller/link_layer_controller.h" +#include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" using namespace bluetooth::hci; using namespace std::literals; diff --git a/model/controller/le_advertiser.h b/model/controller/le_advertiser.h index 80fced0..cef6516 100644 --- a/model/controller/le_advertiser.h +++ b/model/controller/le_advertiser.h @@ -18,13 +18,13 @@ #include #include -#include #include #include +#include +#include "hci/address.h" #include "hci/address_with_type.h" #include "packets/hci_packets.h" -#include "packets/link_layer_packets.h" namespace rootcanal { diff --git a/model/controller/link_layer_controller.cc b/model/controller/link_layer_controller.cc index 830c59a..845f108 100644 --- a/model/controller/link_layer_controller.cc +++ b/model/controller/link_layer_controller.cc @@ -14,26 +14,44 @@ * limitations under the License. */ -#include "link_layer_controller.h" +#include "model/controller/link_layer_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_advertiser.h" +#include "model/controller/sco_connection.h" #include "packets/hci_packets.h" -#include "rootcanal_rs.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 bluetooth::hci::AddressType; using bluetooth::hci::AddressWithType; -using bluetooth::hci::DirectAdvertisingAddressType; -using bluetooth::hci::EventCode; using bluetooth::hci::LLFeaturesBits; using bluetooth::hci::SubeventCode; using namespace model::packets; -using model::packets::PacketType; using namespace std::literals; using TaskId = rootcanal::LinkLayerController::TaskId; @@ -3360,8 +3378,10 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( if (resolved_advertising_address != advertising_address) { DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address, - advertising_address.GetAddressType(), resolved_advertising_address, - resolved_advertising_address.GetAddressType()); + bluetooth::hci::AddressTypeText(advertising_address.GetAddressType()), + resolved_advertising_address, + bluetooth::hci::AddressTypeText( + resolved_advertising_address.GetAddressType())); } // Vol 6, Part B § 4.3.3 Scanner filter policy @@ -5026,6 +5046,20 @@ void LinkLayerController::IncomingPagePacket( 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; @@ -5041,11 +5075,9 @@ void LinkLayerController::IncomingPagePacket( return; } - if (IsEventUnmasked(EventCode::CONNECTION_REQUEST)) { - send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( - bd_addr, page.GetClassOfDevice(), - bluetooth::hci::ConnectionRequestLinkType::ACL)); - } + send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( + bd_addr, page.GetClassOfDevice(), + bluetooth::hci::ConnectionRequestLinkType::ACL)); } void LinkLayerController::IncomingPageRejectPacket( @@ -5296,15 +5328,9 @@ void LinkLayerController::MakePeripheralConnection(const Address& bd_addr, 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 an HCI Connection Complete + // This implementation considers that a unique HCI Connection Complete // event is expected for both the HCI Create Connection and HCI Accept - // Connection Request commands. Both events are sent with the status - // for success. - 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)); - } + // Connection Request commands. page_ = {}; } diff --git a/model/controller/link_layer_controller.h b/model/controller/link_layer_controller.h index 2e426a8..ce50d91 100644 --- a/model/controller/link_layer_controller.h +++ b/model/controller/link_layer_controller.h @@ -16,20 +16,32 @@ #pragma once +#include + #include +#include #include -#include +#include +#include +#include +#include +#include #include +#include +#include #include #include "hci/address.h" -#include "include/phy.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 "rootcanal_rs.h" +#include "phy.h" +#include "rust/include/rootcanal_rs.h" namespace rootcanal { @@ -40,6 +52,7 @@ using ::bluetooth::hci::ErrorCode; using ::bluetooth::hci::FilterAcceptListAddressType; using ::bluetooth::hci::OpCode; using ::bluetooth::hci::PageScanRepetitionMode; +using rootcanal::apcf::ApcfScanner; // Create an address with type Public Device Address or Random Device Address. AddressWithType PeerDeviceAddress(Address address, @@ -568,6 +581,59 @@ class LinkLayerController { // HCI LE Clear Periodic Advertiser List command (Vol 4, Part E § 7.8.72). ErrorCode LeClearPeriodicAdvertiserList(); + // LE APCF + + ErrorCode LeApcfEnable(bool apcf_enable); + + ErrorCode 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, uint8_t onfound_timeout_cnt, + uint8_t rssi_low_thresh, uint16_t onlost_timeout, + uint16_t num_of_tracking_entries, uint8_t* apcf_available_spaces); + + ErrorCode LeApcfDeleteFilteringParameters(uint8_t apcf_filter_index, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfClearFilteringParameters(uint8_t* apcf_available_spaces); + + ErrorCode LeApcfBroadcasterAddress( + bluetooth::hci::ApcfAction apcf_action, uint8_t apcf_filter_index, + bluetooth::hci::Address apcf_broadcaster_address, + bluetooth::hci::ApcfApplicationAddressType apcf_application_address_type, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfServiceUuid(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector acpf_uuid_data, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfServiceSolicitationUuid( + bluetooth::hci::ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector acpf_uuid_data, uint8_t* apcf_available_spaces); + + ErrorCode LeApcfLocalName(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector apcf_local_name, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfManufacturerData(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector apcf_manufacturer_data, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfServiceData(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector apcf_service_data, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfAdTypeFilter(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, uint8_t ad_type, + std::vector apcf_ad_data, + std::vector apcf_ad_data_mask, + uint8_t* apcf_available_spaces); + protected: void SendLinkLayerPacket( std::unique_ptr packet, @@ -1023,6 +1089,9 @@ class LinkLayerController { // Only one type of advertising may be used during a controller session. Scanner scanner_{}; + // APCF scanning state for Android vendor support. + ApcfScanner apcf_scanner_{}; + struct Initiator { bool connect_enable; bluetooth::hci::InitiatorFilterPolicy initiator_filter_policy; diff --git a/model/controller/sco_connection.cc b/model/controller/sco_connection.cc index 9d9b364..e0fb087 100644 --- a/model/controller/sco_connection.cc +++ b/model/controller/sco_connection.cc @@ -14,12 +14,15 @@ * limitations under the License. */ -#include "sco_connection.h" - -#include +#include "model/controller/sco_connection.h" +#include +#include +#include +#include #include +#include "log.h" #include "packets/hci_packets.h" using namespace rootcanal; diff --git a/model/controller/vendor_commands/le_apcf.cc b/model/controller/vendor_commands/le_apcf.cc new file mode 100644 index 0000000..a28fcd7 --- /dev/null +++ b/model/controller/vendor_commands/le_apcf.cc @@ -0,0 +1,395 @@ +/* + * Copyright 2023 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 +#include + +#include "log.h" +#include "model/controller/link_layer_controller.h" +#include "packets/hci_packets.h" + +#pragma GCC diagnostic ignored "-Wunused-parameter" + +namespace rootcanal::apcf { + +bool ApcfScanner::HasFilterIndex(uint8_t apcf_filter_index) const { + return std::any_of(std::begin(filters), std::end(filters), [&](auto it) { + return it.filter_index == apcf_filter_index; + }); +} + +void ApcfScanner::ClearFilterIndex(uint8_t apcf_filter_index) { + broadcaster_address_filters.erase( + std::remove_if( + std::begin(broadcaster_address_filters), + std::end(broadcaster_address_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(broadcaster_address_filters)); + service_uuid_filters.erase( + std::remove_if( + std::begin(service_uuid_filters), std::end(service_uuid_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(service_uuid_filters)); + service_solicitation_uuid_filters.erase( + std::remove_if( + std::begin(service_solicitation_uuid_filters), + std::end(service_solicitation_uuid_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(service_solicitation_uuid_filters)); + local_name_filters.erase( + std::remove_if( + std::begin(local_name_filters), std::end(local_name_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(local_name_filters)); + manufacturer_data_filters.erase( + std::remove_if( + std::begin(manufacturer_data_filters), + std::end(manufacturer_data_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(manufacturer_data_filters)); + service_data_filters.erase( + std::remove_if( + std::begin(service_data_filters), std::end(service_data_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(service_data_filters)); + ad_type_filters.erase( + std::remove_if( + std::begin(ad_type_filters), std::end(ad_type_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(ad_type_filters)); +} + +void ApcfScanner::Clear() { + filters.clear(); + broadcaster_address_filters.clear(); + service_uuid_filters.clear(); + service_solicitation_uuid_filters.clear(); + local_name_filters.clear(); + manufacturer_data_filters.clear(); + service_data_filters.clear(); + ad_type_filters.clear(); +} + +template +ErrorCode ApcfScanner::UpdateFilterList(std::vector& filter_list, + size_t max_filter_list_size, + bluetooth::hci::ApcfAction action, + T filter) { + if (!HasFilterIndex(filter.filter_index)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + switch (action) { + case ApcfAction::ADD: { + if (filter_list.size() == max_filter_list_size) { + return ErrorCode::MEMORY_CAPACITY_EXCEEDED; + } + + filter_list.emplace_back(std::move(filter)); + return ErrorCode::SUCCESS; + } + case ApcfAction::DELETE: { + // Delete will delete the specified data in the specified filter. + filter_list.erase( + std::remove_if(std::begin(filter_list), std::end(filter_list), + [&](auto it) { return it == filter; }), + std::end(filter_list)); + return ErrorCode::SUCCESS; + } + case ApcfAction::CLEAR: { + // Clear will clear all data in the specified filter. + filter_list.erase( + std::remove_if( + std::begin(filter_list), std::end(filter_list), + [&](auto it) { return it.filter_index == filter.filter_index; }), + std::end(filter_list)); + return ErrorCode::SUCCESS; + } + default: + break; + } + + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; +} + +bool operator==(BroadcasterAddressFilter const& lhs, + BroadcasterAddressFilter const& rhs) { + return lhs.filter_index == rhs.filter_index && + lhs.broadcaster_address == rhs.broadcaster_address && + lhs.application_address_type == rhs.application_address_type; +} + +bool operator==(GapDataFilter const& lhs, GapDataFilter const& rhs) { + return lhs.filter_index == rhs.filter_index && lhs.gap_data == rhs.gap_data && + lhs.gap_data_mask == rhs.gap_data_mask; +} + +bool operator==(AdTypeFilter const& lhs, AdTypeFilter const& rhs) { + return lhs.filter_index == rhs.filter_index && lhs.ad_type == rhs.ad_type && + lhs.ad_data == rhs.ad_data && lhs.ad_data_mask == rhs.ad_data_mask; +} + +} // namespace rootcanal::apcf + +namespace rootcanal { + +using bluetooth::hci::ApcfAction; + +ErrorCode LinkLayerController::LeApcfEnable(bool apcf_enable) { + apcf_scanner_.enable = apcf_enable; + return ErrorCode::SUCCESS; +} + +ErrorCode LinkLayerController::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, uint8_t onfound_timeout_cnt, + uint8_t rssi_low_thresh, uint16_t onlost_timeout, + uint16_t num_of_tracking_entries, 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)) { + INFO(id_, "apcf filter index {} already configured", apcf_filter_index); + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + } + + if (*apcf_available_spaces == 0) { + INFO(id_, "reached max number of apcf filters"); + return ErrorCode::MEMORY_CAPACITY_EXCEEDED; + } + + apcf_scanner_.filters.push_back(rootcanal::apcf::Filter{ + .filter_index = apcf_filter_index, + .feature_selection = apcf_feature_selection, + .list_logic_type = apcf_list_logic_type, + .filter_logic_type = apcf_filter_logic_type, + .rssi_high_thresh = rssi_high_thresh, + .delivery_mode = delivery_mode, + .onfound_timeout = onfound_timeout, + .onfound_timeout_cnt = onfound_timeout_cnt, + .rssi_low_thresh = rssi_low_thresh, + .onlost_timeout = onlost_timeout, + .num_of_tracking_entries = num_of_tracking_entries, + }); + + *apcf_available_spaces -= 1; + return ErrorCode::SUCCESS; +} + +ErrorCode LinkLayerController::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)) { + INFO(id_, "apcf filter index {} is not configured", apcf_filter_index); + return ErrorCode::UNKNOWN_CONNECTION; + } + + apcf_scanner_.filters.erase( + std::remove_if( + std::begin(apcf_scanner_.filters), + std::end(apcf_scanner_.filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(apcf_scanner_.filters)); + + apcf_scanner_.ClearFilterIndex(apcf_filter_index); + *apcf_available_spaces += 1; + return ErrorCode::SUCCESS; +} + +ErrorCode LinkLayerController::LeApcfClearFilteringParameters( + uint8_t* apcf_available_spaces) { + apcf_scanner_.Clear(); + *apcf_available_spaces = properties_.le_apcf_filter_list_size; + return ErrorCode::SUCCESS; +} + +ErrorCode LinkLayerController::LeApcfBroadcasterAddress( + ApcfAction apcf_action, uint8_t apcf_filter_index, + bluetooth::hci::Address apcf_broadcaster_address, + bluetooth::hci::ApcfApplicationAddressType apcf_application_address_type, + uint8_t* apcf_available_spaces) { + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.broadcaster_address_filters, + properties_.le_apcf_broadcaster_address_filter_list_size, apcf_action, + rootcanal::apcf::BroadcasterAddressFilter{ + .filter_index = apcf_filter_index, + .broadcaster_address = apcf_broadcaster_address, + .application_address_type = apcf_application_address_type, + }); + + *apcf_available_spaces = + properties_.le_apcf_broadcaster_address_filter_list_size - + apcf_scanner_.broadcaster_address_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::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); + std::vector uuid_data_mask( + std::begin(apcf_uuid_data) + uuid_data_size, std::end(apcf_uuid_data)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.service_uuid_filters, + properties_.le_apcf_service_uuid_filter_list_size, apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = uuid_data, + .gap_data_mask = uuid_data_mask, + }); + + *apcf_available_spaces = properties_.le_apcf_service_uuid_filter_list_size - + apcf_scanner_.service_uuid_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::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); + std::vector uuid_data_mask( + std::begin(apcf_uuid_data) + uuid_data_size, std::end(apcf_uuid_data)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.service_solicitation_uuid_filters, + properties_.le_apcf_service_solicitation_uuid_filter_list_size, + apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = uuid_data, + .gap_data_mask = uuid_data_mask, + }); + + *apcf_available_spaces = + properties_.le_apcf_service_solicitation_uuid_filter_list_size - + apcf_scanner_.service_solicitation_uuid_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::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); + std::vector local_name_mask( + std::begin(apcf_local_name) + local_name_size, std::end(apcf_local_name)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.local_name_filters, + properties_.le_apcf_local_name_filter_list_size, apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = local_name, + .gap_data_mask = local_name_mask, + }); + + *apcf_available_spaces = properties_.le_apcf_local_name_filter_list_size - + apcf_scanner_.local_name_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::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), + std::begin(apcf_manufacturer_data) + manufacturer_data_size); + std::vector manufacturer_data_mask( + std::begin(apcf_manufacturer_data) + manufacturer_data_size, + std::end(apcf_manufacturer_data)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.manufacturer_data_filters, + properties_.le_apcf_manufacturer_data_filter_list_size, apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = manufacturer_data, + .gap_data_mask = manufacturer_data_mask, + }); + + *apcf_available_spaces = + properties_.le_apcf_manufacturer_data_filter_list_size - + apcf_scanner_.manufacturer_data_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::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); + std::vector service_data_mask( + std::begin(apcf_service_data) + service_data_size, + std::end(apcf_service_data)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.service_data_filters, + properties_.le_apcf_service_data_filter_list_size, apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = service_data, + .gap_data_mask = service_data_mask, + }); + + *apcf_available_spaces = properties_.le_apcf_service_data_filter_list_size - + apcf_scanner_.service_data_filters.size(); + + 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 status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.ad_type_filters, + properties_.le_apcf_ad_type_filter_list_size, apcf_action, + rootcanal::apcf::AdTypeFilter{ + .filter_index = apcf_filter_index, + .ad_type = apcf_ad_type, + .ad_data = std::move(apcf_ad_data), + .ad_data_mask = std::move(apcf_ad_data_mask), + }); + + *apcf_available_spaces = properties_.le_apcf_ad_type_filter_list_size - + apcf_scanner_.ad_type_filters.size(); + + return status; +} + +} // namespace rootcanal diff --git a/model/controller/vendor_commands/le_apcf.h b/model/controller/vendor_commands/le_apcf.h new file mode 100644 index 0000000..5c6cce4 --- /dev/null +++ b/model/controller/vendor_commands/le_apcf.h @@ -0,0 +1,94 @@ +/* + * Copyright 2023 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::apcf { + +/// Records the filtering parameters for the specified filter_index. +/// The associated advertising filters are added to their respective tables. +struct Filter { + uint8_t filter_index; + uint16_t feature_selection; + uint16_t list_logic_type; + uint8_t filter_logic_type; + uint8_t rssi_high_thresh; + bluetooth::hci::DeliveryMode delivery_mode; + uint16_t onfound_timeout; + uint8_t onfound_timeout_cnt; + uint8_t rssi_low_thresh; + uint16_t onlost_timeout; + uint16_t num_of_tracking_entries; +}; + +/// Filter for matching the advertiser address. +struct BroadcasterAddressFilter { + uint8_t filter_index; + bluetooth::hci::Address broadcaster_address; + bluetooth::hci::ApcfApplicationAddressType application_address_type; +}; + +/// Generic filter for GAP data information. +/// Used for matching Service UUID, Service Solicitation UUID, +/// Local Name, Manufacturer Data, Service Data. +struct GapDataFilter { + uint8_t filter_index; + std::vector gap_data; + std::vector gap_data_mask; +}; + +/// Filter for matching the AD type. +struct AdTypeFilter { + uint8_t filter_index; + uint8_t ad_type; + std::vector ad_data; + std::vector ad_data_mask; +}; + +/// State of the APCF scanner. +struct ApcfScanner { + bool enable{false}; + std::vector filters{}; + std::vector broadcaster_address_filters{}; + std::vector service_uuid_filters{}; + std::vector service_solicitation_uuid_filters{}; + std::vector local_name_filters{}; + std::vector manufacturer_data_filters{}; + std::vector service_data_filters{}; + std::vector ad_type_filters{}; + + // Return if the APCF filter index is defined in the + // list of filters. + bool HasFilterIndex(uint8_t apcf_filter_index) const; + + // Remove the entries associated with the APCF filter index + // from all tables. + void ClearFilterIndex(uint8_t apcf_filter_index); + + // Remove all entries in all tables. + void Clear(); + + // Apply the requested modification to the selected + // filter list. + template + ErrorCode UpdateFilterList(std::vector& filter_list, + size_t max_filter_list_size, + bluetooth::hci::ApcfAction action, T filter); +}; + +} // namespace rootcanal::apcf diff --git a/model/devices/baseband_sniffer.cc b/model/devices/baseband_sniffer.cc index 114cd24..3bd933f 100644 --- a/model/devices/baseband_sniffer.cc +++ b/model/devices/baseband_sniffer.cc @@ -14,13 +14,20 @@ * limitations under the License. */ -#include "baseband_sniffer.h" +#include "model/devices/baseband_sniffer.h" + +#include +#include +#include +#include +#include +#include #include "log.h" -#include "pcap.h" #include "packets/bredr_bb_packets.h" - -using std::vector; +#include "packets/link_layer_packets.h" +#include "pcap.h" +#include "phy.h" namespace rootcanal { diff --git a/model/devices/baseband_sniffer.h b/model/devices/baseband_sniffer.h index c7b73c4..c910b1e 100644 --- a/model/devices/baseband_sniffer.h +++ b/model/devices/baseband_sniffer.h @@ -18,8 +18,13 @@ #include #include +#include +#include -#include "device.h" +#include "hci/address.h" +#include "model/devices/device.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace bredr_bb { class BaseBandPacketBuilder; diff --git a/model/devices/beacon.cc b/model/devices/beacon.cc index cb87104..d61d44b 100644 --- a/model/devices/beacon.cc +++ b/model/devices/beacon.cc @@ -14,9 +14,18 @@ * limitations under the License. */ -#include "beacon.h" +#include "model/devices/beacon.h" +#include +#include +#include +#include +#include + +#include "hci/address.h" #include "model/setup/device_boutique.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { using namespace model::packets; diff --git a/model/devices/beacon.h b/model/devices/beacon.h index 5a387bc..6b33197 100644 --- a/model/devices/beacon.h +++ b/model/devices/beacon.h @@ -16,12 +16,16 @@ #pragma once +#include #include #include #include +#include #include -#include "device.h" +#include "model/devices/device.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { diff --git a/model/devices/beacon_swarm.cc b/model/devices/beacon_swarm.cc index 45827dc..af4b755 100644 --- a/model/devices/beacon_swarm.cc +++ b/model/devices/beacon_swarm.cc @@ -14,11 +14,16 @@ * limitations under the License. */ -#include "beacon_swarm.h" +#include "model/devices/beacon_swarm.h" -#include "model/setup/device_boutique.h" +#include +#include +#include +#include -using std::vector; +#include "model/devices/beacon.h" +#include "model/setup/device_boutique.h" +#include "packets/link_layer_packets.h" namespace rootcanal { using namespace model::packets; @@ -27,7 +32,7 @@ using namespace std::chrono_literals; bool BeaconSwarm::registered_ = DeviceBoutique::Register("beacon_swarm", &BeaconSwarm::Create); -BeaconSwarm::BeaconSwarm(const vector& args) : Beacon(args) { +BeaconSwarm::BeaconSwarm(const std::vector& args) : Beacon(args) { advertising_interval_ = 1280ms; advertising_type_ = LegacyAdvertisingType::ADV_NONCONN_IND; advertising_data_ = { diff --git a/model/devices/beacon_swarm.h b/model/devices/beacon_swarm.h index d7bc6c1..69f6dd4 100644 --- a/model/devices/beacon_swarm.h +++ b/model/devices/beacon_swarm.h @@ -16,10 +16,12 @@ #pragma once -#include +#include +#include #include -#include "beacon.h" +#include "model/devices/beacon.h" +#include "model/devices/device.h" namespace rootcanal { diff --git a/model/devices/device.cc b/model/devices/device.cc index bf10ae6..9fadf9e 100644 --- a/model/devices/device.cc +++ b/model/devices/device.cc @@ -14,11 +14,17 @@ * limitations under the License. */ -#include "device.h" +#include "model/devices/device.h" +#include +#include +#include +#include #include #include "log.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { diff --git a/model/devices/device.h b/model/devices/device.h index 15ced21..3d5f258 100644 --- a/model/devices/device.h +++ b/model/devices/device.h @@ -16,10 +16,9 @@ #pragma once -#include #include #include -#include +#include #include #include @@ -58,7 +57,7 @@ class Device { virtual void ReceiveLinkLayerPacket( model::packets::LinkLayerPacketView /*packet*/, Phy::Type /*type*/, - int8_t /*rssi*/){}; + int8_t /*rssi*/) {} void SendLinkLayerPacket( std::shared_ptr packet, diff --git a/model/devices/hci_device.cc b/model/devices/hci_device.cc index 710bd3a..9f0b30b 100644 --- a/model/devices/hci_device.cc +++ b/model/devices/hci_device.cc @@ -14,9 +14,17 @@ * limitations under the License. */ -#include "hci_device.h" +#include "model/devices/hci_device.h" + +#include +#include +#include #include "log.h" +#include "model/controller/controller_properties.h" +#include "model/controller/dual_mode_controller.h" +#include "model/hci/hci_transport.h" +#include "packets/link_layer_packets.h" namespace rootcanal { diff --git a/model/devices/hci_device.h b/model/devices/hci_device.h index 65dacd0..38be7fb 100644 --- a/model/devices/hci_device.h +++ b/model/devices/hci_device.h @@ -16,11 +16,12 @@ #pragma once -#include // for shared_ptr, make_... -#include // for string +#include +#include -#include "model/controller/dual_mode_controller.h" // for DualModeController -#include "model/hci/hci_transport.h" // for HciTransport +#include "model/controller/controller_properties.h" +#include "model/controller/dual_mode_controller.h" +#include "model/hci/hci_transport.h" namespace rootcanal { diff --git a/model/devices/link_layer_socket_device.cc b/model/devices/link_layer_socket_device.cc index 92de96e..e61badf 100644 --- a/model/devices/link_layer_socket_device.cc +++ b/model/devices/link_layer_socket_device.cc @@ -14,14 +14,21 @@ * limitations under the License. */ -#include "link_layer_socket_device.h" +#include "model/devices/link_layer_socket_device.h" #include -#include // for remove_extent_t +#include +#include +#include +#include +#include +#include #include "log.h" -#include "phy.h" // for Phy, Phy::Type +#include "model/devices/device.h" +#include "packets/link_layer_packets.h" +#include "phy.h" using std::vector; diff --git a/model/devices/link_layer_socket_device.h b/model/devices/link_layer_socket_device.h index b0adb15..b91263a 100644 --- a/model/devices/link_layer_socket_device.h +++ b/model/devices/link_layer_socket_device.h @@ -16,17 +16,16 @@ #pragma once -#include // for size_t +#include +#include +#include +#include +#include -#include // for uint8_t, uint32_t -#include // for shared_ptr, make_shared -#include // for string -#include // for vector - -#include "device.h" // for Device -#include "include/phy.h" // for Phy, Phy::Type -#include "net/async_data_channel.h" // for AsyncDataChannel -#include "packets/link_layer_packets.h" // for LinkLayerPacketView +#include "model/devices/device.h" +#include "net/async_data_channel.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { diff --git a/model/devices/scripted_beacon.cc b/model/devices/scripted_beacon.cc index 0175ab3..9095d11 100644 --- a/model/devices/scripted_beacon.cc +++ b/model/devices/scripted_beacon.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "scripted_beacon.h" +#include "model/devices/scripted_beacon.h" #include @@ -97,7 +97,7 @@ bool has_time_elapsed(steady_clock::time_point time_point) { static void populate_event(PlaybackEvent* event, PlaybackEvent::PlaybackEventType type) { - INFO("Adding event: {}", type); + INFO("Adding event: {}", PlaybackEvent::PlaybackEventType_Name(type)); event->set_type(type); event->set_secs_since_epoch(system_clock::now().time_since_epoch().count()); } @@ -111,7 +111,8 @@ void ScriptedBeacon::set_state(PlaybackEvent::PlaybackEventType state) { events_ostream_.open(events_file_, std::ios::out | std::ios::binary | std::ios::trunc); if (!events_ostream_.is_open()) { - INFO("Events file not opened yet, for event: {}", state); + INFO("Events file not opened yet, for event: {}", + PlaybackEvent::PlaybackEventType_Name(state)); return; } } diff --git a/model/devices/scripted_beacon.h b/model/devices/scripted_beacon.h index 8bb7b32..4d62ac6 100644 --- a/model/devices/scripted_beacon.h +++ b/model/devices/scripted_beacon.h @@ -20,7 +20,7 @@ #include #include -#include "beacon.h" +#include "model/devices/beacon.h" #include "model/devices/scripted_beacon_ble_payload.pb.h" using android::bluetooth::rootcanal::model::devices::ScriptedBeaconBleAdProto:: diff --git a/model/devices/sniffer.cc b/model/devices/sniffer.cc index 2a4dffb..793b078 100644 --- a/model/devices/sniffer.cc +++ b/model/devices/sniffer.cc @@ -14,19 +14,24 @@ * limitations under the License. */ -#include "sniffer.h" +#include "model/devices/sniffer.h" +#include +#include +#include + +#include "hci/address.h" #include "log.h" #include "model/setup/device_boutique.h" - -using std::vector; +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { bool Sniffer::registered_ = DeviceBoutique::Register("sniffer", &Sniffer::Create); -Sniffer::Sniffer(const vector& args) { +Sniffer::Sniffer(const std::vector& args) { if (args.size() >= 2) { Address::FromString(args[1], address_); } diff --git a/model/devices/sniffer.h b/model/devices/sniffer.h index 5ee49ff..60bee3e 100644 --- a/model/devices/sniffer.h +++ b/model/devices/sniffer.h @@ -25,8 +25,6 @@ namespace rootcanal { -using ::bluetooth::hci::Address; - class Sniffer : public Device { public: Sniffer(const std::vector& args); diff --git a/model/hci/h4_data_channel_packetizer.cc b/model/hci/h4_data_channel_packetizer.cc index e8f2114..15e6f3d 100644 --- a/model/hci/h4_data_channel_packetizer.cc +++ b/model/hci/h4_data_channel_packetizer.cc @@ -90,7 +90,8 @@ void H4DataChannelPacketizer::OnDataReady( disconnect_cb_(); return; } - FATAL("Read error in {}: {}", h4_parser_.CurrentState(), strerror(errno)); + FATAL("Read error in {}: {}", fmt::underlying(h4_parser_.CurrentState()), + strerror(errno)); } h4_parser_.Consume(buffer.data(), bytes_read); } diff --git a/model/hci/h4_parser.cc b/model/hci/h4_parser.cc index c263cd7..b84ad1f 100644 --- a/model/hci/h4_parser.cc +++ b/model/hci/h4_parser.cc @@ -85,7 +85,7 @@ void H4Parser::OnPacketReady() { iso_cb_(packet_); break; default: - FATAL("Unimplemented packet type {}", hci_packet_type_); + FATAL("Unimplemented packet type {}", fmt::underlying(hci_packet_type_)); } // Get ready for the next type byte. hci_packet_type_ = PacketType::UNKNOWN; diff --git a/model/hci/hci_socket_transport.cc b/model/hci/hci_socket_transport.cc index 82632e4..0fc556e 100644 --- a/model/hci/hci_socket_transport.cc +++ b/model/hci/hci_socket_transport.cc @@ -59,7 +59,8 @@ void HciSocketTransport::Tick() { h4_.OnDataReady(socket_); } void HciSocketTransport::Send(PacketType packet_type, const std::vector& packet) { if (!socket_ || !socket_->Connected()) { - INFO("Closed socket. Dropping packet of type {}", packet_type); + INFO("Closed socket. Dropping packet of type {}", + fmt::underlying(packet_type)); return; } uint8_t type = static_cast(packet_type); diff --git a/model/setup/phy_device.cc b/model/setup/phy_device.cc index 7704f36..59f3d52 100644 --- a/model/setup/phy_device.cc +++ b/model/setup/phy_device.cc @@ -40,6 +40,10 @@ bluetooth::hci::Address PhyDevice::GetAddress() const { return device_->GetAddress(); } +std::shared_ptr PhyDevice::GetDevice() const { + return device_; +} + void PhyDevice::SetAddress(bluetooth::hci::Address address) { device_->SetAddress(std::move(address)); } diff --git a/model/setup/phy_device.h b/model/setup/phy_device.h index b23ba87..af45dbe 100644 --- a/model/setup/phy_device.h +++ b/model/setup/phy_device.h @@ -44,6 +44,7 @@ class PhyDevice { int8_t tx_power); bluetooth::hci::Address GetAddress() const; + std::shared_ptr GetDevice() const; void SetAddress(bluetooth::hci::Address address); std::string ToString(); diff --git a/model/setup/test_command_handler.cc b/model/setup/test_command_handler.cc index 3225b53..45b947c 100644 --- a/model/setup/test_command_handler.cc +++ b/model/setup/test_command_handler.cc @@ -25,11 +25,16 @@ #include "device_boutique.h" #include "log.h" #include "phy.h" +#include "rootcanal/configuration.pb.h" using std::vector; namespace rootcanal { +static size_t ParseIntParam(std::string const& in) { + return static_cast(std::strtoul(in.c_str(), nullptr, 0)); +} + TestCommandHandler::TestCommandHandler(TestModel& test_model) : model_(test_model) { #define SET_HANDLER(command_name, method) \ @@ -45,6 +50,7 @@ TestCommandHandler::TestCommandHandler(TestModel& test_model) SET_HANDLER("del_device_from_phy", RemoveDeviceFromPhy); SET_HANDLER("list", List); SET_HANDLER("set_device_address", SetDeviceAddress); + SET_HANDLER("set_device_configuration", SetDeviceConfiguration); SET_HANDLER("set_timer_period", SetTimerPeriod); SET_HANDLER("start_timer", StartTimer); SET_HANDLER("stop_timer", StopTimer); @@ -125,7 +131,7 @@ void TestCommandHandler::AddRemote(const vector& args) { return; } - size_t port = std::stoi(args[1]); + size_t port = ParseIntParam(args[1]); Phy::Type phy_type = Phy::Type::BR_EDR; if ("LOW_ENERGY" == args[2]) { phy_type = Phy::Type::LOW_ENERGY; @@ -146,7 +152,7 @@ void TestCommandHandler::AddRemote(const vector& args) { } void TestCommandHandler::RemoveDevice(const vector& args) { - size_t dev_index = std::stoi(args[0]); + size_t dev_index = ParseIntParam(args[0]); model_.RemoveDevice(dev_index); response_string_ = "TestCommandHandler 'del' called with device at index " + @@ -171,7 +177,7 @@ void TestCommandHandler::AddPhy(const vector& args) { } void TestCommandHandler::RemovePhy(const vector& args) { - size_t phy_index = std::stoi(args[0]); + size_t phy_index = ParseIntParam(args[0]); model_.RemovePhy(phy_index); response_string_ = "TestCommandHandler 'del_phy' called with phy at index " + @@ -186,8 +192,8 @@ void TestCommandHandler::AddDeviceToPhy(const vector& args) { send_response_(response_string_); return; } - size_t dev_index = std::stoi(args[0]); - size_t phy_index = std::stoi(args[1]); + size_t dev_index = ParseIntParam(args[0]); + size_t phy_index = ParseIntParam(args[1]); model_.AddDeviceToPhy(dev_index, phy_index); response_string_ = "TestCommandHandler 'add_device_to_phy' called with device " + @@ -202,8 +208,8 @@ void TestCommandHandler::RemoveDeviceFromPhy(const vector& args) { send_response_(response_string_); return; } - size_t dev_index = std::stoi(args[0]); - size_t phy_index = std::stoi(args[1]); + size_t dev_index = ParseIntParam(args[0]); + size_t phy_index = ParseIntParam(args[1]); model_.RemoveDeviceFromPhy(dev_index, phy_index); response_string_ = "TestCommandHandler 'del_device_from_phy' called with device " + @@ -226,7 +232,7 @@ void TestCommandHandler::SetDeviceAddress(const vector& args) { send_response_(response_string_); return; } - size_t device_id = std::stoi(args[0]); + size_t device_id = ParseIntParam(args[0]); Address device_address{}; Address::FromString(args[1], device_address); model_.SetDeviceAddress(device_id, device_address); @@ -236,11 +242,44 @@ void TestCommandHandler::SetDeviceAddress(const vector& args) { send_response_(response_string_); } +void TestCommandHandler::SetDeviceConfiguration(const vector& args) { + if (args.size() != 2) { + response_string_ = + "TestCommandHandler 'set_device_configuration' takes two arguments"; + send_response_(response_string_); + return; + } + size_t device_id = ParseIntParam(args[0]); + rootcanal::configuration::ControllerPreset preset = + rootcanal::configuration::ControllerPreset::DEFAULT; + + if (args[1] == "default") { + preset = rootcanal::configuration::ControllerPreset::DEFAULT; + } else if (args[1] == "laird_bl654") { + preset = rootcanal::configuration::ControllerPreset::LAIRD_BL654; + } else if (args[1] == "csr_rck_pts_dongle") { + preset = rootcanal::configuration::ControllerPreset::CSR_RCK_PTS_DONGLE; + } else { + response_string_ = + "TestCommandHandler 'set_device_configuration' invalid configuration preset"; + send_response_(response_string_); + return; + } + + rootcanal::configuration::Controller configuration; + configuration.set_preset(preset); + model_.SetDeviceConfiguration(device_id, configuration); + response_string_ = "set_device_configuration " + args[0]; + response_string_ += " "; + response_string_ += args[1]; + send_response_(response_string_); +} + void TestCommandHandler::SetTimerPeriod(const vector& args) { if (args.size() != 1) { INFO("SetTimerPeriod takes 1 argument"); } - size_t period = std::stoi(args[0]); + size_t period = ParseIntParam(args[0]); if (period != 0) { response_string_ = "set timer period to "; response_string_ += args[0]; diff --git a/model/setup/test_command_handler.h b/model/setup/test_command_handler.h index 75b7ba3..4f41c32 100644 --- a/model/setup/test_command_handler.h +++ b/model/setup/test_command_handler.h @@ -72,6 +72,9 @@ class TestCommandHandler { // Change the device's MAC address void SetDeviceAddress(const std::vector& args); + // Change the device's configuration + void SetDeviceConfiguration(const std::vector& args); + // Timer management functions void SetTimerPeriod(const std::vector& args); diff --git a/model/setup/test_model.cc b/model/setup/test_model.cc index aee790f..060b4cf 100644 --- a/model/setup/test_model.cc +++ b/model/setup/test_model.cc @@ -241,6 +241,19 @@ void TestModel::SetDeviceAddress(PhyDevice::Identifier device_id, } } +void TestModel::SetDeviceConfiguration(PhyDevice::Identifier device_id, + rootcanal::configuration::Controller const& configuration) { + if (phy_devices_.find(device_id) != phy_devices_.end()) { + if (phy_devices_[device_id]->GetDevice()->GetTypeString() == "hci_device") { + std::shared_ptr device = std::static_pointer_cast( + phy_devices_[device_id]->GetDevice()); + device->SetProperties(ControllerProperties(configuration)); + } else { + ERROR(device_id, "failed to update the configuration, device is not a controller device"); + } + } +} + const std::string& TestModel::List() { list_string_.clear(); list_string_ += " Devices: \r\n"; diff --git a/model/setup/test_model.h b/model/setup/test_model.h index c9c23e4..b9871a6 100644 --- a/model/setup/test_model.h +++ b/model/setup/test_model.h @@ -30,6 +30,7 @@ #include "model/setup/async_manager.h" // for AsyncUserId, AsyncTaskId #include "phy.h" // for Phy, Phy::Type #include "phy_layer.h" +#include "rootcanal/configuration.pb.h" namespace rootcanal { class Device; @@ -97,6 +98,9 @@ class TestModel { void SetDeviceAddress(PhyDevice::Identifier device_id, Address device_address); + void SetDeviceConfiguration(PhyDevice::Identifier device_id, + rootcanal::configuration::Controller const& configuration); + // Let devices know about the passage of time void Tick(); void StartTimer(); diff --git a/packets/hci_packets.pdl b/packets/hci_packets.pdl index 063fc54..a2610f9 100644 --- a/packets/hci_packets.pdl +++ b/packets/hci_packets.pdl @@ -5633,38 +5633,59 @@ test LeGetVendorCapabilities { "\x53\xfd\x00", } -struct BaseVendorCapabilities { +packet LeGetVendorCapabilitiesComplete : CommandComplete (command_op_code = LE_GET_VENDOR_CAPABILITIES) { + status : ErrorCode, + vendor_capabilities : 8[], +} + +struct VendorCapabilities_V_0_96 { max_advt_instances: 8, - offloaded_resolution_of_private_address : 8, + offloaded_resolution_of_private_address: 8, total_scan_results_storage: 16, max_irk_list_sz: 8, filtering_support: 8, max_filter: 8, activity_energy_info_support: 8, -} - -packet LeGetVendorCapabilitiesComplete : CommandComplete (command_op_code = LE_GET_VENDOR_CAPABILITIES) { - status : ErrorCode, - base_vendor_capabilities : BaseVendorCapabilities, - _payload_, -} - -packet LeGetVendorCapabilitiesComplete095 : LeGetVendorCapabilitiesComplete { - version_supported: 16, + _fixed_ = 0x6000 : 16, // v0.96 total_num_of_advt_tracked: 16, extended_scan_support: 8, debug_logging_supported: 8, - _payload_, + le_address_generation_offloading_support: 8, } -packet LeGetVendorCapabilitiesComplete096 : LeGetVendorCapabilitiesComplete095 { - le_address_generation_offloading_support: 8, - _payload_, +struct VendorCapabilities_V_0_98 { + _reserved_ : 8, + _reserved_ : 8, + total_scan_results_storage: 16, + max_irk_list_sz: 8, + filtering_support: 8, + max_filter: 8, + activity_energy_info_support: 8, + _fixed_ = 0x6200 : 16, // v0.98 + total_num_of_advt_tracked: 16, + extended_scan_support: 8, + debug_logging_supported: 8, + _reserved_ : 8, + a2dp_source_offload_capability_mask: 32, + bluetooth_quality_report_support: 8, } -packet LeGetVendorCapabilitiesComplete098 : LeGetVendorCapabilitiesComplete096 { +struct VendorCapabilities_V_1_03 { + _reserved_ : 8, + _reserved_ : 8, + total_scan_results_storage: 16, + max_irk_list_sz: 8, + filtering_support: 8, + max_filter: 8, + activity_energy_info_support: 8, + _fixed_ = 0x0301 : 16, // v1.03 + total_num_of_advt_tracked: 16, + extended_scan_support: 8, + debug_logging_supported: 8, + _reserved_ : 8, a2dp_source_offload_capability_mask: 32, - bluetooth_quality_report_support: 8 + bluetooth_quality_report_support: 8, + dynamic_audio_buffer_support: 32, } // ----------------------------------------------------------------------------- @@ -5844,6 +5865,10 @@ enum ApcfFeatureSelection : 8 { packet LeApcfSetFilteringParameters : LeApcf (apcf_opcode = SET_FILTERING_PARAMETERS) { apcf_action : ApcfAction, + _payload_, +} + +packet LeApcfAddFilteringParameters : LeApcfSetFilteringParameters (apcf_action = ADD) { apcf_filter_index : 8, apcf_feature_selection : 16, apcf_list_logic_type : 16, @@ -5857,6 +5882,13 @@ packet LeApcfSetFilteringParameters : LeApcf (apcf_opcode = SET_FILTERING_PARAME num_of_tracking_entries : 16, } +packet LeApcfDeleteFilteringParameters : LeApcfSetFilteringParameters (apcf_action = DELETE) { + apcf_filter_index : 8, +} + +packet LeApcfClearFilteringParameters : LeApcfSetFilteringParameters (apcf_action = CLEAR) { +} + packet LeApcfSetFilteringParametersComplete : LeApcfComplete (apcf_opcode = SET_FILTERING_PARAMETERS) { apcf_action : ApcfAction, apcf_available_spaces : 8, @@ -5870,11 +5902,25 @@ enum ApcfApplicationAddressType : 8 { packet LeApcfBroadcasterAddress : LeApcf (apcf_opcode = BROADCASTER_ADDRESS) { apcf_action : ApcfAction, + _payload_, +} + +packet LeApcfAddBroadcasterAddress : LeApcfBroadcasterAddress (apcf_action = ADD) { + apcf_filter_index : 8, + apcf_broadcaster_address : Address, + apcf_application_address_type : ApcfApplicationAddressType, +} + +packet LeApcfDeleteBroadcasterAddress : LeApcfBroadcasterAddress (apcf_action = DELETE) { apcf_filter_index : 8, apcf_broadcaster_address : Address, apcf_application_address_type : ApcfApplicationAddressType, } +packet LeApcfClearBroadcasterAddress : LeApcfBroadcasterAddress (apcf_action = CLEAR) { + apcf_filter_index : 8, +} + packet LeApcfBroadcasterAddressComplete : LeApcfComplete (apcf_opcode = BROADCASTER_ADDRESS) { apcf_action : ApcfAction, apcf_available_spaces : 8, @@ -5891,13 +5937,13 @@ packet LeApcfServiceUuidComplete : LeApcfComplete (apcf_opcode = SERVICE_UUID) { apcf_available_spaces : 8, } -packet LeApcfSolicitationUuid : LeApcf (apcf_opcode = SERVICE_SOLICITATION_UUID) { +packet LeApcfServiceSolicitationUuid : LeApcf (apcf_opcode = SERVICE_SOLICITATION_UUID) { apcf_action : ApcfAction, apcf_filter_index : 8, acpf_uuid_data : 8[], } -packet LeApcfSolicitationUuidComplete : LeApcfComplete (apcf_opcode = SERVICE_SOLICITATION_UUID) { +packet LeApcfServiceSolicitationUuidComplete : LeApcfComplete (apcf_opcode = SERVICE_SOLICITATION_UUID) { apcf_action : ApcfAction, apcf_available_spaces : 8, } @@ -5935,13 +5981,16 @@ packet LeApcfServiceDataComplete : LeApcfComplete (apcf_opcode = SERVICE_DATA) { apcf_available_spaces : 8, } -packet LeApcfADType : LeApcf (apcf_opcode = AD_TYPE_FILTER) { +packet LeApcfAdTypeFilter : LeApcf (apcf_opcode = AD_TYPE_FILTER) { apcf_action : ApcfAction, apcf_filter_index : 8, - apcf_ad_type_data : 8[], + apcf_ad_type : 8, + _size_(apcf_ad_data) : 8, + apcf_ad_data : 8[], + apcf_ad_data_mask : 8[], } -packet LeApcfADTypeComplete : LeApcfComplete (apcf_opcode = AD_TYPE_FILTER) { +packet LeApcfAdTypeFilterComplete : LeApcfComplete (apcf_opcode = AD_TYPE_FILTER) { apcf_action : ApcfAction, apcf_available_spaces : 8, } diff --git a/proto/rootcanal/configuration.proto b/proto/rootcanal/configuration.proto index db0c387..0b6db15 100644 --- a/proto/rootcanal/configuration.proto +++ b/proto/rootcanal/configuration.proto @@ -50,6 +50,11 @@ message ControllerQuirks { message VendorFeatures { // Enable the support for the CSR vendor command. optional bool csr = 1; + // Enable the support for Android vendor commands. + // Note: not all required vendor commands are necessarily implemented + // in RootCanal, unimplemented commands will return a Command Status or + // Command Complete HCI event with the status Unsupported Opcode. + optional bool android = 2; } message Controller { diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 84dbd5e..1510574 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -26,6 +26,7 @@ num-derive = "0.3.3" num-integer = "0.1.45" num-traits = "0.2.14" paste = "1.0.4" +pdl-runtime = "0.2.2" pin-utils = "0.1.0" rand = "0.8.3" thiserror = "1.0.23" diff --git a/rust/src/llcp/iso.rs b/rust/src/llcp/iso.rs index 320651c..75754d3 100644 --- a/rust/src/llcp/iso.rs +++ b/rust/src/llcp/iso.rs @@ -546,12 +546,17 @@ impl IsoManager { } let Some(iso_interval) = iso_interval( - sdu_interval_c_to_p, sdu_interval_p_to_c, framed, + sdu_interval_c_to_p, + sdu_interval_p_to_c, + framed, max_transport_latency_c_to_p as u32 * 1000, - max_transport_latency_p_to_c as u32 * 1000) else { + max_transport_latency_p_to_c as u32 * 1000, + ) else { println!( "ISO_Interval cannot be chosen that fulfills the requirement from the CIG parameters"); - return self.send_hci_event(command_complete(hci::ErrorCode::UnsupportedFeatureOrParameterValue)); + return self.send_hci_event(command_complete( + hci::ErrorCode::UnsupportedFeatureOrParameterValue, + )); }; // If the Status return parameter is non-zero, then the state of the CIG diff --git a/rust/src/lmp/manager.rs b/rust/src/lmp/manager.rs index a1ba64c..9e93a01 100644 --- a/rust/src/lmp/manager.rs +++ b/rust/src/lmp/manager.rs @@ -20,6 +20,7 @@ use std::pin::Pin; use std::rc::{Rc, Weak}; use std::task::{Context, Poll}; +use pdl_runtime::Packet as _; use thiserror::Error; use crate::ffi::ControllerOps; @@ -28,8 +29,6 @@ use crate::lmp::procedure; use crate::num_hci_command_packets; use crate::packets::{hci, lmp}; -use pdl_runtime::Packet as _; - struct Link { peer: Cell, // Only store one HCI packet as our Num_HCI_Command_Packets diff --git a/rust/src/packets.rs b/rust/src/packets.rs index 3ad7e5f..1df9d47 100644 --- a/rust/src/packets.rs +++ b/rust/src/packets.rs @@ -16,6 +16,7 @@ pub mod hci { #![allow(clippy::all)] #![allow(unused)] #![allow(missing_docs)] + #![allow(non_camel_case_types)] include!(env!("HCI_PACKETS_PREBUILT")); diff --git a/scripts/test_channel.py b/scripts/test_channel.py index dc9d8f8..7a2d367 100644 --- a/scripts/test_channel.py +++ b/scripts/test_channel.py @@ -214,6 +214,12 @@ def do_set_device_address(self, args): """ self._test_channel.send_command('set_device_address', args.split()) + def do_set_device_configuration(self, args): + """Arguments: dev_num config Set the controller properties of the selected device. + + """ + self._test_channel.send_command('set_device_configuration', args.split()) + def do_list(self, args): """Arguments: [dev_num [attr]] List the devices from the controller, optionally filtered by device and attr. diff --git a/test/LMP/page_collision.py b/test/LMP/page_collision.py index 630df15..a90c9b1 100644 --- a/test/LMP/page_collision.py +++ b/test/LMP/page_collision.py @@ -56,10 +56,3 @@ async def test(self): bd_addr=peer_address, link_type=hci.LinkType.ACL, encryption_enabled=hci.Enable.DISABLED)) - - await self.expect_evt( - hci.ConnectionComplete(status=ErrorCode.SUCCESS, - connection_handle=acl_connection_handle, - bd_addr=peer_address, - link_type=hci.LinkType.ACL, - encryption_enabled=hci.Enable.DISABLED)) diff --git a/third_party/fmtlib b/third_party/fmtlib index 7bdf062..3a2c50d 160000 --- a/third_party/fmtlib +++ b/third_party/fmtlib @@ -1 +1 @@ -Subproject commit 7bdf0628b1276379886c7f6dda2cef2b3b374f0b +Subproject commit 3a2c50d4ac462d1d526d80f90e2cc3d8adf73e0a