You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

339 lines
10 KiB

/*
* Copyright (C) 2021 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.
*/
#include "gd/rust/topshim/btif/btif_shim.h"
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <memory>
#include "btcore/include/hal_util.h"
#include "include/hardware/bluetooth.h"
#include "rust/cxx.h"
#include "src/btif.rs.h"
namespace bluetooth {
namespace topshim {
namespace rust {
namespace internal {
// We need a global pointer to the Bluetooth interface because callbacks don't
// pass back a pointer to the interface object. As a consequence, attempting to
// initialize the interface multiple times should cause an abort.
static BluetoothIntf* g_btif;
namespace rusty = ::bluetooth::topshim::rust;
static ::rust::Vec<BtProperty> prop_to_vec(int num_properties, bt_property_t* properties) {
::rust::Vec<BtProperty> rust_properties;
for (int i = 0; i < num_properties; ++i) {
::rust::Vec<::rust::u8> val;
val.reserve(properties[i].len);
::rust::u8* p = static_cast<::rust::u8*>(properties[i].val);
for (int j = 0; j < properties[i].len; ++j) {
val.push_back(p[j]);
}
BtProperty prop = {.prop_type = properties[i].type, .len = properties[i].len, .val = std::move(val)};
rust_properties.push_back(std::move(prop));
}
return rust_properties;
}
static RustRawAddress to_rust_address(RawAddress* address) {
RustRawAddress raddr;
std::copy(std::begin(address->address), std::end(address->address), std::begin(raddr.address));
return raddr;
}
static RawAddress from_rust_address(const RustRawAddress& address) {
RawAddress r;
r.FromOctets(address.address.data());
return r;
}
static ::rust::String bdname_to_string(bt_bdname_t* bdname) {
if (!bdname) {
return std::string("");
}
return std::string(reinterpret_cast<const char*>(bdname->name));
}
static void adapter_state_changed_cb(bt_state_t state) {
rusty::adapter_state_changed_callback(*g_btif->GetCallbacks(), state);
}
static void adapter_properties_cb(bt_status_t status, int num_properties, bt_property_t* properties) {
rusty::adapter_properties_callback(
*g_btif->GetCallbacks(), status, num_properties, prop_to_vec(num_properties, properties));
}
static void remote_device_properties_cb(
bt_status_t status, RawAddress* bd_addr, int num_properties, bt_property_t* properties) {
RustRawAddress addr = to_rust_address(bd_addr);
rusty::remote_device_properties_callback(
*g_btif->GetCallbacks(), status, addr, num_properties, prop_to_vec(num_properties, properties));
}
static void device_found_cb(int num_properties, bt_property_t* properties) {
rusty::device_found_callback(*g_btif->GetCallbacks(), num_properties, prop_to_vec(num_properties, properties));
}
static void discovery_state_changed_cb(bt_discovery_state_t state) {
rusty::discovery_state_changed_callback(*g_btif->GetCallbacks(), state);
}
static void pin_request_cb(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod, bool min_16_digit) {
RustRawAddress addr = to_rust_address(remote_bd_addr);
auto name = bdname_to_string(bd_name);
rusty::pin_request_callback(*g_btif->GetCallbacks(), addr, name, cod, min_16_digit);
}
static void ssp_request_cb(
RawAddress* remote_bd_addr,
bt_bdname_t* bd_name,
uint32_t cod,
bt_ssp_variant_t pairing_variant,
uint32_t pass_key) {
RustRawAddress addr = to_rust_address(remote_bd_addr);
auto name = bdname_to_string(bd_name);
rusty::ssp_request_callback(*g_btif->GetCallbacks(), addr, name, cod, pairing_variant, pass_key);
}
static void bond_state_changed_cb(bt_status_t status, RawAddress* remote_bd_addr, bt_bond_state_t state) {
RustRawAddress addr = to_rust_address(remote_bd_addr);
rust::bond_state_changed_callback(*g_btif->GetCallbacks(), status, addr, state);
}
static void acl_state_changed_cb(
bt_status_t status, RawAddress* remote_bd_addr, bt_acl_state_t state, bt_hci_error_code_t hci_reason) {
RustRawAddress addr = to_rust_address(remote_bd_addr);
rust::acl_state_changed_callback(*g_btif->GetCallbacks(), status, addr, state, hci_reason);
}
// TODO(abps) - Implement remaining callbacks
static void thread_event_cb(bt_cb_thread_evt evt) {}
static void dut_mode_recv_cb(uint16_t opcode, uint8_t* buf, uint8_t len) {}
static void le_test_mode_cb(bt_status_t status, uint16_t num_packets) {}
static void energy_info_cb(bt_activity_energy_info* energy_info, bt_uid_traffic_t* uid_data) {}
bt_callbacks_t g_callbacks = {
sizeof(bt_callbacks_t),
adapter_state_changed_cb,
adapter_properties_cb,
remote_device_properties_cb,
device_found_cb,
discovery_state_changed_cb,
pin_request_cb,
ssp_request_cb,
bond_state_changed_cb,
acl_state_changed_cb,
thread_event_cb,
dut_mode_recv_cb,
le_test_mode_cb,
energy_info_cb,
};
} // namespace internal
// Bluetooth interface handler
BluetoothIntf::BluetoothIntf() : init_(false) {}
BluetoothIntf::~BluetoothIntf() {
// We made a copy of flags from initFlags; clean them up here
if (flags_) {
int i = 0;
for (const char* flag = flags_[i]; flags_[i] != nullptr; ++i) {
std::free(const_cast<void*>(static_cast<const void*>(flag)));
}
std::free(const_cast<void*>(static_cast<const void*>(flags_)));
}
}
void BluetoothIntf::ConvertFlags(::rust::Vec<::rust::String>& initFlags) {
// Allocate number of flags + 1 (last entry must be null to signify end)
// Must be calloc so our cleanup correctly frees everything
flags_ = static_cast<const char**>(std::calloc(initFlags.size() + 1, sizeof(char*)));
if (!flags_) return;
for (int i = 0; i < initFlags.size(); ++i) {
flags_[i] = strndup(initFlags[i].data(), initFlags[i].size());
if (!flags_) {
return;
}
}
}
bool BluetoothIntf::Initialize(::rust::Box<RustCallbacks> callbacks, ::rust::Vec<::rust::String> initFlags) {
if (init_) return true;
callbacks_ = std::make_unique<::rust::Box<RustCallbacks>>(std::move(callbacks));
ConvertFlags(initFlags);
if (!hal_util_load_bt_library(&intf_)) {
int ret = intf_->init(
&internal::g_callbacks,
false, // guest_mode,
false, // is_niap_mode,
0, // config_compare_result,
flags_,
false // is_atv
);
// We only accept SUCCESS and not BT_STATUS_DONE. If some other interface
// has already been registered, that means our callbacks won't be called and
// that is problematic.
init_ = ret == BT_STATUS_SUCCESS;
}
return init_;
}
void BluetoothIntf::CleanUp() const {
intf_->cleanup();
}
int BluetoothIntf::Enable() const {
return intf_->enable();
}
int BluetoothIntf::Disable() const {
return intf_->disable();
}
int BluetoothIntf::GetAdapterProperties() const {
return intf_->get_adapter_properties();
}
int BluetoothIntf::GetAdapterProperty(int prop) const {
return intf_->get_adapter_property(static_cast<bt_property_type_t>(prop));
}
static bt_property_t convert_to_cprop(const BtProperty& prop) {
bt_property_t c_prop = {
.type = static_cast<bt_property_type_t>(prop.prop_type),
.len = prop.len,
.val = reinterpret_cast<void*>(const_cast<unsigned char*>(prop.val.data())),
};
return c_prop;
}
int BluetoothIntf::SetAdapterProperty(const BtProperty& prop) const {
bt_property_t c_prop = convert_to_cprop(prop);
return intf_->set_adapter_property(&c_prop);
}
int BluetoothIntf::GetRemoteDeviceProperties(const RustRawAddress& address) const {
RawAddress addr = internal::from_rust_address(address);
return intf_->get_remote_device_properties(&addr);
}
int BluetoothIntf::GetRemoteDeviceProperty(const RustRawAddress& address, int prop_type) const {
RawAddress addr = internal::from_rust_address(address);
return intf_->get_remote_device_property(&addr, static_cast<bt_property_type_t>(prop_type));
}
int BluetoothIntf::SetRemoteDeviceProperty(const RustRawAddress& address, const BtProperty& prop) const {
RawAddress addr = internal::from_rust_address(address);
bt_property_t c_prop = convert_to_cprop(prop);
return intf_->set_remote_device_property(&addr, &c_prop);
}
int BluetoothIntf::GetRemoteServices(const RustRawAddress& address) const {
RawAddress addr = internal::from_rust_address(address);
return intf_->get_remote_services(&addr);
}
int BluetoothIntf::StartDiscovery() const {
return intf_->start_discovery();
}
int BluetoothIntf::CancelDiscovery() const {
return intf_->cancel_discovery();
}
int BluetoothIntf::CreateBond(const RustRawAddress& address, int transport) const {
RawAddress addr = internal::from_rust_address(address);
return intf_->create_bond(&addr, transport);
}
int BluetoothIntf::RemoveBond(const RustRawAddress& address) const {
RawAddress addr = internal::from_rust_address(address);
return intf_->remove_bond(&addr);
}
int BluetoothIntf::CancelBond(const RustRawAddress& address) const {
RawAddress addr = internal::from_rust_address(address);
return intf_->cancel_bond(&addr);
}
int BluetoothIntf::GetConnectionState(const RustRawAddress& address) const {
RawAddress addr = internal::from_rust_address(address);
return intf_->get_connection_state(&addr);
}
int BluetoothIntf::PinReply(
const RustRawAddress& address, uint8_t accept, uint8_t pin_len, const BtPinCode& code) const {
RawAddress addr = internal::from_rust_address(address);
bt_pin_code_t pin_code;
std::copy(std::begin(code.pin), std::end(code.pin), pin_code.pin);
return intf_->pin_reply(&addr, accept, pin_len, &pin_code);
}
int BluetoothIntf::SspReply(const RustRawAddress& address, int ssp_variant, uint8_t accept, uint32_t passkey) const {
RawAddress addr = internal::from_rust_address(address);
return intf_->ssp_reply(&addr, static_cast<bt_ssp_variant_t>(ssp_variant), accept, passkey);
}
std::unique_ptr<BluetoothIntf> Load() {
// Don't allow the bluetooth interface to be allocated twice
if (internal::g_btif) std::abort();
auto btif = std::make_unique<BluetoothIntf>();
internal::g_btif = btif.get();
return btif;
}
} // namespace rust
} // namespace topshim
} // namespace bluetooth