Home | History | Annotate | Download | only in mcap
      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 implementation file for the MCAP Control Channel Action
     22  *  Functions.
     23  *
     24  ******************************************************************************/
     25 #include <string.h>
     26 #include "bt_target.h"
     27 #include "gki.h"
     28 #include "btm_api.h"
     29 #include "mca_api.h"
     30 #include "mca_defs.h"
     31 #include "mca_int.h"
     32 
     33 
     34 #include  "btu.h"
     35 /*****************************************************************************
     36 ** constants
     37 *****************************************************************************/
     38 /*******************************************************************************
     39 **
     40 ** Function         mca_ccb_rsp_tout
     41 **
     42 ** Description      This function processes the response timeout.
     43 **
     44 ** Returns          void.
     45 **
     46 *******************************************************************************/
     47 void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
     48 {
     49    tMCA_CTRL   evt_data;
     50    mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data);
     51 }
     52 
     53 /*******************************************************************************
     54 **
     55 ** Function         mca_ccb_report_event
     56 **
     57 ** Description      This function reports the given event.
     58 **
     59 ** Returns          void.
     60 **
     61 *******************************************************************************/
     62 void mca_ccb_report_event(tMCA_CCB *p_ccb, UINT8 event, tMCA_CTRL *p_data)
     63 {
     64     if (p_ccb && p_ccb->p_rcb && p_ccb->p_rcb->p_cback)
     65         (*p_ccb->p_rcb->p_cback)(mca_rcb_to_handle(p_ccb->p_rcb), mca_ccb_to_hdl(p_ccb), event, p_data);
     66 }
     67 
     68 /*******************************************************************************
     69 **
     70 ** Function         mca_ccb_free_msg
     71 **
     72 ** Description      This function frees the received message.
     73 **
     74 ** Returns          void.
     75 **
     76 *******************************************************************************/
     77 void mca_ccb_free_msg(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
     78 {
     79     GKI_freebuf (p_data);
     80 }
     81 
     82 /*******************************************************************************
     83 **
     84 ** Function         mca_ccb_snd_req
     85 **
     86 ** Description      This function builds a request and sends it to the peer.
     87 **
     88 ** Returns          void.
     89 **
     90 *******************************************************************************/
     91 void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
     92 {
     93     tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
     94     BT_HDR  *p_pkt;
     95     UINT8   *p, *p_start;
     96     BOOLEAN is_abort = FALSE;
     97     tMCA_DCB *p_dcb;
     98 
     99     MCA_TRACE_DEBUG2 ("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong, p_msg->op_code);
    100     /* check for abort request */
    101     if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (p_msg->op_code == MCA_OP_MDL_ABORT_REQ))
    102     {
    103         p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
    104         /* the Abort API does not have the associated mdl_id.
    105          * Get the mdl_id in dcb to compose the request */
    106         p_msg->mdl_id = p_dcb->mdl_id;
    107         mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
    108         mca_free_buf ((void **)&p_ccb->p_tx_req);
    109         p_ccb->status = MCA_CCB_STAT_NORM;
    110         is_abort = TRUE;
    111     }
    112 
    113     /* no pending outgoing messages or it's an abort request for a pending data channel */
    114     if ((!p_ccb->p_tx_req) || is_abort)
    115     {
    116         p_ccb->p_tx_req = p_msg;
    117         if (!p_ccb->cong)
    118         {
    119             p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
    120             if (p_pkt)
    121             {
    122                 p_pkt->offset = L2CAP_MIN_OFFSET;
    123                 p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
    124                 *p++ = p_msg->op_code;
    125                 UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
    126                 if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ)
    127                 {
    128                     *p++ = p_msg->mdep_id;
    129                     *p++ = p_msg->param;
    130                 }
    131                 p_msg->hdr.layer_specific = TRUE;   /* mark this message as sent */
    132                 p_pkt->len = p - p_start;
    133                 L2CA_DataWrite (p_ccb->lcid, p_pkt);
    134                 p_ccb->timer_entry.param = (TIMER_PARAM_TYPE) p_ccb;
    135                 btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_MCA_CCB_RSP, p_ccb->p_rcb->reg.rsp_tout);
    136             }
    137         }
    138         /* else the L2CAP channel is congested. keep the message to be sent later */
    139     }
    140     else
    141     {
    142         MCA_TRACE_WARNING0 ("dropping api req");
    143         GKI_freebuf (p_data);
    144     }
    145 }
    146 
    147 /*******************************************************************************
    148 **
    149 ** Function         mca_ccb_snd_rsp
    150 **
    151 ** Description      This function builds a response and sends it to
    152 **                  the peer.
    153 **
    154 ** Returns          void.
    155 **
    156 *******************************************************************************/
    157 void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    158 {
    159     tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
    160     BT_HDR  *p_pkt;
    161     UINT8   *p, *p_start;
    162     BOOLEAN chk_mdl = FALSE;
    163     tMCA_DCB    *p_dcb;
    164 
    165     MCA_TRACE_DEBUG2 ("mca_ccb_snd_rsp cong=%d req=%d", p_ccb->cong, p_msg->op_code);
    166     /* assume that API functions verified the parameters */
    167     p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
    168     if (p_pkt)
    169     {
    170         p_pkt->offset = L2CAP_MIN_OFFSET;
    171         p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
    172         *p++ = p_msg->op_code;
    173         *p++ = p_msg->rsp_code;
    174         UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
    175         if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP)
    176         {
    177             *p++ = p_msg->param;
    178             chk_mdl = TRUE;
    179         }
    180         else if (p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP)
    181                 chk_mdl = TRUE;
    182 
    183         if (chk_mdl && p_msg->rsp_code == MCA_RSP_SUCCESS)
    184         {
    185             p_dcb = mca_dcb_by_hdl(p_msg->dcb_idx);
    186             BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
    187                 p_ccb->p_rcb->reg.data_psm, BTM_SEC_PROTO_MCA, p_msg->dcb_idx);
    188             p_ccb->status = MCA_CCB_STAT_PENDING;
    189             /* set p_tx_req to block API_REQ/API_RSP before DL is up */
    190             mca_free_buf ((void **)&p_ccb->p_tx_req);
    191             p_ccb->p_tx_req = p_ccb->p_rx_msg;
    192             p_ccb->p_rx_msg = NULL;
    193             p_ccb->p_tx_req->dcb_idx = p_msg->dcb_idx;
    194         }
    195         mca_free_buf ((void **)&p_ccb->p_rx_msg);
    196         p_pkt->len = p - p_start;
    197         L2CA_DataWrite (p_ccb->lcid, p_pkt);
    198     }
    199 
    200 }
    201 
    202 /*******************************************************************************
    203 **
    204 ** Function         mca_ccb_do_disconn
    205 **
    206 ** Description      This function closes a control channel.
    207 **
    208 ** Returns          void.
    209 **
    210 *******************************************************************************/
    211 void mca_ccb_do_disconn (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    212 {
    213     mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID);
    214     L2CA_DisconnectReq(p_ccb->lcid);
    215 }
    216 
    217 /*******************************************************************************
    218 **
    219 ** Function         mca_ccb_cong
    220 **
    221 ** Description      This function sets the congestion state for the CCB.
    222 **
    223 ** Returns          void.
    224 **
    225 *******************************************************************************/
    226 void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    227 {
    228     MCA_TRACE_DEBUG2 ("mca_ccb_cong cong=%d/%d", p_ccb->cong, p_data->llcong);
    229     p_ccb->cong = p_data->llcong;
    230     if (!p_ccb->cong)
    231     {
    232         /* if there's a held packet, send it now */
    233         if (p_ccb->p_tx_req && !p_ccb->p_tx_req->hdr.layer_specific)
    234         {
    235             p_data = (tMCA_CCB_EVT *)p_ccb->p_tx_req;
    236             p_ccb->p_tx_req = NULL;
    237             mca_ccb_snd_req (p_ccb, p_data);
    238         }
    239     }
    240 }
    241 
    242 /*******************************************************************************
    243 **
    244 ** Function         mca_ccb_hdl_req
    245 **
    246 ** Description      This function is called when a MCAP request is received from
    247 **                  the peer. It calls the application callback function to
    248 **                  report the event.
    249 **
    250 ** Returns          void.
    251 **
    252 *******************************************************************************/
    253 void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    254 {
    255     BT_HDR  *p_pkt = &p_data->hdr;
    256     BT_HDR  *p_buf;
    257     UINT8   *p, *p_start;
    258     tMCA_DCB    *p_dcb;
    259     tMCA_CTRL       evt_data;
    260     tMCA_CCB_MSG    *p_rx_msg = NULL;
    261     UINT8           reject_code = MCA_RSP_NO_RESOURCE;
    262     BOOLEAN         send_rsp = FALSE;
    263     BOOLEAN         check_req = FALSE;
    264     UINT8           reject_opcode;
    265 
    266     MCA_TRACE_DEBUG1 ("mca_ccb_hdl_req status:%d", p_ccb->status);
    267     p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
    268     p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    269     evt_data.hdr.op_code = *p++;
    270     BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
    271     reject_opcode = evt_data.hdr.op_code+1;
    272 
    273     MCA_TRACE_DEBUG1 ("received mdl id: %d ", evt_data.hdr.mdl_id);
    274     if (p_ccb->status == MCA_CCB_STAT_PENDING)
    275     {
    276         MCA_TRACE_DEBUG0 ("received req inpending state");
    277         /* allow abort in pending state */
    278         if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ))
    279         {
    280             reject_code = MCA_RSP_SUCCESS;
    281             send_rsp = TRUE;
    282             /* clear the pending status */
    283             p_ccb->status = MCA_CCB_STAT_NORM;
    284             if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL))
    285             {
    286                 mca_dcb_dealloc (p_dcb, NULL);
    287                 mca_free_buf ((void **)&p_ccb->p_tx_req);
    288             }
    289         }
    290         else
    291             reject_code = MCA_RSP_BAD_OP;
    292     }
    293     else if (p_ccb->p_rx_msg)
    294     {
    295         MCA_TRACE_DEBUG0 ("still handling prev req");
    296         /* still holding previous message, reject this new one ?? */
    297 
    298     }
    299     else if (p_ccb->p_tx_req)
    300     {
    301         MCA_TRACE_DEBUG1 ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
    302         /* sent a request; waiting for response */
    303         if (p_ccb->ctrl_vpsm == 0)
    304         {
    305             MCA_TRACE_DEBUG0 ("local is ACP. accept the cmd from INT");
    306             /* local is acceptor, need to handle the request */
    307             check_req = TRUE;
    308             reject_code = MCA_RSP_SUCCESS;
    309             /* drop the previous request */
    310             if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
    311                 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
    312             {
    313                 mca_dcb_dealloc(p_dcb, NULL);
    314             }
    315             mca_free_buf ((void **)&p_ccb->p_tx_req);
    316             mca_stop_timer(p_ccb);
    317         }
    318         else
    319         {
    320             /*  local is initiator, ignore the req */
    321             GKI_freebuf (p_pkt);
    322             return;
    323         }
    324     }
    325     else if (p_pkt->layer_specific != MCA_RSP_SUCCESS)
    326     {
    327 
    328         reject_code = (UINT8)p_pkt->layer_specific;
    329         if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
    330             (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
    331             (evt_data.hdr.op_code > MCA_LAST_SYNC_OP))
    332         {
    333             /* invalid op code */
    334             reject_opcode = MCA_OP_ERROR_RSP;
    335             evt_data.hdr.mdl_id = 0;
    336         }
    337     }
    338     else
    339     {
    340         check_req = TRUE;
    341         reject_code = MCA_RSP_SUCCESS;
    342     }
    343 
    344     if (check_req)
    345     {
    346         if (reject_code == MCA_RSP_SUCCESS)
    347         {
    348             reject_code = MCA_RSP_BAD_MDL;
    349             if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
    350                 ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ)))
    351             {
    352                 reject_code = MCA_RSP_SUCCESS;
    353                 /* mdl_id is valid according to the spec */
    354                 switch (evt_data.hdr.op_code)
    355                 {
    356                 case MCA_OP_MDL_CREATE_REQ:
    357                     evt_data.create_ind.dep_id = *p++;
    358                     evt_data.create_ind.cfg = *p++;
    359                     p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
    360                     if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id))
    361                     {
    362                         MCA_TRACE_ERROR0 ("not a valid local mdep id");
    363                         reject_code = MCA_RSP_BAD_MDEP;
    364                     }
    365                     else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
    366                     {
    367                         MCA_TRACE_DEBUG0 ("the mdl_id is currently used in the CL(create)");
    368                         mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
    369                     }
    370                     else
    371                     {
    372                         /* check if this dep still have MDL available */
    373                         if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0)
    374                         {
    375                             MCA_TRACE_ERROR0 ("the mdep is currently using max_mdl");
    376                             reject_code = MCA_RSP_MDEP_BUSY;
    377                         }
    378                     }
    379                     break;
    380 
    381                 case MCA_OP_MDL_RECONNECT_REQ:
    382                     if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
    383                     {
    384                         MCA_TRACE_ERROR0 ("the mdl_id is currently used in the CL(reconn)");
    385                         reject_code = MCA_RSP_MDL_BUSY;
    386                     }
    387                     break;
    388 
    389                 case MCA_OP_MDL_ABORT_REQ:
    390                     reject_code = MCA_RSP_BAD_OP;
    391                     break;
    392 
    393                 case MCA_OP_MDL_DELETE_REQ:
    394                     /* delete the associated mdl */
    395                     mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
    396                     send_rsp = TRUE;
    397                     break;
    398                 }
    399             }
    400         }
    401     }
    402 
    403     if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
    404         || send_rsp)
    405     {
    406         p_buf = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
    407         if (p_buf)
    408         {
    409             p_buf->offset = L2CAP_MIN_OFFSET;
    410             p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
    411             *p++ = reject_opcode;
    412             *p++ = reject_code;
    413             UINT16_TO_BE_STREAM (p, evt_data.hdr.mdl_id);
    414             /*
    415             if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS))
    416             {
    417                 *p++ = evt_data.create_ind.cfg;
    418             }
    419             */
    420 
    421             p_buf->len = p - p_start;
    422             L2CA_DataWrite (p_ccb->lcid, p_buf);
    423         }
    424     }
    425 
    426     if (reject_code == MCA_RSP_SUCCESS)
    427     {
    428         /* use the received GKI buffer to store information to double check response API */
    429         p_rx_msg->op_code = evt_data.hdr.op_code;
    430         p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
    431         p_ccb->p_rx_msg = p_rx_msg;
    432         if (send_rsp)
    433         {
    434             GKI_freebuf (p_pkt);
    435             p_ccb->p_rx_msg = NULL;
    436         }
    437         mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
    438     }
    439     else
    440         GKI_freebuf (p_pkt);
    441 }
    442 
    443 /*******************************************************************************
    444 **
    445 ** Function         mca_ccb_hdl_rsp
    446 **
    447 ** Description      This function is called when a MCAP response is received from
    448 **                  the peer.  It calls the application callback function with
    449 **                  the results.
    450 **
    451 ** Returns          void.
    452 **
    453 *******************************************************************************/
    454 void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    455 {
    456     BT_HDR  *p_pkt = &p_data->hdr;
    457     UINT8   *p;
    458     tMCA_CTRL   evt_data;
    459     BOOLEAN     chk_mdl = FALSE;
    460     tMCA_DCB    *p_dcb;
    461     tMCA_RESULT result = MCA_BAD_HANDLE;
    462     tMCA_TC_TBL *p_tbl;
    463 
    464     if (p_ccb->p_tx_req)
    465     {
    466         /* verify that the received response matches the sent request */
    467         p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    468         evt_data.hdr.op_code = *p++;
    469         if ((evt_data.hdr.op_code == 0) ||
    470             ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code))
    471         {
    472             evt_data.rsp.rsp_code = *p++;
    473             mca_stop_timer(p_ccb);
    474             BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
    475             if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP)
    476             {
    477                 evt_data.create_cfm.cfg = *p++;
    478                 chk_mdl = TRUE;
    479             }
    480             else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP)
    481                     chk_mdl = TRUE;
    482 
    483             if (chk_mdl)
    484             {
    485                 p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
    486                 if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
    487                 {
    488                     if (evt_data.hdr.mdl_id != p_dcb->mdl_id)
    489                     {
    490                         MCA_TRACE_ERROR2 ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id);
    491                         /* change the response code to be an error */
    492                         if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
    493                         {
    494                             evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL;
    495                             /* send Abort */
    496                             p_ccb->status = MCA_CCB_STAT_PENDING;
    497                             MCA_Abort(mca_ccb_to_hdl(p_ccb));
    498                         }
    499                     }
    500                     else if (p_dcb->p_chnl_cfg)
    501                     {
    502                         /* the data channel configuration is known. Proceed with data channel initiation */
    503                         BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
    504                             p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
    505                         p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
    506                         if (p_dcb->lcid)
    507                         {
    508                             p_tbl = mca_tc_tbl_dalloc(p_dcb);
    509                             if (p_tbl)
    510                             {
    511                                 p_tbl->state = MCA_TC_ST_CONN;
    512                                 p_ccb->status = MCA_CCB_STAT_PENDING;
    513                                 result = MCA_SUCCESS;
    514                             }
    515                         }
    516                     }
    517                     else
    518                     {
    519                         /* mark this MCL as pending and wait for MCA_DataChnlCfg */
    520                         p_ccb->status = MCA_CCB_STAT_PENDING;
    521                         result = MCA_SUCCESS;
    522                     }
    523                 }
    524 
    525                 if (result != MCA_SUCCESS && p_dcb)
    526                 {
    527                     mca_dcb_dealloc(p_dcb, NULL);
    528                 }
    529             } /* end of chk_mdl */
    530 
    531             if (p_ccb->status != MCA_CCB_STAT_PENDING)
    532                 mca_free_buf ((void **)&p_ccb->p_tx_req);
    533             mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
    534         }
    535         /* else a bad response is received */
    536     }
    537     else
    538     {
    539         /* not expecting any response. drop it */
    540         MCA_TRACE_WARNING0 ("dropping received rsp (not expecting a response)");
    541     }
    542     GKI_freebuf (p_data);
    543 }
    544 
    545 /*******************************************************************************
    546 **
    547 ** Function         mca_ccb_ll_open
    548 **
    549 ** Description      This function is called to report MCA_CONNECT_IND_EVT event.
    550 **                  It also clears the congestion flag (ccb.cong).
    551 **
    552 ** Returns          void.
    553 **
    554 *******************************************************************************/
    555 void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    556 {
    557     tMCA_CTRL    evt_data;
    558     p_ccb->cong  = FALSE;
    559     evt_data.connect_ind.mtu = p_data->open.peer_mtu;
    560     memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
    561     mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data);
    562 }
    563 
    564 /*******************************************************************************
    565 **
    566 ** Function         mca_ccb_dl_open
    567 **
    568 ** Description      This function is called when data channel is open.
    569 **                  It clears p_tx_req to allow other message exchage on this CL.
    570 **
    571 ** Returns          void.
    572 **
    573 *******************************************************************************/
    574 void mca_ccb_dl_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    575 {
    576     mca_free_buf ((void **)&p_ccb->p_tx_req);
    577     mca_free_buf ((void **)&p_ccb->p_rx_msg);
    578     p_ccb->status = MCA_CCB_STAT_NORM;
    579 }
    580 
    581