1 /*
2  * Copyright 2017 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 #include <cstring>
17 
18 #include <base/logging.h>
19 
20 #include "mca_api.h"
21 #include "mca_defs.h"
22 #include "mcap_test_mcl.h"
23 
24 namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
25 
McapMcl(btmcap_test_interface_t * mcap_test_interface,tMCA_HANDLE mcap_handle,const RawAddress & peer_bd_addr)26 McapMcl::McapMcl(btmcap_test_interface_t* mcap_test_interface,
27                  tMCA_HANDLE mcap_handle, const RawAddress& peer_bd_addr)
28     : _mdl_list() {
29   _mcap_handle = mcap_handle;
30   _mcap_test_interface = mcap_test_interface;
31   memcpy(_peer_bd_addr.address, peer_bd_addr.address,
32          sizeof(_peer_bd_addr.address));
33 }
34 
Connect(uint16_t ctrl_psm,uint16_t sec_mask)35 bool McapMcl::Connect(uint16_t ctrl_psm, uint16_t sec_mask) {
36   tMCA_RESULT ret = _mcap_test_interface->connect_mcl(
37       _mcap_handle, _peer_bd_addr, ctrl_psm, sec_mask);
38   LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
39   return ret == MCA_SUCCESS;
40 }
41 
Disconnect()42 bool McapMcl::Disconnect() {
43   if (!IsConnected()) {
44     LOG(ERROR) << "MCL is not connected";
45     return false;
46   }
47   tMCA_RESULT ret = _mcap_test_interface->disconnect_mcl(_mcl_handle);
48   LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
49   return ret == MCA_SUCCESS;
50 }
51 
AllocateMdl(tMCA_DEP mdep_handle,uint16_t mdl_id,uint8_t dep_id,uint8_t cfg)52 McapMdl* McapMcl::AllocateMdl(tMCA_DEP mdep_handle, uint16_t mdl_id,
53                               uint8_t dep_id, uint8_t cfg) {
54   if (!IsConnected()) {
55     LOG(ERROR) << "MCL is not connected";
56     return nullptr;
57   }
58   if (FindMdlById(mdl_id) != nullptr) {
59     LOG(ERROR) << "mdl_id=" << mdl_id << "already exists";
60     return nullptr;
61   }
62   if (!HasAvailableMdl()) {
63     LOG(ERROR) << "No more avaible MDL, currently " << _mdl_list.size();
64     return nullptr;
65   }
66   _mdl_list.push_back(McapMdl(_mcap_test_interface, _mcl_handle, mdep_handle,
67                               mdl_id, dep_id, cfg));
68   return &_mdl_list[_mdl_list.size() - 1];
69 }
70 
CreateMdl(tMCA_DEP mdep_handle,uint16_t data_psm,uint16_t mdl_id,uint8_t peer_dep_id,uint8_t cfg,bool should_connect)71 bool McapMcl::CreateMdl(tMCA_DEP mdep_handle, uint16_t data_psm,
72                         uint16_t mdl_id, uint8_t peer_dep_id, uint8_t cfg,
73                         bool should_connect) {
74   if (!IsConnected()) {
75     LOG(ERROR) << "MCL is not connected";
76     return false;
77   }
78   McapMdl* mcap_mdl = FindMdlById(mdl_id);
79   if (!mcap_mdl) {
80     LOG(INFO) << "mdl_id=" << mdl_id << "does not exists, creating new one";
81     mcap_mdl = AllocateMdl(mdep_handle, mdl_id, peer_dep_id, cfg);
82     if (!mcap_mdl) {
83       return false;
84     }
85   }
86   if (mcap_mdl->IsConnected()) {
87     LOG(ERROR) << "mdl_id=" << mdl_id << "is already connected with handle "
88                << (int)mcap_mdl->GetHandle();
89     return false;
90   }
91   return mcap_mdl->Create(data_psm, should_connect);
92 }
93 
DataChannelConfig()94 bool McapMcl::DataChannelConfig() {
95   tMCA_RESULT ret = _mcap_test_interface->data_channel_config(
96       _mcl_handle, get_test_channel_config());
97   LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
98   return ret == MCA_SUCCESS;
99 }
100 
CreateMdlResponse(tMCA_DEP mdep_handle,uint16_t mdl_id,uint8_t my_dep_id,uint8_t cfg)101 bool McapMcl::CreateMdlResponse(tMCA_DEP mdep_handle, uint16_t mdl_id,
102                                 uint8_t my_dep_id, uint8_t cfg) {
103   if (!IsConnected()) {
104     LOG(ERROR) << "MCL is not connected";
105     return false;
106   }
107   McapMdl* mcap_mdl = FindMdlById(mdl_id);
108   if (!mcap_mdl) {
109     LOG(INFO) << "mdl_id=" << mdl_id << " does not exists, creating new one";
110     mcap_mdl = AllocateMdl(mdep_handle, mdl_id, my_dep_id, cfg);
111     if (!mcap_mdl) {
112       LOG(ERROR) << "MDL cannot be created";
113       return false;
114     }
115   }
116   if (mcap_mdl->IsConnected()) {
117     LOG(INFO) << "mdl_id=" << mdl_id << " is already connected with handle "
118               << (int)mcap_mdl->GetHandle() << ", updating context";
119     mcap_mdl->UpdateContext(mdep_handle, my_dep_id, cfg);
120   }
121   return mcap_mdl->CreateResponse();
122 }
123 
AbortMdl()124 bool McapMcl::AbortMdl() {
125   tMCA_RESULT ret = _mcap_test_interface->abort_mdl(_mcl_handle);
126   LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
127   return ret == MCA_SUCCESS;
128 }
129 
DeleteMdl(uint16_t mdl_id)130 bool McapMcl::DeleteMdl(uint16_t mdl_id) {
131   tMCA_RESULT ret = _mcap_test_interface->delete_mdl(_mcl_handle, mdl_id);
132   LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
133   return ret == MCA_SUCCESS;
134 }
135 
GetPeerAddress()136 RawAddress& McapMcl::GetPeerAddress() { return _peer_bd_addr; }
137 
SetHandle(tMCA_CL handle)138 void McapMcl::SetHandle(tMCA_CL handle) { _mcl_handle = handle; }
139 
GetHandle() const140 tMCA_CL McapMcl::GetHandle() const { return _mcl_handle; }
141 
SetMtu(uint16_t mtu)142 void McapMcl::SetMtu(uint16_t mtu) { _control_mtu = mtu; }
143 
GetMtu()144 uint16_t McapMcl::GetMtu() { return _control_mtu; }
145 
FindMdlById(uint16_t mdl_id)146 McapMdl* McapMcl::FindMdlById(uint16_t mdl_id) {
147   for (McapMdl& mdl : _mdl_list) {
148     if (mdl.GetId() == mdl_id) {
149       return &mdl;
150     }
151   }
152   return nullptr;
153 }
154 
FindMdlByHandle(tMCA_DL mdl_handle)155 McapMdl* McapMcl::FindMdlByHandle(tMCA_DL mdl_handle) {
156   for (McapMdl& mdl : _mdl_list) {
157     if (mdl.GetHandle() == mdl_handle) {
158       return &mdl;
159     }
160   }
161   return nullptr;
162 }
163 
RemoveAllMdl()164 void McapMcl::RemoveAllMdl() { _mdl_list.clear(); }
165 
RemoveMdl(uint16_t mdl_id)166 void McapMcl::RemoveMdl(uint16_t mdl_id) {
167   LOG(INFO) << "Removing MDL id " << (int)mdl_id;
168   for (std::vector<McapMdl>::iterator it = _mdl_list.begin();
169        it != _mdl_list.end(); ++it) {
170     if (it->GetId() == mdl_id) {
171       _mdl_list.erase(it);
172       LOG(INFO) << "Removed MDL id " << (int)mdl_id;
173       return;
174     }
175   }
176 }
177 
ResetAllMdl()178 void McapMcl::ResetAllMdl() {
179   for (McapMdl& mcap_mdl : _mdl_list) {
180     mcap_mdl.SetHandle(0);
181     mcap_mdl.SetMtu(0);
182     mcap_mdl.SetResponseCode(-1);
183   }
184 }
185 
ResetMdl(uint16_t mdl_id)186 void McapMcl::ResetMdl(uint16_t mdl_id) {
187   LOG(INFO) << "Closing MDL id " << (int)mdl_id;
188   McapMdl* mcap_mdl = FindMdlById(mdl_id);
189   if (!mcap_mdl) {
190     LOG(ERROR) << "Cannot find MDL for id " << (int)mdl_id;
191     return;
192   }
193   if (mcap_mdl->IsConnected()) {
194     LOG(ERROR) << "MDL " << (int)mdl_id << " is still connected";
195     return;
196   }
197   mcap_mdl->SetHandle(0);
198   mcap_mdl->SetMtu(0);
199   mcap_mdl->SetResponseCode(-1);
200 }
201 
IsConnected()202 bool McapMcl::IsConnected() { return _mcl_handle > 0; }
203 
ConnectedMdlCount()204 int McapMcl::ConnectedMdlCount() {
205   int count = 0;
206   for (McapMdl& mcap_mdl : _mdl_list) {
207     if (mcap_mdl.IsConnected()) {
208       count++;
209     }
210   }
211   return count;
212 }
213 
HasAvailableMdl()214 bool McapMcl::HasAvailableMdl() { return ConnectedMdlCount() < MCA_NUM_MDLS; }
215 
216 }  // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
217