/*******************************************************************************
**
** Function         avrc_prs_get_elem_attrs_rsp
**
** Description      This function parses the Get Element Attributes
**                  response.
**
** Returns          AVRC_STS_NO_ERROR, if the response is parsed successfully
**                  Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_prs_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, UINT8 *p_data)
{
    UINT8   *p_start, *p_len, *p_count;
    UINT16  len;
    UINT8   xx;
    UINT32  attr_id;

    if (p_rsp->num_attr == 0)
        return AVRC_STS_NO_ERROR;

    AVRC_TRACE_API("avrc_prs_get_elem_attrs_rsp num_attr: %d", p_rsp->num_attr);

    p_rsp->p_attrs = (tAVRC_ATTR_ENTRY*)malloc(sizeof(tAVRC_ATTR_ENTRY) * p_rsp->num_attr);

    for (xx=0; xx<p_rsp->num_attr; xx++)
    {
        BE_STREAM_TO_UINT32(attr_id, p_data);
        if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(attr_id))
        {
            AVRC_TRACE_ERROR("avrc_prs_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, attr_id);
            continue;
        }

        p_rsp->p_attrs[xx].attr_id = attr_id;

        BE_STREAM_TO_UINT16(p_rsp->p_attrs[xx].name.charset_id, p_data);
        BE_STREAM_TO_UINT16(p_rsp->p_attrs[xx].name.str_len, p_data);
        p_rsp->p_attrs[xx].name.p_str = (UINT8*)malloc(sizeof(UINT8) * p_rsp->p_attrs[xx].name.str_len);
        BE_STREAM_TO_ARRAY(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len);
        AVRC_TRACE_DEBUG("avrc_prs_get_elem_attrs_rsp str_len: %d, str: %s", p_rsp->p_attrs[xx].name.str_len, p_rsp->p_attrs[xx].name.p_str);
    }

    return AVRC_STS_NO_ERROR;
}
Example #2
0
/*******************************************************************************
**
** Function         avrc_pars_vendor_rsp
**
** Description      This function parses the vendor specific commands defined by
**                  Bluetooth SIG
**
** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
**                  Otherwise, the error code defined by AVRCP 1.4
**
*******************************************************************************/
static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result)
{
    tAVRC_STS  status = AVRC_STS_NO_ERROR;
    UINT8   *p;
    UINT16  len;
    UINT8 eventid = 0;

    /* Check the vendor data */
    if (p_msg->vendor_len == 0) {
        return AVRC_STS_NO_ERROR;
    }
    if (p_msg->p_vendor_data == NULL) {
        return AVRC_STS_INTERNAL_ERR;
    }

    p = p_msg->p_vendor_data;
    BE_STREAM_TO_UINT8 (p_result->pdu, p);
    p++; /* skip the reserved/packe_type byte */
    BE_STREAM_TO_UINT16 (len, p);
    AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len);
    if (p_msg->hdr.ctype == AVRC_RSP_REJ) {
        p_result->rsp.status = *p;
        return p_result->rsp.status;
    }

    switch (p_result->pdu) {
        /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
        /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */

#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
    case AVRC_PDU_SET_ABSOLUTE_VOLUME:      /* 0x50 */
        if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
        }
        break;
#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */

    case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
        BE_STREAM_TO_UINT8 (eventid, p);
        if (AVRC_EVT_VOLUME_CHANGE == eventid
                && (AVRC_RSP_CHANGED == p_msg->hdr.ctype || AVRC_RSP_INTERIM == p_msg->hdr.ctype
                    || AVRC_RSP_REJ == p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL == p_msg->hdr.ctype)) {
            p_result->reg_notif.status = p_msg->hdr.ctype;
            p_result->reg_notif.event_id = eventid;
            BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p);
        }
        AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x", eventid,
                         p_result->reg_notif.param.volume);
#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
        break;
    default:
        status = AVRC_STS_BAD_CMD;
        break;
    }

    return status;
}
/*******************************************************************************
**
** Function         avrc_bld_app_setting_text_rsp
**
** Description      This function builds the Get Application Settings Attribute Text
**                  or Get Application Settings Value Text response.
**
** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
**                  Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt)
{
    UINT8   *p_data, *p_start, *p_len, *p_count;
    UINT16  len, len_left;
    UINT8   xx;
    tAVRC_STS   sts = AVRC_STS_NO_ERROR;
    UINT8       num_added = 0;

    if (!p_rsp->p_attrs)
    {
        AVRC_TRACE_ERROR0("avrc_bld_app_setting_text_rsp NULL parameter");
        return AVRC_STS_BAD_PARAM;
    }
    /* get the existing length, if any, and also the num attributes */
    p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    p_data = p_len = p_start + 2; /* pdu + rsvd */
    len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE - p_pkt->offset - p_pkt->len;

    BE_STREAM_TO_UINT16(len, p_data);
    p_count = p_data;

    if (len == 0)
    {
        *p_count = 0;
        p_data++;
    }
    else
    {
        p_data = p_start + p_pkt->len;
    }

    for (xx=0; xx<p_rsp->num_attr; xx++)
    {
        if  (len_left < (p_rsp->p_attrs[xx].str_len + 4))
        {
            AVRC_TRACE_ERROR3("avrc_bld_app_setting_text_rsp out of room (str_len:%d, left:%d)",
                xx, p_rsp->p_attrs[xx].str_len, len_left);
            p_rsp->num_attr = num_added;
            sts = AVRC_STS_INTERNAL_ERR;
            break;
        }
        if ( !p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str )
        {
            AVRC_TRACE_ERROR1("avrc_bld_app_setting_text_rsp NULL attr text[%d]", xx);
            continue;
        }
        UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].charset_id);
        UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].str_len);
        ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].p_str, p_rsp->p_attrs[xx].str_len);
        (*p_count)++;
        num_added++;
    }
    len = p_data - p_count;
    UINT16_TO_BE_STREAM(p_len, len);
    p_pkt->len = (p_data - p_start);

    return sts;
}
/*******************************************************************************
**
** Function         avrc_bld_get_elem_attrs_rsp
**
** Description      This function builds the Get Element Attributes
**                  response.
**
** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
**                  Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, BT_HDR *p_pkt)
{
    UINT8   *p_data, *p_start, *p_len, *p_count;
    UINT16  len;
    UINT8   xx;

    AVRC_TRACE_API0("avrc_bld_get_elem_attrs_rsp");
    if (!p_rsp->p_attrs)
    {
        AVRC_TRACE_ERROR0("avrc_bld_get_elem_attrs_rsp NULL parameter");
        return AVRC_STS_BAD_PARAM;
    }

    /* get the existing length, if any, and also the num attributes */
    p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    p_data = p_len = p_start + 2; /* pdu + rsvd */

    BE_STREAM_TO_UINT16(len, p_data);
    p_count = p_data;

    if (len == 0)
    {
        *p_count = 0;
        p_data++;
    }
    else
    {
        p_data = p_start + p_pkt->len;
    }

    for (xx=0; xx<p_rsp->num_attr; xx++)
    {
        if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attrs[xx].attr_id))
        {
            AVRC_TRACE_ERROR2("avrc_bld_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, p_rsp->p_attrs[xx].attr_id);
            continue;
        }
        if ( !p_rsp->p_attrs[xx].name.p_str )
        {
            p_rsp->p_attrs[xx].name.str_len = 0;
        }
        UINT32_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.charset_id);
        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.str_len);
        ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len);
        (*p_count)++;
    }
    len = p_data - p_count;
    UINT16_TO_BE_STREAM(p_len, len);
    p_pkt->len = (p_data - p_start);
    return AVRC_STS_NO_ERROR;
}
Example #5
0
/*******************************************************************************
**
** Function         llcp_util_parse_cc
**
** Description      Parse CC PDU
**
** Returns          tLLCP_STATUS
**
*******************************************************************************/
tLLCP_STATUS llcp_util_parse_cc (UINT8 *p_bytes, UINT16 length, UINT16 *p_miu, UINT8 *p_rw)
{
    UINT8 param_type, param_len, *p = p_bytes;

    *p_miu = LLCP_DEFAULT_MIU;
    *p_rw  = LLCP_DEFAULT_RW;

    while (length)
    {
        BE_STREAM_TO_UINT8 (param_type, p);
        length--;

        switch (param_type)
        {
        case LLCP_MIUX_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT16 ((*p_miu), p);
            (*p_miu) &= LLCP_MIUX_MASK;
            (*p_miu) += LLCP_DEFAULT_MIU;

            LLCP_TRACE_DEBUG1 ("llcp_util_parse_cc (): LLCP_MIUX_TYPE:%d", *p_miu);
            break;

        case LLCP_RW_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT8 ((*p_rw), p);
            (*p_rw) &= 0x0F;

            LLCP_TRACE_DEBUG1 ("llcp_util_parse_cc (): LLCP_RW_TYPE:%d", *p_rw);
            break;

        default:
            LLCP_TRACE_ERROR1 ("llcp_util_parse_cc (): Unexpected type 0x%x", param_type);
            BE_STREAM_TO_UINT8 (param_len, p);
            p += param_len;
            break;
        }

        if (length >= param_len + 1)
            length -= param_len + 1;
        else
        {
            LLCP_TRACE_ERROR0 ("llcp_util_parse_cc (): Bad LTV's");
            return LLCP_STATUS_FAIL;
        }
    }
    return LLCP_STATUS_SUCCESS;
}
/*******************************************************************************
**
** Function         avrc_bld_get_cur_app_setting_value_rsp
**
** Description      This function builds the Get Current Application Setting Value
**                  response.
**
** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
**                  Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp (tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp,
    BT_HDR *p_pkt)
{
    UINT8   *p_data, *p_start, *p_len, *p_count;
    UINT16  len;
    UINT8   xx;

    if (!p_rsp->p_vals)
    {
        AVRC_TRACE_ERROR0("avrc_bld_get_cur_app_setting_value_rsp NULL parameter");
        return AVRC_STS_BAD_PARAM;
    }

    AVRC_TRACE_API0("avrc_bld_get_cur_app_setting_value_rsp");
    /* get the existing length, if any, and also the num attributes */
    p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    p_data = p_len = p_start + 2; /* pdu + rsvd */

    BE_STREAM_TO_UINT16(len, p_data);
    p_count = p_data;
    if (len == 0)
    {
        /* first time initialize the attribute count */
        *p_count = 0;
        p_data++;
    }
    else
    {
        p_data = p_start + p_pkt->len;
    }

    for (xx=0; xx<p_rsp->num_val; xx++)
    {
        if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id, p_rsp->p_vals[xx].attr_val))
        {
            (*p_count)++;
            UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_id);
            UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_val);
        }
    }
    len = ((*p_count) << 1) + 1;
    UINT16_TO_BE_STREAM(p_len, len);
    p_pkt->len = (p_data - p_start);

    return AVRC_STS_NO_ERROR;
}
Example #7
0
/*******************************************************************************
**
** Function         ce_t4t_process_select_file_cmd
**
** Description      This function processes Select Command by file ID.
**
** Returns          TRUE if success
**
*******************************************************************************/
static BOOLEAN ce_t4t_process_select_file_cmd (UINT8 *p_cmd)
{
    UINT8  data_len;
    UINT16 file_id, status_words;

    CE_TRACE_DEBUG0 ("ce_t4t_process_select_file_cmd ()");

    p_cmd++; /* skip P2 */

    /* Lc Byte */
    BE_STREAM_TO_UINT8 (data_len, p_cmd);

    if (data_len == T4T_FILE_ID_SIZE)
    {
        /* File ID */
        BE_STREAM_TO_UINT16 (file_id, p_cmd);

        if (ce_t4t_select_file (file_id))
        {
            status_words = T4T_RSP_CMD_CMPLTED;
        }
        else
        {
            status_words = T4T_RSP_NOT_FOUND;
        }
    }
    else
    {
        status_words = T4T_RSP_WRONG_LENGTH;
    }

    if (!ce_t4t_send_status (status_words))
    {
        return FALSE;
    }

    if (status_words == T4T_RSP_CMD_CMPLTED)
    {
        return TRUE;
    }
    return FALSE;
}
Example #8
0
/*******************************************************************************
**
** Function         avrc_pars_pass_thru
**
** Description      This function parses the pass thru commands defined by
**                  Bluetooth SIG
**
** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
**                  Otherwise, the error code defined by AVRCP 1.4
**
*******************************************************************************/
tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, UINT16 *p_vendor_unique_id)
{
    UINT8      *p_data;
    UINT32      co_id;
    UINT16      id;
    tAVRC_STS  status = AVRC_STS_BAD_CMD;

    if (p_msg->op_id == AVRC_ID_VENDOR && p_msg->pass_len == AVRC_PASS_THRU_GROUP_LEN) {
        p_data = p_msg->p_pass_data;
        AVRC_BE_STREAM_TO_CO_ID (co_id, p_data);
        if (co_id == AVRC_CO_METADATA) {
            BE_STREAM_TO_UINT16 (id, p_data);
            if (AVRC_IS_VALID_GROUP(id)) {
                *p_vendor_unique_id = id;
                status = AVRC_STS_NO_ERROR;
            }
        }
    }
    return status;
}
/*******************************************************************************
**
** Function         avrc_bld_list_app_settings_attr_rsp
**
** Description      This function builds the List Application Settings Attribute
**                  response.
**
** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
**                  Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p_rsp, BT_HDR *p_pkt)
{
    UINT8   *p_data, *p_start, *p_len, *p_num;
    UINT16  len = 0;
    UINT8   xx;

    AVRC_TRACE_API0("avrc_bld_list_app_settings_attr_rsp");
    /* get the existing length, if any, and also the num attributes */
    p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    p_data = p_len = p_start + 2; /* pdu + rsvd */

    BE_STREAM_TO_UINT16(len, p_data);
    p_num = p_data;
    if (len == 0)
    {
        /* first time initialize the attribute count */
        *p_num = 0;
        p_data++;
    }
    else
    {
        p_data = p_start + p_pkt->len;
    }

    for (xx=0; xx<p_rsp->num_attr; xx++)
    {
        if(AVRC_IsValidPlayerAttr(p_rsp->attrs[xx]))
        {
            (*p_num)++;
            UINT8_TO_BE_STREAM(p_data, p_rsp->attrs[xx]);
        }
    }

    len = *p_num + 1;
    UINT16_TO_BE_STREAM(p_len, len);
    p_pkt->len = (p_data - p_start);

    return AVRC_STS_NO_ERROR;
}
/*******************************************************************************
**
** Function         avrc_bld_list_app_settings_values_rsp
**
** Description      This function builds the List Application Setting Values
**                  response.
**
** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
**                  Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_bld_list_app_settings_values_rsp (tAVRC_LIST_APP_VALUES_RSP *p_rsp,
    BT_HDR *p_pkt)
{
    UINT8   *p_data, *p_start, *p_len, *p_num;
    UINT8   xx;
    UINT16  len;

    AVRC_TRACE_API0("avrc_bld_list_app_settings_values_rsp");

    p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    p_data = p_len = p_start + 2; /* pdu + rsvd */

    /* get the existing length, if any, and also the num attributes */
    BE_STREAM_TO_UINT16(len, p_data);
    p_num = p_data;
    /* first time initialize the attribute count */
    if (len == 0)
    {
        *p_num = p_rsp->num_val;
        p_data++;
    }
    else
    {
        p_data = p_start + p_pkt->len;
        *p_num += p_rsp->num_val;
    }


    for (xx=0; xx<p_rsp->num_val; xx++)
    {
        UINT8_TO_BE_STREAM(p_data, p_rsp->vals[xx]);
    }

    len = *p_num + 1;
    UINT16_TO_BE_STREAM(p_len, len);
    p_pkt->len = (p_data - p_start);
    return AVRC_STS_NO_ERROR;
}
Example #11
0
/*******************************************************************************
**
** Function         rw_t4t_sm_detect_ndef
**
** Description      State machine for NDEF detection procedure
**
** Returns          none
**
*******************************************************************************/
static void rw_t4t_sm_detect_ndef (BT_HDR *p_r_apdu)
{
    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
    UINT8       *p, type, length;
    UINT16      status_words, nlen;
    tRW_DATA    rw_data;

#if (BT_TRACE_VERBOSE == TRUE)
    RW_TRACE_DEBUG2 ("rw_t4t_sm_detect_ndef (): sub_state:%s (%d)",
                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
#else
    RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): sub_state=%d", p_t4t->sub_state);
#endif

    /* get status words */
    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
    BE_STREAM_TO_UINT16 (status_words, p);

    if (status_words != T4T_RSP_CMD_CMPLTED)
    {
        /* try V1.0 after failing of V2.0 */
        if (  (p_t4t->sub_state == RW_T4T_SUBSTATE_WAIT_SELECT_APP)
            &&(p_t4t->version   == T4T_VERSION_2_0)  )
        {
            p_t4t->version = T4T_VERSION_1_0;

            RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): retry with version=0x%02X",
                              p_t4t->version);

            if (!rw_t4t_select_application (T4T_VERSION_1_0))
            {
                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
            }
            return;
        }

        p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
        return;
    }

    switch (p_t4t->sub_state)
    {
    case RW_T4T_SUBSTATE_WAIT_SELECT_APP:

        /* NDEF Tag application has been selected then select CC file */
        if (!rw_t4t_select_file (T4T_CC_FILE_ID))
        {
            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        }
        else
        {
            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
        }
        break;

    case RW_T4T_SUBSTATE_WAIT_SELECT_CC:

        /* CC file has been selected then read mandatory part of CC file */
        if (!rw_t4t_read_file (0x00, T4T_CC_FILE_MIN_LEN, FALSE))
        {
            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        }
        else
        {
            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_CC_FILE;
        }
        break;

    case RW_T4T_SUBSTATE_WAIT_CC_FILE:

        /* CC file has been read then validate and select mandatory NDEF file */
        if (p_r_apdu->len >= T4T_CC_FILE_MIN_LEN + T4T_RSP_STATUS_WORDS_SIZE)
        {
            p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;

            BE_STREAM_TO_UINT16 (p_t4t->cc_file.cclen, p);
            BE_STREAM_TO_UINT8 (p_t4t->cc_file.version, p);
            BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_le, p);
            BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_lc, p);

            BE_STREAM_TO_UINT8 (type, p);
            BE_STREAM_TO_UINT8 (length, p);

            if (  (type == T4T_NDEF_FILE_CONTROL_TYPE)
                &&(length == T4T_FILE_CONTROL_LENGTH)  )
            {
                BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.file_id, p);
                BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.max_file_size, p);
                BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.read_access, p);
                BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.write_access, p);

#if (BT_TRACE_VERBOSE == TRUE)
                RW_TRACE_DEBUG0 ("Capability Container (CC) file");
                RW_TRACE_DEBUG1 ("  CCLEN:  0x%04X",    p_t4t->cc_file.cclen);
                RW_TRACE_DEBUG1 ("  Version:0x%02X",    p_t4t->cc_file.version);
                RW_TRACE_DEBUG1 ("  MaxLe:  0x%04X",    p_t4t->cc_file.max_le);
                RW_TRACE_DEBUG1 ("  MaxLc:  0x%04X",    p_t4t->cc_file.max_lc);
                RW_TRACE_DEBUG0 ("  NDEF File Control TLV");
                RW_TRACE_DEBUG1 ("    FileID:      0x%04X", p_t4t->cc_file.ndef_fc.file_id);
                RW_TRACE_DEBUG1 ("    MaxFileSize: 0x%04X", p_t4t->cc_file.ndef_fc.max_file_size);
                RW_TRACE_DEBUG1 ("    ReadAccess:  0x%02X", p_t4t->cc_file.ndef_fc.read_access);
                RW_TRACE_DEBUG1 ("    WriteAccess: 0x%02X", p_t4t->cc_file.ndef_fc.write_access);
#endif

                if (rw_t4t_validate_cc_file ())
                {
                    if (!rw_t4t_select_file (p_t4t->cc_file.ndef_fc.file_id))
                    {
                        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
                    }
                    else
                    {
                        p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
                    }
                    break;
                }
            }
        }

        /* invalid response or CC file */
        p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
        rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
        break;

    case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:

        /* NDEF file has been selected then read the first 2 bytes (NLEN) */
        if (!rw_t4t_read_file (0, T4T_FILE_LENGTH_SIZE, FALSE))
        {
            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        }
        else
        {
            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_READ_NLEN;
        }
        break;

    case RW_T4T_SUBSTATE_WAIT_READ_NLEN:

        /* NLEN has been read then report upper layer */
        if (p_r_apdu->len == T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE)
        {
            /* get length of NDEF */
            p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
            BE_STREAM_TO_UINT16 (nlen, p);

            if (nlen <= p_t4t->cc_file.ndef_fc.max_file_size - T4T_FILE_LENGTH_SIZE)
            {
                p_t4t->ndef_status = RW_T4T_NDEF_STATUS_NDEF_DETECTED;

                if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
                {
                    p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY;
                }

                /* Get max bytes to read per command */
                if (p_t4t->cc_file.max_le >= RW_T4T_MAX_DATA_PER_READ)
                {
                    p_t4t->max_read_size = RW_T4T_MAX_DATA_PER_READ;
                }
                else
                {
                    p_t4t->max_read_size = p_t4t->cc_file.max_le;
                }

                /* Le: valid range is 0x01 to 0xFF */
                if (p_t4t->max_read_size >= T4T_MAX_LENGTH_LE)
                {
                    p_t4t->max_read_size = T4T_MAX_LENGTH_LE;
                }

                /* Get max bytes to update per command */
                if (p_t4t->cc_file.max_lc >= RW_T4T_MAX_DATA_PER_WRITE)
                {
                    p_t4t->max_update_size = RW_T4T_MAX_DATA_PER_WRITE;
                }
                else
                {
                    p_t4t->max_update_size = p_t4t->cc_file.max_lc;
                }

                /* Lc: valid range is 0x01 to 0xFF */
                if (p_t4t->max_update_size >= T4T_MAX_LENGTH_LC)
                {
                    p_t4t->max_update_size = T4T_MAX_LENGTH_LC;
                }

                p_t4t->ndef_length = nlen;
                p_t4t->state       = RW_T4T_STATE_IDLE;

                if (rw_cb.p_cback)
                {
                    rw_data.ndef.status   = NFC_STATUS_OK;
                    rw_data.ndef.protocol = NFC_PROTOCOL_ISO_DEP;
                    rw_data.ndef.max_size = (UINT32) (p_t4t->cc_file.ndef_fc.max_file_size - (UINT16) T4T_FILE_LENGTH_SIZE);
                    rw_data.ndef.cur_size = nlen;
                    rw_data.ndef.flags    = RW_NDEF_FL_SUPPORTED | RW_NDEF_FL_FORMATED;
                    if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
                    {
                        rw_data.ndef.flags    |= RW_NDEF_FL_READ_ONLY;
                    }

                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_DETECT_EVT, &rw_data);

                    RW_TRACE_DEBUG0 ("rw_t4t_sm_detect_ndef (): Sent RW_T4T_NDEF_DETECT_EVT");
                }
            }
            else
            {
                /* NLEN should be less than max file size */
                RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): NLEN (%d) + 2 must be <= max file size (%d)",
                                 nlen, p_t4t->cc_file.ndef_fc.max_file_size);

                p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
                rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
            }
        }
        else
        {
            /* response payload size should be T4T_FILE_LENGTH_SIZE */
            RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): Length (%d) of R-APDU must be %d",
                             p_r_apdu->len, T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE);

            p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
            rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
        }
        break;

    default:
        RW_TRACE_ERROR1 ("rw_t4t_sm_detect_ndef (): unknown sub_state=%d", p_t4t->sub_state);
        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        break;
    }
}
Example #12
0
/*******************************************************************************
**
** Function         rw_t4t_sm_update_ndef
**
** Description      State machine for NDEF update procedure
**
** Returns          none
**
*******************************************************************************/
static void rw_t4t_sm_update_ndef (BT_HDR  *p_r_apdu)
{
    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
    UINT8       *p;
    UINT16      status_words;
    tRW_DATA    rw_data;

#if (BT_TRACE_VERBOSE == TRUE)
    RW_TRACE_DEBUG2 ("rw_t4t_sm_update_ndef (): sub_state:%s (%d)",
                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
#else
    RW_TRACE_DEBUG1 ("rw_t4t_sm_update_ndef (): sub_state=%d", p_t4t->sub_state);
#endif

    /* Get status words */
    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
    BE_STREAM_TO_UINT16 (status_words, p);

    if (status_words != T4T_RSP_CMD_CMPLTED)
    {
        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
        return;
    }

    switch (p_t4t->sub_state)
    {
    case RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN:

        /* NLEN has been updated */
        /* if need to update data */
        if (p_t4t->p_update_data)
        {
            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_RESP;

            if (!rw_t4t_update_file ())
            {
                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
                p_t4t->p_update_data = NULL;
            }
        }
        else
        {
            p_t4t->state = RW_T4T_STATE_IDLE;

            /* just finished last step of updating (updating NLEN) */
            if (rw_cb.p_cback)
            {
                rw_data.status = NFC_STATUS_OK;

                (*(rw_cb.p_cback)) (RW_T4T_NDEF_UPDATE_CPLT_EVT, &rw_data);
                RW_TRACE_DEBUG0 ("rw_t4t_sm_update_ndef (): Sent RW_T4T_NDEF_UPDATE_CPLT_EVT");
            }
        }
        break;

    case RW_T4T_SUBSTATE_WAIT_UPDATE_RESP:

        /* if updating is not completed */
        if (p_t4t->rw_length > 0)
        {
            if (!rw_t4t_update_file ())
            {
                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
                p_t4t->p_update_data = NULL;
            }
        }
        else
        {
            p_t4t->p_update_data = NULL;

            /* update NLEN as last step of updating file */
            if (!rw_t4t_update_nlen (p_t4t->ndef_length))
            {
                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
            }
            else
            {
                p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN;
            }
        }
        break;

    default:
        RW_TRACE_ERROR1 ("rw_t4t_sm_update_ndef (): unknown sub_state = %d", p_t4t->sub_state);
        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        break;
    }
}
/*******************************************************************************
**
** Function         avrc_bld_get_capability_rsp
**
** Description      This function builds the Get Capability response.
**
** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
**                  Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR *p_pkt)
{
    UINT8   *p_data, *p_start, *p_len, *p_count;
    UINT16  len = 0;
    UINT8   xx;
    UINT32  *p_company_id;
    UINT8   *p_event_id;
    tAVRC_STS status = AVRC_STS_NO_ERROR;

    if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id)))
    {
        AVRC_TRACE_ERROR1("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", p_rsp);
        status = AVRC_STS_BAD_PARAM;
        return status;
    }

    AVRC_TRACE_API0("avrc_bld_get_capability_rsp");
    /* get the existing length, if any, and also the num attributes */
    p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    p_data = p_len = p_start + 2; /* pdu + rsvd */

    BE_STREAM_TO_UINT16(len, p_data);
    UINT8_TO_BE_STREAM(p_data, p_rsp->capability_id);
    p_count = p_data;

    if (len == 0)
    {
        *p_count = p_rsp->count;
        p_data++;
        len = 2; /* move past the capability_id and count */
    }
    else
    {
        p_data = p_start + p_pkt->len;
        *p_count += p_rsp->count;
    }

    if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID)
    {
        p_company_id = p_rsp->param.company_id;
        for (xx=0; xx< p_rsp->count; xx++)
        {
            UINT24_TO_BE_STREAM(p_data, p_company_id[xx]);
        }
        len += p_rsp->count * 3;
    }
    else
    {
        p_event_id = p_rsp->param.event_id;
        *p_count = 0;
        for (xx=0; xx< p_rsp->count; xx++)
        {
            if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx]))
            {
                (*p_count)++;
                UINT8_TO_BE_STREAM(p_data, p_event_id[xx]);
            }
        }
        len += (*p_count);
    }
    UINT16_TO_BE_STREAM(p_len, len);
    p_pkt->len = (p_data - p_start);
    status = AVRC_STS_NO_ERROR;

    return status;
}
Example #14
0
/*******************************************************************************
**
** Function         llcp_util_parse_link_params
**
** Description      Parse LLCP Link parameters
**
** Returns          TRUE if success
**
*******************************************************************************/
BOOLEAN llcp_util_parse_link_params (UINT16 length, UINT8 *p_bytes)
{
    UINT8 param_type, param_len, *p = p_bytes;

    while (length)
    {
        BE_STREAM_TO_UINT8 (param_type, p);
        length--;

        switch (param_type)
        {
        case LLCP_VERSION_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_version, p);
            LLCP_TRACE_DEBUG1 ("Peer Version - 0x%02X", llcp_cb.lcb.peer_version);
            break;

        case LLCP_MIUX_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT16 (llcp_cb.lcb.peer_miu, p);
            llcp_cb.lcb.peer_miu &= LLCP_MIUX_MASK;
            llcp_cb.lcb.peer_miu += LLCP_DEFAULT_MIU;
            LLCP_TRACE_DEBUG1 ("Peer MIU - %d bytes", llcp_cb.lcb.peer_miu);
            break;

        case LLCP_WKS_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT16 (llcp_cb.lcb.peer_wks, p);
            LLCP_TRACE_DEBUG1 ("Peer WKS - 0x%04X", llcp_cb.lcb.peer_wks);
            break;

        case LLCP_LTO_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_lto, p);
            llcp_cb.lcb.peer_lto *= LLCP_LTO_UNIT;  /* 10ms unit */
            LLCP_TRACE_DEBUG1 ("Peer LTO - %d ms", llcp_cb.lcb.peer_lto);
            break;

        case LLCP_OPT_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_opt, p);
            LLCP_TRACE_DEBUG1 ("Peer OPT - 0x%02X", llcp_cb.lcb.peer_opt);
            break;

        default:
            LLCP_TRACE_ERROR1 ("llcp_util_parse_link_params (): Unexpected type 0x%x", param_type);
            BE_STREAM_TO_UINT8 (param_len, p);
            p += param_len;
            break;
        }

        if (length >= param_len + 1)
            length -= param_len + 1;
        else
        {
            LLCP_TRACE_ERROR0 ("llcp_util_parse_link_params (): Bad LTV's");
            return (FALSE);
        }
    }
    return (TRUE);
}
Example #15
0
/*******************************************************************************
**
** Function         llcp_util_parse_connect
**
** Description      Parse CONNECT PDU
**
** Returns          tLLCP_STATUS
**
*******************************************************************************/
tLLCP_STATUS llcp_util_parse_connect (UINT8  *p_bytes, UINT16 length, tLLCP_CONNECTION_PARAMS *p_params)
{
    UINT8 param_type, param_len, *p = p_bytes;

    p_params->miu = LLCP_DEFAULT_MIU;
    p_params->rw  = LLCP_DEFAULT_RW;
    p_params->sn[0] = 0;

    while (length)
    {
        BE_STREAM_TO_UINT8 (param_type, p);
        length--;

        switch (param_type)
        {
        case LLCP_MIUX_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT16 (p_params->miu, p);
            p_params->miu &= LLCP_MIUX_MASK;
            p_params->miu += LLCP_DEFAULT_MIU;

            LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_MIUX_TYPE:%d", p_params->miu);
            break;

        case LLCP_RW_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);
            BE_STREAM_TO_UINT8 (p_params->rw, p);
            p_params->rw &= 0x0F;

            LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_RW_TYPE:%d", p_params->rw);
            break;

        case LLCP_SN_TYPE:
            BE_STREAM_TO_UINT8 (param_len, p);

            if (param_len <= LLCP_MAX_SN_LEN)
            {
                memcpy (p_params->sn, p, param_len);
                p_params->sn[param_len] = 0;
            }
            else
            {
                memcpy (p_params->sn, p, LLCP_MAX_SN_LEN);
                p_params->sn[LLCP_MAX_SN_LEN] = 0;
            }
            p += param_len;

            LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_SN_TYPE:<%s>", p_params->sn);
            break;

        default:
            LLCP_TRACE_ERROR1 ("llcp_util_parse_connect (): Unexpected type 0x%x", param_type);
            BE_STREAM_TO_UINT8 (param_len, p);
            p += param_len;
            break;
        }

        /* check remaining lengh */
        if (length >= param_len + 1)
        {
            length -= param_len + 1;
        }
        else
        {
            LLCP_TRACE_ERROR0 ("llcp_util_parse_connect (): Bad LTV's");
            return LLCP_STATUS_FAIL;
        }
    }
    return LLCP_STATUS_SUCCESS;
}
/*******************************************************************************
**
** 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);
}
/*******************************************************************************
**
** Function         avrc_pars_vendor_rsp
**
** Description      This function parses the vendor specific commands defined by
**                  Bluetooth SIG
**
** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
**                  Otherwise, the error code defined by AVRCP 1.4
**
*******************************************************************************/
static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result)
{
    tAVRC_STS  status = AVRC_STS_NO_ERROR;
    UINT8   *p = p_msg->p_vendor_data;
    UINT16  len;
    UINT8   xx, yy;
    tAVRC_NOTIF_RSP_PARAM   *p_param;
    tAVRC_APP_SETTING       *p_app_set;
    tAVRC_APP_SETTING_TEXT  *p_app_txt;
    tAVRC_ATTR_ENTRY        *p_entry;
    UINT32  *p_u32;
    UINT8   *p_u8;
    UINT16  size_needed;
    UINT8 eventid=0;

    BE_STREAM_TO_UINT8 (p_result->pdu, p);
    p++; /* skip the reserved/packe_type byte */
    BE_STREAM_TO_UINT16 (len, p);
    AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len);
    if (p_msg->hdr.ctype == AVRC_RSP_REJ)
    {
        p_result->rsp.status = *p;
        return p_result->rsp.status;
    }

    switch (p_result->pdu)
    {
    /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
    /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */

#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
    case AVRC_PDU_SET_ABSOLUTE_VOLUME:      /* 0x50 */
        if (len != 1)
            status = AVRC_STS_INTERNAL_ERR;
        else
        {
            BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
        }
        break;

    case AVRC_PDU_GET_ELEMENT_ATTR:      /* 0x20 */
        BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p);

        AVRC_TRACE_API("num_attr: %d", p_result->get_elem_attrs.num_attr);

        if (len == 0)
            status = AVRC_STS_INTERNAL_ERR;
        else
        {
            status = avrc_prs_get_elem_attrs_rsp(&p_result->get_elem_attrs, p);
        }
        break;
#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */

    case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
        BE_STREAM_TO_UINT8 (eventid, p);
        if(AVRC_EVT_VOLUME_CHANGE==eventid
            && (AVRC_RSP_CHANGED==p_msg->hdr.ctype || AVRC_RSP_INTERIM==p_msg->hdr.ctype
            || AVRC_RSP_REJ==p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL==p_msg->hdr.ctype))
        {
            p_result->reg_notif.status=p_msg->hdr.ctype;
            p_result->reg_notif.event_id=eventid;
            BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p);
        }
        AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x",eventid,
            p_result->reg_notif.param.volume);
#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
        break;
    default:
        status = AVRC_STS_BAD_CMD;
        break;
    }

    return status;
}
Example #18
0
/*******************************************************************************
**
** Function         ce_t4t_data_cback
**
** Description      This callback function receives the data from NFCC.
**
** Returns          none
**
*******************************************************************************/
static void ce_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data)
{
    BT_HDR  *p_c_apdu;
    UINT8   *p_cmd;
    UINT8    cla, instruct, select_type = 0, length;
    UINT16   offset, max_file_size;
    tCE_DATA ce_data;

    if (event == NFC_DEACTIVATE_CEVT)
    {
        NFC_SetStaticRfCback (NULL);
        return;
    }
    if (event != NFC_DATA_CEVT)
    {
        return;
    }

    p_c_apdu = (BT_HDR *) p_data->data.p_data;

#if (BT_TRACE_PROTOCOL == TRUE)
    DispCET4Tags (p_c_apdu, TRUE);
#endif

    CE_TRACE_DEBUG1 ("ce_t4t_data_cback (): conn_id = 0x%02X", conn_id);

    p_cmd = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;

    /* Class Byte */
    BE_STREAM_TO_UINT8 (cla, p_cmd);

    /* Don't check class if registered AID has been selected */
    if (  (cla != T4T_CMD_CLASS)
        &&((ce_cb.mem.t4t.status & CE_T4T_STATUS_REG_AID_SELECTED) == 0)
        &&((ce_cb.mem.t4t.status & CE_T4T_STATUS_WILDCARD_AID_SELECTED) == 0)  )
    {
        GKI_freebuf (p_c_apdu);
        ce_t4t_send_status (T4T_RSP_CLASS_NOT_SUPPORTED);
        return;
    }

    /* Instruction Byte */
    BE_STREAM_TO_UINT8 (instruct, p_cmd);

    if ((cla == T4T_CMD_CLASS) && (instruct == T4T_CMD_INS_SELECT))
    {
        /* P1 Byte */
        BE_STREAM_TO_UINT8 (select_type, p_cmd);

        if (select_type == T4T_CMD_P1_SELECT_BY_NAME)
        {
            ce_t4t_process_select_app_cmd (p_cmd, p_c_apdu);
            return;
        }
    }

    /* if registered AID is selected */
    if (ce_cb.mem.t4t.status & CE_T4T_STATUS_REG_AID_SELECTED)
    {
        CE_TRACE_DEBUG0 ("CET4T: Forward raw frame to registered AID");

        /* forward raw frame to upper layer */
        if (ce_cb.mem.t4t.selected_aid_idx < CE_T4T_MAX_REG_AID)
        {
            ce_data.raw_frame.status = p_data->data.status;
            ce_data.raw_frame.p_data = p_c_apdu;
            ce_data.raw_frame.aid_handle = ce_cb.mem.t4t.selected_aid_idx;
            p_c_apdu = NULL;

            (*(ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].p_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data);
        }
        else
        {
            GKI_freebuf (p_c_apdu);
            ce_t4t_send_status (T4T_RSP_NOT_FOUND);
        }
    }
    else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_WILDCARD_AID_SELECTED)
    {
        CE_TRACE_DEBUG0 ("CET4T: Forward raw frame to wildcard AID handler");

        /* forward raw frame to upper layer */
        ce_data.raw_frame.status = p_data->data.status;
        ce_data.raw_frame.p_data = p_c_apdu;
        ce_data.raw_frame.aid_handle = CE_T4T_WILDCARD_AID_HANDLE;
        p_c_apdu = NULL;

        (*(ce_cb.mem.t4t.p_wildcard_aid_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data);
    }
    else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_T4T_APP_SELECTED)
    {
        if (instruct == T4T_CMD_INS_SELECT)
        {
            /* P1 Byte is already parsed */
            if (select_type == T4T_CMD_P1_SELECT_BY_FILE_ID)
            {
                ce_t4t_process_select_file_cmd (p_cmd);
            }
            else
            {
                CE_TRACE_ERROR1 ("CET4T: Bad P1 byte (0x%02X)", select_type);
                ce_t4t_send_status (T4T_RSP_WRONG_PARAMS);
            }
        }
        else if (instruct == T4T_CMD_INS_READ_BINARY)
        {
            if (  (ce_cb.mem.t4t.status & CE_T4T_STATUS_CC_FILE_SELECTED)
                ||(ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_SELECTED)  )
            {
                if (ce_cb.mem.t4t.status & CE_T4T_STATUS_CC_FILE_SELECTED)
                {
                    max_file_size = T4T_FC_TLV_OFFSET_IN_CC + T4T_FILE_CONTROL_TLV_SIZE;
                }
                else
                {
                    max_file_size = ce_cb.mem.t4t.max_file_size;
                }

                BE_STREAM_TO_UINT16 (offset, p_cmd); /* Offset */
                BE_STREAM_TO_UINT8 (length, p_cmd); /* Le     */

                /* check if valid parameters */
                if (length <= CE_T4T_MAX_LE)
                {
                    /* CE allows to read more than current file size but not max file size */
                    if (length + offset > max_file_size)
                    {
                        if (offset < max_file_size)
                        {
                            length = (UINT8) (max_file_size - offset);

                            CE_TRACE_DEBUG2 ("CET4T: length is reduced to %d by max_file_size (%d)",
                                              length, max_file_size);
                        }
                        else
                        {
                            CE_TRACE_ERROR2 ("CET4T: offset (%d) must be less than max_file_size (%d)",
                                              offset, max_file_size);
                            length = 0;
                        }
                    }
                }
                else
                {
                    CE_TRACE_ERROR2 ("CET4T: length (%d) must be less than MLe (%d)",
                                      length, CE_T4T_MAX_LE);
                    length = 0;
                }

                if (length > 0)
                    ce_t4t_read_binary (offset, length);
                else
                    ce_t4t_send_status (T4T_RSP_WRONG_PARAMS);
            }
            else
            {
                CE_TRACE_ERROR0 ("CET4T: File has not been selected");
                ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED);
            }
        }
        else if (instruct == T4T_CMD_INS_UPDATE_BINARY)
        {
            if (ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_FILE_READ_ONLY)
            {
                CE_TRACE_ERROR0 ("CET4T: No access right");
                ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED);
            }
            else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_SELECTED)
            {
                BE_STREAM_TO_UINT16 (offset, p_cmd); /* Offset */
                BE_STREAM_TO_UINT8 (length, p_cmd); /* Lc     */

                /* check if valid parameters */
                if (length <= CE_T4T_MAX_LC)
                {
                    if (length + offset > ce_cb.mem.t4t.max_file_size)
                    {
                        CE_TRACE_ERROR3 ("CET4T: length (%d) + offset (%d) must be less than max_file_size (%d)",
                                          length, offset, ce_cb.mem.t4t.max_file_size);
                        length = 0;
                    }
                }
                else
                {
                    CE_TRACE_ERROR2 ("CET4T: length (%d) must be less than MLc (%d)",
                                      length, CE_T4T_MAX_LC);
                    length = 0;
                }

                if (length > 0)
                    ce_t4t_update_binary (offset, length, p_cmd);
                else
                    ce_t4t_send_status (T4T_RSP_WRONG_PARAMS);
            }
            else
            {
                CE_TRACE_ERROR0 ("CET4T: NDEF File has not been selected");
                ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED);
            }
        }
        else
        {
            CE_TRACE_ERROR1 ("CET4T: Unsupported Instruction byte (0x%02X)", instruct);
            ce_t4t_send_status (T4T_RSP_INSTR_NOT_SUPPORTED);
        }
    }
    else
    {
        CE_TRACE_ERROR0 ("CET4T: Application has not been selected");
        ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED);
    }

    if (p_c_apdu)
        GKI_freebuf (p_c_apdu);
}
Example #19
0
/*******************************************************************************
**
** Function         rw_t4t_sm_read_ndef
**
** Description      State machine for NDEF read procedure
**
** Returns          none
**
*******************************************************************************/
static void rw_t4t_sm_read_ndef (BT_HDR *p_r_apdu)
{
    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
    UINT8       *p;
    UINT16      status_words;
    tRW_DATA    rw_data;

#if (BT_TRACE_VERBOSE == TRUE)
    RW_TRACE_DEBUG2 ("rw_t4t_sm_read_ndef (): sub_state:%s (%d)",
                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
#else
    RW_TRACE_DEBUG1 ("rw_t4t_sm_read_ndef (): sub_state=%d", p_t4t->sub_state);
#endif

    /* get status words */
    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
    BE_STREAM_TO_UINT16 (status_words, p);

    if (status_words != T4T_RSP_CMD_CMPLTED)
    {
        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
        GKI_freebuf (p_r_apdu);
        return;
    }

    switch (p_t4t->sub_state)
    {
    case RW_T4T_SUBSTATE_WAIT_READ_RESP:

        /* Read partial or complete data */
        p_r_apdu->len -= T4T_RSP_STATUS_WORDS_SIZE;

        if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length))
        {
            p_t4t->rw_length -= p_r_apdu->len;
            p_t4t->rw_offset += p_r_apdu->len;

            if (rw_cb.p_cback)
            {
                rw_data.data.status = NFC_STATUS_OK;
                rw_data.data.p_data = p_r_apdu;

                /* if need to read more data */
                if (p_t4t->rw_length > 0)
                {
                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_EVT, &rw_data);

                    if (!rw_t4t_read_file (p_t4t->rw_offset, p_t4t->rw_length, TRUE))
                    {
                        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
                    }
                }
                else
                {
                    p_t4t->state = RW_T4T_STATE_IDLE;

                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_CPLT_EVT, &rw_data);

                    RW_TRACE_DEBUG0 ("rw_t4t_sm_read_ndef (): Sent RW_T4T_NDEF_READ_CPLT_EVT");

                }

                p_r_apdu = NULL;
            }
            else
            {
                p_t4t->rw_length = 0;
                p_t4t->state = RW_T4T_STATE_IDLE;
            }
        }
        else
        {
            RW_TRACE_ERROR2 ("rw_t4t_sm_read_ndef (): invalid payload length (%d), rw_length (%d)",
                             p_r_apdu->len, p_t4t->rw_length);
            rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
        }
        break;

    default:
        RW_TRACE_ERROR1 ("rw_t4t_sm_read_ndef (): unknown sub_state = %d", p_t4t->sub_state);
        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        break;
    }

    if (p_r_apdu)
        GKI_freebuf (p_r_apdu);
}
Example #20
0
/*******************************************************************************
**
** Function         ce_t4t_update_binary
**
** Description      Update file and send R-APDU to peer
**
** Returns          TRUE if success
**
*******************************************************************************/
static BOOLEAN ce_t4t_update_binary (UINT16 offset, UINT8 length, UINT8 *p_data)
{
    tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
    UINT8       *p;
    UINT8        file_length[2];
    UINT16       starting_offset;
    tCE_DATA     ce_data;

    CE_TRACE_DEBUG3 ("ce_t4t_update_binary (): Offset:0x%04X, Length:0x%04X, selected status = 0x%02X",
                      offset, length, p_t4t->status);

    starting_offset = offset;

    /* update file size (NLEN) */
    if ((offset < T4T_FILE_LENGTH_SIZE) && (length > 0))
    {
        p = file_length;
        UINT16_TO_BE_STREAM (p, p_t4t->nlen);

        while ((offset < T4T_FILE_LENGTH_SIZE) && (length > 0))
        {
            *(file_length + offset++) = *(p_data++);
            length--;
        }

        p = file_length;
        BE_STREAM_TO_UINT16 (p_t4t->nlen, p);
    }

    if (length > 0)
        memcpy (p_t4t->p_scratch_buf + offset - T4T_FILE_LENGTH_SIZE, p_data, length);

    /* if this is the last step: writing non-zero length in NLEN */
    if ((starting_offset == 0) && (p_t4t->nlen > 0))
    {
        nfc_stop_quick_timer (&p_t4t->timer);

        if (ce_cb.p_cback)
        {
            ce_data.update_info.status = NFC_STATUS_OK;
            ce_data.update_info.length = p_t4t->nlen;
            ce_data.update_info.p_data = p_t4t->p_scratch_buf;

            (*ce_cb.p_cback) (CE_T4T_NDEF_UPDATE_CPLT_EVT, &ce_data);
            CE_TRACE_DEBUG0 ("ce_t4t_update_binary (): Sent CE_T4T_NDEF_UPDATE_CPLT_EVT");
        }

        p_t4t->status &= ~ (CE_T4T_STATUS_NDEF_FILE_UPDATING);
    }
    else if (!(p_t4t->status & CE_T4T_STATUS_NDEF_FILE_UPDATING))
    {
        /* starting of updating */
        p_t4t->status |= CE_T4T_STATUS_NDEF_FILE_UPDATING;

        nfc_start_quick_timer (&p_t4t->timer, NFC_TTYPE_CE_T4T_UPDATE,
                               (CE_T4T_TOUT_UPDATE * QUICK_TIMER_TICKS_PER_SEC) / 1000);

        if (ce_cb.p_cback)
            (*ce_cb.p_cback) (CE_T4T_NDEF_UPDATE_START_EVT, NULL);
    }

    if (!ce_t4t_send_status (T4T_RSP_CMD_CMPLTED))
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}
Example #21
0
/*******************************************************************************
**
** Function         avrc_pars_vendor_cmd
**
** Description      This function parses the vendor specific commands defined by
**                  Bluetooth SIG
**
** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
**                  Otherwise, the error code defined by AVRCP 1.4
**
*******************************************************************************/
static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result,
                                      UINT8 *p_buf, UINT16 buf_len)
{
    tAVRC_STS  status = AVRC_STS_NO_ERROR;
    UINT8   *p;
    UINT16  len;
    UINT8   xx, yy;
    UINT8   *p_u8;
    UINT16  *p_u16;
    UINT32  u32, u32_2, *p_u32;
    tAVRC_APP_SETTING       *p_app_set;
    UINT16  size_needed;

    /* Check the vendor data */
    if (p_msg->vendor_len == 0) {
        return AVRC_STS_NO_ERROR;
    }
    if (p_msg->p_vendor_data == NULL) {
        return AVRC_STS_INTERNAL_ERR;
    }

    p = p_msg->p_vendor_data;
    p_result->pdu = *p++;
    AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu);
    if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype)) {
        AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() detects wrong AV/C type!");
        status = AVRC_STS_BAD_CMD;
    }

    p++; /* skip the reserved byte */
    BE_STREAM_TO_UINT16 (len, p);
    if ((len + 4) != (p_msg->vendor_len)) {
        status = AVRC_STS_INTERNAL_ERR;
    }

    if (status != AVRC_STS_NO_ERROR) {
        return status;
    }

    switch (p_result->pdu) {
    case AVRC_PDU_GET_CAPABILITIES:         /* 0x10 */
        p_result->get_caps.capability_id = *p++;
        if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id)) {
            status = AVRC_STS_BAD_PARAM;
        } else if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_LIST_PLAYER_APP_ATTR:     /* 0x11 */
        /* no additional parameters */
        if (len != 0) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_LIST_PLAYER_APP_VALUES:   /* 0x12 */
        p_result->list_app_values.attr_id = *p++;
        if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id)) {
            status = AVRC_STS_BAD_PARAM;
        } else if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
        BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p);
        if (len != (p_result->get_cur_app_val.num_attr + 1)) {
            status = AVRC_STS_INTERNAL_ERR;
            break;
        }
        p_u8 = p_result->get_cur_app_val.attrs;
        for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) {
            /* only report the valid player app attributes */
            if (AVRC_IsValidPlayerAttr(*p)) {
                p_u8[yy++] = *p;
            }
            p++;
        }
        p_result->get_cur_app_val.num_attr = yy;
        if (yy == 0) {
            status = AVRC_STS_BAD_PARAM;
        }
        break;

    case AVRC_PDU_SET_PLAYER_APP_VALUE:     /* 0x14 */
        BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p);
        size_needed = sizeof(tAVRC_APP_SETTING);
        if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) {
            p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf;
            p_app_set = p_result->set_app_val.p_vals;
            for (xx = 0; ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) {
                p_app_set[xx].attr_id = *p++;
                p_app_set[xx].attr_val = *p++;
                if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) {
                    status = AVRC_STS_BAD_PARAM;
                }
            }
            if (xx != p_result->set_app_val.num_val) {
                AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
                                 xx, p_result->set_app_val.num_val);
                p_result->set_app_val.num_val = xx;
            }
        } else {
            AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len");
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */
        if (len < 3) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.attr_id, p);
            if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id)) {
                status = AVRC_STS_BAD_PARAM;
            } else {
                BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.num_val, p);
                if ( (len - 2/* attr_id & num_val */) != p_result->get_app_val_txt.num_val) {
                    status = AVRC_STS_INTERNAL_ERR;
                } else {
                    p_u8 = p_result->get_app_val_txt.vals;
                    for (xx = 0; xx < p_result->get_app_val_txt.num_val; xx++) {
                        p_u8[xx] = *p++;
                        if (!avrc_is_valid_player_attrib_value(p_result->get_app_val_txt.attr_id,
                                                               p_u8[xx])) {
                            status = AVRC_STS_BAD_PARAM;
                            break;
                        }
                    }
                }
            }
        }
        break;

    case AVRC_PDU_INFORM_DISPLAY_CHARSET:  /* 0x17 */
        if (len < 3) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT8 (p_result->inform_charset.num_id, p);
            if ( (len - 1/* num_id */) != p_result->inform_charset.num_id * 2) {
                status = AVRC_STS_INTERNAL_ERR;
            } else {
                p_u16 = p_result->inform_charset.charsets;
                if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE) {
                    p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
                }
                for (xx = 0; xx < p_result->inform_charset.num_id; xx++) {
                    BE_STREAM_TO_UINT16 (p_u16[xx], p);
                }
            }
        }
        break;

    case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */
        if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            p_result->inform_battery_status.battery_status = *p++;
            if (!AVRC_IS_VALID_BATTERY_STATUS(p_result->inform_battery_status.battery_status)) {
                status = AVRC_STS_BAD_PARAM;
            }
        }
        break;

    case AVRC_PDU_GET_ELEMENT_ATTR:         /* 0x20 */
        if (len < 9) { /* UID/8 and num_attr/1 */
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT32 (u32, p);
            BE_STREAM_TO_UINT32 (u32_2, p);
            if (u32 == 0 && u32_2 == 0) {
                BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p);
                if ( (len - 9/* UID/8 and num_attr/1 */) != (p_result->get_elem_attrs.num_attr * 4)) {
                    status = AVRC_STS_INTERNAL_ERR;
                } else {
                    p_u32 = p_result->get_elem_attrs.attrs;
                    if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE) {
                        p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
                    }
                    for (xx = 0; xx < p_result->get_elem_attrs.num_attr; xx++) {
                        BE_STREAM_TO_UINT32 (p_u32[xx], p);
                    }
                }
            } else {
                status = AVRC_STS_NOT_FOUND;
            }
        }
        break;

    case AVRC_PDU_GET_PLAY_STATUS:          /* 0x30 */
        /* no additional parameters */
        if (len != 0) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
        if (len != 5) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
            BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
        }
        break;

    case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
        if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;
    }

    /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
    /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */

    default:
        status = AVRC_STS_BAD_CMD;
        break;
    }

    return status;
}
/*******************************************************************************
**
** 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);
}