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.
Link-Authentication Boundaries
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 managementBLEService+LinkLayerCentralRole.swift: Central-role delegate handling scanning and connection eventsBLEService+LinkLayerPeripheralRole.swift: Peripheral-role delegate managing advertising and inbound requestsBLELinkAuthState.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 → bleQueueto 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →