xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/l2cap/channel_configuration_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_configuration.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
18 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
19 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
20 #include "pw_unit_test/framework.h"
21 
22 namespace bt::l2cap::internal {
23 namespace {
24 
25 using MtuOption = ChannelConfiguration::MtuOption;
26 using RetransmissionAndFlowControlOption =
27     ChannelConfiguration::RetransmissionAndFlowControlOption;
28 using FlushTimeoutOption = ChannelConfiguration::FlushTimeoutOption;
29 using UnknownOption = ChannelConfiguration::UnknownOption;
30 
31 constexpr auto kUnknownOptionType = static_cast<OptionType>(0x10);
32 
33 const MtuOption kMtuOption(48);
34 const RetransmissionAndFlowControlOption kRetransmissionAndFlowControlOption =
35     RetransmissionAndFlowControlOption::MakeBasicMode();
36 const FlushTimeoutOption kFlushTimeoutOption(200);
37 
38 class ChannelConfigurationTest : public ::testing::Test {
39  public:
40   ChannelConfigurationTest() = default;
41   ~ChannelConfigurationTest() override = default;
42   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ChannelConfigurationTest);
43 };
44 
TEST_F(ChannelConfigurationTest,ReadAllOptionTypes)45 TEST_F(ChannelConfigurationTest, ReadAllOptionTypes) {
46   const StaticByteBuffer kOptionBuffer(
47       // MTU Option
48       static_cast<uint8_t>(OptionType::kMTU),
49       MtuOption::kPayloadLength,
50       LowerBits(kMinACLMTU),
51       UpperBits(kMinACLMTU),
52       // Rtx Option
53       static_cast<uint8_t>(OptionType::kRetransmissionAndFlowControl),
54       RetransmissionAndFlowControlOption::kPayloadLength,
55       static_cast<uint8_t>(RetransmissionAndFlowControlMode::kRetransmission),
56       0x00,
57       0x00,
58       0x00,
59       0x00,
60       0x00,
61       0x00,
62       0x00,
63       0x00,
64       // Flush Timeout option (timeout = 200)
65       static_cast<uint8_t>(OptionType::kFlushTimeout),
66       FlushTimeoutOption::kPayloadLength,
67       0xc8,
68       0x00,
69       // Unknown option, Type = 0x70, Length = 1, payload = 0x03
70       0x70,
71       0x01,
72       0x03);
73 
74   ChannelConfiguration config;
75 
76   EXPECT_TRUE(config.ReadOptions(kOptionBuffer));
77 
78   EXPECT_TRUE(config.mtu_option());
79   EXPECT_EQ(kMinACLMTU, config.mtu_option()->mtu());
80 
81   EXPECT_TRUE(config.retransmission_flow_control_option());
82   EXPECT_EQ(RetransmissionAndFlowControlMode::kRetransmission,
83             config.retransmission_flow_control_option()->mode());
84 
85   EXPECT_TRUE(config.flush_timeout_option());
86   EXPECT_EQ(200u, config.flush_timeout_option()->flush_timeout());
87 
88   EXPECT_EQ(1u, config.unknown_options().size());
89   auto& option = config.unknown_options().front();
90   EXPECT_EQ(0x70, static_cast<uint8_t>(option.type()));
91   EXPECT_EQ(1u, option.payload().size());
92   EXPECT_EQ(0x03, option.payload().data()[0]);
93 }
94 
TEST_F(ChannelConfigurationTest,ReadTooShortOption)95 TEST_F(ChannelConfigurationTest, ReadTooShortOption) {
96   // clang-format off
97   // missing required Length field
98   StaticByteBuffer kEncodedOption(
99       // Type = QoS
100       0x03);
101   //clang-format on
102 
103   ChannelConfiguration config;
104   EXPECT_FALSE(config.ReadOptions(kEncodedOption));
105 }
106 
TEST_F(ChannelConfigurationTest,ReadInvalidOptionField)107 TEST_F(ChannelConfigurationTest, ReadInvalidOptionField) {
108   // clang-format off
109   StaticByteBuffer kEncodedOption(
110       // Length = 255
111       static_cast<uint8_t>(kUnknownOptionType), 0xFF);
112   // clang-format on
113 
114   ChannelConfiguration config;
115   EXPECT_FALSE(config.ReadOptions(kEncodedOption));
116 }
117 
TEST_F(ChannelConfigurationTest,ReadIncorrectOptionLength)118 TEST_F(ChannelConfigurationTest, ReadIncorrectOptionLength) {
119   // clang-format off
120   StaticByteBuffer kEncodedMtuOption(
121       // Type = MTU, Length = 3 (spec length is 2)
122       OptionType::kMTU, 0x03, 0x00, 0x00, 0x00);
123   //clang-format on
124 
125   ChannelConfiguration config;
126   EXPECT_FALSE(config.ReadOptions(kEncodedMtuOption));
127 
128   // clang-format off
129   StaticByteBuffer kEncodedRetransmissionOption(
130       // Type, Length = 1 (spec length is 9)
131     OptionType::kRetransmissionAndFlowControl, 0x01, 0x00);
132   //clang-format on
133 
134   EXPECT_FALSE(config.ReadOptions(kEncodedRetransmissionOption));
135 
136   StaticByteBuffer kEncodedFlushTimeoutOption(
137     // Type, Length = 1 (spec length is 2)
138     OptionType::kFlushTimeout, 0x01, 0x00);
139 
140   EXPECT_FALSE(config.ReadOptions(kEncodedFlushTimeoutOption));
141 }
142 
TEST_F(ChannelConfigurationTest,MtuOptionDecodeEncode)143 TEST_F(ChannelConfigurationTest, MtuOptionDecodeEncode) {
144   constexpr uint16_t kMTU = 48;
145 
146   // clang-format off
147   StaticByteBuffer kExpectedEncodedMtuOption(
148       // Type = MTU, Length = 2
149       0x01, 0x02,
150       // MTU = 48
151       LowerBits(kMTU), UpperBits(kMTU));
152   //clang-format on
153   ChannelConfiguration::MtuOption mtu_option(kExpectedEncodedMtuOption.view(sizeof(ConfigurationOption)));
154 
155   EXPECT_EQ(mtu_option.mtu(), kMTU);
156 
157   EXPECT_TRUE(ContainersEqual(mtu_option.Encode(), kExpectedEncodedMtuOption));
158 }
159 
TEST_F(ChannelConfigurationTest,RetransmissionAndFlowControlOptionDecodeEncode)160 TEST_F(ChannelConfigurationTest, RetransmissionAndFlowControlOptionDecodeEncode) {
161   const auto kMode = RetransmissionAndFlowControlMode::kRetransmission;
162   const uint8_t kTxWindow = 32;
163   const uint8_t kMaxTransmit = 1;
164   const uint16_t kRtxTimeout = 512;
165   const uint16_t kMonitorTimeout = 528;
166   const uint16_t kMaxPDUPayloadSize = 256;
167 
168   // clang-format off
169   StaticByteBuffer kExpectedEncodedRetransmissionAndFlowControlOption(
170       // Type = rtx and flow control, Length = 9
171       0x04, 0x09,
172       static_cast<uint8_t>(kMode), kTxWindow, kMaxTransmit,
173       LowerBits(kRtxTimeout), UpperBits(kRtxTimeout),
174       LowerBits(kMonitorTimeout), UpperBits(kMonitorTimeout),
175       LowerBits(kMaxPDUPayloadSize), UpperBits(kMaxPDUPayloadSize)
176       );
177   // clang-format on
178 
179   ChannelConfiguration::RetransmissionAndFlowControlOption rtx_option(
180       kExpectedEncodedRetransmissionAndFlowControlOption.view(
181           sizeof(ConfigurationOption)));
182   EXPECT_EQ(kTxWindow, rtx_option.tx_window_size());
183   EXPECT_EQ(kMaxTransmit, rtx_option.max_transmit());
184   EXPECT_EQ(kRtxTimeout, rtx_option.rtx_timeout());
185   EXPECT_EQ(kMonitorTimeout, rtx_option.monitor_timeout());
186   EXPECT_EQ(kMaxPDUPayloadSize, rtx_option.mps());
187   EXPECT_TRUE(ContainersEqual(
188       rtx_option.Encode(), kExpectedEncodedRetransmissionAndFlowControlOption));
189 }
190 
TEST_F(ChannelConfigurationTest,FlushTimeoutOptionDecodeEncode)191 TEST_F(ChannelConfigurationTest, FlushTimeoutOptionDecodeEncode) {
192   const uint16_t kFlushTimeout = 200;
193 
194   StaticByteBuffer kExpectedEncodedFlushTimeoutOption(
195       // flush timeout type = 0x02, length = 2
196       0x02,
197       0x02,
198       LowerBits(kFlushTimeout),
199       UpperBits(kFlushTimeout));
200 
201   FlushTimeoutOption option(
202       kExpectedEncodedFlushTimeoutOption.view(sizeof(ConfigurationOption)));
203 
204   EXPECT_EQ(kFlushTimeout, option.flush_timeout());
205   EXPECT_EQ(kExpectedEncodedFlushTimeoutOption, option.Encode());
206 }
207 
TEST_F(ChannelConfigurationTest,UnknownOptionDecodeEncode)208 TEST_F(ChannelConfigurationTest, UnknownOptionDecodeEncode) {
209   // clang-format off
210   StaticByteBuffer kExpectedEncodedUnknownOption(
211       kUnknownOptionType, 0x02, // Length = 2
212       0x01, 0x02); // random data
213   // clang-format on
214 
215   ChannelConfiguration::UnknownOption unknown_option(
216       kUnknownOptionType,
217       2,
218       kExpectedEncodedUnknownOption.view(sizeof(ConfigurationOption)));
219   EXPECT_TRUE(
220       ContainersEqual(unknown_option.Encode(), kExpectedEncodedUnknownOption));
221 }
222 
TEST_F(ChannelConfigurationTest,UnknownOptionHints)223 TEST_F(ChannelConfigurationTest, UnknownOptionHints) {
224   constexpr auto kHintOptionType = static_cast<OptionType>(0x80);
225   constexpr auto kNotHintOptionType = static_cast<OptionType>(0x70);
226   StaticByteBuffer data(0x01);
227   ChannelConfiguration::UnknownOption unknown_option_hint(
228       kHintOptionType, 1, data);
229   EXPECT_TRUE(unknown_option_hint.IsHint());
230   ChannelConfiguration::UnknownOption unknown_option(
231       kNotHintOptionType, 1, data);
232   EXPECT_FALSE(unknown_option.IsHint());
233 }
234 
TEST_F(ChannelConfigurationTest,OptionsReturnsKnownOptions)235 TEST_F(ChannelConfigurationTest, OptionsReturnsKnownOptions) {
236   // Empty configuration
237   EXPECT_EQ(0u, ChannelConfiguration().Options().size());
238 
239   // Single option
240   ChannelConfiguration config;
241   config.set_mtu_option(kMtuOption);
242   auto options0 = config.Options();
243   // |options0| should not include all options
244   EXPECT_EQ(1u, options0.size());
245   EXPECT_EQ(OptionType::kMTU, options0[0]->type());
246 
247   // All options
248   config.set_retransmission_flow_control_option(
249       kRetransmissionAndFlowControlOption);
250   config.set_flush_timeout_option(kFlushTimeoutOption);
251   auto options1 = config.Options();
252   EXPECT_EQ(3u, options1.size());
253 
254   const auto OptionsContainsOptionOfType =
255       [](ChannelConfiguration::ConfigurationOptions& options, OptionType type) {
256         return std::find_if(options.begin(), options.end(), [&](auto& option) {
257                  return option->type() == type;
258                }) != options.end();
259       };
260   constexpr std::array<OptionType, 3> AllOptionTypes = {
261       OptionType::kRetransmissionAndFlowControl,
262       OptionType::kMTU,
263       OptionType::kFlushTimeout};
264   for (auto& type : AllOptionTypes) {
265     EXPECT_TRUE(OptionsContainsOptionOfType(options1, type));
266   }
267 
268   // Remove mtu option
269   config.set_mtu_option(std::nullopt);
270   auto options2 = config.Options();
271   EXPECT_EQ(2u, options2.size());
272   EXPECT_FALSE(OptionsContainsOptionOfType(options2, OptionType::kMTU));
273 }
274 
TEST_F(ChannelConfigurationTest,MergingConfigurations)275 TEST_F(ChannelConfigurationTest, MergingConfigurations) {
276   ChannelConfiguration config0;
277   config0.set_mtu_option(kMtuOption);
278   config0.set_retransmission_flow_control_option(
279       kRetransmissionAndFlowControlOption);
280   config0.set_flush_timeout_option(kFlushTimeoutOption);
281 
282   // Test merging options to empty config
283   ChannelConfiguration config1;
284   config1.Merge(config0);
285 
286   EXPECT_EQ(kMtuOption.mtu(), config1.mtu_option()->mtu());
287   EXPECT_EQ(kRetransmissionAndFlowControlOption.mode(),
288             config1.retransmission_flow_control_option()->mode());
289   EXPECT_EQ(kFlushTimeoutOption.flush_timeout(),
290             config1.flush_timeout_option()->flush_timeout());
291 
292   // Test overwriting options
293   constexpr uint16_t kMtu = 96;
294   config0.set_mtu_option(MtuOption(kMtu));
295   constexpr auto kMode =
296       RetransmissionAndFlowControlMode::kEnhancedRetransmission;
297   config0.set_retransmission_flow_control_option(
298       RetransmissionAndFlowControlOption::MakeEnhancedRetransmissionMode(
299           0, 0, 0, 0, 0));
300   constexpr uint16_t kTimeout = 150;
301   config0.set_flush_timeout_option(FlushTimeoutOption(kTimeout));
302 
303   config1.Merge(config0);
304 
305   EXPECT_EQ(kMtu, config1.mtu_option()->mtu());
306   EXPECT_EQ(kMode, config1.retransmission_flow_control_option()->mode());
307   EXPECT_EQ(kTimeout, config1.flush_timeout_option()->flush_timeout());
308 }
309 
TEST_F(ChannelConfigurationTest,MergingUnknownOptionsAppendsThem)310 TEST_F(ChannelConfigurationTest, MergingUnknownOptionsAppendsThem) {
311   const StaticByteBuffer kUnknownOption0(
312       // code, length, payload
313       0x70,
314       0x01,
315       0x01);
316   const StaticByteBuffer kUnknownOption1(
317       // code, length, payload
318       0x71,
319       0x01,
320       0x01);
321   ChannelConfiguration config0;
322   EXPECT_TRUE(config0.ReadOptions(kUnknownOption0));
323   EXPECT_EQ(1u, config0.unknown_options().size());
324 
325   ChannelConfiguration config1;
326   EXPECT_TRUE(config1.ReadOptions(kUnknownOption1));
327   EXPECT_EQ(1u, config1.unknown_options().size());
328 
329   config0.Merge(std::move(config1));
330   EXPECT_EQ(2u, config0.unknown_options().size());
331   EXPECT_EQ(kUnknownOption0.data()[0],
332             static_cast<uint8_t>(config0.unknown_options()[0].type()));
333   EXPECT_EQ(kUnknownOption1.data()[0],
334             static_cast<uint8_t>(config0.unknown_options()[1].type()));
335 
336   ChannelConfiguration config2;
337   EXPECT_TRUE(config2.ReadOptions(kUnknownOption0));
338   EXPECT_EQ(1u, config2.unknown_options().size());
339 
340   // Merge duplicate of kUnknownOption0. Duplicates should be appended.
341   config0.Merge(std::move(config2));
342   EXPECT_EQ(3u, config0.unknown_options().size());
343   EXPECT_EQ(kUnknownOption0.data()[0],
344             static_cast<uint8_t>(config0.unknown_options()[0].type()));
345   EXPECT_EQ(kUnknownOption0.data()[0],
346             static_cast<uint8_t>(config0.unknown_options()[2].type()));
347 }
348 
TEST_F(ChannelConfigurationTest,ReadOptions)349 TEST_F(ChannelConfigurationTest, ReadOptions) {
350   const StaticByteBuffer kOptionBuffer(
351       // MTU Option
352       OptionType::kMTU,
353       MtuOption::kPayloadLength,
354       LowerBits(kMinACLMTU),
355       UpperBits(kMinACLMTU),
356       // Rtx Option
357       OptionType::kRetransmissionAndFlowControl,
358       RetransmissionAndFlowControlOption::kPayloadLength,
359       static_cast<uint8_t>(RetransmissionAndFlowControlMode::kRetransmission),
360       0x00,
361       0x00,
362       0x00,
363       0x00,
364       0x00,
365       0x00,
366       0x00,
367       0x00,
368       // Flush Timeout option (timeout = 200)
369       static_cast<uint8_t>(OptionType::kFlushTimeout),
370       FlushTimeoutOption::kPayloadLength,
371       0xc8,
372       0x00,
373       // Unknown option, Type = 0x70, Length = 1
374       0x70,
375       0x01,
376       0x03,
377       // Unknown option (hint), Type = 0x80, Length = 0
378       0x80,
379       0x00);
380   ChannelConfiguration config;
381   EXPECT_TRUE(config.ReadOptions(kOptionBuffer));
382 
383   EXPECT_TRUE(config.mtu_option().has_value());
384   EXPECT_EQ(kMinACLMTU, config.mtu_option()->mtu());
385 
386   EXPECT_TRUE(config.retransmission_flow_control_option().has_value());
387   EXPECT_EQ(RetransmissionAndFlowControlMode::kRetransmission,
388             config.retransmission_flow_control_option()->mode());
389 
390   EXPECT_TRUE(config.flush_timeout_option().has_value());
391   EXPECT_EQ(200u, config.flush_timeout_option()->flush_timeout());
392 
393   // Hint should have been dropped
394   EXPECT_EQ(1u, config.unknown_options().size());
395   auto& option = config.unknown_options().front();
396   EXPECT_EQ(0x70, static_cast<uint8_t>(option.type()));
397   EXPECT_EQ(1u, option.payload().size());
398   EXPECT_EQ(0x03, option.payload().data()[0]);
399 }
400 
TEST_F(ChannelConfigurationTest,ConfigToString)401 TEST_F(ChannelConfigurationTest, ConfigToString) {
402   const StaticByteBuffer kOptionBuffer(
403       // MTU Option
404       static_cast<uint8_t>(OptionType::kMTU),
405       MtuOption::kPayloadLength,
406       LowerBits(kMinACLMTU),
407       UpperBits(kMinACLMTU),
408       // Rtx Option
409       static_cast<uint8_t>(OptionType::kRetransmissionAndFlowControl),
410       RetransmissionAndFlowControlOption::kPayloadLength,
411       static_cast<uint8_t>(RetransmissionAndFlowControlMode::kRetransmission),
412       0x00,
413       0x00,
414       0x00,
415       0x00,
416       0x00,
417       0x00,
418       0x00,
419       0x00,
420       // Flush Timeout option (timeout = 200)
421       static_cast<uint8_t>(OptionType::kFlushTimeout),
422       FlushTimeoutOption::kPayloadLength,
423       0xc8,
424       0x00,
425       // Unknown option, Type = 0x70, Length = 1, payload = 0x03
426       0x70,
427       0x01,
428       0x03);
429 
430   ChannelConfiguration config;
431   EXPECT_TRUE(config.ReadOptions(kOptionBuffer));
432   const std::string kExpected =
433       "{[type: MTU, mtu: 48], "
434       "[type: RtxFlowControl, mode: 1, tx window size: 0, max transmit: 0, rtx "
435       "timeout: 0, monitor "
436       "timeout: 0, max pdu payload size: 0], "
437       "[type: FlushTimeout, flush timeout: 200], "
438       "[type: 0x70, length: 1]}";
439   EXPECT_EQ(kExpected, config.ToString());
440 }
441 
442 }  // namespace
443 }  // namespace bt::l2cap::internal
444