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 <bluetooth/log.h>
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21
22 #include <vector>
23
24 #include "bind_helpers.h"
25 #include "hci/controller_interface_mock.h"
26 #include "l2c_api.h"
27 #include "mock_btif_storage.h"
28 #include "mock_btm_api_layer.h"
29 #include "mock_eatt.h"
30 #include "mock_gatt_layer.h"
31 #include "mock_l2cap_layer.h"
32 #include "stack/include/bt_hdr.h"
33 #include "stack/include/bt_psm_types.h"
34 #include "stack/include/l2cdefs.h"
35 #include "test/mock/mock_main_shim_entry.h"
36 #include "types/raw_address.h"
37
38 using testing::_;
39 using testing::DoAll;
40 using testing::MockFunction;
41 using testing::NiceMock;
42 using testing::NotNull;
43 using testing::Return;
44 using testing::SaveArg;
45 using testing::SaveArgPointee;
46 using testing::StrictMock;
47
48 using bluetooth::eatt::EattChannel;
49 using bluetooth::eatt::EattChannelState;
50 using namespace bluetooth;
51
52 #define BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK 0x01
53
54 /* Needed for testing context */
55 static tGATT_TCB test_tcb;
btif_storage_add_eatt_supported(const RawAddress & addr)56 void btif_storage_add_eatt_supported(const RawAddress& addr) { return; }
gatt_consolidate(const RawAddress & identity_addr,const RawAddress & rpa)57 void gatt_consolidate(const RawAddress& identity_addr, const RawAddress& rpa) {}
gatt_data_process(tGATT_TCB & tcb,uint16_t cid,BT_HDR * p_buf)58 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)59 tGATT_TCB* gatt_find_tcb_by_addr(const RawAddress& bda,
60 tBT_TRANSPORT transport) {
61 log::info("");
62 return &test_tcb;
63 }
64
65 namespace {
66 const RawAddress test_address({0x11, 0x11, 0x11, 0x11, 0x11, 0x11});
67
68 class EattTest : public testing::Test {
69 protected:
ConnectDeviceEattSupported(int num_of_accepted_connections,bool collision=false)70 void ConnectDeviceEattSupported(int num_of_accepted_connections,
71 bool collision = false) {
72 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
73 .WillByDefault(
74 [](const RawAddress& addr,
75 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
76 std::move(cb).Run(addr, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK);
77 return true;
78 });
79 ON_CALL(gatt_interface_, GetEattSupport)
80 .WillByDefault([](const RawAddress& addr) { return true; });
81
82 std::vector<uint16_t> test_local_cids{61, 62, 63, 64, 65};
83 EXPECT_CALL(l2cap_interface_,
84 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
85 .WillOnce(Return(test_local_cids));
86
87 eatt_instance_->Connect(test_address);
88
89 if (collision) {
90 /* Collision should be handled only if all channels has been rejected in
91 * first place.*/
92 if (num_of_accepted_connections == 0) {
93 EXPECT_CALL(l2cap_interface_,
94 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
95 .Times(1);
96 }
97
98 l2cap_app_info_.pL2CA_CreditBasedCollisionInd_Cb(test_address);
99 }
100
101 int i = 0;
102 for (uint16_t cid : test_local_cids) {
103 EattChannel* channel =
104 eatt_instance_->FindEattChannelByCid(test_address, cid);
105 ASSERT_TRUE(channel != nullptr);
106 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_PENDING);
107
108 if (i < num_of_accepted_connections) {
109 l2cap_app_info_.pL2CA_CreditBasedConnectCfm_Cb(
110 test_address, cid, EATT_MIN_MTU_MPS, L2CAP_CONN_OK);
111 connected_cids_.push_back(cid);
112
113 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
114 ASSERT_TRUE(channel->tx_mtu_ == EATT_MIN_MTU_MPS);
115 } else {
116 l2cap_app_info_.pL2CA_Error_Cb(cid, L2CAP_CONN_NO_RESOURCES);
117
118 EattChannel* channel =
119 eatt_instance_->FindEattChannelByCid(test_address, cid);
120 ASSERT_TRUE(channel == nullptr);
121 }
122 i++;
123 }
124
125 ASSERT_TRUE(test_tcb.eatt == num_of_accepted_connections);
126 }
127
ConnectDeviceBothSides(int num_of_accepted_connections,std::vector<uint16_t> & incoming_cids)128 void ConnectDeviceBothSides(int num_of_accepted_connections,
129 std::vector<uint16_t>& incoming_cids) {
130 base::OnceCallback<void(const RawAddress&, uint8_t)> eatt_supp_feat_cb;
131
132 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
133 .WillByDefault(
134 [&eatt_supp_feat_cb](
135 const RawAddress& addr,
136 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
137 eatt_supp_feat_cb = std::move(cb);
138 return true;
139 });
140
141 // Return false to trigger supported features request
142 ON_CALL(gatt_interface_, GetEattSupport)
143 .WillByDefault([](const RawAddress& addr) { return false; });
144
145 std::vector<uint16_t> test_local_cids{61, 62, 63, 64, 65};
146 EXPECT_CALL(l2cap_interface_,
147 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
148 .WillOnce(Return(test_local_cids));
149
150 eatt_instance_->Connect(test_address);
151
152 // Let the remote connect while we are trying to connect
153 EXPECT_CALL(
154 l2cap_interface_,
155 ConnectCreditBasedRsp(test_address, 1, incoming_cids, L2CAP_CONN_OK, _))
156 .WillOnce(Return(true));
157 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
158 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
159
160 // Respond to feature request scheduled by the connect request
161 ASSERT_TRUE(eatt_supp_feat_cb);
162 if (eatt_supp_feat_cb) {
163 std::move(eatt_supp_feat_cb)
164 .Run(test_address, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK);
165 }
166
167 int i = 0;
168 for (uint16_t cid : test_local_cids) {
169 EattChannel* channel =
170 eatt_instance_->FindEattChannelByCid(test_address, cid);
171 ASSERT_TRUE(channel != nullptr);
172 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_PENDING);
173
174 if (i < num_of_accepted_connections) {
175 l2cap_app_info_.pL2CA_CreditBasedConnectCfm_Cb(
176 test_address, cid, EATT_MIN_MTU_MPS, L2CAP_CONN_OK);
177 connected_cids_.push_back(cid);
178
179 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
180 ASSERT_TRUE(channel->tx_mtu_ == EATT_MIN_MTU_MPS);
181 } else {
182 l2cap_app_info_.pL2CA_Error_Cb(cid, L2CAP_CONN_NO_RESOURCES);
183
184 EattChannel* channel =
185 eatt_instance_->FindEattChannelByCid(test_address, cid);
186 ASSERT_TRUE(channel == nullptr);
187 }
188 i++;
189 }
190
191 // Check the incoming CIDs as well
192 for (auto cid : incoming_cids) {
193 EattChannel* channel =
194 eatt_instance_->FindEattChannelByCid(test_address, cid);
195 ASSERT_NE(nullptr, channel);
196 ASSERT_EQ(channel->state_, EattChannelState::EATT_CHANNEL_OPENED);
197 ASSERT_TRUE(channel->tx_mtu_ == EATT_MIN_MTU_MPS);
198 }
199
200 ASSERT_EQ(test_tcb.eatt,
201 num_of_accepted_connections + incoming_cids.size());
202 }
203
DisconnectEattByPeer(void)204 void DisconnectEattByPeer(void) {
205 for (uint16_t cid : connected_cids_)
206 l2cap_app_info_.pL2CA_DisconnectInd_Cb(cid, true);
207 ASSERT_TRUE(test_tcb.eatt == 0);
208 }
209
DisconnectEattDevice(std::vector<uint16_t> cids)210 void DisconnectEattDevice(std::vector<uint16_t> cids) {
211 EXPECT_CALL(l2cap_interface_, DisconnectRequest(_)).Times(cids.size());
212 eatt_instance_->Disconnect(test_address);
213
214 ASSERT_TRUE(test_tcb.eatt == 0);
215 }
216
SetUp()217 void SetUp() override {
218 le_buffer_size_.le_data_packet_length_ = 128;
219 le_buffer_size_.total_num_le_packets_ = 24;
220 ON_CALL(controller_, GetLeBufferSize)
221 .WillByDefault(Return(le_buffer_size_));
222 bluetooth::l2cap::SetMockInterface(&l2cap_interface_);
223 bluetooth::manager::SetMockBtmApiInterface(&btm_api_interface_);
224 bluetooth::manager::SetMockBtifStorageInterface(&btif_storage_interface_);
225 bluetooth::gatt::SetMockGattInterface(&gatt_interface_);
226 bluetooth::hci::testing::mock_controller_ = &controller_;
227
228 // Clear the static memory for each test case
229 memset(&test_tcb, 0, sizeof(test_tcb));
230
231 EXPECT_CALL(l2cap_interface_, RegisterLECoc(BT_PSM_EATT, _, _))
232 .WillOnce(DoAll(SaveArg<1>(&l2cap_app_info_), Return(BT_PSM_EATT)));
233
234 ON_CALL(btif_storage_interface_, LoadBondedEatt).WillByDefault([]() {
235 return;
236 });
237
238 hci_role_ = HCI_ROLE_CENTRAL;
239
240 ON_CALL(l2cap_interface_, GetBleConnRole(_))
241 .WillByDefault(DoAll(Return(hci_role_)));
242
243 eatt_instance_ = EattExtension::GetInstance();
244 eatt_instance_->Start();
245
246 Test::SetUp();
247 }
248
TearDown()249 void TearDown() override {
250 EXPECT_CALL(l2cap_interface_, DeregisterLECoc(BT_PSM_EATT)).Times(1);
251
252 eatt_instance_->Stop();
253 eatt_instance_ = nullptr;
254 hci_role_ = 0;
255 connected_cids_.clear();
256
257 bluetooth::gatt::SetMockGattInterface(nullptr);
258 bluetooth::l2cap::SetMockInterface(nullptr);
259 bluetooth::manager::SetMockBtifStorageInterface(nullptr);
260 bluetooth::manager::SetMockBtmApiInterface(nullptr);
261 bluetooth::hci::testing::mock_controller_ = nullptr;
262
263 Test::TearDown();
264 }
265
266 bluetooth::manager::MockBtifStorageInterface btif_storage_interface_;
267 bluetooth::manager::MockBtmApiInterface btm_api_interface_;
268 bluetooth::l2cap::MockL2capInterface l2cap_interface_;
269 bluetooth::gatt::MockGattInterface gatt_interface_;
270 bluetooth::hci::testing::MockControllerInterface controller_;
271 bluetooth::hci::LeBufferSize le_buffer_size_;
272
273 tL2CAP_APPL_INFO l2cap_app_info_;
274 EattExtension* eatt_instance_;
275 std::vector<uint16_t> connected_cids_;
276 uint8_t hci_role_ = HCI_ROLE_CENTRAL;
277 };
278
TEST_F(EattTest,ConnectSucceed)279 TEST_F(EattTest, ConnectSucceed) {
280 ConnectDeviceEattSupported(1);
281 DisconnectEattDevice(connected_cids_);
282 }
283
TEST_F(EattTest,IncomingEattConnectionByUnknownDevice)284 TEST_F(EattTest, IncomingEattConnectionByUnknownDevice) {
285 std::vector<uint16_t> incoming_cids{71, 72, 73, 74, 75};
286
287 ON_CALL(btm_api_interface_, IsEncrypted)
288 .WillByDefault(
289 [](const RawAddress& addr, tBT_TRANSPORT transport) { return true; });
290 EXPECT_CALL(
291 l2cap_interface_,
292 ConnectCreditBasedRsp(test_address, 1, incoming_cids, L2CAP_CONN_OK, _))
293 .WillOnce(Return(true));
294
295 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
296 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
297
298 DisconnectEattDevice(incoming_cids);
299 }
300
TEST_F(EattTest,IncomingEattConnectionByKnownDevice)301 TEST_F(EattTest, IncomingEattConnectionByKnownDevice) {
302 hci_role_ = HCI_ROLE_PERIPHERAL;
303 ON_CALL(btm_api_interface_, IsEncrypted)
304 .WillByDefault(
305 [](const RawAddress& addr, tBT_TRANSPORT transport) { return true; });
306 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
307 .WillByDefault(
308 [](const RawAddress& addr,
309 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
310 std::move(cb).Run(addr, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK);
311 return true;
312 });
313 ON_CALL(gatt_interface_, GetEattSupport)
314 .WillByDefault([](const RawAddress& addr) { return true; });
315
316 eatt_instance_->Connect(test_address);
317 std::vector<uint16_t> incoming_cids{71, 72, 73, 74, 75};
318
319 EXPECT_CALL(
320 l2cap_interface_,
321 ConnectCreditBasedRsp(test_address, 1, incoming_cids, L2CAP_CONN_OK, _))
322 .WillOnce(Return(true));
323
324 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
325 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
326
327 DisconnectEattDevice(incoming_cids);
328
329 hci_role_ = HCI_ROLE_CENTRAL;
330 }
331
TEST_F(EattTest,IncomingEattConnectionByKnownDeviceEncryptionOff)332 TEST_F(EattTest, IncomingEattConnectionByKnownDeviceEncryptionOff) {
333 hci_role_ = HCI_ROLE_PERIPHERAL;
334 ON_CALL(btm_api_interface_, IsEncrypted)
335 .WillByDefault([](const RawAddress& addr, tBT_TRANSPORT transport) {
336 return false;
337 });
338 ON_CALL(btm_api_interface_, IsLinkKeyKnown)
339 .WillByDefault(
340 [](const RawAddress& addr, tBT_TRANSPORT transport) { return true; });
341 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
342 .WillByDefault(
343 [](const RawAddress& addr,
344 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
345 std::move(cb).Run(addr, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK);
346 return true;
347 });
348 ON_CALL(gatt_interface_, GetEattSupport)
349 .WillByDefault([](const RawAddress& addr) { return true; });
350
351 eatt_instance_->Connect(test_address);
352 std::vector<uint16_t> incoming_cids{71, 72, 73, 74, 75};
353
354 EXPECT_CALL(l2cap_interface_,
355 ConnectCreditBasedRsp(test_address, 1, _,
356 L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP, _))
357 .WillOnce(Return(true));
358
359 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
360 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
361
362 hci_role_ = HCI_ROLE_CENTRAL;
363 }
364
TEST_F(EattTest,IncomingEattConnectionByUnknownDeviceEncryptionOff)365 TEST_F(EattTest, IncomingEattConnectionByUnknownDeviceEncryptionOff) {
366 std::vector<uint16_t> incoming_cids{71, 72, 73, 74, 75};
367
368 ON_CALL(btm_api_interface_, IsEncrypted)
369 .WillByDefault([](const RawAddress& addr, tBT_TRANSPORT transport) {
370 return false;
371 });
372 ON_CALL(btm_api_interface_, IsLinkKeyKnown)
373 .WillByDefault([](const RawAddress& addr, tBT_TRANSPORT transport) {
374 return false;
375 });
376 EXPECT_CALL(
377 l2cap_interface_,
378 ConnectCreditBasedRsp(test_address, 1, _,
379 L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION, _))
380 .WillOnce(Return(true));
381
382 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
383 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
384 }
385
TEST_F(EattTest,ReconnectInitiatedByRemoteSucceed)386 TEST_F(EattTest, ReconnectInitiatedByRemoteSucceed) {
387 ConnectDeviceEattSupported(1);
388 DisconnectEattDevice(connected_cids_);
389 std::vector<uint16_t> incoming_cids{71, 72, 73, 74, 75};
390
391 ON_CALL(btm_api_interface_, IsEncrypted)
392 .WillByDefault(
393 [](const RawAddress& addr, tBT_TRANSPORT transport) { return true; });
394
395 EXPECT_CALL(
396 l2cap_interface_,
397 ConnectCreditBasedRsp(test_address, 1, incoming_cids, L2CAP_CONN_OK, _))
398 .WillOnce(Return(true));
399
400 l2cap_app_info_.pL2CA_CreditBasedConnectInd_Cb(
401 test_address, incoming_cids, BT_PSM_EATT, EATT_MIN_MTU_MPS, 1);
402
403 DisconnectEattDevice(incoming_cids);
404 }
405
TEST_F(EattTest,ConnectInitiatedWhenRemoteConnects)406 TEST_F(EattTest, ConnectInitiatedWhenRemoteConnects) {
407 ON_CALL(btm_api_interface_, IsEncrypted)
408 .WillByDefault(
409 [](const RawAddress& addr, tBT_TRANSPORT transport) { return true; });
410
411 std::vector<uint16_t> incoming_cids{71, 72, 73, 74};
412 ConnectDeviceBothSides(1, incoming_cids);
413
414 std::vector<uint16_t> disconnecting_cids;
415 disconnecting_cids.insert(disconnecting_cids.end(), incoming_cids.begin(),
416 incoming_cids.end());
417 disconnecting_cids.insert(disconnecting_cids.end(), connected_cids_.begin(),
418 connected_cids_.end());
419 DisconnectEattDevice(disconnecting_cids);
420 }
421
TEST_F(EattTest,ConnectSucceedMultipleChannels)422 TEST_F(EattTest, ConnectSucceedMultipleChannels) {
423 ConnectDeviceEattSupported(5);
424 DisconnectEattDevice(connected_cids_);
425 }
426
TEST_F(EattTest,ConnectFailedEattNotSupported)427 TEST_F(EattTest, ConnectFailedEattNotSupported) {
428 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
429 .WillByDefault(
430 [](const RawAddress& addr,
431 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
432 std::move(cb).Run(addr, 0);
433 return true;
434 });
435 ON_CALL(gatt_interface_, GetEattSupport)
436 .WillByDefault([](const RawAddress& addr) { return false; });
437
438 EXPECT_CALL(l2cap_interface_,
439 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
440 .Times(0);
441 eatt_instance_->Connect(test_address);
442 ASSERT_TRUE(eatt_instance_->IsEattSupportedByPeer(test_address) == false);
443 }
444
TEST_F(EattTest,ConnectFailedSlaveOnTheLink)445 TEST_F(EattTest, ConnectFailedSlaveOnTheLink) {
446 EXPECT_CALL(l2cap_interface_,
447 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
448 .Times(0);
449
450 hci_role_ = HCI_ROLE_PERIPHERAL;
451 eatt_instance_->Connect(test_address);
452
453 /* Back to default btm role */
454 hci_role_ = HCI_ROLE_CENTRAL;
455 }
456
TEST_F(EattTest,DisonnectByPeerSucceed)457 TEST_F(EattTest, DisonnectByPeerSucceed) {
458 ConnectDeviceEattSupported(2);
459
460 uint16_t cid = connected_cids_[0];
461 EattChannel* channel =
462 eatt_instance_->FindEattChannelByCid(test_address, cid);
463 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
464
465 DisconnectEattByPeer();
466
467 channel = eatt_instance_->FindEattChannelByCid(test_address, cid);
468 ASSERT_TRUE(channel == nullptr);
469 }
470
TEST_F(EattTest,ReconfigAllSucceed)471 TEST_F(EattTest, ReconfigAllSucceed) {
472 ConnectDeviceEattSupported(3);
473
474 std::vector<uint16_t> cids;
475 EXPECT_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
476 .WillOnce(DoAll(SaveArg<1>(&cids), Return(true)));
477
478 uint16_t new_mtu = 300;
479 eatt_instance_->ReconfigureAll(test_address, new_mtu);
480
481 ASSERT_TRUE(cids.size() == connected_cids_.size());
482
483 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_OK, .mtu = new_mtu};
484
485 for (uint16_t cid : cids) {
486 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cid,
487 true, &cfg);
488
489 EattChannel* channel =
490 eatt_instance_->FindEattChannelByCid(test_address, cid);
491 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
492 ASSERT_TRUE(channel->rx_mtu_ == new_mtu);
493 }
494
495 DisconnectEattDevice(connected_cids_);
496 }
497
TEST_F(EattTest,ReconfigAllFailed)498 TEST_F(EattTest, ReconfigAllFailed) {
499 ConnectDeviceEattSupported(4);
500
501 std::vector<uint16_t> cids;
502 EXPECT_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
503 .WillOnce(DoAll(SaveArg<1>(&cids), Return(true)));
504
505 uint16_t new_mtu = 300;
506 eatt_instance_->ReconfigureAll(test_address, new_mtu);
507
508 ASSERT_TRUE(cids.size() == connected_cids_.size());
509
510 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_FAILED_NO_REASON,
511 .mtu = new_mtu};
512
513 for (uint16_t cid : cids) {
514 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cid,
515 true, &cfg);
516
517 EattChannel* channel =
518 eatt_instance_->FindEattChannelByCid(test_address, cid);
519 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
520 ASSERT_TRUE(channel->rx_mtu_ != new_mtu);
521 }
522
523 DisconnectEattDevice(connected_cids_);
524 }
525
TEST_F(EattTest,ReconfigSingleSucceed)526 TEST_F(EattTest, ReconfigSingleSucceed) {
527 ConnectDeviceEattSupported(2);
528
529 std::vector<uint16_t> cids;
530 EXPECT_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
531 .WillOnce(DoAll(SaveArg<1>(&cids), Return(true)));
532
533 uint16_t new_mtu = 300;
534 eatt_instance_->Reconfigure(test_address, connected_cids_[1], new_mtu);
535
536 ASSERT_TRUE(cids.size() == 1);
537
538 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_OK, .mtu = new_mtu};
539
540 auto it = std::find(connected_cids_.begin(), connected_cids_.end(), cids[0]);
541 ASSERT_TRUE(it != connected_cids_.end());
542
543 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cids[0],
544 true, &cfg);
545 EattChannel* channel =
546 eatt_instance_->FindEattChannelByCid(test_address, cids[0]);
547 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
548 ASSERT_TRUE(channel->rx_mtu_ == new_mtu);
549
550 DisconnectEattDevice(connected_cids_);
551 }
552
TEST_F(EattTest,ReconfigSingleFailed)553 TEST_F(EattTest, ReconfigSingleFailed) {
554 ConnectDeviceEattSupported(2);
555
556 std::vector<uint16_t> cids;
557 EXPECT_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
558 .WillOnce(DoAll(SaveArg<1>(&cids), Return(true)));
559
560 uint16_t new_mtu = 300;
561 eatt_instance_->ReconfigureAll(test_address, new_mtu);
562
563 ASSERT_TRUE(cids.size() == connected_cids_.size());
564
565 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_FAILED_NO_REASON,
566 .mtu = new_mtu};
567
568 auto it = std::find(connected_cids_.begin(), connected_cids_.end(), cids[0]);
569 ASSERT_TRUE(it != connected_cids_.end());
570
571 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cids[0],
572 true, &cfg);
573 EattChannel* channel =
574 eatt_instance_->FindEattChannelByCid(test_address, cids[0]);
575 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
576 ASSERT_TRUE(channel->rx_mtu_ != new_mtu);
577
578 DisconnectEattDevice(connected_cids_);
579 }
580
TEST_F(EattTest,ReconfigPeerSucceed)581 TEST_F(EattTest, ReconfigPeerSucceed) {
582 ConnectDeviceEattSupported(3);
583
584 uint16_t new_mtu = 300;
585 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_OK, .mtu = new_mtu};
586
587 for (uint16_t cid : connected_cids_) {
588 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cid,
589 false, &cfg);
590
591 EattChannel* channel =
592 eatt_instance_->FindEattChannelByCid(test_address, cid);
593 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
594 ASSERT_TRUE(channel->tx_mtu_ == new_mtu);
595 }
596
597 DisconnectEattDevice(connected_cids_);
598 }
599
TEST_F(EattTest,ReconfigPeerFailed)600 TEST_F(EattTest, ReconfigPeerFailed) {
601 ConnectDeviceEattSupported(2);
602
603 uint16_t new_mtu = 300;
604 tL2CAP_LE_CFG_INFO cfg = {.result = L2CAP_CFG_FAILED_NO_REASON,
605 .mtu = new_mtu};
606
607 for (uint16_t cid : connected_cids_) {
608 l2cap_app_info_.pL2CA_CreditBasedReconfigCompleted_Cb(test_address, cid,
609 false, &cfg);
610
611 EattChannel* channel =
612 eatt_instance_->FindEattChannelByCid(test_address, cid);
613 ASSERT_TRUE(channel->state_ == EattChannelState::EATT_CHANNEL_OPENED);
614 ASSERT_TRUE(channel->tx_mtu_ != new_mtu);
615 }
616
617 DisconnectEattDevice(connected_cids_);
618 }
619
TEST_F(EattTest,DoubleDisconnect)620 TEST_F(EattTest, DoubleDisconnect) {
621 ConnectDeviceEattSupported(1);
622 DisconnectEattDevice(connected_cids_);
623
624 /* Force second disconnect */
625 eatt_instance_->Disconnect(test_address);
626 }
627
TEST_F(EattTest,TestCollisionHandling)628 TEST_F(EattTest, TestCollisionHandling) {
629 ConnectDeviceEattSupported(0, true /* collision*/);
630 ConnectDeviceEattSupported(5, true /* collision*/);
631 }
632
TEST_F(EattTest,ChannelUnavailableWhileOpening)633 TEST_F(EattTest, ChannelUnavailableWhileOpening) {
634 // arrange
635 ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
636 .WillByDefault(
637 [](const RawAddress& addr,
638 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
639 std::move(cb).Run(addr, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK);
640 return true;
641 });
642 ON_CALL(gatt_interface_, GetEattSupport).WillByDefault(Return(true));
643
644 // expect
645 EXPECT_CALL(l2cap_interface_,
646 ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
647 .WillOnce(Return(std::vector<uint16_t>{61}));
648
649 // act: start
650 eatt_instance_->Connect(test_address);
651 auto available_channel_for_request =
652 eatt_instance_->GetChannelAvailableForClientRequest(test_address);
653 auto available_channel_for_indication =
654 eatt_instance_->GetChannelAvailableForIndication(test_address);
655
656 // assert
657 ASSERT_EQ(available_channel_for_request, nullptr);
658 ASSERT_EQ(available_channel_for_indication, nullptr);
659 }
660
TEST_F(EattTest,ChannelUnavailableWhileReconfiguring)661 TEST_F(EattTest, ChannelUnavailableWhileReconfiguring) {
662 // arrange
663 ON_CALL(l2cap_interface_, ReconfigCreditBasedConnsReq(_, _, _))
664 .WillByDefault(Return(true));
665 ConnectDeviceEattSupported(/* num_of_accepted_connections = */ 1);
666
667 // act: reconfigure, then get available channels
668 eatt_instance_->Reconfigure(test_address, connected_cids_[0], 300);
669 auto available_channel_for_request =
670 eatt_instance_->GetChannelAvailableForClientRequest(test_address);
671 auto available_channel_for_indication =
672 eatt_instance_->GetChannelAvailableForIndication(test_address);
673
674 // assert
675 ASSERT_EQ(available_channel_for_request, nullptr);
676 ASSERT_EQ(available_channel_for_indication, nullptr);
677 }
678
679 } // namespace
680