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 <base/strings/stringprintf.h>
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <sys/socket.h>
21
22 #include "bta/dm/bta_dm_sec_int.h"
23 #include "bta/test/bta_test_fixtures.h"
24 #include "btm_status.h"
25 #include "test/mock/mock_stack_btm_inq.h"
26 #include "test/mock/mock_stack_btm_interface.h"
27 #include "types/raw_address.h"
28
29 using ::testing::ElementsAre;
30
31 namespace {
32 const RawAddress kRawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
33 const RawAddress kRawAddress2({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
34 const DEV_CLASS kDeviceClass = {0x11, 0x22, 0x33};
35
36 constexpr char kRemoteName[] = "TheRemoteName";
37
38 } // namespace
39
40 // Test hooks
41 namespace bluetooth {
42 namespace legacy {
43 namespace testing {
44
45 tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data);
46
47 } // namespace testing
48 } // namespace legacy
49 } // namespace bluetooth
50
51 class BtaSecTest : public BtaWithHwOnTest {
52 protected:
SetUp()53 void SetUp() override { BtaWithHwOnTest::SetUp(); }
54
TearDown()55 void TearDown() override { BtaWithHwOnTest::TearDown(); }
56 };
57
TEST_F(BtaSecTest,bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithName)58 TEST_F(BtaSecTest, bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithName) {
59 constexpr uint32_t kNumVal = 1234;
60 static bool callback_sent = false;
61 mock_btm_client_interface.peer.BTM_ReadRemoteDeviceName =
62 [](const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb,
63 tBT_TRANSPORT transport) -> tBTM_STATUS { return BTM_CMD_STARTED; };
64
65 static tBTA_DM_SP_CFM_REQ cfm_req{};
66 bta_dm_sec_enable([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
67 callback_sent = true;
68 cfm_req = p_data->cfm_req;
69 });
70
71 tBTM_SP_EVT_DATA data = {
72 .cfm_req =
73 {
74 // tBTM_SP_CFM_REQ
75 .bd_addr = kRawAddress,
76 .dev_class = {},
77 .bd_name = {},
78 .num_val = kNumVal,
79 .just_works = false,
80 .loc_auth_req = BTM_AUTH_SP_YES,
81 .rmt_auth_req = BTM_AUTH_SP_YES,
82 .loc_io_caps = BTM_IO_CAP_NONE,
83 .rmt_io_caps = BTM_IO_CAP_NONE,
84 },
85 };
86 data.cfm_req.dev_class = kDeviceClass;
87 bd_name_from_char_pointer(data.cfm_req.bd_name, kRemoteName);
88
89 ASSERT_EQ(btm_status_text(BTM_CMD_STARTED),
90 btm_status_text(bluetooth::legacy::testing::bta_dm_sp_cback(
91 BTM_SP_CFM_REQ_EVT, &data)));
92 ASSERT_EQ(kNumVal, bta_dm_sec_cb.num_val);
93 ASSERT_TRUE(callback_sent);
94
95 ASSERT_EQ(kRawAddress, cfm_req.bd_addr);
96 ASSERT_THAT(cfm_req.dev_class,
97 ElementsAre(kDeviceClass[0], kDeviceClass[1], kDeviceClass[2]));
98 ASSERT_STREQ(kRemoteName, reinterpret_cast<const char*>(cfm_req.bd_name));
99 ASSERT_EQ(kNumVal, cfm_req.num_val);
100 ASSERT_EQ(false, cfm_req.just_works);
101 ASSERT_EQ(BTM_AUTH_SP_YES, cfm_req.loc_auth_req);
102 ASSERT_EQ(BTM_AUTH_SP_YES, cfm_req.rmt_auth_req);
103 ASSERT_EQ(BTM_IO_CAP_NONE, cfm_req.loc_io_caps);
104 ASSERT_EQ(BTM_IO_CAP_NONE, cfm_req.rmt_io_caps);
105 }
106
TEST_F(BtaSecTest,bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithoutName_RNRSuccess)107 TEST_F(BtaSecTest, bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithoutName_RNRSuccess) {
108 constexpr uint32_t kNumVal = 1234;
109 static bool callback_sent = false;
110 reset_mock_btm_client_interface();
111 mock_btm_client_interface.peer.BTM_ReadRemoteDeviceName =
112 [](const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb,
113 tBT_TRANSPORT transport) -> tBTM_STATUS { return BTM_CMD_STARTED; };
114
115 static tBTA_DM_SP_CFM_REQ cfm_req{};
116 bta_dm_sec_enable([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
117 callback_sent = true;
118 cfm_req = p_data->cfm_req;
119 });
120
121 tBTM_SP_EVT_DATA data = {
122 .cfm_req =
123 {
124 // tBTM_SP_CFM_REQ
125 .bd_addr = kRawAddress,
126 .dev_class = {},
127 .bd_name = {0}, // No name available
128 .num_val = kNumVal,
129 .just_works = false,
130 .loc_auth_req = BTM_AUTH_SP_YES,
131 .rmt_auth_req = BTM_AUTH_SP_YES,
132 .loc_io_caps = BTM_IO_CAP_NONE,
133 .rmt_io_caps = BTM_IO_CAP_NONE,
134 },
135 };
136 data.cfm_req.dev_class = kDeviceClass;
137
138 ASSERT_EQ(btm_status_text(BTM_CMD_STARTED),
139 btm_status_text(bluetooth::legacy::testing::bta_dm_sp_cback(
140 BTM_SP_CFM_REQ_EVT, &data)));
141 ASSERT_EQ(kNumVal, bta_dm_sec_cb.num_val);
142 ASSERT_FALSE(callback_sent);
143
144 test::mock::stack_btm_inq::BTM_ReadRemoteDeviceName = {};
145 }
146
TEST_F(BtaSecTest,bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithoutName_RNRFail)147 TEST_F(BtaSecTest, bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithoutName_RNRFail) {
148 constexpr uint32_t kNumVal = 1234;
149 static bool callback_sent = false;
150 mock_btm_client_interface.peer.BTM_ReadRemoteDeviceName =
151 [](const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb,
152 tBT_TRANSPORT transport) -> tBTM_STATUS { return BTM_SUCCESS; };
153
154 static tBTA_DM_SP_CFM_REQ cfm_req{};
155 bta_dm_sec_enable([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
156 callback_sent = true;
157 cfm_req = p_data->cfm_req;
158 });
159
160 tBTM_SP_EVT_DATA data = {
161 .cfm_req =
162 {
163 // tBTM_SP_CFM_REQ
164 .bd_addr = kRawAddress,
165 .dev_class = {},
166 .bd_name = {0},
167 .num_val = kNumVal,
168 .just_works = false,
169 .loc_auth_req = BTM_AUTH_SP_YES,
170 .rmt_auth_req = BTM_AUTH_SP_YES,
171 .loc_io_caps = BTM_IO_CAP_NONE,
172 .rmt_io_caps = BTM_IO_CAP_NONE,
173 },
174 };
175 data.cfm_req.dev_class = kDeviceClass;
176
177 ASSERT_EQ(btm_status_text(BTM_CMD_STARTED),
178 btm_status_text(bluetooth::legacy::testing::bta_dm_sp_cback(
179 BTM_SP_CFM_REQ_EVT, &data)));
180 ASSERT_EQ(kNumVal, bta_dm_sec_cb.num_val);
181 ASSERT_TRUE(callback_sent);
182
183 ASSERT_EQ(kRawAddress, cfm_req.bd_addr);
184 ASSERT_THAT(cfm_req.dev_class,
185 ElementsAre(kDeviceClass[0], kDeviceClass[1], kDeviceClass[2]));
186 ASSERT_EQ(kNumVal, cfm_req.num_val);
187 ASSERT_EQ(false, cfm_req.just_works);
188 ASSERT_EQ(BTM_AUTH_SP_YES, cfm_req.loc_auth_req);
189 ASSERT_EQ(BTM_AUTH_SP_YES, cfm_req.rmt_auth_req);
190 ASSERT_EQ(BTM_IO_CAP_NONE, cfm_req.loc_io_caps);
191 ASSERT_EQ(BTM_IO_CAP_NONE, cfm_req.rmt_io_caps);
192 }
193
TEST_F(BtaSecTest,bta_dm_sp_cback__BTM_SP_KEY_NOTIF_EVT)194 TEST_F(BtaSecTest, bta_dm_sp_cback__BTM_SP_KEY_NOTIF_EVT) {
195 constexpr uint32_t kPassKey = 1234;
196 static bool callback_sent = false;
197 mock_btm_client_interface.peer.BTM_ReadRemoteDeviceName =
198 [](const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb,
199 tBT_TRANSPORT transport) -> tBTM_STATUS { return BTM_CMD_STARTED; };
200
201 static tBTA_DM_SP_KEY_NOTIF key_notif{};
202 bta_dm_sec_enable([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
203 callback_sent = true;
204 key_notif = p_data->key_notif;
205 });
206
207 tBTM_SP_EVT_DATA data = {
208 .key_notif =
209 {
210 // tBTM_SP_KEY_NOTIF
211 .bd_addr = kRawAddress,
212 .dev_class = {},
213 .bd_name = {},
214 .passkey = kPassKey,
215 },
216 };
217 data.key_notif.dev_class = kDeviceClass;
218 bd_name_from_char_pointer(data.key_notif.bd_name, kRemoteName);
219
220 ASSERT_EQ(btm_status_text(BTM_CMD_STARTED),
221 btm_status_text(bluetooth::legacy::testing::bta_dm_sp_cback(
222 BTM_SP_KEY_NOTIF_EVT, &data)));
223 ASSERT_EQ(kPassKey, bta_dm_sec_cb.num_val);
224 ASSERT_TRUE(callback_sent);
225
226 ASSERT_EQ(kRawAddress, key_notif.bd_addr);
227 ASSERT_THAT(key_notif.dev_class,
228 ElementsAre(kDeviceClass[0], kDeviceClass[1], kDeviceClass[2]));
229 ASSERT_STREQ(kRemoteName, reinterpret_cast<const char*>(key_notif.bd_name));
230 ASSERT_EQ(kPassKey, key_notif.passkey);
231 }
232