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