# BLE Service Policies for Handling Outbound Packets in BitChat

> Discover BitChat's BLE service policies for outbound packets. Learn how BLEOutboundPacketPolicy manages padding, priority, fragmentation, and deduplication for Bluetooth links.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: performance
- Published: 2026-07-31

---

**BitChat's BLE layer consults the `BLEOutboundPacketPolicy` type to determine padding requirements, queuing priority, fragmentation size, and message deduplication for every packet before it is written to a Bluetooth link.**

BitChat is an open-source, peer-to-peer messaging application that leverages Bluetooth Low Energy (BLE) to create resilient mesh networks. Understanding the BLE service policies for handling outbound packets in BitChat is essential for debugging connectivity issues or extending the protocol, as these policies govern how data is packaged, prioritized, and fragmented across the mesh. The decision-making logic is centralized in [`BLEOutboundPacketPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEOutboundPacketPolicy.swift) and consumed by [`BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEService.swift) during the transmission lifecycle.

## The Four Policy Dimensions

The `BLEOutboundPacketPolicy` type in the `permissionlesstech/bitchat` repository encapsulates four distinct decision points that shape outbound traffic.

### Padding Strategy

The policy determines whether a packet payload must be padded to the BLE MTU (512 bytes) via the `padsBLEFrame(for:)` method. This method inspects the `MessageType` and applies padding only to **Noise-encrypted packets** and **handshake packets**. All other packet types—including voice frames—are transmitted unpadded, conserving bandwidth for latency-sensitive media streams.

### Priority Classification

Queuing order is governed by `priority(for:data:)`, which returns a `BLEOutboundWritePriority` value. Regular chat messages receive **high** priority, ensuring conversational responsiveness. File-transfer payloads are downgraded to **fileTransfer** priority, while fragmented packets receive a specialized **fragment** priority that carries the total fragment count. This hierarchy ensures that small control messages and live text are drained from the outbound queue before large file chunks.

### Fragmentation Logic

Large payloads are divided using `fragmentChunkSize(forLinkLimit:)`, which calculates the maximum safe payload per BLE frame. The implementation subtracts a constant framing overhead of 42 bytes (13 + 8 + 8 + 13) from the negotiated link MTU, then enforces a hard floor of **64 bytes**:

```swift
let maxChunk = BLEOutboundPacketPolicy.fragmentChunkSize(forLinkLimit: 512)
// Returns max(64, 512 - 42) = 470 bytes

```

This ensures that even on constrained links, fragments remain large enough to maintain protocol efficiency without exceeding BLE frame limits.

### Message Identification

Duplicate suppression relies on `messageID(for:)`, which forwards to `BLEIngressLinkRegistry.messageID(for:)` to generate a deterministic identifier. This message ID is attached to each fragment, allowing receiving nodes to detect and discard retransmissions or routing loops.

## How BLEService Orchestrates Policy Application

The integration occurs in [`BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEService.swift), where the four policies are applied at specific transmission phases marked **leave**, **send**, and **queue**:

1. **Priority Resolution**: `BLEOutboundPacketPolicy.priority(...)` is invoked first to obtain the `BLEOutboundWritePriority`, which determines the packet's position in the outbound queue.
2. **Conditional Padding**: If `padsBLEFrame` returns `true`, the service appends zero-padding to align the payload with the 512-byte MTU before fragmentation.
3. **Smart Fragmentation**: For payloads exceeding the calculated chunk size, the service iteratively calls `fragmentChunkSize` to produce appropriately-sized segments, each enqueued as a separate write operation.
4. **Metadata Attachment**: The message ID from `messageID(for:)` is embedded in each fragment header for downstream deduplication.

[`BLEOutboundLinkPlanner.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEOutboundLinkPlanner.swift) additionally utilizes the fragmentation API when preparing per-link transmission schedules, while [`BLESourceRouteOriginationPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLESourceRouteOriginationPolicy.swift) (documented in [`SOURCE_ROUTING.md`](https://github.com/permissionlesstech/bitchat/blob/main/SOURCE_ROUTING.md)) filters eligible links before the policies above are applied.

## Practical Implementation Examples

The following Swift snippets demonstrate how to query the policy decisions directly:

```swift
// Determine if a packet requires MTU padding
let shouldPad = BLEOutboundPacketPolicy.padsBLEFrame(for: packet.type)

// Retrieve the transmission priority for queueing
let priority = BLEOutboundPacketPolicy.priority(for: packet, data: payload)

// Calculate the optimal fragment size for a 512-byte MTU link
let maxChunk = BLEOutboundPacketPolicy.fragmentChunkSize(forLinkLimit: 512)

```

These utility methods provide a clean interface for extending BitChat's protocol handler or debugging transmission behavior.

## Summary

- **Padding is selective**: Only Noise-encrypted and handshake packets are padded to 512 bytes; voice and other data remain unpadded.
- **Priority is hierarchical**: Regular messages receive high priority, file transfers medium, and fragments carry explicit count metadata.
- **Fragmentation is bounded**: Payload chunks enforce a minimum of 64 bytes and account for 42 bytes of protocol overhead.
- **Policy centralization**: All rules reside in [`BLEOutboundPacketPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEOutboundPacketPolicy.swift) and are consumed by [`BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEService.swift) and [`BLEOutboundLinkPlanner.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEOutboundLinkPlanner.swift) to manage the mesh transmission lifecycle.

## Frequently Asked Questions

### Which packet types are padded to the BLE MTU in BitChat?

According to the source code in [`BLEOutboundPacketPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEOutboundPacketPolicy.swift), only Noise-encrypted packets and handshake packets are padded to the full 512-byte MTU. Voice frames and other message types are deliberately sent unpadded to minimize latency and power consumption.

### How does BitChat prioritize different types of network traffic?

The `priority(for:data:)` method assigns **high** priority to regular messages, **fileTransfer** priority to file uploads, and a specialized **fragment** priority (carrying the total fragment count) to segmented packets. This ensures that time-sensitive chat messages are written to the Bluetooth link before bulk data transfers.

### What is the minimum fragment size enforced by BitChat's BLE policies?

The `fragmentChunkSize(forLinkLimit:)` method enforces a hard floor of **64 bytes**. Even if the link MTU is small, fragments will never be smaller than this threshold, calculated as `max(64, linkLimit - 42)` where 42 bytes accounts for framing overhead.

### How does BitChat prevent duplicate packet processing across the mesh?

Each outbound packet receives a deterministic message ID generated by `BLEIngressLinkRegistry.messageID(for:)` and accessed via `BLEOutboundPacketPolicy.messageID(for:)`. This ID is attached to every fragment, allowing receiving nodes to identify and discard duplicates during reassembly or routing.