Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e14287d3 authored by Henri Chataing's avatar Henri Chataing
Browse files

RootCanal: Implement LE-ISO

Implement LE-ISO as rust extension to RootCanal.
This change implements support for the connected
isochronous streams, with some limitations.

Supported features:
     - Connected Isochronous Stream Central
     - Connected Isochronous Stream Peripheral

Implemented commands:
     - LE Set Cig Parameters
     - LE Set Cig Parameters Test
     - LE Create Cis
     - LE Remove Cig
     - LE Accept Cis Request
     - LE Reject Cis Request
     - LE Setup Iso Data Path
     - LE Remove Iso Data Path

Implementation limits:
     - Does not implement support for ISO
       fragmentation and defragmentation
       (framed PDUs)

Bug: 253535400
Test: m root-canal
Change-Id: Ie7c9072d98c74e58dac45086f16028a46fedad0b
parent 6df30ff4
Loading
Loading
Loading
Loading
+22 −19
Original line number Diff line number Diff line
@@ -77,6 +77,10 @@ void DualModeController::ForwardToLm(CommandView command) {
  link_layer_controller_.ForwardToLm(command);
}

void DualModeController::ForwardToLl(CommandView command) {
  link_layer_controller_.ForwardToLl(command);
}

void DualModeController::SniffSubrating(CommandView command) {
  auto command_view = bluetooth::hci::SniffSubratingView::Create(command);
  ASSERT(command_view.IsValid());
@@ -1729,14 +1733,19 @@ void DualModeController::Disconnect(CommandView command) {
  auto command_view = bluetooth::hci::DisconnectView::Create(command);
  ASSERT(command_view.IsValid());

  uint16_t handle = command_view.GetConnectionHandle();
  uint16_t connection_handle = command_view.GetConnectionHandle();

  if (connection_handle >= kCisHandleRangeStart &&
      connection_handle < kCisHandleRangeEnd) {
    link_layer_controller_.ForwardToLl(command);
  } else {
    auto status = link_layer_controller_.Disconnect(
      handle, ErrorCode(command_view.GetReason()));
        connection_handle, ErrorCode(command_view.GetReason()));

    send_event_(bluetooth::hci::DisconnectStatusBuilder::Create(
        status, kNumCommandPackets));
  }
}

void DualModeController::LeReadFilterAcceptListSize(CommandView command) {
  auto command_view =
@@ -3621,16 +3630,12 @@ const std::unordered_map<OpCode, DualModeController::CommandHandler>
        {OpCode::LE_READ_BUFFER_SIZE_V2,
         &DualModeController::LeReadBufferSizeV2},
        //{OpCode::LE_READ_ISO_TX_SYNC, &DualModeController::LeReadIsoTxSync},
        //{OpCode::LE_SET_CIG_PARAMETERS,
        //&DualModeController::LeSetCigParameters},
        //{OpCode::LE_SET_CIG_PARAMETERS_TEST,
        //&DualModeController::LeSetCigParametersTest},
        //{OpCode::LE_CREATE_CIS, &DualModeController::LeCreateCis},
        //{OpCode::LE_REMOVE_CIG, &DualModeController::LeRemoveCig},
        //{OpCode::LE_ACCEPT_CIS_REQUEST,
        //&DualModeController::LeAcceptCisRequest},
        //{OpCode::LE_REJECT_CIS_REQUEST,
        //&DualModeController::LeRejectCisRequest},
        {OpCode::LE_SET_CIG_PARAMETERS, &DualModeController::ForwardToLl},
        {OpCode::LE_SET_CIG_PARAMETERS_TEST, &DualModeController::ForwardToLl},
        {OpCode::LE_CREATE_CIS, &DualModeController::ForwardToLl},
        {OpCode::LE_REMOVE_CIG, &DualModeController::ForwardToLl},
        {OpCode::LE_ACCEPT_CIS_REQUEST, &DualModeController::ForwardToLl},
        {OpCode::LE_REJECT_CIS_REQUEST, &DualModeController::ForwardToLl},
        //{OpCode::LE_CREATE_BIG, &DualModeController::LeCreateBig},
        //{OpCode::LE_CREATE_BIG_TEST, &DualModeController::LeCreateBigTest},
        //{OpCode::LE_TERMINATE_BIG, &DualModeController::LeTerminateBig},
@@ -3638,10 +3643,8 @@ const std::unordered_map<OpCode, DualModeController::CommandHandler>
        //{OpCode::LE_BIG_TERMINATE_SYNC,
        //&DualModeController::LeBigTerminateSync},
        //{OpCode::LE_REQUEST_PEER_SCA, &DualModeController::LeRequestPeerSca},
        //{OpCode::LE_SETUP_ISO_DATA_PATH,
        //&DualModeController::LeSetupIsoDataPath},
        //{OpCode::LE_REMOVE_ISO_DATA_PATH,
        //&DualModeController::LeRemoveIsoDataPath},
        {OpCode::LE_SETUP_ISO_DATA_PATH, &DualModeController::ForwardToLl},
        {OpCode::LE_REMOVE_ISO_DATA_PATH, &DualModeController::ForwardToLl},
        //{OpCode::LE_ISO_TRANSMIT_TEST,
        //&DualModeController::LeIsoTransmitTest},
        //{OpCode::LE_ISO_RECEIVE_TEST, &DualModeController::LeIsoReceiveTest},
+1 −1
Original line number Diff line number Diff line
@@ -547,7 +547,6 @@ class DualModeController : public Device {
  void WriteConnectionAcceptTimeout(CommandView command);

  // Vendor-specific Commands

  void LeGetVendorCapabilities(CommandView command);
  void LeEnergyInfo(CommandView command);
  void LeMultiAdv(CommandView command);
@@ -565,6 +564,7 @@ class DualModeController : public Device {

  // Command pass-through.
  void ForwardToLm(CommandView command);
  void ForwardToLl(CommandView command);

 protected:
  // Controller configuration.
+223 −21
Original line number Diff line number Diff line
@@ -16,13 +16,14 @@

#include "link_layer_controller.h"

#include <algorithm>
#include <hci/hci_packets.h>
#include <lmp.h>

#include <algorithm>

#include "crypto/crypto.h"
#include "log.h"
#include "packet/raw_builder.h"
#include "rootcanal_rs.h"

using namespace std::chrono;
using bluetooth::hci::Address;
@@ -1974,14 +1975,14 @@ LinkLayerController::LinkLayerController(const Address& address,
                                         const ControllerProperties& properties)
    : address_(address),
      properties_(properties),
      lm_(nullptr, link_manager_destroy) {

      lm_(nullptr, link_manager_destroy),
      ll_(nullptr, link_layer_destroy) {
  if (properties_.quirks.has_default_random_address) {
    LOG_WARN("Configuring a default random address for this controller");
    random_address_ = Address { 0xba, 0xdb, 0xad, 0xba, 0xdb, 0xad };
  }

  ops_ = {
  controller_ops_ = {
      .user_pointer = this,
      .get_handle =
          [](void* user, const uint8_t(*address)[6]) {
@@ -2003,12 +2004,24 @@ LinkLayerController::LinkLayerController(const Address& address,
                      reinterpret_cast<uint8_t*>(result));
          },

      .extended_features =
      .get_extended_features =
          [](void* user, uint8_t features_page) {
            auto controller = static_cast<LinkLayerController*>(user);
            return controller->GetLmpFeatures(features_page);
          },

      .get_le_features =
          [](void* user) {
            auto controller = static_cast<LinkLayerController*>(user);
            return controller->GetLeSupportedFeatures();
          },

      .get_le_event_mask =
          [](void* user) {
            auto controller = static_cast<LinkLayerController*>(user);
            return controller->le_event_mask_;
          },

      .send_hci_event =
          [](void* user, const uint8_t* data, uintptr_t len) {
            auto controller = static_cast<LinkLayerController*>(user);
@@ -2034,9 +2047,35 @@ LinkLayerController::LinkLayerController(const Address& address,

            controller->SendLinkLayerPacket(model::packets::LmpBuilder::Create(
                source, dest, std::move(payload)));
          },

      .send_llcp_packet =
          [](void* user, uint16_t acl_connection_handle, const uint8_t* data,
             uintptr_t len) {
            auto controller = static_cast<LinkLayerController*>(user);
            auto payload = std::make_unique<bluetooth::packet::RawBuilder>(
                std::vector(data, data + len));

            if (!controller->connections_.HasHandle(acl_connection_handle)) {
              LOG_ERROR(
                  "Dropping LLCP packet sent for unknown connection handle "
                  "0x%x",
                  acl_connection_handle);
              return;
            }

            AclConnection const& connection =
                controller->connections_.GetAclConnection(
                    acl_connection_handle);
            Address source = connection.GetOwnAddress().GetAddress();
            Address destination = connection.GetAddress().GetAddress();

            controller->SendLinkLayerPacket(model::packets::LlcpBuilder::Create(
                source, destination, std::move(payload)));
          }};

  lm_.reset(link_manager_create(ops_));
  lm_.reset(link_manager_create(controller_ops_));
  ll_.reset(link_layer_create(controller_ops_));
}

LinkLayerController::~LinkLayerController() {}
@@ -2251,12 +2290,18 @@ void LinkLayerController::IncomingPacket(
    case model::packets::PacketType::SCO:
      IncomingScoPacket(incoming);
      break;
    case model::packets::PacketType::LE_CONNECTED_ISOCHRONOUS_PDU:
      IncomingLeConnectedIsochronousPdu(incoming);
      break;
    case model::packets::PacketType::DISCONNECT:
      IncomingDisconnectPacket(incoming);
      break;
    case model::packets::PacketType::LMP:
      IncomingLmpPacket(incoming);
      break;
    case model::packets::PacketType::LLCP:
      IncomingLlcpPacket(incoming);
      break;
    case model::packets::PacketType::INQUIRY:
      if (inquiry_scan_enable_) {
        IncomingInquiryPacket(incoming, rssi);
@@ -2265,9 +2310,6 @@ void LinkLayerController::IncomingPacket(
    case model::packets::PacketType::INQUIRY_RESPONSE:
      IncomingInquiryResponsePacket(incoming);
      break;
    case PacketType::ISO:
      IncomingIsoPacket(incoming);
      break;
    case model::packets::PacketType::LE_LEGACY_ADVERTISING_PDU:
      IncomingLeLegacyAdvertisingPdu(incoming, rssi);
      return;
@@ -2647,6 +2689,8 @@ void LinkLayerController::IncomingDisconnectPacket(
  if (is_br_edr) {
    ASSERT(link_manager_remove_link(
        lm_.get(), reinterpret_cast<uint8_t(*)[6]>(peer.data())));
  } else {
    ASSERT(link_layer_remove_link(ll_.get(), handle));
  }
}

@@ -2766,16 +2810,6 @@ void LinkLayerController::IncomingInquiryResponsePacket(
  }
}

// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
void LinkLayerController::IncomingIsoPacket(LinkLayerPacketView incoming) {
  LOG_ALWAYS_FATAL("ISO not supported; no ISO packets expected");
}

// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) {
  LOG_ALWAYS_FATAL("ISO not supported; no ISO packets expected");
}

Address LinkLayerController::generate_rpa(
    std::array<uint8_t, LinkLayerController::kIrkSize> irk) {
  // most significant bit, bit7, bit6 is 01 to be resolvable random
@@ -4033,6 +4067,160 @@ void LinkLayerController::IncomingLmpPacket(
      packet.size()));
}

void LinkLayerController::IncomingLlcpPacket(
    model::packets::LinkLayerPacketView incoming) {
  Address address = incoming.GetSourceAddress();
  auto request = model::packets::LlcpView::Create(incoming);
  ASSERT(request.IsValid());
  auto payload = request.GetPayload();
  auto packet = std::vector(payload.begin(), payload.end());
  uint16_t acl_connection_handle = connections_.GetHandleOnlyAddress(address);

  if (acl_connection_handle == kReservedHandle) {
    LOG_INFO("Dropping LLCP packet since connection does not exist");
    return;
  }

  ASSERT(link_layer_ingest_llcp(ll_.get(), acl_connection_handle, packet.data(),
                                packet.size()));
}

void LinkLayerController::IncomingLeConnectedIsochronousPdu(
    LinkLayerPacketView incoming) {
  auto pdu = model::packets::LeConnectedIsochronousPduView::Create(incoming);
  ASSERT(pdu.IsValid());
  auto data = pdu.GetData();
  auto packet = std::vector(data.begin(), data.end());
  uint8_t cig_id = pdu.GetCigId();
  uint8_t cis_id = pdu.GetCisId();
  uint16_t cis_connection_handle = 0;
  uint16_t iso_sdu_length = packet.size();

  if (!link_layer_get_cis_connection_handle(ll_.get(), cig_id, cis_id,
                                            &cis_connection_handle)) {
    LOG_INFO(
        "Dropping CIS pdu received on disconnected CIS cig_id=%d, cis_id=%d",
        cig_id, cis_id);
    return;
  }

  // Fragment the ISO SDU if larger than the maximum payload size (4095).
  constexpr size_t kMaxPayloadSize = 4095 - 4;  // remove sequence_number and
                                                // iso_sdu_length
  size_t remaining_size = packet.size();
  size_t offset = 0;
  auto packet_boundary_flag =
      remaining_size <= kMaxPayloadSize
          ? bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU
          : bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT;

  do {
    size_t fragment_size = std::min(kMaxPayloadSize, remaining_size);
    std::vector<uint8_t> fragment(packet.data() + offset,
                                  packet.data() + offset + fragment_size);

    send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create(
        cis_connection_handle, packet_boundary_flag, pdu.GetSequenceNumber(),
        iso_sdu_length, bluetooth::hci::IsoPacketStatusFlag::VALID,
        std::make_unique<bluetooth::packet::RawBuilder>(std::move(fragment))));

    remaining_size -= fragment_size;
    offset += fragment_size;
    packet_boundary_flag =
        remaining_size <= kMaxPayloadSize
            ? bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT
            : bluetooth::hci::IsoPacketBoundaryFlag::CONTINUATION_FRAGMENT;
  } while (remaining_size > 0);
}

void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) {
  uint16_t cis_connection_handle = iso.GetConnectionHandle();
  auto pb_flag = iso.GetPbFlag();
  auto ts_flag = iso.GetTsFlag();
  auto iso_data_load = iso.GetPayload();

  // In the Host to Controller direction, ISO_Data_Load_Length
  // shall be less than or equal to the size of the buffer supported by the
  // Controller (which is returned using the ISO_Data_Packet_Length return
  // parameter of the LE Read Buffer Size command).
  if (iso_data_load.size() > properties_.iso_data_packet_length) {
    LOG_ALWAYS_FATAL(
        "Received ISO HCI packet with ISO_Data_Load_Length (%zu) larger than"
        " the controller buffer size ISO_Data_Packet_Length (%d)",
        iso_data_load.size(), properties_.iso_data_packet_length);
  }

  // The TS_Flag bit shall only be set if the PB_Flag field equals 0b00 or 0b10.
  if (ts_flag == bluetooth::hci::TimeStampFlag::PRESENT &&
      (pb_flag ==
           bluetooth::hci::IsoPacketBoundaryFlag::CONTINUATION_FRAGMENT ||
       pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT)) {
    LOG_ALWAYS_FATAL(
        "Received ISO HCI packet with TS_Flag set, but no ISO Header is "
        "expected");
  }

  uint8_t cig_id = 0;
  uint8_t cis_id = 0;
  uint16_t acl_connection_handle = kReservedHandle;
  uint16_t packet_sequence_number = 0;
  uint16_t max_sdu_length = 0;

  if (!link_layer_get_cis_information(ll_.get(), cis_connection_handle,
                                      &acl_connection_handle, &cig_id, &cis_id,
                                      &max_sdu_length)) {
    LOG_INFO("Ignoring CIS pdu received on disconnected CIS handle=%d",
             cis_connection_handle);
    return;
  }

  if (pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT ||
      pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU) {
    iso_sdu_.clear();
  }

  switch (ts_flag) {
    case bluetooth::hci::TimeStampFlag::PRESENT: {
      auto iso_with_timestamp =
          bluetooth::hci::IsoWithTimestampView::Create(iso);
      ASSERT(iso_with_timestamp.IsValid());
      auto iso_payload = iso_with_timestamp.GetPayload();
      iso_sdu_.insert(iso_sdu_.end(), iso_payload.begin(), iso_payload.end());
      packet_sequence_number = iso_with_timestamp.GetPacketSequenceNumber();
      break;
    }
    default:
    case bluetooth::hci::TimeStampFlag::NOT_PRESENT: {
      auto iso_without_timestamp =
          bluetooth::hci::IsoWithoutTimestampView::Create(iso);
      ASSERT(iso_without_timestamp.IsValid());
      auto iso_payload = iso_without_timestamp.GetPayload();
      iso_sdu_.insert(iso_sdu_.end(), iso_payload.begin(), iso_payload.end());
      packet_sequence_number = iso_without_timestamp.GetPacketSequenceNumber();
      break;
    }
  }

  if (pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT ||
      pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU) {
    // Validate that the Host stack is not sending ISO SDUs that are larger
    // that what was configured for the CIS.
    if (iso_sdu_.size() > max_sdu_length) {
      LOG_WARN(
          "attempted to send an SDU of length %zu that exceeds the configure "
          "Max_SDU_Length (%u)",
          iso_sdu_.size(), max_sdu_length);
      return;
    }

    SendLeLinkLayerPacket(
        model::packets::LeConnectedIsochronousPduBuilder::Create(
            address_,
            connections_.GetAddress(acl_connection_handle).GetAddress(), cig_id,
            cis_id, packet_sequence_number, std::move(iso_sdu_)));
  }
}

uint16_t LinkLayerController::HandleLeConnection(
    AddressWithType address, AddressWithType own_address,
    bluetooth::hci::Role role, uint16_t connection_interval,
@@ -4088,6 +4276,12 @@ uint16_t LinkLayerController::HandleLeConnection(
        supervision_timeout, static_cast<bluetooth::hci::ClockAccuracy>(0x00)));
  }

  // Update the link layer with the new link.
  ASSERT(link_layer_add_link(
      ll_.get(), handle,
      reinterpret_cast<const uint8_t(*)[6]>(address.GetAddress().data()),
      static_cast<uint8_t>(role)));

  // Note: the HCI_LE_Connection_Complete event is immediately followed by
  // an HCI_LE_Channel_Selection_Algorithm event if the connection is created
  // using the LE_Extended_Create_Connection command (see Section 7.7.8.66).
@@ -5051,6 +5245,11 @@ void LinkLayerController::ForwardToLm(bluetooth::hci::CommandView command) {
  ASSERT(link_manager_ingest_hci(lm_.get(), packet.data(), packet.size()));
}

void LinkLayerController::ForwardToLl(bluetooth::hci::CommandView command) {
  auto packet = std::vector(command.begin(), command.end());
  ASSERT(link_layer_ingest_hci(ll_.get(), packet.data(), packet.size()));
}

std::vector<bluetooth::hci::Lap> const& LinkLayerController::ReadCurrentIacLap()
    const {
  return current_iac_lap_list_;
@@ -5287,6 +5486,8 @@ ErrorCode LinkLayerController::Disconnect(uint16_t handle,
    ASSERT(link_manager_remove_link(
        lm_.get(),
        reinterpret_cast<uint8_t(*)[6]>(remote.GetAddress().data())));
  } else {
    ASSERT(link_layer_remove_link(ll_.get(), handle));
  }
  return ErrorCode::SUCCESS;
}
@@ -5803,7 +6004,8 @@ void LinkLayerController::Reset() {
    page_timeout_task_id_ = kInvalidTaskId;
  }

  lm_.reset(link_manager_create(ops_));
  lm_.reset(link_manager_create(controller_ops_));
  ll_.reset(link_layer_create(controller_ops_));
}

void LinkLayerController::StartInquiry(milliseconds timeout) {
+13 −9
Original line number Diff line number Diff line
@@ -29,12 +29,7 @@
#include "model/controller/controller_properties.h"
#include "model/controller/le_advertiser.h"
#include "packets/link_layer_packets.h"

extern "C" {
struct LinkManager;
}

#include "lmp.h"
#include "rootcanal_rs.h"

namespace rootcanal {

@@ -82,6 +77,7 @@ class LinkLayerController {
  ErrorCode SendAclToRemote(bluetooth::hci::AclView acl_packet);

  void ForwardToLm(bluetooth::hci::CommandView command);
  void ForwardToLl(bluetooth::hci::CommandView command);

  std::vector<bluetooth::hci::Lap> const& ReadCurrentIacLap() const;
  void WriteCurrentIacLap(std::vector<bluetooth::hci::Lap> iac_lap);
@@ -581,7 +577,9 @@ class LinkLayerController {
  void IncomingInquiryResponsePacket(
      model::packets::LinkLayerPacketView incoming);
  void IncomingLmpPacket(model::packets::LinkLayerPacketView incoming);
  void IncomingIsoPacket(model::packets::LinkLayerPacketView incoming);
  void IncomingLlcpPacket(model::packets::LinkLayerPacketView incoming);
  void IncomingLeConnectedIsochronousPdu(
      model::packets::LinkLayerPacketView incoming);

  void ScanIncomingLeLegacyAdvertisingPdu(
      model::packets::LeLegacyAdvertisingPduView& pdu, uint8_t rssi);
@@ -1079,10 +1077,16 @@ class LinkLayerController {
  std::optional<Synchronizing> synchronizing_{};
  std::unordered_map<uint16_t, Synchronized> synchronized_{};

  // Classic state
  // Buffer to contain the ISO SDU sent from the host stack over HCI.
  // The SDU is forwarded to the peer only when complete.
  std::vector<uint8_t> iso_sdu_{};

  // Rust state.
  std::unique_ptr<const LinkManager, void (*)(const LinkManager*)> lm_;
  struct LinkManagerOps ops_;
  std::unique_ptr<const LinkLayer, void (*)(const LinkLayer*)> ll_;
  struct ControllerOps controller_ops_;

  // Classic state.
  TaskId page_timeout_task_id_ = kInvalidTaskId;

  std::chrono::steady_clock::time_point last_inquiry_;
+39 −39
Original line number Diff line number Diff line
@@ -656,7 +656,7 @@ enum OpCodeIndex : 16 {
  LE_READ_BUFFER_SIZE_V2 = 415,
  LE_READ_ISO_TX_SYNC = 416,
  LE_SET_CIG_PARAMETERS = 417,
  LE_SET_CIG_PARAMETERS_TEST = 418,
  LE_SET_CIG_PARAMETERS_TEST = 420,
  LE_CREATE_CIS = 421,
  LE_REMOVE_CIG = 422,
  LE_ACCEPT_CIS_REQUEST = 423,
@@ -4304,17 +4304,17 @@ packet LeReadIsoTxSyncComplete : CommandComplete (command_op_code = LE_READ_ISO_

struct CisParametersConfig {
  cis_id : 8,
  max_sdu_m_to_s : 12,
  max_sdu_c_to_p : 12,
  _reserved_ : 4,
  max_sdu_s_to_m : 12,
  max_sdu_p_to_c : 12,
  _reserved_ : 4,
  phy_m_to_s : 3,
  phy_c_to_p : 3,
  _reserved_ : 5,
  phy_s_to_m : 3,
  phy_p_to_c : 3,
  _reserved_ : 5,
  rtn_m_to_s : 4,
  rtn_c_to_p : 4,
  _reserved_ : 4,
  rtn_s_to_m : 4,
  rtn_p_to_c : 4,
  _reserved_ : 4,
}

@@ -4336,13 +4336,13 @@ enum ClockAccuracy : 8 {

packet LeSetCigParameters : Command (op_code = LE_SET_CIG_PARAMETERS) {
  cig_id : 8,
  sdu_interval_m_to_s : 24,
  sdu_interval_s_to_m : 24,
  peripherals_clock_accuracy : ClockAccuracy,
  sdu_interval_c_to_p : 24,
  sdu_interval_p_to_c : 24,
  worst_case_sca: ClockAccuracy,
  packing : Packing,
  framing : Enable,
  max_transport_latency_m_to_s : 16,
  max_transport_latency_s_to_m : 16,
  max_transport_latency_c_to_p : 16,
  max_transport_latency_p_to_c : 16,
  _count_(cis_config) : 8,
  cis_config : CisParametersConfig[],
}
@@ -4357,24 +4357,24 @@ packet LeSetCigParametersComplete : CommandComplete (command_op_code = LE_SET_CI
struct LeCisParametersTestConfig {
  cis_id : 8,
  nse : 8,
  max_sdu_m_to_s : 16,
  max_sdu_s_to_m : 16,
  max_pdu_m_to_s : 16,
  max_pdu_s_to_m : 16,
  phy_m_to_s : 8,
  phy_s_to_m : 8,
  bn_m_to_s : 8,
  bn_s_to_m : 8,
  max_sdu_c_to_p : 16,
  max_sdu_p_to_c : 16,
  max_pdu_c_to_p : 16,
  max_pdu_p_to_c : 16,
  phy_c_to_p : 8,
  phy_p_to_c : 8,
  bn_c_to_p : 8,
  bn_p_to_c : 8,
}

packet LeSetCigParametersTest : Command (op_code = LE_SET_CIG_PARAMETERS_TEST) {
  cig_id : 8,
  sdu_interval_m_to_s : 24,
  sdu_interval_s_to_m : 24,
  ft_m_to_s : 8,
  ft_s_to_m : 8,
  sdu_interval_c_to_p : 24,
  sdu_interval_p_to_c : 24,
  ft_c_to_p : 8,
  ft_p_to_c : 8,
  iso_interval : 16,
  peripherals_clock_accuracy : ClockAccuracy,
  worst_case_sca: ClockAccuracy,
  packing : Packing,
  framing : Enable,
  _count_(cis_config) : 8,
@@ -4388,7 +4388,7 @@ packet LeSetCigParametersTestComplete : CommandComplete (command_op_code = LE_SE
  connection_handle : 16[],
}

struct CreateCisConfig {
struct LeCreateCisConfig {
  cis_connection_handle : 12,
  _reserved_ : 4,
  acl_connection_handle : 12,
@@ -4397,7 +4397,7 @@ struct CreateCisConfig {

packet LeCreateCis : Command (op_code = LE_CREATE_CIS) {
  _count_(cis_config) : 8,
  cis_config : CreateCisConfig[],
  cis_config : LeCreateCisConfig[],
}

packet LeCreateCisStatus : CommandStatus (command_op_code = LE_CREATE_CIS) {
@@ -5868,20 +5868,20 @@ packet LeCisEstablished : LeMetaEvent (subevent_code = CIS_ESTABLISHED) {
  _reserved_ : 4,
  cig_sync_delay : 24,
  cis_sync_delay : 24,
  transport_latency_m_to_s : 24,
  transport_latency_s_to_m : 24,
  phy_m_to_s : SecondaryPhyType,
  phy_s_to_m : SecondaryPhyType,
  transport_latency_c_to_p : 24,
  transport_latency_p_to_c : 24,
  phy_c_to_p : SecondaryPhyType,
  phy_p_to_c : SecondaryPhyType,
  nse : 8,
  bn_m_to_s : 4,
  bn_c_to_p : 4,
  _reserved_ : 4,
  bn_s_to_m : 4,
  bn_p_to_c : 4,
  _reserved_ : 4,
  ft_m_to_s : 8,
  ft_s_to_m : 8,
  max_pdu_m_to_s : 8,
  ft_c_to_p : 8,
  ft_p_to_c : 8,
  max_pdu_c_to_p : 8,
  _reserved_ : 8,
  max_pdu_s_to_m : 8,
  max_pdu_p_to_c : 8,
  _reserved_ : 8,
  iso_interval : 16,
}
@@ -6191,7 +6191,7 @@ enum IsoPacketStatusFlag : 2 {
packet IsoWithTimestamp : Iso (ts_flag = PRESENT) {
  time_stamp : 32,
  packet_sequence_number : 16,
  _size_(_payload_) : 12, // iso_sdu_length
  iso_sdu_length : 12,
  _reserved_ : 2,
  packet_status_flag : IsoPacketStatusFlag,
  _payload_,
@@ -6199,7 +6199,7 @@ packet IsoWithTimestamp : Iso (ts_flag = PRESENT) {

packet IsoWithoutTimestamp : Iso (ts_flag = NOT_PRESENT) {
  packet_sequence_number : 16,
  _size_(_payload_) : 12, // iso_sdu_length
  iso_sdu_length : 12,
  _reserved_ : 2,
  packet_status_flag : IsoPacketStatusFlag,
  _payload_,
Loading