Merge branch 'bugfix/fix_bluedroid_read_multi_v5.3' into 'release/v5.3'

fix(ble/bluedroid): fix GATT Read Multiple response handling (5.3)

See merge request espressif/esp-idf!50706
This commit is contained in:
Island
2026-07-20 10:37:20 +08:00
26 changed files with 175 additions and 146 deletions
@@ -254,31 +254,6 @@ tBTM_STATUS BTM_BleSetExtendedAdvParams(UINT8 instance, tBTM_BLE_GAP_EXT_ADV_PAR
goto end;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE) {
extend_adv_cb.inst[instance].connetable = true;
} else {
extend_adv_cb.inst[instance].connetable = false;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE) {
extend_adv_cb.inst[instance].scannable = true;
} else {
extend_adv_cb.inst[instance].scannable = false;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) {
extend_adv_cb.inst[instance].legacy_pdu = true;
} else {
extend_adv_cb.inst[instance].legacy_pdu = false;
}
if (params->type & (BTM_BLE_GAP_SET_EXT_ADV_PROP_DIRECTED |
BTM_BLE_GAP_SET_EXT_ADV_PROP_HD_DIRECTED)) {
extend_adv_cb.inst[instance].directed = true;
} else {
extend_adv_cb.inst[instance].directed = false;
}
#if (CONTROLLER_RPA_LIST_ENABLE == FALSE)
// if own_addr_type == BLE_ADDR_PUBLIC_ID or BLE_ADDR_RANDOM_ID,
if((params->own_addr_type == BLE_ADDR_PUBLIC_ID || params->own_addr_type == BLE_ADDR_RANDOM_ID) && BTM_GetLocalResolvablePrivateAddr(rand_addr)) {
@@ -315,6 +290,31 @@ tBTM_STATUS BTM_BleSetExtendedAdvParams(UINT8 instance, tBTM_BLE_GAP_EXT_ADV_PAR
}
#endif // (BT_BLE_FEAT_ADV_CODING_SELECTION == TRUE)
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE) {
extend_adv_cb.inst[instance].connetable = true;
} else {
extend_adv_cb.inst[instance].connetable = false;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE) {
extend_adv_cb.inst[instance].scannable = true;
} else {
extend_adv_cb.inst[instance].scannable = false;
}
if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) {
extend_adv_cb.inst[instance].legacy_pdu = true;
} else {
extend_adv_cb.inst[instance].legacy_pdu = false;
}
if (params->type & (BTM_BLE_GAP_SET_EXT_ADV_PROP_DIRECTED |
BTM_BLE_GAP_SET_EXT_ADV_PROP_HD_DIRECTED)) {
extend_adv_cb.inst[instance].directed = true;
} else {
extend_adv_cb.inst[instance].directed = false;
}
extend_adv_cb.inst[instance].configured = true;
/* Record the post-fallback on-air address type for per-set conn_addr fixup. */
extend_adv_cb.inst[instance].own_addr_type = params->own_addr_type;
@@ -612,6 +612,11 @@ void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
STREAM_TO_UINT16(handle, p);
STREAM_TO_UINT8(reason, p);
/* 0x00 is not a valid ATT error code; treat as unknown error. */
if (reason == GATT_SUCCESS) {
reason = GATT_UNKNOWN_ERROR;
}
if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
} else {
@@ -620,9 +625,6 @@ void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
(opcode == GATT_REQ_PREPARE_WRITE) &&
(p_attr) &&
(handle == p_attr->handle) ) {
if (reason == GATT_SUCCESS){
reason = GATT_ERROR;
}
p_clcb->status = reason;
gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
} else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
@@ -193,6 +193,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
@@ -251,24 +311,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) {
@@ -283,16 +331,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;
@@ -307,7 +350,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);
@@ -378,24 +421,11 @@ static BOOLEAN process_read_multi_var_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS sta
*p++ = GATT_RSP_READ_MULTI_VAR;
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);
}
/* Match responses by handle; 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) {
@@ -407,16 +437,11 @@ static BOOLEAN process_read_multi_var_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS sta
}
len = MIN(p_rsp->attr_value.len, (mtu - total_len)); // attribute value length
if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) {
GATT_TRACE_DEBUG("%s handle %x len %u", __func__, p_rsp->attr_value.handle, p_rsp->attr_value.len);
UINT16_TO_STREAM(p, p_rsp->attr_value.len);
memcpy (p, p_rsp->attr_value.value, len);
p += len;
p_buf->len += (2+len);
} else {
p_cmd->status = GATT_NOT_FOUND;
break;
}
GATT_TRACE_DEBUG("%s handle %x len %u", __func__, p_rsp->attr_value.handle, p_rsp->attr_value.len);
UINT16_TO_STREAM(p, p_rsp->attr_value.len);
memcpy (p, p_rsp->attr_value.value, len);
p += len;
p_buf->len += (2+len);
} else {
p_cmd->status = GATT_NOT_FOUND;
break;
@@ -425,7 +450,7 @@ static BOOLEAN process_read_multi_var_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS sta
} /* loop through all handles*/
/* Sanity check on the buffer length */
if (p_buf->len == 0) {
if (p_buf->len <= 1) {
GATT_TRACE_ERROR("%s - nothing found!!", __func__);
p_cmd->status = GATT_NOT_FOUND;
osi_free (p_buf);
@@ -561,10 +586,12 @@ tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if,
ret_code = attp_send_sr_msg (p_tcb, p_tcb->sr_cmd.p_rsp_msg);
p_tcb->sr_cmd.p_rsp_msg = NULL;
} else {
if (p_tcb->sr_cmd.status == GATT_SUCCESS){
status = GATT_UNKNOWN_ERROR;
tGATT_STATUS err_status = p_tcb->sr_cmd.status;
if (err_status == GATT_SUCCESS) {
err_status = GATT_UNKNOWN_ERROR;
}
ret_code = gatt_send_error_rsp (p_tcb, status, op_code, p_tcb->sr_cmd.handle, FALSE);
ret_code = gatt_send_error_rsp (p_tcb, err_status, op_code, p_tcb->sr_cmd.handle, FALSE);
}
#if (BLE_EATT_INCLUDED == TRUE)
@@ -1793,7 +1793,7 @@ UINT32 smp_calculate_g2(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 *y)
smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"cmac mod 2**32 mod 10**6", 4);
#endif
SMP_TRACE_ERROR("Value for numeric comparison = %d", vres);
SMP_TRACE_WARNING("Value for numeric comparison = %d", vres);
return vres;
}