• 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 <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