13  6LoWPAN Review: Hands-On Labs

In 60 Seconds

A practical 6LoWPAN deployment requires three components: a border router (Contiki-NG with tunslip6 creating a TUN interface for IPv6), sensor nodes (exposing data via CoAP REST resources), and a client application (using asynchronous CoAP queries). Simulation frameworks let you validate compression and fragmentation before committing to hardware.

Lab execution time can be estimated before starting runs:

\[ T_{\text{total}} = N_{\text{runs}} \times (t_{\text{setup}} + t_{\text{run}} + t_{\text{review}}) \]

Worked example: With 5 runs and per-run times of 4 min setup, 6 min execution, and 3 min review, total lab time is \(5\times(4+6+3)=65\) minutes. This prevents under-scoping and helps schedule complete experimental cycles.

13.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Configure 6LoWPAN Border Routers: Compile, flash, and validate Contiki-NG border router firmware with tunslip6 TUN interface creation
  • Construct CoAP Sensor Nodes: Implement REST resource handlers in Contiki-NG that expose sensor data as discoverable CoAP endpoints
  • Diagnose Connectivity Failures: Isolate root causes of routing, addressing, and compression problems using ping6, coap-client, and Wireshark
  • Evaluate Fragmentation Trade-offs: Analyse simulation results to assess how payload size affects fragment count, reliability, and overhead
  • Validate Designs Through Simulation: Execute Python-based 6LoWPAN simulations and interpret compression, fragmentation, and packet-loss statistics

These hands-on labs let you explore 6LoWPAN networking through guided exercises. You will set up networks, analyze packet captures, and troubleshoot common issues. Practical experience with 6LoWPAN gives you confidence to work with this important IoT networking technology in real projects.

“Time to get our hands dirty!” announced Max the Microcontroller. “We are going to set up a real 6LoWPAN network with three parts: a border router that connects our mesh to the internet, sensor nodes that collect data, and a client app that reads the sensor values.”

Sammy the Sensor asked, “What software do we use?” Max explained, “Contiki-NG is the operating system designed for tiny IoT devices. It includes a full 6LoWPAN stack with header compression, fragmentation, and RPL routing. The border router runs a special program called tunslip6 that creates a virtual network interface bridging your mesh to the computer’s IPv6 stack.”

“And our sensors talk using CoAP,” added Lila the LED. “It is like a lightweight version of HTTP designed for constrained devices. Each sensor exposes its readings as a REST resource – like a tiny web page that only serves one number. A CoAP client can request temperature from one sensor and humidity from another, just like browsing web pages.”

Bella the Battery offered her usual practical wisdom. “Start in a simulator before touching real hardware! Cooja, the Contiki-NG simulator, lets you create virtual sensor networks and watch every packet flow through the mesh. Once your simulation works perfectly, moving to real hardware is mostly just flashing the same code onto physical boards.”

13.2 Prerequisites

Before working through these labs, you should be familiar with:

  • Cooja Simulator: The Contiki network simulator widely used for 6LoWPAN/RPL research and education, supporting simulated mote hardware with realistic radio models.
  • Wireshark 6LoWPAN Dissector: A Wireshark plugin decoding 6LoWPAN headers and showing decompressed IPv6 packets, essential for debugging compressed-header issues.
  • RIOT OS: A real-time operating system for constrained IoT devices providing 6LoWPAN, RPL, and CoAP support with a Unix-like development environment.
  • Border Router Configuration: The process of setting up a 6LoWPAN border router with correct prefix advertisement, context distribution, and routing policy for the connected mesh network.
  • Serial Line Internet Protocol (SLIP): A legacy serial encapsulation sometimes used to connect embedded border router firmware to a host PC’s Linux network stack for 6LoWPAN development.

13.3 Try It: 6LoWPAN CoAP Sensor Simulator on ESP32

Objective: Simulate a 6LoWPAN CoAP sensor node that exposes REST resources, demonstrating the same patterns used in Contiki-NG.

Paste this code into the Wokwi editor:

#include <WiFi.h>
#include <WiFiUdp.h>

const char* ssid = "Wokwi-GUEST";
const char* password = "";

WiFiUDP udp;
const int COAP_PORT = 5683;

// Simulated 6LoWPAN node state
float temperature = 22.5;
float humidity = 55.0;
int batteryPercent = 95;
unsigned long uptime_s = 0;
int coapRequests = 0;

// Simulated CoAP resources (like Contiki-NG resource definitions)
struct CoapResource {
  const char* path;
  const char* rt;       // Resource Type
  const char* ct;       // Content Format
};

CoapResource resources[] = {
  {"/sensors/temperature", "temperature-c", "application/json"},
  {"/sensors/humidity",    "humidity-pct",  "application/json"},
  {"/device/battery",      "battery-pct",   "application/json"},
  {"/device/info",         "device-info",   "application/json"},
  {"/.well-known/core",    "core-link",     "application/link-format"}
};
const int NUM_RESOURCES = 5;

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println("==============================================");
  Serial.println("  6LoWPAN CoAP Sensor Node Simulator");
  Serial.println("  Equivalent to Contiki-NG coap-sensor.c");
  Serial.println("==============================================\n");

  WiFi.begin(ssid, password);
  Serial.print("Joining network");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" done!\n");

  // Simulate 6LoWPAN boot sequence
  Serial.println("[6LoWPAN] Header compression: IPHC enabled");
  Serial.println("[6LoWPAN] IPv6 header: 40 bytes -> 6 bytes (85% reduction)");
  Serial.println("[6LoWPAN] UDP header:  8 bytes -> 4 bytes (50% reduction)");

  Serial.println("\n[RPL] Joining DODAG...");
  delay(500);
  Serial.println("[RPL] Preferred parent: fe80::1 (border router)");
  Serial.println("[RPL] RANK: 512 (2 hops from root)");

  // Display IPv6 addresses (simulated from MAC)
  uint8_t mac[6];
  WiFi.macAddress(mac);
  Serial.println("\n[IPv6] Addresses:");
  Serial.printf("  Link-local: fe80::%02x%02x:%02xff:fe%02x:%02x%02x\n",
    mac[0] ^ 0x02, mac[1], mac[2], mac[3], mac[4], mac[5]);
  Serial.printf("  Global:     fd00::%s\n", WiFi.localIP().toString().c_str());

  // Register CoAP resources
  Serial.println("\n[CoAP] Registering resources:");
  for (int i = 0; i < NUM_RESOURCES; i++) {
    Serial.printf("  coap://[fd00::node]%s (rt=%s)\n",
      resources[i].path, resources[i].rt);
  }

  // Start UDP listener
  udp.begin(COAP_PORT);
  Serial.printf("\n[CoAP] Server listening on port %d\n", COAP_PORT);
  Serial.println("[CoAP] Ready for requests\n");

  // Simulate incoming CoAP requests
  simulateRequests();
}

void simulateRequests() {
  Serial.println("=== Simulated CoAP Request/Response ===\n");

  // GET /.well-known/core (resource discovery)
  coapRequests++;
  Serial.printf("[REQ %d] GET /.well-known/core\n", coapRequests);
  Serial.println("[RSP] 2.05 Content (application/link-format)");
  Serial.println("  </sensors/temperature>;rt=\"temperature-c\";ct=50,");
  Serial.println("  </sensors/humidity>;rt=\"humidity-pct\";ct=50,");
  Serial.println("  </device/battery>;rt=\"battery-pct\";ct=50,");
  Serial.println("  </device/info>;rt=\"device-info\";ct=50\n");

  delay(1000);

  // GET /sensors/temperature
  coapRequests++;
  temperature += random(-10, 11) / 10.0;
  Serial.printf("[REQ %d] GET /sensors/temperature\n", coapRequests);
  Serial.println("[RSP] 2.05 Content (application/json)");
  Serial.printf("  {\"temperature\":%.1f,\"unit\":\"celsius\"}\n\n", temperature);

  delay(1000);

  // GET /sensors/humidity
  coapRequests++;
  humidity += random(-5, 6);
  humidity = constrain(humidity, 20, 95);
  Serial.printf("[REQ %d] GET /sensors/humidity\n", coapRequests);
  Serial.println("[RSP] 2.05 Content (application/json)");
  Serial.printf("  {\"humidity\":%.0f,\"unit\":\"percent\"}\n\n", humidity);

  delay(1000);

  // Observe /sensors/temperature
  coapRequests++;
  Serial.printf("[REQ %d] GET /sensors/temperature (Observe: register)\n", coapRequests);
  Serial.println("[RSP] 2.05 Content + Observe token registered");
  Serial.println("  --> Client will receive push notifications\n");

  for (int i = 0; i < 3; i++) {
    delay(2000);
    temperature += random(-5, 6) / 10.0;
    Serial.printf("[NOTIFY] /sensors/temperature -> {\"temperature\":%.1f}\n",
      temperature);
  }

  Serial.println("\n[CoAP] Observe: 3 notifications sent (server-push)");
  Serial.println("  Bandwidth savings vs polling: ~97%%\n");
}

void loop() {
  delay(10000);
  uptime_s += 10;
  temperature += random(-3, 4) / 10.0;
  batteryPercent = max(5, batteryPercent - random(0, 2));
  Serial.printf("[Status] Temp: %.1fC | Hum: %.0f%% | Batt: %d%% | "
    "Requests: %d | Uptime: %lus\n",
    temperature, humidity, batteryPercent, coapRequests, uptime_s);
}

What to Observe:

  1. The boot sequence shows 6LoWPAN header compression (85% IPv6 reduction) and RPL DODAG joining
  2. Resource discovery via /.well-known/core returns all available sensor endpoints in link-format
  3. CoAP GET requests return JSON sensor data with proper response codes (2.05 Content)
  4. CoAP Observe demonstrates server-push notifications saving ~97% bandwidth vs polling

13.4 Lab 1: Contiki-NG 6LoWPAN Border Router

Set up a complete 6LoWPAN network with border router and sensor nodes.

Hardware Required:

  • 2x Zolertia RE-Mote (or similar 802.15.4 boards)
  • USB cables
  • Linux PC (Ubuntu 20.04+ recommended)

13.4.1 Part 1: Install Contiki-NG

# Install dependencies
sudo apt-get update
sudo apt-get install -y git gcc-arm-none-eabi gdb-multiarch \
    python3-serial python3-pip

# Clone Contiki-NG
cd ~
git clone https://github.com/contiki-ng/contiki-ng.git
cd contiki-ng

# Verify toolchain
arm-none-eabi-gcc --version

13.4.2 Part 2: Flash Border Router

# Navigate to border router example
cd examples/rpl-border-router

# Compile for Zolertia RE-Mote
make TARGET=zoul BOARD=remote-revb

# Flash to device (connect via USB)
make TARGET=zoul BOARD=remote-revb border-router.upload

# Start border router (creates TUN interface)
sudo make TARGET=zoul BOARD=remote-revb connect-router

# In another terminal, check TUN interface
ifconfig tun0
# Should show fd00::1/64 address

13.4.3 Part 3: Create CoAP Sensor Node

Create coap-sensor.c:

/**
 * 6LoWPAN CoAP Temperature Sensor
 *
 * Exposes temperature reading via CoAP GET request
 */

#include "contiki.h"
#include "coap-engine.h"
#include "dev/button-sensor.h"
#include "dev/leds.h"
#include "sys/log.h"

#define LOG_MODULE "CoAP-Sensor"
#define LOG_LEVEL LOG_LEVEL_INFO

// Simulated temperature (in real device, read from sensor)
static int temperature = 22;

// CoAP resource handler
static void temperature_get_handler(coap_message_t *request,
                                   coap_message_t *response,
                                   uint8_t *buffer, uint16_t preferred_size,
                                   int32_t *offset);

// Define CoAP resource
RESOURCE(temperature_resource,
         "title=\"Temperature\";rt=\"temperature-c\"",
         temperature_get_handler,
         NULL,
         NULL,
         NULL);

static void
temperature_get_handler(coap_message_t *request, coap_message_t *response,
                       uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
    LOG_INFO("CoAP GET /temperature\n");

    // Simulate temperature fluctuation
    temperature = 20 + (random_rand() % 10);

    // Create JSON response
    int length = snprintf((char *)buffer, preferred_size,
                         "{\"temperature\":%d,\"unit\":\"celsius\"}",
                         temperature);

    // Set response
    coap_set_header_content_format(response, APPLICATION_JSON);
    coap_set_payload(response, buffer, length);

    // Blink LED to indicate activity
    leds_toggle(LEDS_GREEN);
}

PROCESS(coap_sensor_process, "CoAP Sensor");
AUTOSTART_PROCESSES(&coap_sensor_process);

PROCESS_THREAD(coap_sensor_process, ev, data)
{
    PROCESS_BEGIN();

    LOG_INFO("CoAP Temperature Sensor Starting\n");

    // Activate CoAP engine
    coap_activate_resource(&temperature_resource, "sensors/temperature");

    // Wait for network configuration
    PROCESS_PAUSE();

    LOG_INFO("IPv6 addresses:\n");
    uip_ds6_addr_t *lladdr = uip_ds6_get_link_local(-1);
    if(lladdr != NULL) {
        LOG_INFO("  Link-local: ");
        LOG_INFO_6ADDR(&lladdr->ipaddr);
        LOG_INFO_("\n");
    }

    uip_ds6_addr_t *globaladdr = uip_ds6_get_global(-1);
    if(globaladdr != NULL) {
        LOG_INFO("  Global: ");
        LOG_INFO_6ADDR(&globaladdr->ipaddr);
        LOG_INFO_("\n");
    }

    LOG_INFO("CoAP server ready\n");
    LOG_INFO("Access: coap://[IPv6]/sensors/temperature\n");

    PROCESS_END();
}

Compile and Flash:

# Compile
make TARGET=zoul BOARD=remote-revb coap-sensor

# Flash to second device
make TARGET=zoul BOARD=remote-revb coap-sensor.upload

13.4.4 Part 4: Test with Python CoAP Client

#!/usr/bin/env python3
"""
6LoWPAN CoAP Client
Fetches temperature from sensor node
"""

import asyncio
from aiocoap import *

async def fetch_temperature(sensor_ipv6):
    """Fetch temperature from CoAP sensor"""

    print(f"Connecting to sensor: {sensor_ipv6}")

    context = await Context.create_client_context()

    uri = f"coap://[{sensor_ipv6}]/sensors/temperature"
    request = Message(code=GET, uri=uri)

    try:
        response = await context.request(request).response

        print(f"Response Code: {response.code}")
        print(f"Payload: {response.payload.decode('utf-8')}")

        return response.payload.decode('utf-8')

    except Exception as e:
        print(f"Error: {e}")
        return None

async def continuous_monitoring(sensor_ipv6, interval=5):
    """Continuously monitor sensor"""

    print(f"\n=== 6LoWPAN Sensor Monitoring ===")
    print(f"Sensor: {sensor_ipv6}")
    print(f"Interval: {interval} seconds\n")

    while True:
        print(f"[{asyncio.get_event_loop().time():.2f}] Fetching...")
        await fetch_temperature(sensor_ipv6)
        print()

        await asyncio.sleep(interval)

if __name__ == "__main__":
    import sys

    if len(sys.argv) < 2:
        print("Usage: python3 coap_client.py <sensor_ipv6_address>")
        print("Example: python3 coap_client.py fd00::212:4b00:1234:5678")
        sys.exit(1)

    sensor_ipv6 = sys.argv[1]

    # Install dependencies first: pip3 install aiocoap
    asyncio.run(continuous_monitoring(sensor_ipv6))

Run Client:

# Install aiocoap
pip3 install aiocoap

# Get sensor IPv6 address (check border router output)
# Example: fd00::212:4b00:615:a4cb

# Run client
python3 coap_client.py fd00::212:4b00:615:a4cb

Expected Output:

=== 6LoWPAN Sensor Monitoring ===
Sensor: fd00::212:4b00:615:a4cb
Interval: 5 seconds

[0.00] Fetching...
Connecting to sensor: fd00::212:4b00:615:a4cb
Response Code: 2.05 Content
Payload: {"temperature":24,"unit":"celsius"}

[5.12] Fetching...
Connecting to sensor: fd00::212:4b00:615:a4cb
Response Code: 2.05 Content
Payload: {"temperature":22,"unit":"celsius"}

[10.24] Fetching...
Connecting to sensor: fd00::212:4b00:615:a4cb
Response Code: 2.05 Content
Payload: {"temperature":26,"unit":"celsius"}

13.4.5 Part 5: Verification and Debugging

# Ping sensor from PC
ping6 fd00::212:4b00:615:a4cb

# Use coap-client tool (libcoap2-bin on Ubuntu 20.04, libcoap3-bin on 22.04+)
sudo apt-get install libcoap2-bin || sudo apt-get install libcoap3-bin
coap-client -m get coap://[fd00::212:4b00:615:a4cb]/sensors/temperature

# Analyze traffic with Wireshark
sudo wireshark -i tun0 -f "ip6"
# See 6LoWPAN compression in action!
Lab Tips

Common Issues and Solutions:

  1. TUN interface not created: Check USB connection and permissions (sudo required)
  2. No ping response: Verify RPL routing has converged (wait 30-60 seconds)
  3. CoAP timeout: Check firewall rules allowing UDP port 5683
  4. Wrong IPv6 address: The sensor address combines the prefix (fd00::/64) with MAC-derived IID

13.5 Lab 2: Python 6LoWPAN Network Simulator

Create a simulation framework for testing 6LoWPAN scenarios without hardware.

Simulation Goals:

  • Model header compression efficiency
  • Calculate fragmentation overhead
  • Simulate packet loss and reliability
  • Analyze network statistics

Run Simulation:

python3 6lowpan_simulator.py

Expected Output:

======================================================================
6LoWPAN NETWORK SIMULATION
======================================================================

Configuration:
  Nodes: 10
  MTU: 102 bytes
  Packet loss rate: 10.0%
  Simulation time: 60s

Running simulation...
Simulation complete

======================================================================
SIMULATION STATISTICS
======================================================================

Packet Transmission:
  Total attempts:        60
  Successful:            47 (78.3%)
  - Single frame:        35
  - Fragmented:          12
  Failed:
  - Lost:                6 (10.0%)
  - Reassembly failed:   7 (11.7%)

Node Statistics:
Node       Sent       Received   Fragments    Bytes Sent
----------------------------------------------------------------------
BR         0          47         0            15324
N1         7          0          21           2268
N2         8          0          24           2592
N3         6          0          18           1944
N4         5          0          15           1620
N5         7          0          21           2268
N6         7          0          21           2268
N7         6          0          18           1944
N8         7          0          21           2268
N9         7          0          21           2268

Header Compression Efficiency:
  Average payload:       426 bytes
  Uncompressed overhead: 48 bytes (10.1%)
  Compressed overhead:   6 bytes (1.4%)
  Overhead reduction:    87.5%

Fragmentation Analysis:
  64 byte payload -> 1 frame (no fragmentation)
  128 byte payload -> 2 fragments
  256 byte payload -> 3 fragments
  512 byte payload -> 6 fragments
  1280 byte payload -> 13 fragments

======================================================================

13.5.1 Understanding the Simulation Results

Key Metrics Explained:

Metric Description Target
Compression Efficiency Header size reduction (48 -> 6 bytes) >85%
Single-Frame Success Packets not requiring fragmentation Maximize
Fragmented Success Multi-frame packet delivery Monitor closely
Reassembly Failures Lost due to missing fragments Minimize

Design Implications:

  1. High reassembly failures (>10%) indicate excessive fragmentation or lossy channel
  2. Low compression efficiency (<80%) suggests non-link-local or context-less traffic
  3. Many fragments per packet (>4) will cause reliability issues in lossy environments
Simulation vs Reality

The simulator models ideal 6LoWPAN behavior. Real-world deployments face additional challenges:

  • Hidden node problem: Nodes can’t hear each other, causing collisions
  • Multipath fading: Signal reflections cause intermittent connectivity
  • Interference: Wi-Fi, microwave ovens, and other 2.4 GHz devices
  • Battery drain: Retransmissions consume significant power

Use simulation for initial design, then validate with real hardware and Wireshark analysis.

13.5.2 Knowledge Check: Simulation Interpretation

13.6 Lab Exercises

13.6.1 Exercise 1: Optimize for Battery Life

Modify the CoAP sensor to minimize transmissions:

  1. Add local averaging (send mean of 10 readings instead of each)
  2. Implement threshold-based reporting (only send if change > 2 degrees)
  3. Measure power consumption difference

13.6.2 Exercise 2: Multi-Hop Routing

Extend the network to test multi-hop scenarios:

  1. Add a third sensor node positioned beyond direct range of border router
  2. Configure as RPL router (not leaf)
  3. Verify traffic routes through intermediate node
  4. Measure additional latency from multi-hop path

13.6.3 Exercise 3: Fragmentation Testing

Test fragmentation behavior with large payloads:

  1. Modify sensor to send 500-byte diagnostic logs
  2. Capture traffic with Wireshark
  3. Count fragments and verify reassembly
  4. Calculate actual vs theoretical reliability

13.6.4 Knowledge Check: Border Router Setup

13.6.5 Knowledge Check: CoAP Sensor Design

13.7 Summary

This chapter provided hands-on experience with 6LoWPAN networks:

  • Border Router Setup: Contiki-NG configuration with tunslip6 for IPv6 connectivity
  • CoAP Sensor Implementation: REST-based sensor interface with JSON payloads
  • Python Client: Asynchronous CoAP client for sensor monitoring
  • Network Simulation: Python framework for testing compression and fragmentation scenarios
  • Debugging Tools: ping6, coap-client, and Wireshark for troubleshooting

Key Takeaways:

  • Border router setup requires TUN interface and proper routing configuration
  • CoAP provides lightweight REST interface ideal for constrained devices
  • Simulation helps validate designs before hardware deployment
  • Real-world testing with Wireshark reveals actual compression behavior

13.8 Knowledge Check

::

::

Common Mistake: Forgetting IPv6 Forwarding on Border Router Host

The Symptom: After successfully setting up the border router with tunslip6 -s /dev/ttyUSB0 fd00::1/64, sensors join the RPL DODAG and receive global addresses. You can ping sensors from the border router PC (ping6 fd00::212:4b00:1234:5678 works), but remote hosts on the building network cannot reach sensors.

Why It Happens: The TUN interface (tun0) creates a virtual network on the border router PC, but Linux disables IPv6 forwarding by default. Without forwarding enabled, the PC treats packets arriving on eth0 (building network) destined for fd00::/64 as “not for me” and drops them instead of routing to tun0.

The Fix (two steps required):

# Step 1: Enable IPv6 forwarding on border router PC
sudo sysctl -w net.ipv6.conf.all.forwarding=1

# Make permanent (survives reboot):
echo "net.ipv6.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.conf

# Step 2: Add route on building network router
# On building core router:
ip -6 route add fd00::/64 via 2001:db8::100  # BR's eth0 address

Verification:

# From remote host on building network:
ping6 fd00::212:4b00:1234:5678
# Should now receive replies

Why This Catches Everyone:

  • Local pings work because they originate on the same host as tunslip6
  • Remote pings fail because they arrive on eth0 and need forwarding to tun0
  • Error message is silent - packets just disappear
  • Affects 90% of first-time 6LoWPAN deployments

13.9 What’s Next

Chapter Focus Why It Matters
6LoWPAN Review: Performance Analysis Compression efficiency calculations, fragmentation reliability modelling Quantify the trade-offs you observed in the labs with formal analysis
6LoWPAN Review: Quiz and Assessment Scenario-based assessment covering addressing, routing, and compression Test your understanding from the hands-on work before moving on
6LoWPAN Lab Simulation Complete ESP32 Wokwi simulation with IPHC, fragmentation, and RPL Run a browser-based 6LoWPAN simulation without physical hardware
6LoWPAN Common Pitfalls Seven frequent mistakes and troubleshooting scenarios Avoid deployment errors encountered in real-world 6LoWPAN networks
Zigbee Fundamentals and Architecture Higher-level protocol built on IEEE 802.15.4 with application profiles Compare 6LoWPAN’s IP-based approach with Zigbee’s cluster-library model