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

Commit fe57e5d2 authored by Henri Chataing's avatar Henri Chataing Committed by Thomas Girardier
Browse files

RootCanal: Implement the CSR Vendor command

The CSR Vendor command multiplexes the four
functions read_varid, write_varid, read_pskey, write_pskey
which are being used by the PTS to configure the dongle
before starting the tests.

Bug: 245578454
Test: atest pts-bot:HFP
Ignore-AOSP-First: Cherry-picked from AOSP
Merged-In: I5c2ff2db404931e2d4bfb85adad49b80c34b622e
Change-Id: I5c2ff2db404931e2d4bfb85adad49b80c34b622e
parent eca4f3a5
Loading
Loading
Loading
Loading
+174 −0
Original line number Diff line number Diff line
@@ -94,6 +94,10 @@ DualModeController::DualModeController(const std::string& properties_filename,
    method(std::move(param));                                      \
  };

#define SET_VENDOR_HANDLER(op_code, method)                            \
  active_hci_commands_[static_cast<bluetooth::hci::OpCode>(op_code)] = \
      [this](CommandView param) { method(std::move(param)); };

#define SET_SUPPORTED(name, method)                                        \
  SET_HANDLER(name, method);                                               \
  {                                                                        \
@@ -235,6 +239,7 @@ DualModeController::DualModeController(const std::string& properties_filename,
  SET_SUPPORTED(LE_RAND, LeRand);
  SET_SUPPORTED(LE_READ_SUPPORTED_STATES, LeReadSupportedStates);
  SET_HANDLER(LE_GET_VENDOR_CAPABILITIES, LeVendorCap);
  SET_VENDOR_HANDLER(CSR_VENDOR, CsrVendorCommand);
  SET_HANDLER(LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY,
              LeRemoteConnectionParameterRequestReply);
  SET_HANDLER(LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY,
@@ -2711,6 +2716,175 @@ void DualModeController::LeEnergyInfo(CommandView command) {
      static_cast<uint16_t>(OpCode::LE_ENERGY_INFO));
}

// CSR vendor command.
// Implement the command specific to the CSR controller
// used specifically by the PTS tool to pass certification tests.
void DualModeController::CsrVendorCommand(CommandView command) {
  // The byte order is little endian.
  // The command parameters are formatted as
  //
  //  00    | 0xc2
  //  01 02 | action
  //          read = 0
  //          write = 2
  //  03 04 | (value length / 2) + 5
  //  04 05 | sequence number
  //  06 07 | varid
  //  08 09 | 00 00
  //  0a .. | value
  //
  // BlueZ has a reference implementation of the CSR vendor command.

  std::vector<uint8_t> parameters(command.GetPayload().begin(),
                                  command.GetPayload().end());

  uint16_t type = 0;
  uint16_t length = 0;
  uint16_t varid = 0;

  if (parameters.size() == 0) {
    LOG_INFO("Empty CSR vendor command");
    goto complete;
  }

  if (parameters[0] != 0xc2 || parameters.size() < 11) {
    LOG_INFO(
        "Unsupported CSR vendor command with code %02x "
        "and parameter length %zu",
        static_cast<int>(parameters[0]), parameters.size());
    goto complete;
  }

  type = (uint16_t)parameters[1] | ((uint16_t)parameters[2] << 8);
  length = (uint16_t)parameters[3] | ((uint16_t)parameters[4] << 8);
  varid = (uint16_t)parameters[7] | ((uint16_t)parameters[8] << 8);
  length = 2 * (length - 5);

  if (parameters.size() < (11 + length) ||
      (varid == CsrVarid::CSR_VARID_PS && length < 6)) {
    LOG_INFO("Invalid CSR vendor command parameter length %zu, expected %u",
             parameters.size(), 11 + length);
    goto complete;
  }

  if (varid == CsrVarid::CSR_VARID_PS) {
    // Subcommand to read or write PSKEY of the selected identifier
    // instead of VARID.
    uint16_t pskey = (uint16_t)parameters[11] | ((uint16_t)parameters[12] << 8);
    uint16_t length =
        (uint16_t)parameters[13] | ((uint16_t)parameters[14] << 8);
    length = 2 * length;

    if (parameters.size() < (17 + length)) {
      LOG_INFO("Invalid CSR vendor command parameter length %zu, expected %u",
               parameters.size(), 17 + length);
      goto complete;
    }

    std::vector<uint8_t> value(parameters.begin() + 17,
                               parameters.begin() + 17 + length);

    LOG_INFO("CSR vendor command type=%04x length=%04x pskey=%04x", type,
             length, pskey);

    if (type == 0) {
      CsrReadPskey(static_cast<CsrPskey>(pskey), value);
      std::copy(value.begin(), value.end(), parameters.begin() + 17);
    } else {
      CsrWritePskey(static_cast<CsrPskey>(pskey), value);
    }

  } else {
    // Subcommand to read or write VARID of the selected identifier.
    std::vector<uint8_t> value(parameters.begin() + 11,
                               parameters.begin() + 11 + length);

    LOG_INFO("CSR vendor command type=%04x length=%04x varid=%04x", type,
             length, varid);

    if (type == 0) {
      CsrReadVarid(static_cast<CsrVarid>(varid), value);
      std::copy(value.begin(), value.end(), parameters.begin() + 11);
    } else {
      CsrWriteVarid(static_cast<CsrVarid>(varid), value);
    }
  }

complete:
  // Overwrite the command type.
  parameters[1] = 0x1;
  parameters[2] = 0x0;
  send_event_(bluetooth::hci::EventBuilder::Create(
      bluetooth::hci::EventCode::VENDOR_SPECIFIC,
      std::make_unique<bluetooth::packet::RawBuilder>(std::move(parameters))));
}

void DualModeController::CsrReadVarid(CsrVarid varid,
                                      std::vector<uint8_t>& value) {
  switch (varid) {
    case CsrVarid::CSR_VARID_BUILDID:
      // Return the extact Build ID returned by the official PTS dongle.
      ASSERT(value.size() >= 2);
      value[0] = 0xe8;
      value[1] = 0x30;
      break;

    default:
      LOG_INFO("Unsupported read of CSR varid 0x%04x", varid);
      break;
  }
}

void DualModeController::CsrWriteVarid(CsrVarid varid,
                                       std::vector<uint8_t> const& value) {
  LOG_INFO("Unsupported write of CSR varid 0x%04x", varid);
}

void DualModeController::CsrReadPskey(CsrPskey pskey,
                                      std::vector<uint8_t>& value) {
  switch (pskey) {
    case CsrPskey::CSR_PSKEY_ENC_KEY_LMIN:
      ASSERT(value.size() >= 1);
      value[0] = 7;
      break;

    case CsrPskey::CSR_PSKEY_ENC_KEY_LMAX:
      ASSERT(value.size() >= 1);
      value[0] = 16;
      break;

    case CSR_PSKEY_HCI_LMP_LOCAL_VERSION:
      // Return the extact version returned by the official PTS dongle.
      ASSERT(value.size() >= 2);
      value[0] = 0x08;
      value[1] = 0x08;
      break;

    default:
      LOG_INFO("Unsupported read of CSR pskey 0x%04x", pskey);
      break;
  }
}

void DualModeController::CsrWritePskey(CsrPskey pskey,
                                       std::vector<uint8_t> const& value) {
  switch (pskey) {
    case CsrPskey::CSR_PSKEY_LOCAL_SUPPORTED_FEATURES:
      ASSERT(value.size() >= 8);
      LOG_INFO("CSR Vendor updating the Local Supported Features");
      properties_.lmp_features[0] =
          ((uint64_t)value[0] << 0) | ((uint64_t)value[1] << 8) |
          ((uint64_t)value[2] << 16) | ((uint64_t)value[3] << 24) |
          ((uint64_t)value[4] << 32) | ((uint64_t)value[5] << 40) |
          ((uint64_t)value[6] << 48) | ((uint64_t)value[7] << 56);
      break;

    default:
      LOG_INFO("Unsupported write of CSR pskey 0x%04x", pskey);
      break;
  }
}

void DualModeController::LeSetAdvertisingSetRandomAddress(CommandView command) {
  auto command_view = gd_hci::LeSetAdvertisingSetRandomAddressView::Create(
      gd_hci::LeAdvertisingCommandView::Create(command));
+11 −1
Original line number Diff line number Diff line
@@ -24,10 +24,11 @@
#include <unordered_map>
#include <vector>

#include "controller_properties.h"
#include "hci/address.h"
#include "hci/hci_packets.h"
#include "controller_properties.h"
#include "link_layer_controller.h"
#include "model/controller/vendor/csr.h"
#include "model/devices/device.h"
#include "model/setup/async_manager.h"
#ifndef ROOTCANAL_LMP
@@ -607,6 +608,15 @@ class DualModeController : public Device {
  void LeAdvertisingFilter(CommandView args);
  void LeExtendedScanParams(CommandView args);

  // CSR vendor command.
  // Implement the command specific to the CSR controller
  // used specifically by the PTS tool to pass certification tests.
  void CsrVendorCommand(CommandView args);
  void CsrReadVarid(CsrVarid varid, std::vector<uint8_t>& value);
  void CsrWriteVarid(CsrVarid varid, std::vector<uint8_t> const& value);
  void CsrReadPskey(CsrPskey pskey, std::vector<uint8_t>& value);
  void CsrWritePskey(CsrPskey pskey, std::vector<uint8_t> const& value);

  // Required commands for handshaking with hci driver
  void ReadClassOfDevice(CommandView args);
  void ReadVoiceSetting(CommandView args);
+38 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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.
 */

#pragma once

#include <cstdint>

namespace rootcanal {

// CSR Vendor command opcode.
static constexpr uint16_t CSR_VENDOR = 0xfc00;

enum CsrVarid : uint16_t {
  CSR_VARID_BUILDID = 0x2819,
  CSR_VARID_PS = 0x7003,
};

enum CsrPskey : uint16_t {
  CSR_PSKEY_ENC_KEY_LMIN = 0x00da,
  CSR_PSKEY_ENC_KEY_LMAX = 0x00db,
  CSR_PSKEY_LOCAL_SUPPORTED_FEATURES = 0x00ef,
  CSR_PSKEY_HCI_LMP_LOCAL_VERSION = 0x010d,
};

}  // namespace rootcanal