• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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