1 /******************************************************************************
2  *
3  *  Copyright (C) 2003-2013 Broadcom Corporation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 #include <string.h>
19 
20 #include "gki.h"
21 #include "avrc_api.h"
22 #include "avrc_defs.h"
23 #include "avrc_int.h"
24 
25 /*****************************************************************************
26 **  Global data
27 *****************************************************************************/
28 #if (AVRC_METADATA_INCLUDED == TRUE)
29 
30 /*******************************************************************************
31 **
32 ** Function         avrc_pars_vendor_cmd
33 **
34 ** Description      This function parses the vendor specific commands defined by
35 **                  Bluetooth SIG
36 **
37 ** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
38 **                  Otherwise, the error code defined by AVRCP 1.4
39 **
40 *******************************************************************************/
avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR * p_msg,tAVRC_COMMAND * p_result,UINT8 * p_buf,UINT16 buf_len)41 static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result,
42                                       UINT8 *p_buf, UINT16 buf_len)
43 {
44     tAVRC_STS  status = AVRC_STS_NO_ERROR;
45     UINT8   *p;
46     UINT16  len;
47     UINT8   xx, yy;
48     UINT8   *p_u8;
49     UINT16  *p_u16;
50     UINT32  u32, u32_2, *p_u32;
51     tAVRC_APP_SETTING       *p_app_set;
52     UINT16  size_needed;
53 
54     /* Check the vendor data */
55     if (p_msg->vendor_len == 0)
56         return AVRC_STS_NO_ERROR;
57     if (p_msg->p_vendor_data == NULL)
58         return AVRC_STS_INTERNAL_ERR;
59 
60     p = p_msg->p_vendor_data;
61     p_result->pdu = *p++;
62     AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu);
63     if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype))
64     {
65         AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() detects wrong AV/C type!");
66         status = AVRC_STS_BAD_CMD;
67     }
68 
69     p++; /* skip the reserved byte */
70     BE_STREAM_TO_UINT16 (len, p);
71     if ((len+4) != (p_msg->vendor_len))
72     {
73         status = AVRC_STS_INTERNAL_ERR;
74     }
75 
76     if (status != AVRC_STS_NO_ERROR)
77         return status;
78 
79     switch (p_result->pdu)
80     {
81     case AVRC_PDU_GET_CAPABILITIES:         /* 0x10 */
82         p_result->get_caps.capability_id = *p++;
83         if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
84             status = AVRC_STS_BAD_PARAM;
85         else if (len != 1)
86             status = AVRC_STS_INTERNAL_ERR;
87         break;
88 
89     case AVRC_PDU_LIST_PLAYER_APP_ATTR:     /* 0x11 */
90         /* no additional parameters */
91         if (len != 0)
92             status = AVRC_STS_INTERNAL_ERR;
93         break;
94 
95     case AVRC_PDU_LIST_PLAYER_APP_VALUES:   /* 0x12 */
96         p_result->list_app_values.attr_id = *p++;
97         if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id))
98             status = AVRC_STS_BAD_PARAM;
99         else if (len != 1)
100             status = AVRC_STS_INTERNAL_ERR;
101         break;
102 
103     case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
104     case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
105         BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p);
106         if (len != (p_result->get_cur_app_val.num_attr+1))
107         {
108             status = AVRC_STS_INTERNAL_ERR;
109             break;
110         }
111         p_u8 = p_result->get_cur_app_val.attrs;
112         for (xx=0, yy=0; xx< p_result->get_cur_app_val.num_attr; xx++)
113         {
114             /* only report the valid player app attributes */
115             if (AVRC_IsValidPlayerAttr(*p))
116                 p_u8[yy++] = *p;
117             p++;
118         }
119         p_result->get_cur_app_val.num_attr = yy;
120         if (yy == 0)
121         {
122             status = AVRC_STS_BAD_PARAM;
123         }
124         break;
125 
126     case AVRC_PDU_SET_PLAYER_APP_VALUE:     /* 0x14 */
127         BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p);
128         size_needed = sizeof(tAVRC_APP_SETTING);
129         if (p_buf && (len == ((p_result->set_app_val.num_val<<1) + 1)))
130         {
131             p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf;
132             p_app_set = p_result->set_app_val.p_vals;
133             for (xx=0; ((xx< p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++)
134             {
135                 p_app_set[xx].attr_id = *p++;
136                 p_app_set[xx].attr_val = *p++;
137                 if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val))
138                     status = AVRC_STS_BAD_PARAM;
139             }
140             if (xx != p_result->set_app_val.num_val)
141             {
142                 AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
143                     xx, p_result->set_app_val.num_val);
144                 p_result->set_app_val.num_val = xx;
145             }
146         }
147         else
148         {
149             AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len");
150             status = AVRC_STS_INTERNAL_ERR;
151         }
152         break;
153 
154     case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */
155         if (len < 3)
156             status = AVRC_STS_INTERNAL_ERR;
157         else
158         {
159             BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.attr_id, p);
160             if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id))
161                 status = AVRC_STS_BAD_PARAM;
162             else
163             {
164                 BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.num_val, p);
165                 if ( (len - 2/* attr_id & num_val */) != p_result->get_app_val_txt.num_val)
166                     status = AVRC_STS_INTERNAL_ERR;
167                 else
168                 {
169                     p_u8 = p_result->get_app_val_txt.vals;
170                     for (xx=0; xx< p_result->get_app_val_txt.num_val; xx++)
171                     {
172                         p_u8[xx] = *p++;
173                         if (!avrc_is_valid_player_attrib_value(p_result->get_app_val_txt.attr_id,
174                             p_u8[xx]))
175                         {
176                             status = AVRC_STS_BAD_PARAM;
177                             break;
178                         }
179                     }
180                 }
181             }
182         }
183         break;
184 
185     case AVRC_PDU_INFORM_DISPLAY_CHARSET:  /* 0x17 */
186         if (len < 3)
187             status = AVRC_STS_INTERNAL_ERR;
188         else
189         {
190             BE_STREAM_TO_UINT8 (p_result->inform_charset.num_id, p);
191             if ( (len - 1/* num_id */) != p_result->inform_charset.num_id * 2)
192                 status = AVRC_STS_INTERNAL_ERR;
193             else
194             {
195                 p_u16 = p_result->inform_charset.charsets;
196                 if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE)
197                     p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
198                 for (xx=0; xx< p_result->inform_charset.num_id; xx++)
199                 {
200                     BE_STREAM_TO_UINT16 (p_u16[xx], p);
201                 }
202             }
203         }
204         break;
205 
206     case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */
207         if (len != 1)
208             status = AVRC_STS_INTERNAL_ERR;
209         else
210         {
211             p_result->inform_battery_status.battery_status = *p++;
212             if (!AVRC_IS_VALID_BATTERY_STATUS(p_result->inform_battery_status.battery_status))
213                 status = AVRC_STS_BAD_PARAM;
214         }
215         break;
216 
217     case AVRC_PDU_GET_ELEMENT_ATTR:         /* 0x20 */
218         if (len < 9) /* UID/8 and num_attr/1 */
219             status = AVRC_STS_INTERNAL_ERR;
220         else
221         {
222             BE_STREAM_TO_UINT32 (u32, p);
223             BE_STREAM_TO_UINT32 (u32_2, p);
224             if (u32== 0 && u32_2 == 0)
225             {
226                 BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p);
227                 if ( (len - 9/* UID/8 and num_attr/1 */) != (p_result->get_elem_attrs.num_attr * 4))
228                     status = AVRC_STS_INTERNAL_ERR;
229                 else
230                 {
231                     p_u32 = p_result->get_elem_attrs.attrs;
232                     if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE)
233                         p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
234                     for (xx=0; xx< p_result->get_elem_attrs.num_attr; xx++)
235                     {
236                         BE_STREAM_TO_UINT32 (p_u32[xx], p);
237                     }
238                 }
239             }
240             else
241                 status = AVRC_STS_NOT_FOUND;
242         }
243         break;
244 
245     case AVRC_PDU_GET_PLAY_STATUS:          /* 0x30 */
246         /* no additional parameters */
247         if (len != 0)
248             status = AVRC_STS_INTERNAL_ERR;
249         break;
250 
251     case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
252         if (len != 5)
253             status = AVRC_STS_INTERNAL_ERR;
254         else
255         {
256             BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
257             BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
258         }
259         break;
260 
261     case AVRC_PDU_SET_ABSOLUTE_VOLUME:
262     {
263         if(len!=1)
264             status = AVRC_STS_INTERNAL_ERR;
265         break;
266     }
267 
268     /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
269     /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */
270 
271     default:
272         status = AVRC_STS_BAD_CMD;
273         break;
274     }
275 
276     return status;
277 }
278 
279 /*******************************************************************************
280 **
281 ** Function         AVRC_ParsCommand
282 **
283 ** Description      This function is a superset of AVRC_ParsMetadata to parse the command.
284 **
285 ** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
286 **                  Otherwise, the error code defined by AVRCP 1.4
287 **
288 *******************************************************************************/
AVRC_ParsCommand(tAVRC_MSG * p_msg,tAVRC_COMMAND * p_result,UINT8 * p_buf,UINT16 buf_len)289 tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len)
290 {
291     tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
292     UINT16  id;
293 
294     if (p_msg && p_result)
295     {
296         switch (p_msg->hdr.opcode)
297         {
298         case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
299             status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
300             break;
301 
302         case AVRC_OP_PASS_THRU:  /*  0x7C    panel subunit opcode */
303             status = avrc_pars_pass_thru(&p_msg->pass, &id);
304             if (status == AVRC_STS_NO_ERROR)
305             {
306                 p_result->pdu = (UINT8)id;
307             }
308             break;
309 
310         default:
311             AVRC_TRACE_ERROR("AVRC_ParsCommand() unknown opcode:0x%x", p_msg->hdr.opcode);
312             break;
313         }
314         p_result->cmd.opcode = p_msg->hdr.opcode;
315         p_result->cmd.status = status;
316     }
317     AVRC_TRACE_DEBUG("AVRC_ParsCommand() return status:0x%x", status);
318     return status;
319 }
320 
321 #endif /* (AVRC_METADATA_INCLUDED == TRUE) */
322 
323