From 9c30851b454fd4ecc253e1e6bb988e88a9ff4d79 Mon Sep 17 00:00:00 2001
From: Martine Lenders <mlenders@inf.fu-berlin.de>
Date: Sat, 28 Mar 2015 14:05:17 +0100
Subject: [PATCH] ipv6_hdr: Initial import

---
 Makefile.dep                                  |   5 +
 sys/Makefile                                  |   3 +
 sys/include/net/ng_ipv6.h                     |   1 +
 sys/include/net/ng_ipv6/hdr.h                 | 324 ++++++++++++++++++
 sys/net/network_layer/ng_ipv6/hdr/Makefile    |   3 +
 .../network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c   |  85 +++++
 6 files changed, 421 insertions(+)
 create mode 100644 sys/include/net/ng_ipv6/hdr.h
 create mode 100644 sys/net/network_layer/ng_ipv6/hdr/Makefile
 create mode 100644 sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c

diff --git a/Makefile.dep b/Makefile.dep
index 8a90097714..f63ce39e8d 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -48,6 +48,11 @@ ifneq (,$(filter sixlowpan,$(USEMODULE)))
   USEMODULE += vtimer
 endif
 
+ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE)))
+  USEMODULE += ng_inet_csum
+  USEMODULE += ng_pktbuf
+endif
+
 ifneq (,$(filter ng_ipv6_nc,$(USEMODULE)))
   USEMODULE += ng_ipv6_addr
 endif
diff --git a/sys/Makefile b/sys/Makefile
index d7117e0286..b5b18b7a8d 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -65,6 +65,9 @@ endif
 ifneq (,$(filter ng_ipv6_addr,$(USEMODULE)))
     DIRS += net/network_layer/ng_ipv6/addr
 endif
+ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE)))
+    DIRS += net/network_layer/ng_ipv6/hdr
+endif
 ifneq (,$(filter ng_ipv6_nc,$(USEMODULE)))
     DIRS += net/network_layer/ng_ipv6/nc
 endif
diff --git a/sys/include/net/ng_ipv6.h b/sys/include/net/ng_ipv6.h
index 0b0086918f..7468121ce8 100644
--- a/sys/include/net/ng_ipv6.h
+++ b/sys/include/net/ng_ipv6.h
@@ -23,6 +23,7 @@
 #define NG_IPV6_H_
 
 #include "net/ng_ipv6/addr.h"
+#include "net/ng_ipv6/hdr.h"
 #include "net/ng_ipv6/netif.h"
 
 #ifdef __cplusplus
diff --git a/sys/include/net/ng_ipv6/hdr.h b/sys/include/net/ng_ipv6/hdr.h
new file mode 100644
index 0000000000..3a18ba0646
--- /dev/null
+++ b/sys/include/net/ng_ipv6/hdr.h
@@ -0,0 +1,324 @@
+/*
+ * 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_hdr IPv6 header defintions
+ * @ingroup     net_ng_ipv6
+ * @{
+ *
+ * @file
+ * @brief   IPv6 header
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef NG_IPV6_HDR_H_
+#define NG_IPV6_HDR_H_
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "byteorder.h"
+#include "net/ng_ipv6/addr.h"
+#include "net/ng_inet_csum.h"
+#include "net/ng_pkt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Data type to represent an IPv6 packet header
+ *
+ * @details The structure of the header is as follows:
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.unparsed}
+ *                      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                        +
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +                      Destination Address                      +
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2460#section-3">
+ *          RFC 2460, section 3
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    /**
+     * @brief Version, traffic class, and flow label
+     *
+     * @details The version are the 4 most significant bits, the traffic class
+     * the 8 next bit, and the remainding 20 bits are the flow label (see
+     * above).
+     *
+     * This module provides helper functions to set, get, and check these
+     * fields accordingly:
+     * * ng_ipv6_hdr_set_version()
+     * * ng_ipv6_hdr_get_version()
+     * * ng_ipv6_hdr_is_ipv6_hdr()
+     * * ng_ipv6_hdr_set_tc()
+     * * ng_ipv6_hdr_set_tc_ecn()
+     * * ng_ipv6_hdr_set_tc_dscp()
+     * * ng_ipv6_hdr_get_tc()
+     * * ng_ipv6_hdr_get_tc_ecn()
+     * * ng_ipv6_hdr_get_tc_dscp()
+     * * ng_ipv6_hdr_set_fl()
+     * * ng_ipv6_hdr_get_fl()
+     */
+    network_uint32_t v_tc_fl;
+    network_uint16_t len;   /**< payload length of this packet. */
+    uint8_t nh;             /**< type of next header in this packet. */
+    uint8_t hl;             /**< hop limit for this packet. */
+    ng_ipv6_addr_t src;     /**< source address of this packet. */
+    ng_ipv6_addr_t dst;     /**< destination address of this packet. */
+} ng_ipv6_hdr_t;
+
+/**
+ * @brief   Sets the version field of @p hdr to 6
+ *
+ * @param[out] hdr  Pointer to an IPv6 header.
+ */
+static inline void ng_ipv6_hdr_set_version(ng_ipv6_hdr_t *hdr)
+{
+    hdr->v_tc_fl.u8[0] &= 0x0f;
+    hdr->v_tc_fl.u8[0] |= 0x60;
+}
+
+/**
+ * @brief   Gets the value of the version field of @p hdr
+ *
+ * @param[in] hdr   Pointer to an IPv6 header.
+ *
+ * @return  Value of the version field of @p hdr.
+ */
+static inline uint8_t ng_ipv6_hdr_get_version(const ng_ipv6_hdr_t *hdr)
+{
+    return ((hdr->v_tc_fl.u8[0]) >> 4);
+}
+
+/**
+ * @brief   Checks if the version field is set to 6
+ *
+ * @param[in] hdr   Pointer to an IPv6 header.
+ *
+ * @return  true, if version field is 6
+ * @return  false, otherwise
+ */
+static inline bool ng_ipv6_hdr_is_ipv6_hdr(const ng_ipv6_hdr_t *hdr)
+{
+    return (((hdr->v_tc_fl.u8[0]) & 0xf0) == 0x60);
+}
+
+/**
+ * @brief   Sets the traffic class field of @p hdr
+ *
+ * @param[out] hdr  Pointer to an IPv6 header.
+ * @param[in] tc    The new value for the traffic class field.
+ */
+static inline void ng_ipv6_hdr_set_tc(ng_ipv6_hdr_t *hdr, uint8_t tc)
+{
+    hdr->v_tc_fl.u8[0] &= 0xf0;
+    hdr->v_tc_fl.u8[0] |= (0x0f & (tc >> 4));
+    hdr->v_tc_fl.u8[1] &= 0x0f;
+    hdr->v_tc_fl.u8[1] |= (0xf0 & (tc << 4));
+}
+
+/**
+ * @brief   Sets the value of the Explicit Congestion Notification (ECN) part
+ *          of the traffic class field of @p hdr
+ *
+ * @details The field is needed e.g. in context of 6LoWPAN header compression
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc3168#section-5">
+ *          RFC 3168, section 5
+ *      </a>
+ *
+ * @param[out] hdr  Pointer to an IPv6 header.
+ * @param[in] ecn   The new value for the 2-bit ECN part of the traffic class
+ *                  field.
+ */
+static inline void ng_ipv6_hdr_set_tc_ecn(ng_ipv6_hdr_t *hdr, uint8_t ecn)
+{
+    hdr->v_tc_fl.u8[0] &= 0xf3;
+    hdr->v_tc_fl.u8[0] |= (0x0c & (ecn << 2));
+}
+
+/**
+ * @brief   Sets the value of the Differentiated Service Codepoint (DSCP) part
+ *          of the traffic class field of @p hdr
+ *
+ * @details The field is needed e.g. in context of 6LoWPAN header compression
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc2474#section-3">
+ *          RFC 2474, section 3
+ *      </a>
+ *
+ * @param[out] hdr  Pointer to an IPv6 header.
+ * @param[in] dscp  The new value for the 6-bit DSCP ng_part of the traffic class
+ *                  field.
+ */
+static inline void ng_ipv6_hdr_set_tc_dscp(ng_ipv6_hdr_t *hdr, uint8_t dscp)
+{
+    hdr->v_tc_fl.u8[0] &= 0xfc;
+    hdr->v_tc_fl.u8[0] |= (0x03 & (dscp >> 4));
+    hdr->v_tc_fl.u8[1] &= 0x0f;
+    hdr->v_tc_fl.u8[1] |= (0xf0 & (dscp << 4));
+}
+
+/**
+ * @brief   Gets the value of the traffic class field of @p hdr
+ *
+ * @param[in] hdr   Pointer to an IPv6 header.
+ *
+ * @return  Value of the traffic class field of @p hdr.
+ */
+static inline uint8_t ng_ipv6_hdr_get_tc(const ng_ipv6_hdr_t *hdr)
+{
+    return ((((hdr->v_tc_fl.u8[0]) & 0x0f) << 4) |
+            ((hdr->v_tc_fl.u8[1] & 0xf0) >> 4));
+}
+
+/**
+ * @brief   Gets the value of the Explicit Congestion Notification (ECN) part
+ *          of the traffic class field of @p hdr
+ *
+ * @details The field is needed e.g. in context of 6LoWPAN header compression
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc3168#section-5">
+ *          RFC 3168, section 5
+ *      </a>
+ *
+ * @param[in] hdr   Pointer to an IPv6 header.
+ *
+ * @return  Value of the ECN part of the traffic class field of @p hdr.
+ */
+static inline uint8_t ng_ipv6_hdr_get_tc_ecn(const ng_ipv6_hdr_t *hdr)
+{
+    return (((hdr->v_tc_fl.u8[0]) & 0x0c) >> 2);
+}
+
+
+/**
+ * @brief   Gets the value of the Differentiated Service Codepoint (DSCP) part
+ *          of the traffic class field of @p hdr
+ *
+ * @details The field is needed e.g. in context of 6LoWPAN header compression
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc2474#section-3">
+ *          RFC 2474, section 3
+ *      </a>
+ *
+ * @param[in] hdr   Pointer to an IPv6 header.
+ *
+ * @return  Value of the DSCP part of the traffic class field of @p hdr.
+ */
+static inline uint8_t ng_ipv6_hdr_get_tc_dscp(const ng_ipv6_hdr_t *hdr)
+{
+    return ((((hdr->v_tc_fl.u8[0]) & 0x03) << 4) |
+            ((hdr->v_tc_fl.u8[1] & 0xf0) >> 4));
+}
+
+/**
+ * @brief   Sets the flow label field of @p hdr
+ *
+ * @param[out] hdr  Pointer to an IPv6 header.
+ * @param[in] fl    The new value for the flow label field in host byte order.
+ */
+static inline void ng_ipv6_hdr_set_fl(ng_ipv6_hdr_t *hdr, uint32_t fl)
+{
+    hdr->v_tc_fl.u8[1] &= 0xf0;
+    hdr->v_tc_fl.u8[1] |= (0x0f & (byteorder_htonl(fl).u8[1]));
+    hdr->v_tc_fl.u16[1] = byteorder_htonl(fl).u16[1];
+}
+
+/**
+ * @brief   Gets the value of the flow label field of @p hdr
+ *
+ * @param[in] hdr   Pointer to an IPv6 header.
+ *
+ * @return  Value of the flow label field of @p hdr.
+ */
+static inline uint32_t ng_ipv6_hdr_get_fl(const ng_ipv6_hdr_t *hdr)
+{
+    return byteorder_ntohl(hdr->v_tc_fl) & 0x000fffff;
+}
+
+/**
+ * @brief   Calculates the Internet Checksum for the IPv6 Pseudo Header.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc2460#section-8.1">
+ *          RFC 2460, section 8.1
+ *      </a>
+ *
+ * @param[in] sum       Preinialized value of the sum.
+ * @param[in] prot_num  The @ref net_ng_protnum you want to calculate the
+ *                      checksum for. Can not be inferred from
+ *                      ng_ipv6_hdr_t::nh, since it can be an IPv6 exentension
+ *                      header.
+ * @param[in] hdr       An IPv6 header to derive the Pseudo Header from.
+ * @param[in] len       The upper-layer packet length for the pseudo header.
+ *                      Can not be inferred from ng_ipv6_hdr_t::len, since
+ *                      there can be extension headers between the IPv6 header
+ *                      and the payload.
+ *
+ * @return  The non-normalized Internet Checksum of the given IPv6 pseudo header.
+ */
+static inline uint16_t ng_ipv6_hdr_inet_csum(uint16_t sum, ng_ipv6_hdr_t *hdr,
+                                             uint8_t prot_num, uint16_t len)
+{
+    return ng_inet_csum(sum + len + prot_num, hdr->src.u8,
+                        (2 * sizeof(ng_ipv6_addr_t)));
+}
+
+/**
+ * @brief   Builds an IPv6 header for sending and adds it to the packet buffer.
+ *
+ * @details Initializes version field with 6, traffic class, flow label, and
+ *          hop limit with 0, and next header with @ref NG_PROTNUM_RESERVED.
+ *
+ * @param[in] payload   Payload for the packet.
+ * @param[in] src       Source address for the header. Can be NULL if not
+ *                      known or required.
+ * @param[in] src_len   Length of @p src. Can be 0 if not known or required or
+ *                      must be `sizeof(ng_ipv6_addr_t)`.
+ * @param[in] dst       Destination address for the header. Can be NULL if not
+ *                      known or required.
+ * @param[in] dst_len   Length of @p dst. Can be 0 if not known or required or
+ *                      must be `sizeof(ng_ipv6_addr_t)`.
+ *
+ * @return  The an IPv6 header in packet buffer on success.
+ * @return  NULL on error.
+ */
+ng_pktsnip_t *ng_ipv6_hdr_build(ng_pktsnip_t *payload,
+                                uint8_t *src, uint8_t src_len,
+                                uint8_t *dst, uint8_t dst_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_IPV6_HDR_H_ */
+/** @} */
diff --git a/sys/net/network_layer/ng_ipv6/hdr/Makefile b/sys/net/network_layer/ng_ipv6/hdr/Makefile
new file mode 100644
index 0000000000..204e78e385
--- /dev/null
+++ b/sys/net/network_layer/ng_ipv6/hdr/Makefile
@@ -0,0 +1,3 @@
+MODULE = ng_ipv6_hdr
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c b/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c
new file mode 100644
index 0000000000..9804b72308
--- /dev/null
+++ b/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c
@@ -0,0 +1,85 @@
+/*
+ * 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 "net/ng_ipv6/addr.h"
+#include "net/ng_ipv6/hdr.h"
+#include "net/ng_nettype.h"
+#include "net/ng_pktbuf.h"
+#include "net/ng_protnum.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#if ENABLE_DEBUG && defined(MODULE_NG_IPV6_ADDR)
+static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN];
+#endif
+
+/* For independent testing */
+#ifdef MODULE_NG_IPV6
+#define HDR_NETTYPE (NG_NETTYPE_IPV6)
+#else
+#define HDR_NETTYPE (NG_NETTYPE_UNDEF)
+#endif
+
+ng_pktsnip_t *ng_ipv6_hdr_build(ng_pktsnip_t *payload,
+                                uint8_t *src, uint8_t src_len,
+                                uint8_t *dst, uint8_t dst_len)
+{
+    ng_pktsnip_t *ipv6;
+    ng_ipv6_hdr_t *hdr;
+
+    if (((src_len != 0) && (src_len != sizeof(ng_ipv6_addr_t))) ||
+        ((dst_len != 0) && (dst_len != sizeof(ng_ipv6_addr_t)))) {
+        DEBUG("ipv6_hdr: Address length was not 0 or %zu byte.\n",
+              sizeof(ng_ipv6_addr_t));
+        return NULL;
+    }
+
+    ipv6 = ng_pktbuf_add(payload, NULL, sizeof(ng_ipv6_hdr_t), HDR_NETTYPE);
+
+    if (ipv6 == NULL) {
+        DEBUG("ipv6_hdr: no space left in packet buffer\n");
+        return NULL;
+    }
+
+    hdr = (ng_ipv6_hdr_t *)ipv6->data;
+
+    if ((src != NULL) && (src_len != 0)) {
+#ifdef MODULE_NG_IPV6_ADDR
+        DEBUG("ipv6_hdr: set packet source to %s\n",
+              ng_ipv6_addr_to_str(addr_str, (ng_ipv6_addr_t *)src,
+                                  sizeof(addr_str)));
+#endif
+        memcpy(&hdr->src, src, src_len);
+    }
+
+    memset(&hdr->dst + dst_len, 0, sizeof(ng_ipv6_addr_t) - dst_len);
+
+    if ((dst != NULL) && (dst_len != 0)) {
+#ifdef MODULE_NG_IPV6_ADDR
+        DEBUG("ipv6_hdr: set packet destination to %s\n",
+              ng_ipv6_addr_to_str(addr_str, (ng_ipv6_addr_t *)dst,
+                                  sizeof(addr_str)));
+#endif
+        memcpy(&hdr->dst, dst, dst_len);
+    }
+
+    hdr->v_tc_fl = byteorder_htonl(0x60000000); /* set version, tc and fl in one go*/
+    hdr->nh = NG_PROTNUM_RESERVED;
+    hdr->hl = 0;
+
+    return ipv6;
+}
+
+/** @} */
-- 
GitLab