示例#1
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_config_cfm_cback
**
** Description      This is the L2CAP config confirm callback function.
**
**
** Returns          void
**
*******************************************************************************/
void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
{
    tAVCT_LCB       *p_lcb;

    /* look up lcb for this channel */
    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
        AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
                         lcid, p_lcb->ch_state, p_cfg->result);
        /* if in correct state */
        if (p_lcb->ch_state == AVCT_CH_CFG) {
            /* if result successful */
            if (p_cfg->result == L2CAP_CFG_OK) {
                /* update flags */
                p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;

                /* if configuration complete */
                if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) {
                    p_lcb->ch_state = AVCT_CH_OPEN;
                    avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
                }
            }
            /* else failure */
            else {
                AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
                /* store result value */
                p_lcb->ch_result = p_cfg->result;

                /* Send L2CAP disconnect req */
                L2CA_DisconnectReq(lcid);
            }
        }
        AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
    }
}
示例#2
0
文件: avct_lcb.c 项目: morrey/bt_bcm
/*******************************************************************************
**
** Function         avct_lcb_dealloc
**
** Description      Deallocate a link control block.
**
**
** Returns          void.
**
*******************************************************************************/
void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
    BOOLEAN     found = FALSE;
    int         i;
    UNUSED(p_data);

    AVCT_TRACE_DEBUG("avct_lcb_dealloc %d", p_lcb->allocated);

    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
    {
        /* if ccb allocated and */
        if (p_ccb->allocated)
        {
            if (p_ccb->p_lcb == p_lcb)
            {
                AVCT_TRACE_DEBUG("avct_lcb_dealloc used by ccb: %d", i);
                found = TRUE;
                break;
            }
        }
    }

    if (!found)
    {
        AVCT_TRACE_DEBUG("avct_lcb_dealloc now");

        /* clear reassembled msg buffer if in use */
        if (p_lcb->p_rx_msg != NULL)
        {
            GKI_freebuf(p_lcb->p_rx_msg);
        }
        memset(p_lcb, 0, sizeof(tAVCT_LCB));
    }
}
示例#3
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_config_ind_cback
**
** Description      This is the L2CAP config indication callback function.
**
**
** Returns          void
**
*******************************************************************************/
void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
{
    tAVCT_LCB       *p_lcb;

    /* look up lcb for this channel */
    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
        AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
        /* store the mtu in tbl */
        if (p_cfg->mtu_present) {
            p_lcb->peer_mtu = p_cfg->mtu;
        } else {
            p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
        }

        /* send L2CAP configure response */
        memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
        p_cfg->result = L2CAP_CFG_OK;
        L2CA_ConfigRsp(lcid, p_cfg);

        /* if first config ind */
        if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
            /* update flags */
            p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;

            /* if configuration complete */
            if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) {
                p_lcb->ch_state = AVCT_CH_OPEN;
                avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
            }
        }
        AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
    }
}
示例#4
0
/*******************************************************************************
**
** Function         avct_lcb_dealloc
**
** Description      Deallocate a link control block.
**
**
** Returns          void.
**
*******************************************************************************/
void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
    UNUSED(p_data);

    AVCT_TRACE_DEBUG("%s allocated: %d", __func__, p_lcb->allocated);

    // Check if the LCB is still referenced

    tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
    for (size_t i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
    {
        if (p_ccb->allocated && p_ccb->p_lcb == p_lcb)
        {
            AVCT_TRACE_DEBUG("%s LCB in use; lcb index: %d", __func__, i);
            return;
        }
    }

    // If not, de-allocate now...

    AVCT_TRACE_DEBUG("%s Freeing LCB", __func__);
    osi_free(p_lcb->p_rx_msg);
    fixed_queue_free(p_lcb->tx_q, NULL);
    memset(p_lcb, 0, sizeof(tAVCT_LCB));
}
示例#5
0
文件: avct_lcb.c 项目: morrey/bt_bcm
/*******************************************************************************
**
** Function         avct_bcb_dealloc
**
** Description      Deallocate a browse control block.
**
**
** Returns          void.
**
*******************************************************************************/
void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
{
    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
    BOOLEAN     found = FALSE;
    int         i;

    if (p_bcb != NULL)
    {
        AVCT_TRACE_DEBUG("avct_bcb_dealloc %d", p_bcb->allocated);
        for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
        {
            /* if ccb allocated and */
            if (p_ccb->allocated)
            {
                if (p_ccb->p_bcb == p_bcb)
                {
                    AVCT_TRACE_DEBUG("avct_lcb_dealloc used by ccb: %d", i);
                    found = TRUE;
                    break;
                }
            }
        }

        if (!found)
        {
           AVCT_TRACE_DEBUG("avct_bcb_dealloc now");
           memset(p_bcb, 0, sizeof(tAVCT_BCB));
        }
    }
    else
    {
        AVCT_TRACE_ERROR("### dealloc Null bcb");
    }

}
示例#6
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_connect_ind_cback
**
** Description      This is the L2CAP connect indication callback function.
**
**
** Returns          void
**
*******************************************************************************/
void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
{
    tAVCT_LCB       *p_lcb;
    UINT16          result = L2CAP_CONN_OK;
    tL2CAP_CFG_INFO cfg;
    UNUSED(psm);

    /* do we already have a channel for this peer? */
    if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL) {
        /* no, allocate lcb */
        if ((p_lcb = avct_lcb_alloc(bd_addr)) == NULL) {
            /* no ccb available, reject L2CAP connection */
            result = L2CAP_CONN_NO_RESOURCES;
        }
    }
    /* else we already have a channel for this peer */
    else {
        if (!avct_l2c_is_passive (p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN)) {
            /* this LCB included CT role - reject */
            result = L2CAP_CONN_NO_RESOURCES;
        } else {
            /* TG role only - accept the connection from CT. move the channel ID to the conflict list */
            p_lcb->conflict_lcid = p_lcb->ch_lcid;
            AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
        }
    }

    if (p_lcb) {
        AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
                         lcid, result, p_lcb->ch_state);
    }
    /* Send L2CAP connect rsp */
    L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);

    /* if result ok, proceed with connection */
    if (result == L2CAP_CONN_OK) {
        /* store LCID */
        p_lcb->ch_lcid = lcid;

        /* transition to configuration state */
        p_lcb->ch_state = AVCT_CH_CFG;

        /* Send L2CAP config req */
        memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
        cfg.mtu_present = TRUE;
        cfg.mtu = avct_cb.mtu;
        L2CA_ConfigReq(lcid, &cfg);
        AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
    }

#if (BT_USE_TRACES == TRUE)
    if (p_lcb) {
        AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state);
    }
#endif
}
示例#7
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_disconnect_ind_cback
**
** Description      This is the L2CAP disconnect indication callback function.
**
**
** Returns          void
**
*******************************************************************************/
void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
{
    tAVCT_LCB       *p_lcb;
    UINT16          result = AVCT_RESULT_FAIL;

    /* look up lcb for this channel */
    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
        AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
        if (ack_needed) {
            /* send L2CAP disconnect response */
            L2CA_DisconnectRsp(lcid);
        }

        avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
        AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
    }
}
示例#8
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_disconnect_cfm_cback
**
** Description      This is the L2CAP disconnect confirm callback function.
**
**
** Returns          void
**
*******************************************************************************/
void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
{
    tAVCT_LCB       *p_lcb;
    UINT16          res;

    /* look up lcb for this channel */
    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
        AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
                         lcid, p_lcb->ch_state, result);
        /* result value may be previously stored */
        res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
        p_lcb->ch_result = 0;

        avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
        AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
    }
}
示例#9
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_connect_cfm_cback
**
** Description      This is the L2CAP connect confirm callback function.
**
**
** Returns          void
**
*******************************************************************************/
void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
{
    tAVCT_LCB       *p_lcb;
    tL2CAP_CFG_INFO cfg;

    /* look up lcb for this channel */
    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
        AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, conflict_lcid:0x%x",
                         lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
        /* if in correct state */
        if (p_lcb->ch_state == AVCT_CH_CONN) {
            /* if result successful */
            if (result == L2CAP_CONN_OK) {
                /* set channel state */
                p_lcb->ch_state = AVCT_CH_CFG;

                /* Send L2CAP config req */
                memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
                cfg.mtu_present = TRUE;
                cfg.mtu = avct_cb.mtu;
                L2CA_ConfigReq(lcid, &cfg);
                AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
            }
            /* else failure */
            else {
                AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
                if (p_lcb->conflict_lcid == lcid) {
                    p_lcb->conflict_lcid = 0;
                } else {
                    avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
                }
            }
        } else if (p_lcb->conflict_lcid == lcid) {
            /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
            AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", p_lcb->ch_state, p_lcb->conflict_lcid);
            if (result == L2CAP_CONN_OK) {
                /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
                L2CA_DisconnectReq(lcid);
            }
            p_lcb->conflict_lcid = 0;
        }
        AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
    }
}
示例#10
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_congestion_ind_cback
**
** Description      This is the L2CAP congestion indication callback function.
**
**
** Returns          void
**
*******************************************************************************/
void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
{
    tAVCT_LCB       *p_lcb;

    AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
    /* look up lcb for this channel */
    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
        avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
    }
}
示例#11
0
文件: avct_lcb.c 项目: morrey/bt_bcm
/*****************************************************************************
**
** Function         avct_lcb_by_bcb
**
** Description      This
**
** Returns          pointer to the lcb, or NULL if none found.
**
*******************************************************************************/
tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb)
{
    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
    int         i;
    for (i = 0; i < AVCT_NUM_CONN; i++)
    {
        AVCT_TRACE_DEBUG("avct_lcb_alloc= %d", p_bcb->allocated);
        if(p_ccb[i].allocated && p_ccb[i].p_bcb == p_bcb)
            return avct_cb.ccb[i].p_lcb;
    }
    AVCT_TRACE_ERROR("###avct_lcb_by_bcb ERROR");
    return NULL ;
}
示例#12
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_data_ind_cback
**
** Description      This is the L2CAP data indication callback function.
**
**
** Returns          void
**
*******************************************************************************/
void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
{
    tAVCT_LCB       *p_lcb;

    AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
    /* look up lcb for this channel */
    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
        avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
    } else { /* prevent buffer leak */
        AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
        osi_free(p_buf);
    }
}
示例#13
0
文件: avct_lcb.c 项目: morrey/bt_bcm
tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid)
{
    AVCT_TRACE_DEBUG("avct_bcb_by_lcid :=%x",lcid);
    tAVCT_BCB  *p_bcb = &avct_cb.bcb[0];
    int         i;

    for (i = 0; i < AVCT_NUM_LINKS; i++, p_bcb++)
    {
        if (p_bcb->allocated && ((p_bcb->ch_lcid == lcid)))
        {
            AVCT_TRACE_DEBUG("avct_bcb_by_lcid :=%x",p_bcb->ch_lcid);
            break;
        }
    }
    if (i == AVCT_NUM_LINKS)
    {
        /*out of bcbs */
        p_bcb = NULL;
        AVCT_TRACE_WARNING("###No bcb for lcid %x", lcid);
    }
    return p_bcb;
}
示例#14
0
文件: avct_lcb.c 项目: morrey/bt_bcm
/*****************************************************************************
**
** Function         avct_bcb_by_lcb
**
** Description      This function finds bcb associated to a lcb
**
** Returns          pointer to the bcb , or NULL if none found.
**
*******************************************************************************/
tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb)
{
    int         i;
    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
    {
        AVCT_TRACE_DEBUG("avct_bcb_by_lcb %d , ccb ", p_ccb->allocated);
        if ( p_ccb->p_lcb == p_lcb )
        {
            return avct_cb.ccb[i].p_bcb;
        }
    }
    AVCT_TRACE_ERROR("###avct_bcb_by_lcb ERROR");
    return NULL ;
}
示例#15
0
文件: avct_lcb.c 项目: morrey/bt_bcm
/*******************************************************************************
**
** Function         avct_lcb_has_pid
**
** Description      See if any ccbs on this lcb have a particular pid.
**
**
** Returns          Pointer to CCB if PID found, NULL otherwise.
**
*******************************************************************************/
tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid)
{
    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
    int         i;

    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
    {
        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid))
        {
            AVCT_TRACE_DEBUG("avct_lcb_has_pid, found");
            return p_ccb;
        }
    }
    AVCT_TRACE_WARNING("avct_lcb_has_pid, not found");
    return NULL;
}
示例#16
0
文件: avct_l2c.c 项目: tve/esp-idf
/*******************************************************************************
**
** Function         avct_l2c_is_passive
**
** Description      check is the CCB associated with the given LCB was created
**                  as passive
**
** Returns          TRUE, if the given LCB is created as AVCT_PASSIVE
**
*******************************************************************************/
static BOOLEAN avct_l2c_is_passive (tAVCT_LCB *p_lcb)
{
    BOOLEAN     is_passive = FALSE;
    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
    int         i;

    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
            AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
            if (p_ccb->cc.control & AVCT_PASSIVE) {
                is_passive = TRUE;
                break;
            }
        }
    }
    return is_passive;
}
示例#17
0
/*******************************************************************************
**
** Function         avct_ccb_alloc
**
** Description      Allocate a connection control block; copy parameters to ccb.
**
**
** Returns          pointer to the ccb, or NULL if none could be allocated.
**
*******************************************************************************/
tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc)
{
    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
    int         i;

    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
        if (!p_ccb->allocated) {
            p_ccb->allocated = AVCT_ALOC_LCB;
            memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC));
            AVCT_TRACE_DEBUG("avct_ccb_alloc %d", i);
            break;
        }
    }

    if (i == AVCT_NUM_CONN) {
        /* out of ccbs */
        p_ccb = NULL;
        AVCT_TRACE_WARNING("Out of ccbs");
    }
    return p_ccb;
}
示例#18
0
/*******************************************************************************
**
** Function         avct_lcb_by_bd
**
** Description      This lookup function finds the lcb for a BD address.
**
**
** Returns          pointer to the lcb, or NULL if none found.
**
*******************************************************************************/
tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr)
{
    tAVCT_LCB   *p_lcb = &avct_cb.lcb[0];
    int         i;

    for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) {
        /* if allocated lcb has matching lcb */
        if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN))) {
            break;
        }
    }

    if (i == AVCT_NUM_LINKS) {
        /* if no lcb found */
        p_lcb = NULL;

        AVCT_TRACE_DEBUG("No lcb for addr %02x-%02x-%02x-%02x-%02x-%02x",
                         bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
    }
    return p_lcb;
}
示例#19
0
/*******************************************************************************
**
** Function         avct_ccb_dealloc
**
** Description      Deallocate a connection control block and call application
**                  callback.
**
**
** Returns          void.
**
*******************************************************************************/
void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr)
{
    tAVCT_CTRL_CBACK    *p_cback = p_ccb->cc.p_ctrl_cback;

    AVCT_TRACE_DEBUG("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb));
#if (AVCT_BROWSE_INCLUDED == TRUE)
    if (p_ccb->p_bcb == NULL) {
        memset(p_ccb, 0, sizeof(tAVCT_CCB));
    } else {
        /* control channel is down, but the browsing channel is still connected 0 disconnect it now */
        avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
        p_ccb->p_lcb = NULL;
    }
#else
    memset(p_ccb, 0, sizeof(tAVCT_CCB));
#endif

    if (event != AVCT_NO_EVT) {
        (*p_cback)(avct_ccb_to_idx(p_ccb), event, result, bd_addr);
    }
}
示例#20
0
/*******************************************************************************
**
** Function         avct_lcb_alloc
**
** Description      Allocate a link control block.
**
**
** Returns          pointer to the lcb, or NULL if none could be allocated.
**
*******************************************************************************/
tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr)
{
    tAVCT_LCB   *p_lcb = &avct_cb.lcb[0];
    int         i;

    for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) {
        if (!p_lcb->allocated) {
            p_lcb->allocated = (UINT8)(i + 1);
            memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
            AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated);
            p_lcb->tx_q = fixed_queue_new(SIZE_MAX);
            break;
        }
    }

    if (i == AVCT_NUM_LINKS) {
        /* out of lcbs */
        p_lcb = NULL;
        AVCT_TRACE_WARNING("Out of lcbs");
    }
    return p_lcb;
}