// 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 "lib/async/default.h"
#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/hci-spec/defaults.h"
#include "src/connectivity/bluetooth/core/bt-host/hci-spec/protocol.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
