| // 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_DATA_DOMAIN_H_ |
| #define GARNET_DRIVERS_BLUETOOTH_LIB_DATA_DOMAIN_H_ |
| |
| #include <fbl/ref_counted.h> |
| #include <fbl/ref_ptr.h> |
| #include <lib/zx/socket.h> |
| |
| #include "garnet/drivers/bluetooth/lib/hci/transport.h" |
| #include "garnet/drivers/bluetooth/lib/l2cap/l2cap.h" |
| #include "lib/fxl/macros.h" |
| |
| namespace btlib { |
| namespace data { |
| |
| // Represents the task domain that implements the host subsystem's data plane. |
| // This domain owns its own thread on which data-path tasks are dispatched. |
| // Protocols implemented here are: |
| // |
| // a. L2CAP and SCO. |
| // b. RFCOMM. |
| // c. Data sockets that bridge out-of-process users to above protocols. |
| // |
| // Interactions between the data domain and other library threads is performed |
| // primarily via message passing. |
| class Domain : public fbl::RefCounted<Domain> { |
| public: |
| // Constructs an uninitialized data domain that can be used in production. |
| // This spawns a thread on which data-domain tasks will be scheduled. |
| static fbl::RefPtr<Domain> Create(fxl::RefPtr<hci::Transport> hci, |
| std::string thread_name); |
| |
| // Constructs an instance using the given |dispatcher| instead of spawning a |
| // thread. This is intended for unit tests. |
| static fbl::RefPtr<Domain> CreateWithDispatcher( |
| fxl::RefPtr<hci::Transport> hci, async_dispatcher_t* dispatcher); |
| |
| // These send an Initialize/ShutDown message to the data task runner. It is |
| // safe for the caller to drop its Domain reference after ShutDown is called. |
| // |
| // Operations on an uninitialized or shut-down Domain 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|. |
| // |
| // |security_callback| will be used to request an upgrade to the link security |
| // level. This can be triggered by dynamic L2CAP channel creation or by a |
| // service-level client via Channel::UpgradeSecurity(). |
| // |
| // Has no effect if this Domain is uninitialized or shut down. |
| virtual void AddACLConnection( |
| hci::ConnectionHandle handle, hci::Connection::Role role, |
| l2cap::LinkErrorCallback link_error_callback, |
| l2cap::SecurityUpgradeCallback security_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. |
| // |
| // |security_callback| will be used to request an upgrade to the link security |
| // level. This can be triggered by dynamic L2CAP channel creation or by a |
| // service-level client via Channel::UpgradeSecurity(). |
| // |
| // Upon successful registration of the link, |channel_callback| will be called |
| // with the ATT and SMP fixed channels. |
| // |
| // Has no effect if this Domain is uninitialized or shut down. |
| virtual 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) = 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 this Domain is uninitialized or shut down. |
| virtual void RemoveConnection(hci::ConnectionHandle handle) = 0; |
| |
| // Assigns the security level of a logical link. Has no effect if |handle| has |
| // not been previously registered or the link is closed. |
| virtual void AssignLinkSecurityProperties( |
| hci::ConnectionHandle handle, sm::SecurityProperties security) = 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 this Domain is uninitialized or shut down. |
| virtual void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm, |
| l2cap::ChannelCallback cb, |
| async_dispatcher_t* dispatcher) = 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 a zx::socket corresponding to the |
| // channel created to the remote or ZX_INVALID_HANDLE if the channel creation |
| // resulted in an error. |
| // |
| // Has no effect if this Domain is uninitialized or shut down. |
| using SocketCallback = |
| fit::function<void(zx::socket, hci::ConnectionHandle link_handle)>; |
| virtual void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm, |
| SocketCallback socket_callback, |
| 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 this Domain 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 void RegisterService(l2cap::PSM psm, l2cap::ChannelCallback callback, |
| async_dispatcher_t* dispatcher) = 0; |
| |
| // Similar to RegisterService, but instead of providing a l2cap::Channel, |
| // provides a zx::socket which can be used to communicate on the channel. |
| // The underlying l2cap::Channel is activated; the socket provided will |
| // receive any data sent to the channel and any data sent to the socket |
| // will be sent as if sent by l2cap::Channel::Send. |
| // |link_handle| disambiguates which remote device initiated the channel. |
| // |
| // TODO(armansito): Return the socket in a data structure that contains |
| // additional meta-data about the connection, such as its link type and |
| // channel configuration parameters (see NET-1084 and TODOs for |
| // RegisterService above. |
| virtual void RegisterService(l2cap::PSM psm, SocketCallback socket_callback, |
| 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 this Domain is uninitialized or shut down. |
| virtual void UnregisterService(l2cap::PSM psm) = 0; |
| |
| protected: |
| friend class fbl::RefPtr<Domain>; |
| Domain() = default; |
| virtual ~Domain() = default; |
| |
| private: |
| FXL_DISALLOW_COPY_AND_ASSIGN(Domain); |
| }; |
| |
| } // namespace data |
| } // namespace btlib |
| |
| #endif // GARNET_DRIVERS_BLUETOOTH_LIB_DATA_DOMAIN_H_ |