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(
57       LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x0, 0x0, 0x3, 0x4, 0x5, 0x6}),
58       std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
59 
60   // TrimAdvertisingData should remove trailing zeros.
61   ASSERT_EQ(
62       LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x0, 0x0}),
63       std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
64 
65   // TrimAdvertisingData should remove overflowing entries.
66   ASSERT_EQ(
67       LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x3, 0x4, 0x5}),
68       std::vector<uint8_t>({0x1, 0x2}));
69 }
70 
TEST_F(LeScanningReassemblerTest,non_scannable_legacy_advertising)71 TEST_F(LeScanningReassemblerTest, non_scannable_legacy_advertising) {
72   // Test non scannable legacy advertising.
73   ASSERT_EQ(
74       reassembler_
75           .ProcessAdvertisingReport(
76               kLegacy | kComplete,
77               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
78               kTestAddress,
79               kSidNotPresent,
80               {0x1, 0x2})
81           .value()
82           .data,
83       std::vector<uint8_t>({0x1, 0x2}));
84 }
85 
TEST_F(LeScanningReassemblerTest,scannable_non_connectable_legacy_advertising)86 TEST_F(LeScanningReassemblerTest, scannable_non_connectable_legacy_advertising) {
87   // Test scannable legacy advertising with well formed advertising and
88   // scan response payload.
89   ASSERT_FALSE(reassembler_
90                    .ProcessAdvertisingReport(
91                        kLegacy | kScannable | kComplete,
92                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
93                        kTestAddress,
94                        kSidNotPresent,
95                        {0x1, 0x2})
96                    .has_value());
97 
98   auto processed_report = reassembler_.ProcessAdvertisingReport(
99       kLegacy | kScannable | kScanResponse | kComplete,
100       (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
101       kTestAddress,
102       kSidNotPresent,
103       {0x3, 0x4, 0x5, 0x6});
104   ASSERT_TRUE(processed_report.has_value());
105   ASSERT_EQ(processed_report.value().extended_event_type, kLegacy | kScannable | kScanResponse);
106   ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
107 
108   // Test scannable legacy advertising with padding after the
109   // advertising and scan response data.
110   ASSERT_FALSE(reassembler_
111                    .ProcessAdvertisingReport(
112                        kLegacy | kScannable | kComplete,
113                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
114                        kTestAddress,
115                        kSidNotPresent,
116                        {0x1, 0x2, 0x0, 0x0})
117                    .has_value());
118 
119   ASSERT_EQ(
120       reassembler_
121           .ProcessAdvertisingReport(
122               kLegacy | kScannable | kScanResponse | kComplete,
123               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
124               kTestAddress,
125               kSidNotPresent,
126               {0x3, 0x4, 0x5, 0x6, 0x0, 0x0})
127           .value()
128           .data,
129       std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
130 }
131 
TEST_F(LeScanningReassemblerTest,scannable_connectable_legacy_advertising)132 TEST_F(LeScanningReassemblerTest, scannable_connectable_legacy_advertising) {
133   ASSERT_FALSE(reassembler_
134                    .ProcessAdvertisingReport(
135                        kLegacy | kScannable | kConnectable,
136                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
137                        kTestAddress,
138                        kSidNotPresent,
139                        {0x1, 0x2})
140                    .has_value());
141 
142   auto processed_report = reassembler_.ProcessAdvertisingReport(
143       kLegacy | kScannable | kScanResponse,
144       (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
145       kTestAddress,
146       kSidNotPresent,
147       {0x3, 0x4, 0x5, 0x6});
148   ASSERT_TRUE(processed_report.has_value());
149   ASSERT_EQ(
150       processed_report.value().extended_event_type,
151       kLegacy | kScannable | kScanResponse | kConnectable);
152   ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
153 }
154 
TEST_F(LeScanningReassemblerTest,non_scannable_extended_advertising)155 TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) {
156   // Test fragmented non scannable extended advertising.
157   // The split may occur in the middle of a GAP entry.
158   ASSERT_FALSE(reassembler_
159                    .ProcessAdvertisingReport(
160                        kContinuation,
161                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
162                        kTestAddress,
163                        kSidNotPresent,
164                        {0x1, 0x2, 0x3})
165                    .has_value());
166 
167   auto processed_report = reassembler_.ProcessAdvertisingReport(
168       kComplete,
169       (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
170       kTestAddress,
171       kSidNotPresent,
172       {0x4, 0x5, 0x6});
173   ASSERT_TRUE(processed_report.has_value());
174   ASSERT_EQ(processed_report.value().extended_event_type, kComplete);
175   ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
176 
177   // Test fragmented and truncated non scannable extended advertising.
178   // The split may occur in the middle of a GAP entry.
179   ASSERT_FALSE(reassembler_
180                    .ProcessAdvertisingReport(
181                        kContinuation,
182                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
183                        kTestAddress,
184                        kSidNotPresent,
185                        {0x1, 0x2, 0x3})
186                    .has_value());
187 
188   ASSERT_EQ(
189       reassembler_
190           .ProcessAdvertisingReport(
191               kTruncated,
192               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
193               kTestAddress,
194               kSidNotPresent,
195               {0x4, 0x5, 0x6, 0x7})
196           .value()
197           .data,
198       std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
199 
200   // Test fragmented and truncated anonymous, non scannable
201   // extended advertising. The split may occur in the middle of a GAP entry.
202   ASSERT_FALSE(reassembler_
203                    .ProcessAdvertisingReport(
204                        kContinuation,
205                        (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
206                        Address::kEmpty,
207                        kSidNotPresent,
208                        {0x1, 0x2, 0x3})
209                    .has_value());
210 
211   ASSERT_EQ(
212       reassembler_
213           .ProcessAdvertisingReport(
214               kTruncated,
215               (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
216               Address::kEmpty,
217               kSidNotPresent,
218               {0x4, 0x5, 0x6, 0x7})
219           .value()
220           .data,
221       std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
222 }
223 
TEST_F(LeScanningReassemblerTest,scannable_extended_advertising)224 TEST_F(LeScanningReassemblerTest, scannable_extended_advertising) {
225   // Test fragmented scannable extended advertising.
226   // The split may occur in the middle of a GAP entry.
227   // Padding may occur at the end of the advertising data.
228   ASSERT_FALSE(reassembler_
229                    .ProcessAdvertisingReport(
230                        kScannable | kContinuation,
231                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
232                        kTestAddress,
233                        kSidNotPresent,
234                        {0x1, 0x2, 0x3})
235                    .has_value());
236 
237   ASSERT_FALSE(reassembler_
238                    .ProcessAdvertisingReport(
239                        kScannable | kComplete,
240                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
241                        kTestAddress,
242                        kSidNotPresent,
243                        {0x4, 0x5, 0x6, 0x0, 0x0})
244                    .has_value());
245 
246   ASSERT_FALSE(reassembler_
247                    .ProcessAdvertisingReport(
248                        kContinuation,
249                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
250                        kTestAddress,
251                        kSidNotPresent,
252                        {0x7, 0x8, 0x9, 0xa})
253                    .has_value());
254 
255   ASSERT_EQ(
256       reassembler_
257           .ProcessAdvertisingReport(
258               kTruncated,
259               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
260               kTestAddress,
261               kSidNotPresent,
262               {0xb, 0xc, 0xd, 0xe, 0x0})
263           .value()
264           .data,
265       std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe}));
266 }
267 
TEST_F(LeScanningReassemblerTest,ignore_scan_responses)268 TEST_F(LeScanningReassemblerTest, ignore_scan_responses) {
269   // Scan response without advertising data are ignored.
270   ASSERT_FALSE(reassembler_
271                    .ProcessAdvertisingReport(
272                        kScannable | kScanResponse | kComplete,
273                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
274                        kTestAddress,
275                        kSidNotPresent,
276                        {0x1, 0x2})
277                    .has_value());
278 
279   ASSERT_EQ(
280       reassembler_
281           .ProcessAdvertisingReport(
282               kComplete,
283               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
284               kTestAddress,
285               kSidNotPresent,
286               {0x1, 0x2})
287           .value()
288           .data,
289       std::vector<uint8_t>({0x1, 0x2}));
290 
291   // The option ignore_scan_responses forces scan responses to be dropped.
292   reassembler_.SetIgnoreScanResponses(true);
293   ASSERT_EQ(
294       reassembler_
295           .ProcessAdvertisingReport(
296               kScannable | kComplete,
297               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
298               kTestAddress,
299               kSidNotPresent,
300               {0x1, 0x2})
301           .value()
302           .data,
303       std::vector<uint8_t>({0x1, 0x2}));
304 }
305 
TEST_F(LeScanningReassemblerTest,interleaved_advertising)306 TEST_F(LeScanningReassemblerTest, interleaved_advertising) {
307   // The reassembler must disambiguate advertising events by address,
308   // address type, and SID.
309   ASSERT_FALSE(reassembler_
310                    .ProcessAdvertisingReport(
311                        kContinuation,
312                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
313                        kTestAddress,
314                        kSidNotPresent,
315                        {0x2, 0x0})
316                    .has_value());
317 
318   ASSERT_FALSE(reassembler_
319                    .ProcessAdvertisingReport(
320                        kContinuation,
321                        (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS,
322                        kTestAddress,
323                        kSidNotPresent,
324                        {0x2, 0x1})
325                    .has_value());
326 
327   ASSERT_FALSE(reassembler_
328                    .ProcessAdvertisingReport(
329                        kContinuation,
330                        (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
331                        kTestAddress,
332                        0x1,
333                        {0x2, 0x2})
334                    .has_value());
335 
336   ASSERT_FALSE(reassembler_
337                    .ProcessAdvertisingReport(
338                        kContinuation,
339                        (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
340                        Address::kEmpty,
341                        0x1,
342                        {0x2, 0x3})
343                    .has_value());
344 
345   ASSERT_EQ(
346       reassembler_
347           .ProcessAdvertisingReport(
348               kComplete,
349               (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
350               kTestAddress,
351               kSidNotPresent,
352               {0x0})
353           .value()
354           .data,
355       std::vector<uint8_t>({0x2, 0x0, 0x0}));
356 
357   ASSERT_EQ(
358       reassembler_
359           .ProcessAdvertisingReport(
360               kComplete,
361               (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS,
362               kTestAddress,
363               kSidNotPresent,
364               {0x1})
365           .value()
366           .data,
367       std::vector<uint8_t>({0x2, 0x1, 0x1}));
368 
369   ASSERT_EQ(
370       reassembler_
371           .ProcessAdvertisingReport(
372               kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, 0x1, {0x2})
373           .value()
374           .data,
375       std::vector<uint8_t>({0x2, 0x2, 0x2}));
376 
377   ASSERT_EQ(
378       reassembler_
379           .ProcessAdvertisingReport(
380               kComplete,
381               (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
382               Address::kEmpty,
383               0x1,
384               {0x3})
385           .value()
386           .data,
387       std::vector<uint8_t>({0x2, 0x3, 0x3}));
388 }
389 
TEST_F(LeScanningReassemblerTest,periodic_advertising)390 TEST_F(LeScanningReassemblerTest, periodic_advertising) {
391   // Test periodic advertising.
392   ASSERT_FALSE(
393       reassembler_
394           .ProcessPeriodicAdvertisingReport(kTestSyncHandle1, DataStatus::CONTINUING, {0x1, 0x2})
395           .has_value());
396 
397   auto processed_report = reassembler_.ProcessPeriodicAdvertisingReport(
398       kTestSyncHandle1, DataStatus::COMPLETE, {0x3, 0x4, 0x5, 0x6});
399   ASSERT_TRUE(processed_report.has_value());
400   ASSERT_EQ(processed_report.value(), std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
401 
402   // Test periodic advertising with the same handle
403   // to validate that the context was cleared.
404   processed_report = reassembler_.ProcessPeriodicAdvertisingReport(
405       kTestSyncHandle1, DataStatus::COMPLETE, {0x4, 0xa0, 0xb0, 0xc0, 0xd0});
406   ASSERT_TRUE(processed_report.has_value());
407   ASSERT_EQ(processed_report.value(), std::vector<uint8_t>({0x4, 0xa0, 0xb0, 0xc0, 0xd0}));
408 }
409 
TEST_F(LeScanningReassemblerTest,interleaved_periodic_advertising)410 TEST_F(LeScanningReassemblerTest, interleaved_periodic_advertising) {
411   // The reassembler must disambiguate advertising events by address,
412   // address type, and SID.
413   ASSERT_FALSE(
414       reassembler_
415           .ProcessPeriodicAdvertisingReport(kTestSyncHandle1, DataStatus::CONTINUING, {0x2, 0x0})
416           .has_value());
417 
418   ASSERT_FALSE(
419       reassembler_
420           .ProcessPeriodicAdvertisingReport(kTestSyncHandle2, DataStatus::CONTINUING, {0x2, 0x1})
421           .has_value());
422 
423   ASSERT_EQ(
424       reassembler_.ProcessPeriodicAdvertisingReport(kTestSyncHandle1, DataStatus::COMPLETE, {0x0})
425           .value(),
426       std::vector<uint8_t>({0x2, 0x0, 0x0}));
427 
428   ASSERT_EQ(
429       reassembler_.ProcessPeriodicAdvertisingReport(kTestSyncHandle2, DataStatus::COMPLETE, {0x1})
430           .value(),
431       std::vector<uint8_t>({0x2, 0x1, 0x1}));
432 }
433 
434 }  // namespace bluetooth::hci
435