1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "hci/le_scanning_reassembler.h"
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 
22 using ::testing::_;
23 using ::testing::Eq;
24 
25 using namespace bluetooth;
26 using namespace std::chrono_literals;
27 
28 namespace bluetooth::hci {
29 
30 // Event type fields.
31 static constexpr uint16_t kConnectable = 0x1;
32 static constexpr uint16_t kScannable = 0x2;
33 static constexpr uint16_t kScanResponse = 0x8;
34 static constexpr uint16_t kLegacy = 0x10;
35 static constexpr uint8_t kComplete = 0x0;
36 static constexpr uint8_t kContinuation = 0x20;
37 static constexpr uint8_t kTruncated = 0x40;
38 
39 // Defaults for other fields.
40 static constexpr uint8_t kSidNotPresent = 0xff;
41 
42 // Test addresses.
43 static const Address kTestAddress = Address({0, 1, 2, 3, 4, 5});
44 
45 // Test sync handles.
46 static const uint16_t kTestSyncHandle1 = 0x4242;
47 static const uint16_t kTestSyncHandle2 = 0x4243;
48 
49 class LeScanningReassemblerTest : public ::testing::Test {
50 public:
51   LeScanningReassembler reassembler_;
52 };
53 
TEST_F(LeScanningReassemblerTest,trim_advertising_data)54 TEST_F(LeScanningReassemblerTest, trim_advertising_data) {
55   // TrimAdvertisingData should filter out empty entries.
56   ASSERT_EQ(LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x0, 0x0, 0x3, 0x4, 0x5, 0x6}),
57             std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
58 
59   // TrimAdvertisingData should remove trailing zeros.
60   ASSERT_EQ(LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x0, 0x0}),
61             std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
62 
63   // TrimAdvertisingData should remove overflowing entries.
64   ASSERT_EQ(LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x3, 0x4, 0x5}),
65             std::vector<uint8_t>({0x1, 0x2}));
66 }
67 
TEST_F(LeScanningReassemblerTest,non_scannable_legacy_advertising)68 TEST_F(LeScanningReassemblerTest, non_scannable_legacy_advertising) {
69   // Test non scannable legacy advertising.
70   ASSERT_EQ(reassembler_
71                     .ProcessAdvertisingReport(kLegacy | kComplete,
72                                               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
73                                               kTestAddress, kSidNotPresent, {0x1, 0x2})
74                     .value()
75                     .data,
76             std::vector<uint8_t>({0x1, 0x2}));
77 }
78 
TEST_F(LeScanningReassemblerTest,scannable_non_connectable_legacy_advertising)79 TEST_F(LeScanningReassemblerTest, scannable_non_connectable_legacy_advertising) {
80   // Test scannable legacy advertising with well formed advertising and
81   // scan response payload.
82   ASSERT_FALSE(reassembler_
83                        .ProcessAdvertisingReport(kLegacy | kScannable | kComplete,
84                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
85                                                  kTestAddress, kSidNotPresent, {0x1, 0x2})
86                        .has_value());
87 
88   auto processed_report =
89           reassembler_.ProcessAdvertisingReport(kLegacy | kScannable | kScanResponse | kComplete,
90                                                 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
91                                                 kTestAddress, kSidNotPresent, {0x3, 0x4, 0x5, 0x6});
92   ASSERT_TRUE(processed_report.has_value());
93   ASSERT_EQ(processed_report.value().extended_event_type, kLegacy | kScannable | kScanResponse);
94   ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
95 
96   // Test scannable legacy advertising with padding after the
97   // advertising and scan response data.
98   ASSERT_FALSE(reassembler_
99                        .ProcessAdvertisingReport(kLegacy | kScannable | kComplete,
100                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
101                                                  kTestAddress, kSidNotPresent, {0x1, 0x2, 0x0, 0x0})
102                        .has_value());
103 
104   ASSERT_EQ(reassembler_
105                     .ProcessAdvertisingReport(kLegacy | kScannable | kScanResponse | kComplete,
106                                               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
107                                               kTestAddress, kSidNotPresent,
108                                               {0x3, 0x4, 0x5, 0x6, 0x0, 0x0})
109                     .value()
110                     .data,
111             std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
112 }
113 
TEST_F(LeScanningReassemblerTest,scannable_connectable_legacy_advertising)114 TEST_F(LeScanningReassemblerTest, scannable_connectable_legacy_advertising) {
115   ASSERT_FALSE(reassembler_
116                        .ProcessAdvertisingReport(kLegacy | kScannable | kConnectable,
117                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
118                                                  kTestAddress, kSidNotPresent, {0x1, 0x2})
119                        .has_value());
120 
121   auto processed_report = reassembler_.ProcessAdvertisingReport(
122           kLegacy | kScannable | kScanResponse, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
123           kTestAddress, kSidNotPresent, {0x3, 0x4, 0x5, 0x6});
124   ASSERT_TRUE(processed_report.has_value());
125   ASSERT_EQ(processed_report.value().extended_event_type,
126             kLegacy | kScannable | kScanResponse | kConnectable);
127   ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
128 }
129 
TEST_F(LeScanningReassemblerTest,non_scannable_extended_advertising)130 TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) {
131   // Test fragmented non scannable extended advertising.
132   // The split may occur in the middle of a GAP entry.
133   ASSERT_FALSE(reassembler_
134                        .ProcessAdvertisingReport(kContinuation,
135                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
136                                                  kTestAddress, kSidNotPresent, {0x1, 0x2, 0x3})
137                        .has_value());
138 
139   auto processed_report = reassembler_.ProcessAdvertisingReport(
140           kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent,
141           {0x4, 0x5, 0x6});
142   ASSERT_TRUE(processed_report.has_value());
143   ASSERT_EQ(processed_report.value().extended_event_type, kComplete);
144   ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
145 
146   // Test fragmented and truncated non scannable extended advertising.
147   // The split may occur in the middle of a GAP entry.
148   ASSERT_FALSE(reassembler_
149                        .ProcessAdvertisingReport(kContinuation,
150                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
151                                                  kTestAddress, kSidNotPresent, {0x1, 0x2, 0x3})
152                        .has_value());
153 
154   ASSERT_EQ(
155           reassembler_
156                   .ProcessAdvertisingReport(kTruncated, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
157                                             kTestAddress, kSidNotPresent, {0x4, 0x5, 0x6, 0x7})
158                   .value()
159                   .data,
160           std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
161 
162   // Test fragmented and truncated anonymous, non scannable
163   // extended advertising. The split may occur in the middle of a GAP entry.
164   ASSERT_FALSE(reassembler_
165                        .ProcessAdvertisingReport(
166                                kContinuation,
167                                (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
168                                Address::kEmpty, kSidNotPresent, {0x1, 0x2, 0x3})
169                        .has_value());
170 
171   ASSERT_EQ(reassembler_
172                     .ProcessAdvertisingReport(
173                             kTruncated, (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
174                             Address::kEmpty, kSidNotPresent, {0x4, 0x5, 0x6, 0x7})
175                     .value()
176                     .data,
177             std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
178 }
179 
TEST_F(LeScanningReassemblerTest,scannable_extended_advertising)180 TEST_F(LeScanningReassemblerTest, scannable_extended_advertising) {
181   // Test fragmented scannable extended advertising.
182   // The split may occur in the middle of a GAP entry.
183   // Padding may occur at the end of the advertising data.
184   ASSERT_FALSE(reassembler_
185                        .ProcessAdvertisingReport(kScannable | kContinuation,
186                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
187                                                  kTestAddress, kSidNotPresent, {0x1, 0x2, 0x3})
188                        .has_value());
189 
190   ASSERT_FALSE(reassembler_
191                        .ProcessAdvertisingReport(
192                                kScannable | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
193                                kTestAddress, kSidNotPresent, {0x4, 0x5, 0x6, 0x0, 0x0})
194                        .has_value());
195 
196   ASSERT_FALSE(reassembler_
197                        .ProcessAdvertisingReport(kContinuation,
198                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
199                                                  kTestAddress, kSidNotPresent, {0x7, 0x8, 0x9, 0xa})
200                        .has_value());
201 
202   ASSERT_EQ(
203           reassembler_
204                   .ProcessAdvertisingReport(kTruncated, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
205                                             kTestAddress, kSidNotPresent, {0xb, 0xc, 0xd, 0xe, 0x0})
206                   .value()
207                   .data,
208           std::vector<uint8_t>(
209                   {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe}));
210 }
211 
TEST_F(LeScanningReassemblerTest,ignore_scan_responses)212 TEST_F(LeScanningReassemblerTest, ignore_scan_responses) {
213   // Scan response without advertising data are ignored.
214   ASSERT_FALSE(reassembler_
215                        .ProcessAdvertisingReport(kScannable | kScanResponse | kComplete,
216                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
217                                                  kTestAddress, kSidNotPresent, {0x1, 0x2})
218                        .has_value());
219 
220   ASSERT_EQ(
221           reassembler_
222                   .ProcessAdvertisingReport(kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
223                                             kTestAddress, kSidNotPresent, {0x1, 0x2})
224                   .value()
225                   .data,
226           std::vector<uint8_t>({0x1, 0x2}));
227 
228   // The option ignore_scan_responses forces scan responses to be dropped.
229   reassembler_.SetIgnoreScanResponses(true);
230   ASSERT_EQ(reassembler_
231                     .ProcessAdvertisingReport(kScannable | kComplete,
232                                               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
233                                               kTestAddress, kSidNotPresent, {0x1, 0x2})
234                     .value()
235                     .data,
236             std::vector<uint8_t>({0x1, 0x2}));
237 }
238 
TEST_F(LeScanningReassemblerTest,interleaved_advertising)239 TEST_F(LeScanningReassemblerTest, interleaved_advertising) {
240   // The reassembler must disambiguate advertising events by address,
241   // address type, and SID.
242   ASSERT_FALSE(reassembler_
243                        .ProcessAdvertisingReport(kContinuation,
244                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
245                                                  kTestAddress, kSidNotPresent, {0x2, 0x0})
246                        .has_value());
247 
248   ASSERT_FALSE(reassembler_
249                        .ProcessAdvertisingReport(kContinuation,
250                                                  (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS,
251                                                  kTestAddress, kSidNotPresent, {0x2, 0x1})
252                        .has_value());
253 
254   ASSERT_FALSE(reassembler_
255                        .ProcessAdvertisingReport(kContinuation,
256                                                  (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
257                                                  kTestAddress, 0x1, {0x2, 0x2})
258                        .has_value());
259 
260   ASSERT_FALSE(reassembler_
261                        .ProcessAdvertisingReport(
262                                kContinuation,
263                                (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
264                                Address::kEmpty, 0x1, {0x2, 0x3})
265                        .has_value());
266 
267   ASSERT_EQ(
268           reassembler_
269                   .ProcessAdvertisingReport(kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
270                                             kTestAddress, kSidNotPresent, {0x0})
271                   .value()
272                   .data,
273           std::vector<uint8_t>({0x2, 0x0, 0x0}));
274 
275   ASSERT_EQ(
276           reassembler_
277                   .ProcessAdvertisingReport(kComplete, (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS,
278                                             kTestAddress, kSidNotPresent, {0x1})
279                   .value()
280                   .data,
281           std::vector<uint8_t>({0x2, 0x1, 0x1}));
282 
283   ASSERT_EQ(
284           reassembler_
285                   .ProcessAdvertisingReport(kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
286                                             kTestAddress, 0x1, {0x2})
287                   .value()
288                   .data,
289           std::vector<uint8_t>({0x2, 0x2, 0x2}));
290 
291   ASSERT_EQ(reassembler_
292                     .ProcessAdvertisingReport(
293                             kComplete, (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
294                             Address::kEmpty, 0x1, {0x3})
295                     .value()
296                     .data,
297             std::vector<uint8_t>({0x2, 0x3, 0x3}));
298 }
299 
TEST_F(LeScanningReassemblerTest,periodic_advertising)300 TEST_F(LeScanningReassemblerTest, periodic_advertising) {
301   // Test periodic advertising.
302   ASSERT_FALSE(reassembler_
303                        .ProcessPeriodicAdvertisingReport(kTestSyncHandle1, DataStatus::CONTINUING,
304                                                          {0x1, 0x2})
305                        .has_value());
306 
307   auto processed_report = reassembler_.ProcessPeriodicAdvertisingReport(
308           kTestSyncHandle1, DataStatus::COMPLETE, {0x3, 0x4, 0x5, 0x6});
309   ASSERT_TRUE(processed_report.has_value());
310   ASSERT_EQ(processed_report.value(), std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
311 
312   // Test periodic advertising with the same handle
313   // to validate that the context was cleared.
314   processed_report = reassembler_.ProcessPeriodicAdvertisingReport(
315           kTestSyncHandle1, DataStatus::COMPLETE, {0x4, 0xa0, 0xb0, 0xc0, 0xd0});
316   ASSERT_TRUE(processed_report.has_value());
317   ASSERT_EQ(processed_report.value(), std::vector<uint8_t>({0x4, 0xa0, 0xb0, 0xc0, 0xd0}));
318 }
319 
TEST_F(LeScanningReassemblerTest,interleaved_periodic_advertising)320 TEST_F(LeScanningReassemblerTest, interleaved_periodic_advertising) {
321   // The reassembler must disambiguate advertising events by address,
322   // address type, and SID.
323   ASSERT_FALSE(reassembler_
324                        .ProcessPeriodicAdvertisingReport(kTestSyncHandle1, DataStatus::CONTINUING,
325                                                          {0x2, 0x0})
326                        .has_value());
327 
328   ASSERT_FALSE(reassembler_
329                        .ProcessPeriodicAdvertisingReport(kTestSyncHandle2, DataStatus::CONTINUING,
330                                                          {0x2, 0x1})
331                        .has_value());
332 
333   ASSERT_EQ(reassembler_
334                     .ProcessPeriodicAdvertisingReport(kTestSyncHandle1, DataStatus::COMPLETE, {0x0})
335                     .value(),
336             std::vector<uint8_t>({0x2, 0x0, 0x0}));
337 
338   ASSERT_EQ(reassembler_
339                     .ProcessPeriodicAdvertisingReport(kTestSyncHandle2, DataStatus::COMPLETE, {0x1})
340                     .value(),
341             std::vector<uint8_t>({0x2, 0x1, 0x1}));
342 }
343 
344 }  // namespace bluetooth::hci
345