// Copyright 2019 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 "connection.h"

#include <endian.h>

#include "command_channel.h"
#include "defaults.h"
#include "lib/async/default.h"
#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/hci.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/status.h"
#include "src/lib/fxl/strings/string_printf.h"
#include "transport.h"

namespace bt::hci {

// Production implementation of the Connection class against a HCI transport.
class ConnectionImpl final : public Connection {
 public:
  ConnectionImpl(ConnectionHandle handle, LinkType ll_type, Role role,
                 const DeviceAddress& local_address, const DeviceAddress& peer_address,
                 fxl::WeakPtr<Transport> hci);
  ~ConnectionImpl() override;

  // Connection overrides:
  fxl::WeakPtr<Connection> WeakPtr() override;
  bool StartEncryption() override;
  State state() const { return conn_state_; }

  // Sends HCI Disconnect command with |reason|. Takes over handling of HCI
  // Disconnection Complete event with a lambda so that connection instance can be safely destroyed
  // immediately.
  void Disconnect(StatusCode reason) override;

  void set_state(State state) { conn_state_ = state; };

 private:
  // Start the BR/EDR link layer encryption. |ltk_| and |ltk_type_| must have already been set and
  // may be used for bonding and detecting the security properties following the encryption enable.
  bool BrEdrStartEncryption();

  // Start the LE link layer authentication procedure using the given |ltk|.
  bool LEStartEncryption(const LinkKey& ltk);

  // Called when encryption is enabled or disabled as a result of the link layer
  // encryption "start" or "pause" procedure. If |status| indicates failure,
  // then this method will disconnect the link before notifying the encryption
  // change handler.
  void HandleEncryptionStatus(Status status, bool enabled);

  // Request the current encryption key size and call |key_size_validity_cb|
  // when the controller responds. |key_size_validity_cb| will be called with a
  // success only if the link is encrypted with a key of size at least
  // |hci::kMinEncryptionKeySize|. Only valid for ACL-U connections.
  void ValidateAclEncryptionKeySize(hci::StatusCallback key_size_validity_cb);

  // HCI event handlers.
  CommandChannel::EventCallbackResult OnEncryptionChangeEvent(const EventPacket& event);
  CommandChannel::EventCallbackResult OnEncryptionKeyRefreshCompleteEvent(const EventPacket& event);
  CommandChannel::EventCallbackResult OnLELongTermKeyRequestEvent(const EventPacket& event);
  CommandChannel::EventCallbackResult OnDisconnectionCompleteEvent(const EventPacket& event);

  // Checks |event|, unregisters link, and clears pending packets count.
  // If the disconnection was initiated by the peer, call |peer_disconnect_callback|.
  // Returns true if event was valid and for this connection.
  // This method is static so that it can be called in an event handler
  // after this object has been destroyed.
  static CommandChannel::EventCallbackResult OnDisconnectionComplete(
      fxl::WeakPtr<ConnectionImpl> self, ConnectionHandle handle, fxl::WeakPtr<Transport> hci,
      const EventPacket& event);

  fit::thread_checker thread_checker_;

  // IDs for encryption related HCI event handlers.
  CommandChannel::EventHandlerId enc_change_id_;
  CommandChannel::EventHandlerId enc_key_refresh_cmpl_id_;
  CommandChannel::EventHandlerId le_ltk_request_id_;

  // The underlying HCI transport.
  fxl::WeakPtr<Transport> hci_;

  State conn_state_;

  // Keep this as the last member to make sure that all weak pointers are
  // invalidated before other members get destroyed.
  fxl::WeakPtrFactory<ConnectionImpl> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ConnectionImpl);
};

namespace {

template <
    CommandChannel::EventCallbackResult (ConnectionImpl::*EventHandlerMethod)(const EventPacket&)>
CommandChannel::EventCallback BindEventHandler(fxl::WeakPtr<ConnectionImpl> conn) {
  return [conn](const auto& event) {
    if (conn) {
      return ((conn.get())->*EventHandlerMethod)(event);
    }
    return CommandChannel::EventCallbackResult::kRemove;
  };
}

}  // namespace

// ====== Connection member methods  =====

std::string Connection::LinkTypeToString(Connection::LinkType type) {
  switch (type) {
    case Connection::LinkType::kACL:
      return "ACL";
    case Connection::LinkType::kSCO:
      return "SCO";
    case Connection::LinkType::kESCO:
      return "ESCO";
    case Connection::LinkType::kLE:
      return "LE";
  }

  ZX_PANIC("invalid link type: %u", static_cast<unsigned int>(type));
  return "(invalid)";
}

// static
std::unique_ptr<Connection> Connection::CreateLE(ConnectionHandle handle, Role role,
                                                 const DeviceAddress& local_address,
                                                 const DeviceAddress& peer_address,
                                                 const LEConnectionParameters& params,
                                                 fxl::WeakPtr<Transport> hci) {
  ZX_DEBUG_ASSERT(local_address.type() != DeviceAddress::Type::kBREDR);
  ZX_DEBUG_ASSERT(peer_address.type() != DeviceAddress::Type::kBREDR);
  auto conn = std::make_unique<ConnectionImpl>(handle, LinkType::kLE, role, local_address,
                                               peer_address, std::move(hci));
  conn->set_low_energy_parameters(params);
  return conn;
}

// static
std::unique_ptr<Connection> Connection::CreateACL(ConnectionHandle handle, Role role,
                                                  const DeviceAddress& local_address,
                                                  const DeviceAddress& peer_address,
                                                  fxl::WeakPtr<Transport> hci) {
  ZX_DEBUG_ASSERT(local_address.type() == DeviceAddress::Type::kBREDR);
  ZX_DEBUG_ASSERT(peer_address.type() == DeviceAddress::Type::kBREDR);
  auto conn = std::make_unique<ConnectionImpl>(handle, LinkType::kACL, role, local_address,
                                               peer_address, std::move(hci));
  return conn;
}

std::unique_ptr<Connection> Connection::CreateSCO(hci::LinkType link_type, ConnectionHandle handle,
                                                  const DeviceAddress& local_address,
                                                  const DeviceAddress& peer_address,
                                                  fxl::WeakPtr<Transport> hci) {
  ZX_ASSERT(local_address.type() == DeviceAddress::Type::kBREDR);
  ZX_ASSERT(peer_address.type() == DeviceAddress::Type::kBREDR);
  ZX_ASSERT(link_type == hci::LinkType::kSCO || link_type == hci::LinkType::kExtendedSCO);

  LinkType conn_type = link_type == hci::LinkType::kSCO ? LinkType::kSCO : LinkType::kESCO;

  // TODO(fxb/61070): remove role for SCO connections, as it has no meaning
  auto conn = std::make_unique<ConnectionImpl>(handle, conn_type, Role::kMaster, local_address,
                                               peer_address, std::move(hci));
  return conn;
}

Connection::Connection(ConnectionHandle handle, LinkType ll_type, Role role,
                       const DeviceAddress& local_address, const DeviceAddress& peer_address)
    : ll_type_(ll_type),
      handle_(handle),
      role_(role),
      local_address_(local_address),
      peer_address_(peer_address) {
  ZX_DEBUG_ASSERT(handle_);
}

std::string Connection::ToString() const {
  std::string params = "";
  if (ll_type() == LinkType::kLE) {
    params = ", " + le_params_.ToString();
  }
  return fxl::StringPrintf("(%s link - handle: %#.4x, role: %s, address: %s%s)",
                           LinkTypeToString(ll_type_).c_str(), handle_,
                           role_ == Role::kMaster ? "master" : "slave",
                           peer_address_.ToString().c_str(), params.c_str());
}

// ====== ConnectionImpl member methods ======

ConnectionImpl::ConnectionImpl(ConnectionHandle handle, LinkType ll_type, Role role,
                               const DeviceAddress& local_address,
                               const DeviceAddress& peer_address, fxl::WeakPtr<Transport> hci)
    : Connection(handle, ll_type, role, local_address, peer_address),
      hci_(std::move(hci)),
      conn_state_(State::kConnected),
      weak_ptr_factory_(this) {
  ZX_DEBUG_ASSERT(hci_);

  auto self = weak_ptr_factory_.GetWeakPtr();

  enc_change_id_ = hci_->command_channel()->AddEventHandler(
      kEncryptionChangeEventCode, BindEventHandler<&ConnectionImpl::OnEncryptionChangeEvent>(self));

  enc_key_refresh_cmpl_id_ = hci_->command_channel()->AddEventHandler(
      kEncryptionKeyRefreshCompleteEventCode,
      BindEventHandler<&ConnectionImpl::OnEncryptionKeyRefreshCompleteEvent>(self));

  le_ltk_request_id_ = hci_->command_channel()->AddLEMetaEventHandler(
      kLELongTermKeyRequestSubeventCode,
      BindEventHandler<&ConnectionImpl::OnLELongTermKeyRequestEvent>(self));

  auto disconn_complete_handler = [self, handle, hci = hci_](auto& event) {
    return ConnectionImpl::OnDisconnectionComplete(self, handle, hci, event);
  };

  hci_->command_channel()->AddEventHandler(kDisconnectionCompleteEventCode,
                                           disconn_complete_handler);

  // Allow packets to be sent on this link immediately.
  hci_->acl_data_channel()->RegisterLink(handle, ll_type);
}

ConnectionImpl::~ConnectionImpl() {
  if (conn_state_ == Connection::State::kConnected) {
    Disconnect(StatusCode::kRemoteUserTerminatedConnection);
  }

  // Unregister HCI event handlers.
  hci_->command_channel()->RemoveEventHandler(enc_change_id_);
  hci_->command_channel()->RemoveEventHandler(enc_key_refresh_cmpl_id_);
  hci_->command_channel()->RemoveEventHandler(le_ltk_request_id_);
}

fxl::WeakPtr<Connection> ConnectionImpl::WeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }

CommandChannel::EventCallbackResult ConnectionImpl::OnDisconnectionComplete(
    fxl::WeakPtr<ConnectionImpl> self, ConnectionHandle handle, fxl::WeakPtr<Transport> hci,
    const EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == kDisconnectionCompleteEventCode);

  if (event.view().payload_size() != sizeof(DisconnectionCompleteEventParams)) {
    bt_log(WARN, "hci", "malformed disconnection complete event");
    return CommandChannel::EventCallbackResult::kContinue;
  }

  const auto& params = event.params<DisconnectionCompleteEventParams>();
  const auto event_handle = le16toh(params.connection_handle);

  // Silently ignore this event as it isn't meant for this connection.
  if (event_handle != handle) {
    return CommandChannel::EventCallbackResult::kContinue;
  }

  bt_log(INFO, "hci", "disconnection complete - %s, handle: %#.4x, reason: %#.2x",
         bt_str(event.ToStatus()), handle, params.reason);

  // Stop data flow and revoke queued packets for this connection.
  hci->acl_data_channel()->UnregisterLink(handle);

  // Notify ACL data channel that packets have been flushed from controller buffer.
  hci->acl_data_channel()->ClearControllerPacketCount(handle);

  if (!self) {
    return CommandChannel::EventCallbackResult::kRemove;
  }

  self->set_state(State::kDisconnected);

  // Peer disconnect. Callback may destroy connection.
  if (self->peer_disconnect_callback()) {
    self->peer_disconnect_callback()(self.get(), params.reason);
  }

  return CommandChannel::EventCallbackResult::kRemove;
}

void ConnectionImpl::Disconnect(StatusCode reason) {
  ZX_ASSERT(conn_state_ == Connection::State::kConnected);

  conn_state_ = Connection::State::kWaitingForDisconnectionComplete;

  // Here we send a HCI_Disconnect command without waiting for it to complete.
  auto status_cb = [](auto id, const EventPacket& event) {
    ZX_DEBUG_ASSERT(event.event_code() == kCommandStatusEventCode);
    hci_is_error(event, TRACE, "hci", "ignoring disconnection failure");
  };

  auto disconn = CommandPacket::New(kDisconnect, sizeof(DisconnectCommandParams));
  auto params = disconn->mutable_payload<DisconnectCommandParams>();
  params->connection_handle = htole16(handle());
  params->reason = reason;

  bt_log(DEBUG, "hci", "disconnecting connection (handle: %#.4x, reason: %#.2x)", handle(), reason);

  // Send HCI Disconnect.
  hci_->command_channel()->SendCommand(std::move(disconn), std::move(status_cb),
                                       kCommandStatusEventCode);
}

bool ConnectionImpl::StartEncryption() {
  ZX_DEBUG_ASSERT(thread_checker_.is_thread_valid());
  if (conn_state_ != Connection::State::kConnected) {
    bt_log(DEBUG, "hci", "connection closed; cannot start encryption");
    return false;
  }

  if (ll_type() != LinkType::kLE) {
    return BrEdrStartEncryption();
  }

  if (role() != Role::kMaster) {
    bt_log(DEBUG, "hci", "only the master can start encryption");
    return false;
  }

  if (!ltk()) {
    bt_log(DEBUG, "hci", "connection has no LTK; cannot start encryption");
    return false;
  }

  return LEStartEncryption(*ltk());
}

bool ConnectionImpl::BrEdrStartEncryption() {
  ZX_DEBUG_ASSERT(thread_checker_.is_thread_valid());

  ZX_ASSERT(ltk().has_value() == ltk_type().has_value());
  if (!ltk().has_value()) {
    bt_log(DEBUG, "hci", "connection link key type has not been set; not starting encryption");
    return false;
  }

  auto cmd =
      CommandPacket::New(kSetConnectionEncryption, sizeof(SetConnectionEncryptionCommandParams));
  auto* params = cmd->mutable_payload<SetConnectionEncryptionCommandParams>();
  params->connection_handle = htole16(handle());
  params->encryption_enable = GenericEnableParam::kEnable;

  auto self = weak_ptr_factory_.GetWeakPtr();
  auto status_cb = [self, handle = handle()](auto id, const EventPacket& event) {
    if (!self) {
      return;
    }

    const Status status = event.ToStatus();
    if (!bt_is_error(status, ERROR, "hci-bredr", "could not set encryption on link %#.04x",
                     handle)) {
      bt_log(DEBUG, "hci-bredr", "requested encryption start on %#.04x", handle);
      return;
    }

    if (self->encryption_change_callback()) {
      self->encryption_change_callback()(status, false);
    }
  };

  return hci_->command_channel()->SendCommand(std::move(cmd), std::move(status_cb),
                                              kCommandStatusEventCode) != 0u;
}

bool ConnectionImpl::LEStartEncryption(const LinkKey& ltk) {
  ZX_DEBUG_ASSERT(thread_checker_.is_thread_valid());
  ZX_ASSERT(!ltk_type().has_value());

  // TODO(fxbug.dev/801): Tell the data channel to stop data flow.

  auto cmd = CommandPacket::New(kLEStartEncryption, sizeof(LEStartEncryptionCommandParams));
  auto* params = cmd->mutable_payload<LEStartEncryptionCommandParams>();
  params->connection_handle = htole16(handle());
  params->random_number = htole64(ltk.rand());
  params->encrypted_diversifier = htole16(ltk.ediv());
  params->long_term_key = ltk.value();

  auto self = weak_ptr_factory_.GetWeakPtr();
  auto status_cb = [self, handle = handle()](auto id, const EventPacket& event) {
    if (!self) {
      return;
    }

    const Status status = event.ToStatus();
    if (!bt_is_error(status, ERROR, "hci-le", "could not set encryption on link %#.04x", handle)) {
      bt_log(DEBUG, "hci-le", "requested encryption start on %#.04x", handle);
      return;
    }

    if (self->encryption_change_callback()) {
      self->encryption_change_callback()(status, false);
    }
  };

  return hci_->command_channel()->SendCommand(std::move(cmd), std::move(status_cb),
                                              kCommandStatusEventCode) != 0u;
}

void ConnectionImpl::HandleEncryptionStatus(Status status, bool enabled) {
  // "On an authentication failure, the connection shall be automatically
  // disconnected by the Link Layer." (HCI_LE_Start_Encryption, Vol 2, Part E,
  // 7.8.24). We make sure of this by telling the controller to disconnect.
  //
  // For ACL-U, Vol 3, Part C, 5.2.2.1.1 and 5.2.2.2.1 mention disconnecting the
  // link after pairing failures (supported by TS GAP/SEC/SEM/BV-10-C), but do
  // not specify actions to take after encryption failures. We'll choose to
  // disconnect ACL links after encryption failure.
  if (!status) {
    Disconnect(StatusCode::kAuthenticationFailure);
  } else {
    // TODO(fxbug.dev/801): Tell the data channel to resume data flow.
  }

  if (!encryption_change_callback()) {
    bt_log(DEBUG, "hci", "%#.4x: no encryption status callback assigned", handle());
    return;
  }

  encryption_change_callback()(status, enabled);
}

void ConnectionImpl::ValidateAclEncryptionKeySize(hci::StatusCallback key_size_validity_cb) {
  ZX_ASSERT(ll_type() == LinkType::kACL);
  ZX_ASSERT(conn_state_ == Connection::State::kConnected);

  auto cmd = CommandPacket::New(kReadEncryptionKeySize, sizeof(ReadEncryptionKeySizeParams));
  auto* params = cmd->mutable_payload<ReadEncryptionKeySizeParams>();
  params->connection_handle = htole16(handle());

  auto status_cb = [self = weak_ptr_factory_.GetWeakPtr(),
                    valid_cb = std::move(key_size_validity_cb)](auto, const EventPacket& event) {
    if (!self) {
      return;
    }

    Status status = event.ToStatus();
    if (!bt_is_error(status, ERROR, "hci", "Could not read ACL encryption key size on %#.4x",
                     self->handle())) {
      const auto& return_params = *event.return_params<ReadEncryptionKeySizeReturnParams>();
      const auto key_size = return_params.key_size;
      bt_log(TRACE, "hci", "%#.4x: encryption key size %hhu", self->handle(), key_size);

      if (key_size < hci::kMinEncryptionKeySize) {
        bt_log(WARN, "hci", "%#.4x: encryption key size %hhu insufficient", self->handle(),
               key_size);
        status = Status(HostError::kInsufficientSecurity);
      }
    }
    valid_cb(status);
  };

  hci_->command_channel()->SendCommand(std::move(cmd), std::move(status_cb));
}

CommandChannel::EventCallbackResult ConnectionImpl::OnEncryptionChangeEvent(
    const EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == kEncryptionChangeEventCode);
  ZX_DEBUG_ASSERT(thread_checker_.is_thread_valid());

  if (event.view().payload_size() != sizeof(EncryptionChangeEventParams)) {
    bt_log(WARN, "hci", "malformed encryption change event");
    return CommandChannel::EventCallbackResult::kContinue;
  }

  const auto& params = event.params<EncryptionChangeEventParams>();
  hci::ConnectionHandle handle = le16toh(params.connection_handle);

  // Silently ignore the event as it isn't meant for this connection.
  if (handle != this->handle()) {
    return CommandChannel::EventCallbackResult::kContinue;
  }

  if (conn_state_ != Connection::State::kConnected) {
    bt_log(DEBUG, "hci", "encryption change ignored: connection closed");
    return CommandChannel::EventCallbackResult::kContinue;
  }

  Status status(params.status);
  bool enabled = params.encryption_enabled != EncryptionStatus::kOff;

  bt_log(DEBUG, "hci", "encryption change (%s) %s", enabled ? "enabled" : "disabled",
         status.ToString().c_str());

  if (ll_type() == LinkType::kACL && status && enabled) {
    ValidateAclEncryptionKeySize([this](const Status& key_valid_status) {
      HandleEncryptionStatus(key_valid_status, true /* enabled */);
    });
    return CommandChannel::EventCallbackResult::kContinue;
  }

  HandleEncryptionStatus(status, enabled);

  return CommandChannel::EventCallbackResult::kContinue;
}

CommandChannel::EventCallbackResult ConnectionImpl::OnEncryptionKeyRefreshCompleteEvent(
    const EventPacket& event) {
  ZX_DEBUG_ASSERT(thread_checker_.is_thread_valid());
  ZX_DEBUG_ASSERT(event.event_code() == kEncryptionKeyRefreshCompleteEventCode);

  if (event.view().payload_size() != sizeof(EncryptionKeyRefreshCompleteEventParams)) {
    bt_log(WARN, "hci", "malformed encryption key refresh complete event");
    return CommandChannel::EventCallbackResult::kContinue;
  }

  const auto& params = event.params<EncryptionKeyRefreshCompleteEventParams>();
  hci::ConnectionHandle handle = le16toh(params.connection_handle);

  // Silently ignore this event as it isn't meant for this connection.
  if (handle != this->handle()) {
    return CommandChannel::EventCallbackResult::kContinue;
  }

  if (conn_state_ != Connection::State::kConnected) {
    bt_log(DEBUG, "hci", "encryption key refresh ignored: connection closed");
    return CommandChannel::EventCallbackResult::kContinue;
  }

  Status status(params.status);

  bt_log(DEBUG, "hci", "encryption key refresh %s", status.ToString().c_str());

  // Report that encryption got disabled on failure status. The accuracy of this
  // isn't that important since the link will be disconnected.
  HandleEncryptionStatus(status, static_cast<bool>(status));

  return CommandChannel::EventCallbackResult::kContinue;
}

CommandChannel::EventCallbackResult ConnectionImpl::OnLELongTermKeyRequestEvent(
    const EventPacket& event) {
  ZX_DEBUG_ASSERT(thread_checker_.is_thread_valid());
  ZX_DEBUG_ASSERT(event.event_code() == kLEMetaEventCode);
  ZX_DEBUG_ASSERT(event.params<LEMetaEventParams>().subevent_code ==
                  kLELongTermKeyRequestSubeventCode);

  auto* params = event.le_event_params<LELongTermKeyRequestSubeventParams>();
  if (!params) {
    bt_log(WARN, "hci", "malformed LE LTK request event");
    return CommandChannel::EventCallbackResult::kContinue;
  }

  hci::ConnectionHandle handle = le16toh(params->connection_handle);

  // Silently ignore the event as it isn't meant for this connection.
  if (handle != this->handle()) {
    return CommandChannel::EventCallbackResult::kContinue;
  }

  // TODO(fxbug.dev/1360): Tell the data channel to stop data flow.

  std::unique_ptr<CommandPacket> cmd;

  uint64_t rand = le64toh(params->random_number);
  uint16_t ediv = le16toh(params->encrypted_diversifier);

  bt_log(DEBUG, "hci", "LE LTK request - ediv: %#.4x, rand: %#.16lx", ediv, rand);
  if (ltk() && ltk()->rand() == rand && ltk()->ediv() == ediv) {
    cmd = CommandPacket::New(kLELongTermKeyRequestReply,
                             sizeof(LELongTermKeyRequestReplyCommandParams));
    auto* params = cmd->mutable_payload<LELongTermKeyRequestReplyCommandParams>();

    params->connection_handle = htole16(handle);
    params->long_term_key = ltk()->value();
  } else {
    bt_log(DEBUG, "hci-le", "LTK request rejected");

    cmd = CommandPacket::New(kLELongTermKeyRequestNegativeReply,
                             sizeof(LELongTermKeyRequestNegativeReplyCommandParams));
    auto* params = cmd->mutable_payload<LELongTermKeyRequestNegativeReplyCommandParams>();
    params->connection_handle = htole16(handle);
  }

  auto status_cb = [](auto id, const EventPacket& event) {
    hci_is_error(event, TRACE, "hci-le", "failed to reply to LTK request");
  };
  hci_->command_channel()->SendCommand(std::move(cmd), std::move(status_cb));
  return CommandChannel::EventCallbackResult::kContinue;
}

}  // namespace bt::hci
