Skip to content

fix(flipper): refuse Reconnect over BLE instead of tearing down the live link#164

Merged
xunholy merged 1 commit into
mainfrom
fix/ble-reconnect-refuse
Jun 29, 2026
Merged

fix(flipper): refuse Reconnect over BLE instead of tearing down the live link#164
xunholy merged 1 commit into
mainfrom
fix/ble-reconnect-refuse

Conversation

@xunholy

@xunholy xunholy commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

A MEDIUM-HIGH correctness bug: Flipper.Reconnect (driven by the /reconnect slash command and POST /api/reconnect) guarded only bridgeMode, not the BLE transport. On a BLE-connected Flipper it ran reconnectIfNeededLocked, which:

  1. calls transport.Reconnect — the BLE transport tears down and re-establishes the peripheral, then
  2. calls handshake — which writes \x03\r and waits for the text "> " CLI prompt. BLE exposes only Protobuf RPC, never a text CLI (rpcMode is permanently latched), so the handshake never sees a prompt, times out, and the loop retries transport.Reconnect — tearing the working link down again — until connectTimeout, then returns "reconnect timed out".

Net effect: /reconnect (or /api/reconnect) on a BLE Flipper repeatedly bounced a healthy connection and reported failure, leaving bleClient session state out of sync — a recovery command actively breaking a working session.

Fix

Flipper.Reconnect now short-circuits IsBLE() (under f.mu, before touching the transport) with usbOnlyError("reconnect") — a clear, actionable error wrapping ErrCommandRequiresUSB, consistent with how other CLI-only commands respond on BLE. The live link is left untouched.

A BLE-aware recovery (re-open peripheral + RPC client, skip the CLI handshake + identity check) and BLE drop auto-detection are larger, BLE-hardware-dependent follow-ups, noted for a steered session.

Found via the internal audit sweep.

Verification

  • TestReconnect_BLE_RefusesWithoutTearingDownLink: a fake BLE transport records whether Reconnect/Close were invoked; asserts the call is refused (errors.Is ErrCommandRequiresUSB) without calling transport.Reconnect. Proven to FAIL on the pre-fix code (transport.Reconnect called; handshake hit the ctx deadline).
  • task ci green (lint 0 / vet / build / test:full 0 fail / govulncheck clean); task eval 17/17.

Bug fix — anchors v0.782.0.

…ive link

Flipper.Reconnect (driven by the /reconnect slash command and POST
/api/reconnect) guarded only bridgeMode, not the BLE transport. On a
BLE-connected Flipper it ran reconnectIfNeededLocked, which:
  1. calls transport.Reconnect — the BLE transport tears down and
     re-establishes the peripheral, then
  2. calls handshake — which writes \x03\r and waits for the text "> " CLI
     prompt. BLE exposes only Protobuf RPC, never a text CLI (rpcMode is
     permanently latched), so the handshake never sees a prompt, times out, and
     the loop retries transport.Reconnect — tearing the working link down again
     — until connectTimeout, then returns "reconnect timed out".

Net effect: /reconnect (or /api/reconnect) on a BLE Flipper repeatedly bounced
a healthy connection and reported failure, leaving bleClient session state out
of sync with the freshly re-established transport beneath it. A recovery
command actively broke a working session.

Fix: Flipper.Reconnect now short-circuits IsBLE() (under f.mu, before touching
the transport) with usbOnlyError("reconnect") — a clear, actionable error that
wraps ErrCommandRequiresUSB, consistent with how other CLI-only commands
respond on BLE. The live link is left untouched.

A BLE-aware recovery (re-open the peripheral + RPC client, skipping the CLI
handshake and the device_info identity check) plus BLE drop auto-detection are
larger, BLE-hardware-dependent follow-ups, noted for a steered session.

Found via the internal audit sweep.

Test: TestReconnect_BLE_RefusesWithoutTearingDownLink uses a fake BLE transport
that records whether Reconnect/Close were invoked and asserts the call is
refused (errors.Is ErrCommandRequiresUSB) WITHOUT calling transport.Reconnect.
Proven to FAIL on the pre-fix code (transport.Reconnect called; handshake hit
the ctx deadline).

Verified: task ci green (lint 0 / vet / build / test:full 0 fail / govulncheck
clean); task eval 17/17.
@xunholy xunholy merged commit 23a72f7 into main Jun 29, 2026
5 of 6 checks passed
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