Bugfix - Keep HCI Number Of Completed Packets enabled in the host event mask#946
Merged
barbibulle merged 2 commits intoJun 27, 2026
Merged
Conversation
`Device.power_on()` resets the host and explicitly sends `HCI_Set_Event_Mask`. That explicit mask omitted `HCI_NUMBER_OF_COMPLETED_PACKETS_EVENT`, even though the controller default mask enables it. That disables `HCI_Number_Of_Completed_Packets` events, which are the only path that returns ACL transmit credits to Bumble's data queue: - The event-mask list is in `bumble/host.py:401`-`bumble/host.py:421`. - LE buffer sizing reads `HCI_LE_Read_Buffer_Size[_V2]` and stores `total_num_le_acl_data_packets` in the queue limit at `bumble/host.py:552`- `bumble/host.py:590`. - `DataPacketQueue` sends only while `_in_flight < max_in_flight` at `bumble/host.py:140`-`bumble/host.py:147`. - Completed-packets credits are consumed by `on_hci_number_of_completed_packets_event()` at `bumble/host.py:1169`- `bumble/host.py:1175`, which calls `DataPacketQueue.on_packets_completed()`. - `DataPacketQueue.on_packets_completed()` decrements `_in_flight` and drains queued packets at `bumble/host.py:149`-`bumble/host.py:180`. With `HCI_NUMBER_OF_COMPLETED_PACKETS_EVENT` masked off, `_in_flight` reaches `max_in_flight` and never decreases, so later ACL packets enqueue indefinitely.
barbibulle
approved these changes
Jun 27, 2026
barbibulle
left a comment
Collaborator
There was a problem hiding this comment.
Thanks for the detailed analysis and fix.
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.
Summary
On controllers with a small LE ACL transmit buffer, Bumble can silently stop sending host-to-controller ACL data after the first controller-credit window is used. We reproduced this with an nRF52840 running Zephyr
hci_usb, which reportedtotal_num_le_acl_data_packets=3: the first writes reached the controller, then later ATT/L2CAP data stayed queued in Bumble and never reached HCI. No error is raised.To reproduce: Use a controller that reports a small LE ACL buffer, such as Zephyr
hci_usbon nRF52840 withtotal_num_le_acl_data_packets=3. Power on Bumble and perform a workflow that sends more than three outbound LE ACL packets. Without this fix, the first three packets leave Bumble, later packets remain queued forever, and no Python exception is raised. With this fix, completed-packets events restore credits and queued ACL data continues flowing.Root Cause
Device.power_on()resets the host and explicitly sendsHCI_Set_Event_Mask. That explicit mask omittedHCI_NUMBER_OF_COMPLETED_PACKETS_EVENT, even though the controller default mask enables it. That disablesHCI_Number_Of_Completed_Packetsevents, which are the only path that returns ACL transmit credits to Bumble's data queue:bumble/host.py:401-bumble/host.py:421.HCI_LE_Read_Buffer_Size[_V2]and storestotal_num_le_acl_data_packetsin the queue limit atbumble/host.py:552-bumble/host.py:590.DataPacketQueuesends only while_in_flight < max_in_flightatbumble/host.py:140-bumble/host.py:147.on_hci_number_of_completed_packets_event()atbumble/host.py:1169-bumble/host.py:1175, which callsDataPacketQueue.on_packets_completed().DataPacketQueue.on_packets_completed()decrements_in_flightand drains queued packets atbumble/host.py:149-bumble/host.py:180.With
HCI_NUMBER_OF_COMPLETED_PACKETS_EVENTmasked off,_in_flightreachesmax_in_flightand never decreases, so later ACL packets enqueue indefinitely.