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 <string.h>
26
27#include "bt_target.h"
28#include "btm_api.h"
29#include "btm_int.h"
30#include "mca_api.h"
31#include "mca_defs.h"
32#include "mca_int.h"
33
34#include "wcassert.h"
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*******************************************************************************/
50void 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*******************************************************************************/
69void 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*******************************************************************************/
101UINT8 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*******************************************************************************/
121tMCA_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    WC_ASSERT(p_reg != NULL );
129    WC_ASSERT(p_cback != NULL );
130
131    MCA_TRACE_API2 ("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_ERROR0 ("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_ERROR0 ("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*******************************************************************************/
189void MCA_Deregister(tMCA_HANDLE handle)
190{
191    tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
192
193    MCA_TRACE_API1 ("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*******************************************************************************/
217tMCA_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    WC_ASSERT(p_dep != NULL );
225    WC_ASSERT(p_cs != NULL );
226    WC_ASSERT(p_cs->p_data_cback != NULL );
227
228    MCA_TRACE_API1 ("MCA_CreateDep: %d", handle);
229    if (p_rcb)
230    {
231        if (p_cs->max_mdl > MCA_NUM_MDLS)
232        {
233            MCA_TRACE_ERROR1 ("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_ERROR0 ("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*******************************************************************************/
287tMCA_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_API2 ("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*******************************************************************************/
335tMCA_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_API2 ("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_ERROR0 ("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*******************************************************************************/
391tMCA_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_API1 ("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*******************************************************************************/
423tMCA_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_API4 ("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_ERROR0 ("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_ERROR2 ("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_ERROR1 ("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*******************************************************************************/
501tMCA_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_API5 ("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl, dep, mdl_id, cfg, rsp_code);
511    WC_ASSERT(p_chnl_cfg != NULL );
512    if (p_ccb)
513    {
514        if (p_ccb->cong)
515        {
516            MCA_TRACE_ERROR0 ("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_ERROR0 ("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*******************************************************************************/
569tMCA_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_API1 ("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*******************************************************************************/
599tMCA_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_API1 ("MCA_ReconnectMdl: %d ", mcl);
608    WC_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_ERROR0 ("pending req");
614            return MCA_BUSY;
615        }
616
617        if (!MCA_IS_VALID_MDL_ID(mdl_id))
618        {
619            MCA_TRACE_ERROR1 ("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_ERROR1 ("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*******************************************************************************/
667tMCA_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_API1 ("MCA_ReconnectMdlRsp: %d ", mcl);
677    WC_ASSERT(p_chnl_cfg != NULL );
678    if (p_ccb)
679    {
680        if (p_ccb->cong)
681        {
682            MCA_TRACE_ERROR0 ("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_ERROR0 ("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_ERROR0 ("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*******************************************************************************/
734tMCA_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_API1 ("MCA_DataChnlCfg: %d ", mcl);
742    WC_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_ERROR1 ("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*******************************************************************************/
781tMCA_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_API1 ("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_ERROR1 ("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_ERROR0 ("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*******************************************************************************/
831tMCA_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_API1 ("MCA_Delete: %d ", mcl);
838    if (p_ccb)
839    {
840        if (p_ccb->cong)
841        {
842            MCA_TRACE_ERROR0 ("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_ERROR1 ("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*******************************************************************************/
883tMCA_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_API1 ("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*******************************************************************************/
915UINT16 MCA_GetL2CapChannel (tMCA_DL mdl)
916{
917    UINT16  lcid = 0;
918    tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
919
920    MCA_TRACE_API1 ("MCA_GetL2CapChannel: %d ", mdl);
921    if (p_dcb)
922        lcid = p_dcb->lcid;
923    return lcid;
924}
925
926