# BLE Link-Layer Connection Scheduling Policies in BitChat

> Explore BitChat's BLE link layer connection scheduling policies. Discover its deterministic system separating radio duty-cycling from authentication logic via strict queue hierarchies and budgets.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: internals
- Published: 2026-08-02

---

**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](https://github.com/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`](https://github.com/permissionlesstech/bitchat/blob/main/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`](https://github.com/permissionlesstech/bitchat/blob/main/BLELinkAuthState.swift) and [`BLELinkBindings.swift`](https://github.com/permissionlesstech/bitchat/blob/main/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`](https://github.com/permissionlesstech/bitchat/blob/main/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`](https://github.com/permissionlesstech/bitchat/blob/main/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`](https://github.com/permissionlesstech/bitchat/blob/main/BLELinkAuthState.swift): Engine-owned authentication state (migrated from BLE queue)
- [`BLELinkBindings.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLELinkBindings.swift): Peer identity mappings owned by the engine

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

```swift
// 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:

```swift
// 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`](https://github.com/permissionlesstech/bitchat/blob/main/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`](https://github.com/permissionlesstech/bitchat/blob/main/BLELinkAuthState.swift) and [`BLELinkBindings.swift`](https://github.com/permissionlesstech/bitchat/blob/main/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`](https://github.com/permissionlesstech/bitchat/blob/main/docs/BLE-ARCHITECTURE-V3.md), while the concrete implementation spans [`BLELinkLayer.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLELinkLayer.swift) for budget management, `BLEService+LinkLayerCentral`/[`PeripheralRole.swift`](https://github.com/permissionlesstech/bitchat/blob/main/PeripheralRole.swift) for radio delegates, and [`BLELinkAuthState.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLELinkAuthState.swift) for security state isolation.