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