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 <optional> 18 19 #include "pw_allocator/allocator.h" 20 #include "pw_bluetooth_proxy/internal/l2cap_channel.h" 21 #include "pw_bluetooth_proxy/internal/l2cap_signaling_channel.h" 22 #include "pw_bluetooth_proxy/l2cap_channel_common.h" 23 #include "pw_sync/mutex.h" 24 25 namespace pw::bluetooth::proxy { 26 27 /// L2CAP connection-oriented channel that supports writing to and reading 28 /// from a remote peer. 29 class L2capCoc : public L2capChannel { 30 public: 31 // TODO: https://pwbug.dev/382783733 - Move downstream client to 32 // `L2capChannelEvent` instead of `L2capCoc::Event` and delete this alias. 33 using Event = L2capChannelEvent; 34 35 /// Parameters for a direction of packet flow in an `L2capCoc`. 36 struct CocConfig { 37 /// Channel identifier of the endpoint. 38 /// For Rx: Local CID. 39 /// For Tx: Remote CID. 40 uint16_t cid; 41 /// Maximum Transmission Unit. 42 /// For Rx: Specified by local device. Indicates the maximum SDU size we are 43 /// capable of accepting. 44 /// For Tx: Specified by remote peer. Indicates the maximum SDU size we are 45 /// allowed to send. 46 uint16_t mtu; 47 /// Maximum PDU payload Size. 48 /// For Rx: Specified by local device. Indicates the maximum payload size 49 /// for an L2CAP packet we are capable of accepting. 50 /// For Tx: Specified by remote peer. Indicates the maximum payload size for 51 /// for an L2CAP packet we are allowed to send. 52 uint16_t mps; 53 /// For Rx: Tracks the number of credits we have currently apportioned to 54 /// the remote peer for sending us K-frames in LE Credit Based Flow 55 /// Control mode. 56 /// For Tx: Currently available credits for sending K-frames in LE Credit 57 /// Based Flow Control mode. This may be different from the initial 58 /// value if the container has already sent K-frames and/or received 59 /// credits. 60 uint16_t credits; 61 }; 62 63 L2capCoc(const L2capCoc& other) = delete; 64 L2capCoc& operator=(const L2capCoc& other) = delete; 65 /// Channel is moved on return from factory function, so client is responsible 66 /// for storing channel. 67 L2capCoc(L2capCoc&& other); 68 // TODO: https://pwbug.dev/360929142 - Define move assignment operator so 69 // `L2capCoc` can be erased from pw containers. 70 L2capCoc& operator=(L2capCoc&& other) = delete; 71 ~L2capCoc() override; 72 73 StatusWithMultiBuf Write(pw::multibuf::MultiBuf&& payload) override; 74 75 /// Send an L2CAP_FLOW_CONTROL_CREDIT_IND signaling packet to dispense the 76 /// remote peer additional L2CAP connection-oriented channel credits for this 77 /// channel. 78 /// 79 /// @param[in] additional_rx_credits Number of credits to dispense. 80 /// 81 /// @returns @rst 82 /// 83 /// .. pw-status-codes:: 84 /// UNAVAILABLE: Send could not be queued due to lack of memory in the 85 /// client-provided rx_multibuf_allocator (transient error). 86 /// FAILED_PRECONDITION: If channel is not `State::kRunning`. 87 /// @endrst 88 pw::Status SendAdditionalRxCredits(uint16_t additional_rx_credits) 89 PW_LOCKS_EXCLUDED(rx_mutex_); 90 91 protected: 92 static pw::Result<L2capCoc> Create( 93 pw::multibuf::MultiBufAllocator& rx_multibuf_allocator, 94 L2capChannelManager& l2cap_channel_manager, 95 L2capSignalingChannel* signaling_channel, 96 uint16_t connection_handle, 97 CocConfig rx_config, 98 CocConfig tx_config, 99 ChannelEventCallback&& event_fn, 100 Function<void(multibuf::MultiBuf&& payload)>&& receive_fn); 101 102 // `SendPayloadFromControllerToClient` with the information payload contained 103 // in `kframe`. 104 bool DoHandlePduFromController(pw::span<uint8_t> kframe) override 105 PW_LOCKS_EXCLUDED(rx_mutex_); 106 107 bool HandlePduFromHost(pw::span<uint8_t> kframe) override; 108 109 void DoClose() override; 110 111 // Increment tx credits by `credits`. 112 void AddTxCredits(uint16_t credits) PW_LOCKS_EXCLUDED(tx_mutex_); 113 114 private: 115 explicit L2capCoc(pw::multibuf::MultiBufAllocator& rx_multibuf_allocator, 116 L2capChannelManager& l2cap_channel_manager, 117 L2capSignalingChannel* signaling_channel, 118 uint16_t connection_handle, 119 CocConfig rx_config, 120 CocConfig tx_config, 121 ChannelEventCallback&& event_fn, 122 Function<void(multibuf::MultiBuf&& payload)>&& receive_fn); 123 124 // Returns max size of L2CAP PDU payload supported by this channel. 125 // 126 // Returns std::nullopt if ACL data channel is not yet initialized. 127 std::optional<uint16_t> MaxL2capPayloadSize() const; 128 129 std::optional<H4PacketWithH4> GenerateNextTxPacket() 130 PW_LOCKS_EXCLUDED(tx_mutex_) 131 PW_EXCLUSIVE_LOCKS_REQUIRED(send_queue_mutex()) override; 132 133 // TODO: https://pwbug.dev/379337272 - Delete this once all channels have 134 // transitioned to payload_queue_. UsesPayloadQueue()135 bool UsesPayloadQueue() override { return true; } 136 137 // Replenish some of the remote's credits. 138 pw::Status ReplenishRxCredits(uint16_t additional_rx_credits) 139 PW_EXCLUSIVE_LOCKS_REQUIRED(rx_mutex_); 140 141 L2capSignalingChannel* signaling_channel_ PW_GUARDED_BY(rx_mutex_); 142 143 uint16_t rx_mtu_; 144 uint16_t rx_mps_; 145 uint16_t tx_mtu_; 146 uint16_t tx_mps_; 147 148 Function<void(multibuf::MultiBuf&& payload)> receive_fn_; 149 150 sync::Mutex rx_mutex_; 151 uint16_t remaining_sdu_bytes_to_ignore_ PW_GUARDED_BY(rx_mutex_) = 0; 152 std::optional<multibuf::MultiBuf> rx_sdu_ PW_GUARDED_BY(rx_mutex_) = 153 std::nullopt; 154 uint16_t rx_sdu_offset_ PW_GUARDED_BY(rx_mutex_) = 0; 155 uint16_t rx_sdu_bytes_remaining_ PW_GUARDED_BY(rx_mutex_) = 0; 156 uint16_t rx_remaining_credits_ PW_GUARDED_BY(rx_mutex_); 157 uint16_t rx_total_credits_ PW_GUARDED_BY(rx_mutex_); 158 159 sync::Mutex tx_mutex_; 160 uint16_t tx_credits_ PW_GUARDED_BY(tx_mutex_); 161 uint16_t tx_sdu_offset_ PW_GUARDED_BY(tx_mutex_) = 0; 162 bool is_continuing_segment_ PW_GUARDED_BY(tx_mutex_) = false; 163 }; 164 165 } // namespace pw::bluetooth::proxy 166