Skip to content

feat(ble): auto-unpair the peer on BT_SECURITY_ERR_PIN_OR_KEY_MISSING#3385

Open
akira-toriyama wants to merge 1 commit into
zmkfirmware:mainfrom
akira-toriyama:feat/ble-auto-unpair-on-key-missing
Open

feat(ble): auto-unpair the peer on BT_SECURITY_ERR_PIN_OR_KEY_MISSING#3385
akira-toriyama wants to merge 1 commit into
zmkfirmware:mainfrom
akira-toriyama:feat/ble-auto-unpair-on-key-missing

Conversation

@akira-toriyama

Copy link
Copy Markdown

What

Add CONFIG_ZMK_BLE_AUTO_UNPAIR_ON_KEY_MISSING (default n). When
enabled, the security_changed handler reacts to
BT_SECURITY_ERR_PIN_OR_KEY_MISSING by calling bt_unpair and
bt_conn_disconnect, so the next advert initiates a fresh pairing
exchange instead of looping on the same handshake failure.

Why

In a split / dongle keyboard setup, if one side's bond is wiped
(partial settings reset, NVS corruption, or reflashing one peer
without rebonding the other), every subsequent reconnect ends in
security_changed with PIN_OR_KEY_MISSING. The connection stays
up but is unusable, and the loop is not recoverable without manually
wiping bonds on both sides and going through the pairing flow again.

The existing handler logs the error and otherwise does nothing,
which means there is no firmware-side recovery path for the
asymmetric-bond case that is easy to hit on dongle setups.

How

The new branch sits inside the existing else arm of
security_changed, guarded by the Kconfig. When the peer reports
PIN_OR_KEY_MISSING, drop our half of the bond and disconnect with
BT_HCI_ERR_AUTH_FAIL. The endpoint goes back to discoverable +
unpaired, and the next advert/scan cycle re-establishes a fresh
pairing without user intervention.

Default-off so the current behaviour (surface the error, take no
action) is preserved for users who would rather notice and act
manually.

Testing

Tested in production on a dongle-based BLE split
(XIAO BLE central + two assimilator-bt peripherals). Reproduced
the loop by wiping one peripheral's bond settings while the central
retains theirs; with the option enabled, the central self-recovers
into a fresh pair on the next reconnect attempt; with the option
disabled (or this patch absent), the loop persists until both bonds
are wiped manually.

Downstream use: akira-toriyama/canon
runs this fix as an out-of-tree patch (patches/zmk/security-changed-auto-unpair.patch)
pending this upstream PR.

PR check-list

  • Branch has a clean commit history
  • Additional tests are included, if changing behaviors/core code that is testable. (no zmk-side test harness for BLE security handshakes; happy to add one if pointed at an existing pattern)
  • Proper Copyright + License headers added to applicable files
  • Pre-commit used to check formatting
  • Includes any necessary documentation changes. (no public docs page on bond recovery semantics; can add a brief mention if maintainers prefer)

Add CONFIG_ZMK_BLE_AUTO_UNPAIR_ON_KEY_MISSING (default n). When the BLE
peer rejects security elevation with BT_SECURITY_ERR_PIN_OR_KEY_MISSING
(its bond table no longer matches ours), call bt_unpair and
bt_conn_disconnect so the next advert initiates a fresh pairing
exchange.

Why
---

In a split / dongle keyboard setup, if one side's bond is wiped (e.g.
partial settings reset, NVS corruption, or one peripheral's flash
re-flashed without the other half being rebonded), every subsequent
reconnect ends in the same security_changed callback with
PIN_OR_KEY_MISSING. The connection stays up but is unusable, and the
loop is not recoverable without manually wiping bonds on both sides
and going through the pairing flow again.

What
----

The existing security_changed handler logs the error and otherwise
takes no action. When the new Kconfig is enabled, the
PIN_OR_KEY_MISSING branch additionally drops our half of the bond
(bt_unpair) and disconnects with BT_HCI_ERR_AUTH_FAIL, putting the
endpoint back into "discoverable and unpaired" state so the next
advert/scan cycle can re-establish a fresh pairing without user
intervention.

Default is `n` to preserve the current behaviour. Firmwares bitten
by the dongle/split stale-bond loop can opt in.

Signed-off-by: Akira Toriyama <noreply@anthropic.com>
@akira-toriyama akira-toriyama requested a review from a team as a code owner June 9, 2026 07:25
akira-toriyama added a commit to akira-toriyama/canon that referenced this pull request Jun 9, 2026
…#46)

両 patch を zmkfirmware/zmk へ Kconfig gate (default n) 付きで PR 済:

- security-changed-auto-unpair → zmkfirmware/zmk#3385
- usb-hid-prime-on-ready → zmkfirmware/zmk#3384

merge され次第 patches/zmk/ から畳む方針。dongle-roadmap.md と
patches/zmk/README.md の該当節を「提案準備中」から「PR 中」状態に
更新する。

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant