blob: 0c1f3512b1100b44d32dddcc262ccb99d49a118b [file] [log] [blame]
// Copyright 2017 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.
#pragma once
#include <memory>
#include <mutex>
#include <unordered_map>
#include <zircon/compiler.h>
#include "garnet/drivers/bluetooth/lib/common/cancelable_callback.h"
#include "garnet/drivers/bluetooth/lib/hci/acl_data_packet.h"
#include "garnet/drivers/bluetooth/lib/hci/connection.h"
#include "garnet/drivers/bluetooth/lib/hci/hci.h"
#include "garnet/drivers/bluetooth/lib/l2cap/channel.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/ref_ptr.h"
#include "lib/fxl/synchronization/thread_checker.h"
#include "lib/fxl/tasks/task_runner.h"
namespace bluetooth {
namespace hci {
class Transport;
} // namespace hci
namespace l2cap {
namespace internal {
class LogicalLink;
} // namespace internal
// ChannelManager implements the "Channel Manager" control block of L2CAP. In
// particular:
//
// * It acts as a routing table for incoming ACL data by directing packets to
// the appropriate internal logical link handler;
//
// * Manages priority based scheduling.
//
// * Provides an API surface for L2CAP channel creation and logical link
// management bound to a single creation thread.
//
// There is a single instance of ChannelManager for each HCI transport.
class ChannelManager final {
public:
ChannelManager(fxl::RefPtr<hci::Transport> hci,
fxl::RefPtr<fxl::TaskRunner> task_runner);
~ChannelManager();
// Registers the given connection with the L2CAP layer. L2CAP channels can be
// opened on the logical link represented by |handle| after a call to this
// method.
//
// It is an error to register the same |handle| value more than once without
// first unregistering it (this is asserted in debug builds).
void Register(hci::ConnectionHandle handle,
hci::Connection::LinkType ll_type,
hci::Connection::Role role);
// Removes a previously registered connection. All corresponding Channels will
// be closed and all incoming data packets on this link will be dropped.
//
// NOTE: It is recommended that a link entry be removed AFTER the controller
// sends a HCI Disconnection Complete Event for the corresponding logical
// link. This is to prevent incorrectly buffering data if the controller has
// more packets to send after removing the link entry.
void Unregister(hci::ConnectionHandle handle);
// Opens the L2CAP fixed channel with |channel_id| over the logical link
// identified by |connection_handle| and starts routing packets. Returns
// nullptr if the channel is already open.
//
// See channel.h for documentation on |rx_callback| and |closed_callback|.
// |rx_callback| is always posted on |rx_task_runner|. |closed_callback|
// always runs on the thread that created this ChannelManager.
std::unique_ptr<Channel> OpenFixedChannel(
hci::ConnectionHandle connection_handle,
ChannelId channel_id);
private:
// Called when an ACL data packet is received from the controller. This method
// is responsible for routing the packet to the corresponding LogicalLink.
void OnACLDataReceived(hci::ACLDataPacketPtr data_packet);
fxl::RefPtr<hci::Transport> hci_;
fxl::RefPtr<fxl::TaskRunner> task_runner_;
std::mutex mtx_;
std::unordered_map<hci::ConnectionHandle,
std::unique_ptr<internal::LogicalLink>>
ll_map_ __TA_GUARDED(mtx_);
// Stores packets received on a connection handle before a link for it has
// been created.
using PendingPacketMap =
std::unordered_map<hci::ConnectionHandle,
fbl::DoublyLinkedList<hci::ACLDataPacketPtr>>;
PendingPacketMap pending_packets_ __TA_GUARDED(mtx_);
common::CancelableCallbackFactory<void()> cancelable_callback_factory_;
fxl::ThreadChecker thread_checker_;
FXL_DISALLOW_COPY_AND_ASSIGN(ChannelManager);
};
} // namespace l2cap
} // namespace bluetooth