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