1 // Copyright 2023 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #pragma once 16 #include <lib/fit/function.h> 17 18 #include <memory> 19 20 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h" 21 #include "pw_bluetooth_sapphire/internal/host/l2cap/types.h" 22 23 namespace bt::l2cap { 24 25 struct ChannelParameters; 26 27 namespace internal { 28 29 class DynamicChannelRegistry; 30 31 // Lifetime management and abstract command interface for opening and closing a 32 // dynamic L2CAP channel. This is an internal object representing an entry in 33 // and owned by DynamicChannelRegistry and does not implement the outward-facing 34 // l2cap::Channel interface. 35 // 36 // Opening a channel may take multiple steps before data packets can flow. This 37 // interface uses the terms "connected" and "open" to distinguish between 38 // connection creation ("connected" but not ready to transfer data) and 39 // establishment ("connected and open" when configuration completes and can 40 // transfer data). 41 // 42 // For channels opened on ACL-U links, the lifetime is described by Core Spec 43 // v5.0 Vol 3, Part A, Section 6, "State Machine." 44 // 45 // For channels opened on LE-U links, the lifetime of Credit Based Flow Control 46 // connection-oriented channels is not explicitly described, but operation is 47 // outlined in Core Spec v5.0 Vol 3, Part A, Section 4.22 to 4.24 "Signaling 48 // Packet Formats" and Section 10 "Procedures for Credit Based Flow Control." 49 // 50 // A channel is considered "not connected and not open" after disconnection by 51 // either endpoint. There is no "closed but not yet disconnected" state. 52 // 53 // This only drives the command transactions over a link's signaling channel to 54 // manage a specific channel and is not used to send or receive data over that 55 // channel (it exists in parallel with an bt::l2cap::Channel for that 56 // purpose). It is intended only to be run from the L2CAP thread. 57 class DynamicChannel { 58 public: 59 // Public dtor for testing (tests can own channels through a base pointer 60 // without a DynamicChannelRegistry). 61 virtual ~DynamicChannel() = default; 62 63 // For outbound channels: begin a connection then configure the channel upon 64 // connection. For inbound channels: configure the channel (it is already 65 // connected if it exists). 66 // 67 // |open_result_cb| will be invoked exactly once, when the channel is ready 68 // for user data transfer or if an error occurred during connection or 69 // configuration. The caller must check |IsOpen| on this channel. If it's 70 // false, this channel must be destroyed and not reused. Otherwise, the 71 // channel is considered open. 72 virtual void Open(fit::closure open_result_cb) = 0; 73 74 // If connected, close the channel. |disconnect_callback| will be called when 75 // the peer confirms that the channel is disconnected, if the channel is 76 // already not connected, or if the underlying Signaling Channel times out 77 // waiting for the peer confirmation. The owner should then destroy this 78 // object and not reuse it. 79 using DisconnectDoneCallback = fit::callback<void()>; 80 virtual void Disconnect(DisconnectDoneCallback done_cb) = 0; 81 82 // If true, both local and remote endpoints are connected and this instance 83 // shall have valid and unique identifiers. 84 virtual bool IsConnected() const = 0; 85 86 // If true, this channel has been connected, has not been disconnected, and 87 // can transfer data. 88 virtual bool IsOpen() const = 0; 89 90 // Parameters to use for the outward-facing l2cap::Channel implementation. 91 virtual ChannelInfo info() const = 0; 92 93 // Service identifier provided by the endpoint requesting the channel. psm()94 Psm psm() const { return psm_; } 95 96 // Identifies the local device's endpoint of this channel. Will be unique on 97 // this device as long as this channel remains open. local_cid()98 ChannelId local_cid() const { return local_cid_; } 99 100 // Identifies the endpoint of this channel on the peer device. Set upon 101 // connection completion. remote_cid()102 ChannelId remote_cid() const { return remote_cid_; } 103 104 // True if the channel was ever opened (that is, if |IsOpen| was ever true and 105 // |Open| provided that result to its caller). Used by DynamicChannelRegistry 106 // to track channel closure cleanup. opened()107 bool opened() const { return opened_; } 108 109 protected: 110 // |registry| points to the registry that created and owns this channel. It 111 // must be valid for the duration of this object. 112 DynamicChannel(DynamicChannelRegistry* registry, 113 Psm psm, 114 ChannelId local_cid, 115 ChannelId remote_cid); 116 117 // Signal the registry of a remote-requested closure. 118 void OnDisconnected(); 119 120 // Checks remote_cid for validity and uniqueness. 121 // Returns true on success, false on error. 122 // bool SetRemoteChannelId(ChannelId remote_cid); 123 [[nodiscard]] bool SetRemoteChannelId(ChannelId remote_cid); 124 set_opened()125 void set_opened() { opened_ = true; } 126 registry()127 DynamicChannelRegistry* registry() { return registry_; } 128 129 private: 130 // Must be valid for the duration of this object. 131 DynamicChannelRegistry* const registry_; 132 133 const Psm psm_; 134 const ChannelId local_cid_; 135 ChannelId remote_cid_; 136 bool opened_; 137 138 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(DynamicChannel); 139 }; 140 141 using DynamicChannelPtr = std::unique_ptr<DynamicChannel>; 142 143 } // namespace internal 144 } // namespace bt::l2cap 145