/*******************************************************************************
**
** Function         mca_ccb_snd_req
**
** Description      This function builds a request and sends it to the peer.
**
** Returns          void.
**
*******************************************************************************/
void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
{
    tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
    BT_HDR  *p_pkt;
    UINT8   *p, *p_start;
    BOOLEAN is_abort = FALSE;
    tMCA_DCB *p_dcb;

    MCA_TRACE_DEBUG ("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong, p_msg->op_code);
    /* check for abort request */
    if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (p_msg->op_code == MCA_OP_MDL_ABORT_REQ))
    {
        p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
        /* the Abort API does not have the associated mdl_id.
         * Get the mdl_id in dcb to compose the request */
        if (p_dcb)
        {
            p_msg->mdl_id = p_dcb->mdl_id;
            mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
        }
        mca_free_buf ((void **)&p_ccb->p_tx_req);
        p_ccb->status = MCA_CCB_STAT_NORM;
        is_abort = TRUE;
    }

    /* no pending outgoing messages or it's an abort request for a pending data channel */
    if ((!p_ccb->p_tx_req) || is_abort)
    {
        p_ccb->p_tx_req = p_msg;
        if (!p_ccb->cong)
        {
            p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
            if (p_pkt)
            {
                p_pkt->offset = L2CAP_MIN_OFFSET;
                p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
                *p++ = p_msg->op_code;
                UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
                if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ)
                {
                    *p++ = p_msg->mdep_id;
                    *p++ = p_msg->param;
                }
                p_msg->hdr.layer_specific = TRUE;   /* mark this message as sent */
                p_pkt->len = p - p_start;
                L2CA_DataWrite (p_ccb->lcid, p_pkt);
                p_ccb->timer_entry.param = (TIMER_PARAM_TYPE) p_ccb;
                btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_MCA_CCB_RSP, p_ccb->p_rcb->reg.rsp_tout);
            }
        }
        /* else the L2CAP channel is congested. keep the message to be sent later */
    }
    else
    {
        MCA_TRACE_WARNING ("dropping api req");
        GKI_freebuf (p_data);
    }
}
Example #2
0
/*******************************************************************************
**
** Function         avdt_ad_write_req
**
** Description      This function is called by a CCB or SCB to send data to a
**                  transport channel.  It looks up the LCID of the channel
**                  based on the type, CCB, and SCB (if present).  Then it
**                  passes the data to L2CA_DataWrite().
**
**
** Returns          AVDT_AD_SUCCESS, if data accepted, else FALSE
**                  AVDT_AD_CONGESTED, if data accepted and the channel is congested
**                  AVDT_AD_FAILED, if error
**
*******************************************************************************/
UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
{
    UINT8   tcid;

    /* get tcid from type, scb */
    tcid = avdt_ad_type_to_tcid(type, p_scb);


    return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
}
Example #3
0
/*******************************************************************************
**
** Function         mca_dcb_snd_data
**
** Description      This function sends the data from application to the peer device.
**
** Returns          void.
**
*******************************************************************************/
void mca_dcb_snd_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
{
    UINT8   status;

    /* do not need to check cong, because API already checked the status */
    status = L2CA_DataWrite (p_dcb->lcid, p_data->p_pkt);
    if (status == L2CAP_DW_CONGESTED)
    {
        p_dcb->cong = TRUE;
        mca_dcb_report_cong(p_dcb);
    }
}
/*******************************************************************************
**
** Function         mca_ccb_snd_rsp
**
** Description      This function builds a response and sends it to
**                  the peer.
**
** Returns          void.
**
*******************************************************************************/
void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
{
    tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
    BT_HDR  *p_pkt;
    UINT8   *p, *p_start;
    BOOLEAN chk_mdl = FALSE;
    tMCA_DCB    *p_dcb;

    MCA_TRACE_DEBUG ("mca_ccb_snd_rsp cong=%d req=%d", p_ccb->cong, p_msg->op_code);
    /* assume that API functions verified the parameters */
    p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
    if (p_pkt)
    {
        p_pkt->offset = L2CAP_MIN_OFFSET;
        p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
        *p++ = p_msg->op_code;
        *p++ = p_msg->rsp_code;
        UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
        if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP)
        {
            *p++ = p_msg->param;
            chk_mdl = TRUE;
        }
        else if (p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP)
            chk_mdl = TRUE;

        if (chk_mdl && p_msg->rsp_code == MCA_RSP_SUCCESS)
        {
            p_dcb = mca_dcb_by_hdl(p_msg->dcb_idx);
            BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
                                 p_ccb->p_rcb->reg.data_psm, BTM_SEC_PROTO_MCA, p_msg->dcb_idx);
            p_ccb->status = MCA_CCB_STAT_PENDING;
            /* set p_tx_req to block API_REQ/API_RSP before DL is up */
            mca_free_buf ((void **)&p_ccb->p_tx_req);
            p_ccb->p_tx_req = p_ccb->p_rx_msg;
            p_ccb->p_rx_msg = NULL;
            p_ccb->p_tx_req->dcb_idx = p_msg->dcb_idx;
        }
        mca_free_buf ((void **)&p_ccb->p_rx_msg);
        p_pkt->len = p - p_start;
        L2CA_DataWrite (p_ccb->lcid, p_pkt);
    }

}
static UINT8 L2cap_DataWrite (UINT16 cid, char *p_data, UINT32 len)
{
    BTIF_TRACE_DEBUG("L2cap_DataWrite:: Invoked");
    BT_HDR  *p_msg = NULL;(BT_HDR *) GKI_getpoolbuf (GKI_POOL_ID_3);
    UINT8   *ptr, *p_start;

    p_msg = (BT_HDR *) GKI_getpoolbuf (GKI_POOL_ID_3);
    BTIF_TRACE_DEBUG("GKI_getpoolbuf");
    if (!p_msg)
    {
        BTIF_TRACE_DEBUG("No resource to allocate");
        return BT_STATUS_FAIL;
    }
    p_msg->offset = L2CAP_MIN_OFFSET;
    ptr = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
    p_msg->len = len;    //Sends len bytes, irrespective of what you copy to the buffer
    memcpy(ptr, p_data, len);
    return L2CA_DataWrite(cid, p_msg);
}
Example #6
0
/*******************************************************************************
**
** Function         attp_send_msg_to_l2cap
**
** Description      Send message to L2CAP.
**
*******************************************************************************/
tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
{
    UINT16      l2cap_ret;


    if (p_tcb->att_lcid == L2CAP_ATT_CID)
        l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
    else
        l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);

    if (l2cap_ret == L2CAP_DW_FAILED)
    {
        GATT_TRACE_ERROR("ATT   failed to pass msg:0x%0x to L2CAP",
            *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
        return GATT_INTERNAL_ERROR;
    }
    else if (l2cap_ret == L2CAP_DW_CONGESTED)
    {
        GATT_TRACE_DEBUG("ATT congested, message accepted");
        return GATT_CONGESTED;
    }
    return GATT_SUCCESS;
}
Example #7
0
/*******************************************************************************
**
** Function         rfc_check_send_cmd
**
** Description      This function is called to send an RFCOMM command message
**                  or to handle the RFCOMM command message queue.
**
** Returns          void
**
*******************************************************************************/
void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf)
{
    BT_HDR  *p;

    /* if passed a buffer queue it */
    if (p_buf != NULL) {
        if (p_mcb->cmd_q == NULL) {
            RFCOMM_TRACE_ERROR("%s: empty queue: p_mcb = %p p_mcb->lcid = %u cached p_mcb = %p",
                               __func__, p_mcb, p_mcb->lcid,
                               rfc_find_lcid_mcb(p_mcb->lcid));
        }
        fixed_queue_enqueue(p_mcb->cmd_q, p_buf);
    }

    /* handle queue if L2CAP not congested */
    while (p_mcb->l2cap_congested == FALSE) {
        if ((p = (BT_HDR *)fixed_queue_try_dequeue(p_mcb->cmd_q)) == NULL) {
            break;
        }


        L2CA_DataWrite (p_mcb->lcid, p);
    }
}
/*******************************************************************************
**
** Function         mca_ccb_hdl_req
**
** Description      This function is called when a MCAP request is received from
**                  the peer. It calls the application callback function to
**                  report the event.
**
** Returns          void.
**
*******************************************************************************/
void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
{
    BT_HDR  *p_pkt = &p_data->hdr;
    BT_HDR  *p_buf;
    UINT8   *p, *p_start;
    tMCA_DCB    *p_dcb;
    tMCA_CTRL       evt_data;
    tMCA_CCB_MSG    *p_rx_msg = NULL;
    UINT8           reject_code = MCA_RSP_NO_RESOURCE;
    BOOLEAN         send_rsp = FALSE;
    BOOLEAN         check_req = FALSE;
    UINT8           reject_opcode;

    MCA_TRACE_DEBUG ("mca_ccb_hdl_req status:%d", p_ccb->status);
    p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
    p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    evt_data.hdr.op_code = *p++;
    BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
    reject_opcode = evt_data.hdr.op_code+1;

    MCA_TRACE_DEBUG ("received mdl id: %d ", evt_data.hdr.mdl_id);
    if (p_ccb->status == MCA_CCB_STAT_PENDING)
    {
        MCA_TRACE_DEBUG ("received req inpending state");
        /* allow abort in pending state */
        if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ))
        {
            reject_code = MCA_RSP_SUCCESS;
            send_rsp = TRUE;
            /* clear the pending status */
            p_ccb->status = MCA_CCB_STAT_NORM;
            if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL))
            {
                mca_dcb_dealloc (p_dcb, NULL);
                mca_free_buf ((void **)&p_ccb->p_tx_req);
            }
        }
        else
            reject_code = MCA_RSP_BAD_OP;
    }
    else if (p_ccb->p_rx_msg)
    {
        MCA_TRACE_DEBUG ("still handling prev req");
        /* still holding previous message, reject this new one ?? */

    }
    else if (p_ccb->p_tx_req)
    {
        MCA_TRACE_DEBUG ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
        /* sent a request; waiting for response */
        if (p_ccb->ctrl_vpsm == 0)
        {
            MCA_TRACE_DEBUG ("local is ACP. accept the cmd from INT");
            /* local is acceptor, need to handle the request */
            check_req = TRUE;
            reject_code = MCA_RSP_SUCCESS;
            /* drop the previous request */
            if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
                    ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
            {
                mca_dcb_dealloc(p_dcb, NULL);
            }
            mca_free_buf ((void **)&p_ccb->p_tx_req);
            mca_stop_timer(p_ccb);
        }
        else
        {
            /*  local is initiator, ignore the req */
            GKI_freebuf (p_pkt);
            return;
        }
    }
    else if (p_pkt->layer_specific != MCA_RSP_SUCCESS)
    {

        reject_code = (UINT8)p_pkt->layer_specific;
        if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
                (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
                (evt_data.hdr.op_code > MCA_LAST_SYNC_OP))
        {
            /* invalid op code */
            reject_opcode = MCA_OP_ERROR_RSP;
            evt_data.hdr.mdl_id = 0;
        }
    }
    else
    {
        check_req = TRUE;
        reject_code = MCA_RSP_SUCCESS;
    }

    if (check_req)
    {
        if (reject_code == MCA_RSP_SUCCESS)
        {
            reject_code = MCA_RSP_BAD_MDL;
            if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
                    ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ)))
            {
                reject_code = MCA_RSP_SUCCESS;
                /* mdl_id is valid according to the spec */
                switch (evt_data.hdr.op_code)
                {
                case MCA_OP_MDL_CREATE_REQ:
                    evt_data.create_ind.dep_id = *p++;
                    evt_data.create_ind.cfg = *p++;
                    p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
                    if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id))
                    {
                        MCA_TRACE_ERROR ("not a valid local mdep id");
                        reject_code = MCA_RSP_BAD_MDEP;
                    }
                    else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
                    {
                        MCA_TRACE_DEBUG ("the mdl_id is currently used in the CL(create)");
                        mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
                    }
                    else
                    {
                        /* check if this dep still have MDL available */
                        if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0)
                        {
                            MCA_TRACE_ERROR ("the mdep is currently using max_mdl");
                            reject_code = MCA_RSP_MDEP_BUSY;
                        }
                    }
                    break;

                case MCA_OP_MDL_RECONNECT_REQ:
                    if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
                    {
                        MCA_TRACE_ERROR ("the mdl_id is currently used in the CL(reconn)");
                        reject_code = MCA_RSP_MDL_BUSY;
                    }
                    break;

                case MCA_OP_MDL_ABORT_REQ:
                    reject_code = MCA_RSP_BAD_OP;
                    break;

                case MCA_OP_MDL_DELETE_REQ:
                    /* delete the associated mdl */
                    mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
                    send_rsp = TRUE;
                    break;
                }
            }
        }
    }

    if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
            || send_rsp)
    {
        p_buf = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
        if (p_buf)
        {
            p_buf->offset = L2CAP_MIN_OFFSET;
            p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
            *p++ = reject_opcode;
            *p++ = reject_code;
            UINT16_TO_BE_STREAM (p, evt_data.hdr.mdl_id);
            /*
            if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS))
            {
                *p++ = evt_data.create_ind.cfg;
            }
            */

            p_buf->len = p - p_start;
            L2CA_DataWrite (p_ccb->lcid, p_buf);
        }
    }

    if (reject_code == MCA_RSP_SUCCESS)
    {
        /* use the received GKI buffer to store information to double check response API */
        p_rx_msg->op_code = evt_data.hdr.op_code;
        p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
        p_ccb->p_rx_msg = p_rx_msg;
        if (send_rsp)
        {
            GKI_freebuf (p_pkt);
            p_ccb->p_rx_msg = NULL;
        }
        mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
    }
    else
        GKI_freebuf (p_pkt);
}
Example #9
0
/*******************************************************************************
**
** Function         hidh_conn_snd_data
**
** Description      This function is sends out data.
**
** Returns          tHID_STATUS
**
*******************************************************************************/
tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param,
                                UINT16 data, UINT8 report_id, BT_HDR *buf)
{
    tHID_CONN   *p_hcon = &hh_cb.devices[dhandle].conn;
    BT_HDR      *p_buf;
    UINT8       *p_out;
    UINT16      bytes_copied;
    BOOLEAN     seg_req = FALSE;
    UINT16      data_size;
    UINT16      cid;
    UINT8       pool_id;
    UINT8       use_data = 0 ;
    BOOLEAN     blank_datc = FALSE;

    if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr, BT_TRANSPORT_BR_EDR))
    {
        if (buf)
            GKI_freebuf ((void *)buf);
        return( HID_ERR_NO_CONNECTION );
    }

    if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
    {
        if (buf)
            GKI_freebuf ((void *)buf);
        return( HID_ERR_CONGESTED );
    }

    switch( trans_type )
    {
    case HID_TRANS_CONTROL:
    case HID_TRANS_GET_REPORT:
    case HID_TRANS_SET_REPORT:
    case HID_TRANS_GET_PROTOCOL:
    case HID_TRANS_SET_PROTOCOL:
    case HID_TRANS_GET_IDLE:
    case HID_TRANS_SET_IDLE:
        cid = p_hcon->ctrl_cid;
        pool_id = HID_CONTROL_POOL_ID;
        break;
    case HID_TRANS_DATA:
        cid = p_hcon->intr_cid;
        pool_id = HID_INTERRUPT_POOL_ID;
        break;
    default:
        return (HID_ERR_INVALID_PARAM) ;
    }

    if( trans_type == HID_TRANS_SET_IDLE )
        use_data = 1;
    else if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
        use_data = 2;

    do
    {
        if ( buf == NULL || blank_datc )
        {
            if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
                return (HID_ERR_NO_RESOURCES);

            p_buf->offset = L2CAP_MIN_OFFSET;
            seg_req = FALSE;
            data_size = 0;
            bytes_copied = 0;
            blank_datc = FALSE;
        }
        else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
        {
            if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
                return (HID_ERR_NO_RESOURCES);

            p_buf->offset = L2CAP_MIN_OFFSET;
            seg_req = TRUE;
            data_size = buf->len;
            bytes_copied = p_hcon->rem_mtu_size - 1;
        }
        else
        {
            p_buf = buf ;
            p_buf->offset -= 1;
            seg_req = FALSE;
            data_size = buf->len;
            bytes_copied = buf->len;
        }

        p_out         = (UINT8 *)(p_buf + 1) + p_buf->offset;
        *p_out++      = HID_BUILD_HDR(trans_type, param);

        /* If report ID required for this device */
        if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
        {
            *p_out = report_id;
            data_size = bytes_copied = 1;
        }


        if (seg_req)
        {
            memcpy (p_out, (((UINT8 *)(buf+1)) + buf->offset), bytes_copied);
            buf->offset += bytes_copied;
            buf->len -= bytes_copied;
        }
        else if( use_data == 1)
        {
            *(p_out+bytes_copied) = data & 0xff;
        }
        else if( use_data == 2 )
        {
            *(p_out+bytes_copied) = data & 0xff;
            *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
        }

        p_buf->len   = bytes_copied + 1 + use_data;
        data_size    -= bytes_copied;

        /* Send the buffer through L2CAP */
        if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
            return (HID_ERR_CONGESTED);

        if (data_size)
            trans_type = HID_TRANS_DATAC;
        else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
        {
            trans_type = HID_TRANS_DATAC;
            blank_datc = TRUE;
        }

    } while ((data_size != 0) || blank_datc ) ;