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