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