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