BLE Link-Layer Connection Scheduling Policies in BitChat

BitChat's BLE transport implements a deterministic connection-scheduling system that separates radio duty-cycling from authentication logic through strict queue hierarchies and connection budgets.

The BitChat protocol (permissionlesstech/bitchat) manages Bluetooth Low Energy connectivity through a dedicated BLELinkLayer component that orchestrates all CoreBluetooth interactions. This Swift-based architecture enforces explicit BLE link-layer connection scheduling policies to prevent radio over-use, eliminate authentication race conditions, and guarantee deadlock-free operation across concurrent queues.

Core Scheduling Policies

The connection scheduler operates on three tightly-coupled rules defined in the project's BLE architecture documentation and implemented across the link-layer source files.

Duty-Cycle and Connection Budget Management

The duty-cycle and connection-budget policy controls how frequently a device may scan, advertise, and initiate connections. This prevents BLE radio over-use and ensures fair resource allocation across multiple concurrent links. According to the BitChat source code, this logic resides in BLELinkLayer.swift, where the component tracks radio usage against configured limits before permitting new connection requests.

All authentication-related state—including noiseAuthenticatedLinkOwners and peer binding maps—is deliberately moved out of the BLE queue and owned by the serial mesh engine. This design guarantees that "check-binding plus authentication to action" sequences execute atomically inside a single critical section. The BLELinkAuthState.swift and BLELinkBindings.swift files implement this separation, ensuring that binding changes cannot occur between a security check and its corresponding action, effectively eliminating time-of-check-to-time-of-use (TOCTOU) races.

Back-Pressure Buffer Management

Write and notification buffers remain confined to the BLE queue, allowing outgoing traffic throttling based on the current connection budget and the link's MTU. This back-pressure mechanism prevents buffer overflow during high-throughput mesh operations while respecting the duty-cycle constraints enforced by the radio manager.

Architectural Safety Mechanisms

Beyond the core policies, BitChat implements specific architectural patterns to prevent deadlocks and race conditions in multi-queue systems.

Binding-Free Radio Operations

Scanning, advertising, duty-cycle handling, and raw connection-budget logic execute in a binding-free radio half—decoupled from peer-specific decisions. This isolation ensures that pure radio management operates independently of higher-level mesh logic, allowing the BLEService+LinkLayerCentralRole.swift and BLEService+LinkLayerPeripheralRole.swift delegates to handle connection events without blocking on authentication checks.

Engine-Owned Authentication State

After the radio half processes events, link-authentication state transitions to the engine queue. The engine enforces atomic operations through its perform method, ensuring that authentication state changes cannot interleave with radio events. This ownership model, implemented in BLELinkAuthState.swift, moves all noiseAuthenticatedLinkOwners management out of the concurrent BLE callback context.

Strict Queue Ordering (Main → Engine → BLE)

The system guarantees a unidirectional sync-edge ordering of main → engine → bleQueue, explicitly preventing reverse-direction synchronous calls that could cause deadlocks. All connection-budget updates flow through this ordered pipeline, ensuring that budget exhaustion checks complete before the engine attempts to authorize new links.

Implementation in Source Code

The scheduling policies manifest in specific file boundaries within the repository:

  • BLELinkLayer.swift: Core implementation owning duty-cycle, connection budget, and buffer management
  • BLEService+LinkLayerCentralRole.swift: Central-role delegate handling scanning and connection events
  • BLEService+LinkLayerPeripheralRole.swift: Peripheral-role delegate managing advertising and inbound requests
  • BLELinkAuthState.swift: Engine-owned authentication state (migrated from BLE queue)
  • BLELinkBindings.swift: Peer identity mappings owned by the engine

The following Swift pattern demonstrates how the engine requests connections while respecting the scheduling budget:

// Request the BLELinkLayer to open a connection respecting the budget
linkLayer.scheduleConnection(to: peripheral,
                             withPriority: .high) { result in
    switch result {
    case .success(let linkID):
        // Connection established – engine will now handle packets for this link
        engine.handleLinkEvent(.connected(linkID))
    case .failure(let error):
        // Budget exhausted or duty‑cycle limits hit
        logger.warn("BLE connect failed: \(error)")
    }
}

Authentication checks execute atomically within the engine queue to prevent TOCTOU vulnerabilities:

// The engine‑owned auth check – runs atomically inside the engine queue
engine.perform { ctx in
    guard ctx.linkAuth.isAuthorized(linkID, for: peer) else { return }
    ctx.linkAuth.grant(linkID, to: peer)
}

Summary

  • Connection budgets in BitChat prevent BLE radio over-use by limiting scan, advertise, and connection operations through the BLELinkLayer.
  • Authentication isolation moves all binding and authorization state to the engine queue, eliminating TOCTOU races by ensuring atomic check-then-act sequences.
  • Queue ordering strictly follows main → engine → bleQueue to prevent deadlocks, with radio operations completing before security checks begin.
  • Back-pressure buffers confined to the BLE queue throttle outgoing traffic according to MTU and budget constraints.

Frequently Asked Questions

How does BitChat prevent BLE radio resource exhaustion?

BitChat implements a duty-cycle and connection-budget policy in BLELinkLayer.swift that tracks radio usage across scanning, advertising, and active connections. The scheduleConnection API checks these budgets before initiating CoreBluetooth operations, returning failures immediately when limits are reached rather than queueing unlimited requests.

What mechanism prevents authentication race conditions in BLE connections?

All authentication state—including peer bindings and noiseAuthenticatedLinkOwners—is owned by the serial mesh engine rather than the concurrent BLE queue. By moving BLELinkAuthState.swift and BLELinkBindings.swift to the engine context, BitChat ensures that authorization checks and subsequent actions execute atomically within the engine's perform blocks, preventing time-of-check-to-time-of-use (TOCTOU) vulnerabilities.

Why does BitChat use a unidirectional queue hierarchy?

The main → engine → bleQueue ordering prevents circular dependencies that could cause deadlocks. Radio events flow upward through delegates, while connection requests flow downward through explicit scheduling APIs. This design ensures that the BLE queue never holds locks while synchronously calling into the engine, and budget updates propagate through a controlled pipeline.

Where are connection scheduling policies documented in the source?

The primary architectural documentation resides in docs/BLE-ARCHITECTURE-V3.md, while the concrete implementation spans BLELinkLayer.swift for budget management, BLEService+LinkLayerCentral/PeripheralRole.swift for radio delegates, and BLELinkAuthState.swift for security state isolation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →