1 /*
2 * Copyright 2022 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 #include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 #include <stdlib.h>
20
21 #include <cstddef>
22
23 #include "osi/include/allocator.h"
24 #include "stack/include/bt_uuid16.h"
25 #include "stack/include/sdpdefs.h"
26 #include "stack/sdp/internal/sdp_api.h"
27 #include "stack/sdp/sdpint.h"
28 #include "test/fake/fake_osi.h"
29 #include "test/mock/mock_osi_allocator.h"
30 #include "test/mock/mock_stack_l2cap_api.h"
31
32 #ifndef BT_DEFAULT_BUFFER_SIZE
33 #define BT_DEFAULT_BUFFER_SIZE (4096 + 16)
34 #endif
35
36 namespace {
37
38 static int L2CA_ConnectReqWithSecurity_cid = 0x42;
39 static RawAddress addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6});
40 static tSDP_DISCOVERY_DB* sdp_db = nullptr;
41
42 class StackSdpWithMocksTest : public ::testing::Test {
43 protected:
SetUp()44 void SetUp() override {
45 fake_osi_ = std::make_unique<test::fake::FakeOsi>();
46
47 test::mock::stack_l2cap_api::L2CA_ConnectReqWithSecurity.body =
48 [](uint16_t /* psm */, const RawAddress& /* p_bd_addr */,
49 uint16_t /* sec_level */) {
50 return ++L2CA_ConnectReqWithSecurity_cid;
51 };
52 test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t /* cid */,
53 BT_HDR* p_data) {
54 osi_free_and_reset((void**)&p_data);
55 return 0;
56 };
57 test::mock::stack_l2cap_api::L2CA_DisconnectReq.body =
58 [](uint16_t /* cid */) { return true; };
59 test::mock::stack_l2cap_api::L2CA_RegisterWithSecurity.body =
60 [](uint16_t psm, const tL2CAP_APPL_INFO& /* p_cb_info */,
61 bool /* enable_snoop */, tL2CAP_ERTM_INFO* /* p_ertm_info */,
62 uint16_t /* my_mtu */, uint16_t /* required_remote_mtu */,
63 uint16_t /* sec_level */) { return psm; };
64 }
65
TearDown()66 void TearDown() override {
67 test::mock::stack_l2cap_api::L2CA_ConnectReqWithSecurity = {};
68 test::mock::stack_l2cap_api::L2CA_RegisterWithSecurity = {};
69 test::mock::stack_l2cap_api::L2CA_DataWrite = {};
70 test::mock::stack_l2cap_api::L2CA_DisconnectReq = {};
71
72 fake_osi_.reset();
73 }
74
75 std::unique_ptr<test::fake::FakeOsi> fake_osi_;
76 };
77
78 class StackSdpInitTest : public StackSdpWithMocksTest {
79 protected:
SetUp()80 void SetUp() override {
81 StackSdpWithMocksTest::SetUp();
82 sdp_init();
83 sdp_db = (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
84 }
85
TearDown()86 void TearDown() override {
87 osi_free(sdp_db);
88 sdp_free();
89 StackSdpWithMocksTest::TearDown();
90 }
91 };
92
93 } // namespace
94
TEST_F(StackSdpInitTest,nop)95 TEST_F(StackSdpInitTest, nop) {}
96
TEST_F(StackSdpInitTest,sdp_service_search_request)97 TEST_F(StackSdpInitTest, sdp_service_search_request) {
98 ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
99 int cid = L2CA_ConnectReqWithSecurity_cid;
100 tCONN_CB* p_ccb = sdpu_find_ccb_by_cid(cid);
101 ASSERT_NE(p_ccb, nullptr);
102 ASSERT_EQ(p_ccb->con_state, SDP_STATE_CONN_SETUP);
103
104 tL2CAP_CFG_INFO cfg;
105 sdp_cb.reg_info.pL2CA_ConfigCfm_Cb(p_ccb->connection_id, 0, &cfg);
106
107 ASSERT_EQ(p_ccb->con_state, SDP_STATE_CONNECTED);
108
109 sdp_disconnect(p_ccb, SDP_SUCCESS);
110 sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb(p_ccb->connection_id, 0);
111
112 ASSERT_EQ(p_ccb->con_state, SDP_STATE_IDLE);
113 }
114
find_ccb(uint16_t cid,uint8_t state)115 tCONN_CB* find_ccb(uint16_t cid, uint8_t state) {
116 uint16_t xx;
117 tCONN_CB* p_ccb;
118
119 // Look through each connection control block
120 for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) {
121 if ((p_ccb->con_state == state) && (p_ccb->connection_id == cid)) {
122 return p_ccb;
123 }
124 }
125 return nullptr; // not found
126 }
127
TEST_F(StackSdpInitTest,sdp_service_search_request_queuing)128 TEST_F(StackSdpInitTest, sdp_service_search_request_queuing) {
129 ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
130 const int cid = L2CA_ConnectReqWithSecurity_cid;
131 tCONN_CB* p_ccb1 = find_ccb(cid, SDP_STATE_CONN_SETUP);
132 ASSERT_NE(p_ccb1, nullptr);
133 ASSERT_EQ(p_ccb1->con_state, SDP_STATE_CONN_SETUP);
134
135 ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
136 tCONN_CB* p_ccb2 = find_ccb(cid, SDP_STATE_CONN_PEND);
137 ASSERT_NE(p_ccb2, nullptr);
138 ASSERT_NE(p_ccb2, p_ccb1);
139 ASSERT_EQ(p_ccb2->con_state, SDP_STATE_CONN_PEND);
140
141 tL2CAP_CFG_INFO cfg;
142 sdp_cb.reg_info.pL2CA_ConfigCfm_Cb(p_ccb1->connection_id, 0, &cfg);
143
144 ASSERT_EQ(p_ccb1->con_state, SDP_STATE_CONNECTED);
145 ASSERT_EQ(p_ccb2->con_state, SDP_STATE_CONN_PEND);
146
147 p_ccb1->disconnect_reason = SDP_SUCCESS;
148 sdp_disconnect(p_ccb1, SDP_SUCCESS);
149
150 ASSERT_EQ(p_ccb1->con_state, SDP_STATE_IDLE);
151 ASSERT_EQ(p_ccb2->con_state, SDP_STATE_CONNECTED);
152
153 sdp_disconnect(p_ccb2, SDP_SUCCESS);
154 sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb(p_ccb2->connection_id, 0);
155
156 ASSERT_EQ(p_ccb1->con_state, SDP_STATE_IDLE);
157 ASSERT_EQ(p_ccb2->con_state, SDP_STATE_IDLE);
158 }
159
sdp_callback(const RawAddress &,tSDP_RESULT result)160 void sdp_callback(const RawAddress& /* bd_addr */, tSDP_RESULT result) {
161 if (result == SDP_SUCCESS) {
162 ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
163 }
164 }
165
TEST_F(StackSdpInitTest,sdp_service_search_request_queuing_race_condition)166 TEST_F(StackSdpInitTest, sdp_service_search_request_queuing_race_condition) {
167 // start first request
168 ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, sdp_callback));
169 const int cid1 = L2CA_ConnectReqWithSecurity_cid;
170 tCONN_CB* p_ccb1 = find_ccb(cid1, SDP_STATE_CONN_SETUP);
171 ASSERT_NE(p_ccb1, nullptr);
172 ASSERT_EQ(p_ccb1->con_state, SDP_STATE_CONN_SETUP);
173
174 tL2CAP_CFG_INFO cfg;
175 sdp_cb.reg_info.pL2CA_ConfigCfm_Cb(p_ccb1->connection_id, 0, &cfg);
176
177 ASSERT_EQ(p_ccb1->con_state, SDP_STATE_CONNECTED);
178
179 sdp_disconnect(p_ccb1, SDP_SUCCESS);
180 sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb(p_ccb1->connection_id, 0);
181
182 const int cid2 = L2CA_ConnectReqWithSecurity_cid;
183 ASSERT_NE(cid1, cid2); // The callback a queued a new request
184 tCONN_CB* p_ccb2 = find_ccb(cid2, SDP_STATE_CONN_SETUP);
185 ASSERT_NE(p_ccb2, nullptr);
186 // If race condition, this will be stuck in PEND
187 ASSERT_EQ(p_ccb2->con_state, SDP_STATE_CONN_SETUP);
188
189 sdp_disconnect(p_ccb2, SDP_SUCCESS);
190 }
191
TEST_F(StackSdpInitTest,sdp_disc_wait_text)192 TEST_F(StackSdpInitTest, sdp_disc_wait_text) {
193 std::vector<std::pair<tSDP_DISC_WAIT, std::string>> states = {
194 std::make_pair(SDP_DISC_WAIT_CONN, "SDP_DISC_WAIT_CONN"),
195 std::make_pair(SDP_DISC_WAIT_HANDLES, "SDP_DISC_WAIT_HANDLES"),
196 std::make_pair(SDP_DISC_WAIT_ATTR, "SDP_DISC_WAIT_ATTR"),
197 std::make_pair(SDP_DISC_WAIT_SEARCH_ATTR, "SDP_DISC_WAIT_SEARCH_ATTR"),
198 std::make_pair(SDP_DISC_WAIT_CANCEL, "SDP_DISC_WAIT_CANCEL"),
199 };
200 for (const auto& state : states) {
201 ASSERT_STREQ(state.second.c_str(), sdp_disc_wait_text(state.first).c_str());
202 }
203 auto unknown =
204 base::StringPrintf("UNKNOWN[%d]", std::numeric_limits<uint8_t>::max());
205 ASSERT_STREQ(unknown.c_str(),
206 sdp_disc_wait_text(static_cast<tSDP_DISC_WAIT>(
207 std::numeric_limits<uint8_t>::max()))
208 .c_str());
209 }
210
TEST_F(StackSdpInitTest,sdp_state_text)211 TEST_F(StackSdpInitTest, sdp_state_text) {
212 std::vector<std::pair<tSDP_STATE, std::string>> states = {
213 std::make_pair(SDP_STATE_IDLE, "SDP_STATE_IDLE"),
214 std::make_pair(SDP_STATE_CONN_SETUP, "SDP_STATE_CONN_SETUP"),
215 std::make_pair(SDP_STATE_CFG_SETUP, "SDP_STATE_CFG_SETUP"),
216 std::make_pair(SDP_STATE_CONNECTED, "SDP_STATE_CONNECTED"),
217 std::make_pair(SDP_STATE_CONN_PEND, "SDP_STATE_CONN_PEND"),
218 };
219 for (const auto& state : states) {
220 ASSERT_STREQ(state.second.c_str(), sdp_state_text(state.first).c_str());
221 }
222 auto unknown = base::StringPrintf("UNKNOWN[%hhu]",
223 std::numeric_limits<std::uint8_t>::max());
224 ASSERT_STREQ(unknown.c_str(),
225 sdp_state_text(static_cast<tSDP_STATE>(
226 std::numeric_limits<std::uint8_t>::max()))
227 .c_str());
228 }
229
TEST_F(StackSdpInitTest,sdp_flags_text)230 TEST_F(StackSdpInitTest, sdp_flags_text) {
231 std::vector<std::pair<tSDP_DISC_WAIT, std::string>> flags = {
232 std::make_pair(SDP_FLAGS_IS_ORIG, "SDP_FLAGS_IS_ORIG"),
233 std::make_pair(SDP_FLAGS_HIS_CFG_DONE, "SDP_FLAGS_HIS_CFG_DONE"),
234 std::make_pair(SDP_FLAGS_MY_CFG_DONE, "SDP_FLAGS_MY_CFG_DONE"),
235 };
236 for (const auto& flag : flags) {
237 ASSERT_STREQ(flag.second.c_str(), sdp_flags_text(flag.first).c_str());
238 }
239 auto unknown =
240 base::StringPrintf("UNKNOWN[%hhu]", std::numeric_limits<uint8_t>::max());
241 ASSERT_STREQ(unknown.c_str(),
242 sdp_flags_text(static_cast<tSDP_DISC_WAIT>(
243 std::numeric_limits<uint8_t>::max()))
244 .c_str());
245 }
246
TEST_F(StackSdpInitTest,sdp_status_text)247 TEST_F(StackSdpInitTest, sdp_status_text) {
248 std::vector<std::pair<tSDP_STATUS, std::string>> status = {
249 std::make_pair(SDP_SUCCESS, "SDP_SUCCESS"),
250 std::make_pair(SDP_INVALID_VERSION, "SDP_INVALID_VERSION"),
251 std::make_pair(SDP_INVALID_SERV_REC_HDL, "SDP_INVALID_SERV_REC_HDL"),
252 std::make_pair(SDP_INVALID_REQ_SYNTAX, "SDP_INVALID_REQ_SYNTAX"),
253 std::make_pair(SDP_INVALID_PDU_SIZE, "SDP_INVALID_PDU_SIZE"),
254 std::make_pair(SDP_INVALID_CONT_STATE, "SDP_INVALID_CONT_STATE"),
255 std::make_pair(SDP_NO_RESOURCES, "SDP_NO_RESOURCES"),
256 std::make_pair(SDP_DI_REG_FAILED, "SDP_DI_REG_FAILED"),
257 std::make_pair(SDP_DI_DISC_FAILED, "SDP_DI_DISC_FAILED"),
258 std::make_pair(SDP_NO_DI_RECORD_FOUND, "SDP_NO_DI_RECORD_FOUND"),
259 std::make_pair(SDP_ERR_ATTR_NOT_PRESENT, "SDP_ERR_ATTR_NOT_PRESENT"),
260 std::make_pair(SDP_ILLEGAL_PARAMETER, "SDP_ILLEGAL_PARAMETER"),
261 std::make_pair(HID_SDP_NO_SERV_UUID, "HID_SDP_NO_SERV_UUID"),
262 std::make_pair(HID_SDP_MANDATORY_MISSING, "HID_SDP_MANDATORY_MISSING"),
263 std::make_pair(SDP_NO_RECS_MATCH, "SDP_NO_RECS_MATCH"),
264 std::make_pair(SDP_CONN_FAILED, "SDP_CONN_FAILED"),
265 std::make_pair(SDP_CFG_FAILED, "SDP_CFG_FAILED"),
266 std::make_pair(SDP_GENERIC_ERROR, "SDP_GENERIC_ERROR"),
267 std::make_pair(SDP_DB_FULL, "SDP_DB_FULL"),
268 std::make_pair(SDP_CANCEL, "SDP_CANCEL"),
269 };
270 for (const auto& stat : status) {
271 ASSERT_STREQ(stat.second.c_str(), sdp_status_text(stat.first).c_str());
272 }
273 auto unknown =
274 base::StringPrintf("UNKNOWN[%hu]", std::numeric_limits<uint16_t>::max());
275 ASSERT_STREQ(unknown.c_str(),
276 sdp_status_text(static_cast<tSDP_STATUS>(
277 std::numeric_limits<uint16_t>::max()))
278 .c_str());
279 }
280
281 static tSDP_DISCOVERY_DB db{};
282 static tSDP_DISC_REC rec{};
283 static tSDP_DISC_ATTR uuid_desc_attr{};
284 static tSDP_DISC_ATTR client_exe_url_attr{};
285 static tSDP_DISC_ATTR service_desc_attr{};
286 static tSDP_DISC_ATTR doc_url_desc_attr{};
287 static tSDP_DISC_ATTR spec_id_attr{};
288 static tSDP_DISC_ATTR vendor_id_attr{};
289 static tSDP_DISC_ATTR vendor_id_src_attr{};
290 static tSDP_DISC_ATTR prod_id_attr{};
291 static tSDP_DISC_ATTR prod_version_attr{};
292 static tSDP_DISC_ATTR primary_rec_attr{};
293
294 class SDP_GetDiRecord_Tests : public ::testing::Test {
295 protected:
296
SetUp()297 void SetUp() override {
298 db.p_first_rec = &rec;
299 rec.p_first_attr = &uuid_desc_attr;
300
301 uuid_desc_attr.attr_id = ATTR_ID_SERVICE_ID;
302 uuid_desc_attr.p_next_attr = &client_exe_url_attr;
303
304 client_exe_url_attr.attr_id = ATTR_ID_CLIENT_EXE_URL;
305 client_exe_url_attr.p_next_attr = &service_desc_attr;
306
307 service_desc_attr.attr_id = ATTR_ID_SERVICE_DESCRIPTION;
308 service_desc_attr.p_next_attr = &doc_url_desc_attr;
309
310 doc_url_desc_attr.attr_id = ATTR_ID_DOCUMENTATION_URL;
311 doc_url_desc_attr.p_next_attr = &spec_id_attr;
312
313 spec_id_attr.attr_id = ATTR_ID_SPECIFICATION_ID;
314 spec_id_attr.p_next_attr = &vendor_id_attr;
315
316 vendor_id_attr.attr_id = ATTR_ID_VENDOR_ID;
317 vendor_id_attr.p_next_attr = &vendor_id_src_attr;
318
319 vendor_id_src_attr.attr_id = ATTR_ID_VENDOR_ID_SOURCE;
320 vendor_id_src_attr.p_next_attr = &prod_id_attr;
321
322 prod_id_attr.attr_id = ATTR_ID_PRODUCT_ID;
323 prod_id_attr.p_next_attr = &prod_version_attr;
324
325 prod_version_attr.attr_id = ATTR_ID_PRODUCT_VERSION;
326 prod_version_attr.p_next_attr = &primary_rec_attr;
327
328 primary_rec_attr.attr_id = ATTR_ID_PRIMARY_RECORD;
329 primary_rec_attr.p_next_attr = nullptr;
330 }
331
TearDown()332 void TearDown() override {
333 db = {};
334 rec = {};
335 uuid_desc_attr = {};
336 client_exe_url_attr = {};
337 service_desc_attr = {};
338 doc_url_desc_attr = {};
339 spec_id_attr = {};
340 vendor_id_attr = {};
341 vendor_id_src_attr = {};
342 prod_id_attr = {};
343 prod_version_attr = {};
344 primary_rec_attr = {};
345 }
346 };
347
348 // regression test for b/297831980 and others
TEST_F(SDP_GetDiRecord_Tests,SDP_GetDiRecord_Regression_test0)349 TEST_F(SDP_GetDiRecord_Tests, SDP_GetDiRecord_Regression_test0) {
350 // tune the type/len and value of each attribute in
351 // each test
352 uuid_desc_attr.attr_len_type = (UUID_DESC_TYPE<<12) | 2;
353 uuid_desc_attr.attr_value.v.u16 = UUID_SERVCLASS_PNP_INFORMATION;
354
355 // use a 2-byte string so that it can be
356 // saved in tSDP_DISC_ATVAL
357 const char *const text = "AB";
358 int len = strlen(text);
359 client_exe_url_attr.attr_len_type = (URL_DESC_TYPE<<12) | len;
360 memcpy(client_exe_url_attr.attr_value.v.array, text, len);
361
362 // make this attr not found by id
363 service_desc_attr.attr_id = ATTR_ID_SERVICE_DESCRIPTION + 1;
364 service_desc_attr.attr_len_type = (TEXT_STR_DESC_TYPE<<12) | len;
365 memcpy(service_desc_attr.attr_value.v.array, text, len);
366
367 // make a wrong type
368 doc_url_desc_attr.attr_len_type =(TEXT_STR_DESC_TYPE<<12) | len;
369 memcpy(doc_url_desc_attr.attr_value.v.array, text, len);
370
371 // setup unexpected sizes for the following attrs
372 spec_id_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1;
373 spec_id_attr.attr_value.v.u16 = 0x1111;
374
375 vendor_id_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1;
376 vendor_id_attr.attr_value.v.u16 = 0x2222;
377
378 vendor_id_src_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1;
379 vendor_id_src_attr.attr_value.v.u16 = 0x3333;
380
381 prod_id_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1;
382 prod_id_attr.attr_value.v.u16 = 0x4444;
383
384 prod_version_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1;
385 prod_version_attr.attr_value.v.u16 = 0x5555;
386
387 // setup wrong size for primary_rec_attr
388 primary_rec_attr.attr_len_type = (BOOLEAN_DESC_TYPE << 12) | 0;
389 primary_rec_attr.attr_value.v.u8 = 0x66;
390
391 tSDP_DI_GET_RECORD device_info{};
392
393 SDP_GetDiRecord(1, &device_info, &db);
394
395 ASSERT_STREQ(text, device_info.rec.client_executable_url);
396
397 // service description could not be found
398 ASSERT_EQ(strlen(device_info.rec.service_description), (size_t) 0);
399
400 // with a wrong attr type, the attr value won't be accepted
401 ASSERT_EQ(strlen(device_info.rec.documentation_url), (size_t) 0);
402
403 // none of the following values got setup
404 ASSERT_EQ(device_info.spec_id, 0);
405 ASSERT_EQ(device_info.rec.vendor, 0);
406 ASSERT_EQ(device_info.rec.vendor_id_source, 0);
407 ASSERT_EQ(device_info.rec.product, 0);
408 ASSERT_EQ(device_info.rec.version, 0);
409 ASSERT_FALSE(device_info.rec.primary_record);
410 }
411