1 // Copyright 2023 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 #include <list>
17 #include <optional>
18 
19 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
21 
22 namespace bt::l2cap::internal {
23 
24 // The ChannelConfiguration class is used for decoding and encoding channel
25 // configuration options (Core spec v5.1, Vol 3, Part A, Section 5) that are in
26 // the payloads of Configuration Requests (Section 4.4) and Configuration
27 // Responses (Section 4.5). To decode a configuration option payload in a
28 // configuration request/response signaling channel packet, instantiate a new
29 // ChannelConfiguration and read options into it via ReadOptions() (which may
30 // fail to decode invalid option payloads). Unknown options (ones we don't
31 // support) that are not hints (types 0x80-0xFF) are available via
32 // unknown_options(). Unknown options should always be handled by rejecting the
33 // packet containing them (Section 5).
34 //
35 // Decoding a configuration option payload example:
36 //   ChannelConfiguration config;
37 //   if (!config.ReadOptions(payload_buffer)) {
38 //     // Handle decoding failure
39 //   }
40 //   if (config.unknown_options.size() != 0) {
41 //     // Reject packet
42 //   }
43 //   if (config.mtu_option()) {
44 //     // Handle mtu option
45 //   }
46 //
47 // Subsequent configuration payload buffers and objects can be merged into an
48 // existing configuration with additional calls to ReadOptions() or Merge(),
49 // which will overwrite current options with the new ones.
50 //
51 // A channel configuration can be iterated through and encoded with
52 // ChannelConfiguration::Options(), which returns a vector of non-null options.
53 // All options can then be encoded into a DynamicByteBuffer with *.Encode().
54 //
55 // Encoding channel configuration options example:
56 //   ChannelConfiguration config;
57 //   config.set_mtu_option(MtuOption(mtu));
58 //   ConfigurationOption options = config.Options();
59 //   DynamicByteBuffer encoded_mtu = options[0].Encode();
60 //   payload_byte_buffer.Write(encoded_mtu);
61 class ChannelConfiguration final {
62  public:
63   class ConfigurationOptionInterface {
64    public:
65     virtual ~ConfigurationOptionInterface() = default;
66 
67     virtual DynamicByteBuffer Encode() const = 0;
68     virtual std::string ToString() const = 0;
69     virtual OptionType type() const = 0;
70     virtual size_t size() const = 0;
71   };
72 
73   using ConfigurationOptionPtr = std::unique_ptr<ConfigurationOptionInterface>;
74   using ConfigurationOptions = std::vector<ConfigurationOptionPtr>;
75 
76   // Maximum Transmission Unit option (Core Spec v5.1, Vol 3, Part A, Sec 5.1).
77   // Specifies the max SDU size the sender is capable of accepting on a channel.
78   class MtuOption final : public ConfigurationOptionInterface {
79    public:
80     static constexpr OptionType kType = OptionType::kMTU;
81     static constexpr uint8_t kPayloadLength = sizeof(MtuOptionPayload);
82     static constexpr size_t kEncodedSize =
83         sizeof(ConfigurationOption) + kPayloadLength;
84 
MtuOption(uint16_t mtu)85     explicit MtuOption(uint16_t mtu) : mtu_(mtu) {}
86 
87     // |data_buf| must contain encoded Mtu option data. The option will be
88     // initialized with the decoded fields.
89     explicit MtuOption(const ByteBuffer& data_buf);
90 
mtu()91     uint16_t mtu() const { return mtu_; }
92 
93     // ConfigurationOptionInterface overrides
94 
95     DynamicByteBuffer Encode() const override;
96 
97     std::string ToString() const override;
98 
type()99     OptionType type() const override { return kType; }
100 
size()101     size_t size() const override { return kEncodedSize; }
102 
103    private:
104     uint16_t mtu_;
105   };
106 
107   // Retransmission and Flow Control option (Core Spec v5.1, Vol 3, Part A,
108   // Sec 5.4). Specifies channel transmission mode and the values of related
109   // parameters.
110   class RetransmissionAndFlowControlOption final
111       : public ConfigurationOptionInterface {
112    public:
113     static constexpr OptionType kType =
114         OptionType::kRetransmissionAndFlowControl;
115     static constexpr uint8_t kPayloadLength =
116         sizeof(RetransmissionAndFlowControlOptionPayload);
117     static constexpr size_t kEncodedSize =
118         sizeof(ConfigurationOption) + kPayloadLength;
119 
120     static RetransmissionAndFlowControlOption MakeBasicMode();
121 
122     static RetransmissionAndFlowControlOption MakeEnhancedRetransmissionMode(
123         uint8_t tx_window_size,
124         uint8_t max_transmit,
125         uint16_t rtx_timeout,
126         uint16_t monitor_timeout,
127         uint16_t mps);
128 
129     // |data_buf| must contain encoded Retransmission And Flow Control option
130     // data. The option will be initialized with the decoded fields.
131     explicit RetransmissionAndFlowControlOption(const ByteBuffer& data_buf);
132 
mode()133     RetransmissionAndFlowControlMode mode() const { return mode_; }
134 
135     // TxWindow: receiver capability in request and transmit capability in
136     // response (ERTM)
tx_window_size()137     uint8_t tx_window_size() const { return tx_window_size_; }
138 
set_tx_window_size(uint8_t tx_window_size)139     void set_tx_window_size(uint8_t tx_window_size) {
140       tx_window_size_ = tx_window_size;
141     }
142 
143     // MaxTransmit: retransmissions allowed before disconnecting (ERTM: 0 means
144     // infinite) in request and ignored in response
max_transmit()145     uint8_t max_transmit() const { return max_transmit_; }
146 
set_max_transmit(uint8_t max_transmit)147     void set_max_transmit(uint8_t max_transmit) {
148       max_transmit_ = max_transmit;
149     }
150 
151     // Retransmission time-out: 0 in request and error detection timeout in
152     // response (ERTM)
rtx_timeout()153     uint16_t rtx_timeout() const { return rtx_timeout_; }
154 
set_rtx_timeout(uint16_t rtx_timeout)155     void set_rtx_timeout(uint16_t rtx_timeout) { rtx_timeout_ = rtx_timeout; }
156 
157     // Monitor time-out: 0 in request and link loss detection timeout in
158     // response (ERTM)
monitor_timeout()159     uint16_t monitor_timeout() const { return monitor_timeout_; }
160 
set_monitor_timeout(uint16_t monitor_timeout)161     void set_monitor_timeout(uint16_t monitor_timeout) {
162       monitor_timeout_ = monitor_timeout;
163     }
164 
165     // Maximum PDU size
mps()166     uint16_t mps() const { return mps_; }
167 
set_mps(uint16_t mps)168     void set_mps(uint16_t mps) { mps_ = mps; }
169 
170     // ConfigurationOptionInterface overrides
171 
172     DynamicByteBuffer Encode() const override;
173 
174     std::string ToString() const override;
175 
type()176     OptionType type() const override { return kType; }
177 
size()178     size_t size() const override { return kEncodedSize; }
179 
180    private:
181     // If |mode| is kBasic, all other parameters are ignored.
182     RetransmissionAndFlowControlOption(RetransmissionAndFlowControlMode mode,
183                                        uint8_t tx_window_size,
184                                        uint8_t max_transmit,
185                                        uint16_t rtx_timeout,
186                                        uint16_t monitor_timeout,
187                                        uint16_t mps);
188 
189     RetransmissionAndFlowControlMode mode_;
190     uint8_t tx_window_size_;
191     uint8_t max_transmit_;
192     uint16_t rtx_timeout_;
193     uint16_t monitor_timeout_;
194     uint16_t mps_;
195   };
196 
197   // Frame Check Sequence (FCS) option (Core Spec v5.4, Vol 3, Part A, Sec 5.5)
198   // Specifies the type of frame check sequence that will be included on S/I
199   // frames. Makes it possible to disable FCS if both entities agree.
200   class FrameCheckSequenceOption final : public ConfigurationOptionInterface {
201    public:
202     static constexpr OptionType kType = OptionType::kFCS;
203     static constexpr uint8_t kPayloadLength =
204         sizeof(FrameCheckSequenceOptionPayload);
205     static constexpr size_t kEncodedSize =
206         sizeof(ConfigurationOption) + kPayloadLength;
207 
FrameCheckSequenceOption(FcsType fcs_type)208     explicit FrameCheckSequenceOption(FcsType fcs_type) : fcs_type_(fcs_type) {}
209 
210     // |data_buf| must contain encoded Frame Check Sequence option data. The
211     // option will be initialized with the encoded FCS type field
212     explicit FrameCheckSequenceOption(const ByteBuffer& data_buf);
213 
fcs_type()214     FcsType fcs_type() const { return fcs_type_; }
215 
216     // ConfigurationOptionInterface overrides
217 
218     DynamicByteBuffer Encode() const override;
219 
220     std::string ToString() const override;
221 
type()222     OptionType type() const override { return kType; }
223 
size()224     size_t size() const override { return kEncodedSize; }
225 
226    private:
227     FcsType fcs_type_;
228   };
229 
230   // Flush Timeout option (Core Spec v5.1, Vol 3, Part A, Sec 5.2).
231   // Specifies flush timeout that sender of this option is going to use.
232   class FlushTimeoutOption final : public ConfigurationOptionInterface {
233    public:
234     static constexpr OptionType kType = OptionType::kFlushTimeout;
235     static constexpr uint8_t kPayloadLength = sizeof(FlushTimeoutOptionPayload);
236     static constexpr size_t kEncodedSize =
237         sizeof(ConfigurationOption) + kPayloadLength;
238 
FlushTimeoutOption(uint16_t flush_timeout)239     explicit FlushTimeoutOption(uint16_t flush_timeout)
240         : flush_timeout_(flush_timeout) {}
241 
242     // |data_buf| must contain encoded Flush Timeout option data. The option
243     // will be initialized with the encoded flush timeout field.
244     explicit FlushTimeoutOption(const ByteBuffer& data_buf);
245 
flush_timeout()246     uint16_t flush_timeout() const { return flush_timeout_; }
247 
248     // ConfigurationOptionInterface overrides
249 
250     DynamicByteBuffer Encode() const override;
251 
252     std::string ToString() const override;
253 
type()254     OptionType type() const override { return kType; }
255 
size()256     size_t size() const override { return kEncodedSize; }
257 
258    private:
259     uint16_t flush_timeout_;
260   };
261 
262   // Unknown options that are not hints must be stored and sent in the
263   // Configuration Response. (Core Spec v5.1, Vol 3, Sec 4.5)
264   class UnknownOption final : public ConfigurationOptionInterface {
265    public:
266     UnknownOption(OptionType type, uint8_t length, const ByteBuffer& data);
267 
268     // Returns true if the unkown option is a hint and may be ignored/skipped.
269     // Returns false if the unknown option may not be ignored (the request
270     // containing this option must be refused).
271     bool IsHint() const;
272 
payload()273     const ByteBuffer& payload() const { return payload_; }
274 
275     // ConfigurationOptionInterface overrides
276 
277     DynamicByteBuffer Encode() const override;
278 
279     // Only includes the type, since options can't be decoded.
280     std::string ToString() const override;
281 
type()282     OptionType type() const override { return type_; }
283 
size()284     size_t size() const override {
285       return sizeof(ConfigurationOption) + payload_.size();
286     }
287 
288    private:
289     OptionType type_;
290     // Raw option payload buffer, since we can't parse it but we must create a
291     // response with it.
292     DynamicByteBuffer payload_;
293   };
294 
295   // Update this configuration based on other configuration's options. Used for
296   // accumulating configuration options sent in a series of packets. Options
297   // that are already set in this configuration will be overwritten if they are
298   // set in |other|. Unknown options will be appended to the unknown options in
299   // this configuration.
300   void Merge(ChannelConfiguration other);
301 
302   // Read encoded list of configuration options from |buffer| and update options
303   // accordingly. Returns true if all options decoded successfully.
304   [[nodiscard]] bool ReadOptions(const ByteBuffer& options_payload);
305 
306   // Convenience method that returns a vector containing only the options that
307   // have been set. Does not include unknown options.
308   ConfigurationOptions Options() const;
309 
310   // Returns a user-friendly string representation. This is intended for debug
311   // messages
312   std::string ToString() const;
313 
set_mtu_option(std::optional<MtuOption> option)314   void set_mtu_option(std::optional<MtuOption> option) {
315     mtu_option_ = std::move(option);
316   }
317 
set_retransmission_flow_control_option(std::optional<RetransmissionAndFlowControlOption> option)318   void set_retransmission_flow_control_option(
319       std::optional<RetransmissionAndFlowControlOption> option) {
320     retransmission_flow_control_option_ = std::move(option);
321   }
322 
set_flush_timeout_option(std::optional<FlushTimeoutOption> option)323   void set_flush_timeout_option(std::optional<FlushTimeoutOption> option) {
324     flush_timeout_option_ = std::move(option);
325   }
326 
set_frame_check_sequence_option(std::optional<FrameCheckSequenceOption> option)327   void set_frame_check_sequence_option(
328       std::optional<FrameCheckSequenceOption> option) {
329     fcs_option_ = std::move(option);
330   }
331 
332   // Returns MtuOption only if it has been previously read or set.
mtu_option()333   const std::optional<MtuOption>& mtu_option() const { return mtu_option_; }
334 
335   // Returns RetransmissionAndFlowControlOption only if it has been previously
336   // read or set.
337   const std::optional<RetransmissionAndFlowControlOption>&
retransmission_flow_control_option()338   retransmission_flow_control_option() const {
339     return retransmission_flow_control_option_;
340   }
341 
flush_timeout_option()342   const std::optional<FlushTimeoutOption>& flush_timeout_option() const {
343     return flush_timeout_option_;
344   }
345 
346   // Returns FrameCheckSequenceOption only if it has been previously set.
frame_check_sequence_option()347   const std::optional<FrameCheckSequenceOption>& frame_check_sequence_option()
348       const {
349     return fcs_option_;
350   }
351 
352   // Returns unknown options previously decoded by |ReadOptions|. Used for
353   // responding to peer with rejected options.
unknown_options()354   const std::vector<UnknownOption>& unknown_options() const {
355     return unknown_options_;
356   }
357 
358  private:
359   // Decoding callbacks
OnReadMtuOption(MtuOption option)360   void OnReadMtuOption(MtuOption option) { mtu_option_ = option; }
OnReadRetransmissionAndFlowControlOption(RetransmissionAndFlowControlOption option)361   void OnReadRetransmissionAndFlowControlOption(
362       RetransmissionAndFlowControlOption option) {
363     retransmission_flow_control_option_ = option;
364   }
OnReadFrameCheckSequenceOption(FrameCheckSequenceOption option)365   void OnReadFrameCheckSequenceOption(FrameCheckSequenceOption option) {
366     fcs_option_ = option;
367   }
OnReadFlushTimeoutOption(FlushTimeoutOption option)368   void OnReadFlushTimeoutOption(FlushTimeoutOption option) {
369     flush_timeout_option_ = option;
370   }
371   void OnReadUnknownOption(UnknownOption option);
372 
373   // Returns number of bytes read. A return value of 0 indicates failure to read
374   // option.
375   size_t ReadNextOption(const ByteBuffer& options);
376 
377   std::optional<MtuOption> mtu_option_;
378   std::optional<RetransmissionAndFlowControlOption>
379       retransmission_flow_control_option_;
380   std::optional<FrameCheckSequenceOption> fcs_option_;
381   std::optional<FlushTimeoutOption> flush_timeout_option_;
382   std::vector<UnknownOption> unknown_options_;
383 };  // ChannelConfiguration
384 
385 }  // namespace bt::l2cap::internal
386