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