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 kScannable = 0x2;
32 static constexpr uint16_t kScanResponse = 0x8;
33 static constexpr uint16_t kLegacy = 0x10;
34 static constexpr uint8_t kComplete = 0x0;
35 static constexpr uint8_t kContinuation = 0x20;
36 static constexpr uint8_t kTruncated = 0x40;
37
38 // Defaults for other fields.
39 static constexpr uint8_t kSidNotPresent = 0xff;
40
41 // Test addresses.
42 static const Address kTestAddress = Address({0, 1, 2, 3, 4, 5});
43
44 class LeScanningReassemblerTest : public ::testing::Test {
45 public:
46 LeScanningReassembler reassembler_;
47 };
48
TEST_F(LeScanningReassemblerTest,trim_advertising_data)49 TEST_F(LeScanningReassemblerTest, trim_advertising_data) {
50 // TrimAdvertisingData should filter out empty entries.
51 ASSERT_EQ(
52 LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x0, 0x0, 0x3, 0x4, 0x5, 0x6}),
53 std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
54
55 // TrimAdvertisingData should remove trailing zeros.
56 ASSERT_EQ(
57 LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x0, 0x0}),
58 std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
59
60 // TrimAdvertisingData should remove overflowing entries.
61 ASSERT_EQ(
62 LeScanningReassembler::TrimAdvertisingData({0x1, 0x2, 0x3, 0x4, 0x5}),
63 std::vector<uint8_t>({0x1, 0x2}));
64 }
65
TEST_F(LeScanningReassemblerTest,non_scannable_legacy_advertising)66 TEST_F(LeScanningReassemblerTest, non_scannable_legacy_advertising) {
67 // Test non scannable legacy advertising.
68 ASSERT_EQ(
69 reassembler_.ProcessAdvertisingReport(
70 kLegacy | kComplete,
71 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
72 kTestAddress,
73 kSidNotPresent,
74 {0x1, 0x2}),
75 std::vector<uint8_t>({0x1, 0x2}));
76 }
77
TEST_F(LeScanningReassemblerTest,scannable_legacy_advertising)78 TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) {
79 // Test scannable legacy advertising with well formed advertising and
80 // scan response payload.
81 ASSERT_FALSE(reassembler_
82 .ProcessAdvertisingReport(
83 kLegacy | kScannable | kComplete,
84 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
85 kTestAddress,
86 kSidNotPresent,
87 {0x1, 0x2})
88 .has_value());
89
90 ASSERT_EQ(
91 reassembler_.ProcessAdvertisingReport(
92 kLegacy | kScannable | kScanResponse | kComplete,
93 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
94 kTestAddress,
95 kSidNotPresent,
96 {0x3, 0x4, 0x5, 0x6}),
97 std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
98
99 // Test scannable legacy advertising with padding after the
100 // advertising and scan response data.
101 ASSERT_FALSE(reassembler_
102 .ProcessAdvertisingReport(
103 kLegacy | kScannable | kComplete,
104 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
105 kTestAddress,
106 kSidNotPresent,
107 {0x1, 0x2, 0x0, 0x0})
108 .has_value());
109
110 ASSERT_EQ(
111 reassembler_.ProcessAdvertisingReport(
112 kLegacy | kScannable | kScanResponse | kComplete,
113 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
114 kTestAddress,
115 kSidNotPresent,
116 {0x3, 0x4, 0x5, 0x6, 0x0, 0x0}),
117 std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
118 }
119
TEST_F(LeScanningReassemblerTest,non_scannable_extended_advertising)120 TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) {
121 // Test fragmented non scannable extended advertising.
122 // The split may occur in the middle of a GAP entry.
123 ASSERT_FALSE(reassembler_
124 .ProcessAdvertisingReport(
125 kContinuation,
126 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
127 kTestAddress,
128 kSidNotPresent,
129 {0x1, 0x2, 0x3})
130 .has_value());
131
132 ASSERT_EQ(
133 reassembler_.ProcessAdvertisingReport(
134 kComplete,
135 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
136 kTestAddress,
137 kSidNotPresent,
138 {0x4, 0x5, 0x6}),
139 std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
140
141 // Test fragmented and truncated non scannable extended advertising.
142 // The split may occur in the middle of a GAP entry.
143 ASSERT_FALSE(reassembler_
144 .ProcessAdvertisingReport(
145 kContinuation,
146 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
147 kTestAddress,
148 kSidNotPresent,
149 {0x1, 0x2, 0x3})
150 .has_value());
151
152 ASSERT_EQ(
153 reassembler_.ProcessAdvertisingReport(
154 kTruncated,
155 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
156 kTestAddress,
157 kSidNotPresent,
158 {0x4, 0x5, 0x6, 0x7}),
159 std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
160
161 // Test fragmented and truncated anonymous, non scannable
162 // extended advertising. The split may occur in the middle of a GAP entry.
163 ASSERT_FALSE(reassembler_
164 .ProcessAdvertisingReport(
165 kContinuation,
166 (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
167 Address::kEmpty,
168 kSidNotPresent,
169 {0x1, 0x2, 0x3})
170 .has_value());
171
172 ASSERT_EQ(
173 reassembler_.ProcessAdvertisingReport(
174 kTruncated,
175 (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
176 Address::kEmpty,
177 kSidNotPresent,
178 {0x4, 0x5, 0x6, 0x7}),
179 std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
180 }
181
TEST_F(LeScanningReassemblerTest,scannable_extended_advertising)182 TEST_F(LeScanningReassemblerTest, scannable_extended_advertising) {
183 // Test fragmented scannable extended advertising.
184 // The split may occur in the middle of a GAP entry.
185 // Padding may occur at the end of the advertising data.
186 ASSERT_FALSE(reassembler_
187 .ProcessAdvertisingReport(
188 kScannable | kContinuation,
189 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
190 kTestAddress,
191 kSidNotPresent,
192 {0x1, 0x2, 0x3})
193 .has_value());
194
195 ASSERT_FALSE(reassembler_
196 .ProcessAdvertisingReport(
197 kScannable | kComplete,
198 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
199 kTestAddress,
200 kSidNotPresent,
201 {0x4, 0x5, 0x6, 0x0, 0x0})
202 .has_value());
203
204 ASSERT_FALSE(reassembler_
205 .ProcessAdvertisingReport(
206 kContinuation,
207 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
208 kTestAddress,
209 kSidNotPresent,
210 {0x7, 0x8, 0x9, 0xa})
211 .has_value());
212
213 ASSERT_EQ(
214 reassembler_.ProcessAdvertisingReport(
215 kTruncated,
216 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
217 kTestAddress,
218 kSidNotPresent,
219 {0xb, 0xc, 0xd, 0xe, 0x0}),
220 std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe}));
221 }
222
TEST_F(LeScanningReassemblerTest,ignore_scan_responses)223 TEST_F(LeScanningReassemblerTest, ignore_scan_responses) {
224 // Scan response without advertising data are ignored.
225 ASSERT_FALSE(reassembler_
226 .ProcessAdvertisingReport(
227 kScannable | kScanResponse | kComplete,
228 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
229 kTestAddress,
230 kSidNotPresent,
231 {0x1, 0x2})
232 .has_value());
233
234 ASSERT_EQ(
235 reassembler_.ProcessAdvertisingReport(
236 kComplete,
237 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
238 kTestAddress,
239 kSidNotPresent,
240 {0x1, 0x2}),
241 std::vector<uint8_t>({0x1, 0x2}));
242
243 // The option ignore_scan_responses forces scan responses to be dropped.
244 reassembler_.SetIgnoreScanResponses(true);
245 ASSERT_EQ(
246 reassembler_.ProcessAdvertisingReport(
247 kScannable | kComplete,
248 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
249 kTestAddress,
250 kSidNotPresent,
251 {0x1, 0x2}),
252 std::vector<uint8_t>({0x1, 0x2}));
253 }
254
TEST_F(LeScanningReassemblerTest,interleaved_advertising)255 TEST_F(LeScanningReassemblerTest, interleaved_advertising) {
256 // The reassembler must disambiguate advertising events by address,
257 // address type, and SID.
258 ASSERT_FALSE(reassembler_
259 .ProcessAdvertisingReport(
260 kContinuation,
261 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
262 kTestAddress,
263 kSidNotPresent,
264 {0x2, 0x0})
265 .has_value());
266
267 ASSERT_FALSE(reassembler_
268 .ProcessAdvertisingReport(
269 kContinuation,
270 (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS,
271 kTestAddress,
272 kSidNotPresent,
273 {0x2, 0x1})
274 .has_value());
275
276 ASSERT_FALSE(reassembler_
277 .ProcessAdvertisingReport(
278 kContinuation,
279 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
280 kTestAddress,
281 0x1,
282 {0x2, 0x2})
283 .has_value());
284
285 ASSERT_FALSE(reassembler_
286 .ProcessAdvertisingReport(
287 kContinuation,
288 (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
289 Address::kEmpty,
290 0x1,
291 {0x2, 0x3})
292 .has_value());
293
294 ASSERT_EQ(
295 reassembler_.ProcessAdvertisingReport(
296 kComplete,
297 (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
298 kTestAddress,
299 kSidNotPresent,
300 {0x0}),
301 std::vector<uint8_t>({0x2, 0x0, 0x0}));
302
303 ASSERT_EQ(
304 reassembler_.ProcessAdvertisingReport(
305 kComplete,
306 (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS,
307 kTestAddress,
308 kSidNotPresent,
309 {0x1}),
310 std::vector<uint8_t>({0x2, 0x1, 0x1}));
311
312 ASSERT_EQ(
313 reassembler_.ProcessAdvertisingReport(
314 kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, 0x1, {0x2}),
315 std::vector<uint8_t>({0x2, 0x2, 0x2}));
316
317 ASSERT_EQ(
318 reassembler_.ProcessAdvertisingReport(
319 kComplete,
320 (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
321 Address::kEmpty,
322 0x1,
323 {0x3}),
324 std::vector<uint8_t>({0x2, 0x3, 0x3}));
325 }
326
327 } // namespace bluetooth::hci
328