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

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

RootCanal: Split the controller properties

- Keep in ControllerProperties the static configuration options,
  that do not change for the lifetime of the controller instance
- Move the LinkLayerController the configuration options that
  are modified by user HCI commands

Test: manual
Change-Id: I78ed3f50064dd6cf5b5692e4d85c5a9701dde8af
parent 97914313
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4482,6 +4482,7 @@ packet LeRemoveIsoDataPathComplete : CommandComplete (command_op_code = LE_REMOV

enum LeHostFeatureBits : 8 {
  CONNECTED_ISO_STREAM_HOST_SUPPORT = 32,
  CONNECTION_SUBRATING_HOST_SUPPORT = 38,
}

packet LeSetHostFeature : Command (op_code = LE_SET_HOST_FEATURE) {
+267 −75
Original line number Diff line number Diff line
@@ -15,23 +15,212 @@

#include "controller_properties.h"

#include <json/json.h>

#include <fstream>
#include <limits>
#include <memory>

#include "json/json.h"
#include "os/log.h"
#include "osi/include/osi.h"

static void ParseUint8t(Json::Value value, uint8_t* field) {
  if (value.isString()) {
    *field = std::stoi(value.asString(), nullptr, 0);
namespace rootcanal {
using namespace bluetooth::hci;

static constexpr uint64_t Page0LmpFeatures() {
  LMPFeaturesPage0Bits features[] = {
      LMPFeaturesPage0Bits::LMP_3_SLOT_PACKETS,
      LMPFeaturesPage0Bits::LMP_5_SLOT_PACKETS,
      LMPFeaturesPage0Bits::ENCRYPTION,
      LMPFeaturesPage0Bits::SLOT_OFFSET,
      LMPFeaturesPage0Bits::TIMING_ACCURACY,
      LMPFeaturesPage0Bits::ROLE_SWITCH,
      LMPFeaturesPage0Bits::HOLD_MODE,
      LMPFeaturesPage0Bits::SNIFF_MODE,
      LMPFeaturesPage0Bits::POWER_CONTROL_REQUESTS,
      LMPFeaturesPage0Bits::CHANNEL_QUALITY_DRIVEN_DATA_RATE,
      LMPFeaturesPage0Bits::SCO_LINK,
      LMPFeaturesPage0Bits::HV2_PACKETS,
      LMPFeaturesPage0Bits::HV3_PACKETS,
      LMPFeaturesPage0Bits::M_LAW_LOG_SYNCHRONOUS_DATA,
      LMPFeaturesPage0Bits::A_LAW_LOG_SYNCHRONOUS_DATA,
      LMPFeaturesPage0Bits::CVSD_SYNCHRONOUS_DATA,
      LMPFeaturesPage0Bits::PAGING_PARAMETER_NEGOTIATION,
      LMPFeaturesPage0Bits::POWER_CONTROL,
      LMPFeaturesPage0Bits::TRANSPARENT_SYNCHRONOUS_DATA,
      LMPFeaturesPage0Bits::BROADCAST_ENCRYPTION,
      LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ACL_2_MB_S_MODE,
      LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ACL_3_MB_S_MODE,
      LMPFeaturesPage0Bits::ENHANCED_INQUIRY_SCAN,
      LMPFeaturesPage0Bits::INTERLACED_INQUIRY_SCAN,
      LMPFeaturesPage0Bits::INTERLACED_PAGE_SCAN,
      LMPFeaturesPage0Bits::RSSI_WITH_INQUIRY_RESULTS,
      LMPFeaturesPage0Bits::EXTENDED_SCO_LINK,
      LMPFeaturesPage0Bits::EV4_PACKETS,
      LMPFeaturesPage0Bits::EV5_PACKETS,
      LMPFeaturesPage0Bits::AFH_CAPABLE_PERIPHERAL,
      LMPFeaturesPage0Bits::AFH_CLASSIFICATION_PERIPHERAL,
      LMPFeaturesPage0Bits::LE_SUPPORTED_CONTROLLER,
      LMPFeaturesPage0Bits::LMP_3_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS,
      LMPFeaturesPage0Bits::LMP_5_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS,
      LMPFeaturesPage0Bits::SNIFF_SUBRATING,
      LMPFeaturesPage0Bits::PAUSE_ENCRYPTION,
      LMPFeaturesPage0Bits::AFH_CAPABLE_CENTRAL,
      LMPFeaturesPage0Bits::AFH_CLASSIFICATION_CENTRAL,
      LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ESCO_2_MB_S_MODE,
      LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ESCO_3_MB_S_MODE,
      LMPFeaturesPage0Bits::LMP_3_SLOT_ENHANCED_DATA_RATE_ESCO_PACKETS,
      LMPFeaturesPage0Bits::EXTENDED_INQUIRY_RESPONSE,
      LMPFeaturesPage0Bits::SIMULTANEOUS_LE_AND_BR_CONTROLLER,
      LMPFeaturesPage0Bits::SECURE_SIMPLE_PAIRING_CONTROLLER,
      LMPFeaturesPage0Bits::ENCAPSULATED_PDU,
      LMPFeaturesPage0Bits::HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT,
      LMPFeaturesPage0Bits::VARIABLE_INQUIRY_TX_POWER_LEVEL,
      LMPFeaturesPage0Bits::ENHANCED_POWER_CONTROL,
      LMPFeaturesPage0Bits::EXTENDED_FEATURES};

  uint64_t value = 0;
  for (auto feature : features) {
    value |= static_cast<uint64_t>(feature);
  }
  return value;
}

static constexpr uint64_t Page1LmpFeatures() {
  LMPFeaturesPage1Bits features[] = {
      LMPFeaturesPage1Bits::SIMULTANEOUS_LE_AND_BR_HOST,
  };

  uint64_t value = 0;
  for (auto feature : features) {
    value |= static_cast<uint64_t>(feature);
  }
  return value;
}

static constexpr uint64_t Page2LmpFeatures() {
  LMPFeaturesPage2Bits features[] = {
      LMPFeaturesPage2Bits::SECURE_CONNECTIONS_CONTROLLER_SUPPORT,
  };

  uint64_t value = 0;
  for (auto feature : features) {
    value |= static_cast<uint64_t>(feature);
  }
  return value;
}

static constexpr uint64_t LlFeatures() {
  LLFeaturesBits features[] = {
      LLFeaturesBits::LE_ENCRYPTION,
      LLFeaturesBits::CONNECTION_PARAMETERS_REQUEST_PROCEDURE,
      LLFeaturesBits::EXTENDED_REJECT_INDICATION,
      LLFeaturesBits::PERIPHERAL_INITIATED_FEATURES_EXCHANGE,
      LLFeaturesBits::LE_PING,

      LLFeaturesBits::EXTENDED_SCANNER_FILTER_POLICIES,
      LLFeaturesBits::LE_EXTENDED_ADVERTISING,

      // TODO: breaks AVD boot tests with LE audio
      // LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_CENTRAL,
      // LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL,
  };

  uint64_t value = 0;
  for (auto feature : features) {
    value |= static_cast<uint64_t>(feature);
  }
  return value;
}

static void ParseUint16t(Json::Value value, uint16_t* field) {
template <typename T>
static bool ParseUint(Json::Value root, std::string field_name,
                      T& output_value) {
  T max_value = std::numeric_limits<T>::max();
  Json::Value value = root[field_name];

  if (value.isString()) {
    *field = std::stoi(value.asString(), nullptr, 0);
    unsigned long long parsed_value = std::stoull(value.asString(), nullptr, 0);
    if (parsed_value > max_value) {
      LOG_INFO("invalid value for %s is discarded: %llu > %llu",
               field_name.c_str(), parsed_value,
               static_cast<unsigned long long>(max_value));
      return false;
    } else {
      output_value = static_cast<T>(parsed_value);
      return true;
    }
  }

  return false;
}

template <typename T, std::size_t N>
static bool ParseUintArray(Json::Value root, std::string field_name,
                           std::array<T, N>& output_value) {
  T max_value = std::numeric_limits<T>::max();
  Json::Value value = root[field_name];

  if (value.empty()) {
    return false;
  }

  if (!value.isArray()) {
    LOG_INFO("invalid value for %s is discarded: not an array",
             field_name.c_str());
    return false;
  }

  if (value.size() != N) {
    LOG_INFO(
        "invalid value for %s is discarded: incorrect size %u, expected %zu",
        field_name.c_str(), value.size(), N);
    return false;
  }

  for (size_t n = 0; n < N; n++) {
    unsigned long long parsed_value = std::stoull(value.asString(), nullptr, 0);
    if (parsed_value > max_value) {
      LOG_INFO("invalid value for %s[%zu] is discarded: %llu > %llu",
               field_name.c_str(), n, parsed_value,
               static_cast<unsigned long long>(max_value));
    } else {
      output_value[n] = parsed_value;
    }
  }

  return false;
}

template <typename T>
static bool ParseUintVector(Json::Value root, std::string field_name,
                            std::vector<T>& output_value) {
  T max_value = std::numeric_limits<T>::max();
  Json::Value value = root[field_name];

  if (value.empty()) {
    return false;
  }

  if (!value.isArray()) {
    LOG_INFO("invalid value for %s is discarded: not an array",
             field_name.c_str());
    return false;
  }

  output_value.clear();
  for (size_t n = 0; n < value.size(); n++) {
    unsigned long long parsed_value = std::stoull(value.asString(), nullptr, 0);
    if (parsed_value > max_value) {
      LOG_INFO("invalid value for %s[%zu] is discarded: %llu > %llu",
               field_name.c_str(), n, parsed_value,
               static_cast<unsigned long long>(max_value));
    } else {
      output_value.push_back(parsed_value);
    }
  }

  return false;
}

static void ParseHex64(Json::Value value, uint64_t* field) {
@@ -44,37 +233,21 @@ static void ParseHex64(Json::Value value, uint64_t* field) {
  }
}

namespace rootcanal {

ControllerProperties::ControllerProperties(const std::string& file_name)
    : acl_data_packet_size_(1024),
      sco_data_packet_size_(255),
      num_acl_data_packets_(10),
      num_sco_data_packets_(10),
      version_(static_cast<uint8_t>(bluetooth::hci::HciVersion::V_5_3)),
      revision_(0),
      lmp_pal_version_(static_cast<uint8_t>(bluetooth::hci::LmpVersion::V_5_3)),
      manufacturer_name_(0),
      lmp_pal_subversion_(0),
      le_data_packet_length_(27),
      num_le_data_packets_(20),
      le_connect_list_size_(15),
      le_resolving_list_size_(15) {
  std::string properties_raw;

  ASSERT(Address::FromString("BB:BB:BB:BB:AD:1E", le_address_));
  name_ = {'D', 'e', 'f', 'a', 'u', 'l', 't'};

  supported_codecs_ = {0};  // Only SBC is supported.
  vendor_specific_codecs_ = {};

  for (int i = 0; i < 35; i++) supported_commands_[i] = 0xff;
  // Mark HCI_LE_Transmitter_Test[v2] and newer commands as unsupported
  // Use SetSupportedComands() to change what's supported.
  for (int i = 35; i < 64; i++) supported_commands_[i] = 0x00;

  le_supported_states_ = 0x3ffffffffff;
  le_vendor_cap_ = {};
    : lmp_features(
          {Page0LmpFeatures(), Page1LmpFeatures(), Page2LmpFeatures()}),
      le_features(LlFeatures()) {
  // Set support for all HCI commands by default.
  // The controller will update the mask with its implemented commands
  // after the creation of the properties.
  for (int i = 0; i < 47; i++) {
    supported_commands[i] = 0xff;
  }

  // Mark reserved commands as unsupported.
  for (int i = 47; i < 64; i++) {
    supported_commands[i] = 0x00;
  }

  if (file_name.empty()) {
    return;
@@ -94,49 +267,68 @@ ControllerProperties::ControllerProperties(const std::string& file_name)
    return;
  }

  ParseUint16t(root["AclDataPacketSize"], &acl_data_packet_size_);
  ParseUint8t(root["ScoDataPacketSize"], &sco_data_packet_size_);
  ParseUint8t(root["EncryptionKeySize"], &encryption_key_size_);
  ParseUint16t(root["NumAclDataPackets"], &num_acl_data_packets_);
  ParseUint16t(root["NumScoDataPackets"], &num_sco_data_packets_);
  ParseUint8t(root["Version"], &version_);
  ParseUint16t(root["Revision"], &revision_);
  ParseUint8t(root["LmpPalVersion"], &lmp_pal_version_);
  ParseUint16t(root["ManufacturerName"], &manufacturer_name_);
  ParseUint16t(root["LmpPalSubversion"], &lmp_pal_subversion_);
  Json::Value supported_commands = root["supported_commands"];
  if (!supported_commands.empty()) {
    use_supported_commands_from_file_ = true;
    for (unsigned i = 0; i < supported_commands.size(); i++) {
      std::string out = supported_commands[i].asString();
      uint8_t number = stoi(out, nullptr, 16);
      supported_commands_[i] = number;
    }
  }
  ParseHex64(root["LeSupportedFeatures"], &le_supported_features_);
  ParseUint16t(root["LeConnectListIgnoreReasons"],
               &le_connect_list_ignore_reasons_);
  ParseUint16t(root["LeResolvingListIgnoreReasons"],
               &le_resolving_list_ignore_reasons_);
}

bool ControllerProperties::SetLeHostFeature(uint8_t bit_number, uint8_t bit_value) {
  if (bit_number >= 64 || bit_value > 1) return false;

  uint64_t bit_mask = UINT64_C(1) << bit_number;
  if (bit_mask !=
          static_cast<uint64_t>(
              LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_HOST_SUPPORT) &&
      bit_mask != static_cast<uint64_t>(
                      LLFeaturesBits::CONNECTION_SUBRATING_HOST_SUPPORT))
    return false;
  // Legacy configuration options.

  if (bit_value == 0)
    le_supported_features_ &= ~bit_mask;
  else if (bit_value == 1)
    le_supported_features_ |= bit_mask;
  ParseUint(root, "AclDataPacketSize", acl_data_packet_length);
  ParseUint(root, "ScoDataPacketSize", sco_data_packet_length);
  ParseUint(root, "NumAclDataPackets", total_num_acl_data_packets);
  ParseUint(root, "NumScoDataPackets", total_num_sco_data_packets);

  return true;
  uint8_t hci_version = static_cast<uint8_t>(this->hci_version);
  uint8_t lmp_version = static_cast<uint8_t>(this->lmp_version);
  ParseUint(root, "Version", hci_version);
  ParseUint(root, "Revision", hci_subversion);
  ParseUint(root, "LmpPalVersion", lmp_version);
  ParseUint(root, "LmpPalSubversion", lmp_subversion);
  ParseUint(root, "ManufacturerName", company_identifier);

  ParseHex64(root["LeSupportedFeatures"], &le_features);
  ParseUint(root, "LeConnectListIgnoreReasons", le_connect_list_ignore_reasons);
  ParseUint(root, "LeResolvingListIgnoreReasons",
            le_resolving_list_ignore_reasons);

  // Configuration options.

  ParseUint(root, "hci_version", hci_version);
  ParseUint(root, "lmp_version", lmp_version);
  ParseUint(root, "hci_subversion", hci_subversion);
  ParseUint(root, "lmp_subversion", lmp_subversion);
  ParseUint(root, "company_identifier", company_identifier);

  ParseUintArray(root, "supported_commands", supported_commands);
  ParseUintArray(root, "lmp_features", lmp_features);
  ParseUint(root, "le_features", le_features);

  ParseUint(root, "acl_data_packet_length", acl_data_packet_length);
  ParseUint(root, "sco_data_packet_length ", sco_data_packet_length);
  ParseUint(root, "total_num_acl_data_packets ", total_num_acl_data_packets);
  ParseUint(root, "total_num_sco_data_packets ", total_num_sco_data_packets);
  ParseUint(root, "le_acl_data_packet_length ", le_acl_data_packet_length);
  ParseUint(root, "iso_data_packet_length ", iso_data_packet_length);
  ParseUint(root, "total_num_le_acl_data_packets ",
            total_num_le_acl_data_packets);
  ParseUint(root, "total_num_iso_data_packets ", total_num_iso_data_packets);

  ParseUintArray(root, "lmp_features", lmp_features);
  ParseUintVector(root, "supported_standard_codecs", supported_standard_codecs);
  ParseUintVector(root, "supported_vendor_specific_codecs",
                  supported_vendor_specific_codecs);

  ParseUint(root, "le_filter_accept_list_size", le_filter_accept_list_size);
  ParseUint(root, "le_resolving_list_size", le_resolving_list_size);
  ParseUint(root, "le_supported_states", le_supported_states);

  ParseUintVector(root, "le_vendor_capabilities", le_vendor_capabilities);

  this->hci_version = static_cast<HciVersion>(hci_version);
  this->lmp_version = static_cast<LmpVersion>(lmp_version);
}

void ControllerProperties::SetSupportedCommands(
    std::array<uint8_t, 64> supported_commands) {
  for (size_t i = 0; i < this->supported_commands.size(); i++) {
    this->supported_commands[i] &= supported_commands[i];
  }
}

}  // namespace rootcanal
+58 −462

File changed.

Preview size limit exceeded, changes collapsed.

+78 −91

File changed.

Preview size limit exceeded, changes collapsed.

+254 −158

File changed.

Preview size limit exceeded, changes collapsed.

Loading