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