From 37599327e214accc849d0d007295028b0ec262ab Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Fri, 3 Jul 2026 11:07:20 +0530 Subject: [PATCH] fix(nimble): Added a change to handle unpair after add was deferred --- nimble/host/src/ble_gap.c | 48 +++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index e21ed3354..1edee4770 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -4858,6 +4858,23 @@ ble_gap_apply_deferred_pvcy_add(void) ble_gap_deferred_pvcy_add = false; ble_gap_deferred_pvcy_replace = false; + /* The bond may have been removed (ble_gap_unpair) after the add was + * deferred but before the connection finished tearing down. Do not + * resurrect a deleted bond in the controller resolving list: only apply + * the deferred add if the peer security record (with IRK) still exists. + * This also guards every other caller of this function. */ + { + struct ble_store_key_sec chk_key; + struct ble_store_value_sec chk_val; + + memset(&chk_key, 0, sizeof chk_key); + chk_key.peer_addr = addr; + if (ble_store_read_peer_sec(&chk_key, &chk_val) != 0 || + !chk_val.irk_present) { + return; + } + } + if (replace) { /* Entry is expected to be present (e.g. already loaded by * ble_hs_misc_restore_irks at startup); use replace_entry which @@ -10059,6 +10076,9 @@ ble_gap_unpair(const ble_addr_t *peer_addr) union ble_store_value value; union ble_store_key key; ble_addr_t *new_addr = (ble_addr_t *) peer_addr; +#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) && MYNEWT_VAL(BLE_HS_PVCY) && !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) + int defer_add_pending = 0; +#endif if (!ble_hs_is_enabled()) { return BLE_HS_EDISABLED; } @@ -10080,6 +10100,17 @@ ble_gap_unpair(const ble_addr_t *peer_addr) conn = ble_hs_conn_find_by_addr(peer_addr); if (conn != NULL) { +#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) && MYNEWT_VAL(BLE_HS_PVCY) && !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) + /* The peer IRK add was deferred and has not been pushed to the + * controller resolving list yet. Cancel the pending deferred add so it + * is not resurrected at disconnect, and remember that there is nothing + * to remove from the controller resolving list. */ + if (conn->bhc_deferred_pvcy_add) { + conn->bhc_deferred_pvcy_add = 0; + conn->bhc_deferred_pvcy_replace = 0; + defer_add_pending = 1; + } +#endif ble_gap_terminate_with_conn(conn, BLE_ERR_REM_USER_CONN_TERM); } @@ -10111,10 +10142,19 @@ ble_gap_unpair(const ble_addr_t *peer_addr) if (!rc) { if (value.sec.irk_present) { #if MYNEWT_VAL(BLE_HS_PVCY) - // Delete the IRK as it is Distributed - rc = ble_hs_pvcy_remove_entry(key.sec.peer_addr.type,key.sec.peer_addr.val); - if (rc != 0) { - BLE_HS_LOG(ERROR, "Error while removing IRK , rc = %x\n",rc); +#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) && !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) + /* If the peer IRK add was deferred and never applied to the + * controller resolving list, there is nothing to remove; issuing + * the HCI remove would only fail with Unknown Connection + * Identifier (0x02). Skip it in that case. */ + if (!defer_add_pending) +#endif + { + // Delete the IRK as it is Distributed + rc = ble_hs_pvcy_remove_entry(key.sec.peer_addr.type,key.sec.peer_addr.val); + if (rc != 0) { + BLE_HS_LOG(ERROR, "Error while removing IRK , rc = %x\n",rc); + } } #endif }