blob: 3deffb1623205b165bf5100e8169fd6cc6f3a9a3 [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 SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_DYNAMIC_CHANNEL_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_DYNAMIC_CHANNEL_H_
#include <lib/fit/function.h>
#include <memory>
#include "src/connectivity/bluetooth/core/bt-host/l2cap/l2cap_defs.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/types.h"
#include "src/lib/fxl/memory/weak_ptr.h"
namespace bt::l2cap {
struct ChannelParameters;
namespace internal {
class DynamicChannelRegistry;
// Lifetime management and abstract command interface for opening and closing a
// dynamic L2CAP channel. This is an internal object representing an entry in
// and owned by DynamicChannelRegistry and does not implement the outward-facing
// l2cap::Channel interface.
//
// Opening a channel may take multiple steps before data packets can flow. This
// interface uses the terms "connected" and "open" to distinguish between
// connection creation ("connected" but not ready to transfer data) and
// establishment ("connected and open" when configuration completes and can
// transfer data).
//
// For channels opened on ACL-U links, the lifetime is described by Core Spec
// v5.0 Vol 3, Part A, Section 6, "State Machine."
//
// For channels opened on LE-U links, the lifetime of Credit Based Flow Control
// connection-oriented channels is not explicitly described, but operation is
// outlined in Core Spec v5.0 Vol 3, Part A, Section 4.22 to 4.24 "Signaling
// Packet Formats" and Section 10 "Procedures for Credit Based Flow Control."
//
// A channel is considered "not connected and not open" after disconnection by
// either endpoint. There is no "closed but not yet disconnected" state.
//
// This only drives the command transactions over a link's signaling channel to
// manage a specific channel and is not used to send or receive data over that
// channel (it exists in parallel with an bt::l2cap::Channel for that
// purpose). It is intended only to be run from the L2CAP thread.
class DynamicChannel {
public:
// Public dtor for testing (tests can own channels through a base pointer
// without a DynamicChannelRegistry).
virtual ~DynamicChannel() = default;
// For outbound channels: begin a connection then configure the channel upon
// connection. For inbound channels: configure the channel (it is already
// connected if it exists).
//
// |open_result_cb| will be invoked exactly once, when the channel is ready
// for user data transfer or if an error occurred during connection or
// configuration. The caller must check |IsOpen| on this channel. If it's
// false, this channel must be destroyed and not reused. Otherwise, the
// channel is considered open.
virtual void Open(fit::closure open_result_cb) = 0;
// If connected, close the channel. |disconnect_callback| will be called when the peer confirms
// that the channel is disconnected, if the channel is already not connected, or if the
// underlying Signaling Channel times out waiting for the peer confirmation. The owner should then
// destroy this object and not reuse it.
using DisconnectDoneCallback = fit::callback<void()>;
virtual void Disconnect(DisconnectDoneCallback done_cb) = 0;
// If true, both local and remote endpoints are connected and this instance
// shall have valid and unique identifiers.
virtual bool IsConnected() const = 0;
// If true, this channel has been connected, has not been disconnected, and
// can transfer data.
virtual bool IsOpen() const = 0;
// Parameters to use for the outward-facing l2cap::Channel implementation.
virtual ChannelInfo info() const = 0;
// Service identifier provided by the endpoint requesting the channel.
PSM psm() const { return psm_; }
// Identifies the local device's endpoint of this channel. Will be unique on
// this device as long as this channel remains open.
ChannelId local_cid() const { return local_cid_; }
// Identifies the endpoint of this channel on the peer device. Set upon
// connection completion.
ChannelId remote_cid() const { return remote_cid_; }
// True if the channel was ever opened (that is, if |IsOpen| was ever true and
// |Open| provided that result to its caller). Used by DynamicChannelRegistry
// to track channel closure cleanup.
bool opened() const { return opened_; }
protected:
// |registry| points to the registry that created and owns this channel. It
// must be valid for the duration of this object.
DynamicChannel(DynamicChannelRegistry* registry, PSM psm, ChannelId local_cid,
ChannelId remote_cid);
// Signal the registry of a remote-requested closure.
void OnDisconnected();
// Checks remote_cid for validity and uniqueness.
// Returns true on success, false on error.
// bool SetRemoteChannelId(ChannelId remote_cid);
[[nodiscard]] bool SetRemoteChannelId(ChannelId remote_cid);
void set_opened() { opened_ = true; }
DynamicChannelRegistry* registry() { return registry_; }
private:
// Must be valid for the duration of this object.
DynamicChannelRegistry* const registry_;
const PSM psm_;
const ChannelId local_cid_;
ChannelId remote_cid_;
bool opened_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(DynamicChannel);
};
using DynamicChannelPtr = std::unique_ptr<DynamicChannel>;
} // namespace internal
} // namespace bt::l2cap
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_DYNAMIC_CHANNEL_H_