blob: b0ea532f4e565239821c17d72f0ffaddb9e697e7 [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.
#ifndef GARNET_DRIVERS_BLUETOOTH_LIB_L2CAP_L2CAP_H_
#define GARNET_DRIVERS_BLUETOOTH_LIB_L2CAP_L2CAP_H_
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include "garnet/drivers/bluetooth/lib/l2cap/le_signaling_channel.h"
#include "lib/fxl/macros.h"
namespace btlib {
namespace l2cap {
class Channel;
// This is the root object of the L2CAP layer. It owns the internal blocks of
// L2CAP, including:
//
// * The ChannelManager which handles the ACL > Link > Channel routing and
// signaling;
//
// * Waiting on L2CAP sockets;
//
// A production L2CAP (obtained via L2CAP::Create()) spawns a thread with a
// dispatcher which is used to serially dispatch all internal L2CAP tasks.
//
// L2CAP is defined as a pure-virtual interface, so that a fake can be injected
// while testing layers that depend on it.
//
// L2CAP is thread-safe. All public functions are asynchronous and can be called
// from any thread.
class L2CAP : public fbl::RefCounted<L2CAP> {
public:
using LEConnectionParameterUpdateCallback =
internal::LESignalingChannel::ConnectionParameterUpdateCallback;
using LinkErrorCallback = fit::closure;
// Constructs an uninitialized L2CAP object that can be used in production.
// This spawns a thread on which L2CAP tasks will be scheduled (using
// |thread_name| as the name).
static fbl::RefPtr<L2CAP> Create(fxl::RefPtr<hci::Transport> hci,
std::string thread_name);
// These send a Initialize/Shutdown message to the L2CAP task runner. It is
// safe for the caller to drop its reference after ShutDown is called.
//
// Operations on an uninitialized/shut-down L2CAP have no effect.
virtual void Initialize() = 0;
virtual void ShutDown() = 0;
// Registers an ACL connection with the L2CAP layer. L2CAP channels can be
// opened on the logical link represented by |handle| after a call to this
// method.
//
// |link_error_callback| will be used to notify when a channel signals a link
// error. It will be posted onto |dispatcher|.
//
// Has no effect if L2CAP is uninitialized or shut down.
virtual void AddACLConnection(hci::ConnectionHandle handle,
hci::Connection::Role role,
LinkErrorCallback link_error_callback,
async_dispatcher_t* dispatcher) = 0;
// Registers an LE connection with the L2CAP layer. L2CAP channels can be
// opened on the logical link represented by |handle| after a call to this
// method.
//
// |conn_param_callback| will be used to notify the caller if new connection
// parameters were accepted from the remote end of the link.
//
// |link_error_callback| will be used to notify when a channel signals a link
// error.
//
// Upon successful registration of the link, |channel_callback| will be called
// with the ATT and SMP fixed channels.
//
// Has no effect if L2CAP is uninitialized or shut down.
using AddLEConnectionCallback =
fit::function<void(fbl::RefPtr<Channel> att, fbl::RefPtr<Channel> smp)>;
virtual void AddLEConnection(
hci::ConnectionHandle handle, hci::Connection::Role role,
LEConnectionParameterUpdateCallback conn_param_callback,
LinkErrorCallback link_error_callback,
AddLEConnectionCallback channel_callback,
async_dispatcher_t* dispatcher) = 0;
// 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.
//
// Has no effect if L2CAP is uninitialized or shut down.
virtual void RemoveConnection(hci::ConnectionHandle handle) = 0;
// Open an outbound dynamic channel against a peer's Protocol/Service
// Multiplexing (PSM) code |psm| on a link identified by |handle|.
//
// |cb| will be called on |dispatcher| with the channel created to the remote,
// or nullptr if the channel creation resulted in an error.
//
// Has no effect if L2CAP is uninitialized or shut down.
virtual void OpenChannel(hci::ConnectionHandle handle, PSM psm,
ChannelCallback cb,
async_dispatcher_t* dispatcher) = 0;
// Registers a handler for peer-initiated dynamic channel requests that have
// the Protocol/Service Multiplexing (PSM) code |psm|.
//
// |cb| will be called on |dispatcher| with the channel created by each
// inbound connection request received. Handlers must be unregistered before
// they are replaced.
//
// Returns false if |psm| is invalid or already has a handler registered.
//
// Inbound connection requests with a PSM that has no registered handler will
// be rejected.
//
// Has no effect if L2CAP is uninitialized or shut down.
//
// TODO(xow): NET-1084 Pass in required channel configurations. Call signature
// will likely change.
// TODO(xow): Dynamic PSMs may need their routing space (ACL or LE) identified
virtual bool RegisterService(PSM psm, ChannelCallback cb,
async_dispatcher_t* dispatcher) = 0;
// Removes the handler for inbound channel requests for the previously-
// registered service identified by |psm|. This only prevents new inbound
// channels from being opened but does not close already-open channels.
//
// Has no effect if L2CAP is uninitialized or shut down.
virtual void UnregisterService(PSM psm) = 0;
protected:
friend class fbl::RefPtr<L2CAP>;
L2CAP() = default;
virtual ~L2CAP() = default;
private:
FXL_DISALLOW_COPY_AND_ASSIGN(L2CAP);
};
} // namespace l2cap
} // namespace btlib
#endif // GARNET_DRIVERS_BLUETOOTH_LIB_L2CAP_L2CAP_H_