1/******************************************************************************
2 *
3 *  Copyright (C) 2009-2012 Broadcom Corporation
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
19/******************************************************************************
20 *
21 *  This is the API implementation file for the Multi-Channel Adaptation
22 *  Protocol (MCAP).
23 *
24 ******************************************************************************/
25#include <base/logging.h>
26#include <string.h>
27
28#include "bt_target.h"
29#include "btm_api.h"
30#include "btm_int.h"
31#include "mca_api.h"
32#include "mca_defs.h"
33#include "mca_int.h"
34
35#include "btu.h"
36
37/*******************************************************************************
38 *
39 * Function         mca_process_timeout
40 *
41 * Description      This function is called by BTU when an MCA timer
42 *                  expires.
43 *
44 *                  This function is for use internal to the stack only.
45 *
46 * Returns          void
47 *
48 ******************************************************************************/
49void mca_ccb_timer_timeout(void* data) {
50  tMCA_CCB* p_ccb = (tMCA_CCB*)data;
51
52  mca_ccb_event(p_ccb, MCA_CCB_RSP_TOUT_EVT, NULL);
53}
54
55/*******************************************************************************
56 *
57 * Function         MCA_Init
58 *
59 * Description      Initialize MCAP main control block.
60 *                  This function is called at stack start up.
61 *
62 * Returns          void
63 *
64 ******************************************************************************/
65void MCA_Init(void) {
66  memset(&mca_cb, 0, sizeof(tMCA_CB));
67
68#if defined(MCA_INITIAL_TRACE_LEVEL)
69  mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL;
70#else
71  mca_cb.trace_level = BT_TRACE_LEVEL_NONE;
72#endif
73}
74
75/*******************************************************************************
76 *
77 * Function         MCA_SetTraceLevel
78 *
79 * Description      This function sets the debug trace level for MCA.
80 *                  If 0xff is passed, the current trace level is returned.
81 *
82 *                  Input Parameters:
83 *                      level:  The level to set the MCA tracing to:
84 *                      0xff-returns the current setting.
85 *                      0-turns off tracing.
86 *                      >= 1-Errors.
87 *                      >= 2-Warnings.
88 *                      >= 3-APIs.
89 *                      >= 4-Events.
90 *                      >= 5-Debug.
91 *
92 * Returns          The new trace level or current trace level if
93 *                  the input parameter is 0xff.
94 *
95 ******************************************************************************/
96uint8_t MCA_SetTraceLevel(uint8_t level) {
97  if (level != 0xFF) mca_cb.trace_level = level;
98
99  return (mca_cb.trace_level);
100}
101
102/*******************************************************************************
103 *
104 * Function         MCA_Register
105 *
106 * Description      This function registers an MCAP implementation.
107 *                  It is assumed that the control channel PSM and data channel
108 *                  PSM are not used by any other instances of the stack.
109 *                  If the given p_reg->ctrl_psm is 0, this handle is INT only.
110 *
111 * Returns          0, if failed. Otherwise, the MCA handle.
112 *
113 ******************************************************************************/
114tMCA_HANDLE MCA_Register(tMCA_REG* p_reg, tMCA_CTRL_CBACK* p_cback) {
115  tMCA_RCB* p_rcb;
116  tMCA_HANDLE handle = 0;
117  tL2CAP_APPL_INFO l2c_cacp_appl;
118  tL2CAP_APPL_INFO l2c_dacp_appl;
119
120  CHECK(p_reg != NULL);
121  CHECK(p_cback != NULL);
122
123  MCA_TRACE_API("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm,
124                p_reg->data_psm);
125
126  p_rcb = mca_rcb_alloc(p_reg);
127  if (p_rcb != NULL) {
128    if (p_reg->ctrl_psm) {
129      if (L2C_INVALID_PSM(p_reg->ctrl_psm) ||
130          L2C_INVALID_PSM(p_reg->data_psm)) {
131        MCA_TRACE_ERROR("INVALID_PSM");
132        return 0;
133      }
134
135      l2c_cacp_appl = *(tL2CAP_APPL_INFO*)&mca_l2c_int_appl;
136      l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL;
137      l2c_dacp_appl = *(tL2CAP_APPL_INFO*)&l2c_cacp_appl;
138      l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback;
139      l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback;
140      if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO*)&l2c_cacp_appl) &&
141          L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO*)&l2c_dacp_appl)) {
142        /* set security level */
143        BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_CTRL,
144                             p_reg->sec_mask, p_reg->ctrl_psm,
145                             BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
146
147        /* in theory, we do not need this one for data_psm
148         * If we don't, L2CAP rejects with security block (3),
149         * which is different reject code from what MCAP spec suggests.
150         * we set this one, so mca_l2c_dconn_ind_cback can reject /w no
151         * resources (4) */
152        BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_DATA,
153                             p_reg->sec_mask, p_reg->data_psm,
154                             BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
155      } else {
156        MCA_TRACE_ERROR("Failed to register to L2CAP");
157        return 0;
158      }
159    } else
160      p_rcb->reg.data_psm = 0;
161    handle = mca_rcb_to_handle(p_rcb);
162    p_rcb->p_cback = p_cback;
163    p_rcb->reg.rsp_tout = p_reg->rsp_tout;
164  }
165  return handle;
166}
167
168/*******************************************************************************
169 *
170 * Function         MCA_Deregister
171 *
172 * Description      Deregister an MCAP implementation.  Before this function can
173 *                  be called, all control and data channels must be removed
174 *                  with MCA_DisconnectReq and MCA_CloseReq.
175 *
176 * Returns          void
177 *
178 ******************************************************************************/
179void MCA_Deregister(tMCA_HANDLE handle) {
180  tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
181
182  MCA_TRACE_API("MCA_Deregister: %d", handle);
183  if (p_rcb && p_rcb->reg.ctrl_psm) {
184    L2CA_Deregister(p_rcb->reg.ctrl_psm);
185    L2CA_Deregister(p_rcb->reg.data_psm);
186    btm_sec_clr_service_by_psm(p_rcb->reg.ctrl_psm);
187    btm_sec_clr_service_by_psm(p_rcb->reg.data_psm);
188  }
189  mca_rcb_dealloc(handle);
190}
191
192/*******************************************************************************
193 *
194 * Function         MCA_CreateDep
195 *
196 * Description      Create a data endpoint. If the MDEP is created successfully,
197 *                  the MDEP ID is returned in *p_dep. After a data endpoint is
198 *                  created, an application can initiate a connection between
199 *                  this endpoint and an endpoint on a peer device.
200 *
201 * Returns          MCA_SUCCESS if successful, otherwise error.
202 *
203 ******************************************************************************/
204tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP* p_dep, tMCA_CS* p_cs) {
205  tMCA_RESULT result = MCA_BAD_HANDLE;
206  int i;
207  tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
208  tMCA_CS* p_depcs;
209
210  CHECK(p_dep != NULL);
211  CHECK(p_cs != NULL);
212  CHECK(p_cs->p_data_cback != NULL);
213
214  MCA_TRACE_API("MCA_CreateDep: %d", handle);
215  if (p_rcb) {
216    if (p_cs->max_mdl > MCA_NUM_MDLS) {
217      MCA_TRACE_ERROR("max_mdl: %d is too big", p_cs->max_mdl);
218      result = MCA_BAD_PARAMS;
219    } else {
220      p_depcs = p_rcb->dep;
221      if (p_cs->type == MCA_TDEP_ECHO) {
222        if (p_depcs->p_data_cback) {
223          MCA_TRACE_ERROR("Already has ECHO MDEP");
224          return MCA_NO_RESOURCES;
225        }
226        memcpy(p_depcs, p_cs, sizeof(tMCA_CS));
227        *p_dep = 0;
228        result = MCA_SUCCESS;
229      } else {
230        result = MCA_NO_RESOURCES;
231        /* non-echo MDEP starts from 1 */
232        p_depcs++;
233        for (i = 1; i < MCA_NUM_DEPS; i++, p_depcs++) {
234          if (p_depcs->p_data_cback == NULL) {
235            memcpy(p_depcs, p_cs, sizeof(tMCA_CS));
236            /* internally use type as the mdep id */
237            p_depcs->type = i;
238            *p_dep = i;
239            result = MCA_SUCCESS;
240            break;
241          }
242        }
243      }
244    }
245  }
246  return result;
247}
248
249/*******************************************************************************
250 *
251 * Function         MCA_DeleteDep
252 *
253 * Description      Delete a data endpoint.  This function is called when
254 *                  the implementation is no longer using a data endpoint.
255 *                  If this function is called when the endpoint is connected
256 *                  the connection is closed and the data endpoint
257 *                  is removed.
258 *
259 * Returns          MCA_SUCCESS if successful, otherwise error.
260 *
261 ******************************************************************************/
262tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep) {
263  tMCA_RESULT result = MCA_BAD_HANDLE;
264  tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
265  tMCA_DCB* p_dcb;
266  int i, max;
267  tMCA_CS* p_depcs;
268
269  MCA_TRACE_API("MCA_DeleteDep: %d dep:%d", handle, dep);
270  if (p_rcb) {
271    if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) {
272      result = MCA_SUCCESS;
273      p_rcb->dep[dep].p_data_cback = NULL;
274      p_depcs = &(p_rcb->dep[dep]);
275      i = handle - 1;
276      max = MCA_NUM_MDLS * MCA_NUM_LINKS;
277      p_dcb = &mca_cb.dcb[i * max];
278      /* make sure no MDL exists for this MDEP */
279      for (i = 0; i < max; i++, p_dcb++) {
280        if (p_dcb->state && p_dcb->p_cs == p_depcs) {
281          mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
282        }
283      }
284    }
285  }
286  return result;
287}
288
289/*******************************************************************************
290 *
291 * Function         MCA_ConnectReq
292 *
293 * Description      This function initiates an MCAP control channel connection
294 *                  to the peer device.  When the connection is completed, an
295 *                  MCA_CONNECT_IND_EVT is reported to the application via its
296 *                  control callback function.
297 *                  This control channel is identified by the tMCA_CL.
298 *                  If the connection attempt fails, an MCA_DISCONNECT_IND_EVT
299 *                  is reported. The security mask parameter overrides the
300 *                  outgoing security mask set in MCA_Register().
301 *
302 * Returns          MCA_SUCCESS if successful, otherwise error.
303 *
304 ******************************************************************************/
305tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, const RawAddress& bd_addr,
306                           uint16_t ctrl_psm, uint16_t sec_mask) {
307  tMCA_RESULT result = MCA_BAD_HANDLE;
308  tMCA_CCB* p_ccb;
309  tMCA_TC_TBL* p_tbl;
310
311  MCA_TRACE_API("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm);
312  p_ccb = mca_ccb_by_bd(handle, bd_addr);
313  if (p_ccb == NULL)
314    p_ccb = mca_ccb_alloc(handle, bd_addr);
315  else {
316    MCA_TRACE_ERROR("control channel already exists");
317    return MCA_BUSY;
318  }
319
320  if (p_ccb) {
321    p_ccb->ctrl_vpsm =
322        L2CA_Register(ctrl_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
323    result = MCA_NO_RESOURCES;
324    if (p_ccb->ctrl_vpsm) {
325      BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask,
326                           p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
327      p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL);
328      if (p_ccb->lcid) {
329        p_tbl = mca_tc_tbl_calloc(p_ccb);
330        if (p_tbl) {
331          p_tbl->state = MCA_TC_ST_CONN;
332          p_ccb->sec_mask = sec_mask;
333          result = MCA_SUCCESS;
334        }
335      }
336    }
337    if (result != MCA_SUCCESS) mca_ccb_dealloc(p_ccb, NULL);
338  }
339  return result;
340}
341
342/*******************************************************************************
343 *
344 * Function         MCA_DisconnectReq
345 *
346 * Description      This function disconnect an MCAP control channel
347 *                  to the peer device.
348 *                  If associated data channel exists, they are disconnected.
349 *                  When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
350 *                  reported to the application via its control callback
351 *                  function.
352 *
353 * Returns          MCA_SUCCESS if successful, otherwise error.
354 *
355 ******************************************************************************/
356tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl) {
357  tMCA_RESULT result = MCA_BAD_HANDLE;
358  tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
359
360  MCA_TRACE_API("MCA_DisconnectReq: %d ", mcl);
361  if (p_ccb) {
362    result = MCA_SUCCESS;
363    mca_ccb_event(p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
364  }
365  return result;
366}
367
368/*******************************************************************************
369 *
370 * Function         MCA_CreateMdl
371 *
372 * Description      This function sends a CREATE_MDL request to the peer device.
373 *                  When the response is received, a MCA_CREATE_CFM_EVT is
374 *                  reported with the given MDL ID.
375 *                  If the response is successful, a data channel is open
376 *                  with the given p_chnl_cfg
377 *                  If p_chnl_cfg is NULL, the data channel is not initiated
378 *                  until MCA_DataChnlCfg is called to provide the p_chnl_cfg.
379 *                  When the data channel is open successfully, a
380 *                  MCA_OPEN_CFM_EVT is reported. This data channel is
381 *                  identified as tMCA_DL.
382 *
383 * Returns          MCA_SUCCESS if successful, otherwise error.
384 *
385 ******************************************************************************/
386tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
387                          uint16_t mdl_id, uint8_t peer_dep_id, uint8_t cfg,
388                          const tMCA_CHNL_CFG* p_chnl_cfg) {
389  tMCA_RESULT result = MCA_BAD_HANDLE;
390  tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
391  tMCA_DCB* p_dcb;
392
393  MCA_TRACE_API("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep,
394                mdl_id, peer_dep_id);
395  if (p_ccb) {
396    if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) {
397      MCA_TRACE_ERROR("pending req");
398      return MCA_BUSY;
399    }
400
401    if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id))) {
402      MCA_TRACE_ERROR("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id,
403                      mdl_id);
404      return MCA_BAD_PARAMS;
405    }
406
407    if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) {
408      MCA_TRACE_ERROR("mdl id: %d is used in the control link", mdl_id);
409      return MCA_BAD_MDL_ID;
410    }
411
412    p_dcb = mca_dcb_alloc(p_ccb, dep);
413    result = MCA_NO_RESOURCES;
414    if (p_dcb) {
415      /* save the info required by dcb connection */
416      p_dcb->p_chnl_cfg = p_chnl_cfg;
417      p_dcb->mdl_id = mdl_id;
418      if (!p_ccb->data_vpsm)
419        p_ccb->data_vpsm =
420            L2CA_Register(data_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
421      if (p_ccb->data_vpsm) {
422        tMCA_CCB_EVT* mca_ccb_evt =
423            (tMCA_CCB_EVT*)osi_malloc(sizeof(tMCA_CCB_EVT));
424        tMCA_CCB_MSG* p_evt_data = &mca_ccb_evt->api;
425        p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb);
426        p_evt_data->mdep_id = peer_dep_id;
427        p_evt_data->mdl_id = mdl_id;
428        p_evt_data->param = cfg;
429        p_evt_data->op_code = MCA_OP_MDL_CREATE_REQ;
430        p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
431        p_evt_data->hdr.layer_specific = false;
432        mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, mca_ccb_evt);
433        return MCA_SUCCESS;
434      }
435
436      mca_dcb_dealloc(p_dcb, NULL);
437    }
438  }
439  return result;
440}
441
442/*******************************************************************************
443 *
444 * Function         MCA_CreateMdlRsp
445 *
446 * Description      This function sends a CREATE_MDL response to the peer device
447 *                  in response to a received MCA_CREATE_IND_EVT.
448 *                  If the rsp_code is successful, a data channel is open
449 *                  with the given p_chnl_cfg
450 *                  When the data channel is open successfully, a
451 *                  MCA_OPEN_IND_EVT
452 *                  is reported. This data channel is identified as tMCA_DL.
453 *
454 * Returns          MCA_SUCCESS if successful, otherwise error.
455 *
456 ******************************************************************************/
457tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
458                             uint8_t cfg, uint8_t rsp_code,
459                             const tMCA_CHNL_CFG* p_chnl_cfg) {
460  tMCA_RESULT result = MCA_BAD_HANDLE;
461  tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
462
463  MCA_TRACE_API("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl,
464                dep, mdl_id, cfg, rsp_code);
465  CHECK(p_chnl_cfg != NULL);
466  if (p_ccb) {
467    if (p_ccb->cong) {
468      MCA_TRACE_ERROR("congested");
469      return MCA_BUSY;
470    }
471    if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep) &&
472        (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
473        (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ)) {
474      tMCA_CCB_MSG evt_data;
475      result = MCA_SUCCESS;
476      evt_data.dcb_idx = 0;
477      if (rsp_code == MCA_RSP_SUCCESS) {
478        tMCA_DCB* p_dcb = mca_dcb_alloc(p_ccb, dep);
479        if (p_dcb) {
480          evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
481          p_dcb->p_chnl_cfg = p_chnl_cfg;
482          p_dcb->mdl_id = mdl_id;
483        } else {
484          rsp_code = MCA_RSP_MDEP_BUSY;
485          result = MCA_NO_RESOURCES;
486        }
487      }
488
489      if (result == MCA_SUCCESS) {
490        evt_data.mdl_id = mdl_id;
491        evt_data.param = cfg;
492        evt_data.rsp_code = rsp_code;
493        evt_data.op_code = MCA_OP_MDL_CREATE_RSP;
494        tMCA_CCB_EVT mca_ccb_evt;
495        mca_ccb_evt.api = evt_data;
496        mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, &mca_ccb_evt);
497      }
498    } else {
499      MCA_TRACE_ERROR(
500          "The given MCL is not expecting a MCA_CreateMdlRsp with the given "
501          "parameters");
502      result = MCA_BAD_PARAMS;
503    }
504  }
505  return result;
506}
507
508/*******************************************************************************
509 *
510 * Function         MCA_CloseReq
511 *
512 * Description      Close a data channel.  When the channel is closed, an
513 *                  MCA_CLOSE_CFM_EVT is sent to the application via the
514 *                  control callback function for this handle.
515 *
516 * Returns          MCA_SUCCESS if successful, otherwise error.
517 *
518 ******************************************************************************/
519tMCA_RESULT MCA_CloseReq(tMCA_DL mdl) {
520  tMCA_RESULT result = MCA_BAD_HANDLE;
521  tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
522
523  MCA_TRACE_API("MCA_CloseReq: %d ", mdl);
524  if (p_dcb) {
525    result = MCA_SUCCESS;
526    mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
527  }
528  return result;
529}
530
531/*******************************************************************************
532 *
533 * Function         MCA_ReconnectMdl
534 *
535 * Description      This function sends a RECONNECT_MDL request to the peer
536 *                  device. When the response is received, a
537 *                  MCA_RECONNECT_CFM_EVT is reported. If p_chnl_cfg is NULL,
538 *                  the data channel is not initiated until MCA_DataChnlCfg is
539 *                  called to provide the p_chnl_cfg. If the response is
540 *                  successful, a data channel is open. When the data channel is
541 *                  open successfully, a MCA_OPEN_CFM_EVT is reported.
542 *
543 * Returns          MCA_SUCCESS if successful, otherwise error.
544 *
545 ******************************************************************************/
546tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
547                             uint16_t mdl_id, const tMCA_CHNL_CFG* p_chnl_cfg) {
548  tMCA_RESULT result = MCA_BAD_HANDLE;
549  tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
550  tMCA_DCB* p_dcb;
551
552  MCA_TRACE_API("MCA_ReconnectMdl: %d ", mcl);
553  CHECK(p_chnl_cfg != NULL);
554  if (p_ccb) {
555    if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) {
556      MCA_TRACE_ERROR("pending req");
557      return MCA_BUSY;
558    }
559
560    if (!MCA_IS_VALID_MDL_ID(mdl_id)) {
561      MCA_TRACE_ERROR("bad mdl id: %d ", mdl_id);
562      return MCA_BAD_PARAMS;
563    }
564
565    if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) {
566      MCA_TRACE_ERROR("mdl id: %d is used in the control link", mdl_id);
567      return MCA_BAD_MDL_ID;
568    }
569
570    p_dcb = mca_dcb_alloc(p_ccb, dep);
571    result = MCA_NO_RESOURCES;
572    if (p_dcb) {
573      tMCA_CCB_EVT* mca_ccb_evt =
574          (tMCA_CCB_EVT*)osi_malloc(sizeof(tMCA_CCB_EVT));
575      tMCA_CCB_MSG* p_evt_data = &mca_ccb_evt->api;
576
577      p_dcb->p_chnl_cfg = p_chnl_cfg;
578      p_dcb->mdl_id = mdl_id;
579      if (!p_ccb->data_vpsm)
580        p_ccb->data_vpsm =
581            L2CA_Register(data_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
582      p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb);
583      p_evt_data->mdl_id = mdl_id;
584      p_evt_data->op_code = MCA_OP_MDL_RECONNECT_REQ;
585      p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
586      mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, mca_ccb_evt);
587      return MCA_SUCCESS;
588    }
589  }
590  return result;
591}
592
593/*******************************************************************************
594 *
595 * Function         MCA_ReconnectMdlRsp
596 *
597 * Description      This function sends a RECONNECT_MDL response to the peer
598 *                  device in response to a MCA_RECONNECT_IND_EVT event.
599 *                  If the response is successful, a data channel is open.
600 *                  When the data channel is open successfully, a
601 *                  MCA_OPEN_IND_EVT is reported.
602 *
603 * Returns          MCA_SUCCESS if successful, otherwise error.
604 *
605 ******************************************************************************/
606tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
607                                uint8_t rsp_code,
608                                const tMCA_CHNL_CFG* p_chnl_cfg) {
609  tMCA_RESULT result = MCA_BAD_HANDLE;
610  tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
611  tMCA_DCB* p_dcb;
612
613  MCA_TRACE_API("MCA_ReconnectMdlRsp: %d ", mcl);
614  CHECK(p_chnl_cfg != NULL);
615  if (p_ccb) {
616    if (p_ccb->cong) {
617      MCA_TRACE_ERROR("congested");
618      return MCA_BUSY;
619    }
620    if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
621        (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ)) {
622      result = MCA_SUCCESS;
623      tMCA_CCB_MSG evt_data;
624      evt_data.dcb_idx = 0;
625      if (rsp_code == MCA_RSP_SUCCESS) {
626        p_dcb = mca_dcb_alloc(p_ccb, dep);
627        if (p_dcb) {
628          evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
629          p_dcb->p_chnl_cfg = p_chnl_cfg;
630          p_dcb->mdl_id = mdl_id;
631        } else {
632          MCA_TRACE_ERROR("Out of MDL for this MDEP");
633          rsp_code = MCA_RSP_MDEP_BUSY;
634          result = MCA_NO_RESOURCES;
635        }
636      }
637
638      evt_data.mdl_id = mdl_id;
639      evt_data.rsp_code = rsp_code;
640      evt_data.op_code = MCA_OP_MDL_RECONNECT_RSP;
641      tMCA_CCB_EVT mca_ccb_evt;
642      mca_ccb_evt.api = evt_data;
643      mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, &mca_ccb_evt);
644    } else {
645      MCA_TRACE_ERROR(
646          "The given MCL is not expecting a MCA_ReconnectMdlRsp with the given "
647          "parameters");
648      result = MCA_BAD_PARAMS;
649    }
650  }
651  return result;
652}
653
654/*******************************************************************************
655 *
656 * Function         MCA_DataChnlCfg
657 *
658 * Description      This function initiates a data channel connection toward the
659 *                  connected peer device.
660 *                  When the data channel is open successfully, a
661 *                  MCA_OPEN_CFM_EVT is reported. This data channel is
662 *                  identified as tMCA_DL.
663 *
664 * Returns          MCA_SUCCESS if successful, otherwise error.
665 *
666 ******************************************************************************/
667tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG* p_chnl_cfg) {
668  tMCA_RESULT result = MCA_BAD_HANDLE;
669  tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
670  tMCA_DCB* p_dcb;
671  tMCA_TC_TBL* p_tbl;
672
673  MCA_TRACE_API("MCA_DataChnlCfg: %d ", mcl);
674  CHECK(p_chnl_cfg != NULL);
675  if (p_ccb) {
676    result = MCA_NO_RESOURCES;
677    if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
678        ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) {
679      MCA_TRACE_ERROR("The given MCL is not expecting this API:%d",
680                      p_ccb->status);
681      return result;
682    }
683
684    p_dcb->p_chnl_cfg = p_chnl_cfg;
685    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
686                         p_ccb->data_vpsm, BTM_SEC_PROTO_MCA,
687                         p_ccb->p_tx_req->dcb_idx);
688    p_dcb->lcid =
689        mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
690    if (p_dcb->lcid) {
691      p_tbl = mca_tc_tbl_dalloc(p_dcb);
692      if (p_tbl) {
693        p_tbl->state = MCA_TC_ST_CONN;
694        result = MCA_SUCCESS;
695      }
696    }
697  }
698  return result;
699}
700
701/*******************************************************************************
702 *
703 * Function         MCA_Abort
704 *
705 * Description      This function sends a ABORT_MDL request to the peer device.
706 *                  When the response is received, a MCA_ABORT_CFM_EVT is
707 *                  reported.
708 *
709 * Returns          MCA_SUCCESS if successful, otherwise error.
710 *
711 ******************************************************************************/
712tMCA_RESULT MCA_Abort(tMCA_CL mcl) {
713  tMCA_RESULT result = MCA_BAD_HANDLE;
714  tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
715  tMCA_DCB* p_dcb;
716
717  MCA_TRACE_API("MCA_Abort: %d", mcl);
718  if (p_ccb) {
719    result = MCA_NO_RESOURCES;
720    /* verify that we are waiting for data channel to come up with the given mdl
721     */
722    if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
723        ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) {
724      MCA_TRACE_ERROR("The given MCL is not expecting this API:%d",
725                      p_ccb->status);
726      return result;
727    }
728
729    if (p_ccb->cong) {
730      MCA_TRACE_ERROR("congested");
731      return MCA_BUSY;
732    }
733
734    tMCA_CCB_EVT* mca_ccb_evt = (tMCA_CCB_EVT*)osi_malloc(sizeof(tMCA_CCB_EVT));
735    tMCA_CCB_MSG* p_evt_data = &mca_ccb_evt->api;
736    result = MCA_SUCCESS;
737    p_evt_data->op_code = MCA_OP_MDL_ABORT_REQ;
738    p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
739    mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, mca_ccb_evt);
740  }
741  return result;
742}
743
744/*******************************************************************************
745 *
746 * Function         MCA_Delete
747 *
748 * Description      This function sends a DELETE_MDL request to the peer device.
749 *                  When the response is received, a MCA_DELETE_CFM_EVT is
750 *                  reported.
751 *
752 * Returns          MCA_SUCCESS if successful, otherwise error.
753 *
754 ******************************************************************************/
755tMCA_RESULT MCA_Delete(tMCA_CL mcl, uint16_t mdl_id) {
756  tMCA_RESULT result = MCA_BAD_HANDLE;
757  tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
758
759  MCA_TRACE_API("MCA_Delete: %d ", mcl);
760  if (p_ccb) {
761    if (p_ccb->cong) {
762      MCA_TRACE_ERROR("congested");
763      return MCA_BUSY;
764    }
765    if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID)) {
766      MCA_TRACE_ERROR("bad mdl id: %d ", mdl_id);
767      return MCA_BAD_PARAMS;
768    }
769
770    tMCA_CCB_EVT* mca_ccb_evt = (tMCA_CCB_EVT*)osi_malloc(sizeof(tMCA_CCB_EVT));
771    tMCA_CCB_MSG* p_evt_data = &mca_ccb_evt->api;
772    result = MCA_SUCCESS;
773    p_evt_data->mdl_id = mdl_id;
774    p_evt_data->op_code = MCA_OP_MDL_DELETE_REQ;
775    p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
776    mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, mca_ccb_evt);
777  }
778  return result;
779}
780
781/*******************************************************************************
782 *
783 * Function         MCA_WriteReq
784 *
785 * Description      Send a data packet to the peer device.
786 *
787 *                  The application passes the packet using the BT_HDR
788 *                  structure. The offset field must be equal to or greater than
789 *                  L2CAP_MIN_OFFSET. This allows enough space in the buffer for
790 *                  the L2CAP header.
791 *
792 *                  The memory pointed to by p_pkt must be a GKI buffer
793 *                  allocated by the application.  This buffer will be freed
794 *                  by the protocol stack; the application must not free
795 *                  this buffer.
796 *
797 * Returns          MCA_SUCCESS if successful, otherwise error.
798 *
799 ******************************************************************************/
800tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR* p_pkt) {
801  tMCA_RESULT result = MCA_BAD_HANDLE;
802  tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
803  tMCA_DCB_EVT evt_data;
804
805  MCA_TRACE_API("MCA_WriteReq: %d ", mdl);
806  if (p_dcb) {
807    if (p_dcb->cong) {
808      result = MCA_BUSY;
809    } else {
810      evt_data.p_pkt = p_pkt;
811      result = MCA_SUCCESS;
812      mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data);
813    }
814  }
815  return result;
816}
817
818/*******************************************************************************
819 *
820 * Function         MCA_GetL2CapChannel
821 *
822 * Description      Get the L2CAP CID used by the given data channel handle.
823 *
824 * Returns          L2CAP channel ID if successful, otherwise 0.
825 *
826 ******************************************************************************/
827uint16_t MCA_GetL2CapChannel(tMCA_DL mdl) {
828  uint16_t lcid = 0;
829  tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
830
831  MCA_TRACE_API("MCA_GetL2CapChannel: %d ", mdl);
832  if (p_dcb) lcid = p_dcb->lcid;
833  return lcid;
834}
835
836static const btmcap_test_interface_t mcap_test_interface = {
837    sizeof(btmcap_test_interface_t),
838    MCA_Init,
839    MCA_Register,
840    MCA_Deregister,
841    MCA_CreateDep,
842    MCA_DeleteDep,
843    MCA_ConnectReq,
844    MCA_DisconnectReq,
845    MCA_CreateMdl,
846    MCA_CreateMdlRsp,
847    MCA_CloseReq,
848    MCA_ReconnectMdl,
849    MCA_ReconnectMdlRsp,
850    MCA_DataChnlCfg,
851    MCA_Abort,
852    MCA_Delete,
853    MCA_WriteReq,
854    MCA_GetL2CapChannel,
855};
856
857const btmcap_test_interface_t* stack_mcap_get_interface(void) {
858  BTIF_TRACE_EVENT("%s", __func__);
859  return &mcap_test_interface;
860}
861