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/internal/acl_data_channel.h" 18 #include "pw_bluetooth_proxy/internal/h4_storage.h" 19 #include "pw_bluetooth_proxy/internal/hci_transport.h" 20 #include "pw_bluetooth_proxy/internal/l2cap_channel_manager.h" 21 #include "pw_bluetooth_proxy/l2cap_coc.h" 22 #include "pw_bluetooth_proxy/rfcomm_channel.h" 23 #include "pw_status/status.h" 24 25 namespace pw::bluetooth::proxy { 26 27 /// `ProxyHost` acts as the main coordinator for proxy functionality. After 28 /// creation, the container then passes packets through the proxy. 29 class ProxyHost { 30 public: 31 /// Creates an `ProxyHost` that will process HCI packets. 32 /// @param[in] send_to_host_fn Callback that will be called when proxy wants 33 /// to send HCI packet towards the host. 34 /// @param[in] send_to_controller_fn - Callback that will be called when 35 /// proxy wants to send HCI packet towards the controller. 36 ProxyHost(pw::Function<void(H4PacketWithHci&& packet)>&& send_to_host_fn, 37 pw::Function<void(H4PacketWithH4&& packet)>&& send_to_controller_fn, 38 uint16_t le_acl_credits_to_reserve, 39 uint16_t br_edr_acl_credits_to_reserve = 0); 40 41 ProxyHost() = delete; 42 ProxyHost(const ProxyHost&) = delete; 43 ProxyHost& operator=(const ProxyHost&) = delete; 44 ProxyHost(ProxyHost&&) = delete; 45 ProxyHost& operator=(ProxyHost&&) = delete; 46 ~ProxyHost(); 47 48 // ##### Container API 49 // Containers are expected to call these functions (in addition to ctor). 50 51 /// Called by container to ask proxy to handle a H4 HCI packet sent from the 52 /// host side towards the controller side. Proxy will in turn call the 53 /// `send_to_controller_fn` provided during construction to pass the packet 54 /// on to the controller. Some packets may be modified, added, or removed. 55 /// 56 /// The proxy host currently does not require any from-host packets to support 57 /// its current functionality. It will pass on all packets, so containers can 58 /// choose to just pass all from-host packets through it. 59 /// 60 /// Container is required to call this function synchronously (one packet at a 61 /// time). 62 void HandleH4HciFromHost(H4PacketWithH4&& h4_packet); 63 64 /// Called by container to ask proxy to handle a H4 packet sent from the 65 /// controller side towards the host side. Proxy will in turn call the 66 /// `send_to_host_fn` provided during construction to pass the packet on to 67 /// the host. Some packets may be modified, added, or removed. 68 /// 69 /// To support all of its current functionality, the proxy host needs at least 70 /// the following from-controller packets passed through it. It will pass on 71 /// all other packets, so containers can choose to just pass all 72 /// from-controller packets through the proxy host. 73 /// 74 /// All packets of this type: 75 /// - L2CAP over ACL packets (specifically those addressed to channels managed 76 /// by the proxy host, including signaling packets) 77 /// 78 /// HCI_Command_Complete events (7.7.14) containing return parameters for 79 /// these commands: 80 /// - HCI_LE_Read_Buffer_Size [v1] command (7.8.2) 81 /// - HCI_LE_Read_Buffer_Size [v2] command (7.8.2) 82 /// 83 /// These HCI event packets: 84 /// - HCI_Number_Of_Completed_Packets event (7.7.19) 85 /// - HCI_Disconnection_Complete event (7.7.5) 86 /// 87 /// Container is required to call this function synchronously (one packet at a 88 /// time). 89 void HandleH4HciFromController(H4PacketWithHci&& h4_packet); 90 91 /// Called by container to notify proxy that the Bluetooth system is being 92 /// reset, so the proxy can reset its internal state. 93 /// Warning: Outstanding H4 packets are not invalidated upon reset. If they 94 /// are destructed post-reset, packets generated post-reset are liable to be 95 /// overwritten prematurely. 96 void Reset(); 97 98 // ##### Client APIs 99 100 /// Returns an L2CAP connection-oriented channel that supports writing to and 101 /// reading from a remote peer. 102 /// 103 /// @param[in] connection_handle The connection handle of the remote peer. 104 /// 105 /// @param[in] rx_config Parameters applying to reading packets. 106 /// See `l2cap_coc.h` for details. 107 /// 108 /// @param[in] tx_config Parameters applying to writing packets. 109 /// See `l2cap_coc.h` for details. 110 /// 111 /// @param[in] receive_fn Read callback to be invoked on Rx SDUs. 112 /// 113 /// @param[in] event_fn Handle asynchronous events such as errors 114 /// encountered by the channel. 115 /// 116 /// @param[in] rx_additional_credits Send L2CAP_FLOW_CONTROL_CREDIT_IND to 117 /// dispense remote peer additional credits 118 /// for this channel. 119 /// 120 /// @returns @rst 121 /// 122 /// .. pw-status-codes:: 123 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 124 /// UNAVAILABLE: If channel could not be created because no memory was 125 /// available to accommodate an additional ACL connection. 126 /// @endrst 127 pw::Result<L2capCoc> AcquireL2capCoc( 128 uint16_t connection_handle, 129 L2capCoc::CocConfig rx_config, 130 L2capCoc::CocConfig tx_config, 131 pw::Function<void(pw::span<uint8_t> payload)>&& receive_fn, 132 pw::Function<void(L2capCoc::Event event)>&& event_fn, 133 uint16_t rx_additional_credits = 0); 134 135 /// Returns an L2CAP channel operating in basic mode that supports writing to 136 /// and reading from a remote peer. 137 /// 138 /// @param[in] connection_handle The connection handle of the remote 139 /// peer. 140 /// 141 /// @param[in] local_cid L2CAP channel ID of the local 142 /// endpoint. 143 /// 144 /// @param[in] remote_cid L2CAP channel ID of the remote 145 /// endpoint. 146 /// 147 /// @param[in] transport Logical link transport type. 148 /// 149 /// @param[in] payload_from_controller_fn Read callback to be invoked on Rx 150 /// SDUs. 151 /// 152 /// @returns @rst 153 /// 154 /// .. pw-status-codes:: 155 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 156 /// UNAVAILABLE: If channel could not be created because no memory was 157 /// available to accommodate an additional ACL connection. 158 /// @endrst 159 pw::Result<BasicL2capChannel> AcquireBasicL2capChannel( 160 uint16_t connection_handle, 161 uint16_t local_cid, 162 uint16_t remote_cid, 163 AclTransportType transport, 164 pw::Function<void(pw::span<uint8_t> payload)>&& 165 payload_from_controller_fn); 166 167 /// Send a GATT Notify to the indicated connection. 168 /// 169 /// @param[in] connection_handle The connection handle of the peer to notify. 170 /// Maximum valid connection handle is 0x0EFF. 171 /// 172 /// @param[in] attribute_handle The attribute handle the notify should be 173 /// sent on. Cannot be 0. 174 /// @param[in] attribute_value The data to be sent. Data will be copied 175 /// before function completes. 176 /// 177 /// @returns @rst 178 /// 179 /// .. pw-status-codes:: 180 /// OK: If notify was successfully queued for send. 181 /// UNAVAILABLE: If CHRE doesn't have resources to queue the send 182 /// at this time (transient error). 183 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 184 /// @endrst 185 pw::Status SendGattNotify(uint16_t connection_handle, 186 uint16_t attribute_handle, 187 pw::span<const uint8_t> attribute_value); 188 189 /// Returns an RFCOMM channel that supports writing to and reading from a 190 /// remote peer. 191 /// 192 /// @param[in] connection_handle The connection handle of the remote peer. 193 /// 194 /// @param[in] rx_config Parameters applying to reading packets. 195 /// See `rfcomm_channel.h` for details. 196 /// 197 /// @param[in] tx_config Parameters applying to writing packets. 198 /// See `rfcomm_channel.h` for details. 199 /// 200 /// @param[in] channel_number RFCOMM channel number to use. 201 /// 202 /// @param[in] receive_fn Read callback to be invoked on Rx frames. 203 /// 204 /// @returns @rst 205 /// 206 /// .. pw-status-codes:: 207 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 208 /// UNAVAILABLE: If channel could not be created. 209 /// @endrst 210 pw::Result<RfcommChannel> AcquireRfcommChannel( 211 uint16_t connection_handle, 212 RfcommChannel::Config rx_config, 213 RfcommChannel::Config tx_config, 214 uint8_t channel_number, 215 pw::Function<void(pw::span<uint8_t> payload)>&& receive_fn); 216 217 /// Indicates whether the proxy has the capability of sending LE ACL packets. 218 /// Note that this indicates intention, so it can be true even if the proxy 219 /// has not yet or has been unable to reserve credits from the host. 220 bool HasSendLeAclCapability() const; 221 222 /// @deprecated Use HasSendLeAclCapability HasSendAclCapability()223 bool HasSendAclCapability() const { return HasSendLeAclCapability(); } 224 225 /// Indicates whether the proxy has the capability of sending BR/EDR ACL 226 /// packets. Note that this indicates intention, so it can be true even if the 227 /// proxy has not yet or has been unable to reserve credits from the host. 228 bool HasSendBrEdrAclCapability() const; 229 230 /// Returns the number of available LE ACL send credits for the proxy. 231 /// Can be zero if the controller has not yet been initialized by the host. 232 uint16_t GetNumFreeLeAclPackets() const; 233 234 /// Returns the number of available BR/EDR ACL send credits for the proxy. 235 /// Can be zero if the controller has not yet been initialized by the host. 236 uint16_t GetNumFreeBrEdrAclPackets() const; 237 238 /// Returns the max number of LE ACL sends that can be in-flight at one time. 239 /// That is, ACL packets that have been sent and not yet released. GetNumSimultaneousAclSendsSupported()240 static constexpr size_t GetNumSimultaneousAclSendsSupported() { 241 return H4Storage::GetNumH4Buffs(); 242 } 243 244 /// Returns the max LE ACL packet size supported to be sent. GetMaxAclSendSize()245 static constexpr size_t GetMaxAclSendSize() { 246 return H4Storage::GetH4BuffSize() - sizeof(emboss::H4PacketType); 247 } 248 249 /// Returns the max number of simultaneous LE ACL connections supported. GetMaxNumLeAclConnections()250 static constexpr size_t GetMaxNumLeAclConnections() { 251 return AclDataChannel::GetMaxNumLeAclConnections(); 252 } 253 254 private: 255 // Handle HCI Event packet from the controller. 256 void HandleEventFromController(H4PacketWithHci&& h4_packet); 257 258 // Handle HCI ACL data packet from the controller. 259 void HandleAclFromController(H4PacketWithHci&& h4_packet); 260 261 // Process an LE_META_EVENT 262 void HandleLeMetaEvent(H4PacketWithHci&& h4_packet); 263 264 // Process a Command_Complete event. 265 void HandleCommandCompleteEvent(H4PacketWithHci&& h4_packet); 266 267 // Handle HCI ACL data packet from the host. 268 void HandleAclFromHost(H4PacketWithH4&& h4_packet); 269 270 // If ACL frame is end of fragment, complete fragment and return false. 271 // Otherwise process frame as part of ongoing fragmented PDU and return true. 272 bool CheckForActiveFragmenting(AclDataChannel::Direction direction, 273 emboss::AclDataFrameWriter& acl); 274 275 // If ACL frame is start of fragment, return true. `channel` is notified and 276 // the connection is marked as having an active fragment. 277 bool CheckForFragmentedStart(AclDataChannel::Direction direction, 278 emboss::AclDataFrameWriter& acl, 279 emboss::BasicL2capHeaderView& l2cap_header, 280 L2capReadChannel* channel); 281 282 // For sending non-ACL data to the host and controller. ACL traffic shall be 283 // sent through the `acl_data_channel_`. 284 HciTransport hci_transport_; 285 286 // Owns management of the LE ACL data channel. 287 AclDataChannel acl_data_channel_; 288 289 // Keeps track of the L2CAP-based channels managed by the proxy. 290 L2capChannelManager l2cap_channel_manager_; 291 }; 292 293 } // namespace pw::bluetooth::proxy 294