// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "low_energy_connection_manager.h"

#include "garnet/drivers/bluetooth/lib/gatt/local_service_manager.h"
#include "garnet/drivers/bluetooth/lib/hci/defaults.h"
#include "garnet/drivers/bluetooth/lib/hci/hci.h"
#include "garnet/drivers/bluetooth/lib/hci/transport.h"
#include "garnet/drivers/bluetooth/lib/hci/util.h"
#include "garnet/drivers/bluetooth/lib/l2cap/channel_manager.h"
#include "garnet/drivers/bluetooth/lib/sm/pairing_state.h"
#include "garnet/drivers/bluetooth/lib/sm/util.h"

#include "lib/fxl/logging.h"
#include "lib/fxl/random/rand.h"
#include "lib/fxl/strings/string_printf.h"

#include "pairing_delegate.h"
#include "remote_device.h"
#include "remote_device_cache.h"

namespace btlib {
namespace gap {
namespace internal {

// Represents the state of an active connection. Each instance is owned
// and managed by a LowEnergyConnectionManager and is kept alive as long as
// there is at least one LowEnergyConnectionRef that references it.
class LowEnergyConnection {
 public:
  LowEnergyConnection(const std::string& id,
                      std::unique_ptr<hci::Connection> link,
                      async_t* dispatcher,
                      fxl::WeakPtr<LowEnergyConnectionManager> conn_mgr)
      : id_(id),
        link_(std::move(link)),
        dispatcher_(dispatcher),
        conn_mgr_(conn_mgr),
        weak_ptr_factory_(this) {
    FXL_DCHECK(!id_.empty());
    FXL_DCHECK(link_);
    FXL_DCHECK(dispatcher_);
    FXL_DCHECK(conn_mgr_);
  }

  ~LowEnergyConnection() {
    // Tell the controller to disconnect the link if it is marked as open.
    link_->Close();

    // Notify all active references that the link is gone. This will
    // synchronously notify all refs.
    CloseRefs();
  }

  LowEnergyConnectionRefPtr AddRef() {
    LowEnergyConnectionRefPtr conn_ref(
        new LowEnergyConnectionRef(id_, handle(), conn_mgr_));
    FXL_CHECK(conn_ref);

    refs_.insert(conn_ref.get());

    FXL_VLOG(1) << fxl::StringPrintf(
        "gap: LowEnergyConnectionManager: added ref (handle: 0x%04x, refs: "
        "%lu)",
        handle(), ref_count());

    return conn_ref;
  }

  void DropRef(LowEnergyConnectionRef* ref) {
    FXL_DCHECK(ref);

    __UNUSED size_t res = refs_.erase(ref);
    FXL_DCHECK(res == 1u) << "DropRef called with wrong connection reference";

    FXL_VLOG(1) << fxl::StringPrintf(
        "gap: LowEnergyConnectionManager: dropped ref (handle: 0x%04x, refs: "
        "%lu)",
        handle(), ref_count());
  }

  // Registers this connection with L2CAP and initializes the fixed channel
  // protocols.
  void InitializeFixedChannels(
      fbl::RefPtr<l2cap::L2CAP> l2cap, fbl::RefPtr<gatt::GATT> gatt,
      l2cap::L2CAP::LEConnectionParameterUpdateCallback cp_cb,
      l2cap::L2CAP::LinkErrorCallback link_error_cb) {
    auto self = weak_ptr_factory_.GetWeakPtr();
    auto channels_cb = [self, gatt](fbl::RefPtr<l2cap::Channel> att,
                                    fbl::RefPtr<l2cap::Channel> smp) {
      if (!self || !att || !smp) {
        FXL_VLOG(1) << "gap: link was closed before opening fixed channels";
        return;
      }

      // TODO(armansito): Provide correct I/O capabilities. Using DisplayOnly
      // for now.
      // TODO(armansito): Refactor so that RegisterLE parameters are passed in
      // the constructor. Each sm::PairingState should always have a LE bearer.
      auto io_cap = sm::IOCapability::kNoInputNoOutput;
      if (self->conn_mgr_->pairing_delegate()) {
        io_cap = self->conn_mgr_->pairing_delegate()->io_capability();
      }
      auto pairing = std::make_unique<sm::PairingState>(io_cap);
      pairing->RegisterLE(self->link_->WeakPtr(), std::move(smp));
      pairing->set_legacy_tk_delegate([self](auto method, auto responder) {
        if (self) {
          self->OnTKRequest(method, std::move(responder));
        }
      });
      pairing->set_le_ltk_callback([self](const sm::LTK& ltk) {
        if (self) {
          self->OnNewLTK(ltk);
        }
      });

      // TODO(armansito): We register the connection with GATT but don't perform
      // service discovery until after pairing has completed. Fix this so that
      // services are discovered immediately and pairing happens in response to
      // a service request.
      gatt->AddConnection(self->id(), std::move(att));
      pairing->UpdateSecurity(
          sm::SecurityLevel::kEncrypted,
          [gatt, id = self->id()](sm::Status status, const auto& props) {
            FXL_LOG(INFO) << "gap: Pairing status: " << status.ToString()
                          << ", properties: " << props.ToString();
            gatt->DiscoverServices(id);
          });

      self->pairing_ = std::move(pairing);
    };

    l2cap->RegisterLE(link_->handle(), link_->role(), std::move(cp_cb),
                      std::move(link_error_cb), std::move(channels_cb),
                      dispatcher_);
  }

  // Cancels any on going pairing procedures and sets up SMP to use the provided
  // new I/O capabilities for future pairing procedures.
  void ResetPairingState(sm::IOCapability ioc) {
    pairing_->Abort();

    // TODO: assign |pairing_| with new I/O capabilities
  }

  size_t ref_count() const { return refs_.size(); }

  const std::string& id() const { return id_; }
  hci::ConnectionHandle handle() const { return link_->handle(); }
  hci::Connection* link() const { return link_.get(); }

 private:
  // Called when a new LTK is received for this connection.
  void OnNewLTK(const sm::LTK& ltk) {
    FXL_VLOG(1) << "gap: Connection has new LTK";

    // TODO(armansito): Store key with remote device cache.
  }

  // Called when a TK is needed for pairing. This request should be resolved by
  // a pairing delegate after involving the user.
  void OnTKRequest(sm::PairingMethod method,
                   sm::PairingState::TKResponse responder) {
    FXL_VLOG(1) << "gap: TK request - method: "
                << sm::util::PairingMethodToString(method);

    auto delegate = conn_mgr_->pairing_delegate();
    if (!delegate) {
      FXL_LOG(ERROR) << "gap: Rejecting pairing without a PairingDelegate!";
      responder(false, 0);
      return;
    }

    if (method == sm::PairingMethod::kPasskeyEntryInput) {
      // The TK will be provided by the user.
      delegate->RequestPasskey(
          id(), [responder = std::move(responder)](int64_t passkey) {
            if (passkey < 0) {
              responder(false, 0);
            } else {
              responder(true, static_cast<uint32_t>(passkey));
            }
          });
      return;
    }

    if (method == sm::PairingMethod::kPasskeyEntryDisplay) {
      // Randomly generate a 6 digit passkey.
      // TODO(armansito): Use a uniform prng.
      uint32_t passkey = fxl::RandUint64() % 1000000;
      delegate->DisplayPasskey(
          id(), passkey,
          [passkey, responder = std::move(responder)](bool confirm) {
            responder(confirm, passkey);
          });
      return;
    }

    // TODO(armansito): Support providing a TK out of band.
    // OnTKRequest() should only be called for legacy pairing.
    FXL_DCHECK(method == sm::PairingMethod::kJustWorks);

    delegate->ConfirmPairing(id(),
                             [responder = std::move(responder)](bool confirm) {
                               // The TK for Just Works pairing is 0 (Vol 3,
                               // Part H, 2.3.5.2).
                               responder(confirm, 0);
                             });
  }

  void CloseRefs() {
    for (auto* ref : refs_) {
      ref->MarkClosed();
    }

    refs_.clear();
  }

  std::string id_;
  std::unique_ptr<hci::Connection> link_;
  async_t* dispatcher_;
  fxl::WeakPtr<LowEnergyConnectionManager> conn_mgr_;

  // SMP pairing manager.
  std::unique_ptr<sm::PairingState> pairing_;

  // LowEnergyConnectionManager is responsible for making sure that these
  // pointers are always valid.
  std::unordered_set<LowEnergyConnectionRef*> refs_;

  fxl::WeakPtrFactory<LowEnergyConnection> weak_ptr_factory_;

  FXL_DISALLOW_COPY_AND_ASSIGN(LowEnergyConnection);
};

}  // namespace internal

LowEnergyConnectionRef::LowEnergyConnectionRef(
    const std::string& device_id, hci::ConnectionHandle handle,
    fxl::WeakPtr<LowEnergyConnectionManager> manager)
    : active_(true), device_id_(device_id), handle_(handle), manager_(manager) {
  FXL_DCHECK(!device_id_.empty());
  FXL_DCHECK(manager_);
  FXL_DCHECK(handle_);
}

LowEnergyConnectionRef::~LowEnergyConnectionRef() {
  FXL_DCHECK(thread_checker_.IsCreationThreadCurrent());
  if (active_) {
    Release();
  }
};

void LowEnergyConnectionRef::Release() {
  FXL_DCHECK(thread_checker_.IsCreationThreadCurrent());
  FXL_DCHECK(active_);
  active_ = false;
  if (manager_) {
    manager_->ReleaseReference(this);
  }
}

void LowEnergyConnectionRef::MarkClosed() {
  active_ = false;
  if (closed_cb_) {
    // Move the callback out of |closed_cb_| to prevent it from deleting itself
    // by deleting |this|.
    auto f = std::move(closed_cb_);
    f();
  }
}

LowEnergyConnectionManager::PendingRequestData::PendingRequestData(
    const common::DeviceAddress& address,
    ConnectionResultCallback first_callback)
    : address_(address) {
  callbacks_.push_back(std::move(first_callback));
}

void LowEnergyConnectionManager::PendingRequestData::NotifyCallbacks(
    hci::Status status, const RefFunc& func) {
  FXL_DCHECK(!callbacks_.empty());
  for (const auto& callback : callbacks_) {
    callback(status, func());
  }
}

LowEnergyConnectionManager::LowEnergyConnectionManager(
    fxl::RefPtr<hci::Transport> hci, hci::LowEnergyConnector* connector,
    RemoteDeviceCache* device_cache, fbl::RefPtr<l2cap::L2CAP> l2cap,
    fbl::RefPtr<gatt::GATT> gatt)
    : hci_(hci),
      request_timeout_ms_(kLECreateConnectionTimeoutMs),
      dispatcher_(async_get_default()),
      device_cache_(device_cache),
      l2cap_(l2cap),
      gatt_(gatt),
      connector_(connector),
      weak_ptr_factory_(this) {
  FXL_DCHECK(dispatcher_);
  FXL_DCHECK(device_cache_);
  FXL_DCHECK(l2cap_);
  FXL_DCHECK(gatt_);
  FXL_DCHECK(hci_);
  FXL_DCHECK(connector_);

  auto self = weak_ptr_factory_.GetWeakPtr();

  // TODO(armansito): Setting this up here means that the
  // ClassicConnectionManager won't be able to listen to the same event. So this
  // event either needs to be handled elsewhere OR we make hci::CommandChannel
  // support registering multiple handlers for the same event.
  disconn_cmpl_handler_id_ = hci->command_channel()->AddEventHandler(
      hci::kDisconnectionCompleteEventCode,
      [self](const auto& event) {
        if (self)
          self->OnDisconnectionComplete(event);
      },
      dispatcher_);

  conn_update_cmpl_handler_id_ = hci_->command_channel()->AddLEMetaEventHandler(
      hci::kLEConnectionUpdateCompleteSubeventCode,
      [self](const auto& event) {
        if (self)
          self->OnLEConnectionUpdateComplete(event);
      },
      dispatcher_);
}

LowEnergyConnectionManager::~LowEnergyConnectionManager() {
  hci_->command_channel()->RemoveEventHandler(conn_update_cmpl_handler_id_);
  hci_->command_channel()->RemoveEventHandler(disconn_cmpl_handler_id_);

  FXL_VLOG(1) << "gap: LowEnergyConnectionManager: shutting down";

  weak_ptr_factory_.InvalidateWeakPtrs();

  // This will cancel any pending request.
  if (connector_->request_pending()) {
    connector_->Cancel();
  }

  // Clear |pending_requests_| and notify failure.
  for (auto& iter : pending_requests_) {
    iter.second.NotifyCallbacks(hci::Status(common::HostError::kFailed),
                                [] { return nullptr; });
  }
  pending_requests_.clear();

  // Clean up all connections.
  for (auto& iter : connections_) {
    CleanUpConnection(std::move(iter.second));
  }

  connections_.clear();
}

bool LowEnergyConnectionManager::Connect(const std::string& device_identifier,
                                         ConnectionResultCallback callback) {
  if (!connector_) {
    FXL_LOG(WARNING)
        << "gap: LowEnergyConnectionManager: Connect called during shutdown!";
    return false;
  }

  RemoteDevice* peer = device_cache_->FindDeviceById(device_identifier);
  if (!peer) {
    FXL_LOG(WARNING)
        << "gap: LowEnergyConnectionManager: device not found (id: "
        << device_identifier << ")";
    return false;
  }

  if (peer->technology() == TechnologyType::kClassic) {
    FXL_LOG(ERROR)
        << "gap: LowEnergyConnectionManager: device does not support LE: "
        << peer->ToString();
    return false;
  }

  if (!peer->connectable()) {
    FXL_LOG(ERROR)
        << "gap: LowEnergyConnectionManager: device not connectable: "
        << peer->ToString();
    return false;
  }

  // If we are already waiting to connect to |device_identifier| then we store
  // |callback| to be processed after the connection attempt completes (in
  // either success of failure).
  auto pending_iter = pending_requests_.find(device_identifier);
  if (pending_iter != pending_requests_.end()) {
    FXL_DCHECK(connections_.find(device_identifier) == connections_.end());
    FXL_DCHECK(connector_->request_pending());

    pending_iter->second.AddCallback(std::move(callback));
    return true;
  }

  // If there is already an active connection then we add a new reference and
  // succeed.
  auto conn_ref = AddConnectionRef(device_identifier);
  if (conn_ref) {
    async::PostTask(dispatcher_, [conn_ref = std::move(conn_ref),
                                  callback = std::move(callback)]() mutable {
      // Do not report success if the link has been disconnected (e.g. via
      // Disconnect() or other circumstances).
      if (!conn_ref->active()) {
        FXL_VLOG(1) << "gap: LowEnergyConnectionManager: Link "
                       "disconnected, ref is inactive";

        callback(hci::Status(common::HostError::kFailed), nullptr);
      } else {
        callback(hci::Status(), std::move(conn_ref));
      }
    });

    return true;
  }

  peer->set_le_connection_state(RemoteDevice::ConnectionState::kInitializing);
  pending_requests_[device_identifier] =
      PendingRequestData(peer->address(), std::move(callback));

  TryCreateNextConnection();

  return true;
}

bool LowEnergyConnectionManager::Disconnect(
    const std::string& device_identifier) {
  auto iter = connections_.find(device_identifier);
  if (iter == connections_.end()) {
    FXL_LOG(WARNING)
        << "gap: LowEnergyConnectionManager: device not connected (id: "
        << device_identifier << ")";
    return false;
  }

  // Remove the connection state from the internal map right away.
  auto conn = std::move(iter->second);
  connections_.erase(iter);

  FXL_LOG(INFO) << "gap: LowEnergyConnectionManager: disconnecting link: "
                << conn->link()->ToString();

  CleanUpConnection(std::move(conn));
  return true;
}

LowEnergyConnectionRefPtr
LowEnergyConnectionManager::RegisterRemoteInitiatedLink(
    hci::ConnectionPtr link) {
  FXL_DCHECK(link);
  FXL_VLOG(1) << "gap: le connmgr: new remote-initiated link (local addr: "
              << link->peer_address().ToString() << ") " << link->ToString();

  RemoteDevice* peer = UpdateRemoteDeviceWithLink(*link);

  // TODO(armansito): Use own address when storing the connection (NET-321).
  // Currently this will refuse the connection and disconnect the link if |peer|
  // is already connected to us by a different local address.
  return InitializeConnection(peer->identifier(), std::move(link));
}

void LowEnergyConnectionManager::SetPairingDelegate(
    fxl::WeakPtr<PairingDelegate> delegate) {
  for (auto& iter : connections_) {
    iter.second->ResetPairingState(delegate
                                       ? delegate->io_capability()
                                       : sm::IOCapability::kNoInputNoOutput);
  }
  pairing_delegate_ = delegate;
}

void LowEnergyConnectionManager::SetConnectionParametersCallbackForTesting(
    ConnectionParametersCallback callback) {
  test_conn_params_cb_ = std::move(callback);
}

void LowEnergyConnectionManager::SetDisconnectCallbackForTesting(
    DisconnectCallback callback) {
  test_disconn_cb_ = std::move(callback);
}

void LowEnergyConnectionManager::ReleaseReference(
    LowEnergyConnectionRef* conn_ref) {
  FXL_DCHECK(conn_ref);

  auto iter = connections_.find(conn_ref->device_identifier());
  FXL_DCHECK(iter != connections_.end());

  iter->second->DropRef(conn_ref);
  if (iter->second->ref_count() != 0u)
    return;

  // Move the connection object before erasing the entry.
  auto conn = std::move(iter->second);
  connections_.erase(iter);

  FXL_LOG(INFO)
      << "gap: LowEnergyConnectionManager: all refs dropped on connection: "
      << conn->link()->ToString();

  CleanUpConnection(std::move(conn));
}

void LowEnergyConnectionManager::TryCreateNextConnection() {
  // There can only be one outstanding LE Create Connection request at a time.
  if (connector_->request_pending()) {
    FXL_VLOG(1) << "gap: LowEnergyConnectionManager: HCI_LE_Create_Connection "
                   "command pending";
    return;
  }

  // TODO(armansito): Perform either the General or Auto Connection
  // Establishment procedure here (see NET-187).

  if (pending_requests_.empty()) {
    FXL_VLOG(2)
        << "gap: LowEnergyConnectionManager: No pending requests remaining";

    // TODO(armansito): Unpause discovery and disable background scanning if
    // there aren't any devices to auto-connect to.
    return;
  }

  for (auto& iter : pending_requests_) {
    const auto& next_device_addr = iter.second.address();
    RemoteDevice* peer = device_cache_->FindDeviceByAddress(next_device_addr);
    if (peer) {
      RequestCreateConnection(peer);
      break;
    }

    FXL_VLOG(1) << "gap: LowEnergyConnectionManager: Deferring connection "
                   "attempt for device: "
                << next_device_addr.ToString();

    // TODO(armansito): For now the requests for this device won't complete
    // until the next device discovery. This will no longer be an issue when we
    // use background scanning (see NET-187).
  }
}

void LowEnergyConnectionManager::RequestCreateConnection(RemoteDevice* peer) {
  FXL_DCHECK(peer);

  // During the initial connection to a peripheral we use the initial high
  // duty-cycle parameters to ensure that initiating procedures (bonding,
  // encryption setup, service discovery) are completed quickly. Once these
  // procedures are complete, we will change the connection interval to the
  // peripheral's preferred connection parameters (see v5.0, Vol 3, Part C,
  // Section 9.3.12).

  // TODO(armansito): Initiate the connection using the cached preferred
  // connection parameters if we are bonded.
  hci::LEPreferredConnectionParameters initial_params(
      kLEInitialConnIntervalMin, kLEInitialConnIntervalMax, 0,
      hci::defaults::kLESupervisionTimeout);

  auto self = weak_ptr_factory_.GetWeakPtr();
  auto status_cb = [self, device_id = peer->identifier()](hci::Status status,
                                                          auto link) {
    if (self)
      self->OnConnectResult(device_id, status, std::move(link));
  };

  // We set the scan window and interval to the same value for continuous
  // scanning.
  // TODO(armansito): Use one of the resolvable address types here.
  connector_->CreateConnection(hci::LEOwnAddressType::kPublic,
                               false /* use_whitelist */, peer->address(),
                               kLEScanFastInterval, kLEScanFastInterval,
                               initial_params, status_cb, request_timeout_ms_);
}

LowEnergyConnectionRefPtr LowEnergyConnectionManager::InitializeConnection(
    const std::string& device_id, std::unique_ptr<hci::Connection> link) {
  FXL_DCHECK(link);
  FXL_DCHECK(link->ll_type() == hci::Connection::LinkType::kLE);

  // TODO(armansito): For now reject having more than one link with the same
  // peer. This should change once this has more context on the local
  // destination for remote initiated connections (see NET-321).
  if (connections_.find(device_id) != connections_.end()) {
    FXL_VLOG(1) << "gap: Multiple links to same device; connection refused";
    link->Close();
    return nullptr;
  }

  // Add the connection to the L2CAP table. Incoming data will be buffered until
  // the channels are open.
  auto self = weak_ptr_factory_.GetWeakPtr();
  auto conn_param_update_cb = [self, handle = link->handle(),
                               device_id](const auto& params) {
    if (self) {
      self->OnNewLEConnectionParams(device_id, handle, params);
    }
  };

  auto link_error_cb = [self, device_id] {
    FXL_VLOG(1) << "gap: Link error received from L2CAP";
    if (self) {
      self->Disconnect(device_id);
    }
  };

  // Initialize connection.
  auto conn = std::make_unique<internal::LowEnergyConnection>(
      device_id, std::move(link), dispatcher_, weak_ptr_factory_.GetWeakPtr());
  conn->InitializeFixedChannels(l2cap_, gatt_, std::move(conn_param_update_cb),
                                std::move(link_error_cb));

  auto first_ref = conn->AddRef();
  connections_[device_id] = std::move(conn);

  // TODO(armansito): Should complete a few more things before returning the
  // connection:
  //    1. If this is the first time we connected to this device:
  //      a. Obtain LE remote features
  //      b. If master, obtain Peripheral Preferred Connection Parameters via
  //         GATT if available
  //      c. Initiate name discovery over GATT if complete name is unknown
  //      e. If master, allow slave to initiate procedures (service discovery,
  //         encryption setup, etc) for kLEConnectionPauseCentralMs before
  //         updating the connection parameters to the slave's preferred values.

  return first_ref;
}

LowEnergyConnectionRefPtr LowEnergyConnectionManager::AddConnectionRef(
    const std::string& device_identifier) {
  auto iter = connections_.find(device_identifier);
  if (iter == connections_.end())
    return nullptr;

  return iter->second->AddRef();
}

void LowEnergyConnectionManager::CleanUpConnection(
    std::unique_ptr<internal::LowEnergyConnection> conn, bool close_link) {
  FXL_DCHECK(conn);

  // Mark the peer device as no longer connected.
  RemoteDevice* peer = device_cache_->FindDeviceById(conn->id());
  FXL_DCHECK(peer);
  peer->set_le_connection_state(RemoteDevice::ConnectionState::kNotConnected);

  // This will disable L2CAP on this link.
  gatt_->RemoveConnection(conn->id());
  l2cap_->Unregister(conn->handle());

  if (!close_link) {
    // Mark the connection as already closed so that hci::Connection::Close()
    // doesn't send HCI_Disconnect to the controller.
    //
    // |close_link| is expected to be false only when this method is called due
    // to a disconnection that was not requested by the local host.
    conn->link()->set_closed();
  }

  // The |conn| is destroyed when it goes out of scope.
}

void LowEnergyConnectionManager::RegisterLocalInitiatedLink(
    std::unique_ptr<hci::Connection> link) {
  FXL_DCHECK(link);
  FXL_DCHECK(link->ll_type() == hci::Connection::LinkType::kLE);
  FXL_LOG(INFO) << "gap: LowEnergyConnectionManager: new connection: "
                << link->ToString();

  RemoteDevice* peer = UpdateRemoteDeviceWithLink(*link);

  // Initialize the connection  and obtain the initial reference.
  // This reference lasts until this method returns to prevent it from dropping
  // to 0 due to an unclaimed reference while notifying pending callbacks and
  // listeners below.
  auto first_ref = InitializeConnection(peer->identifier(), std::move(link));

  // We take care never to initiate more than one connection to the same peer.
  FXL_DCHECK(first_ref);

  auto conn_iter = connections_.find(peer->identifier());
  FXL_DCHECK(conn_iter != connections_.end());

  // For now, jump to the initialized state.
  peer->set_le_connection_state(RemoteDevice::ConnectionState::kConnected);

  auto iter = pending_requests_.find(peer->identifier());
  if (iter != pending_requests_.end()) {
    // Remove the entry from |pending_requests_| before notifying the callbacks.
    auto pending_req_data = std::move(iter->second);
    pending_requests_.erase(iter);

    pending_req_data.NotifyCallbacks(
        hci::Status(), [&conn_iter] { return conn_iter->second->AddRef(); });
  }

  // Release the extra reference before attempting the next connection. This
  // will disconnect the link if no callback retained its reference.
  first_ref = nullptr;

  FXL_DCHECK(!connector_->request_pending());
  TryCreateNextConnection();
}

RemoteDevice* LowEnergyConnectionManager::UpdateRemoteDeviceWithLink(
    const hci::Connection& link) {
  RemoteDevice* peer = device_cache_->FindDeviceByAddress(link.peer_address());
  if (!peer) {
    peer =
        device_cache_->NewDevice(link.peer_address(), true /* connectable */);
  }

  peer->TryMakeNonTemporary();
  peer->set_le_connection_params(link.low_energy_parameters());

  return peer;
}

void LowEnergyConnectionManager::OnConnectResult(
    const std::string& device_identifier, hci::Status status,
    hci::ConnectionPtr link) {
  FXL_DCHECK(connections_.find(device_identifier) == connections_.end());

  if (status) {
    FXL_VLOG(1) << "gap: le connmgr: LE connection request successful";
    RegisterLocalInitiatedLink(std::move(link));
    return;
  }

  // The request failed or timed out.
  FXL_LOG(ERROR)
      << "gap: LowEnergyConnectionManager: Failed to connect to device (id: "
      << device_identifier << ")";

  RemoteDevice* dev = device_cache_->FindDeviceById(device_identifier);
  FXL_CHECK(dev);
  dev->set_le_connection_state(RemoteDevice::ConnectionState::kNotConnected);

  // Notify the matching pending callbacks about the failure.
  auto iter = pending_requests_.find(device_identifier);
  FXL_DCHECK(iter != pending_requests_.end());

  // Remove the entry from |pending_requests_| before notifying callbacks.
  auto pending_req_data = std::move(iter->second);
  pending_requests_.erase(iter);
  pending_req_data.NotifyCallbacks(status, [] { return nullptr; });

  // Process the next pending attempt.
  FXL_DCHECK(!connector_->request_pending());
  TryCreateNextConnection();
}

void LowEnergyConnectionManager::OnDisconnectionComplete(
    const hci::EventPacket& event) {
  FXL_DCHECK(event.event_code() == hci::kDisconnectionCompleteEventCode);
  const auto& params =
      event.view().payload<hci::DisconnectionCompleteEventParams>();
  hci::ConnectionHandle handle = le16toh(params.connection_handle);

  if (params.status != hci::StatusCode::kSuccess) {
    FXL_VLOG(1) << fxl::StringPrintf(
        "gap: LowEnergyConnectionManager: HCI disconnection event received "
        "with error "
        "(status: \"%s\", handle: 0x%04x)",
        hci::StatusCodeToString(params.status).c_str(), handle);
    return;
  }

  FXL_LOG(INFO) << fxl::StringPrintf(
      "gap: LowEnergyConnectionManager: Link disconnected - "
      "status: \"%s\", handle: 0x%04x, reason: 0x%02x",
      hci::StatusCodeToString(params.status).c_str(), handle, params.reason);

  if (test_disconn_cb_)
    test_disconn_cb_(handle);

  // See if we can find a connection with a matching handle by walking the
  // connections list.
  auto iter = FindConnection(handle);
  if (iter == connections_.end()) {
    FXL_VLOG(1) << fxl::StringPrintf(
        "gap: LowEnergyConnectionManager: unknown connection handle: 0x%04x",
        handle);
    return;
  }

  // Found the connection. Remove the entry from |connections_| before notifying
  // the "closed" handlers.
  auto conn = std::move(iter->second);
  connections_.erase(iter);

  FXL_DCHECK(conn->ref_count());

  // The connection is already closed, so no need to send HCI_Disconnect.
  CleanUpConnection(std::move(conn), false /* close_link */);
}

void LowEnergyConnectionManager::OnLEConnectionUpdateComplete(
    const hci::EventPacket& event) {
  FXL_DCHECK(event.event_code() == hci::kLEMetaEventCode);
  FXL_DCHECK(event.view().payload<hci::LEMetaEventParams>().subevent_code ==
             hci::kLEConnectionUpdateCompleteSubeventCode);

  auto payload =
      event.le_event_params<hci::LEConnectionUpdateCompleteSubeventParams>();
  FXL_CHECK(payload);
  hci::ConnectionHandle handle = le16toh(payload->connection_handle);

  if (payload->status != hci::StatusCode::kSuccess) {
    FXL_LOG(WARNING) << fxl::StringPrintf(
        "gap: LowEnergyConnectionManager: HCI LE Connection Update Complete "
        "event with error (status: 0x%02x, handle: 0x%04x)",
        payload->status, handle);
    return;
  }

  auto iter = FindConnection(handle);
  if (iter == connections_.end()) {
    FXL_VLOG(1) << fxl::StringPrintf(
        "gap: Connection parameters received for unknown connection (handle: "
        "0x%04x)",
        handle);
    return;
  }

  const auto& conn = *iter->second;
  FXL_DCHECK(conn.handle() == handle);

  FXL_LOG(INFO) << fxl::StringPrintf(
      "gap: LE conn. params. updated (id: %s, handle: 0x%04x)",
      conn.id().c_str(), handle);

  hci::LEConnectionParameters params(le16toh(payload->conn_interval),
                                     le16toh(payload->conn_latency),
                                     le16toh(payload->supervision_timeout));
  conn.link()->set_low_energy_parameters(params);

  RemoteDevice* peer = device_cache_->FindDeviceById(conn.id());
  if (!peer) {
    FXL_VLOG(1) << "(ERROR): gap: LE conn. params. updated for peer no longer "
                   "in cache!";
    return;
  }

  peer->set_le_connection_params(params);

  if (test_conn_params_cb_)
    test_conn_params_cb_(*peer);
}

void LowEnergyConnectionManager::OnNewLEConnectionParams(
    const std::string& device_identifier, hci::ConnectionHandle handle,
    const hci::LEPreferredConnectionParameters& params) {
  FXL_VLOG(1) << fxl::StringPrintf(
      "gap: LE conn. params. received (handle: 0x%04x)", handle);

  RemoteDevice* peer = device_cache_->FindDeviceById(device_identifier);
  if (!peer) {
    FXL_VLOG(1) << "(ERROR): gap: LE conn. params. received from unknown peer";
    FXL_VLOG(1) << fxl::StringPrintf(
        "(ERROR): gap: LE conn. params. received from unknown peer (handle: "
        "0x%02x)",
        handle);
    return;
  }

  peer->set_le_preferred_connection_params(params);

  // Use the new parameters if we're not performing service discovery or
  // bonding.
  if (peer->le_connection_state() ==
          RemoteDevice::ConnectionState::kConnected ||
      peer->le_connection_state() == RemoteDevice::ConnectionState::kBonded) {
    UpdateConnectionParams(handle, params);
  }
}

void LowEnergyConnectionManager::UpdateConnectionParams(
    hci::ConnectionHandle handle,
    const hci::LEPreferredConnectionParameters& params) {
  FXL_VLOG(1) << fxl::StringPrintf(
      "gap: Sending LE conn. params. to controller (handle: 0x%04x)", handle);

  auto command = hci::CommandPacket::New(
      hci::kLEConnectionUpdate, sizeof(hci::LEConnectionUpdateCommandParams));
  auto event_params =
      command->mutable_view()
          ->mutable_payload<hci::LEConnectionUpdateCommandParams>();

  event_params->connection_handle = htole16(handle);
  event_params->conn_interval_min = htole16(params.min_interval());
  event_params->conn_interval_max = htole16(params.max_interval());
  event_params->conn_latency = htole16(params.max_latency());
  event_params->supervision_timeout = htole16(params.supervision_timeout());
  event_params->minimum_ce_length = 0x0000;
  event_params->maximum_ce_length = 0x0000;

  auto status_cb = [handle](auto id, const hci::EventPacket& event) {
    FXL_DCHECK(event.event_code() == hci::kCommandStatusEventCode);

    BTEV_TEST_VLOG(event, 1, "gap: Controller rejected LE conn. params");
  };

  hci_->command_channel()->SendCommand(std::move(command), dispatcher_,
                                       status_cb, hci::kCommandStatusEventCode);
}

LowEnergyConnectionManager::ConnectionMap::iterator
LowEnergyConnectionManager::FindConnection(hci::ConnectionHandle handle) {
  auto iter = connections_.begin();
  for (; iter != connections_.end(); ++iter) {
    const auto& conn = *iter->second;
    if (conn.handle() == handle)
      break;
  }
  return iter;
}

}  // namespace gap
}  // namespace btlib
