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