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