# How BitChat Handles BLE Mesh Packet Fragmentation: A Complete Technical Guide

> Discover how BitChat manages BLE mesh packet fragmentation. Learn about its structured chunking, transmission scheduling, and reassembly for reliable data transfer.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: deep-dive
- Published: 2026-08-22

---

**TLDR:** BitChat’s BLE mesh implementation automatically fragments packets exceeding the BLE MTU into structured chunks using `BLEFragmentHeader`, schedules transmission via `BLEOutboundFragmentTransferScheduler`, and reassembles them on the receiving side using `BLEFragmentAssemblyBuffer`.

BitChat is an open-source decentralized messaging platform built on a Bluetooth Low Energy (BLE) mesh network architecture. When transmitting payloads larger than the BLE MTU (approximately 512 bytes), the protocol must fragment data into smaller units and reliably reconstruct them at the destination. This article analyzes the fragmentation pipeline implemented in the `permissionlesstech/bitchat` repository, covering packet detection, header formatting, transmission scheduling, and reassembly logic.

## Detecting Oversized Packets with BLEOutboundPacketPolicy

Before fragmentation occurs, the `BLEOutboundPacketPolicy` inspects each packet prepared for BLE transmission. If the payload size exceeds the negotiated MTU, the policy marks the packet with `MessageType.fragment`, triggering the fragmentation workflow. This detection happens early in the outbound pipeline to ensure large payloads never attempt transmission as single units.

## Fragment Planning and Version Selection

Once flagged for fragmentation, the `BLEOutboundFragmentPlanner` examines the destination and link capabilities to determine the appropriate fragment format. BitChat supports two fragment versions:

- **Version 1:** A simple fragment format for basic payload chunking.
- **Version 2:** An advanced format incorporating route-aware chunking that respects specific link bandwidth limits and routing information.

The planner slices the payload into chunks that fit the negotiated fragment chunk size, typically ≤64 bytes for the smallest BLE link, ensuring compatibility across diverse device capabilities.

## The BLEFragmentHeader Structure

Each fragment carries a `BLEFragmentHeader` defined in [`localPackages/BitFoundation/Sources/BitFoundation/BLEFragmentHeader.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/BLEFragmentHeader.swift). This header contains:

- **Fragment ID:** An 8-byte identifier linking fragments to the original packet.
- **Sequence Number:** The position of this fragment within the sequence.
- **Total Fragment Count:** The total number of fragments in the complete packet.
- **Optional Routing Info:** Present in version 2 fragments to enable route-aware transmission.

This metadata enables the receiving side to correctly order fragments and detect when a packet is complete.

## Fragment Transmission Pipeline

### Scheduling with BLEOutboundFragmentTransferScheduler

The `BLEOutboundFragmentTransferScheduler` manages transmission slots for different fragment types. For file-type fragments, the scheduler reserves dedicated transfer slots to prevent flooding the network with large data transfers. Simple data fragments bypass the slot manager and transmit immediately, prioritizing latency-sensitive messages over bulk transfers.

### Buffered Writing via BLEOutboundWriteBuffer

Located in [`bitcat/Services/BLEOutboundWriteBuffer.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitcat/Services/BLEOutboundWriteBuffer.swift), the write buffer dequeues fragments in sequence and applies pacing algorithms before writing to the BLE peripheral. The buffer supports both direct and route-aware pacing strategies, ensuring fragments arrive at the destination without overwhelming the link layer.

## Receiving and Reassembling Fragments

### Processing Incoming Fragments with BLEFragmentHandler

On the receiving device, `BLEFragmentHandler` inspects incoming packets for the `fragment` type. When detected, the handler extracts the `BLEFragmentHeader` and forwards the fragment payload to the assembly buffer. This component acts as the entry point for the reassembly pipeline.

### Assembly Management in BLEFragmentAssemblyBuffer

The `BLEFragmentAssemblyBuffer` stores incoming fragments in a keyed structure using the 8-byte Fragment ID. It tracks received sequence numbers to detect duplicates, which are ignored to prevent data corruption. When the buffer receives a fragment whose sequence number matches the total count specified in the header, it concatenates all chunks to recreate the original payload.

If fragments remain incomplete for an extended period or a newer packet arrives with the same Fragment ID, the buffer evicts the stale assembly, freeing memory and allowing fresh reassembly attempts. Private media transfers impose a hard cap of 256 fragments; attempts to exceed this limit are rejected early in the planning phase.

## Edge Cases and Resilience

BitChat’s fragmentation layer handles several edge cases to maintain mesh stability:

- **Duplicate Detection:** The assembly buffer tracks sequence numbers to filter redundant fragments without aborting reassembly.
- **Stale Fragment Eviction:** Incomplete assemblies time out or clear when superseded by newer packets, preventing memory exhaustion.
- **Version Negotiation:** The planner automatically falls back to version 1 fragments when communicating with older peers that lack version 2 support.
- **Size Limitations:** Media transfers are capped at 256 fragments to balance reliability with resource constraints.

## Implementation Example

The following Swift code demonstrates the complete fragmentation workflow, from creating an oversized packet to reassembly:

```swift
// 1. Build a packet that exceeds BLE MTU
let largeData = Data(count: 2000)  // Larger than typical 512-byte MTU
let packet = BitchatPacket(
    recipientID: nil,
    type: .message,
    payload: largeData
)

// 2. Plan fragments respecting the smallest link MTU
let planner = BLEOutboundFragmentPlanner(
    packet: packet,
    linkLimit: .smallest
)
let fragments = try planner.fragmentPackets  // Returns [BLEPacket]

// 3. Enqueue for transmission with pacing
let writeBuffer = BLEOutboundWriteBuffer()
writeBuffer.enqueue(fragments)

// 4. On receiver side, process and reassemble
let handler = BLEFragmentHandler()
handler.process(incomingPacket) { reassembledPayload in
    // Original 2000-byte Data restored
    handleMessage(payload: reassembledPayload)
}

```

## Summary

- **Automatic Detection:** `BLEOutboundPacketPolicy` identifies packets exceeding MTU and marks them for fragmentation.
- **Structured Headers:** `BLEFragmentHeader` carries 8-byte IDs, sequence numbers, and routing metadata for each chunk.
- **Smart Planning:** `BLEOutboundFragmentPlanner` selects between simple (v1) and route-aware (v2) fragment formats based on link capabilities.
- **Scheduled Transmission:** `BLEOutboundFragmentTransferScheduler` reserves slots for file fragments while prioritizing simple data.
- **Reliable Reassembly:** `BLEFragmentAssemblyBuffer` reconstructs original payloads while handling duplicates, timeouts, and version mismatches.
- **Safety Limits:** Private media transfers are capped at 256 fragments to prevent resource exhaustion.

## Frequently Asked Questions

### What is the maximum size of a single fragment in BitChat?

BitChat typically limits individual fragments to 64 bytes or less, accommodating the smallest BLE link MTU in the mesh network. This ensures compatibility across devices with varying hardware capabilities.

### How does BitChat handle missing or duplicate fragments?

The `BLEFragmentAssemblyBuffer` tracks received sequence numbers to ignore duplicate fragments without disrupting reassembly. If fragments remain missing for too long, the buffer evicts the incomplete assembly to free resources, allowing newer transmissions to use the same Fragment ID.

### What is the difference between fragment version 1 and version 2?

Version 1 provides basic fragmentation with simple headers suitable for standard data transfers. Version 2 adds route-aware chunking that incorporates bandwidth limits and routing information, optimizing transmission across complex mesh topologies while maintaining backward compatibility through automatic fallback.

### Is there a limit to how many fragments a single packet can have?

Yes, BitChat enforces a maximum of 256 fragments for private media transfers. The `BLEOutboundFragmentPlanner` rejects attempts to create larger fragment sequences early in the pipeline, preventing potential denial-of-service scenarios and memory exhaustion on resource-constrained devices.