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