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 <memory>
17 #include <unordered_map>
18 
19 #include "pw_bluetooth_sapphire/internal/host/common/inspect.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
21 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel.h"
23 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
24 #include "pw_bluetooth_sapphire/internal/host/l2cap/le_signaling_channel.h"
25 #include "pw_bluetooth_sapphire/internal/host/l2cap/types.h"
26 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_channel.h"
27 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_packet.h"
28 #include "pw_bluetooth_sapphire/internal/host/transport/link_type.h"
29 
30 namespace bt::l2cap {
31 
32 // ChannelManager implements the "Channel Manager" control block of L2CAP. In
33 // particular:
34 //
35 //   * It acts as a routing table for incoming ACL data by directing packets to
36 //     the appropriate internal logical link handler;
37 //
38 //   * Manages priority based scheduling.
39 //
40 //   * Provides an API surface for L2CAP channel creation and logical link
41 //     management bound to a single creation thread.
42 //
43 // There can be a single instance of ChannelManager for a HCI transport.
44 class ChannelManager {
45  public:
46   // Information stored and returned for registered services that is needed to
47   // configure and forward new channels for this service.
48   using ServiceInfo = ServiceInfo<ChannelCallback>;
49 
50   struct LEFixedChannels {
51     l2cap::Channel::WeakPtr att;
52     l2cap::Channel::WeakPtr smp;
53   };
54 
55   struct BrEdrFixedChannels {
56     l2cap::Channel::WeakPtr smp;
57   };
58 
59   // Create a ChannelManager. FakeL2cap can be used instead in tests.
60   static std::unique_ptr<ChannelManager> Create(
61       hci::AclDataChannel* acl_data_channel,
62       hci::CommandChannel* cmd_channel,
63       bool random_channel_ids,
64       pw::async::Dispatcher& dispatcher);
65 
66   virtual ~ChannelManager() = default;
67 
68   // Attach ChannelManager's inspect node as a child of |parent| with the given
69   // |name|
70   static constexpr const char* kInspectNodeName = "l2cap";
71   virtual void AttachInspect(inspect::Node& parent, std::string name) = 0;
72 
73   // Registers an ACL connection with the L2CAP layer. L2CAP channels can be
74   // opened on the logical link represented by |handle| after a call to this
75   // method. It is an error to register the same |handle| value more than once
76   // as either kind of channel without first unregistering it.
77   //
78   // |link_error_callback| will be used to notify when a channel signals a link
79   // error.
80   //
81   // |security_callback| will be used to request an upgrade to the link security
82   // level. This can be triggered by dynamic L2CAP channel creation or by a
83   // service-level client via Channel::UpgradeSecurity().
84   //
85   // Returns the fixed channels of this link.
86   virtual BrEdrFixedChannels AddACLConnection(
87       hci_spec::ConnectionHandle handle,
88       pw::bluetooth::emboss::ConnectionRole role,
89       l2cap::LinkErrorCallback link_error_callback,
90       l2cap::SecurityUpgradeCallback security_callback) = 0;
91 
92   // Registers an LE connection with the L2CAP layer. L2CAP channels can be
93   // opened on the logical link represented by |handle| after a call to this
94   // method.  It is an error to register the same |handle| value more than once
95   // as either kind of channel without first unregistering it (asserted in debug
96   // builds).
97   //
98   // |conn_param_callback| will be used to notify the caller if new connection
99   // parameters were accepted from the remote end of the link.
100   //
101   // |link_error_callback| will be used to notify when a channel signals a link
102   // error.
103   //
104   // |security_callback| will be used to request an upgrade to the link security
105   // level. This can be triggered by dynamic L2CAP channel creation or by a
106   // service-level client via Channel::UpgradeSecurity().
107   //
108   // Returns the ATT and SMP fixed channels of this link.
109   [[nodiscard]] virtual LEFixedChannels AddLEConnection(
110       hci_spec::ConnectionHandle handle,
111       pw::bluetooth::emboss::ConnectionRole role,
112       l2cap::LinkErrorCallback link_error_callback,
113       l2cap::LEConnectionParameterUpdateCallback conn_param_callback,
114       l2cap::SecurityUpgradeCallback security_callback) = 0;
115 
116   // Removes a previously registered connection. All corresponding Channels will
117   // be closed and all incoming data packets on this link will be dropped.
118   //
119   // NOTE: It is recommended that a link entry be removed AFTER the controller
120   // sends a HCI Disconnection Complete Event for the corresponding logical
121   // link. This is to prevent incorrectly buffering data if the controller has
122   // more packets to send after removing the link entry.
123   virtual void RemoveConnection(hci_spec::ConnectionHandle handle) = 0;
124 
125   // Assigns the security level of a logical link. Has no effect if |handle| has
126   // not been previously registered or the link is closed.
127   virtual void AssignLinkSecurityProperties(
128       hci_spec::ConnectionHandle handle, sm::SecurityProperties security) = 0;
129 
130   // Send an LE Connection Parameter Update Request requesting |params| on the
131   // LE signaling channel of the LE connection represented by |handle|. This
132   // should only be used if the LE peripheral and LE central do not support the
133   // Connection Parameters Request Link Layer Control Procedure (Core Spec v5.2
134   // Vol 3, Part A, Sec 4.20). This should only be called when the local host is
135   // an LE peripheral.
136   //
137   // |request_cb| will be called when a response (acceptance or rejection) is
138   // received.
139   virtual void RequestConnectionParameterUpdate(
140       hci_spec::ConnectionHandle handle,
141       hci_spec::LEPreferredConnectionParameters params,
142       l2cap::ConnectionParameterUpdateRequestCallback request_cb) = 0;
143 
144   // Opens the L2CAP fixed channel with |channel_id| over the logical link
145   // identified by |connection_handle| and starts routing packets.
146   //
147   // Returns nullptr if the channel is already open.
148   virtual Channel::WeakPtr OpenFixedChannel(
149       hci_spec::ConnectionHandle connection_handle, ChannelId channel_id) = 0;
150 
151   // Open an outbound dynamic channel against a peer's Protocol/Service
152   // Multiplexing (PSM) code |psm| on a link identified by |handle| using the
153   // preferred channel parameters |params|. If the peer requires different
154   // higher priority parameters, the local device will accept those instead.
155   //
156   // |cb| will be called with the channel created to the remote, or nullptr if
157   // the channel creation resulted in an error.
158   virtual void OpenL2capChannel(hci_spec::ConnectionHandle handle,
159                                 l2cap::Psm psm,
160                                 l2cap::ChannelParameters params,
161                                 l2cap::ChannelCallback cb) = 0;
162 
163   // Registers a handler for peer-initiated dynamic channel requests that have
164   // the Protocol/Service Multiplexing (PSM) code |psm|. The local device will
165   // attempt to configure these channels using the preferred parameters
166   // |params|, but will accept different channel parameters required by the peer
167   // if they are higher priority.
168   //
169   // |cb| will be called with the channel created by each inbound connection
170   // request received. Handlers must be unregistered before they are replaced.
171   //
172   // Returns false if |psm| is invalid or already has a handler registered.
173   //
174   // Inbound connection requests with a PSM that has no registered handler will
175   // be rejected.
176   //
177   // TODO(fxbug.dev/42181829): Dynamic PSMs may need their routing space (ACL or
178   // LE) identified
179   virtual bool RegisterService(l2cap::Psm psm,
180                                l2cap::ChannelParameters params,
181                                l2cap::ChannelCallback callback) = 0;
182 
183   // Removes the handler for inbound channel requests for the previously-
184   // registered service identified by |psm|. This only prevents new inbound
185   // channels from being opened but does not close already-open channels.
186   virtual void UnregisterService(l2cap::Psm psm) = 0;
187 
188   // Returns a pointer to the internal LogicalLink with the corresponding link
189   // |handle|, or nullptr if none exists. NOTE: This is intended ONLY for unit
190   // tests. Clients should use the other public methods to interact with the
191   // link.
192   virtual WeakSelf<internal::LogicalLink>::WeakPtr LogicalLinkForTesting(
193       hci_spec::ConnectionHandle handle) = 0;
194 };
195 
196 }  // namespace bt::l2cap
197