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

Commit bf009322 authored by Myles Watson's avatar Myles Watson Committed by Gerrit Code Review
Browse files

Merge changes from topic "msft_module_pdl"

* changes:
  PDL: MsftReadSupportedFeaturesCommandComplete
  PDL: Define MSFT packets in PDL
parents 6f0caa72 9f97bb50
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -43,3 +43,32 @@ source_set("BluetoothHciSources") {

  configs += [ "//bt/system:target_defaults" ]
}

if (use.test) {
  executable("hci_tests") {
    sources = [
      "hci_packets_test.cc",
    ]

    include_dirs = [ "//bt/system/gd" ]

    deps = [
      "//bt/system/main:bluetooth-static",
    ]

    configs += [
      "//bt/system:target_defaults",
      "//bt/system:external_gtest_main",
    ]

    libs = [
      "pthread",
      "rt",
      "dl",
    ]

    ldflags = [
      "-lpthread"
    ]
  }
}
+7 −0
Original line number Diff line number Diff line
@@ -882,6 +882,13 @@ struct Controller::impl {
        return vendor_capabilities_.a2dp_source_offload_capability_mask_ != 0x00;
      case OpCode::CONTROLLER_BQR:
        return vendor_capabilities_.bluetooth_quality_report_support_ == 0x01;
      // Before MSFT extension is fully supported, return false for the following MSFT_OPCODE_XXXX for now.
      case OpCode::MSFT_OPCODE_INTEL:
        return false;
      case OpCode::MSFT_OPCODE_MEDIATEK:
        return false;
      case OpCode::MSFT_OPCODE_QUALCOMM:
        return false;
      // undefined in local_supported_commands_
      case OpCode::READ_LOCAL_SUPPORTED_COMMANDS:
        return true;
+176 −0
Original line number Diff line number Diff line
@@ -387,6 +387,8 @@ enum OpCode : 16 {
  LE_SUBRATE_REQUEST = 0x207E,

  // VENDOR_SPECIFIC
  // MSFT_OPCODE_xxxx below is needed for the tests.
  MSFT_OPCODE_INTEL = 0xFC1E,
  LE_GET_VENDOR_CAPABILITIES = 0xFD53,
  LE_MULTI_ADVT = 0xFD54,
  LE_BATCH_SCAN = 0xFD56,
@@ -396,6 +398,9 @@ enum OpCode : 16 {
  CONTROLLER_DEBUG_INFO = 0xFD5B,
  CONTROLLER_A2DP_OPCODE = 0xFD5D,
  CONTROLLER_BQR = 0xFD5E,
  // MSFT_OPCODE_xxxx below are needed for the tests.
  MSFT_OPCODE_MEDIATEK = 0xFD30,
  MSFT_OPCODE_QUALCOMM = 0xFD70,
}

// For mapping Local Supported Commands command
@@ -6261,3 +6266,174 @@ packet IsoWithoutTimestamp : Iso (ts_flag = NOT_PRESENT) {
  packet_status_flag : IsoPacketStatusFlag,
  _payload_,
}

// MSFT packets
// Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events

enum MsftSubcommandOpcode : 8 {
  MSFT_READ_SUPPORTED_FEATURES = 0x00,
  MSFT_MONITOR_RSSI = 0x01,
  MSFT_CANCEL_MONITOR_RSSI = 0x02,
  MSFT_LE_MONITOR_ADV = 0x03,
  MSFT_LE_CANCEL_MONITOR_ADV = 0x04,
  MSFT_LE_SET_ADV_FILTER_ENABLE = 0x05,
  MSFT_READ_ABSOLUTE_RSSI = 0x06,
}

// MSFT Commands don't have a constant opcode, so leave `op_code` undefined.
packet MsftCommand : Command {
  subcommand_opcode: MsftSubcommandOpcode,
  _payload_,
}

packet MsftReadSupportedFeatures : MsftCommand (subcommand_opcode = MSFT_READ_SUPPORTED_FEATURES) {}

enum MsftLeMonitorAdvConditionType : 8 {
  MSFT_CONDITION_TYPE_PATTERNS = 0x01,
  MSFT_CONDITION_TYPE_UUID = 0x02,
  MSFT_CONDITION_TYPE_IRK_RESOLUTION = 0x03,
  MSFT_CONDITION_TYPE_ADDRESS = 0x04,
}

enum MsftLeMonitorAdvConditionUuidType : 8 {
  MSFT_CONDITION_UUID_TYPE_16_BIT = 0x01,
  MSFT_CONDITION_UUID_TYPE_32_BIT = 0x02,
  MSFT_CONDITION_UUID_TYPE_128_BIT = 0x03,
}

packet MsftLeMonitorAdv : MsftCommand (subcommand_opcode = MSFT_LE_MONITOR_ADV) {
  rssi_threshold_high : 8,
  rssi_threshold_low : 8,
  rssi_threshold_low_time_interval : 8,
  rssi_sampling_period : 8,
  condition_type: MsftLeMonitorAdvConditionType,
  _payload_,
}

struct MsftLeMonitorAdvConditionPattern {
  _size_(pattern) : 8, // including one byte for ad_type and one byte for start_of_pattern
  ad_type: 8,
  start_of_pattern: 8,
  pattern: 8[+2],
}

packet MsftLeMonitorAdvConditionPatterns : MsftLeMonitorAdv (condition_type = MSFT_CONDITION_TYPE_PATTERNS) {
  _count_(patterns): 8,
  patterns: MsftLeMonitorAdvConditionPattern[],
}

test MsftLeMonitorAdvConditionPatterns {
  "\x1e\xfc\x0e\x03\x10\x05\x04\xaa\x01\x01\x06\x03\x00\x80\x81\x82\x83", // 1 pattern
  "\x70\xfd\x13\x03\x15\x04\x02\xbb\x01\x02\x04\x03\x00\x80\x81\x06\x0f\x00\x90\x91\x92\x93", // 2 patterns
}

packet MsftLeMonitorAdvConditionUuid : MsftLeMonitorAdv (condition_type = MSFT_CONDITION_TYPE_UUID) {
  uuid_type: MsftLeMonitorAdvConditionUuidType,
  _payload_,
}

packet MsftLeMonitorAdvConditionUuid2 : MsftLeMonitorAdvConditionUuid (uuid_type = MSFT_CONDITION_UUID_TYPE_16_BIT) {
  uuid2: 8[2],
}

test MsftLeMonitorAdvConditionUuid2 {
  "\x1e\xfc\x09\x03\x10\x11\x12\x13\x02\x01\x70\x71", // opcode = fc1e for Intel
  "\x70\xfd\x09\x03\x10\x11\x12\x13\x02\x01\x70\x71", // opcode = fd70 for Qualcomm
}

packet MsftLeMonitorAdvConditionUuid4 : MsftLeMonitorAdvConditionUuid (uuid_type = MSFT_CONDITION_UUID_TYPE_32_BIT) {
  uuid4: 8[4],
}

test MsftLeMonitorAdvConditionUuid4 {
  "\x1e\xfc\x0b\x03\x10\x11\x12\x13\x02\x02\x70\x71\x72\x73",
  "\x70\xfd\x0b\x03\x10\x11\x12\x13\x02\x02\x70\x71\x72\x73",
}

packet MsftLeMonitorAdvConditionUuid16 : MsftLeMonitorAdvConditionUuid (uuid_type = MSFT_CONDITION_UUID_TYPE_128_BIT) {
  uuid16: 8[16],
}

test MsftLeMonitorAdvConditionUuid16 {
  "\x1e\xfc\x17\x03\x10\x11\x12\x13\x02\x03\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
  "\x70\xfd\x17\x03\x10\x11\x12\x13\x02\x03\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
}

packet MsftLeSetAdvFilterEnable : MsftCommand (subcommand_opcode = MSFT_LE_SET_ADV_FILTER_ENABLE) {
  enable: 8,
}

test MsftLeSetAdvFilterEnable {
  "\x1e\xfc\x02\x05\x01", // disable
  "\x70\xfd\x02\x05\x01", // enable
}

packet MsftCommandComplete : CommandComplete {
  status: ErrorCode,
  subcommand_opcode: MsftSubcommandOpcode,
  _payload_,
}

packet MsftReadSupportedFeaturesCommandComplete : MsftCommandComplete (subcommand_opcode = MSFT_READ_SUPPORTED_FEATURES) {
  supported_features: 64,
  _size_(prefix) : 8,
  prefix: 8[],
}

test MsftReadSupportedFeaturesCommandComplete {
  "\x0e\x10\x01\x1e\xfc\x00\x00\x7f\x00\x00\x00\x00\x00\x00\x00\x02\x87\x80", // Msft opcode by Intel
  "\x0e\x12\x01\x70\xfd\x00\x00\x1f\x00\x00\x00\x00\x00\x00\x00\x04\x4d\x53\x46\x54", // Msft opcode by Qualcomm
}

packet MsftLeMonitorAdvCommandComplete : MsftCommandComplete (subcommand_opcode = MSFT_LE_MONITOR_ADV) {
  monitor_handle: 8,
}

test MsftLeMonitorAdvCommandComplete {
  "\x0e\x06\x01\x1e\xfc\x00\x03\x05", // succeeded
  "\x0e\x06\x01\x70\xfd\x01\x03\x06", // failed
}

packet MsftLeSetAdvFilterEnableCommandComplete : MsftCommandComplete (subcommand_opcode = MSFT_LE_SET_ADV_FILTER_ENABLE) {}

enum MsftEventCode : 8 {
  MSFT_RSSI_EVENT = 0x01,
  MSFT_LE_MONITOR_DEVICE_EVENT = 0x02,
}

enum MsftEventStatus : 8 {
  MSFT_EVENT_STATUS_SUCCESS = 0x00,
  MSFT_EVENT_STATUS_FAILURE = 0x01,
}

// It is not possible to define MSFT Event packet by deriving `Event` packet
// because it starts with variable-length event prefix which can only be determined
// at run-time (after receiving return of MSFT Read Supported Features).
// Therefore we only define the payload which is located after the event prefix.
packet MsftEventPayload {
  msft_event_code : MsftEventCode,
  _payload_,
}

packet MsftRssiEventPayload : MsftEventPayload (msft_event_code = MSFT_RSSI_EVENT) {
  status: MsftEventStatus,
  connection_handle: 16,
  rssi: 8,
}

test MsftRssiEventPayload {
  "\x01\x00\x01\x10\xf0", // MSFT_RSSI_EVENT succeeded
  "\x01\x01\x02\x02\x08", // MSFT_RSSI_EVENT failed
}

packet MsftLeMonitorDeviceEventPayload : MsftEventPayload (msft_event_code = MSFT_LE_MONITOR_DEVICE_EVENT) {
  address_type: 8,
  bd_addr: 48,
  monitor_handle: 8,
  monitor_state: 8,
}

test MsftLeMonitorDeviceEventPayload {
  "\x02\x01\x00\x01\x02\x03\x04\x05\x10\x00",
  "\x02\x02\xf0\xf1\xf2\xf3\xf4\xf5\xaa\x02",
}
+182 −1
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@
#include "packet/raw_builder.h"

using bluetooth::packet::BitInserter;
using bluetooth::packet::RawBuilder;
using std::vector;

namespace bluetooth {
@@ -444,5 +443,187 @@ TEST(HciPacketsTest, testLeMultiAdvSetScanResponseDataBuilderLength) {
  ASSERT_EQ(view.GetAdvertisingInstance(), 3);
}

TEST(HciPacketsTest, testMsftReadSupportedFeatures) {
  // MSFT opcode is not defined in PDL.
  auto msft_opcode = static_cast<OpCode>(0xfc01);

  auto builder = MsftReadSupportedFeaturesBuilder::Create(msft_opcode);

  auto packet_bytes = std::make_shared<std::vector<uint8_t>>();
  packet_bytes->reserve(builder->size());
  BitInserter bit_inserter(*packet_bytes);
  builder->Serialize(bit_inserter);

  std::vector<uint8_t> expected_bytes{
      0x01,  // Vendor command opcode and MSFT base code.
      0xfc,
      0x01,  // Packet length
      0x00,  // Subcommand Opcode for Read Supported Features
  };
  ASSERT_EQ(expected_bytes, *packet_bytes);
}

TEST(HciPacketsTest, testMsftLeMonitorAdvUuid) {
  // MSFT opcode is not defined in PDL.
  auto msft_opcode = static_cast<OpCode>(0xfc01);

  auto builder = MsftLeMonitorAdvConditionUuid2Builder::Create(
      msft_opcode,
      0x10 /* RSSI threshold high */,
      0x11 /* RSSI threshold low */,
      0x12 /* RSSI threshold low timeout */,
      0x13 /* RSSI sampling period */,
      std::array<uint8_t, 2>{0x71, 0x72} /* 16-bit UUID */);

  auto packet_bytes = std::make_shared<std::vector<uint8_t>>();
  packet_bytes->reserve(builder->size());
  BitInserter bit_inserter(*packet_bytes);
  builder->Serialize(bit_inserter);

  std::vector<uint8_t> expected_bytes{
      0x01,  // Vendor command opcode and MSFT base code.
      0xfc,
      0x09,  // Packet length
      0x03,  // Subcommand Opcode for LE Monitor Adv
      0x10,  // RSSI threshold high
      0x11,  // RSSI threshold low
      0x12,  // RSSI threshold low timeout
      0x13,  // RSSI sampling period
      0x02,  // Condition type = UUID
      0x01,  // UUID type = 16-bit UUID
      0x71,  // UUID content
      0x72,
  };
  ASSERT_EQ(expected_bytes, *packet_bytes);
}

TEST(HciPacketsTest, testMsftLeMonitorAdvPatternsEmpty) {
  // MSFT opcode is not defined in PDL.
  auto msft_opcode = static_cast<OpCode>(0xfc01);

  std::vector<MsftLeMonitorAdvConditionPattern> patterns;

  auto builder = MsftLeMonitorAdvConditionPatternsBuilder::Create(
      msft_opcode,
      0x10 /* RSSI threshold high */,
      0x11 /* RSSI threshold low */,
      0x12 /* RSSI threshold low timeout */,
      0x13 /* RSSI sampling period */,
      patterns);

  auto packet_bytes = std::make_shared<std::vector<uint8_t>>();
  packet_bytes->reserve(builder->size());
  BitInserter bit_inserter(*packet_bytes);
  builder->Serialize(bit_inserter);

  std::vector<uint8_t> expected_bytes{
      0x01,  // Vendor command opcode and MSFT base code.
      0xfc,
      0x07,  // Packet length
      0x03,  // Subcommand Opcode for LE Monitor Adv
      0x10,  // RSSI threshold high
      0x11,  // RSSI threshold low
      0x12,  // RSSI threshold low timeout
      0x13,  // RSSI sampling period
      0x01,  // Condition type = Patterns
      0x00,  // Number of patterns
  };
  ASSERT_EQ(expected_bytes, *packet_bytes);
}

TEST(HciPacketsTest, testMsftLeMonitorAdvPatterns) {
  // MSFT opcode is not defined in PDL.
  auto msft_opcode = static_cast<OpCode>(0xfc01);

  MsftLeMonitorAdvConditionPattern pattern1;
  pattern1.ad_type_ = 0x03;
  pattern1.start_of_pattern_ = 0x00;
  pattern1.pattern_ = {1, 2, 3};

  MsftLeMonitorAdvConditionPattern pattern2;
  pattern2.ad_type_ = 0x0f;
  pattern2.start_of_pattern_ = 0x10;
  pattern2.pattern_ = {0xa1, 0xa2};

  std::vector<MsftLeMonitorAdvConditionPattern> patterns{pattern1, pattern2};

  auto builder = MsftLeMonitorAdvConditionPatternsBuilder::Create(
      msft_opcode,
      0x10 /* RSSI threshold high */,
      0x11 /* RSSI threshold low */,
      0x12 /* RSSI threshold low timeout */,
      0x13 /* RSSI sampling period */,
      patterns);

  auto packet_bytes = std::make_shared<std::vector<uint8_t>>();
  packet_bytes->reserve(builder->size());
  BitInserter bit_inserter(*packet_bytes);
  builder->Serialize(bit_inserter);

  std::vector<uint8_t> expected_bytes{
      0x01,  // Vendor command opcode and MSFT base code.
      0xfc,
      0x12,  // Packet length
      0x03,  // Subcommand Opcode for LE Monitor Adv
      0x10,  // RSSI threshold high
      0x11,  // RSSI threshold low
      0x12,  // RSSI threshold low timeout
      0x13,  // RSSI sampling period
      0x01,  // Condition type = Patterns
      0x02,  // Number of patterns
      // Pattern 1
      0x05,  // Length
      0x03,  // AD Type
      0x00,  // Start of pattern
      0x01,  // Pattern
      0x02,
      0x03,
      // Pattern 2
      0x04,  // Length
      0x0f,  // AD Type
      0x10,  // Start of pattern
      0xa1,  // Pattern
      0xa2,
  };
  ASSERT_EQ(expected_bytes, *packet_bytes);
}

std::vector<uint8_t> msft_read_supported_features_complete{
    0x0e,  // command complete event code
    0x10,  // event size
    0x01,  // num_hci_command_packets
    0x1e,
    0xfc,  // vendor specific MSFT opcode assigned by Intel
    0x00,  // status
    0x00,  // MSFT subcommand opcode
    0x7f,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,  // supported features
    0x02,  // MSFT event prefix length
    0x87,
    0x80,  // prefix: MSFT event prefix provided by Intel
};
TEST(HciPacketsTest, testMsftReadSupportedFeaturesComplete) {
  PacketView<kLittleEndian> packet_bytes_view(
      std::make_shared<std::vector<uint8_t>>(msft_read_supported_features_complete));
  auto view = MsftReadSupportedFeaturesCommandCompleteView::Create(
      MsftCommandCompleteView::Create(CommandCompleteView::Create(EventView::Create(packet_bytes_view))));

  ASSERT_TRUE(view.IsValid());
  ASSERT_EQ(ErrorCode::SUCCESS, view.GetStatus());
  ASSERT_EQ((uint8_t)0x00, (uint8_t)view.GetSubcommandOpcode());
  ASSERT_EQ((uint64_t)0x000000000000007f, view.GetSupportedFeatures());
  ASSERT_EQ(2ul, view.GetPrefix().size());

  uint16_t prefix = 0;
  for (auto p : view.GetPrefix()) prefix = (prefix << 8) + p;
  ASSERT_EQ((uint16_t)0x8780, prefix);
}

}  // namespace hci
}  // namespace bluetooth
+0 −1
Original line number Diff line number Diff line
@@ -115,7 +115,6 @@ target(lib_type, "bluetooth") {
    "resolv",
    "rt",
    "z",
    "bt_shim_ffi",
  ]

  lib_dirs = [ "${root_out_dir}/rust" ]