// Copyright 2023 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

#include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"

#include <cpp-string/string_printf.h>
#include <endian.h>
#include <pw_bluetooth/hci_android.emb.h>

#include <cstddef>

#include "pw_bluetooth_sapphire/internal/host/common/log.h"
#include "pw_bluetooth_sapphire/internal/host/common/packet_view.h"
#include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
#include "pw_bluetooth_sapphire/internal/host/hci-spec/defaults.h"
#include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
#include "pw_bluetooth_sapphire/internal/host/hci-spec/util.h"
#include "pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
#include "pw_bluetooth_sapphire/internal/host/hci/util.h"

namespace bt::testing {
namespace {

template <typename NUM_TYPE, typename ENUM_TYPE>
void SetBit(NUM_TYPE* num_type, ENUM_TYPE bit) {
  *num_type |= static_cast<NUM_TYPE>(bit);
}

template <typename NUM_TYPE, typename ENUM_TYPE>
void UnsetBit(NUM_TYPE* num_type, ENUM_TYPE bit) {
  *num_type &= ~static_cast<NUM_TYPE>(bit);
}

template <typename NUM_TYPE, typename ENUM_TYPE>
bool CheckBit(NUM_TYPE num_type, ENUM_TYPE bit) {
  return (num_type & static_cast<NUM_TYPE>(bit));
}

}  // namespace

namespace hci_android = hci_spec::vendor::android;

void FakeController::Settings::ApplyDualModeDefaults() {
  le_connection_delay = std::chrono::seconds(0);
  hci_version = pw::bluetooth::emboss::CoreSpecificationVersion::V5_0;
  num_hci_command_packets = 250;
  event_mask = 0;
  le_event_mask = 0;
  bd_addr = DeviceAddress();
  lmp_features_page0 = 0;
  SetBit(&lmp_features_page0, hci_spec::LMPFeature::kLESupportedHost);
  SetBit(&lmp_features_page0, hci_spec::LMPFeature::kSimultaneousLEAndBREDR);
  SetBit(&lmp_features_page0, hci_spec::LMPFeature::kExtendedFeatures);
  SetBit(&lmp_features_page0, hci_spec::LMPFeature::kRSSIwithInquiryResults);
  SetBit(&lmp_features_page0, hci_spec::LMPFeature::kExtendedInquiryResponse);
  lmp_features_page1 = 0;
  lmp_features_page2 = 0;
  le_features = 0;
  le_supported_states = 0;
  std::memset(supported_commands, 0, sizeof(supported_commands));
  AddBREDRSupportedCommands();
  AddLESupportedCommands();
  acl_data_packet_length = 512;
  total_num_acl_data_packets = 1;
  le_acl_data_packet_length = 512;
  le_total_num_acl_data_packets = 1;
  synchronous_data_packet_length = 0;
  total_num_synchronous_data_packets = 0;
  iso_data_packet_length = 512;
  total_num_iso_data_packets = 1;
  android_extension_settings.SetToZeros();
}

void FakeController::Settings::ApplyLEOnlyDefaults() {
  ApplyDualModeDefaults();

  UnsetBit(&lmp_features_page0, hci_spec::LMPFeature::kSimultaneousLEAndBREDR);
  SetBit(&lmp_features_page0, hci_spec::LMPFeature::kBREDRNotSupported);
  std::memset(supported_commands, 0, sizeof(supported_commands));

  AddLESupportedCommands();
}

void FakeController::Settings::AddBREDRSupportedCommands() {
  SetBit(supported_commands + 0, hci_spec::SupportedCommand::kCreateConnection);
  SetBit(supported_commands + 0,
         hci_spec::SupportedCommand::kCreateConnectionCancel);
  SetBit(supported_commands + 0, hci_spec::SupportedCommand::kDisconnect);
  SetBit(supported_commands + 7, hci_spec::SupportedCommand::kWriteLocalName);
  SetBit(supported_commands + 7, hci_spec::SupportedCommand::kReadLocalName);
  SetBit(supported_commands + 7, hci_spec::SupportedCommand::kReadScanEnable);
  SetBit(supported_commands + 7, hci_spec::SupportedCommand::kWriteScanEnable);
  SetBit(supported_commands + 8,
         hci_spec::SupportedCommand::kReadPageScanActivity);
  SetBit(supported_commands + 8,
         hci_spec::SupportedCommand::kWritePageScanActivity);
  SetBit(supported_commands + 9,
         hci_spec::SupportedCommand::kWriteClassOfDevice);
  SetBit(supported_commands + 10,
         hci_spec::SupportedCommand::kWriteSynchronousFlowControlEnable);
  SetBit(supported_commands + 12, hci_spec::SupportedCommand::kReadInquiryMode);
  SetBit(supported_commands + 12,
         hci_spec::SupportedCommand::kWriteInquiryMode);
  SetBit(supported_commands + 13,
         hci_spec::SupportedCommand::kReadPageScanType);
  SetBit(supported_commands + 13,
         hci_spec::SupportedCommand::kWritePageScanType);
  SetBit(supported_commands + 14, hci_spec::SupportedCommand::kReadBufferSize);
  SetBit(supported_commands + 17,
         hci_spec::SupportedCommand::kReadSimplePairingMode);
  SetBit(supported_commands + 17,
         hci_spec::SupportedCommand::kWriteSimplePairingMode);
  SetBit(supported_commands + 17,
         hci_spec::SupportedCommand::kWriteExtendedInquiryResponse);
  SetBit(supported_commands + 32,
         hci_spec::SupportedCommand::kWriteSecureConnectionsHostSupport);
}

void FakeController::Settings::AddLESupportedCommands() {
  SetBit(supported_commands + 0, hci_spec::SupportedCommand::kDisconnect);
  SetBit(supported_commands + 5, hci_spec::SupportedCommand::kSetEventMask);
  SetBit(supported_commands + 5, hci_spec::SupportedCommand::kReset);
  SetBit(supported_commands + 14,
         hci_spec::SupportedCommand::kReadLocalVersionInformation);
  SetBit(supported_commands + 14,
         hci_spec::SupportedCommand::kReadLocalSupportedFeatures);
  SetBit(supported_commands + 14,
         hci_spec::SupportedCommand::kReadLocalExtendedFeatures);
  SetBit(supported_commands + 24,
         hci_spec::SupportedCommand::kWriteLEHostSupport);
  SetBit(supported_commands + 25, hci_spec::SupportedCommand::kLESetEventMask);
  SetBit(supported_commands + 25,
         hci_spec::SupportedCommand::kLEReadBufferSizeV1);
  SetBit(supported_commands + 25,
         hci_spec::SupportedCommand::kLEReadLocalSupportedFeatures);
  SetBit(supported_commands + 25,
         hci_spec::SupportedCommand::kLESetRandomAddress);
  SetBit(supported_commands + 25,
         hci_spec::SupportedCommand::kLESetAdvertisingParameters);
  SetBit(supported_commands + 25,
         hci_spec::SupportedCommand::kLESetAdvertisingData);
  SetBit(supported_commands + 26,
         hci_spec::SupportedCommand::kLESetScanResponseData);
  SetBit(supported_commands + 26,
         hci_spec::SupportedCommand::kLESetAdvertisingEnable);
  SetBit(supported_commands + 26,
         hci_spec::SupportedCommand::kLECreateConnection);
  SetBit(supported_commands + 26,
         hci_spec::SupportedCommand::kLECreateConnectionCancel);
  SetBit(supported_commands + 27,
         hci_spec::SupportedCommand::kLEConnectionUpdate);
  SetBit(supported_commands + 27,
         hci_spec::SupportedCommand::kLEReadRemoteFeatures);
  SetBit(supported_commands + 28,
         hci_spec::SupportedCommand::kLEStartEncryption);
  SetBit(supported_commands + 41,
         hci_spec::SupportedCommand::kLEReadBufferSizeV2);
}

void FakeController::Settings::ApplyLegacyLEConfig() {
  ApplyLEOnlyDefaults();

  hci_version = pw::bluetooth::emboss::CoreSpecificationVersion::V4_2;

  SetBit(supported_commands + 26,
         hci_spec::SupportedCommand::kLESetScanParameters);
  SetBit(supported_commands + 26, hci_spec::SupportedCommand::kLESetScanEnable);
}

void FakeController::Settings::ApplyExtendedLEConfig() {
  ApplyLEOnlyDefaults();

  SetBit(&le_features, hci_spec::LESupportedFeature::kLEExtendedAdvertising);
  SetBit(supported_commands + 36,
         hci_spec::SupportedCommand::kLESetAdvertisingSetRandomAddress);
  SetBit(supported_commands + 36,
         hci_spec::SupportedCommand::kLESetExtendedAdvertisingParameters);
  SetBit(supported_commands + 36,
         hci_spec::SupportedCommand::kLESetExtendedAdvertisingData);
  SetBit(supported_commands + 36,
         hci_spec::SupportedCommand::kLESetExtendedScanResponseData);
  SetBit(supported_commands + 36,
         hci_spec::SupportedCommand::kLESetExtendedAdvertisingEnable);
  SetBit(supported_commands + 36,
         hci_spec::SupportedCommand::kLEReadMaximumAdvertisingDataLength);
  SetBit(supported_commands + 36,
         hci_spec::SupportedCommand::kLEReadNumberOfSupportedAdvertisingSets);
  SetBit(supported_commands + 37,
         hci_spec::SupportedCommand::kLERemoveAdvertisingSet);
  SetBit(supported_commands + 37,
         hci_spec::SupportedCommand::kLEClearAdvertisingSets);
}

void FakeController::Settings::ApplyAndroidVendorExtensionDefaults() {
  // Settings for the android vendor extensions component within the Fake
  // Controller. These settings correspond to the vendor capabilities returned
  // by the controller. See
  // pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h and
  // LEGetVendorCapabilities for more information.
  android_extension_settings.view().status().Write(
      pw::bluetooth::emboss::StatusCode::SUCCESS);
  android_extension_settings.view().max_advt_instances().Write(3);
  android_extension_settings.view().total_scan_results_storage().Write(1024);
}

void FakeController::SetDefaultCommandStatus(
    hci_spec::OpCode opcode, pw::bluetooth::emboss::StatusCode status) {
  default_command_status_map_[opcode] = status;
}

void FakeController::ClearDefaultCommandStatus(hci_spec::OpCode opcode) {
  default_command_status_map_.erase(opcode);
}

void FakeController::SetDefaultResponseStatus(
    hci_spec::OpCode opcode, pw::bluetooth::emboss::StatusCode status) {
  BT_DEBUG_ASSERT(status != pw::bluetooth::emboss::StatusCode::SUCCESS);
  default_status_map_[opcode] = status;
}

void FakeController::ClearDefaultResponseStatus(hci_spec::OpCode opcode) {
  default_status_map_.erase(opcode);
}

bool FakeController::AddPeer(std::unique_ptr<FakePeer> peer) {
  BT_DEBUG_ASSERT(peer);

  if (peers_.count(peer->address()) != 0u) {
    return false;
  }

  peer->set_controller(this);

  // If a scan is enabled then send an advertising report for the peer that just
  // got registered if it supports advertising.
  SendAdvertisingReport(*peer);

  peers_[peer->address()] = std::move(peer);
  return true;
}

void FakeController::RemovePeer(const DeviceAddress& address) {
  peers_.erase(address);
}

FakePeer* FakeController::FindPeer(const DeviceAddress& address) {
  auto iter = peers_.find(address);
  return (iter == peers_.end()) ? nullptr : iter->second.get();
}

void FakeController::SendCommand(pw::span<const std::byte> command) {
  BT_ASSERT(command.size() >= sizeof(hci_spec::CommandHeader));

  // Post the packet to simulate async HCI behavior.
  (void)heap_dispatcher().Post(
      [self = GetWeakPtr(), command = DynamicByteBuffer(BufferView(command))](
          pw::async::Context /*ctx*/, pw::Status status) {
        if (!self.is_alive() || !status.ok()) {
          return;
        }
        const size_t payload_size =
            command.size() - sizeof(hci_spec::CommandHeader);
        PacketView<hci_spec::CommandHeader> packet_view(&command, payload_size);
        self->OnCommandPacketReceived(packet_view);
      });
}

FakePeer* FakeController::FindByConnHandle(hci_spec::ConnectionHandle handle) {
  for (auto& [addr, peer] : peers_) {
    if (peer->HasLink(handle)) {
      return peer.get();
    }
  }
  return nullptr;
}

uint8_t FakeController::NextL2CAPCommandId() {
  // TODO(armansito): Guard against overflow?
  return next_le_sig_id_++;
}

void FakeController::RespondWithCommandComplete(
    hci_spec::OpCode opcode, pw::bluetooth::emboss::StatusCode status) {
  hci_spec::SimpleReturnParams params;
  params.status = status;
  RespondWithCommandComplete(opcode, BufferView(&params, sizeof(params)));
}

void FakeController::RespondWithCommandComplete(hci_spec::OpCode opcode,
                                                const ByteBuffer& params) {
  DynamicByteBuffer buffer(sizeof(hci_spec::CommandCompleteEventParams) +
                           params.size());
  MutablePacketView<hci_spec::CommandCompleteEventParams> event(&buffer,
                                                                params.size());

  event.mutable_header()->num_hci_command_packets =
      settings_.num_hci_command_packets;
  event.mutable_header()->command_opcode = htole16(opcode);
  event.mutable_payload_data().Write(params);

  SendEvent(hci_spec::kCommandCompleteEventCode, buffer);
}

void FakeController::RespondWithCommandComplete(
    hci_spec::OpCode opcode, hci::EmbossEventPacket* packet) {
  auto header =
      packet
          ->template view<pw::bluetooth::emboss::CommandCompleteEventWriter>();

  header.num_hci_command_packets().Write(settings_.num_hci_command_packets);
  header.command_opcode().BackingStorage().WriteUInt(opcode);

  SendEvent(hci_spec::kCommandCompleteEventCode, packet);
}

void FakeController::RespondWithCommandStatus(
    hci_spec::OpCode opcode, pw::bluetooth::emboss::StatusCode status) {
  StaticByteBuffer<sizeof(hci_spec::CommandStatusEventParams)> buffer;
  MutablePacketView<hci_spec::CommandStatusEventParams> event(&buffer);

  event.mutable_header()->status = status;
  event.mutable_header()->num_hci_command_packets =
      settings_.num_hci_command_packets;
  event.mutable_header()->command_opcode = htole16(opcode);

  SendEvent(hci_spec::kCommandStatusEventCode, buffer);
}

void FakeController::SendEvent(hci_spec::EventCode event_code,
                               const ByteBuffer& payload) {
  DynamicByteBuffer buffer(sizeof(hci_spec::EventHeader) + payload.size());
  MutablePacketView<hci_spec::EventHeader> event(&buffer, payload.size());

  event.mutable_header()->event_code = event_code;
  event.mutable_header()->parameter_total_size = payload.size();
  event.mutable_payload_data().Write(payload);

  SendCommandChannelPacket(buffer);
}

void FakeController::SendEvent(hci_spec::EventCode event_code,
                               hci::EmbossEventPacket* packet) {
  auto header =
      packet->template view<pw::bluetooth::emboss::EventHeaderWriter>();
  uint8_t parameter_total_size =
      packet->size() -
      pw::bluetooth::emboss::EventHeader::IntrinsicSizeInBytes();

  header.event_code().Write(event_code);
  header.parameter_total_size().Write(parameter_total_size);

  SendCommandChannelPacket(packet->data());
}

void FakeController::SendLEMetaEvent(hci_spec::EventCode subevent_code,
                                     const ByteBuffer& payload) {
  DynamicByteBuffer buffer(sizeof(hci_spec::LEMetaEventParams) +
                           payload.size());
  buffer[0] = subevent_code;
  buffer.Write(payload, 1);
  SendEvent(hci_spec::kLEMetaEventCode, buffer);
}

void FakeController::SendACLPacket(hci_spec::ConnectionHandle handle,
                                   const ByteBuffer& payload) {
  BT_DEBUG_ASSERT(payload.size() <= hci_spec::kMaxACLPayloadSize);

  DynamicByteBuffer buffer(sizeof(hci_spec::ACLDataHeader) + payload.size());
  MutablePacketView<hci_spec::ACLDataHeader> acl(&buffer, payload.size());

  acl.mutable_header()->handle_and_flags = htole16(handle);
  acl.mutable_header()->data_total_length =
      htole16(static_cast<uint16_t>(payload.size()));
  acl.mutable_payload_data().Write(payload);

  SendACLDataChannelPacket(buffer);
}

void FakeController::SendL2CAPBFrame(hci_spec::ConnectionHandle handle,
                                     l2cap::ChannelId channel_id,
                                     const ByteBuffer& payload) {
  BT_DEBUG_ASSERT(payload.size() <=
                  hci_spec::kMaxACLPayloadSize - sizeof(l2cap::BasicHeader));

  DynamicByteBuffer buffer(sizeof(l2cap::BasicHeader) + payload.size());
  MutablePacketView<l2cap::BasicHeader> bframe(&buffer, payload.size());

  bframe.mutable_header()->length = htole16(payload.size());
  bframe.mutable_header()->channel_id = htole16(channel_id);
  bframe.mutable_payload_data().Write(payload);

  SendACLPacket(handle, buffer);
}

void FakeController::SendL2CAPCFrame(hci_spec::ConnectionHandle handle,
                                     bool is_le,
                                     l2cap::CommandCode code,
                                     uint8_t id,
                                     const ByteBuffer& payload) {
  DynamicByteBuffer buffer(sizeof(l2cap::CommandHeader) + payload.size());
  MutablePacketView<l2cap::CommandHeader> cframe(&buffer, payload.size());

  cframe.mutable_header()->code = code;
  cframe.mutable_header()->id = id;
  cframe.mutable_header()->length = payload.size();
  cframe.mutable_payload_data().Write(payload);

  SendL2CAPBFrame(
      handle,
      is_le ? l2cap::kLESignalingChannelId : l2cap::kSignalingChannelId,
      buffer);
}

void FakeController::SendNumberOfCompletedPacketsEvent(
    hci_spec::ConnectionHandle handle, uint16_t num) {
  StaticByteBuffer<sizeof(hci_spec::NumberOfCompletedPacketsEventParams) +
                   sizeof(hci_spec::NumberOfCompletedPacketsEventData)>
      buffer;

  auto* params =
      reinterpret_cast<hci_spec::NumberOfCompletedPacketsEventParams*>(
          buffer.mutable_data());
  params->number_of_handles = 1;
  params->data->connection_handle = htole16(handle);
  params->data->hc_num_of_completed_packets = htole16(num);

  SendEvent(hci_spec::kNumberOfCompletedPacketsEventCode, buffer);
}

void FakeController::ConnectLowEnergy(
    const DeviceAddress& addr, pw::bluetooth::emboss::ConnectionRole role) {
  (void)heap_dispatcher().Post(
      [addr, role, this](pw::async::Context /*ctx*/, pw::Status status) {
        if (!status.ok()) {
          return;
        }
        FakePeer* peer = FindPeer(addr);
        if (!peer) {
          bt_log(WARN,
                 "fake-hci",
                 "no peer found with address: %s",
                 addr.ToString().c_str());
          return;
        }

        // TODO(armansito): Don't worry about managing multiple links per peer
        // until this supports Bluetooth classic.
        if (peer->connected()) {
          bt_log(WARN, "fake-hci", "peer already connected");
          return;
        }

        hci_spec::ConnectionHandle handle = ++next_conn_handle_;
        peer->AddLink(handle);

        NotifyConnectionState(addr, handle, /*connected=*/true);

        auto interval_min = hci_spec::defaults::kLEConnectionIntervalMin;
        auto interval_max = hci_spec::defaults::kLEConnectionIntervalMax;

        hci_spec::LEConnectionParameters conn_params(
            interval_min + ((interval_max - interval_min) / 2),
            0,
            hci_spec::defaults::kLESupervisionTimeout);
        peer->set_le_params(conn_params);

        auto packet = hci::EmbossEventPacket::New<
            pw::bluetooth::emboss::LEConnectionCompleteSubeventWriter>(
            hci_spec::kLEMetaEventCode);
        auto view = packet.view_t();
        view.le_meta_event().subevent_code().Write(
            hci_spec::kLEConnectionCompleteSubeventCode);
        view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
        view.peer_address().CopyFrom(addr.value().view());
        view.peer_address_type().Write(
            DeviceAddress::DeviceAddrToLePeerAddr(addr.type()));
        view.peripheral_latency().Write(conn_params.latency());
        view.connection_interval().Write(conn_params.interval());
        view.supervision_timeout().Write(conn_params.supervision_timeout());
        view.role().Write(role);
        view.connection_handle().Write(handle);
        SendCommandChannelPacket(packet.data());
      });
}

void FakeController::SendConnectionRequest(
    const DeviceAddress& addr, pw::bluetooth::emboss::LinkType link_type) {
  FakePeer* peer = FindPeer(addr);
  BT_ASSERT(peer);
  peer->set_last_connection_request_link_type(link_type);

  bt_log(DEBUG,
         "fake-hci",
         "sending connection request (addr: %s, link: %s)",
         bt_str(addr),
         hci_spec::LinkTypeToString(link_type));
  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::ConnectionRequestEventWriter>(
      hci_spec::kConnectionRequestEventCode);
  packet.view_t().bd_addr().CopyFrom(addr.value().view());
  packet.view_t().link_type().Write(link_type);
  SendCommandChannelPacket(packet.data());
}

void FakeController::L2CAPConnectionParameterUpdate(
    const DeviceAddress& addr,
    const hci_spec::LEPreferredConnectionParameters& params) {
  (void)heap_dispatcher().Post(
      [addr, params, this](pw::async::Context /*ctx*/, pw::Status status) {
        if (!status.ok()) {
          return;
        }
        FakePeer* peer = FindPeer(addr);
        if (!peer) {
          bt_log(WARN,
                 "fake-hci",
                 "no peer found with address: %s",
                 addr.ToString().c_str());
          return;
        }

        if (!peer->connected()) {
          bt_log(WARN, "fake-hci", "peer not connected");
          return;
        }

        BT_DEBUG_ASSERT(!peer->logical_links().empty());

        l2cap::ConnectionParameterUpdateRequestPayload payload;
        payload.interval_min = htole16(params.min_interval());
        payload.interval_max = htole16(params.max_interval());
        payload.peripheral_latency = htole16(params.max_latency());
        payload.timeout_multiplier = htole16(params.supervision_timeout());

        // TODO(armansito): Instead of picking the first handle we should pick
        // the handle that matches the current LE-U link.
        SendL2CAPCFrame(*peer->logical_links().begin(),
                        /*is_le=*/true,
                        l2cap::kConnectionParameterUpdateRequest,
                        NextL2CAPCommandId(),
                        BufferView(&payload, sizeof(payload)));
      });
}

void FakeController::SendLEConnectionUpdateCompleteSubevent(
    hci_spec::ConnectionHandle handle,
    const hci_spec::LEConnectionParameters& params,
    pw::bluetooth::emboss::StatusCode status) {
  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::LEConnectionUpdateCompleteSubeventWriter>(
      hci_spec::kLEMetaEventCode);
  auto view = packet.view_t();
  view.le_meta_event().subevent_code().Write(
      hci_spec::kLEConnectionUpdateCompleteSubeventCode);
  view.status().Write(status);
  view.connection_handle().Write(handle);
  view.connection_interval().UncheckedWrite(params.interval());
  view.peripheral_latency().Write(params.latency());
  view.supervision_timeout().UncheckedWrite(params.supervision_timeout());
  SendCommandChannelPacket(packet.data());
}

void FakeController::Disconnect(const DeviceAddress& addr,
                                pw::bluetooth::emboss::StatusCode reason) {
  (void)heap_dispatcher().Post(
      [this, addr, reason](pw::async::Context /*ctx*/, pw::Status status) {
        if (!status.ok()) {
          return;
        }
        FakePeer* peer = FindPeer(addr);
        if (!peer || !peer->connected()) {
          bt_log(WARN,
                 "fake-hci",
                 "no connected peer found with address: %s",
                 addr.ToString().c_str());
          return;
        }

        auto links = peer->Disconnect();
        BT_DEBUG_ASSERT(!peer->connected());
        BT_DEBUG_ASSERT(!links.empty());

        for (auto link : links) {
          NotifyConnectionState(addr, link, /*connected=*/false);
          SendDisconnectionCompleteEvent(link, reason);
        }
      });
}

void FakeController::SendDisconnectionCompleteEvent(
    hci_spec::ConnectionHandle handle,
    pw::bluetooth::emboss::StatusCode reason) {
  auto event = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::DisconnectionCompleteEventWriter>(
      hci_spec::kDisconnectionCompleteEventCode);
  event.view_t().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
  event.view_t().connection_handle().Write(handle);
  event.view_t().reason().Write(reason);
  SendCommandChannelPacket(event.data());
}

void FakeController::SendEncryptionChangeEvent(
    hci_spec::ConnectionHandle handle,
    pw::bluetooth::emboss::StatusCode status,
    pw::bluetooth::emboss::EncryptionStatus encryption_enabled) {
  auto response = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::EncryptionChangeEventV1Writer>(
      hci_spec::kEncryptionChangeEventCode);
  response.view_t().status().Write(status);
  response.view_t().connection_handle().Write(handle);
  response.view_t().encryption_enabled().Write(encryption_enabled);
  SendCommandChannelPacket(response.data());
}

bool FakeController::MaybeRespondWithDefaultCommandStatus(
    hci_spec::OpCode opcode) {
  auto iter = default_command_status_map_.find(opcode);
  if (iter == default_command_status_map_.end()) {
    return false;
  }

  RespondWithCommandStatus(opcode, iter->second);
  return true;
}

bool FakeController::MaybeRespondWithDefaultStatus(hci_spec::OpCode opcode) {
  auto iter = default_status_map_.find(opcode);
  if (iter == default_status_map_.end())
    return false;

  bt_log(INFO,
         "fake-hci",
         "responding with error (command: %#.4x, status: %#.2hhx)",
         opcode,
         static_cast<unsigned char>(iter->second));
  RespondWithCommandComplete(opcode, iter->second);
  return true;
}

void FakeController::SendInquiryResponses() {
  // TODO(jamuraa): combine some of these into a single response event
  for (const auto& [addr, peer] : peers_) {
    if (!peer->supports_bredr()) {
      continue;
    }

    SendCommandChannelPacket(peer->CreateInquiryResponseEvent(inquiry_mode_));
    inquiry_num_responses_left_--;
    if (inquiry_num_responses_left_ == 0) {
      break;
    }
  }
}

static void WriteScanResponseReport(const FakePeer& peer,
                                    hci_spec::LEAdvertisingReportData* report) {
  BT_DEBUG_ASSERT(peer.scannable());
  report->event_type = hci_spec::LEAdvertisingEventType::kScanRsp;

  report->address = peer.address().value();
  report->address_type = hci_spec::LEAddressType::kPublic;
  if (peer.address().type() == DeviceAddress::Type::kLERandom) {
    report->address_type = hci_spec::LEAddressType::kRandom;
  }

  report->length_data = peer.scan_response().size();
  std::memcpy(
      report->data, peer.scan_response().data(), peer.scan_response().size());

  report->data[report->length_data] = peer.rssi();
}

DynamicByteBuffer FakeController::BuildLegacyAdvertisingReportEvent(
    const FakePeer& peer, bool include_scan_rsp) {
  BT_DEBUG_ASSERT(peer.advertising_data().size() <=
                  hci_spec::kMaxLEAdvertisingDataLength);
  size_t param_size = sizeof(hci_spec::LEMetaEventParams) +
                      sizeof(hci_spec::LEAdvertisingReportSubeventParams) +
                      sizeof(hci_spec::LEAdvertisingReportData) +
                      peer.advertising_data().size() + sizeof(int8_t);

  if (include_scan_rsp) {
    BT_DEBUG_ASSERT(peer.scannable());
    BT_DEBUG_ASSERT(peer.scan_response().size() <=
                    hci_spec::kMaxLEAdvertisingDataLength);
    param_size += sizeof(hci_spec::LEAdvertisingReportData) +
                  peer.scan_response().size() + sizeof(int8_t);
  }

  DynamicByteBuffer buffer(sizeof(hci_spec::EventHeader) + param_size);
  MutablePacketView<hci_spec::EventHeader> event(&buffer, param_size);
  event.mutable_header()->event_code = hci_spec::kLEMetaEventCode;
  event.mutable_header()->parameter_total_size = param_size;

  auto payload = event.mutable_payload<hci_spec::LEMetaEventParams>();
  payload->subevent_code = hci_spec::kLEAdvertisingReportSubeventCode;

  auto subevent_payload =
      reinterpret_cast<hci_spec::LEAdvertisingReportSubeventParams*>(
          payload->subevent_parameters);
  subevent_payload->num_reports = 1;
  if (include_scan_rsp) {
    subevent_payload->num_reports++;
  }
  auto report = reinterpret_cast<hci_spec::LEAdvertisingReportData*>(
      subevent_payload->reports);
  if (peer.directed_advertising_enabled()) {
    report->event_type = hci_spec::LEAdvertisingEventType::kAdvDirectInd;
  } else if (peer.connectable()) {
    report->event_type = hci_spec::LEAdvertisingEventType::kAdvInd;
  } else if (peer.scannable()) {
    report->event_type = hci_spec::LEAdvertisingEventType::kAdvScanInd;
  } else {
    report->event_type = hci_spec::LEAdvertisingEventType::kAdvNonConnInd;
  }

  if (peer.address().type() == DeviceAddress::Type::kLERandom) {
    report->address_type = hci_spec::LEAddressType::kRandom;
    if (peer.address_resolved()) {
      report->address_type = hci_spec::LEAddressType::kRandomIdentity;
    }
  } else {
    report->address_type = hci_spec::LEAddressType::kPublic;
    if (peer.address_resolved()) {
      report->address_type = hci_spec::LEAddressType::kPublicIdentity;
    }
  }

  report->address = peer.address().value();
  report->length_data = peer.advertising_data().size();
  std::memcpy(report->data,
              peer.advertising_data().data(),
              peer.advertising_data().size());
  report->data[report->length_data] = peer.rssi();

  if (include_scan_rsp) {
    auto* scan_response_report =
        reinterpret_cast<hci_spec::LEAdvertisingReportData*>(
            report->data + report->length_data + sizeof(int8_t));
    WriteScanResponseReport(peer, scan_response_report);
  }

  return buffer;
}

DynamicByteBuffer FakeController::BuildLegacyScanResponseReportEvent(
    const FakePeer& peer) const {
  BT_DEBUG_ASSERT(peer.scannable());
  BT_DEBUG_ASSERT(peer.scan_response().size() <=
                  hci_spec::kMaxLEAdvertisingDataLength);
  size_t param_size = sizeof(hci_spec::LEMetaEventParams) +
                      sizeof(hci_spec::LEAdvertisingReportSubeventParams) +
                      sizeof(hci_spec::LEAdvertisingReportData) +
                      peer.scan_response().size() + sizeof(int8_t);

  DynamicByteBuffer buffer(sizeof(hci_spec::EventHeader) + param_size);
  MutablePacketView<hci_spec::EventHeader> event(&buffer, param_size);
  event.mutable_header()->event_code = hci_spec::kLEMetaEventCode;
  event.mutable_header()->parameter_total_size = param_size;

  auto payload = event.mutable_payload<hci_spec::LEMetaEventParams>();
  payload->subevent_code = hci_spec::kLEAdvertisingReportSubeventCode;

  auto subevent_payload =
      reinterpret_cast<hci_spec::LEAdvertisingReportSubeventParams*>(
          payload->subevent_parameters);
  subevent_payload->num_reports = 1;

  auto report = reinterpret_cast<hci_spec::LEAdvertisingReportData*>(
      subevent_payload->reports);
  WriteScanResponseReport(peer, report);

  return buffer;
}

void FakeController::FillExtendedAdvertisingReport(
    const FakePeer& peer,
    pw::bluetooth::emboss::LEExtendedAdvertisingReportDataWriter report,
    const ByteBuffer& data,
    bool is_fragmented,
    bool is_scan_response) const {
  if (peer.use_extended_advertising_pdus()) {
    report.event_type().directed().Write(peer.directed_advertising_enabled());
    report.event_type().connectable().Write(peer.connectable());
    report.event_type().scannable().Write(peer.scannable());
    report.event_type().scan_response().Write(is_scan_response);

    if (is_fragmented) {
      report.event_type().data_status().Write(
          pw::bluetooth::emboss::LEAdvertisingDataStatus::INCOMPLETE);
    } else {
      report.event_type().data_status().Write(
          pw::bluetooth::emboss::LEAdvertisingDataStatus::COMPLETE);
    }
  } else {
    report.event_type().legacy().Write(true);
    if (is_scan_response) {
      report.event_type().scan_response().Write(true);
    }

    if (peer.directed_advertising_enabled()) {  // ADV_DIRECT_IND
      report.event_type().directed().Write(true);
      report.event_type().connectable().Write(true);
    } else if (peer.connectable()) {  // ADV_IND
      report.event_type().connectable().Write(true);
      report.event_type().scannable().Write(true);
    } else if (peer.scannable()) {  // ADV_SCAN_IND
      report.event_type().scannable().Write(true);
    }
    // else ADV_NONCONN_IND
  }

  if (peer.address().type() == DeviceAddress::Type::kLERandom) {
    if (peer.address_resolved()) {
      report.address_type().Write(
          pw::bluetooth::emboss::LEExtendedAddressType::RANDOM_IDENTITY);
    } else {
      report.address_type().Write(
          pw::bluetooth::emboss::LEExtendedAddressType::RANDOM);
    }
  } else {
    if (peer.address_resolved()) {
      report.address_type().Write(
          pw::bluetooth::emboss::LEExtendedAddressType::PUBLIC_IDENTITY);
    } else {
      report.address_type().Write(
          pw::bluetooth::emboss::LEExtendedAddressType::PUBLIC);
    }
  }

  report.address().bd_addr().CopyFrom(peer.address().value().view().bd_addr());
  report.primary_phy().Write(
      pw::bluetooth::emboss::LEPrimaryAdvertisingPHY::LE_1M);
  report.secondary_phy().Write(
      pw::bluetooth::emboss::LESecondaryAdvertisingPHY::NONE);
  report.advertising_sid().Write(0);
  report.tx_power().Write(peer.tx_power());
  report.rssi().Write(peer.rssi());
  report.periodic_advertising_interval().Write(0);

  // skip direct_address_type and direct_address for now since we don't use it

  report.data_length().Write(data.size());
  std::memcpy(report.data().BackingStorage().begin(), data.data(), data.size());
}

DynamicByteBuffer FakeController::BuildExtendedAdvertisingReports(
    const FakePeer& peer, const ByteBuffer& data, bool is_scan_response) const {
  using pw::bluetooth::emboss::LEExtendedAdvertisingReportDataWriter;
  using pw::bluetooth::emboss::LEExtendedAdvertisingReportSubeventWriter;

  size_t num_full_reports =
      data.size() / hci_spec::kMaxPduLEExtendedAdvertisingDataLength;
  size_t full_report_size =
      pw::bluetooth::emboss::LEExtendedAdvertisingReportData::MinSizeInBytes() +
      hci_spec::kMaxPduLEExtendedAdvertisingDataLength;
  size_t last_report_size =
      pw::bluetooth::emboss::LEExtendedAdvertisingReportData::MinSizeInBytes() +
      (data.size() % hci_spec::kMaxPduLEExtendedAdvertisingDataLength);

  size_t reports_size = num_full_reports * full_report_size + last_report_size;
  size_t packet_size =
      pw::bluetooth::emboss::LEExtendedAdvertisingReportSubevent::
          MinSizeInBytes() +
      reports_size;

  auto event =
      hci::EmbossEventPacket::New<LEExtendedAdvertisingReportSubeventWriter>(
          hci_spec::kLEMetaEventCode, packet_size);
  auto packet =
      event.view<LEExtendedAdvertisingReportSubeventWriter>(reports_size);
  packet.le_meta_event().subevent_code().Write(
      hci_spec::kLEExtendedAdvertisingReportSubeventCode);

  uint8_t num_reports = num_full_reports + 1;
  packet.num_reports().Write(num_reports);

  for (size_t i = 0; i < num_full_reports; i++) {
    bool is_fragmented = false;
    if (num_reports > 1) {
      is_fragmented = true;
    }

    LEExtendedAdvertisingReportDataWriter report(
        packet.reports().BackingStorage().begin() + full_report_size * i,
        full_report_size);
    FillExtendedAdvertisingReport(
        peer, report, data, is_fragmented, is_scan_response);
  }

  LEExtendedAdvertisingReportDataWriter report(
      packet.reports().BackingStorage().begin() +
          full_report_size * num_full_reports,
      last_report_size);
  FillExtendedAdvertisingReport(peer, report, data, false, is_scan_response);

  return event.release();
}

DynamicByteBuffer FakeController::BuildExtendedAdvertisingReportEvent(
    const FakePeer& peer) const {
  BT_DEBUG_ASSERT(peer.advertising_data().size() <=
                  hci_spec::kMaxLEExtendedAdvertisingDataLength);
  return BuildExtendedAdvertisingReports(peer, peer.advertising_data(), false);
}

DynamicByteBuffer FakeController::BuildExtendedScanResponseEvent(
    const FakePeer& peer) const {
  BT_DEBUG_ASSERT(peer.scannable());
  BT_DEBUG_ASSERT(peer.scan_response().size() <=
                  hci_spec::kMaxLEExtendedAdvertisingDataLength);
  return BuildExtendedAdvertisingReports(peer, peer.scan_response(), true);
}

void FakeController::SendAdvertisingReports() {
  if (!le_scan_state_.enabled || peers_.empty()) {
    return;
  }

  for (const auto& iter : peers_) {
    SendAdvertisingReport(*iter.second);
  }

  // We'll send new reports for the same peers if duplicate filtering is
  // disabled.
  if (!le_scan_state_.filter_duplicates) {
    (void)heap_dispatcher().Post(
        [this](pw::async::Context /*ctx*/, pw::Status status) {
          if (status.ok()) {
            SendAdvertisingReports();
          }
        });
  }
}

void FakeController::SendAdvertisingReport(const FakePeer& peer) {
  if (!le_scan_state_.enabled || !peer.supports_le() ||
      !peer.advertising_enabled()) {
    return;
  }

  // We want to send scan response packets only during an active scan and if the
  // peer is scannable.
  bool is_active_scan =
      (le_scan_state_.scan_type == pw::bluetooth::emboss::LEScanType::ACTIVE);
  bool need_scan_rsp = (is_active_scan && peer.scannable());

  if (received_extended_operations_) {
    SendCommandChannelPacket(BuildExtendedAdvertisingReportEvent(peer));

    if (need_scan_rsp) {
      SendCommandChannelPacket(BuildExtendedScanResponseEvent(peer));
    }
  } else {
    bool include_scan_rsp = (need_scan_rsp && peer.should_batch_reports());
    SendCommandChannelPacket(
        BuildLegacyAdvertisingReportEvent(peer, include_scan_rsp));

    // If the original report did not include a scan response then we send it as
    // a separate event.
    if (need_scan_rsp && !peer.should_batch_reports()) {
      SendCommandChannelPacket(BuildLegacyScanResponseReportEvent(peer));
    }
  }
}

void FakeController::NotifyControllerParametersChanged() {
  if (controller_parameters_cb_) {
    controller_parameters_cb_();
  }
}

void FakeController::NotifyAdvertisingState() {
  if (advertising_state_cb_) {
    advertising_state_cb_();
  }
}

void FakeController::NotifyConnectionState(const DeviceAddress& addr,
                                           hci_spec::ConnectionHandle handle,
                                           bool connected,
                                           bool canceled) {
  if (conn_state_cb_) {
    conn_state_cb_(addr, handle, connected, canceled);
  }
}

void FakeController::NotifyLEConnectionParameters(
    const DeviceAddress& addr, const hci_spec::LEConnectionParameters& params) {
  if (le_conn_params_cb_) {
    le_conn_params_cb_(addr, params);
  }
}

void FakeController::OnCreateConnectionCommandReceived(
    const pw::bluetooth::emboss::CreateConnectionCommandView& params) {
  acl_create_connection_command_count_++;

  // Cannot issue this command while a request is already pending.
  if (bredr_connect_pending_) {
    RespondWithCommandStatus(
        hci_spec::kCreateConnection,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  const DeviceAddress peer_address(DeviceAddress::Type::kBREDR,
                                   DeviceAddressBytes(params.bd_addr()));
  pw::bluetooth::emboss::StatusCode status =
      pw::bluetooth::emboss::StatusCode::SUCCESS;

  // Find the peer that matches the requested address.
  FakePeer* peer = FindPeer(peer_address);
  if (peer) {
    if (peer->connected())
      status = pw::bluetooth::emboss::StatusCode::CONNECTION_ALREADY_EXISTS;
    else
      status = peer->connect_status();
  }

  // First send the Command Status response.
  RespondWithCommandStatus(hci_spec::kCreateConnection, status);

  // If we just sent back an error status then the operation is complete.
  if (status != pw::bluetooth::emboss::StatusCode::SUCCESS)
    return;

  bredr_connect_pending_ = true;
  pending_bredr_connect_addr_ = peer_address;

  // The procedure was initiated successfully but the peer cannot be connected
  // because it either doesn't exist or isn't connectable.
  if (!peer || !peer->connectable()) {
    bt_log(INFO,
           "fake-hci",
           "requested peer %s cannot be connected; request will time out",
           peer_address.ToString().c_str());

    bredr_connect_rsp_task_.Cancel();
    bredr_connect_rsp_task_.set_function(
        [this, peer_address](pw::async::Context /*ctx*/, pw::Status status) {
          if (!status.ok()) {
            return;
          }
          bredr_connect_pending_ = false;

          auto response = hci::EmbossEventPacket::New<
              pw::bluetooth::emboss::ConnectionCompleteEventWriter>(
              hci_spec::kConnectionCompleteEventCode);
          response.view_t().status().Write(
              pw::bluetooth::emboss::StatusCode::PAGE_TIMEOUT);
          response.view_t().bd_addr().CopyFrom(peer_address.value().view());
          SendCommandChannelPacket(response.data());
        });

    // Default page timeout of 5.12s
    // See Core Spec v5.0 Vol 2, Part E, Section 6.6
    constexpr pw::chrono::SystemClock::duration default_page_timeout =
        std::chrono::microseconds(static_cast<int64_t>(625) * 0x2000);
    bredr_connect_rsp_task_.PostAfter(default_page_timeout);
    return;
  }

  if (next_conn_handle_ == 0x0FFF) {
    // Ran out of handles
    status = pw::bluetooth::emboss::StatusCode::CONNECTION_LIMIT_EXCEEDED;
  } else {
    status = peer->connect_response();
  }

  auto response = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::ConnectionCompleteEventWriter>(
      hci_spec::kConnectionCompleteEventCode);
  response.view_t().status().Write(status);
  response.view_t().bd_addr().CopyFrom(params.bd_addr());
  response.view_t().link_type().Write(pw::bluetooth::emboss::LinkType::ACL);
  response.view_t().encryption_enabled().Write(
      pw::bluetooth::emboss::GenericEnableParam::DISABLE);

  if (status == pw::bluetooth::emboss::StatusCode::SUCCESS) {
    hci_spec::ConnectionHandle handle = ++next_conn_handle_;
    response.view_t().connection_handle().Write(handle);
  }

  // Don't send a connection event if we were asked to force the request to
  // remain pending. This is used by test cases that operate during the pending
  // state.
  if (peer->force_pending_connect())
    return;

  bredr_connect_rsp_task_.Cancel();
  bredr_connect_rsp_task_.set_function(
      [response, peer, this](pw::async::Context /*ctx*/,
                             pw::Status status) mutable {
        if (!status.ok()) {
          return;
        }
        bredr_connect_pending_ = false;

        if (response.view_t().status().Read() ==
            pw::bluetooth::emboss::StatusCode::SUCCESS) {
          bool notify = !peer->connected();
          hci_spec::ConnectionHandle handle =
              response.view_t().connection_handle().Read();
          peer->AddLink(handle);
          if (notify && peer->connected()) {
            NotifyConnectionState(peer->address(), handle, /*connected=*/true);
          }
        }

        SendCommandChannelPacket(response.data());
      });
  bredr_connect_rsp_task_.Post();
}

void FakeController::OnLECreateConnectionCommandReceived(
    const pw::bluetooth::emboss::LECreateConnectionCommandView& params) {
  le_create_connection_command_count_++;
  if (le_create_connection_cb_) {
    le_create_connection_cb_(params);
  }

  // Cannot issue this command while a request is already pending.
  if (le_connect_pending_) {
    RespondWithCommandStatus(
        hci_spec::kLECreateConnection,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  DeviceAddress::Type addr_type =
      DeviceAddress::LeAddrToDeviceAddr(params.peer_address_type().Read());
  BT_DEBUG_ASSERT(addr_type != DeviceAddress::Type::kBREDR);

  const DeviceAddress peer_address(addr_type,
                                   DeviceAddressBytes(params.peer_address()));
  pw::bluetooth::emboss::StatusCode status =
      pw::bluetooth::emboss::StatusCode::SUCCESS;

  // Find the peer that matches the requested address.
  FakePeer* peer = FindPeer(peer_address);
  if (peer) {
    if (peer->connected())
      status = pw::bluetooth::emboss::StatusCode::CONNECTION_ALREADY_EXISTS;
    else
      status = peer->connect_status();
  }

  // First send the Command Status response.
  RespondWithCommandStatus(hci_spec::kLECreateConnection, status);

  // If we just sent back an error status then the operation is complete.
  if (status != pw::bluetooth::emboss::StatusCode::SUCCESS)
    return;

  le_connect_pending_ = true;
  if (!le_connect_params_) {
    le_connect_params_ = LEConnectParams();
  }

  le_connect_params_->own_address_type = params.own_address_type().Read();
  le_connect_params_->peer_address = peer_address;

  // The procedure was initiated successfully but the peer cannot be connected
  // because it either doesn't exist or isn't connectable.
  if (!peer || !peer->connectable()) {
    bt_log(INFO,
           "fake-hci",
           "requested fake peer cannot be connected; request will time out");
    return;
  }

  if (next_conn_handle_ == 0x0FFF) {
    // Ran out of handles
    status = pw::bluetooth::emboss::StatusCode::CONNECTION_LIMIT_EXCEEDED;
  } else {
    status = peer->connect_response();
  }

  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::LEConnectionCompleteSubeventWriter>(
      hci_spec::kLEMetaEventCode);
  auto view = packet.view_t();
  view.le_meta_event().subevent_code().Write(
      hci_spec::kLEConnectionCompleteSubeventCode);
  view.status().Write(status);
  view.peer_address().CopyFrom(params.peer_address());
  view.peer_address_type().Write(
      DeviceAddress::DeviceAddrToLePeerAddr(addr_type));

  if (status == pw::bluetooth::emboss::StatusCode::SUCCESS) {
    uint16_t interval_min = params.connection_interval_min().UncheckedRead();
    uint16_t interval_max = params.connection_interval_max().UncheckedRead();
    uint16_t interval = interval_min + ((interval_max - interval_min) / 2);

    hci_spec::LEConnectionParameters conn_params(
        interval,
        params.max_latency().UncheckedRead(),
        params.supervision_timeout().UncheckedRead());
    peer->set_le_params(conn_params);

    view.peripheral_latency().UncheckedCopyFrom(params.max_latency());
    view.connection_interval().UncheckedWrite(interval);
    view.supervision_timeout().UncheckedCopyFrom(params.supervision_timeout());
    view.role().Write(pw::bluetooth::emboss::ConnectionRole::CENTRAL);
    view.connection_handle().Write(++next_conn_handle_);
  }

  // Don't send a connection event if we were asked to force the request to
  // remain pending. This is used by test cases that operate during the pending
  // state.
  if (peer->force_pending_connect())
    return;

  le_connect_rsp_task_.Cancel();
  le_connect_rsp_task_.set_function([packet, address = peer_address, this](
                                        pw::async::Context /*ctx*/,
                                        pw::Status status) {
    auto peer = FindPeer(address);
    if (!peer || !status.ok()) {
      // The peer has been removed or dispatcher shut down; Ignore this response
      return;
    }

    le_connect_pending_ = false;

    auto view =
        packet.view<pw::bluetooth::emboss::LEConnectionCompleteSubeventView>();
    if (view.status().Read() == pw::bluetooth::emboss::StatusCode::SUCCESS) {
      bool not_previously_connected = !peer->connected();
      hci_spec::ConnectionHandle handle = view.connection_handle().Read();
      peer->AddLink(handle);
      if (not_previously_connected && peer->connected()) {
        NotifyConnectionState(peer->address(), handle, /*connected=*/true);
      }
    }

    SendCommandChannelPacket(packet.data());
  });
  le_connect_rsp_task_.PostAfter(settings_.le_connection_delay);
}

void FakeController::OnLEConnectionUpdateCommandReceived(
    const pw::bluetooth::emboss::LEConnectionUpdateCommandView& params) {
  hci_spec::ConnectionHandle handle = params.connection_handle().Read();
  FakePeer* peer = FindByConnHandle(handle);
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kLEConnectionUpdate,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  BT_DEBUG_ASSERT(peer->connected());

  uint16_t min_interval = params.connection_interval_min().UncheckedRead();
  uint16_t max_interval = params.connection_interval_max().UncheckedRead();
  uint16_t max_latency = params.max_latency().UncheckedRead();
  uint16_t supv_timeout = params.supervision_timeout().UncheckedRead();

  if (min_interval > max_interval) {
    RespondWithCommandStatus(
        hci_spec::kLEConnectionUpdate,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  RespondWithCommandStatus(hci_spec::kLEConnectionUpdate,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  hci_spec::LEConnectionParameters conn_params(
      min_interval + ((max_interval - min_interval) / 2),
      max_latency,
      supv_timeout);
  peer->set_le_params(conn_params);

  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::LEConnectionUpdateCompleteSubeventWriter>(
      hci_spec::kLEMetaEventCode);
  auto view = packet.view_t();
  view.le_meta_event().subevent_code().Write(
      hci_spec::kLEConnectionUpdateCompleteSubeventCode);
  view.connection_handle().CopyFrom(params.connection_handle());
  if (peer->supports_ll_conn_update_procedure()) {
    view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
    view.connection_interval().UncheckedWrite(conn_params.interval());
    view.peripheral_latency().CopyFrom(params.max_latency());
    view.supervision_timeout().UncheckedCopyFrom(params.supervision_timeout());
  } else {
    view.status().Write(
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_REMOTE_FEATURE);
  }
  SendCommandChannelPacket(packet.data());

  NotifyLEConnectionParameters(peer->address(), conn_params);
}

void FakeController::OnDisconnectCommandReceived(
    const pw::bluetooth::emboss::DisconnectCommandView& params) {
  hci_spec::ConnectionHandle handle = params.connection_handle().Read();

  // Find the peer that matches the disconnected handle.
  FakePeer* peer = FindByConnHandle(handle);
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kDisconnect,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  BT_DEBUG_ASSERT(peer->connected());

  RespondWithCommandStatus(hci_spec::kDisconnect,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  bool notify = peer->connected();
  peer->RemoveLink(handle);
  if (notify && !peer->connected()) {
    NotifyConnectionState(peer->address(), handle, /*connected=*/false);
  }

  if (auto_disconnection_complete_event_enabled_) {
    SendDisconnectionCompleteEvent(handle);
  }
}

void FakeController::OnWriteLEHostSupportCommandReceived(
    const pw::bluetooth::emboss::WriteLEHostSupportCommandView& params) {
  if (params.le_supported_host().Read() ==
      pw::bluetooth::emboss::GenericEnableParam::ENABLE) {
    SetBit(&settings_.lmp_features_page1,
           hci_spec::LMPFeature::kLESupportedHost);
  } else {
    UnsetBit(&settings_.lmp_features_page1,
             hci_spec::LMPFeature::kLESupportedHost);
  }

  RespondWithCommandComplete(hci_spec::kWriteLEHostSupport,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnWriteSecureConnectionsHostSupport(
    const pw::bluetooth::emboss::WriteSecureConnectionsHostSupportCommandView&
        params) {
  // Core Spec Volume 4, Part E, Section 7.3.92: If the Host issues this command
  // while the Controller is paging, has page scanning enabled, or has an ACL
  // connection, the Controller shall return the error code Command Disallowed
  // (0x0C).
  bool has_acl_connection = false;
  for (auto& [_, peer] : peers_) {
    if (peer->connected()) {
      has_acl_connection = true;
      break;
    }
  }
  if (bredr_connect_pending_ || isBREDRPageScanEnabled() ||
      has_acl_connection) {
    RespondWithCommandComplete(
        hci_spec::kWriteSecureConnectionsHostSupport,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  if (params.secure_connections_host_support().Read() ==
      pw::bluetooth::emboss::GenericEnableParam::ENABLE) {
    SetBit(&settings_.lmp_features_page1,
           hci_spec::LMPFeature::kSecureConnectionsHostSupport);
  } else {
    UnsetBit(&settings_.lmp_features_page1,
             hci_spec::LMPFeature::kSecureConnectionsHostSupport);
  }

  RespondWithCommandComplete(hci_spec::kWriteSecureConnectionsHostSupport,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnReset() {
  // TODO(fxbug.dev/42159137): actually do some resetting of stuff here
  RespondWithCommandComplete(hci_spec::kReset,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnInquiry(
    const pw::bluetooth::emboss::InquiryCommandView& params) {
  // Confirm that LAP array is equal to either kGIAC or kLIAC.
  if (params.lap().Read() != pw::bluetooth::emboss::InquiryAccessCode::GIAC &&
      params.lap().Read() != pw::bluetooth::emboss::InquiryAccessCode::LIAC) {
    RespondWithCommandStatus(
        hci_spec::kInquiry,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  if (params.inquiry_length().Read() == 0x00 ||
      params.inquiry_length().Read() > hci_spec::kInquiryLengthMax) {
    RespondWithCommandStatus(
        hci_spec::kInquiry,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  inquiry_num_responses_left_ = params.num_responses().Read();
  if (params.num_responses().Read() == 0) {
    inquiry_num_responses_left_ = -1;
  }

  RespondWithCommandStatus(hci_spec::kInquiry,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  bt_log(INFO, "fake-hci", "sending inquiry responses..");
  SendInquiryResponses();

  (void)heap_dispatcher().PostAfter(
      [this](pw::async::Context /*ctx*/, pw::Status status) {
        if (!status.ok()) {
          return;
        }
        auto output = hci::EmbossEventPacket::New<
            pw::bluetooth::emboss::InquiryCompleteEventWriter>(
            hci_spec::kInquiryCompleteEventCode);
        output.view_t().status().Write(
            pw::bluetooth::emboss::StatusCode::SUCCESS);
        SendCommandChannelPacket(output.data());
      },
      std::chrono::milliseconds(params.inquiry_length().Read()) * 1280);
}

void FakeController::OnLESetScanEnable(
    const pw::bluetooth::emboss::LESetScanEnableCommandView& params) {
  le_scan_state_.enabled = false;
  if (params.le_scan_enable().Read() ==
      pw::bluetooth::emboss::GenericEnableParam::ENABLE) {
    le_scan_state_.enabled = true;
  }

  le_scan_state_.filter_duplicates = false;
  if (params.filter_duplicates().Read() ==
      pw::bluetooth::emboss::GenericEnableParam::ENABLE) {
    le_scan_state_.filter_duplicates = true;
  }

  // Post the scan state update before scheduling the HCI Command Complete
  // event. This guarantees that single-threaded unit tests receive the scan
  // state update BEFORE the HCI command sequence terminates.
  if (scan_state_cb_) {
    scan_state_cb_(le_scan_state_.enabled);
  }

  RespondWithCommandComplete(hci_spec::kLESetScanEnable,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);

  if (le_scan_state_.enabled) {
    SendAdvertisingReports();
  }
}

void FakeController::OnLESetExtendedScanEnable(
    const pw::bluetooth::emboss::LESetExtendedScanEnableCommandView& params) {
  received_extended_operations_ = true;

  le_scan_state_.enabled = false;
  if (params.scanning_enabled().Read() ==
      pw::bluetooth::emboss::GenericEnableParam::ENABLE) {
    le_scan_state_.enabled = true;
  }

  le_scan_state_.filter_duplicates = true;
  if (params.filter_duplicates().Read() ==
      pw::bluetooth::emboss::LEExtendedDuplicateFilteringOption::DISABLED) {
    le_scan_state_.filter_duplicates = false;
  }

  le_scan_state_.duration = params.duration().Read();
  le_scan_state_.period = params.period().Read();

  // Post the scan state update before scheduling the HCI Command Complete
  // event. This guarantees that single-threaded unit tests receive the scan
  // state update BEFORE the HCI command sequence terminates.
  if (scan_state_cb_) {
    scan_state_cb_(le_scan_state_.enabled);
  }

  RespondWithCommandComplete(hci_spec::kLESetExtendedScanEnable,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);

  if (le_scan_state_.enabled) {
    SendAdvertisingReports();
  }
}

void FakeController::OnLESetScanParameters(
    const pw::bluetooth::emboss::LESetScanParametersCommandView& params) {
  if (le_scan_state_.enabled) {
    RespondWithCommandComplete(
        hci_spec::kLESetScanParameters,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  le_scan_state_.own_address_type = params.own_address_type().Read();
  le_scan_state_.filter_policy = params.scanning_filter_policy().Read();
  le_scan_state_.scan_type = params.le_scan_type().Read();
  le_scan_state_.scan_interval = params.le_scan_interval().Read();
  le_scan_state_.scan_window = params.le_scan_window().Read();

  RespondWithCommandComplete(hci_spec::kLESetScanParameters,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnLESetExtendedScanParameters(
    const pw::bluetooth::emboss::LESetExtendedScanParametersCommandView&
        params) {
  received_extended_operations_ = true;

  if (le_scan_state_.enabled) {
    RespondWithCommandComplete(
        hci_spec::kLESetScanParameters,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  if (params.num_entries().Read() == 0) {
    RespondWithCommandComplete(
        hci_spec::kLESetScanParameters,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  le_scan_state_.own_address_type = params.own_address_type().Read();
  le_scan_state_.filter_policy = params.scanning_filter_policy().Read();

  // ExtendedLowEnergyScanner sets the same parameters for both the LE 1M and LE
  // Coded PHYs. We just take the parameters from the LE 1M PHY for now since we
  // don't support using different parameters for different PHYs.
  if (!params.scanning_phys().le_1m().Read()) {
    RespondWithCommandComplete(
        hci_spec::kLESetScanParameters,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  le_scan_state_.scan_type = params.data()[0].scan_type().Read();
  le_scan_state_.scan_interval = params.data()[0].scan_interval().Read();
  le_scan_state_.scan_window = params.data()[0].scan_window().Read();
  RespondWithCommandComplete(hci_spec::kLESetExtendedScanParameters,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnReadLocalExtendedFeatures(
    const pw::bluetooth::emboss::ReadLocalExtendedFeaturesCommandView& params) {
  hci_spec::ReadLocalExtendedFeaturesReturnParams out_params;
  out_params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  out_params.page_number = params.page_number().Read();
  out_params.maximum_page_number = 2;
  out_params.extended_lmp_features = 0;

  switch (params.page_number().Read()) {
    case 0:
      out_params.extended_lmp_features = htole64(settings_.lmp_features_page0);
      break;
    case 1:
      out_params.extended_lmp_features = htole64(settings_.lmp_features_page1);
      break;
    case 2:
      out_params.extended_lmp_features = htole64(settings_.lmp_features_page2);
      break;
    default:
      out_params.status =
          pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
  }

  RespondWithCommandComplete(hci_spec::kReadLocalExtendedFeatures,
                             BufferView(&out_params, sizeof(out_params)));
}

void FakeController::OnSetEventMask(
    const pw::bluetooth::emboss::SetEventMaskCommandView& params) {
  settings_.event_mask = params.event_mask().Read();
  RespondWithCommandComplete(hci_spec::kSetEventMask,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnLESetEventMask(
    const pw::bluetooth::emboss::LESetEventMaskCommandView& params) {
  settings_.le_event_mask = params.le_event_mask().BackingStorage().ReadUInt();
  RespondWithCommandComplete(hci_spec::kLESetEventMask,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnLEReadBufferSizeV1() {
  hci_spec::LEReadBufferSizeV1ReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.hc_le_acl_data_packet_length =
      htole16(settings_.le_acl_data_packet_length);
  params.hc_total_num_le_acl_data_packets =
      settings_.le_total_num_acl_data_packets;
  RespondWithCommandComplete(hci_spec::kLEReadBufferSizeV1,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnLEReadBufferSizeV2() {
  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::LEReadBufferSizeV2CommandCompleteEventWriter>(
      hci_spec::kCommandCompleteEventCode);
  auto view = packet.view_t();

  view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
  view.le_acl_data_packet_length().Write(settings_.le_acl_data_packet_length);
  view.total_num_le_acl_data_packets().Write(
      settings_.le_total_num_acl_data_packets);
  view.iso_data_packet_length().Write(settings_.iso_data_packet_length);
  view.total_num_iso_data_packets().Write(settings_.total_num_iso_data_packets);

  RespondWithCommandComplete(hci_spec::kLEReadBufferSizeV2, &packet);
}

void FakeController::OnLEReadSupportedStates() {
  hci_spec::LEReadSupportedStatesReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.le_states = htole64(settings_.le_supported_states);
  RespondWithCommandComplete(hci_spec::kLEReadSupportedStates,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnLEReadLocalSupportedFeatures() {
  hci_spec::LEReadLocalSupportedFeaturesReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.le_features = htole64(settings_.le_features);
  RespondWithCommandComplete(hci_spec::kLEReadLocalSupportedFeatures,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnLECreateConnectionCancel() {
  if (!le_connect_pending_) {
    // No request is currently pending.
    RespondWithCommandComplete(
        hci_spec::kLECreateConnectionCancel,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  le_connect_pending_ = false;
  le_connect_rsp_task_.Cancel();
  BT_DEBUG_ASSERT(le_connect_params_);

  NotifyConnectionState(le_connect_params_->peer_address,
                        0,
                        /*connected=*/false,
                        /*canceled=*/true);

  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::LEConnectionCompleteSubeventWriter>(
      hci_spec::kLEMetaEventCode);
  auto view = packet.view_t();
  view.le_meta_event().subevent_code().Write(
      hci_spec::kLEConnectionCompleteSubeventCode);
  view.status().Write(pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
  view.peer_address().CopyFrom(le_connect_params_->peer_address.value().view());
  view.peer_address_type().Write(DeviceAddress::DeviceAddrToLePeerAddr(
      le_connect_params_->peer_address.type()));

  RespondWithCommandComplete(hci_spec::kLECreateConnectionCancel,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  SendCommandChannelPacket(packet.data());
}

void FakeController::OnWriteExtendedInquiryResponse(
    const pw::bluetooth::emboss::WriteExtendedInquiryResponseCommandView&
        params) {
  // As of now, we don't support FEC encoding enabled.
  if (params.fec_required().Read() != 0x00) {
    RespondWithCommandStatus(
        hci_spec::kWriteExtendedInquiryResponse,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
  }

  RespondWithCommandComplete(hci_spec::kWriteExtendedInquiryResponse,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnWriteSimplePairingMode(
    const pw::bluetooth::emboss::WriteSimplePairingModeCommandView& params) {
  // "A host shall not set the Simple Pairing Mode to 'disabled'"
  // Spec 5.0 Vol 2 Part E Sec 7.3.59
  if (params.simple_pairing_mode().Read() !=
      pw::bluetooth::emboss::GenericEnableParam::ENABLE) {
    RespondWithCommandComplete(
        hci_spec::kWriteSimplePairingMode,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  SetBit(&settings_.lmp_features_page1,
         hci_spec::LMPFeature::kSecureSimplePairingHostSupport);
  RespondWithCommandComplete(hci_spec::kWriteSimplePairingMode,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnReadSimplePairingMode() {
  hci_spec::ReadSimplePairingModeReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  if (CheckBit(settings_.lmp_features_page1,
               hci_spec::LMPFeature::kSecureSimplePairingHostSupport)) {
    params.simple_pairing_mode =
        pw::bluetooth::emboss::GenericEnableParam::ENABLE;
  } else {
    params.simple_pairing_mode =
        pw::bluetooth::emboss::GenericEnableParam::DISABLE;
  }

  RespondWithCommandComplete(hci_spec::kReadSimplePairingMode,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnWritePageScanType(
    const pw::bluetooth::emboss::WritePageScanTypeCommandView& params) {
  page_scan_type_ = params.page_scan_type().Read();
  RespondWithCommandComplete(hci_spec::kWritePageScanType,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnReadPageScanType() {
  hci_spec::ReadPageScanTypeReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.page_scan_type = page_scan_type_;
  RespondWithCommandComplete(hci_spec::kReadPageScanType,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnWriteInquiryMode(
    const pw::bluetooth::emboss::WriteInquiryModeCommandView& params) {
  inquiry_mode_ = params.inquiry_mode().Read();
  RespondWithCommandComplete(hci_spec::kWriteInquiryMode,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnReadInquiryMode() {
  hci_spec::ReadInquiryModeReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.inquiry_mode = inquiry_mode_;
  RespondWithCommandComplete(hci_spec::kReadInquiryMode,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnWriteClassOfDevice(
    const pw::bluetooth::emboss::WriteClassOfDeviceCommandView& params) {
  device_class_ =
      DeviceClass(params.class_of_device().BackingStorage().ReadUInt());
  NotifyControllerParametersChanged();
  RespondWithCommandComplete(hci_spec::kWriteClassOfDevice,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnWritePageScanActivity(
    const pw::bluetooth::emboss::WritePageScanActivityCommandView& params) {
  page_scan_interval_ = params.page_scan_interval().Read();
  page_scan_window_ = params.page_scan_window().Read();
  RespondWithCommandComplete(hci_spec::kWritePageScanActivity,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnReadPageScanActivity() {
  hci_spec::ReadPageScanActivityReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.page_scan_interval = htole16(page_scan_interval_);
  params.page_scan_window = htole16(page_scan_window_);
  RespondWithCommandComplete(hci_spec::kReadPageScanActivity,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnWriteScanEnable(
    const pw::bluetooth::emboss::WriteScanEnableCommandView& params) {
  bredr_scan_state_ = params.scan_enable().BackingStorage().ReadUInt();
  RespondWithCommandComplete(hci_spec::kWriteScanEnable,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnReadScanEnable() {
  hci_spec::ReadScanEnableReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.scan_enable = bredr_scan_state_;
  RespondWithCommandComplete(hci_spec::kReadScanEnable,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnReadLocalName() {
  hci_spec::ReadLocalNameReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  auto mut_view =
      MutableBufferView(params.local_name, hci_spec::kMaxNameLength);
  mut_view.Write((const uint8_t*)(local_name_.c_str()),
                 std::min(local_name_.length() + 1, hci_spec::kMaxNameLength));
  RespondWithCommandComplete(hci_spec::kReadLocalName,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnWriteLocalName(
    const pw::bluetooth::emboss::WriteLocalNameCommandView& params) {
  std::size_t name_len = 0;

  auto local_name = params.local_name().BackingStorage().data();

  for (; name_len < hci_spec::kMaxNameLength; ++name_len) {
    if (local_name[name_len] == '\0') {
      break;
    }
  }
  local_name_ = std::string(local_name, local_name + name_len);
  NotifyControllerParametersChanged();
  RespondWithCommandComplete(hci_spec::kWriteLocalName,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnCreateConnectionCancel() {
  hci_spec::CreateConnectionCancelReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.bd_addr = pending_bredr_connect_addr_.value();

  if (!bredr_connect_pending_) {
    // No request is currently pending.
    params.status = pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID;
    RespondWithCommandComplete(hci_spec::kCreateConnectionCancel,
                               BufferView(&params, sizeof(params)));
    return;
  }

  bredr_connect_pending_ = false;
  bredr_connect_rsp_task_.Cancel();

  NotifyConnectionState(
      pending_bredr_connect_addr_, 0, /*connected=*/false, /*canceled=*/true);

  RespondWithCommandComplete(hci_spec::kCreateConnectionCancel,
                             BufferView(&params, sizeof(params)));

  auto response = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::ConnectionCompleteEventWriter>(
      hci_spec::kConnectionCompleteEventCode);
  response.view_t().status().Write(
      pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
  response.view_t().bd_addr().CopyFrom(
      pending_bredr_connect_addr_.value().view());
  SendCommandChannelPacket(response.data());
}

void FakeController::OnReadBufferSize() {
  hci_spec::ReadBufferSizeReturnParams params;
  std::memset(&params, 0, sizeof(params));
  params.hc_acl_data_packet_length = htole16(settings_.acl_data_packet_length);
  params.hc_total_num_acl_data_packets = settings_.total_num_acl_data_packets;
  params.hc_synchronous_data_packet_length =
      htole16(settings_.synchronous_data_packet_length);
  params.hc_total_num_synchronous_data_packets =
      settings_.total_num_synchronous_data_packets;
  RespondWithCommandComplete(hci_spec::kReadBufferSize,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnReadBRADDR() {
  hci_spec::ReadBDADDRReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.bd_addr = settings_.bd_addr.value();
  RespondWithCommandComplete(hci_spec::kReadBDADDR,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnLESetAdvertisingEnable(
    const pw::bluetooth::emboss::LESetAdvertisingEnableCommandView& params) {
  // TODO(fxbug.dev/42161900): if own address type is random, check that a
  // random address is set

  legacy_advertising_state_.enabled =
      params.advertising_enable().Read() ==
      pw::bluetooth::emboss::GenericEnableParam::ENABLE;
  RespondWithCommandComplete(hci_spec::kLESetAdvertisingEnable,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLESetScanResponseData(
    const pw::bluetooth::emboss::LESetScanResponseDataCommandView& params) {
  legacy_advertising_state_.scan_rsp_length =
      params.scan_response_data_length().Read();

  if (params.scan_response_data_length().Read() == 0) {
    std::memset(legacy_advertising_state_.scan_rsp_data,
                0,
                sizeof(legacy_advertising_state_.scan_rsp_data));
  } else {
    std::memcpy(legacy_advertising_state_.scan_rsp_data,
                params.scan_response_data().BackingStorage().data(),
                params.scan_response_data_length().Read());
  }

  RespondWithCommandComplete(hci_spec::kLESetScanResponseData,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLESetAdvertisingData(
    const pw::bluetooth::emboss::LESetAdvertisingDataCommandView& params) {
  legacy_advertising_state_.data_length =
      params.advertising_data_length().Read();

  if (params.advertising_data_length().Read() == 0) {
    std::memset(legacy_advertising_state_.data,
                0,
                sizeof(legacy_advertising_state_.data));
  } else {
    std::memcpy(legacy_advertising_state_.data,
                params.advertising_data().BackingStorage().data(),
                params.advertising_data_length().Read());
  }

  RespondWithCommandComplete(hci_spec::kLESetAdvertisingData,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLESetAdvertisingParameters(
    const pw::bluetooth::emboss::LESetAdvertisingParametersCommandView&
        params) {
  if (legacy_advertising_state_.enabled) {
    bt_log(INFO,
           "fake-hci",
           "cannot set advertising parameters while advertising enabled");
    RespondWithCommandComplete(
        hci_spec::kLESetAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  uint16_t interval_min = params.advertising_interval_min().UncheckedRead();
  uint16_t interval_max = params.advertising_interval_max().UncheckedRead();

  // Core Spec Volume 4, Part E, Section 7.8.5: For high duty cycle directed
  // advertising, the Advertising_Interval_Min and Advertising_Interval_Max
  // parameters are not used and shall be ignored.
  if (params.adv_type().Read() != pw::bluetooth::emboss::LEAdvertisingType::
                                      CONNECTABLE_HIGH_DUTY_CYCLE_DIRECTED) {
    if (interval_min >= interval_max) {
      bt_log(INFO,
             "fake-hci",
             "advertising interval min (%d) not strictly less than max (%d)",
             interval_min,
             interval_max);
      RespondWithCommandComplete(
          hci_spec::kLESetAdvertisingParameters,
          pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER);
      return;
    }

    if (interval_min < hci_spec::kLEAdvertisingIntervalMin) {
      bt_log(INFO,
             "fake-hci",
             "advertising interval min (%d) less than spec min (%d)",
             interval_min,
             hci_spec::kLEAdvertisingIntervalMin);
      RespondWithCommandComplete(
          hci_spec::kLESetAdvertisingParameters,
          pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER);
      return;
    }

    if (interval_max > hci_spec::kLEAdvertisingIntervalMax) {
      bt_log(INFO,
             "fake-hci",
             "advertising interval max (%d) greater than spec max (%d)",
             interval_max,
             hci_spec::kLEAdvertisingIntervalMax);
      RespondWithCommandComplete(
          hci_spec::kLESetAdvertisingParameters,
          pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER);
      return;
    }
  }

  legacy_advertising_state_.interval_min = interval_min;
  legacy_advertising_state_.interval_max = interval_max;
  legacy_advertising_state_.adv_type =
      static_cast<pw::bluetooth::emboss::LEAdvertisingType>(
          params.adv_type().Read());
  legacy_advertising_state_.own_address_type = params.own_address_type().Read();

  bt_log(INFO,
         "fake-hci",
         "start advertising using address type: %hhd",
         static_cast<char>(legacy_advertising_state_.own_address_type));

  RespondWithCommandComplete(hci_spec::kLESetAdvertisingParameters,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLESetRandomAddress(
    const pw::bluetooth::emboss::LESetRandomAddressCommandView& params) {
  if (legacy_advertising_state().enabled || le_scan_state().enabled) {
    bt_log(INFO,
           "fake-hci",
           "cannot set LE random address while scanning or advertising");
    RespondWithCommandComplete(
        hci_spec::kLESetRandomAddress,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  legacy_advertising_state_.random_address =
      DeviceAddress(DeviceAddress::Type::kLERandom,
                    DeviceAddressBytes(params.random_address()));
  RespondWithCommandComplete(hci_spec::kLESetRandomAddress,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnReadLocalSupportedFeatures() {
  hci_spec::ReadLocalSupportedFeaturesReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.lmp_features = htole64(settings_.lmp_features_page0);
  RespondWithCommandComplete(hci_spec::kReadLocalSupportedFeatures,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnReadLocalSupportedCommands() {
  hci_spec::ReadLocalSupportedCommandsReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  std::memcpy(params.supported_commands,
              settings_.supported_commands,
              sizeof(params.supported_commands));
  RespondWithCommandComplete(hci_spec::kReadLocalSupportedCommands,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnReadLocalVersionInfo() {
  hci_spec::ReadLocalVersionInfoReturnParams params;
  std::memset(&params, 0, sizeof(params));
  params.hci_version = settings_.hci_version;
  RespondWithCommandComplete(hci_spec::kReadLocalVersionInfo,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnReadRemoteNameRequestCommandReceived(
    const pw::bluetooth::emboss::RemoteNameRequestCommandView& params) {
  const DeviceAddress peer_address(DeviceAddress::Type::kBREDR,
                                   DeviceAddressBytes(params.bd_addr()));

  // Find the peer that matches the requested address.
  FakePeer* peer = FindPeer(peer_address);
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kRemoteNameRequest,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  RespondWithCommandStatus(hci_spec::kRemoteNameRequest,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  struct RemoteNameRequestCompleteEventParams {
    pw::bluetooth::emboss::StatusCode status;
    DeviceAddressBytes bd_addr;
    uint8_t remote_name[hci_spec::kMaxNameLength];
  } __attribute__((packed));
  RemoteNameRequestCompleteEventParams response = {};
  response.bd_addr = DeviceAddressBytes(params.bd_addr());
  std::strncpy((char*)response.remote_name,
               peer->name().c_str(),
               hci_spec::kMaxNameLength);
  response.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  SendEvent(hci_spec::kRemoteNameRequestCompleteEventCode,
            BufferView(&response, sizeof(response)));
}

void FakeController::OnReadRemoteSupportedFeaturesCommandReceived(
    const pw::bluetooth::emboss::ReadRemoteSupportedFeaturesCommandView&
        params) {
  RespondWithCommandStatus(hci_spec::kReadRemoteSupportedFeatures,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  hci_spec::ReadRemoteSupportedFeaturesCompleteEventParams response = {};
  response.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  response.connection_handle = htole16(params.connection_handle().Read());
  response.lmp_features = settings_.lmp_features_page0;
  SendEvent(hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode,
            BufferView(&response, sizeof(response)));
}

void FakeController::OnReadRemoteVersionInfoCommandReceived(
    const pw::bluetooth::emboss::ReadRemoteVersionInfoCommandView& params) {
  RespondWithCommandStatus(hci_spec::kReadRemoteVersionInfo,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);
  auto response = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::ReadRemoteVersionInfoCompleteEventWriter>(
      hci_spec::kReadRemoteVersionInfoCompleteEventCode);
  auto view = response.view_t();
  view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
  view.connection_handle().CopyFrom(params.connection_handle());
  view.version().Write(pw::bluetooth::emboss::CoreSpecificationVersion::V4_2);
  view.company_identifier().Write(0xFFFF);  // anything
  view.subversion().Write(0xADDE);          // anything
  SendCommandChannelPacket(response.data());
}

void FakeController::OnReadRemoteExtendedFeaturesCommandReceived(
    const pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCommandView&
        params) {
  auto response = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCompleteEventWriter>(
      hci_spec::kReadRemoteExtendedFeaturesCompleteEventCode);
  auto view = response.view_t();

  switch (params.page_number().Read()) {
    case 1: {
      view.lmp_features().BackingStorage().WriteUInt(
          settings_.lmp_features_page1);
      break;
    }
    case 2: {
      view.lmp_features().BackingStorage().WriteUInt(
          settings_.lmp_features_page2);
      break;
    }
    default: {
      RespondWithCommandStatus(
          hci_spec::kReadRemoteExtendedFeatures,
          pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
      return;
    }
  }

  RespondWithCommandStatus(hci_spec::kReadRemoteExtendedFeatures,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);
  view.page_number().CopyFrom(params.page_number());
  view.max_page_number().Write(3);
  view.connection_handle().CopyFrom(params.connection_handle());
  view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
  SendCommandChannelPacket(response.data());
}

void FakeController::OnAuthenticationRequestedCommandReceived(
    const pw::bluetooth::emboss::AuthenticationRequestedCommandView& params) {
  hci_spec::ConnectionHandle handle = params.connection_handle().Read();
  FakePeer* peer = FindByConnHandle(handle);
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kAuthenticationRequested,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  RespondWithCommandStatus(hci_spec::kAuthenticationRequested,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  auto event = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::LinkKeyRequestEventWriter>(
      hci_spec::kLinkKeyRequestEventCode);
  event.view_t().bd_addr().CopyFrom(peer->address_.value().view());
  SendCommandChannelPacket(event.data());
}

void FakeController::OnLinkKeyRequestReplyCommandReceived(
    const pw::bluetooth::emboss::LinkKeyRequestReplyCommandView& params) {
  DeviceAddress peer_address(DeviceAddress::Type::kBREDR,
                             DeviceAddressBytes(params.bd_addr()));
  FakePeer* peer = FindPeer(peer_address);
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kLinkKeyRequestReply,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  RespondWithCommandStatus(hci_spec::kLinkKeyRequestReply,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);
  RespondWithCommandComplete(hci_spec::kLinkKeyRequestReply,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);

  BT_ASSERT(!peer->logical_links().empty());
  for (auto& conn_handle : peer->logical_links()) {
    auto event = hci::EmbossEventPacket::New<
        pw::bluetooth::emboss::AuthenticationCompleteEventWriter>(
        hci_spec::kAuthenticationCompleteEventCode);
    event.view_t().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
    event.view_t().connection_handle().Write(conn_handle);
    SendCommandChannelPacket(event.data());
  }
}

void FakeController::OnLinkKeyRequestNegativeReplyCommandReceived(
    const pw::bluetooth::emboss::LinkKeyRequestNegativeReplyCommandView&
        params) {
  FakePeer* peer = FindPeer(DeviceAddress(
      DeviceAddress::Type::kBREDR, DeviceAddressBytes(params.bd_addr())));
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kLinkKeyRequestNegativeReply,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }
  RespondWithCommandStatus(hci_spec::kLinkKeyRequestNegativeReply,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  auto event = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::IoCapabilityRequestEventWriter>(
      hci_spec::kIOCapabilityRequestEventCode);
  event.view_t().bd_addr().CopyFrom(params.bd_addr());
  SendCommandChannelPacket(event.data());
}

void FakeController::OnIOCapabilityRequestReplyCommand(
    const pw::bluetooth::emboss::IoCapabilityRequestReplyCommandView& params) {
  RespondWithCommandStatus(hci_spec::kIOCapabilityRequestReply,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  auto io_response = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::IoCapabilityResponseEventWriter>(
      hci_spec::kIOCapabilityResponseEventCode);
  io_response.view_t().bd_addr().CopyFrom(params.bd_addr());
  io_response.view_t().io_capability().Write(
      pw::bluetooth::emboss::IoCapability::NO_INPUT_NO_OUTPUT);
  io_response.view_t().oob_data_present().Write(
      pw::bluetooth::emboss::GenericPresenceParam::NOT_PRESENT);
  io_response.view_t().authentication_requirements().Write(
      pw::bluetooth::emboss::AuthenticationRequirements::GENERAL_BONDING);
  SendCommandChannelPacket(io_response.data());

  // Event type based on |params.io_capability| and |io_response.io_capability|.
  hci_spec::UserConfirmationRequestEventParams request = {};
  request.bd_addr = DeviceAddressBytes(params.bd_addr());
  request.numeric_value = 0;
  SendEvent(hci_spec::kUserConfirmationRequestEventCode,
            BufferView(&request, sizeof(request)));
}

void FakeController::OnUserConfirmationRequestReplyCommand(
    const pw::bluetooth::emboss::UserConfirmationRequestReplyCommandView&
        params) {
  FakePeer* peer = FindPeer(DeviceAddress(
      DeviceAddress::Type::kBREDR, DeviceAddressBytes(params.bd_addr())));
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kUserConfirmationRequestReply,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  RespondWithCommandStatus(hci_spec::kUserConfirmationRequestReply,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  hci_spec::SimplePairingCompleteEventParams pairing_event;
  pairing_event.bd_addr = DeviceAddressBytes(params.bd_addr());
  pairing_event.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  SendEvent(hci_spec::kSimplePairingCompleteEventCode,
            BufferView(&pairing_event, sizeof(pairing_event)));

  auto link_key_event = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::LinkKeyNotificationEventWriter>(
      hci_spec::kLinkKeyNotificationEventCode);
  auto link_key_view = link_key_event.view_t();
  link_key_view.bd_addr().CopyFrom(params.bd_addr());
  uint8_t key[] = {0xc0,
                   0xde,
                   0xfa,
                   0x57,
                   0x4b,
                   0xad,
                   0xf0,
                   0x0d,
                   0xa7,
                   0x60,
                   0x06,
                   0x1e,
                   0xca,
                   0x1e,
                   0xca,
                   0xfe};
  link_key_view.link_key().value().BackingStorage().CopyFrom(
      ::emboss::support::ReadOnlyContiguousBuffer(key, sizeof(key)),
      sizeof(key));
  link_key_view.key_type().Write(
      pw::bluetooth::emboss::KeyType::UNAUTHENTICATED_COMBINATION_FROM_P192);
  SendCommandChannelPacket(link_key_event.data());

  BT_ASSERT(!peer->logical_links().empty());
  for (auto& conn_handle : peer->logical_links()) {
    auto event = hci::EmbossEventPacket::New<
        pw::bluetooth::emboss::AuthenticationCompleteEventWriter>(
        hci_spec::kAuthenticationCompleteEventCode);
    event.view_t().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
    event.view_t().connection_handle().Write(conn_handle);
    SendCommandChannelPacket(event.data());
  }
}

void FakeController::OnUserConfirmationRequestNegativeReplyCommand(
    const pw::bluetooth::emboss::
        UserConfirmationRequestNegativeReplyCommandView& params) {
  FakePeer* peer = FindPeer(DeviceAddress(
      DeviceAddress::Type::kBREDR, DeviceAddressBytes(params.bd_addr())));
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kUserConfirmationRequestNegativeReply,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  RespondWithCommandStatus(hci_spec::kUserConfirmationRequestNegativeReply,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);
  RespondWithCommandComplete(hci_spec::kUserConfirmationRequestNegativeReply,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);

  hci_spec::SimplePairingCompleteEventParams pairing_event;
  pairing_event.bd_addr = DeviceAddressBytes(params.bd_addr());
  pairing_event.status =
      pw::bluetooth::emboss::StatusCode::AUTHENTICATION_FAILURE;
  SendEvent(hci_spec::kSimplePairingCompleteEventCode,
            BufferView(&pairing_event, sizeof(pairing_event)));
}

void FakeController::OnSetConnectionEncryptionCommand(
    const pw::bluetooth::emboss::SetConnectionEncryptionCommandView& params) {
  RespondWithCommandStatus(hci_spec::kSetConnectionEncryption,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);
  SendEncryptionChangeEvent(params.connection_handle().Read(),
                            pw::bluetooth::emboss::StatusCode::SUCCESS,
                            pw::bluetooth::emboss::EncryptionStatus::
                                ON_WITH_E0_FOR_BREDR_OR_AES_FOR_LE);
}

void FakeController::OnReadEncryptionKeySizeCommand(
    const pw::bluetooth::emboss::ReadEncryptionKeySizeCommandView& params) {
  hci_spec::ReadEncryptionKeySizeReturnParams response;
  response.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  response.connection_handle = params.connection_handle().Read();
  response.key_size = 16;
  RespondWithCommandComplete(hci_spec::kReadEncryptionKeySize,
                             BufferView(&response, sizeof(response)));
}

void FakeController::OnEnhancedAcceptSynchronousConnectionRequestCommand(
    const pw::bluetooth::emboss::
        EnhancedAcceptSynchronousConnectionRequestCommandView& params) {
  DeviceAddress peer_address(DeviceAddress::Type::kBREDR,
                             DeviceAddressBytes(params.bd_addr()));
  FakePeer* peer = FindPeer(peer_address);
  if (!peer || !peer->last_connection_request_link_type().has_value()) {
    RespondWithCommandStatus(
        hci_spec::kEnhancedAcceptSynchronousConnectionRequest,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  RespondWithCommandStatus(
      hci_spec::kEnhancedAcceptSynchronousConnectionRequest,
      pw::bluetooth::emboss::StatusCode::SUCCESS);

  hci_spec::ConnectionHandle sco_handle = ++next_conn_handle_;
  peer->AddLink(sco_handle);

  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::SynchronousConnectionCompleteEventWriter>(
      hci_spec::kSynchronousConnectionCompleteEventCode);
  auto view = packet.view_t();
  view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
  view.connection_handle().Write(sco_handle);
  view.bd_addr().CopyFrom(peer->address().value().view());
  view.link_type().Write(peer->last_connection_request_link_type().value());
  view.transmission_interval().Write(1);
  view.retransmission_window().Write(2);
  view.rx_packet_length().Write(3);
  view.tx_packet_length().Write(4);
  view.air_mode().Write(params.connection_parameters()
                            .transmit_coding_format()
                            .coding_format()
                            .Read());
  SendCommandChannelPacket(packet.data());
}

void FakeController::OnEnhancedSetupSynchronousConnectionCommand(
    const pw::bluetooth::emboss::EnhancedSetupSynchronousConnectionCommandView&
        params) {
  const hci_spec::ConnectionHandle acl_handle =
      params.connection_handle().Read();
  FakePeer* peer = FindByConnHandle(acl_handle);
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kEnhancedSetupSynchronousConnection,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  RespondWithCommandStatus(hci_spec::kEnhancedSetupSynchronousConnection,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  hci_spec::ConnectionHandle sco_handle = ++next_conn_handle_;
  peer->AddLink(sco_handle);

  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::SynchronousConnectionCompleteEventWriter>(
      hci_spec::kSynchronousConnectionCompleteEventCode);
  auto view = packet.view_t();
  view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
  view.connection_handle().Write(sco_handle);
  view.bd_addr().CopyFrom(peer->address().value().view());
  view.link_type().Write(pw::bluetooth::emboss::LinkType::ESCO);
  view.transmission_interval().Write(1);
  view.retransmission_window().Write(2);
  view.rx_packet_length().Write(3);
  view.tx_packet_length().Write(4);
  view.air_mode().Write(params.connection_parameters()
                            .transmit_coding_format()
                            .coding_format()
                            .Read());
  SendCommandChannelPacket(packet.data());
}

void FakeController::OnLEReadRemoteFeaturesCommand(
    const hci_spec::LEReadRemoteFeaturesCommandParams& params) {
  if (le_read_remote_features_cb_) {
    le_read_remote_features_cb_();
  }

  const hci_spec::ConnectionHandle handle = le16toh(params.connection_handle);
  FakePeer* peer = FindByConnHandle(handle);
  if (!peer) {
    RespondWithCommandStatus(
        hci_spec::kLEReadRemoteFeatures,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID);
    return;
  }

  RespondWithCommandStatus(hci_spec::kLEReadRemoteFeatures,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);

  auto response = hci::EmbossEventPacket::New<
      pw::bluetooth::emboss::LEReadRemoteFeaturesCompleteSubeventWriter>(
      hci_spec::kLEMetaEventCode);
  auto view = response.view_t();
  view.le_meta_event().subevent_code().Write(
      hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode);
  view.connection_handle().Write(params.connection_handle);
  view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
  view.le_features().BackingStorage().WriteUInt(
      peer->le_features().le_features);
  SendCommandChannelPacket(response.data());
}

void FakeController::OnLEStartEncryptionCommand(
    const pw::bluetooth::emboss::LEEnableEncryptionCommandView& params) {
  RespondWithCommandStatus(hci_spec::kLEStartEncryption,
                           pw::bluetooth::emboss::StatusCode::SUCCESS);
  SendEncryptionChangeEvent(params.connection_handle().Read(),
                            pw::bluetooth::emboss::StatusCode::SUCCESS,
                            pw::bluetooth::emboss::EncryptionStatus::
                                ON_WITH_E0_FOR_BREDR_OR_AES_FOR_LE);
}

void FakeController::OnWriteSynchronousFlowControlEnableCommand(
    const pw::bluetooth::emboss::WriteSynchronousFlowControlEnableCommandView&
        params) {
  constexpr size_t flow_control_enable_octet = 10;
  bool supported =
      settings_.supported_commands[flow_control_enable_octet] &
      static_cast<uint8_t>(
          hci_spec::SupportedCommand::kWriteSynchronousFlowControlEnable);
  if (!supported) {
    RespondWithCommandComplete(
        hci_spec::kWriteSynchronousFlowControlEnable,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
    return;
  }
  RespondWithCommandComplete(hci_spec::kWriteSynchronousFlowControlEnable,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnLESetAdvertisingSetRandomAddress(
    const pw::bluetooth::emboss::LESetAdvertisingSetRandomAddressCommandView&
        params) {
  hci_spec::AdvertisingHandle handle = params.advertising_handle().Read();

  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);
    RespondWithCommandComplete(
        hci_spec::kLESetAdvertisingSetRandomAddress,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  if (extended_advertising_states_.count(handle) == 0) {
    bt_log(INFO,
           "fake-hci",
           "unknown advertising handle (%d), "
           "use HCI_LE_Set_Extended_Advertising_Parameters to create one first",
           handle);
    RespondWithCommandComplete(
        hci_spec::kLESetAdvertisingSetRandomAddress,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  LEAdvertisingState& state = extended_advertising_states_[handle];
  if (state.IsConnectableAdvertising() && state.enabled) {
    bt_log(
        INFO,
        "fake-hci",
        "cannot set LE random address while connectable advertising enabled");
    RespondWithCommandComplete(
        hci_spec::kLESetAdvertisingSetRandomAddress,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  state.random_address =
      DeviceAddress(DeviceAddress::Type::kLERandom,
                    DeviceAddressBytes(params.random_address()));
  RespondWithCommandComplete(hci_spec::kLESetAdvertisingSetRandomAddress,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
}

void FakeController::OnLESetExtendedAdvertisingParameters(
    const pw::bluetooth::emboss::
        LESetExtendedAdvertisingParametersV1CommandView& params) {
  hci_spec::AdvertisingHandle handle = params.advertising_handle().Read();

  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  // ensure we can allocate memory for this advertising set if not already
  // present
  if (extended_advertising_states_.count(handle) == 0 &&
      extended_advertising_states_.size() >= num_supported_advertising_sets()) {
    bt_log(INFO,
           "fake-hci",
           "no available memory for new advertising set, handle: %d",
           handle);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::MEMORY_CAPACITY_EXCEEDED);
    return;
  }

  // for backwards compatibility, we only support legacy pdus
  if (!params.advertising_event_properties().use_legacy_pdus().Read()) {
    bt_log(
        INFO,
        "fake-hci",
        "only legacy PDUs are supported, extended PDUs are not supported yet");
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  // ensure we have a valid bit combination in the advertising event properties
  constexpr uint16_t legacy_pdu = hci_spec::kLEAdvEventPropBitUseLegacyPDUs;
  constexpr uint16_t prop_bits_adv_ind =
      legacy_pdu | hci_spec::kLEAdvEventPropBitConnectable |
      hci_spec::kLEAdvEventPropBitScannable;
  constexpr uint16_t prop_bits_adv_direct_ind_low_duty_cycle =
      legacy_pdu | hci_spec::kLEAdvEventPropBitConnectable |
      hci_spec::kLEAdvEventPropBitDirected;
  constexpr uint16_t prop_bits_adv_direct_ind_high_duty_cycle =
      prop_bits_adv_direct_ind_low_duty_cycle |
      hci_spec::kLEAdvEventPropBitHighDutyCycleDirectedConnectable;
  constexpr uint16_t prop_bits_adv_scan_ind =
      legacy_pdu | hci_spec::kLEAdvEventPropBitScannable;
  constexpr uint16_t prop_bits_adv_nonconn_ind = legacy_pdu;

  pw::bluetooth::emboss::LEAdvertisingType adv_type;
  uint16_t advertising_event_properties =
      params.advertising_event_properties().BackingStorage().ReadUInt();
  switch (advertising_event_properties) {
    case prop_bits_adv_ind:
      adv_type = pw::bluetooth::emboss::LEAdvertisingType::
          CONNECTABLE_AND_SCANNABLE_UNDIRECTED;
      break;
    case prop_bits_adv_direct_ind_high_duty_cycle:
      adv_type = pw::bluetooth::emboss::LEAdvertisingType::
          CONNECTABLE_HIGH_DUTY_CYCLE_DIRECTED;
      break;
    case prop_bits_adv_direct_ind_low_duty_cycle:
      adv_type = pw::bluetooth::emboss::LEAdvertisingType::
          CONNECTABLE_LOW_DUTY_CYCLE_DIRECTED;
      break;
    case prop_bits_adv_scan_ind:
      adv_type = pw::bluetooth::emboss::LEAdvertisingType::SCANNABLE_UNDIRECTED;
      break;
    case prop_bits_adv_nonconn_ind:
      adv_type =
          pw::bluetooth::emboss::LEAdvertisingType::NOT_CONNECTABLE_UNDIRECTED;
      break;
    default:
      bt_log(INFO,
             "fake-hci",
             "invalid bit combination: %d",
             advertising_event_properties);
      RespondWithCommandComplete(
          hci_spec::kLESetExtendedAdvertisingParameters,
          pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
      return;
  }

  // In case there is an error below, we want to reject all parameters instead
  // of storing a dead state and taking up an advertising handle. Avoid creating
  // the LEAdvertisingState directly in the map and add it in only once we have
  // made sure all is good.
  LEAdvertisingState state;
  if (extended_advertising_states_.count(handle) != 0) {
    state = extended_advertising_states_[handle];
  }

  uint32_t interval_min = params.primary_advertising_interval_min().Read();
  uint32_t interval_max = params.primary_advertising_interval_max().Read();

  if (interval_min >= interval_max) {
    bt_log(INFO,
           "fake-hci",
           "advertising interval min (%d) not strictly less than max (%d)",
           interval_min,
           interval_max);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER);
    return;
  }

  if (interval_min < hci_spec::kLEExtendedAdvertisingIntervalMin) {
    bt_log(INFO,
           "fake-hci",
           "advertising interval min (%d) less than spec min (%d)",
           interval_min,
           hci_spec::kLEAdvertisingIntervalMin);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER);
    return;
  }

  if (interval_max > hci_spec::kLEExtendedAdvertisingIntervalMax) {
    bt_log(INFO,
           "fake-hci",
           "advertising interval max (%d) greater than spec max (%d)",
           interval_max,
           hci_spec::kLEAdvertisingIntervalMax);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER);
    return;
  }

  uint8_t advertising_channels =
      params.primary_advertising_channel_map().BackingStorage().ReadUInt();
  if (!advertising_channels) {
    bt_log(INFO,
           "fake-hci",
           "at least one bit must be set in primary advertising channel map");
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  int8_t advertising_tx_power = params.advertising_tx_power().Read();
  if (advertising_tx_power !=
          hci_spec::kLEExtendedAdvertisingTxPowerNoPreference &&
      (advertising_tx_power < hci_spec::kLEAdvertisingTxPowerMin ||
       advertising_tx_power > hci_spec::kLEAdvertisingTxPowerMax)) {
    bt_log(INFO,
           "fake-hci",
           "advertising tx power out of range: %d",
           advertising_tx_power);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  // TODO(fxbug.dev/42160350): Core spec Volume 4, Part E, Section 7.8.53: if
  // legacy advertising PDUs are being used, the Primary_Advertising_PHY shall
  // indicate the LE 1M PHY.
  if (params.primary_advertising_phy().Read() !=
      pw::bluetooth::emboss::LEPrimaryAdvertisingPHY::LE_1M) {
    bt_log(INFO,
           "fake-hci",
           "only legacy pdus are supported, requires advertising on 1M PHY");
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER);
    return;
  }

  if (params.secondary_advertising_phy().Read() !=
      pw::bluetooth::emboss::LESecondaryAdvertisingPHY::LE_1M) {
    bt_log(INFO, "fake-hci", "secondary advertising PHY must be selected");
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER);
    return;
  }

  if (state.enabled) {
    bt_log(INFO,
           "fake-hci",
           "cannot set parameters while advertising set is enabled");
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingParameters,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  // all errors checked, set parameters that we care about
  state.adv_type = adv_type;
  state.own_address_type = params.own_address_type().Read();
  state.interval_min = interval_min;
  state.interval_max = interval_max;

  // write full state back only at the end (we don't have a reference because we
  // only want to write if there are no errors)
  extended_advertising_states_[handle] = state;

  hci_spec::LESetExtendedAdvertisingParametersReturnParams return_params;
  return_params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  return_params.selected_tx_power = hci_spec::kLEAdvertisingTxPowerMax;
  RespondWithCommandComplete(hci_spec::kLESetExtendedAdvertisingParameters,
                             BufferView(&return_params, sizeof(return_params)));
  NotifyAdvertisingState();
}

void FakeController::OnLESetExtendedAdvertisingData(
    const pw::bluetooth::emboss::LESetExtendedAdvertisingDataCommandView&
        params) {
  // controller currently doesn't support fragmented advertising, assert so we
  // fail if we ever use it in host code without updating the controller for
  // tests
  BT_ASSERT(params.operation().Read() ==
            pw::bluetooth::emboss::LESetExtendedAdvDataOp::COMPLETE);
  BT_ASSERT(params.fragment_preference().Read() ==
            pw::bluetooth::emboss::LEExtendedAdvFragmentPreference::
                SHOULD_NOT_FRAGMENT);

  hci_spec::AdvertisingHandle handle = params.advertising_handle().Read();

  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingData,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  if (extended_advertising_states_.count(handle) == 0) {
    bt_log(INFO,
           "fake-hci",
           "advertising handle (%d) maps to an unknown advertising set",
           handle);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingData,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER);
    return;
  }

  LEAdvertisingState& state = extended_advertising_states_[handle];

  // removing advertising data entirely doesn't require us to check for error
  // conditions
  size_t advertising_data_length = params.advertising_data_length().Read();
  if (advertising_data_length == 0) {
    state.data_length = 0;
    std::memset(state.data, 0, sizeof(state.data));
    RespondWithCommandComplete(hci_spec::kLESetExtendedAdvertisingData,
                               pw::bluetooth::emboss::StatusCode::SUCCESS);
    NotifyAdvertisingState();
    return;
  }

  // directed advertising doesn't support advertising data
  if (state.IsDirectedAdvertising()) {
    bt_log(INFO,
           "fake-hci",
           "cannot provide advertising data when using directed advertising");
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingData,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  // For backwards compatibility with older devices, the host currently uses
  // legacy advertising PDUs. The advertising data cannot exceed the legacy
  // advertising PDU limit.
  if (advertising_data_length > hci_spec::kMaxLEAdvertisingDataLength) {
    bt_log(INFO,
           "fake-hci",
           "data length (%zu bytes) larger than legacy PDU size limit",
           advertising_data_length);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingData,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  state.data_length = advertising_data_length;
  std::memcpy(state.data,
              params.advertising_data().BackingStorage().data(),
              advertising_data_length);
  RespondWithCommandComplete(hci_spec::kLESetExtendedAdvertisingData,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLESetExtendedScanResponseData(
    const pw::bluetooth::emboss::LESetExtendedScanResponseDataCommandView&
        params) {
  // controller currently doesn't support fragmented advertising, assert so we
  // fail if we ever use it in host code without updating the controller for
  // tests
  BT_ASSERT(params.operation().Read() ==
            pw::bluetooth::emboss::LESetExtendedAdvDataOp::COMPLETE);
  BT_ASSERT(params.fragment_preference().Read() ==
            pw::bluetooth::emboss::LEExtendedAdvFragmentPreference::
                SHOULD_NOT_FRAGMENT);

  hci_spec::AdvertisingHandle handle = params.advertising_handle().Read();

  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedScanResponseData,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  if (extended_advertising_states_.count(handle) == 0) {
    bt_log(INFO,
           "fake-hci",
           "advertising handle (%d) maps to an unknown advertising set",
           handle);
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedScanResponseData,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER);
    return;
  }

  LEAdvertisingState& state = extended_advertising_states_[handle];

  // removing scan response data entirely doesn't require us to check for error
  // conditions
  if (params.scan_response_data_length().Read() == 0) {
    state.scan_rsp_length = 0;
    std::memset(state.scan_rsp_data, 0, sizeof(state.scan_rsp_data));
    RespondWithCommandComplete(hci_spec::kLESetExtendedScanResponseData,
                               pw::bluetooth::emboss::StatusCode::SUCCESS);
    NotifyAdvertisingState();
    return;
  }

  // adding or changing scan response data, check for error conditions
  if (!state.IsScannableAdvertising()) {
    bt_log(
        INFO,
        "fake-hci",
        "cannot provide scan response data for unscannable advertising types");
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedScanResponseData,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  // For backwards compatibility with older devices, the host currently uses
  // legacy advertising PDUs. The scan response data cannot exceed the legacy
  // advertising PDU limit.
  if (params.scan_response_data_length().Read() >
      hci_spec::kMaxLEAdvertisingDataLength) {
    bt_log(INFO,
           "fake-hci",
           "data length (%d bytes) larger than legacy PDU size limit",
           params.scan_response_data_length().Read());
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedScanResponseData,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  state.scan_rsp_length = params.scan_response_data_length().Read();
  std::memcpy(state.scan_rsp_data,
              params.scan_response_data().BackingStorage().data(),
              params.scan_response_data_length().Read());

  RespondWithCommandComplete(hci_spec::kLESetExtendedScanResponseData,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLESetExtendedAdvertisingEnable(
    const pw::bluetooth::emboss::LESetExtendedAdvertisingEnableCommandView&
        params) {
  uint8_t num_sets = params.num_sets().Read();

  // do some preliminary checks before making any state changes
  if (num_sets != 0) {
    std::unordered_set<hci_spec::AdvertisingHandle> handles;

    for (uint8_t i = 0; i < num_sets; i++) {
      hci_spec::AdvertisingHandle handle =
          params.data()[i].advertising_handle().Read();

      if (!IsValidAdvertisingHandle(handle)) {
        bt_log(
            ERROR, "fake-hci", "advertising handle outside range: %d", handle);
        RespondWithCommandComplete(
            hci_spec::kLESetExtendedAdvertisingEnable,
            pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
        return;
      }

      // cannot have two array entries for the same advertising handle
      if (handles.count(handle) != 0) {
        bt_log(INFO,
               "fake-hci",
               "cannot refer to handle more than once (handle: %d)",
               handle);
        RespondWithCommandComplete(
            hci_spec::kLESetExtendedAdvertisingEnable,
            pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
        return;
      }
      handles.insert(handle);

      // cannot have instructions for an advertising handle we don't know about
      if (extended_advertising_states_.count(handle) == 0) {
        bt_log(INFO,
               "fake-hci",
               "cannot enable/disable an unknown handle (handle: %d)",
               handle);
        RespondWithCommandComplete(
            hci_spec::kLESetExtendedAdvertisingEnable,
            pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER);
        return;
      }
    }
  }

  if (params.enable().Read() ==
      pw::bluetooth::emboss::GenericEnableParam::DISABLE) {
    if (num_sets == 0) {
      // if params.enable == kDisable and params.num_sets == 0, spec asks we
      // disable all
      for (auto& element : extended_advertising_states_) {
        element.second.enabled = false;
      }
    } else {
      for (int i = 0; i < num_sets; i++) {
        hci_spec::AdvertisingHandle handle =
            params.data()[i].advertising_handle().Read();
        extended_advertising_states_[handle].enabled = false;
      }
    }

    RespondWithCommandComplete(hci_spec::kLESetExtendedAdvertisingEnable,
                               pw::bluetooth::emboss::StatusCode::SUCCESS);
    NotifyAdvertisingState();
    return;
  }

  // rest of the function deals with enabling advertising for a given set of
  // advertising sets
  BT_ASSERT(params.enable().Read() ==
            pw::bluetooth::emboss::GenericEnableParam::ENABLE);

  if (num_sets == 0) {
    bt_log(
        INFO, "fake-hci", "cannot enable with an empty advertising set list");
    RespondWithCommandComplete(
        hci_spec::kLESetExtendedAdvertisingEnable,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  for (uint8_t i = 0; i < num_sets; i++) {
    // FakeController currently doesn't support testing with duration and max
    // events. When those are used in the host, these checks will fail and
    // remind us to add the necessary code to FakeController.
    BT_ASSERT(params.data()[i].duration().Read() == 0);
    BT_ASSERT(params.data()[i].max_extended_advertising_events().Read() == 0);

    hci_spec::AdvertisingHandle handle =
        params.data()[i].advertising_handle().Read();
    LEAdvertisingState& state = extended_advertising_states_[handle];

    if (state.IsDirectedAdvertising() && state.data_length == 0) {
      bt_log(
          INFO,
          "fake-hci",
          "cannot enable type requiring advertising data without setting it");
      RespondWithCommandComplete(
          hci_spec::kLESetExtendedAdvertisingEnable,
          pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
      return;
    }

    if (state.IsScannableAdvertising() && state.scan_rsp_length == 0) {
      bt_log(INFO,
             "fake-hci",
             "cannot enable, requires scan response data but hasn't been set");
      RespondWithCommandComplete(
          hci_spec::kLESetExtendedAdvertisingEnable,
          pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
      return;
    }

    // TODO(fxbug.dev/42161900): if own address type is random, check that a
    // random address is set
    state.enabled = true;
  }

  RespondWithCommandComplete(hci_spec::kLESetExtendedAdvertisingEnable,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLEReadMaximumAdvertisingDataLength() {
  hci_spec::LEReadMaxAdvertisingDataLengthReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;

  // TODO(fxbug.dev/42157495): Extended advertising supports sending larger
  // amounts of data, but they have to be fragmented across multiple commands to
  // the controller. This is not yet supported in this implementation. We should
  // support larger than kMaxPduLEExtendedAdvertisingDataLength advertising data
  // with fragmentation.
  params.max_adv_data_length = htole16(hci_spec::kMaxLEAdvertisingDataLength);
  RespondWithCommandComplete(hci_spec::kLEReadMaxAdvertisingDataLength,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnLEReadNumberOfSupportedAdvertisingSets() {
  hci_spec::LEReadNumSupportedAdvertisingSetsReturnParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.num_supported_adv_sets = htole16(num_supported_advertising_sets_);
  RespondWithCommandComplete(hci_spec::kLEReadNumSupportedAdvertisingSets,
                             BufferView(&params, sizeof(params)));
}

void FakeController::OnLERemoveAdvertisingSet(
    const hci_spec::LERemoveAdvertisingSetCommandParams& params) {
  hci_spec::AdvertisingHandle handle = params.adv_handle;

  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);
    RespondWithCommandComplete(
        hci_spec::kLERemoveAdvertisingSet,
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS);
    return;
  }

  if (extended_advertising_states_.count(handle) == 0) {
    bt_log(INFO,
           "fake-hci",
           "advertising handle (%d) maps to an unknown advertising set",
           handle);
    RespondWithCommandComplete(
        hci_spec::kLERemoveAdvertisingSet,
        pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER);
    return;
  }

  if (extended_advertising_states_[handle].enabled) {
    bt_log(INFO,
           "fake-hci",
           "cannot remove enabled advertising set (handle: %d)",
           handle);
    RespondWithCommandComplete(
        hci_spec::kLERemoveAdvertisingSet,
        pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
    return;
  }

  extended_advertising_states_.erase(handle);
  RespondWithCommandComplete(hci_spec::kLERemoveAdvertisingSet,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLEClearAdvertisingSets() {
  for (const auto& element : extended_advertising_states_) {
    if (element.second.enabled) {
      bt_log(INFO,
             "fake-hci",
             "cannot remove currently enabled advertising set (handle: %d)",
             element.second.enabled);
      RespondWithCommandComplete(
          hci_spec::kLEClearAdvertisingSets,
          pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
      return;
    }
  }

  extended_advertising_states_.clear();
  RespondWithCommandComplete(hci_spec::kLEClearAdvertisingSets,
                             pw::bluetooth::emboss::StatusCode::SUCCESS);
  NotifyAdvertisingState();
}

void FakeController::OnLEReadAdvertisingChannelTxPower() {
  if (!respond_to_tx_power_read_) {
    return;
  }

  hci_spec::LEReadAdvertisingChannelTxPowerReturnParams params;
  // Send back arbitrary tx power.
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.tx_power = 9;
  RespondWithCommandComplete(hci_spec::kLEReadAdvertisingChannelTxPower,
                             BufferView(&params, sizeof(params)));
}

void FakeController::SendLEAdvertisingSetTerminatedEvent(
    hci_spec::ConnectionHandle conn_handle,
    hci_spec::AdvertisingHandle adv_handle) {
  hci_spec::LEAdvertisingSetTerminatedSubeventParams params;
  params.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  params.connection_handle = conn_handle;
  params.adv_handle = adv_handle;
  SendLEMetaEvent(hci_spec::kLEAdvertisingSetTerminatedSubeventCode,
                  BufferView(&params, sizeof(params)));
}

void FakeController::SendAndroidLEMultipleAdvertisingStateChangeSubevent(
    hci_spec::ConnectionHandle conn_handle,
    hci_spec::AdvertisingHandle adv_handle) {
  auto packet = hci::EmbossEventPacket::New<
      pw::bluetooth::vendor::android_hci::LEMultiAdvtStateChangeSubeventWriter>(
      hci_spec::kVendorDebugEventCode);
  auto view = packet.view_t();
  view.vendor_event().subevent_code().Write(
      hci_android::kLEMultiAdvtStateChangeSubeventCode);
  view.advertising_handle().Write(adv_handle);
  view.status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
  view.connection_handle().Write(conn_handle);
  SendCommandChannelPacket(packet.data());
}

void FakeController::OnCommandPacketReceived(
    const PacketView<hci_spec::CommandHeader>& command_packet) {
  hci_spec::OpCode opcode = le16toh(command_packet.header().opcode);

  bt_log(
      TRACE, "fake-hci", "received command packet with opcode: %#.4x", opcode);
  // We handle commands immediately unless a client has explicitly set a
  // listener for `opcode`.
  if (paused_opcode_listeners_.find(opcode) == paused_opcode_listeners_.end()) {
    HandleReceivedCommandPacket(command_packet);
    return;
  }

  bt_log(DEBUG, "fake-hci", "pausing response for opcode: %#.4x", opcode);
  paused_opcode_listeners_[opcode](
      [this, packet_data = DynamicByteBuffer(command_packet.data())]() {
        PacketView<hci_spec::CommandHeader> command_packet(
            &packet_data, packet_data.size() - sizeof(hci_spec::CommandHeader));
        HandleReceivedCommandPacket(command_packet);
      });
}

void FakeController::OnAndroidLEGetVendorCapabilities() {
  RespondWithCommandComplete(hci_android::kLEGetVendorCapabilities,
                             settings_.android_extension_settings.data());
}

void FakeController::OnAndroidStartA2dpOffload(
    const pw::bluetooth::vendor::android_hci::StartA2dpOffloadCommandView&
        params) {
  hci_android::StartA2dpOffloadCommandReturnParams ret;
  ret.opcode = hci_android::kStartA2dpOffloadCommandSubopcode;

  // return in case A2DP offload already started
  if (offloaded_a2dp_channel_state_) {
    ret.status = pw::bluetooth::emboss::StatusCode::CONNECTION_ALREADY_EXISTS;
    RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  // SCMS-T is not currently supported
  hci_android::A2dpScmsTEnable scms_t_enable;
  scms_t_enable.enabled = params.scms_t_enable().enabled().Read();
  scms_t_enable.header = params.scms_t_enable().header().Read();
  if (scms_t_enable.enabled ==
      pw::bluetooth::emboss::GenericEnableParam::ENABLE) {
    ret.status =
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER;
    RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  // return in case any parameter has an invalid value
  ret.status =
      pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;

  hci_android::A2dpCodecType const codec_type =
      static_cast<hci_android::A2dpCodecType>(
          le32toh(static_cast<uint32_t>(params.codec_type().Read())));
  switch (codec_type) {
    case hci_android::A2dpCodecType::kSbc:
    case hci_android::A2dpCodecType::kAac:
    case hci_android::A2dpCodecType::kAptx:
    case hci_android::A2dpCodecType::kAptxhd:
    case hci_android::A2dpCodecType::kLdac:
      break;
    default:
      RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                                 BufferView(&ret, sizeof(ret)));
      return;
  }

  hci_android::A2dpSamplingFrequency const sampling_frequency =
      static_cast<hci_android::A2dpSamplingFrequency>(
          le32toh(static_cast<uint32_t>(params.sampling_frequency().Read())));
  switch (sampling_frequency) {
    case hci_android::A2dpSamplingFrequency::k44100Hz:
    case hci_android::A2dpSamplingFrequency::k48000Hz:
    case hci_android::A2dpSamplingFrequency::k88200Hz:
    case hci_android::A2dpSamplingFrequency::k96000Hz:
      break;
    default:
      RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                                 BufferView(&ret, sizeof(ret)));
      return;
  }

  hci_android::A2dpBitsPerSample const bits_per_sample =
      static_cast<hci_android::A2dpBitsPerSample>(
          params.bits_per_sample().Read());
  switch (bits_per_sample) {
    case hci_android::A2dpBitsPerSample::k16BitsPerSample:
    case hci_android::A2dpBitsPerSample::k24BitsPerSample:
    case hci_android::A2dpBitsPerSample::k32BitsPerSample:
      break;
    default:
      RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                                 BufferView(&ret, sizeof(ret)));
      return;
  }

  hci_android::A2dpChannelMode const channel_mode =
      static_cast<hci_android::A2dpChannelMode>(params.channel_mode().Read());
  switch (channel_mode) {
    case hci_android::A2dpChannelMode::kMono:
    case hci_android::A2dpChannelMode::kStereo:
      break;
    default:
      RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                                 BufferView(&ret, sizeof(ret)));
      return;
  }

  uint32_t const encoded_audio_bitrate =
      le32toh(params.encoded_audio_bitrate().Read());
  // Bits 0x01000000 to 0xFFFFFFFF are reserved
  if (encoded_audio_bitrate >= 0x01000000) {
    RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  OffloadedA2dpChannel state;
  state.codec_type = codec_type;
  state.max_latency = le16toh(params.max_latency().Read());
  state.scms_t_enable = scms_t_enable;
  state.sampling_frequency = sampling_frequency;
  state.bits_per_sample = bits_per_sample;
  state.channel_mode = channel_mode;
  state.encoded_audio_bitrate = encoded_audio_bitrate;
  state.connection_handle = le16toh(params.connection_handle().Read());
  state.l2cap_channel_id = le16toh(params.l2cap_channel_id().Read());
  state.l2cap_mtu_size = le16toh(params.l2cap_mtu_size().Read());
  offloaded_a2dp_channel_state_ = state;

  ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                             BufferView(&ret, sizeof(ret)));
}

void FakeController::OnAndroidStopA2dpOffload() {
  hci_android::StartA2dpOffloadCommandReturnParams ret;
  ret.opcode = hci_android::kStopA2dpOffloadCommandSubopcode;

  if (!offloaded_a2dp_channel_state_) {
    ret.status = pw::bluetooth::emboss::StatusCode::REPEATED_ATTEMPTS;
    RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  offloaded_a2dp_channel_state_ = std::nullopt;

  ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  RespondWithCommandComplete(hci_android::kA2dpOffloadCommand,
                             BufferView(&ret, sizeof(ret)));
}

void FakeController::OnAndroidA2dpOffloadCommand(
    const PacketView<hci_spec::CommandHeader>& command_packet) {
  const auto& payload = command_packet.payload_data();

  uint8_t subopcode = payload.To<uint8_t>();
  switch (subopcode) {
    case hci_android::kStartA2dpOffloadCommandSubopcode: {
      auto view =
          pw::bluetooth::vendor::android_hci::MakeStartA2dpOffloadCommandView(
              command_packet.data().data(),
              pw::bluetooth::vendor::android_hci::StartA2dpOffloadCommand::
                  MaxSizeInBytes());
      OnAndroidStartA2dpOffload(view);
      break;
    }
    case hci_android::kStopA2dpOffloadCommandSubopcode:
      OnAndroidStopA2dpOffload();
      break;
    default:
      bt_log(WARN,
             "fake-hci",
             "unhandled android A2DP offload command, subopcode: %#.4x",
             subopcode);
      RespondWithCommandComplete(
          subopcode, pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
      break;
  }
}

void FakeController::OnAndroidLEMultiAdvtSetAdvtParam(
    const hci_android::LEMultiAdvtSetAdvtParamCommandParams& params) {
  hci_spec::AdvertisingHandle handle = params.adv_handle;

  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtParamSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  // ensure we can allocate memory for this advertising set if not already
  // present
  if (extended_advertising_states_.count(handle) == 0 &&
      extended_advertising_states_.size() >= num_supported_advertising_sets()) {
    bt_log(INFO,
           "fake-hci",
           "no available memory for new advertising set, handle: %d",
           handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status = pw::bluetooth::emboss::StatusCode::MEMORY_CAPACITY_EXCEEDED;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtParamSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  // In case there is an error below, we want to reject all parameters instead
  // of storing a dead state and taking up an advertising handle. Avoid creating
  // the LEAdvertisingState directly in the map and add it in only once we have
  // made sure all is good.
  LEAdvertisingState state;
  if (extended_advertising_states_.count(handle) != 0) {
    state = extended_advertising_states_[handle];
  }

  uint16_t interval_min = le16toh(params.adv_interval_min);
  uint16_t interval_max = le16toh(params.adv_interval_max);

  if (interval_min >= interval_max) {
    bt_log(INFO,
           "fake-hci",
           "advertising interval min (%d) not strictly less than max (%d)",
           interval_min,
           interval_max);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtParamSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  if (interval_min < hci_spec::kLEAdvertisingIntervalMin) {
    bt_log(INFO,
           "fake-hci",
           "advertising interval min (%d) less than spec min (%d)",
           interval_min,
           hci_spec::kLEAdvertisingIntervalMin);
    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtParamSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  if (interval_max > hci_spec::kLEAdvertisingIntervalMax) {
    bt_log(INFO,
           "fake-hci",
           "advertising interval max (%d) greater than spec max (%d)",
           interval_max,
           hci_spec::kLEAdvertisingIntervalMax);
    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::UNSUPPORTED_FEATURE_OR_PARAMETER;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtParamSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  state.interval_min = interval_min;
  state.interval_max = interval_max;
  state.adv_type = params.adv_type;
  state.own_address_type = params.own_address_type;

  // write full state back only at the end (we don't have a reference because we
  // only want to write if there are no errors)
  extended_advertising_states_[handle] = state;

  hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
  ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  ret.opcode = hci_android::kLEMultiAdvtSetAdvtParamSubopcode;
  RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                             BufferView(&ret, sizeof(ret)));
  NotifyAdvertisingState();
}

void FakeController::OnAndroidLEMultiAdvtSetAdvtData(
    const hci_android::LEMultiAdvtSetAdvtDataCommandParams& params) {
  hci_spec::AdvertisingHandle handle = params.adv_handle;
  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtDataSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  if (extended_advertising_states_.count(handle) == 0) {
    bt_log(INFO,
           "fake-hci",
           "advertising handle (%d) maps to an unknown advertising set",
           handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtDataSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  LEAdvertisingState& state = extended_advertising_states_[handle];

  // removing advertising data entirely doesn't require us to check for error
  // conditions
  if (params.adv_data_length == 0) {
    state.data_length = 0;
    std::memset(state.data, 0, sizeof(state.data));
    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtDataSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    NotifyAdvertisingState();
    return;
  }

  // directed advertising doesn't support advertising data
  if (state.IsDirectedAdvertising()) {
    bt_log(INFO,
           "fake-hci",
           "cannot provide advertising data when using directed advertising");

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtDataSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  if (params.adv_data_length > hci_spec::kMaxLEAdvertisingDataLength) {
    bt_log(INFO,
           "fake-hci",
           "data length (%d bytes) larger than legacy PDU size limit",
           params.adv_data_length);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetAdvtDataSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  state.data_length = params.adv_data_length;
  std::memcpy(state.data, params.adv_data, params.adv_data_length);

  hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
  ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  ret.opcode = hci_android::kLEMultiAdvtSetAdvtDataSubopcode;
  RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                             BufferView(&ret, sizeof(ret)));
  NotifyAdvertisingState();
}

void FakeController::OnAndroidLEMultiAdvtSetScanResp(
    const hci_android::LEMultiAdvtSetScanRespCommandParams& params) {
  hci_spec::AdvertisingHandle handle = params.adv_handle;
  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetScanRespSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  if (extended_advertising_states_.count(handle) == 0) {
    bt_log(INFO,
           "fake-hci",
           "advertising handle (%d) maps to an unknown advertising set",
           handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER;
    ret.opcode = hci_android::kLEMultiAdvtSetScanRespSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  LEAdvertisingState& state = extended_advertising_states_[handle];

  // removing scan response data entirely doesn't require us to check for error
  // conditions
  if (params.scan_rsp_data_length == 0) {
    state.scan_rsp_length = 0;
    std::memset(state.scan_rsp_data, 0, sizeof(state.scan_rsp_data));

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
    ret.opcode = hci_android::kLEMultiAdvtSetScanRespSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    NotifyAdvertisingState();
    return;
  }

  // adding or changing scan response data, check for error conditions
  if (!state.IsScannableAdvertising()) {
    bt_log(
        INFO,
        "fake-hci",
        "cannot provide scan response data for unscannable advertising types");

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetScanRespSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  if (params.scan_rsp_data_length > hci_spec::kMaxLEAdvertisingDataLength) {
    bt_log(INFO,
           "fake-hci",
           "data length (%d bytes) larger than legacy PDU size limit",
           params.scan_rsp_data_length);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetScanRespSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  state.scan_rsp_length = params.scan_rsp_data_length;
  std::memcpy(
      state.scan_rsp_data, params.scan_rsp_data, params.scan_rsp_data_length);

  hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
  ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  ret.opcode = hci_android::kLEMultiAdvtSetScanRespSubopcode;
  RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                             BufferView(&ret, sizeof(ret)));
  NotifyAdvertisingState();
}

void FakeController::OnAndroidLEMultiAdvtSetRandomAddr(
    const hci_android::LEMultiAdvtSetRandomAddrCommandParams& params) {
  hci_spec::AdvertisingHandle handle = params.adv_handle;

  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
    ret.opcode = hci_android::kLEMultiAdvtSetRandomAddrSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  if (extended_advertising_states_.count(handle) == 0) {
    bt_log(INFO,
           "fake-hci",
           "advertising handle (%d) maps to an unknown advertising set",
           handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER;
    ret.opcode = hci_android::kLEMultiAdvtSetRandomAddrSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  LEAdvertisingState& state = extended_advertising_states_[handle];
  if (state.IsConnectableAdvertising() && state.enabled) {
    bt_log(
        INFO,
        "fake-hci",
        "cannot set LE random address while connectable advertising enabled");

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status = pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED;
    ret.opcode = hci_android::kLEMultiAdvtSetRandomAddrSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  state.random_address =
      DeviceAddress(DeviceAddress::Type::kLERandom, params.random_address);

  hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
  ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  ret.opcode = hci_android::kLEMultiAdvtSetRandomAddrSubopcode;
  RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                             BufferView(&ret, sizeof(ret)));
}

void FakeController::OnAndroidLEMultiAdvtEnable(
    const pw::bluetooth::vendor::android_hci::LEMultiAdvtEnableCommandView&
        params) {
  hci_spec::AdvertisingHandle handle = params.advertising_handle().Read();

  if (!IsValidAdvertisingHandle(handle)) {
    bt_log(ERROR, "fake-hci", "advertising handle outside range: %d", handle);

    hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
    ret.status =
        pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER;
    ret.opcode = hci_android::kLEMultiAdvtEnableSubopcode;
    RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                               BufferView(&ret, sizeof(ret)));
    return;
  }

  bool enabled = false;
  if (params.enable().Read() ==
      pw::bluetooth::emboss::GenericEnableParam::ENABLE) {
    enabled = true;
  }

  extended_advertising_states_[handle].enabled = enabled;

  hci_android::LEMultiAdvtSetAdvtParamReturnParams ret;
  ret.status = pw::bluetooth::emboss::StatusCode::SUCCESS;
  ret.opcode = hci_android::kLEMultiAdvtEnableSubopcode;
  RespondWithCommandComplete(hci_android::kLEMultiAdvt,
                             BufferView(&ret, sizeof(ret)));
  NotifyAdvertisingState();
}

void FakeController::OnAndroidLEMultiAdvt(
    const PacketView<hci_spec::CommandHeader>& command_packet) {
  const auto& payload = command_packet.payload_data();

  uint8_t subopcode = payload.To<uint8_t>();
  switch (subopcode) {
    case hci_android::kLEMultiAdvtSetAdvtParamSubopcode: {
      auto params =
          payload.To<hci_android::LEMultiAdvtSetAdvtParamCommandParams>();
      OnAndroidLEMultiAdvtSetAdvtParam(params);
      break;
    }
    case hci_android::kLEMultiAdvtSetAdvtDataSubopcode: {
      auto params =
          payload.To<hci_android::LEMultiAdvtSetAdvtDataCommandParams>();
      OnAndroidLEMultiAdvtSetAdvtData(params);
      break;
    }
    case hci_android::kLEMultiAdvtSetScanRespSubopcode: {
      auto params =
          payload.To<hci_android::LEMultiAdvtSetScanRespCommandParams>();
      OnAndroidLEMultiAdvtSetScanResp(params);
      break;
    }
    case hci_android::kLEMultiAdvtSetRandomAddrSubopcode: {
      auto params =
          payload.To<hci_android::LEMultiAdvtSetRandomAddrCommandParams>();
      OnAndroidLEMultiAdvtSetRandomAddr(params);
      break;
    }
    case hci_android::kLEMultiAdvtEnableSubopcode: {
      auto view =
          pw::bluetooth::vendor::android_hci::MakeLEMultiAdvtEnableCommandView(
              command_packet.data().data(),
              pw::bluetooth::vendor::android_hci::LEMultiAdvtEnableCommand::
                  MaxSizeInBytes());
      OnAndroidLEMultiAdvtEnable(view);
      break;
    }
    default: {
      bt_log(WARN,
             "fake-hci",
             "unhandled android multiple advertising command, subopcode: %#.4x",
             subopcode);
      RespondWithCommandComplete(
          subopcode, pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
      break;
    }
  }
}

void FakeController::OnVendorCommand(
    const PacketView<hci_spec::CommandHeader>& command_packet) {
  auto opcode = le16toh(command_packet.header().opcode);

  switch (opcode) {
    case hci_android::kLEGetVendorCapabilities:
      OnAndroidLEGetVendorCapabilities();
      break;
    case hci_android::kA2dpOffloadCommand:
      OnAndroidA2dpOffloadCommand(command_packet);
      break;
    case hci_android::kLEMultiAdvt:
      OnAndroidLEMultiAdvt(command_packet);
      break;
    default:
      bt_log(WARN,
             "fake-hci",
             "received unhandled vendor command with opcode: %#.4x",
             opcode);
      RespondWithCommandComplete(
          opcode, pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
      break;
  }
}

void FakeController::OnACLDataPacketReceived(
    const ByteBuffer& acl_data_packet) {
  if (acl_data_callback_) {
    BT_DEBUG_ASSERT(data_dispatcher_);
    DynamicByteBuffer packet_copy(acl_data_packet);
    (void)data_dispatcher_->Post(
        [packet_copy = std::move(packet_copy), cb = acl_data_callback_.share()](
            pw::async::Context /*ctx*/, pw::Status status) mutable {
          if (status.ok()) {
            cb(packet_copy);
          }
        });
  }

  if (acl_data_packet.size() < sizeof(hci_spec::ACLDataHeader)) {
    bt_log(WARN, "fake-hci", "malformed ACL packet!");
    return;
  }

  const auto& header = acl_data_packet.To<hci_spec::ACLDataHeader>();
  hci_spec::ConnectionHandle handle =
      le16toh(header.handle_and_flags) & 0x0FFFF;
  FakePeer* peer = FindByConnHandle(handle);
  if (!peer) {
    bt_log(WARN, "fake-hci", "ACL data received for unknown handle!");
    return;
  }

  if (auto_completed_packets_event_enabled_) {
    SendNumberOfCompletedPacketsEvent(handle, 1);
  }
  peer->OnRxL2CAP(handle,
                  acl_data_packet.view(sizeof(hci_spec::ACLDataHeader)));
}

void FakeController::OnScoDataPacketReceived(
    const ByteBuffer& sco_data_packet) {
  if (sco_data_callback_) {
    sco_data_callback_(sco_data_packet);
  }

  if (sco_data_packet.size() < sizeof(hci_spec::SynchronousDataHeader)) {
    bt_log(WARN, "fake-hci", "malformed SCO packet!");
    return;
  }

  const auto& header = sco_data_packet.To<hci_spec::SynchronousDataHeader>();
  hci_spec::ConnectionHandle handle =
      le16toh(header.handle_and_flags) & 0x0FFFF;
  FakePeer* peer = FindByConnHandle(handle);
  if (!peer) {
    bt_log(WARN, "fake-hci", "SCO data received for unknown handle!");
    return;
  }

  if (auto_completed_packets_event_enabled_) {
    SendNumberOfCompletedPacketsEvent(handle, 1);
  }
}

void FakeController::SetDataCallback(DataCallback callback,
                                     pw::async::Dispatcher& pw_dispatcher) {
  BT_DEBUG_ASSERT(callback);
  BT_DEBUG_ASSERT(!acl_data_callback_);
  BT_DEBUG_ASSERT(!data_dispatcher_);

  acl_data_callback_ = std::move(callback);
  data_dispatcher_.emplace(pw_dispatcher);
}

void FakeController::ClearDataCallback() {
  // Leave dispatcher set (if already set) to preserve its write-once-ness (this
  // catches bugs with setting multiple data callbacks in class hierarchies).
  acl_data_callback_ = nullptr;
}

bool FakeController::LEAdvertisingState::IsDirectedAdvertising() const {
  return adv_type == pw::bluetooth::emboss::LEAdvertisingType::
                         CONNECTABLE_HIGH_DUTY_CYCLE_DIRECTED ||
         adv_type == pw::bluetooth::emboss::LEAdvertisingType::
                         CONNECTABLE_LOW_DUTY_CYCLE_DIRECTED;
}

bool FakeController::LEAdvertisingState::IsScannableAdvertising() const {
  return adv_type == pw::bluetooth::emboss::LEAdvertisingType::
                         CONNECTABLE_AND_SCANNABLE_UNDIRECTED ||
         adv_type ==
             pw::bluetooth::emboss::LEAdvertisingType::SCANNABLE_UNDIRECTED;
}

bool FakeController::LEAdvertisingState::IsConnectableAdvertising() const {
  return adv_type == pw::bluetooth::emboss::LEAdvertisingType::
                         CONNECTABLE_AND_SCANNABLE_UNDIRECTED ||
         adv_type == pw::bluetooth::emboss::LEAdvertisingType::
                         CONNECTABLE_HIGH_DUTY_CYCLE_DIRECTED ||
         adv_type == pw::bluetooth::emboss::LEAdvertisingType::
                         CONNECTABLE_LOW_DUTY_CYCLE_DIRECTED;
}

void FakeController::HandleReceivedCommandPacket(
    const PacketView<hci_spec::CommandHeader>& command_packet) {
  hci_spec::OpCode opcode = le16toh(command_packet.header().opcode);

  if (MaybeRespondWithDefaultCommandStatus(opcode)) {
    return;
  }

  if (MaybeRespondWithDefaultStatus(opcode)) {
    return;
  }

  auto ogf = hci_spec::GetOGF(opcode);
  if (ogf == hci_spec::kVendorOGF) {
    OnVendorCommand(command_packet);
    return;
  }

  // TODO(fxbug.dev/42175513): Validate size of payload to be the correct length
  // below.
  switch (opcode) {
    case hci_spec::kReadLocalVersionInfo: {
      OnReadLocalVersionInfo();
      break;
    }
    case hci_spec::kReadLocalSupportedCommands: {
      OnReadLocalSupportedCommands();
      break;
    }
    case hci_spec::kReadLocalSupportedFeatures: {
      OnReadLocalSupportedFeatures();
      break;
    }
    case hci_spec::kLERemoveAdvertisingSet: {
      const auto& params =
          command_packet
              .payload<hci_spec::LERemoveAdvertisingSetCommandParams>();
      OnLERemoveAdvertisingSet(params);
      break;
    }
    case hci_spec::kReadBDADDR: {
      OnReadBRADDR();
      break;
    }
    case hci_spec::kReadBufferSize: {
      OnReadBufferSize();
      break;
    }
    case hci_spec::kCreateConnectionCancel: {
      OnCreateConnectionCancel();
      break;
    }
    case hci_spec::kReadLocalName: {
      OnReadLocalName();
      break;
    }
    case hci_spec::kReadScanEnable: {
      OnReadScanEnable();
      break;
    }
    case hci_spec::kReadPageScanActivity: {
      OnReadPageScanActivity();
      break;
    }
    case hci_spec::kReadInquiryMode: {
      OnReadInquiryMode();
      break;
    }
    case hci_spec::kReadPageScanType: {
      OnReadPageScanType();
      break;
    }
    case hci_spec::kReadSimplePairingMode: {
      OnReadSimplePairingMode();
      break;
    }
    case hci_spec::kLECreateConnectionCancel: {
      OnLECreateConnectionCancel();
      break;
    }
    case hci_spec::kLEReadLocalSupportedFeatures: {
      OnLEReadLocalSupportedFeatures();
      break;
    }
    case hci_spec::kLEReadSupportedStates: {
      OnLEReadSupportedStates();
      break;
    }
    case hci_spec::kLEReadBufferSizeV1: {
      OnLEReadBufferSizeV1();
      break;
    }
    case hci_spec::kLEReadBufferSizeV2: {
      OnLEReadBufferSizeV2();
      break;
    }
    case hci_spec::kReset: {
      OnReset();
      break;
    }
    case hci_spec::kLinkKeyRequestReply: {
      const auto& params =
          command_packet
              .payload<pw::bluetooth::emboss::LinkKeyRequestReplyCommandView>();
      OnLinkKeyRequestReplyCommandReceived(params);
      break;
    }
    case hci_spec::kLEReadRemoteFeatures: {
      const auto& params =
          command_packet.payload<hci_spec::LEReadRemoteFeaturesCommandParams>();
      OnLEReadRemoteFeaturesCommand(params);
      break;
    }
    case hci_spec::kLEReadAdvertisingChannelTxPower: {
      OnLEReadAdvertisingChannelTxPower();
      break;
    }
    case hci_spec::kAuthenticationRequested:
    case hci_spec::kCreateConnection:
    case hci_spec::kDisconnect:
    case hci_spec::kEnhancedAcceptSynchronousConnectionRequest:
    case hci_spec::kEnhancedSetupSynchronousConnection:
    case hci_spec::kIOCapabilityRequestReply:
    case hci_spec::kInquiry:
    case hci_spec::kLEClearAdvertisingSets:
    case hci_spec::kLEConnectionUpdate:
    case hci_spec::kLECreateConnection:
    case hci_spec::kLEReadMaxAdvertisingDataLength:
    case hci_spec::kLEReadNumSupportedAdvertisingSets:
    case hci_spec::kLESetAdvertisingData:
    case hci_spec::kLESetAdvertisingEnable:
    case hci_spec::kLESetAdvertisingParameters:
    case hci_spec::kLESetAdvertisingSetRandomAddress:
    case hci_spec::kLESetEventMask:
    case hci_spec::kLESetExtendedAdvertisingData:
    case hci_spec::kLESetExtendedAdvertisingEnable:
    case hci_spec::kLESetExtendedAdvertisingParameters:
    case hci_spec::kLESetExtendedScanEnable:
    case hci_spec::kLESetExtendedScanParameters:
    case hci_spec::kLESetExtendedScanResponseData:
    case hci_spec::kLESetRandomAddress:
    case hci_spec::kLESetScanEnable:
    case hci_spec::kLESetScanParameters:
    case hci_spec::kLESetScanResponseData:
    case hci_spec::kLEStartEncryption:
    case hci_spec::kLinkKeyRequestNegativeReply:
    case hci_spec::kReadEncryptionKeySize:
    case hci_spec::kReadLocalExtendedFeatures:
    case hci_spec::kReadRemoteExtendedFeatures:
    case hci_spec::kReadRemoteSupportedFeatures:
    case hci_spec::kReadRemoteVersionInfo:
    case hci_spec::kRemoteNameRequest:
    case hci_spec::kSetConnectionEncryption:
    case hci_spec::kSetEventMask:
    case hci_spec::kUserConfirmationRequestNegativeReply:
    case hci_spec::kUserConfirmationRequestReply:
    case hci_spec::kWriteClassOfDevice:
    case hci_spec::kWriteExtendedInquiryResponse:
    case hci_spec::kWriteInquiryMode:
    case hci_spec::kWriteLEHostSupport:
    case hci_spec::kWriteLocalName:
    case hci_spec::kWritePageScanActivity:
    case hci_spec::kWritePageScanType:
    case hci_spec::kWriteScanEnable:
    case hci_spec::kWriteSecureConnectionsHostSupport:
    case hci_spec::kWriteSimplePairingMode:
    case hci_spec::kWriteSynchronousFlowControlEnable: {
      // This case is for packet types that have been migrated to the new Emboss
      // architecture. Their old version can be still be assembled from the
      // HciEmulator channel, so here we repackage and forward them as Emboss
      // packets.
      auto emboss_packet = bt::hci::EmbossCommandPacket::New<
          pw::bluetooth::emboss::CommandHeaderView>(opcode,
                                                    command_packet.size());
      bt::MutableBufferView dest = emboss_packet.mutable_data();
      command_packet.data().view().Copy(&dest);
      HandleReceivedCommandPacket(emboss_packet);
      break;
    }
    default: {
      bt_log(WARN,
             "fake-hci",
             "received unhandled command with opcode: %#.4x",
             opcode);
      RespondWithCommandComplete(
          opcode, pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
      break;
    }
  }
}

void FakeController::HandleReceivedCommandPacket(
    const hci::EmbossCommandPacket& command_packet) {
  hci_spec::OpCode opcode = command_packet.opcode();

  if (MaybeRespondWithDefaultCommandStatus(opcode)) {
    return;
  }

  if (MaybeRespondWithDefaultStatus(opcode)) {
    return;
  }

  auto ogf = command_packet.ogf();
  if (ogf == hci_spec::kVendorOGF) {
    bt_log(WARN,
           "fake-hci",
           "vendor commands not yet migrated to Emboss; received Emboss vendor "
           "command with "
           "opcode: %#.4x",
           opcode);
    RespondWithCommandComplete(
        opcode, pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
    return;
  }

  switch (opcode) {
    case hci_spec::kInquiry: {
      auto params =
          command_packet.view<pw::bluetooth::emboss::InquiryCommandView>();
      OnInquiry(params);
      break;
    }
    case hci_spec::kEnhancedAcceptSynchronousConnectionRequest: {
      auto params = command_packet.view<
          pw::bluetooth::emboss::
              EnhancedAcceptSynchronousConnectionRequestCommandView>();
      OnEnhancedAcceptSynchronousConnectionRequestCommand(params);
      break;
    }
    case hci_spec::kEnhancedSetupSynchronousConnection: {
      auto params =
          command_packet
              .view<pw::bluetooth::emboss::
                        EnhancedSetupSynchronousConnectionCommandView>();
      OnEnhancedSetupSynchronousConnectionCommand(params);
      break;
    }
    case hci_spec::kCreateConnection: {
      const auto params =
          command_packet
              .view<pw::bluetooth::emboss::CreateConnectionCommandView>();
      OnCreateConnectionCommandReceived(params);
      break;
    }
    case hci_spec::kDisconnect: {
      const auto params =
          command_packet.view<pw::bluetooth::emboss::DisconnectCommandView>();
      OnDisconnectCommandReceived(params);
      break;
    }
    case hci_spec::kLESetAdvertisingEnable: {
      const auto params =
          command_packet
              .view<pw::bluetooth::emboss::LESetAdvertisingEnableCommandView>();
      OnLESetAdvertisingEnable(params);
      break;
    }
    case hci_spec::kLESetExtendedAdvertisingEnable: {
      const auto params = command_packet.view<
          pw::bluetooth::emboss::LESetExtendedAdvertisingEnableCommandView>();
      OnLESetExtendedAdvertisingEnable(params);
      break;
    }
    case hci_spec::kLinkKeyRequestNegativeReply: {
      const auto params = command_packet.view<
          pw::bluetooth::emboss::LinkKeyRequestNegativeReplyCommandView>();
      OnLinkKeyRequestNegativeReplyCommandReceived(params);
      break;
    }
    case hci_spec::kAuthenticationRequested: {
      const auto params = command_packet.view<
          pw::bluetooth::emboss::AuthenticationRequestedCommandView>();
      OnAuthenticationRequestedCommandReceived(params);
      break;
    }
    case hci_spec::kSetConnectionEncryption: {
      const auto params = command_packet.view<
          pw::bluetooth::emboss::SetConnectionEncryptionCommandView>();
      OnSetConnectionEncryptionCommand(params);
      break;
    }
    case hci_spec::kRemoteNameRequest: {
      const auto params =
          command_packet
              .view<pw::bluetooth::emboss::RemoteNameRequestCommandView>();
      OnReadRemoteNameRequestCommandReceived(params);
      break;
    }
    case hci_spec::kReadRemoteSupportedFeatures: {
      const auto params = command_packet.view<
          pw::bluetooth::emboss::ReadRemoteSupportedFeaturesCommandView>();
      OnReadRemoteSupportedFeaturesCommandReceived(params);
      break;
    }
    case hci_spec::kReadRemoteExtendedFeatures: {
      const auto params = command_packet.view<
          pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCommandView>();
      OnReadRemoteExtendedFeaturesCommandReceived(params);
      break;
    }
    case hci_spec::kReadRemoteVersionInfo: {
      const auto params =
          command_packet
              .view<pw::bluetooth::emboss::ReadRemoteVersionInfoCommandView>();
      OnReadRemoteVersionInfoCommandReceived(params);
      break;
    }
    case hci_spec::kIOCapabilityRequestReply: {
      const auto params = command_packet.view<
          pw::bluetooth::emboss::IoCapabilityRequestReplyCommandView>();
      OnIOCapabilityRequestReplyCommand(params);
      break;
    }
    case hci_spec::kSetEventMask: {
      const auto params =
          command_packet.view<pw::bluetooth::emboss::SetEventMaskCommandView>();
      OnSetEventMask(params);
      break;
    }
    case hci_spec::kWriteLocalName: {
      const auto params =
          command_packet
              .view<pw::bluetooth::emboss::WriteLocalNameCommandView>();
      OnWriteLocalName(params);
      break;
    }
    case hci_spec::kWriteScanEnable: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::WriteScanEnableCommandView>();
      OnWriteScanEnable(params);
      break;
    }
    case hci_spec::kWritePageScanActivity: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::WritePageScanActivityCommandView>();
      OnWritePageScanActivity(params);
      break;
    }
    case hci_spec::kUserConfirmationRequestReply: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::UserConfirmationRequestReplyCommandView>();
      OnUserConfirmationRequestReplyCommand(params);
      break;
    }
    case hci_spec::kUserConfirmationRequestNegativeReply: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::
                        UserConfirmationRequestNegativeReplyCommandView>();
      OnUserConfirmationRequestNegativeReplyCommand(params);
      break;
    }
    case hci_spec::kWriteSynchronousFlowControlEnable: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::
                        WriteSynchronousFlowControlEnableCommandView>();
      OnWriteSynchronousFlowControlEnableCommand(params);
      break;
    }
    case hci_spec::kWriteExtendedInquiryResponse: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::WriteExtendedInquiryResponseCommandView>();
      OnWriteExtendedInquiryResponse(params);
      break;
    }
    case hci_spec::kWriteSimplePairingMode: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::WriteSimplePairingModeCommandView>();
      OnWriteSimplePairingMode(params);
      break;
    }
    case hci_spec::kWriteClassOfDevice: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::WriteClassOfDeviceCommandView>();
      OnWriteClassOfDevice(params);
      break;
    }
    case hci_spec::kWriteInquiryMode: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::WriteInquiryModeCommandView>();
      OnWriteInquiryMode(params);
      break;
    };
    case hci_spec::kWritePageScanType: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::WritePageScanTypeCommandView>();
      OnWritePageScanType(params);
      break;
    }
    case hci_spec::kWriteLEHostSupport: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::WriteLEHostSupportCommandView>();
      OnWriteLEHostSupportCommandReceived(params);
      break;
    }
    case hci_spec::kWriteSecureConnectionsHostSupport: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::
                        WriteSecureConnectionsHostSupportCommandView>();
      OnWriteSecureConnectionsHostSupport(params);
      break;
    }
    case hci_spec::kReadEncryptionKeySize: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::ReadEncryptionKeySizeCommandView>();
      OnReadEncryptionKeySizeCommand(params);
      break;
    }
    case hci_spec::kLESetEventMask: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LESetEventMaskCommandView>();
      OnLESetEventMask(params);
      break;
    }
    case hci_spec::kLESetRandomAddress: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LESetRandomAddressCommandView>();
      OnLESetRandomAddress(params);
      break;
    }
    case hci_spec::kLESetAdvertisingData: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LESetAdvertisingDataCommandView>();
      OnLESetAdvertisingData(params);
      break;
    }
    case hci_spec::kLESetScanResponseData: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LESetScanResponseDataCommandView>();
      OnLESetScanResponseData(params);
      break;
    }
    case hci_spec::kLESetScanParameters: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LESetScanParametersCommandView>();
      OnLESetScanParameters(params);
      break;
    }
    case hci_spec::kLESetExtendedScanParameters: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::LESetExtendedScanParametersCommandView>();
      OnLESetExtendedScanParameters(params);
      break;
    }
    case hci_spec::kLESetScanEnable: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LESetScanEnableCommandView>();
      OnLESetScanEnable(params);
      break;
    }
    case hci_spec::kLESetExtendedScanEnable: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::LESetExtendedScanEnableCommandView>();
      OnLESetExtendedScanEnable(params);
      break;
    }
    case hci_spec::kLECreateConnection: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LECreateConnectionCommandView>();
      OnLECreateConnectionCommandReceived(params);
      break;
    }
    case hci_spec::kLEConnectionUpdate: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LEConnectionUpdateCommandView>();
      OnLEConnectionUpdateCommandReceived(params);
      break;
    }
    case hci_spec::kLEStartEncryption: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::LEEnableEncryptionCommandView>();
      OnLEStartEncryptionCommand(params);
      break;
    }
    case hci_spec::kReadLocalExtendedFeatures: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::ReadLocalExtendedFeaturesCommandView>();
      OnReadLocalExtendedFeatures(params);
      break;
    }
    case hci_spec::kLESetAdvertisingParameters: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::LESetAdvertisingParametersCommandView>();
      OnLESetAdvertisingParameters(params);
      break;
    }
    case hci_spec::kLESetExtendedAdvertisingData: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::LESetExtendedAdvertisingDataCommandView>();
      OnLESetExtendedAdvertisingData(params);
      break;
    }
    case hci_spec::kLESetExtendedScanResponseData: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::LESetExtendedScanResponseDataCommandView>();
      OnLESetExtendedScanResponseData(params);
      break;
    }
    case hci_spec::kLEReadMaxAdvertisingDataLength: {
      OnLEReadMaximumAdvertisingDataLength();
      break;
    }
    case hci_spec::kLEReadNumSupportedAdvertisingSets: {
      OnLEReadNumberOfSupportedAdvertisingSets();
      break;
    }
    case hci_spec::kLEClearAdvertisingSets: {
      OnLEClearAdvertisingSets();
      break;
    }
    case hci_spec::kLESetAdvertisingSetRandomAddress: {
      const auto& params = command_packet.view<
          pw::bluetooth::emboss::LESetAdvertisingSetRandomAddressCommandView>();
      OnLESetAdvertisingSetRandomAddress(params);
      break;
    }
    case hci_spec::kLESetExtendedAdvertisingParameters: {
      const auto& params =
          command_packet
              .view<pw::bluetooth::emboss::
                        LESetExtendedAdvertisingParametersV1CommandView>();
      OnLESetExtendedAdvertisingParameters(params);
      break;
    }
    default: {
      bt_log(WARN, "fake-hci", "opcode: %#.4x", opcode);
      break;
    }
  }
}
}  // namespace bt::testing
