blob: 3ca100f7a8d5d01be34c0fbc857adbb538e6f6c7 [file] [log] [blame]
/*
* Copyright 2019 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 "hci/cert/cert.h"
#include <condition_variable>
#include <memory>
#include <mutex>
#include <set>
#include "common/blocking_queue.h"
#include "grpc/grpc_event_stream.h"
#include "hci/cert/api.grpc.pb.h"
#include "hci/classic_security_manager.h"
#include "hci/controller.h"
#include "hci/hci_layer.h"
#include "hci/hci_packets.h"
#include "os/queue.h"
#include "packet/raw_builder.h"
using ::grpc::ServerAsyncResponseWriter;
using ::grpc::ServerAsyncWriter;
using ::grpc::ServerContext;
using ::bluetooth::common::Bind;
using ::bluetooth::common::BindOnce;
using ::bluetooth::facade::EventStreamRequest;
using ::bluetooth::packet::RawBuilder;
namespace bluetooth {
namespace hci {
namespace cert {
class AclManagerCertService : public AclManagerCert::Service {
public:
AclManagerCertService(Controller* controller, HciLayer* hci_layer, ::bluetooth::os::Handler* facade_handler)
: controller_(controller), hci_layer_(hci_layer), handler_(facade_handler),
acl_queue_end_(hci_layer_->GetAclQueueEnd()) {
hci_layer_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
Bind(&AclManagerCertService::on_connection_complete, common::Unretained(this)),
handler_);
hci_layer_->RegisterEventHandler(EventCode::DISCONNECTION_COMPLETE,
Bind(&AclManagerCertService::on_disconnection_complete, common::Unretained(this)),
handler_);
hci_layer_->RegisterEventHandler(EventCode::CONNECTION_REQUEST,
Bind(&AclManagerCertService::on_incoming_connection, common::Unretained(this)),
handler_);
hci_layer_->RegisterEventHandler(
EventCode::CONNECTION_PACKET_TYPE_CHANGED,
Bind(&AclManagerCertService::on_connection_packet_type_changed, common::Unretained(this)), handler_);
hci_layer_->RegisterEventHandler(EventCode::QOS_SETUP_COMPLETE,
Bind(&AclManagerCertService::on_qos_setup_complete, common::Unretained(this)),
handler_);
hci_layer_->RegisterEventHandler(EventCode::ROLE_CHANGE,
Bind(&AclManagerCertService::on_role_change, common::Unretained(this)), handler_);
controller_->RegisterCompletedAclPacketsCallback(common::Bind([](uint16_t, uint16_t) { /* TODO check */ }),
handler_);
acl_queue_end_->RegisterDequeue(handler_,
Bind(&AclManagerCertService::on_incoming_packet, common::Unretained(this)));
}
void on_incoming_packet() {
auto packet = acl_queue_end_->TryDequeue();
ASSERT(packet->IsValid());
AclData acl_data;
if (connected_devices_.find(packet->GetHandle()) == connected_devices_.end()) {
LOG_ERROR("Can't find remote device");
return;
}
auto address = connected_devices_[packet->GetHandle()];
acl_data.mutable_remote()->set_address(address.ToString());
std::string data = std::string(packet->begin(), packet->end());
acl_data.set_payload(data);
acl_stream_.OnIncomingEvent(acl_data);
}
~AclManagerCertService() {
acl_queue_end_->UnregisterDequeue();
hci_layer_->UnregisterEventHandler(EventCode::CONNECTION_REQUEST);
hci_layer_->UnregisterEventHandler(EventCode::DISCONNECTION_COMPLETE);
hci_layer_->UnregisterEventHandler(EventCode::CONNECTION_COMPLETE);
}
void on_connection_complete(EventPacketView packet) {
ConnectionCompleteView connection_complete = ConnectionCompleteView::Create(std::move(packet));
ASSERT(connection_complete.IsValid());
auto status = connection_complete.GetStatus();
auto address = connection_complete.GetBdAddr();
auto handle = connection_complete.GetConnectionHandle();
if (status == ErrorCode::SUCCESS) {
connected_devices_.emplace(handle, address);
ConnectionEvent event;
event.mutable_remote()->set_address(address.ToString());
connection_complete_stream_.OnIncomingEvent(event);
} else {
ConnectionFailedEvent event;
event.mutable_remote()->set_address(address.ToString());
event.set_reason(static_cast<uint32_t>(connection_complete.GetStatus()));
connection_failed_stream_.OnIncomingEvent(event);
}
}
void on_disconnection_complete(EventPacketView packet) {
DisconnectionCompleteView disconnection_complete = DisconnectionCompleteView::Create(std::move(packet));
ASSERT(disconnection_complete.IsValid());
auto status = disconnection_complete.GetStatus();
auto handle = disconnection_complete.GetConnectionHandle();
auto device = connected_devices_.find(handle);
ASSERT(device != connected_devices_.end());
auto address = device->second;
if (status == ErrorCode::SUCCESS) {
connected_devices_.erase(handle);
DisconnectionEvent event;
event.mutable_remote()->set_address(address.ToString());
event.set_reason(static_cast<uint32_t>(disconnection_complete.GetReason()));
disconnection_stream_.OnIncomingEvent(event);
}
}
void on_incoming_connection(EventPacketView packet) {
ConnectionRequestView request = ConnectionRequestView::Create(packet);
ASSERT(request.IsValid());
Address address = request.GetBdAddr();
if (accepted_devices_.find(address) != accepted_devices_.end()) {
auto role = AcceptConnectionRequestRole::BECOME_MASTER; // We prefer to be master
hci_layer_->EnqueueCommand(AcceptConnectionRequestBuilder::Create(address, role),
common::BindOnce([](CommandStatusView status) { /* TODO: check? */ }), handler_);
} else {
auto reason = RejectConnectionReason::LIMITED_RESOURCES;
auto builder = RejectConnectionRequestBuilder::Create(address, reason);
hci_layer_->EnqueueCommand(std::move(builder), BindOnce([](CommandStatusView status) { /* TODO: check? */ }),
handler_);
}
}
void on_connection_packet_type_changed(EventPacketView packet) { /*TODO*/
}
void on_qos_setup_complete(EventPacketView packet) { /*TODO*/
}
void on_role_change(EventPacketView packet) { /*TODO*/
}
using EventStream = ::bluetooth::grpc::GrpcEventStream<AclData, AclPacketView>;
::grpc::Status SetPageScanMode(::grpc::ServerContext* context, const ::bluetooth::hci::cert::PageScanMode* request,
::google::protobuf::Empty* response) override {
ScanEnable scan_enable = request->enabled() ? ScanEnable::PAGE_SCAN_ONLY : ScanEnable::NO_SCANS;
std::promise<void> promise;
auto future = promise.get_future();
hci_layer_->EnqueueCommand(
WriteScanEnableBuilder::Create(scan_enable),
common::BindOnce([](std::promise<void> promise, CommandCompleteView) { promise.set_value(); },
std::move(promise)),
handler_);
future.wait();
return ::grpc::Status::OK;
}
::grpc::Status SetIncomingConnectionPolicy(::grpc::ServerContext* context,
const ::bluetooth::hci::cert::IncomingConnectionPolicy* request,
::google::protobuf::Empty* response) override {
std::unique_lock<std::mutex> lock(mutex_);
Address peer;
ASSERT(Address::FromString(request->remote().address(), peer));
if (request->accepted()) {
accepted_devices_.insert(peer);
} else {
accepted_devices_.erase(peer);
}
return ::grpc::Status::OK;
}
::grpc::Status Connect(::grpc::ServerContext* context, const facade::BluetoothAddress* remote,
::google::protobuf::Empty* response) override {
std::unique_lock<std::mutex> lock(mutex_);
uint16_t packet_type = 0x4408 /* DM 1,3,5 */ | 0x8810 /*DH 1,3,5 */;
PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R1;
uint16_t clock_offset = 0;
ClockOffsetValid clock_offset_valid = ClockOffsetValid::INVALID;
CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
Address peer;
ASSERT(Address::FromString(remote->address(), peer));
std::unique_ptr<CreateConnectionBuilder> packet = CreateConnectionBuilder::Create(
peer, packet_type, page_scan_repetition_mode, clock_offset, clock_offset_valid, allow_role_switch);
hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) {
ASSERT(status.IsValid());
ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
}),
handler_);
return ::grpc::Status::OK;
}
::grpc::Status Disconnect(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
::google::protobuf::Empty* response) override {
std::unique_lock<std::mutex> lock(mutex_);
Address peer;
Address::FromString(request->address(), peer);
uint16_t handle = find_connected_device_handle_by_address(peer);
if (handle == kInvalidHandle) {
return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
}
DisconnectReason reason = DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION;
std::unique_ptr<DisconnectBuilder> packet = DisconnectBuilder::Create(handle, reason);
hci_layer_->EnqueueCommand(std::move(packet), BindOnce([](CommandStatusView status) { /* TODO: check? */ }),
handler_);
return ::grpc::Status::OK;
}
::grpc::Status SendAclData(::grpc::ServerContext* context, const AclData* request,
::google::protobuf::Empty* response) override {
Address peer;
Address::FromString(request->remote().address(), peer);
auto handle = find_connected_device_handle_by_address(peer);
if (handle == kInvalidHandle) {
return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
}
constexpr PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
constexpr BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
auto req_string = request->payload();
packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end()));
auto acl_packet = AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(packet));
acl_enqueue_buffer_.Enqueue(std::move(acl_packet), handler_);
return ::grpc::Status::OK;
}
::grpc::Status FetchAclData(::grpc::ServerContext* context, const facade::EventStreamRequest* request,
::grpc::ServerWriter<AclData>* writer) override {
return acl_stream_.HandleRequest(context, request, writer);
}
::grpc::Status FetchConnectionComplete(::grpc::ServerContext* context, const EventStreamRequest* request,
::grpc::ServerWriter<ConnectionEvent>* writer) override {
return connection_complete_stream_.HandleRequest(context, request, writer);
};
::grpc::Status FetchConnectionFailed(::grpc::ServerContext* context, const EventStreamRequest* request,
::grpc::ServerWriter<ConnectionFailedEvent>* writer) override {
return connection_failed_stream_.HandleRequest(context, request, writer);
};
::grpc::Status FetchDisconnection(::grpc::ServerContext* context,
const ::bluetooth::facade::EventStreamRequest* request,
::grpc::ServerWriter<DisconnectionEvent>* writer) override {
return disconnection_stream_.HandleRequest(context, request, writer);
}
private:
Controller* controller_;
HciLayer* hci_layer_;
::bluetooth::os::Handler* handler_;
common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* acl_queue_end_;
os::EnqueueBuffer<AclPacketBuilder> acl_enqueue_buffer_{acl_queue_end_};
mutable std::mutex mutex_;
std::set<Address> accepted_devices_;
std::map<uint16_t /* handle */, Address> connected_devices_;
constexpr static uint16_t kInvalidHandle = 0xffff;
uint16_t find_connected_device_handle_by_address(Address address) {
for (auto device : connected_devices_) {
if (device.second == address) {
return device.first;
}
}
return kInvalidHandle; // Can't find
}
class ConnectionCompleteStreamCallback
: public ::bluetooth::grpc::GrpcEventStreamCallback<ConnectionEvent, ConnectionEvent> {
public:
void OnWriteResponse(ConnectionEvent* response, const ConnectionEvent& connection) override {
response->CopyFrom(connection);
}
} connection_complete_stream_callback_;
::bluetooth::grpc::GrpcEventStream<ConnectionEvent, ConnectionEvent> connection_complete_stream_{
&connection_complete_stream_callback_};
class ConnectionFailedStreamCallback
: public ::bluetooth::grpc::GrpcEventStreamCallback<ConnectionFailedEvent, ConnectionFailedEvent> {
public:
void OnWriteResponse(ConnectionFailedEvent* response, const ConnectionFailedEvent& event) override {
response->CopyFrom(event);
}
} connection_failed_stream_callback_;
::bluetooth::grpc::GrpcEventStream<ConnectionFailedEvent, ConnectionFailedEvent> connection_failed_stream_{
&connection_failed_stream_callback_};
class DisconnectionStreamCallback
: public ::bluetooth::grpc::GrpcEventStreamCallback<DisconnectionEvent, DisconnectionEvent> {
public:
void OnWriteResponse(DisconnectionEvent* response, const DisconnectionEvent& event) override {
response->CopyFrom(event);
}
} disconnection_stream_callback_;
::bluetooth::grpc::GrpcEventStream<DisconnectionEvent, DisconnectionEvent> disconnection_stream_{
&disconnection_stream_callback_};
class AclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<AclData, AclData> {
public:
void OnWriteResponse(AclData* response, const AclData& event) override {
response->CopyFrom(event);
}
} acl_stream_callback_;
::bluetooth::grpc::GrpcEventStream<AclData, AclData> acl_stream_{&acl_stream_callback_};
};
void AclManagerCertModule::ListDependencies(ModuleList* list) {
::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
list->add<Controller>();
list->add<HciLayer>();
list->add<ClassicSecurityManager>();
}
void AclManagerCertModule::Start() {
::bluetooth::grpc::GrpcFacadeModule::Start();
service_ = new AclManagerCertService(GetDependency<Controller>(), GetDependency<HciLayer>(), GetHandler());
}
void AclManagerCertModule::Stop() {
delete service_;
::bluetooth::grpc::GrpcFacadeModule::Stop();
}
::grpc::Service* AclManagerCertModule::GetService() const {
return service_;
}
const ModuleFactory AclManagerCertModule::Factory =
::bluetooth::ModuleFactory([]() { return new AclManagerCertModule(); });
} // namespace cert
} // namespace hci
} // namespace bluetooth