Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b1f4b9e authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Do not enter DISARMED for incoming connection"

parents c252318d 9b0a43b8
Loading
Loading
Loading
Loading
+114 −61
Original line number Diff line number Diff line
@@ -306,13 +306,17 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
    auto status = connection_complete.GetStatus();
    auto address = connection_complete.GetPeerAddress();
    auto peer_address_type = connection_complete.GetPeerAddressType();
    auto role = connection_complete.GetRole();
    AddressWithType remote_address(address, peer_address_type);
    AddressWithType local_address = le_address_manager_->GetCurrentAddress();
    const bool in_filter_accept_list = is_device_in_connect_list(remote_address);

    if (role == hci::Role::CENTRAL) {
      connectability_state_ = ConnectabilityState::DISARMED;
      if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) {
        on_le_connection_canceled_on_pause();
        return;
      }
    AddressWithType remote_address(address, peer_address_type);
    AddressWithType local_address = le_address_manager_->GetCurrentAddress();
      on_common_le_connection_complete(remote_address);
      if (status == ErrorCode::UNKNOWN_CONNECTION) {
        if (remote_address.GetAddress() != Address::kEmpty) {
@@ -325,7 +329,6 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {

      arm_on_resume_ = false;
      ready_to_unregister = true;
    const bool in_filter_accept_list = is_device_in_connect_list(remote_address);
      remove_device_from_connect_list(remote_address);

      if (!connect_list.empty()) {
@@ -339,11 +342,35 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
      }

      if (status != ErrorCode::SUCCESS) {
      le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectFail,
                                                common::Unretained(le_client_callbacks_), remote_address, status));
        le_client_handler_->Post(common::BindOnce(
            &LeConnectionCallbacks::OnLeConnectFail, common::Unretained(le_client_callbacks_), remote_address, status));
        return;
      }
    } else {
      LOG_INFO("Received connection complete with Peripheral role");
      if (le_client_handler_ == nullptr) {
        LOG_ERROR("No callbacks to call");
        return;
      }

      if (status != ErrorCode::SUCCESS) {
        std::string error_code = ErrorCodeText(status);
        LOG_WARN("Received on_le_connection_complete with error code %s", error_code.c_str());
        return;
      }

      if (in_filter_accept_list) {
        LOG_INFO(
            "Received incoming connection of device in filter accept_list, %s",
            PRIVATE_ADDRESS_WITH_TYPE(remote_address));
        remove_device_from_connect_list(remote_address);
        if (create_connection_timeout_alarms_.find(remote_address) != create_connection_timeout_alarms_.end()) {
          create_connection_timeout_alarms_.at(remote_address).Cancel();
          create_connection_timeout_alarms_.erase(remote_address);
        }
      }
    }

    uint16_t conn_interval = connection_complete.GetConnInterval();
    uint16_t conn_latency = connection_complete.GetConnLatency();
    uint16_t supervision_timeout = connection_complete.GetSupervisionTimeout();
@@ -352,7 +379,6 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
      return;
    }

    auto role = connection_complete.GetRole();
    uint16_t handle = connection_complete.GetConnectionHandle();
    auto queue = std::make_shared<AclConnection::Queue>(10);
    auto queue_down_end = queue->GetDownEnd();
@@ -380,14 +406,9 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
    auto address = connection_complete.GetPeerAddress();
    auto peer_address_type = connection_complete.GetPeerAddressType();
    auto peer_resolvable_address = connection_complete.GetPeerResolvablePrivateAddress();
    connectability_state_ = ConnectabilityState::DISARMED;
    if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) {
      on_le_connection_canceled_on_pause();
      return;
    }
    auto role = connection_complete.GetRole();

    AddressType remote_address_type;

    switch (peer_address_type) {
      case AddressType::PUBLIC_DEVICE_ADDRESS:
      case AddressType::PUBLIC_IDENTITY_ADDRESS:
@@ -399,6 +420,15 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
        break;
    }
    AddressWithType remote_address(address, remote_address_type);
    const bool in_filter_accept_list = is_device_in_connect_list(remote_address);

    if (role == hci::Role::CENTRAL) {
      connectability_state_ = ConnectabilityState::DISARMED;

      if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) {
        on_le_connection_canceled_on_pause();
        return;
      }

      on_common_le_connection_complete(remote_address);
      if (status == ErrorCode::UNKNOWN_CONNECTION) {
@@ -412,7 +442,6 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {

      arm_on_resume_ = false;
      ready_to_unregister = true;
    const bool in_filter_accept_list = is_device_in_connect_list(remote_address);
      remove_device_from_connect_list(remote_address);

      if (!connect_list.empty()) {
@@ -426,12 +455,36 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
      }

      if (status != ErrorCode::SUCCESS) {
      le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectFail,
                                                common::Unretained(le_client_callbacks_), remote_address, status));
        le_client_handler_->Post(common::BindOnce(
            &LeConnectionCallbacks::OnLeConnectFail, common::Unretained(le_client_callbacks_), remote_address, status));
        return;
      }

    auto role = connection_complete.GetRole();
    } else {
      LOG_INFO("Received connection complete with Peripheral role");
      if (le_client_handler_ == nullptr) {
        LOG_ERROR("No callbacks to call");
        return;
      }

      if (status != ErrorCode::SUCCESS) {
        std::string error_code = ErrorCodeText(status);
        LOG_WARN("Received on_le_enhanced_connection_complete with error code %s", error_code.c_str());
        return;
      }

      if (in_filter_accept_list) {
        LOG_INFO(
            "Received incoming connection of device in filter accept_list, %s",
            PRIVATE_ADDRESS_WITH_TYPE(remote_address));
        remove_device_from_connect_list(remote_address);
        if (create_connection_timeout_alarms_.find(remote_address) != create_connection_timeout_alarms_.end()) {
          create_connection_timeout_alarms_.at(remote_address).Cancel();
          create_connection_timeout_alarms_.erase(remote_address);
        }
      }
    }

    AddressWithType local_address;
    if (role == hci::Role::CENTRAL) {
      local_address = le_address_manager_->GetCurrentAddress();
+292 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "hci/acl_manager/le_impl.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <chrono>
@@ -23,6 +24,7 @@
#include "common/bidi_queue.h"
#include "common/callback.h"
#include "hci/acl_manager.h"
#include "hci/acl_manager/le_connection_management_callbacks.h"
#include "hci/address_with_type.h"
#include "hci/controller.h"
#include "hci/hci_packets.h"
@@ -41,8 +43,26 @@ namespace bluetooth {
namespace hci {
namespace acl_manager {

PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
  auto bytes = std::make_shared<std::vector<uint8_t>>();
  BitInserter i(*bytes);
  bytes->reserve(packet->size());
  packet->Serialize(i);
  return packet::PacketView<packet::kLittleEndian>(bytes);
}

class TestController : public Controller {
 public:
  bool IsSupported(OpCode op_code) const override {
    LOG_INFO("IsSupported");
    return supported_opcodes_.count(op_code) == 1;
  }

  void AddSupported(OpCode op_code) {
    LOG_INFO("AddSupported");
    supported_opcodes_.insert(op_code);
  }

  uint16_t GetNumAclPacketBuffers() const {
    return max_acl_packet_credits_;
  }
@@ -77,6 +97,7 @@ class TestController : public Controller {

 private:
  CompletedAclPacketsCallback acl_credits_callback_;
  std::set<OpCode> supported_opcodes_{};
};

class TestHciLayer : public HciLayer {
@@ -98,7 +119,90 @@ class TestHciLayer : public HciLayer {
    HciLayer& hci_;
  };

  void EnqueueCommand(
      std::unique_ptr<CommandBuilder> command,
      common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
    command_queue_.push(std::move(command));
    command_status_callbacks.push_back(std::move(on_status));
    if (command_promise_ != nullptr) {
      command_promise_->set_value();
      command_promise_.reset();
    }
  }

  void EnqueueCommand(
      std::unique_ptr<CommandBuilder> command,
      common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
    command_queue_.push(std::move(command));
    command_complete_callbacks.push_back(std::move(on_complete));
    if (command_promise_ != nullptr) {
      command_promise_->set_value();
      command_promise_.reset();
    }
  }

 public:
  void SetCommandFuture() {
    ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
    command_promise_ = std::make_unique<std::promise<void>>();
    command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
  }

  CommandView GetLastCommand() {
    if (command_queue_.empty()) {
      return CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
    }
    auto last = std::move(command_queue_.front());
    command_queue_.pop();
    return CommandView::Create(GetPacketView(std::move(last)));
  }

  CommandView GetCommand(OpCode op_code) {
    if (!command_queue_.empty()) {
      std::lock_guard<std::mutex> lock(mutex_);
      if (command_future_ != nullptr) {
        command_future_.reset();
        command_promise_.reset();
      }
    } else if (command_future_ != nullptr) {
      auto result = command_future_->wait_for(std::chrono::milliseconds(1000));
      EXPECT_NE(std::future_status::timeout, result);
    }
    std::lock_guard<std::mutex> lock(mutex_);
    ASSERT_LOG(
        !command_queue_.empty(), "Expecting command %s but command queue was empty", OpCodeText(op_code).c_str());
    CommandView command_packet_view = GetLastCommand();
    EXPECT_TRUE(command_packet_view.IsValid());
    EXPECT_EQ(command_packet_view.GetOpCode(), op_code);
    return command_packet_view;
  }

  void CommandCompleteCallback(std::unique_ptr<EventBuilder> event_builder) {
    auto event = EventView::Create(GetPacketView(std::move(event_builder)));
    CommandCompleteView complete_view = CommandCompleteView::Create(event);
    ASSERT_TRUE(complete_view.IsValid());
    ASSERT_NE((uint16_t)command_complete_callbacks.size(), 0);
    std::move(command_complete_callbacks.front()).Invoke(complete_view);
    command_complete_callbacks.pop_front();
  }

  void CommandStatusCallback(std::unique_ptr<EventBuilder> event_builder) {
    auto event = EventView::Create(GetPacketView(std::move(event_builder)));
    CommandStatusView status_view = CommandStatusView::Create(event);
    ASSERT_TRUE(status_view.IsValid());
    ASSERT_NE((uint16_t)command_status_callbacks.size(), 0);
    std::move(command_status_callbacks.front()).Invoke(status_view);
    command_status_callbacks.pop_front();
  }

  void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
    auto packet = GetPacketView(std::move(event_builder));
    EventView event = EventView::Create(packet);
    LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
    EXPECT_TRUE(meta_event_view.IsValid());
    le_event_handler_.Invoke(meta_event_view);
  }

  LeAclConnectionInterface* GetLeAclConnectionInterface(
      common::ContextualCallback<void(LeMetaEventView)> event_handler,
      common::ContextualCallback<void(uint16_t, ErrorCode)> on_disconnect,
@@ -107,12 +211,21 @@ class TestHciLayer : public HciLayer {
          on_read_remote_version) override {
    disconnect_handlers_.push_back(on_disconnect);
    read_remote_version_handlers_.push_back(on_read_remote_version);
    return &le_acl_connection_manager_interface_2_;
    le_event_handler_ = event_handler;
    return &le_acl_connection_manager_interface_;
  }

  void PutLeAclConnectionInterface() override {}

  CommandInterfaceImpl<AclCommandBuilder> le_acl_connection_manager_interface_2_{*this};
 private:
  std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
  std::list<common::ContextualOnceCallback<void(CommandStatusView)>> command_status_callbacks;
  common::ContextualCallback<void(LeMetaEventView)> le_event_handler_;
  std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
  std::unique_ptr<std::promise<void>> command_promise_;
  std::unique_ptr<std::future<void>> command_future_;
  mutable std::mutex mutex_;
  CommandInterfaceImpl<AclCommandBuilder> le_acl_connection_manager_interface_{*this};
};

class LeImplTest : public ::testing::Test {
@@ -127,6 +240,24 @@ class LeImplTest : public ::testing::Test {
    hci_queue_.GetDownEnd()->RegisterDequeue(
        handler_, common::Bind(&LeImplTest::HciDownEndDequeue, common::Unretained(this)));
    le_impl_ = new le_impl(hci_layer_, controller_, handler_, round_robin_scheduler_, true);
    le_impl_->handle_register_le_callbacks(&mock_le_connection_callbacks_, handler_);

    // Set address policy
    hci_layer_->SetCommandFuture();
    hci::Address address;
    Address::FromString("D0:05:04:03:02:01", address);
    hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
    crypto_toolbox::Octet16 rotation_irk{};
    auto minimum_rotation_time = std::chrono::milliseconds(7 * 60 * 1000);
    auto maximum_rotation_time = std::chrono::milliseconds(15 * 60 * 1000);
    le_impl_->set_privacy_policy_for_initiator_address(
        LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS,
        address_with_type,
        rotation_irk,
        minimum_rotation_time,
        maximum_rotation_time);
    hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
    hci_layer_->CommandCompleteCallback(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  }

  void TearDown() override {
@@ -172,6 +303,16 @@ class LeImplTest : public ::testing::Test {
    }
  }

  class MockLeConnectionCallbacks : public LeConnectionCallbacks {
   public:
    MOCK_METHOD(
        void,
        OnLeConnectSuccess,
        (AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection),
        (override));
    MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
  } mock_le_connection_callbacks_;

  uint16_t packet_count_;
  std::unique_ptr<std::promise<void>> packet_promise_;
  std::unique_ptr<std::future<void>> packet_future_;
@@ -181,7 +322,7 @@ class LeImplTest : public ::testing::Test {

  Thread* thread_;
  Handler* handler_;
  HciLayer* hci_layer_{nullptr};
  TestHciLayer* hci_layer_{nullptr};
  TestController* controller_;
  RoundRobinScheduler* round_robin_scheduler_{nullptr};

@@ -228,6 +369,154 @@ TEST_F(LeImplTest, remove_device_from_connect_list) {
  ASSERT_EQ(0UL, le_impl_->connect_list.size());
}

TEST_F(LeImplTest, connection_complete_with_periperal_role) {
  // Create connection
  hci_layer_->SetCommandFuture();
  le_impl_->create_le_connection(
      {{0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, AddressType::PUBLIC_DEVICE_ADDRESS}, true, false);
  hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
  hci_layer_->SetCommandFuture();
  hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
  hci_layer_->CommandStatusCallback(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  // Check state is ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);

  // Receive connection complete of incoming connection (Role::PERIPHERAL)
  hci::Address remote_address;
  Address::FromString("D0:05:04:03:02:01", remote_address);
  hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, testing::_));
  hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
      ErrorCode::SUCCESS,
      0x0041,
      Role::PERIPHERAL,
      AddressType::PUBLIC_DEVICE_ADDRESS,
      remote_address,
      0x0024,
      0x0000,
      0x0011,
      ClockAccuracy::PPM_30));
  sync_handler();

  // Check state is still ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
}

TEST_F(LeImplTest, enhanced_connection_complete_with_periperal_role) {
  controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION);
  // Create connection
  hci_layer_->SetCommandFuture();
  le_impl_->create_le_connection(
      {{0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, AddressType::PUBLIC_DEVICE_ADDRESS}, true, false);
  hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
  hci_layer_->SetCommandFuture();
  hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION);
  hci_layer_->CommandStatusCallback(LeExtendedCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  // Check state is ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);

  // Receive connection complete of incoming connection (Role::PERIPHERAL)
  hci::Address remote_address;
  Address::FromString("D0:05:04:03:02:01", remote_address);
  hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, testing::_));
  hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
      ErrorCode::SUCCESS,
      0x0041,
      Role::PERIPHERAL,
      AddressType::PUBLIC_DEVICE_ADDRESS,
      remote_address,
      Address::kEmpty,
      Address::kEmpty,
      0x0024,
      0x0000,
      0x0011,
      ClockAccuracy::PPM_30));
  sync_handler();

  // Check state is still ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
}

TEST_F(LeImplTest, connection_complete_with_central_role) {
  hci::Address remote_address;
  Address::FromString("D0:05:04:03:02:01", remote_address);
  hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
  // Create connection
  hci_layer_->SetCommandFuture();
  le_impl_->create_le_connection(address_with_type, true, false);
  hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
  hci_layer_->SetCommandFuture();
  hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
  hci_layer_->CommandStatusCallback(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  // Check state is ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);

  // Receive connection complete of outgoing connection (Role::CENTRAL)
  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, testing::_));
  hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
      ErrorCode::SUCCESS,
      0x0041,
      Role::CENTRAL,
      AddressType::PUBLIC_DEVICE_ADDRESS,
      remote_address,
      0x0024,
      0x0000,
      0x0011,
      ClockAccuracy::PPM_30));
  sync_handler();

  // Check state is DISARMED
  ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
}

TEST_F(LeImplTest, enhanced_connection_complete_with_central_role) {
  controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION);
  hci::Address remote_address;
  Address::FromString("D0:05:04:03:02:01", remote_address);
  hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
  // Create connection
  hci_layer_->SetCommandFuture();
  le_impl_->create_le_connection(address_with_type, true, false);
  hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
  hci_layer_->SetCommandFuture();
  hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION);
  hci_layer_->CommandStatusCallback(LeExtendedCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  // Check state is ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);

  // Receive connection complete of outgoing connection (Role::CENTRAL)
  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, testing::_));
  hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
      ErrorCode::SUCCESS,
      0x0041,
      Role::CENTRAL,
      AddressType::PUBLIC_DEVICE_ADDRESS,
      remote_address,
      Address::kEmpty,
      Address::kEmpty,
      0x0024,
      0x0000,
      0x0011,
      ClockAccuracy::PPM_30));
  sync_handler();

  // Check state is DISARMED
  ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
}

}  // namespace acl_manager
}  // namespace hci
}  // namespace bluetooth