Bluetooth HCI UART Framing: Recover Parser Alignment After a Corrupted Transport Byte

After a byte disappears from an HCI UART stream, recognizing a plausible packet-type byte does not prove that framing has recovered. Choose the recovery mechanism from the actual transport contract, and distinguish locating a packet boundary from proving that its payload is intact.

Applicability: Bluetooth Core 6.1 UART transport, commonly called H4, and Three-wire UART transport, commonly called H5, with Linux v6.12 parser evidence. Electrical UART diagnosis and full controller-state restoration are separate tasks. Byte examples and fault experiments below are proposed fixtures, not executed parser or hardware tests.

An H4 dropped byte consumes the next indicator as payload, while H5 escapes delimiter bytes and applies separate admission checks; optional CRC support must be verified.
Original hypothetical framing diagram. No parser replay, UART corruption or hardware recovery test was executed; the Linux CRC limitation is source inspection.

1. Establish the transport mode at both endpoints

Record controller model, firmware, host driver, transport mode, baud-rate setup and initialization sequence. An H4 peer cannot interpret H5 framing merely because the host changed its parser. Any migration needs compatible support and configuration at both ends.

Core’s UART transport assumes communication without line errors. It prefixes HCI packets with a type indicator and uses each packet’s length field to determine the next boundary. It does not add a separate transport checksum or delimiter around the payload.

RTS/CTS protects against temporary UART-buffer overrun under its hardware timing contract. It is separate from HCI command and data flow control, and does not create a packet-integrity check.

Keep driver error evidence beside the byte capture. A missing byte can result from several stages, but this article’s question is what the parser can safely conclude once its input is corrupted.

2. Demonstrate why H4 byte scanning is ambiguous

Consider the hypothetical controller-to-host frame 04 FF 03 AA BB CC. Here 04 identifies an HCI Event, FF is a vendor-specific event code and 03 declares three parameter octets. AA BB CC are synthetic parameter bytes.

If BB is removed and the next frame begins with 04, a length-driven parser can consume AA CC 04 as the first event’s three parameters. The second frame’s type indicator has become apparent payload. A later error does not recover the missing boundary retrospectively.

Conversely, 04 can legitimately occur inside a payload. Searching for every 04 and declaring it a new event can split valid data. A plausible type and in-range length are necessary parser checks, not an integrity proof.

The Linux v6.12 H4 helper returns -EILSEQ for an unrecognized packet type and -EMSGSIZE when the declared data exceeds the allocated packet capacity. The caller logs reassembly failure and clears its partial buffer. Those branches do not themselves prove that the next input chunk starts at a true packet boundary.

3. Use H4’s specified reset synchronization procedure

Core Part A section 4 defines recovery when an incorrect indicator or out-of-range length exposes synchronization loss. For host-to-controller loss, the controller reports Hardware Error and expects HCI Reset, using that command to resynchronize its input.

For controller-to-host loss, the host sends HCI Reset and looks for the corresponding Reset Command Complete in the returning byte stream. This is a specific UART transport recovery procedure, not a generic rule that any successful HCI command resets every transport.

Invoke the owning stack’s supported recovery path. Do not inject a raw reset behind a live host or invent an application-level scan for likely event bytes. Coordinate parser retirement, pending command outcomes and the restart boundary with that owner.

After framing is trustworthy, controller configuration and volatile host objects still need their proper recovery. Keep the framing milestone distinct from the later milestone at which product roles are usable again.

4. Inspect what three-wire framing adds

Core Part D wraps packets in SLIP delimiters. It uses 0xC0 at packet boundaries, replaces an internal 0xC0 with DB DC and replaces an internal 0xDB with DB DD. This escaping lets the receiver search for a boundary without confusing ordinary payload values with delimiters.

For a SLIP-only fragment fixture, raw bytes C0 DB become DB DC DB DD inside the framed packet. This fragment is not a complete H5 packet; a complete packet also needs its four-byte header and any selected integrity field.

The header includes payload length, packet type, reliable sequence/acknowledgment information and an eight-bit header checksum. With no optional integrity field, the decoded packet length is four plus payload length; with the two-byte integrity field, it is six plus payload length.

Header checksum, decoded length, sequence acceptance and optional payload integrity are different checks. Reliable sequence numbers advance modulo eight and retransmission retains the same number. A transport acknowledgment concerns transport delivery, not completion of the remote application operation.

5. Do not assume that “H5” guarantees CRC protection

The three-wire 16-bit Data Integrity Check is optional and negotiated. When used, the specification requires checking it and discarding a mismatch. When it is not used, a payload corruption that preserves framing, length and header can escape those checks.

The exact Linux v6.12 implementation is an important limit. Its transmit construction does not set the CRC-present bit or append a computed CRC. Its h5_rx_crc function completes the packet after receiving the indicated bytes; that function does not calculate and compare the CRC.

Therefore this source is not evidence that a CRC-protected mode is available and verified. Inspect the negotiated configuration and shipping driver before making that requirement a product claim. A function named “crc” is insufficient evidence of integrity validation.

The same source does provide concrete framing checks: invalid escapes, a delimiter arriving before the expected bytes, bad header checksum and out-of-order reliable sequence handling lead to defined receive-state actions. Its reset helper returns the receiver to delimiter search.

6. Build a corrupted-byte test matrix

Proposed mutation Evidence to require
Remove BB from the H4 example Show boundary corruption and the supported reset synchronization path
Put 04 inside valid H4 payload No false packet split while length framing is intact
Change H5 escape DB DC to DB 00 Invalid-escape handling and return to delimiter search
Insert an early H5 C0 Partial-packet rejection before later valid traffic is admitted
Flip one header bit without fixing checksum Header rejection, not delivery as a valid HCI packet
Change payload with length/header intact Separate no-CRC behavior from a genuinely supported CRC-checked mode

Split each test stream at several receive-call boundaries, including between escape bytes and inside headers. UART read chunking is not packet framing. Retain parser state transitions, discarded-byte counts, accepted packets and recovery completion evidence.

Use an isolated replay harness first, then authorized hardware qualification. A replay test cannot establish physical line robustness or a controller’s recovery behavior. Acceptance requires a supported transport pair, explicit integrity limits and a reproducible path back to trustworthy framing without silently promoting corrupted bytes into valid events.

Similar Posts