nimble/host: Evict stale resolving list entry before adding - #2282
Open
sanastasiou wants to merge 1 commit into
Open
nimble/host: Evict stale resolving list entry before adding#2282sanastasiou wants to merge 1 commit into
sanastasiou wants to merge 1 commit into
Conversation
sjanc
reviewed
Sep 8, 2026
sjanc
left a comment
Contributor
There was a problem hiding this comment.
looks ok to me, however you probably need to adjust unittests to this change
(and fix compliance check)
Some controllers reject LE Add Device To Resolving List with Invalid
HCI Command Parameters (0x12) when an entry for that peer identity
already exists. ble_hs_pvcy_add_entry() does not handle this: the error
is returned to ble_store_write_peer_sec(), which discards it ("There is
not much to do here if it fails"). The controller is then left
resolving the OLD IRK.
This is reachable whenever a peer re-pairs over an existing bond.
Peers that rotate their IRK on unpair -- Android does -- become
permanently unresolvable afterwards: the controller silently drops
their CONNECT_IND because it still holds the previous IRK, and the host
never learns why. The only recovery is a reset that rebuilds the
resolving list from the bond store. Peers with a stable IRK are
unaffected, which is why this tends to show up as "Android cannot
reconnect after re-pairing, iOS is fine".
Remove any existing entry for the identity before the add. Removing an
absent entry is harmless, so it needs no prior lookup -- and the
resolving list cannot be read back, so a lookup is not possible in the
general case anyway.
Note this calls ble_hs_pvcy_remove_entry_hci() rather than
ble_hs_pvcy_remove_entry(). The latter wraps the command in its own
ble_gap_preempt()/ble_gap_preempt_done() pair, and
ble_gap_preempt_done() is not depth counted, so using it here would end
the preemption established above before the add is issued.
Observed on an ESP32-C3 (NimBLE-Arduino, host based privacy disabled)
with rc=530 == BLE_HS_HCI_ERR(0x12) logged from the add path on every
re-pair, and fixed by this change on the same hardware.
Adjust the host unit tests for the extra LE Remove Device From
Resolving List command that now precedes every add.
sanastasiou
force-pushed
the
host-pvcy-evict-stale-rl-entry
branch
from
September 8, 2026 22:07
98347d7 to
351b3d5
Compare
Author
|
Thanks for the review. Updated: the host unit tests now expect the LE Remove Device From Resolving List that precedes every add (params verified where the add's are), and the commit body is rewrapped to 72 columns. The CodeQL startup failure is the org's allowed-actions policy rejecting |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Some controllers reject
LE Add Device To Resolving Listwith Invalid HCI Command Parameters (0x12) when an entry for that peer identity is already present.ble_hs_pvcy_add_entry()does not handle this. The error propagates toble_store_write_peer_sec(), which discards it:/* There is not much to do here if it fails */The controller is therefore left resolving the old IRK, and the host has no way to notice — the resolving list cannot be read back.
Impact
Reachable whenever a peer re-pairs over an existing bond.
Peers that rotate their IRK on unpair — Android does — become permanently unresolvable afterwards. The controller silently drops their
CONNECT_INDbecause it still holds the previous IRK. There is no error anywhere: the peer simply stops being able to reconnect. The only recovery is a reset that rebuilds the resolving list from the bond store.Peers with a stable IRK are unaffected, which is why this typically presents as "Android cannot reconnect after re-pairing, iOS is fine".
Fix
Remove any existing entry for the identity before the add. Removing an absent entry is harmless, so no prior lookup is needed — and since the resolving list is not readable, a lookup is not generally possible anyway.
Note the call is to
ble_hs_pvcy_remove_entry_hci()rather thanble_hs_pvcy_remove_entry(). The latter wraps the command in its ownble_gap_preempt()/ble_gap_preempt_done()pair, andble_gap_preempt_done()is not depth counted — using it here would end the preemption established a few lines above, before the add is issued. That preemption is required by Vol 2, Part E, 7.8.38.Testing
Observed and fixed on an ESP32-C3 (NimBLE-Arduino,
BLE_HOST_BASED_PRIVACY=0, so the resolving list lives in the controller).Before: every re-pair over an existing bond logged
rc=530(BLE_HS_HCI_ERR(0x12)) from the add path, after which the Android peer could no longer reconnect until reboot.After: the add succeeds, and repeated OS-forget + re-pair cycles reconnect normally. Verified across both an Android peer (rotating IRK) and an iOS peer (stable IRK) to confirm no regression on the previously-working path.
I do not have a multi-controller test bed, so I can only confirm the 0x12 behaviour on the ESP32-C3. The change should be a no-op on controllers that already tolerate a duplicate add.