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 Main Control Block and
     22  *  Utility functions.
     23  *
     24  ******************************************************************************/
     25 #include <string.h>
     26 
     27 #include "bt_target.h"
     28 #include "gki.h"
     29 #include "mca_api.h"
     30 #include "mca_defs.h"
     31 #include "mca_int.h"
     32 #include "wcassert.h"
     33 #include "l2c_api.h"
     34 
     35 /* Main Control block for MCA */
     36 #if MCA_DYNAMIC_MEMORY == FALSE
     37 tMCA_CB mca_cb;
     38 #endif
     39 
     40 /*****************************************************************************
     41 ** constants
     42 *****************************************************************************/
     43 
     44 /* table of standard opcode message size */
     45 const UINT8 mca_std_msg_len[MCA_NUM_STANDARD_OPCODE] = {
     46     4,          /* MCA_OP_ERROR_RSP         */
     47     5,          /* MCA_OP_MDL_CREATE_REQ    */
     48     5,          /* MCA_OP_MDL_CREATE_RSP    */
     49     3,          /* MCA_OP_MDL_RECONNECT_REQ */
     50     4,          /* MCA_OP_MDL_RECONNECT_RSP */
     51     3,          /* MCA_OP_MDL_ABORT_REQ     */
     52     4,          /* MCA_OP_MDL_ABORT_RSP     */
     53     3,          /* MCA_OP_MDL_DELETE_REQ    */
     54     4           /* MCA_OP_MDL_DELETE_RSP    */
     55 };
     56 
     57 
     58 /*******************************************************************************
     59 **
     60 ** Function         mca_handle_by_cpsm
     61 **
     62 ** Description      This function returns the handle for the given control
     63 **                  channel PSM. 0, if not found.
     64 **
     65 ** Returns          the MCA handle.
     66 **
     67 *******************************************************************************/
     68 tMCA_HANDLE mca_handle_by_cpsm(UINT16 psm)
     69 {
     70     int     i;
     71     tMCA_HANDLE handle = 0;
     72     tMCA_RCB *p_rcb = &mca_cb.rcb[0];
     73 
     74     for (i=0; i<MCA_NUM_REGS; i++, p_rcb++)
     75     {
     76         if (p_rcb->p_cback && p_rcb->reg.ctrl_psm == psm)
     77         {
     78             handle = i+1;
     79             break;
     80         }
     81     }
     82     return handle;
     83 }
     84 
     85 /*******************************************************************************
     86 **
     87 ** Function         mca_handle_by_dpsm
     88 **
     89 ** Description      This function returns the handle for the given data
     90 **                  channel PSM. 0, if not found.
     91 **
     92 ** Returns          the MCA handle.
     93 **
     94 *******************************************************************************/
     95 tMCA_HANDLE mca_handle_by_dpsm(UINT16 psm)
     96 {
     97     int     i;
     98     tMCA_HANDLE handle = 0;
     99     tMCA_RCB *p_rcb = &mca_cb.rcb[0];
    100 
    101     for (i=0; i<MCA_NUM_REGS; i++, p_rcb++)
    102     {
    103         if (p_rcb->p_cback && p_rcb->reg.data_psm == psm)
    104         {
    105             handle = i+1;
    106             break;
    107         }
    108     }
    109     return handle;
    110 }
    111 
    112 /*******************************************************************************
    113 **
    114 ** Function         mca_tc_tbl_calloc
    115 **
    116 ** Description      This function allocates a transport table for the given
    117 **                  control channel.
    118 **
    119 ** Returns          The tranport table.
    120 **
    121 *******************************************************************************/
    122 tMCA_TC_TBL * mca_tc_tbl_calloc(tMCA_CCB *p_ccb)
    123 {
    124     tMCA_TC_TBL *p_tbl = mca_cb.tc.tc_tbl;
    125     int             i;
    126 
    127     /* find next free entry in tc table */
    128     for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++)
    129     {
    130         if (p_tbl->state == MCA_TC_ST_UNUSED)
    131         {
    132             break;
    133         }
    134     }
    135 
    136     /* sanity check */
    137     WC_ASSERT(i != MCA_NUM_TC_TBL);
    138 
    139     /* initialize entry */
    140     p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    141     p_tbl->cfg_flags= 0;
    142     p_tbl->cb_idx   = mca_ccb_to_hdl(p_ccb);
    143     p_tbl->tcid     = MCA_CTRL_TCID;
    144     p_tbl->my_mtu   = MCA_CTRL_MTU;
    145     p_tbl->state    = MCA_TC_ST_IDLE;
    146     p_tbl->lcid     = p_ccb->lcid;
    147     mca_cb.tc.lcid_tbl[p_ccb->lcid - L2CAP_BASE_APPL_CID] = i;
    148     MCA_TRACE_DEBUG("mca_tc_tbl_calloc cb_idx: %d", p_tbl->cb_idx);
    149 
    150     return p_tbl;
    151 }
    152 
    153 /*******************************************************************************
    154 **
    155 ** Function         mca_tc_tbl_dalloc
    156 **
    157 ** Description      This function allocates a transport table for the given
    158 **                  data channel.
    159 **
    160 ** Returns          The tranport table.
    161 **
    162 *******************************************************************************/
    163 tMCA_TC_TBL * mca_tc_tbl_dalloc(tMCA_DCB *p_dcb)
    164 {
    165     tMCA_TC_TBL *p_tbl = mca_cb.tc.tc_tbl;
    166     int             i;
    167 
    168     /* find next free entry in tc table */
    169     for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++)
    170     {
    171         if (p_tbl->state == MCA_TC_ST_UNUSED)
    172         {
    173             break;
    174         }
    175     }
    176 
    177     /* sanity check */
    178     WC_ASSERT(i != MCA_NUM_TC_TBL);
    179 
    180     /* initialize entry */
    181     p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    182     p_tbl->cfg_flags= 0;
    183     p_tbl->cb_idx   = mca_dcb_to_hdl(p_dcb);
    184     p_tbl->tcid     = p_dcb->p_cs->type + 1;
    185     p_tbl->my_mtu   = p_dcb->p_chnl_cfg->data_mtu;
    186     p_tbl->state    = MCA_TC_ST_IDLE;
    187     p_tbl->lcid     = p_dcb->lcid;
    188     mca_cb.tc.lcid_tbl[p_dcb->lcid - L2CAP_BASE_APPL_CID] = i;
    189     MCA_TRACE_DEBUG("mca_tc_tbl_dalloc tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
    190 
    191     return p_tbl;
    192 }
    193 
    194 /*******************************************************************************
    195 **
    196 ** Function         mca_tc_tbl_by_lcid
    197 **
    198 ** Description      Find the transport channel table entry by LCID.
    199 **
    200 **
    201 ** Returns          The tranport table.
    202 **
    203 *******************************************************************************/
    204 tMCA_TC_TBL *mca_tc_tbl_by_lcid(UINT16 lcid)
    205 {
    206     UINT8 idx;
    207 
    208     if (lcid)
    209     {
    210         idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
    211 
    212         if (idx < MCA_NUM_TC_TBL)
    213         {
    214             return &mca_cb.tc.tc_tbl[idx];
    215         }
    216     }
    217     return NULL;
    218 }
    219 
    220 /*******************************************************************************
    221 **
    222 ** Function         mca_free_tc_tbl_by_lcid
    223 **
    224 ** Description      Find the  transport table entry by LCID
    225 **                  and free the tc_tbl
    226 **
    227 ** Returns          void.
    228 **
    229 *******************************************************************************/
    230 void mca_free_tc_tbl_by_lcid(UINT16 lcid)
    231 {
    232     UINT8 idx;
    233 
    234     if (lcid)
    235     {
    236         idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
    237 
    238         if (idx < MCA_NUM_TC_TBL)
    239         {
    240             mca_cb.tc.tc_tbl[idx].state = MCA_TC_ST_UNUSED;
    241         }
    242     }
    243 }
    244 
    245 
    246 /*******************************************************************************
    247 **
    248 ** Function         mca_set_cfg_by_tbl
    249 **
    250 ** Description      Set the L2CAP configuration information
    251 **
    252 ** Returns          none.
    253 **
    254 *******************************************************************************/
    255 void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO *p_cfg, tMCA_TC_TBL *p_tbl)
    256 {
    257     tMCA_DCB   *p_dcb;
    258     const tL2CAP_FCR_OPTS *p_opt;
    259     tMCA_FCS_OPT    fcs = MCA_FCS_NONE;
    260 
    261     if (p_tbl->tcid == MCA_CTRL_TCID)
    262     {
    263         p_opt = &mca_l2c_fcr_opts_def;
    264     }
    265     else
    266     {
    267         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    268         p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
    269         fcs   = p_dcb->p_chnl_cfg->fcs;
    270     }
    271     memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    272     p_cfg->mtu_present = TRUE;
    273     p_cfg->mtu = p_tbl->my_mtu;
    274     p_cfg->fcr_present = TRUE;
    275     memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS));
    276     if (fcs & MCA_FCS_PRESNT_MASK)
    277     {
    278         p_cfg->fcs_present = TRUE;
    279         p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
    280     }
    281 }
    282 
    283 /*******************************************************************************
    284 **
    285 ** Function         mca_tc_close_ind
    286 **
    287 ** Description      This function is called by the L2CAP interface when the
    288 **                  L2CAP channel is closed.  It looks up the CCB or DCB for
    289 **                  the channel and sends it a close event.  The reason
    290 **                  parameter is the same value passed by the L2CAP
    291 **                  callback function.
    292 **
    293 ** Returns          Nothing.
    294 **
    295 *******************************************************************************/
    296 void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, UINT16 reason)
    297 {
    298     tMCA_CCB   *p_ccb;
    299     tMCA_DCB   *p_dcb;
    300     tMCA_CLOSE  close;
    301 
    302     close.param  = MCA_ACP;
    303     close.reason = reason;
    304     close.lcid   = p_tbl->lcid;
    305 
    306     MCA_TRACE_DEBUG("mca_tc_close_ind tcid: %d, cb_idx:%d, old: %d",
    307                      p_tbl->tcid, p_tbl->cb_idx, p_tbl->state);
    308 
    309     /* Check if the transport channel is in use */
    310     if (p_tbl->state == MCA_TC_ST_UNUSED)
    311         return;
    312 
    313     /* clear mca_tc_tbl entry */
    314     if (p_tbl->cfg_flags&MCA_L2C_CFG_DISCN_INT)
    315         close.param = MCA_INT;
    316     p_tbl->cfg_flags = 0;
    317     p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    318 
    319     /* if control channel, notify ccb that channel close */
    320     if (p_tbl->tcid == MCA_CTRL_TCID)
    321     {
    322         p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    323         mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close);
    324     }
    325     /* notify dcb that channel close */
    326     else
    327     {
    328         /* look up dcb  */
    329         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    330         if (p_dcb != NULL)
    331         {
    332             mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close);
    333         }
    334     }
    335     p_tbl->state = MCA_TC_ST_UNUSED;
    336 }
    337 
    338 /*******************************************************************************
    339 **
    340 ** Function         mca_tc_open_ind
    341 **
    342 ** Description      This function is called by the L2CAP interface when
    343 **                  the L2CAP channel is opened.  It looks up the CCB or DCB
    344 **                  for the channel and sends it an open event.
    345 **
    346 ** Returns          Nothing.
    347 **
    348 *******************************************************************************/
    349 void mca_tc_open_ind(tMCA_TC_TBL *p_tbl)
    350 {
    351     tMCA_CCB   *p_ccb;
    352     tMCA_DCB   *p_dcb;
    353     tMCA_OPEN  open;
    354 
    355     MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
    356     p_tbl->state = MCA_TC_ST_OPEN;
    357 
    358     open.peer_mtu = p_tbl->peer_mtu;
    359     open.lcid = p_tbl->lcid;
    360     /* use param to indicate the role of connection.
    361      * MCA_ACP, if ACP */
    362     open.param = MCA_INT;
    363     if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP)
    364     {
    365         open.param = MCA_ACP;
    366     }
    367 
    368     /* if control channel, notify ccb that channel open */
    369     if (p_tbl->tcid == MCA_CTRL_TCID)
    370     {
    371         p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    372 
    373         mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open);
    374     }
    375     /* must be data channel, notify dcb that channel open */
    376     else
    377     {
    378         /* look up dcb */
    379         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    380 
    381         /* put lcid in event data */
    382         if (p_dcb != NULL)
    383         {
    384             mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT *) &open);
    385         }
    386     }
    387 }
    388 
    389 
    390 /*******************************************************************************
    391 **
    392 ** Function         mca_tc_cong_ind
    393 **
    394 ** Description      This function is called by the L2CAP interface layer when
    395 **                  L2CAP calls the congestion callback.  It looks up the CCB
    396 **                  or DCB for the channel and sends it a congestion event.
    397 **                  The is_congested parameter is the same value passed by
    398 **                  the L2CAP callback function.
    399 **
    400 **
    401 ** Returns          Nothing.
    402 **
    403 *******************************************************************************/
    404 void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, BOOLEAN is_congested)
    405 {
    406     tMCA_CCB   *p_ccb;
    407     tMCA_DCB   *p_dcb;
    408 
    409     MCA_TRACE_DEBUG("mca_tc_cong_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
    410     /* if control channel, notify ccb of congestion */
    411     if (p_tbl->tcid == MCA_CTRL_TCID)
    412     {
    413         p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    414         mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested);
    415     }
    416     /* notify dcb that channel open */
    417     else
    418     {
    419         /* look up dcb by cb_idx */
    420         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    421         if (p_dcb != NULL)
    422         {
    423             mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT *) &is_congested);
    424         }
    425     }
    426 }
    427 
    428 
    429 /*******************************************************************************
    430 **
    431 ** Function         mca_tc_data_ind
    432 **
    433 ** Description      This function is called by the L2CAP interface layer when
    434 **                  incoming data is received from L2CAP.  It looks up the CCB
    435 **                  or DCB for the channel and routes the data accordingly.
    436 **
    437 ** Returns          Nothing.
    438 **
    439 *******************************************************************************/
    440 void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf)
    441 {
    442     tMCA_CCB   *p_ccb;
    443     tMCA_DCB   *p_dcb;
    444     UINT8       event = MCA_CCB_MSG_RSP_EVT;
    445     UINT8       *p;
    446     UINT8       rej_rsp_code = MCA_RSP_SUCCESS;
    447 
    448     MCA_TRACE_DEBUG("mca_tc_data_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
    449 
    450 
    451     /* if control channel, handle control message */
    452     if (p_tbl->tcid == MCA_CTRL_TCID)
    453     {
    454         p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    455         if (p_ccb)
    456         {
    457             p = (UINT8*)(p_buf+1) + p_buf->offset;
    458             /* all the request opcode has bit 0 set. response code has bit 0 clear */
    459             if ((*p) & 0x01)
    460                 event = MCA_CCB_MSG_REQ_EVT;
    461 
    462             if (*p < MCA_NUM_STANDARD_OPCODE)
    463             {
    464                 if (p_buf->len != mca_std_msg_len[*p])
    465                 {
    466                     MCA_TRACE_ERROR ("opcode: %d required len:%d, got len:%d", *p, mca_std_msg_len[*p], p_buf->len);
    467                     rej_rsp_code = MCA_RSP_BAD_PARAM;
    468                 }
    469             }
    470             else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP))
    471             {
    472                 MCA_TRACE_ERROR ("unsupported SYNC opcode: %d len:%d", *p, p_buf->len);
    473                 /* reject unsupported request */
    474                 rej_rsp_code = MCA_RSP_NO_SUPPORT;
    475             }
    476             else
    477             {
    478                 MCA_TRACE_ERROR ("bad opcode: %d len:%d", *p, p_buf->len);
    479                 /* reject unsupported request */
    480                 rej_rsp_code = MCA_RSP_BAD_OPCODE;
    481             }
    482 
    483             p_buf->layer_specific = rej_rsp_code;
    484             /* forward the request/response to state machine */
    485             mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT *) p_buf);
    486         } /* got a valid ccb */
    487         else
    488             GKI_freebuf(p_buf);
    489     }
    490     /* else send event to dcb */
    491     else
    492     {
    493         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    494         if (p_dcb != NULL)
    495         {
    496             mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT *) p_buf);
    497         }
    498         else
    499             GKI_freebuf(p_buf);
    500     }
    501 }
    502 
    503 /*******************************************************************************
    504 **
    505 ** Function         mca_rcb_alloc
    506 **
    507 ** Description      This function allocates a registration control block.
    508 **                  If no free RCB is available, it returns NULL.
    509 **
    510 ** Returns          tMCA_RCB *
    511 **
    512 *******************************************************************************/
    513 tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg)
    514 {
    515     int     i;
    516     tMCA_RCB *p_rcb = NULL;
    517 
    518     for (i=0; i<MCA_NUM_REGS; i++)
    519     {
    520         if (mca_cb.rcb[i].p_cback == NULL)
    521         {
    522             p_rcb = &mca_cb.rcb[i];
    523             memcpy (&p_rcb->reg, p_reg, sizeof(tMCA_REG));
    524             break;
    525         }
    526     }
    527     return p_rcb;
    528 }
    529 
    530 /*******************************************************************************
    531 **
    532 ** Function         mca_rcb_dealloc
    533 **
    534 ** Description      This function deallocates the RCB with the given handle.
    535 **
    536 ** Returns          void.
    537 **
    538 *******************************************************************************/
    539 void mca_rcb_dealloc(tMCA_HANDLE handle)
    540 {
    541     int      i;
    542     BOOLEAN  done = TRUE;
    543     tMCA_RCB *p_rcb;
    544     tMCA_CCB *p_ccb;
    545 
    546     if (handle && (handle<=MCA_NUM_REGS))
    547     {
    548         handle--;
    549         p_rcb = &mca_cb.rcb[handle];
    550         if (p_rcb->p_cback)
    551         {
    552             p_ccb = &mca_cb.ccb[handle*MCA_NUM_LINKS];
    553             /* check if all associated CCB are disconnected */
    554             for (i=0; i<MCA_NUM_LINKS; i++, p_ccb++)
    555             {
    556                 if (p_ccb->p_rcb)
    557                 {
    558                     done = FALSE;
    559                     mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
    560                 }
    561             }
    562 
    563             if (done)
    564             {
    565                 memset (p_rcb, 0, sizeof(tMCA_RCB));
    566                 MCA_TRACE_DEBUG("Reset MCA_RCB index=%d",handle);
    567             }
    568         }
    569     }
    570 }
    571 
    572 /*******************************************************************************
    573 **
    574 ** Function         mca_rcb_to_handle
    575 **
    576 ** Description      This function converts a pointer to an RCB to
    577 **                  a handle (tMCA_HANDLE).  It returns the handle.
    578 **
    579 ** Returns          void.
    580 **
    581 *******************************************************************************/
    582 tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb)
    583 {
    584     return(UINT8) (p_rcb - mca_cb.rcb + 1);
    585 }
    586 
    587 /*******************************************************************************
    588 **
    589 ** Function         mca_rcb_by_handle
    590 **
    591 ** Description      This function finds the RCB for a handle (tMCA_HANDLE).
    592 **                  It returns a pointer to the RCB.  If no RCB matches the
    593 **                  handle it returns NULL.
    594 **
    595 ** Returns          tMCA_RCB *
    596 **
    597 *******************************************************************************/
    598 tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle)
    599 {
    600     tMCA_RCB *p_rcb = NULL;
    601 
    602     if (handle && (handle<=MCA_NUM_REGS) && mca_cb.rcb[handle-1].p_cback)
    603     {
    604         p_rcb = &mca_cb.rcb[handle-1];
    605     }
    606     return p_rcb;
    607 }
    608 
    609 /*******************************************************************************
    610 **
    611 ** Function         mca_is_valid_dep_id
    612 **
    613 ** Description      This function checks if the given dep_id is valid.
    614 **
    615 ** Returns          TRUE, if this is a valid local dep_id
    616 **
    617 *******************************************************************************/
    618 BOOLEAN mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep)
    619 {
    620     BOOLEAN valid = FALSE;
    621     if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
    622     {
    623         valid = TRUE;
    624     }
    625     return valid;
    626 }
    627 
    628 /*******************************************************************************
    629 **
    630 ** Function         mca_free_buf
    631 **
    632 ** Description      free memory for specified GKI packet
    633 **
    634 ** Returns          void
    635 **
    636 *******************************************************************************/
    637 void mca_free_buf (void **p_buf)
    638 {
    639     if (p_buf && *p_buf)
    640     {
    641         GKI_freebuf(*p_buf);
    642         *p_buf = NULL;
    643     }
    644 }
    645