blob: 935546c833d6656d57a61ba294f4e4af93604dc8 [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 <src/lib/fxl/memory/weak_ptr.h>
#include <memory>
#include "src/connectivity/bluetooth/core/bt-host/l2cap/l2cap.h"
namespace bt {
namespace l2cap {
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;
// Close the channel and notify the remote of the closure if already
// connected. The owner should then destroy this object and not reuse it.
virtual void Disconnect() = 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;
// 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();
// TODO(NET-1320): This should query its DynamicChannelRegistry for uniqueness
// among open dynamic channels of this remote ID.
void set_remote_cid(ChannelId remote_cid) { remote_cid_ = remote_cid; }
void set_opened() { opened_ = true; }
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 l2cap
} // namespace bt
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_DYNAMIC_CHANNEL_H_