• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   // |fixed_channels_callback| will be called with the fixed channels after
86   // interrogating the peer. Channels not supported by the peer will be null.
87   virtual void AddACLConnection(
88       hci_spec::ConnectionHandle handle,
89       pw::bluetooth::emboss::ConnectionRole role,
90       l2cap::LinkErrorCallback link_error_callback,
91       l2cap::SecurityUpgradeCallback security_callback,
92       fit::callback<void(BrEdrFixedChannels)> fixed_channels_callback) = 0;
93 
94   // Registers an LE connection with the L2CAP layer. L2CAP channels can be
95   // opened on the logical link represented by |handle| after a call to this
96   // method.  It is an error to register the same |handle| value more than once
97   // as either kind of channel without first unregistering it (asserted in debug
98   // builds).
99   //
100   // |conn_param_callback| will be used to notify the caller if new connection
101   // parameters were accepted from the remote end of the link.
102   //
103   // |link_error_callback| will be used to notify when a channel signals a link
104   // error.
105   //
106   // |security_callback| will be used to request an upgrade to the link security
107   // level. This can be triggered by dynamic L2CAP channel creation or by a
108   // service-level client via Channel::UpgradeSecurity().
109   //
110   // Returns the ATT and SMP fixed channels of this link.
111   [[nodiscard]] virtual LEFixedChannels AddLEConnection(
112       hci_spec::ConnectionHandle handle,
113       pw::bluetooth::emboss::ConnectionRole role,
114       l2cap::LinkErrorCallback link_error_callback,
115       l2cap::LEConnectionParameterUpdateCallback conn_param_callback,
116       l2cap::SecurityUpgradeCallback security_callback) = 0;
117 
118   // Removes a previously registered connection. All corresponding Channels will
119   // be closed and all incoming data packets on this link will be dropped.
120   //
121   // NOTE: It is recommended that a link entry be removed AFTER the controller
122   // sends a HCI Disconnection Complete Event for the corresponding logical
123   // link. This is to prevent incorrectly buffering data if the controller has
124   // more packets to send after removing the link entry.
125   virtual void RemoveConnection(hci_spec::ConnectionHandle handle) = 0;
126 
127   // Assigns the security level of a logical link. Has no effect if |handle| has
128   // not been previously registered or the link is closed.
129   virtual void AssignLinkSecurityProperties(
130       hci_spec::ConnectionHandle handle, sm::SecurityProperties security) = 0;
131 
132   // Send an LE Connection Parameter Update Request requesting |params| on the
133   // LE signaling channel of the LE connection represented by |handle|. This
134   // should only be used if the LE peripheral and LE central do not support the
135   // Connection Parameters Request Link Layer Control Procedure (Core Spec v5.2
136   // Vol 3, Part A, Sec 4.20). This should only be called when the local host is
137   // an LE peripheral.
138   //
139   // |request_cb| will be called when a response (acceptance or rejection) is
140   // received.
141   virtual void RequestConnectionParameterUpdate(
142       hci_spec::ConnectionHandle handle,
143       hci_spec::LEPreferredConnectionParameters params,
144       l2cap::ConnectionParameterUpdateRequestCallback request_cb) = 0;
145 
146   // Opens the L2CAP fixed channel with |channel_id| over the logical link
147   // identified by |connection_handle| and starts routing packets.
148   //
149   // Returns nullptr if the channel is already open.
150   virtual Channel::WeakPtr OpenFixedChannel(
151       hci_spec::ConnectionHandle connection_handle, ChannelId channel_id) = 0;
152 
153   // Open an outbound dynamic channel against a peer's Protocol/Service
154   // Multiplexing (PSM) code |psm| on a link identified by |handle| using the
155   // preferred channel parameters |params|. If the peer requires different
156   // higher priority parameters, the local device will accept those instead.
157   //
158   // |cb| will be called with the channel created to the remote, or nullptr if
159   // the channel creation resulted in an error.
160   virtual void OpenL2capChannel(hci_spec::ConnectionHandle handle,
161                                 l2cap::Psm psm,
162                                 l2cap::ChannelParameters params,
163                                 l2cap::ChannelCallback cb) = 0;
164 
165   // Registers a handler for peer-initiated dynamic channel requests that have
166   // the Protocol/Service Multiplexing (PSM) code |psm|. The local device will
167   // attempt to configure these channels using the preferred parameters
168   // |params|, but will accept different channel parameters required by the peer
169   // if they are higher priority.
170   //
171   // |cb| will be called with the channel created by each inbound connection
172   // request received. Handlers must be unregistered before they are replaced.
173   //
174   // Returns false if |psm| is invalid or already has a handler registered.
175   //
176   // Inbound connection requests with a PSM that has no registered handler will
177   // be rejected.
178   //
179   // TODO(fxbug.dev/42181829): Dynamic PSMs may need their routing space (ACL or
180   // LE) identified
181   virtual bool RegisterService(l2cap::Psm psm,
182                                l2cap::ChannelParameters params,
183                                l2cap::ChannelCallback callback) = 0;
184 
185   // Removes the handler for inbound channel requests for the previously-
186   // registered service identified by |psm|. This only prevents new inbound
187   // channels from being opened but does not close already-open channels.
188   virtual void UnregisterService(l2cap::Psm psm) = 0;
189 
190   // Returns a pointer to the internal LogicalLink with the corresponding link
191   // |handle|, or nullptr if none exists. NOTE: This is intended ONLY for unit
192   // tests. Clients should use the other public methods to interact with the
193   // link.
194   virtual WeakSelf<internal::LogicalLink>::WeakPtr LogicalLinkForTesting(
195       hci_spec::ConnectionHandle handle) = 0;
196 };
197 
198 }  // namespace bt::l2cap
199