nimble/host: Fix ATT Read By Type Response handling

ATT_READ_BY_TYPE_RSP handler will extract proc from the proc list and
then call the callback for each handle-value pair in the PDU. However,
this means each time proc is extracted it will be then added to the
tail of the proc list. If there are more than 1 matching procesures on
the list, subsequent extracts when handling *the same PDU* may extract
invalid proc from the list and break the procedure.

This fixes the problem by adding proc back to list at the head instead
of the tail of proc list. This way subsequent iterations of handle-value
pairs handling will extract proper proc as it will be the first matching
on the list.
This commit is contained in:
Andrzej Kaczmarek
2025-12-11 13:45:20 +01:00
committed by Szymon Janc
parent e33120e643
commit e9b014e535
3 changed files with 59 additions and 41 deletions
+8 -1
View File
@@ -431,13 +431,20 @@ ble_att_clt_rx_read_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rx
adata.value_len = data_len - sizeof(*data);
adata.value = data->value;
ble_gattc_rx_read_type_adata(conn_handle, cid, &adata);
rc = ble_gattc_rx_read_type_adata(conn_handle, cid, &adata);
if (rc != 0) {
/* We should not call complete callback if this returned an error
* since proc is not added to the proc list.
*/
return 0;
}
os_mbuf_adj(*rxom, data_len);
}
done:
/* Notify GATT that the response is done being parsed. */
ble_gattc_rx_read_type_complete(conn_handle, cid, rc);
return rc;
}
+2 -2
View File
@@ -119,8 +119,8 @@ void ble_gatts_indicate_fail_notconn(uint16_t conn_handle);
void ble_gattc_rx_err(uint16_t conn_handle, uint16_t cid, uint16_t handle, uint16_t status);
void ble_gattc_rx_mtu(uint16_t conn_handle, uint16_t cid, int status, uint16_t chan_mtu);
void ble_gattc_rx_read_type_adata(uint16_t conn_handle, uint16_t cid,
struct ble_att_read_type_adata *adata);
int ble_gattc_rx_read_type_adata(uint16_t conn_handle, uint16_t cid,
struct ble_att_read_type_adata *adata);
void ble_gattc_rx_read_type_complete(uint16_t conn_handle, uint16_t cid, int status);
void ble_gattc_rx_read_rsp(uint16_t conn_handle, uint16_t cid, int status,
struct os_mbuf **rxom);
+49 -38
View File
@@ -754,12 +754,16 @@ ble_gattc_proc_free(struct ble_gattc_proc *proc)
}
static void
ble_gattc_proc_insert(struct ble_gattc_proc *proc)
ble_gattc_proc_insert(struct ble_gattc_proc *proc, bool insert_head)
{
ble_gattc_dbg_assert_proc_not_inserted(proc);
ble_hs_lock();
STAILQ_INSERT_TAIL(&ble_gattc_procs, proc, next);
if (insert_head) {
STAILQ_INSERT_HEAD(&ble_gattc_procs, proc, next);
} else {
STAILQ_INSERT_TAIL(&ble_gattc_procs, proc, next);
}
ble_hs_unlock();
}
@@ -790,7 +794,7 @@ ble_gattc_proc_set_resume_timer(struct ble_gattc_proc *proc)
}
static void
ble_gattc_process_status(struct ble_gattc_proc *proc, int status)
ble_gattc_process_status(struct ble_gattc_proc *proc, int status, bool insert_head)
{
switch (status) {
case 0:
@@ -798,7 +802,7 @@ ble_gattc_process_status(struct ble_gattc_proc *proc, int status)
ble_gattc_proc_set_exp_timer(proc);
}
ble_gattc_proc_insert(proc);
ble_gattc_proc_insert(proc, insert_head);
ble_hs_timer_resched();
break;
@@ -1187,7 +1191,7 @@ ble_gattc_resume_procs(void)
proc->flags &= ~BLE_GATTC_PROC_F_STALLED;
rc = resume_cb(proc);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -1398,7 +1402,7 @@ done:
STATS_INC(ble_gattc_stats, mtu_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -1623,7 +1627,7 @@ done:
STATS_INC(ble_gattc_stats, disc_all_svcs_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -1837,7 +1841,7 @@ done:
STATS_INC(ble_gattc_stats, disc_svc_uuid_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -2153,7 +2157,7 @@ done:
STATS_INC(ble_gattc_stats, find_inc_svcs_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -2386,7 +2390,7 @@ done:
STATS_INC(ble_gattc_stats, disc_all_chrs_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -2626,7 +2630,7 @@ done:
STATS_INC(ble_gattc_stats, disc_chrs_uuid_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -2836,7 +2840,7 @@ done:
STATS_INC(ble_gattc_stats, disc_all_dscs_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -2971,7 +2975,7 @@ done:
STATS_INC(ble_gattc_stats, read_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -3135,7 +3139,7 @@ done:
STATS_INC(ble_gattc_stats, read_uuid_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -3331,7 +3335,7 @@ done:
STATS_INC(ble_gattc_stats, read_long_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -3555,7 +3559,7 @@ done:
STATS_INC(ble_gattc_stats, read_mult_fail);
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -3730,7 +3734,7 @@ done:
/* Free the mbuf in case the send failed. */
os_mbuf_free_chain(txom);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -4048,7 +4052,7 @@ done:
/* Free the mbuf in case of failure. */
os_mbuf_free_chain(txom);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -4337,7 +4341,7 @@ done:
attrs[i].om = NULL;
}
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
return rc;
}
@@ -4709,7 +4713,7 @@ done:
/* Tell the application that an indication transmission was attempted. */
ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 1);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
os_mbuf_free_chain(txom);
return rc;
}
@@ -4777,7 +4781,7 @@ ble_gattc_rx_mtu(uint16_t conn_handle, uint16_t cid, int status, uint16_t chan_m
proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, BLE_L2CAP_CID_ATT, BLE_GATT_OP_MTU);
if (proc != NULL) {
ble_gattc_mtu_cb(proc, status, 0, chan_mtu);
ble_gattc_process_status(proc, BLE_HS_EDONE);
ble_gattc_process_status(proc, BLE_HS_EDONE, false);
}
}
@@ -4800,7 +4804,7 @@ ble_gattc_rx_find_info_idata(uint16_t conn_handle, uint16_t cid,
BLE_GATT_OP_DISC_ALL_DSCS);
if (proc != NULL) {
rc = ble_gattc_disc_all_dscs_rx_idata(proc, idata);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -4822,7 +4826,7 @@ ble_gattc_rx_find_info_complete(uint16_t conn_handle, uint16_t cid, int status)
BLE_GATT_OP_DISC_ALL_DSCS);
if (proc != NULL) {
rc = ble_gattc_disc_all_dscs_rx_complete(proc, status);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -4845,7 +4849,7 @@ ble_gattc_rx_find_type_value_hinfo(uint16_t conn_handle, uint16_t cid,
BLE_GATT_OP_DISC_SVC_UUID);
if (proc != NULL) {
rc = ble_gattc_disc_svc_uuid_rx_hinfo(proc, hinfo);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -4867,7 +4871,7 @@ ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, uint16_t cid, int st
BLE_GATT_OP_DISC_SVC_UUID);
if (proc != NULL) {
rc = ble_gattc_disc_svc_uuid_rx_complete(proc, status);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -4875,12 +4879,12 @@ ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, uint16_t cid, int st
* Dispatches an incoming "attribute data" entry from a read-by-type-response
* to the appropriate active GATT procedure.
*/
void
int
ble_gattc_rx_read_type_adata(uint16_t conn_handle, uint16_t cid,
struct ble_att_read_type_adata *adata)
{
#if !NIMBLE_BLE_ATT_CLT_READ_TYPE
return;
return BLE_HS_ENOTSUP;
#endif
const struct ble_gattc_rx_adata_entry *rx_entry;
@@ -4892,8 +4896,15 @@ ble_gattc_rx_read_type_adata(uint16_t conn_handle, uint16_t cid,
&rx_entry);
if (proc != NULL) {
rc = rx_entry->cb(proc, adata);
ble_gattc_process_status(proc, rc);
/* We need to put procedure on head of the queue since caller expects
* to process the same proc again.
*/
ble_gattc_process_status(proc, rc, true);
} else {
rc = -1;
}
return rc;
}
/**
@@ -4916,7 +4927,7 @@ ble_gattc_rx_read_type_complete(uint16_t conn_handle, uint16_t cid, int status)
&rx_entry);
if (proc != NULL) {
rc = rx_entry->cb(proc, status);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -4939,7 +4950,7 @@ ble_gattc_rx_read_group_type_adata(uint16_t conn_handle, uint16_t cid,
BLE_GATT_OP_DISC_ALL_SVCS);
if (proc != NULL) {
rc = ble_gattc_disc_all_svcs_rx_adata(proc, adata);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -4961,7 +4972,7 @@ ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, uint16_t cid, int st
BLE_GATT_OP_DISC_ALL_SVCS);
if (proc != NULL) {
rc = ble_gattc_disc_all_svcs_rx_complete(proc, status);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -4985,7 +4996,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, uint16_t cid, int status, struct os_
&rx_entry);
if (proc != NULL) {
rc = rx_entry->cb(proc, status, om);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -5008,7 +5019,7 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, uint16_t cid, int status,
BLE_GATT_OP_READ_LONG);
if (proc != NULL) {
rc = ble_gattc_read_long_rx_read_rsp(proc, status, om);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -5032,7 +5043,7 @@ ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, uint16_t cid, int status,
proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, op);
if (proc != NULL) {
ble_gattc_read_mult_cb(proc, status, 0, om);
ble_gattc_process_status(proc, BLE_HS_EDONE);
ble_gattc_process_status(proc, BLE_HS_EDONE, false);
}
}
@@ -5053,7 +5064,7 @@ ble_gattc_rx_write_rsp(uint16_t conn_handle, uint16_t cid)
BLE_GATT_OP_WRITE);
if (proc != NULL) {
ble_gattc_write_cb(proc, 0, 0);
ble_gattc_process_status(proc, BLE_HS_EDONE);
ble_gattc_process_status(proc, BLE_HS_EDONE, false);
}
}
@@ -5079,7 +5090,7 @@ ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, uint16_t cid, int status,
&rx_entry);
if (proc != NULL) {
rc = rx_entry->cb(proc, status, handle, offset, om);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -5102,7 +5113,7 @@ ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, uint16_t cid, int status)
ble_gattc_rx_exec_entries, &rx_entry);
if (proc != NULL) {
rc = rx_entry->cb(proc, status);
ble_gattc_process_status(proc, rc);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -5123,7 +5134,7 @@ ble_gatts_rx_indicate_rsp(uint16_t conn_handle, uint16_t cid)
BLE_GATT_OP_INDICATE);
if (proc != NULL) {
ble_gatts_indicate_rx_rsp(proc);
ble_gattc_process_status(proc, BLE_HS_EDONE);
ble_gattc_process_status(proc, BLE_HS_EDONE, false);
}
}