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