From 3a0344e321dd89d46d4530473f81b9b8fef2b6fa Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:15:33 +0800 Subject: [PATCH 01/12] fix(ble/bluedroid): skip identity conversion for static random direct connect Do not rewrite static or non-resolvable random peer addresses to identity type 0x03 when CONFIG_BT_BLE_RPA_SUPPORTED is enabled. (cherry picked from commit 2ef10ef488d7a11f665ecac3a77fedfe875784db) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/stack/l2cap/l2c_ble.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c index d4acd714ae8..39ce43265d7 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c @@ -993,12 +993,14 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) #if (CONTROLLER_RPA_LIST_ENABLE) if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) { - if (btm_cb.ble_ctr_cb.privacy_mode >= BTM_PRIVACY_1_2) { - own_addr_type |= BLE_ADDR_TYPE_ID_BIT; - } + if (!(peer_addr_type == BLE_ADDR_RANDOM && !BTM_BLE_IS_RESOLVE_BDA(peer_addr))) { + if (btm_cb.ble_ctr_cb.privacy_mode >= BTM_PRIVACY_1_2) { + own_addr_type |= BLE_ADDR_TYPE_ID_BIT; + } - //btm_ble_enable_resolving_list(BTM_BLE_RL_INIT); - btm_random_pseudo_to_identity_addr(peer_addr, &peer_addr_type); + //btm_ble_enable_resolving_list(BTM_BLE_RL_INIT); + btm_random_pseudo_to_identity_addr(peer_addr, &peer_addr_type); + } } else { btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, TRUE); } From 702972227df45844df18f735128f4337765de965 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:15:52 +0800 Subject: [PATCH 02/12] fix(ble/bluedroid): reject adv data on legacy directed ext adv (cherry picked from commit c339cec380f1df577faaba0cb852fde495ac3828) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c index bcf2cc0ea45..f9fa9ebec74 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c @@ -269,6 +269,13 @@ tBTM_STATUS BTM_BleSetExtendedAdvParams(UINT8 instance, tBTM_BLE_GAP_EXT_ADV_PAR 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)) { From 78f1bd2ccff6afb1a89969ff71c9afad1c02953b Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:16:29 +0800 Subject: [PATCH 03/12] fix(ble/bluedroid): set REQ_WAITING before GATTC service-change rediscovery When service change cancels in-progress discovery, bta_gattc_disc_cmpl() re-triggers discovery without marking auto_update as REQ_WAITING. If a client command is queued in p_q_cmd, bta_gattc_start_discover() refuses to restart and the command is never dispatched. (cherry picked from commit 13926bb9bc7a36beb5f4b67709924c7fc9ae5aa1) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c index 9dce7417070..1b17e58622a 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c @@ -1153,7 +1153,9 @@ void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) } if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) { - /* start discovery again */ + /* Service change arrived during discovery; restart even if p_q_cmd is set. + * Mirrors bta_gattc_op_cmpl(). */ + p_clcb->auto_update = BTA_GATTC_REQ_WAITING; bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); } /* get any queued command to proceed */ From be3b2cf56bea55f20598e520f7efd93c8fa70481 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:16:47 +0800 Subject: [PATCH 04/12] fix(ble/bluedroid): unblock sync HCI cmd on Command Status error Release the BLE sync semaphore and record HCI status when a synchronous command is rejected via Command Status, since no Command Complete event follows. (cherry picked from commit 29ae92f4ef846600804ac9a7757d137f6ea9a2db) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/hci/hci_layer.c | 12 ++++++++++++ components/bt/host/bluedroid/stack/btu/btu_hcif.c | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 4bf553d0ce6..5c4a904b249 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -518,6 +518,18 @@ static bool filter_incoming_event(BT_HDR *packet) metadata = (hci_cmd_metadata_t *)(wait_entry->data); if (metadata->command_status_cb) { metadata->command_status_cb(status, &metadata->command, metadata->context); +#if ((BLE_50_FEATURE_SUPPORT == TRUE) || (BLE_42_FEATURE_SUPPORT == TRUE)) + /* No Command Complete follows a failed Command Status (Core Spec Vol 4 Part E). */ + if (status != HCI_SUCCESS) { + BlE_SYNC *sync_info = btsnd_hcic_ble_get_sync_info(); + if (!sync_info) { + HCI_TRACE_WARNING("%s sync_info is NULL. opcode = 0x%x", __func__, opcode); + } else if (sync_info->sync_sem && sync_info->opcode == opcode) { + osi_sem_give(&sync_info->sync_sem); + sync_info->opcode = 0; + } + } +#endif // #if ((BLE_50_FEATURE_SUPPORT == TRUE) || (BLE_42_FEATURE_SUPPORT == TRUE)) } goto intercepted; diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index 2f65fb0d475..983a7af59ff 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1909,6 +1909,11 @@ static void btu_hcif_command_status_evt(uint8_t status, BT_HDR *command, void *c { BT_HDR *event = osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)); command_status_hack_t *hack = (command_status_hack_t *)&event->data[0]; +#if ((BLE_50_FEATURE_SUPPORT == TRUE) || (BLE_42_FEATURE_SUPPORT == TRUE)) + if (status != HCI_SUCCESS) { + btsnd_hci_ble_set_status(status); + } +#endif // #if ((BLE_50_FEATURE_SUPPORT == TRUE) || (BLE_42_FEATURE_SUPPORT == TRUE)) hack->callback = btu_hcif_command_status_evt_on_task; hack->status = status; From 50b98393c67f3b152c94e9d8096afb33cd3f00d9 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:23:57 +0800 Subject: [PATCH 05/12] fix(ble/bluedroid): Fixed potential double Execute Write Response (cherry picked from commit 0a93ccd3b30852ed563698ec32d0aa02ae1a0b06) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/stack/gatt/gatt_sr.c | 32 +++++++++++++++++++ .../bluedroid/stack/gatt/include/gatt_int.h | 1 + 2 files changed, 33 insertions(+) diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_sr.c b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c index b30fd173f0e..41b6db2d184 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c @@ -414,6 +414,27 @@ tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if, UINT32 trans_id, UINT8 op_code, tGATT_STATUS status, tGATTS_RSP *p_msg) { + if ((p_tcb->exec_write_rsp_trans_id == trans_id) && (op_code == GATT_REQ_EXEC_WRITE)) { + /* + * Execute Write is a special case without a handle, so both stack and application + * may try to send a response. + * - Stack: may have already sent an automatic Execute Write Response. + * - App: may call esp_gatts_send_response() with the same trans_id. + * + * To prevent sending two responses for the same Execute Write request, + * we check if this trans_id has already been auto-responded by stack. + * If so, ignore the application response without sending another ATT packet. + * Still update cback_cnt/dequeue sr_cmd so state stays consistent when multiple + * apps are registered; only clear exec_write_rsp_trans_id after all apps respond. + */ + gatt_sr_update_cback_cnt(p_tcb, gatt_if, FALSE, FALSE); + if (gatt_sr_is_cback_cnt_zero(p_tcb)) { + gatt_dequeue_sr_cmd(p_tcb); + p_tcb->exec_write_rsp_trans_id = 0; + } + return GATT_SUCCESS; + } + tGATT_STATUS ret_code = GATT_SUCCESS; UNUSED(trans_id); @@ -481,6 +502,7 @@ tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if, *******************************************************************************/ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data) { + BOOLEAN response_sent = false; UINT8 *p = p_data, flag, i = 0; UINT32 trans_id = 0; tGATT_IF gatt_if; @@ -536,6 +558,7 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U is_prepare_write_valid = TRUE; } GATT_TRACE_DEBUG("Send execute_write_rsp\n"); + response_sent = TRUE; } else if ((prepare_record->error_code_app == GATT_SUCCESS) && (prepare_record->total_num > queue_num)){ //No error for stack_rsp's handles and there exist some app_rsp's handles, @@ -580,6 +603,10 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0); gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb); } + /* Record trans_id if stack already sent response, to prevent app from sending duplicate */ + if (response_sent) { + p_tcb->exec_write_rsp_trans_id = trans_id; + } for (i = 0; i < GATT_MAX_APPS; i++) { if (p_tcb->prep_cnt[i]) { gatt_if = (tGATT_IF) (i + 1); @@ -657,6 +684,11 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb); } + /* Record trans_id if stack already sent response, to prevent app from sending duplicate */ + if (response_sent) { + p_tcb->exec_write_rsp_trans_id = trans_id; + } + for (i = 0; i < GATT_MAX_APPS; i++) { if (p_tcb->prep_cnt[i]) { gatt_if = (tGATT_IF) (i + 1); diff --git a/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h index 76432c4f1b6..44af16eec70 100644 --- a/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h +++ b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h @@ -421,6 +421,7 @@ typedef struct { UINT8 tcb_idx; #if (GATTS_INCLUDED == TRUE) tGATT_PREPARE_WRITE_RECORD prepare_write_record; /* prepare write packets record */ + UINT32 exec_write_rsp_trans_id; /* trans_id of auto-responded execute write */ #endif // (GATTS_INCLUDED == TRUE) } tGATT_TCB; From ad3a325cc923c4faf60c4ca1281f7b5b27983728 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:24:14 +0800 Subject: [PATCH 06/12] fix(ble/bluedroid): cap Read By Type response length at ATT maximum Read By Type Response Length is one octet (max 255). When MTU was large enough to return a long characteristic value in one pair, the server wrote (UINT8)(value_len + 2) and overflowed (e.g. 513 -> 1), so the client rejected the PDU as GATT_INVALID_PDU (0x04). Cap server value to 253 bytes per pair, clamp the length byte, and continue long reads via Read Blob when the capped size is returned. (cherry picked from commit 97905afccc3741266402e70aef1fc7227b8382e1) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/stack/gatt/gatt_cl.c | 6 +++++- components/bt/host/bluedroid/stack/gatt/gatt_db.c | 8 +++++++- .../bt/host/bluedroid/stack/gatt/include/gatt_int.h | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c index 28a50c4ac35..1fc86945659 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c @@ -891,7 +891,11 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 /* value_len is the length of current record's value; use it to avoid overread when multiple records present */ p_clcb->counter = value_len; p_clcb->s_handle = handle; - if ( p_clcb->counter == (p_clcb->p_tcb->payload_size - 4)) { + UINT16 max_rbtype_val_len = (p_clcb->p_tcb->payload_size - 4); + if (max_rbtype_val_len > GATT_MAX_READ_BY_TYPE_VALUE_LEN) { + max_rbtype_val_len = GATT_MAX_READ_BY_TYPE_VALUE_LEN; + } + if (p_clcb->counter == max_rbtype_val_len) { p_clcb->op_subtype = GATT_READ_BY_HANDLE; if (!p_clcb->p_attr_buf) { p_clcb->p_attr_buf = (UINT8 *)osi_malloc(GATT_MAX_ATTR_LEN); diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_db.c b/components/bt/host/bluedroid/stack/gatt/gatt_db.c index 73037155f27..299eb80927d 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_db.c @@ -370,7 +370,13 @@ tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb, UINT16_TO_STREAM (p, p_attr->handle); - status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len - 2), &len, sec_flag, key_size); + { + UINT16 max_val_len = (UINT16)(*p_len - 2); + if (max_val_len > GATT_MAX_READ_BY_TYPE_VALUE_LEN) { + max_val_len = GATT_MAX_READ_BY_TYPE_VALUE_LEN; + } + status = read_attr_value ((void *)p_attr, 0, &p, FALSE, max_val_len, &len, sec_flag, key_size); + } if (status == GATT_PENDING) { diff --git a/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h index 44af16eec70..0f2a7b08831 100644 --- a/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h +++ b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h @@ -76,6 +76,10 @@ typedef UINT8 tGATT_SEC_ACTION; #define GATT_HDR_SIZE 3 /* 1B opcode + 2B handle */ +/* ATT Read By Type Response: Length field is 1 octet (max 255). */ +#define GATT_MAX_READ_BY_TYPE_PAIR_LEN 255 +#define GATT_MAX_READ_BY_TYPE_VALUE_LEN (GATT_MAX_READ_BY_TYPE_PAIR_LEN - 2) + /** * Wait for ATT cmd response timeout value (40 seconds). * The max connection supervision timeout is 32 seconds, From 005e8029a97b1986323c4c6c1825ec4e62442822 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:24:32 +0800 Subject: [PATCH 07/12] feat(ble/bluedroid): Optimize Bluedroid memory usage - Delete unused device records (~356B each) (cherry picked from commit 7d1c0e9a32c0cd508e112a7793c6f443b28d76bf) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/btc/core/btc_main.c | 5 +- .../bt/host/bluedroid/stack/btm/btm_ble.c | 37 +++++++++--- .../bt/host/bluedroid/stack/btu/btu_hcif.c | 56 +++++++++++++++++++ 3 files changed, 87 insertions(+), 11 deletions(-) diff --git a/components/bt/host/bluedroid/btc/core/btc_main.c b/components/bt/host/bluedroid/btc/core/btc_main.c index bbcb17b670b..f42d37771de 100644 --- a/components/bt/host/bluedroid/btc/core/btc_main.c +++ b/components/bt/host/bluedroid/btc/core/btc_main.c @@ -183,7 +183,6 @@ uint32_t btc_get_ble_status(void) } #endif // #if ((SMP_INCLUDED == TRUE) || (BLE_PRIVACY_SPT == TRUE)) -#if (SMP_INCLUDED == TRUE) // Number of recorded devices extern uint8_t btm_ble_sec_dev_record_count(void); uint8_t sec_dev_cnt = btm_ble_sec_dev_record_count(); @@ -191,14 +190,14 @@ uint32_t btc_get_ble_status(void) BTC_TRACE_WARNING("%s security device record count %d", __func__, sec_dev_cnt); status |= BIT(BTC_BLE_STATUS_DEVICE_REC); } - +#if SMP_INCLUDED == TRUE // Number of saved bonded devices int bond_cnt = btc_storage_get_num_ble_bond_devices(); if (bond_cnt) { BTC_TRACE_WARNING("%s bonded devices count %d", __func__, bond_cnt); status |= BIT(BTC_BLE_STATUS_BOND); } -#endif // SMP_INCLUDED +#endif // SMP_INCLUDED == TRUE #if (BLE_PRIVACY_SPT == TRUE) // Privacy enabled diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble.c b/components/bt/host/bluedroid/stack/btm/btm_ble.c index 81a0c449547..7bc86d38e70 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble.c @@ -2989,26 +2989,47 @@ uint8_t btm_ble_scan_active_count(void) return count; } +#if (BLE_INCLUDED == TRUE) #if (SMP_INCLUDED == TRUE) +extern bool btc_config_has_section(const char *section); +#endif + uint8_t btm_ble_sec_dev_record_count(void) { tBTM_SEC_DEV_REC *p_dev_rec = NULL; list_node_t *p_node = NULL; uint8_t count = 0; - /* First look for the non-paired devices for the oldest entry */ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) { p_dev_rec = list_node(p_node); +#if (SMP_INCLUDED == TRUE) if (p_dev_rec && (p_dev_rec->sec_flags & BTM_SEC_IN_USE) && (p_dev_rec->ble.key_type != BTM_LE_KEY_NONE)) { - BTM_TRACE_DEBUG("%s BLE security device #%d: bd_addr=%02X:%02X:%02X:%02X:%02X:%02X", +#else + if (p_dev_rec && (p_dev_rec->sec_flags & BTM_SEC_IN_USE)) { +#endif +#if (SMP_INCLUDED == TRUE) + /* Check if device exists in NVS */ + char bdstr[18] = {0}; + bdaddr_to_string((bt_bdaddr_t *)p_dev_rec->bd_addr, bdstr, sizeof(bdstr)); + + BTM_TRACE_WARNING("%s device #%d: "MACSTR", key_type=0x%02x (PENC:%d PID:%d PCSRK:%d LENC:%d LID:%d LCSRK:%d), in_nvs=%d", __func__, count, - p_dev_rec->bd_addr[0], - p_dev_rec->bd_addr[1], - p_dev_rec->bd_addr[2], - p_dev_rec->bd_addr[3], - p_dev_rec->bd_addr[4], - p_dev_rec->bd_addr[5]); + MAC2STR(p_dev_rec->bd_addr), + p_dev_rec->ble.key_type, + (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC) ? 1 : 0, + (p_dev_rec->ble.key_type & BTM_LE_KEY_PID) ? 1 : 0, + (p_dev_rec->ble.key_type & BTM_LE_KEY_PCSRK) ? 1 : 0, + (p_dev_rec->ble.key_type & BTM_LE_KEY_LENC) ? 1 : 0, + (p_dev_rec->ble.key_type & BTM_LE_KEY_LID) ? 1 : 0, + (p_dev_rec->ble.key_type & BTM_LE_KEY_LCSRK) ? 1 : 0, + btc_config_has_section(bdstr)); +#else + BTM_TRACE_WARNING("%s device #%d: "MACSTR, + __func__, + count, + MAC2STR(p_dev_rec->bd_addr)); +#endif count++; } } diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index 983a7af59ff..b56bf58969e 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -983,6 +983,20 @@ static void btu_hcif_disconnection_comp_evt (UINT8 *p) handle = HCID_GET_HANDLE (handle); +#if BLE_INCLUDED == TRUE + /* Capture the disconnecting device's address before btm_acl_disconnected() + * clears the matched connection handle. The record itself is re-looked-up + * afterwards (by address) because callbacks fired during disconnection may + * have already freed it. */ + BD_ADDR disc_bda; + BOOLEAN have_disc_bda = FALSE; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle(handle); + if (p_dev_rec) { + memcpy(disc_bda, p_dev_rec->bd_addr, BD_ADDR_LEN); + have_disc_bda = TRUE; + } +#endif + dev_find = btm_acl_disconnected(handle, reason); #if (BLE_FEAT_ISO_CIG_EN == TRUE) @@ -995,6 +1009,48 @@ static void btu_hcif_disconnection_comp_evt (UINT8 *p) HCI_TRACE_WARNING("hcif disc complete: hdl 0x%x, rsn 0x%x dev_find %d", handle, reason, dev_find); UNUSED(dev_find); + +#if BLE_INCLUDED == TRUE + /* Delete unpaired device records to free memory (~356B per device). + * + * Re-find the record by address: callbacks invoked during + * btm_acl_disconnected() may already have freed it, so the pointer captured + * before the call cannot be trusted. + * + * Only delete when the device is fully idle and unpaired: + * 1. No active BR/EDR connection (hci_handle invalid) + * 2. No active LE connection (ble_hci_handle invalid) - protects the still + * connected transport of a dual-mode device when the other one drops + * 3. No BLE security keys (unpaired) - when SMP is enabled + * + * BT_TRANSPORT_LE is used so that any retained BR/EDR link key keeps a + * BR/EDR-bonded record alive; an LE-unpaired record that has no BR/EDR key + * collapses to BTM_SEC_IN_USE only and is removed from the list. + * + * Skip deletion on HCI_ERR_CONN_FAILED_ESTABLISHMENT when connect + * retry is enabled. + */ + if (have_disc_bda +#if (GATTC_CONNECT_RETRY_EN == TRUE) + && reason != HCI_ERR_CONN_FAILED_ESTABLISHMENT +#endif + ) { + p_dev_rec = btm_find_dev(disc_bda); + if (p_dev_rec + && p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE /* No active BR/EDR connection */ + && p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE /* No active LE connection */ +#if SMP_INCLUDED == TRUE + && !p_dev_rec->ble.key_type /* No BLE security keys */ +#endif + ) { + BTM_TRACE_WARNING( + "Deleting unpaired device %02X:%02X:%02X:%02X:%02X:%02X", + p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2], + p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]); + btm_sec_free_dev(p_dev_rec, BT_TRANSPORT_LE); + } + } +#endif // BLE_INCLUDED == TRUE } /******************************************************************************* From a8ee33b38fa5854e1a64785555431dbc0552c186 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:24:52 +0800 Subject: [PATCH 08/12] fix(ble/bluedroid): preserve HCI status on BLE 4.2 GAP failures Return BTM_HCI_ERROR | hci_status from legacy BLE 4.2 GAP HCI command paths instead of mapping failures to BTM_ILLEGAL_VALUE or BTM_NO_RESOURCES. Add btm_ble_status_from_hci() helper and propagate real status through scan start/stop completion callbacks. (cherry picked from commit 47dd785a1825c24b05561f55c32ab4cb663458b6) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/bta/dm/bta_dm_act.c | 6 +- .../bt/host/bluedroid/stack/btm/btm_acl.c | 2 +- .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 88 ++++++++++++------- .../bt/host/bluedroid/stack/btm/btm_devctl.c | 6 +- .../bluedroid/stack/btm/include/btm_ble_int.h | 8 ++ 5 files changed, 69 insertions(+), 41 deletions(-) diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c index 8c2aef3554c..9b51c486c06 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -5402,10 +5402,11 @@ void bta_dm_ble_scan (tBTA_DM_MSG *p_data) if ((status = BTM_BleScan(TRUE, p_data->ble_scan.duration, bta_dm_scan_results_cb, bta_dm_scan_cmpl_cb, bta_dm_scan_discard_cb)) != BTM_CMD_STARTED) { APPL_TRACE_WARNING(" %s start scan failed. status=0x%x\n", __FUNCTION__, status); + } else { + status = BTM_SUCCESS; } memset(&cb_params, 0, sizeof(cb_params)); - status = (status == BTM_CMD_STARTED ? BTA_SUCCESS : BTA_FAILURE); cb_params.status = status; BTM_LegacyBleCallbackTrigger(BTM_BLE_LEGACY_GAP_SCAN_START_COMPLETE_EVT, &cb_params); @@ -5415,10 +5416,11 @@ void bta_dm_ble_scan (tBTA_DM_MSG *p_data) if (status != BTM_CMD_STARTED){ APPL_TRACE_WARNING(" %s stop scan failed, status=0x%x\n", __FUNCTION__, status); + } else { + status = BTM_SUCCESS; } memset(&cb_params, 0, sizeof(cb_params)); - status = (status == BTM_CMD_STARTED ? BTA_SUCCESS : BTA_FAILURE); cb_params.status = status; BTM_LegacyBleCallbackTrigger(BTM_BLE_LEGACY_GAP_SCAN_STOP_COMPLETE_EVT, &cb_params); #if (BLE_TOPOLOGY_CHECK == TRUE) diff --git a/components/bt/host/bluedroid/stack/btm/btm_acl.c b/components/bt/host/bluedroid/stack/btm/btm_acl.c index 4621e6092e8..cc22fb5e4e8 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_acl.c @@ -2393,7 +2393,7 @@ void btm_read_channel_map_complete(UINT8 *p) memcpy(results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN); } } else { - results.status = BTM_ERR_PROCESSING; + results.status = BTM_HCI_ERROR | results.hci_status; BTM_TRACE_ERROR("BTM Channel Map Read Failed: hci status 0x%02x", results.hci_status); } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index 2446251dd54..5d317fe4db9 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -1117,15 +1117,17 @@ tBTM_STATUS BTM_BleStartAdvWithParams(UINT16 adv_int_min, UINT16 adv_int_max, UI tBTM_STATUS status = BTM_SUCCESS; /* update adv params */ - if (btsnd_hcic_ble_write_adv_params (adv_int_min, + UINT8 hci_status = btsnd_hcic_ble_write_adv_params (adv_int_min, adv_int_max, adv_type, own_bda_type, p_dir_bda->type, p_dir_bda->bda, chnl_map, - p_cb->afp) != HCI_SUCCESS) { - status = BTM_NO_RESOURCES; + p_cb->afp); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + status = btm_ble_status_from_hci(hci_status); } osi_mutex_unlock(&btm_lock); @@ -1175,13 +1177,13 @@ tBTM_STATUS BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, (scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS) && (scan_duplicate_filter < BTM_BLE_SCAN_DUPLICATE_MAX) && (scan_window <= scan_interval)) { - if ((btsnd_hcic_ble_set_scan_params(scan_mode, (UINT16)scan_interval, - (UINT16)scan_window, - addr_type_own, - scan_filter_policy)) != HCI_SUCCESS) { - ret = BTM_ILLEGAL_VALUE; - BTM_TRACE_ERROR("Illegal params: scan_interval = %d scan_window = %d\n", - scan_interval, scan_window); + UINT8 hci_status = btsnd_hcic_ble_set_scan_params(scan_mode, (UINT16)scan_interval, + (UINT16)scan_window, + addr_type_own, + scan_filter_policy); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + ret = btm_ble_status_from_hci(hci_status); } else { p_cb->scan_type = scan_mode; p_cb->scan_interval = scan_interval; @@ -1232,8 +1234,10 @@ tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p BTM_TRACE_WARNING("%s, Partial data write into ADV", __func__); } - if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data) != HCI_SUCCESS) { - ret = BTM_ILLEGAL_VALUE; + UINT8 hci_status = btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + ret = btm_ble_status_from_hci(hci_status); btm_cb.ble_ctr_cb.inq_var.scan_rsp = FALSE; } else { ret = BTM_SUCCESS; @@ -1265,8 +1269,10 @@ tBTM_STATUS BTM_BleWriteScanRspRaw(UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_le tBTM_STATUS ret = BTM_SUCCESS; osi_mutex_lock(&btm_lock, OSI_MUTEX_MAX_TIMEOUT); - if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)raw_scan_rsp_len, p_raw_scan_rsp) != HCI_SUCCESS) { - ret = BTM_NO_RESOURCES; + UINT8 hci_status = btsnd_hcic_ble_set_scan_rsp_data((UINT8)raw_scan_rsp_len, p_raw_scan_rsp); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + ret = btm_ble_status_from_hci(hci_status); } osi_mutex_unlock(&btm_lock); @@ -1377,9 +1383,11 @@ tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p p_cb_data->data_mask &= ~mask; - if ((btsnd_hcic_ble_set_adv_data((UINT8)(p_cb_data->p_pad - p_cb_data->ad_data), - p_cb_data->ad_data)) != HCI_SUCCESS) { - ret = BTM_NO_RESOURCES; + UINT8 hci_status = btsnd_hcic_ble_set_adv_data((UINT8)(p_cb_data->p_pad - p_cb_data->ad_data), + p_cb_data->ad_data); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + ret = btm_ble_status_from_hci(hci_status); } osi_mutex_unlock(&btm_lock); return ret; @@ -1400,8 +1408,10 @@ tBTM_STATUS BTM_BleWriteAdvDataRaw(UINT8 *p_raw_adv, UINT32 raw_adv_len) { tBTM_STATUS ret = BTM_SUCCESS; osi_mutex_lock(&btm_lock, OSI_MUTEX_MAX_TIMEOUT); - if ((btsnd_hcic_ble_set_adv_data((UINT8)raw_adv_len, p_raw_adv)) != HCI_SUCCESS) { - ret = BTM_NO_RESOURCES; + UINT8 hci_status = btsnd_hcic_ble_set_adv_data((UINT8)raw_adv_len, p_raw_adv); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + ret = btm_ble_status_from_hci(hci_status); } osi_mutex_unlock(&btm_lock); @@ -2065,15 +2075,17 @@ tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode) #endif // #if (BLE_42_ADV_EN == TRUE) /* update adv params */ - if (btsnd_hcic_ble_write_adv_params (adv_int_min, + UINT8 hci_status = btsnd_hcic_ble_write_adv_params (adv_int_min, adv_int_max, evt_type, own_addr_type, init_addr_type, p_addr_ptr, p_cb->adv_chnl_map, - p_cb->afp) != HCI_SUCCESS) { - status = BTM_NO_RESOURCES; + p_cb->afp); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + status = btm_ble_status_from_hci(hci_status); } else { p_cb->evt_type = evt_type; p_cb->adv_addr_type = own_addr_type; @@ -2163,15 +2175,17 @@ tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode) btm_ble_stop_adv(); #endif // #if (BLE_42_ADV_EN == TRUE) - if (btsnd_hcic_ble_write_adv_params (adv_int_min, + UINT8 hci_status = btsnd_hcic_ble_write_adv_params (adv_int_min, adv_int_max, evt_type, own_addr_type, peer_addr_type, p_addr_ptr, p_cb->adv_chnl_map, - p_cb->afp) != HCI_SUCCESS) { - status = BTM_NO_RESOURCES; + p_cb->afp); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + status = btm_ble_status_from_hci(hci_status); } else { p_cb->evt_type = evt_type; p_cb->adv_addr_type = own_addr_type; @@ -3241,8 +3255,10 @@ tBTM_STATUS btm_ble_start_scan(void) p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE; } /* start scan, disable duplicate filtering */ - if ((btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)) != HCI_SUCCESS) { - status = BTM_NO_RESOURCES; + UINT8 hci_status = btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + status = btm_ble_status_from_hci(hci_status); } else { btm_cb.ble_ctr_cb.inq_var.state |= BTM_BLE_SCANNING; #if (BLE_TOPOLOGY_CHECK == TRUE) @@ -3312,8 +3328,10 @@ static tBTM_STATUS btm_ble_stop_discover(void) /* Clear the inquiry callback if set */ btm_cb.ble_ctr_cb.inq_var.state &= ~BTM_BLE_SCANNING; /* stop discovery now */ - if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE) != HCI_SUCCESS) { - status = BTM_NO_RESOURCES; + UINT8 hci_status = btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + status = btm_ble_status_from_hci(hci_status); } #if (BLE_TOPOLOGY_CHECK == TRUE) /* reset status */ @@ -3428,8 +3446,10 @@ tBTM_STATUS btm_ble_start_adv(void) #if (BLE_TOPOLOGY_CHECK == TRUE) btm_ble_adv_states_operation(btm_ble_set_topology_mask, p_cb->evt_type); #endif // (BLE_TOPOLOGY_CHECK == TRUE) - if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE) != HCI_SUCCESS) { - rt = BTM_NO_RESOURCES; + UINT8 hci_status = btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE); + if (hci_status != HCI_SUCCESS) { + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + rt = btm_ble_status_from_hci(hci_status); p_cb->state = temp_state; p_cb->adv_mode = adv_mode; #if (BLE_TOPOLOGY_CHECK == TRUE) @@ -3472,7 +3492,8 @@ tBTM_STATUS btm_ble_stop_adv(void) /* clear all adv states */ btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_ADV_MASK); #endif // (BLE_TOPOLOGY_CHECK == TRUE) - if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE) != HCI_SUCCESS) { + UINT8 hci_status = btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE); + if (hci_status != HCI_SUCCESS) { // reset state p_cb->fast_adv_on = temp_fast_adv_on; p_cb->adv_mode = temp_adv_mode; @@ -3481,7 +3502,8 @@ tBTM_STATUS btm_ble_stop_adv(void) #if (BLE_TOPOLOGY_CHECK == TRUE) btm_ble_set_topology_mask (temp_mask); #endif // (BLE_TOPOLOGY_CHECK == TRUE) - rt = BTM_NO_RESOURCES; + BTM_BLE_TRACE_HCI_CMD_FAIL(__func__, hci_status); + rt = btm_ble_status_from_hci(hci_status); } if(rt != HCI_SUCCESS) { p_cb->adv_mode = temp_adv_mode; diff --git a/components/bt/host/bluedroid/stack/btm/btm_devctl.c b/components/bt/host/bluedroid/stack/btm/btm_devctl.c index 9b6052f9adb..854f4778d1d 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_devctl.c @@ -1327,12 +1327,8 @@ void btm_ble_set_channels_complete (UINT8 *p) case HCI_SUCCESS: cb_params.set_channels.status = BTM_SUCCESS; break; - case HCI_ERR_UNSUPPORTED_VALUE: - case HCI_ERR_ILLEGAL_PARAMETER_FMT: - cb_params.set_channels.status = BTM_ILLEGAL_VALUE; - break; default: - cb_params.set_channels.status = BTM_ERR_PROCESSING; + cb_params.set_channels.status = BTM_HCI_ERROR | cb_params.set_channels.hci_status; break; } BTM_LegacyBleCallbackTrigger(BTM_BLE_LEGACY_GAP_SET_CHANNELS_COMPLETE_EVT, &cb_params); diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h index 398c2fec990..6057f7951f5 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h @@ -628,6 +628,14 @@ void btm_ble_cs_subevt_result_evt(tBTM_BLE_CS_SUBEVT_RESULT_CMPL_EVT *subevt_res void btm_ble_cs_subevt_continue_result_evt(tBTM_BLE_CS_SUBEVT_RESULT_CONTINUE_EVT *subevt_continue_result); #endif // (BT_BLE_FEAT_CHANNEL_SOUNDING == TRUE) +static inline tBTM_STATUS btm_ble_status_from_hci(UINT8 hci_status) +{ + return (hci_status == HCI_SUCCESS) ? BTM_SUCCESS : (tBTM_STATUS)(BTM_HCI_ERROR | hci_status); +} + +#define BTM_BLE_TRACE_HCI_CMD_FAIL(func, hci_status) \ + BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = 0x%x", (func), (hci_status)) + /* #ifdef __cplusplus From 0217c922fe1d729a73a1b35ce7178712e1393cb2 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:23:33 +0800 Subject: [PATCH 09/12] fix(ble/bluedroid): preserve ATT error on prepare write completion Skip prepare-write echo validation when the GATT stack reports a non-success status. ATT Error Response carries no prepare-write echo body (rsp_len=0), so the check incorrectly overwrote errors such as GATT_INSUF_AUTHENTICATION (0x05) with GATT_INVALID_PDU (0x04). (cherry picked from commit d5b9350d0fa2b74ea8810874163e972663d45fb2) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c index 1b17e58622a..2fcf2bdcb8e 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c @@ -1486,8 +1486,9 @@ void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_PREP_WRITE_EVT, (tBTA_GATTC *)&cb_data); return; } - /* Rsp value is one ATT chunk (<= MTU-5), not necessarily full api_write.len. */ - { + /* Rsp value is one ATT chunk (<= MTU-5), not necessarily full api_write.len. + * Only validate echo on success; ATT Error Response has no prepare-write body. */ + if (p_data->status == BTA_GATT_OK) { UINT16 rsp_len = p_data->p_cmpl->att_value.len; UINT16 req_len = p_clcb->p_q_cmd->api_write.len; tGATT_VALUE *a = &p_data->p_cmpl->att_value; From b13f63fd7ffd132dc2829dafa48af68fbc089ea8 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:16:10 +0800 Subject: [PATCH 10/12] fix(ble/bluedroid): report conn param update failure for unknown BD_ADDR Route unknown BD_ADDR and other immediate failures through the existing need_cb path so ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT is always delivered. (cherry picked from commit f9eaeb5e84c8e3f5c29d586c1321a8dfd945b84a) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/stack/l2cap/l2c_ble.c | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c index 39ce43265d7..3dfd210cc24 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c @@ -147,40 +147,42 @@ BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int, UINT16 max_in /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_LE); - /* If we don't have one, create one and accept the connection. */ if (!p_lcb || !p_acl_cb) { L2CAP_TRACE_WARNING ("L2CA_UpdateBleConnParams - unknown BD_ADDR "MACSTR"", MAC2STR(rem_bda)); - return (FALSE); - } - - if (p_lcb->transport != BT_TRANSPORT_LE) { + status = HCI_ERR_NO_CONNECTION; + need_cb = true; + } else if (p_lcb->transport != BT_TRANSPORT_LE) { L2CAP_TRACE_WARNING ("L2CA_UpdateBleConnParams - BD_ADDR "MACSTR" not LE", MAC2STR(rem_bda)); - return (FALSE); - } - - /* Check whether the request conn params is already set */ - if ((max_int == p_lcb->current_used_conn_interval) && (latency == p_lcb->current_used_conn_latency) && - (timeout == p_lcb->current_used_conn_timeout)) { - status = HCI_SUCCESS; + status = HCI_ERR_NO_CONNECTION; need_cb = true; - L2CAP_TRACE_WARNING("%s connection parameter already set", __func__); - } + } else { + /* Check whether the request conn params is already set */ + if ((max_int == p_lcb->current_used_conn_interval) && (latency == p_lcb->current_used_conn_latency) && + (timeout == p_lcb->current_used_conn_timeout)) { + status = HCI_SUCCESS; + need_cb = true; + L2CAP_TRACE_WARNING("%s connection parameter already set", __func__); + } - if (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PARAM_FULL){ - status = HCI_ERR_ILLEGAL_COMMAND; - need_cb = true; - L2CAP_TRACE_ERROR("%s connection parameter update in progress, please try later", __func__); + if (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PARAM_FULL){ + status = HCI_ERR_ILLEGAL_COMMAND; + need_cb = true; + L2CAP_TRACE_ERROR("%s connection parameter update in progress, please try later", __func__); + } } if (need_cb) { tBTM_BLE_LEGACY_GAP_CB_PARAMS cb_params = {0}; cb_params.conn_params_update.status = status; - memcpy(cb_params.conn_params_update.remote_bd_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN); + memcpy(cb_params.conn_params_update.remote_bd_addr, + p_lcb ? p_lcb->remote_bd_addr : rem_bda, BD_ADDR_LEN); cb_params.conn_params_update.min_conn_int = min_int; cb_params.conn_params_update.max_conn_int = max_int; - cb_params.conn_params_update.conn_int = p_lcb->current_used_conn_interval; - cb_params.conn_params_update.slave_latency = p_lcb->current_used_conn_latency; - cb_params.conn_params_update.supervision_tout = p_lcb->current_used_conn_timeout; + if (p_lcb) { + cb_params.conn_params_update.conn_int = p_lcb->current_used_conn_interval; + cb_params.conn_params_update.slave_latency = p_lcb->current_used_conn_latency; + cb_params.conn_params_update.supervision_tout = p_lcb->current_used_conn_timeout; + } BTM_LegacyBleCallbackTrigger(BTM_BLE_LEGACY_GAP_CONNECTION_PARAMS_UPDATE_EVT, &cb_params); From add48e6f2ccf0712651692d6be8cf41fca2ca098 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:16:09 +0800 Subject: [PATCH 11/12] fix(ble/bluedroid): add context to GATTC reg-notify cache warning Include client_if, handle, bd_addr, and server cache state in the warning logged when notification registration skips handle validation. (cherry picked from commit 1085a32be8c97193aec94a4b0dc8bd17ef32be1e) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c index 6eb81b24311..c0de44c2b44 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c @@ -951,7 +951,10 @@ tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if, return BTA_GATT_ILLEGAL_PARAMETER; } } else { - APPL_TRACE_WARNING("reg notif: cache not ready, skip check"); + APPL_TRACE_WARNING("reg notif: cache not ready, skip check, client_if=%d handle=0x%04x bd_addr:%02x:%02x:%02x:%02x:%02x:%02x state=%d", + client_if, handle, + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], + p_srcb ? p_srcb->state : 0xff); } if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) { From af02bd901832cdf53dd7426fc9864a0a699a1927 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:16:09 +0800 Subject: [PATCH 12/12] fix(ble/bluedroid): return ESP_ERR_INVALID_ARG for invalid conn params Return ESP_ERR_INVALID_ARG instead of ESP_FAIL when connection parameter validation fails (cherry picked from commit 6c53838e6661a286e32e3cb6665fa345e714080c) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/api/esp_gap_ble_api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/api/esp_gap_ble_api.c b/components/bt/host/bluedroid/api/esp_gap_ble_api.c index eca58b2515e..81a8069848b 100644 --- a/components/bt/host/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/host/bluedroid/api/esp_gap_ble_api.c @@ -154,7 +154,7 @@ esp_err_t esp_ble_gap_update_conn_params(esp_ble_conn_update_params_t *params) ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); if(!params) { LOG_ERROR("%s,params is NULL", __func__); - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } if (ESP_BLE_IS_VALID_PARAM(params->min_int, BLE_CONN_INT_MIN_HOST_CHECK, ESP_BLE_CONN_INT_MAX) && @@ -187,7 +187,7 @@ esp_err_t esp_ble_gap_update_conn_params(esp_ble_conn_update_params_t *params) } else { LOG_ERROR("%s,invalid connection params:min_int = %d, max_int = %d, latency = %d, timeout = %d",\ __func__, params->min_int, params->max_int, params->latency, params->timeout); - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } } @@ -433,7 +433,7 @@ esp_err_t esp_ble_gap_set_prefer_conn_params(esp_bd_addr_t bd_addr, } else { LOG_ERROR("%s,invalid connection params:min_int = %d, max_int = %d, latency = %d, timeout = %d",\ __func__, min_conn_int, max_conn_int, slave_latency, supervision_tout); - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } } #endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)