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 <assert.h>
     26 #include <string.h>
     27 
     28 #include "bt_target.h"
     29 #include "gki.h"
     30 #include "mca_api.h"
     31 #include "mca_defs.h"
     32 #include "mca_int.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     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 
    149     MCA_TRACE_DEBUG("%s() - cb_idx: %d", __func__, p_tbl->cb_idx);
    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     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 
    190     MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
    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         if (p_dcb)
    269         {
    270             p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
    271             fcs   = p_dcb->p_chnl_cfg->fcs;
    272         }
    273     }
    274     memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    275     p_cfg->mtu_present = TRUE;
    276     p_cfg->mtu = p_tbl->my_mtu;
    277     p_cfg->fcr_present = TRUE;
    278     memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS));
    279     if (fcs & MCA_FCS_PRESNT_MASK)
    280     {
    281         p_cfg->fcs_present = TRUE;
    282         p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
    283     }
    284 }
    285 
    286 /*******************************************************************************
    287 **
    288 ** Function         mca_tc_close_ind
    289 **
    290 ** Description      This function is called by the L2CAP interface when the
    291 **                  L2CAP channel is closed.  It looks up the CCB or DCB for
    292 **                  the channel and sends it a close event.  The reason
    293 **                  parameter is the same value passed by the L2CAP
    294 **                  callback function.
    295 **
    296 ** Returns          Nothing.
    297 **
    298 *******************************************************************************/
    299 void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, UINT16 reason)
    300 {
    301     tMCA_CCB   *p_ccb;
    302     tMCA_DCB   *p_dcb;
    303     tMCA_CLOSE  close;
    304 
    305     close.param  = MCA_ACP;
    306     close.reason = reason;
    307     close.lcid   = p_tbl->lcid;
    308 
    309     MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__,
    310                      p_tbl->tcid, p_tbl->cb_idx, p_tbl->state);
    311 
    312     /* Check if the transport channel is in use */
    313     if (p_tbl->state == MCA_TC_ST_UNUSED)
    314         return;
    315 
    316     /* clear mca_tc_tbl entry */
    317     if (p_tbl->cfg_flags&MCA_L2C_CFG_DISCN_INT)
    318         close.param = MCA_INT;
    319     p_tbl->cfg_flags = 0;
    320     p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    321 
    322     /* if control channel, notify ccb that channel close */
    323     if (p_tbl->tcid == MCA_CTRL_TCID)
    324     {
    325         p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    326         mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close);
    327     }
    328     /* notify dcb that channel close */
    329     else
    330     {
    331         /* look up dcb  */
    332         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    333         if (p_dcb != NULL)
    334         {
    335             mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close);
    336         }
    337     }
    338     p_tbl->state = MCA_TC_ST_UNUSED;
    339 }
    340 
    341 /*******************************************************************************
    342 **
    343 ** Function         mca_tc_open_ind
    344 **
    345 ** Description      This function is called by the L2CAP interface when
    346 **                  the L2CAP channel is opened.  It looks up the CCB or DCB
    347 **                  for the channel and sends it an open event.
    348 **
    349 ** Returns          Nothing.
    350 **
    351 *******************************************************************************/
    352 void mca_tc_open_ind(tMCA_TC_TBL *p_tbl)
    353 {
    354     tMCA_CCB   *p_ccb;
    355     tMCA_DCB   *p_dcb;
    356     tMCA_OPEN  open;
    357 
    358     MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
    359     p_tbl->state = MCA_TC_ST_OPEN;
    360 
    361     open.peer_mtu = p_tbl->peer_mtu;
    362     open.lcid = p_tbl->lcid;
    363     /* use param to indicate the role of connection.
    364      * MCA_ACP, if ACP */
    365     open.param = MCA_INT;
    366     if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP)
    367     {
    368         open.param = MCA_ACP;
    369     }
    370 
    371     /* if control channel, notify ccb that channel open */
    372     if (p_tbl->tcid == MCA_CTRL_TCID)
    373     {
    374         p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    375 
    376         mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open);
    377     }
    378     /* must be data channel, notify dcb that channel open */
    379     else
    380     {
    381         /* look up dcb */
    382         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    383 
    384         /* put lcid in event data */
    385         if (p_dcb != NULL)
    386         {
    387             mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT *) &open);
    388         }
    389     }
    390 }
    391 
    392 
    393 /*******************************************************************************
    394 **
    395 ** Function         mca_tc_cong_ind
    396 **
    397 ** Description      This function is called by the L2CAP interface layer when
    398 **                  L2CAP calls the congestion callback.  It looks up the CCB
    399 **                  or DCB for the channel and sends it a congestion event.
    400 **                  The is_congested parameter is the same value passed by
    401 **                  the L2CAP callback function.
    402 **
    403 **
    404 ** Returns          Nothing.
    405 **
    406 *******************************************************************************/
    407 void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, BOOLEAN is_congested)
    408 {
    409     tMCA_CCB   *p_ccb;
    410     tMCA_DCB   *p_dcb;
    411 
    412     MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
    413 
    414     /* if control channel, notify ccb of congestion */
    415     if (p_tbl->tcid == MCA_CTRL_TCID)
    416     {
    417         p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    418         mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested);
    419     }
    420     /* notify dcb that channel open */
    421     else
    422     {
    423         /* look up dcb by cb_idx */
    424         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    425         if (p_dcb != NULL)
    426         {
    427             mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT *) &is_congested);
    428         }
    429     }
    430 }
    431 
    432 
    433 /*******************************************************************************
    434 **
    435 ** Function         mca_tc_data_ind
    436 **
    437 ** Description      This function is called by the L2CAP interface layer when
    438 **                  incoming data is received from L2CAP.  It looks up the CCB
    439 **                  or DCB for the channel and routes the data accordingly.
    440 **
    441 ** Returns          Nothing.
    442 **
    443 *******************************************************************************/
    444 void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf)
    445 {
    446     tMCA_CCB   *p_ccb;
    447     tMCA_DCB   *p_dcb;
    448     UINT8       event = MCA_CCB_MSG_RSP_EVT;
    449     UINT8       *p;
    450     UINT8       rej_rsp_code = MCA_RSP_SUCCESS;
    451 
    452     MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
    453 
    454     /* if control channel, handle control message */
    455     if (p_tbl->tcid == MCA_CTRL_TCID)
    456     {
    457         p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    458         if (p_ccb)
    459         {
    460             p = (UINT8*)(p_buf+1) + p_buf->offset;
    461             /* all the request opcode has bit 0 set. response code has bit 0 clear */
    462             if ((*p) & 0x01)
    463                 event = MCA_CCB_MSG_REQ_EVT;
    464 
    465             if (*p < MCA_NUM_STANDARD_OPCODE)
    466             {
    467                 if (p_buf->len != mca_std_msg_len[*p])
    468                 {
    469                     MCA_TRACE_ERROR ("$s() - opcode: %d required len: %d, got len: %d"
    470                       , __func__, *p, mca_std_msg_len[*p], p_buf->len);
    471                     rej_rsp_code = MCA_RSP_BAD_PARAM;
    472                 }
    473             }
    474             else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP))
    475             {
    476                 MCA_TRACE_ERROR ("%s() - unsupported SYNC opcode: %d len:%d"
    477                     , __func__, *p, p_buf->len);
    478                 /* reject unsupported request */
    479                 rej_rsp_code = MCA_RSP_NO_SUPPORT;
    480             }
    481             else
    482             {
    483                 MCA_TRACE_ERROR ("%s() - bad opcode: %d len:%d", __func__, *p, p_buf->len);
    484                 /* reject unsupported request */
    485                 rej_rsp_code = MCA_RSP_BAD_OPCODE;
    486             }
    487 
    488             p_buf->layer_specific = rej_rsp_code;
    489             /* forward the request/response to state machine */
    490             mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT *) p_buf);
    491         } /* got a valid ccb */
    492         else
    493             GKI_freebuf(p_buf);
    494     }
    495     /* else send event to dcb */
    496     else
    497     {
    498         p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    499         if (p_dcb != NULL)
    500         {
    501             mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT *) p_buf);
    502         }
    503         else
    504             GKI_freebuf(p_buf);
    505     }
    506 }
    507 
    508 /*******************************************************************************
    509 **
    510 ** Function         mca_rcb_alloc
    511 **
    512 ** Description      This function allocates a registration control block.
    513 **                  If no free RCB is available, it returns NULL.
    514 **
    515 ** Returns          tMCA_RCB *
    516 **
    517 *******************************************************************************/
    518 tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg)
    519 {
    520     int     i;
    521     tMCA_RCB *p_rcb = NULL;
    522 
    523     for (i=0; i<MCA_NUM_REGS; i++)
    524     {
    525         if (mca_cb.rcb[i].p_cback == NULL)
    526         {
    527             p_rcb = &mca_cb.rcb[i];
    528             memcpy (&p_rcb->reg, p_reg, sizeof(tMCA_REG));
    529             break;
    530         }
    531     }
    532     return p_rcb;
    533 }
    534 
    535 /*******************************************************************************
    536 **
    537 ** Function         mca_rcb_dealloc
    538 **
    539 ** Description      This function deallocates the RCB with the given handle.
    540 **
    541 ** Returns          void.
    542 **
    543 *******************************************************************************/
    544 void mca_rcb_dealloc(tMCA_HANDLE handle)
    545 {
    546     int      i;
    547     BOOLEAN  done = TRUE;
    548     tMCA_RCB *p_rcb;
    549     tMCA_CCB *p_ccb;
    550 
    551     if (handle && (handle<=MCA_NUM_REGS))
    552     {
    553         handle--;
    554         p_rcb = &mca_cb.rcb[handle];
    555         if (p_rcb->p_cback)
    556         {
    557             p_ccb = &mca_cb.ccb[handle*MCA_NUM_LINKS];
    558             /* check if all associated CCB are disconnected */
    559             for (i=0; i<MCA_NUM_LINKS; i++, p_ccb++)
    560             {
    561                 if (p_ccb->p_rcb)
    562                 {
    563                     done = FALSE;
    564                     mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
    565                 }
    566             }
    567 
    568             if (done)
    569             {
    570                 memset (p_rcb, 0, sizeof(tMCA_RCB));
    571                 MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle);
    572             }
    573         }
    574     }
    575 }
    576 
    577 /*******************************************************************************
    578 **
    579 ** Function         mca_rcb_to_handle
    580 **
    581 ** Description      This function converts a pointer to an RCB to
    582 **                  a handle (tMCA_HANDLE).  It returns the handle.
    583 **
    584 ** Returns          void.
    585 **
    586 *******************************************************************************/
    587 tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb)
    588 {
    589     return(UINT8) (p_rcb - mca_cb.rcb + 1);
    590 }
    591 
    592 /*******************************************************************************
    593 **
    594 ** Function         mca_rcb_by_handle
    595 **
    596 ** Description      This function finds the RCB for a handle (tMCA_HANDLE).
    597 **                  It returns a pointer to the RCB.  If no RCB matches the
    598 **                  handle it returns NULL.
    599 **
    600 ** Returns          tMCA_RCB *
    601 **
    602 *******************************************************************************/
    603 tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle)
    604 {
    605     tMCA_RCB *p_rcb = NULL;
    606 
    607     if (handle && (handle<=MCA_NUM_REGS) && mca_cb.rcb[handle-1].p_cback)
    608     {
    609         p_rcb = &mca_cb.rcb[handle-1];
    610     }
    611     return p_rcb;
    612 }
    613 
    614 /*******************************************************************************
    615 **
    616 ** Function         mca_is_valid_dep_id
    617 **
    618 ** Description      This function checks if the given dep_id is valid.
    619 **
    620 ** Returns          TRUE, if this is a valid local dep_id
    621 **
    622 *******************************************************************************/
    623 BOOLEAN mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep)
    624 {
    625     BOOLEAN valid = FALSE;
    626     if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
    627     {
    628         valid = TRUE;
    629     }
    630     return valid;
    631 }
    632 
    633 /*******************************************************************************
    634 **
    635 ** Function         mca_free_buf
    636 **
    637 ** Description      free memory for specified GKI packet
    638 **
    639 ** Returns          void
    640 **
    641 *******************************************************************************/
    642 void mca_free_buf (void **p_buf)
    643 {
    644     if (p_buf && *p_buf)
    645     {
    646         GKI_freebuf(*p_buf);
    647         *p_buf = NULL;
    648     }
    649 }
    650