blob: c21d9a504a2f3ceb3693f7c73e139437256ece90 [file] [log] [blame]
//
// Copyright 2015 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 "dual_mode_controller"
#include "vendor_libs/test_vendor_lib/include/dual_mode_controller.h"
#include "base/logging.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/values.h"
#include "vendor_libs/test_vendor_lib/include/event_packet.h"
#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
extern "C" {
#include "stack/include/hcidefs.h"
#include "osi/include/log.h"
} // extern "C"
namespace {
// Included in certain events to indicate success (specific to the event
// context).
const uint8_t kSuccessStatus = 0;
// The default number encoded in event packets to indicate to the HCI how many
// command packets it can send to the controller.
const uint8_t kNumHciCommandPackets = 1;
// The location of the config file loaded to populate controller attributes.
const std::string kControllerPropertiesFile =
"/etc/bluetooth/controller_properties.json";
// Inquiry modes for specifiying inquiry result formats.
const uint8_t kStandardInquiry = 0x00;
const uint8_t kRssiInquiry = 0x01;
const uint8_t kExtendedOrRssiInquiry = 0x02;
// The bd address of another (fake) device.
const std::vector<uint8_t> kOtherDeviceBdAddress = {6, 5, 4, 3, 2, 1};
// Fake inquiry response for a fake device.
const std::vector<uint8_t> kPageScanRepetitionMode = {0};
const std::vector<uint8_t> kPageScanPeriodMode = {0};
const std::vector<uint8_t> kPageScanMode = {0};
const std::vector<uint8_t> kClassOfDevice = {1, 2, 3};
const std::vector<uint8_t> kClockOffset = {1, 2};
void LogCommand(const char* command) {
LOG_INFO(LOG_TAG, "Controller performing command: %s", command);
}
// Functions used by JSONValueConverter to read stringified JSON into Properties
// object.
bool ParseUint8t(const base::StringPiece& value, uint8_t* field) {
*field = std::stoi(value.as_string());
return true;
}
bool ParseUint16t(const base::StringPiece& value, uint16_t* field) {
*field = std::stoi(value.as_string());
return true;
}
bool ParseUint8tVector(const base::StringPiece& value,
std::vector<uint8_t>* field) {
for (char& c : value.as_string())
field->push_back(c - '0');
return true;
}
} // namespace
namespace test_vendor_lib {
void DualModeController::SendCommandComplete(
uint16_t command_opcode,
const std::vector<uint8_t>& return_parameters) const {
std::unique_ptr<EventPacket> command_complete =
EventPacket::CreateCommandCompleteEvent(
kNumHciCommandPackets, command_opcode, return_parameters);
send_event_(std::move(command_complete));
}
void DualModeController::SendCommandCompleteSuccess(
uint16_t command_opcode) const {
SendCommandComplete(command_opcode, {kSuccessStatus});
}
void DualModeController::SendCommandStatus(uint8_t status,
uint16_t command_opcode) const {
std::unique_ptr<EventPacket> command_status =
EventPacket::CreateCommandStatusEvent(status, kNumHciCommandPackets,
command_opcode);
send_event_(std::move(command_status));
}
void DualModeController::SendCommandStatusSuccess(
uint16_t command_opcode) const {
SendCommandStatus(kSuccessStatus, command_opcode);
}
void DualModeController::SendInquiryResult() const {
std::unique_ptr<EventPacket> inquiry_result =
EventPacket::CreateInquiryResultEvent(
1, kOtherDeviceBdAddress, kPageScanRepetitionMode,
kPageScanPeriodMode, kPageScanMode, kClassOfDevice, kClockOffset);
send_event_(std::move(inquiry_result));
}
void DualModeController::SendExtendedInquiryResult(
const std::string& name, const std::string& address) const {
std::vector<uint8_t> rssi = {0};
std::vector<uint8_t> extended_inquiry_data = {name.length() + 1, 0x09};
std::copy(name.begin(), name.end(),
std::back_inserter(extended_inquiry_data));
std::vector<uint8_t> bd_address(address.begin(), address.end());
// TODO(dennischeng): Use constants for parameter sizes, here and elsewhere.
while (extended_inquiry_data.size() < 240) {
extended_inquiry_data.push_back(0);
}
std::unique_ptr<EventPacket> extended_inquiry_result =
EventPacket::CreateExtendedInquiryResultEvent(
bd_address, kPageScanRepetitionMode, kPageScanPeriodMode,
kClassOfDevice, kClockOffset, rssi, extended_inquiry_data);
send_event_(std::move(extended_inquiry_result));
}
DualModeController::DualModeController()
: state_(kStandby),
test_channel_state_(kNone),
properties_(kControllerPropertiesFile) {
#define SET_HANDLER(opcode, method) \
active_hci_commands_[opcode] = \
std::bind(&DualModeController::method, this, std::placeholders::_1);
SET_HANDLER(HCI_RESET, HciReset);
SET_HANDLER(HCI_READ_BUFFER_SIZE, HciReadBufferSize);
SET_HANDLER(HCI_HOST_BUFFER_SIZE, HciHostBufferSize);
SET_HANDLER(HCI_READ_LOCAL_VERSION_INFO, HciReadLocalVersionInformation);
SET_HANDLER(HCI_READ_BD_ADDR, HciReadBdAddr);
SET_HANDLER(HCI_READ_LOCAL_SUPPORTED_CMDS, HciReadLocalSupportedCommands);
SET_HANDLER(HCI_READ_LOCAL_EXT_FEATURES, HciReadLocalExtendedFeatures);
SET_HANDLER(HCI_WRITE_SIMPLE_PAIRING_MODE, HciWriteSimplePairingMode);
SET_HANDLER(HCI_WRITE_LE_HOST_SUPPORT, HciWriteLeHostSupport);
SET_HANDLER(HCI_SET_EVENT_MASK, HciSetEventMask);
SET_HANDLER(HCI_WRITE_INQUIRY_MODE, HciWriteInquiryMode);
SET_HANDLER(HCI_WRITE_PAGESCAN_TYPE, HciWritePageScanType);
SET_HANDLER(HCI_WRITE_INQSCAN_TYPE, HciWriteInquiryScanType);
SET_HANDLER(HCI_WRITE_CLASS_OF_DEVICE, HciWriteClassOfDevice);
SET_HANDLER(HCI_WRITE_PAGE_TOUT, HciWritePageTimeout);
SET_HANDLER(HCI_WRITE_DEF_POLICY_SETTINGS, HciWriteDefaultLinkPolicySettings);
SET_HANDLER(HCI_READ_LOCAL_NAME, HciReadLocalName);
SET_HANDLER(HCI_CHANGE_LOCAL_NAME, HciWriteLocalName);
SET_HANDLER(HCI_WRITE_EXT_INQ_RESPONSE, HciWriteExtendedInquiryResponse);
SET_HANDLER(HCI_WRITE_VOICE_SETTINGS, HciWriteVoiceSetting);
SET_HANDLER(HCI_WRITE_CURRENT_IAC_LAP, HciWriteCurrentIacLap);
SET_HANDLER(HCI_WRITE_INQUIRYSCAN_CFG, HciWriteInquiryScanActivity);
SET_HANDLER(HCI_WRITE_SCAN_ENABLE, HciWriteScanEnable);
SET_HANDLER(HCI_SET_EVENT_FILTER, HciSetEventFilter);
SET_HANDLER(HCI_INQUIRY, HciInquiry);
SET_HANDLER(HCI_INQUIRY_CANCEL, HciInquiryCancel);
SET_HANDLER(HCI_DELETE_STORED_LINK_KEY, HciDeleteStoredLinkKey);
SET_HANDLER(HCI_RMT_NAME_REQUEST, HciRemoteNameRequest);
#undef SET_HANDLER
#define SET_TEST_HANDLER(command_name, method) \
active_test_channel_commands_[command_name] = \
std::bind(&DualModeController::method, this, std::placeholders::_1);
SET_TEST_HANDLER("CLEAR", TestChannelClear);
SET_TEST_HANDLER("CLEAR_EVENT_DELAY", TestChannelClearEventDelay);
SET_TEST_HANDLER("DISCOVER", TestChannelDiscover);
SET_TEST_HANDLER("SET_EVENT_DELAY", TestChannelSetEventDelay);
SET_TEST_HANDLER("TIMEOUT_ALL", TestChannelTimeoutAll);
#undef SET_TEST_HANDLER
}
void DualModeController::RegisterHandlersWithHciTransport(
HciTransport& transport) {
transport.RegisterCommandHandler(std::bind(&DualModeController::HandleCommand,
this, std::placeholders::_1));
}
void DualModeController::RegisterHandlersWithTestChannelTransport(
TestChannelTransport& transport) {
transport.RegisterCommandHandler(
std::bind(&DualModeController::HandleTestChannelCommand, this,
std::placeholders::_1, std::placeholders::_2));
}
void DualModeController::HandleTestChannelCommand(
const std::string& name, const std::vector<std::string>& args) {
if (active_test_channel_commands_.count(name) == 0)
return;
active_test_channel_commands_[name](args);
}
void DualModeController::HandleCommand(
std::unique_ptr<CommandPacket> command_packet) {
uint16_t opcode = command_packet->GetOpcode();
LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode,
command_packet->GetOGF(), command_packet->GetOCF());
// The command hasn't been registered with the handler yet. There is nothing
// to do.
if (active_hci_commands_.count(opcode) == 0)
return;
else if (test_channel_state_ == kTimeoutAll)
return;
active_hci_commands_[opcode](command_packet->GetPayload());
}
void DualModeController::RegisterEventChannel(
std::function<void(std::unique_ptr<EventPacket>)> callback) {
send_event_ = callback;
}
void DualModeController::RegisterDelayedEventChannel(
std::function<void(std::unique_ptr<EventPacket>, base::TimeDelta)>
callback) {
send_delayed_event_ = callback;
SetEventDelay(0);
}
void DualModeController::SetEventDelay(int64_t delay) {
if (delay < 0)
delay = 0;
send_event_ = std::bind(send_delayed_event_, std::placeholders::_1,
base::TimeDelta::FromMilliseconds(delay));
}
void DualModeController::TestChannelClear(
const std::vector<std::string>& args) {
LogCommand("TestChannel Clear");
test_channel_state_ = kNone;
SetEventDelay(0);
}
void DualModeController::TestChannelDiscover(
const std::vector<std::string>& args) {
LogCommand("TestChannel Discover");
for (size_t i = 0; i < args.size()-1; i+=2)
SendExtendedInquiryResult(args[i], args[i+1]);
}
void DualModeController::TestChannelTimeoutAll(
const std::vector<std::string>& args) {
LogCommand("TestChannel Timeout All");
test_channel_state_ = kTimeoutAll;
}
void DualModeController::TestChannelSetEventDelay(
const std::vector<std::string>& args) {
LogCommand("TestChannel Set Event Delay");
test_channel_state_ = kDelayedResponse;
SetEventDelay(std::stoi(args[0]));
}
void DualModeController::TestChannelClearEventDelay(
const std::vector<std::string>& args) {
LogCommand("TestChannel Clear Event Delay");
test_channel_state_ = kNone;
SetEventDelay(0);
}
void DualModeController::HciReset(const std::vector<uint8_t>& /* args */) {
LogCommand("Reset");
state_ = kStandby;
SendCommandCompleteSuccess(HCI_RESET);
}
void DualModeController::HciReadBufferSize(
const std::vector<uint8_t>& /* args */) {
LogCommand("Read Buffer Size");
SendCommandComplete(HCI_READ_BUFFER_SIZE, properties_.GetBufferSize());
}
void DualModeController::HciHostBufferSize(
const std::vector<uint8_t>& /* args */) {
LogCommand("Host Buffer Size");
SendCommandCompleteSuccess(HCI_HOST_BUFFER_SIZE);
}
void DualModeController::HciReadLocalVersionInformation(
const std::vector<uint8_t>& /* args */) {
LogCommand("Read Local Version Information");
SendCommandComplete(HCI_READ_LOCAL_VERSION_INFO,
properties_.GetLocalVersionInformation());
}
void DualModeController::HciReadBdAddr(const std::vector<uint8_t>& /* args */) {
LogCommand("Read Bd Addr");
std::vector<uint8_t> bd_address_with_status = properties_.GetBdAddress();
bd_address_with_status.insert(bd_address_with_status.begin(),
kSuccessStatus);
SendCommandComplete(HCI_READ_BD_ADDR, bd_address_with_status);
}
void DualModeController::HciReadLocalSupportedCommands(
const std::vector<uint8_t>& /* args */) {
LogCommand("Read Local Supported Commands");
SendCommandComplete(HCI_READ_LOCAL_SUPPORTED_CMDS,
properties_.GetLocalSupportedCommands());
}
void DualModeController::HciReadLocalExtendedFeatures(
const std::vector<uint8_t>& args) {
LogCommand("Read Local Extended Features");
SendCommandComplete(HCI_READ_LOCAL_EXT_FEATURES,
properties_.GetLocalExtendedFeatures(args[0]));
}
void DualModeController::HciWriteSimplePairingMode(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Simple Pairing Mode");
SendCommandCompleteSuccess(HCI_WRITE_SIMPLE_PAIRING_MODE);
}
void DualModeController::HciWriteLeHostSupport(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Le Host Support");
SendCommandCompleteSuccess(HCI_WRITE_LE_HOST_SUPPORT);
}
void DualModeController::HciSetEventMask(
const std::vector<uint8_t>& /* args */) {
LogCommand("Set Event Mask");
SendCommandCompleteSuccess(HCI_SET_EVENT_MASK);
}
void DualModeController::HciWriteInquiryMode(const std::vector<uint8_t>& args) {
LogCommand("Write Inquiry Mode");
CHECK(args.size() == 1);
inquiry_mode_ = args[0];
SendCommandCompleteSuccess(HCI_WRITE_INQUIRY_MODE);
}
void DualModeController::HciWritePageScanType(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Page Scan Type");
SendCommandCompleteSuccess(HCI_WRITE_PAGESCAN_TYPE);
}
void DualModeController::HciWriteInquiryScanType(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Inquiry Scan Type");
SendCommandCompleteSuccess(HCI_WRITE_INQSCAN_TYPE);
}
void DualModeController::HciWriteClassOfDevice(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Class Of Device");
SendCommandCompleteSuccess(HCI_WRITE_CLASS_OF_DEVICE);
}
void DualModeController::HciWritePageTimeout(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Page Timeout");
SendCommandCompleteSuccess(HCI_WRITE_PAGE_TOUT);
}
void DualModeController::HciWriteDefaultLinkPolicySettings(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Default Link Policy Settings");
SendCommandCompleteSuccess(HCI_WRITE_DEF_POLICY_SETTINGS);
}
void DualModeController::HciReadLocalName(
const std::vector<uint8_t>& /* args */) {
LogCommand("Get Local Name");
SendCommandComplete(HCI_READ_LOCAL_NAME, properties_.GetLocalName());
}
void DualModeController::HciWriteLocalName(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Local Name");
SendCommandCompleteSuccess(HCI_CHANGE_LOCAL_NAME);
}
void DualModeController::HciWriteExtendedInquiryResponse(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Extended Inquiry Response");
SendCommandCompleteSuccess(HCI_WRITE_EXT_INQ_RESPONSE);
}
void DualModeController::HciWriteVoiceSetting(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Voice Setting");
SendCommandCompleteSuccess(HCI_WRITE_VOICE_SETTINGS);
}
void DualModeController::HciWriteCurrentIacLap(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Current IAC LAP");
SendCommandCompleteSuccess(HCI_WRITE_CURRENT_IAC_LAP);
}
void DualModeController::HciWriteInquiryScanActivity(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Inquiry Scan Activity");
SendCommandCompleteSuccess(HCI_WRITE_INQUIRYSCAN_CFG);
}
void DualModeController::HciWriteScanEnable(
const std::vector<uint8_t>& /* args */) {
LogCommand("Write Scan Enable");
SendCommandCompleteSuccess(HCI_WRITE_SCAN_ENABLE);
}
void DualModeController::HciSetEventFilter(
const std::vector<uint8_t>& /* args */) {
LogCommand("Set Event Filter");
SendCommandCompleteSuccess(HCI_SET_EVENT_FILTER);
}
void DualModeController::HciInquiry(const std::vector<uint8_t>& /* args */) {
LogCommand("Inquiry");
state_ = kInquiry;
SendCommandStatusSuccess(HCI_INQUIRY);
switch (inquiry_mode_) {
case (kStandardInquiry):
SendInquiryResult();
break;
case (kRssiInquiry):
LOG_INFO(LOG_TAG, "RSSI Inquiry Mode currently not supported.");
break;
case (kExtendedOrRssiInquiry):
SendExtendedInquiryResult("FooBar", "123456");
break;
}
}
void DualModeController::HciInquiryCancel(
const std::vector<uint8_t>& /* args */) {
LogCommand("Inquiry Cancel");
CHECK(state_ == kInquiry);
state_ = kStandby;
SendCommandCompleteSuccess(HCI_INQUIRY_CANCEL);
}
void DualModeController::HciDeleteStoredLinkKey(
const std::vector<uint8_t>& args) {
LogCommand("Delete Stored Link Key");
/* Check the last octect in |args|. If it is 0, delete only the link key for
* the given BD_ADDR. If is is 1, delete all stored link keys. */
SendCommandComplete(HCI_DELETE_STORED_LINK_KEY, {1});
}
void DualModeController::HciRemoteNameRequest(
const std::vector<uint8_t>& args) {
LogCommand("Remote Name Request");
SendCommandStatusSuccess(HCI_RMT_NAME_REQUEST);
}
DualModeController::Properties::Properties(const std::string& file_name)
: local_supported_commands_size_(64), local_name_size_(248) {
std::string properties_raw;
if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw))
LOG_INFO(LOG_TAG, "Error reading controller properties from file.");
scoped_ptr<base::Value> properties_value_ptr =
base::JSONReader::Read(properties_raw);
if (properties_value_ptr.get() == nullptr)
LOG_INFO(LOG_TAG,
"Error controller properties may consist of ill-formed JSON.");
// Get the underlying base::Value object, which is of type
// base::Value::TYPE_DICTIONARY, and read it into member variables.
base::Value& properties_dictionary = *(properties_value_ptr.get());
base::JSONValueConverter<DualModeController::Properties> converter;
if (!converter.Convert(properties_dictionary, this))
LOG_INFO(LOG_TAG,
"Error converting JSON properties into Properties object.");
}
const std::vector<uint8_t> DualModeController::Properties::GetBufferSize() {
return std::vector<uint8_t>(
{kSuccessStatus, acl_data_packet_size_, acl_data_packet_size_ >> 8,
sco_data_packet_size_, num_acl_data_packets_, num_acl_data_packets_ >> 8,
num_sco_data_packets_, num_sco_data_packets_ >> 8});
}
const std::vector<uint8_t>
DualModeController::Properties::GetLocalVersionInformation() {
return std::vector<uint8_t>({kSuccessStatus, version_, revision_,
revision_ >> 8, lmp_pal_version_,
manufacturer_name_, manufacturer_name_ >> 8,
lmp_pal_subversion_, lmp_pal_subversion_ >> 8});
}
const std::vector<uint8_t> DualModeController::Properties::GetBdAddress() {
return bd_address_;
}
const std::vector<uint8_t>
DualModeController::Properties::GetLocalExtendedFeatures(uint8_t page_number) {
return std::vector<uint8_t>({kSuccessStatus, page_number,
maximum_page_number_, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF});
}
const std::vector<uint8_t>
DualModeController::Properties::GetLocalSupportedCommands() {
std::vector<uint8_t> local_supported_commands;
local_supported_commands.push_back(kSuccessStatus);
for (uint8_t i = 0; i < local_supported_commands_size_; ++i)
local_supported_commands.push_back(0xFF);
return local_supported_commands;
}
const std::vector<uint8_t> DualModeController::Properties::GetLocalName() {
std::vector<uint8_t> local_name;
local_name.push_back(kSuccessStatus);
for (uint8_t i = 0; i < local_name_size_; ++i)
local_name.push_back(0xFF);
return local_name;
}
// static
void DualModeController::Properties::RegisterJSONConverter(
base::JSONValueConverter<DualModeController::Properties>* converter) {
// TODO(dennischeng): Use RegisterIntField() here?
#define REGISTER_UINT8_T(field_name, field) \
converter->RegisterCustomField<uint8_t>( \
field_name, &DualModeController::Properties::field, &ParseUint8t);
#define REGISTER_UINT16_T(field_name, field) \
converter->RegisterCustomField<uint16_t>( \
field_name, &DualModeController::Properties::field, &ParseUint16t);
REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
REGISTER_UINT8_T("Version", version_);
REGISTER_UINT16_T("Revision", revision_);
REGISTER_UINT8_T("LmpPalVersion", lmp_pal_version_);
REGISTER_UINT16_T("ManufacturerName", manufacturer_name_);
REGISTER_UINT16_T("LmpPalSubversion", lmp_pal_subversion_);
REGISTER_UINT8_T("MaximumPageNumber", maximum_page_number_);
converter->RegisterCustomField<std::vector<uint8_t>>(
"BdAddress", &DualModeController::Properties::bd_address_,
&ParseUint8tVector);
#undef REGISTER_UINT8_T
#undef REGISTER_UINT16_T
}
} // namespace test_vendor_lib