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/l2cap_read_channel.h"
20 #include "pw_bluetooth_proxy/internal/l2cap_write_channel.h"
21 
22 namespace pw::bluetooth::proxy {
23 
24 // `L2capChannelManager` mediates between `ProxyHost` and the L2CAP-based
25 // channels held by clients of `ProxyHost`, such as L2CAP connection-oriented
26 // channels, GATT Notify channels, and RFCOMM channels.
27 //
28 // When an L2CAP-based channel is constructed, it registers itself in one or
29 // both of the lists managed by `L2capChannelManager`: `read_channels_`, for
30 // channels to which Rx L2CAP packets are to be routed, and/or
31 // `write_channels_`, for channels exposing packet Tx capabilities to clients.
32 //
33 // ACL packet transmission is subject to data control flow, managed by
34 // `AclDataChannel`. `L2capChannelManager` handles queueing Tx packets when
35 // credits are unavailable and sending Tx packets as credits become available,
36 // dequeueing packets in FIFO order per channel and in round robin fashion
37 // around channels.
38 class L2capChannelManager {
39  public:
40   L2capChannelManager(AclDataChannel& acl_data_channel);
41 
42   // Reset state.
43   void Reset();
44 
45   // Start proxying L2CAP packets addressed to `channel` arriving from
46   // the controller.
47   void RegisterReadChannel(L2capReadChannel& channel);
48 
49   // Stop proxying L2CAP packets addressed to `channel`.
50   //
51   // Returns false if `channel` is not found.
52   bool ReleaseReadChannel(L2capReadChannel& channel);
53 
54   // Allow `channel` to send & queue Tx L2CAP packets.
55   void RegisterWriteChannel(L2capWriteChannel& channel);
56 
57   // Stop sending L2CAP packets queued in `channel` and clear its queue.
58   //
59   // Returns false if `channel` is not found.
60   bool ReleaseWriteChannel(L2capWriteChannel& channel);
61 
62   // Get an `H4PacketWithH4` backed by a buffer in `H4Storage` able to hold
63   // `size` bytes of data.
64   //
65   // Returns PW_STATUS_UNAVAILABLE if all buffers are currently occupied.
66   // Returns PW_STATUS_INVALID_ARGUMENT if `size` is too large for a buffer.
67   pw::Result<H4PacketWithH4> GetTxH4Packet(uint16_t size);
68 
69   // Send L2CAP packets queued in registered write channels as long as ACL
70   // send credits are available.
71   void DrainWriteChannelQueues() PW_LOCKS_EXCLUDED(write_channels_mutex_);
72 
73   // Returns the size of an H4 buffer reserved for Tx packets.
74   uint16_t GetH4BuffSize() const;
75 
76   // Returns pointer to L2CAP channel with given `connection_handle` &
77   // `remote_cid` if contained in `write_channels_`. Returns nullptr if not
78   // found.
79   L2capWriteChannel* FindWriteChannel(uint16_t connection_handle,
80                                       uint16_t remote_cid);
81 
82   // Returns pointer to L2CAP channel with given `connection_handle` &
83   // `local_cid` if contained in `read_channels_`. Returns nullptr if not
84   // found.
85   L2capReadChannel* FindReadChannel(uint16_t connection_handle,
86                                     uint16_t local_cid);
87 
88  private:
89   // Circularly advance `it`, wrapping around to front if `it` reaches the end.
90   void Advance(IntrusiveForwardList<L2capWriteChannel>::iterator& it)
91       PW_EXCLUSIVE_LOCKS_REQUIRED(write_channels_mutex_);
92 
93   // Send L2CAP packets queued in registered write channels as long as ACL
94   // credits are available on the specified transport.
95   void DrainWriteChannelQueues(AclTransportType transport)
96       PW_EXCLUSIVE_LOCKS_REQUIRED(write_channels_mutex_);
97 
98   // Reference to the ACL data channel owned by the proxy.
99   AclDataChannel& acl_data_channel_;
100 
101   // Owns H4 packet buffers.
102   H4Storage h4_storage_;
103 
104   // List of active L2CAP channels to which Rx packets are routed.
105   IntrusiveForwardList<L2capReadChannel> read_channels_;
106 
107   // Enforce mutual exclusion of all operations on write channels.
108   sync::Mutex write_channels_mutex_;
109 
110   // List of active L2CAP channels with packet Tx capabilities.
111   IntrusiveForwardList<L2capWriteChannel> write_channels_
112       PW_GUARDED_BY(write_channels_mutex_);
113 
114   // Iterator to "least recently drained" write channel.
115   IntrusiveForwardList<L2capWriteChannel>::iterator lrd_write_channel_
116       PW_GUARDED_BY(write_channels_mutex_);
117 };
118 
119 }  // namespace pw::bluetooth::proxy
120