xref: /aosp_15_r20/external/pigweed/pw_bluetooth_proxy/public/pw_bluetooth_proxy/proxy_host.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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