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_interrogator.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/hci-spec/util.h"
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_l2cap.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
25 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
26 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
27 #include "pw_bluetooth_sapphire/internal/host/transport/error.h"
28
29 namespace bt::gap {
30
31 constexpr hci_spec::ConnectionHandle kConnectionHandle = 0x0BAA;
32 const DeviceAddress kTestDevAddr(DeviceAddress::Type::kBREDR, {1});
33
34 const auto kRemoteNameRequestRsp = testing::CommandStatusPacket(
35 hci_spec::kRemoteNameRequest, pw::bluetooth::emboss::StatusCode::SUCCESS);
36
37 const auto kReadRemoteVersionInfoRsp =
38 testing::CommandStatusPacket(hci_spec::kReadRemoteVersionInfo,
39 pw::bluetooth::emboss::StatusCode::SUCCESS);
40
41 const auto kReadRemoteSupportedFeaturesRsp =
42 testing::CommandStatusPacket(hci_spec::kReadRemoteSupportedFeatures,
43 pw::bluetooth::emboss::StatusCode::SUCCESS);
44
45 const auto kReadRemoteExtendedFeaturesRsp =
46 testing::CommandStatusPacket(hci_spec::kReadRemoteExtendedFeatures,
47 pw::bluetooth::emboss::StatusCode::SUCCESS);
48
49 using bt::testing::CommandTransaction;
50
51 using TestingBase =
52 bt::testing::FakeDispatcherControllerTest<bt::testing::MockController>;
53
54 class BrEdrInterrogatorTest : public TestingBase {
55 public:
56 BrEdrInterrogatorTest() = default;
57 ~BrEdrInterrogatorTest() override = default;
58
SetUp()59 void SetUp() override {
60 TestingBase::SetUp();
61
62 peer_cache_ = std::make_unique<PeerCache>(dispatcher());
63 peer_ = peer_cache()->NewPeer(kTestDevAddr, /*connectable=*/true);
64 EXPECT_FALSE(peer_->name());
65 EXPECT_FALSE(peer_->version());
66 EXPECT_FALSE(peer_->features().HasPage(0));
67 EXPECT_FALSE(peer_->features().HasBit(
68 /*page=*/0, hci_spec::LMPFeature::kExtendedFeatures));
69 EXPECT_EQ(0u, peer_->features().last_page_number());
70
71 interrogator_ = std::make_unique<BrEdrInterrogator>(
72 peer_->GetWeakPtr(), kConnectionHandle, cmd_channel()->AsWeakPtr());
73 }
74
TearDown()75 void TearDown() override {
76 RunUntilIdle();
77 test_device()->Stop();
78 interrogator_ = nullptr;
79 peer_cache_ = nullptr;
80 TestingBase::TearDown();
81 }
82
83 protected:
QueueSuccessfulInterrogation(DeviceAddress addr,hci_spec::ConnectionHandle conn,bool extended_features=true) const84 void QueueSuccessfulInterrogation(DeviceAddress addr,
85 hci_spec::ConnectionHandle conn,
86 bool extended_features = true) const {
87 const DynamicByteBuffer remote_name_request_complete_packet =
88 testing::RemoteNameRequestCompletePacket(addr);
89 const DynamicByteBuffer remote_version_complete_packet =
90 testing::ReadRemoteVersionInfoCompletePacket(conn);
91 const DynamicByteBuffer remote_supported_complete_packet =
92 testing::ReadRemoteSupportedFeaturesCompletePacket(conn,
93 extended_features);
94
95 EXPECT_CMD_PACKET_OUT(test_device(),
96 testing::RemoteNameRequestPacket(addr),
97 &kRemoteNameRequestRsp,
98 &remote_name_request_complete_packet);
99 EXPECT_CMD_PACKET_OUT(test_device(),
100 testing::ReadRemoteVersionInfoPacket(conn),
101 &kReadRemoteVersionInfoRsp,
102 &remote_version_complete_packet);
103 EXPECT_CMD_PACKET_OUT(test_device(),
104 testing::ReadRemoteSupportedFeaturesPacket(conn),
105 &kReadRemoteSupportedFeaturesRsp,
106 &remote_supported_complete_packet);
107 if (extended_features) {
108 QueueSuccessfulReadRemoteExtendedFeatures(conn);
109 }
110 }
111
QueueSuccessfulReadRemoteExtendedFeatures(hci_spec::ConnectionHandle conn) const112 void QueueSuccessfulReadRemoteExtendedFeatures(
113 hci_spec::ConnectionHandle conn) const {
114 const DynamicByteBuffer remote_extended1_complete_packet =
115 testing::ReadRemoteExtended1CompletePacket(conn);
116 const DynamicByteBuffer remote_extended2_complete_packet =
117 testing::ReadRemoteExtended2CompletePacket(conn);
118
119 EXPECT_CMD_PACKET_OUT(test_device(),
120 testing::ReadRemoteExtended1Packet(conn),
121 &kReadRemoteExtendedFeaturesRsp,
122 &remote_extended1_complete_packet);
123 EXPECT_CMD_PACKET_OUT(test_device(),
124 testing::ReadRemoteExtended2Packet(conn),
125 &kReadRemoteExtendedFeaturesRsp,
126 &remote_extended2_complete_packet);
127 }
128
DestroyInterrogator()129 void DestroyInterrogator() { interrogator_.reset(); }
130
peer() const131 Peer* peer() const { return peer_; }
132
peer_cache() const133 PeerCache* peer_cache() const { return peer_cache_.get(); }
134
interrogator() const135 BrEdrInterrogator* interrogator() const { return interrogator_.get(); }
136
137 private:
138 Peer* peer_ = nullptr;
139 std::unique_ptr<PeerCache> peer_cache_;
140 std::unique_ptr<BrEdrInterrogator> interrogator_;
141
142 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(BrEdrInterrogatorTest);
143 };
144
145 using GAP_BrEdrInterrogatorTest = BrEdrInterrogatorTest;
146
TEST_F(BrEdrInterrogatorTest,InterrogationFailsWithMalformedRemoteNameRequestComplete)147 TEST_F(BrEdrInterrogatorTest,
148 InterrogationFailsWithMalformedRemoteNameRequestComplete) {
149 // Remote Name Request Complete event with insufficient length.
150 const auto addr = kTestDevAddr.value().bytes();
151 StaticByteBuffer remote_name_request_complete_packet(
152 hci_spec::kRemoteNameRequestCompleteEventCode,
153 0x08, // parameter_total_size (8)
154 pw::bluetooth::emboss::StatusCode::SUCCESS, // status
155 addr[0],
156 addr[1],
157 addr[2],
158 addr[3],
159 addr[4],
160 addr[5], // peer address
161 'F' // remote name
162 );
163 EXPECT_CMD_PACKET_OUT(test_device(),
164 testing::RemoteNameRequestPacket(kTestDevAddr),
165 &kRemoteNameRequestRsp,
166 &remote_name_request_complete_packet);
167 EXPECT_CMD_PACKET_OUT(
168 test_device(), testing::ReadRemoteVersionInfoPacket(kConnectionHandle));
169 EXPECT_CMD_PACKET_OUT(
170 test_device(),
171 testing::ReadRemoteSupportedFeaturesPacket(kConnectionHandle));
172
173 hci::Result<> status = fit::ok();
174 interrogator()->Start(
175 [&status](hci::Result<> cb_status) { status = cb_status; });
176 RunUntilIdle();
177 EXPECT_TRUE(status.is_error());
178 }
179
TEST_F(BrEdrInterrogatorTest,SuccessfulInterrogation)180 TEST_F(BrEdrInterrogatorTest, SuccessfulInterrogation) {
181 QueueSuccessfulInterrogation(kTestDevAddr, kConnectionHandle);
182
183 std::optional<hci::Result<>> status;
184 interrogator()->Start(
185 [&status](hci::Result<> cb_status) { status = cb_status; });
186 RunUntilIdle();
187
188 ASSERT_TRUE(status.has_value());
189 EXPECT_EQ(fit::ok(), *status);
190
191 EXPECT_TRUE(peer()->name());
192 EXPECT_TRUE(peer()->version());
193 EXPECT_TRUE(peer()->features().HasPage(0));
194 EXPECT_TRUE(peer()->features().HasBit(
195 /*page=*/0, hci_spec::LMPFeature::kExtendedFeatures));
196 EXPECT_EQ(2u, peer()->features().last_page_number());
197 }
198
TEST_F(BrEdrInterrogatorTest,SuccessfulReinterrogation)199 TEST_F(BrEdrInterrogatorTest, SuccessfulReinterrogation) {
200 QueueSuccessfulInterrogation(kTestDevAddr, kConnectionHandle);
201
202 std::optional<hci::Result<>> status;
203 interrogator()->Start(
204 [&status](hci::Result<> cb_status) { status = cb_status; });
205 RunUntilIdle();
206
207 ASSERT_TRUE(status.has_value());
208 EXPECT_EQ(fit::ok(), *status);
209 status = std::nullopt;
210
211 QueueSuccessfulReadRemoteExtendedFeatures(kConnectionHandle);
212 interrogator()->Start(
213 [&status](hci::Result<> cb_status) { status = cb_status; });
214 RunUntilIdle();
215 ASSERT_TRUE(status.has_value());
216 EXPECT_EQ(fit::ok(), *status);
217 }
218
TEST_F(BrEdrInterrogatorTest,InterrogationFailedToGetName)219 TEST_F(BrEdrInterrogatorTest, InterrogationFailedToGetName) {
220 const DynamicByteBuffer remote_name_request_failure_rsp =
221 testing::CommandStatusPacket(
222 hci_spec::kRemoteNameRequest,
223 pw::bluetooth::emboss::StatusCode::UNSPECIFIED_ERROR);
224 EXPECT_CMD_PACKET_OUT(test_device(),
225 testing::RemoteNameRequestPacket(kTestDevAddr),
226 &remote_name_request_failure_rsp);
227 EXPECT_CMD_PACKET_OUT(
228 test_device(), testing::ReadRemoteVersionInfoPacket(kConnectionHandle));
229 EXPECT_CMD_PACKET_OUT(
230 test_device(),
231 testing::ReadRemoteSupportedFeaturesPacket(kConnectionHandle));
232
233 std::optional<hci::Result<>> status;
234 interrogator()->Start(
235 [&status](hci::Result<> cb_status) { status = cb_status; });
236 RunUntilIdle();
237
238 ASSERT_TRUE(status.has_value());
239 EXPECT_FALSE(status->is_ok());
240 }
241
TEST_F(BrEdrInterrogatorTest,Cancel)242 TEST_F(BrEdrInterrogatorTest, Cancel) {
243 QueueSuccessfulInterrogation(
244 kTestDevAddr, kConnectionHandle, /*extended_features=*/false);
245
246 std::optional<hci::Result<>> result;
247 interrogator()->Start([&](hci::Result<> status) { result = status; });
248 EXPECT_FALSE(result.has_value());
249
250 interrogator()->Cancel();
251
252 // The result callback should be called synchronously.
253 ASSERT_TRUE(result.has_value());
254 EXPECT_EQ(result.value(), ToResult(HostError::kCanceled));
255 result.reset();
256
257 // Events should be ignored.
258 RunUntilIdle();
259 EXPECT_FALSE(result.has_value());
260 }
261
TEST_F(BrEdrInterrogatorTest,InterrogatorDestroyedInCompleteCallback)262 TEST_F(BrEdrInterrogatorTest, InterrogatorDestroyedInCompleteCallback) {
263 QueueSuccessfulInterrogation(kTestDevAddr, kConnectionHandle);
264
265 std::optional<hci::Result<>> status;
266 interrogator()->Start([this, &status](hci::Result<> cb_status) {
267 status = cb_status;
268 DestroyInterrogator();
269 });
270 RunUntilIdle();
271
272 ASSERT_TRUE(status.has_value());
273 EXPECT_TRUE(status->is_ok());
274
275 EXPECT_TRUE(peer()->name());
276 EXPECT_TRUE(peer()->version());
277 EXPECT_TRUE(peer()->features().HasPage(0));
278 EXPECT_TRUE(peer()->features().HasBit(
279 /*page=*/0, hci_spec::LMPFeature::kExtendedFeatures));
280 EXPECT_EQ(2u, peer()->features().last_page_number());
281 }
282 } // namespace bt::gap
283