fix(bt): Fix the high issues related to AVRCP from AI review report

- SDP/registration: handle SDP record creation and discovery failures safely
- AVRC stack: fix packet checks, fragment leaks, response build, and compile guards
- BTC AVRCP: fix return codes, connection state, metadata parsing, and memory leaks
- AVCTP: fix event passing, L2CAP conflicts, TX queue leaks, and disconnect handling
- Example: remove TG RN capability setup before initialization
This commit is contained in:
yangfeng
2026-06-25 14:58:17 +08:00
parent 6c34f8140d
commit 2184fae05b
12 changed files with 221 additions and 58 deletions
@@ -64,6 +64,31 @@ static const UINT8 avrc_ctrl_event_map[] = {
#define AVRC_OP_SUB_UNIT_INFO_RSP_LEN 8
#define AVRC_OP_REJ_MSG_LEN 11
#if (AVRC_METADATA_INCLUDED == TRUE)
/******************************************************************************
**
** Function avrc_free_far_cb
**
** Description Free fragmentation/reassembly buffers for a connection.
**
******************************************************************************/
static void avrc_free_far_cb(UINT8 handle)
{
if (handle >= AVCT_NUM_CONN) {
return;
}
if (avrc_cb.fcb[handle].p_fmsg) {
osi_free(avrc_cb.fcb[handle].p_fmsg);
avrc_cb.fcb[handle].p_fmsg = NULL;
}
avrc_cb.fcb[handle].frag_enabled = FALSE;
if (avrc_cb.rcb[handle].p_rmsg) {
osi_free(avrc_cb.rcb[handle].p_rmsg);
avrc_cb.rcb[handle].p_rmsg = NULL;
}
}
#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
/******************************************************************************
**
** Function avrc_ctrl_cback
@@ -83,6 +108,13 @@ static void avrc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result,
return;
}
/* Release pending fragment/reassembly buffers on disconnect */
if (event == AVCT_DISCONNECT_CFM_EVT || event == AVCT_DISCONNECT_IND_EVT) {
#if (AVRC_METADATA_INCLUDED == TRUE)
avrc_free_far_cb(handle);
#endif
}
if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback) {
avrc_event = avrc_ctrl_event_map[event];
if (event == AVCT_CONNECT_CFM_EVT) {
@@ -298,6 +330,11 @@ static BT_HDR *avrc_proc_vendor_command(UINT8 handle, UINT8 label,
if (p_msg->company_id == AVRC_CO_METADATA) {
switch (*p_data) {
case AVRC_PDU_ABORT_CONTINUATION_RSP:
if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_ABORT_CONTINUATION_RSP_CMD_SIZE)) {
status = AVRC_STS_INTERNAL_ERR;
abort_frag = TRUE;
break;
}
/* aborted by CT - send accept response */
abort_frag = TRUE;
p_begin = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
@@ -315,6 +352,11 @@ static BT_HDR *avrc_proc_vendor_command(UINT8 handle, UINT8 label,
break;
case AVRC_PDU_REQUEST_CONTINUATION_RSP:
if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_REQUEST_CONTINUATION_RSP_CMD_SIZE)) {
status = AVRC_STS_INTERNAL_ERR;
abort_frag = TRUE;
break;
}
if (*(p_data + 4) == p_fcb->frag_pdu) {
avrc_send_continue_frag(handle, label);
p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
@@ -520,6 +562,14 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR) {
drop_code = 2;
AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd);
} else {
AVRC_TRACE_ERROR("Failed to build continuation command");
if (p_rcb->p_rmsg) {
osi_free(p_rcb->p_rmsg);
p_rcb->p_rmsg = NULL;
*pp_pkt = NULL;
}
drop_code = 5;
}
}
}
@@ -952,6 +1002,8 @@ UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
if (status == AVCT_SUCCESS) {
memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
#if (AVRC_METADATA_INCLUDED == TRUE)
/* free fragmentation/reassembly buffers before memset clears pointers */
avrc_free_far_cb(*p_handle);
memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
#endif
@@ -983,6 +1035,10 @@ UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
UINT16 AVRC_Close(UINT8 handle)
{
AVRC_TRACE_DEBUG("AVRC_Close handle:%d", handle);
#if (AVRC_METADATA_INCLUDED == TRUE)
/* release pending fragment/reassembly buffers before removing connection */
avrc_free_far_cb(handle);
#endif
return AVCT_RemoveConn(handle);
}
@@ -1066,7 +1122,7 @@ UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
/* AVRCP spec has not defined any control channel commands that needs fragmentation at this level
* check for fragmentation only on the response */
if ((cr == AVCT_RSP) && (chk_frag == TRUE)) {
if ((cr == AVCT_RSP) && (chk_frag == TRUE) && (p_pkt->event == AVRC_OP_VENDOR)) {
if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) {
int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
p_pkt_new = (BT_HDR *)osi_malloc((UINT16)(AVRC_PACKET_LEN + offset_len
@@ -1098,6 +1154,9 @@ UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
p_pkt->len, len, p_fcb->p_fmsg->len );
} else {
AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation" );
if (p_pkt_new) {
osi_free(p_pkt_new);
}
osi_free(p_pkt);
return AVRC_NO_RESOURCES;
}
@@ -318,9 +318,11 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
status = avrc_bld_get_element_attr_cmd(&p_cmd->get_elem_attrs, p_pkt);
break;
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
status = avrc_bld_register_change_notfn(p_cmd->reg_notif.event_id, p_cmd->reg_notif.param, p_pkt);
break;
#endif
case AVRC_PDU_GET_CAPABILITIES:
status = avrc_bld_get_caps_cmd(&p_cmd->get_caps, p_pkt);
break;
@@ -87,15 +87,17 @@ static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR
}
len += count * 3;
} else {
UINT8 valid_count = 0;
p_event_id = p_rsp->param.event_id;
*p_count = 0;
*p_count -= count;
for (xx = 0; xx < count; xx++) {
if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx])) {
(*p_count)++;
valid_count++;
UINT8_TO_BE_STREAM(p_data, p_event_id[xx]);
}
}
len += (*p_count);
*p_count += valid_count;
len += valid_count;
}
UINT16_TO_BE_STREAM(p_len, len);
p_pkt->len = (p_data - p_start);
@@ -921,6 +923,10 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
status = avrc_bld_set_absolute_volume_rsp(&p_rsp->volume, p_pkt);
break;
default:
status = AVRC_STS_BAD_PARAM;
break;
}
if (alloc && (status != AVRC_STS_NO_ERROR) ) {
@@ -52,9 +52,6 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
tAVRC_APP_SETTING *p_app_set;
/* Check the vendor data */
if (p_msg->vendor_len == 0) {
return AVRC_STS_NO_ERROR;
}
if ((p_msg->p_vendor_data == NULL) || (p_msg->vendor_len < AVRC_CMD_FIXED_SIZE)) {
return AVRC_STS_INTERNAL_ERR;
}
@@ -199,6 +199,11 @@ UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
/* perform service search */
result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback);
if (!result) {
avrc_cb.service_uuid = 0;
avrc_cb.p_db = NULL;
avrc_cb.p_cback = NULL;
}
}
return (result ? AVRC_SUCCESS : AVRC_FAIL);
@@ -413,6 +418,17 @@ void AVRC_Deinit(void)
{
#if AVRC_DYNAMIC_MEMORY
if (avrc_cb_ptr){
#if (AVRC_METADATA_INCLUDED == TRUE)
UINT8 i;
for (i = 0; i < AVCT_NUM_CONN; i++) {
if (avrc_cb_ptr->fcb[i].p_fmsg) {
osi_free(avrc_cb_ptr->fcb[i].p_fmsg);
}
if (avrc_cb_ptr->rcb[i].p_rmsg) {
osi_free(avrc_cb_ptr->rcb[i].p_rmsg);
}
}
#endif
osi_free(avrc_cb_ptr);
avrc_cb_ptr = NULL;
}