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