From 84d3c00b6312093b203e11e62112b7ad799e9474 Mon Sep 17 00:00:00 2001 From: tony weston Date: Tue, 10 Nov 2026 22:44:43 +0000 Subject: [PATCH] [Bugfix] Client: don't drop passkey requests that arrive before the connect event The host reports BLE_GAP_EVENT_CONNECT only after the LE Read Remote Features procedure completes, but it already processes SMP on the link before that. NimBLEClient ignores every event whose conn_handle differs from m_connHandle, and m_connHandle is only set when the connect event arrives. So when a peripheral sends a Security Request right after connecting, the host starts pairing at once (as the spec requires). If the peer's Pairing Response lands before the remote features read finishes, the resulting BLE_GAP_EVENT_PASSKEY_ACTION is dropped: onPassKeyEntry() is never called, no passkey is injected, and the peer times out after 30s (disconnect reason 0x205). Seen with an oven using an old BLE module (50 ms connection interval): sending the Pairing Request pushes the features read back one interval, so CONNECT arrives at +100.3 ms and the Pairing Response at +99.7 ms, and pairing failed 4 out of 4 times. With this change, 6 out of 6 attempts got a passkey request, and a full passkey pairing and bond completed. The GAP callback is registered per connection attempt, so while the client is CONNECTING with no handle yet, a passkey event can only be for the connection it is creating. Accept it in that state. Fixes #1182 Co-Authored-By: Claude Opus 5.5 --- src/NimBLEClient.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index 98d045e6..8bf7e58f 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -1345,7 +1345,12 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) { } // BLE_GAP_EVENT_MTU case BLE_GAP_EVENT_PASSKEY_ACTION: { - if (pClient->m_connHandle != event->passkey.conn_handle) { + // The host reports BLE_GAP_EVENT_CONNECT only after reading the peer's features, but + // already runs SMP on the link. A peer that sends a Security Request right after + // connecting can therefore trigger this before m_connHandle is set. This callback is + // registered only for the connection this client is creating, so accept it. + if (pClient->m_connHandle != event->passkey.conn_handle && + !(pClient->m_connStatus == CONNECTING && pClient->m_connHandle == BLE_HS_CONN_HANDLE_NONE)) { return 0; }