• 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 #include "pw_bluetooth_proxy_private/test_utils.h"
16 
17 namespace pw::bluetooth::proxy {
18 namespace {
19 
20 // ########## UtilsTest
21 
TEST(UtilsTest,SetupKFrameProperlySegments)22 TEST(UtilsTest, SetupKFrameProperlySegments) {
23   std::array<uint8_t, 23> expected_payload = {1,  2,  3,  4,  5,  6,  7,  8,
24                                               9,  10, 11, 12, 13, 14, 15, 16,
25                                               17, 18, 19, 20, 21, 22, 23};
26   ASSERT_GE(expected_payload.size(), 2ul);
27   constexpr uint16_t kHandle = 0x123;
28   constexpr uint16_t kCid = 0x456;
29 
30   // Validate the segmentation of `expected_payload` based on every MPS from 2
31   // octets up to 5 octets greater than the length of `expected_payload`.
32   for (size_t mps = 2; mps < expected_payload.size() + 5; ++mps) {
33     size_t segment_no;
34     size_t pdu_total_length = expected_payload.size() + kSduLengthFieldSize;
35     size_t total_num_segments = 1;
36     size_t final_segment_payload_size =
37         std::min(mps, expected_payload.size() + kSduLengthFieldSize);
38     // Only if total L2CAP PDU payload bytes to be sent are greater than MPS
39     // will multiple segments be sent.
40     if (mps < pdu_total_length) {
41       total_num_segments = pdu_total_length / mps;
42       // Account for the final segment, which may be sub-MPS sized and not
43       // accounted for in the above int division operation.
44       if (pdu_total_length % mps != 0) {
45         ++total_num_segments;
46         final_segment_payload_size = pdu_total_length % mps;
47       }
48     }
49 
50     for (segment_no = 0; segment_no < total_num_segments; ++segment_no) {
51       PW_TEST_ASSERT_OK_AND_ASSIGN(
52           KFrameWithStorage kframe,
53           SetupKFrame(kHandle, kCid, mps, segment_no, span(expected_payload)));
54 
55       uint16_t pdu_length = mps;
56       if (segment_no == total_num_segments - 1) {
57         pdu_length = final_segment_payload_size;
58       }
59 
60       // Validate ACL header.
61       emboss::AclDataFrameView acl = kframe.acl.writer;
62       EXPECT_EQ(acl.header().handle().Read(), kHandle);
63       EXPECT_EQ(acl.data_total_length().Read(),
64                 emboss::BasicL2capHeader::IntrinsicSizeInBytes() + pdu_length);
65 
66       uint8_t* kframe_payload_start;
67       if (std::holds_alternative<emboss::FirstKFrameWriter>(kframe.writer)) {
68         emboss::FirstKFrameWriter first_kframe_writer =
69             std::get<emboss::FirstKFrameWriter>(kframe.writer);
70         EXPECT_EQ(first_kframe_writer.pdu_length().Read(), pdu_length);
71         EXPECT_EQ(first_kframe_writer.channel_id().Read(), kCid);
72         EXPECT_EQ(first_kframe_writer.sdu_length().Read(),
73                   expected_payload.size());
74         kframe_payload_start =
75             first_kframe_writer.payload().BackingStorage().data();
76       } else {
77         emboss::SubsequentKFrameWriter subsequent_kframe_writer =
78             std::get<emboss::SubsequentKFrameWriter>(kframe.writer);
79         EXPECT_EQ(subsequent_kframe_writer.pdu_length().Read(), pdu_length);
80         EXPECT_EQ(subsequent_kframe_writer.channel_id().Read(), kCid);
81         kframe_payload_start =
82             subsequent_kframe_writer.payload().BackingStorage().data();
83       }
84 
85       // Validate payload of segment.
86       size_t payload_length = pdu_length;
87       uint8_t* expected_payload_start =
88           expected_payload.data() + segment_no * mps;
89       if (segment_no == 0) {
90         payload_length -= kSduLengthFieldSize;
91       } else {
92         expected_payload_start -= kSduLengthFieldSize;
93       }
94       EXPECT_EQ(
95           0,
96           std::memcmp(
97               kframe_payload_start, expected_payload_start, payload_length));
98     }
99 
100     // Confirm that requesting a segment one past the final expected segment
101     // results in an error.
102     EXPECT_EQ(
103         SetupKFrame(kHandle, kCid, mps, segment_no, span(expected_payload))
104             .status(),
105         Status::OutOfRange());
106   }
107 }
108 
109 }  // namespace
110 }  // namespace pw::bluetooth::proxy
111