1/******************************************************************************
2 *
3 *  Copyright (C) 2003-2012 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
19/******************************************************************************
20 *
21 *  Interface to AVRCP mandatory commands
22 *
23 ******************************************************************************/
24#include <assert.h>
25#include <string.h>
26
27#include "bt_common.h"
28#include "avrc_api.h"
29#include "avrc_int.h"
30
31/*****************************************************************************
32**  Global data
33*****************************************************************************/
34
35
36#define AVRC_MAX_RCV_CTRL_EVT   AVCT_BROWSE_UNCONG_IND_EVT
37
38#ifndef MAX
39#define MAX(a, b) ((a) > (b) ? (a) : (b))
40#endif
41
42static const UINT8 avrc_ctrl_event_map[] =
43{
44    AVRC_OPEN_IND_EVT,  /* AVCT_CONNECT_CFM_EVT */
45    AVRC_OPEN_IND_EVT,  /* AVCT_CONNECT_IND_EVT */
46    AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_CFM_EVT */
47    AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_IND_EVT */
48    AVRC_CONG_IND_EVT,  /* AVCT_CONG_IND_EVT */
49    AVRC_UNCONG_IND_EVT,/* AVCT_UNCONG_IND_EVT */
50    AVRC_BROWSE_OPEN_IND_EVT,  /* AVCT_BROWSE_CONN_CFM_EVT   */
51    AVRC_BROWSE_OPEN_IND_EVT,  /* AVCT_BROWSE_CONN_IND_EVT   */
52    AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_CFM_EVT */
53    AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_IND_EVT */
54    AVRC_BROWSE_CONG_IND_EVT,  /* AVCT_BROWSE_CONG_IND_EVT    */
55    AVRC_BROWSE_UNCONG_IND_EVT /* AVCT_BROWSE_UNCONG_IND_EVT  */
56};
57
58#define AVRC_OP_DROP        0xFE    /* use this unused opcode to indication no need to call the callback function */
59#define AVRC_OP_DROP_N_FREE 0xFD    /* use this unused opcode to indication no need to call the callback function & free buffer */
60
61#define AVRC_OP_UNIT_INFO_RSP_LEN       8
62#define AVRC_OP_SUB_UNIT_INFO_RSP_LEN   8
63#define AVRC_OP_REJ_MSG_LEN            11
64
65/******************************************************************************
66**
67** Function         avrc_ctrl_cback
68**
69** Description      This is the callback function used by AVCTP to report
70**                  received link events.
71**
72** Returns          Nothing.
73**
74******************************************************************************/
75static void avrc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result,
76                                BD_ADDR peer_addr)
77{
78    UINT8   avrc_event;
79
80    if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback)
81    {
82        avrc_event = avrc_ctrl_event_map[event];
83        if (event == AVCT_CONNECT_CFM_EVT)
84        {
85            if (result != 0) /* failed */
86                avrc_event = AVRC_CLOSE_IND_EVT;
87        }
88        (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr);
89    }
90    /* else drop the unknown event*/
91}
92
93/******************************************************************************
94**
95** Function         avrc_get_data_ptr
96**
97** Description      Gets a pointer to the data payload in the packet.
98**
99** Returns          A pointer to the data payload.
100**
101******************************************************************************/
102static UINT8 * avrc_get_data_ptr(BT_HDR *p_pkt)
103{
104    return (UINT8 *)(p_pkt + 1) + p_pkt->offset;
105}
106
107/******************************************************************************
108**
109** Function         avrc_copy_packet
110**
111** Description      Copies an AVRC packet to a new buffer. In the new buffer,
112**                  the payload offset is at least AVCT_MSG_OFFSET octets.
113**
114** Returns          The buffer with the copied data.
115**
116******************************************************************************/
117static BT_HDR * avrc_copy_packet(BT_HDR *p_pkt, int rsp_pkt_len)
118{
119    const int offset = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
120    const int pkt_len = MAX(rsp_pkt_len, p_pkt->len);
121    BT_HDR *p_pkt_copy = (BT_HDR *)osi_malloc(BT_HDR_SIZE + offset + pkt_len);
122
123    /* Copy the packet header, set the new offset, and copy the payload */
124    memcpy(p_pkt_copy, p_pkt, BT_HDR_SIZE);
125    p_pkt_copy->offset = offset;
126    UINT8 *p_data = avrc_get_data_ptr(p_pkt);
127    UINT8 *p_data_copy = avrc_get_data_ptr(p_pkt_copy);
128    memcpy(p_data_copy, p_data, p_pkt->len);
129
130    return p_pkt_copy;
131}
132
133#if (AVRC_METADATA_INCLUDED == TRUE)
134/******************************************************************************
135**
136** Function         avrc_prep_end_frag
137**
138** Description      This function prepares an end response fragment
139**
140** Returns          Nothing.
141**
142******************************************************************************/
143static void avrc_prep_end_frag(UINT8 handle)
144{
145    tAVRC_FRAG_CB   *p_fcb;
146    BT_HDR  *p_pkt_new;
147    UINT8   *p_data, *p_orig_data;
148    UINT8   rsp_type;
149
150    AVRC_TRACE_DEBUG ("avrc_prep_end_frag" );
151    p_fcb = &avrc_cb.fcb[handle];
152
153    /* The response type of the end fragment should be the same as the the PDU of "End Fragment
154    ** Response" Errata: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383
155    */
156    p_orig_data = ((UINT8 *)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset);
157    rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK);
158
159    p_pkt_new           = p_fcb->p_fmsg;
160    p_pkt_new->len      -= (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
161    p_pkt_new->offset   += (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
162    p_data = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset;
163    *p_data++       = rsp_type;
164    *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
165    *p_data++       = AVRC_OP_VENDOR;
166    AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
167    *p_data++       = p_fcb->frag_pdu;
168    *p_data++       = AVRC_PKT_END;
169
170    /* 4=pdu, pkt_type & len */
171    UINT16_TO_BE_STREAM(p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE));
172}
173
174/******************************************************************************
175**
176** Function         avrc_send_continue_frag
177**
178** Description      This function sends a continue response fragment
179**
180** Returns          Nothing.
181**
182******************************************************************************/
183static void avrc_send_continue_frag(UINT8 handle, UINT8 label)
184{
185    tAVRC_FRAG_CB   *p_fcb;
186    BT_HDR  *p_pkt_old, *p_pkt;
187    UINT8   *p_old, *p_data;
188    UINT8   cr = AVCT_RSP;
189
190    p_fcb = &avrc_cb.fcb[handle];
191    p_pkt = p_fcb->p_fmsg;
192
193    AVRC_TRACE_DEBUG("%s handle = %u label = %u len = %d",
194                     __func__, handle, label, p_pkt->len);
195    if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) {
196        int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
197        p_pkt_old = p_fcb->p_fmsg;
198        p_pkt = (BT_HDR *)osi_malloc(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE);
199        p_pkt->len = AVRC_MAX_CTRL_DATA_LEN;
200        p_pkt->offset = AVCT_MSG_OFFSET;
201        p_pkt->layer_specific = p_pkt_old->layer_specific;
202        p_pkt->event = p_pkt_old->event;
203        p_old = (UINT8 *)(p_pkt_old + 1) + p_pkt_old->offset;
204        p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
205        memcpy (p_data, p_old, AVRC_MAX_CTRL_DATA_LEN);
206        /* use AVRC continue packet type */
207        p_data += AVRC_VENDOR_HDR_SIZE;
208        p_data++; /* pdu */
209        *p_data++ = AVRC_PKT_CONTINUE;
210        /* 4=pdu, pkt_type & len */
211        UINT16_TO_BE_STREAM(p_data, (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - 4));
212
213        /* prepare the left over for as an end fragment */
214        avrc_prep_end_frag (handle);
215    } else {
216        /* end fragment. clean the control block */
217        p_fcb->frag_enabled = FALSE;
218        p_fcb->p_fmsg       = NULL;
219    }
220    AVCT_MsgReq( handle, label, cr, p_pkt);
221}
222
223/******************************************************************************
224**
225** Function         avrc_proc_vendor_command
226**
227** Description      This function processes received vendor command.
228**
229** Returns          if not NULL, the response to send right away.
230**
231******************************************************************************/
232static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label,
233                               BT_HDR *p_pkt, tAVRC_MSG_VENDOR *p_msg)
234{
235    BT_HDR      *p_rsp = NULL;
236    UINT8       *p_data;
237    UINT8       *p_begin;
238    UINT8       pkt_type;
239    BOOLEAN     abort_frag = FALSE;
240    tAVRC_STS   status = AVRC_STS_NO_ERROR;
241    tAVRC_FRAG_CB   *p_fcb;
242
243    p_begin  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
244    p_data   = p_begin + AVRC_VENDOR_HDR_SIZE;
245    pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
246
247    if (pkt_type != AVRC_PKT_SINGLE)
248    {
249        /* reject - commands can only be in single packets at AVRCP level */
250        AVRC_TRACE_ERROR ("commands must be in single packet pdu:0x%x", *p_data );
251        /* use the current GKI buffer to send the reject */
252        status = AVRC_STS_BAD_CMD;
253    }
254    /* check if there are fragments waiting to be sent */
255    else if (avrc_cb.fcb[handle].frag_enabled)
256    {
257        p_fcb = &avrc_cb.fcb[handle];
258        if (p_msg->company_id == AVRC_CO_METADATA)
259        {
260            switch (*p_data)
261            {
262            case AVRC_PDU_ABORT_CONTINUATION_RSP:
263                /* aborted by CT - send accept response */
264                abort_frag = TRUE;
265                p_begin = (UINT8 *)(p_pkt+1) + p_pkt->offset;
266                *p_begin = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK);
267                if (*(p_data + 4) != p_fcb->frag_pdu)
268                {
269                    *p_begin = (AVRC_RSP_REJ & AVRC_CTYPE_MASK);
270                    *(p_data + 4) = AVRC_STS_BAD_PARAM;
271                }
272                else
273                {
274                    p_data = (p_begin + AVRC_VENDOR_HDR_SIZE + 2);
275                    UINT16_TO_BE_STREAM(p_data, 0);
276                    p_pkt->len = (p_data - p_begin);
277                }
278                AVCT_MsgReq( handle, label, AVCT_RSP, p_pkt);
279                p_msg->hdr.opcode = AVRC_OP_DROP; /* used the p_pkt to send response */
280                break;
281
282            case AVRC_PDU_REQUEST_CONTINUATION_RSP:
283                if (*(p_data + 4) == p_fcb->frag_pdu)
284                {
285                    avrc_send_continue_frag(handle, label);
286                    p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
287                }
288                else
289                {
290                    /* the pdu id does not match - reject the command using the current GKI buffer */
291                    AVRC_TRACE_ERROR("avrc_proc_vendor_command continue pdu: 0x%x does not match \
292                    current re-assembly pdu: 0x%x",
293                        *(p_data + 4), p_fcb->frag_pdu);
294                    status = AVRC_STS_BAD_PARAM;
295                    abort_frag = TRUE;
296                }
297                break;
298
299            default:
300                /* implicit abort */
301                abort_frag = TRUE;
302            }
303        }
304        else
305        {
306            abort_frag = TRUE;
307            /* implicit abort */
308        }
309
310        if (abort_frag)
311        {
312            osi_free_and_reset((void **)&p_fcb->p_fmsg);
313            p_fcb->frag_enabled = FALSE;
314        }
315    }
316
317    if (status != AVRC_STS_NO_ERROR)
318    {
319        /* use the current GKI buffer to build/send the reject message */
320        p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
321        *p_data++ = AVRC_RSP_REJ;
322        p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */
323        *p_data++ = 0;                  /* pkt_type */
324        UINT16_TO_BE_STREAM(p_data, 1); /* len */
325        *p_data++ = status;             /* error code */
326        p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
327        p_rsp = p_pkt;
328    }
329
330    return p_rsp;
331}
332
333/******************************************************************************
334**
335** Function         avrc_proc_far_msg
336**
337** Description      This function processes metadata fragmenation
338**                  and reassembly
339**
340** Returns          0, to report the message with msg_cback .
341**
342******************************************************************************/
343static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_pkt,
344    tAVRC_MSG_VENDOR *p_msg)
345{
346    BT_HDR      *p_pkt = *pp_pkt;
347    UINT8       *p_data;
348    UINT8       drop_code = 0;
349    BOOLEAN     buf_overflow = FALSE;
350    BT_HDR      *p_rsp = NULL;
351    BT_HDR      *p_cmd = NULL;
352    BOOLEAN     req_continue = FALSE;
353    BT_HDR      *p_pkt_new = NULL;
354    UINT8       pkt_type;
355    tAVRC_RASM_CB   *p_rcb;
356    tAVRC_NEXT_CMD   avrc_cmd;
357
358    p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
359
360    /* Skip over vendor header (ctype, subunit*, opcode, CO_ID) */
361    p_data += AVRC_VENDOR_HDR_SIZE;
362
363    pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
364    AVRC_TRACE_DEBUG ("pkt_type %d", pkt_type );
365    p_rcb = &avrc_cb.rcb[handle];
366    if (p_msg->company_id == AVRC_CO_METADATA)
367    {
368        /* check if the message needs to be re-assembled */
369        if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START)
370        {
371            /* previous fragments need to be dropped, when received another new message */
372            p_rcb->rasm_offset = 0;
373            osi_free_and_reset((void **)&p_rcb->p_rmsg);
374        }
375
376        if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP)
377        {
378            /* not a single response packet - need to re-assemble metadata messages */
379            if (pkt_type == AVRC_PKT_START) {
380                /* Allocate buffer for re-assembly */
381                p_rcb->rasm_pdu = *p_data;
382                p_rcb->p_rmsg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
383                /* Copy START packet to buffer for re-assembling fragments */
384                memcpy(p_rcb->p_rmsg, p_pkt, sizeof(BT_HDR)); /* Copy bt hdr */
385
386                /* Copy metadata message */
387                memcpy((UINT8 *)(p_rcb->p_rmsg + 1),
388                       (UINT8 *)(p_pkt+1) + p_pkt->offset, p_pkt->len);
389
390                /* offset of start of metadata response in reassembly buffer */
391                p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0;
392
393                /*
394                 * Free original START packet, replace with pointer to
395                 * reassembly buffer.
396                 */
397                osi_free(p_pkt);
398                *pp_pkt = p_rcb->p_rmsg;
399
400                /*
401                 * Set offset to point to where to copy next - use the same
402                 * reassembly logic as AVCT.
403                 */
404                p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
405                req_continue = TRUE;
406            } else if (p_rcb->p_rmsg == NULL) {
407                /* Received a CONTINUE/END, but no corresponding START
408                              (or previous fragmented response was dropped) */
409                AVRC_TRACE_DEBUG ("Received a CONTINUE/END without no corresponding START \
410                                   (or previous fragmented response was dropped)");
411                drop_code = 5;
412                osi_free(p_pkt);
413                *pp_pkt = NULL;
414            }
415            else
416            {
417                /* get size of buffer holding assembled message */
418                /*
419                 * NOTE: The buffer is allocated above at the beginning of the
420                 * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
421                 */
422                UINT16 buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
423                /* adjust offset and len of fragment for header byte */
424                p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
425                p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
426                /* verify length */
427                if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len)
428                {
429                    AVRC_TRACE_WARNING("Fragmented message too big! - report the partial message");
430                    p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
431                    pkt_type = AVRC_PKT_END;
432                    buf_overflow = true;
433                }
434
435                /* copy contents of p_pkt to p_rx_msg */
436                memcpy((UINT8 *)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset,
437                       (UINT8 *)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
438
439                if (pkt_type == AVRC_PKT_END)
440                {
441                    p_rcb->p_rmsg->offset = p_rcb->rasm_offset;
442                    p_rcb->p_rmsg->len += p_pkt->len;
443                    p_pkt_new = p_rcb->p_rmsg;
444                    p_rcb->rasm_offset = 0;
445                    p_rcb->p_rmsg = NULL;
446                    p_msg->p_vendor_data   = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset;
447                    p_msg->hdr.ctype       = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK;
448                    /* 6 = ctype, subunit*, opcode & CO_ID */
449                    p_msg->p_vendor_data  += AVRC_VENDOR_HDR_SIZE;
450                    p_msg->vendor_len      = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE;
451                    p_data = p_msg->p_vendor_data + 1; /* skip pdu */
452                    *p_data++ = AVRC_PKT_SINGLE;
453                    UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE));
454                    AVRC_TRACE_DEBUG("end frag:%d, total len:%d, offset:%d", p_pkt->len,
455                        p_pkt_new->len, p_pkt_new->offset);
456                }
457                else
458                {
459                    p_rcb->p_rmsg->offset += p_pkt->len;
460                    p_rcb->p_rmsg->len += p_pkt->len;
461                    p_pkt_new = NULL;
462                    req_continue = TRUE;
463                }
464                osi_free(p_pkt);
465                *pp_pkt = p_pkt_new;
466            }
467        }
468
469        if (cr == AVCT_CMD)
470        {
471            p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg);
472            if (p_rsp)
473            {
474                AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
475                drop_code = 3;
476            }
477            else if (p_msg->hdr.opcode == AVRC_OP_DROP)
478            {
479                drop_code = 1;
480            }
481            else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE)
482                drop_code = 4;
483
484        }
485        else if (cr == AVCT_RSP && req_continue == TRUE)
486        {
487            avrc_cmd.pdu    = AVRC_PDU_REQUEST_CONTINUATION_RSP;
488            avrc_cmd.status = AVRC_STS_NO_ERROR;
489            avrc_cmd.target_pdu = p_rcb->rasm_pdu;
490            if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR)
491            {
492                drop_code = 2;
493                AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd);
494            }
495        }
496        /*
497         * Drop it if we are out of buffer
498         */
499        else if (cr == AVCT_RSP && req_continue == FALSE  && buf_overflow == TRUE)
500        {
501            avrc_cmd.pdu    = AVRC_PDU_ABORT_CONTINUATION_RSP;
502            avrc_cmd.status = AVRC_STS_NO_ERROR;
503            avrc_cmd.target_pdu = p_rcb->rasm_pdu;
504            if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR)
505            {
506                drop_code = 4;
507                AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd);
508            }
509        }
510    }
511
512    return drop_code;
513}
514#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
515
516/******************************************************************************
517**
518** Function         avrc_msg_cback
519**
520** Description      This is the callback function used by AVCTP to report
521**                  received AV control messages.
522**
523** Returns          Nothing.
524**
525******************************************************************************/
526static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
527                               BT_HDR *p_pkt)
528{
529    UINT8       opcode;
530    tAVRC_MSG   msg;
531    UINT8       *p_data;
532    UINT8       *p_begin;
533    BOOLEAN     drop = FALSE;
534    BOOLEAN     do_free = TRUE;
535    BT_HDR      *p_rsp = NULL;
536    UINT8       *p_rsp_data;
537    int         xx;
538    BOOLEAN     reject = FALSE;
539#if (BT_USE_TRACES == TRUE)
540    char        *p_drop_msg = "dropped";
541#endif
542    tAVRC_MSG_VENDOR *p_msg = &msg.vendor;
543
544    if (cr == AVCT_CMD &&
545        (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len)))
546    {
547        /* Ignore the invalid AV/C command frame */
548#if (BT_USE_TRACES == TRUE)
549        p_drop_msg = "dropped - too long AV/C cmd frame size";
550#endif
551        osi_free(p_pkt);
552        return;
553    }
554
555    if (cr == AVCT_REJ)
556    {
557        /* The peer thinks that this PID is no longer open - remove this handle */
558        /*  */
559        osi_free(p_pkt);
560        AVCT_RemoveConn(handle);
561        return;
562    }
563
564    p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
565    memset(&msg, 0, sizeof(tAVRC_MSG) );
566    {
567        msg.hdr.ctype           = p_data[0] & AVRC_CTYPE_MASK;
568        AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
569                handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
570        msg.hdr.subunit_type    = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
571        msg.hdr.subunit_id      = p_data[1] & AVRC_SUBID_MASK;
572        opcode                  = p_data[2];
573    }
574
575    if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
576        ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
577    {
578
579        switch(opcode)
580        {
581        case AVRC_OP_UNIT_INFO:
582            if (cr == AVCT_CMD)
583            {
584                /* send the response to the peer */
585                p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
586                p_rsp_data = avrc_get_data_ptr(p_rsp);
587                *p_rsp_data = AVRC_RSP_IMPL_STBL;
588                /* check & set the offset. set response code, set subunit_type & subunit_id,
589                   set AVRC_OP_UNIT_INFO */
590                /* 3 bytes: ctype, subunit*, opcode */
591                p_rsp_data      += AVRC_AVC_HDR_SIZE;
592                *p_rsp_data++   = 7;
593                /* Panel subunit & id=0 */
594                *p_rsp_data++   = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
595                AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
596                p_rsp->len      = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
597                cr = AVCT_RSP;
598#if (BT_USE_TRACES == TRUE)
599                p_drop_msg = "auto respond";
600#endif
601            }
602            else
603            {
604                /* parse response */
605                p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
606                msg.unit.unit_type  = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
607                msg.unit.unit       = *p_data & AVRC_SUBID_MASK;
608                p_data++;
609                AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
610            }
611            break;
612
613        case AVRC_OP_SUB_INFO:
614            if (cr == AVCT_CMD)
615            {
616                /* send the response to the peer */
617                p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
618                p_rsp_data = avrc_get_data_ptr(p_rsp);
619                *p_rsp_data = AVRC_RSP_IMPL_STBL;
620                /* check & set the offset. set response code, set (subunit_type & subunit_id),
621                   set AVRC_OP_SUB_INFO, set (page & extention code) */
622                p_rsp_data      += 4;
623                /* Panel subunit & id=0 */
624                *p_rsp_data++   = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
625                memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
626                p_rsp_data      += AVRC_SUBRSP_OPRND_BYTES;
627                p_rsp->len      = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
628                cr = AVCT_RSP;
629#if (BT_USE_TRACES == TRUE)
630                p_drop_msg = "auto responded";
631#endif
632            }
633            else
634            {
635                /* parse response */
636                p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
637                msg.sub.page    = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
638                xx      = 0;
639                while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
640                {
641                    msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
642                    if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
643                        msg.sub.panel   = TRUE;
644                    xx++;
645                }
646            }
647            break;
648
649        case AVRC_OP_VENDOR:
650            p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
651            p_begin = p_data;
652            if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
653            {
654                if (cr == AVCT_CMD)
655                    reject = TRUE;
656                else
657                    drop = TRUE;
658                break;
659            }
660            p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
661            AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
662            p_msg->p_vendor_data   = p_data;
663            p_msg->vendor_len      = p_pkt->len - (p_data - p_begin);
664
665#if (AVRC_METADATA_INCLUDED == TRUE)
666            UINT8 drop_code = 0;
667            if (p_msg->company_id == AVRC_CO_METADATA)
668            {
669                /* Validate length for metadata message */
670                if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE))
671                {
672                    if (cr == AVCT_CMD)
673                        reject = TRUE;
674                    else
675                        drop = TRUE;
676                    break;
677                }
678
679                /* Check+handle fragmented messages */
680                drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
681                if (drop_code > 0)
682                    drop = TRUE;
683            }
684            if (drop_code > 0)
685            {
686                if (drop_code != 4)
687                    do_free = FALSE;
688#if (BT_USE_TRACES == TRUE)
689                switch (drop_code)
690                {
691                case 1:
692                    p_drop_msg = "sent_frag";
693                    break;
694                case 2:
695                    p_drop_msg = "req_cont";
696                    break;
697                case 3:
698                    p_drop_msg = "sent_frag3";
699                    break;
700                case 4:
701                    p_drop_msg = "sent_frag_free";
702                    break;
703                default:
704                    p_drop_msg = "sent_fragd";
705                }
706#endif
707            }
708#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
709            break;
710
711        case AVRC_OP_PASS_THRU:
712            if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
713            {
714                if (cr == AVCT_CMD)
715                    reject = TRUE;
716                else
717                    drop = TRUE;
718                break;
719            }
720            p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
721            msg.pass.op_id  = (AVRC_PASS_OP_ID_MASK & *p_data);
722            if (AVRC_PASS_STATE_MASK & *p_data)
723                msg.pass.state  = TRUE;
724            else
725                msg.pass.state  = FALSE;
726            p_data++;
727            msg.pass.pass_len    = *p_data++;
728            if (msg.pass.pass_len != p_pkt->len - 5)
729                msg.pass.pass_len = p_pkt->len - 5;
730            if (msg.pass.pass_len)
731                msg.pass.p_pass_data = p_data;
732            else
733                msg.pass.p_pass_data = NULL;
734            break;
735
736
737        default:
738            if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
739            {
740                /* reject unsupported opcode */
741                reject = TRUE;
742            }
743            drop    = TRUE;
744            break;
745        }
746    }
747    else /* drop the event */
748    {
749            drop    = TRUE;
750    }
751
752    if (reject)
753    {
754        /* reject unsupported opcode */
755        p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
756        p_rsp_data = avrc_get_data_ptr(p_rsp);
757        *p_rsp_data = AVRC_RSP_REJ;
758#if (BT_USE_TRACES == TRUE)
759        p_drop_msg = "rejected";
760#endif
761        cr      = AVCT_RSP;
762        drop    = TRUE;
763    }
764
765    if (p_rsp)
766    {
767        /* set to send response right away */
768        AVCT_MsgReq( handle, label, cr, p_rsp);
769        drop = TRUE;
770    }
771
772    if (drop == FALSE)
773    {
774        msg.hdr.opcode = opcode;
775        (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
776    }
777#if (BT_USE_TRACES == TRUE)
778    else
779    {
780        AVRC_TRACE_WARNING("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
781                p_drop_msg,
782                handle, avrc_cb.ccb[handle].control, cr, opcode);
783    }
784#endif
785
786
787    if (do_free)
788        osi_free(p_pkt);
789}
790
791
792
793
794/******************************************************************************
795**
796** Function         avrc_pass_msg
797**
798** Description      Compose a PASS THROUGH command according to p_msg
799**
800**                  Input Parameters:
801**                      p_msg: Pointer to PASS THROUGH message structure.
802**
803**                  Output Parameters:
804**                      None.
805**
806** Returns          pointer to a valid GKI buffer if successful.
807**                  NULL if p_msg is NULL.
808**
809******************************************************************************/
810static BT_HDR  * avrc_pass_msg(tAVRC_MSG_PASS *p_msg)
811{
812    assert(p_msg != NULL);
813    assert(AVRC_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len));
814
815    BT_HDR  *p_cmd = (BT_HDR *)osi_malloc(AVRC_CMD_BUF_SIZE);
816    p_cmd->offset = AVCT_MSG_OFFSET;
817    p_cmd->layer_specific = AVCT_DATA_CTRL;
818
819    UINT8 *p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
820    *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
821    *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */
822    *p_data++ = AVRC_OP_PASS_THRU;
823    *p_data = (AVRC_PASS_OP_ID_MASK&p_msg->op_id);
824    if (p_msg->state)
825        *p_data     |= AVRC_PASS_STATE_MASK;
826    p_data++;
827
828    if (p_msg->op_id == AVRC_ID_VENDOR) {
829        *p_data++ = p_msg->pass_len;
830        if (p_msg->pass_len && p_msg->p_pass_data) {
831            memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
832            p_data += p_msg->pass_len;
833        }
834    } else {
835        /* set msg len to 0 for other op_id */
836        *p_data++       = 0;
837    }
838    p_cmd->len = (UINT16) (p_data - (UINT8 *)(p_cmd + 1) - p_cmd->offset);
839
840    return p_cmd;
841}
842
843/******************************************************************************
844**
845** Function         AVRC_Open
846**
847** Description      This function is called to open a connection to AVCTP.
848**                  The connection can be either an initiator or acceptor, as
849**                  determined by the p_ccb->stream parameter.
850**                  The connection can be a target, a controller or for both role,
851**                  as determined by the p_ccb->control parameter.
852**                  By definition, a target connection is an acceptor connection
853**                  that waits for an incoming AVCTP connection from the peer.
854**                  The connection remains available to the application until
855**                  the application closes it by calling AVRC_Close().  The
856**                  application does not need to reopen the connection after an
857**                  AVRC_CLOSE_IND_EVT is received.
858**
859**                  Input Parameters:
860**                      p_ccb->company_id: Company Identifier.
861**
862**                      p_ccb->p_ctrl_cback:  Pointer to control callback function.
863**
864**                      p_ccb->p_msg_cback:  Pointer to message callback function.
865**
866**                      p_ccb->conn: AVCTP connection role.  This is set to
867**                      AVCTP_INT for initiator connections and AVCTP_ACP
868**                      for acceptor connections.
869**
870**                      p_ccb->control: Control role.  This is set to
871**                      AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
872**                      for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL)
873**                      for connections that support both roles.
874**
875**                      peer_addr: BD address of peer device.  This value is
876**                      only used for initiator connections; for acceptor
877**                      connections it can be set to NULL.
878**
879**                  Output Parameters:
880**                      p_handle: Pointer to handle.  This parameter is only
881**                                valid if AVRC_SUCCESS is returned.
882**
883** Returns          AVRC_SUCCESS if successful.
884**                  AVRC_NO_RESOURCES if there are not enough resources to open
885**                  the connection.
886**
887******************************************************************************/
888UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
889{
890    UINT16      status;
891    tAVCT_CC    cc;
892
893    cc.p_ctrl_cback = avrc_ctrl_cback;      /* Control callback */
894    cc.p_msg_cback  = avrc_msg_cback;       /* Message callback */
895    cc.pid          = UUID_SERVCLASS_AV_REMOTE_CONTROL;  /* Profile ID */
896    cc.role         = p_ccb->conn;          /* Initiator/acceptor role */
897    cc.control      = p_ccb->control;       /* Control role (Control/Target) */
898
899    status = AVCT_CreateConn(p_handle, &cc, peer_addr);
900    if (status == AVCT_SUCCESS)
901    {
902        memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
903#if (AVRC_METADATA_INCLUDED == TRUE)
904        memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
905        memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
906#endif
907    }
908    AVRC_TRACE_DEBUG("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control,
909        status, *p_handle);
910
911    return status;
912}
913
914/******************************************************************************
915**
916** Function         AVRC_Close
917**
918** Description      Close a connection opened with AVRC_Open().
919**                  This function is called when the
920**                  application is no longer using a connection.
921**
922**                  Input Parameters:
923**                      handle: Handle of this connection.
924**
925**                  Output Parameters:
926**                      None.
927**
928** Returns          AVRC_SUCCESS if successful.
929**                  AVRC_BAD_HANDLE if handle is invalid.
930**
931******************************************************************************/
932UINT16 AVRC_Close(UINT8 handle)
933{
934    AVRC_TRACE_DEBUG("AVRC_Close handle:%d", handle);
935    return AVCT_RemoveConn(handle);
936}
937
938
939/******************************************************************************
940**
941** Function         AVRC_MsgReq
942**
943** Description      This function is used to send the AVRCP byte stream in p_pkt
944**                  down to AVCTP.
945**
946**                  It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET
947**                  p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
948**                  p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
949**                  The above BT_HDR settings are set by the AVRC_Bld* functions.
950**
951** Returns          AVRC_SUCCESS if successful.
952**                  AVRC_BAD_HANDLE if handle is invalid.
953**
954******************************************************************************/
955UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
956{
957#if (AVRC_METADATA_INCLUDED == TRUE)
958    UINT8   *p_data;
959    UINT8   cr = AVCT_CMD;
960    BOOLEAN chk_frag = TRUE;
961    UINT8   *p_start = NULL;
962    tAVRC_FRAG_CB   *p_fcb;
963    UINT16  len;
964
965    if (!p_pkt)
966        return AVRC_BAD_PARAM;
967
968    AVRC_TRACE_DEBUG("%s handle = %u label = %u ctype = %u len = %d",
969                     __func__, handle, label, ctype, p_pkt->len);
970
971    if (ctype >= AVRC_RSP_NOT_IMPL)
972        cr = AVCT_RSP;
973
974    if (p_pkt->event == AVRC_OP_VENDOR)
975    {
976        /* add AVRCP Vendor Dependent headers */
977        p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset);
978        p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
979        p_pkt->len += AVRC_VENDOR_HDR_SIZE;
980        p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
981        *p_data++       = (ctype & AVRC_CTYPE_MASK);
982        *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
983        *p_data++       = AVRC_OP_VENDOR;
984        AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
985    }
986    else if (p_pkt->event == AVRC_OP_PASS_THRU)
987    {
988        /* add AVRCP Pass Through headers */
989        p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset);
990        p_pkt->offset -= AVRC_PASS_THRU_SIZE;
991        p_pkt->len += AVRC_PASS_THRU_SIZE;
992        p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
993        *p_data++       = (ctype & AVRC_CTYPE_MASK);
994        *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
995        *p_data++       = AVRC_OP_PASS_THRU;/* opcode */
996        *p_data++       = AVRC_ID_VENDOR;   /* operation id */
997        *p_data++       = 5;                /* operation data len */
998        AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
999    }
1000
1001    /* abandon previous fragments */
1002    p_fcb = &avrc_cb.fcb[handle];
1003    if (p_fcb->frag_enabled)
1004        p_fcb->frag_enabled = FALSE;
1005
1006    osi_free_and_reset((void **)&p_fcb->p_fmsg);
1007
1008    /* AVRCP spec has not defined any control channel commands that needs fragmentation at this level
1009     * check for fragmentation only on the response */
1010    if ((cr == AVCT_RSP) && (chk_frag == TRUE))
1011    {
1012        if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN)
1013        {
1014            int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
1015            BT_HDR *p_pkt_new =
1016                (BT_HDR *)osi_malloc(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE);
1017            if (p_start != NULL) {
1018                p_fcb->frag_enabled = TRUE;
1019                p_fcb->p_fmsg       = p_pkt;
1020                p_fcb->frag_pdu     = *p_start;
1021                p_pkt               = p_pkt_new;
1022                p_pkt_new           = p_fcb->p_fmsg;
1023                p_pkt->len          = AVRC_MAX_CTRL_DATA_LEN;
1024                p_pkt->offset       = p_pkt_new->offset;
1025                p_pkt->layer_specific = p_pkt_new->layer_specific;
1026                p_pkt->event = p_pkt_new->event;
1027                p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
1028                p_start -= AVRC_VENDOR_HDR_SIZE;
1029                memcpy (p_data, p_start, AVRC_MAX_CTRL_DATA_LEN);
1030                /* use AVRC start packet type */
1031                p_data += AVRC_VENDOR_HDR_SIZE;
1032                p_data++; /* pdu */
1033                *p_data++ = AVRC_PKT_START;
1034                /* 4 pdu, pkt_type & len */
1035                len = (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
1036                UINT16_TO_BE_STREAM(p_data, len);
1037
1038                /* prepare the left over for as an end fragment */
1039                avrc_prep_end_frag (handle);
1040                AVRC_TRACE_DEBUG ("%s p_pkt len:%d/%d, next len:%d", __func__,
1041                                  p_pkt->len, len, p_fcb->p_fmsg->len );
1042            } else {
1043                /* TODO: Is this "else" block valid? Remove it? */
1044                AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation" );
1045                osi_free(p_pkt);
1046                return AVRC_NO_RESOURCES;
1047            }
1048        }
1049    }
1050
1051    return AVCT_MsgReq( handle, label, cr, p_pkt);
1052#else
1053    return AVRC_NO_RESOURCES;
1054#endif
1055}
1056
1057
1058/******************************************************************************
1059**
1060** Function         AVRC_PassCmd
1061**
1062** Description      Send a PASS THROUGH command to the peer device.  This
1063**                  function can only be called for controller role connections.
1064**                  Any response message from the peer is passed back through
1065**                  the tAVRC_MSG_CBACK callback function.
1066**
1067**                  Input Parameters:
1068**                      handle: Handle of this connection.
1069**
1070**                      label: Transaction label.
1071**
1072**                      p_msg: Pointer to PASS THROUGH message structure.
1073**
1074**                  Output Parameters:
1075**                      None.
1076**
1077** Returns          AVRC_SUCCESS if successful.
1078**                  AVRC_BAD_HANDLE if handle is invalid.
1079**
1080******************************************************************************/
1081UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
1082{
1083    BT_HDR *p_buf;
1084    assert(p_msg != NULL);
1085    if (p_msg)
1086    {
1087        p_msg->hdr.ctype    = AVRC_CMD_CTRL;
1088        p_buf = avrc_pass_msg(p_msg);
1089        if (p_buf)
1090            return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
1091    }
1092    return AVRC_NO_RESOURCES;
1093}
1094
1095/******************************************************************************
1096**
1097** Function         AVRC_PassRsp
1098**
1099** Description      Send a PASS THROUGH response to the peer device.  This
1100**                  function can only be called for target role connections.
1101**                  This function must be called when a PASS THROUGH command
1102**                  message is received from the peer through the
1103**                  tAVRC_MSG_CBACK callback function.
1104**
1105**                  Input Parameters:
1106**                      handle: Handle of this connection.
1107**
1108**                      label: Transaction label.  Must be the same value as
1109**                      passed with the command message in the callback function.
1110**
1111**                      p_msg: Pointer to PASS THROUGH message structure.
1112**
1113**                  Output Parameters:
1114**                      None.
1115**
1116** Returns          AVRC_SUCCESS if successful.
1117**                  AVRC_BAD_HANDLE if handle is invalid.
1118**
1119******************************************************************************/
1120UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
1121{
1122    BT_HDR *p_buf;
1123    assert(p_msg != NULL);
1124    if (p_msg)
1125    {
1126        p_buf = avrc_pass_msg(p_msg);
1127        if (p_buf)
1128            return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
1129    }
1130    return AVRC_NO_RESOURCES;
1131}
1132
1133