1 /*
2 * Copyright 2020 HIMSA II K/S - www.himsa.dk.
3 * Represented by EHIMA - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20
21 #include <vector>
22
23 #include "base/bind_helpers.h"
24 #include "btm_api.h"
25 #include "l2c_api.h"
26 #include "mock_btif_storage.h"
27 #include "mock_btm_api_layer.h"
28 #include "mock_controller.h"
29 #include "mock_eatt.h"
30 #include "mock_gatt_layer.h"
31 #include "mock_l2cap_layer.h"
32
33 using testing::_;
34 using testing::DoAll;
35 using testing::MockFunction;
36 using testing::NiceMock;
37 using testing::NotNull;
38 using testing::Return;
39 using testing::SaveArg;
40 using testing::SaveArgPointee;
41 using testing::StrictMock;
42
43 using bluetooth::eatt::EattChannel;
44 using bluetooth::eatt::EattChannelState;
45
46 #define BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK 0x01
47
48 /* Needed for testing context */
49 static tGATT_TCB test_tcb;
btif_storage_add_eatt_supported(const RawAddress & addr)50 void btif_storage_add_eatt_supported(const RawAddress& addr) { return; }
gatt_data_process(tGATT_TCB & tcb,uint16_t cid,BT_HDR * p_buf)51 void gatt_data_process(tGATT_TCB& tcb, uint16_t cid, BT_HDR* p_buf) { return; }
gatt_find_tcb_by_addr(const RawAddress & bda,tBT_TRANSPORT transport)52 tGATT_TCB* gatt_find_tcb_by_addr(const RawAddress& bda,
53 tBT_TRANSPORT transport) {
54 LOG(INFO) << __func__;
55 return &test_tcb;
56 }
57
58 namespace {
59 const RawAddress test_address({0x11, 0x11, 0x11, 0x11, 0x11, 0x11});
60
61 class EattTest : public testing::Test {
62 protected:
ConnectDeviceEattSupported(int num_of_accepted_connections)63 void ConnectDeviceEattSupported(int num_of_accepted_connections) {
64 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
65 .WillByDefault(
66 [](const RawAddress& addr,
67 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
68 std::move(cb).Run(addr, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK);
69 return true;
70 });
71 ON_CALL(gatt_interface_, GetEattSupport)
72 .WillByDefault([](const RawAddress& addr) { return true; });
73
74 std::vector<uint16_t> test_local_cids{61, 62, 63, 64, 65};
75 EXPECT_CALL(l2cap_interface_,
76 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
77 .WillOnce(Return(test_local_cids));
78
79 eatt_instance_->Connect(test_address);
80
81 int i = 0;
82 for (uint16_t cid : test_local_cids) {
83 EattChannel* channel =
84 eatt_instance_->FindEattChannelByCid(test_address, cid);
85 ASSERT_TRUE(channel != nullptr);
86 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_PENDING);
87
88 if (i < num_of_accepted_connections) {
89 l2cap_app_info_.pL2CA_CreditBasedConnectCfm_Cb(
90 test_address, cid, EATT_MIN_MTU_MPS, L2CAP_CONN_OK);
91 connected_cids_.push_back(cid);
92
93 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
94 } else {
95 l2cap_app_info_.pL2CA_Error_Cb(cid, L2CAP_CONN_NO_RESOURCES);
96
97 EattChannel* channel =
98 eatt_instance_->FindEattChannelByCid(test_address, cid);
99 ASSERT_TRUE(channel == nullptr);
100 }
101 i++;
102 }
103
104 ASSERT_TRUE(test_tcb.eatt == num_of_accepted_connections);
105 }
106
DisconnectEattByPeer(void)107 void DisconnectEattByPeer(void) {
108 for (uint16_t cid : connected_cids_)
109 l2cap_app_info_.pL2CA_DisconnectInd_Cb(cid, true);
110 ASSERT_TRUE(test_tcb.eatt == 0);
111 }
112
DisconnectEattDevice(std::vector<uint16_t> cids)113 void DisconnectEattDevice(std::vector<uint16_t> cids) {
114 EXPECT_CALL(l2cap_interface_, DisconnectRequest(_)).Times(cids.size());
115 eatt_instance_->Disconnect(test_address);
116
117 ASSERT_TRUE(test_tcb.eatt == 0);
118 }
119
SetUp()120 void SetUp() override {
121 bluetooth::l2cap::SetMockInterface(&l2cap_interface_);
122 bluetooth::manager::SetMockBtmApiInterface(&btm_api_interface_);
123 bluetooth::manager::SetMockBtifStorageInterface(&btif_storage_interface_);
124 bluetooth::gatt::SetMockGattInterface(&gatt_interface_);
125 controller::SetMockControllerInterface(&controller_interface);
126
127 EXPECT_CALL(l2cap_interface_, RegisterLECoc(BT_PSM_EATT, _, _))
128 .WillOnce(DoAll(SaveArg<1>(&l2cap_app_info_), Return(BT_PSM_EATT)));
129
130 ON_CALL(btif_storage_interface_, LoadBondedEatt).WillByDefault([]() {
131 return;
132 });
133
134 hci_role_ = HCI_ROLE_CENTRAL;
135
136 ON_CALL(l2cap_interface_, GetBleConnRole(_))
137 .WillByDefault(DoAll(Return(hci_role_)));
138
139 ON_CALL(controller_interface, GetAclDataSizeBle())
140 .WillByDefault(Return(128));
141
142 eatt_instance_ = EattExtension::GetInstance();
143 eatt_instance_->Start();
144
145 Test::SetUp();
146 }
147
TearDown()148 void TearDown() override {
149 EXPECT_CALL(l2cap_interface_, DeregisterLECoc(BT_PSM_EATT)).Times(1);
150
151 eatt_instance_->Stop();
152 eatt_instance_ = nullptr;
153 hci_role_ = 0;
154 connected_cids_.clear();
155
156 bluetooth::gatt::SetMockGattInterface(nullptr);
157 bluetooth::l2cap::SetMockInterface(nullptr);
158 bluetooth::manager::SetMockBtifStorageInterface(nullptr);
159 bluetooth::manager::SetMockBtmApiInterface(nullptr);
160 controller::SetMockControllerInterface(nullptr);
161
162 Test::TearDown();
163 }
164
165 bluetooth::manager::MockBtifStorageInterface btif_storage_interface_;
166 bluetooth::manager::MockBtmApiInterface btm_api_interface_;
167 bluetooth::l2cap::MockL2capInterface l2cap_interface_;
168 bluetooth::gatt::MockGattInterface gatt_interface_;
169 controller::MockControllerInterface controller_interface;
170
171 tL2CAP_APPL_INFO l2cap_app_info_;
172 EattExtension* eatt_instance_;
173 std::vector<uint16_t> connected_cids_;
174 uint8_t hci_role_ = HCI_ROLE_CENTRAL;
175 };
176
TEST_F(EattTest,ConnectSucceed)177 TEST_F(EattTest, ConnectSucceed) {
178 ConnectDeviceEattSupported(1);
179 DisconnectEattDevice(connected_cids_);
180 }
181
TEST_F(EattTest,IncomingEattConnectionByUnknownDevice)182 TEST_F(EattTest, IncomingEattConnectionByUnknownDevice) {
183 std::vector<uint16_t> incoming_cids{71, 72, 73, 74, 75};
184
185 EXPECT_CALL(l2cap_interface_,
186 ConnectCreditBasedRsp(test_address, 1, incoming_cids,
187 L2CAP_CONN_NO_RESOURCES, _))
188 .WillOnce(Return(true));
189
190 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
191 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
192 }
193
TEST_F(EattTest,IncomingEattConnectionByKnownDevice)194 TEST_F(EattTest, IncomingEattConnectionByKnownDevice) {
195 hci_role_ = HCI_ROLE_PERIPHERAL;
196 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
197 .WillByDefault(
198 [](const RawAddress& addr,
199 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
200 std::move(cb).Run(addr, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK);
201 return true;
202 });
203 ON_CALL(gatt_interface_, GetEattSupport)
204 .WillByDefault([](const RawAddress& addr) { return true; });
205
206 eatt_instance_->Connect(test_address);
207 std::vector<uint16_t> incoming_cids{71, 72, 73, 74, 75};
208
209 EXPECT_CALL(
210 l2cap_interface_,
211 ConnectCreditBasedRsp(test_address, 1, incoming_cids, L2CAP_CONN_OK, _))
212 .WillOnce(Return(true));
213
214 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
215 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
216
217 DisconnectEattDevice(incoming_cids);
218
219 hci_role_ = HCI_ROLE_CENTRAL;
220 }
221
TEST_F(EattTest,ReconnectInitiatedByRemoteSucceed)222 TEST_F(EattTest, ReconnectInitiatedByRemoteSucceed) {
223 ConnectDeviceEattSupported(1);
224 DisconnectEattDevice(connected_cids_);
225 std::vector<uint16_t> incoming_cids{71, 72, 73, 74, 75};
226
227 EXPECT_CALL(
228 l2cap_interface_,
229 ConnectCreditBasedRsp(test_address, 1, incoming_cids, L2CAP_CONN_OK, _))
230 .WillOnce(Return(true));
231
232 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
233 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
234
235 DisconnectEattDevice(incoming_cids);
236 }
237
TEST_F(EattTest,ConnectSucceedMultipleChannels)238 TEST_F(EattTest, ConnectSucceedMultipleChannels) {
239 ConnectDeviceEattSupported(5);
240 DisconnectEattDevice(connected_cids_);
241 }
242
TEST_F(EattTest,ConnectFailedEattNotSupported)243 TEST_F(EattTest, ConnectFailedEattNotSupported) {
244 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
245 .WillByDefault(
246 [](const RawAddress& addr,
247 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
248 std::move(cb).Run(addr, 0);
249 return true;
250 });
251 ON_CALL(gatt_interface_, GetEattSupport)
252 .WillByDefault([](const RawAddress& addr) { return false; });
253
254 EXPECT_CALL(l2cap_interface_,
255 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
256 .Times(0);
257 eatt_instance_->Connect(test_address);
258 ASSERT_TRUE(eatt_instance_->IsEattSupportedByPeer(test_address) == false);
259 }
260
TEST_F(EattTest,ConnectFailedSlaveOnTheLink)261 TEST_F(EattTest, ConnectFailedSlaveOnTheLink) {
262 EXPECT_CALL(l2cap_interface_,
263 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
264 .Times(0);
265
266 hci_role_ = HCI_ROLE_PERIPHERAL;
267 eatt_instance_->Connect(test_address);
268
269 /* Back to default btm role */
270 hci_role_ = HCI_ROLE_CENTRAL;
271 }
272
TEST_F(EattTest,DisonnectByPeerSucceed)273 TEST_F(EattTest, DisonnectByPeerSucceed) {
274 ConnectDeviceEattSupported(2);
275
276 uint16_t cid = connected_cids_[0];
277 EattChannel* channel =
278 eatt_instance_->FindEattChannelByCid(test_address, cid);
279 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
280
281 DisconnectEattByPeer();
282
283 channel = eatt_instance_->FindEattChannelByCid(test_address, cid);
284 ASSERT_TRUE(channel == nullptr);
285 }
286
TEST_F(EattTest,ReconfigAllSucceed)287 TEST_F(EattTest, ReconfigAllSucceed) {
288 ConnectDeviceEattSupported(3);
289
290 std::vector<uint16_t> cids;
291 EXPECT_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
292 .WillOnce(DoAll(SaveArg<1>(&cids), Return(true)));
293
294 uint16_t new_mtu = 300;
295 eatt_instance_->ReconfigureAll(test_address, new_mtu);
296
297 ASSERT_TRUE(cids.size() == connected_cids_.size());
298
299 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_OK, .mtu = new_mtu};
300
301 for (uint16_t cid : cids) {
302 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cid,
303 true, &cfg);
304
305 EattChannel* channel =
306 eatt_instance_->FindEattChannelByCid(test_address, cid);
307 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
308 ASSERT_TRUE(channel->rx_mtu_ == new_mtu);
309 }
310
311 DisconnectEattDevice(connected_cids_);
312 }
313
TEST_F(EattTest,ReconfigAllFailed)314 TEST_F(EattTest, ReconfigAllFailed) {
315 ConnectDeviceEattSupported(4);
316
317 std::vector<uint16_t> cids;
318 EXPECT_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
319 .WillOnce(DoAll(SaveArg<1>(&cids), Return(true)));
320
321 uint16_t new_mtu = 300;
322 eatt_instance_->ReconfigureAll(test_address, new_mtu);
323
324 ASSERT_TRUE(cids.size() == connected_cids_.size());
325
326 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_FAILED_NO_REASON,
327 .mtu = new_mtu};
328
329 for (uint16_t cid : cids) {
330 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cid,
331 true, &cfg);
332
333 EattChannel* channel =
334 eatt_instance_->FindEattChannelByCid(test_address, cid);
335 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
336 ASSERT_TRUE(channel->rx_mtu_ != new_mtu);
337 }
338
339 DisconnectEattDevice(connected_cids_);
340 }
341
TEST_F(EattTest,ReconfigSingleSucceed)342 TEST_F(EattTest, ReconfigSingleSucceed) {
343 ConnectDeviceEattSupported(2);
344
345 std::vector<uint16_t> cids;
346 EXPECT_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
347 .WillOnce(DoAll(SaveArg<1>(&cids), Return(true)));
348
349 uint16_t new_mtu = 300;
350 eatt_instance_->Reconfigure(test_address, connected_cids_[1], new_mtu);
351
352 ASSERT_TRUE(cids.size() == 1);
353
354 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_OK, .mtu = new_mtu};
355
356 auto it = std::find(connected_cids_.begin(), connected_cids_.end(), cids[0]);
357 ASSERT_TRUE(it != connected_cids_.end());
358
359 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cids[0],
360 true, &cfg);
361 EattChannel* channel =
362 eatt_instance_->FindEattChannelByCid(test_address, cids[0]);
363 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
364 ASSERT_TRUE(channel->rx_mtu_ == new_mtu);
365
366 DisconnectEattDevice(connected_cids_);
367 }
368
TEST_F(EattTest,ReconfigSingleFailed)369 TEST_F(EattTest, ReconfigSingleFailed) {
370 ConnectDeviceEattSupported(2);
371
372 std::vector<uint16_t> cids;
373 EXPECT_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
374 .WillOnce(DoAll(SaveArg<1>(&cids), Return(true)));
375
376 uint16_t new_mtu = 300;
377 eatt_instance_->ReconfigureAll(test_address, new_mtu);
378
379 ASSERT_TRUE(cids.size() == connected_cids_.size());
380
381 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_FAILED_NO_REASON,
382 .mtu = new_mtu};
383
384 auto it = std::find(connected_cids_.begin(), connected_cids_.end(), cids[0]);
385 ASSERT_TRUE(it != connected_cids_.end());
386
387 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cids[0],
388 true, &cfg);
389 EattChannel* channel =
390 eatt_instance_->FindEattChannelByCid(test_address, cids[0]);
391 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
392 ASSERT_TRUE(channel->rx_mtu_ != new_mtu);
393
394 DisconnectEattDevice(connected_cids_);
395 }
396
TEST_F(EattTest,ReconfigPeerSucceed)397 TEST_F(EattTest, ReconfigPeerSucceed) {
398 ConnectDeviceEattSupported(3);
399
400 uint16_t new_mtu = 300;
401 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_OK, .mtu = new_mtu};
402
403 for (uint16_t cid : connected_cids_) {
404 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cid,
405 false, &cfg);
406
407 EattChannel* channel =
408 eatt_instance_->FindEattChannelByCid(test_address, cid);
409 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
410 ASSERT_TRUE(channel->tx_mtu_ == new_mtu);
411 }
412
413 DisconnectEattDevice(connected_cids_);
414 }
415
TEST_F(EattTest,ReconfigPeerFailed)416 TEST_F(EattTest, ReconfigPeerFailed) {
417 ConnectDeviceEattSupported(2);
418
419 uint16_t new_mtu = 300;
420 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_FAILED_NO_REASON,
421 .mtu = new_mtu};
422
423 for (uint16_t cid : connected_cids_) {
424 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cid,
425 false, &cfg);
426
427 EattChannel* channel =
428 eatt_instance_->FindEattChannelByCid(test_address, cid);
429 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
430 ASSERT_TRUE(channel->tx_mtu_ != new_mtu);
431 }
432
433 DisconnectEattDevice(connected_cids_);
434 }
435
TEST_F(EattTest,DoubleDisconnect)436 TEST_F(EattTest, DoubleDisconnect) {
437 ConnectDeviceEattSupported(1);
438 DisconnectEattDevice(connected_cids_);
439
440 /* Force second disconnect */
441 eatt_instance_->Disconnect(test_address);
442 }
443 } // namespace
444