How nodes find each other and what a mesh packet actually looks like under the hood
Address Types
PDU Fields
Max TTL Hops
Max NetMIC
Why Does Addressing Matter in a Mesh Network?
In a Bluetooth Mesh network, a single light switch might need to control one specific bulb, every bulb on a floor, or every bulb in the whole building — all using the same radio protocol. To support all these scenarios cleanly, Bluetooth Mesh defines a flexible addressing model with four distinct address types.
Once a message is addressed, it gets wrapped in a Network PDU — a carefully structured packet that carries the payload, routing info, and cryptographic protection all in one. This tutorial walks through both topics step by step.
Topics Covered
1. Virtual Addresses — The “PO Box” of Bluetooth Mesh
Imagine two devices that want to exchange private messages without registering anything in a central provisioning database. They agree on a shared secret label (a 128-bit UUID) out-of-band, but broadcasting that full 128-bit UUID as a destination address every time would be wasteful and expose too much information.
Virtual addresses solve this elegantly: a compact 14-bit hash is derived from the 128-bit Label UUID and packed into a 16-bit virtual address. Any device that knows the Label UUID can derive the same hash and recognise messages meant for it.
hash = AES-CMACSALT(Label UUID) mod 214
The result is a 14-bit value embedded into the lower 14 bits of the virtual address. Because the hash is only 14 bits, multiple different Label UUIDs can produce the same hash — a deliberate design that provides privacy. On receiving a matching virtual address, the upper transport layer checks each candidate Label UUID in full until a genuine match is confirmed via cryptographic authentication.
The bit pattern is always 1 0 in the two most significant bits, followed by the 14-bit hash. This pattern uniquely distinguishes virtual addresses from all other address types.
| 1 | 0 | Hash (14 bits) | |||||||||||||
| bit 15 | bit 14 | bits 13 → 0 | |||||||||||||
| Valid range: 0x8000 – 0xBFFF | |||||||||||||||
2. Group Addresses — Send One, Reach Many
A group address is a destination that zero or more elements can subscribe to. When a message is sent to a group address, every element in the mesh that has registered a subscription to that group receives and processes it — just like joining a mailing list.
Group addresses are identified by having both bit 15 and bit 14 set to 1. There are two flavours: dynamically assigned addresses (configured by a provisioner, range 0xC000–0xFEFF) and fixed addresses (pre-defined in the spec, range 0xFF00–0xFFFF).
| 1 | 1 | Group Address (14 bits) | |||||||||||||
| bit 15 | bit 14 | bits 13 → 0 | |||||||||||||
| Dynamic range: 0xC000 – 0xFEFF | Fixed range: 0xFF00 – 0xFFFF | |||||||||||||||
The top of the group address space holds four special fixed addresses. They let a provisioner or controller reach every node of a specific feature type without knowing individual unicast addresses — extremely handy for large deployments.
| Address | Name | Who processes the message? |
|---|---|---|
| 0xFF00–0xFFFB | RFU | Reserved — not yet defined |
| 0xFFFC | all-proxies | Primary element of every node with Proxy feature enabled |
| 0xFFFD | all-friends | Primary element of every node with Friend feature enabled |
| 0xFFFE | all-relays | Primary element of every node with Relay feature enabled |
| 0xFFFF | all-nodes | Primary element of every node in the network, unconditionally |
A real-world use case: if you want to broadcast a new TTL default to every relay node in a building, send a configuration message to 0xFFFE. No address book needed.
3. Address Validity — Which Address Works Where?
Not every address type is allowed in every field of a Network PDU. The key rule is simple: a node always identifies itself with a unicast address — there’s no anonymous or multi-cast source. Destinations are more flexible depending on message type.
| Address Type | Source (SRC) | Dest: Control Msg | Dest: Access Msg |
|---|---|---|---|
| Unassigned | ✗ | ✗ | ✗ |
| Unicast | ✓ | ✓ | ✓ |
| Virtual | ✗ | ✗ | ✓ |
| Group | ✗ | ✓ | ✓ |
There is also a separate rule about which address types can be used with which key type:
- Device key — only unicast destinations. Used for direct node-to-node configuration traffic.
- Application key — unicast, virtual, or group. Used for all normal application-level messaging.
This makes security sense: device keys are for provisioning and per-node configuration — there’s no reason to multicast those with a device key.
4. The Network PDU — Anatomy of a Mesh Packet
Every message traveling through a Bluetooth Mesh network is carried inside a Network PDU. This is the packet format at the network layer — it wraps the transport payload with routing info, a sequence number, and a cryptographic integrity check. The whole PDU is protected by keys derived from the network key, identified by the NID field.
Two things are worth understanding before diving into individual fields: some bytes are obfuscated (scrambled for privacy but not fully encrypted), while others are fully encrypted. The diagram below shows this split.
| IVI 1 bit |
NID 7 bits |
CTL 1 bit |
TTL 7 bits |
SEQ 24 bits |
SRC 16 bits |
| DST 16 bits |
TransportPDU 8 – 128 bits |
NetMIC 32 or 64 bits |
IVI — IV Index Bit (1 bit)
The IV Index is a 32-bit security counter that the entire mesh network increments periodically to prevent sequence number exhaustion. Embedding the full 32 bits in every packet would be wasteful, so only the least significant bit travels in this field. The receiver uses this bit to quickly determine which IV Index the sender used during encryption, then verifies with the full value during decryption.
NID — Network Identifier (7 bits)
Think of the NID as a compact key-ring index. A receiving node may have multiple network keys for different subnets. Instead of trying every key, it uses the 7-bit NID to quickly narrow down which Encryption Key and Privacy Key to apply. Importantly, the NID is derived differently for standard mesh traffic versus Friend-to-LPN (Low Power Node) private messages, keeping those conversations isolated even on the same network.
CTL — Control Flag (1 bit)
A single bit that answers the question: “Is this packet carrying application data or network management instructions?” It also directly controls the size of the NetMIC integrity check.
| CTL | Message Type | NetMIC Size |
|---|---|---|
| 0 | Access Message (sensor readings, light commands, etc.) | 32 bits |
| 1 | Control Message (relay/friend/heartbeat operations) | 64 bits |
Control messages get a larger 64-bit MIC because tampering with network management traffic (like friend subscriptions or IV index updates) could destabilise the whole network. The extra 32 bits of MIC make forgery exponentially harder.
TTL — Time To Live (7 bits)
TTL limits how far a message propagates through the mesh by counting relay hops. Each relay node decrements TTL by 1 before re-transmitting. When the count hits 1, the message is delivered but not forwarded further.
| Value | What it means in practice |
|---|---|
| 0 | No relay, ever. The receiver knows the sender is exactly one radio hop away — great for proximity-aware logic. |
| 1 | Delivered at next hop but not relayed onward. The message has reached its final relay step. |
| 2–126 | Normal operational range — message may have already been relayed and can still be relayed further. Most applications start here. |
| 127 | Maximum TTL — packet is fresh off the originator and can travel up to 126 relay hops before stopping. |
SEQ — Sequence Number (24 bits)
Every element in a mesh network maintains a monotonically increasing 24-bit counter. Each message it originates gets the next value. The SEQ is critical for two things: it feeds into the encryption nonce (making each encrypted packet unique), and it defends against replay attacks — a node that has already processed SEQ 1000 from a given source will reject any later packet with SEQ ≤ 1000 from that same source.
SRC — Source Address (16 bits)
Always the unicast address of the element that originated the message. Combined with SEQ and IVI, it forms the complete nonce used to encrypt the payload. There is no anonymous transmission at the mesh network layer.
DST — Destination Address (16 bits)
The intended recipient — unicast, virtual, or group. Because DST is part of the encrypted payload, relay nodes cannot read it without the network key. This provides a meaningful level of destination privacy against passive listeners who don’t have the key.
TransportPDU (8–128 bits)
The payload handed down from the Transport layer. This could be a segmented or unsegmented access message (sensor data, a light command) or a control message (a heartbeat, a friend request acknowledgment). It is fully encrypted alongside DST.
NetMIC — Network Message Integrity Check (32 or 64 bits)
The cryptographic authentication tag appended to the encrypted portion of the PDU. Any tampering with DST or TransportPDU will cause the MIC verification to fail, and the packet will be silently discarded. Size is determined by CTL: 32 bits for access messages, 64 bits for control messages.
Quick Reference Summary
| Type | Bit Pattern | Range | Use Case |
|---|---|---|---|
| Unassigned | 0x0000 | 0x0000 | Not yet configured — invalid in messages |
| Unicast | 0b0xxxxxxx xxxxxxxx | 0x0001–0x7FFF | One specific element; source & destination |
| Virtual | 0b10xxxxxx xxxxxxxx | 0x8000–0xBFFF | Private group via Label UUID hash; access messages only |
| Group | 0b11xxxxxx xxxxxxxx | 0xC000–0xFFFF | Subscription-based multicast; fixed all-* aliases at top |
Key Takeaways
Continue Your Bluetooth Mesh Journey
This post covered the mesh addressing system and the Network PDU format. Next up: how the Transport layer handles segmentation, reassembly, and friend queuing for Low Power Nodes.
