From 9a989264d8faf68840380ad7ac0ed5510fb593e0 Mon Sep 17 00:00:00 2001
From: Martine Lenders <mail@martine-lenders.eu>
Date: Mon, 13 Apr 2015 12:48:53 +0200
Subject: [PATCH] ng_sixlowpan: initial import of IP header compression

---
 Makefile.dep                                  |   5 +
 sys/Makefile                                  |   3 +
 sys/include/net/ng_sixlowpan.h                |   1 +
 sys/include/net/ng_sixlowpan/iphc.h           | 171 +++++
 sys/include/net/ng_sixlowpan/netif.h          |   5 +
 .../network_layer/ng_sixlowpan/iphc/Makefile  |   3 +
 .../ng_sixlowpan/iphc/ng_sixlowpan_iphc.c     | 697 ++++++++++++++++++
 .../ng_sixlowpan/netif/ng_sixlowpan_netif.c   |   3 +
 .../network_layer/ng_sixlowpan/ng_sixlowpan.c |  77 +-
 9 files changed, 948 insertions(+), 17 deletions(-)
 create mode 100644 sys/include/net/ng_sixlowpan/iphc.h
 create mode 100644 sys/net/network_layer/ng_sixlowpan/iphc/Makefile
 create mode 100644 sys/net/network_layer/ng_sixlowpan/iphc/ng_sixlowpan_iphc.c

diff --git a/Makefile.dep b/Makefile.dep
index 143d9c6caf..1ff604b745 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -95,6 +95,11 @@ ifneq (,$(filter ng_sixlowpan_frag,$(USEMODULE)))
   USEMODULE += vtimer
 endif
 
+ifneq (,$(filter ng_sixlowpan_iphc,$(USEMODULE)))
+  USEMODULE += ng_sixlowpan
+  USEMODULE += ng_sixlowpan_ctx
+endif
+
 ifneq (,$(filter ng_sixlowpan,$(USEMODULE)))
   USEMODULE += ng_ipv6
   USEMODULE += ng_sixlowpan_netif
diff --git a/sys/Makefile b/sys/Makefile
index 71fdea57ae..41788ecee7 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -116,6 +116,9 @@ endif
 ifneq (,$(filter ng_sixlowpan_frag,$(USEMODULE)))
     DIRS += net/network_layer/ng_sixlowpan/frag
 endif
+ifneq (,$(filter ng_sixlowpan_iphc,$(USEMODULE)))
+    DIRS += net/network_layer/ng_sixlowpan/iphc
+endif
 ifneq (,$(filter ng_sixlowpan_netif,$(USEMODULE)))
     DIRS += net/network_layer/ng_sixlowpan/netif
 endif
diff --git a/sys/include/net/ng_sixlowpan.h b/sys/include/net/ng_sixlowpan.h
index d05524eaf4..b58bf1b8ab 100644
--- a/sys/include/net/ng_sixlowpan.h
+++ b/sys/include/net/ng_sixlowpan.h
@@ -25,6 +25,7 @@
 #include "kernel_types.h"
 
 #include "net/ng_sixlowpan/frag.h"
+#include "net/ng_sixlowpan/iphc.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/sys/include/net/ng_sixlowpan/iphc.h b/sys/include/net/ng_sixlowpan/iphc.h
new file mode 100644
index 0000000000..9f5f53309c
--- /dev/null
+++ b/sys/include/net/ng_sixlowpan/iphc.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    net_ng_sixlowpan_iphc   IPv6 header compression (IPHC)
+ * @ingroup     net_ng_sixlowpan
+ * @brief       IPv6 header compression for 6LoWPAN.
+ * @{
+ *
+ * @file
+ * @brief   6LoWPAN IPHC definitions
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef NG_SIXLOWPAN_IPHC_H_
+#define NG_SIXLOWPAN_IPHC_H_
+
+#include <stdbool.h>
+
+#include "net/ng_pkt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Dispatch mask for LOWPAN_IPHC.
+ */
+#define NG_SIXLOWPAN_IPHC1_DISP_MASK    (0xe0)
+
+/**
+ * @brief   Dispatch for LOWPAN_IPHC.
+ */
+#define NG_SIXLOWPAN_IPHC1_DISP         (0x60)
+
+/**
+ * @brief   Flag for Traffic Class & Flow Label elision (part of first byte of
+ *          LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC1_TF           (0x18)
+
+/**
+ * @brief   Flag for Next Header Compression (part of first byte of
+ *          LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC1_NH           (0x04)
+
+/**
+ * @brief   Flag for Hop Limit elision (part of first byte of LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC1_HL           (0x03)
+
+/**
+ * @brief   Flag for Context Identifier Extention (part of second byte
+ *          of LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC2_CID_EXT      (0x80)
+
+/**
+ * @brief   Flag for Source Address Compression (part of second byte
+ *          of LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC2_SAC          (0x40)
+
+/**
+ * @brief   Bits for Source Address Mode (part of second byte of
+ *          LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC2_SAM          (0x30)
+
+/**
+ * @brief   Flag for Destination Address Compression (part of second
+ *          byte of LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC2_DAC          (0x04)
+
+/**
+ * @brief   Bits for Destination Address Mode (part of second byte of
+ *          LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC2_DAM          (0x03)
+
+/**
+ * @brief   Flag for Multicast Compression (part of second byte of
+ *          LOWPAN_IPHC).
+ * @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
+ *          RFC 6282, section 3.1.1
+ *      </a>
+ */
+#define NG_SIXLOWPAN_IPHC2_M            (0x08)
+
+/**
+ * @brief   6LoWPAN IPHC header length
+ */
+#define NG_SIXLOWPAN_IPHC_HDR_LEN       (2)
+
+/**
+ * @brief   6LoWPAN context idendifier extension header length
+ */
+#define NG_SIXLOWPAN_IPHC_CID_EXT_LEN   (1)
+
+/**
+ * @brief   Checks if datagram is an IPHC datagram.
+ *
+ * @param[in] data  Data of a datagram, may not be NULL.
+ *
+ * @return  true, if datagram is an IPHC datagram.
+ * @return  false, if datagram is not an IPHC datagram.
+ */
+static inline bool ng_sixlowpan_iphc_is(uint8_t *data)
+{
+    return ((*data & NG_SIXLOWPAN_IPHC1_DISP_MASK) == NG_SIXLOWPAN_IPHC1_DISP);
+}
+
+/**
+ * @brief   Decompresses a received 6LoWPAN IPHC frame.
+ *
+ * @param[in,out] pkt   A received 6LoWPAN IPHC frame. Will be translated
+ *                      into an IPv6 packet.
+ *
+ * @return  true, on success
+ * @return  false, on error.
+ */
+bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt);
+
+/**
+ * @brief   Compresses a 6LoWPAN for IPHC.
+ *
+ * @param[in,out] pkt   A 6LoWPAN frame with an uncompressed IPv6 header to
+ *                      send. Will be translated to an 6LoWPAN IPHC frame.
+ *
+ * @return  true, on success
+ * @return  false, on error.
+ */
+bool ng_sixlowpan_iphc_encode(ng_pktsnip_t *pkt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_SIXLOWPAN_IPHC_H_ */
+/** @} */
diff --git a/sys/include/net/ng_sixlowpan/netif.h b/sys/include/net/ng_sixlowpan/netif.h
index 11d845eb43..ce08ff9409 100644
--- a/sys/include/net/ng_sixlowpan/netif.h
+++ b/sys/include/net/ng_sixlowpan/netif.h
@@ -20,6 +20,8 @@
 #ifndef NG_SIXLOWPAN_NETIF_H_
 #define NG_SIXLOWPAN_NETIF_H_
 
+#include <stdbool.h>
+
 #include "kernel_types.h"
 
 #ifdef __cplusplus
@@ -32,6 +34,9 @@ extern "C" {
 typedef struct {
     kernel_pid_t pid;       /**< PID of the interface */
     uint16_t max_frag_size; /**< Maximum fragment size for this interface */
+#ifdef MODULE_NG_SIXLOWPAN_IPHC
+    bool iphc_enabled;      /**< enable or disable IPHC */
+#endif
 } ng_sixlowpan_netif_t;
 
 /**
diff --git a/sys/net/network_layer/ng_sixlowpan/iphc/Makefile b/sys/net/network_layer/ng_sixlowpan/iphc/Makefile
new file mode 100644
index 0000000000..766032ebe7
--- /dev/null
+++ b/sys/net/network_layer/ng_sixlowpan/iphc/Makefile
@@ -0,0 +1,3 @@
+MODULE = ng_sixlowpan_iphc
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/network_layer/ng_sixlowpan/iphc/ng_sixlowpan_iphc.c b/sys/net/network_layer/ng_sixlowpan/iphc/ng_sixlowpan_iphc.c
new file mode 100644
index 0000000000..babdfeb593
--- /dev/null
+++ b/sys/net/network_layer/ng_sixlowpan/iphc/ng_sixlowpan_iphc.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ */
+
+#include <stdbool.h>
+
+#include "byteorder.h"
+#include "net/ng_ipv6/hdr.h"
+#include "net/ng_netbase.h"
+#include "net/ng_sixlowpan/ctx.h"
+#include "utlist.h"
+
+#include "net/ng_sixlowpan/iphc.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+/* dispatch byte definitions */
+#define IPHC1_IDX                   (0U)
+#define IPHC2_IDX                   (1U)
+#define CID_EXT_IDX                 (2U)
+
+/* compression values for traffic class and flow label */
+#define IPHC_TF_ECN_DSCP_FL         (0x00)
+#define IPHC_TF_ECN_FL              (0x08)
+#define IPHC_TF_ECN_DSCP            (0x10)
+#define IPHC_TF_ECN_ELIDE           (0x18)
+
+/* compression values for hop limit */
+#define IPHC_HL_INLINE              (0x00)
+#define IPHC_HL_1                   (0x01)
+#define IPHC_HL_64                  (0x02)
+#define IPHC_HL_255                 (0x03)
+
+/* compression values for source address */
+#define IPHC_SAC_SAM_FULL           (0x00)
+#define IPHC_SAC_SAM_64             (0x10)
+#define IPHC_SAC_SAM_16             (0x20)
+#define IPHC_SAC_SAM_L2             (0x30)
+#define IPHC_SAC_SAM_UNSPEC         (0x40)
+#define IPHC_SAC_SAM_CTX_64         (0x50)
+#define IPHC_SAC_SAM_CTX_16         (0x60)
+#define IPHC_SAC_SAM_CTX_L2         (0x70)
+
+/* compression values for destination address */
+#define IPHC_M_DAC_DAM_U_FULL       (0x00)
+#define IPHC_M_DAC_DAM_U_64         (0x01)
+#define IPHC_M_DAC_DAM_U_16         (0x02)
+#define IPHC_M_DAC_DAM_U_L2         (0x03)
+#define IPHC_M_DAC_DAM_U_UNSPEC     (0x04)
+#define IPHC_M_DAC_DAM_U_CTX_64     (0x05)
+#define IPHC_M_DAC_DAM_U_CTX_16     (0x06)
+#define IPHC_M_DAC_DAM_U_CTX_L2     (0x07)
+#define IPHC_M_DAC_DAM_M_FULL       (0x08)
+#define IPHC_M_DAC_DAM_M_48         (0x09)
+#define IPHC_M_DAC_DAM_M_32         (0x0a)
+#define IPHC_M_DAC_DAM_M_8          (0x0b)
+#define IPHC_M_DAC_DAM_M_UC_PREFIX  (0x0c)
+
+static network_uint64_t _init_iid(uint8_t *l2addr, size_t l2addr_len)
+{
+    network_uint64_t res = { 0 };
+
+    if (l2addr_len <= 4) {
+        res = byteorder_htonll(0x000000fffe000000);
+
+        if (l2addr_len == 1) {
+            res.u8[7] = l2addr[0];
+        }
+        else if (l2addr_len == 2) {
+            res.u8[6] = l2addr[0];
+            res.u8[7] = l2addr[1];
+        }
+        else if (l2addr_len == 4) {
+            res.u8[0] = l2addr[0];
+            res.u8[1] = l2addr[1];
+            res.u8[6] = l2addr[2];
+            res.u8[7] = l2addr[3];
+        }
+    }
+    else if (l2addr_len == 8) {
+        network_uint64_t *l2addr_u64 = (network_uint64_t *)l2addr;
+        res = *l2addr_u64;
+        res.u8[0] ^= 0x02;     /* swap local/universal bit */
+    }
+
+    return res;
+}
+
+static inline bool _context_overlaps_iid(ng_sixlowpan_ctx_t *ctx,
+                                         ng_ipv6_addr_t *addr,
+                                         network_uint64_t *iid)
+{
+    uint8_t byte_mask[] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+    if (ctx == NULL) {
+        return false;
+    }
+
+    return ((ctx->prefix_len == 128) || /* Full-length prefix overlaps IID in any case */
+            ((ctx->prefix_len > 64) &&  /* otherwise, if bigger than 64-bit */
+             /* compare bytes until prefix length with IID */
+             (memcmp(&(addr->u8[(ctx->prefix_len / 8) + 1]),
+                     &(iid->u8[(ctx->prefix_len / 8) - 7]),
+                     sizeof(network_uint64_t) - ((ctx->prefix_len / 8) - 7)) == 0) &&
+             /* compare bits at prefix length with IID */
+             (addr->u8[(ctx->prefix_len / 8)] & byte_mask[ctx->prefix_len % 8]) ==
+             (iid->u8[(ctx->prefix_len / 8) - 8] & byte_mask[ctx->prefix_len % 8])));
+}
+
+bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt)
+{
+    ng_netif_hdr_t *netif_hdr = pkt->next->data;
+    ng_ipv6_hdr_t *ipv6_hdr;
+    uint8_t *iphc_hdr = pkt->data;
+    uint16_t payload_offset = NG_SIXLOWPAN_IPHC_HDR_LEN;
+    ng_sixlowpan_ctx_t *ctx = NULL;
+    ng_pktsnip_t *payload;
+    ng_pktsnip_t *ipv6 = ng_pktbuf_add(NULL, NULL, sizeof(ng_ipv6_hdr_t),
+                                       NG_NETTYPE_IPV6);
+
+    if (ipv6 == NULL) {
+        DEBUG("6lo iphc: error allocating ipv6 header space\n");
+        return false;
+    }
+
+    ipv6_hdr = ipv6->data;
+
+    if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_CID_EXT) {
+        payload_offset++;
+    }
+
+    ng_ipv6_hdr_set_version(ipv6_hdr);
+
+    switch (iphc_hdr[IPHC1_IDX] & NG_SIXLOWPAN_IPHC1_TF) {
+        case IPHC_TF_ECN_DSCP_FL:
+            ng_ipv6_hdr_set_tc(ipv6_hdr, iphc_hdr[payload_offset++]);
+            ipv6_hdr->v_tc_fl.u8[1] |= iphc_hdr[payload_offset++] & 0x0f;
+            ipv6_hdr->v_tc_fl.u8[2] |= iphc_hdr[payload_offset++];
+            ipv6_hdr->v_tc_fl.u8[3] |= iphc_hdr[payload_offset++];
+            break;
+
+        case IPHC_TF_ECN_FL:
+            ng_ipv6_hdr_set_tc_ecn(ipv6_hdr, iphc_hdr[payload_offset] >> 6);
+            ng_ipv6_hdr_set_tc_dscp(ipv6_hdr, 0);
+            ipv6_hdr->v_tc_fl.u8[1] |= iphc_hdr[payload_offset++] & 0x0f;
+            ipv6_hdr->v_tc_fl.u8[2] |= iphc_hdr[payload_offset++];
+            ipv6_hdr->v_tc_fl.u8[3] |= iphc_hdr[payload_offset++];
+            break;
+
+        case IPHC_TF_ECN_DSCP:
+            ng_ipv6_hdr_set_tc(ipv6_hdr, iphc_hdr[payload_offset++]);
+            ng_ipv6_hdr_set_fl(ipv6_hdr, 0);
+            break;
+
+        case IPHC_TF_ECN_ELIDE:
+            ng_ipv6_hdr_set_tc(ipv6_hdr, 0);
+            ng_ipv6_hdr_set_fl(ipv6_hdr, 0);
+            break;
+    }
+
+    if (!(iphc_hdr[IPHC1_IDX] & NG_SIXLOWPAN_IPHC1_NH)) {
+        ipv6_hdr->nh = iphc_hdr[payload_offset++];
+    }
+
+    switch (iphc_hdr[IPHC1_IDX] & NG_SIXLOWPAN_IPHC1_HL) {
+        case IPHC_HL_INLINE:
+            ipv6_hdr->hl = iphc_hdr[payload_offset++];
+            break;
+
+        case IPHC_HL_1:
+            ipv6_hdr->hl = 1;
+            break;
+
+        case IPHC_HL_64:
+            ipv6_hdr->hl = 64;
+            break;
+
+        case IPHC_HL_255:
+            ipv6_hdr->hl = 255;
+            break;
+    }
+
+    if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_SAC) {
+        uint8_t sci = 0;
+
+        if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_CID_EXT) {
+            sci = iphc_hdr[CID_EXT_IDX] >> 4;
+        }
+
+        if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_SAM) {
+            ctx = ng_sixlowpan_ctx_lookup_id(sci);
+
+            if (ctx == NULL) {
+                DEBUG("6lo iphc: could not find source context\n");
+                return false;
+            }
+        }
+    }
+
+    switch (iphc_hdr[IPHC2_IDX] & (NG_SIXLOWPAN_IPHC2_SAC | NG_SIXLOWPAN_IPHC2_SAM)) {
+        case IPHC_SAC_SAM_FULL:
+            /* take full 128 from inline */
+            memcpy(&(ipv6_hdr->src), iphc_hdr + payload_offset, 16);
+            payload_offset += 16;
+            break;
+
+        case IPHC_SAC_SAM_64:
+            ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->src);
+            memcpy(ipv6_hdr->src.u8 + 8, iphc_hdr + payload_offset, 8);
+            payload_offset += 8;
+            break;
+
+        case IPHC_SAC_SAM_16:
+            ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->src);
+            ipv6_hdr->src.u32[2] = byteorder_htonl(0x000000ff);
+            ipv6_hdr->src.u16[6] = byteorder_htons(0xfe00);
+            memcpy(ipv6_hdr->src.u8 + 14, iphc_hdr + payload_offset, 2);
+            payload_offset += 2;
+            break;
+
+        case IPHC_SAC_SAM_L2:
+            ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->src);
+            ipv6_hdr->src.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr),
+                                             netif_hdr->src_l2addr_len);
+            break;
+
+        case IPHC_SAC_SAM_UNSPEC:
+            ng_ipv6_addr_set_unspecified(&ipv6_hdr->src);
+            break;
+
+        case IPHC_SAC_SAM_CTX_64:
+            memcpy(ipv6_hdr->src.u8 + 8, iphc_hdr + payload_offset, 8);
+            ng_ipv6_addr_init_prefix(&ipv6_hdr->src, &ctx->prefix,
+                                     ctx->prefix_len);
+            payload_offset += 8;
+            break;
+
+        case IPHC_SAC_SAM_CTX_16:
+            ipv6_hdr->src.u32[2] = byteorder_htonl(0x000000ff);
+            ipv6_hdr->src.u16[6] = byteorder_htons(0xfe00);
+            memcpy(ipv6_hdr->src.u8 + 14, iphc_hdr + payload_offset, 2);
+            ng_ipv6_addr_init_prefix(&ipv6_hdr->src, &ctx->prefix,
+                                     ctx->prefix_len);
+            payload_offset += 2;
+            break;
+
+        case IPHC_SAC_SAM_CTX_L2:
+            ipv6_hdr->src.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr),
+                                             netif_hdr->src_l2addr_len);
+            ng_ipv6_addr_init_prefix(&ipv6_hdr->src, &ctx->prefix,
+                                     ctx->prefix_len);
+            break;
+    }
+
+    if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_DAC) {
+        uint8_t dci = 0;
+
+        if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_CID_EXT) {
+            dci = iphc_hdr[CID_EXT_IDX] & 0x0f;
+        }
+
+        if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_DAM) {
+            ctx = ng_sixlowpan_ctx_lookup_id(dci);
+
+            if (ctx == NULL) {
+                DEBUG("6lo iphc: could not find destination context\n");
+                return false;
+            }
+        }
+    }
+
+    switch (iphc_hdr[IPHC2_IDX] & (NG_SIXLOWPAN_IPHC2_M | NG_SIXLOWPAN_IPHC2_DAC |
+                                   NG_SIXLOWPAN_IPHC2_DAM)) {
+        case IPHC_M_DAC_DAM_U_FULL:
+        case IPHC_M_DAC_DAM_M_FULL:
+            memcpy(&(ipv6_hdr->dst.u8), iphc_hdr + payload_offset, 16);
+            payload_offset += 16;
+            break;
+
+        case IPHC_M_DAC_DAM_U_64:
+            ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->dst);
+            memcpy(ipv6_hdr->dst.u8 + 8, iphc_hdr + payload_offset, 8);
+            payload_offset += 8;
+            break;
+
+        case IPHC_M_DAC_DAM_U_16:
+            ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->dst);
+            ipv6_hdr->dst.u32[2] = byteorder_htonl(0x000000ff);
+            ipv6_hdr->dst.u16[6] = byteorder_htons(0xfe00);
+            memcpy(ipv6_hdr->dst.u8 + 14, iphc_hdr + payload_offset, 2);
+            payload_offset += 2;
+            break;
+
+        case IPHC_M_DAC_DAM_U_L2:
+            ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->dst);
+            ipv6_hdr->dst.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr),
+                                             netif_hdr->src_l2addr_len);
+            break;
+
+        case IPHC_M_DAC_DAM_U_CTX_64:
+            memcpy(ipv6_hdr->dst.u8 + 8, iphc_hdr + payload_offset, 8);
+            ng_ipv6_addr_init_prefix(&ipv6_hdr->dst, &ctx->prefix,
+                                     ctx->prefix_len);
+            payload_offset += 8;
+            break;
+
+        case IPHC_M_DAC_DAM_U_CTX_16:
+            ipv6_hdr->dst.u32[2] = byteorder_htonl(0x000000ff);
+            ipv6_hdr->dst.u16[6] = byteorder_htons(0xfe00);
+            memcpy(ipv6_hdr->dst.u8 + 14, iphc_hdr + payload_offset, 2);
+            ng_ipv6_addr_init_prefix(&ipv6_hdr->dst, &ctx->prefix,
+                                     ctx->prefix_len);
+            payload_offset += 2;
+            break;
+
+        case IPHC_M_DAC_DAM_U_CTX_L2:
+            ipv6_hdr->dst.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr),
+                                             netif_hdr->src_l2addr_len);
+            ng_ipv6_addr_init_prefix(&ipv6_hdr->dst, &ctx->prefix,
+                                     ctx->prefix_len);
+            break;
+
+        case IPHC_M_DAC_DAM_M_48:
+            /* ffXX::00XX:XXXX:XXXX */
+            ng_ipv6_addr_set_unspecified(&ipv6_hdr->dst);
+            ipv6_hdr->dst.u8[0] = 0xff;
+            ipv6_hdr->dst.u8[1] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[11] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[12] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[13] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[14] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[15] = iphc_hdr[payload_offset++];
+            break;
+
+        case IPHC_M_DAC_DAM_M_32:
+            /* ffXX::00XX:XXXX */
+            ng_ipv6_addr_set_unspecified(&ipv6_hdr->dst);
+            ipv6_hdr->dst.u8[0] = 0xff;
+            ipv6_hdr->dst.u8[1] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[13] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[14] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[15] = iphc_hdr[payload_offset++];
+            break;
+
+        case IPHC_M_DAC_DAM_M_8:
+            /* ffXX::XX: */
+            ng_ipv6_addr_set_unspecified(&ipv6_hdr->dst);
+            ipv6_hdr->dst.u8[0] = 0xff;
+            ipv6_hdr->dst.u8[1] = iphc_hdr[payload_offset++];
+            ipv6_hdr->dst.u8[15] = iphc_hdr[payload_offset++];
+            break;
+
+        case IPHC_M_DAC_DAM_M_UC_PREFIX:
+            do {
+                uint8_t orig_ctx_len = ctx->prefix_len;
+
+                ng_ipv6_addr_set_unspecified(&ipv6_hdr->dst);
+
+                if (ctx->prefix_len > 64) {
+                    ctx->prefix_len = 64;
+                }
+
+                ipv6_hdr->dst.u8[0] = 0xff;
+                ipv6_hdr->dst.u8[1] = iphc_hdr[payload_offset++];
+                ipv6_hdr->dst.u8[2] = iphc_hdr[payload_offset++];
+                ipv6_hdr->dst.u8[3] = ctx->prefix_len;
+                ng_ipv6_addr_init_prefix((ng_ipv6_addr_t *)ipv6_hdr->dst.u8 + 4,
+                                         &ctx->prefix, ctx->prefix_len);
+                memcpy(ipv6_hdr->dst.u8 + 12, iphc_hdr + payload_offset + 2, 4);
+
+                payload_offset += 4;
+
+                ctx->prefix_len = orig_ctx_len;
+            } while (0);    /* ANSI-C compatible block creation for orig_ctx_len allocation*/
+            break;
+
+        default:
+            DEBUG("6lo iphc: unspecified or reserved M, DAC, DAM combination\n");
+            return false;
+
+    }
+
+    /* TODO: add next header decoding */
+
+    /* remove 6LoWPAN dispatch */
+    payload = ng_pktbuf_add(pkt, pkt->data, payload_offset, NG_NETTYPE_SIXLOWPAN);
+    pkt = ng_pktbuf_remove_snip(pkt, payload);
+
+    /* insert IPv6 header */
+    ipv6->next = pkt->next;
+    pkt->next = ipv6;
+
+    return true;
+}
+
+bool ng_sixlowpan_iphc_encode(ng_pktsnip_t *pkt)
+{
+    ng_netif_hdr_t *netif_hdr = pkt->data;
+    ng_ipv6_hdr_t *ipv6_hdr = pkt->next->data;
+    uint8_t *iphc_hdr;
+    uint16_t inline_pos = NG_SIXLOWPAN_IPHC_HDR_LEN;
+    bool addr_comp = false;
+    ng_sixlowpan_ctx_t *src_ctx = NULL, *dst_ctx = NULL;
+    ng_pktsnip_t *dispatch = ng_pktbuf_add(NULL, NULL, pkt->next->size,
+                                           NG_NETTYPE_SIXLOWPAN);
+
+    if (dispatch == NULL) {
+        DEBUG("6lo iphc: error allocating dispatch space\n");
+        return false;
+    }
+
+    iphc_hdr = dispatch->data;
+
+    /* set initial dispatch value*/
+    iphc_hdr[IPHC1_IDX] = NG_SIXLOWPAN_IPHC1_DISP;
+    iphc_hdr[2] = 0;
+
+    /* check for available contexts */
+    if (!ng_ipv6_addr_is_unspecified(&(ipv6_hdr->src))) {
+        src_ctx = ng_sixlowpan_ctx_lookup_addr(&(ipv6_hdr->src));
+    }
+
+    if (!ng_ipv6_addr_is_multicast(&ipv6_hdr->dst)) {
+        dst_ctx = ng_sixlowpan_ctx_lookup_addr(&(ipv6_hdr->dst));
+    }
+
+    /* if contexts available and both != 0 */
+    /* since this moves inline_pos we have to do this ahead*/
+    if (((src_ctx != NULL) && (src_ctx->id != 0)) ||
+        ((dst_ctx != NULL) && (dst_ctx->id != 0))) {
+        /* add context identifier extension */
+        iphc_hdr[IPHC2_IDX] |= NG_SIXLOWPAN_IPHC2_CID_EXT;
+        iphc_hdr[CID_EXT_IDX] = 0;
+
+        /* move position to behind CID extension */
+        inline_pos += NG_SIXLOWPAN_IPHC_CID_EXT_LEN;
+    }
+
+    /* compress flow label and traffic class */
+    if (ng_ipv6_hdr_get_fl(ipv6_hdr) == 0) {
+        if (ng_ipv6_hdr_get_tc(ipv6_hdr) == 0) {
+            /* elide both traffic class and flow label */
+            iphc_hdr[IPHC1_IDX] |= IPHC_TF_ECN_ELIDE;
+        }
+        else {
+            /* elide flow label, traffic class (ECN + DSCP) inline (1 byte) */
+            iphc_hdr[IPHC1_IDX] |= IPHC_TF_ECN_DSCP;
+            iphc_hdr[inline_pos++] = ng_ipv6_hdr_get_tc(ipv6_hdr);
+        }
+    }
+    else {
+        if (ng_ipv6_hdr_get_tc_dscp(ipv6_hdr) == 0) {
+            /* elide DSCP, ECN + 2-bit pad + flow label inline (3 byte) */
+            iphc_hdr[IPHC1_IDX] |= IPHC_TF_ECN_FL;
+            iphc_hdr[inline_pos++] = (uint8_t)((ng_ipv6_hdr_get_tc_ecn(ipv6_hdr) << 6) |
+                                               ((ng_ipv6_hdr_get_fl(ipv6_hdr) & 0x000f0000) >> 16));
+        }
+        else {
+            /* ECN + DSCP + 4-bit pad + flow label (4 bytes) */
+            iphc_hdr[IPHC1_IDX] |= IPHC_TF_ECN_DSCP_FL;
+            iphc_hdr[inline_pos++] = ng_ipv6_hdr_get_tc(ipv6_hdr);
+            iphc_hdr[inline_pos++] = (uint8_t)((ng_ipv6_hdr_get_fl(ipv6_hdr) & 0x000f0000) >> 16);
+        }
+
+        /* copy remaining byteos of flow label */
+        iphc_hdr[inline_pos++] = (uint8_t)((ng_ipv6_hdr_get_fl(ipv6_hdr) & 0x0000ff00) >> 8);
+        iphc_hdr[inline_pos++] = (uint8_t)((ng_ipv6_hdr_get_fl(ipv6_hdr) & 0x000000ff) >> 8);
+    }
+
+    /* compress next header */
+    switch (ipv6_hdr->nh) {
+        /* TODO: add next header compression and set NH bit */
+        default:
+            iphc_hdr[inline_pos++] = ipv6_hdr->nh;
+            break;
+    }
+
+    /* compress hop limit */
+    switch (ipv6_hdr->hl) {
+        case 1:
+            iphc_hdr[IPHC1_IDX] |= IPHC_HL_1;
+            break;
+
+        case 64:
+            iphc_hdr[IPHC1_IDX] |= IPHC_HL_64;
+            break;
+
+        case 255:
+            iphc_hdr[IPHC1_IDX] |= IPHC_HL_255;
+            break;
+
+        default:
+            iphc_hdr[IPHC1_IDX] |= IPHC_HL_INLINE;
+            iphc_hdr[inline_pos++] = ipv6_hdr->hl;
+            break;
+    }
+
+    if (ng_ipv6_addr_is_unspecified(&(ipv6_hdr->src))) {
+        iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_UNSPEC;
+    }
+    else {
+        if (src_ctx != NULL) {
+            /* stateful source address compression */
+            iphc_hdr[IPHC2_IDX] |= NG_SIXLOWPAN_IPHC2_SAC;
+
+            if (src_ctx->id != 0) { /* context id is elided */
+                iphc_hdr[CID_EXT_IDX] |= (src_ctx->id << 4);
+            }
+        }
+
+        if ((src_ctx != NULL) || ng_ipv6_addr_is_link_local(&(ipv6_hdr->src))) {
+            uint16_t l2src_len = 0;
+            uint8_t l2src[8];
+
+            if (netif_hdr->src_l2addr_len > 0) {
+                l2src_len = netif_hdr->src_l2addr_len;
+                memcpy(l2src, ng_netif_hdr_get_src_addr(netif_hdr), l2src_len);
+            }
+            else {
+                bool try_long = false;
+
+                if ((ng_netapi_get(netif_hdr->if_pid, NETCONF_OPT_ADDR_LEN, 0,
+                                   &l2src_len, sizeof(l2src_len)) >= 0) &&
+                    (l2src_len >= 8)) {
+                    try_long = true;
+                }
+
+                if ((!try_long) || (ng_netapi_get(netif_hdr->if_pid,
+                                                  NETCONF_OPT_ADDRESS_LONG, 0,
+                                                  &l2src, sizeof(l2src)) < 0)) {
+                    if (ng_netapi_get(netif_hdr->if_pid, NETCONF_OPT_ADDRESS,
+                                      0, &l2src, sizeof(l2src)) < 0) {
+                        l2src_len = 0;
+                    }
+                }
+
+            }
+
+            if (l2src_len > 0) {
+                network_uint64_t iid = _init_iid(l2src, l2src_len);
+
+                if ((memcmp(ipv6_hdr->src.u64 + 1, &iid,
+                            sizeof(network_uint64_t)) == 0) ||
+                    _context_overlaps_iid(src_ctx, &ipv6_hdr->src, &iid)) {
+                    /* 0 bits. The address is derived from link-layer address */
+                    iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_L2;
+                }
+                else if ((byteorder_ntohl(ipv6_hdr->src.u32[2]) == 0x000000ff) &&
+                         (byteorder_ntohs(ipv6_hdr->src.u16[6]) == 0xfe00)) {
+                    /* 16 bits. The address is derived using 16 bits carried inline */
+                    iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_16;
+                    memcpy(iphc_hdr + inline_pos, ipv6_hdr->src.u16 + 7, 2);
+                    inline_pos += 2;
+                }
+                else {
+                    /* 64 bits. The address is derived using 64 bits carried inline */
+                    iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_64;
+                    memcpy(iphc_hdr + inline_pos, ipv6_hdr->src.u64 + 1, 8);
+                    inline_pos += 8;
+                }
+
+                addr_comp = true;
+            }
+        }
+
+        if (!addr_comp) {
+            /* full address is carried inline */
+            iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_FULL;
+            memcpy(iphc_hdr + inline_pos, &ipv6_hdr->src, 16);
+            inline_pos += 16;
+        }
+    }
+
+    addr_comp = false;
+
+    /* M: Multicast compression */
+    if (ng_ipv6_addr_is_multicast(&(ipv6_hdr->dst))) {
+        iphc_hdr[IPHC2_IDX] |= NG_SIXLOWPAN_IPHC2_M;
+
+        /* if multicast address is of format ffXX::XXXX:XXXX:XXXX */
+        if ((ipv6_hdr->dst.u16[1].u16 == 0) &&
+            (ipv6_hdr->dst.u32[1].u32 == 0) &&
+            (ipv6_hdr->dst.u16[4].u16 == 0)) {
+            /* if multicast address is of format ff02::XX */
+            if ((ipv6_hdr->dst.u8[1] == 2) &&
+                (ipv6_hdr->dst.u32[2].u32 == 0) &&
+                (ipv6_hdr->dst.u16[6].u16 == 0) &&
+                (ipv6_hdr->dst.u8[14] == 0)) {
+                /* 8 bits. The address is derived using 8 bits carried inline */
+                iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_M_8;
+                iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[15];
+                addr_comp = true;
+            }
+            /* if multicast address is of format ffXX::XX:XXXX */
+            else if ((ipv6_hdr->dst.u16[5].u16 == 0) &&
+                     (ipv6_hdr->dst.u8[12] == 0)) {
+                /* 32 bits. The address is derived using 32 bits carried inline */
+                iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_M_32;
+                iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[1];
+                memcpy(iphc_hdr + inline_pos, ipv6_hdr->dst.u8 + 13, 3);
+                inline_pos += 3;
+                addr_comp = true;
+            }
+            /* if multicast address is of format ffXX::XX:XXXX:XXXX */
+            else if (ipv6_hdr->dst.u8[10] == 0) {
+                /* 32 bits. The address is derived using 32 bits carried inline */
+                iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_M_32;
+                iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[1];
+                memcpy(iphc_hdr + inline_pos, ipv6_hdr->dst.u8 + 13, 3);
+                inline_pos += 3;
+                addr_comp = true;
+            }
+        }
+        /* try unicast prefix based compression */
+        else {
+            ng_sixlowpan_ctx_t *ctx;
+            ng_ipv6_addr_t unicast_prefix;
+            unicast_prefix.u16[0] = ipv6_hdr->dst.u16[2];
+            unicast_prefix.u16[1] = ipv6_hdr->dst.u16[3];
+            unicast_prefix.u16[2] = ipv6_hdr->dst.u16[4];
+            unicast_prefix.u16[3] = ipv6_hdr->dst.u16[5];
+
+            ctx = ng_sixlowpan_ctx_lookup_addr(&unicast_prefix);
+
+            if ((ctx != NULL) && (ctx->prefix_len == ipv6_hdr->dst.u8[3])) {
+                /* Unicast prefix based IPv6 multicast address with given
+                 * context for unicast prefix -> context based compression */
+                iphc_hdr[IPHC2_IDX] |= NG_SIXLOWPAN_IPHC2_DAC;
+                iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[1];
+                iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[2];
+                memcpy(iphc_hdr + inline_pos, ipv6_hdr->dst.u16 + 6, 4);
+                inline_pos += 4;
+                addr_comp = true;
+            }
+        }
+    }
+    else if (((dst_ctx != NULL) || ng_ipv6_addr_is_link_local(&ipv6_hdr->dst)) &&
+             (netif_hdr->dst_l2addr_len > 0)) {
+        network_uint64_t iid = _init_iid(ng_netif_hdr_get_dst_addr(netif_hdr),
+                                         netif_hdr->dst_l2addr_len);
+
+        if ((memcmp(&(ipv6_hdr->dst.u8[8]), &iid, sizeof(uint64_t)) == 0) ||
+            _context_overlaps_iid(dst_ctx, &(ipv6_hdr->dst), &iid)) {
+            /* 0 bits. The address is derived using the link-layer address */
+            iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_U_L2;
+            addr_comp = true;
+        }
+        else if ((byteorder_ntohl(ipv6_hdr->dst.u32[2]) == 0x000000ff) &&
+                 (byteorder_ntohs(ipv6_hdr->dst.u16[6]) == 0xfe00)) {
+            /* 16 bits. The address is derived using 16 bits carried inline */
+            iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_U_16;
+            memcpy(&(iphc_hdr[inline_pos]), &(ipv6_hdr->dst.u16[7]), 2);
+            inline_pos += 2;
+            addr_comp = true;
+        }
+        else {
+            /* 64 bits. The address is derived using 64 bits carried inline */
+            iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_U_64;
+            memcpy(&(iphc_hdr[inline_pos]), &(ipv6_hdr->dst.u8[8]), 8);
+            inline_pos += 8;
+            addr_comp = true;
+        }
+    }
+
+    if (!addr_comp) {
+        /* full destination address is carried inline */
+        iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_FULL;
+        memcpy(iphc_hdr + inline_pos, &ipv6_hdr->dst, 16);
+        inline_pos += 16;
+    }
+
+    /* shrink dispatch allocation to final size */
+    /* NOTE: Since this only shrinks the data nothing bad SHOULD happen ;-) */
+    ng_pktbuf_realloc_data(dispatch, (size_t)inline_pos);
+
+    /* remove IPv6 header */
+    pkt = ng_pktbuf_remove_snip(pkt, pkt->next);
+
+    /* insert dispatch into packet */
+    dispatch->next = pkt->next;
+    pkt->next = dispatch;
+
+    return true;
+}
+
+/** @} */
diff --git a/sys/net/network_layer/ng_sixlowpan/netif/ng_sixlowpan_netif.c b/sys/net/network_layer/ng_sixlowpan/netif/ng_sixlowpan_netif.c
index 03949a3cca..1fcbed08e7 100644
--- a/sys/net/network_layer/ng_sixlowpan/netif/ng_sixlowpan_netif.c
+++ b/sys/net/network_layer/ng_sixlowpan/netif/ng_sixlowpan_netif.c
@@ -49,6 +49,9 @@ void ng_sixlowpan_netif_add(kernel_pid_t pid, uint16_t max_frag_size)
 
     free_entry->pid = pid;
     free_entry->max_frag_size = max_frag_size;
+#ifdef MODULE_NG_SIXLOWPAN_IPHC
+    free_entry->iphc_enabled = true;
+#endif
     return;
 }
 
diff --git a/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c b/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c
index f008e8f744..af0a9a76fd 100644
--- a/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c
+++ b/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c
@@ -19,6 +19,7 @@
 
 #include "net/ng_sixlowpan.h"
 #include "net/ng_sixlowpan/frag.h"
+#include "net/ng_sixlowpan/iphc.h"
 #include "net/ng_sixlowpan/netif.h"
 
 #define ENABLE_DEBUG    (0)
@@ -101,6 +102,18 @@ void _receive(ng_pktsnip_t *pkt)
         return;
     }
 
+#ifdef MODULE_NG_SIXLOWPAN_IPHC
+    if (ng_sixlowpan_iphc_is(payload->data)) {
+        if (!ng_sixlowpan_iphc_decode(pkt)) {
+            DEBUG("6lo: error on IPHC decoding\n");
+            ng_pktbuf_release(pkt);
+            return;
+        }
+        LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_IPV6);
+
+    }
+#endif
+
     payload->type = NG_NETTYPE_IPV6;
 
     entry = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL);
@@ -151,6 +164,8 @@ void _send(ng_pktsnip_t *pkt)
      * length is the length of the IPv6 datagram + 6LoWPAN dispatches,
      * while the datagram size is the size of only the IPv6 datagram */
     payload_len = ng_pkt_len(ipv6);
+    /* cppcheck: datagram_size will be read by ng_sixlowpan_frag implementation */
+    /* cppcheck-suppress unreadVariable */
     datagram_size = (uint16_t)payload_len;
 
     /* use sixlowpan packet snip as temporary one */
@@ -163,23 +178,6 @@ void _send(ng_pktsnip_t *pkt)
     }
 
     pkt = sixlowpan;
-
-    DEBUG("6lo: Send uncompressed\n");
-
-    sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN);
-
-    if (sixlowpan == NULL) {
-        DEBUG("6lo: no space left in packet buffer\n");
-        ng_pktbuf_release(pkt);
-        return;
-    }
-
-    sixlowpan->next = ipv6;
-    pkt->next = sixlowpan;
-    disp = sixlowpan->data;
-    disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
-    payload_len++;
-
     iface = ng_sixlowpan_netif_get(hdr->if_pid);
 
     if (iface == NULL) {
@@ -192,11 +190,56 @@ void _send(ng_pktsnip_t *pkt)
         }
 
         ng_sixlowpan_netif_add(hdr->if_pid, max_frag_size);
+        iface = ng_sixlowpan_netif_get(hdr->if_pid);
     }
     else {
         max_frag_size = iface->max_frag_size;
     }
 
+#ifdef MODULE_NG_SIXLOWPAN_IPHC
+    if (iface->iphc_enabled) {
+        if (!ng_sixlowpan_iphc_encode(pkt)) {
+            DEBUG("6lo: error on IPHC encoding\n");
+            ng_pktbuf_release(pkt);
+            return;
+        }
+    }
+    else {
+        DEBUG("6lo: Send uncompressed\n");
+
+        sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t),
+                                  NG_NETTYPE_SIXLOWPAN);
+
+        if (sixlowpan == NULL) {
+            DEBUG("6lo: no space left in packet buffer\n");
+            ng_pktbuf_release(pkt);
+            return;
+        }
+
+        sixlowpan->next = ipv6;
+        pkt->next = sixlowpan;
+        disp = sixlowpan->data;
+        disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
+        payload_len++;
+    }
+#else
+    DEBUG("6lo: Send uncompressed\n");
+
+    sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN);
+
+    if (sixlowpan == NULL) {
+        DEBUG("6lo: no space left in packet buffer\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    sixlowpan->next = ipv6;
+    pkt->next = sixlowpan;
+    disp = sixlowpan->data;
+    disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
+    payload_len++;
+#endif
+
     DEBUG("6lo: max_frag_size = %" PRIu16 " for interface %"
           PRIkernel_pid "\n", max_frag_size, hdr->if_pid);
 
-- 
GitLab