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