/******************************************************************************* ** ** 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_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_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; }
/****************************************************************************** ** ** Function avrc_prep_end_frag ** ** Description This function prepares an end response fragment ** ** Returns Nothing. ** ******************************************************************************/ static void avrc_prep_end_frag(UINT8 handle) { tAVRC_FRAG_CB *p_fcb; BT_HDR *p_pkt_new; UINT8 *p_data, *p_orig_data; UINT8 rsp_type; AVRC_TRACE_DEBUG ("avrc_prep_end_frag" ); p_fcb = &avrc_cb.fcb[handle]; /* The response type of the end fragment should be the same as the the PDU of "End Fragment ** Response" Errata: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383 */ p_orig_data = ((UINT8 *)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset); rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK); p_pkt_new = p_fcb->p_fmsg; p_pkt_new->len -= (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE); p_pkt_new->offset += (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE); p_data = (UINT8 *)(p_pkt_new + 1) + p_pkt_new->offset; *p_data++ = rsp_type; *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); *p_data++ = AVRC_OP_VENDOR; AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA); *p_data++ = p_fcb->frag_pdu; *p_data++ = AVRC_PKT_END; /* 4=pdu, pkt_type & len */ UINT16_TO_BE_STREAM(p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE)); }
/****************************************************************************** ** ** 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); }
/******************************************************************************* ** ** 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; }
/******************************************************************************* ** ** 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; }