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/l2cap_channel.h" 18 #include "pw_sync/mutex.h" 19 20 namespace pw::bluetooth::proxy { 21 22 /// L2CAP RFCOMM channel that supports writing to and reading 23 /// from a remote peer. 24 /// TODO: https://pwbug.dev/378691959 - Switch to just containing a 25 /// BasicL2capChannel instead of inheritance. 26 /// 27 /// This implementation requires use of RFCOMM credit based flow control. 28 class RfcommChannel final : public L2capChannel { 29 public: 30 /// Parameters for a direction of packet flow in an `RfcommChannel`. 31 struct Config { 32 /// Channel identifier of the endpoint. 33 /// For Rx: Local CID. 34 /// For Tx: Remote CID. 35 uint16_t cid; 36 /// Maximum Information Length. 37 /// For Rx: Specified by local device. Indicates the maximum frame size 38 /// for an RFCOMM packet we are capable of accepting. 39 /// For Tx: Specified by remote peer. Indicates the maximum frame size for 40 /// for an RFCOMM packet we are allowed to send. 41 uint16_t max_information_length; 42 /// For Rx: Tracks the number of RFCOMM credits we have currently 43 /// apportioned to the remote peer for sending us frames. 44 /// For Tx: Currently available credits for sending frames in RFCOMM Credit 45 /// Based Flow Control mode. This may be different from the initial 46 /// value if the container has already sent frames and/or received 47 /// credits. 48 uint16_t credits; 49 }; 50 51 RfcommChannel(const RfcommChannel& other) = delete; 52 RfcommChannel& operator=(const RfcommChannel& other) = delete; 53 RfcommChannel(RfcommChannel&& other); 54 RfcommChannel& operator=(RfcommChannel&& other) = delete; 55 ~RfcommChannel() override; 56 57 /// Returns an RFCOMM channel that supports writing to and reading from a 58 /// remote peer. 59 /// 60 /// @param[in] l2cap_channel_manager The L2CAP channel manager to register 61 /// with. 62 /// 63 /// @param[in] connection_handle The connection handle of the remote peer. 64 /// 65 /// @param[in] rx_config Parameters applying to reading packets. 66 /// See `rfcomm_channel.h` for details. 67 /// 68 /// @param[in] tx_config Parameters applying to writing packets. 69 /// See `rfcomm_channel.h` for details. 70 /// 71 /// @param[in] channel_number RFCOMM channel number to use. 72 /// 73 /// @param[in] payload_from_controller_fn Read callback to be invoked 74 /// on Rx frames. 75 /// 76 /// @returns @rst 77 /// 78 /// .. pw-status-codes:: 79 /// INVALID_ARGUMENT: If arguments are invalid (check logs). 80 /// UNAVAILABLE: If channel could not be created. 81 /// @endrst 82 static pw::Result<RfcommChannel> Create( 83 L2capChannelManager& l2cap_channel_manager, 84 multibuf::MultiBufAllocator& rx_multibuf_allocator, 85 uint16_t connection_handle, 86 Config rx_config, 87 Config tx_config, 88 uint8_t channel_number, 89 Function<void(multibuf::MultiBuf&& payload)>&& payload_from_controller_fn, 90 ChannelEventCallback&& event_fn); 91 92 // Overridden here to do additional length checks. 93 StatusWithMultiBuf Write(multibuf::MultiBuf&& payload) override; 94 rx_config()95 Config rx_config() const { return rx_config_; } tx_config()96 Config tx_config() const { return tx_config_; } 97 98 private: 99 static constexpr uint8_t kMinRxCredits = 2; 100 101 RfcommChannel( 102 L2capChannelManager& l2cap_channel_manager, 103 multibuf::MultiBufAllocator& rx_multibuf_allocator, 104 uint16_t connection_handle, 105 Config rx_config, 106 Config tx_config, 107 uint8_t channel_number, 108 Function<void(multibuf::MultiBuf&& payload)>&& payload_from_controller_fn, 109 ChannelEventCallback&& event_fn); 110 111 // TODO: https://pwbug.dev/379337272 - Delete this once all channels have 112 // transitioned to payload_queue_. UsesPayloadQueue()113 bool UsesPayloadQueue() override { return true; } 114 115 [[nodiscard]] std::optional<H4PacketWithH4> GenerateNextTxPacket() 116 PW_EXCLUSIVE_LOCKS_REQUIRED(send_queue_mutex()) override; 117 118 // Parses out RFCOMM payload from `l2cap_pdu` and calls 119 // `SendPayloadFromControllerToClient`. 120 bool DoHandlePduFromController(pw::span<uint8_t> l2cap_pdu) override; 121 bool HandlePduFromHost(pw::span<uint8_t> l2cap_pdu) override; 122 123 // Override: Dequeue a packet only if a credit is able to be subtracted. 124 std::optional<H4PacketWithH4> DequeuePacket() override 125 PW_LOCKS_EXCLUDED(tx_mutex_); 126 127 // Override: All traffic on this channel goes to client. 128 bool SendPayloadFromControllerToClient(pw::span<uint8_t> payload) override; 129 DoClose()130 void DoClose() override {} 131 132 const Config rx_config_; 133 const Config tx_config_; 134 const uint8_t channel_number_; 135 sync::Mutex rx_mutex_; 136 uint8_t rx_credits_ PW_GUARDED_BY(rx_mutex_); 137 138 sync::Mutex tx_mutex_; 139 uint8_t tx_credits_ PW_GUARDED_BY(tx_mutex_); 140 Function<void(multibuf::MultiBuf&& payload)> payload_from_controller_fn_; 141 }; 142 143 } // namespace pw::bluetooth::proxy 144