From 4c282bd44a6053cef8b538aa2142ba40d7a8ff23 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Wed, 29 Jul 2026 18:38:02 +0530 Subject: [PATCH] fix(nimble): Fix adding device to resolving list when defer connection --- nimble/host/src/ble_gap.c | 56 ++++++++++++++++++++++++++++++++++++- nimble/host/src/ble_store.c | 17 +++++++---- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 242fc53ca..1b0a55338 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -27,6 +27,7 @@ #include "ble_hs_priv.h" #include "ble_gap_priv.h" #include "ble_hs_resolv_priv.h" +#include "ble_sm_priv.h" #if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) #include "ble_hs_pvcy_priv.h" #include "ble_att_priv.h" @@ -1263,6 +1264,7 @@ static void ble_gap_notify_conn_event(uint16_t conn_handle, static enum ble_gap_defer_result ble_gap_defer_event(uint16_t conn_handle, const struct ble_gap_event *event, const struct ble_gap_defer_meta *meta); +static bool ble_gap_connect_delivered(uint16_t conn_handle); static void ble_gap_mark_connect_delivered(uint16_t conn_handle); static bool @@ -1382,6 +1384,9 @@ ble_gap_notify_conn_event(uint16_t conn_handle, struct ble_gap_event *event) BLE_HS_LOG(ERROR, "ble_gap_notify_conn_event: defer failed; type=%d conn=%u\n", event->type, conn_handle); + if (!ble_gap_connect_delivered(conn_handle)) { + return; + } ble_gap_event_listener_call(event); ble_gap_call_conn_event_cb(event, conn_handle); break; @@ -1562,6 +1567,20 @@ ble_gap_mark_connect_delivered(uint16_t conn_handle) ble_hs_unlock(); } +static bool +ble_gap_connect_delivered(uint16_t conn_handle) +{ + struct ble_hs_conn *conn; + bool delivered; + + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + delivered = conn != NULL && conn->bhc_connect_delivered; + ble_hs_unlock(); + + return delivered; +} + void ble_gap_conn_deferred_init(struct ble_hs_conn *conn) { @@ -10067,9 +10086,19 @@ ble_gap_rx_param_req(const struct ble_hci_ev_le_subev_rem_conn_param_req *ev) BLE_HS_LOG(ERROR, "ble_gap_rx_param_req: defer failed; conn=%u\n", conn_handle); + if (!ble_gap_connect_delivered(conn_handle)) { + rc = ble_gap_tx_param_neg_reply(conn_handle, BLE_ERR_CONN_PARMS); + if (rc != 0) { + BLE_HS_LOG(ERROR, + "ble_gap_rx_param_req: negative reply failed; " + "conn=%u rc=%d\n", + conn_handle, rc); + } + return; + } } - /* NOT_NEEDED or FAILED: fall through to the normal path. */ + /* NOT_NEEDED, or FAILED after CONNECT was delivered: normal path. */ } } #endif @@ -10836,6 +10865,16 @@ ble_gap_passkey_event(uint16_t conn_handle, BLE_HS_LOG(ERROR, "ble_gap_passkey_event: defer failed; conn=%u\n", conn_handle); + if (!ble_gap_connect_delivered(conn_handle)) { + struct ble_sm_result res; + + memset(&res, 0, sizeof res); + res.sm_err = BLE_SM_ERR_UNSPECIFIED; + res.app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_UNSPECIFIED); + res.enc_cb = 1; + ble_sm_process_result(conn_handle, &res, true); + return; + } ble_gap_event_listener_call(&event); ble_gap_call_conn_event_cb(&event, conn_handle); break; @@ -10876,6 +10915,11 @@ ble_gap_enc_event(uint16_t conn_handle, int status, BLE_HS_LOG(ERROR, "ble_gap_enc_event: defer failed; conn=%u status=%d\n", conn_handle, status); + if (!ble_gap_connect_delivered(conn_handle)) { + ble_gap_enc_side_effects(conn_handle, status, + security_restored, bonded); + return; + } break; } } @@ -11002,6 +11046,9 @@ ble_gap_pairing_complete_event(uint16_t conn_handle, int status) BLE_HS_LOG(ERROR, "ble_gap_pairing_complete_event: defer failed; conn=%u\n", conn_handle); + if (!ble_gap_connect_delivered(conn_handle)) { + return; + } ble_gap_event_listener_call(&event); ble_gap_call_conn_event_cb(&event, conn_handle); break; @@ -11039,6 +11086,9 @@ ble_gap_assoc_event(uint16_t conn_handle, int status, uint8_t cache_state) BLE_HS_LOG(ERROR, "ble_gap_assoc_event: defer failed; conn=%u\n", conn_handle); + if (!ble_gap_connect_delivered(conn_handle)) { + return; + } ble_gap_call_conn_event_cb(&event, conn_handle); break; } @@ -11115,6 +11165,10 @@ ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle, BLE_HS_LOG(ERROR, "ble_gap_notify_rx_event: defer failed; conn=%u\n", conn_handle); + if (!ble_gap_connect_delivered(conn_handle)) { + os_mbuf_free_chain(event.notify_rx.om); + return; + } } } #endif diff --git a/nimble/host/src/ble_store.c b/nimble/host/src/ble_store.c index 734e9980d..1041ca1cb 100644 --- a/nimble/host/src/ble_store.c +++ b/nimble/host/src/ble_store.c @@ -283,6 +283,9 @@ ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec) #if NIMBLE_BLE_CONNECT int rc; + int valid_peer_addr; + + valid_peer_addr = ble_addr_cmp(&value_sec->peer_addr, BLE_ADDR_ANY); #if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) && MYNEWT_VAL(BLE_HS_PVCY) struct ble_store_key_sec key_sec; struct ble_store_value_sec old_sec; @@ -303,19 +306,21 @@ ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec) return rc; } - if (ble_addr_cmp(&value_sec->peer_addr, BLE_ADDR_ANY) && + if (valid_peer_addr && value_sec->irk_present) { #if MYNEWT_VAL(BLE_HS_PVCY) #if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) - /* Do not update the controller resolving list while this peer is still - * connected. The bond is already persisted for the current link, and - * some controllers reject LE Add Device To Resolving List in this - * state even when GAP is preempted. + /* Defer the controller resolving-list update only until the CONNECT + * event has been delivered. Once the application knows about the + * connection, resolving-list setup must proceed so scanning can use + * the newly exchanged IRK while the connection remains active. */ #if !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) ble_hs_lock(); struct ble_hs_conn *conn = ble_hs_conn_find_by_addr(&value_sec->peer_addr); - if (conn != NULL) { + if (conn != NULL && !conn->bhc_connect_delivered) { + BLE_HS_LOG(INFO, "PVCY: deferring controller resolving-list add " + "until CONNECT is delivered\n"); conn->bhc_deferred_pvcy_add = 1; conn->bhc_deferred_pvcy_replace = replace_entry; conn->bhc_deferred_pvcy_addr = value_sec->peer_addr;