예제 #1
0
/*******************************************************************************
**
** Function         llcp_util_send_connect
**
** Description      Send CONNECT PDU
**
** Returns          tLLCP_STATUS
**
******************************************************************************/
tLLCP_STATUS llcp_util_send_connect (tLLCP_DLCB *p_dlcb, tLLCP_CONNECTION_PARAMS *p_params)
{
    BT_HDR *p_msg;
    UINT8  *p;
    UINT16  miu_len = 0, rw_len = 0, sn_len = 0;

    if (p_params->miu != LLCP_DEFAULT_MIU)
    {
        miu_len = 4;    /* TYPE, LEN, 2 bytes MIU */
    }
    if (p_params->rw != LLCP_DEFAULT_RW)
    {
        rw_len = 3;     /* TYPE, LEN, 1 byte RW */
        p_params->rw &= 0x0F;   /* only 4 bits  */
    }
    if ((strlen (p_params->sn)) && (p_dlcb->remote_sap == LLCP_SAP_SDP))
    {
        sn_len = (UINT16) (2 + strlen (p_params->sn));    /* TYPE, LEN, SN */
    }

    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);

    if (p_msg)
    {
        p_msg->len    = LLCP_PDU_HEADER_SIZE + miu_len + rw_len + sn_len;
        p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;

        p = (UINT8 *) (p_msg + 1) + p_msg->offset;

        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_CONNECT_TYPE, p_dlcb->local_sap));

        if (miu_len)
        {
            UINT8_TO_BE_STREAM (p, LLCP_MIUX_TYPE);
            UINT8_TO_BE_STREAM (p, LLCP_MIUX_LEN);
            UINT16_TO_BE_STREAM (p, p_params->miu - LLCP_DEFAULT_MIU);
        }

        if (rw_len)
        {
            UINT8_TO_BE_STREAM (p, LLCP_RW_TYPE);
            UINT8_TO_BE_STREAM (p, LLCP_RW_LEN);
            UINT8_TO_BE_STREAM (p, p_params->rw);
        }

        if (sn_len)
        {
            UINT8_TO_BE_STREAM (p, LLCP_SN_TYPE);
            UINT8_TO_BE_STREAM (p, sn_len - 2);
            memcpy (p, p_params->sn, sn_len - 2);
        }

        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
        llcp_link_check_send_data ();

        return LLCP_STATUS_SUCCESS;
    }

    return LLCP_STATUS_FAIL;
}
예제 #2
0
/*******************************************************************************
**
** Function         llcp_sdp_check_send_snl
**
** Description      Enqueue Service Name Lookup PDU into sig_xmit_q for transmitting
**
**
** Returns          void
**
*******************************************************************************/
void llcp_sdp_check_send_snl (void)
{
    UINT8 *p;

    if (llcp_cb.sdp_cb.p_snl)
    {
        LLCP_TRACE_DEBUG0 ("SDP: llcp_sdp_check_send_snl ()");

        llcp_cb.sdp_cb.p_snl->len     += LLCP_PDU_HEADER_SIZE;
        llcp_cb.sdp_cb.p_snl->offset  -= LLCP_PDU_HEADER_SIZE;

        p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset;
        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (LLCP_SAP_SDP, LLCP_PDU_SNL_TYPE, LLCP_SAP_SDP ));

        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, llcp_cb.sdp_cb.p_snl);
        llcp_cb.sdp_cb.p_snl = NULL;
    }
#if(NFC_NXP_NOT_OPEN_INCLUDED == TRUE)
    else
    {
        /* Notify DTA after sending out SNL with SDRES not to send SNLs in AGF PDU */
        if ((llcp_cb.p_dta_cback) && (llcp_cb.dta_snl_resp))
        {
            llcp_cb.dta_snl_resp = FALSE;
            (*llcp_cb.p_dta_cback) ();
        }
    }
#endif
}
예제 #3
0
/*******************************************************************************
**
** Function         gap_data_ind
**
** Description      This function is called when data is received from L2CAP.
**
** Returns          void
**
*******************************************************************************/
static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
{
    tGAP_CCB    *p_ccb;

    /* Find CCB based on CID */
    if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
    {
        GKI_freebuf (p_msg);
        return;
    }

    if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
    {
        GKI_enqueue (&p_ccb->rx_queue, p_msg);

        p_ccb->rx_queue_size += p_msg->len;
        /*
        GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d",
                                       p_ccb->rx_queue_size, p_msg->len);
         */

        p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
    }
    else
    {
        GKI_freebuf (p_msg);
    }
}
예제 #4
0
/*******************************************************************************
**
** Function         llcp_util_send_frmr
**
** Description      Send FRMR PDU
**
** Returns          tLLCP_STATUS
**
*******************************************************************************/
tLLCP_STATUS llcp_util_send_frmr (tLLCP_DLCB *p_dlcb, UINT8 flags, UINT8 ptype, UINT8 sequence)
{
    BT_HDR *p_msg;
    UINT8  *p;

    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);

    if (p_msg)
    {
        p_msg->len      = LLCP_PDU_FRMR_SIZE;
        p_msg->offset   = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;

        p = (UINT8 *) (p_msg + 1) + p_msg->offset;

        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_FRMR_TYPE, p_dlcb->local_sap));
        UINT8_TO_BE_STREAM (p, (flags << 4) | ptype);
        UINT8_TO_BE_STREAM (p, sequence);
        UINT8_TO_BE_STREAM (p, (p_dlcb->next_tx_seq << 4) | p_dlcb->next_rx_seq);
        UINT8_TO_BE_STREAM (p, (p_dlcb->rcvd_ack_seq << 4) | p_dlcb->sent_ack_seq);

        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
        llcp_link_check_send_data ();

        return LLCP_STATUS_SUCCESS;
    }
    else
    {
        LLCP_TRACE_ERROR0 ("llcp_util_send_frmr (): Out of resource");
        return LLCP_STATUS_FAIL;
    }
}
예제 #5
0
/*******************************************************************************
**
** Function         llcp_util_send_ui
**
** Description      Send UI PDU
**
** Returns          tLLCP_STATUS
**
*******************************************************************************/
tLLCP_STATUS llcp_util_send_ui (UINT8 ssap, UINT8 dsap, tLLCP_APP_CB *p_app_cb, BT_HDR *p_msg)
{
    UINT8        *p;
    tLLCP_STATUS status = LLCP_STATUS_SUCCESS;

    p_msg->offset -= LLCP_PDU_HEADER_SIZE;
    p_msg->len    += LLCP_PDU_HEADER_SIZE;

    p = (UINT8 *) (p_msg + 1) + p_msg->offset;
    UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (dsap, LLCP_PDU_UI_TYPE, ssap));

    GKI_enqueue (&p_app_cb->ui_xmit_q, p_msg);
    llcp_cb.total_tx_ui_pdu++;

    llcp_link_check_send_data ();

    if (  (p_app_cb->is_ui_tx_congested)
        ||(p_app_cb->ui_xmit_q.count >= llcp_cb.ll_tx_congest_start)
        ||(llcp_cb.overall_tx_congested)
        ||(llcp_cb.total_tx_ui_pdu >= llcp_cb.max_num_ll_tx_buff)  )
    {
        /* set congested here so overall congestion check routine will not report event again, */
        /* or notify uncongestion later                                                        */
        p_app_cb->is_ui_tx_congested = TRUE;

        LLCP_TRACE_WARNING2 ("Logical link (SAP=0x%X) congested: ui_xmit_q.count=%d",
                              ssap, p_app_cb->ui_xmit_q.count);

        status = LLCP_STATUS_CONGESTED;
    }

    return status;
}
예제 #6
0
/*******************************************************************************
**
** Function         btm_ble_enqueue_direct_conn_req
**
** Description      This function enqueue the direct connection request
**
** Returns          None.
**
*******************************************************************************/
void btm_ble_enqueue_direct_conn_req(void *p_param)
{
    tBTM_BLE_CONN_REQ   *p = (tBTM_BLE_CONN_REQ *)GKI_getbuf(sizeof(tBTM_BLE_CONN_REQ));

    p->p_param = p_param;

    GKI_enqueue (&btm_cb.ble_ctr_cb.conn_pending_q, p);
}
/*******************************************************************************
**
** Function         btm_ble_enqueue_direct_conn_req
**
** Description      This function enqueue the direct connection request
**
** Returns          None.
**
*******************************************************************************/
void btm_ble_enqueue_direct_conn_req(void *p_param)
{
    tBTM_BLE_CONN_REQ   *p = (tBTM_BLE_CONN_REQ *)GKI_getbuf(sizeof(tBTM_BLE_CONN_REQ));

    if (NULL != p)
    {
        p->p_param = p_param;
        GKI_enqueue (&btm_cb.ble_ctr_cb.conn_pending_q, p);
    } else {
        BTM_TRACE_ERROR ("%s: Failed to get memory", __FUNCTION__);
    }
}
/*******************************************************************************
**
** Function         bta_pan_data_buf_ind_cback
**
** Description      data indication callback from pan profile
**
**
** Returns          void
**
*******************************************************************************/
static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf,
                                   BOOLEAN ext, BOOLEAN forward)
{
    tBTA_PAN_SCB *p_scb;
    BT_HDR * p_event;
    BT_HDR *p_new_buf;

    if ( sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset )
    {
        /* offset smaller than data structure in front of actual data */
        p_new_buf = (BT_HDR *)GKI_getpoolbuf( PAN_POOL_ID );
        if(!p_new_buf)
        {
            APPL_TRACE_WARNING0("Cannot get a PAN GKI buffer");
            GKI_freebuf( p_buf );
            return;
        }
        else
        {
            memcpy( (UINT8 *)(p_new_buf+1)+sizeof(tBTA_PAN_DATA_PARAMS), (UINT8 *)(p_buf+1)+p_buf->offset, p_buf->len );
            p_new_buf->len    = p_buf->len;
            p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
            GKI_freebuf( p_buf );
        }
    }
    else
    {
        p_new_buf = p_buf;
    }
    /* copy params into the space before the data */
    bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->src, src);
    bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->dst, dst);
    ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->protocol = protocol;
    ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->ext = ext;
    ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->forward = forward;


    if((p_scb = bta_pan_scb_by_handle(handle)) == NULL)
    {

        GKI_freebuf( p_new_buf );
        return;
    }

    GKI_enqueue(&p_scb->data_queue, p_new_buf);
    if ((p_event = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
    {
        p_event->layer_specific = handle;
        p_event->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
        bta_sys_sendmsg(p_event);
    }

}
예제 #9
0
/*******************************************************************************
**
** Function         llcp_util_send_cc
**
** Description      Send CC PDU
**
** Returns          tLLCP_STATUS
**
******************************************************************************/
tLLCP_STATUS llcp_util_send_cc (tLLCP_DLCB *p_dlcb, tLLCP_CONNECTION_PARAMS *p_params)
{
    BT_HDR *p_msg;
    UINT8  *p;
    UINT16  miu_len = 0, rw_len = 0;

    if (p_params->miu != LLCP_DEFAULT_MIU)
    {
        miu_len = 4;
    }
    if (p_params->rw != LLCP_DEFAULT_RW)
    {
        rw_len = 3;
        p_params->rw &= 0x0F;
    }

    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);

    if (p_msg)
    {
        p_msg->len      = LLCP_PDU_HEADER_SIZE + miu_len + rw_len;
        p_msg->offset   = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;

        p = (UINT8 *) (p_msg + 1) + p_msg->offset;

        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_CC_TYPE, p_dlcb->local_sap));

        if (miu_len)
        {
            UINT8_TO_BE_STREAM (p, LLCP_MIUX_TYPE);
            UINT8_TO_BE_STREAM (p, LLCP_MIUX_LEN);
            UINT16_TO_BE_STREAM (p, p_params->miu - LLCP_DEFAULT_MIU);
        }

        if (rw_len)
        {
            UINT8_TO_BE_STREAM (p, LLCP_RW_TYPE);
            UINT8_TO_BE_STREAM (p, LLCP_RW_LEN);
            UINT8_TO_BE_STREAM (p, p_params->rw);
        }

        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
        llcp_link_check_send_data ();

        return LLCP_STATUS_SUCCESS;
    }

    return LLCP_STATUS_FAIL;
}
예제 #10
0
/*******************************************************************************
**
** Function         GAP_ConnBTWrite
**
** Description      Bluetooth Aware applications can call this function to write data.
**
** Parameters:      handle      - Handle of the connection returned in the Open
**                  p_buf      - pointer to address of buffer with data,
**
** Returns          BT_PASS                 - data read
**                  GAP_ERR_BAD_HANDLE      - invalid handle
**                  GAP_ERR_BAD_STATE       - connection not established
**                  GAP_INVALID_BUF_OFFSET  - buffer offset is invalid
*******************************************************************************/
UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf)
{
    tGAP_CCB    *p_ccb = gap_find_ccb_by_handle (gap_handle);

    if (!p_ccb)
    {
        GKI_freebuf (p_buf);
        return (GAP_ERR_BAD_HANDLE);
    }

    if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED)
    {
        GKI_freebuf (p_buf);
        return (GAP_ERR_BAD_STATE);
    }

    if (p_buf->offset < L2CAP_MIN_OFFSET)
    {
        GKI_freebuf (p_buf);
        return (GAP_ERR_BUF_OFFSET);
    }

    GKI_enqueue (&p_ccb->tx_queue, p_buf);

    if (p_ccb->is_congested)
    {
        return (BT_PASS);
    }

    /* Send the buffer through L2CAP */
#if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
    gap_send_event (gap_handle);
#else
    while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL)
    {
        UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);

        if (status == L2CAP_DW_CONGESTED)
        {
            p_ccb->is_congested = TRUE;
            break;
        }
        else if (status != L2CAP_DW_SUCCESS)
            return (GAP_ERR_BAD_STATE);
    }
#endif
    return (BT_PASS);
}
예제 #11
0
/*******************************************************************************
 **
 ** Function        btusb_lite_hci_cmd_cplt_evt_send
 **
 ** Description     Send an HCI VSC Cmd Complete.
 **
 ** Returns         Void
 **
 *******************************************************************************/
static void btusb_lite_hci_cmd_cplt_evt_send(struct btusb *p_dev,
        UINT16 opcode, UINT8 *p_param, UINT8 param_len)
{
    BT_HDR *p_msg;
    UINT16 size = param_len + 5;
    UINT8 *p;

    /* Get a buffer from the pool */
    p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + size);
    if(unlikely(!p_msg))
    {
        BTUSB_ERR("Unable to get GKI buffer\n");
        return;
    }

    if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) &&
        unlikely(GKI_buffer_status(p_msg) != BUF_STATUS_UNLINKED))
    {
        BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_msg);
        return;
    }

    p_msg->offset = 0;
    p_msg->event = HCIT_TYPE_EVENT;
    p_msg->len = size;
    p_msg->layer_specific = BTUSB_LS_GKI_BUFFER;

    p = (UINT8 *)(p_msg + 1) + p_msg->offset;

    p = btusb_lite_hci_write_evt_header(p, HCI_COMMAND_COMPLETE_EVT, size - 2);

    UINT8_TO_STREAM(p, BTUSB_LITE_HCI_NUM_CMD);  /* HCI Num Command */
    UINT16_TO_STREAM(p, opcode);  /* HCI OpCode */

    if (p_param)
    {
        ARRAY_TO_STREAM(p, p_param, param_len)
    }

    /* InQ for user-space to read */
    GKI_enqueue(&p_dev->rx_queue, p_msg);

    /* if the process is polling, indicate RX event */
    wake_up_interruptible(&p_dev->rx_wait_q);
}
/*******************************************************************************
**
** Function         llcp_sdp_check_send_snl
**
** Description      Enqueue Service Name Lookup PDU into sig_xmit_q for transmitting
**
**
** Returns          void
**
*******************************************************************************/
void llcp_sdp_check_send_snl (void)
{
    UINT8 *p;

    if (llcp_cb.sdp_cb.p_snl)
    {
        LLCP_TRACE_DEBUG0 ("SDP: llcp_sdp_check_send_snl ()");

        llcp_cb.sdp_cb.p_snl->len     += LLCP_PDU_HEADER_SIZE;
        llcp_cb.sdp_cb.p_snl->offset  -= LLCP_PDU_HEADER_SIZE;

        p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset;
        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (LLCP_SAP_SDP, LLCP_PDU_SNL_TYPE, LLCP_SAP_SDP ));

        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, llcp_cb.sdp_cb.p_snl);
        llcp_cb.sdp_cb.p_snl = NULL;
    }
}
예제 #13
0
/*******************************************************************************
**
** Function         llcp_util_send_disc
**
** Description      Send DISC PDU
**
** Returns          void
**
*******************************************************************************/
void llcp_util_send_disc (UINT8 dsap, UINT8 ssap)
{
    BT_HDR *p_msg;
    UINT8  *p;

    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);

    if (p_msg)
    {
        p_msg->len      = LLCP_PDU_DISC_SIZE;
        p_msg->offset   = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;

        p = (UINT8 *) (p_msg + 1) + p_msg->offset;
        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (dsap, LLCP_PDU_DISC_TYPE, ssap));

        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
        llcp_link_check_send_data ();
    }
}
/*******************************************************************************
**
** Function         bta_av_dup_audio_buf
**
** Description      dup the audio data to the q_info.a2d of other audio channels
**
** Returns          void
**
*******************************************************************************/
void bta_av_dup_audio_buf(tBTA_AV_SCB *p_scb, BT_HDR *p_buf)
{
    tBTA_AV_SCB *p_scbi;
    BUFFER_Q    *pq;
    int     i;
    UINT16  size, copy_size;
    BT_HDR *p_new;

    if(!p_buf)
        return;

    if(bta_av_cb.audio_open_cnt >= 2)
    {
        size = GKI_get_buf_size(p_buf);
        copy_size = BT_HDR_SIZE + p_buf->len + p_buf->offset;
        /* more than one audio channel is connected */
        for(i=0; i<BTA_AV_NUM_STRS; i++)
        {
            p_scbi = bta_av_cb.p_scb[i];
            if( (p_scb->hdi != i) && /* not the original channel */
                (bta_av_cb.conn_audio & BTA_AV_HNDL_TO_MSK(i)) && /* connected audio */
                p_scbi && p_scbi->co_started ) /* scb is used and started */
            {
                /* enqueue the data only when the stream is started */
                p_new = (BT_HDR *)GKI_getbuf(size);
                if(p_new)
                {
                    memcpy(p_new, p_buf, copy_size);
                    pq = &p_scbi->q_info.a2d;
                    GKI_enqueue(pq, p_new);
                    if(pq->count > p_bta_av_cfg->audio_mqs)
                    {
                        bta_av_co_audio_drop(p_scbi->hndl);
                        GKI_freebuf(GKI_dequeue(pq));
                    }
                }
            }
        }
    }

}
예제 #15
0
/*******************************************************************************
**
** Function         GAP_ConnWriteData
**
** Description      Normally not GKI aware application will call this function
**                  to send data to the connection.
**
** Parameters:      handle      - Handle of the connection returned in the Open
**                  p_data      - Data area
**                  max_len     - Byte count requested
**                  p_len       - Byte count received
**
** Returns          BT_PASS                 - data read
**                  GAP_ERR_BAD_HANDLE      - invalid handle
**                  GAP_ERR_BAD_STATE       - connection not established
**                  GAP_CONGESTION          - system is congested
**
*******************************************************************************/
UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len)
{
    tGAP_CCB    *p_ccb = gap_find_ccb_by_handle (gap_handle);
    BT_HDR     *p_buf;

    *p_len = 0;

    if (!p_ccb)
        return (GAP_ERR_BAD_HANDLE);

    if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED)
        return (GAP_ERR_BAD_STATE);

    while (max_len)
    {
        if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
        {
            if ((p_buf = (BT_HDR *)GKI_getpoolbuf (p_ccb->ertm_info.user_tx_pool_id)) == NULL)
                return (GAP_ERR_CONGESTED);
        }
        else
        {
            if ((p_buf = (BT_HDR *)GKI_getpoolbuf (GAP_DATA_POOL_ID)) == NULL)
                return (GAP_ERR_CONGESTED);
        }

        p_buf->offset = L2CAP_MIN_OFFSET;
        p_buf->len = (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len;
        p_buf->event = BT_EVT_TO_BTU_SP_DATA;

        memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);

        *p_len  += p_buf->len;
        max_len -= p_buf->len;
        p_data  += p_buf->len;

        GAP_TRACE_EVENT ("GAP_WriteData %d bytes", p_buf->len);

        GKI_enqueue (&p_ccb->tx_queue, p_buf);
    }

    if (p_ccb->is_congested)
    {
        return (BT_PASS);
    }

    /* Send the buffer through L2CAP */
#if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
    gap_send_event (gap_handle);
#else
    while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL)
    {
        UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);

        if (status == L2CAP_DW_CONGESTED)
        {
            p_ccb->is_congested = TRUE;
            break;
        }
        else if (status != L2CAP_DW_SUCCESS)
            return (GAP_ERR_BAD_STATE);
    }
#endif
    return (BT_PASS);
}
예제 #16
0
/*******************************************************************************
**
** Function         llcp_util_send_rr_rnr
**
** Description      Send RR or RNR PDU
**
** Returns          void
**
*******************************************************************************/
void llcp_util_send_rr_rnr (tLLCP_DLCB *p_dlcb)
{
    BT_HDR *p_msg;
    UINT8  *p;
    UINT8   pdu_type;
    UINT8   pdu_size;
    UINT8   rcv_seq;

    /* if no indication of change in local busy or rx congestion */
    if ((p_dlcb->flags & LLCP_DATA_LINK_FLAG_PENDING_RR_RNR) == 0)
    {
        /* if all ack is sent */
        if (p_dlcb->sent_ack_seq == p_dlcb->next_rx_seq)
        {
            /* we don't need to send RR/RNR */
            return;
        }
        else
        {
            /* if rx flow off because of local busy or congestion */
            if (  (p_dlcb->local_busy)
                ||(p_dlcb->is_rx_congested)
                ||(llcp_cb.overall_rx_congested)  )
            {
                /* don't send RR/RNR */
                return;
            }
        }
    }

    if (  (p_dlcb->local_busy)
        ||(p_dlcb->is_rx_congested)
        ||(llcp_cb.overall_rx_congested)  )
    {
        LLCP_TRACE_DEBUG3 ("llcp_util_send_rr_rnr (): local_busy=%d,is_rx_congested=%d,overall_rx_congested=%d",
                            p_dlcb->local_busy, p_dlcb->is_rx_congested, llcp_cb.overall_rx_congested);

        /* if local_busy or rx congested then do not update receive sequence number to flow off */
        pdu_type = LLCP_PDU_RNR_TYPE;
        pdu_size = LLCP_PDU_RNR_SIZE;
        rcv_seq = p_dlcb->sent_ack_seq;
    }
    else
    {
        pdu_type = LLCP_PDU_RR_TYPE;
        pdu_size = LLCP_PDU_RR_SIZE;

        p_dlcb->sent_ack_seq = p_dlcb->next_rx_seq;
        rcv_seq = p_dlcb->sent_ack_seq;
    }

    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);

    if (p_msg)
    {
        p_dlcb->flags &= ~LLCP_DATA_LINK_FLAG_PENDING_RR_RNR;

        p_msg->len    = pdu_size;
        p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;

        p = (UINT8 *) (p_msg + 1) + p_msg->offset;

        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, pdu_type, p_dlcb->local_sap));

        UINT8_TO_BE_STREAM (p, rcv_seq);

#if (BT_TRACE_VERBOSE == TRUE)
        LLCP_TRACE_DEBUG5 ("LLCP TX - N(S,R):(NA,%d) V(S,SA,R,RA):(%d,%d,%d,%d)",
                            p_dlcb->next_rx_seq,
                            p_dlcb->next_tx_seq, p_dlcb->rcvd_ack_seq,
                            p_dlcb->next_rx_seq, p_dlcb->sent_ack_seq);
#endif
        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
        llcp_link_check_send_data ();
    }
    else
    {
        LLCP_TRACE_ERROR0 ("llcp_util_send_rr_rnr (): Out of resource");
    }
}
예제 #17
0
/*******************************************************************************
**
** Function         l2c_rcv_acl_data
**
** Description      This function is called from the HCI Interface when an ACL
**                  data packet is received.
**
** Returns          void
**
*******************************************************************************/
void l2c_rcv_acl_data (BT_HDR *p_msg)
{
    UINT8       *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
    UINT16      handle, hci_len;
    UINT8       pkt_type;
    tL2C_LCB    *p_lcb;
    tL2C_CCB    *p_ccb = NULL;
    UINT16      l2cap_len, rcv_cid, psm;

    /* Extract the handle */
    STREAM_TO_UINT16 (handle, p);
    pkt_type = HCID_GET_EVENT (handle);
    handle   = HCID_GET_HANDLE (handle);

    /* Since the HCI Transport is putting segmented packets back together, we */
    /* should never get a valid packet with the type set to "continuation"    */
    if (pkt_type != L2CAP_PKT_CONTINUE)
    {
        /* Find the LCB based on the handle */
        if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
        {
            UINT8       cmd_code;

            /* There is a slight possibility (specifically with USB) that we get an */
            /* L2CAP connection request before we get the HCI connection complete.  */
            /* So for these types of messages, hold them for up to 2 seconds.       */
            STREAM_TO_UINT16 (hci_len, p);
            STREAM_TO_UINT16 (l2cap_len, p);
            STREAM_TO_UINT16 (rcv_cid, p);
            STREAM_TO_UINT8  (cmd_code, p);

            if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID)
                && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ))
            {
                L2CAP_TRACE_WARNING5 ("L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
                                    handle, p_msg->layer_specific, rcv_cid, cmd_code,
                                    l2cb.rcv_hold_q.count);
                p_msg->layer_specific = 2;
                GKI_enqueue (&l2cb.rcv_hold_q, p_msg);

                if (l2cb.rcv_hold_q.count == 1)
                    btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);

                return;
            }
            else
            {
                L2CAP_TRACE_ERROR5 ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
                                    handle, p_msg->layer_specific, rcv_cid, cmd_code, l2cb.rcv_hold_q.count);
            }
            GKI_freebuf (p_msg);
            return;
        }
    }
    else
    {
        L2CAP_TRACE_WARNING1 ("L2CAP - expected pkt start or complete, got: %d", pkt_type);
        GKI_freebuf (p_msg);
        return;
    }

    /* Extract the length and update the buffer header */
    STREAM_TO_UINT16 (hci_len, p);
    p_msg->offset += 4;

#if (L2CAP_HOST_FLOW_CTRL == TRUE)
    /* Send ack if we hit the threshold */
    if (++p_lcb->link_pkts_unacked >= p_lcb->link_ack_thresh)
        btu_hcif_send_host_rdy_for_data();
#endif

    /* Extract the length and CID */
    STREAM_TO_UINT16 (l2cap_len, p);
    STREAM_TO_UINT16 (rcv_cid, p);

    /* Find the CCB for this CID */
    if (rcv_cid >= L2CAP_BASE_APPL_CID)
    {
        if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL)
        {
            L2CAP_TRACE_WARNING1 ("L2CAP - unknown CID: 0x%04x", rcv_cid);
            GKI_freebuf (p_msg);
            return;
        }
    }

    if (hci_len >= L2CAP_PKT_OVERHEAD)  /* Must receive at least the L2CAP length and CID.*/
    {
        p_msg->len    = hci_len - L2CAP_PKT_OVERHEAD;
        p_msg->offset += L2CAP_PKT_OVERHEAD;
    }
    else
    {
        L2CAP_TRACE_WARNING0 ("L2CAP - got incorrect hci header" );
        GKI_freebuf (p_msg);
        return;
    }

    if (l2cap_len != p_msg->len)
    {
        L2CAP_TRACE_WARNING2 ("L2CAP - bad length in pkt. Exp: %d  Act: %d",
                              l2cap_len, p_msg->len);

        GKI_freebuf (p_msg);
        return;
    }

    /* Send the data through the channel state machine */
    if (rcv_cid == L2CAP_SIGNALLING_CID)
    {
        process_l2cap_cmd (p_lcb, p, l2cap_len);
        GKI_freebuf (p_msg);
    }
    else if (rcv_cid == L2CAP_CONNECTIONLESS_CID)
    {
        /* process_connectionless_data (p_lcb); */
        STREAM_TO_UINT16 (psm, p);
        L2CAP_TRACE_DEBUG1( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ;
#if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
        if (psm == TCS_PSM_INTERCOM || psm == TCS_PSM_CORDLESS)
        {
            p_msg->offset += L2CAP_BCST_OVERHEAD;
            p_msg->len -= L2CAP_BCST_OVERHEAD;
            tcs_proc_bcst_msg( p_lcb->remote_bd_addr, p_msg ) ;
            GKI_freebuf (p_msg);
        }
        else
#endif

#if (L2CAP_UCD_INCLUDED == TRUE)
        /* if it is not broadcast, check UCD registration */
        if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) )
        {
            /* nothing to do */
        }
        else
#endif
            GKI_freebuf (p_msg);
    }
#if (BLE_INCLUDED == TRUE)
    else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID)
    {
        l2cble_process_sig_cmd (p_lcb, p, l2cap_len);
        GKI_freebuf (p_msg);
    }
#endif
#if (L2CAP_NUM_FIXED_CHNLS > 0)
    else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
             (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) )
    {
        /* If no CCB for this channel, allocate one */
        if (l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
        {
            p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];

            if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
                l2c_fcr_proc_pdu (p_ccb, p_msg);
            else
                (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_lcb->remote_bd_addr, p_msg);
        }
        else
            GKI_freebuf (p_msg);
    }
#endif

    else
    {
        if (p_ccb == NULL)
            GKI_freebuf (p_msg);
        else
        {
            /* Basic mode packets go straight to the state machine */
            if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
                l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg);
            else
            {
                /* eRTM or streaming mode, so we need to validate states first */
                if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG))
                    l2c_fcr_proc_pdu (p_ccb, p_msg);
                else
                    GKI_freebuf (p_msg);
            }
        }
    }
}
예제 #18
0
/*******************************************************************************
**
** Function         PORT_DataInd
**
** Description      This function is called from the RFCOMM layer when data
**                  buffer is received from the peer.
**
*******************************************************************************/
void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
{
    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
    UINT8  rx_char1;
    UINT32 events = 0;
    UINT8  *p;
    int    i;

    RFCOMM_TRACE_EVENT("PORT_DataInd with data length %d, p_mcb:%p,p_port:%p,dlci:%d",
                        p_buf->len, p_mcb, p_port, dlci);
    if (!p_port)
    {
        GKI_freebuf (p_buf);
        return;
    }
    /* If client registered callout callback with flow control we can just deliver receive data */
    if (p_port->p_data_co_callback)
    {
        /* Another packet is delivered to user.  Send credits to peer if required */

        if(p_port->p_data_co_callback(p_port->inx, (UINT8*)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING))
            port_flow_control_peer(p_port, TRUE, 1);
        else port_flow_control_peer(p_port, FALSE, 0);
        //GKI_freebuf (p_buf);
        return;
    }
    else RFCOMM_TRACE_ERROR("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port);
    /* If client registered callback we can just deliver receive data */
    if (p_port->p_data_callback)
    {
        /* Another packet is delivered to user.  Send credits to peer if required */
        port_flow_control_peer(p_port, TRUE, 1);

        p_port->p_data_callback (p_port->inx, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
        GKI_freebuf (p_buf);
        return;
    }

    /* Check if rx queue exceeds the limit */
    if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM)
     || (GKI_queue_length(&p_port->rx.queue) + 1 > p_port->rx_buf_critical))
    {
        RFCOMM_TRACE_EVENT ("PORT_DataInd. Buffer over run. Dropping the buffer");
        GKI_freebuf (p_buf);

        RFCOMM_LineStatusReq (p_mcb, dlci, LINE_STATUS_OVERRUN);
        return;
    }

    /* If user registered to receive notification when a particular byte is */
    /* received we mast check all received bytes */
    if (((rx_char1 = p_port->user_port_pars.rx_char1) != 0)
     && (p_port->ev_mask & PORT_EV_RXFLAG))
    {
        for (i = 0, p = (UINT8 *)(p_buf + 1) + p_buf->offset; i < p_buf->len; i++)
        {
            if (*p++ == rx_char1)
            {
                events |= PORT_EV_RXFLAG;
                break;
            }
        }
    }

    PORT_SCHEDULE_LOCK;

    GKI_enqueue (&p_port->rx.queue, p_buf);
    p_port->rx.queue_size += p_buf->len;

    PORT_SCHEDULE_UNLOCK;

    /* perform flow control procedures if necessary */
    port_flow_control_peer(p_port, FALSE, 0);

    /* If user indicated flow control can not deliver any notifications to him */
    if (p_port->rx.user_fc)
    {
        if (events & PORT_EV_RXFLAG)
            p_port->rx_flag_ev_pending = TRUE;

        return;
    }

    events |= PORT_EV_RXCHAR;

    /* Mask out all events that are not of interest to user */
    events &= p_port->ev_mask;

    if (p_port->p_callback && events)
        p_port->p_callback (events, p_port->inx);
}