diff --git a/Makefile.dep b/Makefile.dep
index 1775fd02467ad5ac832640df8258c8bb238434aa..85c785d83a7c286ed7d7221b0501f5f28b2c1add 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -258,3 +258,13 @@ endif
 ifneq (,$(filter hih6130,$(USEMODULE)))
   USEMODULE += vtimer
 endif
+
+ifneq (,$(filter ng_rpl,$(USEMODULE)))
+  USEMODULE += timex
+  USEMODULE += vtimer
+  USEMODULE += ng_ipv6_router_default
+  USEMODULE += trickle
+  USEMODULE += net_help
+  USEMODULE += universal_address
+  USEMODULE += fib
+endif
diff --git a/sys/Makefile b/sys/Makefile
index 6343af63fe93a6b6d50089288994faa6d8f1f91c..94bce4564dddbd2bcaf0bace92161517d2ad3671 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -88,6 +88,9 @@ endif
 ifneq (,$(filter ng_zep,$(USEMODULE)))
     DIRS += net/application_layer/ng_zep
 endif
+ifneq (,$(filter ng_rpl,$(USEMODULE)))
+    DIRS += net/routing/ng_rpl
+endif
 ifneq (,$(filter ng_rpl_srh,$(USEMODULE)))
     DIRS += net/routing/ng_rpl/srh
 endif
diff --git a/sys/include/net/ng_ipv6/netif.h b/sys/include/net/ng_ipv6/netif.h
index dcb2b8851d739d2707f7de45a7b96a7194559c2d..a217739b038b87a27aac3fa9a9ce3e3d2b664a35 100644
--- a/sys/include/net/ng_ipv6/netif.h
+++ b/sys/include/net/ng_ipv6/netif.h
@@ -42,9 +42,9 @@ extern "C" {
  */
 #ifndef NG_IPV6_NETIF_ADDR_NUMOF
 #ifdef MODULE_NG_IPV6_ROUTER
-#define NG_IPV6_NETIF_ADDR_NUMOF    (7) /* router needs all-routers multicast address */
+#define NG_IPV6_NETIF_ADDR_NUMOF    (8) /* router needs all-routers multicast address */
 #else
-#define NG_IPV6_NETIF_ADDR_NUMOF    (6)
+#define NG_IPV6_NETIF_ADDR_NUMOF    (7)
 #endif
 #endif
 
diff --git a/sys/include/net/ng_rpl.h b/sys/include/net/ng_rpl.h
index fc738e282314610df26e9415fd5519b57c27b64b..67717a1ab6c94a1fb9e2fd31e36521379cdc68fe 100644
--- a/sys/include/net/ng_rpl.h
+++ b/sys/include/net/ng_rpl.h
@@ -1,5 +1,7 @@
 /*
+ * Copyright (C) 2013 - 2014  INRIA.
  * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
+ * Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
  *
  * 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
@@ -7,27 +9,414 @@
  */
 
 /**
- * @defgroup    net_ng_rpl  New RPL
+ * @defgroup    net_ng_rpl RPL
  * @ingroup     net
  * @{
  *
  * @file
- * @brief   TODO
+ * @brief       RPL header. Declaration of global variables and functions needed for
+ *              core functionality of RPL.
  *
- * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ * Header which includes all core RPL-functions.
+ *
+ * @author      Eric Engel <eric.engel@fu-berlin.de>
+ * @author      Fabian Brandt <fabianbr@zedat.fu-berlin.de>
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ * @author      Cenk Gündoğan <cnkgndgn@gmail.com>
  */
+
 #ifndef NG_RPL_H_
 #define NG_RPL_H_
 
-
+#include <string.h>
+#include <stdint.h>
+#include "net/ng_ipv6.h"
+#include "net/ng_icmpv6.h"
+#include "net/ng_nettype.h"
+#include "net/ng_rpl/structs.h"
+#include "net/ng_rpl/dodag.h"
+#include "net/ng_rpl/of_manager.h"
+#include "inet_ntop.h"
+#include "net/fib.h"
+#include "vtimer.h"
+#include "trickle.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/**
+ * @brief   Default stack size to use for the IPv6 thread
+ */
+#ifndef NG_RPL_STACK_SIZE
+#define NG_RPL_STACK_SIZE (THREAD_STACKSIZE_DEFAULT)
+#endif
+
+/**
+ * @brief   Default priority for the RPL thread
+ */
+#ifndef NG_RPL_PRIO
+#define NG_RPL_PRIO            (THREAD_PRIORITY_MAIN - 4)
+#endif
+
+/**
+ * @brief   Default message queue size to use for the RPL thread.
+ */
+#ifndef NG_RPL_MSG_QUEUE_SIZE
+#define NG_RPL_MSG_QUEUE_SIZE  (8U)
+#endif
+
+/**
+ * @brief   Static initializer for the all-RPL-nodes multicast IPv6
+ *          address (ff02::1a)
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
+ *          RFC 6550, section 6
+ *      </a>
+ */
+#define NG_IPV6_ADDR_ALL_RPL_NODES {{ 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1a }}
+
+/**
+ * @brief   Message type for lifetime updates
+ */
+#define NG_RPL_MSG_TYPE_LIFETIME_UPDATE     (0x0900)
+
+/**
+ * @brief   Message type for trickle intervals
+ */
+#define NG_RPL_MSG_TYPE_TRICKLE_INTERVAL    (0x0901)
+
+/**
+ * @brief   Message type for trickle callbacks
+ */
+#define NG_RPL_MSG_TYPE_TRICKLE_CALLBACK    (0x0902)
+
+/**
+ * @brief   Message type for handling DAO sending
+ */
+#define NG_RPL_MSG_TYPE_DAO_HANDLE  (0x0903)
+
+/**
+ * @brief   Message type for handling DODAG cleanup
+ */
+#define NG_RPL_MSG_TYPE_CLEANUP_HANDLE  (0x0904)
+
+/**
+ * @brief   Infinite rank
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-17">
+ *          RFC 6550, section 17
+ *      </a>
+ */
+#define NG_RPL_INFINITE_RANK (0xFFFF)
+
+/**
+ * @brief   Default minimum hop rank increase
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-17">
+ *          RFC 6550, section 17
+ *      </a>
+ */
+#define NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE (256)
+
+/**
+ * @brief   Maximum rank increase
+ */
+#define NG_RPL_DEFAULT_MAX_RANK_INCREASE (0)
+
+/**
+ * @brief   Number of implemented Objective Functions
+ */
+#define NG_RPL_IMPLEMENTED_OFS_NUMOF (1)
+
+/**
+ * @brief   Default Objective Code Point (OF0)
+ */
+#define NG_RPL_DEFAULT_OCP (0)
+
+/**
+ * @name RPL Mode of Operations
+ * @{
+ */
+#define NG_RPL_MOP_NO_DOWNWARD_ROUTES  (0x00)
+#define NG_RPL_MOP_NON_STORING_MODE    (0x01)
+#define NG_RPL_MOP_STORING_MODE_NO_MC  (0x02)
+#define NG_RPL_MOP_STORING_MODE_MC     (0x03)
+/** default MOP set on compile time */
+#ifndef NG_RPL_DEFAULT_MOP
+#   define NG_RPL_DEFAULT_MOP NG_RPL_MOP_STORING_MODE_NO_MC
+#endif
+/** @} */
+
+/**
+ * @name Sequence counter handling
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-7.2">
+ *          Sequence Counter Operation
+ *      </a>
+ * @{
+ */
+#define NG_RPL_COUNTER_MAX                 (255)
+#define NG_RPL_COUNTER_LOWER_REGION        (127)
+#define NG_RPL_COUNTER_SEQ_WINDOW          (16)
+#define NG_RPL_COUNTER_INIT                (NG_RPL_COUNTER_MAX - NG_RPL_COUNTER_SEQ_WINDOW + 1)
+
+static inline uint8_t NG_RPL_COUNTER_INCREMENT(uint8_t counter)
+{
+    return ((counter > NG_RPL_COUNTER_LOWER_REGION) ?
+            ((counter == NG_RPL_COUNTER_MAX) ? counter = 0 : ++counter) :
+            ((counter == NG_RPL_COUNTER_LOWER_REGION) ? counter = 0 : ++counter));
+}
+
+static inline bool NG_RPL_COUNTER_IS_INIT(uint8_t counter)
+{
+    return (counter > NG_RPL_COUNTER_LOWER_REGION);
+}
+
+static inline bool NG_RPL_COUNTER_GREATER_THAN_LOCAL(uint8_t A, uint8_t B)
+{
+    return (((A < B) && (NG_RPL_COUNTER_LOWER_REGION + 1 - B + A < NG_RPL_COUNTER_SEQ_WINDOW))
+            || ((A > B) && (A - B < NG_RPL_COUNTER_SEQ_WINDOW)));
+}
+
+static inline bool NG_RPL_COUNTER_GREATER_THAN(uint8_t A, uint8_t B)
+{
+    return ((A > NG_RPL_COUNTER_LOWER_REGION) ? ((B > NG_RPL_COUNTER_LOWER_REGION) ?
+                NG_RPL_COUNTER_GREATER_THAN_LOCAL(A, B) : 0) :
+            ((B > NG_RPL_COUNTER_LOWER_REGION) ? 1 : NG_RPL_COUNTER_GREATER_THAN_LOCAL(A, B)));
+}
+/** @} */
+
+/**
+ * @name Trickle parameters
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-8.3.1">
+ *          Trickle Parameters
+ *      </a>
+ * @{
+ */
+#define NG_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS (20)
+#define NG_RPL_DEFAULT_DIO_INTERVAL_MIN (3)
+#define NG_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT (10)
+/** @} */
+
+/**
+ * @name Default parent and route entry lifetime
+ * default lifetime will be multiplied by the lifetime unit to obtain the resulting lifetime
+ * @{
+ */
+#define NG_RPL_DEFAULT_LIFETIME (60)
+#define NG_RPL_LIFETIME_UNIT (2)
+/** @} */
+
+/**
+ * @brief Interval of the void _update_lifetime() function
+ */
+#define NG_RPL_LIFETIME_STEP (2)
+
+/**
+ * @brief A DODAG can be grounded or floating
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-3.2.4">
+ *          Grounded and Floating DODAGs
+ *      </a>
+ */
+#define NG_RPL_GROUNDED (1)
+
+/**
+ * @name Parameters used for DAO handling
+ * @{
+ */
+#define NG_RPL_DAO_SEND_RETRIES (4)
+#define NG_RPL_DEFAULT_WAIT_FOR_DAO_ACK (3)
+#define NG_RPL_REGULAR_DAO_INTERVAL (60)
+#define NG_RPL_DEFAULT_DAO_DELAY (5)
+/** @} */
+
+/**
+ * @brief Cleanup timeout in seconds
+ */
+#define NG_RPL_CLEANUP_TIME (30)
+
+/**
+ * @name Node Status
+ * @{
+ */
+#define NG_RPL_NORMAL_NODE  (0)
+#define NG_RPL_ROOT_NODE (1)
+#define NG_RPL_LEAF_NODE (2)
+/** @} */
+
+
+/**
+ * @name RPL Control Message Options
+ *  @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7">
+ *          RPL Control Message Options
+ *      </a>
+ * @{
+ */
+#define NG_RPL_OPT_PAD1                 (0)
+#define NG_RPL_OPT_PADN                 (1)
+#define NG_RPL_OPT_DAG_METRIC_CONTAINER (2)
+#define NG_RPL_OPT_ROUTE_INFO           (3)
+#define NG_RPL_OPT_DODAG_CONF           (4)
+#define NG_RPL_OPT_TARGET               (5)
+#define NG_RPL_OPT_TRANSIT              (6)
+#define NG_RPL_OPT_SOLICITED_INFO       (7)
+#define NG_RPL_OPT_PREFIX_INFO          (8)
+#define NG_RPL_OPT_TARGET_DESC          (9)
+/** @} */
+
+/**
+ * @brief Rank of the root node
+ */
+#define NG_RPL_ROOT_RANK (256)
+
+/**
+ *  @brief  DIS ICMPv6 code
+ *  @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
+ *          RFC 6550, section 6
+ *      </a>
+ */
+#define NG_RPL_ICMPV6_CODE_DIS (0x00)
+
+/**
+ *  @brief  DIO ICMPv6 code
+ *  @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
+ *          RFC 6550, section 6
+ *      </a>
+ */
+#define NG_RPL_ICMPV6_CODE_DIO (0x01)
+
+/**
+ *  @brief  DAO ICMPv6 code
+ *  @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
+ *          RFC 6550, section 6
+ *      </a>
+ */
+#define NG_RPL_ICMPV6_CODE_DAO (0x02)
+
+/**
+ *  @brief  DAO ACK ICMPv6 code
+ *  @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
+ *          RFC 6550, section 6
+ *      </a>
+ */
+#define NG_RPL_ICMPV6_CODE_DAO_ACK (0x03)
+
+/**
+ * @brief Update interval of the lifetime update function
+ */
+#define NG_RPL_LIFETIME_UPDATE_STEP (2)
+
+/**
+ * @brief PID of the RPL thread.
+ */
+extern kernel_pid_t ng_rpl_pid;
+
+/**
+ * @brief Initialization of the RPL thread.
+ *
+ * @param[in] if_pid            PID of the interface
+ *
+ * @return  The PID of the RPL thread, on success.
+ * @return  a negative errno on error.
+ */
+kernel_pid_t ng_rpl_init(kernel_pid_t if_pid);
+
+/**
+ * @brief Initialization of a RPL DODAG as root node. Creates a new instance if necessary.
+ *
+ * @param[in] instance_id       Id of the instance
+ * @param[in] dodag_id          Id of the DODAG
+ *
+ * @return  Pointer to the new DODAG, on success.
+ * @return  NULL, otherwise.
+ */
+ng_rpl_dodag_t *ng_rpl_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id);
+
+/**
+ * @brief   Send a DIO of the @p dodag to the @p destination.
+ *
+ * @param[in] dodag             Pointer to the DODAG.
+ * @param[in] destination       IPv6 addres of the destination.
+ */
+void ng_rpl_send_DIO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination);
+
+/**
+ * @brief   Send a DIS of the @p dodag to the @p destination.
+ *
+ * @param[in] dodag             Pointer to the DODAG, optional.
+ * @param[in] destination       IPv6 addres of the destination.
+ */
+void ng_rpl_send_DIS(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination);
+
+/**
+ * @brief   Send a DAO of the @p dodag to the @p destination.
+ *
+ * @param[in] dodag             Pointer to the DODAG.
+ * @param[in] destination       IPv6 addres of the destination.
+ * @param[in] lifetime          Lifetime of the route to announce.
+ */
+void ng_rpl_send_DAO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_t lifetime);
+
+/**
+ * @brief   Send a DAO-ACK of the @p dodag to the @p destination.
+ *
+ * @param[in] dodag             Pointer to the DODAG, optional.
+ * @param[in] destination       IPv6 addres of the destination.
+ * @param[in] seq				Sequence number to be acknowledged.
+ */
+void ng_rpl_send_DAO_ACK(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_t seq);
+
+/**
+ * @brief   Parse a DIS.
+ *
+ * @param[in] dis       Pointer to the DIS message.
+ * @param[in] src       Pointer to the source address of the IPv6 packet.
+ * @param[in] dst       Pointer to the destination address of the IPv6 packet.
+ * @param[in] len       Length of the IPv6 packet.
+ */
+void ng_rpl_recv_DIS(ng_rpl_dis_t *dis, ipv6_addr_t *src, ipv6_addr_t *dst, uint16_t len);
+
+/**
+ * @brief   Parse a DIO.
+ *
+ * @param[in] dio       Pointer to the DIO message.
+ * @param[in] src       Pointer to the source address of the IPv6 packet.
+ * @param[in] len       Length of the IPv6 packet.
+ */
+void ng_rpl_recv_DIO(ng_rpl_dio_t *dio, ipv6_addr_t *src, uint16_t len);
+
+/**
+ * @brief   Parse a DAO.
+ *
+ * @param[in] dao       Pointer to the DAO message.
+ * @param[in] src       Pointer to the source address of the IPv6 packet.
+ * @param[in] len       Length of the IPv6 packet.
+ */
+void ng_rpl_recv_DAO(ng_rpl_dao_t *dao, ipv6_addr_t *src, uint16_t len);
+
+/**
+ * @brief   Parse a DAO-ACK.
+ *
+ * @param[in] dao_ack   Pointer to the DAO-ACK message.
+ */
+void ng_rpl_recv_DAO_ACK(ng_rpl_dao_ack_t *dao_ack);
+
+/**
+ * @brief   Delay the DAO sending interval
+ *
+ * @param[in] dodag     The DODAG of the DAO
+ */
+void ng_rpl_delay_dao(ng_rpl_dodag_t *dodag);
+
+/**
+ * @brief   Long delay the DAO sending interval
+ *
+ * @param[in] dodag     The DODAG of the DAO
+ */
+void ng_rpl_long_delay_dao(ng_rpl_dodag_t *dodag);
 #ifdef __cplusplus
 }
 #endif
 
 #endif /* NG_RPL_H_ */
-/** @} */
+/**
+ * @}
+ */
diff --git a/sys/include/net/ng_rpl/dodag.h b/sys/include/net/ng_rpl/dodag.h
new file mode 100644
index 0000000000000000000000000000000000000000..43eeb67d8a54b9fa608c055939f102228b2c380a
--- /dev/null
+++ b/sys/include/net/ng_rpl/dodag.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2013  INRIA.
+ * Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
+ *
+ * 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_rpl
+ * @{
+ *
+ * @file
+ * @brief       DODAG-related functions for RPL
+ *
+ * Header file, which defines all public known DODAG-related functions for RPL.
+ *
+ * @author      Eric Engel <eric.engel@fu-berlin.de>
+ * @author      Cenk Gündoğan <cnkgndgn@gmail.com>
+ */
+
+#ifndef NG_RPL_DODAG_H_
+#define NG_RPL_DODAG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "net/ng_ipv6.h"
+#include "trickle.h"
+#include "net/ng_rpl.h"
+#include "net/ng_rpl/structs.h"
+
+/**
+ * @brief   Number of RPL instances
+ */
+#ifndef NG_RPL_INSTANCES_NUMOF
+#define NG_RPL_INSTANCES_NUMOF (2)
+#endif
+
+/**
+ * @brief   Number of RPL dodags
+ */
+#ifndef NG_RPL_DODAGS_NUMOF
+#define NG_RPL_DODAGS_NUMOF (4)
+#endif
+
+/**
+ * @brief   Number of RPL parents
+ */
+#ifndef NG_RPL_PARENTS_NUMOF
+#define NG_RPL_PARENTS_NUMOF (6)
+#endif
+
+/**
+ * @brief   RPL instance table
+ */
+extern ng_rpl_instance_t ng_rpl_instances[NG_RPL_INSTANCES_NUMOF];
+
+/**
+ * @brief   RPL DODAG table
+ */
+extern ng_rpl_dodag_t ng_rpl_dodags[NG_RPL_DODAGS_NUMOF];
+
+/**
+ * @brief   RPL parent table
+ */
+extern ng_rpl_parent_t ng_rpl_parents[NG_RPL_PARENTS_NUMOF];
+
+/**
+ * @brief   Add a new RPL instance with the id @p instance_id.
+ *
+ * @param[in]   instance_id     The instance id of the new RPL instance.
+ * @param[out]  inst            Pointer to an existing or new instance. Otherwise NULL.
+ *
+ * @return  true, if instance could be created.
+ * @return  false, if instance could not be created or exists already.
+ */
+bool ng_rpl_instance_add(uint8_t instance_id, ng_rpl_instance_t **inst);
+
+/**
+ * @brief   Remove a RPL instance with the id @p instance_id.
+ *
+ * @param[in] instance_id     The instance id of the RPL instance to remove.
+ *
+ * @return  true, on success.
+ * @return  false, otherwise.
+ */
+bool ng_rpl_instance_remove_by_id(uint8_t instance_id);
+
+/**
+ * @brief   Remove a RPL instance with the pointer @p inst.
+ *
+ * @param[in] inst     Pointer to the the RPL instance to remove.
+ *
+ * @return  true, on success.
+ * @return  false, otherwise.
+ */
+bool ng_rpl_instance_remove(ng_rpl_instance_t *inst);
+
+/**
+ * @brief   Get the RPL instance with the id @p instance_id.
+ *
+ * @param[in] instance_id     The instance id of the RPL instance to get.
+ *
+ * @return  Pointer to the RPL instance, on success.
+ * @return  NULL, otherwise.
+ */
+ng_rpl_instance_t *ng_rpl_instance_get(uint8_t instance_id);
+
+/**
+ * @brief   Add a new RPL DODAG with the id @p dodag_id to the instance @p instance.
+ *
+ * @param[in]   instance        Pointer to the instance to add the DODAG to
+ * @param[in]   dodag_id        The DODAG-ID of the new DODAG
+ * @param[out]  dodag           Pointer to an existing or new DODAG. Otherwise NULL.
+ *
+ * @return  true, if DODAG could be created.
+ * @return  false, if DODAG could not be created or exists already.
+ */
+bool ng_rpl_dodag_add(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id, ng_rpl_dodag_t **dodag);
+
+/**
+ * @brief   Remove the RPL DODAG @p dodag.
+ *
+ * @param[in] dodag     Pointer to the dodag.
+ *
+ * @return  true, on success.
+ * @return  false, otherwise.
+ */
+bool ng_rpl_dodag_remove(ng_rpl_dodag_t *dodag);
+
+/**
+ * @brief   Remove all parents from the @p dodag.
+ *
+ * @param[in] dodag     Pointer to the dodag.
+ */
+void ng_rpl_dodag_remove_all_parents(ng_rpl_dodag_t *dodag);
+
+/**
+ * @brief   Get the RPL DODAG with the id @p dodag_id to the instance @p instance.
+ *
+ * @param[in] instance      Pointer to the instance of the RPL DODAG
+ * @param[in] dodag_id      The DODAG-ID of the RPL DODAG
+ *
+ * @return  Pointer to the existing RPL DODAG, on success.
+ * @return  NULL, otherwise.
+ */
+ng_rpl_dodag_t *ng_rpl_dodag_get(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id);
+
+/**
+ * @brief   Add a new parent with the IPv6 address @p addr to the @p dodag.
+ *
+ * @param[in]   dodag           Pointer to the DODAG
+ * @param[in]   addr            IPV6 address of the parent
+ * @param[out]  parent          Pointer to an existing or new parent. Otherwise NULL.
+ *
+ * @return  true. if parent could be created.
+ * @return  false, if parent could not be created or exists already.
+ */
+bool ng_rpl_parent_add_by_addr(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr, ng_rpl_parent_t **parent);
+
+/**
+ * @brief   Remove the @p parent from its DODAG.
+ *
+ * @param[in] parent     Pointer to the parent.
+ *
+ * @return  true, on success.
+ * @return  false, otherwise.
+ */
+bool ng_rpl_parent_remove(ng_rpl_parent_t *parent);
+
+/**
+ * @brief   Get a parent with the IPv6 addr @p addr of the DODAG @p dodag.
+ *
+ * @param[in] dodag     Pointer to the DODAG
+ * @param[in] addr      IPv6 address of the parent
+ *
+ * @return  Pointer to the existing parent, on success.
+ * @return  NULL, otherwise.
+ */
+ng_rpl_parent_t *ng_rpl_parent_get(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr);
+
+/**
+ * @brief   Update a @p parent of the @p dodag.
+ *
+ * @param[in] dodag     Pointer to the DODAG
+ * @param[in] parent    Pointer to the parent
+ */
+void ng_rpl_parent_update(ng_rpl_dodag_t *dodag, ng_rpl_parent_t *parent);
+
+/**
+ * @brief   Find the parent with the lowest rank and update the DODAG's preferred parent
+ *
+ * @param[in] dodag     Pointer to the DODAG
+ *
+ * @return  Pointer to the preferred parent, on success.
+ * @return  NULL, otherwise.
+ */
+ng_rpl_parent_t *ng_rpl_find_preferred_parent(ng_rpl_dodag_t *dodag);
+
+/**
+ * @brief   Start a local repair.
+ *
+ * @param[in] dodag     Pointer to the DODAG
+ */
+void ng_rpl_local_repair(ng_rpl_dodag_t *dodag);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_RPL_DODAG_H_ */
+/**
+ * @}
+ */
diff --git a/sys/include/net/ng_rpl/of_manager.h b/sys/include/net/ng_rpl/of_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a24db01cb43ff47709a581a6518800a661a5b18
--- /dev/null
+++ b/sys/include/net/ng_rpl/of_manager.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 Freie Universität Berlin
+ *
+ * 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_rpl
+ * @{
+ *
+ * @file
+ * @brief   RPL Objective functions manager header
+ *
+ * @author  Fabian Brandt <fabianbr@zedat.fu-berlin.de>
+ */
+
+#ifndef RPL_OFM_H
+#define RPL_OFM_H
+
+#include "structs.h"
+#include "net/ng_ipv6.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Initialization of Manager and of-functions.
+*/
+void ng_rpl_of_manager_init(void);
+
+/**
+ * @brief Returns objective function with a given cope point
+ * @param[in]   ocp Objective code point of objective function
+ * @return      Pointer of corresponding objective function implementation
+*/
+ng_rpl_of_t *ng_rpl_get_of_for_ocp(uint16_t ocp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPL_OFM_H */
+/** @} */
diff --git a/sys/include/net/ng_rpl/structs.h b/sys/include/net/ng_rpl/structs.h
new file mode 100644
index 0000000000000000000000000000000000000000..4e601c335990d84e7e2233d01068cfa18841aaed
--- /dev/null
+++ b/sys/include/net/ng_rpl/structs.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2013  INRIA.
+ * Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
+ *
+ * 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_rpl
+ * @{
+ *
+ * @file
+ * @brief       RPL data structs
+ *
+ * Header file, which defines all structs used by RPL.
+ *
+ * @author      Eric Engel <eric.engel@fu-berlin.de>
+ * @author      Cenk Gündoğan <cnkgndgn@gmail.com>
+ */
+
+#ifndef NG_RPL_STRUCTS_H_
+#define NG_RPL_STRUCTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "net/ng_ipv6.h"
+#include "trickle.h"
+
+/**
+ * @brief RPL-Option Generic Format
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.1">
+ *          RPL Control Message Option Generic Format
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;       /**< Option Type */
+    uint8_t length;     /**< Option Length, does not include the first two byte */
+} ng_rpl_opt_t;
+
+/**
+ * @brief DIO Base Object
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6.3.1">
+ *          Format of the DIO Base Object
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t instance_id;        /**< id of the instance */
+    uint8_t version_number;     /**< version number of the DODAG */
+    network_uint16_t rank;      /**< rank of the parent emitting the DIO */
+    uint8_t g_mop_prf;          /**< grounded, MOP, preferred flags */
+    uint8_t dtsn;               /**< Destination Advertisement Trigger Sequence Number */
+    uint8_t flags;              /**< unused */
+    uint8_t reserved;           /**< reserved */
+    ipv6_addr_t dodag_id;       /**< id of the dodag */
+} ng_rpl_dio_t;
+
+/**
+ * @brief DODAG Configuration Option
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.6">
+ *          DODAG Configuration
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;                       /**< Option Type: 0x04 */
+    uint8_t length;                     /**< length of option, not including first two bytes */
+    uint8_t flags_a_pcs;                /**< flags */
+    uint8_t dio_int_doubl;              /**< trickle Imax parameter */
+    uint8_t dio_int_min;                /**< trickle Imin parameter */
+    uint8_t dio_redun;                  /**< trickle k parameter */
+    network_uint16_t max_rank_inc;      /**< allowable increase in rank */
+    network_uint16_t min_hop_rank_inc;  /**< DAGRank(rank) = floor(rank/MinHopRankIncrease) */
+    network_uint16_t ocp;               /**< Objective Code Point */
+    uint8_t reserved;                   /**< reserved */
+    uint8_t default_lifetime;           /**< lifetime of RPL routes (lifetime * lifetime_unit) */
+    network_uint16_t lifetime_unit;     /**< unit in seconds */
+} ng_rpl_opt_dodag_conf_t;
+
+/**
+ * @brief DODAG Information Solicitation
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6.2">
+ *          DODAG Information Solicitation
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t flags;      /**< unused */
+    uint8_t reserved;   /**< reserved */
+} ng_rpl_dis_t;
+
+/**
+ * @brief Destination Advertisement Object
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6.4">
+ *          Destination Advertisement Object
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t instance_id;        /**< id of the instance */
+    uint8_t k_d_flags;          /**< K and D flags */
+    uint8_t reserved;           /**< reserved */
+    uint8_t dao_sequence;       /**< sequence of the DAO, needs to be used for DAO-ACK */
+    ipv6_addr_t dodag_id;       /**< id of the DODAG */
+} ng_rpl_dao_t;
+
+/**
+ * @brief Destination Advertisement Object Acknowledgement
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6.5">
+ *          Destination Advertisement Object Acknowledgement
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t instance_id;        /**< id of the instance */
+    uint8_t d_reserved;         /**< if set, indicates that the DODAG id should be included */
+    uint8_t dao_sequence;       /**< sequence must be equal to the sequence from the DAO object */
+    uint8_t status;             /**< indicates completion */
+    ipv6_addr_t dodag_id;       /**< id of the DODAG */
+} ng_rpl_dao_ack_t;
+
+/**
+ * @brief Target Option
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.7">
+ *          RPL Target
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;               /**< option type */
+    uint8_t length;             /**< option length without the first two bytes */
+    uint8_t flags;              /**< unused */
+    uint8_t prefix_length;      /**< number of valid leading bits in the IPv6 prefix */
+    ipv6_addr_t target;         /**< IPv6 prefix, address or multicast group */
+} ng_rpl_opt_target_t;
+
+/**
+ * @brief Transit Option
+ * @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.8">
+ *          Transit Information
+ *      </a>
+ */
+typedef struct __attribute__((packed)) {
+    uint8_t type;               /**< option type */
+    uint8_t length;             /**< option length without the first two bytes */
+    uint8_t e_flags;            /**< external flag indicates external routes */
+    uint8_t path_control;       /**< limits the number of DAO parents */
+    uint8_t path_sequence;      /**< increased value for route updates */
+    uint8_t path_lifetime;      /**< lifetime of routes */
+} ng_rpl_opt_transit_t;
+
+typedef struct ng_rpl_dodag ng_rpl_dodag_t;
+typedef struct ng_rpl_parent ng_rpl_parent_t;
+
+/**
+ * @brief Parent representation
+ */
+struct ng_rpl_parent {
+    ng_rpl_parent_t *next;          /**< pointer to the next parent */
+    uint8_t state;                  /**< 0 for unsued, 1 for used */
+    ipv6_addr_t addr;               /**< link-local IPv6 address of this parent */
+    uint16_t rank;                  /**< rank of the parent */
+    uint8_t dtsn;                   /**< last seen dtsn of this parent */
+    ng_rpl_dodag_t *dodag;          /**< DODAG the parent belongs to */
+    timex_t lifetime;               /**< lifetime of this parent */
+    double  link_metric;            /**< metric of the link */
+    uint8_t link_metric_type;       /**< type of the metric */
+};
+
+/**
+ * @brief Objective function representation
+ */
+typedef struct {
+    uint16_t ocp;   /**< objective code point */
+    uint16_t (*calc_rank)(ng_rpl_parent_t *parent, uint16_t base_rank); /**< calculate the rank */
+    ng_rpl_parent_t *(*which_parent)(ng_rpl_parent_t *, ng_rpl_parent_t *); /**< compare for parents */
+    ng_rpl_dodag_t *(*which_dodag)(ng_rpl_dodag_t *, ng_rpl_dodag_t *); /**< compare for dodags */
+    void (*reset)(ng_rpl_dodag_t *);    /**< resets the OF */
+    void (*parent_state_callback)(ng_rpl_parent_t *, int, int); /**< retrieves the state of a parent*/
+    void (*init)(void);  /**< OF specific init function */
+    void (*process_dio)(void);  /**< DIO processing callback (acc. to OF0 spec, chpt 5) */
+} ng_rpl_of_t;
+
+
+/**
+ * @brief Instance representation
+ */
+typedef struct {
+    uint8_t id;                     /**< id of the instance */
+    uint8_t state;                  /**< 0 for unused, 1 for used */
+    ng_rpl_dodag_t *dodags;         /**< pointer to the DODAG list of this instance */
+    uint8_t mop;                    /**< configured Mode of Operation */
+    ng_rpl_of_t *of;                /**< configured Objective Function */
+    uint16_t min_hop_rank_inc;      /**< minimum hop rank increase */
+    uint16_t max_rank_inc;          /**< max increase in the rank */
+} ng_rpl_instance_t;
+
+/**
+ * @brief DODAG representation
+ */
+struct ng_rpl_dodag {
+    ng_rpl_instance_t *instance;    /**< id of the instance */
+    ng_rpl_dodag_t *next;           /**< pointer to the next dodag */
+    ng_rpl_parent_t *parents;       /**< pointer to the parents list of this DODAG */
+    ipv6_addr_t dodag_id;           /**< id of the DODAG */
+    uint8_t state;                  /**< 0 for unused, 1 for used */
+    uint8_t dtsn;                   /**< DAO Trigger Sequence Number */
+    uint8_t prf;                    /**< preferred flag */
+    uint8_t dio_interval_doubl;     /**< trickle Imax parameter */
+    uint8_t dio_min;                /**< trickle Imin parameter */
+    uint8_t dio_redun;              /**< trickle k parameter */
+    uint8_t default_lifetime;       /**< lifetime of routes (lifetime * unit) */
+    uint16_t lifetime_unit;         /**< unit in seconds of the lifetime */
+    uint8_t version;                /**< version of this DODAG */
+    uint8_t grounded;               /**< grounded flag */
+    uint16_t my_rank;               /**< rank/position in the DODAG */
+    uint8_t node_status;            /**< leaf, normal, or root node */
+    uint8_t dao_seq;                /**< dao sequence number */
+    uint8_t dao_counter;            /**< amount of retried DAOs */
+    bool dao_ack_received;          /**< flag to check for DAO-ACK */
+    uint8_t dodag_conf_counter;     /**< limitation of the sending of DODAG_CONF options */
+    timex_t dao_time;               /**< time to schedule the next DAO */
+    vtimer_t dao_timer;             /**< timer to schedule the next DAO */
+    timex_t cleanup_time;           /**< time to schedula a DODAG cleanup */
+    vtimer_t cleanup_timer;         /**< timer to schedula a DODAG cleanup */
+    trickle_t trickle;              /**< trickle representation */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_RPL_STRUCTS_H_ */
+/**
+ * @}
+ */
diff --git a/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c
index 3c811976da7a534df09aae8e110ee5ef377daf67..bfb372fa5d8988c3dc1a7d2c7d1c8a60b5e702f5 100644
--- a/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c
+++ b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c
@@ -114,13 +114,6 @@ void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt)
             /* TODO */
             break;
 
-#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;
diff --git a/sys/net/routing/ng_rpl/Makefile b/sys/net/routing/ng_rpl/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2
--- /dev/null
+++ b/sys/net/routing/ng_rpl/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/routing/ng_rpl/ng_rpl.c b/sys/net/routing/ng_rpl/ng_rpl.c
new file mode 100644
index 0000000000000000000000000000000000000000..2f8e1c798b7b075357fa4e5a6e2072ed82979cf0
--- /dev/null
+++ b/sys/net/routing/ng_rpl/ng_rpl.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
+ *
+ * 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
+ *
+ * @author  Cenk Gündoğan <cnkgndgn@gmail.com>
+ */
+#include "net/ng_rpl.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#if ENABLE_DEBUG && defined(MODULE_IPV6_ADDR)
+static char addr_str[IPV6_ADDR_MAX_STR_LEN];
+#endif
+
+static char _stack[NG_RPL_STACK_SIZE];
+kernel_pid_t ng_rpl_pid = KERNEL_PID_UNDEF;
+static timex_t _lt_time;
+static vtimer_t _lt_timer;
+static msg_t _msg_q[NG_RPL_MSG_QUEUE_SIZE];
+static ng_netreg_entry_t _me_reg;
+
+ng_rpl_instance_t ng_rpl_instances[NG_RPL_INSTANCES_NUMOF];
+ng_rpl_dodag_t ng_rpl_dodags[NG_RPL_DODAGS_NUMOF];
+ng_rpl_parent_t ng_rpl_parents[NG_RPL_PARENTS_NUMOF];
+
+static void _update_lifetime(void);
+static void _dao_handle_send(ng_rpl_dodag_t *dodag);
+static void _receive(ng_pktsnip_t *pkt);
+static void *_event_loop(void *args);
+static ng_rpl_dodag_t *_root_dodag_init(uint8_t instance_id, ipv6_addr_t *dodag_id, uint8_t mop);
+
+kernel_pid_t ng_rpl_init(kernel_pid_t if_pid)
+{
+    /* check if RPL was initialized before */
+    if (ng_rpl_pid == KERNEL_PID_UNDEF) {
+        /* start the event loop */
+        ng_rpl_pid = thread_create(_stack, sizeof(_stack), NG_RPL_PRIO, CREATE_STACKTEST,
+                _event_loop, NULL, "RPL");
+
+        if (ng_rpl_pid == KERNEL_PID_UNDEF) {
+            DEBUG("RPL: could not start the event loop\n");
+            return KERNEL_PID_UNDEF;
+        }
+
+        _me_reg.demux_ctx = NG_ICMPV6_RPL_CTRL;
+        _me_reg.pid = ng_rpl_pid;
+        /* register interest in all ICMPv6 packets */
+        ng_netreg_register(NG_NETTYPE_ICMPV6, &_me_reg);
+
+        ng_rpl_of_manager_init();
+        _lt_time = timex_set(NG_RPL_LIFETIME_UPDATE_STEP, 0);
+        vtimer_set_msg(&_lt_timer, _lt_time, ng_rpl_pid, NG_RPL_MSG_TYPE_LIFETIME_UPDATE, NULL);
+    }
+
+    /* register all_RPL_nodes multicast address */
+    ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
+    ng_ipv6_netif_add_addr(if_pid, &all_RPL_nodes, IPV6_ADDR_BIT_LEN, 0);
+
+    ng_rpl_send_DIS(NULL, &all_RPL_nodes);
+    return ng_rpl_pid;
+}
+
+ng_rpl_dodag_t *ng_rpl_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id)
+{
+    ng_rpl_dodag_t *dodag = _root_dodag_init(instance_id, dodag_id, NG_RPL_DEFAULT_MOP);
+
+    if (!dodag) {
+        return NULL;
+    }
+
+    dodag->dtsn = 1;
+    dodag->prf = 0;
+    dodag->dio_interval_doubl = NG_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS;
+    dodag->dio_min = NG_RPL_DEFAULT_DIO_INTERVAL_MIN;
+    dodag->dio_redun = NG_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT;
+    dodag->default_lifetime = NG_RPL_DEFAULT_LIFETIME;
+    dodag->lifetime_unit = NG_RPL_LIFETIME_UNIT;
+    dodag->version = NG_RPL_COUNTER_INIT;
+    dodag->grounded = NG_RPL_GROUNDED;
+    dodag->node_status = NG_RPL_ROOT_NODE;
+    dodag->my_rank = NG_RPL_ROOT_RANK;
+
+    trickle_start(ng_rpl_pid, &dodag->trickle, NG_RPL_MSG_TYPE_TRICKLE_INTERVAL,
+                  NG_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min),
+                  dodag->dio_interval_doubl, dodag->dio_redun);
+
+    return dodag;
+}
+
+static ng_rpl_dodag_t *_root_dodag_init(uint8_t instance_id, ipv6_addr_t *dodag_id, uint8_t mop)
+{
+    if (ng_rpl_pid == KERNEL_PID_UNDEF) {
+        DEBUG("RPL: RPL thread not started\n");
+        return NULL;
+    }
+
+    ipv6_addr_t *configured_addr;
+    ng_rpl_instance_t *inst = NULL;
+    ng_rpl_dodag_t *dodag = NULL;
+
+    if (instance_id == 0) {
+        DEBUG("RPL: instance id (%d) must be a positive number greater than zero\n", instance_id);
+        return NULL;
+    }
+
+    if (ng_ipv6_netif_find_by_addr(&configured_addr, dodag_id) == KERNEL_PID_UNDEF) {
+        DEBUG("RPL: no IPv6 address configured to match the given dodag id: %s\n",
+              ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str)));
+        return NULL;
+    }
+
+    if (ng_rpl_instance_add(instance_id, &inst)) {
+        inst->of = (ng_rpl_of_t *) ng_rpl_get_of_for_ocp(NG_RPL_DEFAULT_OCP);
+        inst->mop = mop;
+        inst->min_hop_rank_inc = NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE;
+        inst->max_rank_inc = NG_RPL_DEFAULT_MAX_RANK_INCREASE;
+    }
+    else if (inst == NULL) {
+        DEBUG("RPL: could not allocate memory for a new instance with id %d", instance_id);
+        return NULL;
+    }
+    else if (inst->mop != mop) {
+        DEBUG("RPL: instance (%d) exists with another MOP", instance_id);
+        return NULL;
+    }
+
+    if (!ng_rpl_dodag_add(inst, dodag_id, &dodag)) {
+        DEBUG("RPL: DODAG with id %s exists or no memory left for a new DODAG",
+                ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str)));
+        return NULL;
+    }
+
+    return dodag;
+}
+
+static void _receive(ng_pktsnip_t *icmpv6)
+{
+    ng_pktsnip_t *ipv6 = NULL;
+    ipv6_hdr_t *ipv6_hdr = NULL;
+    ng_icmpv6_hdr_t *icmpv6_hdr = NULL;
+
+    LL_SEARCH_SCALAR(icmpv6, ipv6, type, NG_NETTYPE_IPV6);
+    ipv6_hdr = (ipv6_hdr_t *)ipv6->data;
+
+    icmpv6_hdr = (ng_icmpv6_hdr_t *)icmpv6->data;
+    switch (icmpv6_hdr->code) {
+        case NG_RPL_ICMPV6_CODE_DIS:
+            DEBUG("RPL: DIS received\n");
+            ng_rpl_recv_DIS((ng_rpl_dis_t *)(icmpv6_hdr + 1), &ipv6_hdr->src, &ipv6_hdr->dst,
+                    byteorder_ntohs(ipv6_hdr->len));
+            break;
+        case NG_RPL_ICMPV6_CODE_DIO:
+            DEBUG("RPL: DIO received\n");
+            ng_rpl_recv_DIO((ng_rpl_dio_t *)(icmpv6_hdr + 1), &ipv6_hdr->src,
+                    byteorder_ntohs(ipv6_hdr->len));
+            break;
+        case NG_RPL_ICMPV6_CODE_DAO:
+            DEBUG("RPL: DAO received\n");
+            ng_rpl_recv_DAO((ng_rpl_dao_t *)(icmpv6_hdr + 1), &ipv6_hdr->src,
+                    byteorder_ntohs(ipv6_hdr->len));
+            break;
+        case NG_RPL_ICMPV6_CODE_DAO_ACK:
+            DEBUG("RPL: DAO-ACK received\n");
+            ng_rpl_recv_DAO_ACK((ng_rpl_dao_ack_t *)(icmpv6_hdr + 1));
+            break;
+        default:
+            DEBUG("RPL: Unknown ICMPV6 code received\n");
+            break;
+    }
+
+    ng_pktbuf_release(icmpv6);
+}
+
+static void *_event_loop(void *args)
+{
+    msg_t msg, reply;
+
+    (void)args;
+    msg_init_queue(_msg_q, NG_RPL_MSG_QUEUE_SIZE);
+
+    /* preinitialize ACK */
+    reply.type = NG_NETAPI_MSG_TYPE_ACK;
+
+    trickle_t *trickle;
+    ng_rpl_dodag_t *dodag;
+    /* start event loop */
+    while (1) {
+        DEBUG("RPL: waiting for incoming message.\n");
+        msg_receive(&msg);
+
+        switch (msg.type) {
+            case NG_RPL_MSG_TYPE_LIFETIME_UPDATE:
+                DEBUG("RPL: NG_RPL_MSG_TYPE_LIFETIME_UPDATE received\n");
+                _update_lifetime();
+                break;
+            case NG_RPL_MSG_TYPE_TRICKLE_INTERVAL:
+                DEBUG("RPL: NG_RPL_MSG_TYPE_TRICKLE_INTERVAL received\n");
+                trickle = (trickle_t *) msg.content.ptr;
+                if (trickle && (trickle->callback.func != NULL)) {
+                    trickle_interval(trickle);
+                }
+                break;
+            case NG_RPL_MSG_TYPE_TRICKLE_CALLBACK:
+                DEBUG("RPL: NG_RPL_MSG_TYPE_TRICKLE_CALLBACK received\n");
+                trickle = (trickle_t *) msg.content.ptr;
+                if (trickle && (trickle->callback.func != NULL)) {
+                    trickle_callback(trickle);
+                }
+                break;
+            case NG_RPL_MSG_TYPE_DAO_HANDLE:
+                DEBUG("RPL: NG_RPL_MSG_TYPE_DAO_HANDLE received\n");
+                dodag = (ng_rpl_dodag_t *) msg.content.ptr;
+                if (dodag && (dodag->state != 0)) {
+                    _dao_handle_send(dodag);
+                }
+                break;
+            case NG_RPL_MSG_TYPE_CLEANUP_HANDLE:
+                DEBUG("RPL: NG_RPL_MSG_TYPE_CLEANUP received\n");
+                dodag = (ng_rpl_dodag_t *) msg.content.ptr;
+                if (dodag && (dodag->state != 0) && (dodag->parents == NULL)) {
+                    /* no parents - delete this DODAG */
+                    ng_rpl_dodag_remove(dodag);
+                }
+                break;
+            case NG_NETAPI_MSG_TYPE_RCV:
+                DEBUG("RPL: NG_NETAPI_MSG_TYPE_RCV received\n");
+                _receive((ng_pktsnip_t *)msg.content.ptr);
+                break;
+            case NG_NETAPI_MSG_TYPE_SND:
+            case NG_NETAPI_MSG_TYPE_GET:
+            case NG_NETAPI_MSG_TYPE_SET:
+                DEBUG("RPL: reply to unsupported recv/get/set\n");
+                reply.content.value = -ENOTSUP;
+                msg_reply(&msg, &reply);
+                break;
+            default:
+                break;
+        }
+    }
+
+    return NULL;
+}
+
+void _update_lifetime(void)
+{
+    timex_t now;
+    vtimer_now(&now);
+    ng_rpl_parent_t *parent;
+    for (uint8_t i = 0; i < NG_RPL_PARENTS_NUMOF; ++i) {
+        parent = &ng_rpl_parents[i];
+        if (parent->state != 0) {
+            if ((signed)(parent->lifetime.seconds - now.seconds) <= NG_RPL_LIFETIME_UPDATE_STEP) {
+                ng_rpl_dodag_t *dodag = parent->dodag;
+                ng_rpl_parent_remove(parent);
+                ng_rpl_parent_update(dodag, NULL);
+                continue;
+            }
+            else if (((signed)(parent->lifetime.seconds - now.seconds) <=
+                        NG_RPL_LIFETIME_UPDATE_STEP * 2)) {
+                ng_rpl_send_DIS(parent->dodag, &parent->addr);
+            }
+        }
+    }
+    vtimer_remove(&_lt_timer);
+    vtimer_set_msg(&_lt_timer, _lt_time, ng_rpl_pid, NG_RPL_MSG_TYPE_LIFETIME_UPDATE, NULL);
+}
+
+void ng_rpl_delay_dao(ng_rpl_dodag_t *dodag)
+{
+    dodag->dao_time = timex_set(NG_RPL_DEFAULT_DAO_DELAY, 0);
+    dodag->dao_counter = 0;
+    dodag->dao_ack_received = false;
+    vtimer_remove(&dodag->dao_timer);
+    vtimer_set_msg(&dodag->dao_timer, dodag->dao_time, ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag);
+}
+
+void ng_rpl_long_delay_dao(ng_rpl_dodag_t *dodag)
+{
+    dodag->dao_time = timex_set(NG_RPL_REGULAR_DAO_INTERVAL, 0);
+    dodag->dao_counter = 0;
+    dodag->dao_ack_received = false;
+    vtimer_remove(&dodag->dao_timer);
+    vtimer_set_msg(&dodag->dao_timer, dodag->dao_time, ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag);
+}
+
+void _dao_handle_send(ng_rpl_dodag_t *dodag)
+{
+    if ((dodag->dao_ack_received == false) && (dodag->dao_counter < NG_RPL_DAO_SEND_RETRIES)) {
+        dodag->dao_counter++;
+        ng_rpl_send_DAO(dodag, NULL, dodag->default_lifetime);
+        dodag->dao_time = timex_set(NG_RPL_DEFAULT_WAIT_FOR_DAO_ACK, 0);
+        vtimer_remove(&dodag->dao_timer);
+        vtimer_set_msg(&dodag->dao_timer, dodag->dao_time,
+                       ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag);
+    }
+    else if (dodag->dao_ack_received == false) {
+        ng_rpl_long_delay_dao(dodag);
+    }
+}
+
+/**
+ * @}
+ */
diff --git a/sys/net/routing/ng_rpl/ng_rpl_control_messages.c b/sys/net/routing/ng_rpl/ng_rpl_control_messages.c
new file mode 100644
index 0000000000000000000000000000000000000000..e98cd6ee5c9b8ef8ef5e92391600ee9f84781b36
--- /dev/null
+++ b/sys/net/routing/ng_rpl/ng_rpl_control_messages.c
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2013 - 2014  INRIA.
+ * Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
+ *
+ * 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
+ *
+ * @author  Cenk Gündoğan <cnkgndgn@gmail.com>
+ */
+
+#include "net/ng_rpl.h"
+#include "inet_ntop.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#if ENABLE_DEBUG && defined(MODULE_IPV6_ADDR)
+static char addr_str[IPV6_ADDR_MAX_STR_LEN];
+#endif
+
+#define NG_RPL_GROUNDED_SHIFT           (7)
+#define NG_RPL_MOP_SHIFT                (3)
+#define NG_RPL_OPT_DODAG_CONF_LEN       (14)
+#define NG_RPL_SHIFTED_MOP_MASK         (0x7)
+#define NG_RPL_PRF_MASK                 (0x7)
+
+void _ng_rpl_send(ng_pktsnip_t *pkt, ipv6_addr_t *src, ipv6_addr_t *dst,
+        ipv6_addr_t *dodag_id)
+{
+    ng_pktsnip_t *hdr;
+    ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES, ll_addr;
+    kernel_pid_t iface = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
+    if (iface == KERNEL_PID_UNDEF) {
+        DEBUG("RPL: no suitable interface found for this destination address\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    if (src == NULL) {
+        ipv6_addr_t *tmp = NULL;
+        if (dodag_id != NULL) {
+            tmp = ng_ipv6_netif_match_prefix(iface, dodag_id);
+        }
+        else if (dodag_id == NULL) {
+            tmp = ng_ipv6_netif_find_best_src_addr(iface, &all_RPL_nodes);
+        }
+
+        if (tmp == NULL) {
+            DEBUG("RPL: no suitable src address found\n");
+            ng_pktbuf_release(pkt);
+            return;
+        }
+
+        memcpy(&ll_addr, tmp, sizeof(ll_addr));
+        ipv6_addr_set_link_local_prefix(&ll_addr);
+        src = &ll_addr;
+    }
+
+    if (dst == NULL) {
+        dst = &all_RPL_nodes;
+    }
+
+    hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)src, sizeof(ipv6_addr_t), (uint8_t *)dst,
+                            sizeof(ipv6_addr_t));
+
+    if (hdr == NULL) {
+        DEBUG("RPL: Send - no space left in packet buffer\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    if (!ng_netapi_dispatch_send(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL,hdr)) {
+        DEBUG("RPL: cannot send packet: no subscribers found.\n");
+        ng_pktbuf_release(hdr);
+    }
+
+}
+
+void ng_rpl_send_DIO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination)
+{
+    if (dodag == NULL) {
+        DEBUG("RPL: Error - trying to send DIO without being part of a dodag.\n");
+        return;
+    }
+
+    ng_pktsnip_t *pkt;
+    ng_icmpv6_hdr_t *icmp;
+    ng_rpl_dio_t *dio;
+    uint8_t *pos;
+    int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dio_t);
+
+    if ((dodag->dodag_conf_counter % 3) == 0) {
+        size += sizeof(ng_rpl_opt_dodag_conf_t);
+    }
+
+    if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DIO, size)) == NULL) {
+        DEBUG("RPL: Send DIO - no space left in packet buffer\n");
+        return;
+    }
+
+    icmp = (ng_icmpv6_hdr_t *)pkt->data;
+    dio = (ng_rpl_dio_t *)(icmp + 1);
+    pos = (uint8_t *) dio;
+    dio->instance_id = dodag->instance->id;
+    dio->version_number = dodag->version;
+    dio->rank = byteorder_htons(dodag->my_rank);
+    dio->g_mop_prf = (dodag->grounded << NG_RPL_GROUNDED_SHIFT) |
+        (dodag->instance->mop << NG_RPL_MOP_SHIFT) | dodag->prf;
+    dio->dtsn = dodag->dtsn;
+    dio->flags = 0;
+    dio->reserved = 0;
+    dio->dodag_id = dodag->dodag_id;
+
+    pos += sizeof(*dio);
+
+    if ((dodag->dodag_conf_counter % 3) == 0) {
+        ng_rpl_opt_dodag_conf_t *dodag_conf;
+        dodag_conf = (ng_rpl_opt_dodag_conf_t *) pos;
+        dodag_conf->type = NG_RPL_OPT_DODAG_CONF;
+        dodag_conf->length = NG_RPL_OPT_DODAG_CONF_LEN;
+        dodag_conf->flags_a_pcs = 0;
+        dodag_conf->dio_int_doubl = dodag->dio_interval_doubl;
+        dodag_conf->dio_int_min = dodag->dio_min;
+        dodag_conf->dio_redun = dodag->dio_redun;
+        dodag_conf->max_rank_inc = byteorder_htons(dodag->instance->max_rank_inc);
+        dodag_conf->min_hop_rank_inc = byteorder_htons(dodag->instance->min_hop_rank_inc);
+        dodag_conf->ocp = byteorder_htons(dodag->instance->of->ocp);
+        dodag_conf->reserved = 0;
+        dodag_conf->default_lifetime = dodag->default_lifetime;
+        dodag_conf->lifetime_unit = byteorder_htons(dodag->lifetime_unit);
+        pos += sizeof(*dodag_conf);
+    }
+
+    dodag->dodag_conf_counter++;
+    _ng_rpl_send(pkt, NULL, destination, &dodag->dodag_id);
+}
+
+void ng_rpl_send_DIS(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination)
+{
+    (void) dodag;
+    ng_pktsnip_t *pkt;
+    ng_icmpv6_hdr_t *icmp;
+    ng_rpl_dis_t *dis;
+    /* TODO: Currently the DIS is too small so that wireshark complains about an incorrect
+     * ethernet frame check sequence. In order to prevent this, 4 PAD1 options are added.
+     * This will be addressed in follow-up PRs */
+    int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dis_t) + 4;
+
+    if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DIS, size)) == NULL) {
+        DEBUG("RPL: Send DIS - no space left in packet buffer\n");
+        return;
+    }
+
+    icmp = (ng_icmpv6_hdr_t *)pkt->data;
+    dis = (ng_rpl_dis_t *)(icmp + 1);
+    dis->flags = 0;
+    dis->reserved = 0;
+    /* TODO: see above TODO */
+    memset((dis + 1), 0, 4);
+
+    _ng_rpl_send(pkt, NULL, destination, (dodag ? &dodag->dodag_id : NULL));
+}
+
+void ng_rpl_recv_DIS(ng_rpl_dis_t *dis, ipv6_addr_t *src, ipv6_addr_t *dst, uint16_t len)
+{
+    /* TODO handle Solicited Information Option */
+    (void) dis;
+    (void) len;
+
+    if (ipv6_addr_is_multicast(dst)) {
+        for (uint8_t i = 0; i < NG_RPL_DODAGS_NUMOF; ++i) {
+            if (ng_rpl_dodags[i].state != 0) {
+                trickle_reset_timer(&ng_rpl_dodags[i].trickle);
+            }
+        }
+    }
+    else {
+        for (uint8_t i = 0; i < NG_RPL_DODAGS_NUMOF; ++i) {
+            if (ng_rpl_dodags[i].state != 0) {
+                ng_rpl_dodags[i].dodag_conf_counter = 0;
+                ng_rpl_send_DIO(&ng_rpl_dodags[i], src);
+            }
+        }
+    }
+}
+
+/** @todo allow target prefixes in target options to be of variable length */
+bool _parse_options(int msg_type, ng_rpl_dodag_t *dodag, ng_rpl_opt_t *opt, uint16_t len,
+                    ipv6_addr_t *src)
+{
+    uint16_t l = 0;
+    ng_rpl_opt_target_t *first_target = NULL;
+    while(l < len) {
+        if ((opt->type != NG_RPL_OPT_PAD1) && (len < opt->length + sizeof(ng_rpl_opt_t) + l)) {
+            /* return false to delete the dodag,
+             * because former options may also contain errors */
+            return false;
+        }
+
+        switch(opt->type) {
+            case (NG_RPL_OPT_PAD1): {
+                DEBUG("RPL: PAD1 option parsed\n");
+                l += 1;
+                opt = (ng_rpl_opt_t *) (((uint8_t *) opt) + 1);
+                continue;
+            }
+            case (NG_RPL_OPT_PADN): {
+                DEBUG("RPL: PADN option parsed\n");
+                break;
+            }
+            case (NG_RPL_OPT_DODAG_CONF): {
+                if (msg_type != NG_RPL_ICMPV6_CODE_DIO) {
+                    DEBUG("RPL: Ignore DODAG CONF DIO option\n");
+                    return true;
+                }
+                DEBUG("RPL: DODAG CONF DIO option parsed\n");
+                ng_rpl_opt_dodag_conf_t *dc = (ng_rpl_opt_dodag_conf_t *) opt;
+                ng_rpl_of_t *of = ng_rpl_get_of_for_ocp(byteorder_ntohs(dc->ocp));
+                if (of != NULL) {
+                    dodag->instance->of = of;
+                }
+                else {
+                    DEBUG("RPL: Unsupported OCP 0x%02x\n", byteorder_ntohs(dc->ocp));
+                    dodag->instance->of = ng_rpl_get_of_for_ocp(NG_RPL_DEFAULT_OCP);
+                }
+                dodag->dio_interval_doubl = dc->dio_int_doubl;
+                dodag->dio_min = dc->dio_int_min;
+                dodag->dio_redun = dc->dio_redun;
+                dodag->instance->max_rank_inc = byteorder_ntohs(dc->max_rank_inc);
+                dodag->instance->min_hop_rank_inc = byteorder_ntohs(dc->min_hop_rank_inc);
+                dodag->default_lifetime = dc->default_lifetime;
+                dodag->lifetime_unit = byteorder_ntohs(dc->lifetime_unit);
+                dodag->trickle.Imin = (1 << dodag->dio_min);
+                dodag->trickle.Imax = dodag->dio_interval_doubl;
+                dodag->trickle.k = dodag->dio_redun;
+                break;
+            }
+            case (NG_RPL_OPT_TARGET): {
+                if (msg_type != NG_RPL_ICMPV6_CODE_DAO) {
+                    DEBUG("RPL: Ignore RPL TARGET DAO option\n");
+                    return true;
+                }
+                DEBUG("RPL: RPL TARGET DAO option parsed\n");
+                kernel_pid_t if_id = ng_ipv6_netif_find_by_prefix(NULL, &dodag->dodag_id);
+                if (if_id == KERNEL_PID_UNDEF) {
+                    DEBUG("RPL: no interface found for the configured DODAG id\n");
+                    return false;
+                }
+
+                ng_rpl_opt_target_t *target = (ng_rpl_opt_target_t *) opt;
+                if (first_target == NULL) {
+                    first_target = target;
+                }
+
+                fib_add_entry(if_id, target->target.u8, sizeof(ipv6_addr_t), AF_INET6, src->u8,
+                        sizeof(ipv6_addr_t), AF_INET6,
+                        (dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS);
+                break;
+            }
+            case (NG_RPL_OPT_TRANSIT): {
+                if (msg_type != NG_RPL_ICMPV6_CODE_DAO) {
+                    DEBUG("RPL: Ignore RPL TRANSIT INFO DAO option\n");
+                    return true;
+                }
+                DEBUG("RPL: RPL TRANSIT INFO DAO option parsed\n");
+                ng_rpl_opt_transit_t *transit = (ng_rpl_opt_transit_t *) opt;
+                if (first_target == NULL) {
+                    DEBUG("RPL: Encountered a RPL TRANSIT DAO option without \
+a preceding RPL TARGET DAO option\n");
+                    break;
+                }
+
+                do {
+                    fib_update_entry(first_target->target.u8, sizeof(ipv6_addr_t),
+                            src->u8, sizeof(ipv6_addr_t), AF_INET6,
+                            (transit->path_lifetime * dodag->lifetime_unit * SEC_IN_MS));
+                    first_target = (ng_rpl_opt_target_t *) (((uint8_t *) (first_target)) +
+                        sizeof(ng_rpl_opt_t) + first_target->length);
+                }
+                while (first_target->type == NG_RPL_OPT_TARGET);
+
+                first_target = NULL;
+                break;
+            }
+        }
+        l += opt->length + sizeof(ng_rpl_opt_t);
+        opt = (ng_rpl_opt_t *) (((uint8_t *) (opt + 1)) + opt->length);
+    }
+    return true;
+}
+
+void ng_rpl_recv_DIO(ng_rpl_dio_t *dio, ipv6_addr_t *src, uint16_t len)
+{
+    ng_rpl_instance_t *inst = NULL;
+    ng_rpl_dodag_t *dodag = NULL;
+
+    len -= (sizeof(ng_rpl_dio_t) + sizeof(ng_icmpv6_hdr_t));
+
+    if (ng_rpl_instance_add(dio->instance_id, &inst)) {
+        inst->mop = (dio->g_mop_prf >> NG_RPL_MOP_SHIFT) & NG_RPL_SHIFTED_MOP_MASK;
+        inst->of = ng_rpl_get_of_for_ocp(NG_RPL_DEFAULT_OCP);
+    }
+    else if (inst == NULL) {
+        DEBUG("RPL: Could not allocate a new instance.\n");
+        return;
+    }
+
+    if ((byteorder_ntohs(dio->rank) == NG_RPL_INFINITE_RANK) &&
+            (ng_rpl_dodag_get(inst, &dio->dodag_id) == NULL)) {
+        DEBUG("RPL: ignore INFINITE_RANK DIO when we are not part of this DODAG\n");
+        ng_rpl_instance_remove(inst);
+        return;
+    }
+
+    if (ng_rpl_dodag_add(inst, &dio->dodag_id, &dodag)) {
+        DEBUG("RPL: Joined DODAG (%s).\n",
+                ipv6_addr_to_str(addr_str, &dio->dodag_id, sizeof(addr_str)));
+
+        ng_rpl_parent_t *parent = NULL;
+
+        if (!ng_rpl_parent_add_by_addr(dodag, src, &parent) && (parent == NULL)) {
+            DEBUG("RPL: Could not allocate new parent.\n");
+            ng_rpl_dodag_remove(dodag);
+            return;
+        }
+
+        dodag->version = dio->version_number;
+
+        parent->rank = byteorder_ntohs(dio->rank);
+
+        if(!_parse_options(NG_RPL_ICMPV6_CODE_DIO, dodag, (ng_rpl_opt_t *)(dio + 1), len, NULL)) {
+            ng_rpl_dodag_remove(dodag);
+            return;
+        }
+
+        ng_rpl_delay_dao(dodag);
+        trickle_start(ng_rpl_pid, &dodag->trickle, NG_RPL_MSG_TYPE_TRICKLE_INTERVAL,
+                      NG_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min),
+                      dodag->dio_interval_doubl, dodag->dio_redun);
+
+        ng_rpl_parent_update(dodag, parent);
+        return;
+    }
+    else if (dodag == NULL) {
+        DEBUG("RPL: Could not allocate a new DODAG.\n");
+        if (inst->dodags == NULL) {
+            ng_rpl_instance_remove(inst);
+        }
+        return;
+    }
+
+    if (dodag->instance->mop !=
+            ((dio->g_mop_prf >> NG_RPL_MOP_SHIFT) & NG_RPL_SHIFTED_MOP_MASK)) {
+        DEBUG("RPL: invalid MOP for this instance.\n");
+        return;
+    }
+
+    if (NG_RPL_COUNTER_GREATER_THAN(dio->version_number, dodag->version)) {
+        if (dodag->node_status == NG_RPL_ROOT_NODE) {
+            dodag->version = NG_RPL_COUNTER_INCREMENT(dio->version_number);
+            trickle_reset_timer(&dodag->trickle);
+        }
+        else {
+            dodag->version = dio->version_number;
+            ng_rpl_local_repair(dodag);
+        }
+    }
+    else if (NG_RPL_COUNTER_GREATER_THAN(dodag->version, dio->version_number)) {
+        trickle_reset_timer(&dodag->trickle);
+        return;
+    }
+
+    if (dodag->node_status == NG_RPL_ROOT_NODE) {
+        if (byteorder_ntohs(dio->rank) != NG_RPL_INFINITE_RANK) {
+            trickle_increment_counter(&dodag->trickle);
+        }
+        return;
+    }
+
+    dodag->grounded = dio->g_mop_prf >> NG_RPL_GROUNDED_SHIFT;
+    dodag->prf = dio->g_mop_prf & NG_RPL_PRF_MASK;
+
+    ng_rpl_parent_t *parent = NULL;
+
+    if (!ng_rpl_parent_add_by_addr(dodag, src, &parent) && (parent == NULL)) {
+        DEBUG("RPL: Could not allocate new parent.\n");
+        if (dodag->parents == NULL) {
+            ng_rpl_dodag_remove(dodag);
+        }
+        return;
+    }
+    /* cppcheck-suppress nullPointer */
+    else if (parent != NULL) {
+        trickle_increment_counter(&dodag->trickle);
+    }
+
+    parent->rank = byteorder_ntohs(dio->rank);
+
+    if(!_parse_options(NG_RPL_ICMPV6_CODE_DIO, dodag, (ng_rpl_opt_t *)(dio + 1), len, NULL)) {
+        ng_rpl_dodag_remove(dodag);
+        return;
+    }
+
+    ng_rpl_parent_update(dodag, parent);
+
+    if (parent->state != 0) {
+        if (dodag->parents && (parent == dodag->parents) && (parent->dtsn != dio->dtsn)) {
+            ng_rpl_delay_dao(dodag);
+        }
+        parent->dtsn = dio->dtsn;
+    }
+}
+
+void _dao_fill_target(ng_rpl_opt_target_t *target, ipv6_addr_t *addr)
+{
+    target->type = NG_RPL_OPT_TARGET;
+    target->length = sizeof(target->flags) + sizeof(target->prefix_length) + sizeof(target->target);
+    target->flags = 0;
+    target->prefix_length = 128;
+    target->target = *addr;
+}
+
+void ng_rpl_send_DAO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_t lifetime)
+{
+    size_t dst_size = NG_RPL_PARENTS_NUMOF;
+    fib_destination_set_entry_t fib_dest_set[NG_RPL_PARENTS_NUMOF];
+
+    if (dodag == NULL) {
+        DEBUG("RPL: Error - trying to send DAO without being part of a dodag.\n");
+        return;
+    }
+
+    if (dodag->node_status == NG_RPL_ROOT_NODE) {
+        return;
+    }
+
+    if (destination == NULL) {
+        if (dodag->parents == NULL) {
+            DEBUG("RPL: dodag has no preferred parent\n");
+            return;
+        }
+
+        destination = &(dodag->parents->addr);
+    }
+
+    ng_pktsnip_t *pkt;
+    ng_icmpv6_hdr_t *icmp;
+    ng_rpl_dao_t *dao;
+    ng_rpl_opt_target_t *target;
+    ng_rpl_opt_transit_t *transit;
+
+    /* find my address */
+    ipv6_addr_t *me = NULL;
+    ng_ipv6_netif_find_by_prefix(&me, &dodag->dodag_id);
+    if (me == NULL) {
+        DEBUG("RPL: no address configured\n");
+        return;
+    }
+
+    ng_ipv6_netif_addr_t *me_netif = ng_ipv6_netif_addr_get(me);
+    if (me_netif == NULL) {
+        DEBUG("RPL: no netif address found for %s\n", ipv6_addr_to_str(addr_str, me,
+                    sizeof(addr_str)));
+        return;
+    }
+
+    /* find prefix for my address */
+    ipv6_addr_t prefix;
+    ipv6_addr_init_prefix(&prefix, me, me_netif->prefix_len);
+    fib_get_destination_set(prefix.u8, sizeof(ipv6_addr_t), fib_dest_set, &dst_size);
+
+    int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dao_t) +
+        (sizeof(ng_rpl_opt_target_t) * (dst_size + 1)) + sizeof(ng_rpl_opt_transit_t);
+
+    if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DAO, size)) == NULL) {
+        DEBUG("RPL: Send DAO - no space left in packet buffer\n");
+        return;
+    }
+
+    icmp = (ng_icmpv6_hdr_t *)pkt->data;
+    dao = (ng_rpl_dao_t *)(icmp + 1);
+
+    dao->instance_id = dodag->instance->id;
+    /* set the D flag to indicate that a DODAG id is present */
+    /* set the K flag to indicate that a ACKs are required */
+    dao->k_d_flags = ((1 << 6) | (1 << 7));
+    dao->dao_sequence = dodag->dao_seq;
+    dao->dodag_id = dodag->dodag_id;
+    dao->reserved = 0;
+
+    /* add own address */
+    target = (ng_rpl_opt_target_t *) (dao + 1);
+    _dao_fill_target(target, me);
+    /* add children */
+    for (size_t i = 0; i < dst_size; ++i) {
+        target = (target + 1);
+        _dao_fill_target(target, ((ipv6_addr_t *) fib_dest_set[i].dest));
+    }
+
+    transit = (ng_rpl_opt_transit_t *) (target + 1);
+    transit->type = NG_RPL_OPT_TRANSIT;
+    transit->length = sizeof(transit->e_flags) + sizeof(transit->path_control) +
+        sizeof(transit->path_sequence) + sizeof(transit->path_lifetime);
+    transit->e_flags = 0;
+    transit->path_control = 0;
+    transit->path_sequence = 0;
+    transit->path_lifetime = lifetime;
+
+    _ng_rpl_send(pkt, NULL, destination, &dodag->dodag_id);
+
+    NG_RPL_COUNTER_INCREMENT(dodag->dao_seq);
+}
+
+void ng_rpl_send_DAO_ACK(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_t seq)
+{
+    if (dodag == NULL) {
+        DEBUG("RPL: Error - trying to send DAO-ACK without being part of a dodag.\n");
+        return;
+    }
+
+    ng_pktsnip_t *pkt;
+    ng_icmpv6_hdr_t *icmp;
+    ng_rpl_dao_ack_t *dao_ack;
+    int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dao_ack_t);
+
+    if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DAO_ACK, size)) == NULL) {
+        DEBUG("RPL: Send DAOACK - no space left in packet buffer\n");
+        return;
+    }
+
+    icmp = (ng_icmpv6_hdr_t *)pkt->data;
+    dao_ack = (ng_rpl_dao_ack_t *)(icmp + 1);
+
+    dao_ack->instance_id = dodag->instance->id;
+    /* set the D flag to indicate that a DODAG id is present */
+    dao_ack->d_reserved = (1 << 7);
+    dao_ack->dao_sequence = seq;
+    dao_ack->status = 0;
+    dao_ack->dodag_id = dodag->dodag_id;
+
+    _ng_rpl_send(pkt, NULL, destination, &dodag->dodag_id);
+}
+
+void ng_rpl_recv_DAO(ng_rpl_dao_t *dao, ipv6_addr_t *src, uint16_t len)
+{
+    ng_rpl_instance_t *inst = NULL;
+    ng_rpl_dodag_t *dodag = NULL;
+    if ((inst = ng_rpl_instance_get(dao->instance_id)) == NULL) {
+        DEBUG("RPL: DAO with unknown instance id (%d) received\n", dao->instance_id);
+        return;
+    }
+
+    /* check if the D flag is set before accessing the DODAG id */
+    if (!(dao->k_d_flags & (1 << 6))) {
+        DEBUG("RPL: DAO with D flag unset - global instances not supported\n");
+        return;
+    }
+
+    if ((dodag = ng_rpl_dodag_get(inst, &dao->dodag_id)) == NULL) {
+        DEBUG("RPL: DAO with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
+                    &dao->dodag_id, sizeof(addr_str)));
+        return;
+    }
+
+    len -= (sizeof(ng_rpl_dao_t) + sizeof(ng_icmpv6_hdr_t));
+    if(!_parse_options(NG_RPL_ICMPV6_CODE_DAO, dodag, (ng_rpl_opt_t *) (dao + 1), len, src)) {
+        ng_rpl_dodag_remove(dodag);
+        return;
+    }
+
+    /* send a DAO-ACK if K flag is set */
+    if (dao->k_d_flags & (1 << 7)) {
+        ng_rpl_send_DAO_ACK(dodag, src, dao->dao_sequence);
+    }
+
+    ng_rpl_delay_dao(dodag);
+}
+
+void ng_rpl_recv_DAO_ACK(ng_rpl_dao_ack_t *dao_ack)
+{
+    ng_rpl_instance_t *inst = NULL;
+    ng_rpl_dodag_t *dodag = NULL;
+    if ((inst = ng_rpl_instance_get(dao_ack->instance_id)) == NULL) {
+        DEBUG("RPL: DAO-ACK with unknown instance id (%d) received\n", dao_ack->instance_id);
+        return;
+    }
+
+    /* check if the D flag is set before accessing the DODAG id */
+    if (!(dao_ack->d_reserved & (1 << 7))) {
+        DEBUG("RPL: DAO-ACK with D flag unset - global instances not supported\n");
+        return;
+    }
+
+    if ((dodag = ng_rpl_dodag_get(inst, &dao_ack->dodag_id)) == NULL) {
+        DEBUG("RPL: DAO-ACK with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
+                    &dao_ack->dodag_id, sizeof(addr_str)));
+        return;
+    }
+
+    if ((dao_ack->status != 0) && (dao_ack->dao_sequence != dodag->dao_seq)) {
+        DEBUG("RPL: DAO-ACK sequence (%d) does not match expected sequence (%d)\n",
+                dao_ack->dao_sequence, dodag->dao_seq);
+        return;
+    }
+
+    dodag->dao_ack_received = true;
+    ng_rpl_long_delay_dao(dodag);
+}
+
+/**
+ * @}
+ */
diff --git a/sys/net/routing/ng_rpl/ng_rpl_dodag.c b/sys/net/routing/ng_rpl/ng_rpl_dodag.c
new file mode 100644
index 0000000000000000000000000000000000000000..6da4b1703dfbbd687ce381636c0cffe88518e52d
--- /dev/null
+++ b/sys/net/routing/ng_rpl/ng_rpl_dodag.c
@@ -0,0 +1,398 @@
+/**
+ * Copyright (C) 2013, 2014  INRIA.
+ * Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
+ *
+ * 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
+ * @author      Eric Engel <eric.engel@fu-berlin.de>
+ * @author      Cenk Gündoğan <cnkgndgn@gmail.com>
+ */
+
+#include <stdbool.h>
+#include "net/ng_rpl/dodag.h"
+#include "net/ng_rpl/structs.h"
+#include "utlist.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#if ENABLE_DEBUG && defined(MODULE_PV6_ADDR)
+static char addr_str[IPV6_ADDR_MAX_STR_LEN];
+#endif
+
+void rpl_trickle_send_dio(void *args)
+{
+    ng_rpl_dodag_t *dodag = (ng_rpl_dodag_t *) args;
+    ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
+    ng_rpl_send_DIO(dodag, &all_RPL_nodes);
+    DEBUG("trickle callback: Instance (%d) | DODAG: (%s)\n", dodag->instance->id,
+            ipv6_addr_to_str(addr_str,&dodag->dodag_id, sizeof(addr_str)));
+}
+
+bool ng_rpl_instance_add(uint8_t instance_id, ng_rpl_instance_t **inst)
+{
+    *inst = NULL;
+    bool first = true;
+    for (uint8_t i = 0; i < NG_RPL_INSTANCES_NUMOF; ++i) {
+        /* save position to the first unused instance */
+        if ((ng_rpl_instances[i].state == 0) && first) {
+            *inst = &ng_rpl_instances[i];
+            first = false;
+            continue;
+        }
+        else if ((ng_rpl_instances[i].state != 0) && (ng_rpl_instances[i].id == instance_id)) {
+            DEBUG("Instance with id %d exists\n", instance_id);
+            *inst = &ng_rpl_instances[i];
+            return false;
+        }
+    }
+
+    if (*inst != NULL) {
+        (*inst)->id = instance_id;
+        (*inst)->state = 1;
+        (*inst)->max_rank_inc = NG_RPL_DEFAULT_MAX_RANK_INCREASE;
+        (*inst)->min_hop_rank_inc = NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE;
+        (*inst)->dodags = NULL;
+        return true;
+    }
+
+    /* no space available to allocate a new instance */
+    DEBUG("Could not allocate a new RPL instance\n");
+    *inst = NULL;
+    return false;
+}
+
+bool ng_rpl_instance_remove_by_id(uint8_t instance_id)
+{
+    for(uint8_t i = 0; i < NG_RPL_INSTANCES_NUMOF; ++i) {
+        if (ng_rpl_instances[i].id == instance_id) {
+            ng_rpl_dodag_t *elt, *tmp;
+            LL_FOREACH_SAFE(ng_rpl_instances[i].dodags, elt, tmp) {
+                ng_rpl_dodag_remove(elt);
+            }
+            memset(&ng_rpl_instances[i], 0, sizeof(ng_rpl_instance_t));
+            return true;
+        }
+    }
+    return false;
+}
+
+bool ng_rpl_instance_remove(ng_rpl_instance_t *inst)
+{
+    ng_rpl_dodag_t *elt, *tmp;
+    LL_FOREACH_SAFE(inst->dodags, elt, tmp) {
+        ng_rpl_dodag_remove(elt);
+    }
+    memset(inst, 0, sizeof(ng_rpl_instance_t));
+    return true;
+}
+
+ng_rpl_instance_t *ng_rpl_instance_get(uint8_t instance_id)
+{
+    for (uint8_t i = 0; i < NG_RPL_INSTANCES_NUMOF; ++i) {
+        if (ng_rpl_instances[i].id == instance_id) {
+            return &ng_rpl_instances[i];
+        }
+    }
+    return NULL;
+}
+
+bool ng_rpl_dodag_add(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id, ng_rpl_dodag_t **dodag)
+{
+    if ((instance == NULL) || instance->state == 0) {
+        DEBUG("Instance is NULL or unused\n");
+        return false;
+    }
+
+    *dodag = NULL;
+    bool first = true;
+    for (uint8_t i = 0; i < NG_RPL_DODAGS_NUMOF; ++i) {
+        /* save position to the first unused instance */
+        if ((ng_rpl_dodags[i].state == 0) && first) {
+            *dodag = &ng_rpl_dodags[i];
+            first = false;
+            continue;
+        }
+        else if ((ng_rpl_dodags[i].state != 0) &&
+                (ng_rpl_dodags[i].instance->id == instance->id) &&
+                ipv6_addr_equal(&ng_rpl_dodags[i].dodag_id, dodag_id)) {
+            DEBUG("DODAG with id: %s does exist\n", ipv6_addr_to_str(addr_str, dodag_id,
+                        sizeof(addr_str)));
+            *dodag = &ng_rpl_dodags[i];
+            return false;
+        }
+    }
+
+    if (*dodag != NULL) {
+        (*dodag)->instance = instance;
+        LL_APPEND(instance->dodags, *dodag);
+        (*dodag)->state = 1;
+        (*dodag)->dodag_id = *dodag_id;
+        (*dodag)->my_rank = NG_RPL_INFINITE_RANK;
+        (*dodag)->trickle.callback.func = &rpl_trickle_send_dio;
+        (*dodag)->trickle.callback.args = *dodag;
+        (*dodag)->dio_interval_doubl = NG_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS;
+        (*dodag)->dio_min = NG_RPL_DEFAULT_DIO_INTERVAL_MIN;
+        (*dodag)->dio_redun = NG_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT;
+        (*dodag)->default_lifetime = NG_RPL_DEFAULT_LIFETIME;
+        (*dodag)->lifetime_unit = NG_RPL_LIFETIME_UNIT;
+        (*dodag)->node_status = NG_RPL_NORMAL_NODE;
+        (*dodag)->dao_seq = NG_RPL_COUNTER_INIT;
+        (*dodag)->dtsn = 0;
+        (*dodag)->dao_ack_received = false;
+        (*dodag)->dao_counter = 0;
+        (*dodag)->parents = NULL;
+        (*dodag)->cleanup_time = timex_set(NG_RPL_CLEANUP_TIME, 0);
+        return true;
+    }
+
+    /* no space available to allocate a new dodag */
+    DEBUG("Could not allocate a new RPL DODAG\n");
+    *dodag = NULL;
+    return false;
+}
+
+bool ng_rpl_dodag_remove(ng_rpl_dodag_t *dodag)
+{
+    ng_rpl_dodag_remove_all_parents(dodag);
+    ng_rpl_instance_t *inst = dodag->instance;
+    LL_DELETE(inst->dodags, dodag);
+    trickle_stop(&dodag->trickle);
+    vtimer_remove(&dodag->dao_timer);
+    vtimer_remove(&dodag->cleanup_timer);
+    memset(dodag, 0, sizeof(ng_rpl_dodag_t));
+    if (inst->dodags == NULL) {
+        ng_rpl_instance_remove(inst);
+    }
+    return true;
+}
+
+void ng_rpl_dodag_remove_all_parents(ng_rpl_dodag_t *dodag)
+{
+    ng_rpl_parent_t *elt, *tmp;
+    LL_FOREACH_SAFE(dodag->parents, elt, tmp) {
+        ng_rpl_parent_remove(elt);
+    }
+    vtimer_remove(&dodag->cleanup_timer);
+    vtimer_set_msg(&dodag->cleanup_timer, dodag->cleanup_time, ng_rpl_pid,
+            NG_RPL_MSG_TYPE_CLEANUP_HANDLE, dodag);
+}
+
+ng_rpl_dodag_t *ng_rpl_dodag_get(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id)
+{
+    if ((instance == NULL) || (instance->state == 0)) {
+        DEBUG("Instance is NULL or unused\n");
+        return NULL;
+    }
+
+    ng_rpl_dodag_t *dodag = NULL;
+    LL_FOREACH(instance->dodags, dodag) {
+        if (ipv6_addr_equal(&dodag->dodag_id, dodag_id)) {
+            return dodag;
+        }
+    }
+    return NULL;
+}
+
+bool ng_rpl_parent_add_by_addr(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr, ng_rpl_parent_t **parent)
+{
+    if ((dodag == NULL) || (dodag->state == 0)) {
+        DEBUG("DODAG is NULL or unused\n");
+        return false;
+    }
+
+    *parent = NULL;
+    bool first = true;
+    for (uint8_t i = 0; i < NG_RPL_PARENTS_NUMOF; ++i) {
+        /* save position to the first unused instance */
+        if ((ng_rpl_parents[i].state == 0) && first) {
+            *parent = &ng_rpl_parents[i];
+            first = false;
+            continue;
+        }
+        /* return false if parent exists */
+        else if ((ng_rpl_parents[i].state != 0) &&
+                (ng_rpl_parents[i].dodag->instance->id == dodag->instance->id) &&
+                ipv6_addr_equal(&ng_rpl_parents[i].dodag->dodag_id, &dodag->dodag_id) &&
+                ipv6_addr_equal(&ng_rpl_parents[i].addr, addr)) {
+            DEBUG("parent with addr: %s does exist\n", ipv6_addr_to_str(addr_str, addr,
+                        sizeof(addr_str)));
+            *parent = &ng_rpl_parents[i];
+            return false;
+        }
+    }
+
+    if (*parent != NULL) {
+        (*parent)->dodag = dodag;
+        LL_APPEND(dodag->parents, *parent);
+        (*parent)->state = 1;
+        (*parent)->addr = *addr;
+        if ((*parent) == (*parent)->dodag->parents) {
+            ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
+            ipv6_addr_t def = IPV6_ADDR_UNSPECIFIED;
+            kernel_pid_t if_id = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
+            if (if_id == KERNEL_PID_UNDEF) {
+                DEBUG("RPL: no interface found for the parent addres\n");
+                return false;
+            }
+            if (fib_add_entry(if_id, def.u8, sizeof(ipv6_addr_t), AF_INET6, dodag->parents->addr.u8,
+                    sizeof(ipv6_addr_t), AF_INET6,
+                    (dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS) != 0) {
+                DEBUG("RPL: error adding parent to FIB\n");
+                ng_rpl_parent_remove(*parent);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /* no space available to allocate a new parent */
+    DEBUG("Could not allocate a new parent\n");
+    *parent = NULL;
+    return false;
+}
+
+ng_rpl_parent_t *ng_rpl_parent_get(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr)
+{
+    if ((dodag == NULL) || (dodag->state == 0)) {
+        DEBUG("DODAG is NULL or unused\n");
+        return NULL;
+    }
+
+    ng_rpl_parent_t *parent = NULL;
+    LL_FOREACH(dodag->parents, parent) {
+        if (ipv6_addr_equal(&parent->addr, addr)) {
+            return parent;
+        }
+    }
+    return NULL;
+}
+
+bool ng_rpl_parent_remove(ng_rpl_parent_t *parent)
+{
+    if (parent == parent->dodag->parents) {
+        ipv6_addr_t def = { .u64 = {{0}, {0}} };
+        fib_remove_entry(def.u8, sizeof(ipv6_addr_t));
+    }
+    ng_rpl_dodag_t *dodag = parent->dodag;
+    LL_DELETE(dodag->parents, parent);
+    memset(parent, 0, sizeof(ng_rpl_parent_t));
+    return true;
+}
+
+void ng_rpl_local_repair(ng_rpl_dodag_t *dodag)
+{
+    DEBUG("RPL: [INFO] Local Repair started\n");
+
+    dodag->dtsn++;
+
+    if (dodag->parents) {
+        ng_rpl_dodag_remove_all_parents(dodag);
+        ipv6_addr_t def = IPV6_ADDR_UNSPECIFIED;
+        fib_remove_entry(def.u8, sizeof(ipv6_addr_t));
+    }
+
+    if (dodag->my_rank != NG_RPL_INFINITE_RANK) {
+        trickle_reset_timer(&dodag->trickle);
+        vtimer_remove(&dodag->cleanup_timer);
+        vtimer_set_msg(&dodag->cleanup_timer, dodag->cleanup_time, ng_rpl_pid,
+            NG_RPL_MSG_TYPE_CLEANUP_HANDLE, dodag);
+    }
+
+    dodag->my_rank = NG_RPL_INFINITE_RANK;
+}
+
+void ng_rpl_parent_update(ng_rpl_dodag_t *dodag, ng_rpl_parent_t *parent)
+{
+    uint16_t old_rank = dodag->my_rank;
+    timex_t now;
+    vtimer_now(&now);
+    ipv6_addr_t def = IPV6_ADDR_UNSPECIFIED;
+
+    /* update Parent lifetime */
+    if (parent != NULL) {
+        parent->lifetime.seconds = now.seconds + (dodag->default_lifetime * dodag->lifetime_unit);
+        parent->lifetime.microseconds = 0;
+        if (parent == dodag->parents) {
+            ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
+            kernel_pid_t if_id;
+            if ((if_id = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes)) != KERNEL_PID_UNDEF) {
+                fib_add_entry(if_id, def.u8, sizeof(ipv6_addr_t), AF_INET6,
+                        dodag->parents->addr.u8, sizeof(ipv6_addr_t), AF_INET6,
+                        (dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS);
+            }
+        }
+    }
+
+    if (ng_rpl_find_preferred_parent(dodag) == NULL) {
+        ng_rpl_local_repair(dodag);
+    }
+
+    if (dodag->parents && (old_rank != dodag->my_rank)) {
+        trickle_reset_timer(&dodag->trickle);
+    }
+}
+
+int _compare_parents(ng_rpl_parent_t *p1, ng_rpl_parent_t *p2)
+{
+    return p1->dodag->instance->of->which_parent(p1, p2) == p1 ? -1 : 1;
+}
+
+ng_rpl_parent_t *ng_rpl_find_preferred_parent(ng_rpl_dodag_t *dodag)
+{
+    ipv6_addr_t def = IPV6_ADDR_UNSPECIFIED;
+    ng_rpl_parent_t *old_best = dodag->parents;
+
+    LL_SORT(dodag->parents, _compare_parents);
+
+    if (dodag->parents == NULL) {
+        return NULL;
+    }
+    else if (dodag->parents->rank >= dodag->my_rank) {
+        ng_rpl_parent_remove(dodag->parents);
+        return NULL;
+    }
+
+    dodag->my_rank = dodag->instance->of->calc_rank(dodag->parents, 0);
+    ng_rpl_parent_t *elt, *tmp;
+    LL_FOREACH_SAFE(dodag->parents, elt, tmp) {
+        if (dodag->parents->rank < elt->rank) {
+            ng_rpl_parent_remove(elt);
+        }
+    }
+
+    if (old_best != dodag->parents) {
+        if (dodag->instance->mop != NG_RPL_MOP_NO_DOWNWARD_ROUTES) {
+            ng_rpl_send_DAO(dodag, &old_best->addr, 0);
+            ng_rpl_delay_dao(dodag);
+        }
+        trickle_reset_timer(&dodag->trickle);
+
+        fib_remove_entry(def.u8, sizeof(ipv6_addr_t));
+        ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
+
+        kernel_pid_t if_id = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
+
+        if (if_id == KERNEL_PID_UNDEF) {
+            DEBUG("RPL: no interface found for the parent addres\n");
+            return NULL;
+        }
+
+        fib_add_entry(if_id, def.u8, sizeof(ipv6_addr_t), AF_INET6, dodag->parents->addr.u8,
+                sizeof(ipv6_addr_t), AF_INET6,
+                (dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS);
+    }
+
+    return dodag->parents;
+}
+
+/**
+ * @}
+ */
diff --git a/sys/net/routing/ng_rpl/of0.c b/sys/net/routing/ng_rpl/of0.c
new file mode 100644
index 0000000000000000000000000000000000000000..3f8fd393cbbdba421770b19d0b7dfb4d2e73d38f
--- /dev/null
+++ b/sys/net/routing/ng_rpl/of0.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 Oliver Hahm <oliver.hahm@inria.fr>
+ *
+ * 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_rpl
+ * @{
+ * @file
+ * @brief       Objective Function Zero.
+ *
+ * Implementation of Objective Function Zero.
+ *
+ * @author      Eric Engel <eric.engel@fu-berlin.de>
+ * @}
+ */
+
+#include <string.h>
+#include "of0.h"
+#include "net/ng_rpl.h"
+#include "net/ng_rpl/structs.h"
+
+static uint16_t calc_rank(ng_rpl_parent_t *, uint16_t);
+static ng_rpl_parent_t *which_parent(ng_rpl_parent_t *, ng_rpl_parent_t *);
+static ng_rpl_dodag_t *which_dodag(ng_rpl_dodag_t *, ng_rpl_dodag_t *);
+static void reset(ng_rpl_dodag_t *);
+
+static ng_rpl_of_t ng_rpl_of0 = {
+    0x0,
+    calc_rank,
+    which_parent,
+    which_dodag,
+    reset,
+    NULL,
+    NULL,
+    NULL
+};
+
+ng_rpl_of_t *ng_rpl_get_of0(void)
+{
+    return &ng_rpl_of0;
+}
+
+void reset(ng_rpl_dodag_t *dodag)
+{
+    /* Nothing to do in OF0 */
+    (void) dodag;
+}
+
+uint16_t calc_rank(ng_rpl_parent_t *parent, uint16_t base_rank)
+{
+    if (base_rank == 0) {
+        if (parent == NULL) {
+            return NG_RPL_INFINITE_RANK;
+        }
+
+        base_rank = parent->rank;
+    }
+
+    uint16_t add;
+
+    if (parent != NULL) {
+        add = parent->dodag->instance->min_hop_rank_inc;
+    }
+    else {
+        add = NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE;
+    }
+
+    if ((base_rank + add) < base_rank) {
+        return NG_RPL_INFINITE_RANK;
+    }
+
+    return base_rank + add;
+}
+
+/* We simply return the Parent with lower rank */
+ng_rpl_parent_t *which_parent(ng_rpl_parent_t *p1, ng_rpl_parent_t *p2)
+{
+    if (p1->rank <= p2->rank) {
+        return p1;
+    }
+
+    return p2;
+}
+
+/* Not used yet, as the implementation only makes use of one dodag for now. */
+ng_rpl_dodag_t *which_dodag(ng_rpl_dodag_t *d1, ng_rpl_dodag_t *d2)
+{
+    (void) d2;
+    return d1;
+}
diff --git a/sys/net/routing/ng_rpl/of0.h b/sys/net/routing/ng_rpl/of0.h
new file mode 100644
index 0000000000000000000000000000000000000000..373a51bb324131c8f1696e4b1c77ce87731b3223
--- /dev/null
+++ b/sys/net/routing/ng_rpl/of0.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 Oliver Hahm <oliver.hahm@inria.fr>
+ *
+ * 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_rpl
+ * @{
+ * @file
+ * @brief       Objective Function Zero.
+ *
+ * Header-file, which defines all functions for the implementation of Objective Function Zero.
+ *
+ * @author      Eric Engel <eric.engel@fu-berlin.de>
+ */
+
+#ifndef OF0_H
+#define OF0_H
+
+#include "net/ng_rpl/structs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Return the address to the of0 objective function
+ *
+ * @return  Address of the of0 objective function
+ */
+ng_rpl_of_t *ng_rpl_get_of0(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OF0_H */
+/**
+ * @}
+ */
diff --git a/sys/net/routing/ng_rpl/rpl_of_manager.c b/sys/net/routing/ng_rpl/rpl_of_manager.c
new file mode 100644
index 0000000000000000000000000000000000000000..8ea0d1595b0c31568b492583cb97aa1a93c70cd3
--- /dev/null
+++ b/sys/net/routing/ng_rpl/rpl_of_manager.c
@@ -0,0 +1,54 @@
+/*
+* RPL dodag implementation
+*
+* Copyright (C) 2014 Freie Universität Berlin
+*
+* 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 rpl
+ * @{
+ * @file
+ * @brief   RPL Objective functions manager
+ * @author  Fabian Brandt <fabianbr@zedat.fu-berlin.de>
+ * @}
+ */
+
+
+
+#include "net/ng_rpl.h"
+#include "net/ng_rpl/of_manager.h"
+#include "of0.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+/* !!! TODO: port etx/mrhof to the new network stack */
+
+static ng_rpl_of_t *objective_functions[NG_RPL_IMPLEMENTED_OFS_NUMOF];
+
+void ng_rpl_of_manager_init(void)
+{
+    /* insert new objective functions here */
+    objective_functions[0] = ng_rpl_get_of0();
+    /*objective_functions[1] = ng_rpl_get_of_mrhof(); */
+}
+
+/* find implemented OF via objective code point */
+ng_rpl_of_t *ng_rpl_get_of_for_ocp(uint16_t ocp)
+{
+    for (uint16_t i = 0; i < NG_RPL_IMPLEMENTED_OFS_NUMOF; i++) {
+        if (objective_functions[i] == NULL) {
+            /* fallback if something goes wrong */
+            return ng_rpl_get_of0();
+        }
+        else if (ocp == objective_functions[i]->ocp) {
+            return objective_functions[i];
+        }
+    }
+
+    return NULL;
+}