Skip to content

firmware: a Computer pairing again keeps its new keys after a restart (#155) - #157

Open
Skeyelab wants to merge 2 commits into
mainfrom
ble-persist-rebond
Open

Skeyelab wants to merge 2 commits into
mainfrom
ble-persist-rebond

Conversation

@Skeyelab

@Skeyelab Skeyelab commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Fixes #155.

Cause (agent2 traced it in the source; confirmed on black2): NimBLE's NVS store (ble_store_config_persist_*_secs) only writes when the number of bonds changes. When a Computer pairs again while the panel still has a bond for the same identity, ble_store_config_write_*_sec overwrites the record in RAM, the count stays the same, and NVS keeps the old keys. After a restart those come back. In the test, the old record was black2's earlier privacy-off bond, with irk_present=0. So there was no resolving-list entry, the RPA wasn't resolved (diag: id == ota on every connect), the LTK lookup missed, and every connect ended in Authentication Failure.

Fix: in ReplaceOthers, persistBond() reads the Computer's our_sec and peer_sec from RAM, deletes them, and writes them back. The count drops and then grows, so both reach NVS, and the peer write re-adds the IRK to the resolving list. Only the key records are rewritten. ble_store_util_delete_peer would also delete the Computer's stored subscriptions. Before the peer record is rewritten, advertising stops and the Computer's resolving-list entry is removed (ble_hs_pvcy_remove_entry). The controller already holds that entry, from the pairing or from boot with the old IRK, and would refuse a second one, which would fail every pairing that sends an IRK. The rewrite then re-adds it with the new IRK. Each record is rewritten in turn. The peer record is judged by reading it back, because a resolving-list error is returned after the record is saved; that error is logged. If the rewrite fails, the pairing is rejected, as for a refused write.

Evidence on black2 (privacy on, RPAs), with diag builds of main:

  • Stale bond present: after a restart, peer_sec irk_present=0; connects arrive unresolved; Authentication Failure loop.
  • All bonds wiped, then one fresh pairing (count grows): after a restart, irk_present=1; the connect resolves (ota = RPA, id = identity); it reconnects and stays connected.

Tests: pio test -e native passes 69/69 and pio run -e crowpanel builds. There's no native test because the fix is entirely in NimBLE's store, which the native env doesn't have. The hardware check, through the panel-owner rule: pair black2 (privacy on) on a panel that already has a bond for it, restart, and it reconnects. Also check the log for a resolving-list rc.

Who it affects: a Computer pairing again while an old bond for it still exists, for example a Mac re-pairing. A first pairing on a clean panel was fine.

No auto-merge until the firmware and AppSec reviews pass and the hardware check is done. #153 will merge main once this lands.

…#155)

NimBLE's NVS store saves a bond only when the number of bonds changes.
A pairing that replaced an existing bond for the same identity updated
RAM only; after a restart the old keys came back, often without the new
IRK, so a Computer on private addresses was never resolved and couldn't
reconnect. When a pairing replaces the Computer, its keys are now deleted
and written again, which makes both reach NVS. Subscriptions are kept.

Assisted-by: Claude Code:claude-opus-5-5
- Remove the Computer's resolving-list entry before rewriting its peer
  keys: the controller already holds it (from the pairing, or from boot
  with the old IRK) and would refuse the re-add, failing every pairing
  that sends an IRK. Advertising is stopped first, as HCI requires.
- Rewrite each record in turn, and judge the peer record by reading it
  back, since a resolving-list error is returned after it's saved.

Assisted-by: Claude Code:claude-opus-5-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Panel: a Computer with a private Bluetooth address can't reconnect after the panel restarts

1 participant