1 /*
2 * Copyright (C) 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