From f91a41510cdb9bb82457591b6ec17d751caefc1a Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Thu, 2 Jul 2026 16:01:17 +0800 Subject: [PATCH] fix(ble/bluedroid): match read-multiple responses by handle Read Multiple may mix stack auto-responses with app async responses, so multi_rsp_q order can differ from the request handle order. Look up each response by handle (with occurrence for duplicates) instead of walking the queue by index, and treat opcode-only buffers as empty. --- .../bt/host/bluedroid/stack/gatt/gatt_sr.c | 97 +++++++++++++------ 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_sr.c b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c index b30fd173f0e..0965d0fe5e8 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c @@ -148,6 +148,66 @@ void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb) memset( &p_tcb->sr_cmd, 0, sizeof(tGATT_SR_CMD)); } +/******************************************************************************* +** +** Function gatt_find_multi_rsp_by_handle +** +** Description Find a read-multiple response entry by attribute handle. +** occurrence selects the Nth matching entry (for duplicate +** handles in the same request). +** +** Returns Pointer to response, or NULL if not found +** +*******************************************************************************/ +static tGATTS_RSP *gatt_find_multi_rsp_by_handle(tGATT_SR_CMD *p_cmd, UINT16 handle, + UINT16 occurrence) +{ + list_t *list; + const list_node_t *node; + UINT16 match_count = 0; + + if (p_cmd->multi_rsp_q == NULL || fixed_queue_is_empty(p_cmd->multi_rsp_q)) { + return NULL; + } + + list = fixed_queue_get_list(p_cmd->multi_rsp_q); + for (node = list_begin(list); node != list_end(list); node = list_next(node)) { + tGATTS_RSP *p_rsp = (tGATTS_RSP *)list_node(node); + + if (p_rsp->attr_value.handle == handle) { + if (match_count == occurrence) { + return p_rsp; + } + match_count++; + } + } + + return NULL; +} + +/******************************************************************************* +** +** Function gatt_get_multi_handle_occurrence +** +** Description Return occurrence index of handle at multi_req index. +** +** Returns occurrence count +** +*******************************************************************************/ +static UINT16 gatt_get_multi_handle_occurrence(tGATT_SR_CMD *p_cmd, UINT16 index) +{ + UINT16 ii; + UINT16 occurrence = 0; + + for (ii = 0; ii < index; ii++) { + if (p_cmd->multi_req.handles[ii] == p_cmd->multi_req.handles[index]) { + occurrence++; + } + } + + return occurrence; +} + /******************************************************************************* ** ** Function process_read_multi_rsp @@ -206,24 +266,12 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status, *p++ = GATT_RSP_READ_MULTI; p_buf->len = 1; - /* Now walk through the buffers putting the data into the response in order */ - list_t *list = NULL; - const list_node_t *node = NULL; - if (! fixed_queue_is_empty(p_cmd->multi_rsp_q)) { - list = fixed_queue_get_list(p_cmd->multi_rsp_q); - } + /* Walk request handles in order; match responses by handle because + * stack (sync) and app (async) replies may arrive out of order. */ for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++) { - tGATTS_RSP *p_rsp = NULL; - if (list != NULL) { - if (ii == 0) { - node = list_begin(list); - } else { - node = list_next(node); - } - if (node != list_end(list)) { - p_rsp = (tGATTS_RSP *)list_node(node); - } - } + tGATTS_RSP *p_rsp = gatt_find_multi_rsp_by_handle( + p_cmd, p_cmd->multi_req.handles[ii], + gatt_get_multi_handle_occurrence(p_cmd, ii)); if (p_rsp != NULL) { @@ -238,16 +286,11 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status, len = p_rsp->attr_value.len; } - if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) { - memcpy (p, p_rsp->attr_value.value, len); - if (!is_overflow) { - p += len; - } - p_buf->len += len; - } else { - p_cmd->status = GATT_NOT_FOUND; - break; + memcpy (p, p_rsp->attr_value.value, len); + if (!is_overflow) { + p += len; } + p_buf->len += len; if (is_overflow) { break; @@ -262,7 +305,7 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status, /* Sanity check on the buffer length */ - if (p_buf->len == 0) { + if (p_buf->len <= 1) { GATT_TRACE_ERROR("process_read_multi_rsp - nothing found!!"); p_cmd->status = GATT_NOT_FOUND; osi_free (p_buf);