/*******************************************************************************
**
** Function         mca_ccb_rsp_tout
**
** Description      This function processes the response timeout.
**
** Returns          void.
**
*******************************************************************************/
void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
{
    tMCA_CTRL   evt_data;
    UNUSED(p_data);

    mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data);
}
/*******************************************************************************
**
** Function         mca_ccb_ll_open
**
** Description      This function is called to report MCA_CONNECT_IND_EVT event.
**                  It also clears the congestion flag (ccb.cong).
**
** Returns          void.
**
*******************************************************************************/
void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
{
    tMCA_CTRL    evt_data;
    p_ccb->cong  = FALSE;
    evt_data.connect_ind.mtu = p_data->open.peer_mtu;
    memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
    mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data);
}
Esempio n. 3
0
/*******************************************************************************
**
** Function         mca_dcb_report_cong
**
** Description      This function is called to report the congestion flag.
**
** Returns          void.
**
*******************************************************************************/
void mca_dcb_report_cong (tMCA_DCB *p_dcb)
{
    tMCA_CTRL   evt_data;

    evt_data.cong_chg.cong   = p_dcb->cong;
    evt_data.cong_chg.mdl    = mca_dcb_to_hdl(p_dcb);
    evt_data.cong_chg.mdl_id = p_dcb->mdl_id;
    mca_ccb_report_event (p_dcb->p_ccb, MCA_CONG_CHG_EVT, &evt_data);
}
Esempio n. 4
0
/*******************************************************************************
**
** Function         mca_dcb_tc_open
**
** Description      This function is called to report MCA_OPEN_IND_EVT or
**                  MCA_OPEN_CFM_EVT event.
**                  It also clears the congestion flag (dcb.cong).
**
** Returns          void.
**
*******************************************************************************/
void mca_dcb_tc_open (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
{
    tMCA_CTRL   evt_data;
    tMCA_CCB    *p_ccb = p_dcb->p_ccb;
    UINT8       event = MCA_OPEN_IND_EVT;

    if (p_data->open.param == MCA_INT)
        event = MCA_OPEN_CFM_EVT;
    p_dcb->cong  = FALSE;
    evt_data.open_cfm.mtu       = p_data->open.peer_mtu;
    evt_data.open_cfm.mdl_id    = p_dcb->mdl_id;
    evt_data.open_cfm.mdl       = mca_dcb_to_hdl(p_dcb);
    mca_ccb_event (p_ccb, MCA_CCB_DL_OPEN_EVT, NULL);
    mca_ccb_report_event (p_ccb, event, &evt_data);
}
/*******************************************************************************
**
** Function         mca_dcb_dealloc
**
** Description      This function deallocates an DCB.
**
** Returns          void.
**
*******************************************************************************/
void mca_dcb_dealloc(tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
{
    tMCA_CCB *p_ccb = p_dcb->p_ccb;
    UINT8    event = MCA_CLOSE_IND_EVT;
    tMCA_CTRL   evt_data;

    MCA_TRACE_DEBUG("mca_dcb_dealloc");
    mca_free_buf ((void **)&p_dcb->p_data);
    if (p_data)
    {
        /* non-NULL -> an action function -> report disconnect event */
        evt_data.close_cfm.mdl      = mca_dcb_to_hdl(p_dcb);
        evt_data.close_cfm.reason   = p_data->close.reason;
        evt_data.close_cfm.mdl_id   = p_dcb->mdl_id;
        if (p_data->close.param == MCA_INT)
            event = MCA_CLOSE_CFM_EVT;
        if (p_data->close.lcid)
            mca_ccb_report_event(p_ccb, event, &evt_data);
    }
    mca_free_tc_tbl_by_lcid (p_dcb->lcid);
    memset (p_dcb, 0, sizeof (tMCA_DCB));
}
/*******************************************************************************
**
** Function         mca_ccb_hdl_rsp
**
** Description      This function is called when a MCAP response is received from
**                  the peer.  It calls the application callback function with
**                  the results.
**
** Returns          void.
**
*******************************************************************************/
void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
{
    BT_HDR  *p_pkt = &p_data->hdr;
    UINT8   *p;
    tMCA_CTRL   evt_data;
    BOOLEAN     chk_mdl = FALSE;
    tMCA_DCB    *p_dcb;
    tMCA_RESULT result = MCA_BAD_HANDLE;
    tMCA_TC_TBL *p_tbl;

    if (p_ccb->p_tx_req)
    {
        /* verify that the received response matches the sent request */
        p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
        evt_data.hdr.op_code = *p++;
        if ((evt_data.hdr.op_code == 0) ||
                ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code))
        {
            evt_data.rsp.rsp_code = *p++;
            mca_stop_timer(p_ccb);
            BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
            if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP)
            {
                evt_data.create_cfm.cfg = *p++;
                chk_mdl = TRUE;
            }
            else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP)
                chk_mdl = TRUE;

            if (chk_mdl)
            {
                p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
                if (p_dcb && evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
                {
                    if (evt_data.hdr.mdl_id != p_dcb->mdl_id)
                    {
                        MCA_TRACE_ERROR ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id);
                        /* change the response code to be an error */
                        if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
                        {
                            evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL;
                            /* send Abort */
                            p_ccb->status = MCA_CCB_STAT_PENDING;
                            MCA_Abort(mca_ccb_to_hdl(p_ccb));
                        }
                    }
                    else if (p_dcb->p_chnl_cfg)
                    {
                        /* the data channel configuration is known. Proceed with data channel initiation */
                        BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
                                             p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
                        p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
                        if (p_dcb->lcid)
                        {
                            p_tbl = mca_tc_tbl_dalloc(p_dcb);
                            if (p_tbl)
                            {
                                p_tbl->state = MCA_TC_ST_CONN;
                                p_ccb->status = MCA_CCB_STAT_PENDING;
                                result = MCA_SUCCESS;
                            }
                        }
                    }
                    else
                    {
                        /* mark this MCL as pending and wait for MCA_DataChnlCfg */
                        p_ccb->status = MCA_CCB_STAT_PENDING;
                        result = MCA_SUCCESS;
                    }
                }

                if (result != MCA_SUCCESS && p_dcb)
                {
                    mca_dcb_dealloc(p_dcb, NULL);
                }
            } /* end of chk_mdl */

            if (p_ccb->status != MCA_CCB_STAT_PENDING)
                mca_free_buf ((void **)&p_ccb->p_tx_req);
            mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
        }
        /* else a bad response is received */
    }
    else
    {
        /* not expecting any response. drop it */
        MCA_TRACE_WARNING ("dropping received rsp (not expecting a response)");
    }
    GKI_freebuf (p_data);
}
/*******************************************************************************
**
** 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);
}