blob: 2aa38d56f8c98482f8b86832781bb81619d95b03 [file] [log] [blame]
/******************************************************************************
*
* Copyright 2003-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This module contains action functions of the link control state machine.
*
******************************************************************************/
#include <android_bluetooth_sysprop.h>
#include <bluetooth/log.h>
#include <string.h>
#include "avct_api.h"
#include "avct_int.h"
#include "bta/include/bta_sec_api.h"
#include "device/include/device_iot_config.h"
#include "internal_include/bt_target.h"
#include "osi/include/allocator.h"
#include "osi/include/osi.h"
#include "stack/avct/avct_defs.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/bt_types.h"
using namespace bluetooth;
/* packet header length lookup table */
const uint8_t avct_lcb_pkt_type_len[] = {AVCT_HDR_LEN_SINGLE,
AVCT_HDR_LEN_START, AVCT_HDR_LEN_CONT,
AVCT_HDR_LEN_END};
/*******************************************************************************
*
* Function avct_lcb_msg_asmbl
*
* Description Reassemble incoming message.
*
*
* Returns Pointer to reassembled message; NULL if no message
* available.
*
******************************************************************************/
static BT_HDR* avct_lcb_msg_asmbl(tAVCT_LCB* p_lcb, BT_HDR* p_buf) {
uint8_t* p;
uint8_t pkt_type;
BT_HDR* p_ret;
if (p_buf->len < 1) {
osi_free(p_buf);
p_ret = NULL;
return p_ret;
}
/* parse the message header */
p = (uint8_t*)(p_buf + 1) + p_buf->offset;
pkt_type = AVCT_PKT_TYPE(p);
/* quick sanity check on length */
if (p_buf->len < avct_lcb_pkt_type_len[pkt_type] ||
(sizeof(BT_HDR) + p_buf->offset + p_buf->len) > BT_DEFAULT_BUFFER_SIZE) {
osi_free(p_buf);
log::warn("Bad length during reassembly");
p_ret = NULL;
}
/* single packet */
else if (pkt_type == AVCT_PKT_TYPE_SINGLE) {
/* if reassembly in progress drop message and process new single */
if (p_lcb->p_rx_msg != NULL) log::warn("Got single during reassembly");
osi_free_and_reset((void**)&p_lcb->p_rx_msg);
p_ret = p_buf;
}
/* start packet */
else if (pkt_type == AVCT_PKT_TYPE_START) {
/* if reassembly in progress drop message and process new start */
if (p_lcb->p_rx_msg != NULL) log::warn("Got start during reassembly");
osi_free_and_reset((void**)&p_lcb->p_rx_msg);
/*
* Allocate bigger buffer for reassembly. As lower layers are
* not aware of possible packet size after reassembly, they
* would have allocated smaller buffer.
*/
if (sizeof(BT_HDR) + p_buf->offset + p_buf->len > BT_DEFAULT_BUFFER_SIZE) {
osi_free(p_buf);
p_ret = NULL;
return p_ret;
}
p_lcb->p_rx_msg = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
memcpy(p_lcb->p_rx_msg, p_buf, sizeof(BT_HDR) + p_buf->offset + p_buf->len);
/* Free original buffer */
osi_free(p_buf);
/* update p to point to new buffer */
p = (uint8_t*)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset;
/* copy first header byte over nosp */
*(p + 1) = *p;
/* set offset to point to where to copy next */
p_lcb->p_rx_msg->offset += p_lcb->p_rx_msg->len;
/* adjust length for packet header */
p_lcb->p_rx_msg->len -= 1;
p_ret = NULL;
}
/* continue or end */
else {
/* if no reassembly in progress drop message */
if (p_lcb->p_rx_msg == NULL) {
osi_free(p_buf);
log::warn("Pkt type={} out of order", pkt_type);
p_ret = NULL;
} else {
/* get size of buffer holding assembled message */
/*
* NOTE: The buffer is allocated above at the beginning of the
* reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
*/
uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
/* adjust offset and len of fragment for header byte */
p_buf->offset += AVCT_HDR_LEN_CONT;
p_buf->len -= AVCT_HDR_LEN_CONT;
/* verify length */
if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len) {
/* won't fit; free everything */
log::warn("Fragmented message too big!");
osi_free_and_reset((void**)&p_lcb->p_rx_msg);
osi_free(p_buf);
p_ret = NULL;
} else {
/* copy contents of p_buf to p_rx_msg */
memcpy((uint8_t*)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset,
(uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
if (pkt_type == AVCT_PKT_TYPE_END) {
p_lcb->p_rx_msg->offset -= p_lcb->p_rx_msg->len;
p_lcb->p_rx_msg->len += p_buf->len;
p_ret = p_lcb->p_rx_msg;
p_lcb->p_rx_msg = NULL;
} else {
p_lcb->p_rx_msg->offset += p_buf->len;
p_lcb->p_rx_msg->len += p_buf->len;
p_ret = NULL;
}
osi_free(p_buf);
}
}
}
return p_ret;
}
/*******************************************************************************
*
* Function avct_lcb_chnl_open
*
* Description Open L2CAP channel to peer
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_chnl_open(tAVCT_LCB* p_lcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
uint16_t result = AVCT_RESULT_FAIL;
p_lcb->ch_state = AVCT_CH_CONN;
p_lcb->ch_lcid =
L2CA_ConnectReq2(AVCT_PSM, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE);
if (p_lcb->ch_lcid == 0) {
/* if connect req failed, send ourselves close event */
tAVCT_LCB_EVT avct_lcb_evt;
avct_lcb_evt.result = result;
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
}
}
/*******************************************************************************
*
* Function avct_lcb_unbind_disc
*
* Description Deallocate ccb and call callback with disconnect event.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_unbind_disc(UNUSED_ATTR tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
}
/*******************************************************************************
*
* Function avct_lcb_open_ind
*
* Description Handle an LL_OPEN event. For each allocated ccb already
* bound to this lcb, send a connect event. For each
* unbound ccb with a new PID, bind that ccb to this lcb and
* send a connect event.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
int i;
bool bind = false;
if (GET_SYSPROP(A2dp, src_sink_coexist, false)) {
bool is_originater = false;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) &&
p_ccb->cc.role == AVCT_INT) {
log::verbose("find int handle {}", i);
is_originater = true;
}
}
p_ccb = &avct_cb.ccb[0];
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
/* if ccb allocated and */
/** M: to avoid avctp collision, make sure the collision can be checked @{
*/
log::verbose("{} ccb to lcb, alloc {}, lcb {}, role {}, pid 0x{:x}", i,
p_ccb->allocated, fmt::ptr(p_ccb->p_lcb), p_ccb->cc.role,
p_ccb->cc.pid);
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
/* if bound to this lcb send connect confirm event */
if (p_ccb->cc.role == AVCT_INT) {
/** @} */
bind = true;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
0, &p_lcb->peer_addr);
}
/* if unbound acceptor and lcb doesn't already have a ccb for this PID
*/
/** M: to avoid avctp collision, make sure the collision can be checked
@{ */
else if ((p_ccb->cc.role == AVCT_ACP) &&
avct_lcb_has_pid(p_lcb, p_ccb->cc.pid)) {
/* bind ccb to lcb and send connect ind event */
if (is_originater) {
log::error("int exist, unbind acp handle:{}", i);
p_ccb->p_lcb = NULL;
} else {
bind = true;
p_ccb->p_lcb = p_lcb;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT,
0, &p_lcb->peer_addr);
}
}
}
}
} else {
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
/* if ccb allocated and */
if (p_ccb->allocated) {
/* if bound to this lcb send connect confirm event */
if (p_ccb->p_lcb == p_lcb) {
bind = true;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
0, &p_lcb->peer_addr);
}
/* if unbound acceptor and lcb doesn't already have a ccb for this PID
*/
else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
(avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL)) {
/* bind ccb to lcb and send connect ind event */
bind = true;
p_ccb->p_lcb = p_lcb;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT,
0, &p_lcb->peer_addr);
}
}
}
}
/* if no ccbs bound to this lcb, disconnect */
if (!bind) {
DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(p_lcb->peer_addr,
IOT_CONF_KEY_AVRCP_CONN_FAIL_COUNT);
avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
}
}
/*******************************************************************************
*
* Function avct_lcb_open_fail
*
* Description L2CAP channel open attempt failed. Deallocate any ccbs
* on this lcb and send connect confirm event with failure.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_open_fail(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
int i;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
avct_ccb_dealloc(p_ccb, AVCT_CONNECT_CFM_EVT, p_data->result,
&p_lcb->peer_addr);
DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(p_lcb->peer_addr,
IOT_CONF_KEY_AVRCP_CONN_FAIL_COUNT);
}
}
}
/*******************************************************************************
*
* Function avct_lcb_close_ind
*
* Description L2CAP channel closed by peer. Deallocate any initiator
* ccbs on this lcb and send disconnect ind event.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_close_ind(tAVCT_LCB* p_lcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
int i;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
if (p_ccb->cc.role == AVCT_INT) {
avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT, 0, &p_lcb->peer_addr);
} else {
p_ccb->p_lcb = NULL;
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb),
AVCT_DISCONNECT_IND_EVT, 0,
&p_lcb->peer_addr);
}
}
}
}
/*******************************************************************************
*
* Function avct_lcb_close_cfm
*
* Description L2CAP channel closed by us. Deallocate any initiator
* ccbs on this lcb and send disconnect ind or cfm event.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_close_cfm(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
int i;
uint8_t event;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
/* if this ccb initiated close send disconnect cfm otherwise ind */
if (p_ccb->ch_close) {
p_ccb->ch_close = false;
event = AVCT_DISCONNECT_CFM_EVT;
} else {
event = AVCT_DISCONNECT_IND_EVT;
}
if (p_ccb->cc.role == AVCT_INT) {
avct_ccb_dealloc(p_ccb, event, p_data->result, &p_lcb->peer_addr);
} else {
p_ccb->p_lcb = NULL;
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, p_data->result,
&p_lcb->peer_addr);
}
}
}
}
/*******************************************************************************
*
* Function avct_lcb_bind_conn
*
* Description Bind ccb to lcb and send connect cfm event.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_bind_conn(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
p_data->p_ccb->p_lcb = p_lcb;
(*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
AVCT_CONNECT_CFM_EVT, 0, &p_lcb->peer_addr);
}
/*******************************************************************************
*
* Function avct_lcb_chk_disc
*
* Description A ccb wants to close; if it is the last ccb on this lcb,
* close channel. Otherwise just deallocate and call
* callback.
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_chk_disc(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
avct_close_bcb(p_lcb, p_data);
if (avct_lcb_last_ccb(p_lcb, p_data->p_ccb)) {
log::info("Closing last avct channel to device");
p_data->p_ccb->ch_close = true;
avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
} else {
log::info("Closing avct channel with active remaining channels");
avct_lcb_unbind_disc(p_lcb, p_data);
}
}
/*******************************************************************************
*
* Function avct_lcb_chnl_disc
*
* Description Disconnect L2CAP channel.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_chnl_disc(tAVCT_LCB* p_lcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
avct_l2c_disconnect(p_lcb->ch_lcid, 0);
}
/*******************************************************************************
*
* Function avct_lcb_bind_fail
*
* Description Deallocate ccb and call callback with connect event
* with failure result.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_bind_fail(UNUSED_ATTR tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(p_lcb->peer_addr,
IOT_CONF_KEY_AVRCP_CONN_FAIL_COUNT);
}
/*******************************************************************************
*
* Function avct_lcb_cong_ind
*
* Description Handle congestion indication from L2CAP.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_cong_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
int i;
uint8_t event;
BT_HDR* p_buf;
/* set event */
event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
p_lcb->cong = p_data->cong;
if (!p_lcb->cong && !fixed_queue_is_empty(p_lcb->tx_q)) {
while (!p_lcb->cong &&
(p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_lcb->tx_q)) != NULL) {
if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) {
p_lcb->cong = true;
}
}
}
/* send event to all ccbs on this lcb */
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0,
&p_lcb->peer_addr);
}
}
}
/*******************************************************************************
*
* Function avct_lcb_discard_msg
*
* Description Discard a message sent in from the API.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_discard_msg(UNUSED_ATTR tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
log::warn("Dropping message");
osi_free_and_reset((void**)&p_data->ul_msg.p_buf);
}
/*******************************************************************************
*
* Function avct_lcb_send_msg
*
* Description Build and send an AVCTP message.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_send_msg(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
uint16_t curr_msg_len;
uint8_t pkt_type;
uint8_t hdr_len;
uint8_t* p;
uint8_t nosp = 0; /* number of subsequent packets */
uint16_t temp;
uint16_t buf_size = p_lcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
/* store msg len */
curr_msg_len = p_data->ul_msg.p_buf->len;
/* initialize packet type and other stuff */
if (curr_msg_len <= (p_lcb->peer_mtu - AVCT_HDR_LEN_SINGLE)) {
pkt_type = AVCT_PKT_TYPE_SINGLE;
} else {
pkt_type = AVCT_PKT_TYPE_START;
temp = (curr_msg_len + AVCT_HDR_LEN_START - p_lcb->peer_mtu);
nosp = temp / (p_lcb->peer_mtu - 1) + 1;
if ((temp % (p_lcb->peer_mtu - 1)) != 0) nosp++;
}
/* while we haven't sent all packets */
while (curr_msg_len != 0) {
BT_HDR* p_buf;
/* set header len */
hdr_len = avct_lcb_pkt_type_len[pkt_type];
/* if remaining msg must be fragmented */
if (p_data->ul_msg.p_buf->len > (p_lcb->peer_mtu - hdr_len)) {
/* get a new buffer for fragment we are sending */
p_buf = (BT_HDR*)osi_malloc(buf_size);
/* copy portion of data from current message to new buffer */
p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
p_buf->len = p_lcb->peer_mtu - hdr_len;
memcpy(
(uint8_t*)(p_buf + 1) + p_buf->offset,
(uint8_t*)(p_data->ul_msg.p_buf + 1) + p_data->ul_msg.p_buf->offset,
p_buf->len);
p_data->ul_msg.p_buf->offset += p_buf->len;
p_data->ul_msg.p_buf->len -= p_buf->len;
} else {
p_buf = p_data->ul_msg.p_buf;
}
curr_msg_len -= p_buf->len;
/* set up to build header */
p_buf->len += hdr_len;
p_buf->offset -= hdr_len;
p = (uint8_t*)(p_buf + 1) + p_buf->offset;
/* build header */
AVCT_BUILD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
if (pkt_type == AVCT_PKT_TYPE_START) {
UINT8_TO_STREAM(p, nosp);
}
if ((pkt_type == AVCT_PKT_TYPE_START) ||
(pkt_type == AVCT_PKT_TYPE_SINGLE)) {
UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
}
if (p_lcb->cong) {
fixed_queue_enqueue(p_lcb->tx_q, p_buf);
}
/* send message to L2CAP */
else {
if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) {
p_lcb->cong = true;
}
}
/* update pkt type for next packet */
if (curr_msg_len > (p_lcb->peer_mtu - AVCT_HDR_LEN_END)) {
pkt_type = AVCT_PKT_TYPE_CONT;
} else {
pkt_type = AVCT_PKT_TYPE_END;
}
}
log::verbose("tx_q_count:{}", fixed_queue_length(p_lcb->tx_q));
return;
}
/*******************************************************************************
*
* Function avct_lcb_free_msg_ind
*
* Description Discard an incoming AVCTP message.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_free_msg_ind(UNUSED_ATTR tAVCT_LCB* p_lcb,
tAVCT_LCB_EVT* p_data) {
if (p_data == NULL) return;
osi_free_and_reset((void**)&p_data->p_buf);
}
/*******************************************************************************
*
* Function avct_lcb_msg_ind
*
* Description Handle an incoming AVCTP message.
*
*
* Returns Nothing.
*
******************************************************************************/
void avct_lcb_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
uint8_t* p;
uint8_t label, type, cr_ipid;
uint16_t pid;
tAVCT_CCB* p_ccb;
/* this p_buf is to be reported through p_msg_cback. The layer_specific
* needs to be set properly to indicate that it is received through
* control channel */
p_data->p_buf->layer_specific = AVCT_DATA_CTRL;
/* reassemble message; if no message available (we received a fragment) return
*/
p_data->p_buf = avct_lcb_msg_asmbl(p_lcb, p_data->p_buf);
if (p_data->p_buf == NULL) {
return;
}
p = (uint8_t*)(p_data->p_buf + 1) + p_data->p_buf->offset;
/* parse header byte */
AVCT_PARSE_HDR(p, label, type, cr_ipid);
/* parse PID */
BE_STREAM_TO_UINT16(pid, p);
/* check for invalid cr_ipid */
if (cr_ipid == AVCT_CR_IPID_INVALID) {
log::warn("Invalid cr_ipid {}", cr_ipid);
osi_free_and_reset((void**)&p_data->p_buf);
return;
}
bool bind = false;
if (GET_SYSPROP(A2dp, src_sink_coexist, false)) {
bind = avct_msg_ind_for_src_sink_coexist(p_lcb, p_data, label, cr_ipid);
osi_free_and_reset((void**)&p_data->p_buf);
if (bind) return;
} else {
/* lookup PID */
p_ccb = avct_lcb_has_pid(p_lcb, pid);
if (p_ccb) {
/* PID found; send msg up, adjust bt hdr and call msg callback */
p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
(*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid,
p_data->p_buf);
return;
}
}
/* PID not found; drop message */
log::warn("No ccb for PID={:x}", pid);
osi_free_and_reset((void**)&p_data->p_buf);
/* if command send reject */
if (cr_ipid == AVCT_CMD) {
BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVCT_CMD_BUF_SIZE);
p_buf->len = AVCT_HDR_LEN_SINGLE;
p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
p = (uint8_t*)(p_buf + 1) + p_buf->offset;
AVCT_BUILD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
UINT16_TO_BE_STREAM(p, pid);
L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
}
}
bool avct_msg_ind_for_src_sink_coexist(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data,
uint8_t label, uint8_t cr_ipid) {
bool bind = false;
tAVCT_CCB* p_ccb;
int p_buf_len;
uint8_t* p;
uint16_t pid;
p = (uint8_t*)(p_data->p_buf + 1) + p_data->p_buf->offset;
BE_STREAM_TO_UINT16(pid, p);
p_ccb = &avct_cb.ccb[0];
p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
p_buf_len = BT_HDR_SIZE + p_data->p_buf->offset + p_data->p_buf->len;
for (int i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid)) {
/* PID found; send msg up, adjust bt hdr and call msg callback */
bind = true;
BT_HDR* p_tmp_buf = (BT_HDR*)osi_malloc(p_buf_len);
memcpy(p_tmp_buf, p_data->p_buf, p_buf_len);
(*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid,
p_tmp_buf);
}
}
return bind;
}