diff --git a/Makefile.dep b/Makefile.dep
index 378b8d943a49ca9fa38cbbe4a99a2ba62e0d93bb..c688738e446707cfa716810350c52685cb3d0c7d 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -72,6 +72,15 @@ 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
+
 ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE)))
   USEMODULE += ng_inet_csum
   USEMODULE += ng_pktbuf
@@ -82,6 +91,7 @@ ifneq (,$(filter ng_ipv6_router,$(USEMODULE)))
 endif
 
 ifneq (,$(filter ng_ipv6,$(USEMODULE)))
+  USEMODULE += ng_icmpv6
   USEMODULE += ng_inet_csum
   USEMODULE += ng_ipv6_addr
   USEMODULE += ng_ipv6_hdr
diff --git a/sys/Makefile b/sys/Makefile
index da888e73cfd6167bcc034129dda76cb9aee59ba6..4d2bc7642c33a8bdd2e7ea82644744f83ad527a3 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -62,6 +62,12 @@ endif
 ifneq (,$(filter oneway_malloc,$(USEMODULE)))
     DIRS += oneway-malloc
 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
new file mode 100644
index 0000000000000000000000000000000000000000..ba590b20deccb0ea8c6ad6645f4de9d2f5c36782
--- /dev/null
+++ b/sys/include/net/ng_icmpv6.h
@@ -0,0 +1,103 @@
+/*
+ * 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  Internet Control Message Protocol for IPv6
+ * @ingroup     net_ng_ipv6
+ * @brief       Basic implementation of ICMPv6
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443">
+ *          RFC 4443
+ *      </a>
+ * @{
+ *
+ * @file
+ * @brief       Definitions for ICMPv6
+ *
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#ifndef NG_ICMPV6_H_
+#define NG_ICMPV6_H_
+
+#include <inttypes.h>
+
+#include "byteorder.h"
+#include "kernel_types.h"
+#include "net/ng_ipv6/hdr.h"
+#include "net/ng_nettype.h"
+#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"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   General ICMPv6 message format.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-2.1">
+ *          RFC 4443, section 2.1
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;           /**< message type */
+    uint8_t code;           /**< message code */
+    network_uint16_t csum;  /**< checksum */
+} ng_icmpv6_hdr_t;
+
+/**
+ * @brief   Demultiplexes a received ICMPv6 packet according to its type field.
+ *
+ * @param[in] iface     The receiving interface
+ * @param[in] pkt       The packet to demultiplex.
+ */
+void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt);
+
+/**
+ * @brief   Builds an ICMPv6 message for sending.
+ *
+ * @param[in] type  Type for the ICMPv6 message.
+ * @param[in] code  Code for the ICMPv6 message.
+ * @param[in] size  Size of the ICMPv6 message (needs do be >
+ *                  `sizeof(ng_icmpv6_hdr_t)`).
+ *
+ * @return  The ICMPv6 message on success
+ * @return  NULL, on failure
+ */
+ng_pktsnip_t *ng_icmpv6_build(uint8_t type, uint8_t code, size_t size);
+
+/* TODO: build error messages */
+
+/**
+ * @brief   Calculates the checksum for an ICMPv6 packet.
+ *
+ * @param[in] hdr           The header the checksum should be calculated
+ *                          for.
+ * @param[in] pseudo_hdr    The header the pseudo header shall be generated
+ *                          from. NULL if none is needed.
+ *
+ * @return  0, on success.
+ * @return  -EINVAL, if ng_pktsnip_t::type of @p pkt was not NG_NETTYPE_ICMPV6
+ * @return  -ENOENT, if ng_pktsnip_t::type of @p pseudo_hdr was not
+ *          NG_NETTYPE_IPV6
+ */
+int ng_icmpv6_calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_ICMPV6_H_ */
+/**
+ * @}
+ */
diff --git a/sys/include/net/ng_icmpv6/echo.h b/sys/include/net/ng_icmpv6/echo.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7470746a3dcbef1a16e732f9d37fb320d35aca2
--- /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/include/net/ng_icmpv6/error.h b/sys/include/net/ng_icmpv6/error.h
new file mode 100644
index 0000000000000000000000000000000000000000..dd4f0a2712170e01d022351723a4d32778ecd717
--- /dev/null
+++ b/sys/include/net/ng_icmpv6/error.h
@@ -0,0 +1,156 @@
+/*
+ * 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_error ICMPv6 error messages
+ * @ingroup     net_ng_icmpv6
+ * @brief       ICMPv6 error message handling and creation
+ * @{
+ *
+ * @file
+ * @brief   ICMPv6 error message definitions
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef NG_ICMPV6_ERROR_H_
+#define NG_ICMPV6_ERROR_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
+
+
+/**
+ * @{
+ * @name Codes for destination unreachable messages
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.1">
+ *          RFC 4443, section 3.1
+ *      </a>
+ */
+#define NG_ICMPV6_ERROR_DEST_UNR_NO_ROUTE   (0) /**< no route to destination */
+#define NG_ICMPV6_ERROR_DEST_UNR_PROHIB     (1) /**< communictation with
+                                                 *   destination administratively
+                                                 *   prohibited */
+#define NG_ICMPV6_ERROR_DEST_UNR_SCOPE      (2) /**< beyond scope of source address */
+#define NG_ICMPV6_ERROR_DEST_UNR_ADDR       (3) /**< address unreachable */
+#define NG_ICMPV6_ERROR_DEST_UNR_PORT       (4) /**< port unreachable */
+#define NG_ICMPV6_ERROR_DEST_UNR_POLICY     (5) /**< source address failed ingress/egress
+                                                 *   policy */
+#define NG_ICMPV6_ERROR_DEST_UNR_REJECT     (6) /**< reject route to destination */
+/**
+ * @}
+ */
+
+/**
+ * @{
+ * @name Codes for time exceeded messages
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.3">
+ *          RFC 4443, section 3.3
+ *      </a>
+ */
+#define NG_ICMPV6_ERROR_TIME_EXC_HL     (0) /**< hop limit exceeded in transit */
+#define NG_ICMPV6_ERROR_TIME_EXC_FRAG   (1) /**< fragment reassembly time exceeded */
+/**
+ * @}
+ */
+
+/**
+ * @{
+ * @name Codes for parameter problem messages
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.4">
+ *          RFC 4443, section 3.4
+ *      </a>
+ */
+#define NG_ICMPV6_ERROR_PARAM_PROB_HDR_FIELD    (0) /**< errorneous header field
+                                                     *   encountered */
+#define NG_ICMPV6_ERROR_PARAM_PROB_NH           (1) /**< unrecognized next header
+                                                     *   field encountered */
+#define NG_ICMPV6_ERROR_PARAM_PROB_OPT          (2) /**< unrecognized IPv6 option
+                                                     *   field encountered */
+/**
+ * @}
+ */
+
+/**
+ * @brief   Destination unreachable message format.
+ * @extends ng_icmpv6_hdr_t
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.1">
+ *          RFC 4443, section 3.1
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;               /**< message type */
+    uint8_t code;               /**< message code */
+    network_uint16_t csum;      /**< checksum */
+    network_uint32_t unused;    /**< unused field */
+} ng_icmpv6_error_dst_unr_t;
+
+/**
+ * @brief   Packet too big message format.
+ * @extends ng_icmpv6_hdr_t
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.2">
+ *          RFC 4443, section 3.2
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;           /**< message type */
+    uint8_t code;           /**< message code */
+    network_uint16_t csum;  /**< checksum */
+    network_uint32_t mtu;   /**< MTU */
+} ng_icmpv6_error_pkt_too_big_t;
+
+/**
+ * @brief   Time exceeded message format.
+ * @extends ng_icmpv6_hdr_t
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.3">
+ *          RFC 4443, section 3.3
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;               /**< message type */
+    uint8_t code;               /**< message code */
+    network_uint16_t csum;      /**< checksum */
+    network_uint32_t unused;    /**< unused field */
+} ng_icmpv6_error_time_exc_t;
+
+/**
+ * @brief   Parameter problem message format.
+ * @extends ng_icmpv6_hdr_t
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.4">
+ *          RFC 4443, section 3.3
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;           /**< message type */
+    uint8_t code;           /**< message code */
+    network_uint16_t csum;  /**< checksum */
+    network_uint32_t ptr;   /**< pointer */
+} ng_icmpv6_error_param_prob_t;
+
+/* TODO: implement build and handle functions */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_ICMPV6_ERROR_H_ */
+/** @} */
diff --git a/sys/include/net/ng_icmpv6/types.h b/sys/include/net/ng_icmpv6/types.h
new file mode 100644
index 0000000000000000000000000000000000000000..fddac3d4f6ead7b23dc84556e80cc37b1c7e5f8e
--- /dev/null
+++ b/sys/include/net/ng_icmpv6/types.h
@@ -0,0 +1,70 @@
+/*
+ * 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_types ICMPv6 message type definitions
+ * @ingroup     net_ng_icmpv6
+ * @brief       Type numbers for the corresponding field in ICMPv6 messages.
+ * @{
+ *
+ * @file
+ * @brief   Macro definitions for ICMPv6 type fields
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef NG_ICMPV6_TYPES_H_
+#define NG_ICMPV6_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @{
+ * @name Error message types
+ * @see <a href="http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2">
+ *          IANA, ICMPv6 "type" Numbers
+ *      </a>
+ */
+#define NG_ICMPV6_DEST_UNR      (1)     /**< Destination unreachable message */
+#define NG_ICMPV6_PKT_TOO_BIG   (2)     /**< Packet Too Big message */
+#define NG_ICMPV6_TIME_EXC      (3)     /**< Time Exceeded message */
+#define NG_ICMPV6_PARAM_PROB    (4)     /**< Parameter Problem message */
+#define NG_ICMPV6_ERR_EXP1      (100)   /**< message type for private experimentation */
+#define NG_ICMPV6_ERR_EXP2      (101)   /**< message type for private experimentation */
+/**
+ * @}
+ */
+
+/**
+ * @{
+ * @name Informational message types
+ * @see <a href="http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2">
+ *          IANA, ICMPv6 "type" Numbers
+ *      </a>
+ */
+#define NG_ICMPV6_ECHO_REQ      (128)   /**< Echo request message (ping) */
+#define NG_ICMPV6_ECHO_REP      (129)   /**< Echo reply message (pong) */
+#define NG_ICMPV6_RTR_SOL       (133)   /**< NDP router solicitation message */
+#define NG_ICMPV6_RTR_ADV       (134)   /**< NDP router advertisement message */
+#define NG_ICMPV6_NBR_SOL       (135)   /**< NDP neighbor solicitation message */
+#define NG_ICMPV6_NBR_ADV       (136)   /**< NDP neighbor advertisement message */
+#define NG_ICMPV6_REDIRECT      (137)   /**< NDP redirect message */
+#define NG_ICMPV6_RPL_CTRL      (155)   /**< RPL control message */
+#define NG_ICMPV6_INF_EXP1      (200)   /**< message type for private experimentation */
+#define NG_ICMPV6_INF_EXP2      (201)   /**< message type for private experimentation */
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_ICMPV6_TYPES_H_ */
+/** @} */
diff --git a/sys/net/crosslayer/ng_netreg/ng_netreg.c b/sys/net/crosslayer/ng_netreg/ng_netreg.c
index 0e014cd99e309eccfd7a0dbb42926df2a97ae92d..1d4517e9f3a810083fe16916daaf2dde534cd22b 100644
--- a/sys/net/crosslayer/ng_netreg/ng_netreg.c
+++ b/sys/net/crosslayer/ng_netreg/ng_netreg.c
@@ -20,6 +20,7 @@
 #include "net/ng_netreg.h"
 #include "net/ng_nettype.h"
 #include "net/ng_pkt.h"
+#include "net/ng_icmpv6.h"
 #include "net/ng_ipv6.h"
 #include "net/ng_udp.h"
 
diff --git a/sys/net/network_layer/ng_icmpv6/Makefile b/sys/net/network_layer/ng_icmpv6/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2
--- /dev/null
+++ b/sys/net/network_layer/ng_icmpv6/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
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 0000000000000000000000000000000000000000..f30fd54da6e7224beb019b02697bbc871d02319d
--- /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 0000000000000000000000000000000000000000..24f4701acbae88e9dbea445312439d4147ab9bd3
--- /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
new file mode 100644
index 0000000000000000000000000000000000000000..fb93c5a44da547d3f9d23108063b162c7c2cf368
--- /dev/null
+++ b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup     net_ng_icmpv6
+ * @{
+ *
+ * @file
+ *
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "byteorder.h"
+#include "kernel_types.h"
+#include "net/ng_netbase.h"
+#include "net/ng_protnum.h"
+#include "net/ng_ipv6/hdr.h"
+#include "od.h"
+#include "utlist.h"
+
+#include "net/ng_icmpv6.h"
+#include "net/ng_icmpv6/echo.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+static inline uint16_t _calc_csum(ng_pktsnip_t *hdr,
+                                  ng_pktsnip_t *pseudo_hdr,
+                                  ng_pktsnip_t *payload)
+{
+    uint16_t csum = 0;
+    uint16_t len = (uint16_t)hdr->size;
+
+    while (payload && (payload != hdr)) {
+        csum = ng_inet_csum(csum, payload->data, payload->size);
+        len += (uint16_t)payload->size;
+        payload = payload->next;
+    }
+
+    csum = ng_inet_csum(csum, hdr->data, hdr->size);
+    csum = ng_ipv6_hdr_inet_csum(csum, pseudo_hdr->data, NG_PROTNUM_ICMPV6,
+                                 len);
+
+    return ~csum;
+}
+
+void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt)
+{
+    ng_pktsnip_t *icmpv6, *ipv6;
+    ng_icmpv6_hdr_t *hdr;
+    ng_netreg_entry_t *sendto;
+
+    LL_SEARCH_SCALAR(pkt, icmpv6, type, NG_NETTYPE_ICMPV6);
+
+    /* there can be extension headers between IPv6 and ICMPv6 header so we have
+     * to search it */
+    LL_SEARCH_SCALAR(icmpv6, ipv6, type, NG_NETTYPE_IPV6);
+
+    hdr = (ng_icmpv6_hdr_t *)icmpv6->data;
+
+    if (_calc_csum(icmpv6, ipv6, pkt)) {
+        DEBUG("icmpv6: wrong checksum.\n");
+        /* don't release: IPv6 does this */
+        return;
+    }
+
+    switch (hdr->type) {
+        /* TODO: handle ICMPv6 errors */
+#ifdef MODULE_NG_ICMPV6_ECHO
+        case NG_ICMPV6_ECHO_REQ:
+            DEBUG("icmpv6: handle echo request.\n");
+            ng_icmpv6_echo_req_handle(iface, (ng_ipv6_hdr_t *)ipv6->data,
+                                      (ng_icmpv6_echo_t *)hdr, icmpv6->size);
+            break;
+#endif
+
+#ifdef MODULE_NG_NDP
+        case NG_ICMPV6_RTR_SOL:
+        case NG_ICMPV6_RTR_ADV:
+        case NG_ICMPV6_NBR_SOL:
+        case NG_ICMPV6_NBR_ADV:
+        case NG_ICMPV6_REDIRECT:
+            DEBUG("icmpv6: neighbor discovery message received\n");
+            /* TODO */
+            break;
+#endif
+
+#ifdef MODULE_NG_RPL
+        case NG_ICMPV6_RPL_CTRL:
+            DEBUG("icmpv6: RPL control message received\n");
+            /* TODO */
+            break;
+#endif
+
+        default:
+            DEBUG("icmpv6: unknown type field %" PRIu8 "\n", hdr->type);
+            break;
+    }
+
+    /* ICMPv6-all will be send in ng_ipv6.c so only dispatch of subtypes is
+     * needed */
+
+    sendto = ng_netreg_lookup(NG_NETTYPE_ICMPV6, hdr->type);
+
+    if (sendto == NULL) {
+        DEBUG("icmpv6: no receivers for ICMPv6 type %" PRIu8 "\n", hdr->type);
+        /* don't release: IPv6 does this */
+        return;
+    }
+
+    /* ICMPv6 is not interested anymore so `- 1` */
+    ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_ICMPV6, hdr->type) - 1);
+
+    while (sendto != NULL) {
+        ng_netapi_receive(sendto->pid, pkt);
+        sendto = ng_netreg_getnext(sendto);
+    }
+}
+
+ng_pktsnip_t *ng_icmpv6_build(uint8_t type, uint8_t code, size_t size)
+{
+    ng_pktsnip_t *pkt;
+    ng_icmpv6_hdr_t *icmpv6;
+
+    pkt = ng_pktbuf_add(NULL, NULL, size, NG_NETTYPE_ICMPV6);
+
+    if (pkt == NULL) {
+        DEBUG("icmpv6_echo: no space left in packet buffer\n");
+        return NULL;
+    }
+
+    DEBUG("icmpv6: Building ICMPv6 message with type=%" PRIu8 ", code=%" PRIu8 "\n",
+          type, code);
+    icmpv6 = (ng_icmpv6_hdr_t *)pkt->data;
+    icmpv6->type = type;
+    icmpv6->code = code;
+
+    return pkt;
+}
+
+int ng_icmpv6_calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr)
+{
+    uint32_t csum = 0;
+
+    if (hdr == NULL) {
+        return -EFAULT;
+    }
+    if (hdr->type != NG_NETTYPE_ICMPV6) {
+        return -EBADMSG;
+    }
+
+    csum = _calc_csum(hdr, pseudo_hdr, hdr->next);
+
+    if (csum == 0) {
+        return -ENOENT;
+    }
+
+    ((ng_icmpv6_hdr_t *)hdr->data)->csum = byteorder_htons(csum);
+
+    return 0;
+}
+
+/**
+ * @}
+ */
diff --git a/sys/net/network_layer/ng_ipv6/ng_ipv6.c b/sys/net/network_layer/ng_ipv6/ng_ipv6.c
index 6e36ce857d1eda383effeafde9fc3594b9dcc8c7..2526417c0a06c6e21cc54d9144e76d18997d79c0 100644
--- a/sys/net/network_layer/ng_ipv6/ng_ipv6.c
+++ b/sys/net/network_layer/ng_ipv6/ng_ipv6.c
@@ -18,6 +18,7 @@
 #include "byteorder.h"
 #include "cpu-conf.h"
 #include "kernel_types.h"
+#include "net/ng_icmpv6.h"
 #include "net/ng_netbase.h"
 #include "net/ng_protnum.h"
 #include "thread.h"
@@ -68,8 +69,14 @@ void ng_ipv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt, uint8_t nh)
 
     pkt->type = ng_nettype_from_protnum(nh);
 
-    /* TODO: add ICMPv6 and extension header handling */
-    (void)iface;    /* will be used by that */
+    switch (nh) {
+        case NG_PROTNUM_ICMPV6:
+            ng_icmpv6_demux(iface, pkt);
+            break;
+        /* TODO: add extension header handling */
+        default:
+            break;
+    }
 
     receiver_num = ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) +
                    ng_netreg_num(NG_NETTYPE_IPV6, nh);
diff --git a/sys/shell/commands/Makefile b/sys/shell/commands/Makefile
index d2d2dbf6e959101d23bbf42625faeb97268d9e99..b64d70c46c76527c2830cab7d21523fa1e07a781 100644
--- a/sys/shell/commands/Makefile
+++ b/sys/shell/commands/Makefile
@@ -64,6 +64,9 @@ endif
 ifneq (,$(filter ng_ipv6_nc,$(USEMODULE)))
     SRC += sc_ipv6_nc.c
 endif
+ifneq (,$(filter ng_icmpv6_echo vtimer,$(USEMODULE)))
+    SRC += sc_icmpv6_echo.c
+endif
 
 # TODO
 # Conditional building not possible at the moment due to
diff --git a/sys/shell/commands/sc_icmpv6_echo.c b/sys/shell/commands/sc_icmpv6_echo.c
new file mode 100644
index 0000000000000000000000000000000000000000..f9fb102576239d7c1e4a0e24b221fb9c1bf51916
--- /dev/null
+++ b/sys/shell/commands/sc_icmpv6_echo.c
@@ -0,0 +1,240 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup     sys_shell_commands
+ * @{
+ *
+ * @file
+ *
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef MODULE_NG_ICMPV6
+
+#include "byteorder.h"
+#include "net/ng_icmpv6.h"
+#include "net/ng_ipv6/addr.h"
+#include "net/ng_ipv6/hdr.h"
+#include "net/ng_netbase.h"
+#include "thread.h"
+#include "utlist.h"
+#include "vtimer.h"
+
+static uint16_t id = 0x53;
+static uint16_t seq = 1;
+static char ipv6_str[NG_IPV6_ADDR_MAX_STR_LEN];
+
+static void usage(char **argv)
+{
+    printf("%s [<n>] <ipv6 addr> [<payload_len>]\n", argv[0]);
+}
+
+void _set_payload(ng_icmpv6_echo_t *hdr, size_t payload_len)
+{
+    size_t i = 0;
+    uint8_t *payload = (uint8_t *)(hdr + 1);
+
+    while (i < payload_len) {
+        if (seq > 0xff) {
+            payload[i] = (uint8_t)(seq >> 8);
+            payload[i + 1] = (uint8_t)(seq & 0xff);
+            i += 2;
+        }
+        else {
+            payload[i++] = (uint8_t)(seq & 0xff);
+        }
+    }
+
+    if (i > payload_len) {
+        payload[payload_len - 1] = seq >> 8;
+    }
+}
+
+int _handle_reply(ng_pktsnip_t *pkt, uint64_t time)
+{
+    ng_pktsnip_t *ipv6, *icmpv6;
+    ng_ipv6_hdr_t *ipv6_hdr;
+    ng_icmpv6_echo_t *icmpv6_hdr;
+
+    LL_SEARCH_SCALAR(pkt, ipv6, type, NG_NETTYPE_IPV6);
+    LL_SEARCH_SCALAR(pkt, icmpv6, type, NG_NETTYPE_ICMPV6);
+
+    if ((ipv6 == NULL) || (icmpv6 == NULL)) {
+        puts("error: IPv6 header or ICMPv6 header not found in reply");
+        return 0;
+    }
+
+    ipv6_hdr = ipv6->data;
+    icmpv6_hdr = icmpv6->data;
+
+    if ((byteorder_ntohs(icmpv6_hdr->id) == id) &&
+        (byteorder_ntohs(icmpv6_hdr->seq) == seq)) {
+        printf("%zu bytes from %s: id=%" PRIu16 " seq=%" PRIu16 " hop limit=%" PRIu8
+               "time = %" PRIu64 ".%03" PRIu64 " ms\n", icmpv6->size,
+               ng_ipv6_addr_to_str(ipv6_str, &(ipv6_hdr->src), sizeof(ipv6_str)),
+               byteorder_ntohs(icmpv6_hdr->id), byteorder_ntohs(icmpv6_hdr->seq),
+               ipv6_hdr->hl, time / MS_IN_USEC, time % MS_IN_USEC);
+    }
+    else {
+        puts("error: unexpected parameters");
+        return 0;
+    }
+
+    return 1;
+}
+
+int _icmpv6_ping(int argc, char **argv)
+{
+    int n = 3, success = 0, count;
+    size_t payload_len = 4;
+    char *addr_str;
+    ng_ipv6_addr_t addr;
+    ng_netreg_entry_t *ipv6_entry, my_entry = { NULL, NG_ICMPV6_ECHO_REP,
+                                                thread_getpid()
+                                              };
+    timex_t min_rtt = { UINT32_MAX, UINT32_MAX }, max_rtt = { 0, 0 };
+    timex_t sum_rtt = { 0, 0 };
+
+    switch (argc) {
+        case 1:
+            usage(argv);
+            return 1;
+
+        case 2:
+            addr_str = argv[1];
+            break;
+
+        case 3:
+            n = atoi(argv[1]);
+            addr_str = argv[2];
+            break;
+
+        case 4:
+        default:
+            n = atoi(argv[1]);
+            addr_str = argv[2];
+            payload_len = atoi(argv[3]);
+            break;
+    }
+
+    if (ng_ipv6_addr_from_str(&addr, addr_str) == NULL) {
+        usage(argv);
+        return 1;
+    }
+
+    if (ng_netreg_register(NG_NETTYPE_ICMPV6, &my_entry) < 0) {
+        puts("error: network registry is full");
+        return 1;
+    }
+
+    ipv6_entry = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL);
+
+    if (ipv6_entry == NULL) {
+        puts("error: ipv6 thread missing");
+        return 1;
+    }
+
+    count = n;
+
+    while ((count--) > 0) {
+        msg_t msg;
+        ng_pktsnip_t *pkt;
+        timex_t start, stop, timeout = { 5, 0 };
+
+        pkt = ng_icmpv6_echo_req_build(id, seq, NULL, payload_len);
+
+        if (pkt == NULL) {
+            puts("error: packet buffer full");
+            return 1;
+        }
+
+        _set_payload(pkt->data, payload_len);
+
+        pkt = ng_netreg_hdr_build(NG_NETTYPE_IPV6, pkt, NULL, 0, addr.u8,
+                                  sizeof(ng_ipv6_addr_t));
+
+        if (pkt == NULL) {
+            puts("error: packet buffer full");
+            return 1;
+        }
+
+        vtimer_now(&start);
+        ng_netapi_send(ipv6_entry->pid, pkt);
+
+        if (vtimer_msg_receive_timeout(&msg, timeout) >= 0) {
+            switch (msg.type) {
+                case NG_NETAPI_MSG_TYPE_RCV:
+                    vtimer_now(&stop);
+                    stop = timex_sub(stop, start);
+                    success += _handle_reply((ng_pktsnip_t *)msg.content.ptr,
+                                             timex_uint64(stop));
+
+                    if (timex_cmp(stop, max_rtt) > 0) {
+                        max_rtt = stop;
+                    }
+
+                    if (timex_cmp(stop, min_rtt) < 1) {
+                        min_rtt = stop;
+                    }
+
+                    sum_rtt = timex_add(sum_rtt, stop);
+
+                    break;
+
+                default:
+                    /* requeue wrong packets */
+                    msg_send(&msg, thread_getpid());
+                    break;
+            }
+        }
+        else {
+            puts("ping timeout");
+        }
+
+        seq++;
+    }
+
+    seq = 1;
+    id++;
+
+    ng_netreg_unregister(NG_NETTYPE_ICMPV6, &my_entry);
+
+    printf("--- %s ping statistics ---\n", addr_str);
+
+    if (success > 0) {
+        printf("%d packets transmitted, %d received, %d%% packet loss, time %"
+               PRIu64 " ms\n", n, success, (success - n) / n,
+               timex_uint64(sum_rtt) / MS_IN_USEC);
+        uint64_t avg_rtt = timex_uint64(sum_rtt) / n;  /* get average */
+        printf("rtt min/avg/max = "
+               "%" PRIu64 ".%03" PRIu64 "/"
+               "%" PRIu64 ".%03" PRIu64 "/"
+               "%" PRIu64 ".%03" PRIu64 " ms\n",
+               timex_uint64(min_rtt) / MS_IN_USEC,
+               timex_uint64(min_rtt) % MS_IN_USEC,
+               avg_rtt / MS_IN_USEC, avg_rtt % MS_IN_USEC,  /* sum is now avg, see above */
+               timex_uint64(max_rtt) / MS_IN_USEC,
+               timex_uint64(max_rtt) % MS_IN_USEC);
+    }
+    else {
+        printf("%d packets transmitted, 0 received, 100%% packet loss\n", n);
+        return 1;
+    }
+
+    return 0;
+}
+
+#endif
+
+/**
+ * @}
+ */
diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c
index dc0714d500c7c86e46ae65c9aa1988e7fae7dbbb..5adad5e2916c3fec49b6386909721643e5b63f26 100644
--- a/sys/shell/commands/shell_commands.c
+++ b/sys/shell/commands/shell_commands.c
@@ -145,6 +145,12 @@ extern int _read_sector(int argc, char **argv);
 extern int _read_bytes(int argc, char **argv);
 #endif
 
+#ifdef MODULE_NG_ICMPV6_ECHO
+#ifdef MODULE_VTIMER
+extern int _icmpv6_ping(int argc, char **argv);
+#endif
+#endif
+
 #ifdef MODULE_RANDOM
 extern int _mersenne_init(int argc, char **argv);
 extern int _mersenne_get(int argc, char **argv);
@@ -251,6 +257,11 @@ const shell_command_t _shell_command_list[] = {
     {DISK_GET_SECTOR_COUNT, "Get the sector count of inserted memory card", _get_sectorcount},
     {DISK_GET_BLOCK_SIZE, "Get the block size of inserted memory card", _get_blocksize},
 #endif
+#ifdef MODULE_NG_ICMPV6_ECHO
+#ifdef MODULE_VTIMER
+    { "ping6", "Ping via ICMPv6", _icmpv6_ping },
+#endif
+#endif
 #ifdef MODULE_RANDOM
     { "mersenne_init", "initializes the PRNG", _mersenne_init },
     { "mersenne_get", "returns 32 bit of pseudo randomness", _mersenne_get },