/*******************************************************************************
**
** 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;
}
/*******************************************************************************
**
** Function         AVRC_ParsResponse
**
** Description      This function is a superset of AVRC_ParsMetadata to parse the response.
**
** 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_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len)
{
    tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
    UINT16  id;
    UNUSED(p_buf);
    UNUSED(buf_len);

    if (p_msg && p_result)
    {
        switch (p_msg->hdr.opcode)
        {
        case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
            status = avrc_pars_vendor_rsp(&p_msg->vendor, p_result);
            break;

        case AVRC_OP_PASS_THRU:  /*  0x7C    panel subunit opcode */
            status = avrc_pars_pass_thru(&p_msg->pass, &id);
            if (status == AVRC_STS_NO_ERROR)
            {
                p_result->pdu = (UINT8)id;
            }
            break;

        default:
            AVRC_TRACE_ERROR("AVRC_ParsResponse() unknown opcode:0x%x", p_msg->hdr.opcode);
            break;
        }
        p_result->rsp.opcode = p_msg->hdr.opcode;
        p_result->rsp.status = status;
    }
    return status;
}
Beispiel #3
0
/*******************************************************************************
**
** Function         AVRC_ParsCommand
**
** Description      This function is a superset of AVRC_ParsMetadata to parse the command.
**
** 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_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len)
{
    tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
    UINT16  id;

    if (p_msg && p_result) {
        switch (p_msg->hdr.opcode) {
        case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
            status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
            break;

        case AVRC_OP_PASS_THRU:  /*  0x7C    panel subunit opcode */
            status = avrc_pars_pass_thru(&p_msg->pass, &id);
            if (status == AVRC_STS_NO_ERROR) {
                p_result->pdu = (UINT8)id;
            }
            break;

        default:
            AVRC_TRACE_ERROR("AVRC_ParsCommand() unknown opcode:0x%x", p_msg->hdr.opcode);
            break;
        }
        p_result->cmd.opcode = p_msg->hdr.opcode;
        p_result->cmd.status = status;
    }
    AVRC_TRACE_DEBUG("AVRC_ParsCommand() return status:0x%x", status);
    return status;
}
Beispiel #4
0
/******************************************************************************
**
** Function         avrc_send_continue_frag
**
** Description      This function sends a continue response fragment
**
** Returns          Nothing.
**
******************************************************************************/
static void avrc_send_continue_frag(UINT8 handle, UINT8 label)
{
    tAVRC_FRAG_CB   *p_fcb;
    BT_HDR  *p_pkt_old, *p_pkt;
    UINT8   *p_old, *p_data;
    UINT8   cr = AVCT_RSP;
    tAVRC_RSP   rej_rsp;

    p_fcb = &avrc_cb.fcb[handle];
    p_pkt = p_fcb->p_fmsg;

    AVRC_TRACE_DEBUG("%s handle = %u label = %u len = %d",
                     __func__, handle, label, p_pkt->len);
    if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) {
        int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
        p_pkt_old = p_fcb->p_fmsg;
        p_pkt = (BT_HDR *)osi_malloc((UINT16)(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE));
        if (p_pkt) {
            p_pkt->len          = AVRC_MAX_CTRL_DATA_LEN;
            p_pkt->offset       = AVCT_MSG_OFFSET;
            p_pkt->layer_specific = p_pkt_old->layer_specific;
            p_pkt->event = p_pkt_old->event;
            p_old = (UINT8 *)(p_pkt_old + 1) + p_pkt_old->offset;
            p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
            memcpy (p_data, p_old, AVRC_MAX_CTRL_DATA_LEN);
            /* use AVRC continue packet type */
            p_data += AVRC_VENDOR_HDR_SIZE;
            p_data++; /* pdu */
            *p_data++ = AVRC_PKT_CONTINUE;
            /* 4=pdu, pkt_type & len */
            UINT16_TO_BE_STREAM(p_data, (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - 4));

            /* prepare the left over for as an end fragment */
            avrc_prep_end_frag (handle);
        } else {
            /* use the current GKI buffer to send Internal error status */
            p_pkt = p_fcb->p_fmsg;
            p_fcb->p_fmsg = NULL;
            p_fcb->frag_enabled = FALSE;
            AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation - send internal error" );
            p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
            *p_data++ = AVRC_PDU_REQUEST_CONTINUATION_RSP;
            *p_data++ = 0;
            UINT16_TO_BE_STREAM(p_data, 0);
            p_pkt->len = 4;
            rej_rsp.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
            rej_rsp.status = AVRC_STS_INTERNAL_ERR;
            AVRC_BldResponse( handle, (tAVRC_RESPONSE *)&rej_rsp, &p_pkt);
            cr = AVCT_RSP;
        }
    } else {
        /* end fragment. clean the control block */
        p_fcb->frag_enabled = FALSE;
        p_fcb->p_fmsg       = NULL;
    }
    AVCT_MsgReq( handle, label, cr, p_pkt);
}
Beispiel #5
0
/*******************************************************************************
**
** Function         avrc_is_valid_player_attrib_value
**
** Description      Check if the given attrib value is valid for its attribute
**
** Returns          returns TRUE if it is valid
**
*******************************************************************************/
BOOLEAN avrc_is_valid_player_attrib_value(UINT8 attrib, UINT8 value)
{
    BOOLEAN result = FALSE;

    switch (attrib) {
    case AVRC_PLAYER_SETTING_EQUALIZER:
        if ((value > 0)  &&
                (value <= AVRC_PLAYER_VAL_ON)) {
            result = TRUE;
        }
        break;

    case AVRC_PLAYER_SETTING_REPEAT:
        if ((value > 0)  &&
                (value <= AVRC_PLAYER_VAL_GROUP_REPEAT)) {
            result = TRUE;
        }
        break;

    case AVRC_PLAYER_SETTING_SHUFFLE:
    case AVRC_PLAYER_SETTING_SCAN:
        if ((value > 0)  &&
                (value <= AVRC_PLAYER_VAL_GROUP_SHUFFLE)) {
            result = TRUE;
        }
        break;
    }

    if (attrib >= AVRC_PLAYER_SETTING_LOW_MENU_EXT) {
        result = TRUE;
    }

    if (!result)
        AVRC_TRACE_ERROR(
            "avrc_is_valid_player_attrib_value() found not matching attrib(x%x)-value(x%x) pair!",
            attrib, value);

    return result;
}
Beispiel #6
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;
}
Beispiel #7
0
/******************************************************************************
**
** Function         avrc_proc_vendor_command
**
** Description      This function processes received vendor command.
**
** Returns          if not NULL, the response to send right away.
**
******************************************************************************/
static BT_HDR *avrc_proc_vendor_command(UINT8 handle, UINT8 label,
                                        BT_HDR *p_pkt, tAVRC_MSG_VENDOR *p_msg)
{
    BT_HDR      *p_rsp = NULL;
    UINT8       *p_data;
    UINT8       *p_begin;
    UINT8       pkt_type;
    BOOLEAN     abort_frag = FALSE;
    tAVRC_STS   status = AVRC_STS_NO_ERROR;
    tAVRC_FRAG_CB   *p_fcb;

    p_begin  = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    p_data   = p_begin + AVRC_VENDOR_HDR_SIZE;
    pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;

    if (pkt_type != AVRC_PKT_SINGLE) {
        /* reject - commands can only be in single packets at AVRCP level */
        AVRC_TRACE_ERROR ("commands must be in single packet pdu:0x%x", *p_data );
        /* use the current GKI buffer to send the reject */
        status = AVRC_STS_BAD_CMD;
    }
    /* check if there are fragments waiting to be sent */
    else if (avrc_cb.fcb[handle].frag_enabled) {
        p_fcb = &avrc_cb.fcb[handle];
        if (p_msg->company_id == AVRC_CO_METADATA) {
            switch (*p_data) {
            case AVRC_PDU_ABORT_CONTINUATION_RSP:
                /* aborted by CT - send accept response */
                abort_frag = TRUE;
                p_begin = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
                *p_begin = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK);
                if (*(p_data + 4) != p_fcb->frag_pdu) {
                    *p_begin = (AVRC_RSP_REJ & AVRC_CTYPE_MASK);
                    *(p_data + 4) = AVRC_STS_BAD_PARAM;
                } else {
                    p_data = (p_begin + AVRC_VENDOR_HDR_SIZE + 2);
                    UINT16_TO_BE_STREAM(p_data, 0);
                    p_pkt->len = (p_data - p_begin);
                }
                AVCT_MsgReq( handle, label, AVCT_RSP, p_pkt);
                p_msg->hdr.opcode = AVRC_OP_DROP; /* used the p_pkt to send response */
                break;

            case AVRC_PDU_REQUEST_CONTINUATION_RSP:
                if (*(p_data + 4) == p_fcb->frag_pdu) {
                    avrc_send_continue_frag(handle, label);
                    p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
                } else {
                    /* the pdu id does not match - reject the command using the current GKI buffer */
                    AVRC_TRACE_ERROR("avrc_proc_vendor_command continue pdu: 0x%x does not match \
                    current re-assembly pdu: 0x%x",
                                     *(p_data + 4), p_fcb->frag_pdu);
                    status = AVRC_STS_BAD_PARAM;
                    abort_frag = TRUE;
                }
                break;

            default:
                /* implicit abort */
                abort_frag = TRUE;
            }
        } else {