| // 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" |
| |
| namespace bt { |
| namespace data { |
| |
| class Impl final : public Domain { |
| public: |
| Impl(fxl::RefPtr<hci::Transport> hci, inspect::Node node) |
| : Domain(), dispatcher_(async_get_default_dispatcher()), node_(std::move(node)), hci_(hci) { |
| ZX_ASSERT(hci_); |
| ZX_ASSERT(hci_->acl_data_channel()); |
| const auto& acl_buffer_info = hci_->acl_data_channel()->GetBufferInfo(); |
| const auto& le_buffer_info = hci_->acl_data_channel()->GetLEBufferInfo(); |
| |
| // LE Buffer Info is always available from ACLDataChannel. |
| ZX_ASSERT(acl_buffer_info.IsAvailable()); |
| auto send_packets = |
| fit::bind_member(hci_->acl_data_channel(), &hci::ACLDataChannel::SendPackets); |
| auto drop_queued_acl = |
| fit::bind_member(hci_->acl_data_channel(), &hci::ACLDataChannel::DropQueuedPackets); |
| |
| channel_manager_ = std::make_unique<l2cap::ChannelManager>( |
| acl_buffer_info.max_data_length(), le_buffer_info.max_data_length(), |
| std::move(send_packets), std::move(drop_queued_acl), dispatcher_); |
| hci_->acl_data_channel()->SetDataRxHandler(channel_manager_->MakeInboundDataHandler(), |
| dispatcher_); |
| |
| l2cap_socket_factory_ = std::make_unique<internal::SocketFactory<l2cap::Channel>>(); |
| |
| bt_log(TRACE, "data-domain", "initialized"); |
| } |
| |
| ~Impl() { |
| bt_log(TRACE, "data-domain", "shutting down"); |
| l2cap_socket_factory_ = nullptr; |
| |
| ZX_ASSERT(hci_->acl_data_channel()); |
| hci_->acl_data_channel()->SetDataRxHandler(nullptr, nullptr); |
| |
| channel_manager_ = nullptr; |
| } |
| |
| void AddACLConnection(hci::ConnectionHandle handle, hci::Connection::Role role, |
| l2cap::LinkErrorCallback link_error_callback, |
| l2cap::SecurityUpgradeCallback security_callback) override { |
| channel_manager_->RegisterACL(handle, role, std::move(link_error_callback), |
| std::move(security_callback)); |
| } |
| |
| 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) override { |
| channel_manager_->RegisterLE(handle, role, std::move(conn_param_callback), |
| std::move(link_error_callback), std::move(security_callback)); |
| |
| auto att = channel_manager_->OpenFixedChannel(handle, l2cap::kATTChannelId); |
| auto smp = channel_manager_->OpenFixedChannel(handle, l2cap::kLESMPChannelId); |
| ZX_ASSERT(att); |
| ZX_ASSERT(smp); |
| channel_callback(std::move(att), std::move(smp)); |
| } |
| |
| void RemoveConnection(hci::ConnectionHandle handle) override { |
| channel_manager_->Unregister(handle); |
| } |
| |
| void AssignLinkSecurityProperties(hci::ConnectionHandle handle, |
| sm::SecurityProperties security) override { |
| channel_manager_->AssignLinkSecurityProperties(handle, security); |
| } |
| |
| void RequestConnectionParameterUpdate(hci::ConnectionHandle handle, |
| hci::LEPreferredConnectionParameters params, |
| l2cap::ConnectionParameterUpdateRequestCallback request_cb, |
| async_dispatcher_t* dispatcher) override { |
| channel_manager_->RequestConnectionParameterUpdate(handle, params, std::move(request_cb), |
| dispatcher); |
| } |
| |
| void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm, |
| l2cap::ChannelParameters params, l2cap::ChannelCallback cb, |
| async_dispatcher_t* dispatcher) override { |
| ZX_DEBUG_ASSERT(dispatcher); |
| channel_manager_->OpenChannel(handle, psm, params, std::move(cb), dispatcher); |
| } |
| |
| void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm, |
| l2cap::ChannelParameters params, SocketCallback socket_callback, |
| async_dispatcher_t* cb_dispatcher) override { |
| ZX_DEBUG_ASSERT(cb_dispatcher); |
| OpenL2capChannel( |
| handle, psm, params, |
| [this, handle, cb = std::move(socket_callback), cb_dispatcher](auto channel) mutable { |
| // MakeSocketForChannel makes invalid sockets for null channels (i.e. |
| // that have failed to open). |
| zx::socket s = l2cap_socket_factory_->MakeSocketForChannel(channel); |
| auto chan_info = channel ? std::optional(channel->info()) : std::nullopt; |
| l2cap::ChannelSocket chan_sock(std::move(s), chan_info); |
| async::PostTask(cb_dispatcher, [chan_sock = std::move(chan_sock), cb = std::move(cb), |
| handle]() mutable { cb(std::move(chan_sock), handle); }); |
| }, |
| dispatcher_); |
| } |
| |
| void RegisterService(l2cap::PSM psm, l2cap::ChannelParameters params, |
| l2cap::ChannelCallback callback, async_dispatcher_t* dispatcher) override { |
| const bool result = |
| channel_manager_->RegisterService(psm, params, std::move(callback), dispatcher); |
| ZX_DEBUG_ASSERT(result); |
| } |
| |
| void RegisterService(l2cap::PSM psm, l2cap::ChannelParameters params, |
| SocketCallback socket_callback, async_dispatcher_t* cb_dispatcher) override { |
| RegisterService( |
| psm, params, |
| [this, cb = std::move(socket_callback), cb_dispatcher](auto channel) mutable { |
| zx::socket s = l2cap_socket_factory_->MakeSocketForChannel(channel); |
| auto chan_info = channel ? std::optional(channel->info()) : std::nullopt; |
| l2cap::ChannelSocket chan_sock(std::move(s), chan_info); |
| // Called every time the service is connected, cb must be shared. |
| async::PostTask(cb_dispatcher, [sock = std::move(chan_sock), cb = cb.share(), |
| handle = channel->link_handle()]() mutable { |
| cb(std::move(sock), handle); |
| }); |
| }, |
| dispatcher_); |
| } |
| |
| void UnregisterService(l2cap::PSM psm) override { channel_manager_->UnregisterService(psm); } |
| |
| private: |
| async_dispatcher_t* dispatcher_; |
| |
| // Inspect hierarchy node representing the data domain. |
| inspect::Node node_; |
| |
| // Handle to the underlying HCI transport. |
| fxl::RefPtr<hci::Transport> hci_; |
| |
| std::unique_ptr<l2cap::ChannelManager> channel_manager_; |
| |
| // Creates sockets that bridge internal L2CAP channels to profile processes. |
| std::unique_ptr<internal::SocketFactory<l2cap::Channel>> l2cap_socket_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Impl); |
| }; |
| |
| // static |
| fbl::RefPtr<Domain> Domain::Create(fxl::RefPtr<hci::Transport> hci, inspect::Node node) { |
| ZX_DEBUG_ASSERT(hci); |
| return AdoptRef(new Impl(hci, std::move(node))); |
| } |
| |
| } // namespace data |
| } // namespace bt |