From dcfa2681d68fc1b833c5ec9eb5aa6505c59b4c29 Mon Sep 17 00:00:00 2001
From: Martine Lenders <mlenders@inf.fu-berlin.de>
Date: Sat, 7 Mar 2015 21:46:57 +0100
Subject: [PATCH] ng_ipv6_ext: initial import of extension header handling

---
 Makefile.dep                                  |  12 ++
 sys/Makefile                                  |   3 +
 sys/include/net/ng_ipv6.h                     |   1 +
 sys/include/net/ng_ipv6/ext.h                 | 105 +++++++++++++++++
 sys/include/net/ng_protnum.h                  |   6 +-
 sys/net/network_layer/ng_ipv6/ext/Makefile    |   3 +
 .../network_layer/ng_ipv6/ext/ng_ipv6_ext.c   | 111 ++++++++++++++++++
 sys/net/network_layer/ng_ipv6/ng_ipv6.c       |  13 +-
 8 files changed, 250 insertions(+), 4 deletions(-)
 create mode 100644 sys/include/net/ng_ipv6/ext.h
 create mode 100644 sys/net/network_layer/ng_ipv6/ext/Makefile
 create mode 100644 sys/net/network_layer/ng_ipv6/ext/ng_ipv6_ext.c

diff --git a/Makefile.dep b/Makefile.dep
index 85facbec08..57b2e52e1b 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -112,6 +112,18 @@ ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE)))
   USEMODULE += ng_pktbuf
 endif
 
+ifneq (,$(filter ng_rpl_srh,$(USEMODULE)))
+  USEMODULE += ng_ipv6_ext_rh
+endif
+
+ifneq (,$(filter ng_ipv6_ext_rh,$(USEMODULE)))
+  USEMODULE += ng_ipv6_ext
+endif
+
+ifneq (,$(filter ng_ipv6_ext,$(USEMODULE)))
+  USEMODULE += ng_ipv6
+endif
+
 ifneq (,$(filter ng_ipv6_router,$(USEMODULE)))
   USEMODULE += ng_ipv6
 endif
diff --git a/sys/Makefile b/sys/Makefile
index b5ce3cd2bc..d48d954c22 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -74,6 +74,9 @@ endif
 ifneq (,$(filter ng_ipv6_addr,$(USEMODULE)))
     DIRS += net/network_layer/ng_ipv6/addr
 endif
+ifneq (,$(filter ng_ipv6_ext,$(USEMODULE)))
+    DIRS += net/network_layer/ng_ipv6/ext
+endif
 ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE)))
     DIRS += net/network_layer/ng_ipv6/hdr
 endif
diff --git a/sys/include/net/ng_ipv6.h b/sys/include/net/ng_ipv6.h
index b7415de35c..b76107d5bc 100644
--- a/sys/include/net/ng_ipv6.h
+++ b/sys/include/net/ng_ipv6.h
@@ -33,6 +33,7 @@
 #include "thread.h"
 
 #include "net/ng_ipv6/addr.h"
+#include "net/ng_ipv6/ext.h"
 #include "net/ng_ipv6/hdr.h"
 #include "net/ng_ipv6/nc.h"
 #include "net/ng_ipv6/netif.h"
diff --git a/sys/include/net/ng_ipv6/ext.h b/sys/include/net/ng_ipv6/ext.h
new file mode 100644
index 0000000000..f86c9f0d75
--- /dev/null
+++ b/sys/include/net/ng_ipv6/ext.h
@@ -0,0 +1,105 @@
+/*
+ * 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_ipv6_ext IPv6 extension headers.
+ * @ingroup     net_ng_ipv6
+ * @brief       Implementation of IPv6 extension headers
+ * @see <a href="https://tools.ietf.org/html/rfc2460#section-4">
+ *          RFC 2460, section 4
+ *      </a>
+ * @{
+ *
+ * @file
+ * @brief       Definititions for IPv6 extension headers
+ *
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+
+#ifndef NG_IPV6_EXT_H_
+#define NG_IPV6_EXT_H_
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "byteorder.h"
+#include "kernel_types.h"
+#include "net/ng_pkt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NG_IPV6_EXT_LEN_UNIT    (8U)    /**< Unit in byte for the extension header's
+                                         *   length field */
+
+/**
+ * @brief   IPv6 extension headers.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc2460#section-4">
+ *          RFC 2460, section 4.1
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t nh;     /**< next header */
+    uint8_t len;    /**< length in 8 octets without first octet */
+} ng_ipv6_ext_t;
+
+/**
+ * @brief   Demultiplex extension headers according to @p nh.
+ *
+ * @internal
+ *
+ * @param[in] iface The receiving interface.
+ * @param[in] pkt   A packet.
+ * @param[in] nh    A protocol number (see @ref net_ng_protnum).
+ *
+ * @return  true, on success.
+ * @return  false, on failure.
+ */
+bool ng_ipv6_ext_demux(kernel_pid_t iface, ng_pktsnip_t *pkt,
+                       uint8_t nh);
+
+/**
+ * @brief   Gets the next extension header in a packet.
+ *
+ * @param[in] ext   The current extension header.
+ *
+ * @return  The next extension header.
+ */
+static inline ng_ipv6_ext_t *ng_ipv6_ext_get_next(ng_ipv6_ext_t *ext)
+{
+    return (ng_ipv6_ext_t *)((uint8_t *)(ext) +
+                             (ext->len * NG_IPV6_EXT_LEN_UNIT) +
+                             NG_IPV6_EXT_LEN_UNIT);
+}
+
+/**
+ * @brief   Builds an extension header for sending.
+ *
+ * @param[in] ipv6  The IPv6 header. Can be NULL.
+ * @param[in] next  The next header. Must be a successor to @p ipv6 if it is
+ *                  not NULL.
+ * @param[in] nh    @ref net_ng_protnum of the next header.
+ * @param[in] size  Size of the extension header.
+ *
+ * @return  The extension header on success.
+ * @return  NULL, on error.
+ */
+ng_pktsnip_t *ng_ipv6_ext_build(ng_pktsnip_t *ipv6, ng_pktsnip_t *next,
+                                uint8_t nh, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_IPV6_EXT_H_ */
+/**
+ * @}
+ */
diff --git a/sys/include/net/ng_protnum.h b/sys/include/net/ng_protnum.h
index f1d476079c..3f82d8b625 100644
--- a/sys/include/net/ng_protnum.h
+++ b/sys/include/net/ng_protnum.h
@@ -75,7 +75,7 @@ extern "C" {
 #define NG_PROTNUM_IL                   (40)    /**< IL Transport Protocol */
 #define NG_PROTNUM_IPV6                 (41)    /**< IPv6 encapsulation */
 #define NG_PROTNUM_SDRP                 (42)    /**< Source Demand Routing Protocol */
-#define NG_PROTNUM_IPV6_EXT_ROUTE       (43)    /**< Routing Header for IPv6 */
+#define NG_PROTNUM_IPV6_EXT_RH          (43)    /**< Routing Header for IPv6 */
 #define NG_PROTNUM_IPV6_EXT_FRAG        (44)    /**< Fragment Header for IPv6 */
 #define NG_PROTNUM_IDRP                 (45)    /**< Inter-Domain Routing Protocol */
 #define NG_PROTNUM_RSVP                 (46)    /**< Reservation Protocol */
@@ -95,7 +95,7 @@ extern "C" {
 #define NG_PROTNUM_SKIP                 (57)    /**< SKIP */
 #define NG_PROTNUM_ICMPV6               (58)    /**< ICMP for IPv6 */
 #define NG_PROTNUM_IPV6_NONXT           (59)    /**< No Next Header for IPv6 */
-#define NG_PROTNUM_IPV6_EXT_DEST_OPTS   (60)    /**< IPv6 Extension Header:
+#define NG_PROTNUM_IPV6_EXT_DST         (60)    /**< IPv6 Extension Header:
                                                  *   Destination Options */
 #define NG_PROTNUM_CFTP                 (62)    /**< CFTP */
 #define NG_PROTNUM_SAT_EXPAK            (64)    /**< SATNET and Backroom EXPAK */
@@ -168,7 +168,7 @@ extern "C" {
 #define NG_PROTNUM_SCTP                 (132)   /**< Stream Control Transmission Protocol */
 #define NG_PROTNUM_FC                   (133)   /**< Fibre Channel */
 #define NG_PROTNUM_RSVP_E2E_IGNORE      (134)   /**< RSVP-E2E-IGNORE */
-#define NG_PROTNUM_IPV6_EXT_MOB_HDR     (135)   /**< IPv6 Mobility Extension Header */
+#define NG_PROTNUM_IPV6_EXT_MOB         (135)   /**< IPv6 Mobility Extension Header */
 #define NG_PROTNUM_UDPLITE              (136)   /**< UDPLite */
 #define NG_PROTNUM_MPLS_IN_IP           (137)   /**< MPLS-in-IP */
 #define NG_PROTNUM_MANET                (138)   /**< MANET Protocols */
diff --git a/sys/net/network_layer/ng_ipv6/ext/Makefile b/sys/net/network_layer/ng_ipv6/ext/Makefile
new file mode 100644
index 0000000000..e8b4519769
--- /dev/null
+++ b/sys/net/network_layer/ng_ipv6/ext/Makefile
@@ -0,0 +1,3 @@
+MODULE = ng_ipv6_ext
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/network_layer/ng_ipv6/ext/ng_ipv6_ext.c b/sys/net/network_layer/ng_ipv6/ext/ng_ipv6_ext.c
new file mode 100644
index 0000000000..8919291e0f
--- /dev/null
+++ b/sys/net/network_layer/ng_ipv6/ext/ng_ipv6_ext.c
@@ -0,0 +1,111 @@
+/*
+ * 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 <errno.h>
+
+#include "utlist.h"
+#include "net/ng_pktbuf.h"
+#include "net/ng_ipv6.h"
+
+#include "net/ng_ipv6/ext.h"
+
+bool ng_ipv6_ext_demux(kernel_pid_t iface, ng_pktsnip_t *pkt,
+                       uint8_t nh)
+{
+    ng_pktsnip_t *ext_snip;
+    ng_ipv6_ext_t *ext;
+    unsigned int offset = 0;
+
+    ext = ((ng_ipv6_ext_t *)(((uint8_t *)pkt->data) + sizeof(ng_ipv6_hdr_t)));
+
+    bool c = true;
+
+    while (c) {
+        switch (nh) {
+            case NG_PROTNUM_IPV6_EXT_HOPOPT:
+            case NG_PROTNUM_IPV6_EXT_DST:
+            case NG_PROTNUM_IPV6_EXT_RH:
+            case NG_PROTNUM_IPV6_EXT_FRAG:
+            case NG_PROTNUM_IPV6_EXT_AH:
+            case NG_PROTNUM_IPV6_EXT_ESP:
+            case NG_PROTNUM_IPV6_EXT_MOB:
+                /* TODO: add handling of types */
+                nh = ext->nh;
+                offset += ((ext->len * NG_IPV6_EXT_LEN_UNIT) + NG_IPV6_EXT_LEN_UNIT);
+                ext = ng_ipv6_ext_get_next((ng_ipv6_ext_t *)ext);
+                break;
+
+            default:
+                c = false;
+                offset += ((ext->len * NG_IPV6_EXT_LEN_UNIT) + NG_IPV6_EXT_LEN_UNIT);
+                ext = ng_ipv6_ext_get_next((ng_ipv6_ext_t *)ext);
+                break;
+        }
+    }
+
+    ext_snip = ng_pktbuf_add(pkt, pkt->data, offset, NG_NETTYPE_IPV6);
+
+    if (ext_snip == NULL) {
+        return false;
+    }
+
+    ng_ipv6_demux(iface, pkt, nh); /* demultiplex next header */
+
+    return true;
+}
+
+ng_pktsnip_t *ng_ipv6_ext_build(ng_pktsnip_t *ipv6, ng_pktsnip_t *next,
+                                uint8_t nh, size_t size)
+{
+    ng_pktsnip_t *prev = NULL, *snip;
+    ng_ipv6_ext_t *ext;
+
+    if (ipv6 != NULL) {
+        LL_SEARCH_SCALAR(ipv6, prev, next, next);
+
+        if (prev == NULL) {
+            return NULL;
+        }
+    }
+
+    if (size < NG_IPV6_EXT_LEN_UNIT) {
+        return NULL;
+    }
+
+    snip = ng_pktbuf_add(next, NULL, size, NG_NETTYPE_IPV6);
+
+    if (snip == NULL) {
+        return NULL;
+    }
+
+    ext = snip->data;
+
+    ext->nh = nh;
+
+    if (size & 0x7) { /* not divisible by eight */
+        ext->len = (size / NG_IPV6_EXT_LEN_UNIT);
+    }
+    else {
+        ext->len = (size / NG_IPV6_EXT_LEN_UNIT) - 1;
+    }
+
+    if (prev != NULL) {
+        prev->next = snip;
+    }
+
+    return snip;
+}
+
+
+/** @} */
diff --git a/sys/net/network_layer/ng_ipv6/ng_ipv6.c b/sys/net/network_layer/ng_ipv6/ng_ipv6.c
index 9389b60ceb..2b49496cc8 100644
--- a/sys/net/network_layer/ng_ipv6/ng_ipv6.c
+++ b/sys/net/network_layer/ng_ipv6/ng_ipv6.c
@@ -78,7 +78,18 @@ void ng_ipv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt, uint8_t nh)
         case NG_PROTNUM_ICMPV6:
             ng_icmpv6_demux(iface, pkt);
             break;
-        /* TODO: add extension header handling */
+        case NG_PROTNUM_IPV6_EXT_HOPOPT:
+        case NG_PROTNUM_IPV6_EXT_DST:
+        case NG_PROTNUM_IPV6_EXT_RH:
+        case NG_PROTNUM_IPV6_EXT_FRAG:
+        case NG_PROTNUM_IPV6_EXT_AH:
+        case NG_PROTNUM_IPV6_EXT_ESP:
+        case NG_PROTNUM_IPV6_EXT_MOB:
+            if (!ng_ipv6_ext_demux(iface, pkt, nh)) {
+                DEBUG("ipv6: unable to parse extension headers.\n");
+                ng_pktbuf_release(pkt);
+                return;
+            }
         case NG_PROTNUM_IPV6:
             _decapsulate(pkt);
             break;
-- 
GitLab