/*
 * Copyright 2019 The Android Open Source Project
 *
 * 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
 *
 *      http://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.
 */
#define LOG_TAG "bt_shim_hci"
#include "hci/hci_layer.h"
#include 
#include 
#include 
#include "gd/common/init_flags.h"
#include "hci/hci_packets.h"
#include "hci/include/packet_fragmenter.h"
#include "hci/le_acl_connection_interface.h"
#include "hci/vendor_specific_event_manager.h"
#include "main/shim/hci_layer.h"
#include "main/shim/shim.h"
#include "main/shim/stack.h"
#include "osi/include/allocator.h"
#include "osi/include/future.h"
#include "packet/raw_builder.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/bt_types.h"
#include "stack/include/hcimsgs.h"
/**
 * Callback data wrapped as opaque token bundled with the command
 * transmit request to the Gd layer.
 *
 * Upon completion a token for a corresponding command transmit.
 * request is returned from the Gd layer.
 */
using CommandCallbackData = struct {
  void* context;
};
constexpr size_t kBtHdrSize = sizeof(BT_HDR);
constexpr size_t kCommandLengthSize = sizeof(uint8_t);
constexpr size_t kCommandOpcodeSize = sizeof(uint16_t);
static base::Callback send_data_upwards;
static const packet_fragmenter_t* packet_fragmenter;
namespace {
bool is_valid_event_code(bluetooth::hci::EventCode event_code) {
  switch (event_code) {
    case bluetooth::hci::EventCode::INQUIRY_COMPLETE:
    case bluetooth::hci::EventCode::INQUIRY_RESULT:
    case bluetooth::hci::EventCode::CONNECTION_COMPLETE:
    case bluetooth::hci::EventCode::CONNECTION_REQUEST:
    case bluetooth::hci::EventCode::DISCONNECTION_COMPLETE:
    case bluetooth::hci::EventCode::AUTHENTICATION_COMPLETE:
    case bluetooth::hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE:
    case bluetooth::hci::EventCode::ENCRYPTION_CHANGE:
    case bluetooth::hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE:
    case bluetooth::hci::EventCode::CENTRAL_LINK_KEY_COMPLETE:
    case bluetooth::hci::EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE:
    case bluetooth::hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE:
    case bluetooth::hci::EventCode::QOS_SETUP_COMPLETE:
    case bluetooth::hci::EventCode::COMMAND_COMPLETE:
    case bluetooth::hci::EventCode::COMMAND_STATUS:
    case bluetooth::hci::EventCode::HARDWARE_ERROR:
    case bluetooth::hci::EventCode::FLUSH_OCCURRED:
    case bluetooth::hci::EventCode::ROLE_CHANGE:
    case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_PACKETS:
    case bluetooth::hci::EventCode::MODE_CHANGE:
    case bluetooth::hci::EventCode::RETURN_LINK_KEYS:
    case bluetooth::hci::EventCode::PIN_CODE_REQUEST:
    case bluetooth::hci::EventCode::LINK_KEY_REQUEST:
    case bluetooth::hci::EventCode::LINK_KEY_NOTIFICATION:
    case bluetooth::hci::EventCode::LOOPBACK_COMMAND:
    case bluetooth::hci::EventCode::DATA_BUFFER_OVERFLOW:
    case bluetooth::hci::EventCode::MAX_SLOTS_CHANGE:
    case bluetooth::hci::EventCode::READ_CLOCK_OFFSET_COMPLETE:
    case bluetooth::hci::EventCode::CONNECTION_PACKET_TYPE_CHANGED:
    case bluetooth::hci::EventCode::QOS_VIOLATION:
    case bluetooth::hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE:
    case bluetooth::hci::EventCode::FLOW_SPECIFICATION_COMPLETE:
    case bluetooth::hci::EventCode::INQUIRY_RESULT_WITH_RSSI:
    case bluetooth::hci::EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE:
    case bluetooth::hci::EventCode::SYNCHRONOUS_CONNECTION_COMPLETE:
    case bluetooth::hci::EventCode::SYNCHRONOUS_CONNECTION_CHANGED:
    case bluetooth::hci::EventCode::SNIFF_SUBRATING:
    case bluetooth::hci::EventCode::EXTENDED_INQUIRY_RESULT:
    case bluetooth::hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE:
    case bluetooth::hci::EventCode::IO_CAPABILITY_REQUEST:
    case bluetooth::hci::EventCode::IO_CAPABILITY_RESPONSE:
    case bluetooth::hci::EventCode::USER_CONFIRMATION_REQUEST:
    case bluetooth::hci::EventCode::USER_PASSKEY_REQUEST:
    case bluetooth::hci::EventCode::REMOTE_OOB_DATA_REQUEST:
    case bluetooth::hci::EventCode::SIMPLE_PAIRING_COMPLETE:
    case bluetooth::hci::EventCode::LINK_SUPERVISION_TIMEOUT_CHANGED:
    case bluetooth::hci::EventCode::ENHANCED_FLUSH_COMPLETE:
    case bluetooth::hci::EventCode::USER_PASSKEY_NOTIFICATION:
    case bluetooth::hci::EventCode::KEYPRESS_NOTIFICATION:
    case bluetooth::hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION:
    case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_DATA_BLOCKS:
      return true;
    case bluetooth::hci::EventCode::VENDOR_SPECIFIC:
    case bluetooth::hci::EventCode::LE_META_EVENT:  // Private to hci
      return false;
  }
  return false;
};
bool is_valid_subevent_code(bluetooth::hci::SubeventCode subevent_code) {
  switch (subevent_code) {
    case bluetooth::hci::SubeventCode::CONNECTION_COMPLETE:
    case bluetooth::hci::SubeventCode::CONNECTION_UPDATE_COMPLETE:
    case bluetooth::hci::SubeventCode::DATA_LENGTH_CHANGE:
    case bluetooth::hci::SubeventCode::ENHANCED_CONNECTION_COMPLETE:
    case bluetooth::hci::SubeventCode::PHY_UPDATE_COMPLETE:
    case bluetooth::hci::SubeventCode::READ_REMOTE_FEATURES_COMPLETE:
    case bluetooth::hci::SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST:
    case bluetooth::hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE:
    case bluetooth::hci::SubeventCode::GENERATE_DHKEY_COMPLETE:
    case bluetooth::hci::SubeventCode::DIRECTED_ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::EXTENDED_ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED:
    case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST:
    case bluetooth::hci::SubeventCode::SCAN_TIMEOUT:
    case bluetooth::hci::SubeventCode::ADVERTISING_SET_TERMINATED:
    case bluetooth::hci::SubeventCode::SCAN_REQUEST_RECEIVED:
    case bluetooth::hci::SubeventCode::CHANNEL_SELECTION_ALGORITHM:
    case bluetooth::hci::SubeventCode::CONNECTIONLESS_IQ_REPORT:
    case bluetooth::hci::SubeventCode::CONNECTION_IQ_REPORT:
    case bluetooth::hci::SubeventCode::CTE_REQUEST_FAILED:
    case bluetooth::hci::SubeventCode::
        PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED:
    case bluetooth::hci::SubeventCode::CIS_ESTABLISHED:
    case bluetooth::hci::SubeventCode::CIS_REQUEST:
    case bluetooth::hci::SubeventCode::CREATE_BIG_COMPLETE:
    case bluetooth::hci::SubeventCode::TERMINATE_BIG_COMPLETE:
    case bluetooth::hci::SubeventCode::BIG_SYNC_ESTABLISHED:
    case bluetooth::hci::SubeventCode::BIG_SYNC_LOST:
    case bluetooth::hci::SubeventCode::REQUEST_PEER_SCA_COMPLETE:
    case bluetooth::hci::SubeventCode::PATH_LOSS_THRESHOLD:
    case bluetooth::hci::SubeventCode::TRANSMIT_POWER_REPORTING:
    case bluetooth::hci::SubeventCode::BIG_INFO_ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::LONG_TERM_KEY_REQUEST:
      return true;
    default:
      return false;
  }
}
static bool event_already_registered_in_hci_layer(
    bluetooth::hci::EventCode event_code) {
  switch (event_code) {
    case bluetooth::hci::EventCode::COMMAND_COMPLETE:
    case bluetooth::hci::EventCode::COMMAND_STATUS:
    case bluetooth::hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE:
    case bluetooth::hci::EventCode::MAX_SLOTS_CHANGE:
    case bluetooth::hci::EventCode::LE_META_EVENT:
    case bluetooth::hci::EventCode::DISCONNECTION_COMPLETE:
    case bluetooth::hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE:
      return true;
    case bluetooth::hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION:
    case bluetooth::hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE:
      return bluetooth::common::init_flags::gd_remote_name_request_is_enabled();
    default:
      return false;
  }
}
static bool event_already_registered_in_controller_layer(
    bluetooth::hci::EventCode event_code) {
  switch (event_code) {
    case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_PACKETS:
      return true;
    default:
      return false;
  }
}
static bool event_already_registered_in_acl_layer(
    bluetooth::hci::EventCode event_code) {
  for (auto event : bluetooth::hci::AclConnectionEvents) {
    if (event == event_code) {
      return true;
    }
  }
  return false;
}
static bool subevent_already_registered_in_le_hci_layer(
    bluetooth::hci::SubeventCode subevent_code) {
  switch (subevent_code) {
    case bluetooth::hci::SubeventCode::CONNECTION_COMPLETE:
    case bluetooth::hci::SubeventCode::CONNECTION_UPDATE_COMPLETE:
    case bluetooth::hci::SubeventCode::DATA_LENGTH_CHANGE:
    case bluetooth::hci::SubeventCode::ENHANCED_CONNECTION_COMPLETE:
    case bluetooth::hci::SubeventCode::PHY_UPDATE_COMPLETE:
    case bluetooth::hci::SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST:
    case bluetooth::hci::SubeventCode::ADVERTISING_SET_TERMINATED:
    case bluetooth::hci::SubeventCode::SCAN_REQUEST_RECEIVED:
    case bluetooth::hci::SubeventCode::SCAN_TIMEOUT:
    case bluetooth::hci::SubeventCode::ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::DIRECTED_ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::EXTENDED_ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_REPORT:
    case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED:
    case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST:
    case bluetooth::hci::SubeventCode::
        PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED:
    case bluetooth::hci::SubeventCode::TRANSMIT_POWER_REPORTING:
    case bluetooth::hci::SubeventCode::BIG_INFO_ADVERTISING_REPORT:
      return true;
    case bluetooth::hci::SubeventCode::READ_REMOTE_FEATURES_COMPLETE:
    case bluetooth::hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE:
    case bluetooth::hci::SubeventCode::GENERATE_DHKEY_COMPLETE:
    case bluetooth::hci::SubeventCode::CHANNEL_SELECTION_ALGORITHM:
    case bluetooth::hci::SubeventCode::CONNECTIONLESS_IQ_REPORT:
    case bluetooth::hci::SubeventCode::CONNECTION_IQ_REPORT:
    case bluetooth::hci::SubeventCode::CTE_REQUEST_FAILED:
    case bluetooth::hci::SubeventCode::CIS_ESTABLISHED:
    case bluetooth::hci::SubeventCode::CIS_REQUEST:
    case bluetooth::hci::SubeventCode::CREATE_BIG_COMPLETE:
    case bluetooth::hci::SubeventCode::TERMINATE_BIG_COMPLETE:
    case bluetooth::hci::SubeventCode::BIG_SYNC_ESTABLISHED:
    case bluetooth::hci::SubeventCode::BIG_SYNC_LOST:
    case bluetooth::hci::SubeventCode::REQUEST_PEER_SCA_COMPLETE:
    case bluetooth::hci::SubeventCode::PATH_LOSS_THRESHOLD:
    case bluetooth::hci::SubeventCode::LONG_TERM_KEY_REQUEST:
    default:
      return false;
  }
}
static bool event_already_registered_in_le_advertising_manager(
    bluetooth::hci::EventCode event_code) {
  for (auto event : bluetooth::hci::AclConnectionEvents) {
    if (event == event_code) {
      return true;
    }
  }
  return false;
}
static bool event_already_registered_in_le_scanning_manager(
    bluetooth::hci::EventCode event_code) {
  for (auto event : bluetooth::hci::AclConnectionEvents) {
    if (event == event_code) {
      return true;
    }
  }
  return false;
}
}  // namespace
namespace cpp {
bluetooth::common::BidiQueueEnd* hci_queue_end =
    nullptr;
bluetooth::common::BidiQueueEnd* hci_sco_queue_end =
    nullptr;
bluetooth::common::BidiQueueEnd* hci_iso_queue_end =
    nullptr;
static bluetooth::os::EnqueueBuffer* pending_data =
    nullptr;
static bluetooth::os::EnqueueBuffer*
    pending_iso_data = nullptr;
static bluetooth::os::EnqueueBuffer*
    pending_sco_data = nullptr;
static std::unique_ptr MakeUniquePacket(
    const uint8_t* data, size_t len) {
  bluetooth::packet::RawBuilder builder;
  std::vector bytes(data, data + len);
  auto payload = std::make_unique();
  payload->AddOctets(bytes);
  return payload;
}
static BT_HDR* WrapPacketAndCopy(
    uint16_t event,
    bluetooth::hci::PacketView* data) {
  size_t packet_size = data->size() + kBtHdrSize;
  BT_HDR* packet = reinterpret_cast(osi_malloc(packet_size));
  packet->offset = 0;
  packet->len = data->size();
  packet->layer_specific = 0;
  packet->event = event;
  std::copy(data->begin(), data->end(), packet->data);
  return packet;
}
static void event_callback(bluetooth::hci::EventView event_packet_view) {
  if (!send_data_upwards) {
    return;
  }
  send_data_upwards.Run(FROM_HERE, WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT,
                                                     &event_packet_view));
}
static void subevent_callback(
    bluetooth::hci::LeMetaEventView le_meta_event_view) {
  if (!send_data_upwards) {
    return;
  }
  send_data_upwards.Run(FROM_HERE, WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT,
                                                     &le_meta_event_view));
}
void OnTransmitPacketCommandComplete(command_complete_cb complete_callback,
                                     void* context,
                                     bluetooth::hci::CommandCompleteView view) {
  LOG_DEBUG("Received cmd complete for %s",
            bluetooth::hci::OpCodeText(view.GetCommandOpCode()).c_str());
  BT_HDR* response = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &view);
  complete_callback(response, context);
}
void OnTransmitPacketStatus(command_status_cb status_callback, void* context,
                            std::unique_ptr command,
                            bluetooth::hci::CommandStatusView view) {
  LOG_DEBUG("Received cmd status %s for %s",
            bluetooth::hci::ErrorCodeText(view.GetStatus()).c_str(),
            bluetooth::hci::OpCodeText(view.GetCommandOpCode()).c_str());
  uint8_t status = static_cast(view.GetStatus());
  status_callback(status, static_cast(command->Release()), context);
}
static void transmit_command(const BT_HDR* command,
                             command_complete_cb complete_callback,
                             command_status_cb status_callback, void* context) {
  CHECK(command != nullptr);
  const uint8_t* data = command->data + command->offset;
  size_t len = command->len;
  CHECK(len >= (kCommandOpcodeSize + kCommandLengthSize));
  // little endian command opcode
  uint16_t command_op_code = (data[1] << 8 | data[0]);
  // Gd stack API requires opcode specification and calculates length, so
  // no need to provide opcode or length here.
  data += (kCommandOpcodeSize + kCommandLengthSize);
  len -= (kCommandOpcodeSize + kCommandLengthSize);
  auto op_code = static_cast(command_op_code);
  auto payload = MakeUniquePacket(data, len);
  auto packet =
      bluetooth::hci::CommandBuilder::Create(op_code, std::move(payload));
  LOG_DEBUG("Sending command %s", bluetooth::hci::OpCodeText(op_code).c_str());
  if (bluetooth::hci::Checker::IsCommandStatusOpcode(op_code)) {
    auto command_unique = std::make_unique(command);
    bluetooth::shim::GetHciLayer()->EnqueueCommand(
        std::move(packet), bluetooth::shim::GetGdShimHandler()->BindOnce(
                               OnTransmitPacketStatus, status_callback, context,
                               std::move(command_unique)));
  } else {
    bluetooth::shim::GetHciLayer()->EnqueueCommand(
        std::move(packet),
        bluetooth::shim::GetGdShimHandler()->BindOnce(
            OnTransmitPacketCommandComplete, complete_callback, context));
    osi_free(const_cast(static_cast(command)));
  }
}
static void transmit_fragment(const uint8_t* stream, size_t length) {
  uint16_t handle_with_flags;
  STREAM_TO_UINT16(handle_with_flags, stream);
  auto pb_flag = static_cast(
      handle_with_flags >> 12 & 0b11);
  auto bc_flag =
      static_cast(handle_with_flags >> 14);
  uint16_t handle = HCID_GET_HANDLE(handle_with_flags);
  ASSERT_LOG(handle <= HCI_HANDLE_MAX, "Require handle <= 0x%X, but is 0x%X",
             HCI_HANDLE_MAX, handle);
  length -= 2;
  // skip data total length
  stream += 2;
  length -= 2;
  auto payload = MakeUniquePacket(stream, length);
  auto acl_packet = bluetooth::hci::AclBuilder::Create(handle, pb_flag, bc_flag,
                                                       std::move(payload));
  pending_data->Enqueue(std::move(acl_packet),
                        bluetooth::shim::GetGdShimHandler());
}
static void transmit_sco_fragment(const uint8_t* stream, size_t length) {
  uint16_t handle_with_flags;
  STREAM_TO_UINT16(handle_with_flags, stream);
  uint16_t handle = HCID_GET_HANDLE(handle_with_flags);
  ASSERT_LOG(handle <= HCI_HANDLE_MAX, "Require handle <= 0x%X, but is 0x%X",
             HCI_HANDLE_MAX, handle);
  length -= 2;
  // skip data total length
  stream += 1;
  length -= 1;
  auto payload = std::vector(stream, stream + length);
  auto sco_packet = bluetooth::hci::ScoBuilder::Create(
      handle, bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED,
      std::move(payload));
  pending_sco_data->Enqueue(std::move(sco_packet),
                            bluetooth::shim::GetGdShimHandler());
}
static void transmit_iso_fragment(const uint8_t* stream, size_t length) {
  uint16_t handle_with_flags;
  STREAM_TO_UINT16(handle_with_flags, stream);
  auto pb_flag = static_cast(
      handle_with_flags >> 12 & 0b11);
  auto ts_flag =
      static_cast(handle_with_flags >> 14);
  uint16_t handle = HCID_GET_HANDLE(handle_with_flags);
  ASSERT_LOG(handle <= HCI_HANDLE_MAX, "Require handle <= 0x%X, but is 0x%X",
             HCI_HANDLE_MAX, handle);
  length -= 2;
  // skip data total length
  stream += 2;
  length -= 2;
  auto payload = MakeUniquePacket(stream, length);
  auto iso_packet = bluetooth::hci::IsoBuilder::Create(handle, pb_flag, ts_flag,
                                                       std::move(payload));
  pending_iso_data->Enqueue(std::move(iso_packet),
                            bluetooth::shim::GetGdShimHandler());
}
static void register_event(bluetooth::hci::EventCode event_code) {
  auto handler = bluetooth::shim::GetGdShimHandler();
  bluetooth::shim::GetHciLayer()->RegisterEventHandler(
      event_code, handler->Bind(event_callback));
}
static void register_le_event(bluetooth::hci::SubeventCode subevent_code) {
  auto handler = bluetooth::shim::GetGdShimHandler();
  bluetooth::shim::GetHciLayer()->RegisterLeEventHandler(
      subevent_code, handler->Bind(subevent_callback));
}
static void sco_data_callback() {
  if (hci_sco_queue_end == nullptr) {
    return;
  }
  auto packet = hci_sco_queue_end->TryDequeue();
  ASSERT(packet != nullptr);
  if (!packet->IsValid()) {
    LOG_INFO("Dropping invalid packet of size %zu", packet->size());
    return;
  }
  if (!send_data_upwards) {
    return;
  }
  auto data = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_SCO, packet.get());
  packet_fragmenter->reassemble_and_dispatch(data);
}
static void iso_data_callback() {
  if (hci_iso_queue_end == nullptr) {
    return;
  }
  auto packet = hci_iso_queue_end->TryDequeue();
  ASSERT(packet != nullptr);
  if (!packet->IsValid()) {
    LOG_INFO("Dropping invalid packet of size %zu", packet->size());
    return;
  }
  if (!send_data_upwards) {
    return;
  }
  auto data = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ISO, packet.get());
  packet_fragmenter->reassemble_and_dispatch(data);
}
static void register_for_sco() {
  hci_sco_queue_end = bluetooth::shim::GetHciLayer()->GetScoQueueEnd();
  hci_sco_queue_end->RegisterDequeue(
      bluetooth::shim::GetGdShimHandler(),
      bluetooth::common::Bind(sco_data_callback));
  pending_sco_data =
      new bluetooth::os::EnqueueBuffer(
          hci_sco_queue_end);
}
static void register_for_iso() {
  hci_iso_queue_end = bluetooth::shim::GetHciLayer()->GetIsoQueueEnd();
  hci_iso_queue_end->RegisterDequeue(
      bluetooth::shim::GetGdShimHandler(),
      bluetooth::common::Bind(iso_data_callback));
  pending_iso_data =
      new bluetooth::os::EnqueueBuffer(
          hci_iso_queue_end);
}
static void on_shutting_down() {
  if (pending_data != nullptr) {
    pending_data->Clear();
    delete pending_data;
    pending_data = nullptr;
  }
  if (pending_sco_data != nullptr) {
    pending_sco_data->Clear();
    delete pending_sco_data;
    pending_sco_data = nullptr;
  }
  if (pending_iso_data != nullptr) {
    pending_iso_data->Clear();
    delete pending_iso_data;
    pending_iso_data = nullptr;
  }
  if (hci_queue_end != nullptr) {
    for (uint16_t event_code_raw = 0; event_code_raw < 0x100;
         event_code_raw++) {
      auto event_code = static_cast(event_code_raw);
      if (!is_valid_event_code(event_code)) {
        continue;
      }
      if (event_already_registered_in_hci_layer(event_code)) {
        continue;
      } else if (event_already_registered_in_le_advertising_manager(
                     event_code)) {
        continue;
      } else if (event_already_registered_in_le_scanning_manager(event_code)) {
        continue;
      }
      bluetooth::shim::GetHciLayer()->UnregisterEventHandler(event_code);
    }
    hci_queue_end = nullptr;
  }
  if (hci_sco_queue_end != nullptr) {
    hci_sco_queue_end->UnregisterDequeue();
    hci_sco_queue_end = nullptr;
  }
  if (hci_iso_queue_end != nullptr) {
    hci_iso_queue_end->UnregisterDequeue();
    hci_iso_queue_end = nullptr;
  }
}
}  // namespace cpp
using bluetooth::common::Bind;
using bluetooth::common::BindOnce;
using bluetooth::common::Unretained;
static void set_data_cb(
    base::Callback send_data_cb) {
  send_data_upwards = std::move(send_data_cb);
}
static void transmit_command(const BT_HDR* command,
                             command_complete_cb complete_callback,
                             command_status_cb status_callback, void* context) {
  cpp::transmit_command(command, complete_callback, status_callback, context);
}
static void command_complete_callback(BT_HDR* response, void* context) {
  auto future = static_cast(context);
  future_ready(future, response);
}
static void command_status_callback(uint8_t status, BT_HDR* command,
                                    void* context) {
  LOG_ALWAYS_FATAL(
      "transmit_command_futured should only send command complete opcode");
}
static future_t* transmit_command_futured(const BT_HDR* command) {
  future_t* future = future_new();
  transmit_command(command, command_complete_callback, command_status_callback,
                   future);
  return future;
}
static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) {
  uint16_t event = packet->event & MSG_EVT_MASK;
  // HCI command packets are freed on a different thread when the matching
  // event is received. Check packet->event before sending to avoid a race.
  bool free_after_transmit =
      event != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished;
  if (event == MSG_STACK_TO_HC_HCI_ACL) {
    const uint8_t* stream = packet->data + packet->offset;
    size_t length = packet->len;
    cpp::transmit_fragment(stream, length);
  } else if (event == MSG_STACK_TO_HC_HCI_SCO) {
    const uint8_t* stream = packet->data + packet->offset;
    size_t length = packet->len;
    cpp::transmit_sco_fragment(stream, length);
  } else if (event == MSG_STACK_TO_HC_HCI_ISO) {
    const uint8_t* stream = packet->data + packet->offset;
    size_t length = packet->len;
    cpp::transmit_iso_fragment(stream, length);
  }
  if (free_after_transmit) {
    osi_free(packet);
  }
}
static void dispatch_reassembled(BT_HDR* packet) {
  // Events should already have been dispatched before this point
  CHECK((packet->event & MSG_EVT_MASK) != MSG_HC_TO_STACK_HCI_EVT);
  CHECK(!send_data_upwards.is_null());
  send_data_upwards.Run(FROM_HERE, packet);
}
static void fragmenter_transmit_finished(BT_HDR* packet,
                                         bool all_fragments_sent) {
  if (all_fragments_sent) {
    osi_free(packet);
  } else {
    // This is kind of a weird case, since we're dispatching a partially sent
    // packet up to a higher layer.
    // TODO(zachoverflow): rework upper layer so this isn't necessary.
    send_data_upwards.Run(FROM_HERE, packet);
  }
}
static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
    transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished};
static void transmit_downward(uint16_t type, void* raw_data) {
  bluetooth::shim::GetGdShimHandler()->Call(
      packet_fragmenter->fragment_and_dispatch, static_cast(raw_data));
}
static hci_t interface = {.set_data_cb = set_data_cb,
                          .transmit_command = transmit_command,
                          .transmit_command_futured = transmit_command_futured,
                          .transmit_downward = transmit_downward};
const hci_t* bluetooth::shim::hci_layer_get_interface() {
  packet_fragmenter = packet_fragmenter_get_interface();
  packet_fragmenter->init(&packet_fragmenter_callbacks);
  return &interface;
}
void bluetooth::shim::hci_on_reset_complete() {
  ASSERT(send_data_upwards);
  for (uint16_t event_code_raw = 0; event_code_raw < 0x100; event_code_raw++) {
    auto event_code = static_cast(event_code_raw);
    if (!is_valid_event_code(event_code)) {
      continue;
    }
    if (event_already_registered_in_acl_layer(event_code)) {
      continue;
    } else if (event_already_registered_in_controller_layer(event_code)) {
      continue;
    } else if (event_already_registered_in_hci_layer(event_code)) {
      continue;
    } else if (event_already_registered_in_le_advertising_manager(event_code)) {
      continue;
    } else if (event_already_registered_in_le_scanning_manager(event_code)) {
      continue;
    }
    cpp::register_event(event_code);
  }
  for (uint16_t subevent_code_raw = 0; subevent_code_raw < 0x100;
       subevent_code_raw++) {
    auto subevent_code =
        static_cast(subevent_code_raw);
    if (!is_valid_subevent_code(subevent_code)) {
      continue;
    }
    if (subevent_already_registered_in_le_hci_layer(subevent_code)) {
      continue;
    }
    cpp::register_le_event(subevent_code);
  }
  cpp::register_for_sco();
  cpp::register_for_iso();
}
void bluetooth::shim::hci_on_shutting_down() { cpp::on_shutting_down(); }