1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_discovery_manager.h"
16
17 #include "pw_bluetooth_sapphire/internal/host/gap/peer_cache.h"
18 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
19 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
20 #include "pw_bluetooth_sapphire/internal/host/testing/inspect.h"
21 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
24
25 namespace bt::gap {
26 namespace {
27
28 using namespace inspect::testing;
29
30 using bt::testing::CommandTransaction;
31
32 using TestingBase =
33 bt::testing::FakeDispatcherControllerTest<bt::testing::MockController>;
34
35 // clang-format off
36 #define COMMAND_COMPLETE_RSP(opcode) \
37 StaticByteBuffer(hci_spec::kCommandCompleteEventCode, 0x04, 0xF0, \
38 LowerBits((opcode)), UpperBits((opcode)), \
39 pw::bluetooth::emboss::StatusCode::SUCCESS)
40
41 #define COMMAND_STATUS_RSP(opcode, statuscode) \
42 StaticByteBuffer( hci_spec::kCommandStatusEventCode, 0x04, \
43 (statuscode), 0xF0, \
44 LowerBits((opcode)), UpperBits((opcode)))
45
46
47 const StaticByteBuffer kWriteInquiryActivity(
48 LowerBits(hci_spec::kWriteInquiryScanActivity), UpperBits(hci_spec::kWriteInquiryScanActivity),
49 0x04, // Param total size
50 LowerBits(kInquiryScanInterval), UpperBits(kInquiryScanInterval),
51 LowerBits(kInquiryScanWindow), UpperBits(kInquiryScanWindow)
52 );
53
54 const auto kWriteInquiryActivityRsp = COMMAND_COMPLETE_RSP(hci_spec::kWriteInquiryScanActivity);
55
56 const StaticByteBuffer kWriteInquiryType(
57 LowerBits(hci_spec::kWriteInquiryScanType), UpperBits(hci_spec::kWriteInquiryScanType),
58 0x01, // Param total size
59 0x01 // Interlaced Inquiry Scan
60 );
61
62 const auto kWriteInquiryTypeRsp = COMMAND_COMPLETE_RSP(hci_spec::kWriteInquiryScanType);
63 // clang-format on
64
65 class BrEdrDiscoveryManagerTest : public TestingBase {
66 public:
67 BrEdrDiscoveryManagerTest() = default;
68 ~BrEdrDiscoveryManagerTest() override = default;
69
SetUp()70 void SetUp() override {
71 TestingBase::SetUp();
72
73 NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode::STANDARD);
74 }
75
TearDown()76 void TearDown() override {
77 discovery_manager_ = nullptr;
78 TestingBase::TearDown();
79 }
80
NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode mode)81 void NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode mode) {
82 // We expect to set the Inquiry Scan and the Type when we start.
83 EXPECT_CMD_PACKET_OUT(
84 test_device(), kWriteInquiryActivity, &kWriteInquiryActivityRsp);
85 EXPECT_CMD_PACKET_OUT(
86 test_device(), kWriteInquiryType, &kWriteInquiryTypeRsp);
87
88 discovery_manager_ = std::make_unique<BrEdrDiscoveryManager>(
89 dispatcher(),
90 transport()->command_channel()->AsWeakPtr(),
91 mode,
92 &peer_cache_);
93
94 RunUntilIdle();
95 }
96
DestroyDiscoveryManager()97 void DestroyDiscoveryManager() { discovery_manager_.reset(); }
98
peer_cache()99 PeerCache* peer_cache() { return &peer_cache_; }
100
101 protected:
discovery_manager() const102 BrEdrDiscoveryManager* discovery_manager() const {
103 return discovery_manager_.get();
104 }
105
106 private:
107 PeerCache peer_cache_{dispatcher()};
108 std::unique_ptr<BrEdrDiscoveryManager> discovery_manager_;
109
110 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(BrEdrDiscoveryManagerTest);
111 };
112
113 using GAP_BrEdrDiscoveryManagerTest = BrEdrDiscoveryManagerTest;
114
115 // Suffix DeathTest has GoogleTest-specific behavior
116 using BrEdrDiscoveryManagerDeathTest = BrEdrDiscoveryManagerTest;
117
118 // clang-format off
119 const StaticByteBuffer kInquiry(
120 LowerBits(hci_spec::kInquiry), UpperBits(hci_spec::kInquiry),
121 0x05, // Paramreter total size
122 0x33, 0x8B, 0x9E, // GIAC
123 0x08, // hci_spec::kInquiryLengthDefault
124 0x00 // Unlimited responses
125 );
126
127 const auto kWriteLocalNameRsp =
128 COMMAND_STATUS_RSP(hci_spec::kWriteLocalName, pw::bluetooth::emboss::StatusCode::SUCCESS);
129
130 const auto kWriteLocalNameRspError =
131 COMMAND_STATUS_RSP(hci_spec::kWriteLocalName, pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
132
133 const auto kWriteExtendedInquiryResponseRsp =
134 COMMAND_STATUS_RSP(hci_spec::kWriteExtendedInquiryResponse, pw::bluetooth::emboss::StatusCode::SUCCESS);
135
136 const auto kWriteExtendedInquiryResponseRspError =
137 COMMAND_STATUS_RSP(hci_spec::kWriteExtendedInquiryResponse, pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
138
139 const auto kInquiryRsp = COMMAND_STATUS_RSP(hci_spec::kInquiry, pw::bluetooth::emboss::StatusCode::SUCCESS);
140
141 const auto kInquiryRspError = COMMAND_STATUS_RSP(hci_spec::kInquiry, pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
142
143 const StaticByteBuffer kInquiryComplete(
144 hci_spec::kInquiryCompleteEventCode,
145 0x01, // parameter_total_size (1 bytes)
146 pw::bluetooth::emboss::StatusCode::SUCCESS
147 );
148
149 const StaticByteBuffer kInquiryCompleteError(
150 hci_spec::kInquiryCompleteEventCode,
151 0x01, // parameter_total_size (1 bytes)
152 pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE
153 );
154
155 #define BD_ADDR(addr1) addr1, 0x00, 0x00, 0x00, 0x00, 0x00
156
157 const DeviceAddress kDeviceAddress1(DeviceAddress::Type::kBREDR,
158 {BD_ADDR(0x01)});
159 const DeviceAddress kLeAliasAddress1(DeviceAddress::Type::kLEPublic,
160 kDeviceAddress1.value());
161 const DeviceAddress kDeviceAddress2(DeviceAddress::Type::kBREDR,
162 {BD_ADDR(0x02)});
163 const DeviceAddress kLeAliasAddress2(DeviceAddress::Type::kLEPublic,
164 kDeviceAddress2.value());
165 const DeviceAddress kDeviceAddress3(DeviceAddress::Type::kBREDR,
166 {BD_ADDR(0x03)});
167 const DeviceAddress kLeAliasAddress3(DeviceAddress::Type::kLEPublic,
168 kDeviceAddress3.value());
169
170 const StaticByteBuffer kInquiryResult(
171 hci_spec::kInquiryResultEventCode,
172 0x0F, // parameter_total_size (15 bytes)
173 0x01, // num_responses
174 BD_ADDR(0x01), // bd_addr[0]
175 0x00, // page_scan_repetition_mode[0] (R0)
176 0x00, // unused / reserved
177 0x00, // unused / reserved
178 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
179 0x00, 0x00 // clock_offset[0]
180 );
181
182 const StaticByteBuffer kInquiryResultIncompleteHeader(
183 hci_spec::kInquiryResultEventCode,
184 0x00 // parameter_total_size (0 bytes)
185 // truncated
186 );
187
188 const StaticByteBuffer kInquiryResultMissingResponses(
189 hci_spec::kInquiryResultEventCode,
190 0x1D, // parameter_total_size (29 bytes)
191 0x03, // num_responses (only two responses are packed)
192
193 // first response
194 BD_ADDR(0x01), // bd_addr[0]
195 0x00, // page_scan_repetition_mode[0] (R0)
196 0x00, // unused / reserved
197 0x00, // unused / reserved
198 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
199 0x00, 0x00, // clock_offset[0]
200
201 // second response
202 BD_ADDR(0x02), // bd_addr[0]
203 0x00, // page_scan_repetition_mode[0] (R0)
204 0x00, // unused / reserved
205 0x00, // unused / reserved
206 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
207 0x00, 0x00 // clock_offset[0]
208 );
209
210 const StaticByteBuffer kInquiryResultIncompleteResponse(
211 hci_spec::kInquiryResultEventCode,
212 0x15, // parameter_total_size (21 bytes)
213 0x02, // num_responses
214
215 // first response
216 BD_ADDR(0x01), // bd_addr[0]
217 0x00, // page_scan_repetition_mode[0] (R0)
218 0x00, // unused / reserved
219 0x00, // unused / reserved
220 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
221 0x00, 0x00, // clock_offset[0]
222
223 // second response
224 BD_ADDR(0x02) // bd_addr[0]
225 // truncated
226 );
227
228 const StaticByteBuffer kRSSIInquiryResult(
229 hci_spec::kInquiryResultWithRSSIEventCode,
230 0x0F, // parameter_total_size (15 bytes)
231 0x01, // num_responses
232 BD_ADDR(0x02), // bd_addr[0]
233 0x00, // page_scan_repetition_mode[0] (R0)
234 0x00, // unused / reserved
235 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
236 0x00, 0x00, // clock_offset[0]
237 0xEC // RSSI (-20dBm)
238 );
239
240 #define REMOTE_NAME_REQUEST(addr1) StaticByteBuffer( \
241 LowerBits(hci_spec::kRemoteNameRequest), UpperBits(hci_spec::kRemoteNameRequest), \
242 0x0a, /* parameter_total_size (10 bytes) */ \
243 BD_ADDR(addr1), /* BD_ADDR */ \
244 0x00, 0x00, 0x00, 0x80 /* page_scan_repetition_mode, 0, clock_offset */ \
245 );
246
247 const auto kRemoteNameRequest1 = REMOTE_NAME_REQUEST(0x01)
248 const auto kRemoteNameRequest2 = REMOTE_NAME_REQUEST(0x02)
249
250 #undef REMOTE_NAME_REQUEST
251
252 const auto kRemoteNameRequestRsp =
253 COMMAND_STATUS_RSP(hci_spec::kRemoteNameRequest, pw::bluetooth::emboss::StatusCode::SUCCESS);
254
255 #undef COMMAND_STATUS_RSP
256
257 const auto kRemoteNameRequestComplete1 = testing::RemoteNameRequestCompletePacket(
258 kDeviceAddress1, {'F', 'u', 'c', 'h', 's', 'i', 'a', '\xF0', '\x9F',
259 '\x92', '\x96', '\x00', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19',
260 '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '\x20'}
261 // remote name (Fuchsia)
262 // Everything after the 0x00 should be ignored.
263 );
264 const auto kRemoteNameRequestComplete2 =
265 testing::RemoteNameRequestCompletePacket(kDeviceAddress2, "Sapphire");
266
267 const StaticByteBuffer kExtendedInquiryResult(
268 hci_spec::kExtendedInquiryResultEventCode,
269 0xFF, // parameter_total_size (255 bytes)
270 0x01, // num_responses
271 BD_ADDR(0x03), // bd_addr
272 0x00, // page_scan_repetition_mode (R0)
273 0x00, // unused / reserved
274 0x00, 0x1F, 0x00, // class_of_device (unspecified)
275 0x00, 0x00, // clock_offset
276 0xEC, // RSSI (-20dBm)
277 // Extended Inquiry Response (240 bytes total)
278 // Complete Local Name (12 bytes): Fuchsia
279 0x0C, 0x09, 'F', 'u', 'c', 'h', 's', 'i', 'a', 0xF0, 0x9F, 0x92, 0x96,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
298 );
299
300 #undef BD_ADDR
301
302 const StaticByteBuffer kSetExtendedMode(
303 LowerBits(hci_spec::kWriteInquiryMode), UpperBits(hci_spec::kWriteInquiryMode),
304 0x01, // parameter_total_size
305 0x02 // Extended Inquiry Result or Inquiry Result with RSSI
306 );
307
308 const auto kSetExtendedModeRsp = COMMAND_COMPLETE_RSP(hci_spec::kWriteInquiryMode);
309
310 const StaticByteBuffer kReadScanEnable(
311 LowerBits(hci_spec::kReadScanEnable), UpperBits(hci_spec::kReadScanEnable),
312 0x00 // No parameters
313 );
314
315 const StaticByteBuffer kWriteLocalName(
316 LowerBits(hci_spec::kWriteLocalName), UpperBits(hci_spec::kWriteLocalName),
317 0xF8, // parameter_total_size (248 bytes)
318 // Complete Local Name ()
319 'A', 'B', 'C', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x00
339 );
340
341 const StaticByteBuffer kWriteExtendedInquiryResponse(
342 LowerBits(hci_spec::kWriteExtendedInquiryResponse),
343 UpperBits(hci_spec::kWriteExtendedInquiryResponse),
344 0xF1, // parameter_total_size (241 bytes)
345 0x00, // fec_required
346 0x04, // name_length + 1
347 0x09, // DataType::kCompleteLocalName,
348 // Complete Local Name (3 bytes + 1 byte null terminator + 234 bytes of zero padding)
349 'A', 'B', 'C', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
368 );
369
370 #define READ_SCAN_ENABLE_RSP(scan_enable) \
371 StaticByteBuffer(hci_spec::kCommandCompleteEventCode, 0x05, 0xF0, \
372 LowerBits(hci_spec::kReadScanEnable), \
373 UpperBits(hci_spec::kReadScanEnable), \
374 pw::bluetooth::emboss::StatusCode::SUCCESS, (scan_enable))
375
376 const auto kReadScanEnableRspNone = READ_SCAN_ENABLE_RSP(0x00);
377 const auto kReadScanEnableRspInquiry = READ_SCAN_ENABLE_RSP(0x01);
378 const auto kReadScanEnableRspPage = READ_SCAN_ENABLE_RSP(0x02);
379 const auto kReadScanEnableRspBoth = READ_SCAN_ENABLE_RSP(0x03);
380
381 #undef READ_SCAN_ENABLE_RSP
382
383 #define WRITE_SCAN_ENABLE_CMD(scan_enable) \
384 StaticByteBuffer(LowerBits(hci_spec::kWriteScanEnable), \
385 UpperBits(hci_spec::kWriteScanEnable), 0x01, \
386 (scan_enable))
387
388 const auto kWriteScanEnableNone = WRITE_SCAN_ENABLE_CMD(0x00);
389 const auto kWriteScanEnableInq = WRITE_SCAN_ENABLE_CMD(0x01);
390 const auto kWriteScanEnablePage = WRITE_SCAN_ENABLE_CMD(0x02);
391 const auto kWriteScanEnableBoth = WRITE_SCAN_ENABLE_CMD(0x03);
392
393 #undef WRITE_SCAN_ENABLE_CMD
394
395 const auto kWriteScanEnableRsp = COMMAND_COMPLETE_RSP(hci_spec::kWriteScanEnable);
396
397 #undef COMMAND_COMPLETE_RSP
398 // clang-format on
399
400 // Test: malformed inquiry result is fatal
TEST_F(BrEdrDiscoveryManagerDeathTest,MalformedInquiryResultFromControllerIsFatal)401 TEST_F(BrEdrDiscoveryManagerDeathTest,
402 MalformedInquiryResultFromControllerIsFatal) {
403 EXPECT_CMD_PACKET_OUT(test_device(), hci_spec::kInquiry, &kInquiryRsp);
404
405 std::unique_ptr<BrEdrDiscoverySession> session;
406
407 discovery_manager()->RequestDiscovery(
408 [&session](auto status, auto cb_session) {
409 EXPECT_EQ(fit::ok(), status);
410 session = std::move(cb_session);
411 });
412
413 RunUntilIdle();
414
415 for (auto event : {kInquiryResultIncompleteHeader.view(),
416 kInquiryResultMissingResponses.view(),
417 kInquiryResultIncompleteResponse.view()}) {
418 EXPECT_DEATH_IF_SUPPORTED(
419 [=] {
420 test_device()->SendCommandChannelPacket(event);
421 RunUntilIdle();
422 }(),
423 ".*");
424 }
425 }
426
427 // Test: discovering() answers correctly
428
429 // Test: requesting discovery should start inquiry
430 // Test: Inquiry Results that come in when there is discovery get reported up
431 // correctly to the sessions
432 // Test: Peers discovered are reported to the cache
433 // Test: RemoteNameRequest is processed correctly
434 // Test: Inquiry Results that come in when there's no discovery happening get
435 // discarded.
TEST_F(BrEdrDiscoveryManagerTest,RequestDiscoveryAndDrop)436 TEST_F(BrEdrDiscoveryManagerTest, RequestDiscoveryAndDrop) {
437 EXPECT_CMD_PACKET_OUT(
438 test_device(), hci_spec::kInquiry, &kInquiryRsp, &kInquiryResult);
439 EXPECT_CMD_PACKET_OUT(test_device(),
440 kRemoteNameRequest1,
441 &kRemoteNameRequestRsp,
442 &kRemoteNameRequestComplete1);
443
444 std::unique_ptr<BrEdrDiscoverySession> session;
445 size_t peers_found = 0u;
446
447 discovery_manager()->RequestDiscovery(
448 [&session, &peers_found](auto status, auto cb_session) {
449 EXPECT_EQ(fit::ok(), status);
450 cb_session->set_result_callback(
451 [&peers_found](const auto&) { peers_found++; });
452 session = std::move(cb_session);
453 });
454
455 EXPECT_FALSE(discovery_manager()->discovering());
456
457 RunUntilIdle();
458
459 EXPECT_EQ(1u, peers_found);
460 EXPECT_TRUE(discovery_manager()->discovering());
461
462 EXPECT_CMD_PACKET_OUT(
463 test_device(), hci_spec::kInquiry, &kInquiryRsp, &kInquiryResult);
464
465 test_device()->SendCommandChannelPacket(kInquiryComplete);
466
467 RunUntilIdle();
468
469 // Confirm that post-inquiry peer name request is processed correctly.
470 Peer* peer = peer_cache()->FindByAddress(kDeviceAddress1);
471 ASSERT_TRUE(peer);
472 EXPECT_EQ("Fuchsia", *peer->name());
473 EXPECT_EQ(Peer::NameSource::kNameDiscoveryProcedure, *peer->name_source());
474
475 EXPECT_EQ(2u, peers_found);
476
477 // TODO(fxbug.dev/42145646): test InquiryCancel when it is implemented
478
479 session = nullptr;
480 test_device()->SendCommandChannelPacket(kInquiryResult);
481
482 RunUntilIdle();
483
484 EXPECT_EQ(2u, peers_found);
485 EXPECT_FALSE(discovery_manager()->discovering());
486
487 test_device()->SendCommandChannelPacket(kInquiryComplete);
488 RunUntilIdle();
489 }
490
491 // Test: requesting a second discovery should start a session without sending
492 // any more HCI commands.
493 // Test: dropping the first discovery shouldn't stop inquiry
494 // Test: starting two sessions at once should only start inquiry once
TEST_F(BrEdrDiscoveryManagerTest,MultipleRequests)495 TEST_F(BrEdrDiscoveryManagerTest, MultipleRequests) {
496 EXPECT_CMD_PACKET_OUT(
497 test_device(), hci_spec::kInquiry, &kInquiryRsp, &kInquiryResult);
498 EXPECT_CMD_PACKET_OUT(test_device(),
499 kRemoteNameRequest1,
500 &kRemoteNameRequestRsp,
501 &kRemoteNameRequestComplete1);
502
503 std::unique_ptr<BrEdrDiscoverySession> session1;
504 size_t peers_found1 = 0u;
505
506 discovery_manager()->RequestDiscovery(
507 [&session1, &peers_found1](auto status, auto cb_session) {
508 EXPECT_EQ(fit::ok(), status);
509 cb_session->set_result_callback(
510 [&peers_found1](const auto&) { peers_found1++; });
511 session1 = std::move(cb_session);
512 });
513
514 EXPECT_FALSE(discovery_manager()->discovering());
515
516 RunUntilIdle();
517
518 EXPECT_TRUE(session1);
519 EXPECT_EQ(1u, peers_found1);
520 EXPECT_TRUE(discovery_manager()->discovering());
521
522 std::unique_ptr<BrEdrDiscoverySession> session2;
523 size_t peers_found2 = 0u;
524
525 discovery_manager()->RequestDiscovery(
526 [&session2, &peers_found2](auto status, auto cb_session) {
527 EXPECT_EQ(fit::ok(), status);
528 cb_session->set_result_callback(
529 [&peers_found2](const auto&) { peers_found2++; });
530 session2 = std::move(cb_session);
531 });
532
533 RunUntilIdle();
534
535 EXPECT_TRUE(session2);
536 EXPECT_EQ(1u, peers_found1);
537 EXPECT_EQ(0u, peers_found2);
538 EXPECT_TRUE(discovery_manager()->discovering());
539
540 test_device()->SendCommandChannelPacket(kInquiryResult);
541
542 RunUntilIdle();
543
544 EXPECT_EQ(2u, peers_found1);
545 EXPECT_EQ(1u, peers_found2);
546
547 session1 = nullptr;
548
549 RunUntilIdle();
550
551 test_device()->SendCommandChannelPacket(kInquiryResult);
552
553 RunUntilIdle();
554
555 EXPECT_EQ(2u, peers_found1);
556 EXPECT_EQ(2u, peers_found2);
557
558 // TODO(fxbug.dev/42145646): test InquiryCancel when it is implemented
559
560 session2 = nullptr;
561
562 test_device()->SendCommandChannelPacket(kInquiryResult);
563
564 RunUntilIdle();
565
566 EXPECT_EQ(2u, peers_found1);
567 EXPECT_EQ(2u, peers_found2);
568
569 EXPECT_FALSE(discovery_manager()->discovering());
570
571 test_device()->SendCommandChannelPacket(kInquiryComplete);
572
573 RunUntilIdle();
574 }
575
576 // Test: starting a session "while" the other one is stopping a session should
577 // still restart the Inquiry.
578 // Test: starting a session "while" the other one is stopping should return
579 // without needing an InquiryComplete first.
580 // Test: we should only request a peer's name if it's the first time we
581 // encounter it.
TEST_F(BrEdrDiscoveryManagerTest,RequestDiscoveryWhileStop)582 TEST_F(BrEdrDiscoveryManagerTest, RequestDiscoveryWhileStop) {
583 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp, &kInquiryResult);
584 EXPECT_CMD_PACKET_OUT(test_device(),
585 kRemoteNameRequest1,
586 &kRemoteNameRequestRsp,
587 &kRemoteNameRequestComplete1);
588
589 std::unique_ptr<BrEdrDiscoverySession> session1;
590 size_t peers_found1 = 0u;
591
592 discovery_manager()->RequestDiscovery(
593 [&session1, &peers_found1](auto status, auto cb_session) {
594 EXPECT_EQ(fit::ok(), status);
595 cb_session->set_result_callback(
596 [&peers_found1](const auto&) { peers_found1++; });
597 session1 = std::move(cb_session);
598 });
599
600 EXPECT_FALSE(discovery_manager()->discovering());
601
602 RunUntilIdle();
603
604 EXPECT_TRUE(session1);
605 EXPECT_EQ(1u, peers_found1);
606 EXPECT_TRUE(discovery_manager()->discovering());
607
608 // Drop the active session.
609 session1 = nullptr;
610 RunUntilIdle();
611
612 std::unique_ptr<BrEdrDiscoverySession> session2;
613 size_t peers_found2 = 0u;
614 discovery_manager()->RequestDiscovery(
615 [&session2, &peers_found2](auto status, auto cb_session) {
616 EXPECT_EQ(fit::ok(), status);
617 cb_session->set_result_callback(
618 [&peers_found2](const auto&) { peers_found2++; });
619 session2 = std::move(cb_session);
620 });
621
622 // The new session should be started at this point, and inquiry results
623 // returned.
624 EXPECT_TRUE(session2);
625 test_device()->SendCommandChannelPacket(kInquiryResult);
626
627 RunUntilIdle();
628
629 EXPECT_EQ(1u, peers_found2);
630
631 // Inquiry should be restarted when the Complete comes in because an active
632 // session2 still exists.
633 // TODO(fxbug.dev/42145646): test InquiryCancel when it is implemented
634 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp, &kInquiryResult);
635 test_device()->SendCommandChannelPacket(kInquiryComplete);
636
637 RunUntilIdle();
638
639 EXPECT_EQ(1u, peers_found1);
640 EXPECT_EQ(2u, peers_found2);
641 EXPECT_TRUE(discovery_manager()->discovering());
642
643 test_device()->SendCommandChannelPacket(kInquiryResult);
644
645 RunUntilIdle();
646
647 EXPECT_EQ(1u, peers_found1);
648 EXPECT_EQ(3u, peers_found2);
649
650 // TODO(fxbug.dev/42145646): test InquiryCancel when it is implemented
651 session2 = nullptr;
652
653 // After the session is dropped, even if another result comes in, no results
654 // are sent to the callback.
655 test_device()->SendCommandChannelPacket(kInquiryResult);
656
657 RunUntilIdle();
658
659 EXPECT_EQ(1u, peers_found1);
660 EXPECT_EQ(3u, peers_found2);
661 }
662
663 // Test: When Inquiry Fails to start, we report this back to the requester.
TEST_F(BrEdrDiscoveryManagerTest,RequestDiscoveryError)664 TEST_F(BrEdrDiscoveryManagerTest, RequestDiscoveryError) {
665 EXPECT_CMD_PACKET_OUT(
666 test_device(), kInquiry, &kInquiryRspError, &kInquiryResult);
667 EXPECT_CMD_PACKET_OUT(test_device(),
668 kRemoteNameRequest1,
669 &kRemoteNameRequestRsp,
670 &kRemoteNameRequestComplete1);
671
672 std::unique_ptr<BrEdrDiscoverySession> session;
673
674 discovery_manager()->RequestDiscovery([](auto status, auto cb_session) {
675 EXPECT_TRUE(status.is_error());
676 EXPECT_FALSE(cb_session);
677 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE),
678 status);
679 });
680
681 EXPECT_FALSE(discovery_manager()->discovering());
682
683 RunUntilIdle();
684
685 EXPECT_FALSE(discovery_manager()->discovering());
686 }
687
688 // Test: When inquiry complete indicates failure, we signal to the current
689 // sessions.
TEST_F(BrEdrDiscoveryManagerTest,ContinuingDiscoveryError)690 TEST_F(BrEdrDiscoveryManagerTest, ContinuingDiscoveryError) {
691 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp, &kInquiryResult);
692 EXPECT_CMD_PACKET_OUT(test_device(),
693 kRemoteNameRequest1,
694 &kRemoteNameRequestRsp,
695 &kRemoteNameRequestComplete1);
696
697 std::unique_ptr<BrEdrDiscoverySession> session;
698 size_t peers_found = 0u;
699 bool error_callback = false;
700
701 discovery_manager()->RequestDiscovery(
702 [&session, &peers_found, &error_callback](auto status, auto cb_session) {
703 EXPECT_EQ(fit::ok(), status);
704 cb_session->set_result_callback(
705 [&peers_found](const auto&) { peers_found++; });
706 cb_session->set_error_callback(
707 [&error_callback]() { error_callback = true; });
708 session = std::move(cb_session);
709 });
710
711 EXPECT_FALSE(discovery_manager()->discovering());
712
713 RunUntilIdle();
714
715 EXPECT_EQ(1u, peers_found);
716 EXPECT_TRUE(discovery_manager()->discovering());
717
718 test_device()->SendCommandChannelPacket(kInquiryCompleteError);
719
720 RunUntilIdle();
721
722 EXPECT_TRUE(error_callback);
723 EXPECT_FALSE(discovery_manager()->discovering());
724
725 session = nullptr;
726
727 RunUntilIdle();
728 }
729
730 // clang-format off
731 const StaticByteBuffer kWriteLocalNameMaxLen(
732 LowerBits(hci_spec::kWriteLocalName), UpperBits(hci_spec::kWriteLocalName),
733 0xF8, // parameter_total_size (248 bytes)
734 // Complete Local Name (exactly 248 bytes)
735 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
736 'T', 'U', 'V', 'W', 'X', 'Y',
737 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
738 'T', 'U', 'V', 'W', 'X', 'Y',
739 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
740 'T', 'U', 'V', 'W', 'X', 'Y',
741 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
742 'T', 'U', 'V', 'W', 'X', 'Y',
743 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
744 'T', 'U', 'V', 'W', 'X', 'Y',
745 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
746 'T', 'U', 'V', 'W', 'X', 'Y',
747 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
748 'T', 'U', 'V', 'W', 'X', 'Y',
749 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
750 'T', 'U', 'V', 'W', 'X', 'Y',
751 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
752 'T', 'U', 'V', 'W', 'X', 'Y',
753 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
754 'T', 'U', 'V', 'W'
755 );
756
757 const StaticByteBuffer kWriteExtInquiryResponseMaxLen(
758 LowerBits(hci_spec::kWriteExtendedInquiryResponse),
759 UpperBits(hci_spec::kWriteExtendedInquiryResponse),
760 0xF1, // parameter_total_size (241 bytes)
761 0x00, // fec_required
762 0xEF, // 239 bytes (1 + 238 bytes)
763 0x08, // DataType::kShortenedLocalName,
764 // Shortened Local Name (238 bytes, truncated from above)
765 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
766 'T', 'U', 'V', 'W', 'X', 'Y',
767 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
768 'T', 'U', 'V', 'W', 'X', 'Y',
769 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
770 'T', 'U', 'V', 'W', 'X', 'Y',
771 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
772 'T', 'U', 'V', 'W', 'X', 'Y',
773 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
774 'T', 'U', 'V', 'W', 'X', 'Y',
775 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
776 'T', 'U', 'V', 'W', 'X', 'Y',
777 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
778 'T', 'U', 'V', 'W', 'X', 'Y',
779 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
780 'T', 'U', 'V', 'W', 'X', 'Y',
781 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
782 'T', 'U', 'V', 'W', 'X', 'Y',
783 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M'
784 );
785 // clang-format on
786
787 // Test: UpdateLocalName successfully sends hci command, and further calls
788 // UpdateEIRResponseData (private). Ensures the name is updated at the very end.
TEST_F(BrEdrDiscoveryManagerTest,UpdateLocalNameShortenedSuccess)789 TEST_F(BrEdrDiscoveryManagerTest, UpdateLocalNameShortenedSuccess) {
790 EXPECT_CMD_PACKET_OUT(test_device(), kWriteLocalNameMaxLen, );
791
792 // Set the status to be an arbitrary invalid status.
793 hci::Result<> result =
794 ToResult(pw::bluetooth::emboss::StatusCode::PAIRING_NOT_ALLOWED);
795 size_t callback_count = 0u;
796 auto name_cb = [&result, &callback_count](const auto& status) {
797 EXPECT_EQ(fit::ok(), status);
798 callback_count++;
799 result = status;
800 };
801 std::string kNewName = "";
802 while (kNewName.length() < 225) {
803 kNewName.append("ABCDEFGHIJKLMNOPQRSTUVWXY");
804 }
805 kNewName.append("ABCDEFGHIJKLMNOPQRSTUVW");
806 discovery_manager()->UpdateLocalName(kNewName, name_cb);
807
808 RunUntilIdle();
809
810 // Local name should not be set, callback shouldn't be called yet.
811 EXPECT_NE(kNewName, discovery_manager()->local_name());
812 EXPECT_EQ(0u, callback_count);
813
814 test_device()->SendCommandChannelPacket(kWriteLocalNameRsp);
815 EXPECT_CMD_PACKET_OUT(test_device(), kWriteExtInquiryResponseMaxLen, );
816
817 RunUntilIdle();
818
819 // Still waiting on EIR response.
820 // Local name should not be set, callback shouldn't be called yet.
821 EXPECT_NE(kNewName, discovery_manager()->local_name());
822 EXPECT_EQ(0u, callback_count);
823
824 test_device()->SendCommandChannelPacket(kWriteExtendedInquiryResponseRsp);
825
826 RunUntilIdle();
827
828 EXPECT_EQ(kNewName, discovery_manager()->local_name());
829 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::SUCCESS), result);
830 EXPECT_EQ(1u, callback_count);
831 }
832
833 // Test: UpdateLocalName successfully sends hci command, and further calls
834 // UpdateEIRResponseData (private). Ensures the name is updated at the very end.
TEST_F(BrEdrDiscoveryManagerTest,UpdateLocalNameSuccess)835 TEST_F(BrEdrDiscoveryManagerTest, UpdateLocalNameSuccess) {
836 EXPECT_CMD_PACKET_OUT(test_device(), kWriteLocalName, );
837
838 // Set the status to be an arbitrary invalid status.
839 hci::Result<> result =
840 ToResult(pw::bluetooth::emboss::StatusCode::PAIRING_NOT_ALLOWED);
841 size_t callback_count = 0u;
842 auto name_cb = [&result, &callback_count](const auto& status) {
843 EXPECT_EQ(fit::ok(), status);
844 callback_count++;
845 result = status;
846 };
847 const std::string kNewName = "ABC";
848 discovery_manager()->UpdateLocalName(kNewName, name_cb);
849
850 RunUntilIdle();
851
852 // Local name should not be set, callback shouldn't be called yet.
853 EXPECT_NE(kNewName, discovery_manager()->local_name());
854 EXPECT_EQ(0u, callback_count);
855
856 test_device()->SendCommandChannelPacket(kWriteLocalNameRsp);
857 EXPECT_CMD_PACKET_OUT(test_device(), kWriteExtendedInquiryResponse, );
858
859 RunUntilIdle();
860
861 // Still waiting on EIR response.
862 // Local name should not be set, callback shouldn't be called yet.
863 EXPECT_NE(kNewName, discovery_manager()->local_name());
864 EXPECT_EQ(0u, callback_count);
865
866 test_device()->SendCommandChannelPacket(kWriteExtendedInquiryResponseRsp);
867
868 RunUntilIdle();
869
870 EXPECT_EQ(kNewName, discovery_manager()->local_name());
871 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::SUCCESS), result);
872 EXPECT_EQ(1u, callback_count);
873 }
874
875 // Test: UpdateLocalName passes back error code through the callback and
876 // |local_name_| does not get updated.
TEST_F(BrEdrDiscoveryManagerTest,UpdateLocalNameError)877 TEST_F(BrEdrDiscoveryManagerTest, UpdateLocalNameError) {
878 EXPECT_CMD_PACKET_OUT(test_device(), kWriteLocalName, );
879
880 // Set the status to be an arbitrary invalid status.
881 hci::Result<> result =
882 ToResult(pw::bluetooth::emboss::StatusCode::UNSUPPORTED_REMOTE_FEATURE);
883 size_t callback_count = 0u;
884 auto name_cb = [&result, &callback_count](const auto& status) {
885 EXPECT_TRUE(status.is_error());
886 callback_count++;
887 result = status;
888 };
889 const std::string kNewName = "ABC";
890 discovery_manager()->UpdateLocalName(kNewName, name_cb);
891
892 RunUntilIdle();
893
894 // Local name should not be set, callback shouldn't be called yet.
895 EXPECT_NE(kNewName, discovery_manager()->local_name());
896 EXPECT_EQ(0u, callback_count);
897
898 // Send a response error.
899 test_device()->SendCommandChannelPacket(kWriteLocalNameRspError);
900
901 RunUntilIdle();
902
903 // |local_name_| should not be updated, return status should be error.
904 EXPECT_NE(kNewName, discovery_manager()->local_name());
905 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE),
906 result);
907 EXPECT_EQ(1u, callback_count);
908 }
909
910 // Test: UpdateLocalName should succeed, but UpdateEIRResponseData should fail.
911 // Consequently, the |local_name_| should not be updated, and the callback
912 // should return the error.
TEST_F(BrEdrDiscoveryManagerTest,UpdateEIRResponseDataError)913 TEST_F(BrEdrDiscoveryManagerTest, UpdateEIRResponseDataError) {
914 EXPECT_CMD_PACKET_OUT(test_device(), kWriteLocalName, );
915
916 // Set the status to be an arbitrary invalid status.
917 hci::Result<> result =
918 ToResult(pw::bluetooth::emboss::StatusCode::UNSUPPORTED_REMOTE_FEATURE);
919 size_t callback_count = 0u;
920 auto name_cb = [&result, &callback_count](const auto& status) {
921 EXPECT_TRUE(status.is_error());
922 callback_count++;
923 result = status;
924 };
925 const std::string kNewName = "ABC";
926 discovery_manager()->UpdateLocalName(kNewName, name_cb);
927
928 RunUntilIdle();
929
930 // Local name should not be set, callback shouldn't be called yet.
931 EXPECT_NE(kNewName, discovery_manager()->local_name());
932 EXPECT_EQ(0u, callback_count);
933
934 // kWriteLocalName should succeed.
935 test_device()->SendCommandChannelPacket(kWriteLocalNameRsp);
936 EXPECT_CMD_PACKET_OUT(test_device(), kWriteExtendedInquiryResponse, );
937
938 RunUntilIdle();
939
940 // Still waiting on EIR response.
941 // Local name should not be set, callback shouldn't be called yet.
942 EXPECT_NE(kNewName, discovery_manager()->local_name());
943 EXPECT_EQ(0u, callback_count);
944
945 // kWriteExtendedInquiryResponse should fail.
946 test_device()->SendCommandChannelPacket(
947 kWriteExtendedInquiryResponseRspError);
948
949 RunUntilIdle();
950
951 // |local_name_| should not be updated, return status should be error.
952 EXPECT_NE(kNewName, discovery_manager()->local_name());
953 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE),
954 result);
955 EXPECT_EQ(1u, callback_count);
956 }
957
958 // Test: requesting discoverable works
959 // Test: requesting discoverable while discoverable is pending doesn't send
960 // any more HCI commands
TEST_F(BrEdrDiscoveryManagerTest,DiscoverableSet)961 TEST_F(BrEdrDiscoveryManagerTest, DiscoverableSet) {
962 EXPECT_CMD_PACKET_OUT(test_device(), kReadScanEnable, );
963
964 std::vector<std::unique_ptr<BrEdrDiscoverableSession>> sessions;
965 auto session_cb = [&sessions](auto status, auto cb_session) {
966 EXPECT_EQ(fit::ok(), status);
967 sessions.emplace_back(std::move(cb_session));
968 };
969
970 discovery_manager()->RequestDiscoverable(session_cb);
971
972 RunUntilIdle();
973
974 EXPECT_EQ(0u, sessions.size());
975 EXPECT_FALSE(discovery_manager()->discoverable());
976
977 EXPECT_CMD_PACKET_OUT(test_device(), kWriteScanEnableInq, );
978
979 test_device()->SendCommandChannelPacket(kReadScanEnableRspNone);
980
981 RunUntilIdle();
982
983 // Request another session while the first is pending.
984 discovery_manager()->RequestDiscoverable(session_cb);
985
986 test_device()->SendCommandChannelPacket(kWriteScanEnableRsp);
987
988 RunUntilIdle();
989
990 EXPECT_EQ(2u, sessions.size());
991 EXPECT_TRUE(discovery_manager()->discoverable());
992
993 discovery_manager()->RequestDiscoverable(session_cb);
994
995 EXPECT_EQ(3u, sessions.size());
996 EXPECT_TRUE(discovery_manager()->discoverable());
997
998 EXPECT_CMD_PACKET_OUT(
999 test_device(), kReadScanEnable, &kReadScanEnableRspInquiry);
1000 EXPECT_CMD_PACKET_OUT(
1001 test_device(), kWriteScanEnableNone, &kWriteScanEnableRsp);
1002
1003 sessions.clear();
1004
1005 RunUntilIdle();
1006
1007 EXPECT_FALSE(discovery_manager()->discoverable());
1008 }
1009
1010 // Test: requesting discoverable while discovery is disabling leaves
1011 // the discoverable enabled and reports success
1012 // Test: enable/disable while page scan is enabled works.
TEST_F(BrEdrDiscoveryManagerTest,DiscoverableRequestWhileStopping)1013 TEST_F(BrEdrDiscoveryManagerTest, DiscoverableRequestWhileStopping) {
1014 EXPECT_CMD_PACKET_OUT(
1015 test_device(), kReadScanEnable, &kReadScanEnableRspPage);
1016 EXPECT_CMD_PACKET_OUT(
1017 test_device(), kWriteScanEnableBoth, &kWriteScanEnableRsp);
1018
1019 std::vector<std::unique_ptr<BrEdrDiscoverableSession>> sessions;
1020 auto session_cb = [&sessions](auto status, auto cb_session) {
1021 EXPECT_EQ(fit::ok(), status);
1022 sessions.emplace_back(std::move(cb_session));
1023 };
1024
1025 discovery_manager()->RequestDiscoverable(session_cb);
1026
1027 RunUntilIdle();
1028
1029 EXPECT_EQ(1u, sessions.size());
1030 EXPECT_TRUE(discovery_manager()->discoverable());
1031
1032 EXPECT_CMD_PACKET_OUT(test_device(), kReadScanEnable, );
1033
1034 sessions.clear();
1035
1036 RunUntilIdle();
1037
1038 // Request a new discovery before the procedure finishes.
1039 // This will queue another ReadScanEnable just in case the disable write is
1040 // in progress.
1041 EXPECT_CMD_PACKET_OUT(test_device(), kReadScanEnable, );
1042 discovery_manager()->RequestDiscoverable(session_cb);
1043
1044 test_device()->SendCommandChannelPacket(kReadScanEnableRspBoth);
1045
1046 // This shouldn't send any WriteScanEnable because we're already in the right
1047 // mode (MockController will assert if we do as it's not expecting)
1048 RunUntilIdle();
1049
1050 EXPECT_EQ(1u, sessions.size());
1051 EXPECT_TRUE(discovery_manager()->discoverable());
1052
1053 // If somehow the scan got turned off, we will still turn it back on.
1054 EXPECT_CMD_PACKET_OUT(
1055 test_device(), kWriteScanEnableBoth, &kWriteScanEnableRsp);
1056 test_device()->SendCommandChannelPacket(kReadScanEnableRspPage);
1057
1058 RunUntilIdle();
1059
1060 EXPECT_EQ(1u, sessions.size());
1061 EXPECT_TRUE(discovery_manager()->discoverable());
1062
1063 EXPECT_CMD_PACKET_OUT(
1064 test_device(), kReadScanEnable, &kReadScanEnableRspBoth);
1065 EXPECT_CMD_PACKET_OUT(
1066 test_device(), kWriteScanEnablePage, &kWriteScanEnableRsp);
1067
1068 sessions.clear();
1069
1070 RunUntilIdle();
1071
1072 EXPECT_FALSE(discovery_manager()->discoverable());
1073 }
1074
1075 // Test: non-standard inquiry modes mean before the first discovery, the
1076 // inquiry mode is set.
1077 // Test: extended inquiry is stored in the remote peer
TEST_F(BrEdrDiscoveryManagerTest,ExtendedInquiry)1078 TEST_F(BrEdrDiscoveryManagerTest, ExtendedInquiry) {
1079 NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode::EXTENDED);
1080
1081 EXPECT_CMD_PACKET_OUT(test_device(), kSetExtendedMode, &kSetExtendedModeRsp);
1082 EXPECT_CMD_PACKET_OUT(test_device(),
1083 kInquiry,
1084 &kInquiryRsp,
1085 &kExtendedInquiryResult,
1086 &kRSSIInquiryResult);
1087 EXPECT_CMD_PACKET_OUT(test_device(),
1088 kRemoteNameRequest2,
1089 &kRemoteNameRequestRsp,
1090 &kRemoteNameRequestComplete2);
1091
1092 std::unique_ptr<BrEdrDiscoverySession> session1;
1093 size_t peers_found1 = 0u;
1094
1095 discovery_manager()->RequestDiscovery(
1096 [&session1, &peers_found1](auto status, auto cb_session) {
1097 EXPECT_EQ(fit::ok(), status);
1098 cb_session->set_result_callback(
1099 [&peers_found1](const auto&) { peers_found1++; });
1100 session1 = std::move(cb_session);
1101 });
1102
1103 EXPECT_FALSE(discovery_manager()->discovering());
1104
1105 RunUntilIdle();
1106
1107 EXPECT_TRUE(session1);
1108 EXPECT_EQ(2u, peers_found1);
1109 EXPECT_TRUE(discovery_manager()->discovering());
1110 session1 = nullptr;
1111
1112 Peer* peer1 = peer_cache()->FindByAddress(kDeviceAddress2);
1113 ASSERT_TRUE(peer1);
1114 EXPECT_EQ(-20, peer1->rssi());
1115
1116 Peer* peer2 = peer_cache()->FindByAddress(kDeviceAddress3);
1117 ASSERT_TRUE(peer2);
1118 ASSERT_TRUE(peer2->name());
1119 EXPECT_EQ("Fuchsia", *peer2->name());
1120 EXPECT_EQ(Peer::NameSource::kInquiryResultComplete, *peer2->name_source());
1121
1122 test_device()->SendCommandChannelPacket(kInquiryComplete);
1123
1124 RunUntilIdle();
1125
1126 EXPECT_FALSE(discovery_manager()->discovering());
1127 }
1128
1129 // Verify that receiving a inquiry response for a known LE non-connectable peer
1130 // results in the peer being changed to DualMode and connectable.
TEST_F(BrEdrDiscoveryManagerTest,InquiryResultUpgradesKnownLowEnergyPeer)1131 TEST_F(BrEdrDiscoveryManagerTest, InquiryResultUpgradesKnownLowEnergyPeer) {
1132 Peer* peer = peer_cache()->NewPeer(kLeAliasAddress1, /*connectable=*/false);
1133 ASSERT_TRUE(peer);
1134 ASSERT_FALSE(peer->connectable());
1135 ASSERT_EQ(TechnologyType::kLowEnergy, peer->technology());
1136
1137 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp, &kInquiryResult);
1138 EXPECT_CMD_PACKET_OUT(test_device(),
1139 kRemoteNameRequest1,
1140 &kRemoteNameRequestRsp,
1141 &kRemoteNameRequestComplete1);
1142
1143 std::unique_ptr<BrEdrDiscoverySession> session;
1144 size_t peers_found = 0u;
1145
1146 discovery_manager()->RequestDiscovery([&session, &peers_found](
1147 auto status, auto cb_session) {
1148 EXPECT_EQ(fit::ok(), status);
1149 cb_session->set_result_callback([&peers_found](auto&) { peers_found++; });
1150 session = std::move(cb_session);
1151 });
1152 RunUntilIdle();
1153 session = nullptr;
1154
1155 EXPECT_EQ(1u, peers_found);
1156 ASSERT_EQ(peer, peer_cache()->FindByAddress(kDeviceAddress1));
1157 EXPECT_EQ(TechnologyType::kDualMode, peer->technology());
1158 EXPECT_TRUE(peer->connectable());
1159
1160 test_device()->SendCommandChannelPacket(kInquiryComplete);
1161
1162 RunUntilIdle();
1163 }
1164
1165 // Verify that receiving an extended inquiry response for a known LE
1166 // non-connectable peer results in the peer being changed to DualMode and
1167 // connectable.
TEST_F(BrEdrDiscoveryManagerTest,ExtendedInquiryResultUpgradesKnownLowEnergyPeer)1168 TEST_F(BrEdrDiscoveryManagerTest,
1169 ExtendedInquiryResultUpgradesKnownLowEnergyPeer) {
1170 Peer* peer = peer_cache()->NewPeer(kLeAliasAddress3, /*connectable=*/false);
1171 ASSERT_TRUE(peer);
1172 ASSERT_FALSE(peer->connectable());
1173 ASSERT_EQ(TechnologyType::kLowEnergy, peer->technology());
1174
1175 NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode::EXTENDED);
1176
1177 EXPECT_CMD_PACKET_OUT(test_device(), kSetExtendedMode, &kSetExtendedModeRsp);
1178 EXPECT_CMD_PACKET_OUT(
1179 test_device(), kInquiry, &kInquiryRsp, &kExtendedInquiryResult);
1180
1181 std::unique_ptr<BrEdrDiscoverySession> session;
1182 size_t peers_found = 0u;
1183
1184 discovery_manager()->RequestDiscovery([&session, &peers_found](
1185 auto status, auto cb_session) {
1186 EXPECT_EQ(fit::ok(), status);
1187 cb_session->set_result_callback([&peers_found](auto&) { peers_found++; });
1188 session = std::move(cb_session);
1189 });
1190 RunUntilIdle();
1191 session = nullptr;
1192
1193 EXPECT_EQ(1u, peers_found);
1194 ASSERT_EQ(peer, peer_cache()->FindByAddress(kDeviceAddress3));
1195 EXPECT_EQ(TechnologyType::kDualMode, peer->technology());
1196 EXPECT_TRUE(peer->connectable());
1197
1198 test_device()->SendCommandChannelPacket(kInquiryComplete);
1199
1200 RunUntilIdle();
1201 }
1202
1203 // Verify that receiving an extended inquiry response with RSSI for a known LE
1204 // non-connectable peer results in the peer being changed to DualMode and
1205 // connectable.
TEST_F(BrEdrDiscoveryManagerTest,RSSIInquiryResultUpgradesKnownLowEnergyPeer)1206 TEST_F(BrEdrDiscoveryManagerTest, RSSIInquiryResultUpgradesKnownLowEnergyPeer) {
1207 Peer* peer = peer_cache()->NewPeer(kLeAliasAddress2, /*connectable=*/false);
1208 ASSERT_TRUE(peer);
1209 ASSERT_FALSE(peer->connectable());
1210 ASSERT_EQ(TechnologyType::kLowEnergy, peer->technology());
1211
1212 NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode::EXTENDED);
1213
1214 EXPECT_CMD_PACKET_OUT(test_device(), kSetExtendedMode, &kSetExtendedModeRsp);
1215 EXPECT_CMD_PACKET_OUT(
1216 test_device(), kInquiry, &kInquiryRsp, &kRSSIInquiryResult);
1217 EXPECT_CMD_PACKET_OUT(test_device(),
1218 kRemoteNameRequest2,
1219 &kRemoteNameRequestRsp,
1220 &kRemoteNameRequestComplete2);
1221
1222 std::unique_ptr<BrEdrDiscoverySession> session;
1223 size_t peers_found = 0u;
1224
1225 discovery_manager()->RequestDiscovery([&session, &peers_found](
1226 auto status, auto cb_session) {
1227 EXPECT_EQ(fit::ok(), status);
1228 cb_session->set_result_callback([&peers_found](auto&) { peers_found++; });
1229 session = std::move(cb_session);
1230 });
1231 RunUntilIdle();
1232 session = nullptr;
1233
1234 EXPECT_EQ(1u, peers_found);
1235 ASSERT_EQ(peer, peer_cache()->FindByAddress(kDeviceAddress2));
1236 EXPECT_EQ(TechnologyType::kDualMode, peer->technology());
1237 EXPECT_TRUE(peer->connectable());
1238
1239 test_device()->SendCommandChannelPacket(kInquiryComplete);
1240
1241 RunUntilIdle();
1242 }
1243
1244 #ifndef NINSPECT
TEST_F(BrEdrDiscoveryManagerTest,Inspect)1245 TEST_F(BrEdrDiscoveryManagerTest, Inspect) {
1246 inspect::Inspector inspector;
1247 discovery_manager()->AttachInspect(inspector.GetRoot(),
1248 "bredr_discovery_manager");
1249
1250 auto discoverable_session_active_matcher =
1251 Contains(UintIs("discoverable_sessions", 1));
1252
1253 std::unique_ptr<BrEdrDiscoverableSession> discoverable_session;
1254 auto session_cb = [&discoverable_session](auto status, auto cb_session) {
1255 EXPECT_EQ(fit::ok(), status);
1256 discoverable_session = std::move(cb_session);
1257 };
1258
1259 EXPECT_CMD_PACKET_OUT(
1260 test_device(), kReadScanEnable, &kReadScanEnableRspPage);
1261 EXPECT_CMD_PACKET_OUT(
1262 test_device(), kWriteScanEnableBoth, &kWriteScanEnableRsp);
1263 discovery_manager()->RequestDiscoverable(session_cb);
1264 RunUntilIdle();
1265 EXPECT_TRUE(discoverable_session);
1266
1267 auto properties = inspect::ReadFromVmo(inspector.DuplicateVmo())
1268 .take_value()
1269 .take_children()
1270 .front()
1271 .node_ptr()
1272 ->take_properties();
1273 EXPECT_THAT(properties, discoverable_session_active_matcher);
1274
1275 auto discoverable_session_counted_matcher =
1276 ::testing::IsSupersetOf({UintIs("discoverable_sessions", 0),
1277 UintIs("discoverable_sessions_count", 1),
1278 UintIs("last_discoverable_length_sec", 4)});
1279
1280 RunFor(std::chrono::seconds(4));
1281 discoverable_session = nullptr;
1282 EXPECT_CMD_PACKET_OUT(
1283 test_device(), kReadScanEnable, &kReadScanEnableRspBoth);
1284 EXPECT_CMD_PACKET_OUT(
1285 test_device(), kWriteScanEnablePage, &kWriteScanEnableRsp);
1286 RunUntilIdle();
1287
1288 properties = inspect::ReadFromVmo(inspector.DuplicateVmo())
1289 .take_value()
1290 .take_children()
1291 .front()
1292 .node_ptr()
1293 ->take_properties();
1294 EXPECT_THAT(properties, discoverable_session_counted_matcher);
1295
1296 auto discovery_session_active_matcher =
1297 Contains(UintIs("discovery_sessions", 1));
1298
1299 std::unique_ptr<BrEdrDiscoverySession> discovery_session;
1300
1301 discovery_manager()->RequestDiscovery(
1302 [&discovery_session](auto status, auto cb_session) {
1303 EXPECT_EQ(fit::ok(), status);
1304 discovery_session = std::move(cb_session);
1305 });
1306
1307 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp);
1308 RunUntilIdle();
1309 EXPECT_TRUE(discovery_session);
1310
1311 properties = inspect::ReadFromVmo(inspector.DuplicateVmo())
1312 .take_value()
1313 .take_children()
1314 .front()
1315 .node_ptr()
1316 ->take_properties();
1317 EXPECT_THAT(properties, discovery_session_active_matcher);
1318
1319 auto discovery_session_counted_matcher =
1320 ::testing::IsSupersetOf({UintIs("discovery_sessions", 0),
1321 UintIs("inquiry_sessions_count", 1),
1322 UintIs("last_inquiry_length_sec", 7)});
1323
1324 RunFor(std::chrono::seconds(7));
1325 discovery_session = nullptr;
1326 RunUntilIdle();
1327 test_device()->SendCommandChannelPacket(kInquiryComplete);
1328 RunUntilIdle();
1329
1330 properties = inspect::ReadFromVmo(inspector.DuplicateVmo())
1331 .take_value()
1332 .take_children()
1333 .front()
1334 .node_ptr()
1335 ->take_properties();
1336 EXPECT_THAT(properties, discovery_session_counted_matcher);
1337 }
1338 #endif // NINSPECT
1339
1340 } // namespace
1341 } // namespace bt::gap
1342