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*******************************************************************************/
50void 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*******************************************************************************/
67void 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*******************************************************************************/
99UINT8 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*******************************************************************************/
119tMCA_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*******************************************************************************/
187void 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*******************************************************************************/
215tMCA_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*******************************************************************************/
285tMCA_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*******************************************************************************/
333tMCA_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*******************************************************************************/
389tMCA_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*******************************************************************************/
421tMCA_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*******************************************************************************/
496tMCA_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*******************************************************************************/
564tMCA_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*******************************************************************************/
594tMCA_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*******************************************************************************/
658tMCA_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*******************************************************************************/
725tMCA_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*******************************************************************************/
772tMCA_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*******************************************************************************/
817tMCA_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*******************************************************************************/
864tMCA_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*******************************************************************************/
896UINT16 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