Skip to content

Fix several independent BLE bugs, split from #11178 - #11225

Open
dhalbert wants to merge 7 commits into
adafruit:mainfrom
dhalbert:ble-small-fixes
Open

Fix several independent BLE bugs, split from #11178#11225
dhalbert wants to merge 7 commits into
adafruit:mainfrom
dhalbert:ble-small-fixes

Conversation

@dhalbert

@dhalbert dhalbert commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Claude found these bugs in the course of working on #11178.

  • Incorrect _incoming buffer size passed to _common_hal_bleio_characteristic_buffer_construct().
  • Incorrect disconnect wait loop in bleio_adapter_reset() (nordic, espressif, silabs): while loop never ran because initial condition was false, so explicit disconnect didn't happen. The central saw a supervision timeout instead of a clean disconnect. Changed to do-while.
  • Heap event handler cleanup loop didn't iterate over linked list properly (nordic ble_drv.c, espressif ble_events.c): only the first entry was removed.
  • common_hal_bleio_packet_buffer_deinited() could never return true (nordic, silabs, ble_hci): deinit() did not clear self->characteristic, so the guards in supervisor/shared/bluetooth/serial.c never took effect.
  • Nordic packet_buffer_deinit() removed the wrong event handler: it always removed the client-event handler, leaving a server packet buffer's handler registered and pointing at a freed buffer.
  • Resolvable private address rotated too fast (nordic): with an unlimited advertising timeout, private_addr_cycle_s = timeout + 1 was only one second. Changed to use the SoftDevice default of 15 minutes.
  • Do more thorough cleanup on connection-slot reuse (nordic): before, a reused slot kept the previous peer's bonding keys, ediv, and pending bond-save flags, which could mix one peer's IRK with another's LTK or save bond data under the wrong ediv.

First of the series of small PRs replacing #11178, as discussed there. These are the independent bug fixes; the reset-logic and advertising-behavior changes will follow in separate PRs.

Tested on Nordic and Espressif. This does not fix the primary bug that #11178 started to address. That will come later in a further PR.

@tannewt We can look for these issues in the zephyr BLE port, since it took inspiration from the other ports.

dhalbert and others added 7 commits August 20, 2026 22:07
`_incoming` is `uint32_t[64]`, so `sizeof(_incoming)` is already 256 bytes.
Multiplying by `sizeof(uint32_t)` told the ring buffer it had 1024, letting it
write past the array.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
any_connected was initialized to false, so the wait loop never ran and the
stack was torn down before the disconnect went out. The central then saw a
supervision timeout instead of a clean disconnect. Same copied bug in
nordic, espressif, and silabs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ble_drv_remove_event_handler() clears the removed entry's next pointer, so
iterating via it->next after removal ended the walk at the first heap
handler, leaving the rest pointing into a heap about to be freed. Capture
next first. Also remove entries that themselves live on the heap, not just
those with a heap param. Same copied bug in nordic ble_drv.c and espressif
ble_events.c.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
common_hal_bleio_packet_buffer_deinit() left self->characteristic set, so
deinited() -- which tests it against NULL -- never reported the buffer as
deinited, and guards like the ones in supervisor/shared/bluetooth/serial.c
never took effect. Same copied bug in nordic, silabs, and ble_hci.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Registration chooses packet_buffer_on_ble_client_evt or
packet_buffer_on_ble_server_evt by self->client, but deinit always removed
the client handler, leaving a server packet buffer's handler registered and
pointing at a freed buffer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
For unlimited advertising (timeout 0), private_addr_cycle_s = timeout + 1
rotated the address every second -- too fast for a central to resolve an
address and connect to it before it changed. Use 0, which selects the
SoftDevice default cycle of 15 minutes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On BLE_GAP_EVT_CONNECTED, a recycled slot kept the previous peer's
bonding keys, ediv, and pending bond-save flags. The SoftDevice fills in
only the keys the new peer distributes, so the leftovers could mix one
peer's IRK with another's LTK in a stored bond, or save this connection's
bond data under the previous peer's ediv.

Co-Authored-By: Claude Fable 5 <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