1 /******************************************************************************
2  *
3  *  Copyright 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  ******************************************************************************/
mca_ccb_timer_timeout(void * data)49 void 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  ******************************************************************************/
MCA_Init(void)65 void 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  ******************************************************************************/
MCA_SetTraceLevel(uint8_t level)96 uint8_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  ******************************************************************************/
MCA_Register(tMCA_REG * p_reg,tMCA_CTRL_CBACK * p_cback)114 tMCA_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  ******************************************************************************/
MCA_Deregister(tMCA_HANDLE handle)179 void 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  ******************************************************************************/
MCA_CreateDep(tMCA_HANDLE handle,tMCA_DEP * p_dep,tMCA_CS * p_cs)204 tMCA_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  ******************************************************************************/
MCA_DeleteDep(tMCA_HANDLE handle,tMCA_DEP dep)262 tMCA_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  ******************************************************************************/
MCA_ConnectReq(tMCA_HANDLE handle,const RawAddress & bd_addr,uint16_t ctrl_psm,uint16_t sec_mask)305 tMCA_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  ******************************************************************************/
MCA_DisconnectReq(tMCA_CL mcl)356 tMCA_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  ******************************************************************************/
MCA_CreateMdl(tMCA_CL mcl,tMCA_DEP dep,uint16_t data_psm,uint16_t mdl_id,uint8_t peer_dep_id,uint8_t cfg,const tMCA_CHNL_CFG * p_chnl_cfg)386 tMCA_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  ******************************************************************************/
MCA_CreateMdlRsp(tMCA_CL mcl,tMCA_DEP dep,uint16_t mdl_id,uint8_t cfg,uint8_t rsp_code,const tMCA_CHNL_CFG * p_chnl_cfg)457 tMCA_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  ******************************************************************************/
MCA_CloseReq(tMCA_DL mdl)519 tMCA_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  ******************************************************************************/
MCA_ReconnectMdl(tMCA_CL mcl,tMCA_DEP dep,uint16_t data_psm,uint16_t mdl_id,const tMCA_CHNL_CFG * p_chnl_cfg)546 tMCA_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  ******************************************************************************/
MCA_ReconnectMdlRsp(tMCA_CL mcl,tMCA_DEP dep,uint16_t mdl_id,uint8_t rsp_code,const tMCA_CHNL_CFG * p_chnl_cfg)606 tMCA_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  ******************************************************************************/
MCA_DataChnlCfg(tMCA_CL mcl,const tMCA_CHNL_CFG * p_chnl_cfg)667 tMCA_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  ******************************************************************************/
MCA_Abort(tMCA_CL mcl)712 tMCA_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  ******************************************************************************/
MCA_Delete(tMCA_CL mcl,uint16_t mdl_id)755 tMCA_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  ******************************************************************************/
MCA_WriteReq(tMCA_DL mdl,BT_HDR * p_pkt)800 tMCA_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  ******************************************************************************/
MCA_GetL2CapChannel(tMCA_DL mdl)827 uint16_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 
836 static 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 
stack_mcap_get_interface(void)857 const btmcap_test_interface_t* stack_mcap_get_interface(void) {
858   BTIF_TRACE_EVENT("%s", __func__);
859   return &mcap_test_interface;
860 }
861