• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 2003-2016 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 "avrc_api.h"
21 #include "avrc_defs.h"
22 #include "avrc_int.h"
23 
24 #include "osi/include/log.h"
25 
26 /*****************************************************************************
27  *  Global data
28  ****************************************************************************/
29 
30 /*******************************************************************************
31  *
32  * Function         avrc_ctrl_pars_vendor_cmd
33  *
34  * Description      This function parses the vendor specific commands defined by
35  *                  Bluetooth SIG for AVRCP Conroller.
36  *
37  * Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed
38  *                  successfully.
39  *                  Otherwise, the error code defined by AVRCP 1.4
40  *
41  ******************************************************************************/
avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR * p_msg,tAVRC_COMMAND * p_result)42 static tAVRC_STS avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
43                                            tAVRC_COMMAND* p_result) {
44   tAVRC_STS status = AVRC_STS_NO_ERROR;
45 
46   if (p_msg->vendor_len < 4) {  // 4 == pdu + reserved byte + len as uint16
47     AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4",
48                        __func__, p_msg->vendor_len);
49     return AVRC_STS_INTERNAL_ERR;
50   }
51   uint8_t* p = p_msg->p_vendor_data;
52   p_result->pdu = *p++;
53   AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
54   if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) {
55     AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
56     status = AVRC_STS_BAD_CMD;
57   }
58 
59   p++; /* skip the reserved byte */
60   uint16_t len;
61   BE_STREAM_TO_UINT16(len, p);
62   if ((len + 4) != (p_msg->vendor_len)) {
63     status = AVRC_STS_INTERNAL_ERR;
64   }
65 
66   if (status != AVRC_STS_NO_ERROR) return status;
67 
68   switch (p_result->pdu) {
69     case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
70       if (len != 1)
71         status = AVRC_STS_INTERNAL_ERR;
72       else {
73         BE_STREAM_TO_UINT8(p_result->volume.volume, p);
74         p_result->volume.volume = AVRC_MAX_VOLUME & p_result->volume.volume;
75       }
76       break;
77     }
78     case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
79       if (len < 5) return AVRC_STS_INTERNAL_ERR;
80 
81       BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
82       BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
83 
84       if (p_result->reg_notif.event_id == 0 ||
85           p_result->reg_notif.event_id > AVRC_NUM_NOTIF_EVENTS) {
86         status = AVRC_STS_BAD_PARAM;
87       }
88       break;
89     default:
90       status = AVRC_STS_BAD_CMD;
91       break;
92   }
93   return status;
94 }
95 
96 /*******************************************************************************
97  *
98  * Function         avrc_pars_vendor_cmd
99  *
100  * Description      This function parses the vendor specific commands defined by
101  *                  Bluetooth SIG
102  *
103  * Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed
104  *                  successfully.
105  *                  Otherwise, the error code defined by AVRCP 1.4
106  *
107  ******************************************************************************/
avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)108 static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
109                                       tAVRC_COMMAND* p_result, uint8_t* p_buf,
110                                       uint16_t buf_len) {
111   tAVRC_STS status = AVRC_STS_NO_ERROR;
112   uint8_t* p;
113   uint16_t len;
114   uint8_t xx, yy;
115   uint8_t* p_u8;
116   uint16_t* p_u16;
117   uint32_t u32, u32_2, *p_u32;
118   tAVRC_APP_SETTING* p_app_set;
119   uint16_t size_needed;
120 
121   /* Check the vendor data */
122   if (p_msg->vendor_len == 0) return AVRC_STS_NO_ERROR;
123   if (p_msg->p_vendor_data == NULL) return AVRC_STS_INTERNAL_ERR;
124 
125   if (p_msg->vendor_len < 4) {
126     AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4",
127                        __func__, p_msg->vendor_len);
128     return AVRC_STS_INTERNAL_ERR;
129   }
130 
131   p = p_msg->p_vendor_data;
132   p_result->pdu = *p++;
133   AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
134   if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) {
135     AVRC_TRACE_DEBUG("%s detects wrong AV/C type(0x%x)!", __func__,
136                      p_msg->hdr.ctype);
137     status = AVRC_STS_BAD_CMD;
138   }
139 
140   p++; /* skip the reserved byte */
141   BE_STREAM_TO_UINT16(len, p);
142   if ((len + 4) != (p_msg->vendor_len)) {
143     AVRC_TRACE_ERROR("%s incorrect length :%d, %d", __func__, len,
144                      p_msg->vendor_len);
145     status = AVRC_STS_INTERNAL_ERR;
146   }
147 
148   if (status != AVRC_STS_NO_ERROR) return status;
149 
150   switch (p_result->pdu) {
151     case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
152       p_result->get_caps.capability_id = *p++;
153       if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
154         status = AVRC_STS_BAD_PARAM;
155       else if (len != 1)
156         return AVRC_STS_INTERNAL_ERR;
157       break;
158 
159     case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
160       /* no additional parameters */
161       if (len != 0) return AVRC_STS_INTERNAL_ERR;
162       break;
163 
164     case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
165       if (len == 0) return AVRC_STS_INTERNAL_ERR;
166       p_result->list_app_values.attr_id = *p++;
167       if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id))
168         status = AVRC_STS_BAD_PARAM;
169       else if (len != 1)
170         status = AVRC_STS_INTERNAL_ERR;
171       break;
172 
173     case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
174     case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
175       if (len == 0) return AVRC_STS_INTERNAL_ERR;
176       BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_attr, p);
177       if (len != (p_result->get_cur_app_val.num_attr + 1)) {
178         status = AVRC_STS_INTERNAL_ERR;
179         break;
180       }
181 
182       if (p_result->get_cur_app_val.num_attr > AVRC_MAX_APP_ATTR_SIZE) {
183         p_result->get_cur_app_val.num_attr = AVRC_MAX_APP_ATTR_SIZE;
184       }
185 
186       p_u8 = p_result->get_cur_app_val.attrs;
187       for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) {
188         /* only report the valid player app attributes */
189         if (AVRC_IsValidPlayerAttr(*p)) p_u8[yy++] = *p;
190         p++;
191       }
192       p_result->get_cur_app_val.num_attr = yy;
193       if (yy == 0) {
194         status = AVRC_STS_BAD_PARAM;
195       }
196       break;
197 
198     case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
199       if (len == 0) return AVRC_STS_INTERNAL_ERR;
200       BE_STREAM_TO_UINT8(p_result->set_app_val.num_val, p);
201       size_needed = sizeof(tAVRC_APP_SETTING);
202       if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) {
203         p_result->set_app_val.p_vals = (tAVRC_APP_SETTING*)p_buf;
204         p_app_set = p_result->set_app_val.p_vals;
205         for (xx = 0;
206              ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed));
207              xx++) {
208           p_app_set[xx].attr_id = *p++;
209           p_app_set[xx].attr_val = *p++;
210           if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id,
211                                                  p_app_set[xx].attr_val))
212             status = AVRC_STS_BAD_PARAM;
213         }
214         if (xx != p_result->set_app_val.num_val) {
215           AVRC_TRACE_ERROR(
216               "%s AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig "
217               "num_val:%d",
218               __func__, xx, p_result->set_app_val.num_val);
219           p_result->set_app_val.num_val = xx;
220         }
221       } else {
222         AVRC_TRACE_ERROR(
223             "%s AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len",
224             __func__);
225         status = AVRC_STS_INTERNAL_ERR;
226       }
227       break;
228 
229     case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: /* 0x16 */
230       if (len < 3)
231         return AVRC_STS_INTERNAL_ERR;
232       else {
233         BE_STREAM_TO_UINT8(p_result->get_app_val_txt.attr_id, p);
234         if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id))
235           status = AVRC_STS_BAD_PARAM;
236         else {
237           BE_STREAM_TO_UINT8(p_result->get_app_val_txt.num_val, p);
238           if ((len - 2 /* attr_id & num_val */) !=
239               p_result->get_app_val_txt.num_val)
240             status = AVRC_STS_INTERNAL_ERR;
241           else {
242             if (p_result->get_app_val_txt.num_val > AVRC_MAX_APP_ATTR_SIZE) {
243               p_result->get_app_val_txt.num_val = AVRC_MAX_APP_ATTR_SIZE;
244             }
245 
246             p_u8 = p_result->get_app_val_txt.vals;
247             for (xx = 0; xx < p_result->get_app_val_txt.num_val; xx++) {
248               p_u8[xx] = *p++;
249               if (!avrc_is_valid_player_attrib_value(
250                       p_result->get_app_val_txt.attr_id, p_u8[xx])) {
251                 status = AVRC_STS_BAD_PARAM;
252                 break;
253               }
254             }
255           }
256         }
257       }
258       break;
259 
260     case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
261       if (len < 3)
262         return AVRC_STS_INTERNAL_ERR;
263       else {
264         BE_STREAM_TO_UINT8(p_result->inform_charset.num_id, p);
265         if ((len - 1 /* num_id */) != p_result->inform_charset.num_id * 2)
266           status = AVRC_STS_INTERNAL_ERR;
267         else {
268           p_u16 = p_result->inform_charset.charsets;
269           if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE)
270             p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
271           for (xx = 0; xx < p_result->inform_charset.num_id; xx++) {
272             BE_STREAM_TO_UINT16(p_u16[xx], p);
273           }
274         }
275       }
276       break;
277 
278     case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
279       if (len != 1)
280         return AVRC_STS_INTERNAL_ERR;
281       else {
282         p_result->inform_battery_status.battery_status = *p++;
283         if (!AVRC_IS_VALID_BATTERY_STATUS(
284                 p_result->inform_battery_status.battery_status))
285           status = AVRC_STS_BAD_PARAM;
286       }
287       break;
288 
289     case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
290       if (len < 9)                  /* UID/8 and num_attr/1 */
291         return AVRC_STS_INTERNAL_ERR;
292       else {
293         BE_STREAM_TO_UINT32(u32, p);
294         BE_STREAM_TO_UINT32(u32_2, p);
295         if (u32 == 0 && u32_2 == 0) {
296           BE_STREAM_TO_UINT8(p_result->get_elem_attrs.num_attr, p);
297           if ((len - 9 /* UID/8 and num_attr/1 */) !=
298               (p_result->get_elem_attrs.num_attr * 4))
299             status = AVRC_STS_INTERNAL_ERR;
300           else {
301             p_u32 = p_result->get_elem_attrs.attrs;
302             if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE)
303               p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
304             for (xx = 0; xx < p_result->get_elem_attrs.num_attr; xx++) {
305               BE_STREAM_TO_UINT32(p_u32[xx], p);
306             }
307           }
308         } else
309           status = AVRC_STS_NOT_FOUND;
310       }
311       break;
312 
313     case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
314       /* no additional parameters */
315       if (len != 0) return AVRC_STS_INTERNAL_ERR;
316       break;
317 
318     case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
319       if (len != 5)
320         return AVRC_STS_INTERNAL_ERR;
321       else {
322         BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
323         if (!AVRC_IS_VALID_EVENT_ID(p_result->reg_notif.event_id)) {
324           AVRC_TRACE_ERROR("%s: Invalid event id: %d", __func__,
325                            p_result->reg_notif.event_id);
326           return AVRC_STS_BAD_PARAM;
327         }
328 
329         BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
330       }
331       break;
332 
333     case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
334       if (len != 1)
335         return AVRC_STS_INTERNAL_ERR;
336       else
337         p_result->volume.volume = *p++;
338       break;
339 
340     case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
341       if (len != 1) {
342         return AVRC_STS_INTERNAL_ERR;
343       }
344       BE_STREAM_TO_UINT8(p_result->continu.target_pdu, p);
345       break;
346 
347     case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
348       if (len != 1) {
349         return AVRC_STS_INTERNAL_ERR;
350       }
351       BE_STREAM_TO_UINT8(p_result->abort.target_pdu, p);
352       break;
353 
354     case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
355       if (len != 2) {
356         AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d",
357                          len);
358         return AVRC_STS_INTERNAL_ERR;
359       }
360       BE_STREAM_TO_UINT16(p_result->addr_player.player_id, p);
361       break;
362 
363     case AVRC_PDU_PLAY_ITEM:          /* 0x74 */
364     case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
365       if (len != (AVRC_UID_SIZE + 3)) return AVRC_STS_INTERNAL_ERR;
366       BE_STREAM_TO_UINT8(p_result->play_item.scope, p);
367       if (p_result->play_item.scope > AVRC_SCOPE_NOW_PLAYING) {
368         status = AVRC_STS_BAD_SCOPE;
369       }
370       BE_STREAM_TO_ARRAY(p, p_result->play_item.uid, AVRC_UID_SIZE);
371       BE_STREAM_TO_UINT16(p_result->play_item.uid_counter, p);
372       break;
373 
374     default:
375       status = AVRC_STS_BAD_CMD;
376       break;
377   }
378 
379   return status;
380 }
381 
382 /*******************************************************************************
383  *
384  * Function         AVRC_Ctrl_ParsCommand
385  *
386  * Description      This function is used to parse cmds received for CTRL
387  *                  Currently it is for SetAbsVolume and Volume Change
388  *                  Notification.
389  *
390  * Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed
391  *                  successfully.
392  *                  Otherwise, the error code defined by AVRCP 1.4
393  *
394  ******************************************************************************/
AVRC_Ctrl_ParsCommand(tAVRC_MSG * p_msg,tAVRC_COMMAND * p_result)395 tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
396   tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
397 
398   if (p_msg && p_result) {
399     switch (p_msg->hdr.opcode) {
400       case AVRC_OP_VENDOR: /*  0x00    Vendor-dependent commands */
401         status = avrc_ctrl_pars_vendor_cmd(&p_msg->vendor, p_result);
402         break;
403 
404       default:
405         AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
406         break;
407     }
408     p_result->cmd.opcode = p_msg->hdr.opcode;
409     p_result->cmd.status = status;
410   }
411   AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
412   return status;
413 }
414 
415 #define RETURN_STATUS_IF_FALSE(_status_, _b_, _msg_, ...) \
416   if (!(_b_)) {                                           \
417     AVRC_TRACE_DEBUG(_msg_, ##__VA_ARGS__);               \
418     return _status_;                                      \
419   }
420 
421 /*******************************************************************************
422  *
423  * Function         avrc_pars_browsing_cmd
424  *
425  * Description      This function parses the commands that go through the
426  *                  browsing channel
427  *
428  * Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed
429  *                  successfully.
430  *                  Otherwise, the error code defined by AVRCP+1
431  *
432  ******************************************************************************/
avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)433 static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
434                                         tAVRC_COMMAND* p_result, uint8_t* p_buf,
435                                         uint16_t buf_len) {
436   tAVRC_STS status = AVRC_STS_NO_ERROR;
437   uint8_t* p = p_msg->p_browse_data;
438   int count;
439 
440   uint32_t min_len = 3;
441   RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
442                          "msg too short");
443 
444   p_result->pdu = *p++;
445   AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
446   /* skip over len */
447   p += 2;
448 
449   switch (p_result->pdu) {
450     case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
451       min_len += 2;
452       RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
453                              "msg too short");
454 
455       // For current implementation all players are browsable.
456       BE_STREAM_TO_UINT16(p_result->br_player.player_id, p);
457       break;
458 
459     case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
460 
461       min_len += 10;
462       RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
463                              "msg too short");
464 
465       STREAM_TO_UINT8(p_result->get_items.scope, p);
466       // To be modified later here (Scope) when all browsing commands are
467       // supported
468       if (p_result->get_items.scope > AVRC_SCOPE_NOW_PLAYING) {
469         status = AVRC_STS_BAD_SCOPE;
470       }
471       BE_STREAM_TO_UINT32(p_result->get_items.start_item, p);
472       BE_STREAM_TO_UINT32(p_result->get_items.end_item, p);
473       if (p_result->get_items.start_item > p_result->get_items.end_item) {
474         status = AVRC_STS_BAD_RANGE;
475       }
476       STREAM_TO_UINT8(p_result->get_items.attr_count, p);
477       p_result->get_items.p_attr_list = NULL;
478       if (p_result->get_items.attr_count && p_buf &&
479           (p_result->get_items.attr_count != AVRC_FOLDER_ITEM_COUNT_NONE)) {
480         p_result->get_items.p_attr_list = (uint32_t*)p_buf;
481         count = p_result->get_items.attr_count;
482         if (buf_len < (count << 2))
483           p_result->get_items.attr_count = count = (buf_len >> 2);
484         for (int idx = 0; idx < count; idx++) {
485           min_len += 4;
486           RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD,
487                                  (p_msg->browse_len >= min_len),
488                                  "msg too short");
489 
490           BE_STREAM_TO_UINT32(p_result->get_items.p_attr_list[idx], p);
491         }
492       }
493       break;
494 
495     case AVRC_PDU_CHANGE_PATH: /* 0x72 */
496       min_len += 11;
497       RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
498                              "msg too short");
499 
500       BE_STREAM_TO_UINT16(p_result->chg_path.uid_counter, p);
501       BE_STREAM_TO_UINT8(p_result->chg_path.direction, p);
502       if (p_result->chg_path.direction != AVRC_DIR_UP &&
503           p_result->chg_path.direction != AVRC_DIR_DOWN) {
504         status = AVRC_STS_BAD_DIR;
505       }
506       BE_STREAM_TO_ARRAY(p, p_result->chg_path.folder_uid, AVRC_UID_SIZE);
507       break;
508 
509     case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
510       min_len += 12;
511       RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
512                              "msg too short");
513 
514       BE_STREAM_TO_UINT8(p_result->get_attrs.scope, p);
515 
516       if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING) {
517         status = AVRC_STS_BAD_SCOPE;
518         break;
519       }
520       BE_STREAM_TO_ARRAY(p, p_result->get_attrs.uid, AVRC_UID_SIZE);
521       BE_STREAM_TO_UINT16(p_result->get_attrs.uid_counter, p);
522       BE_STREAM_TO_UINT8(p_result->get_attrs.attr_count, p);
523       p_result->get_attrs.p_attr_list = NULL;
524       if (p_result->get_attrs.attr_count && p_buf) {
525         p_result->get_attrs.p_attr_list = (uint32_t*)p_buf;
526         count = p_result->get_attrs.attr_count;
527         if (buf_len < (count << 2))
528           p_result->get_attrs.attr_count = count = (buf_len >> 2);
529         for (int idx = 0, count = 0; idx < p_result->get_attrs.attr_count;
530              idx++) {
531           min_len += 4;
532           RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD,
533                                  (p_msg->browse_len >= min_len),
534                                  "msg too short");
535 
536           BE_STREAM_TO_UINT32(p_result->get_attrs.p_attr_list[count], p);
537           if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(
538                   p_result->get_attrs.p_attr_list[count])) {
539             count++;
540           }
541         }
542 
543         if (p_result->get_attrs.attr_count != count && count == 0)
544           status = AVRC_STS_BAD_PARAM;
545         else
546           p_result->get_attrs.attr_count = count;
547       }
548       break;
549 
550     case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: /* 0x75 */
551       ++min_len;
552       RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
553                              "msg too short");
554 
555       BE_STREAM_TO_UINT8(p_result->get_num_of_items.scope, p);
556       if (p_result->get_num_of_items.scope > AVRC_SCOPE_NOW_PLAYING) {
557         status = AVRC_STS_BAD_SCOPE;
558       }
559       break;
560 
561     case AVRC_PDU_SEARCH: /* 0x80 */
562       min_len += 4;
563       RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
564                              "msg too short");
565 
566       BE_STREAM_TO_UINT16(p_result->search.string.charset_id, p);
567       BE_STREAM_TO_UINT16(p_result->search.string.str_len, p);
568       p_result->search.string.p_str = p_buf;
569       if (p_buf) {
570         if (p_result->search.string.str_len > buf_len) {
571           p_result->search.string.str_len = buf_len;
572         }
573         min_len += p_result->search.string.str_len;
574         RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
575                                "msg too short");
576 
577         BE_STREAM_TO_ARRAY(p, p_buf, p_result->search.string.str_len);
578       } else {
579         status = AVRC_STS_INTERNAL_ERR;
580       }
581       break;
582 
583     default:
584       status = AVRC_STS_BAD_CMD;
585       break;
586   }
587   return status;
588 }
589 
590 /*******************************************************************************
591  *
592  * Function         AVRC_ParsCommand
593  *
594  * Description      This function is a superset of AVRC_ParsMetadata to parse
595  *                  the command.
596  *
597  * Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed
598  *                  successfully.
599  *                  Otherwise, the error code defined by AVRCP 1.4
600  *
601  ******************************************************************************/
AVRC_ParsCommand(tAVRC_MSG * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)602 tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result,
603                            uint8_t* p_buf, uint16_t buf_len) {
604   tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
605   uint16_t id;
606 
607   if (p_msg && p_result) {
608     switch (p_msg->hdr.opcode) {
609       case AVRC_OP_VENDOR: /*  0x00    Vendor-dependent commands */
610         status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
611         break;
612 
613       case AVRC_OP_PASS_THRU: /*  0x7C    panel subunit opcode */
614         status = avrc_pars_pass_thru(&p_msg->pass, &id);
615         if (status == AVRC_STS_NO_ERROR) {
616           p_result->pdu = (uint8_t)id;
617         }
618         break;
619 
620       case AVRC_OP_BROWSE:
621         status =
622             avrc_pars_browsing_cmd(&p_msg->browse, p_result, p_buf, buf_len);
623         break;
624 
625       default:
626         AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
627         break;
628     }
629     p_result->cmd.opcode = p_msg->hdr.opcode;
630     p_result->cmd.status = status;
631   }
632   AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
633   return status;
634 }
635