blob: 651e31c29db81f8d790c615822115cedd89fd9a2 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "domain.h"
#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/common/task_domain.h"
#include "src/connectivity/bluetooth/core/bt-host/data/socket_factory.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/transport.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/channel_manager.h"
#include "src/connectivity/bluetooth/core/bt-host/rfcomm/channel_manager.h"
namespace bt {
namespace data {
class Impl final : public Domain, public TaskDomain<Impl, Domain> {
public:
Impl(fxl::RefPtr<hci::Transport> hci, std::string thread_name)
: Domain(),
TaskDomain<Impl, Domain>(this, std::move(thread_name)),
hci_(hci) {
ZX_DEBUG_ASSERT(hci_);
}
// Second constructor used by CreateWithDispatcher.
Impl(fxl::RefPtr<hci::Transport> hci, async_dispatcher_t* dispatcher)
: Domain(), TaskDomain<Impl, Domain>(this, dispatcher), hci_(hci) {
ZX_DEBUG_ASSERT(hci_);
}
void Initialize() override {
PostMessage([this] {
// This can only run once during initialization.
ZX_DEBUG_ASSERT(!l2cap_);
ZX_DEBUG_ASSERT(!rfcomm_);
InitializeL2CAP();
InitializeRFCOMM();
l2cap_socket_factory_ =
std::make_unique<internal::SocketFactory<l2cap::Channel>>();
rfcomm_socket_factory_ =
std::make_unique<internal::SocketFactory<rfcomm::Channel>>();
bt_log(TRACE, "data-domain", "initialized");
});
}
void ShutDown() override { TaskDomain<Impl, Domain>::ScheduleCleanUp(); }
// Called by the domain dispatcher as a result of ScheduleCleanUp().
void CleanUp() {
AssertOnDispatcherThread();
bt_log(TRACE, "data-domain", "shutting down");
rfcomm_socket_factory_ = nullptr;
l2cap_socket_factory_ = nullptr;
rfcomm_ = nullptr;
l2cap_ = nullptr; // Unregisters the RFCOMM PSM.
}
void AddACLConnection(hci::ConnectionHandle handle,
hci::Connection::Role role,
l2cap::LinkErrorCallback link_error_callback,
l2cap::SecurityUpgradeCallback security_callback,
async_dispatcher_t* dispatcher) override {
PostMessage([this, handle, role, lec = std::move(link_error_callback),
suc = std::move(security_callback), dispatcher]() mutable {
if (l2cap_) {
l2cap_->RegisterACL(handle, role, std::move(lec), std::move(suc),
dispatcher);
}
});
}
void AddLEConnection(
hci::ConnectionHandle handle, hci::Connection::Role role,
l2cap::LinkErrorCallback link_error_callback,
l2cap::LEConnectionParameterUpdateCallback conn_param_callback,
l2cap::LEFixedChannelsCallback channel_callback,
l2cap::SecurityUpgradeCallback security_callback,
async_dispatcher_t* dispatcher) override {
PostMessage([this, handle, role, cpc = std::move(conn_param_callback),
lec = std::move(link_error_callback),
suc = std::move(security_callback),
cc = std::move(channel_callback), dispatcher]() mutable {
if (l2cap_) {
l2cap_->RegisterLE(handle, role, std::move(cpc), std::move(lec),
std::move(suc), dispatcher);
auto att = l2cap_->OpenFixedChannel(handle, l2cap::kATTChannelId);
auto smp = l2cap_->OpenFixedChannel(handle, l2cap::kLESMPChannelId);
ZX_DEBUG_ASSERT(att);
ZX_DEBUG_ASSERT(smp);
async::PostTask(dispatcher, [att = std::move(att), smp = std::move(smp),
cb = std::move(cc)]() mutable {
cb(std::move(att), std::move(smp));
});
}
});
}
void RemoveConnection(hci::ConnectionHandle handle) override {
PostMessage([this, handle] {
if (l2cap_) {
l2cap_->Unregister(handle);
}
});
}
void AssignLinkSecurityProperties(hci::ConnectionHandle handle,
sm::SecurityProperties security) override {
PostMessage([this, handle, security] {
if (l2cap_) {
l2cap_->AssignLinkSecurityProperties(handle, security);
}
});
}
void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm,
l2cap::ChannelCallback cb,
async_dispatcher_t* dispatcher) override {
ZX_DEBUG_ASSERT(dispatcher);
PostMessage([this, handle, psm, cb = std::move(cb), dispatcher]() mutable {
if (l2cap_) {
l2cap_->OpenChannel(handle, psm, std::move(cb), dispatcher);
}
});
}
void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm,
SocketCallback socket_callback,
async_dispatcher_t* cb_dispatcher) override {
ZX_DEBUG_ASSERT(cb_dispatcher);
OpenL2capChannel(
handle, psm,
[this, cb = std::move(socket_callback),
cb_dispatcher](auto channel) mutable {
zx::socket s = l2cap_socket_factory_->MakeSocketForChannel(channel);
// Called every time the service is connected, cb must be shared.
async::PostTask(cb_dispatcher,
[s = std::move(s), cb = cb.share(),
handle = channel->link_handle()]() mutable {
cb(std::move(s), handle);
});
},
dispatcher());
}
void RegisterService(l2cap::PSM psm, l2cap::ChannelCallback callback,
async_dispatcher_t* dispatcher) override {
PostMessage([this, psm, callback = std::move(callback),
dispatcher]() mutable {
if (l2cap_) {
const bool result =
l2cap_->RegisterService(psm, std::move(callback), dispatcher);
ZX_DEBUG_ASSERT(result);
} else {
// RegisterService could be called early in host initialization, so log
// cases where L2CAP isn't ready for a service handler.
bt_log(WARN, "l2cap",
"failed to register handler for PSM %#.4x while uninitialized",
psm);
}
});
}
void RegisterService(l2cap::PSM psm, SocketCallback socket_callback,
async_dispatcher_t* cb_dispatcher) override {
RegisterService(
psm, [ this, cb = std::move(socket_callback),
cb_dispatcher ](auto channel) mutable {
zx::socket s = l2cap_socket_factory_->MakeSocketForChannel(channel);
// Called every time the service is connected, cb must be shared.
async::PostTask(cb_dispatcher,
[s = std::move(s), cb = cb.share(),
handle = channel->link_handle()]() mutable {
cb(std::move(s), handle);
});
},
dispatcher());
}
void UnregisterService(l2cap::PSM psm) override {
PostMessage([this, psm] {
if (l2cap_) {
l2cap_->UnregisterService(psm);
}
});
}
private:
void InitializeL2CAP() {
AssertOnDispatcherThread();
l2cap_ = std::make_unique<l2cap::ChannelManager>(hci_, dispatcher());
}
void InitializeRFCOMM() {
AssertOnDispatcherThread();
// |this| is safe to capture here since |rfcomm_| is owned by |this| and the
// delegate callback only runs synchronously on |rfcomm_|'s creation thread
// as a result of OpenRemoteChannel.
rfcomm_ = std::make_unique<rfcomm::ChannelManager>(
[this](hci::ConnectionHandle handle, l2cap::ChannelCallback cb) {
l2cap_->OpenChannel(handle, l2cap::kRFCOMM, std::move(cb),
dispatcher());
});
// Claim the RFCOMM PSM for inbound connections.
auto rfcomm_cb = [self = fbl::WrapRefPtr(this)](auto channel) {
ZX_DEBUG_ASSERT(channel);
if (!self->rfcomm_) {
bt_log(SPEW, "data-domain", "RFCOMM connected after shutdown");
return;
}
if (self->rfcomm_->RegisterL2CAPChannel(std::move(channel))) {
bt_log(TRACE, "data-domain", "RFCOMM session initialized");
} else {
bt_log(ERROR, "data-domain",
"failed to initialize RFCOMM session after L2CAP connection");
}
};
// Registering the RFCOMM PSM immediately after creation should always
// succeed.
bool result = l2cap_->RegisterService(l2cap::kRFCOMM, std::move(rfcomm_cb),
dispatcher());
ZX_ASSERT_MSG(result, "failed to register RFCOMM PSM");
}
// All members below must be accessed on the data domain thread.
// Handle to the underlying HCI transport.
fxl::RefPtr<hci::Transport> hci_;
std::unique_ptr<l2cap::ChannelManager> l2cap_;
std::unique_ptr<rfcomm::ChannelManager> rfcomm_;
// Creates sockets that bridge internal L2CAP channels to profile processes.
std::unique_ptr<internal::SocketFactory<l2cap::Channel>>
l2cap_socket_factory_;
// Creates sockets that bridge internal RFCOMM channels to profile processes.
std::unique_ptr<internal::SocketFactory<rfcomm::Channel>>
rfcomm_socket_factory_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Impl);
};
// static
fbl::RefPtr<Domain> Domain::Create(fxl::RefPtr<hci::Transport> hci,
std::string thread_name) {
ZX_DEBUG_ASSERT(hci);
return AdoptRef(new Impl(hci, std::move(thread_name)));
}
// static
fbl::RefPtr<Domain> Domain::CreateWithDispatcher(
fxl::RefPtr<hci::Transport> hci, async_dispatcher_t* dispatcher) {
ZX_DEBUG_ASSERT(hci);
ZX_DEBUG_ASSERT(dispatcher);
return AdoptRef(new Impl(hci, dispatcher));
}
} // namespace data
} // namespace bt