From 86133b8404c8d599ebf9bd5f8276f6bd0f5aa6bf Mon Sep 17 00:00:00 2001
From: Martine Lenders <mlenders@inf.fu-berlin.de>
Date: Wed, 1 Apr 2015 17:35:23 +0200
Subject: [PATCH] ng_icmpv6_echo: initial import

---
 Makefile.dep                                  |   5 +
 sys/Makefile                                  |   3 +
 sys/include/net/ng_icmpv6.h                   |   1 +
 sys/include/net/ng_icmpv6/echo.h              | 129 ++++++++++++++++++
 sys/net/network_layer/ng_icmpv6/echo/Makefile |   3 +
 .../ng_icmpv6/echo/ng_icmpv6_echo.c           | 119 ++++++++++++++++
 sys/net/network_layer/ng_icmpv6/ng_icmpv6.c   |   4 +-
 7 files changed, 263 insertions(+), 1 deletion(-)
 create mode 100644 sys/include/net/ng_icmpv6/echo.h
 create mode 100644 sys/net/network_layer/ng_icmpv6/echo/Makefile
 create mode 100644 sys/net/network_layer/ng_icmpv6/echo/ng_icmpv6_echo.c

diff --git a/Makefile.dep b/Makefile.dep
index 3fe29f8597..1ba0400568 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -53,6 +53,11 @@ ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE)))
   USEMODULE += vtimer
 endif
 
+ifneq (,$(filter ng_icmpv6_echo,$(USEMODULE)))
+  USEMODULE += ng_icmpv6
+  USEMODULE += ng_netbase
+endif
+
 ifneq (,$(filter ng_icmpv6,$(USEMODULE)))
   USEMODULE += ng_ipv6
 endif
diff --git a/sys/Makefile b/sys/Makefile
index 3ec57b53d6..33569987c6 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -65,6 +65,9 @@ endif
 ifneq (,$(filter ng_icmpv6,$(USEMODULE)))
     DIRS += net/network_layer/ng_icmpv6
 endif
+ifneq (,$(filter ng_icmpv6_echo,$(USEMODULE)))
+    DIRS += net/network_layer/ng_icmpv6/echo
+endif
 ifneq (,$(filter ng_ipv6,$(USEMODULE)))
     DIRS += net/network_layer/ng_ipv6
 endif
diff --git a/sys/include/net/ng_icmpv6.h b/sys/include/net/ng_icmpv6.h
index daec59a27d..ba590b20de 100644
--- a/sys/include/net/ng_icmpv6.h
+++ b/sys/include/net/ng_icmpv6.h
@@ -34,6 +34,7 @@
 #include "net/ng_nettype.h"
 #include "net/ng_pkt.h"
 
+#include "net/ng_icmpv6/echo.h"
 #include "net/ng_icmpv6/error.h"
 #include "net/ng_icmpv6/types.h"
 
diff --git a/sys/include/net/ng_icmpv6/echo.h b/sys/include/net/ng_icmpv6/echo.h
new file mode 100644
index 0000000000..e7470746a3
--- /dev/null
+++ b/sys/include/net/ng_icmpv6/echo.h
@@ -0,0 +1,129 @@
+/*
+ * 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_icmpv6_echo  ICMPv6 echo messages
+ * @ingroup     net_ng_icmpv6
+ * @brief       ICMPv6 echo request and reply
+ * @{
+ *
+ * @file
+ * @brief   ICMPv6 echo message definitions
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef NG_ICMPV6_ECHO_H_
+#define NG_ICMPV6_ECHO_H_
+
+#include <inttypes.h>
+
+#include "byteorder.h"
+#include "kernel_types.h"
+#include "net/ng_icmpv6/types.h"
+#include "net/ng_ipv6/hdr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Echo request and response message format.
+ * @extends ng_icmpv6_hdr_t
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-4.1">
+ *          RFC 4443, section 4.1
+ *      </a>
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-4.2">
+ *          RFC 4443, section 4.2
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;           /**< message type */
+    uint8_t code;           /**< message code */
+    network_uint16_t csum;  /**< checksum */
+    network_uint16_t id;    /**< identifier */
+    network_uint16_t seq;   /**< Sequence number */
+} ng_icmpv6_echo_t;
+
+/**
+ * @brief   Builds an ICMPv6 echo message of type @p type for sending.
+ *
+ * @param[in] type      Type of the echo message. Expected to be either
+ *                      NG_ICMPV6_ECHO_REQ or NG_ICMPV6_ECHO_REP.
+ * @param[in] id        ID for the echo message in host byte-order
+ * @param[in] seq       Sequence number for the echo message in host byte-order
+ * @param[in] data      Payload for the echo message
+ * @param[in] data_len  Length of @p data
+ *
+ * @return  The echo message on success
+ * @return  NULL, on failure
+ */
+ng_pktsnip_t *ng_icmpv6_echo_build(uint8_t type, uint16_t id, uint16_t seq,
+                                   uint8_t *data, size_t data_len);
+
+/**
+ * @brief   Builds an ICMPv6 echo request for sending.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-4.1">
+ *          RFC 4443, section 4.1
+ *      </a>
+ *
+ * @param[in] id        ID for the echo request in host byte-order
+ * @param[in] seq       Sequence number for the echo request in host byte-order
+ * @param[in] data      Payload for the echo request
+ * @param[in] data_len  Length of @p data
+ *
+ * @return  The echo request message on success
+ * @return  NULL, on failure
+ */
+static inline ng_pktsnip_t *ng_icmpv6_echo_req_build(uint16_t id, uint16_t seq,
+        uint8_t *data, size_t data_len)
+{
+    return ng_icmpv6_echo_build(NG_ICMPV6_ECHO_REQ, id, seq, data, data_len);
+}
+
+/**
+ * @brief   Builds an ICMPv6 echo reply for sending.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-4.2">
+ *          RFC 4443, section 4.2
+ *      </a>
+ *
+ * @param[in] id        ID for the echo reply in host byte-order
+ * @param[in] seq       Sequence number for the echo reply in host byte-order
+ * @param[in] data      Payload for the echo reply
+ * @param[in] data_len  Length of @p data
+ *
+ * @return  The echo reply message on success
+ * @return  NULL, on failure
+ */
+static inline ng_pktsnip_t *ng_icmpv6_echo_rep_build(uint16_t id, uint16_t seq,
+        uint8_t *data, size_t data_len)
+{
+    return ng_icmpv6_echo_build(NG_ICMPV6_ECHO_REP, id, seq, data, data_len);
+}
+
+
+/**
+ * @brief   ICMPv6 echo request handler
+ *
+ * @param[in] iface     The interface the echo requuest was received on.
+ * @param[in] ipv6_hdr  The IPv6 header of the echo request.
+ * @param[in] echo      The Echo Request message.
+ * @param[in] len       Length of the echo request message (ng_ipv6_hdr_t::len
+ *                      of @p ipv6_hdr minus length of extension headers).
+ */
+void ng_icmpv6_echo_req_handle(kernel_pid_t iface, ng_ipv6_hdr_t *ipv6_hdr,
+                               ng_icmpv6_echo_t *echo, uint16_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_ICMPV6_ECHO_H_ */
+/** @} */
diff --git a/sys/net/network_layer/ng_icmpv6/echo/Makefile b/sys/net/network_layer/ng_icmpv6/echo/Makefile
new file mode 100644
index 0000000000..f30fd54da6
--- /dev/null
+++ b/sys/net/network_layer/ng_icmpv6/echo/Makefile
@@ -0,0 +1,3 @@
+MODULE = ng_icmpv6_echo
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/network_layer/ng_icmpv6/echo/ng_icmpv6_echo.c b/sys/net/network_layer/ng_icmpv6/echo/ng_icmpv6_echo.c
new file mode 100644
index 0000000000..24f4701acb
--- /dev/null
+++ b/sys/net/network_layer/ng_icmpv6/echo/ng_icmpv6_echo.c
@@ -0,0 +1,119 @@
+/*
+ * 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_netbase.h"
+
+#include "net/ng_icmpv6.h"
+#include "net/ng_icmpv6/echo.h"
+#include "utlist.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+ng_pktsnip_t *ng_icmpv6_echo_build(uint8_t type, uint16_t id, uint16_t seq,
+                                   uint8_t *data, size_t data_len)
+{
+    ng_pktsnip_t *pkt;
+    ng_icmpv6_echo_t *echo;
+
+    if ((pkt = ng_icmpv6_build(type, 0, data_len + sizeof(ng_icmpv6_echo_t))) == NULL) {
+        return NULL;
+    }
+
+    DEBUG("icmpv6_echo: Building echo message with type=%" PRIu8 "id=%" PRIu16
+          ", seq=%" PRIu16, type, id, seq);
+    echo = (ng_icmpv6_echo_t *)pkt->data;
+    echo->id = byteorder_htons(id >> 16);
+    echo->seq = byteorder_htons(seq);
+
+    if (data != NULL) {
+        memcpy(echo + 1, data, data_len);
+#if defined(MODULE_OD) && ENABLE_DEBUG
+        DEBUG(", payload:\n");
+        od_hex_dump(data, data_len, OD_WIDTH_DEFAULT);
+#endif
+        DEBUG("\n");
+    }
+#if ENABLE_DEBUG
+    else {
+        DEBUG("\n");
+    }
+#endif
+
+    return pkt;
+}
+
+void ng_icmpv6_echo_req_handle(kernel_pid_t iface, ng_ipv6_hdr_t *ipv6_hdr,
+                               ng_icmpv6_echo_t *echo, uint16_t len)
+{
+    uint8_t *payload = ((uint8_t *)echo) + sizeof(ng_icmpv6_echo_t);
+    ng_pktsnip_t *hdr, *pkt;
+    ng_netreg_entry_t *sendto = NULL;
+
+    if ((echo == NULL) || (len < sizeof(ng_icmpv6_echo_t))) {
+        DEBUG("icmpv6_echo: echo was NULL or len (%" PRIu16
+              ") was < sizeof(ng_icmpv6_echo_t)\n", len);
+        return;
+    }
+
+    pkt = _echo_build(NG_ICMPV6_ECHO_REP, byteorder_ntohs(echo->id),
+                      byteorder_ntohs(echo->seq), payload,
+                      len - sizeof(ng_icmpv6_echo_t));
+
+    if (pkt == NULL) {
+        DEBUG("icmpv6_echo: no space left in packet buffer\n");
+        return;
+    }
+
+    if (ng_ipv6_addr_is_multicast(&ipv6_hdr->dst)) {
+        hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)&ipv6_hdr->src,
+                                sizeof(ng_ipv6_addr_t));
+    }
+    else {
+        hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)&ipv6_hdr->dst,
+                                sizeof(ng_ipv6_addr_t), (uint8_t *)&ipv6_hdr->src,
+                                sizeof(ng_ipv6_addr_t));
+    }
+
+    if (hdr == NULL) {
+        DEBUG("icmpv6_echo: no space left in packet buffer\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    pkt = hdr;
+    hdr = ng_netif_hdr_build(NULL, 0, NULL, 0);
+
+    ((ng_netif_hdr_t *)hdr->data)->if_pid = iface;
+
+    LL_PREPEND(pkt, hdr);
+
+    sendto = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL);
+
+    if (sendto == NULL) {
+        DEBUG("icmpv6_echo: no receivers for IPv6 packets\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    /* ICMPv6 is not interested anymore so `- 1` */
+    ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL) - 1);
+
+    while (sendto != NULL) {
+        ng_netapi_send(sendto->pid, pkt);
+        sendto = ng_netreg_getnext(sendto);
+    }
+}
+
+/** @} */
diff --git a/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c
index f75e57b5aa..fb93c5a44d 100644
--- a/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c
+++ b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c
@@ -28,6 +28,7 @@
 #include "utlist.h"
 
 #include "net/ng_icmpv6.h"
+#include "net/ng_icmpv6/echo.h"
 
 #define ENABLE_DEBUG    (0)
 #include "debug.h"
@@ -77,7 +78,8 @@ void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt)
 #ifdef MODULE_NG_ICMPV6_ECHO
         case NG_ICMPV6_ECHO_REQ:
             DEBUG("icmpv6: handle echo request.\n");
-            /* TODO */
+            ng_icmpv6_echo_req_handle(iface, (ng_ipv6_hdr_t *)ipv6->data,
+                                      (ng_icmpv6_echo_t *)hdr, icmpv6->size);
             break;
 #endif
 
-- 
GitLab