• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "stack/include/sdp_api.h"
24 #include "stack/sdp/sdpint.h"
25 #include "test/mock/mock_osi_allocator.h"
26 #include "test/mock/mock_stack_l2cap_api.h"
27 
28 #ifndef BT_DEFAULT_BUFFER_SIZE
29 #define BT_DEFAULT_BUFFER_SIZE (4096 + 16)
30 #endif
31 
32 static int L2CA_ConnectReq2_cid = 0x42;
33 static RawAddress addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6});
34 static tSDP_DISCOVERY_DB* sdp_db = nullptr;
35 
36 class StackSdpMainTest : public ::testing::Test {
37  protected:
SetUp()38   void SetUp() override {
39     sdp_init();
40     test::mock::stack_l2cap_api::L2CA_ConnectReq2.body =
41         [](uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level) {
42           return ++L2CA_ConnectReq2_cid;
43         };
44     test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t cid,
45                                                           BT_HDR* p_data) {
46       osi_free_and_reset((void**)&p_data);
47       return 0;
48     };
49     test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t cid) {
50       return true;
51     };
52     test::mock::stack_l2cap_api::L2CA_Register2.body =
53         [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop,
54            tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu,
55            uint16_t required_remote_mtu, uint16_t sec_level) {
56           return 42;  // return non zero
57         };
58     test::mock::osi_allocator::osi_malloc.body = [](size_t size) {
59       return malloc(size);
60     };
61     test::mock::osi_allocator::osi_free.body = [](void* ptr) { free(ptr); };
62     test::mock::osi_allocator::osi_free_and_reset.body = [](void** ptr) {
63       free(*ptr);
64       *ptr = nullptr;
65     };
66     sdp_db = (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
67   }
68 
TearDown()69   void TearDown() override {
70     osi_free(sdp_db);
71     test::mock::stack_l2cap_api::L2CA_ConnectReq2 = {};
72     test::mock::stack_l2cap_api::L2CA_Register2 = {};
73     test::mock::stack_l2cap_api::L2CA_DataWrite = {};
74     test::mock::stack_l2cap_api::L2CA_DisconnectReq = {};
75     test::mock::osi_allocator::osi_malloc = {};
76     test::mock::osi_allocator::osi_free = {};
77     test::mock::osi_allocator::osi_free_and_reset = {};
78   }
79 };
80 
TEST_F(StackSdpMainTest,sdp_service_search_request)81 TEST_F(StackSdpMainTest, sdp_service_search_request) {
82   ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
83   int cid = L2CA_ConnectReq2_cid;
84   tCONN_CB* p_ccb = sdpu_find_ccb_by_cid(cid);
85   ASSERT_NE(p_ccb, nullptr);
86   ASSERT_EQ(p_ccb->con_state, SDP_STATE_CONN_SETUP);
87 
88   tL2CAP_CFG_INFO cfg;
89   sdp_cb.reg_info.pL2CA_ConfigCfm_Cb(p_ccb->connection_id, 0, &cfg);
90 
91   ASSERT_EQ(p_ccb->con_state, SDP_STATE_CONNECTED);
92 
93   sdp_disconnect(p_ccb, SDP_SUCCESS);
94   sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb(p_ccb->connection_id, 0);
95 
96   ASSERT_EQ(p_ccb->con_state, SDP_STATE_IDLE);
97 }
98 
find_ccb(uint16_t cid,uint8_t state)99 tCONN_CB* find_ccb(uint16_t cid, uint8_t state) {
100   uint16_t xx;
101   tCONN_CB* p_ccb;
102 
103   // Look through each connection control block
104   for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) {
105     if ((p_ccb->con_state == state) && (p_ccb->connection_id == cid)) {
106       return p_ccb;
107     }
108   }
109   return nullptr;  // not found
110 }
111 
TEST_F(StackSdpMainTest,sdp_service_search_request_queuing)112 TEST_F(StackSdpMainTest, sdp_service_search_request_queuing) {
113   ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
114   const int cid = L2CA_ConnectReq2_cid;
115   tCONN_CB* p_ccb1 = find_ccb(cid, SDP_STATE_CONN_SETUP);
116   ASSERT_NE(p_ccb1, nullptr);
117   ASSERT_EQ(p_ccb1->con_state, SDP_STATE_CONN_SETUP);
118 
119   ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
120   tCONN_CB* p_ccb2 = find_ccb(cid, SDP_STATE_CONN_PEND);
121   ASSERT_NE(p_ccb2, nullptr);
122   ASSERT_NE(p_ccb2, p_ccb1);
123   ASSERT_EQ(p_ccb2->con_state, SDP_STATE_CONN_PEND);
124 
125   tL2CAP_CFG_INFO cfg;
126   sdp_cb.reg_info.pL2CA_ConfigCfm_Cb(p_ccb1->connection_id, 0, &cfg);
127 
128   ASSERT_EQ(p_ccb1->con_state, SDP_STATE_CONNECTED);
129   ASSERT_EQ(p_ccb2->con_state, SDP_STATE_CONN_PEND);
130 
131   p_ccb1->disconnect_reason = SDP_SUCCESS;
132   sdp_disconnect(p_ccb1, SDP_SUCCESS);
133 
134   ASSERT_EQ(p_ccb1->con_state, SDP_STATE_IDLE);
135   ASSERT_EQ(p_ccb2->con_state, SDP_STATE_CONNECTED);
136 
137   sdp_disconnect(p_ccb2, SDP_SUCCESS);
138   sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb(p_ccb2->connection_id, 0);
139 
140   ASSERT_EQ(p_ccb1->con_state, SDP_STATE_IDLE);
141   ASSERT_EQ(p_ccb2->con_state, SDP_STATE_IDLE);
142 }
143 
sdp_callback(tSDP_RESULT result)144 void sdp_callback(tSDP_RESULT result) {
145   if (result == SDP_SUCCESS) {
146     ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
147   }
148 }
149 
TEST_F(StackSdpMainTest,sdp_service_search_request_queuing_race_condition)150 TEST_F(StackSdpMainTest, sdp_service_search_request_queuing_race_condition) {
151   // start first request
152   ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, sdp_callback));
153   const int cid1 = L2CA_ConnectReq2_cid;
154   tCONN_CB* p_ccb1 = find_ccb(cid1, SDP_STATE_CONN_SETUP);
155   ASSERT_NE(p_ccb1, nullptr);
156   ASSERT_EQ(p_ccb1->con_state, SDP_STATE_CONN_SETUP);
157 
158   tL2CAP_CFG_INFO cfg;
159   sdp_cb.reg_info.pL2CA_ConfigCfm_Cb(p_ccb1->connection_id, 0, &cfg);
160 
161   ASSERT_EQ(p_ccb1->con_state, SDP_STATE_CONNECTED);
162 
163   sdp_disconnect(p_ccb1, SDP_SUCCESS);
164   sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb(p_ccb1->connection_id, 0);
165 
166   const int cid2 = L2CA_ConnectReq2_cid;
167   ASSERT_NE(cid1, cid2);  // The callback a queued a new request
168   tCONN_CB* p_ccb2 = find_ccb(cid2, SDP_STATE_CONN_SETUP);
169   ASSERT_NE(p_ccb2, nullptr);
170   // If race condition, this will be stuck in PEND
171   ASSERT_EQ(p_ccb2->con_state, SDP_STATE_CONN_SETUP);
172 
173   sdp_disconnect(p_ccb2, SDP_SUCCESS);
174 }
175