6LoWPAN: Squeezing IPv6 Through a 127-Byte Keyhole
How the IETF made the 40-byte IPv6 header fit in networks where 81 bytes is all you get β and why this compression layer enabled the βIP everywhereβ vision that became IoT
The year was 2007. I was building wireless sensor networks with Jennic JN5139 modules β IEEE 802.15.4 radios running at 2.4 GHz with 250 kbps data rates. The chips were capable. The problem was the protocol stack.
IEEE 802.15.4 gives you 127 bytes per frame. After the MAC header (up to 25 bytes) and optional link-layer security (21 bytes for AES-CCM-128), youβre left with roughly 81 bytes for your actual data. And we wanted to run IP.
IPv6βs header alone is 40 bytes. Half your available space, gone before you transmit a single byte of payload. Add a UDP header (8 bytes) and youβve got 33 bytes left for application data. Thatβs barely enough for a sensor reading and a timestamp.
The IETFβs answer was 6LoWPAN β IPv6 over Low-Power Wireless Personal Area Networks. Published as RFC 4944 in 2007 (the same year I was wrestling with those Jennic boards), it defined how to compress, fragment, and adapt IPv6 for networks where every byte is precious.
The result: that 40-byte IPv6 header can compress down to 2 bytes in common cases. The βIP everywhereβ dream became practical.
6LoWPAN IPHC compression β the 40-byte IPv6 header compresses to as few as 2 bytes by exploiting predictable patterns and shared context
The Problem: IPv6 Was Not Designed for Constrained Networks
IPv6 was designed in the 1990s for the internet backbone. Its minimum MTU requirement is 1280 bytes. Its header is 40 bytes fixed β no options, no variability, just 40 bytes every single packet.
IEEE 802.15.4 was designed for low-power wireless sensor networks. Its maximum frame is 127 bytes. The mismatch is brutal:
IPv6 minimum MTU: 1,280 bytes
802.15.4 max frame: 127 bytes
βββββββββββββ
Ratio: 10:1 mismatch
You canβt just βrun IPv6β over 802.15.4. The packets donβt fit. An IPv6 packet at minimum MTU would need to be split across 10+ link-layer frames, with all the complexity of fragmentation, reassembly, and loss handling that implies.
Even a single IPv6 header plus a tiny payload exceeds what one 802.15.4 frame can carry after accounting for link-layer overhead.
6LoWPAN solves this with two mechanisms:
- Header compression β Shrink the IPv6 header by exploiting predictable patterns
- Fragmentation β Split packets across multiple frames when compression isnβt enough
The Insight: Most Header Fields Are Predictable
Hereβs the IPv6 header:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
βββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ€
βVersionβ Traffic Class β Flow Label β
βββββββββ΄ββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββ€
β Payload Length β Next Header β Hop Limit β
βββββββββββββββββββββββββββββββββ΄ββββββββββββββββ΄ββββββββββββββββ€
β β
β Source Address β
β (128 bits) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Destination Address β
β (128 bits) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Total: 40 bytes
Now look at whatβs actually variable in a typical sensor network:
| Field | Size | Typical Value | Compressible? |
|---|---|---|---|
| Version | 4 bits | Always 6 | Yes β implicit |
| Traffic Class | 8 bits | Usually 0 | Yes β elide |
| Flow Label | 20 bits | Usually 0 | Yes β elide |
| Payload Length | 16 bits | Derivable from link layer | Yes β elide |
| Next Header | 8 bits | Usually UDP (17) | Yes β encode |
| Hop Limit | 8 bits | 1, 64, or 255 typically | Partially β 2-bit encoding |
| Source Address | 128 bits | Often link-local, derivable from MAC | Yes β elide |
| Destination Address | 128 bits | Often link-local, derivable from MAC | Yes β elide |
In the best case β link-local addresses derivable from IEEE 802.15.4 MAC addresses, zero traffic class and flow label, standard hop limit, UDP next header β you can compress the entire 40-byte header down to 2 bytes.
Thatβs a 95% reduction. From 40 bytes to 2.
LOWPAN_IPHC: The Compression Format
RFC 6282 (2011) defined the current header compression format, replacing the simpler HC1/HC2 scheme from RFC 4944. Itβs called LOWPAN_IPHC (IP Header Compression).
The 2-Byte Base Encoding
1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
βββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ€
β 0 β 1 β 1 β TF βNH β HLIMβCIDβSACβ SAM βMβDACβ DAM β
βββββ΄ββββ΄ββββ΄ββββββββ΄ββββ΄ββββββ΄ββββ΄ββββ΄ββββββββ΄ββ΄ββββ΄ββββββββ
Dispatch (011) β β β β β β β β
β β β β β β β ββ Dest Addr Mode (2 bits)
β β β β β β ββ Dest Addr Compression
β β β β β ββ Multicast flag
β β β β ββ Source Addr Mode (2 bits)
β β β ββ Source Addr Compression
β β ββ Context Identifier Extension
β ββ Hop Limit encoding (2 bits)
β
ββ Traffic Class/Flow Label (2 bits)
Next Header compressed (1 bit)
The dispatch prefix 011 identifies this as an IPHC-compressed packet. The remaining 13 bits control how each IPv6 field is compressed.
Traffic Class and Flow Label (TF)
| TF | Traffic Class | Flow Label | Inline Bytes |
|---|---|---|---|
| 00 | Inline (8 bits) | Inline (20 bits) | 4 bytes |
| 01 | Inline (2 bits ECN) | Inline (20 bits) | 3 bytes |
| 10 | Inline (8 bits) | Elided (zero) | 1 byte |
| 11 | Elided (zero) | Elided (zero) | 0 bytes |
Most sensor traffic uses TF=11 β no QoS, no flow label, zero bytes transmitted.
Hop Limit (HLIM)
| HLIM | Value | Inline Bytes |
|---|---|---|
| 00 | Inline | 1 byte |
| 01 | 1 | 0 bytes |
| 10 | 64 | 0 bytes |
| 11 | 255 | 0 bytes |
The three most common hop limits (single-hop, default TTL, max TTL) need zero inline bytes.
Address Compression (SAM/DAM)
This is where the real savings come from. For unicast addresses:
| Mode | Compression | Inline Bytes |
|---|---|---|
| 00 | Full address | 16 bytes |
| 01 | 64 bits (prefix from context) | 8 bytes |
| 10 | 16 bits (prefix + IID derived) | 2 bytes |
| 11 | Fully elided (derived from link-layer) | 0 bytes |
When source and destination addresses can be derived from IEEE 802.15.4 MAC addresses (using the EUI-64 to IID mapping), both 128-bit addresses compress to zero bytes.
The Best Case
Link-local communication, UDP payload, standard hop limit:
Original IPv6 + UDP: 40 + 8 = 48 bytes
Compressed IPHC + NHC: 2 + 1 = 3 bytes
βββββββββββββββββ
Savings: 45 bytes (94%)
Thatβs 45 extra bytes for your sensor data. In a network where 81 bytes is your budget, thatβs the difference between βbarely worksβ and βactually useful.β
LOWPAN_NHC: Compressing What Comes Next
IPHC handles the IPv6 header. LOWPAN_NHC (Next Header Compression) handles everything that follows β UDP headers, IPv6 extension headers, even IPv6-in-IPv6 encapsulation.
UDP Compression
UDP is the most common transport for sensor data. Its header:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
βββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ€
β Source Port β Destination Port β
βββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββ€
β Length β Checksum β
βββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββ
Total: 8 bytes
NHC compresses this too:
| Field | Compression |
|---|---|
| Source Port | 4 bits if in range 0xF0Bx |
| Destination Port | 4 bits if in range 0xF0Bx |
| Length | Derivable from link layer |
| Checksum | Elide if upper-layer MIC exists |
When both ports are in the βwell-known 6LoWPAN rangeβ (0xF0B0-0xF0BF), the entire UDP header compresses from 8 bytes to 1 byte (the NHC encoding byte with 4-bit port fields).
Fragmentation: When Compression Isnβt Enough
Even with aggressive compression, some packets wonβt fit in a single 802.15.4 frame. 6LoWPAN defines a fragmentation scheme:
Fragment Header
First fragment:
βββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ¬ββββββββββββββ€
β 1 1 0 0 0 β datagram_size (11 bits) β β
βββββββββββββ΄ββββββββββββββββββββββββββββββββββββββ€ β
β datagram_tag (16 bits) β payload β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€ β
4 bytes total
Subsequent fragments:
βββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ¬ββββββββββββββ€
β 1 1 1 0 0 β datagram_size (11 bits) β β
βββββββββββββ΄ββββββββββββββββββββββββββββββββββββββ€ β
β datagram_tag (16 bits) β payload β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€ β
β datagram_offset (8 bits) β β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€ β
5 bytes total
The datagram_tag links fragments from the same original packet. The datagram_offset specifies where this fragmentβs payload goes in the reassembled packet (in 8-byte units).
Reassembly Challenges
Fragmentation in constrained networks is painful:
- Memory: The receiver must buffer partial datagrams until all fragments arrive
- Loss: A single lost fragment means the entire datagram is lost
- Timeout: How long do you wait before giving up on missing fragments?
- Ordering: Fragments can arrive out of order over mesh networks
This is why 6LoWPAN applications try hard to fit packets in a single frame. Compression is the first line of defense; fragmentation is the fallback.
Context: Compressing Global Addresses
Link-local addresses compress beautifully β theyβre derivable from MAC addresses. But what about global addresses? A sensor reporting to a cloud server needs routable IPv6 addresses.
6LoWPAN uses shared context β both ends agree on common address prefixes. The IPHC CID (Context Identifier) bit enables this:
Context 0: 2001:db8:1234::/48 (our network prefix)
Context 1: 2001:db8:5678::/48 (cloud server network)
With context, a full global address like 2001:db8:1234:0000:0212:4b00:1234:5678 compresses the same way as a link-local β the prefix comes from context, the IID from the MAC address.
Context is configured out-of-band (typically by the border router or through RFC 6775 Neighbor Discovery).
Mesh Addressing: Layer 2.5 Routing
6LoWPAN also defines a mesh addressing header for βmesh-underβ routing β forwarding at layer 2 before the IP layer sees the packet:
βββββββββββββ¬ββββββ¬ββββββ¬ββββββββββββββββββββββββββββββββββββββββββ€
β 1 0 β V β F β Hops β Originator Address β Final Address β
βββββββ΄ββββ΄ββββ΄βββββββββ΄βββββββββββββββββββββββ΄βββββββββββββββββββ
Dispatch β β
β ββ Final addr size (0=16-bit, 1=64-bit)
ββ Originator addr size
This allows 802.15.4 devices without full IP stacks to forward packets at the link layer. The Hops Left field decrements at each hop, preventing loops.
Most modern deployments use βroute-overβ (IP-layer routing via RPL) rather than mesh-under, but the option exists for simpler networks.
The Dispatch Byte: Identifying Packet Types
Every 6LoWPAN packet starts with a dispatch byte (or bytes) that identifies what follows:
| Pattern | Type |
|---|---|
00 xxxxxx | Not a 6LoWPAN frame (NALP) |
01 000001 | Uncompressed IPv6 |
01 1xxxxx | IPHC compressed IPv6 |
10 xxxxxx | Mesh addressing header |
11 000xxx | First fragment |
11 100xxx | Subsequent fragment |
11 110000 | Extended dispatch |
Multiple headers can be chained. A packet might have:
[Mesh Header] [Fragment Header] [IPHC Header] [NHC UDP] [Payload]
Where 6LoWPAN Lives Today
6LoWPAN itself is mostly invisible now β itβs the adaptation layer underneath higher-level protocols:
Thread β The smart home protocol (used by Apple HomeKit, Google Nest, Amazon) runs IPv6 over 802.15.4 using 6LoWPAN compression. Every Thread device speaks compressed IPv6.
Zigbee IP β The IP-based variant of Zigbee uses 6LoWPAN. (Classic Zigbee uses its own network layer, but Zigbee IP chose standard IPv6.)
Wi-SUN β Smart utility networks (meters, grid infrastructure) use 6LoWPAN over 802.15.4g for IPv6 connectivity.
Bluetooth Mesh β While Bluetooth Low Energy has its own adaptation layer (RFC 7668), the concepts are similar β compressing IPv6 for constrained links.
The IETF has also adapted the compression concepts for other constrained links:
- RFC 7400 β Generic Header Compression (6LoWPAN-GHC) for arbitrary headers
- RFC 8724 β SCHC (Static Context Header Compression) for LPWAN technologies like LoRaWAN and Sigfox
The Jennic Connection
Those Jennic JN5139 modules I mentioned? They shipped with a proprietary Zigbee-style stack, but the more forward-thinking engineers were already looking at 6LoWPAN. The Contiki operating system had a 6LoWPAN implementation. The dream was βIP to every sensor.β
The irony is that in 2007, we were fighting for every byte in 127-byte frames, compressing headers to fit sensor readings through tiny links. Today, Iβm working with LoRa networks where the constraints are even tighter β and the MeshCore firmware uses many of the same architectural patterns: role separation, efficient encoding, careful airtime budgeting.
The wheel keeps turning. The bytes keep being precious. And the engineers keep finding ways to squeeze meaning through impossibly small keyholes.
Technical Reference
Key RFCs
| RFC | Year | Title |
|---|---|---|
| RFC 4944 | 2007 | Transmission of IPv6 Packets over IEEE 802.15.4 Networks |
| RFC 6282 | 2011 | Compression Format for IPv6 Datagrams (IPHC) |
| RFC 6775 | 2012 | Neighbor Discovery Optimization for 6LoWPAN |
| RFC 7400 | 2014 | 6LoWPAN-GHC: Generic Header Compression |
| RFC 8724 | 2020 | SCHC: Static Context Header Compression |
Compression Summary
| Original | Compressed | Savings |
|---|---|---|
| IPv6 header (40 bytes) | 2-3 bytes typical | 92-95% |
| UDP header (8 bytes) | 1-4 bytes typical | 50-87% |
| IPv6 + UDP (48 bytes) | 3-7 bytes typical | 85-94% |
IEEE 802.15.4 Frame Budget
| Component | Size |
|---|---|
| Max frame size | 127 bytes |
| MAC header (typical) | 21-25 bytes |
| Link-layer security (AES-CCM-128) | 21 bytes |
| Available for 6LoWPAN | 81-85 bytes |
Dispatch Prefixes
| Binary | Hex | Meaning |
|---|---|---|
00 xxxxxx | 0x00-0x3F | NALP (Not a LoWPAN) |
01 000001 | 0x41 | Uncompressed IPv6 |
01 000010 | 0x42 | LOWPAN_HC1 (deprecated) |
01 1xxxxx | 0x60-0x7F | LOWPAN_IPHC |
10 xxxxxx | 0x80-0xBF | Mesh header |
11 000xxx | 0xC0-0xC7 | FRAG1 (first fragment) |
11 100xxx | 0xE0-0xE7 | FRAGN (nth fragment) |
The Closing Thought
6LoWPAN is infrastructure. You donβt see it; you benefit from it. Every Thread smart home device, every Zigbee IP sensor, every Wi-SUN utility meter β theyβre all running compressed IPv6 through that 127-byte keyhole.
The elegance is in the observation: most of those 40 bytes are predictable. The version is always 6. The traffic class is usually 0. The addresses are often derivable from link-layer identifiers. By encoding whatβs different rather than whatβs present, 6LoWPAN turns an impossible mismatch into a working system.
Itβs the same lesson that shows up everywhere in constrained networking: understand your traffic patterns, then optimize for the common case. The uncommon cases still work β you just pay more bytes for them.
Those Jennic boards from 2007 are long retired. The problem they faced β fitting IP into tiny frames β spawned a family of standards that now powers billions of devices. The βIP everywhereβ vision won. And it won by compression.
This post is part of a series on network protocols. See LoRa for the physical layer thatβs bringing similar constraints back to radio mesh networks, and MeshCore for how modern mesh firmware handles byte-level efficiency. For the foundational protocol being compressed, see IP and UDP. Browse our complete protocol collection.
Sources: