Skip to content

Map non-transmittable disconnect reasons to a valid HCI error code - #5

Open
vkolotov wants to merge 1 commit into
sgothel:masterfrom
vkolotov:disconnect-wire-reason
Open

Map non-transmittable disconnect reasons to a valid HCI error code#5
vkolotov wants to merge 1 commit into
sgothel:masterfrom
vkolotov:disconnect-wire-reason

Conversation

@vkolotov

@vkolotov vkolotov commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

HCIHandler::disconnect() puts the given HCIStatusCode straight into the DISCONNECT command. The controller only accepts the reason codes from the spec (Core v5.2, Vol 4, Part E, 7.1.6). If the reason is one of the extended values, for example L2CAP_CLIENT_TIMEOUT or one of the MgmtStatus mappings, the controller rejects the command with INVALID_HCI_COMMAND_PARAMETERS and nothing gets disconnected. The failure branch then removes the connection tracker entry anyway, so the library thinks the link is gone while the ACL is actually still up. The peripheral stops advertising and there is no way to reach it again until the HCI channel is closed.

I hit this on an RTL8761BU in central role. An L2CAP ATT open failed with EBUSY, which triggered disconnect(L2CAP_CLIENT_TIMEOUT). In btmon you can see the command going out with reason 0xfc and the controller answering with status 0x12. The ACL stayed up and the device was stuck until I restarted the process.

The fix maps any reason that is not valid on the wire to REMOTE_USER_TERMINATED_CONNECTION. Only the wire value changes, the original reason is still used for tracking and logging.

… error code

The DISCONNECT command only accepts the reason codes listed in BT Core Spec
v5.2, Vol 4, Part E, 7.1.6. Extended HCIStatusCode values (MgmtStatus mappings
and internal codes such as L2CAP_CLIENT_TIMEOUT) sent as-is are rejected by the
controller with INVALID_HCI_COMMAND_PARAMETERS, so no disconnect is performed:
the failure branch drops the connection tracker entry while the ACL remains
established. The peripheral then stops advertising and stays unreachable until
the HCI channel is closed.

Observed live on an RTL8761BU (BT5) central: processL2CAPSetup failing with
EBUSY issued disconnect(L2CAP_CLIENT_TIMEOUT) = 0xfc on the wire, the
controller rejected it and the leaked ACL held the peripheral captive.

Keep the caller's reason for tracking and logging; only the wire value is
mapped, defaulting to REMOTE_USER_TERMINATED_CONNECTION.
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