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