1 // Copyright 2024 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 17 #include "pw_bluetooth_proxy/gatt_notify_channel.h" 18 #include "pw_bluetooth_proxy/internal/acl_data_channel.h" 19 #include "pw_bluetooth_proxy/internal/h4_storage.h" 20 #include "pw_bluetooth_proxy/internal/hci_transport.h" 21 #include "pw_bluetooth_proxy/internal/l2cap_channel_manager.h" 22 #include "pw_bluetooth_proxy/l2cap_channel_common.h" 23 #include "pw_bluetooth_proxy/l2cap_coc.h" 24 #include "pw_bluetooth_proxy/l2cap_status_delegate.h" 25 #include "pw_bluetooth_proxy/rfcomm_channel.h" 26 #include "pw_status/status.h" 27 28 namespace pw::bluetooth::proxy { 29 30 /// `ProxyHost` acts as the main coordinator for proxy functionality. After 31 /// creation, the container then passes packets through the proxy. 32 class ProxyHost { 33 public: 34 /// Creates an `ProxyHost` that will process HCI packets. 35 /// @param[in] send_to_host_fn Callback that will be called when proxy wants 36 /// to send HCI packet towards the host. 37 /// @param[in] send_to_controller_fn - Callback that will be called when 38 /// proxy wants to send HCI packet towards the controller. 39 /// @param[in] le_acl_credits_to_reserve - How many buffers to reserve for the 40 /// proxy out of any LE ACL buffers received from controller. 41 /// @param[in] br_edr_acl_credits_to_reserve - How many buffers to reserve for 42 /// the proxy out of any BR/EDR ACL buffers received from controller. 43 ProxyHost(pw::Function<void(H4PacketWithHci&& packet)>&& send_to_host_fn, 44 pw::Function<void(H4PacketWithH4&& packet)>&& send_to_controller_fn, 45 uint16_t le_acl_credits_to_reserve, 46 uint16_t br_edr_acl_credits_to_reserve); 47 48 ProxyHost() = delete; 49 ProxyHost(const ProxyHost&) = delete; 50 ProxyHost& operator=(const ProxyHost&) = delete; 51 ProxyHost(ProxyHost&&) = delete; 52 ProxyHost& operator=(ProxyHost&&) = delete; 53 /// Deregisters all channels, and if any channels are not yet closed, closes 54 /// them and sends `L2capChannelEvent::kChannelClosedByOther`. 55 ~ProxyHost(); 56 57 // ##### Container API 58 // Containers are expected to call these functions (in addition to ctor). 59 60 /// Called by container to ask proxy to handle a H4 HCI packet sent from the 61 /// host side towards the controller side. Proxy will in turn call the 62 /// `send_to_controller_fn` provided during construction to pass the packet 63 /// on to the controller. Some packets may be modified, added, or removed. 64 /// 65 /// The proxy host currently does not require any from-host packets to support 66 /// its current functionality. It will pass on all packets, so containers can 67 /// choose to just pass all from-host packets through it. 68 /// 69 /// Container is required to call this function synchronously (one packet at a 70 /// time). 71 void HandleH4HciFromHost(H4PacketWithH4&& h4_packet); 72 73 /// Called by container to ask proxy to handle a H4 packet sent from the 74 /// controller side towards the host side. Proxy will in turn call the 75 /// `send_to_host_fn` provided during construction to pass the packet on to 76 /// the host. Some packets may be modified, added, or removed. 77 /// 78 /// To support all of its current functionality, the proxy host needs at least 79 /// the following from-controller packets passed through it. It will pass on 80 /// all other packets, so containers can choose to just pass all 81 /// from-controller packets through the proxy host. 82 /// 83 /// All packets of this type: 84 /// - L2CAP over ACL packets (specifically those addressed to channels managed 85 /// by the proxy host, including signaling packets) 86 /// 87 /// HCI_Command_Complete events (7.7.14) containing return parameters for 88 /// these commands: 89 /// - HCI_LE_Read_Buffer_Size [v1] command (7.8.2) 90 /// - HCI_LE_Read_Buffer_Size [v2] command (7.8.2) 91 /// 92 /// These HCI event packets: 93 /// - HCI_Number_Of_Completed_Packets event (7.7.19) 94 /// - HCI_Disconnection_Complete event (7.7.5) 95 /// 96 /// Container is required to call this function synchronously (one packet at a 97 /// time). 98 void HandleH4HciFromController(H4PacketWithHci&& h4_packet); 99 100 /// Called when an HCI_Reset Command packet is observed. Proxy resets its 101 /// internal state. Deregisters all channels, and if any channels are not yet 102 /// closed, closes them and sends `L2capChannelEvent::kReset`. 103 /// 104 /// May also be called by container to notify proxy that the Bluetooth system 105 /// is being otherwise reset. 106 /// 107 /// Warning: Outstanding H4 packets are not invalidated upon reset. If they 108 /// are destructed post-reset, packets generated post-reset are liable to be 109 /// overwritten prematurely. 110 void Reset(); 111 112 // ##### Client APIs 113 114 /// Register for notifications of connection and disconnection for a 115 /// particular L2cap service identified by its PSM. 116 /// 117 /// @param[in] delegate A delegate that will be notified when a successful 118 /// L2cap connection is made on its PSM. Note: This 119 /// must outlive the ProxyHost. 120 void RegisterL2capStatusDelegate(L2capStatusDelegate& delegate); 121 122 /// Unregister a service delegate. 123 /// 124 /// @param[in] delegate The delegate to unregister. Must have been 125 /// previously registered. 126 void UnregisterL2capStatusDelegate(L2capStatusDelegate& delegate); 127 128 /// Returns an L2CAP connection-oriented channel that supports writing to and 129 /// reading from a remote peer. 130 /// 131 /// @param[in] rx_multibuf_allocator 132 /// Provides the allocator the channel will use 133 /// for its Rx buffers (for both queueing and 134 /// returning to the client). 135 /// 136 /// @param[in] connection_handle The connection handle of the remote peer. 137 /// 138 /// @param[in] rx_config Parameters applying to reading packets. See 139 /// `l2cap_coc.h` for details. 140 /// 141 /// @param[in] tx_config Parameters applying to writing packets. See 142 /// `l2cap_coc.h` for details. 143 /// 144 /// @param[in] receive_fn Read callback to be invoked on Rx SDUs. 145 /// 146 /// @param[in] event_fn Handle asynchronous events such as errors and 147 /// flow control events encountered by the 148 /// channel. See `l2cap_channel_event.h`. 149 /// 150 /// @returns @rst 151 /// 152 /// .. pw-status-codes:: 153 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 154 /// UNAVAILABLE: If channel could not be created because no memory was 155 /// available to accommodate an additional ACL connection. 156 /// @endrst 157 pw::Result<L2capCoc> AcquireL2capCoc( 158 pw::multibuf::MultiBufAllocator& rx_multibuf_allocator, 159 uint16_t connection_handle, 160 L2capCoc::CocConfig rx_config, 161 L2capCoc::CocConfig tx_config, 162 Function<void(multibuf::MultiBuf&& payload)>&& receive_fn, 163 ChannelEventCallback&& event_fn); 164 165 /// TODO: https://pwbug.dev/380076024 - Delete after downstream client uses 166 /// this method on `L2capCoc`. 167 /// @deprecated Use L2capCoc::SendAdditionalRxCredits instead. 168 pw::Status SendAdditionalRxCredits(uint16_t connection_handle, 169 uint16_t local_cid, 170 uint16_t additional_rx_credits); 171 172 /// Returns an L2CAP channel operating in basic mode that supports writing to 173 /// and reading from a remote peer. 174 /// 175 /// @param[in] rx_multibuf_allocator Provides the allocator the channel 176 /// will use for its Rx buffers (for 177 /// both queueing and returning to the 178 /// client). 179 /// 180 /// @param[in] connection_handle The connection handle of the remote 181 /// peer. 182 /// 183 /// @param[in] local_cid L2CAP channel ID of the local 184 /// endpoint. 185 /// 186 /// @param[in] remote_cid L2CAP channel ID of the remote 187 /// endpoint. 188 /// 189 /// @param[in] transport Logical link transport type. 190 /// 191 /// @param[in] payload_from_controller_fn Read callback to be invoked on Rx 192 /// SDUs. Return value of passed-in 193 /// multibuf indicates the packet should 194 /// be forwarded on to host. 195 /// 196 /// @param[in] payload_from_host_fn Read callback to be invoked on Tx 197 /// SDUs. Return value of passed-in 198 /// multibuf indicates the packet should 199 /// be forwarded on to the controller. 200 /// 201 /// @param[in] event_fn Handle asynchronous events such as 202 /// errors encountered by the channel. 203 /// See `l2cap_channel_common.h`. 204 /// 205 /// @returns @rst 206 /// 207 /// .. pw-status-codes:: 208 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 209 /// UNAVAILABLE: If channel could not be created because no memory was 210 /// available to accommodate an additional ACL connection. 211 /// @endrst 212 pw::Result<BasicL2capChannel> AcquireBasicL2capChannel( 213 multibuf::MultiBufAllocator& rx_multibuf_allocator, 214 uint16_t connection_handle, 215 uint16_t local_cid, 216 uint16_t remote_cid, 217 AclTransportType transport, 218 OptionalPayloadReceiveCallback&& payload_from_controller_fn, 219 OptionalPayloadReceiveCallback&& payload_from_host_fn, 220 ChannelEventCallback&& event_fn); 221 222 /// Returns a GATT Notify channel channel that supports sending notifications 223 /// to a particular connection handle and attribute. 224 /// 225 /// @param[in] connection_handle The connection handle of the peer to notify. 226 /// Maximum valid connection handle is 0x0EFF. 227 /// 228 /// @param[in] attribute_handle The attribute handle the notify should be 229 /// sent on. Cannot be 0. 230 /// 231 /// @param[in] event_fn Handle asynchronous events such as errors and 232 /// flow control events encountered by the 233 /// channel. See `l2cap_channel_event.h`. 234 /// 235 /// @returns @rst 236 /// 237 /// .. pw-status-codes:: 238 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 239 /// UNAVAILABLE: If channel could not be created because no memory was 240 /// available to accommodate an additional ACL connection. 241 /// @endrst 242 pw::Result<GattNotifyChannel> AcquireGattNotifyChannel( 243 int16_t connection_handle, 244 uint16_t attribute_handle, 245 ChannelEventCallback&& event_fn); 246 247 /// Send a GATT Notify to the indicated connection. 248 /// 249 /// @param[in] connection_handle The connection handle of the peer to notify. 250 /// Maximum valid connection handle is 0x0EFF. 251 /// 252 /// @param[in] attribute_handle The attribute handle the notify should be 253 /// sent on. Cannot be 0. 254 /// @param[in] attribute_value The client payload to be sent. Payload will 255 /// be destroyed once its data has been used. 256 /// 257 /// @returns @rst 258 /// 259 /// .. pw-status-codes:: 260 /// OK: If notify was successfully queued for send. 261 /// UNAVAILABLE: If CHRE doesn't have resources to queue the send at this 262 /// time (transient error). 263 /// 264 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 265 /// @endrst 266 /// 267 /// @deprecated - Clients should use `ProxyHost::AcquireGattNotifyChannel` and 268 /// then call `GattNotifyChannel::Write` on that. 269 // TODO: https://pwbug.dev/369709521 - Delete this once all downstreams 270 // have transitioned. 271 StatusWithMultiBuf SendGattNotify(uint16_t connection_handle, 272 uint16_t attribute_handle, 273 pw::multibuf::MultiBuf&& payload); 274 275 /// Send a GATT Notify to the indicated connection. 276 /// 277 /// Deprecated, use MultiBuf version above instead. 278 /// 279 /// @param[in] connection_handle The connection handle of the peer to notify. 280 /// Maximum valid connection handle is 0x0EFF. 281 /// 282 /// @param[in] attribute_handle The attribute handle the notify should be 283 /// sent on. Cannot be 0. 284 /// @param[in] attribute_value The data to be sent. Data will be copied 285 /// before function completes. 286 /// 287 /// @returns @rst 288 /// 289 /// .. pw-status-codes:: 290 /// OK: If notify was successfully queued for send. 291 /// UNAVAILABLE: If CHRE doesn't have resources to queue the send 292 /// at this time (transient error). 293 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 294 /// @endrst 295 /// @deprecated - Clients should use `ProxyHost::AcquireGattNotifyChannel` and 296 /// then call `GattNotifyChannel::Write` on that. 297 // TODO: https://pwbug.dev/379337272 - Delete this once all downstreams 298 // have transitioned. 299 pw::Status SendGattNotify(uint16_t connection_handle, 300 uint16_t attribute_handle, 301 pw::span<const uint8_t> attribute_value); 302 303 /// Returns an RFCOMM channel that supports writing to and reading from a 304 /// remote peer. 305 /// 306 /// @param[in] rx_multibuf_allocator 307 /// Provides the allocator the channel will use 308 /// for its Rx buffers (for both queueing and 309 /// returning to the client). 310 /// 311 /// @param[in] connection_handle The connection handle of the remote peer. 312 /// 313 /// @param[in] rx_config Parameters applying to reading packets. 314 /// See `rfcomm_channel.h` for details. 315 /// 316 /// @param[in] tx_config Parameters applying to writing packets. 317 /// See `rfcomm_channel.h` for details. 318 /// 319 /// @param[in] channel_number RFCOMM channel number to use. 320 /// 321 /// @param[in] payload_from_controller_fn 322 /// Read callback to be invoked on Rx frames. 323 /// 324 /// @param[in] event_fn Handle asynchronous events such as errors 325 /// encountered by the channel. See 326 /// `l2cap_channel_common.h`. 327 /// 328 /// @returns @rst 329 /// 330 /// .. pw-status-codes:: 331 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 332 /// UNAVAILABLE: If channel could not be created. 333 /// @endrst 334 pw::Result<RfcommChannel> AcquireRfcommChannel( 335 multibuf::MultiBufAllocator& rx_multibuf_allocator, 336 uint16_t connection_handle, 337 RfcommChannel::Config rx_config, 338 RfcommChannel::Config tx_config, 339 uint8_t channel_number, 340 Function<void(multibuf::MultiBuf&& payload)>&& payload_from_controller_fn, 341 ChannelEventCallback&& event_fn); 342 343 /// Indicates whether the proxy has the capability of sending LE ACL packets. 344 /// Note that this indicates intention, so it can be true even if the proxy 345 /// has not yet or has been unable to reserve credits from the host. 346 bool HasSendLeAclCapability() const; 347 348 /// Indicates whether the proxy has the capability of sending BR/EDR ACL 349 /// packets. Note that this indicates intention, so it can be true even if the 350 /// proxy has not yet or has been unable to reserve credits from the host. 351 bool HasSendBrEdrAclCapability() const; 352 353 /// Returns the number of available LE ACL send credits for the proxy. 354 /// Can be zero if the controller has not yet been initialized by the host. 355 uint16_t GetNumFreeLeAclPackets() const; 356 357 /// Returns the number of available BR/EDR ACL send credits for the proxy. 358 /// Can be zero if the controller has not yet been initialized by the host. 359 uint16_t GetNumFreeBrEdrAclPackets() const; 360 361 /// Returns the max number of LE ACL sends that can be in-flight at one time. 362 /// That is, ACL packets that have been sent and not yet released. GetNumSimultaneousAclSendsSupported()363 static constexpr size_t GetNumSimultaneousAclSendsSupported() { 364 return H4Storage::GetNumH4Buffs(); 365 } 366 367 /// Returns the max LE ACL packet size supported to be sent. GetMaxAclSendSize()368 static constexpr size_t GetMaxAclSendSize() { 369 return H4Storage::GetH4BuffSize() - sizeof(emboss::H4PacketType); 370 } 371 372 /// Returns the max number of simultaneous LE ACL connections supported. GetMaxNumAclConnections()373 static constexpr size_t GetMaxNumAclConnections() { 374 return AclDataChannel::GetMaxNumAclConnections(); 375 } 376 377 private: 378 // Handle HCI Event packet from the controller. 379 void HandleEventFromController(H4PacketWithHci&& h4_packet); 380 381 // Handle HCI Event packet from the host. 382 void HandleEventFromHost(H4PacketWithH4&& h4_packet); 383 384 // Handle HCI ACL data packet from the controller. 385 void HandleAclFromController(H4PacketWithHci&& h4_packet); 386 387 // Process an LE_META_EVENT 388 void HandleLeMetaEvent(H4PacketWithHci&& h4_packet); 389 390 // Process a Command_Complete event. 391 void HandleCommandCompleteEvent(H4PacketWithHci&& h4_packet); 392 393 // Handle HCI Command packet from the host. 394 void HandleCommandFromHost(H4PacketWithH4&& h4_packet); 395 396 // Handle HCI ACL data packet from the host. 397 void HandleAclFromHost(H4PacketWithH4&& h4_packet); 398 399 // For sending non-ACL data to the host and controller. ACL traffic shall be 400 // sent through the `acl_data_channel_`. 401 HciTransport hci_transport_; 402 403 // Owns management of the LE ACL data channel. 404 AclDataChannel acl_data_channel_; 405 406 // Keeps track of the L2CAP-based channels managed by the proxy. 407 L2capChannelManager l2cap_channel_manager_; 408 }; 409 410 } // namespace pw::bluetooth::proxy 411