diff --git a/Makefile.dep b/Makefile.dep
index e5239c3a49873ca34dd9ecb0145d844b55b91bee..8504c0addc30018e790dc0b35639e98d70b1d1e9 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -52,6 +52,7 @@ endif
 ifneq (,$(filter gnrc_sixlowpan_default,$(USEMODULE)))
   USEMODULE += gnrc_ipv6_default
   USEMODULE += gnrc_sixlowpan
+  USEMODULE += gnrc_sixlowpan_nd
   USEMODULE += gnrc_sixlowpan_frag
   USEMODULE += gnrc_sixlowpan_iphc
 endif
@@ -77,10 +78,24 @@ ifneq (,$(filter gnrc_sixlowpan_ctx,$(USEMODULE)))
   USEMODULE += vtimer
 endif
 
+ifneq (,$(filter gnrc_sixlowpan_nd,$(USEMODULE)))
+  USEMODULE += gnrc_ndp
+  USEMODULE += gnrc_ndp_internal
+  USEMODULE += gnrc_sixlowpan_ctx
+  USEMODULE += random
+  USEMODULE += vtimer
+endif
+
 ifneq (,$(filter gnrc_ipv6_default,$(USEMODULE)))
   USEMODULE += gnrc_ipv6
   USEMODULE += gnrc_icmpv6
-  USEMODULE += gnrc_ndp_host
+  ifeq (1,$(GNRC_NETIF_NUMOF))
+    ifeq (,$(filter gnrc_sixlowpan_nd,$(USEMODULE)))
+      USEMODULE += gnrc_ndp_host
+    endif
+  else
+    USEMODULE += gnrc_ndp_host
+  endif
 endif
 
 ifneq (,$(filter gnrc_ipv6_router_default,$(USEMODULE)))
diff --git a/sys/include/net/gnrc/ipv6/netif.h b/sys/include/net/gnrc/ipv6/netif.h
index ef5961c06980804d175f21e43e44e1692e3ec959..4027bb6ebe5f6190cfe54e70ef3db489dcf86067 100644
--- a/sys/include/net/gnrc/ipv6/netif.h
+++ b/sys/include/net/gnrc/ipv6/netif.h
@@ -277,7 +277,7 @@ typedef struct {
     uint16_t flags;         /**< flags for 6LoWPAN and Neighbor Discovery */
     uint16_t mtu;           /**< Maximum Transmission Unit (MTU) of the interface */
     uint8_t cur_hl;         /**< current hop limit for the interface */
-#ifdef MODULE_GNRC_NDP_HOST
+#if defined(MODULE_GNRC_NDP_HOST) || defined(MODULE_GNRC_SIXLOWPAN_ND)
     /**
      * @brief   Counter for send router solicitations.
      */
diff --git a/sys/include/net/gnrc/sixlowpan/nd.h b/sys/include/net/gnrc/sixlowpan/nd.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a3bb8b61ff36a83fd4841e3ea1f9b34ecf64efa
--- /dev/null
+++ b/sys/include/net/gnrc/sixlowpan/nd.h
@@ -0,0 +1,190 @@
+/*
+ * 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_gnrc_sixlowpan_nd 6LoWPAN neighbor discovery
+ * @ingroup     net_gnrc_sixlowpan
+ * @brief       Neighbor Discovery Optimization for 6LoWPAN
+ * @see         <a href="https://tools.ietf.org/html/rfc6775">
+ *                  RFC 6775
+ *              </a>
+ * @{
+ *
+ * @file
+ * @brief   General 6LoWPAN ND definitions
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef GNRC_SIXLOWPAN_ND_H_
+#define GNRC_SIXLOWPAN_ND_H_
+
+#include <stdint.h>
+
+#include "kernel_types.h"
+#include "net/gnrc/ipv6/nc.h"
+#include "net/gnrc/ipv6/netif.h"
+#include "net/ipv6/addr.h"
+#include "net/ndp.h"
+#include "net/sixlowpan/nd.h"
+#include "timex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Message type for next multicast router solicitation.
+ */
+#define GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL    (0x0220)
+
+/**
+ * @brief   Message type for next unicast router solicitation.
+ */
+#define GNRC_SIXLOWPAN_ND_MSG_UC_RTR_SOL    (0x0221)
+
+/**
+ * @brief   Message type for removing 6LoWPAN contexts.
+ */
+#define GNRC_SIXLOWPAN_ND_MSG_DELETE_CTX    (0x0222)
+
+#ifndef GNRC_SIXLOWPAN_ND_AR_LTIME
+/**
+ * @brief   Registration lifetime in minutes for the address registration option
+ *
+ * This value should be adapted to the devices power-lifecycle so that it is greater than the
+ * time the device spends sleeping.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6775#section-5.8.1">
+ *          RFC 6775, section 5.8.1
+ *      </a>
+ */
+#define GNRC_SIXLOWPAN_ND_AR_LTIME          (15U)
+#endif
+
+/**
+ * @name    Host constants
+ * @{
+ * @see     <a href="https://tools.ietf.org/html/rfc6775#section-9">
+ *              RFC 6775, section 9
+ *          </a>
+ */
+#define GNRC_SIXLOWPAN_ND_RTR_SOL_INT       (10U)   /**< replacement value (in seconds) for
+                                                     *   @ref GNRC_NDP_MAX_RTR_SOL_INT */
+#define GNRC_SIXLOWPAN_ND_MAX_RTR_SOL_INT   (60U)   /**< retransmission increment for exponential
+                                                     *   backoff of subsequent RS */
+/** @} */
+
+/**
+ * @brief   Initializes 6LoWPAN neighbor discovery for the interface.
+ * @pre     @p iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN
+ * @param[in] iface An IPv6 interface.
+ */
+void gnrc_sixlowpan_nd_init(gnrc_ipv6_netif_t *iface);
+
+/**
+ * @brief   Multicasts a router solicitation over @p iface
+ * @pre     @p iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN
+ * @param[in] iface An IPv6 interface.
+ */
+void gnrc_sixlowpan_nd_mc_rtr_sol(gnrc_ipv6_netif_t *iface);
+
+/**
+ * @brief   Unicasts a router solicitation to the neighbor represented by @p nce
+ * @pre     @p nce->iface is an IPv6 interface and @ref GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN is set
+ *          in its flags.
+ * @param[in] nce   The neighbor to send the router solicitation to.
+ */
+void gnrc_sixlowpan_nd_uc_rtr_sol(gnrc_ipv6_nc_t *nce);
+
+/**
+ * @brief   Get link-layer address and interface for next hop to destination
+ *          IPv6 address.
+ *
+ * @param[out] l2addr           The link-layer for the next hop to @p dst.
+ * @param[out] l2addr_len       Length of @p l2addr.
+ * @param[in] iface             The interface to search the next hop on.
+ *                              May be @ref KERNEL_PID_UNDEF if not specified.
+ * @param[in] dst               An IPv6 address to search the next hop for.
+ *
+ * @return  The PID of the interface, on success.
+ * @return  -EHOSTUNREACH, if @p dst is not reachable.
+ * @return  -ENOBUFS, if @p l2addr_len was smaller than the resulting @p l2addr
+ *          would be long.
+ */
+kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
+                                               kernel_pid_t iface, ipv6_addr_t *dst);
+
+/**
+ * @brief   Reschedules the next router advertisement for a neighboring router.
+ *
+ * @pre nce != NULL && sec_delay != 0U
+ *
+ * @param[in] nce       Neighbor cache entry representing the neighboring router.
+ * @param[in] sec_delay The delay for the next router solicitation in seconds.
+ */
+void gnrc_sixlowpan_nd_rtr_sol_reschedule(gnrc_ipv6_nc_t *nce, uint32_t sec_delay);
+
+/**
+ * @brief   Builds the address registration option.
+ *
+ * @param[in] status    Status for the ARO.
+ * @param[in] ltime     Registration lifetime for the ARO.
+ * @param[in] eui64     The EUI-64 for the ARO
+ * @param[in] next          More options in the packet. NULL, if there are none.
+ *
+ * @return  The pkt snip list of options, on success
+ * @return  NULL, if packet buffer is full
+ */
+gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_ar_build(uint8_t status, uint16_t ltime, eui64_t *eui64,
+                                               gnrc_pktsnip_t *next);
+
+/**
+ * @brief   Handles address registration option.
+ *
+ * @param[in] iface         The interface the ARO was received on.
+ * @param[in] ipv6          The IPv6 header the ARO was received in.
+ * @param[in] icmpv6_type   Message type of the ICMPv6 message that contained.
+ *                          this message.
+ * @param[in] ar_opt        The address registration option.
+ * @param[in] sl2a          The link-layer source address contained in SL2A accompanying this
+ *                          option. May be NULL for icmpv6_type == ICMPV6_NBR_ADV.
+ * @param[in] sl2a_len      Length of @p sl2a. May be 0 if sl2a == NULL.
+ *
+ * @return  Status for the ARO in the replying NA (always 0 if icmpv6_type == ICMPV6_NBR_ADV).
+ */
+uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6,
+                                        uint8_t icmpv6_type, sixlowpan_nd_opt_ar_t *ar_opt,
+                                        uint8_t *sl2a, size_t sl2a_len);
+
+/**
+ * @brief   Handles 6LoWPAN context option.
+ *
+ * @param[in] icmpv6_type   Message type of the ICMPv6 message that contained.
+ *                          this message.
+ * @param[in] ctx_opt       The 6LoWPAN context option.
+ *
+ * @return  true, when 6LoWPAN context option was correct.
+ * @return  false, when it was incorrect.
+ */
+bool gnrc_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, sixlowpan_nd_opt_6ctx_t *ctx_opt);
+
+/**
+ * @brief   Handles registration calls after node-wakeup.
+ *
+ * @see     <a href="https://tools.ietf.org/html/rfc6775#section-5.8.2">
+ *              RFC 6776, section 5.8.2
+ *          </a>
+ */
+void gnrc_sixlowpan_nd_wakeup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GNRC_SIXLOWPAN_ND_H_ */
+/** @} */
diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile
index 69439a9aa96f42887252774505b8f47cf8ce9159..ce91aa59c2e88ae4ad6a487572579665f093f0b2 100644
--- a/sys/net/gnrc/Makefile
+++ b/sys/net/gnrc/Makefile
@@ -79,6 +79,9 @@ endif
 ifneq (,$(filter gnrc_sixlowpan_iphc,$(USEMODULE)))
     DIRS += network_layer/sixlowpan/iphc
 endif
+ifneq (,$(filter gnrc_sixlowpan_nd,$(USEMODULE)))
+    DIRS += network_layer/sixlowpan/nd
+endif
 ifneq (,$(filter gnrc_sixlowpan_netif,$(USEMODULE)))
     DIRS += network_layer/sixlowpan/netif
 endif
diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
index 0f876f2425f52d7187f412e1486d57488c6964af..19edf024ff350be6d98f186ef362027e32b79f31 100644
--- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
+++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
@@ -19,9 +19,11 @@
 #include "byteorder.h"
 #include "cpu_conf.h"
 #include "kernel_types.h"
-#include "net/gnrc/icmpv6.h"
 #include "net/gnrc.h"
+#include "net/gnrc/icmpv6.h"
 #include "net/gnrc/ndp.h"
+#include "net/gnrc/sixlowpan/ctx.h"
+#include "net/gnrc/sixlowpan/nd.h"
 #include "net/protnum.h"
 #include "thread.h"
 #include "utlist.h"
@@ -228,7 +230,21 @@ static void *_event_loop(void *args)
                 gnrc_ndp_host_retrans_rtr_sol((gnrc_ipv6_netif_t *)msg.content.ptr);
                 break;
 #endif
-
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+            case GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL:
+                DEBUG("ipv6: Multicast router solicitation event received\n");
+                gnrc_sixlowpan_nd_mc_rtr_sol((gnrc_ipv6_netif_t *)msg.content.ptr);
+                break;
+            case GNRC_SIXLOWPAN_ND_MSG_UC_RTR_SOL:
+                DEBUG("ipv6: Unicast router solicitation event received\n");
+                gnrc_sixlowpan_nd_uc_rtr_sol((gnrc_ipv6_nc_t *)msg.content.ptr);
+                break;
+            case GNRC_SIXLOWPAN_ND_MSG_DELETE_CTX:
+                DEBUG("ipv6: Delete 6LoWPAN context event received\n");
+                gnrc_sixlowpan_ctx_remove(((((gnrc_sixlowpan_ctx_t *)msg.content.ptr)->flags_id) &
+                                           GNRC_SIXLOWPAN_CTX_FLAGS_CID_MASK));
+                break;
+#endif
             default:
                 break;
         }
@@ -497,16 +513,24 @@ static inline kernel_pid_t _next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len
                                             kernel_pid_t iface, ipv6_addr_t *dst,
                                             gnrc_pktsnip_t *pkt)
 {
-#ifdef MODULE_GNRC_NDP_NODE
-    return gnrc_ndp_node_next_hop_l2addr(l2addr, l2addr_len, iface, dst, pkt);
-#else
+#if defined(MODULE_GNRC_SIXLOWPAN_ND)
+    (void)pkt;
+    iface = gnrc_sixlowpan_nd_next_hop_l2addr(l2addr, l2addr_len, iface, dst);
+    if (iface <= KERNEL_PID_UNDEF) {
+        return iface;
+    }
+#endif
+#if defined(MODULE_GNRC_NDP_NODE)
+    iface = gnrc_ndp_node_next_hop_l2addr(l2addr, l2addr_len, iface, dst, pkt);
+#elif !defined(MODULE_GNRC_SIXLOWPAN_ND)
+    iface = KERNEL_PID_UNDEF;
     (void)l2addr;
     (void)iface;
     (void)dst;
     (void)pkt;
     *l2addr_len = 0;
-    return KERNEL_PID_UNDEF;
 #endif
+    return iface;
 }
 
 static void _send(gnrc_pktsnip_t *pkt, bool prep_hdr)
diff --git a/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c b/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c
index 2967a07962d269a0aa86e92bf0888fe47c897722..cc7d7fb9f5660c22dabd0390dd7357865708ceb7 100644
--- a/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c
+++ b/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c
@@ -29,6 +29,7 @@
 #include "net/gnrc/netapi.h"
 #include "net/gnrc/netif.h"
 #include "net/gnrc/netif/hdr.h"
+#include "net/gnrc/sixlowpan/nd.h"
 #include "net/gnrc/sixlowpan/netif.h"
 
 #include "net/gnrc/ipv6/netif.h"
@@ -90,8 +91,6 @@ static ipv6_addr_t *_add_addr_to_entry(gnrc_ipv6_netif_t *entry, const ipv6_addr
         tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST;
     }
     else {
-        ipv6_addr_t sol_node;
-
         if (!ipv6_addr_is_link_local(addr)) {
             /* add also corresponding link-local address */
             ipv6_addr_t ll_addr;
@@ -117,9 +116,18 @@ static ipv6_addr_t *_add_addr_to_entry(gnrc_ipv6_netif_t *entry, const ipv6_addr
         else {
             tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK;
         }
-
-        ipv6_addr_set_solicited_nodes(&sol_node, addr);
-        _add_addr_to_entry(entry, &sol_node, IPV6_ADDR_BIT_LEN, 0);
+#if defined(MODULE_GNRC_NDP_NODE) || defined(MODULE_GNRC_SIXLOWPAN_ND)
+        /* add solicited-nodes multicast address for new address if interface is not a
+         * 6LoWPAN host interface (see: https://tools.ietf.org/html/rfc6775#section-5.2) */
+        if (!(entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) ||
+            (entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
+            ipv6_addr_t sol_node;
+            ipv6_addr_set_solicited_nodes(&sol_node, addr);
+            _add_addr_to_entry(entry, &sol_node, IPV6_ADDR_BIT_LEN, 0);
+        }
+#endif
+        /* TODO: send NS with ARO on 6LoWPAN interfaces, but not so many and only for the new
+         *       source address. */
     }
 
     return &(tmp_addr->addr);
@@ -804,6 +812,12 @@ void gnrc_ipv6_netif_init_by_dev(void)
 #if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
         gnrc_ipv6_netif_set_router(ipv6_if, true);
 #endif
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+        if (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
+            gnrc_sixlowpan_nd_init(ipv6_if);
+            continue;   /* skip gnrc_ndp_host_init() */
+        }
+#endif
 #ifdef MODULE_GNRC_NDP_HOST
         /* start periodic router solicitations */
         gnrc_ndp_host_init(ipv6_if);
diff --git a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c
index 42683a64698fdaaf8338ddbc3214e237dca3d170..4b246e9caef67a03b3a8efe88aa198fb2e98a774 100644
--- a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c
+++ b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c
@@ -23,7 +23,9 @@
 #include "net/ipv6/ext/rh.h"
 #include "net/gnrc/icmpv6.h"
 #include "net/gnrc/ipv6.h"
+#include "net/gnrc/sixlowpan/nd.h"
 #include "net/gnrc.h"
+#include "net/sixlowpan/nd.h"
 #include "random.h"
 #include "utlist.h"
 #include "thread.h"
@@ -175,9 +177,14 @@ void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
                     /* invalid target link-layer address option */
                     return;
                 }
-
                 break;
-
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+            case NDP_OPT_AR:
+                /* address registration option is always ignored when invalid */
+                gnrc_sixlowpan_nd_opt_ar_handle(iface, ipv6, nbr_adv->type,
+                                                (sixlowpan_nd_opt_ar_t *)opt, NULL, 0);
+                break;
+#endif
             default:
                 /* silently discard all other options */
                 break;
@@ -194,6 +201,13 @@ void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
     }
 
     if (l2tgt_len != -ENOTSUP) {
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+        /* check if entry wasn't removed by ARO, ideally there should not be any TL2A in here */
+        nc_entry = gnrc_ipv6_nc_get(iface, &nbr_adv->tgt);
+        if (nc_entry == NULL) {
+            return;
+        }
+#endif
         if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) {
             if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) {
                 /* link-layer has addresses, but no TLLAO supplied: discard silently
@@ -358,6 +372,9 @@ void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t
     gnrc_ipv6_nc_t *nc_entry = NULL;
     gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);
     uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+    uint32_t next_rtr_sol = 0;
+#endif
     int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
     uint16_t opt_offset = 0;
 
@@ -388,9 +405,12 @@ void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t
     }
     /* set router life timer */
     if (rtr_adv->ltime.u16 != 0) {
+        uint16_t ltime = byteorder_ntohs(rtr_adv->ltime);
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+        next_rtr_sol = ltime;
+#endif
         vtimer_remove(&nc_entry->rtr_timeout);
-        vtimer_set_msg(&nc_entry->rtr_timeout,
-                       timex_set(byteorder_ntohs(rtr_adv->ltime), 0),
+        vtimer_set_msg(&nc_entry->rtr_timeout, timex_set(ltime, 0),
                        thread_getpid(), GNRC_NDP_MSG_RTR_TIMEOUT, nc_entry);
     }
     /* set current hop limit from message if available */
@@ -437,10 +457,51 @@ void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t
                     /* invalid prefix information option */
                     return;
                 }
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+                if (byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime) <
+                    next_rtr_sol) {
+                    next_rtr_sol = byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime);
+                }
+#endif
+                break;
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+            case NDP_OPT_6CTX:
+                if (!gnrc_sixlowpan_nd_opt_6ctx_handle(rtr_adv->type,
+                                                       (sixlowpan_nd_opt_6ctx_t *)opt)) {
+                    /* invalid 6LoWPAN context option */
+                    return;
+                }
+                if (byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime) <
+                    (next_rtr_sol / 60)) {
+                    next_rtr_sol = byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime) * 60;
+                }
+
                 break;
+#endif
         }
     }
+#if ENABLE_DEBUG && defined(MODULE_NG_SIXLOWPAN_ND)
+    if ((if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (l2src_len <= 0)) {
+        DEBUG("ndp: Router advertisement did not contain any source address information\n");
+    }
+#endif
     _stale_nc(iface, &ipv6->src, l2src, l2src_len);
+#ifdef MODULE_NG_SIXLOWPAN_ND
+    if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
+        timex_t t = { 0, GNRC_NDP_RETRANS_TIMER };
+        /* stop multicast router solicitation retransmission timer */
+        vtimer_remove(&if_entry->rtr_sol_timer);
+        /* 3/4 of the time should be "well before" enough the respective timeout
+         * not to run out; see https://tools.ietf.org/html/rfc6775#section-5.4.3 */
+        next_rtr_sol *= 3;
+        next_rtr_sol >>= 2;
+        gnrc_sixlowpan_nd_rtr_sol_reschedule(nc_entry, next_rtr_sol);
+        gnrc_ndp_internal_send_nbr_sol(ifs[i], &nc_entry->ipv6_addr, &nc_entry->ipv6_addr);
+        vtimer_remove(&nc_entry->nbr_sol_timer);
+        vtimer_set_msg(&nc_entry->nbr_sol_timer, t, gnrc_ipv6_pid, GNRC_NDP_MSG_NBR_SOL_RETRANS,
+                       nc_entry);
+    }
+#endif
 }
 
 void gnrc_ndp_retrans_nbr_sol(gnrc_ipv6_nc_t *nc_entry)
diff --git a/sys/net/gnrc/network_layer/ndp/internal/gnrc_ndp_internal.c b/sys/net/gnrc/network_layer/ndp/internal/gnrc_ndp_internal.c
index 870dffcf773d1d42af011f3c82f13ef852e97f99..32016c438757571dbb68e8e5203b95e82f59e225 100644
--- a/sys/net/gnrc/network_layer/ndp/internal/gnrc_ndp_internal.c
+++ b/sys/net/gnrc/network_layer/ndp/internal/gnrc_ndp_internal.c
@@ -14,8 +14,10 @@
 
 #include <stdlib.h>
 
+#include "net/eui64.h"
 #include "net/gnrc/ipv6.h"
 #include "net/gnrc/ndp.h"
+#include "net/gnrc/sixlowpan/nd.h"
 #include "random.h"
 #include "timex.h"
 #include "vtimer.h"
@@ -228,8 +230,17 @@ void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_a
 void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt,
                                     ipv6_addr_t *dst)
 {
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+    gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
+    assert(ipv6_iface != NULL);
+#endif
     gnrc_pktsnip_t *hdr, *pkt = NULL;
     ipv6_addr_t *src = NULL;
+    /* both suppressions, since they are needed in the MODULE_GNRC_SIXLOWPAN_ND branch */
+    /* cppcheck-suppress variableScope */
+    uint8_t l2src[8];
+    /* cppcheck-suppress variableScope */
+    size_t l2src_len = 0;
 
     DEBUG("ndp internal: send neighbor solicitation (iface: %" PRIkernel_pid ", tgt: %s, ",
           iface, ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str)));
@@ -237,8 +248,6 @@ void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt,
 
     /* check if there is a fitting source address to target */
     if ((src = gnrc_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) {
-        uint8_t l2src[8];
-        size_t l2src_len;
         l2src_len = _get_l2src(iface, l2src, sizeof(l2src));
 
         if (l2src_len > 0) {
@@ -253,6 +262,27 @@ void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt,
         }
     }
 
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+    if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
+        if (l2src_len != sizeof(eui64_t)) {
+            l2src_len = (uint16_t)gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, l2src,
+                                                  sizeof(l2src));
+            if (l2src_len != sizeof(eui64_t)) {
+                DEBUG("ndp internal: can't get EUI-64 of the interface\n");
+                gnrc_pktbuf_release(pkt);
+                return;
+            }
+        }
+        hdr = gnrc_sixlowpan_nd_opt_ar_build(0, GNRC_SIXLOWPAN_ND_AR_LTIME, (eui64_t *)l2src, pkt);
+        if (hdr == NULL) {
+            DEBUG("ndp internal: error allocatin Address Registration option.\n");
+            gnrc_pktbuf_release(pkt);
+            return;
+        }
+        pkt = hdr;
+    }
+#endif
+
     hdr = gnrc_ndp_nbr_sol_build(tgt, pkt);
 
     if (hdr == NULL) {
@@ -571,6 +601,13 @@ bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type,
         /* else discard silently */
         return true;
     }
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+    if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
+        (pi_opt->flags & NDP_OPT_PI_FLAGS_L)) {
+        /* ignore: see https://tools.ietf.org/html/rfc6775#section-5.4 */
+        return true;
+    }
+#endif
     prefix = gnrc_ipv6_netif_find_addr(iface, &pi_opt->prefix);
     if (((prefix == NULL) ||
          (gnrc_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) &&
diff --git a/sys/net/gnrc/network_layer/sixlowpan/nd/Makefile b/sys/net/gnrc/network_layer/sixlowpan/nd/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..cbcef5d3cf9e9be85f3afa12195349eba676fcbb
--- /dev/null
+++ b/sys/net/gnrc/network_layer/sixlowpan/nd/Makefile
@@ -0,0 +1,3 @@
+MODULE = gnrc_sixlowpan_nd
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c b/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c
new file mode 100644
index 0000000000000000000000000000000000000000..d87f19cfbd7615f3cdcb94dd88cc71c7ec19b1b0
--- /dev/null
+++ b/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c
@@ -0,0 +1,296 @@
+/*
+ * 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/eui64.h"
+#include "net/gnrc/ipv6.h"
+#include "net/gnrc/ndp.h"
+#include "net/gnrc/ndp/internal.h"
+#include "net/gnrc/netif.h"
+#include "net/gnrc/sixlowpan.h"
+#include "net/gnrc/sixlowpan/ctx.h"
+#include "random.h"
+#include "timex.h"
+
+#include "net/gnrc/sixlowpan/nd.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+static inline void _rtr_sol_reschedule(gnrc_ipv6_netif_t *iface, uint32_t sec_delay)
+{
+    vtimer_remove(&iface->rtr_sol_timer);
+    vtimer_set_msg(&iface->rtr_sol_timer, timex_set(sec_delay, 0), gnrc_ipv6_pid,
+                   GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL, iface);
+}
+
+static inline uint32_t _binary_exp_backoff(uint32_t base_sec, unsigned int exp)
+{
+    return genrand_uint32_range(0, (1 << exp) - 1) * base_sec;
+}
+
+static inline void _revert_iid(uint8_t *iid)
+{
+    iid[0] ^= 0x02;
+}
+
+void gnrc_sixlowpan_nd_init(gnrc_ipv6_netif_t *iface)
+{
+    assert(iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN);
+    mutex_lock(&iface->mutex);
+    iface->rtr_sol_count = 0;   /* first will be send immediately */
+
+    DEBUG("6lo nd: retransmit multicast rtr sol in 10 sec\n");
+    _rtr_sol_reschedule(iface, GNRC_SIXLOWPAN_ND_RTR_SOL_INT);
+    mutex_unlock(&iface->mutex);
+    gnrc_ndp_internal_send_rtr_sol(iface->pid, NULL);
+}
+
+void gnrc_sixlowpan_nd_mc_rtr_sol(gnrc_ipv6_netif_t *iface)
+{
+    uint32_t interval;
+    assert(iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN);
+    mutex_lock(&iface->mutex);
+    if (iface->rtr_sol_count < GNRC_NDP_MAX_RTR_SOL_NUMOF) {
+        DEBUG("6lo nd: retransmit multicast rtr sol in 10 sec\n");
+        iface->rtr_sol_count++;
+        interval = GNRC_SIXLOWPAN_ND_RTR_SOL_INT;
+    }
+    else {
+        unsigned int exp = (unsigned int)(iface->rtr_sol_count - GNRC_NDP_MAX_RTR_SOL_NUMOF);
+        interval = _binary_exp_backoff(1, exp);
+        if (((1U << exp) - 1U) < GNRC_SIXLOWPAN_ND_MAX_RTR_SOL_INT) {
+            /* XXX Not sure if this is the correct interpretation of the truncation described in
+             * https://tools.ietf.org/html/rfc6775#section-5.3. In every source I've read the
+             * truncating value was the exponent, not the target value, so I'm very confused
+             * about this sentencing. Anyway, since 60 sec is a maximum value this should only
+             * affect the energy consumption of the implementation by sending the next RS too fast
+             * but not its interoperability. */
+            iface->rtr_sol_count++;
+        }
+
+        DEBUG("6lo nd: retransmit multicast rtr sol in %" PRIu32 " sec\n", interval);
+        iface->rtr_sol_count--;
+    }
+    _rtr_sol_reschedule(iface, interval);
+    mutex_unlock(&iface->mutex);
+    gnrc_ndp_internal_send_rtr_sol(iface->pid, NULL);
+}
+
+void gnrc_sixlowpan_nd_uc_rtr_sol(gnrc_ipv6_nc_t *nce)
+{
+    assert(gnrc_ipv6_netif_get(nce->iface)->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN);
+    /* neighbor is not a router anymore */
+    if (!(nce->flags & GNRC_IPV6_NC_IS_ROUTER) || ipv6_addr_is_unspecified(&nce->ipv6_addr)) {
+        /* and there are no routers anymore */
+        if (gnrc_ipv6_nc_get_next_router(NULL) == NULL) {
+            /* start search for routers */
+            gnrc_sixlowpan_nd_init(gnrc_ipv6_netif_get(nce->iface));
+        }
+        /* otherwise ignore this call */
+        return;
+    }
+    /* next RS is rescheduled by RA handle function */
+    gnrc_ndp_internal_send_rtr_sol(nce->iface, &nce->ipv6_addr);
+}
+
+kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
+                                               kernel_pid_t iface, ipv6_addr_t *dst)
+{
+    ipv6_addr_t *next_hop = NULL;
+    gnrc_ipv6_nc_t *nc_entry = NULL;
+
+#ifdef MODULE_GNRC_IPV6_EXT_RH
+    ipv6_hdr_t *hdr;
+    gnrc_pktsnip_t *ipv6;
+    LL_SEARCH_SCALAR(pkt, ipv6, type, GNRC_NETTYPE_IPV6);
+    assert(ipv6);
+    hdr = ipv6->data;
+    next_hop = ipv6_ext_rh_next_hop(hdr);
+#endif
+#ifdef MODULE_FIB
+    ipv6_addr_t next_hop_actual;    /* FIB copies address into this variable */
+    /* don't look-up link local addresses in FIB */
+    if ((next_hop == NULL) && !ipv6_addr_is_link_local(dst)) {
+        size_t next_hop_size = sizeof(ipv6_addr_t);
+        uint32_t next_hop_flags = 0;
+        if ((next_hop == NULL) &&
+            (fib_get_next_hop(&gnrc_ipv6_fib_table, &iface, next_hop_actual.u8, &next_hop_size,
+                              &next_hop_flags, (uint8_t *)dst,
+                              sizeof(ipv6_addr_t), 0) >= 0) &&
+            (next_hop_size == sizeof(ipv6_addr_t))) {
+            next_hop = &next_hop_actual;
+        }
+    }
+#endif
+    /* next hop determination according to: https://tools.ietf.org/html/rfc6775#section-5.6 */
+    if ((next_hop == NULL) && ipv6_addr_is_link_local(dst)) {   /* prefix is "on-link" */
+        /* multicast is not handled here anyway so we don't need to check that */
+        next_hop = dst;
+    }
+    else if (next_hop == NULL) {                                /* prefix is off-link */
+        next_hop = gnrc_ndp_internal_default_router();
+    }
+
+    /* address resolution of next_hop: https://tools.ietf.org/html/rfc6775#section-5.7 */
+    if (ipv6_addr_is_link_local(next_hop)) {
+        kernel_pid_t ifs[GNRC_NETIF_NUMOF];
+        size_t ifnum = gnrc_netif_get(ifs);
+        /* we don't need address resolution, the EUI-64 is in next_hop's IID */
+        *l2addr_len = sizeof(eui64_t);
+        memcpy(l2addr, &next_hop->u8[8], sizeof(eui64_t));
+        _revert_iid(l2addr);
+        if (iface == KERNEL_PID_UNDEF) {
+            for (unsigned i = 0; i < ifnum; i++) {
+                gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(ifs[i]);
+                if ((ipv6_if != NULL) && (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) {
+                    /* always take the first 6LoWPAN interface we can find */
+                    return ifs[i];
+                }
+            }
+        }
+        return iface;
+    }
+    else {
+        nc_entry = gnrc_ipv6_nc_get(iface, next_hop);
+        if ((nc_entry == NULL) || (!gnrc_ipv6_nc_is_reachable(nc_entry))) {
+            return KERNEL_PID_UNDEF;
+        }
+        if (nc_entry->l2_addr_len > 0) {
+            memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len);
+        }
+        *l2addr_len = nc_entry->l2_addr_len;
+        return nc_entry->iface;
+    }
+}
+
+void gnrc_sixlowpan_nd_rtr_sol_reschedule(gnrc_ipv6_nc_t *nce, uint32_t sec_delay)
+{
+    assert(nce != NULL);
+    assert(sec_delay != 0U);
+    vtimer_remove(&nce->rtr_sol_timer);
+    vtimer_set_msg(&nce->rtr_sol_timer, timex_set(sec_delay, 0), gnrc_ipv6_pid,
+                   GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL, nce);
+}
+
+gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_ar_build(uint8_t status, uint16_t ltime, eui64_t *eui64,
+                                               gnrc_pktsnip_t *next)
+{
+    gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_AR, sizeof(sixlowpan_nd_opt_ar_t), next);
+
+    if (pkt != NULL) {
+        sixlowpan_nd_opt_ar_t *ar_opt = pkt->data;
+        ar_opt->status = status;
+        ar_opt->resv[0] = ar_opt->resv[1] = ar_opt->resv[2] = 0;
+        ar_opt->ltime = byteorder_htons(ltime);
+        memcpy(&ar_opt->eui64, eui64, sizeof(eui64_t));
+    }
+
+    return pkt;
+}
+
+uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
+                                        sixlowpan_nd_opt_ar_t *ar_opt, uint8_t *sl2a,
+                                        size_t sl2a_len)
+{
+    eui64_t eui64;
+    gnrc_ipv6_netif_t *ipv6_iface;
+    gnrc_ipv6_nc_t *nc_entry;
+    (void)sl2a;
+    (void)sl2a_len;
+    if (ar_opt->len != SIXLOWPAN_ND_OPT_AR_LEN) {
+        /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */
+        return 0;
+    }
+    if (gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, &eui64,
+                        sizeof(eui64)) < 0) {
+        /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */
+        return 0;
+    }
+    ipv6_iface = gnrc_ipv6_netif_get(iface);
+    nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
+    switch (icmpv6_type) {
+        case ICMPV6_NBR_ADV:
+            if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) {
+                DEBUG("6lo nd: interface not a 6LoWPAN interface\n");
+                return 0;
+            }
+            if (eui64.uint64.u64 != ar_opt->eui64.uint64.u64) {
+                /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */
+                return 0;
+            }
+            switch (ar_opt->status) {
+                case SIXLOWPAN_ND_STATUS_SUCCESS:
+                    DEBUG("6lo nd: address registration successful\n");
+                    mutex_lock(&ipv6_iface->mutex);
+                    vtimer_remove(&nc_entry->nbr_sol_timer);
+                    vtimer_set_msg(&nc_entry->nbr_sol_timer, ipv6_iface->retrans_timer,
+                                   gnrc_ipv6_pid, GNRC_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
+                    mutex_unlock(&ipv6_iface->mutex);
+                    break;
+                case SIXLOWPAN_ND_STATUS_DUP:
+                    DEBUG("6lo nd: address registration determined duplicated\n");
+                    /* TODO: handle DAD failed case */
+                    gnrc_ipv6_netif_remove_addr(iface, &ipv6->dst);
+                    /* address should not be used anymore */
+                    break;
+                case SIXLOWPAN_ND_STATUS_NC_FULL:
+                    DEBUG("6lo nd: neighbor cache on router is full\n");
+                    gnrc_ipv6_nc_remove(iface, &ipv6->src);
+                    /* try to find another router */
+                    gnrc_sixlowpan_nd_init(ipv6_iface);
+                    break;
+                default:
+                    DEBUG("6lo nd: unknown status for registration received\n");
+                    break;
+            }
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+bool gnrc_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, sixlowpan_nd_opt_6ctx_t *ctx_opt)
+{
+    if (((ctx_opt->ctx_len < 64) && (ctx_opt->len != 2)) ||
+        ((ctx_opt->ctx_len >= 64) && (ctx_opt->len != 3))) {
+        DEBUG("6lo nd: invalid 6LoWPAN context option received\n");
+        return false;
+    }
+    if (icmpv6_type != ICMPV6_RTR_ADV) {
+        /* discard silently */
+        return true;
+    }
+    /* don't care for result */
+    gnrc_sixlowpan_ctx_update(sixlowpan_nd_opt_6ctx_get_cid(ctx_opt), (ipv6_addr_t *)(ctx_opt + 1),
+                              ctx_opt->ctx_len, byteorder_ntohs(ctx_opt->ltime),
+                              sixlowpan_nd_opt_6ctx_is_comp(ctx_opt));
+    return true;
+}
+
+void gnrc_sixlowpan_nd_wakeup(void)
+{
+    gnrc_ipv6_nc_t *router = gnrc_ipv6_nc_get_next_router(NULL);
+    while (router) {
+        timex_t t = { 0, GNRC_NDP_RETRANS_TIMER };
+        vtimer_remove(&router->rtr_sol_timer);
+        gnrc_sixlowpan_nd_uc_rtr_sol(router);
+        gnrc_ndp_internal_send_nbr_sol(router->iface, &router->ipv6_addr, &router->ipv6_addr);
+        vtimer_remove(&router->nbr_sol_timer);
+        vtimer_set_msg(&router->nbr_sol_timer, t, gnrc_ipv6_pid, GNRC_NDP_MSG_NBR_SOL_RETRANS,
+                       router);
+    }
+}
+
+/** @} */