Skip to content

dbus backend leaves BlueZ discovery running during a connect attempt, unlike the hci backend #136

Description

@Apollon77

What differs between the backends

The hci backend stops scanning before it issues a connection and does not resume until the
attempt has settled. processConnectionQueue (lib/hci-socket/bindings.js:147-163):

if (this._isScanning) {
  this.stopScanning();
  return;
}

The dbus backend has no equivalent. _connect (lib/dbus/bindings.js:600-626) calls
iface.Connect() with discovery left running, and BlueZ resumes its own scan as soon as the
LL connection is reported complete — which is before the connection is actually usable.

From a user capture on a Raspberry Pi 5 (btsnoop, matterjs-server 1.4.0, NOBLE_BINDINGS=dbus):

40.035974  Sent LE Create Connection
40.244794  Rcvd LE Meta (LE Connection Complete)      interval 48.75 ms, supervision 420 ms
40.248855  Sent LE Set Random Address
40.249210  Sent LE Set Scan Parameters                Active, interval 11.25 ms, window 11.25 ms
40.249525  Sent LE Set Scan Enable                    ← 100% duty cycle, 5 ms into setup
40.249889  Sent LE Read Remote Features
40.584371  Rcvd LE Read Remote Features Complete      Status: 0x3e
40.584776  Rcvd Disconnect Complete                   Reason: 0x3e

No ACL packet is ever exchanged. The link dies 334 ms after Connection Complete, which is
about six connection intervals — the Link Layer connection establishment window from Core
Spec Vol 6 Part B 4.5. BlueZ pauses discovery for the connect request on its own, but
resumes it the moment the controller reports Connection Complete, because the client never
asked it to stop.

What I am not claiming

I first assumed the resumed scan was the cause of the 0x3e. It is not, or at least not on
its own: a capture from a different user on the hci backend hits the same 0x3e with
scanning explicitly disabled.

577: LE Set Scan Enable -> Scanning: Disabled (0x00)
581: LE Create Connection
599: LE Connection Complete   Status: Success (0x00)
617:                          Status: Connection Failed to be Established (0x3e)
625: LE Create Connection          ← retry, succeeds

So this peripheral intermittently fails to complete establishment regardless of scan state,
and what rescues the hci user is the retry, not the quiet radio. Resuming a 100%-duty active
scan inside the establishment window on a single-radio controller plausibly raises the
failure rate, but I have no capture isolating it, and I would rather file this as a
behavioural inconsistency between the two backends than as a diagnosed root cause.

The retry asymmetry itself is a consumer-side issue, not noble's: a failed attempt correctly
emits connect(id, err) and no disconnect on both backends, and the consumer here only
retries on disconnect. That is being fixed on the matter.js side.

Proposal

Pause BlueZ discovery for the duration of a connect attempt in the dbus backend, so both
backends serialise scanning against connecting the same way.

Three constraints I would want any patch to respect:

  1. Reference counting. The dbus backend has no connection queue, and callers do connect
    to several peripherals in parallel. Discovery should stop when the first attempt starts
    and resume only when the last one finishes, and only if it was running to begin with.
  2. Restore on every exit path. A rejected or timed-out Connect() must not leave
    discovery switched off.
  3. Do not reuse _stopScanning/_startScanning as they are. Those flip _isScanning,
    run _unwatchAllDeviceProps(), emit scanStop/scanStart and re-run
    GetManagedObjects(). Firing that around every connect would look like a full scan
    restart to consumers and re-surface every cached device — one user on this path is already
    reporting a flood of re-discovery events. The pause needs to be quiet: call BlueZ
    StopDiscovery/StartDiscovery only, leaving noble's own scan state and watchers intact.

Two adjacent levers I checked and ruled out: SetDiscoveryFilter already sets
Transport: 'le' (lib/dbus/bindings.js:302-305), so there is no BR/EDR inquiry
interleaving to remove; and scan interval and window cannot be influenced at all, since
BlueZ owns them and setScanParameters is a deliberate no-op
(lib/dbus/bindings.js:279-282).

Happy to open a PR for this if you want it — it is small, and I would keep it to the pause
plus tests. Equally happy to leave it if you would rather not add moving parts to the dbus
connect path on the strength of a correlation.

Context: matter-js/matterjs-server#929.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions