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

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

Merge "LE ACL: Expose Connection Update API to L2CAP"

parents d3ba7be7 6e2ea0eb
Loading
Loading
Loading
Loading
+81 −3
Original line number Diff line number Diff line
@@ -46,6 +46,9 @@ struct AclManager::acl_connection {
  os::Handler* disconnect_handler_ = nullptr;
  ConnectionManagementCallbacks* command_complete_callbacks_;
  common::OnceCallback<void(ErrorCode)> on_disconnect_callback_;
  // For LE Connection parameter update from L2CAP
  common::OnceCallback<void(ErrorCode)> on_connection_update_complete_callback_;
  os::Handler* on_connection_update_complete_callback_handler_ = nullptr;
  // Round-robin: Track if dequeue is registered for this connection
  bool is_registered_ = false;
  // Credits: Track the number of packets which have been sent to the controller
@@ -84,6 +87,9 @@ struct AclManager::impl {
    hci_layer_->RegisterLeEventHandler(SubeventCode::ENHANCED_CONNECTION_COMPLETE,
                                       Bind(&impl::on_le_enhanced_connection_complete, common::Unretained(this)),
                                       handler_);
    hci_layer_->RegisterLeEventHandler(SubeventCode::CONNECTION_UPDATE_COMPLETE,
                                       Bind(&impl::on_le_connection_update_complete, common::Unretained(this)),
                                       handler_);
    hci_layer_->RegisterEventHandler(EventCode::CONNECTION_PACKET_TYPE_CHANGED,
                                     Bind(&impl::on_connection_packet_type_changed, common::Unretained(this)),
                                     handler_);
@@ -864,6 +870,34 @@ struct AclManager::impl {
    }
  }

  void on_le_connection_update_complete(LeMetaEventView view) {
    auto complete_view = LeConnectionUpdateCompleteView::Create(view);
    if (!complete_view.IsValid()) {
      LOG_ERROR("Received on_le_connection_update_complete with invalid packet");
      return;
    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
      auto status = complete_view.GetStatus();
      std::string error_code = ErrorCodeText(status);
      LOG_ERROR("Received on_le_connection_update_complete with error code %s", error_code.c_str());
      return;
    }
    auto handle = complete_view.GetConnectionHandle();
    if (acl_connections_.find(handle) == acl_connections_.end()) {
      LOG_WARN("Can't find connection");
      return;
    }
    auto& connection = acl_connections_.find(handle)->second;
    if (connection.is_disconnected_) {
      LOG_INFO("Already disconnected");
      return;
    }
    if (!connection.on_connection_update_complete_callback_.is_null()) {
      connection.on_connection_update_complete_callback_handler_->Post(
          common::BindOnce(std::move(connection.on_connection_update_complete_callback_), complete_view.GetStatus()));
      connection.on_connection_update_complete_callback_handler_ = nullptr;
    }
  }

  bool is_classic_link_already_connected(Address address) {
    for (const auto& connection : acl_connections_) {
      if (connection.second.address_with_type_.GetAddress() == address) {
@@ -911,8 +945,6 @@ struct AclManager::impl {
    uint16_t conn_interval_max = 0x0C00;
    uint16_t conn_latency = 0x0C0;
    uint16_t supervision_timeout = 0x0C00;
    uint16_t minimum_ce_length = 0x0002;
    uint16_t maximum_ce_length = 0x0C00;
    ASSERT(le_client_callbacks_ != nullptr);

    connecting_le_.insert(address_with_type);
@@ -921,7 +953,7 @@ struct AclManager::impl {
        LeCreateConnectionBuilder::Create(le_scan_interval, le_scan_window, initiator_filter_policy,
                                          address_with_type.GetAddressType(), address_with_type.GetAddress(),
                                          own_address_type, conn_interval_min, conn_interval_max, conn_latency,
                                          supervision_timeout, minimum_ce_length, maximum_ce_length),
                                          supervision_timeout, kMinimumCeLength, kMaximumCeLength),
        common::BindOnce([](CommandStatusView status) {
          ASSERT(status.IsValid());
          ASSERT(status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION);
@@ -1188,6 +1220,17 @@ struct AclManager::impl {
                               common::BindOnce(&impl::on_read_clock_complete, common::Unretained(this)), handler_);
  }

  void handle_le_connection_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max,
                                   uint16_t conn_latency, uint16_t supervision_timeout) {
    auto packet = LeConnectionUpdateBuilder::Create(handle, conn_interval_min, conn_interval_max, conn_latency,
                                                    supervision_timeout, kMinimumCeLength, kMaximumCeLength);
    hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) {
                                 ASSERT(status.IsValid());
                                 ASSERT(status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION);
                               }),
                               handler_);
  }

  template <class T>
  void check_command_complete(CommandCompleteView view) {
    ASSERT(view.IsValid());
@@ -1574,6 +1617,31 @@ struct AclManager::impl {
    return true;
  }

  bool LeConnectionUpdate(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max,
                          uint16_t conn_latency, uint16_t supervision_timeout,
                          common::OnceCallback<void(ErrorCode)> done_callback, os::Handler* handler) {
    auto& connection = check_and_get_connection(handle);
    if (connection.is_disconnected_) {
      LOG_INFO("Already disconnected");
      return false;
    }
    if (!connection.on_connection_update_complete_callback_.is_null()) {
      LOG_INFO("There is another pending connection update");
      return false;
    }
    connection.on_connection_update_complete_callback_ = std::move(done_callback);
    connection.on_connection_update_complete_callback_handler_ = handler;
    if (conn_interval_min < 0x0006 || conn_interval_min > 0x0C80 || conn_interval_max < 0x0006 ||
        conn_interval_max > 0x0C80 || conn_latency > 0x01F3 || supervision_timeout < 0x000A ||
        supervision_timeout > 0x0C80) {
      LOG_ERROR("Invalid parameter");
      return false;
    }
    handler_->Post(BindOnce(&impl::handle_le_connection_update, common::Unretained(this), handle, conn_interval_min,
                            conn_interval_max, conn_latency, supervision_timeout));
    return true;
  }

  void Finish(uint16_t handle) {
    auto& connection = check_and_get_connection(handle);
    ASSERT_LOG(connection.is_disconnected_, "Finish must be invoked after disconnection (handle 0x%04hx)", handle);
@@ -1582,6 +1650,9 @@ struct AclManager::impl {

  const AclManager& acl_manager_;

  static constexpr uint16_t kMinimumCeLength = 0x0002;
  static constexpr uint16_t kMaximumCeLength = 0x0C00;

  Controller* controller_ = nullptr;
  uint16_t max_acl_packet_credits_ = 0;
  uint16_t acl_packet_credits_ = 0;
@@ -1732,6 +1803,13 @@ bool AclConnection::ReadClock(WhichClock which_clock) {
  return manager_->pimpl_->ReadClock(handle_, which_clock);
}

bool AclConnection::LeConnectionUpdate(uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency,
                                       uint16_t supervision_timeout,
                                       common::OnceCallback<void(ErrorCode)> done_callback, os::Handler* handler) {
  return manager_->pimpl_->LeConnectionUpdate(handle_, conn_interval_min, conn_interval_max, conn_latency,
                                              supervision_timeout, std::move(done_callback), handler);
}

void AclConnection::Finish() {
  return manager_->pimpl_->Finish(handle_);
}
+5 −0
Original line number Diff line number Diff line
@@ -143,6 +143,11 @@ class AclConnection {
  virtual bool ReadRssi();
  virtual bool ReadClock(WhichClock which_clock);

  // LE ACL Method
  virtual bool LeConnectionUpdate(uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency,
                                  uint16_t supervision_timeout, common::OnceCallback<void(ErrorCode)> done_callback,
                                  os::Handler* handler);

  // Ask AclManager to clean me up. Must invoke after on_disconnect is called
  virtual void Finish();

+39 −0
Original line number Diff line number Diff line
@@ -537,6 +537,45 @@ TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_fail) {
      0x0100, 0x0010, 0x0011, MasterClockAccuracy::PPM_30));
}

TEST_F(AclManagerTest, invoke_registered_callback_le_connection_update_success) {
  AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
  test_hci_layer_->SetCommandFuture();
  acl_manager_->CreateLeConnection(remote_with_type);

  auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_CREATE_CONNECTION);
  auto le_connection_management_command_view = LeConnectionManagementCommandView::Create(packet);
  auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
  ASSERT(command_view.IsValid());
  EXPECT_EQ(command_view.GetPeerAddress(), remote);
  EXPECT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);

  test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));

  auto first_connection = GetLeConnectionFuture();

  test_hci_layer_->IncomingLeMetaEvent(
      LeConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, 0x123, Role::SLAVE, AddressType::PUBLIC_DEVICE_ADDRESS,
                                          remote, 0x0100, 0x0010, 0x0011, MasterClockAccuracy::PPM_30));

  auto first_connection_status = first_connection.wait_for(kTimeout);
  ASSERT_EQ(first_connection_status, std::future_status::ready);

  std::shared_ptr<AclConnection> connection = GetLastLeConnection();
  ASSERT_EQ(connection->GetAddress(), remote);

  std::promise<ErrorCode> promise;
  auto future = promise.get_future();
  connection->LeConnectionUpdate(
      0x0006, 0x0C80, 0x0000, 0x000A,
      common::BindOnce([](std::promise<ErrorCode> promise, ErrorCode code) { promise.set_value(code); },
                       std::move(promise)),
      client_handler_);
  test_hci_layer_->IncomingLeMetaEvent(
      LeConnectionUpdateCompleteBuilder::Create(ErrorCode::SUCCESS, 0x123, 0x0006, 0x0000, 0x000A));
  EXPECT_EQ(future.wait_for(std::chrono::milliseconds(3)), std::future_status::ready);
  EXPECT_EQ(future.get(), ErrorCode::SUCCESS);
}

TEST_F(AclManagerTest, invoke_registered_callback_disconnection_complete) {
  uint16_t handle = 0x123;

+14 −1
Original line number Diff line number Diff line
@@ -55,6 +55,13 @@ void Link::Disconnect() {
  acl_connection_->Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
}

void Link::UpdateConnectionParameter(SignalId signal_id, uint16_t conn_interval_min, uint16_t conn_interval_max,
                                     uint16_t conn_latency, uint16_t supervision_timeout) {
  acl_connection_->LeConnectionUpdate(
      conn_interval_min, conn_interval_max, conn_latency, supervision_timeout,
      common::BindOnce(&Link::on_connection_update_complete, common::Unretained(this), signal_id), l2cap_handler_);
}

std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
  auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
  data_pipeline_manager_.AttachChannel(cid, channel,
@@ -172,11 +179,17 @@ uint16_t Link::GetInitialCredit() const {
  return parameter_provider_->GetLeInitialCredit();
}


void Link::SendLeCredit(Cid local_cid, uint16_t credit) {
  signalling_manager_.SendCredit(local_cid, credit);
}

void Link::on_connection_update_complete(SignalId signal_id, hci::ErrorCode error_code) {
  ConnectionParameterUpdateResponseResult result = (error_code == hci::ErrorCode::SUCCESS)
                                                       ? ConnectionParameterUpdateResponseResult::ACCEPTED
                                                       : ConnectionParameterUpdateResponseResult::REJECTED;
  signalling_manager_.SendConnectionParameterUpdateResponse(SignalId(), result);
}

}  // namespace internal
}  // namespace le
}  // namespace l2cap
+6 −0
Original line number Diff line number Diff line
@@ -67,6 +67,10 @@ class Link : public l2cap::internal::ILink {

  virtual void Disconnect();

  // Handles connection parameter update request from remote
  virtual void UpdateConnectionParameter(SignalId signal_id, uint16_t conn_interval_min, uint16_t conn_interval_max,
                                         uint16_t conn_latency, uint16_t supervision_timeout);

  // FixedChannel methods

  virtual std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy);
@@ -122,6 +126,8 @@ class Link : public l2cap::internal::ILink {
  std::unordered_map<Cid, PendingDynamicChannelConnection> local_cid_to_pending_dynamic_channel_connection_map_;
  os::Alarm link_idle_disconnect_alarm_{l2cap_handler_};
  DISALLOW_COPY_AND_ASSIGN(Link);

  void on_connection_update_complete(SignalId signal_id, hci::ErrorCode error_code);
};

}  // namespace internal
Loading