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