diff --git a/examples/nanocoap_server/Makefile b/examples/nanocoap_server/Makefile
index bc42fcb766c4cd00eeb62839891a401d99878c13..f4303ec89341ef6f0cbb6a21efb1ee21c893fd42 100644
--- a/examples/nanocoap_server/Makefile
+++ b/examples/nanocoap_server/Makefile
@@ -9,7 +9,7 @@ RIOTBASE ?= $(CURDIR)/../..
 
 BOARD_INSUFFICIENT_MEMORY := chronos msb-430 msb-430h nucleo32-f031 nucleo32-f042 \
                              nucleo32-l031 nucleo-f030 nucleo-l053 stm32f0discovery \
-                             telosb
+                             telosb z1
 
 # Include packages that pull up and auto-init the link layer.
 # NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h
index 43fe775635d6083ffc4e267688b01c8046800454..22f1ff989a6cacb31bd836083d5557ec473a7431 100644
--- a/sys/include/net/gnrc/ipv6/nib.h
+++ b/sys/include/net/gnrc/ipv6/nib.h
@@ -14,6 +14,7 @@
  * @todo    Add detailed description
  * @todo    Implement multihop DAD
  * @todo    Implement classic SLAAC
+ * @todo    Implement MLD
  * @{
  *
  * @file
@@ -86,16 +87,6 @@ extern "C" {
  */
 #define GNRC_IPV6_NIB_SEARCH_RTR            (0x4fc3U)
 
-/**
- * @brief   Reconfirm router event.
- *
- * This message type is for the event the reconfirmation of a router (which
- * implies sending a unicast Router Solicitation). The expected message context
- * is a pointer to a valid on-link entry representing the router that is to be
- * confirmed.
- */
-#define GNRC_IPV6_NIB_RECONFIRM_RTR         (0x4fc4U)
-
 /**
  * @brief   Reply Router Solicitation event.
  *
@@ -153,17 +144,6 @@ extern "C" {
  */
 #define GNRC_IPV6_NIB_ADDR_REG_TIMEOUT      (0x4fc9U)
 
-/**
- * @brief   6LoWPAN context timeout event.
- *
- * This message type is for the event of a 6LoWPAN compression context timeout.
- * The expected message context is the compression context's numerical
- * identifier.
- *
- * @note    Only handled with @ref GNRC_IPV6_NIB_CONF_6LN != 0
- */
-#define GNRC_IPV6_NIB_6LO_CTX_TIMEOUT       (0x4fcaU)
-
 /**
  * @brief   Authoritative border router timeout event.
  *
@@ -201,6 +181,17 @@ extern "C" {
  * @note    Only handled with @ref GNRC_IPV6_NIB_CONF_ARSM != 0
  */
 #define GNRC_IPV6_NIB_RECALC_REACH_TIME     (0x4fceU)
+
+/**
+ * @brief   Reregister address.
+ *
+ * This message type is for the event of reregistering an IPv6 address to the
+ * upstream router. The expected message context is an IPv6 address assigned to
+ * one of the nodes interfaces.
+ *
+ * @note    Only handled with @ref GNRC_IPV6_NIB_CONF_6LN != 0
+ */
+#define GNRC_IPV6_NIB_REREG_ADDRESS         (0x4fcfU)
 /** @} */
 
 /**
diff --git a/sys/include/net/gnrc/ipv6/nib/conf.h b/sys/include/net/gnrc/ipv6/nib/conf.h
index 90992df16583363a3503bc4c9aadf533ee6e06ca..999350eaad28884cf5624a21d70c50a02ed9bbe5 100644
--- a/sys/include/net/gnrc/ipv6/nib/conf.h
+++ b/sys/include/net/gnrc/ipv6/nib/conf.h
@@ -29,6 +29,9 @@ extern "C" {
 #ifndef GNRC_IPV6_NIB_CONF_6LBR
 #define GNRC_IPV6_NIB_CONF_6LBR         (1)
 #endif
+#ifndef GNRC_IPV6_NIB_NUMOF
+#define GNRC_IPV6_NIB_NUMOF             (16)
+#endif
 #endif
 
 #ifdef MODULE_GNRC_IPV6_NIB_6LR
@@ -174,8 +177,12 @@ extern "C" {
  * @see [RFC 6775, section 8.1](https://tools.ietf.org/html/rfc6775#section-8.1)
  */
 #ifndef GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+#if GNRC_IPV6_NIB_CONF_6LN
+#define GNRC_IPV6_NIB_CONF_MULTIHOP_P6C (1)
+#else
 #define GNRC_IPV6_NIB_CONF_MULTIHOP_P6C (0)
 #endif
+#endif
 
 /**
  * @brief   Multihop duplicate address detection
diff --git a/sys/include/net/gnrc/netif2/ipv6.h b/sys/include/net/gnrc/netif2/ipv6.h
index 4357ddcf5bd88995442de76e0567dd264312ad47..56e5dfe26ecf900b1000141f662a5694c4d5754f 100644
--- a/sys/include/net/gnrc/netif2/ipv6.h
+++ b/sys/include/net/gnrc/netif2/ipv6.h
@@ -148,6 +148,18 @@ typedef struct {
      *          and @ref net_gnrc_ipv6_nib "NIB"
      */
     evtimer_msg_event_t search_rtr;
+#if GNRC_IPV6_NIB_CONF_6LN || DOXYGEN
+    /**
+     * @brief   Timers for address re-registration
+     *
+     * @note    Only available with module @ref net_gnrc_ipv6 "gnrc_ipv6" and
+     *          @ref net_gnrc_ipv6_nib "NIB" and if
+     *          @ref GNRC_IPV6_NIB_CONF_6LN != 0
+     * @note    Might also be usable in the later default SLAAC implementation
+     *          for NS retransmission timers.
+     */
+    evtimer_msg_event_t addrs_timers[GNRC_NETIF2_IPV6_ADDRS_NUMOF];
+#endif
 
 #if GNRC_IPV6_NIB_CONF_ROUTER || DOXYGEN
     /**
@@ -210,16 +222,13 @@ typedef struct {
      */
     uint8_t ra_sent;
 #endif
-#if GNRC_IPV6_NIB_CONF_6LN || DOXYGEN
     /**
      * @brief   number of unsolicited router solicitations scheduled
      *
      * @note    Only available with module @ref net_gnrc_ipv6 "gnrc_ipv6" and
-     *          @ref net_gnrc_ipv6_nib "NIB" and if
-     *          @ref GNRC_IPV6_NIB_CONF_6LN != 0
+     *          @ref net_gnrc_ipv6_nib "NIB"
      */
     uint8_t rs_sent;
-#endif
     /**
      * @brief   number of unsolicited neighbor advertisements scheduled
      *
diff --git a/sys/include/net/gnrc/sixlowpan/nd.h b/sys/include/net/gnrc/sixlowpan/nd.h
index 61bc05255699c633f54a846b217a77239f4f5667..7a97f326cce15f0c30b141e708368d05d3c9358d 100644
--- a/sys/include/net/gnrc/sixlowpan/nd.h
+++ b/sys/include/net/gnrc/sixlowpan/nd.h
@@ -26,45 +26,15 @@
 #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"
 
-#include "net/gnrc/sixlowpan/nd/border_router.h"
-#include "net/gnrc/sixlowpan/nd/router.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)
-
-/**
- * @brief   Message type for authoritative border router timeout
- */
-#define GNRC_SIXLOWPAN_ND_MSG_ABR_TIMEOUT   (0x0223)
-
-/**
- * @brief   Message type for address registration timeout
- */
-#define GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT    (0x0224)
-
 #ifndef GNRC_SIXLOWPAN_ND_AR_LTIME
 /**
  * @brief   Registration lifetime in minutes for the address registration option
@@ -79,101 +49,6 @@ extern "C" {
 #define GNRC_SIXLOWPAN_ND_AR_LTIME          (15U)
 #endif
 
-/**
- * @name    Border router constants
- * @{
- * @see     <a href="https://tools.ietf.org/html/rfc6775#section-9">
- *              RFC 6775, section 9
- *          </a>
- */
-#define GNRC_SIXLOWPAN_ND_RTR_MIN_CTX_DELAY (300U)  /**< minimum delay between context change and
-                                                     *   stop of C=0 dissimination in seconds */
-/** @} */
-/**
- * @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 */
-/** @} */
-/**
- * @name    Router constants
- * @{
- * @see     <a href="https://tools.ietf.org/html/rfc6775#section-9">
- *              RFC 6775, section 9
- *          </a>
- */
-#define GNRC_SIXLOWPAN_ND_MIN_RTR_ADV_DELAY (10U)   /**< replacement value (in seconds) for
-                                                     *   @ref GNRC_NDP_MIN_RTR_ADV_DELAY */
-/**
- * @brief   replacement value (in microseconds) for @ref GNRC_NDP_MAX_RTR_ADV_DELAY
- */
-#define GNRC_SIXLOWPAN_ND_MAX_RTR_ADV_DELAY (2U * US_PER_SEC)
-/**
- * @brief   Lifetime of a tentative address entry in seconds
- */
-#define GNRC_SIXLOWPAN_ND_TENTATIVE_NCE_LIFETIME    (20U)
-/**
- * @brief   6LoWPAN Multihop Hoplimit
- */
-#define GNRC_SIXLOWPAN_ND_MULTIHOP_HOPLIMIT (64U)
-/** @} */
-
-/**
- * @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.
  *
@@ -188,62 +63,6 @@ void gnrc_sixlowpan_nd_rtr_sol_reschedule(gnrc_ipv6_nc_t *nce, uint32_t sec_dela
 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] addr          The IPv6 address to register.
- * @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, ipv6_addr_t *addr,
-                                        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 MODULE_GNRC_SIXLOWPAN_ND_ROUTER
-/**
- * @brief   Handles authoritative border router option.
- *
- * @param[in] iface         Interface the source link-layer option was received
- *                          on.
- * @param[in] rtr_adv       The router advertisement containing the ABRO.
- * @param[in] icmpv6_size   The size of the @p rtr_adv.
- * @param[in] abr_opt       The ABRO.
- *
- * @note    Erroneous ABROs are always ignored silently.
- */
-void gnrc_sixlowpan_nd_opt_abr_handle(kernel_pid_t iface, ndp_rtr_adv_t *rtr_adv, int icmpv6_size,
-                                      sixlowpan_nd_opt_abr_t *abr_opt);
-
 /**
  * @brief   Builds the 6LoWPAN context option.
  *
@@ -272,11 +91,6 @@ gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_6ctx_build(uint8_t prefix_len, uint8_t fla
  */
 gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_abr_build(uint32_t version, uint16_t ltime,
                                                 ipv6_addr_t *braddr, gnrc_pktsnip_t *next);
-#else
-#define gnrc_sixlowpan_nd_opt_abr_handle(iface, rtr_adv, icmpv6_size, abr_opt)
-#define gnrc_sixlowpan_nd_opt_6ctx_build(prefix_len, flags, ltime, prefix, next)        (NULL)
-#define gnrc_sixlowpan_nd_opt_abr_build(version, ltime, braddr, next)                   (NULL)
-#endif
 
 #ifdef __cplusplus
 }
diff --git a/sys/include/net/ndp.h b/sys/include/net/ndp.h
index df8a25a386f7a0b55a09750c0da3ea529222e704..11830388db9199ff9df375b27352bbb7c97750a3 100644
--- a/sys/include/net/ndp.h
+++ b/sys/include/net/ndp.h
@@ -123,6 +123,7 @@ extern "C" {
 /**
  * @{
  * @name    Router constants
+ * @see     [RFC 4861, section 6.2.1](https://tools.ietf.org/html/rfc4861#section-6.2.1)
  * @see     [RFC 4861, section 10](https://tools.ietf.org/html/rfc4861#section-10)
  */
 #define NDP_MAX_INIT_RA_INTERVAL        (16000U)   /**< MAX_INITIAL_RTR_ADVERT_INTERVAL (in ms) */
@@ -130,6 +131,9 @@ extern "C" {
 #define NDP_MAX_FIN_RA_NUMOF            (3U)       /**< MAX_FINAL_RTR_ADVERTISEMENT */
 #define NDP_MIN_MS_DELAY_BETWEEN_RAS    (3000U)    /**< MIN_DELAY_BETWEEN_RAS (in ms) */
 #define NDP_MAX_RA_DELAY                (500U)     /**< MAX_RA_DELAY_TIME (in ms) */
+#define NDP_MAX_RA_INTERVAL_MS          (600000U)  /**< default of MaxRtrAdvInterval (in ms) */
+#define NDP_MIN_RA_INTERVAL_MS          (198000U)  /**< default of MinRtrAdvInterval (in ms) */
+#define NDP_RTR_LTIME_SEC               (1800U)    /**< default of AdvDefaultLifetime (in sec) */
 /** @} */
 
 /**
@@ -149,6 +153,13 @@ extern "C" {
  */
 #define NDP_MAX_MC_SOL_NUMOF        (3U)        /**< MAX_MULTICAST_SOLICIT */
 #define NDP_MAX_UC_SOL_NUMOF        (3U)        /**< MAX_UNICAST_SOLICIT */
+
+/**
+ * @brief   Default for DupAddrDetectTransmits
+ * @see     [RFC 4862, section 5.1](https://tools.ietf.org/html/rfc4862#section-5.1)
+ * @note    May not be greater than 7.
+ */
+#define NDP_DAD_TRANSMIT_NUMOF      (1U)
 #define NDP_MAX_ANYCAST_MS_DELAY    (1000U)     /**< MAX_ANYCAST_DELAY_TIME (in ms) */
 #define NDP_MAX_NA_NUMOF            (3U)        /**< MAX_NEIGHBOR_ADVERTISEMENT */
 #define NDP_REACH_MS                (30000U)    /**< REACHABLE_TIME (in ms) */
diff --git a/sys/include/net/sixlowpan/nd.h b/sys/include/net/sixlowpan/nd.h
index c7e6eda749662aef78480dc93835bd0f0a20d89b..2c631e42eb46fcf1d3520c4285f0ea20c2d49b6b 100644
--- a/sys/include/net/sixlowpan/nd.h
+++ b/sys/include/net/sixlowpan/nd.h
@@ -37,6 +37,8 @@ extern "C" {
  * @name    Lengths for fixed length options
  * @note    Options don't use bytes as their length unit, but 8 bytes.
  */
+#define SIXLOWPAN_ND_OPT_6CTX_LEN_MIN           (2U)
+#define SIXLOWPAN_ND_OPT_6CTX_LEN_MAX           (3U)
 #define SIXLOWPAN_ND_OPT_AR_LEN                 (2U)
 #define SIXLOWPAN_ND_OPT_ABR_LEN                (3U)
 /**
@@ -110,6 +112,12 @@ extern "C" {
  * @see     [RFC 6775, section 9](https://tools.ietf.org/html/rfc6775#section-9)
  * @{
  */
+/**
+ * @brief   Number of address registration retries
+ *
+ * @note    May not be greater than 7.
+ */
+#define SIXLOWPAN_ND_REG_TRANSMIT_NUMOF         (3U)
 /**
  * @brief   RTR_SOLICITATION_INTERVAL (in msec)
  */
diff --git a/sys/net/gnrc/application_layer/uhcpc/gnrc_uhcpc.c b/sys/net/gnrc/application_layer/uhcpc/gnrc_uhcpc.c
index 05984803a060f4fc75ba25f156699af4cd6e37f5..cdcc01eea0145f50ebb7e497c4a9fd257c59386e 100644
--- a/sys/net/gnrc/application_layer/uhcpc/gnrc_uhcpc.c
+++ b/sys/net/gnrc/application_layer/uhcpc/gnrc_uhcpc.c
@@ -6,12 +6,10 @@
  * directory for more details.
  */
 
-#include "net/fib.h"
+#include "net/gnrc/ipv6/nib.h"
 #include "net/gnrc/ipv6.h"
-#include "net/gnrc/ipv6/nc.h"
-#include "net/gnrc/ipv6/netif.h"
 #include "net/gnrc/netapi.h"
-#include "net/gnrc/netif.h"
+#include "net/gnrc/netif2.h"
 #include "net/ipv6/addr.h"
 #include "net/netdev.h"
 #include "net/netopt.h"
@@ -31,19 +29,13 @@ static void set_interface_roles(void)
         kernel_pid_t dev = netif->pid;
         int is_wired = gnrc_netapi_get(dev, NETOPT_IS_WIRED, 0, NULL, 0);
         if ((!gnrc_border_interface) && (is_wired == 1)) {
-            ipv6_addr_t addr;
+            ipv6_addr_t addr, defroute = IPV6_ADDR_UNSPECIFIED;
             gnrc_border_interface = dev;
 
             ipv6_addr_from_str(&addr, "fe80::2");
             gnrc_netapi_set(dev, NETOPT_IPV6_ADDR, 64 << 8, &addr, sizeof(addr));
-#ifdef MODULE_FIB
-            ipv6_addr_t defroute = IPV6_ADDR_UNSPECIFIED;
-
             ipv6_addr_from_str(&addr, "fe80::1");
-            fib_add_entry(&gnrc_ipv6_fib_table, dev, defroute.u8, 16,
-                    0x00, addr.u8, 16, 0,
-                    (uint32_t)FIB_LIFETIME_NO_EXPIRE);
-#endif
+            gnrc_ipv6_nib_ft_add(&defroute, IPV6_ADDR_BIT_LEN, &addr, dev);
         }
         else if ((!gnrc_wireless_interface) && (is_wired != 1)) {
             gnrc_wireless_interface = dev;
@@ -92,6 +84,10 @@ void uhcp_handle_prefix(uint8_t *prefix, uint8_t prefix_len, uint16_t lifetime,
 
     gnrc_netapi_set(gnrc_wireless_interface, NETOPT_IPV6_ADDR, (64 << 8),
                     prefix, sizeof(ipv6_addr_t));
+#if defined(MODULE_GNRC_IPV6_NIB) && GNRC_IPV6_NIB_CONF_6LBR && \
+    GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+    gnrc_ipv6_nib_abr_add((ipv6_addr_t *)prefix);
+#endif
     gnrc_netapi_set(gnrc_wireless_interface, NETOPT_IPV6_ADDR_REMOVE, 0,
                     &_prefix, sizeof(_prefix));
     print_str("gnrc_uhcpc: uhcp_handle_prefix(): configured new prefix ");
@@ -101,6 +97,10 @@ void uhcp_handle_prefix(uint8_t *prefix, uint8_t prefix_len, uint16_t lifetime,
     if (!ipv6_addr_is_unspecified(&_prefix)) {
         gnrc_netapi_set(gnrc_wireless_interface, NETOPT_IPV6_ADDR_REMOVE, 0,
                         &_prefix, sizeof(_prefix));
+#if defined(MODULE_GNRC_IPV6_NIB) && GNRC_IPV6_NIB_CONF_6LBR && \
+    GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+        gnrc_ipv6_nib_abr_del(&_prefix);
+#endif
         print_str("gnrc_uhcpc: uhcp_handle_prefix(): removed old prefix ");
         ipv6_addr_print(&_prefix);
         puts("/64");
diff --git a/sys/net/gnrc/netif2/gnrc_netif2.c b/sys/net/gnrc/netif2/gnrc_netif2.c
index 2d643bea4f1fb1d3d3e1630648e8e129cb85821d..804d7aa69356abd9b67f6c55490d5a664eaf30dd 100644
--- a/sys/net/gnrc/netif2/gnrc_netif2.c
+++ b/sys/net/gnrc/netif2/gnrc_netif2.c
@@ -550,10 +550,30 @@ int gnrc_netif2_ipv6_addr_add(gnrc_netif2_t *netif, const ipv6_addr_t *addr,
     }
     netif->ipv6.addrs_flags[idx] = flags;
     memcpy(&netif->ipv6.addrs[idx], addr, sizeof(netif->ipv6.addrs[idx]));
-    /* TODO:
-     *  - update prefix list, if flags == VALID
-     *  - with SLAAC, send out NS otherwise for DAD probing */
+#ifdef MODULE_GNRC_IPV6_NIB
+    if (_get_state(netif, idx) == GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_VALID) {
+        void *state = NULL;
+        gnrc_ipv6_nib_pl_t ple;
+        bool in_pl = false;
+
+        while (gnrc_ipv6_nib_pl_iter(netif->pid, &state, &ple)) {
+            if (ipv6_addr_match_prefix(&ple.pfx, addr) >= pfx_len) {
+                in_pl = true;
+            }
+        }
+        if (!in_pl) {
+            gnrc_ipv6_nib_pl_set(netif->pid, addr, pfx_len,
+                                 UINT32_MAX, UINT32_MAX);
+        }
+    }
+#if GNRC_IPV6_NIB_CONF_SLAAC
+    else {
+        /* TODO: send out NS to solicited nodes for DAD probing */
+    }
+#endif
+#else
     (void)pfx_len;
+#endif
     gnrc_netif2_release(netif);
     return idx;
 }
@@ -569,8 +589,6 @@ void gnrc_netif2_ipv6_addr_remove(gnrc_netif2_t *netif,
     if (idx >= 0) {
         netif->ipv6.addrs_flags[idx] = 0;
         ipv6_addr_set_unspecified(&netif->ipv6.addrs[idx]);
-        /* TODO:
-         *  - update prefix list, if necessary */
     }
     gnrc_netif2_release(netif);
 }
diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
index e70da32d3587ee99a0815a98cdfae90fac5a2807..7fd41fb0859fc928c056a948d04ff464da6d5d77 100644
--- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
+++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
@@ -290,17 +290,16 @@ static void *_event_loop(void *args)
             case GNRC_IPV6_NIB_SND_MC_NS:
             case GNRC_IPV6_NIB_SND_NA:
             case GNRC_IPV6_NIB_SEARCH_RTR:
-            case GNRC_IPV6_NIB_RECONFIRM_RTR:
             case GNRC_IPV6_NIB_REPLY_RS:
             case GNRC_IPV6_NIB_SND_MC_RA:
             case GNRC_IPV6_NIB_REACH_TIMEOUT:
             case GNRC_IPV6_NIB_DELAY_TIMEOUT:
             case GNRC_IPV6_NIB_ADDR_REG_TIMEOUT:
-            case GNRC_IPV6_NIB_6LO_CTX_TIMEOUT:
             case GNRC_IPV6_NIB_ABR_TIMEOUT:
             case GNRC_IPV6_NIB_PFX_TIMEOUT:
             case GNRC_IPV6_NIB_RTR_TIMEOUT:
             case GNRC_IPV6_NIB_RECALC_REACH_TIME:
+            case GNRC_IPV6_NIB_REREG_ADDRESS:
                 DEBUG("ipv6: NIB timer event received\n");
                 gnrc_ipv6_nib_handle_timer_event(msg.content.ptr, msg.type);
                 break;
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.c
index e4beb0e09f023be4ce6b317a798153aab63ac195..982635b9b86ad88ca88c6afe274edd96d7171d37 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.c
@@ -15,6 +15,7 @@
 
 #include "net/gnrc/netif2/internal.h"
 #include "net/gnrc/ipv6/nib.h"
+#include "net/gnrc/ndp2.h"
 
 #include "_nib-6ln.h"
 #include "_nib-6lr.h"
@@ -27,11 +28,13 @@
 static char addr_str[IPV6_ADDR_MAX_STR_LEN];
 #endif
 
+extern void _handle_search_rtr(gnrc_netif2_t *netif);
+
 static inline bool _is_iface_eui64(gnrc_netif2_t *netif, const eui64_t *eui64)
 {
     /* TODO: adapt for short addresses */
     return (netif->l2addr_len == sizeof(eui64_t)) &&
-            (memcmp(&netif->l2addr, eui64, netif->l2addr_len) == 0);
+           (memcmp(&netif->l2addr, eui64, netif->l2addr_len) == 0);
 }
 
 static inline uint8_t _reverse_iid(const ipv6_addr_t *dst,
@@ -47,7 +50,7 @@ static inline uint8_t _reverse_iid(const ipv6_addr_t *dst,
             l2addr[4] = dst->u8[14];
             l2addr[5] = dst->u8[15];
             return ETHERNET_ADDR_LEN;
-#endif
+#endif  /* MODULE_NETDEV_ETH */
 #ifdef MODULE_NETDEV_IEEE802154
         case NETDEV_TYPE_IEEE802154:
             /* assume address was based on EUI-64
@@ -55,12 +58,12 @@ static inline uint8_t _reverse_iid(const ipv6_addr_t *dst,
             memcpy(l2addr, &dst->u64[1], sizeof(dst->u64[1]));
             l2addr[0] ^= 0x02;
             return sizeof(dst->u64[1]);
-#endif
+#endif  /* MODULE_NETDEV_IEEE802154 */
 #ifdef MODULE_CC110X
         case NETDEV_TYPE_CC110X:
             l2addr[0] = dst->u8[15];
             return sizeof(uint8_t);
-#endif
+#endif  /* MODULE_CC110X */
         default:
             (void)dst;
             (void)l2addr;
@@ -104,9 +107,6 @@ uint8_t _handle_aro(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                     const sixlowpan_nd_opt_ar_t *aro, const ndp_opt_t *sl2ao,
                     _nib_onl_entry_t *nce)
 {
-#if !GNRC_IPV6_NIB_CONF_6LR
-    (void)sl2ao;
-#endif
     assert(netif != NULL);
     if (gnrc_netif2_is_6ln(netif) && (aro->len == SIXLOWPAN_ND_OPT_AR_LEN)) {
         DEBUG("nib: valid ARO received\n");
@@ -125,23 +125,27 @@ uint8_t _handle_aro(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
             switch (aro->status) {
                 case SIXLOWPAN_ND_STATUS_SUCCESS: {
                     uint16_t ltime = byteorder_ntohs(aro->ltime);
-                    uint32_t next_ns;
+                    uint32_t rereg_time;
+                    int idx = gnrc_netif2_ipv6_addr_idx(netif, &ipv6->dst);
                     /* if ltime 1min, reschedule NS in 30sec, otherwise 1min
                      * before timeout */
-                    next_ns = (ltime == 1U) ? (30 * MS_PER_SEC) :
-                                (byteorder_ntohs(aro->ltime) - 1U) *
-                                SEC_PER_MIN * MS_PER_SEC;
-                    DEBUG("nib: Address registration successful. "
-                               "Scheduling re-registration in %" PRIu32 "ms\n",
-                          next_ns);
-                    assert(nce != NULL);
-                    _evtimer_add(nce, GNRC_IPV6_NIB_SND_UC_NS, &nce->nud_timeout,
-                                 next_ns);
+                    rereg_time = (ltime == 1U) ? (30 * MS_PER_SEC) :
+                                 (ltime - 1U) * SEC_PER_MIN * MS_PER_SEC;
+                    DEBUG("nib: Address registration of %s successful. "
+                          "Scheduling re-registration in %" PRIu32 "ms\n",
+                          ipv6_addr_to_str(addr_str, &ipv6->dst,
+                                           sizeof(addr_str)), rereg_time);
+                    netif->ipv6.addrs_flags[idx] &= ~GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_MASK;
+                    netif->ipv6.addrs_flags[idx] |= GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_VALID;
+                    _evtimer_add(&netif->ipv6.addrs[idx],
+                                 GNRC_IPV6_NIB_REREG_ADDRESS,
+                                 &netif->ipv6.addrs_timers[idx],
+                                 rereg_time);
                     break;
                 }
                 case SIXLOWPAN_ND_STATUS_DUP:
                     DEBUG("nib: Address registration reports duplicate. "
-                               "Removing address %s%%%u\n",
+                          "Removing address %s%%%u\n",
                           ipv6_addr_to_str(addr_str,
                                            &ipv6->dst,
                                            sizeof(addr_str)), netif->pid);
@@ -150,17 +154,18 @@ uint8_t _handle_aro(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                     break;
                 case SIXLOWPAN_ND_STATUS_NC_FULL: {
                         DEBUG("nib: Router's neighbor cache is full. "
-                                   "Searching new router for DAD\n");
+                              "Searching new router for DAD\n");
                         _nib_dr_entry_t *dr = _nib_drl_get(&ipv6->src, netif->pid);
                         assert(dr != NULL); /* otherwise we wouldn't be here */
                         _nib_drl_remove(dr);
                         if (_nib_drl_iter(NULL) == NULL) { /* no DRL left */
                             netif->ipv6.rs_sent = 0;
-                            /* TODO: search new router */
+                            /* search (hopefully) new router */
+                            _handle_search_rtr(netif);
                         }
                         else {
                             assert(dr->next_hop != NULL);
-                            _snd_uc_ns(dr->next_hop, true);
+                            _handle_rereg_address(&ipv6->dst);
                         }
                     }
                     break;
@@ -170,17 +175,153 @@ uint8_t _handle_aro(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
 #if GNRC_IPV6_NIB_CONF_6LR
         else if (gnrc_netif2_is_6lr(netif) &&
                  (icmpv6->type == ICMPV6_NBR_SOL)) {
-            return _reg_addr_upstream(netif, ipv6, icmpv6, aro, sl2ao);
+            assert(nce != NULL);
+            return _reg_addr_upstream(netif, ipv6, icmpv6, aro, sl2ao, nce);
         }
-#endif
+#else   /* GNRC_IPV6_NIB_CONF_6LR */
+        (void)sl2ao;
+        (void)nce;
+#endif  /* GNRC_IPV6_NIB_CONF_6LR */
     }
 #if ENABLE_DEBUG
     else if (aro->len != SIXLOWPAN_ND_OPT_AR_LEN) {
         DEBUG("nib: ARO of unexpected length %u, ignoring ARO\n", aro->len);
     }
-#endif
+#endif  /* ENABLE_DEBUG */
     return _ADDR_REG_STATUS_IGNORE;
 }
+
+static inline bool _is_tentative(const gnrc_netif2_t *netif, int idx)
+{
+    return (gnrc_netif2_ipv6_addr_get_state(netif, idx) &
+            GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_TENTATIVE);
+}
+
+static inline bool _is_valid(const gnrc_netif2_t *netif, int idx)
+{
+    return (gnrc_netif2_ipv6_addr_get_state(netif, idx) ==
+            GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_VALID);
+}
+
+void _handle_rereg_address(const ipv6_addr_t *addr)
+{
+    gnrc_netif2_t *netif = gnrc_netif2_get_by_ipv6_addr(addr);
+    _nib_dr_entry_t *router = _nib_drl_get_dr();
+
+    if ((netif != NULL) && (router != NULL)) {
+        assert((unsigned)netif->pid == _nib_onl_get_if(router->next_hop));
+        DEBUG("nib: Re-registering %s",
+              ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)));
+        DEBUG(" with upstream router %s\n",
+              ipv6_addr_to_str(addr_str, &router->next_hop->ipv6,
+                               sizeof(addr_str)));
+        _snd_ns(&router->next_hop->ipv6, netif, addr, &router->next_hop->ipv6);
+    }
+    else {
+        DEBUG("nib: Couldn't re-register %s, no current router found or address "
+              "wasn't assigned to any interface anymore.\n",
+              ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)));
+    }
+    if (netif != NULL) {
+        int idx = gnrc_netif2_ipv6_addr_idx(netif, addr);
+
+        if (_is_valid(netif, idx) || (_is_tentative(netif, idx) &&
+             (gnrc_netif2_ipv6_addr_dad_trans(netif, idx) <
+              SIXLOWPAN_ND_REG_TRANSMIT_NUMOF))) {
+            uint32_t retrans_time;
+
+            if (_is_valid(netif, idx)) {
+                retrans_time = SIXLOWPAN_ND_MAX_RS_SEC_INTERVAL;
+            }
+            else {
+                retrans_time = netif->ipv6.retrans_time;
+                /* increment encoded retransmission count */
+                netif->ipv6.addrs_flags[idx]++;
+            }
+            _evtimer_add(&netif->ipv6.addrs[idx], GNRC_IPV6_NIB_REREG_ADDRESS,
+                         &netif->ipv6.addrs_timers[idx], retrans_time);
+        }
+        else {
+            netif->ipv6.rs_sent = 0;
+            _handle_search_rtr(netif);
+        }
+    }
+}
+
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+_nib_abr_entry_t *_handle_abro(const sixlowpan_nd_opt_abr_t *abro)
+{
+    _nib_abr_entry_t *abr = NULL;
+
+    if (abro->len != SIXLOWPAN_ND_OPT_ABR_LEN) {
+        /* ignore silently */
+        return NULL;
+    }
+    abr = _nib_abr_add(&abro->braddr);
+    if (abr != NULL) {
+        uint32_t abro_version = sixlowpan_nd_opt_abr_get_version(abro);
+        uint16_t ltime = byteorder_ntohs(abro->ltime);
+
+        if (abr->version >= abro_version) {
+            abr->version = abro_version;
+            abr->valid_until = _now_min() + ltime;
+        }
+        /* correct for default value */
+        ltime = (ltime == 0) ? SIXLOWPAN_ND_OPT_ABR_LTIME_DEFAULT : ltime;
+        _evtimer_add(abr, GNRC_IPV6_NIB_ABR_TIMEOUT, &abr->timeout,
+                     /* UINT16_MAX min < UINT32_MAX ms so no risk of overflow */
+                     MS_PER_SEC * SEC_PER_MIN * ltime);
+    }
+    return abr;
+}
+#endif /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+uint32_t _handle_6co(const icmpv6_hdr_t *icmpv6,
+                     const sixlowpan_nd_opt_6ctx_t *sixco,
+                     _nib_abr_entry_t *abr)
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+uint32_t _handle_6co(const icmpv6_hdr_t *icmpv6,
+                     const sixlowpan_nd_opt_6ctx_t *sixco)
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+{
+    uint16_t ltime;
+
+#ifdef MODULE_GNRC_SIXLOWPAN_CTX
+    uint8_t cid;
+#endif  /* MODULE_GNRC_SIXLOWPAN_CTX */
+
+    if ((sixco->len != SIXLOWPAN_ND_OPT_6CTX_LEN_MIN) ||
+        ((sixco->len != SIXLOWPAN_ND_OPT_6CTX_LEN_MAX) &&
+         (sixco->ctx_len > 64U)) ||
+        (icmpv6->type != ICMPV6_RTR_ADV)) {
+        DEBUG("nib: received 6CO of invalid length (%u), must be %u "
+              "or wasn't delivered by RA."
+              "\n",
+              sixco->len,
+              (sixco->ctx_len > 64U) ? SIXLOWPAN_ND_OPT_6CTX_LEN_MAX :
+                                       SIXLOWPAN_ND_OPT_6CTX_LEN_MIN);
+        return UINT32_MAX;
+    }
+    ltime = byteorder_ntohs(sixco->ltime);
+#ifdef MODULE_GNRC_SIXLOWPAN_CTX
+    cid = sixlowpan_nd_opt_6ctx_get_cid(sixco);
+    gnrc_sixlowpan_ctx_update(cid, (ipv6_addr_t *)(sixco + 1), sixco->ctx_len,
+                              ltime, sixlowpan_nd_opt_6ctx_is_comp(sixco));
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+    assert(abr != NULL);    /* should have been set in _handle_abro() */
+    if (ltime == 0) {
+        bf_unset(abr->ctxs, cid);
+    }
+    else {
+        bf_set(abr->ctxs, cid);
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+#else   /* MODULE_GNRC_SIXLOWPAN_CTX */
+    (void)abr;
+#endif  /* MODULE_GNRC_SIXLOWPAN_CTX */
+    return ltime * SEC_PER_MIN * MS_PER_SEC;
+}
 #else  /* GNRC_IPV6_NIB_CONF_6LN */
 typedef int dont_be_pedantic;
 #endif /* GNRC_IPV6_NIB_CONF_6LN */
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.h
index 1ba822bf58caeb3b039bce39be7c91cec22a0be5..d371aebc9372b2eb2acb9a3003c9034a2a1a980a 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.h
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.h
@@ -23,6 +23,8 @@
 
 #include "net/gnrc/ipv6/nib/conf.h"
 #include "net/sixlowpan/nd.h"
+#include "timex.h"
+#include "xtimer.h"
 
 #include "_nib-arsm.h"
 #include "_nib-internal.h"
@@ -31,6 +33,12 @@
 extern "C" {
 #endif
 
+static inline uint32_t _now_min(void)
+{
+    return (uint32_t)((xtimer_now_usec64() / (US_PER_SEC * SEC_PER_MIN)) &
+                      UINT32_MAX);
+}
+
 #if GNRC_IPV6_NIB_CONF_6LN || defined(DOXYGEN)
 /**
  * @brief   Additional (local) status to ARO status values for tentative
@@ -57,6 +65,37 @@ extern "C" {
 bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
                              gnrc_ipv6_nib_nc_t *nce);
 
+/**
+ * @brief   Calculates exponential backoff for RS retransmissions
+ *
+ * @see [RFC 6775, section 5.3](https://tools.ietf.org/html/rfc6775#section-5.3)
+ *
+ * @param[in] netif The network interface that the RS will be sent over.
+ *
+ * @return  The interval in ms to the next RS
+ */
+static inline uint32_t _get_next_rs_interval(const gnrc_netif2_t *netif)
+{
+    if (gnrc_netif2_is_6ln(netif)) {
+        if (netif->ipv6.rs_sent < SIXLOWPAN_ND_MAX_RS_NUMOF) {
+            return SIXLOWPAN_ND_RS_MSEC_INTERVAL;
+        }
+        else {
+            unsigned exp = netif->ipv6.rs_sent - SIXLOWPAN_ND_MAX_RS_NUMOF;
+            uint32_t tmp = SIXLOWPAN_ND_RS_MSEC_INTERVAL +
+                           ((1 << exp) * (NDP_RS_MS_INTERVAL));
+
+            if (tmp > (SIXLOWPAN_ND_MAX_RS_SEC_INTERVAL * MS_PER_SEC)) {
+                tmp = SIXLOWPAN_ND_MAX_RS_SEC_INTERVAL * MS_PER_SEC;
+            }
+            return tmp;
+        }
+    }
+    else {
+        return NDP_RS_MS_INTERVAL;
+    }
+}
+
 /**
  * @brief   Handles ARO
  *
@@ -74,11 +113,36 @@ uint8_t _handle_aro(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                     const icmpv6_hdr_t *icmpv6,
                     const sixlowpan_nd_opt_ar_t *aro, const ndp_opt_t *sl2ao,
                     _nib_onl_entry_t *nce);
+
+/**
+ * @brief   Handler for @ref GNRC_IPV6_NIB_REREG_ADDRESS event handler
+ *
+ * @param[in] addr  An IPv6 address.
+ */
+void _handle_rereg_address(const ipv6_addr_t *addr);
+
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN)
+_nib_abr_entry_t *_handle_abro(const sixlowpan_nd_opt_abr_t *abro);
+uint32_t _handle_6co(const icmpv6_hdr_t *icmpv6,
+                     const sixlowpan_nd_opt_6ctx_t *sixco,
+                     _nib_abr_entry_t *abr);
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN) */
+uint32_t _handle_6co(const icmpv6_hdr_t *icmpv6,
+                     const sixlowpan_nd_opt_6ctx_t *sixco);
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN) */
 #else   /* GNRC_IPV6_NIB_CONF_6LN || defined(DOXYGEN) */
 #define _resolve_addr_from_ipv6(dst, netif, nce)    (false)
 /* _handle_aro() doesn't make sense without 6LR so don't even use it
  * => throw error in case it is compiled in => don't define it here as NOP macro
  */
+#define _get_next_rs_interval(netif)                (NDP_RS_MS_INTERVAL)
+#define _handle_rereg_address(netif)                (void)netif
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN)
+#define _handle_abro(abro)                          (NULL)
+#define _handle_6co(icmpv6, sixco, abr)             (UINT32_MAX)
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN) */
+#define _handle_6co(icmpv6, sixco)                  (UINT32_MAX)
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN) */
 #endif  /* GNRC_IPV6_NIB_CONF_6LN || defined(DOXYGEN) */
 
 
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.c
index 9cfaf55f0aa3ab4457d1122150814e1d8dad56e0..4342b0b354e39339baba13afa3f48732cb7b3738 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.c
@@ -51,11 +51,9 @@ static uint8_t _update_nce_ar_state(const sixlowpan_nd_opt_ar_t *aro,
 uint8_t _reg_addr_upstream(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                            const icmpv6_hdr_t *icmpv6,
                            const sixlowpan_nd_opt_ar_t *aro,
-                           const ndp_opt_t *sl2ao)
+                           const ndp_opt_t *sl2ao, _nib_onl_entry_t *nce)
 {
     if (!ipv6_addr_is_unspecified(&ipv6->src) && (sl2ao != NULL)) {
-        _nib_onl_entry_t *nce = _nib_onl_get(&ipv6->src, netif->pid);
-
         DEBUG("nib: Trying to register %s with EUI-64 "
               "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
               ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)),
@@ -66,9 +64,11 @@ uint8_t _reg_addr_upstream(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
             (memcmp(&nce->eui64, &aro->eui64, sizeof(aro->eui64)) == 0)) {
 #if GNRC_IPV6_NIB_CONF_MULTIHOP_DAD
             /* TODO */
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_DAD */
             if (aro->ltime.u16 != 0) {
                 _handle_sl2ao(netif, ipv6, icmpv6, sl2ao);
+                /* re-get NCE in case it was updated */
+                nce = _nib_onl_get(&ipv6->src, netif->pid);
                 return _update_nce_ar_state(aro, nce);
             }
             else if (nce != NULL) {
@@ -76,7 +76,8 @@ uint8_t _reg_addr_upstream(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                 return SIXLOWPAN_ND_STATUS_SUCCESS;
             }
         }
-        else {
+        else if (_get_ar_state(nce) != GNRC_IPV6_NIB_NC_INFO_AR_STATE_GC) {
+            /* ignore address registration requests from upstream */
             DEBUG("nib: Could not register %s, duplicate entry with EUI-64 "
                   "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
                   ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)),
@@ -116,7 +117,7 @@ gnrc_pktsnip_t *_copy_and_handle_aro(gnrc_netif2_t *netif,
             DEBUG("nib: Address was marked TENTATIVE => not replying NS, "
                   "waiting for DAC\n");
         }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_DAD */
     }
     return reply_aro;
 }
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.h
index 6248600e69cef16fcdc6b541c81705c73d7fec0b..e7b7661a55317c58567e711c9c816ad9e8974dd0 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.h
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.h
@@ -83,6 +83,9 @@ static inline bool _rtr_sol_on_6lr(const gnrc_netif2_t *netif,
  *                      handed to the SL2AO handler function).
  * @param[in] aro       ARO that carries the address registration information.
  * @param[in] sl2ao     SL2AO associated with the ARO.
+ * @param[in] nce       The local neighbor cache entry the registration
+ *                      information is supposed to be copied into. May be NULL
+ *                      (this might create one).
  *
  * @return  registration status of the address (including
  *          @ref _ADDR_REG_STATUS_TENTATIVE and @ref _ADDR_REG_STATUS_IGNORE).
@@ -90,7 +93,7 @@ static inline bool _rtr_sol_on_6lr(const gnrc_netif2_t *netif,
 uint8_t _reg_addr_upstream(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                            const icmpv6_hdr_t *icmpv6,
                            const sixlowpan_nd_opt_ar_t *aro,
-                           const ndp_opt_t *sl2ao);
+                           const ndp_opt_t *sl2ao, _nib_onl_entry_t *nce);
 
 
 /**
@@ -112,15 +115,23 @@ gnrc_pktsnip_t *_copy_and_handle_aro(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv
                                      const ndp_nbr_sol_t *nbr_sol,
                                      const sixlowpan_nd_opt_ar_t *aro,
                                      const ndp_opt_t *sl2ao);
+
+/**
+ * @brief   Sets the @ref GNRC_NETIF2_FLAGS_IPV6_RTR_ADV flags of an interface
+ *
+ * @param[in] netif The interface.
+ */
+void _set_rtr_adv(gnrc_netif2_t *netif);
 #else   /* GNRC_IPV6_NIB_CONF_6LR || defined(DOXYGEN) */
 #define _rtr_sol_on_6lr(netif, icmpv6)  (false)
 #define _get_ar_state(nbr)              (_ADDR_REG_STATUS_IGNORE)
 #define _set_ar_state(nbr, state)       (void)nbr; (void)state
-#define _copy_and_handle_aro(netif, ipv6, icmpv6, aro, sl2ao) \
-                                        (NULL)
 /* _reg_addr_upstream() doesn't make sense without 6LR so don't even use it
  * => throw error in case it is compiled in => don't define it here as NOP macro
  */
+#define _copy_and_handle_aro(netif, ipv6, icmpv6, aro, sl2ao) \
+                                        (NULL)
+#define _set_rtr_adv(netif)             (void)netif
 #endif  /* GNRC_IPV6_NIB_CONF_6LR || defined(DOXYGEN) */
 
 #ifdef __cplusplus
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c
index 22ac8c2ce19ed2b27865d12e9b2ba5ec90b284c5..a1d814e10e1af7baa9784ec7bfb62d921ac5ca05 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c
@@ -19,9 +19,10 @@
 #include "net/gnrc/netif2/internal.h"
 #ifdef MODULE_GNRC_SIXLOWPAN_ND
 #include "net/gnrc/sixlowpan/nd.h"
-#endif
+#endif  /* MODULE_GNRC_SIXLOWPAN_ND */
 
 #include "_nib-arsm.h"
+#include "_nib-router.h"
 #include "_nib-6lr.h"
 
 #define ENABLE_DEBUG    (0)
@@ -88,16 +89,16 @@ void _snd_uc_ns(_nib_onl_entry_t *nbr, bool reset)
     if (reset) {
         nbr->ns_sent = 0;
     }
-#else
+#else   /* GNRC_IPV6_NIB_CONF_ARSM */
     (void)reset;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
     _snd_ns(&nbr->ipv6, netif, NULL, &nbr->ipv6);
     _evtimer_add(nbr, GNRC_IPV6_NIB_SND_UC_NS, &nbr->nud_timeout,
                  netif->ipv6.retrans_time);
     gnrc_netif2_release(netif);
 #if GNRC_IPV6_NIB_CONF_ARSM
     nbr->ns_sent++;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
 }
 
 void _handle_sl2ao(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
@@ -118,7 +119,7 @@ void _handle_sl2ao(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
          (memcmp(nce->l2addr, sl2ao + 1, nce->l2addr_len) != 0)) &&
         /* a 6LR MUST NOT modify an existing NCE based on an SL2AO in an RS
          * see https://tools.ietf.org/html/rfc6775#section-6.3 */
-         !_rtr_sol_on_6lr(netif, icmpv6)) {
+        !_rtr_sol_on_6lr(netif, icmpv6)) {
         DEBUG("nib: L2 address differs. Setting STALE\n");
         evtimer_del(&_nib_evtimer, &nce->nud_timeout.event);
         _set_nud_state(netif, nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
@@ -142,13 +143,13 @@ void _handle_sl2ao(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                              &nce->addr_reg_timeout,
                              SIXLOWPAN_ND_TENTATIVE_NCE_SEC_LTIME * MS_PER_SEC);
             }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_DAD && GNRC_IPV6_NIB_CONF_6LR */
         }
 #if ENABLE_DEBUG
         else {
             DEBUG("nib: Neighbor cache full\n");
         }
-#endif
+#endif  /* ENABLE_DEBUG */
     }
     /* not else to include NCE created in nce == NULL branch */
     if ((nce != NULL) && (nce->mode & _NC)) {
@@ -171,7 +172,7 @@ void _handle_sl2ao(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
             nce->l2addr_len = l2addr_len;
             memcpy(nce->l2addr, sl2ao + 1, l2addr_len);
         }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
     }
 }
 
@@ -183,17 +184,17 @@ static inline unsigned _get_l2addr_len(gnrc_netif2_t *netif,
         case NETDEV_TYPE_CC110X:
             (void)opt;
             return sizeof(uint8_t);
-#endif
+#endif  /* MODULE_CC110X */
 #ifdef MODULE_NETDEV_ETH
         case NETDEV_TYPE_ETHERNET:
             (void)opt;
             return ETHERNET_ADDR_LEN;
-#endif
+#endif  /* MODULE_NETDEV_ETH */
 #ifdef MODULE_NETDEV_NRFMIN
         case NETDEV_TYPE_NRFMIN:
             (void)opt;
             return sizeof(uint16_t);
-#endif
+#endif  /* MODULE_NETDEV_NRFMIN */
 #ifdef MODULE_NETDEV_IEEE802154
         case NETDEV_TYPE_IEEE802154:
             switch (opt->len) {
@@ -204,7 +205,7 @@ static inline unsigned _get_l2addr_len(gnrc_netif2_t *netif,
                 default:
                     return 0U;
             }
-#endif
+#endif  /* MODULE_NETDEV_IEEE802154 */
         default:
             (void)opt;
             return 0U;
@@ -314,6 +315,7 @@ void _handle_state_timeout(_nib_onl_entry_t *nbr)
 void _probe_nbr(_nib_onl_entry_t *nbr, bool reset)
 {
     const uint16_t state = _get_nud_state(nbr);
+
     DEBUG("nib: Probing ");
     switch (state) {
         case GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED:
@@ -363,7 +365,7 @@ void _probe_nbr(_nib_onl_entry_t *nbr, bool reset)
                                            sizeof(addr_str)),
                           (unsigned)netif->ipv6.retrans_time);
                 }
-#endif
+#endif  /* ENABLE_DEBUG */
                 gnrc_netif2_release(netif);
             }
             break;
@@ -483,14 +485,14 @@ void _set_nud_state(gnrc_netif2_t *netif, _nib_onl_entry_t *nce,
 
 #if GNRC_IPV6_NIB_CONF_ROUTER
     gnrc_netif2_acquire(netif);
-    if ((netif != NULL) && (netif->ipv6.route_info_cb)) {
-        netif->ipv6.route_info_cb(GNRC_IPV6_NIB_ROUTE_INFO_TYPE_NSC,
-                                  &nce->ipv6, (void *)((intptr_t)state));
+    if (netif != NULL) {
+        _call_route_info_cb(netif, GNRC_IPV6_NIB_ROUTE_INFO_TYPE_NSC,
+                            &nce->ipv6, (void *)((intptr_t)state));
     }
     gnrc_netif2_release(netif);
-#else
+#else   /* GNRC_IPV6_NIB_CONF_ROUTER */
     (void)netif;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
 }
 
 /* internal functions */
@@ -515,7 +517,7 @@ static inline bool _redirect_with_tl2ao(icmpv6_hdr_t *icmpv6, ndp_opt_t *tl2ao)
 {
     return (icmpv6->type == ICMPV6_REDIRECT) && (tl2ao != NULL);
 }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_REDIRECT */
 
 static inline bool _tl2ao_changes_nce(_nib_onl_entry_t *nce,
                                       const ndp_opt_t *tl2ao,
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c
index 4b1be07f50cf741106a8651f6adbffdd5f9b2233..98d528d839b6751f20a673d913628430cbc6c7d7 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c
@@ -25,6 +25,7 @@
 #include "random.h"
 
 #include "_nib-internal.h"
+#include "_nib-router.h"
 
 #define ENABLE_DEBUG    (0)
 #include "debug.h"
@@ -39,7 +40,7 @@ static _nib_dr_entry_t _def_routers[GNRC_IPV6_NIB_DEFAULT_ROUTER_NUMOF];
 
 #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
 static _nib_abr_entry_t _abrs[GNRC_IPV6_NIB_ABR_NUMOF];
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
 
 #if ENABLE_DEBUG
 static char addr_str[IPV6_ADDR_MAX_STR_LEN];
@@ -62,8 +63,8 @@ void _nib_init(void)
     memset(_dsts, 0, sizeof(_dsts));
 #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
     memset(_abrs, 0, sizeof(_abrs));
-#endif
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+#endif  /* TEST_SUITES */
     evtimer_init_msg(&_nib_evtimer);
     /* TODO: load ABR information from persistent memory */
 }
@@ -103,7 +104,7 @@ _nib_onl_entry_t *_nib_onl_alloc(const ipv6_addr_t *addr, unsigned iface)
     else {
         DEBUG("  NIB full\n");
     }
-#endif
+#endif  /* ENABLE_DEBUG */
     return node;
 }
 
@@ -233,15 +234,15 @@ void _nib_nc_set_reachable(_nib_onl_entry_t *node)
     if (netif == NULL) {
         return;
     }
-#endif
+#endif  /* TEST_SUITES */
     DEBUG("nib: set %s%%%u reachable (reachable time = %u)\n",
           ipv6_addr_to_str(addr_str, &node->ipv6, sizeof(addr_str)),
           _nib_onl_get_if(node), (unsigned)netif->ipv6.reach_time);
     _evtimer_add(node, GNRC_IPV6_NIB_REACH_TIMEOUT, &node->nud_timeout,
                  netif->ipv6.reach_time);
-#else
+#else   /* GNRC_IPV6_NIB_CONF_ARSM */
     (void)node;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
 }
 
 void _nib_nc_remove(_nib_onl_entry_t *node)
@@ -253,10 +254,13 @@ void _nib_nc_remove(_nib_onl_entry_t *node)
     evtimer_del((evtimer_t *)&_nib_evtimer, &node->snd_na.event);
 #if GNRC_IPV6_NIB_CONF_ARSM
     evtimer_del((evtimer_t *)&_nib_evtimer, &node->nud_timeout.event);
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
+#if GNRC_IPV6_NIB_CONF_ROUTER
+    evtimer_del((evtimer_t *)&_nib_evtimer, &node->reply_rs.event);
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
 #if GNRC_IPV6_NIB_CONF_6LR
     evtimer_del((evtimer_t *)&_nib_evtimer, &node->addr_reg_timeout.event);
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_6LR */
 #if GNRC_IPV6_NIB_CONF_QUEUE_PKT
     gnrc_pktqueue_t *tmp;
     for (gnrc_pktqueue_t *ptr = node->pktqueue;
@@ -293,17 +297,17 @@ void _nib_nc_get(const _nib_onl_entry_t *node, gnrc_ipv6_nib_nc_t *nce)
             return;
         }
     }
-#else
+#else   /* GNRC_IPV6_NIB_CONF_6LN */
     /* Prevent unused function error thrown by clang */
     (void)_get_l2addr_from_ipv6;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
     nce->l2addr_len = node->l2addr_len;
     memcpy(&nce->l2addr, &node->l2addr, node->l2addr_len);
-#else
+#else   /* GNRC_IPV6_NIB_CONF_ARSM */
     assert(ipv6_addr_is_link_local(&nce->ipv6));
     _get_l2addr_from_ipv6(nce->l2addr, &node->ipv6);
     nce->l2addr_len = sizeof(uint64_t);
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
 }
 
 _nib_dr_entry_t *_nib_drl_add(const ipv6_addr_t *router_addr, unsigned iface)
@@ -495,7 +499,7 @@ static inline bool _in_abrs(const _nib_abr_entry_t *abr)
 {
     return (abr < (_abrs + GNRC_IPV6_NIB_ABR_NUMOF));
 }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
 
 void _nib_offl_clear(_nib_offl_entry_t *dst)
 {
@@ -588,14 +592,22 @@ int _nib_get_route(const ipv6_addr_t *dst, gnrc_pktsnip_t *pkt,
           (void *)pkt);
     _nib_offl_entry_t *offl = _nib_offl_get_match(dst);
 
-    assert((dst != NULL) && (fte != NULL));
     if ((offl == NULL) || (offl->mode == _PL)) {
         /* give default router precedence over PLE */
         _nib_dr_entry_t *router = _nib_drl_get_dr();
 
         if ((router == NULL) && (offl == NULL)) {
+#if GNRC_IPV6_NIB_CONF_ROUTER
+            gnrc_netif2_t *ptr = NULL;
+
+            while ((ptr = gnrc_netif2_iter(ptr))) {
+                _call_route_info_cb(ptr,
+                                    GNRC_IPV6_NIB_ROUTE_INFO_TYPE_RRQ,
+                                    dst, pkt);
+            }
+#else   /* GNRC_IPV6_NIB_CONF_ROUTER */
             (void)pkt;
-            /* TODO: ask RRP to search for route (using pkt) */
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
             return -ENETUNREACH;
         }
         else if (router != NULL) {
@@ -629,7 +641,7 @@ void _nib_pl_remove(_nib_offl_entry_t *nib_offl)
             }
         }
     }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
 }
 
 #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
@@ -660,7 +672,7 @@ _nib_abr_entry_t *_nib_abr_add(const ipv6_addr_t *addr)
     else {
         DEBUG("  NIB full\n");
     }
-#endif
+#endif  /* ENABLE_DEBUG */
     return abr;
 }
 
@@ -682,7 +694,7 @@ void _nib_abr_remove(const ipv6_addr_t *addr)
                     gnrc_sixlowpan_ctx_remove(i);
                 }
             }
-#endif
+#endif  /* MODULE_GNRC_SIXLOWPAN_CTX */
             memset(abr, 0, sizeof(_nib_abr_entry_t));
         }
     }
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h
index 97af9ec93e4b37ef305c8f2f7005e3585686ad85..9b914c12a1101eba3614dc68fa3ceb28a8c34286 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h
@@ -60,6 +60,15 @@ extern "C" {
                                  to this @ref _nib_onl_entry_t */
 /** @} */
 
+/**
+ * @name    Off-link entry flags
+ * @anchor  net_gnrc_ipv6_nib_offl_flags
+ * @{
+ */
+#define _PFX_ON_LINK    (0x0001)
+#define _PFX_SLAAC      (0x0002)
+/** @} */
+
 /**
  * @brief   Shorter name for convenience ;-)
  */
@@ -131,6 +140,9 @@ typedef struct _nib_onl_entry {
      * @brief Event for @ref GNRC_IPV6_NIB_SND_NA
      */
     evtimer_msg_event_t snd_na;
+#if GNRC_IPV6_NIB_CONF_ROUTER || defined(DOXYGEN)
+    evtimer_msg_event_t reply_rs;           /**< Event for @ref GNRC_IPV6_NIB_REPLY_RS */
+#endif
 #if GNRC_IPV6_NIB_CONF_6LR || defined(DOXYGEN)
     evtimer_msg_event_t addr_reg_timeout;   /**< Event for @ref GNRC_IPV6_NIB_ADDR_REG_TIMEOUT */
 #endif
@@ -150,12 +162,14 @@ typedef struct _nib_onl_entry {
      * @see [Mode flags for entries](@ref net_gnrc_ipv6_nib_mode).
      */
     uint8_t mode;
+#if GNRC_IPV6_NIB_CONF_ARSM || defined(DOXYGEN)
     /**
      * @brief   Neighbor solicitations sent for probing
+     *
+     * @note    Only available if @ref GNRC_IPV6_NIB_CONF_ARSM != 0.
      */
     uint8_t ns_sent;
 
-#if GNRC_IPV6_NIB_CONF_ARSM || defined(DOXYGEN)
     /**
      * @brief   length in bytes of _nib_onl_entry_t::l2addr
      *
@@ -187,6 +201,7 @@ typedef struct {
     evtimer_msg_event_t pfx_timeout;
     uint8_t mode;               /**< [mode](@ref net_gnrc_ipv6_nib_mode) of the
                                  *   off-link entry */
+    uint16_t flags;             /**< [flags](@ref net_gnrc_ipv6_nib_offl_flags */
     uint32_t valid_until;       /**< timestamp (in ms) until which the prefix
                                      valid (UINT32_MAX means forever) */
     uint32_t pref_until;        /**< timestamp (in ms) until which the prefix
@@ -201,6 +216,8 @@ typedef struct {
     ipv6_addr_t addr;               /**< The address of the border router */
     uint32_t version;               /**< last received version of the info of
                                      *   the _nib_abr_entry_t::addr */
+    uint32_t valid_until;           /**< timestamp (in minutes) until which
+                                     *   information is valid */
     evtimer_msg_event_t timeout;    /**< timeout of the information */
     /**
      * @brief   Bitfield marking the prefixes in the NIB's off-link entries
@@ -589,11 +606,15 @@ static inline void _nib_dc_remove(_nib_offl_entry_t *nib_offl)
  * @pre     `(pfx != NULL) && (pfx != "::") && (pfx_len != 0) && (pfx_len <= 128)`
  * @pre     `(pref_ltime <= valid_ltime)`
  *
- * @param[in] iface     The interface to the prefix is added to.
- * @param[in] pfx       The IPv6 prefix or address of the destination.
- *                      May not be NULL or unspecified address. Use
- *                      @ref _nib_drl_add() for default route destinations.
- * @param[in] pfx_len   The length in bits of @p pfx in bits.
+ * @param[in] iface         The interface to the prefix is added to.
+ * @param[in] pfx           The IPv6 prefix or address of the destination.
+ *                          May not be NULL or unspecified address. Use
+ *                          @ref _nib_drl_add() for default route destinations.
+ * @param[in] pfx_len       The length in bits of @p pfx in bits.
+ * @param[in] valid_ltime   Valid lifetime in microseconds. `UINT32_MAX` for
+ *                          infinite.
+ * @param[in] pref_ltime    Preferred lifetime in microseconds. `UINT32_MAX` for
+ *                          infinite.
  *
  * @return  A new or existing off-link entry with _nib_offl_entry_t::pfx set to
  *          @p pfx.
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c
new file mode 100644
index 0000000000000000000000000000000000000000..90d95baad168efe547d01896c3b4e91cc50ab6c9
--- /dev/null
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+
+#include "net/gnrc/ipv6/nib.h"
+#include "net/gnrc/ndp2.h"
+#include "net/gnrc/netif2/internal.h"
+#include "net/gnrc/sixlowpan/nd.h"
+
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+#include "_nib-6ln.h"
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+#include "_nib-router.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#if GNRC_IPV6_NIB_CONF_ROUTER
+#if ENABLE_DEBUG
+static char addr_str[IPV6_ADDR_MAX_STR_LEN];
+#endif
+
+static void _snd_ra(gnrc_netif2_t *netif, const ipv6_addr_t *dst,
+                    bool final, _nib_abr_entry_t *abr);
+
+void _handle_reply_rs(_nib_onl_entry_t *host)
+{
+    gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(_nib_onl_get_if(host));
+
+    assert(netif != NULL);
+    gnrc_netif2_acquire(netif);
+    if (gnrc_netif2_is_rtr_adv(netif)) {
+        _snd_rtr_advs(netif, &host->ipv6, false);
+    }
+    gnrc_netif2_release(netif);
+}
+
+void _handle_snd_mc_ra(gnrc_netif2_t *netif)
+{
+    gnrc_netif2_acquire(netif);
+    assert(netif != NULL);
+    if (!gnrc_netif2_is_6ln(netif)) {
+        bool final_ra = (netif->ipv6.ra_sent > (UINT8_MAX - NDP_MAX_FIN_RA_NUMOF));
+        uint32_t next_ra_time = random_uint32_range(NDP_MIN_RA_INTERVAL_MS,
+                                                    NDP_MAX_RA_INTERVAL_MS);
+
+        /* router has router advertising interface or the RA is one of the
+         * (now deactivated) routers final one */
+        if (final_ra || gnrc_netif2_is_rtr_adv(netif)) {
+            _snd_rtr_advs(netif, NULL, final_ra);
+            netif->ipv6.last_ra = (xtimer_now_usec64() / US_PER_MS) & UINT32_MAX;
+            if ((netif->ipv6.ra_sent < NDP_MAX_INIT_RA_NUMOF) || final_ra) {
+                if ((netif->ipv6.ra_sent < NDP_MAX_INIT_RA_NUMOF) &&
+                    (next_ra_time > NDP_MAX_INIT_RA_INTERVAL)) {
+                    next_ra_time = NDP_MAX_INIT_RA_INTERVAL;
+                }
+                netif->ipv6.ra_sent++;
+            }
+            /* netif->ipv6.ra_sent overflowed => this was our last final RA */
+            if (netif->ipv6.ra_sent != 0) {
+                _evtimer_add(netif, GNRC_IPV6_NIB_SND_MC_RA, &netif->ipv6.snd_mc_ra,
+                             next_ra_time);
+            }
+        }
+    }
+    gnrc_netif2_release(netif);
+}
+
+void _snd_rtr_advs(gnrc_netif2_t *netif, const ipv6_addr_t *dst, bool final)
+{
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+    _nib_abr_entry_t *abr = NULL;
+
+    DEBUG("nib: Send router advertisements for each border router:\n");
+    while ((abr = _nib_abr_iter(abr))) {
+        DEBUG("    - %s\n", ipv6_addr_to_str(addr_str, &abr->addr,
+                                             sizeof(addr_str)));
+        _snd_ra(netif, dst, final, abr);
+    }
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+    _snd_ra(netif, dst, final, NULL);
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+}
+
+static gnrc_pktsnip_t *_offl_to_pio(_nib_offl_entry_t *offl,
+                                    gnrc_pktsnip_t *ext_opts)
+{
+    uint32_t now = (xtimer_now_usec64() / US_PER_MS) & UINT32_MAX;
+    gnrc_pktsnip_t *pio;
+    uint8_t flags = 0;
+    uint32_t valid_ltime = (offl->valid_until == UINT32_MAX) ? UINT32_MAX :
+                           (offl->valid_until - now);
+    uint32_t pref_ltime = (offl->pref_until == UINT32_MAX) ? UINT32_MAX :
+                          (offl->pref_until - now);
+
+    DEBUG("nib: Build PIO for %s/%u\n",
+          ipv6_addr_to_str(addr_str, &offl->pfx, sizeof(addr_str)),
+          offl->pfx_len);
+    if (offl->flags & _PFX_ON_LINK) {
+        flags |= NDP_OPT_PI_FLAGS_L;
+    }
+    if (offl->flags & _PFX_SLAAC) {
+        flags |= NDP_OPT_PI_FLAGS_A;
+    }
+    pio = gnrc_ndp2_opt_pi_build(&offl->pfx, offl->pfx_len, valid_ltime,
+                                 pref_ltime, flags, ext_opts);
+
+    if ((pio == NULL) && (ext_opts != NULL)) {
+        DEBUG("nib: No space left in packet buffer. Not adding PIO\n");
+        return NULL;
+    }
+    return pio;
+}
+
+static gnrc_pktsnip_t *_build_ext_opts(gnrc_netif2_t *netif,
+                                       _nib_abr_entry_t *abr)
+{
+    gnrc_pktsnip_t *ext_opts = NULL;
+    _nib_offl_entry_t *pfx = NULL;
+    unsigned id = netif->pid;
+
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+    uint16_t ltime;
+    gnrc_pktsnip_t *abro;
+
+#ifdef MODULE_GNRC_SIXLOWPAN_CTX
+    for (int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) {
+        gnrc_sixlowpan_ctx_t *ctx;
+        if (bf_isset(abr->ctxs, i) &&
+            ((ctx = gnrc_sixlowpan_ctx_lookup_id(i)) != NULL)) {
+            gnrc_pktsnip_t *sixco = gnrc_sixlowpan_nd_opt_6ctx_build(
+                                            ctx->prefix_len, ctx->flags_id,
+                                            ctx->ltime, &ctx->prefix, NULL);
+            if (sixco == NULL) {
+                DEBUG("nib: No space left in packet buffer. Not adding 6LO\n");
+                return NULL;
+            }
+            ext_opts = sixco;
+        }
+    }
+#endif  /* MODULE_GNRC_SIXLOWPAN_CTX */
+    while ((pfx = _nib_abr_iter_pfx(abr, pfx))) {
+        if (_nib_onl_get_if(pfx->next_hop) == id) {
+            if ((ext_opts = _offl_to_pio(pfx, ext_opts)) == NULL) {
+                return NULL;
+            }
+        }
+    }
+    ltime = (gnrc_netif2_is_6lbr(netif)) ?
+            (SIXLOWPAN_ND_OPT_ABR_LTIME_DEFAULT) :
+            (abr->valid_until - _now_min());
+    (void)ltime;    /* gnrc_sixlowpan_nd_opt_abr_build might evaluate to NOP */
+    abro = gnrc_sixlowpan_nd_opt_abr_build(abr->version, ltime, &abr->addr,
+                                           ext_opts);
+    if (abro == NULL) {
+        DEBUG("nib: No space left in packet buffer. Not adding ABRO\n");
+        return NULL;
+    }
+    ext_opts = abro;
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+    (void)abr;
+    while ((pfx = _nib_offl_iter(pfx))) {
+        if ((pfx->mode & _PL) && (_nib_onl_get_if(pfx->next_hop) == id)) {
+            if ((ext_opts = _offl_to_pio(pfx, ext_opts)) == NULL) {
+                return NULL;
+            }
+        }
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+    return ext_opts;
+}
+
+void _set_rtr_adv(gnrc_netif2_t *netif)
+{
+    DEBUG("nib: set RTR_ADV flag for interface %i\n", netif->pid);
+    netif->ipv6.ra_sent = 0;
+    netif->flags |= GNRC_NETIF2_FLAGS_IPV6_RTR_ADV;
+    _handle_snd_mc_ra(netif);
+}
+
+static void _snd_ra(gnrc_netif2_t *netif, const ipv6_addr_t *dst,
+                    bool final, _nib_abr_entry_t *abr)
+{
+    gnrc_pktsnip_t *ext_opts = _build_ext_opts(netif, abr);
+
+    gnrc_ndp2_rtr_adv_send(netif, NULL, dst, final, ext_opts);
+}
+#else  /* GNRC_IPV6_NIB_CONF_ROUTER */
+typedef int dont_be_pedantic;
+#endif /* GNRC_IPV6_NIB_CONF_ROUTER */
+
+/** @} */
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.h
new file mode 100644
index 0000000000000000000000000000000000000000..1205dc555f2a0f7ff73de8a100bec87e832ee58d
--- /dev/null
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 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_gnrc_ipv6_nib
+ * @internal
+ * @{
+ *
+ * @file
+ * @brief   Definitions related to router functionality of NIB
+ *
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+#ifndef PRIV_NIB_ROUTER_H
+#define PRIV_NIB_ROUTER_H
+
+#include "net/gnrc/ipv6/nib/conf.h"
+#include "net/gnrc/netif2/internal.h"
+#include "net/gnrc/netif2/ipv6.h"
+#include "net/ipv6/addr.h"
+#include "net/ndp.h"
+
+#include "_nib-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if GNRC_IPV6_NIB_CONF_ROUTER || defined(DOXYGEN)
+/**
+ * @brief   Initializes interface for router behavior
+ *
+ * @param[in] netif An interface.
+ */
+static inline void _init_iface_router(gnrc_netif2_t *netif)
+{
+    netif->ipv6.rtr_ltime = NDP_RTR_LTIME_SEC;
+    netif->ipv6.last_ra = UINT32_MAX;
+    netif->ipv6.ra_sent = 0;
+    netif->flags |= GNRC_NETIF2_FLAGS_IPV6_FORWARDING;
+#if !GNRC_IPV6_NIB_CONF_6LR || GNRC_IPV6_NIB_CONF_6LBR
+    netif->flags |= GNRC_NETIF2_FLAGS_IPV6_RTR_ADV;
+#endif  /* !GNRC_IPV6_NIB_CONF_6LR || GNRC_IPV6_NIB_CONF_6LBR */
+#if GNRC_IPV6_NIB_CONF_6LBR
+    netif->flags |= GNRC_NETIF2_FLAGS_6LO_ABR;
+#endif  /* GNRC_IPV6_NIB_CONF_6LBR */
+    gnrc_netif2_ipv6_group_join(netif, &ipv6_addr_all_routers_link_local);
+}
+
+/**
+ * @brief   Helper function to safely call the
+ *          [route info callback](@ref gnrc_netif2_ipv6_t::route_info_cb) of an
+ *          interface
+ *
+ * @param[in] netif     An interface.
+ * @param[in] type      [Type](@ref net_gnrc_ipv6_nib_route_info_type) of the
+ *                      route info.
+ * @param[in] ctx_addr  Context address of the route info.
+ * @param[in] ctx       Further context of the route info.
+ */
+static inline void _call_route_info_cb(gnrc_netif2_t *netif, unsigned type,
+                                       const ipv6_addr_t *ctx_addr,
+                                       const void *ctx)
+{
+    if (netif->ipv6.route_info_cb != NULL) {
+        netif->ipv6.route_info_cb(type, ctx_addr, ctx);
+    }
+}
+
+/**
+ * @brief   Handler for @ref GNRC_IPV6_NIB_REPLY_RS event handler
+ *
+ * @param[in] host  Host that sent the router solicitation
+ */
+void _handle_reply_rs(_nib_onl_entry_t *host);
+
+/**
+ * @brief   Handler for @ref GNRC_IPV6_NIB_SND_MC_RA event handler
+ *
+ * @param[in] netif Network interface to send multicast router advertisement
+ *                  over.
+ */
+void _handle_snd_mc_ra(gnrc_netif2_t *netif);
+
+/**
+ * @brief   Set the @ref GNRC_NETIF2_FLAGS_IPV6_RTR_ADV flag for an interface
+ *          and starts advertising that interface as a router
+ *
+ * @param[in] netif Interface to set the @ref GNRC_NETIF2_FLAGS_IPV6_RTR_ADV
+ *                  for.
+ */
+void _set_rtr_adv(gnrc_netif2_t *netif);
+
+/**
+ * @brief   Send router advertisements
+ *
+ * If @ref GNRC_IPV6_NIB_CONF_MULTIHOP_P6C is not 0 this sends one router
+ * advertisement per configured ABR, otherwise it just sends one single router
+ * advertisement for the interface.
+ *
+ * @param[in] netif The interface to send the router advertisement over.
+ * @param[in] dst   Destination address for the router advertisement.
+ * @param[in] final The router advertisement are the final ones of the @p netif
+ *                  (because it was set to be a non-forwarding interface e.g.).
+ */
+void _snd_rtr_advs(gnrc_netif2_t *netif, const ipv6_addr_t *dst,
+                  bool final);
+#else  /* GNRC_IPV6_NIB_CONF_ROUTER */
+#define _init_iface_router(netif)                       (void)netif
+#define _call_route_info_cb(netif, type, ctx_addr, ctx) (void)netif; \
+                                                        (void)type; \
+                                                        (void)ctx_addr; \
+                                                        (void)ctx
+#define _handle_reply_rs(host)                          (void)host
+#define _handle_snd_mc_ra(netif)                        (void)netif
+#define _set_rtr_adv(netif)                             (void)netif
+#define _snd_rtr_advs(netif, dst, final)                (void)netif; \
+                                                        (void)dst; \
+                                                        (void)final
+#endif /* GNRC_IPV6_NIB_CONF_ROUTER */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PRIV_NIB_ROUTER_H */
+/** @} */
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c
index 58219d4503fb17f0c7696e2f6021636a56f81d33..9ff8d152757ce4d67b79a0ece2e5a30f52eea874 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/nib.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/nib.c
@@ -29,6 +29,7 @@
 
 #include "_nib-internal.h"
 #include "_nib-arsm.h"
+#include "_nib-router.h"
 #include "_nib-6ln.h"
 #include "_nib-6lr.h"
 
@@ -44,12 +45,18 @@ static char addr_str[IPV6_ADDR_MAX_STR_LEN];
 
 #if GNRC_IPV6_NIB_CONF_QUEUE_PKT
 static gnrc_pktqueue_t _queue_pool[GNRC_IPV6_NIB_NUMOF];
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_QUEUE_PKT */
 
 /**
  * @internal
  * @{
  */
+#if GNRC_IPV6_NIB_CONF_ROUTER
+static void _handle_rtr_sol(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
+                            const ndp_rtr_sol_t *rtr_sol, size_t icmpv6_len);
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
+static void _handle_rtr_adv(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
+                            const ndp_rtr_adv_t *rtr_adv, size_t icmpv6_len);
 static void _handle_nbr_sol(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                             const ndp_nbr_sol_t *nbr_sol, size_t icmpv6_len);
 static void _handle_nbr_adv(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
@@ -59,7 +66,19 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
                           gnrc_pktsnip_t *pkt, gnrc_ipv6_nib_nc_t *nce,
                           _nib_onl_entry_t *entry);
 
+static void _handle_pfx_timeout(_nib_offl_entry_t *pfx);
+static void _handle_rtr_timeout(_nib_dr_entry_t *router);
 static void _handle_snd_na(gnrc_pktsnip_t *pkt);
+#if GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC
+static void _auto_configure_addr(gnrc_netif2_t *netif, const ipv6_addr_t *pfx,
+                                 uint8_t pfx_len);
+#else   /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */
+#define _auto_configure_addr(netif, pfx, pfx_len)   (void)netif; \
+                                                    (void)pfx; \
+                                                    (void)pfx_len
+#endif  /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */
+/* needs to be exported for 6LN's ARO handling */
+void _handle_search_rtr(gnrc_netif2_t *netif);
 /** @} */
 
 void gnrc_ipv6_nib_init(void)
@@ -78,51 +97,20 @@ void gnrc_ipv6_nib_init(void)
 
 void gnrc_ipv6_nib_init_iface(gnrc_netif2_t *netif)
 {
-    ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED;
-
     assert(netif != NULL);
     DEBUG("nib: Initialize interface %u\n", netif->pid);
     gnrc_netif2_acquire(netif);
-    /* TODO:
-     * - set link-local address here for stateless address auto-configuration
-     *   and 6LN
-     * - join solicited nodes group of link-local address here for address
-     *   resolution here
-     * - join all router group of link-local address here on router node here
-     * - become an router advertising interface here on non-6LR here */
 
     _init_iface_arsm(netif);
     netif->ipv6.retrans_time = NDP_RETRANS_TIMER_MS;
-    netif->ipv6.na_sent = 0;
-#if GNRC_IPV6_NIB_CONF_ROUTER
-    netif->ipv6.rtr_ltime = 1800U;
-    netif->ipv6.last_ra = UINT32_MAX;
-    netif->ipv6.ra_sent = 0;
-    netif->flags |= GNRC_NETIF2_FLAGS_IPV6_FORWARDING;
-#if !GNRC_IPV6_NIB_CONF_6LR || GNRC_IPV6_NIB_CONF_6LBR
-    netif->flags |= GNRC_NETIF2_FLAGS_IPV6_RTR_ADV;
-#endif
-#if GNRC_IPV6_NIB_CONF_6LBR
-    netif->flags |= GNRC_NETIF2_FLAGS_6LO_ABR;
-#endif
-    memcpy(&addr, &ipv6_addr_all_routers_link_local, sizeof(addr));
-    if (gnrc_netif2_ipv6_group_join(netif, &addr) < 0) {
-        LOG_ERROR("nib: Can't join link-local all-routers on interface %u\n",
-                  netif->pid);
-        return;
-    }
-#endif
+#if GNRC_IPV6_NIB_CONF_SLAAC || GNRC_IPV6_NIB_CONF_6LN
+    /* TODO: set differently dependent on GNRC_IPV6_NIB_CONF_SLAAC if
+     * alternatives exist */
+    netif->ipv6.aac_mode = GNRC_NETIF2_AAC_AUTO;
+#endif  /* GNRC_IPV6_NIB_CONF_SLAAC || GNRC_IPV6_NIB_CONF_6LN */
+    _init_iface_router(netif);
 #if GNRC_IPV6_NIB_CONF_6LN
     netif->ipv6.rs_sent = 0;
-#endif
-    memcpy(&addr, &ipv6_addr_all_nodes_link_local, sizeof(addr));
-    if (gnrc_netif2_ipv6_group_join(netif, &addr) < 0) {
-        LOG_ERROR("nib: Can't join link-local all-nodes on interface %u\n",
-                  netif->pid);
-        return;
-    }
-#if GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC
-#if GNRC_IPV6_NIB_CONF_6LN
     if (netif->device_type == NETDEV_TYPE_IEEE802154) {
         /* see https://tools.ietf.org/html/rfc6775#section-5.2 */
         uint16_t src_len = IEEE802154_LONG_ADDRESS_LEN;
@@ -134,35 +122,52 @@ void gnrc_ipv6_nib_init_iface(gnrc_netif2_t *netif)
          * directly everything else would deadlock anyway */
         netif->ops->set(netif, &opt);
     }
-#endif
-    uint8_t flags = GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_VALID;
-    /* TODO: set TENTATIVE as soon as there is a SLAAC implementation if not
-     * 6LN ;-) */
-
-    gnrc_netif2_ipv6_get_iid(netif, (eui64_t *)&addr.u64[1]);
-    ipv6_addr_set_link_local_prefix(&addr);
-    if (gnrc_netif2_ipv6_addr_add(netif, &addr, 64U, flags) < 0) {
-        LOG_ERROR("nib: Can't add link-local address on interface %u\n",
-                  netif->pid);
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+    netif->ipv6.na_sent = 0;
+    if (gnrc_netif2_ipv6_group_join(netif,
+                                    &ipv6_addr_all_nodes_link_local) < 0) {
+        DEBUG("nib: Can't join link-local all-nodes on interface %u\n",
+              netif->pid);
+        gnrc_netif2_release(netif);
         return;
     }
-#if GNRC_IPV6_NIB_CONF_ARSM
-    /* TODO: SHOULD delay join between 0 and MAX_RTR_SOLICITATION_DELAY */
-    ipv6_addr_set_solicited_nodes(&addr, &addr);
-    if (gnrc_netif2_ipv6_group_join(netif, &addr) < 0) {
-        LOG_ERROR("nib: Can't join solicited-nodes of link-local address on "
-                  "interface %u\n", netif->pid);
-        return;
+    _auto_configure_addr(netif, &ipv6_addr_link_local_prefix, 64U);
+    if (!(gnrc_netif2_is_rtr_adv(netif)) ||
+        (gnrc_netif2_is_6ln(netif) && !gnrc_netif2_is_6lbr(netif))) {
+        uint32_t next_rs_time = random_uint32_range(0, NDP_MAX_RS_MS_DELAY);
+
+        _evtimer_add(netif, GNRC_IPV6_NIB_SEARCH_RTR, &netif->ipv6.search_rtr,
+                     next_rs_time);
     }
-#endif
-#if GNRC_IPV6_NIB_CONF_SLAAC
-    /* TODO send NS to solicited nodes and wait netif->ipv6.retrans_time to
-     * confirm uniqueness of the link-local address */
-#endif
-#endif
+#if GNRC_IPV6_NIB_CONF_ROUTER
+    else {
+        _handle_snd_mc_ra(netif);
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
     gnrc_netif2_release(netif);
 }
 
+static bool _on_link(const ipv6_addr_t *dst, unsigned *iface)
+{
+    _nib_offl_entry_t *entry = NULL;
+
+#if GNRC_IPV6_NIB_CONF_6LN
+    if (*iface != 0) {
+        if (gnrc_netif2_is_6ln(gnrc_netif2_get_by_pid(*iface))) {
+            return ipv6_addr_is_link_local(dst);
+        }
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+    while ((entry = _nib_offl_iter(entry))) {
+        if ((entry->mode & _PL) && (entry->flags & _PFX_ON_LINK) &&
+            (ipv6_addr_match_prefix(dst, &entry->pfx) >= entry->pfx_len)) {
+            *iface = _nib_onl_get_if(entry->next_hop);
+            return true;
+        }
+    }
+    return ipv6_addr_is_link_local(dst);
+}
+
 int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
                                       gnrc_netif2_t *netif, gnrc_pktsnip_t *pkt,
                                       gnrc_ipv6_nib_nc_t *nce)
@@ -175,19 +180,71 @@ int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
     gnrc_netif2_acquire(netif);
     mutex_lock(&_nib_mutex);
     do {    /* XXX: hidden goto ;-) */
-        if (ipv6_addr_is_link_local(dst)) {
-            /* TODO: Prefix-based on-link determination */
+        _nib_onl_entry_t *node = _nib_onl_get(dst,
+                                              (netif == NULL) ? 0 : netif->pid);
+        /* consider neighbor cache entries first */
+        unsigned iface = (node == NULL) ? 0 : _nib_onl_get_if(node);
+
+        if ((node != NULL) || _on_link(dst, &iface)) {
+            DEBUG("nib: %s is on-link or in NC, start address resolution\n",
+                  ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
+            /* on-link prefixes return their interface */
+            if (!ipv6_addr_is_link_local(dst) && (iface != 0)) {
+                /* release preassumed interface */
+                gnrc_netif2_release(netif);
+                netif = gnrc_netif2_get_by_pid(iface);
+                gnrc_netif2_acquire(netif);
+            }
             if ((netif == NULL) ||
-                !_resolve_addr(dst, netif, pkt, nce,
-                               _nib_onl_get(dst, netif->pid))) {
+                !_resolve_addr(dst, netif, pkt, nce, node)) {
+                DEBUG("nib: host unreachable\n");
                 res = -EHOSTUNREACH;
                 break;
             }
         }
         else {
-            /* TODO: Off-link next hop determination;
-             *       might need netif locking */
-            res = -EHOSTUNREACH;
+            gnrc_ipv6_nib_ft_t route;
+
+            DEBUG("nib: %s is off-link, resolve route\n",
+                  ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
+            res = _nib_get_route(dst, pkt, &route);
+            if ((res < 0) || ipv6_addr_is_unspecified(&route.next_hop)) {
+                DEBUG("nib: no route to %s found or is prefix list entry, "
+                      "search neighbor cache\n",
+                      ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
+
+                if (res == 0) {
+                    DEBUG("nib: prefix list entry => taking dst as next hop\n");
+                    memcpy(&route.next_hop, dst, sizeof(route.next_hop));
+                }
+                else {
+                    res = -ENETUNREACH;
+                    break;
+                }
+            }
+            if ((netif != NULL) && (netif->pid != route.iface)) {
+                /* drop pre-assumed netif */
+                gnrc_netif2_release(netif);
+            }
+            if ((netif == NULL) || (netif->pid != route.iface)) {
+                /* get actual netif */
+                netif = gnrc_netif2_get_by_pid(route.iface);
+                gnrc_netif2_acquire(netif);
+            }
+            node = _nib_onl_get(&route.next_hop,
+                                (netif == NULL) ? netif->pid : 0);
+            if (_resolve_addr(&route.next_hop, netif, pkt, nce, node)) {
+                _call_route_info_cb(netif,
+                                    GNRC_IPV6_NIB_ROUTE_INFO_TYPE_RN,
+                                    &route.dst,
+                                    (void *)((intptr_t)route.dst_len));
+#if GNRC_IPV6_NIB_CONF_DC
+                _nib_dc_add(&route.next_hop, netif->pid, dst);
+#endif  /* GNRC_IPV6_NIB_CONF_DC */
+            }
+            else {
+                res = -EHOSTUNREACH;
+            }
         }
     } while (0);
     mutex_unlock(&_nib_mutex);
@@ -205,11 +262,11 @@ void gnrc_ipv6_nib_handle_pkt(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
     switch (icmpv6->type) {
 #if GNRC_IPV6_NIB_CONF_ROUTER
         case ICMPV6_RTR_SOL:
-            /* TODO */
+            _handle_rtr_sol(netif, ipv6, (ndp_rtr_sol_t *)icmpv6, icmpv6_len);
             break;
 #endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
         case ICMPV6_RTR_ADV:
-            /* TODO */
+            _handle_rtr_adv(netif, ipv6, (ndp_rtr_adv_t *)icmpv6, icmpv6_len);
             break;
         case ICMPV6_NBR_SOL:
             _handle_nbr_sol(netif, ipv6, (ndp_nbr_sol_t *)icmpv6, icmpv6_len);
@@ -241,7 +298,6 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type)
           ctx, type, (unsigned)xtimer_now_usec() / 1000);
     mutex_lock(&_nib_mutex);
     switch (type) {
-        /* TODO: remember netif locking if ctx is a gnrc_netif2_t */
 #if GNRC_IPV6_NIB_CONF_ARSM
         case GNRC_IPV6_NIB_SND_UC_NS:
         case GNRC_IPV6_NIB_SND_MC_NS:
@@ -259,38 +315,37 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type)
             _handle_snd_na(ctx);
             break;
         case GNRC_IPV6_NIB_SEARCH_RTR:
-            /* TODO */
-            break;
-        case GNRC_IPV6_NIB_RECONFIRM_RTR:
-            /* TODO */
+            _handle_search_rtr(ctx);
             break;
 #if GNRC_IPV6_NIB_CONF_ROUTER
         case GNRC_IPV6_NIB_REPLY_RS:
-            /* TODO */
+            _handle_reply_rs(ctx);
             break;
         case GNRC_IPV6_NIB_SND_MC_RA:
-            /* TODO */
+            _handle_snd_mc_ra(ctx);
             break;
 #endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
-#if GNRC_IPV6_NIB_CONF_6LN
+#if GNRC_IPV6_NIB_CONF_6LR
         case GNRC_IPV6_NIB_ADDR_REG_TIMEOUT:
-            /* TODO */
+            _nib_nc_remove(ctx);
             break;
-        case GNRC_IPV6_NIB_6LO_CTX_TIMEOUT:
-            /* TODO */
-            break;
-#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+#endif  /* GNRC_IPV6_NIB_CONF_6LR */
 #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
         case GNRC_IPV6_NIB_ABR_TIMEOUT:
-            /* TODO */
+            _nib_abr_remove(&((_nib_abr_entry_t *)ctx)->addr);
             break;
 #endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
         case GNRC_IPV6_NIB_PFX_TIMEOUT:
-            /* TODO */
+            _handle_pfx_timeout(ctx);
             break;
         case GNRC_IPV6_NIB_RTR_TIMEOUT:
-            /* TODO */
+            _handle_rtr_timeout(ctx);
+            break;
+#if GNRC_IPV6_NIB_CONF_6LN
+        case GNRC_IPV6_NIB_REREG_ADDRESS:
+            _handle_rereg_address(ctx);
             break;
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
         default:
             break;
     }
@@ -300,18 +355,39 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type)
 #if GNRC_IPV6_NIB_CONF_ROUTER
 void gnrc_ipv6_nib_change_rtr_adv_iface(gnrc_netif2_t *netif, bool enable)
 {
+    gnrc_netif2_acquire(netif);
     if (enable) {
-        netif->flags |= GNRC_NETIF2_FLAGS_IPV6_RTR_ADV;
-        /* TODO: start router advertisements */
+        _set_rtr_adv(netif);
     }
     else {
+        uint32_t next_rs_time = random_uint32_range(0, NDP_MAX_RS_MS_DELAY);
+
+        netif->ipv6.ra_sent = (UINT8_MAX - NDP_MAX_FIN_RA_NUMOF) + 1;
         netif->flags &= ~GNRC_NETIF2_FLAGS_IPV6_RTR_ADV;
-        /* TODO:
-         *  - start final router advertisements,
-         *  - start router solicitations? */
+        /* send final router advertisements */
+        _handle_snd_mc_ra(netif);
+        _evtimer_add(netif, GNRC_IPV6_NIB_SEARCH_RTR, &netif->ipv6.search_rtr,
+                     next_rs_time);
     }
+    gnrc_netif2_release(netif);
 }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
+
+/*
+ * @internal
+ * @{
+ */
+static void _handle_mtuo(gnrc_netif2_t *netif, const icmpv6_hdr_t *icmpv6,
+                         const ndp_opt_mtu_t *mtuo);
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+static uint32_t _handle_pio(gnrc_netif2_t *netif, const icmpv6_hdr_t *icmpv6,
+                            const ndp_opt_pi_t *pio,
+                            _nib_abr_entry_t *abr);
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+static uint32_t _handle_pio(gnrc_netif2_t *netif, const icmpv6_hdr_t *icmpv6,
+                            const ndp_opt_pi_t *pio);
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+/** @} */
 
 /* Iterator for NDP options in a packet */
 #define FOREACH_OPT(ndp_pkt, opt, icmpv6_len) \
@@ -320,16 +396,323 @@ void gnrc_ipv6_nib_change_rtr_adv_iface(gnrc_netif2_t *netif, bool enable)
          icmpv6_len -= (opt->len << 3), \
          opt = (ndp_opt_t *)(((uint8_t *)opt) + (opt->len << 3)))
 
+#if GNRC_IPV6_NIB_CONF_ROUTER
+static void _handle_rtr_sol(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
+                            const ndp_rtr_sol_t *rtr_sol, size_t icmpv6_len)
+{
+    size_t tmp_len = icmpv6_len - sizeof(ndp_rtr_sol_t);
+    _nib_onl_entry_t *nce = NULL;
+    ndp_opt_t *opt;
+    uint32_t next_ra_delay = random_uint32_range(0, NDP_MAX_RA_DELAY);
+
+    assert(netif != NULL);
+    /* check validity, see: https://tools.ietf.org/html/rfc4861#section-6.1.1 */
+    /* checksum is checked by GNRC's ICMPv6 module */
+    if (!(gnrc_netif2_is_rtr(netif)) || (ipv6->hl != 255U) ||
+        (rtr_sol->code != 0U) || (icmpv6_len < sizeof(ndp_rtr_sol_t))) {
+        DEBUG("nib: Received router solicitation is invalid (or interface %i "
+              "is not a forwarding interface). Discarding silently\n",
+              netif->pid);
+        DEBUG("     - IP Hop Limit: %u (should be 255)\n", ipv6->hl);
+        DEBUG("     - ICMP code: %u (should be 0)\n", rtr_sol->code);
+        DEBUG("     - ICMP length: %u (should > %u)\n", icmpv6_len,
+              sizeof(ndp_rtr_sol_t));
+        return;
+    }
+    /* pre-check option length */
+    FOREACH_OPT(rtr_sol, opt, tmp_len) {
+        if (tmp_len > icmpv6_len) {
+            DEBUG("nib: Payload length (%u) of RS doesn't align with options\n",
+                  (unsigned)icmpv6_len);
+            return;
+        }
+        if (opt->len == 0U) {
+            DEBUG("nib: Option of length 0 detected. "
+                  "Discarding router solicitation silently\n");
+            return;
+        }
+        if ((opt->type == NDP_OPT_SL2A) &&
+            ipv6_addr_is_unspecified(&ipv6->src)) {
+            DEBUG("nib: RS contains SLLAO, but source was unspecfied. "
+                  "Discarding router solicitation silently\n");
+            return;
+        }
+    }
+    DEBUG("nib: Received valid router solicitation:\n");
+    DEBUG("     - Source address: %s\n",
+          ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
+    DEBUG("     - Destination address: %s\n",
+          ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
+    if (!ipv6_addr_is_unspecified(&ipv6->src)) {
+        tmp_len = icmpv6_len - sizeof(ndp_rtr_sol_t);
+        FOREACH_OPT(rtr_sol, opt, tmp_len) {
+            switch (opt->type) {
+                case NDP_OPT_SL2A:
+                    if (!gnrc_netif2_is_6ln(netif)) {
+                        _handle_sl2ao(netif, ipv6, (const icmpv6_hdr_t *)rtr_sol,
+                                      opt);
+                    }
+
+                    break;
+                default:
+                    break;
+            }
+        }
+        nce = _nib_onl_get(&ipv6->src, netif->pid);
+    }
+    if (!gnrc_netif2_is_6ln(netif)) {
+        uint32_t next_ra_scheduled = _evtimer_lookup(netif,
+                                                     GNRC_IPV6_NIB_SND_MC_RA);
+        if (next_ra_scheduled < next_ra_delay) {
+            DEBUG("nib: There is a MC RA scheduled within the next %" PRIu32 "ms. "
+                  "Using that to advertise router\n", next_ra_scheduled);
+            return;
+        }
+        else if (nce != NULL) {
+            /* we send unicast RAs so we do not need to rate-limit as
+             * https://tools.ietf.org/html/rfc4861#section-6.2.6 asks for */
+            _evtimer_add(nce, GNRC_IPV6_NIB_REPLY_RS, &nce->reply_rs,
+                         next_ra_delay);
+        }
+        else {
+            uint32_t now = (xtimer_now_usec64() / MS_PER_SEC) & UINT32_MAX;
+
+            /* check for integer overflows and initial value of last_ra */
+            if (((netif->ipv6.last_ra > (UINT32_MAX - NDP_MIN_MS_DELAY_BETWEEN_RAS) &&
+                  (now < NDP_MIN_MS_DELAY_BETWEEN_RAS))) ||
+                ((now - NDP_MIN_MS_DELAY_BETWEEN_RAS) > netif->ipv6.last_ra)) {
+                next_ra_delay += NDP_MIN_MS_DELAY_BETWEEN_RAS;
+            }
+            _evtimer_add(netif, GNRC_IPV6_NIB_SND_MC_RA, &netif->ipv6.snd_mc_ra,
+                         next_ra_delay);
+        }
+    }
+#if GNRC_IPV6_NIB_CONF_6LR
+    else if (gnrc_netif2_is_rtr(netif) && gnrc_netif2_is_rtr_adv(netif)) {
+        _snd_rtr_advs(netif, &ipv6->src, false);
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_6LR */
+}
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
+
+static inline uint32_t _min(uint32_t a, uint32_t b)
+{
+    return (a < b) ? a : b;
+}
+
+static void _handle_rtr_adv(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
+                            const ndp_rtr_adv_t *rtr_adv, size_t icmpv6_len)
+{
+    size_t tmp_len = icmpv6_len - sizeof(ndp_rtr_adv_t);
+    _nib_dr_entry_t *dr = NULL;
+    ndp_opt_t *opt;
+
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+    sixlowpan_nd_opt_abr_t *abro = NULL;
+    _nib_abr_entry_t *abr = NULL;
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+    uint32_t next_timeout = UINT32_MAX;
+
+    assert(netif != NULL);
+    /* check validity, see: https://tools.ietf.org/html/rfc4861#section-6.1.1 */
+    /* checksum is checked by GNRC's ICMPv6 module */
+    if (!(ipv6_addr_is_link_local(&ipv6->src)) ||
+        (ipv6->hl != 255U) || (rtr_adv->code != 0U) ||
+        (icmpv6_len < sizeof(ndp_rtr_adv_t)) ||
+        (!gnrc_netif2_is_6ln(netif) &&
+         (byteorder_ntohs(rtr_adv->ltime) > NDP_RTR_ADV_LTIME_SEC_MAX))) {
+        DEBUG("nib: Received router advertisement is invalid. "
+              "Discarding silently\n");
+        DEBUG("     - IP Hop Limit: %u (should be 255)\n", ipv6->hl);
+        DEBUG("     - ICMP code: %u (should be 0)\n", rtr_adv->code);
+        DEBUG("     - ICMP length: %u (should > %u)\n", (unsigned)icmpv6_len,
+              sizeof(ndp_rtr_adv_t));
+        DEBUG("     - Source address: %s (should be link-local)\n",
+              ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
+        DEBUG("     - Router lifetime: %u (should be <= 9000 on non-6LN)\n",
+              byteorder_ntohs(rtr_adv->ltime));
+        return;
+    }
+    /* pre-check option length */
+    FOREACH_OPT(rtr_adv, opt, tmp_len) {
+        if (tmp_len > icmpv6_len) {
+            DEBUG("nib: Payload length (%u) of RA doesn't align with options\n",
+                  (unsigned)icmpv6_len);
+            return;
+        }
+        if (opt->len == 0U) {
+            DEBUG("nib: Option of length 0 detected. "
+                  "Discarding router advertisement silently\n");
+            return;
+        }
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+        if (opt->type == NDP_OPT_ABR) {
+            if (abro != NULL) {
+                DEBUG("nib: More than one ABRO. "
+                      "Discarding router advertisement silently\n");
+                return;
+            }
+            abro = (sixlowpan_nd_opt_abr_t *)opt;
+        }
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+    }
+    DEBUG("nib: Received valid router advertisement:\n");
+    DEBUG("     - Source address: %s\n",
+          ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
+    DEBUG("     - Destination address: %s\n",
+          ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
+    DEBUG("     - Cur Hop Limit: %u\n", rtr_adv->cur_hl);
+    DEBUG("     - Flags: %c%c\n",
+          (rtr_adv->flags & NDP_RTR_ADV_FLAGS_M) ? 'M' : '-',
+          (rtr_adv->flags & NDP_RTR_ADV_FLAGS_O) ? 'O' : '-');
+    DEBUG("     - Router Lifetime: %us\n", byteorder_ntohs(rtr_adv->ltime));
+    DEBUG("     - Reachable Time: %" PRIu32 "ms\n",
+          byteorder_ntohl(rtr_adv->reach_time));
+    DEBUG("     - Retrans Timer: %" PRIu32 "ms\n",
+          byteorder_ntohl(rtr_adv->retrans_timer));
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+    if (abro != NULL) {
+        if ((abr = _handle_abro(abro)) == NULL) {
+            DEBUG("nib: could not allocate space for new border router or "
+                  "there is no new information in the RA. "
+                  "Discarding silently\n");
+            return;
+        }
+        /* UINT16_MAX * 60 * 1000 < UINT32_MAX so there are no overflows */
+        next_timeout = _min(next_timeout,
+                            byteorder_ntohs(abro->ltime) * SEC_PER_MIN *
+                            MS_PER_SEC);
+    }
+#if !GNRC_IPV6_NIB_CONF_6LBR
+    else {
+        DEBUG("nib: multihop prefix and context dissemination activated,\n"
+              "     but no ABRO found. Discarding router advertisement silently\n");
+        return;
+    }
+#endif  /* !GNRC_IPV6_NIB_CONF_6LBR */
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+    if (rtr_adv->ltime.u16 != 0) {
+        dr = _nib_drl_add(&ipv6->src, netif->pid);
+        if (dr != NULL) {
+            dr->ltime = byteorder_ntohs(rtr_adv->ltime);
+        }
+        else {
+            DEBUG("nib: default router list is full. Ignoring RA from %s\n",
+                  ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
+            return;
+        }
+        /* UINT16_MAX * 1000 < UINT32_MAX so there are no overflows */
+        next_timeout = _min(next_timeout, dr->ltime * MS_PER_SEC);
+    }
+    else {
+        dr = _nib_drl_get(&ipv6->src, netif->pid);
+
+        DEBUG("nib: router lifetime was 0. Removing router and routes via it.");
+        if (dr != NULL) {
+            _handle_rtr_timeout(dr);
+        }
+        dr = NULL;
+    }
+    if (rtr_adv->cur_hl != 0) {
+        netif->cur_hl = rtr_adv->cur_hl;
+    }
+#if GNRC_IPV6_NIB_CONF_ARSM
+    if (rtr_adv->reach_time.u32 != 0) {
+        uint32_t reach_time = byteorder_ntohl(rtr_adv->reach_time);
+
+        if (reach_time != netif->ipv6.reach_time_base) {
+            _evtimer_add(netif, GNRC_IPV6_NIB_RECALC_REACH_TIME,
+                         &netif->ipv6.recalc_reach_time,
+                         GNRC_IPV6_NIB_CONF_REACH_TIME_RESET);
+            netif->ipv6.reach_time_base = reach_time;
+            _recalc_reach_time(&netif->ipv6);
+        }
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
+    if (rtr_adv->retrans_timer.u32 != 0) {
+        netif->ipv6.retrans_time = byteorder_ntohl(rtr_adv->retrans_timer);
+    }
+#if GNRC_IPV6_NIB_CONF_6LN
+    if ((dr != NULL) && gnrc_netif2_is_6ln(netif) &&
+        !gnrc_netif2_is_6lbr(netif) &&
+        !(netif->flags & GNRC_NETIF2_FLAGS_6LO_ADDRS_REG)) {
+        /* (register addresses already assigned)*/
+        for (int i = 0; i < GNRC_NETIF2_IPV6_ADDRS_NUMOF; i++) {
+            if ((netif->ipv6.addrs_flags[i] != 0)) {
+                _handle_rereg_address(&netif->ipv6.addrs[i]);
+            }
+        }
+        netif->flags |= GNRC_NETIF2_FLAGS_6LO_ADDRS_REG;
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+    tmp_len = icmpv6_len - sizeof(ndp_rtr_adv_t);
+    FOREACH_OPT(rtr_adv, opt, tmp_len) {
+        switch (opt->type) {
+            case NDP_OPT_SL2A:
+                _handle_sl2ao(netif, ipv6, (const icmpv6_hdr_t *)rtr_adv,
+                              opt);
+
+                break;
+            case NDP_OPT_MTU:
+                _handle_mtuo(netif, (const icmpv6_hdr_t *)rtr_adv,
+                             (ndp_opt_mtu_t *)opt);
+                break;
+            case NDP_OPT_PI: {
+                uint32_t min_pfx_timeout;
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+                min_pfx_timeout = _handle_pio(netif,
+                                              (const icmpv6_hdr_t *)rtr_adv,
+                                              (ndp_opt_pi_t *)opt, abr);
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+                min_pfx_timeout = _handle_pio(netif,
+                                              (const icmpv6_hdr_t *)rtr_adv,
+                                              (ndp_opt_pi_t *)opt);
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+                next_timeout = _min(next_timeout, min_pfx_timeout);
+                break;
+            }
+            /* ABRO was already secured in the option check above */
+#if GNRC_IPV6_NIB_CONF_6LN
+            case NDP_OPT_6CTX:
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+                next_timeout = _min(_handle_6co((icmpv6_hdr_t *)rtr_adv,
+                                                (sixlowpan_nd_opt_6ctx_t *)opt,
+                                                abr), next_timeout);
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+                next_timeout = _min(_handle_6co((icmpv6_hdr_t *)rtr_adv,
+                                                (sixlowpan_nd_opt_6ctx_t *)opt),
+                                    next_timeout);
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+                break;
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+            default:
+                break;
+        }
+    }
+    /* stop sending router solicitations
+     * see https://tools.ietf.org/html/rfc4861#section-6.3.7 */
+    evtimer_del(&_nib_evtimer, &netif->ipv6.search_rtr.event);
+#if GNRC_IPV6_NIB_CONF_6LN
+    if (gnrc_netif2_is_6ln(netif) && !gnrc_netif2_is_6lbr(netif)) {
+        _set_rtr_adv(netif);
+        /* but re-fetch information from router in time */
+        _evtimer_add(netif, GNRC_IPV6_NIB_SEARCH_RTR,
+                     &netif->ipv6.search_rtr, (next_timeout >> 2) * 3);
+        /* i.e. 3/4 of the time before the earliest expires */
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+}
+
 static inline size_t _get_l2src(const gnrc_netif2_t *netif, uint8_t *l2src)
 {
 #if GNRC_NETIF2_L2ADDR_MAXLEN > 0
     memcpy(l2src, netif->l2addr, netif->l2addr_len);
     return netif->l2addr_len;
-#else
+#else   /* GNRC_NETIF2_L2ADDR_MAXLEN > 0 */
     (void)netif;
     (void)l2src;
     return 0;
-#endif
+#endif  /* GNRC_NETIF2_L2ADDR_MAXLEN > 0 */
 }
 
 static void _send_delayed_nbr_adv(const gnrc_netif2_t *netif,
@@ -345,7 +728,7 @@ static void _send_delayed_nbr_adv(const gnrc_netif2_t *netif,
     if (gnrc_netif2_is_rtr(netif)) {
         reply_flags |= NDP_NBR_ADV_FLAGS_R;
     }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
 #if GNRC_NETIF2_L2ADDR_MAXLEN > 0
     if (ipv6_addr_is_multicast(dst)) {
         uint8_t l2addr[GNRC_NETIF2_L2ADDR_MAXLEN];
@@ -369,7 +752,7 @@ static void _send_delayed_nbr_adv(const gnrc_netif2_t *netif,
     }
 #else /* GNRC_NETIF2_L2ADDR_MAXLEN > 0 */
     reply_flags |= NDP_NBR_ADV_FLAGS_O;
-#endif
+#endif  /* GNRC_NETIF2_L2ADDR_MAXLEN > 0 */
     /* discard const qualifier */
     nbr_adv = gnrc_ndp2_nbr_adv_build(tgt, reply_flags, extra_opts);
     if (nbr_adv == NULL) {
@@ -382,8 +765,7 @@ static void _send_delayed_nbr_adv(const gnrc_netif2_t *netif,
         /* usually this should be the case, but when NCE is full, just
          * ignore the sending. Other nodes in this anycast group are
          * then preferred */
-        _evtimer_add(nce, GNRC_IPV6_NIB_SND_NA,
-                     &nce->snd_na,
+        _evtimer_add(nce, GNRC_IPV6_NIB_SND_NA, &nce->snd_na,
                      random_uint32_range(0, NDP_MAX_ANYCAST_MS_DELAY));
     }
 }
@@ -412,7 +794,7 @@ static void _handle_nbr_sol(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
         DEBUG("     - Source address: %s\n",
               ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
         DEBUG("     - Destination address: %s (should be of format "
-                      "ff02::1:ffxx:xxxx if source address is ::)\n",
+              "ff02::1:ffxx:xxxx if source address is ::)\n",
               ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
         return;
     }
@@ -484,6 +866,7 @@ static void _handle_nbr_sol(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                 default:
                     DEBUG("nib: Ignoring unrecognized option type %u for NS\n",
                           opt->type);
+                    break;
             }
         }
         reply_aro = _copy_and_handle_aro(netif, ipv6, nbr_sol, aro, sl2ao);
@@ -554,12 +937,12 @@ static void _handle_nbr_adv(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
           (nbr_adv->flags & NDP_NBR_ADV_FLAGS_O) ? 'O' : '-');
 #if GNRC_IPV6_NIB_CONF_SLAAC
     /* TODO SLAAC behavior */
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_SLAAC */
     if (((nce = _nib_onl_get(&nbr_adv->tgt, netif->pid)) != NULL) &&
         (nce->mode & _NC)) {
 #if GNRC_IPV6_NIB_CONF_ARSM
         bool tl2ao_avail = false;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
 
         tmp_len = icmpv6_len - sizeof(ndp_nbr_adv_t);
         FOREACH_OPT(nbr_adv, opt, tmp_len) {
@@ -569,13 +952,13 @@ static void _handle_nbr_adv(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                     _handle_adv_l2(netif, nce, (icmpv6_hdr_t *)nbr_adv, opt);
                     tl2ao_avail = true;
                     break;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
 #if GNRC_IPV6_NIB_CONF_6LN
                 case NDP_OPT_AR:
                     _handle_aro(netif, ipv6, (const icmpv6_hdr_t *)nbr_adv,
                                 (const sixlowpan_nd_opt_ar_t *)opt, opt, nce);
                     break;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
                 default:
                     DEBUG("nib: Ignoring unrecognized option type %u for NA\n",
                           opt->type);
@@ -590,7 +973,7 @@ static void _handle_nbr_adv(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
         if (!(netif->flags & GNRC_NETIF2_FLAGS_HAS_L2ADDR)) {
             _handle_adv_l2(netif, nce, (icmpv6_hdr_t *)nbr_adv, NULL);
         }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
     }
 }
 
@@ -606,7 +989,7 @@ static inline bool _is_reachable(_nib_onl_entry_t *entry)
             return true;
     }
 }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
 
 #if GNRC_IPV6_NIB_CONF_QUEUE_PKT
 static gnrc_pktqueue_t *_alloc_queue_entry(gnrc_pktsnip_t *pkt)
@@ -619,13 +1002,14 @@ static gnrc_pktqueue_t *_alloc_queue_entry(gnrc_pktsnip_t *pkt)
     }
     return NULL;
 }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_QUEUE_PKT */
 
 static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
                           gnrc_pktsnip_t *pkt, gnrc_ipv6_nib_nc_t *nce,
                           _nib_onl_entry_t *entry)
 {
     bool res = false;
+
     if ((netif != NULL) && (netif->device_type == NETDEV_TYPE_SLIP)) {
         /* XXX: Linux doesn't do neighbor discovery for SLIP so no use sending
          * NS and since SLIP doesn't have link-layer addresses anyway, we can
@@ -648,7 +1032,7 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
         _nib_nc_get(entry, nce);
         res = true;
     }
-#else
+#else   /* GNRC_IPV6_NIB_CONF_ARSM */
     if (entry != NULL) {
         DEBUG("nib: resolve address %s%%%u from neighbor cache\n",
               ipv6_addr_to_str(addr_str, &entry->ipv6, sizeof(addr_str)),
@@ -656,11 +1040,11 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
         _nib_nc_get(entry, nce);
         res = true;
     }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
     else if (!(res = _resolve_addr_from_ipv6(dst, netif, nce))) {
 #if GNRC_IPV6_NIB_CONF_ARSM
         bool reset = false;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
 
         DEBUG("nib: resolve address %s by probing neighbors\n",
               ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
@@ -671,14 +1055,16 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
                 return false;
             }
 #if GNRC_IPV6_NIB_CONF_ROUTER
-            if ((netif != NULL) && (netif->ipv6.route_info_cb != NULL)) {
-                netif->ipv6.route_info_cb(GNRC_IPV6_NIB_ROUTE_INFO_TYPE_NSC,
-                      dst, (void *)GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE);
+            if (netif != NULL) {
+                _call_route_info_cb(netif,
+                                    GNRC_IPV6_NIB_ROUTE_INFO_TYPE_NSC,
+                                    dst,
+                                    (void *)GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE);
             }
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
 #if GNRC_IPV6_NIB_CONF_ARSM
             reset = true;
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
         }
         if (pkt != NULL) {
 #if GNRC_IPV6_NIB_CONF_QUEUE_PKT
@@ -698,7 +1084,7 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
         }
 #if GNRC_IPV6_NIB_CONF_ARSM
         _probe_nbr(entry, reset);
-#endif
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
     }
     return res;
 }
@@ -712,10 +1098,257 @@ static void _handle_snd_na(gnrc_pktsnip_t *pkt)
         DEBUG("nib: No receivers for neighbor advertisement\n");
         gnrc_pktbuf_release_error(pkt, EBADF);
     }
-#else
+#else   /* MODULE_GNRC_IPV6 */
     (void)pkt;
     DEBUG("nib: No IPv6 module to send delayed neighbor advertisement\n");
-#endif
+#endif  /* MODULE_GNRC_IPV6 */
+}
+
+static void _handle_pfx_timeout(_nib_offl_entry_t *pfx)
+{
+    gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(_nib_onl_get_if(pfx->next_hop));
+    uint32_t now = (xtimer_now_usec64() / US_PER_MS) & UINT32_MAX;
+
+    gnrc_netif2_acquire(netif);
+    if (now >= pfx->valid_until) {
+        evtimer_del(&_nib_evtimer, &pfx->pfx_timeout.event);
+        for (int i = 0; i < GNRC_NETIF2_IPV6_ADDRS_NUMOF; i++) {
+            if (ipv6_addr_match_prefix(&netif->ipv6.addrs[i],
+                                       &pfx->pfx) >= pfx->pfx_len) {
+                gnrc_netif2_ipv6_addr_remove(netif, &netif->ipv6.addrs[i]);
+            }
+        }
+        pfx->mode &= ~_PL;
+        _nib_offl_clear(pfx);
+    }
+    else if (now >= pfx->pref_until) {
+        for (int i = 0; i < GNRC_NETIF2_IPV6_ADDRS_NUMOF; i++) {
+            if (ipv6_addr_match_prefix(&netif->ipv6.addrs[i],
+                                       &pfx->pfx) >= pfx->pfx_len) {
+                netif->ipv6.addrs_flags[i] &= ~GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_MASK;
+                netif->ipv6.addrs_flags[i] |= GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_DEPRECATED;
+            }
+        }
+        _evtimer_add(pfx, GNRC_IPV6_NIB_PFX_TIMEOUT, &pfx->pfx_timeout,
+                     pfx->valid_until - now);
+    }
+    gnrc_netif2_release(netif);
+}
+
+static void _handle_rtr_timeout(_nib_dr_entry_t *router)
+{
+    if ((router->next_hop != NULL) && (router->next_hop->mode & _DRL)) {
+        _nib_offl_entry_t *route = NULL;
+        unsigned iface = _nib_onl_get_if(router->next_hop);
+        ipv6_addr_t addr;
+
+        memcpy(&addr, &router->next_hop, sizeof(addr));
+        _nib_drl_remove(router);
+        /* also remove all routes to that router */
+        while ((route = _nib_offl_iter(route))) {
+            if ((route->next_hop != NULL) &&
+                (_nib_onl_get_if(route->next_hop) == iface) &&
+                (ipv6_addr_equal(&route->next_hop->ipv6, &addr))) {
+                route->mode = _EMPTY;
+                route->next_hop->mode &= ~_DST;
+                _nib_offl_clear(route);
+                /* XXX routing protocol get's informed in case NUD
+                 * determines ipv6->src (still in neighbor cache) to be
+                 * unreachable */
+            }
+        }
+    }
+}
+
+void _handle_search_rtr(gnrc_netif2_t *netif)
+{
+    gnrc_netif2_acquire(netif);
+    if (!(gnrc_netif2_is_rtr_adv(netif)) || gnrc_netif2_is_6ln(netif)) {
+        uint32_t next_rs = _evtimer_lookup(netif, GNRC_IPV6_NIB_SEARCH_RTR);
+        uint32_t interval = _get_next_rs_interval(netif);
+
+        if (next_rs > interval) {
+            gnrc_ndp2_rtr_sol_send(netif, &ipv6_addr_all_routers_link_local);
+            if (netif->ipv6.rs_sent < 10U) {
+                /* with more the backoff (required in RFC 6775) is truncated
+                 * anyway and this way we prevent overflows. 10 is arbitrary, so
+                 * we do not need a define here */
+                netif->ipv6.rs_sent++;
+            }
+            if ((netif->ipv6.rs_sent < NDP_MAX_RS_NUMOF) ||
+                gnrc_netif2_is_6ln(netif)) {
+                /* 6LN will solicitate indefinitely */
+                _evtimer_add(netif, GNRC_IPV6_NIB_SEARCH_RTR,
+                             &netif->ipv6.search_rtr, interval);
+            }
+        }
+    }
+    gnrc_netif2_release(netif);
+}
+
+static void _handle_mtuo(gnrc_netif2_t *netif, const icmpv6_hdr_t *icmpv6,
+                         const ndp_opt_mtu_t *mtuo)
+{
+    if ((mtuo->len != NDP_OPT_MTU_LEN) || (icmpv6->type != ICMPV6_RTR_ADV)) {
+        return;
+    }
+    if (byteorder_ntohl(mtuo->mtu) >= IPV6_MIN_MTU) {
+        netif->ipv6.mtu = byteorder_ntohl(mtuo->mtu);
+    }
+}
+
+static void _remove_prefix(const ipv6_addr_t *pfx, unsigned pfx_len)
+{
+    _nib_offl_entry_t *offl = NULL;
+
+    while ((offl = _nib_offl_iter(offl))) {
+        if ((offl->mode & _PL) &&
+            (offl->pfx_len == pfx_len) &&
+            (ipv6_addr_match_prefix(&offl->pfx, pfx) >= pfx_len)) {
+            _nib_pl_remove(offl);
+        }
+    }
+    return;
+}
+
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+static uint32_t _handle_pio(gnrc_netif2_t *netif, const icmpv6_hdr_t *icmpv6,
+                            const ndp_opt_pi_t *pio, _nib_abr_entry_t *abr)
+#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+static uint32_t _handle_pio(gnrc_netif2_t *netif, const icmpv6_hdr_t *icmpv6,
+                            const ndp_opt_pi_t *pio)
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+{
+    uint32_t valid_ltime;
+    uint32_t pref_ltime;
+
+    valid_ltime = byteorder_ntohl(pio->valid_ltime);
+    pref_ltime = byteorder_ntohl(pio->pref_ltime);
+    if ((pio->len != NDP_OPT_PI_LEN) || (icmpv6->type != ICMPV6_RTR_ADV) ||
+        ipv6_addr_is_link_local(&pio->prefix) || (valid_ltime < pref_ltime)) {
+        DEBUG("nib: ignoring PIO with invalid data\n");
+        return UINT32_MAX;
+    }
+    DEBUG("nib: received valid Prefix Information option:\n");
+    DEBUG("     - Prefix: %s/%u\n",
+          ipv6_addr_to_str(addr_str, &pio->prefix, sizeof(addr_str)),
+          pio->prefix_len);
+    DEBUG("     - Flags: %c%c\n",
+          (pio->flags & NDP_OPT_PI_FLAGS_L) ? 'L' : '-',
+          (pio->flags & NDP_OPT_PI_FLAGS_A) ? 'A' : '-');
+    DEBUG("     - Valid lifetime: %" PRIu32 "\n",
+          byteorder_ntohl(pio->valid_ltime));
+    DEBUG("     - Preferred lifetime: %" PRIu32 "\n",
+          byteorder_ntohl(pio->pref_ltime));
+
+#if GNRC_IPV6_NIB_CONF_SLAAC || GNRC_IPV6_NIB_CONF_6LN
+    if (pio->flags & NDP_OPT_PI_FLAGS_A) {
+        _auto_configure_addr(netif, &pio->prefix, pio->prefix_len);
+    }
+#endif /* GNRC_IPV6_NIB_CONF_SLAAC || GNRC_IPV6_NIB_CONF_6LN */
+    if ((pio->flags & NDP_OPT_PI_FLAGS_L) || gnrc_netif2_is_6lr(netif)) {
+        _nib_offl_entry_t *pfx;
+
+        if (pio->valid_ltime.u32 == 0) {
+            DEBUG("nib: PIO for %s/%u with lifetime 0. Removing prefix.\n",
+                  ipv6_addr_to_str(addr_str, &pio->prefix, sizeof(addr_str)),
+                  pio->prefix_len);
+            _remove_prefix(&pio->prefix, pio->prefix_len);
+            return UINT32_MAX;
+        }
+
+        if (valid_ltime < UINT32_MAX) { /* UINT32_MAX means infinite lifetime */
+            /* the valid lifetime is given in seconds, but our timers work in
+             * microseconds, so we have to scale down to the smallest possible
+             * value (UINT32_MAX). This is however alright since we ask for a
+             * new router advertisement before this timeout expires */
+            valid_ltime = (valid_ltime > (UINT32_MAX / MS_PER_SEC)) ?
+                          UINT32_MAX : valid_ltime * MS_PER_SEC;
+        }
+        if (pref_ltime < UINT32_MAX) { /* UINT32_MAX means infinite lifetime */
+            /* same treatment for pref_ltime */
+            pref_ltime = (pref_ltime > (UINT32_MAX / MS_PER_SEC)) ?
+                         UINT32_MAX : pref_ltime * MS_PER_SEC;
+        }
+        if ((pfx = _nib_pl_add(netif->pid, &pio->prefix, pio->prefix_len,
+                               valid_ltime, pref_ltime))) {
+#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+            assert(abr != NULL);    /* should have been set in _handle_abro() */
+            _nib_abr_add_pfx(abr, pfx);
+#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
+            if (pio->flags & NDP_OPT_PI_FLAGS_L) {
+                pfx->flags |= _PFX_ON_LINK;
+            }
+            if (pio->flags & NDP_OPT_PI_FLAGS_A) {
+                pfx->flags |= _PFX_SLAAC;
+            }
+            return _min(pref_ltime, valid_ltime);
+        }
+    }
+    return UINT32_MAX;
+}
+
+#if GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC
+static void _auto_configure_addr(gnrc_netif2_t *netif, const ipv6_addr_t *pfx,
+                                 uint8_t pfx_len)
+{
+    ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED;
+    int idx;
+    uint8_t flags = GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_TENTATIVE;
+
+    DEBUG("nib: add address based on %s/%u automatically to interface %u\n",
+          ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)),
+          pfx_len, netif->pid);
+#if GNRC_IPV6_NIB_CONF_6LN
+    bool new_address = false;
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+    gnrc_netif2_ipv6_get_iid(netif, (eui64_t *)&addr.u64[1]);
+    ipv6_addr_init_prefix(&addr, pfx, pfx_len);
+    if ((idx = gnrc_netif2_ipv6_addr_idx(netif, &addr)) < 0) {
+        if ((idx = gnrc_netif2_ipv6_addr_add(netif, &addr, pfx_len, flags)) < 0) {
+            DEBUG("nib: Can't add link-local address on interface %u\n",
+                  netif->pid);
+            return;
+        }
+#if GNRC_IPV6_NIB_CONF_6LN
+        new_address = true;
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+    }
+
+#if GNRC_IPV6_NIB_CONF_6LN
+    if (gnrc_netif2_is_6ln(netif)) {
+        /* don't do this beforehand or risk a deadlock:
+         *  * gnrc_netif2_ipv6_addr_add() adds VALID (i.e. manually configured
+         *    addresses to the prefix list locking the NIB's mutex which is already
+         *    locked here) */
+        netif->ipv6.addrs_flags[idx] &= ~GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_MASK;
+        netif->ipv6.addrs_flags[idx] |= GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_VALID;
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+    (void)idx;
+    /* TODO: make this line conditional on 6LN when there is a SLAAC
+     * implementation */
+#if GNRC_IPV6_NIB_CONF_ARSM
+    /* TODO: SHOULD delay join between 0 and MAX_RTR_SOLICITATION_DELAY
+     * for SLAAC */
+    ipv6_addr_set_solicited_nodes(&addr, &addr);
+    if (gnrc_netif2_ipv6_group_join(netif, &addr) < 0) {
+        DEBUG("nib: Can't join solicited-nodes of link-local address on "
+              "interface %u\n", netif->pid);
+        return;
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_ARSM */
+#if GNRC_IPV6_NIB_CONF_6LN
+    if (new_address && gnrc_netif2_is_6ln(netif) &&
+        !gnrc_netif2_is_6lbr(netif)) {
+        _handle_rereg_address(&netif->ipv6.addrs[idx]);
+    }
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+#if GNRC_IPV6_NIB_CONF_SLAAC
+    /* TODO send NS to solicited nodes and wait netif->ipv6.retrans_time to
+     * confirm uniqueness of the link-local address */
+#endif  /* GNRC_IPV6_NIB_CONF_SLAAC */
 }
+#endif  /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */
 
 /** @} */
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c b/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c
index 125582a2a7164f040fdf58c8384ad36214ef19fb..49abce66a5d633dcc872ac7e565e64ebf509b806 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c
@@ -18,10 +18,12 @@
 #include <stdio.h>
 
 #include "net/gnrc/ipv6/nib/pl.h"
+#include "net/gnrc/netif2/internal.h"
 #include "timex.h"
 #include "xtimer.h"
 
 #include "_nib-internal.h"
+#include "_nib-router.h"
 
 int gnrc_ipv6_nib_pl_set(unsigned iface,
                          const ipv6_addr_t *pfx, unsigned pfx_len,
@@ -47,8 +49,40 @@ int gnrc_ipv6_nib_pl_set(unsigned iface,
     if (dst == NULL) {
         res = -ENOMEM;
     }
+#ifdef MODULE_GNRC_NETIF2
+    gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(iface);
+    int idx;
+
+    if (netif == NULL) {
+        mutex_unlock(&_nib_mutex);
+        return res;
+    }
+    gnrc_netif2_acquire(netif);
+    if (!gnrc_netif2_is_6ln(netif) &&
+        ((idx = gnrc_netif2_ipv6_addr_match(netif, pfx)) >= 0) &&
+        (ipv6_addr_match_prefix(&netif->ipv6.addrs[idx], pfx) >= pfx_len)) {
+        dst->flags |= _PFX_ON_LINK;
+    }
+    if (netif->ipv6.aac_mode == GNRC_NETIF2_AAC_AUTO) {
+        dst->flags |= _PFX_SLAAC;
+    }
+#if GNRC_IPV6_NIB_CONF_6LBR && GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
+    if (gnrc_netif2_is_6lbr(netif)) {
+        _nib_abr_entry_t *abr = NULL;
+
+        while ((abr = _nib_abr_iter(abr))) {
+            abr->version++;
+            _nib_abr_add_pfx(abr, dst);
+        }
+    }
+#endif
+    gnrc_netif2_release(netif);
+#endif  /* MODULE_GNRC_NETIF2 */
     mutex_unlock(&_nib_mutex);
-    /* TODO: send RA with PIO, if iface is allowed to send RAs */
+#if defined(MODULE_GNRC_NETIF2) && GNRC_IPV6_NIB_CONF_ROUTER
+    /* update prefixes down-stream */
+    _handle_snd_mc_ra(netif);
+#endif
     return res;
 }
 
@@ -66,7 +100,14 @@ void gnrc_ipv6_nib_pl_del(unsigned iface,
             (ipv6_addr_match_prefix(pfx, &dst->pfx) >= pfx_len)) {
             _nib_pl_remove(dst);
             mutex_unlock(&_nib_mutex);
-            /* TODO: send RA with PIO, if iface is allowed to send RAs */
+#if GNRC_IPV6_NIB_CONF_ROUTER
+            gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(iface);
+
+            if (netif) {
+                /* update prefixes down-stream */
+                _handle_snd_mc_ra(netif);
+            }
+#endif
             return;
         }
     }
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
index 42f60163f1238f99843a7d15a9f61ae0db9bc7c7..7b3526051afbc7abd8f81ab1aaf0ee6fb4821e49 100644
--- a/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c
+++ b/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c
@@ -42,6 +42,42 @@ gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_ar_build(uint8_t status, uint16_t ltime, e
     return pkt;
 }
 
-/* gnrc_sixlowpan_nd_opt_abr_handle etc. implemented in gnrc_sixlowpan_nd_router */
+gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_6ctx_build(uint8_t prefix_len, uint8_t flags, uint16_t ltime,
+                                                 ipv6_addr_t *prefix, gnrc_pktsnip_t *next)
+{
+    gnrc_pktsnip_t *pkt = gnrc_ndp2_opt_build(NDP_OPT_6CTX,
+                                             sizeof(sixlowpan_nd_opt_6ctx_t) + (prefix_len / 8),
+                                             next);
+
+    if (pkt != NULL) {
+        sixlowpan_nd_opt_6ctx_t *ctx_opt = pkt->data;
+        ctx_opt->ctx_len = prefix_len;
+        ctx_opt->resv_c_cid = flags;
+        ctx_opt->resv.u16 = 0;
+        ctx_opt->ltime = byteorder_htons(ltime);
+        /* Bits beyond prefix_len MUST be 0 */
+        memset(ctx_opt + 1, 0, pkt->size - sizeof(sixlowpan_nd_opt_6ctx_t));
+        ipv6_addr_init_prefix((ipv6_addr_t *)(ctx_opt + 1), prefix, prefix_len);
+    }
+
+    return pkt;
+}
+
+gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_abr_build(uint32_t version, uint16_t ltime,
+                                                ipv6_addr_t *braddr, gnrc_pktsnip_t *next)
+{
+    gnrc_pktsnip_t *pkt = gnrc_ndp2_opt_build(NDP_OPT_ABR, sizeof(sixlowpan_nd_opt_abr_t), next);
+
+    if (pkt != NULL) {
+        sixlowpan_nd_opt_abr_t *abr_opt = pkt->data;
+        abr_opt->vlow = byteorder_htons(version & 0xffff);
+        abr_opt->vhigh = byteorder_htons(version >> 16);
+        abr_opt->ltime = byteorder_htons(ltime);
+        abr_opt->braddr.u64[0] = braddr->u64[0];
+        abr_opt->braddr.u64[1] = braddr->u64[1];
+    }
+
+    return pkt;
+}
 
 /** @} */
diff --git a/sys/net/gnrc/network_layer/sixlowpan/nd/router/gnrc_sixlowpan_nd_router.c b/sys/net/gnrc/network_layer/sixlowpan/nd/router/gnrc_sixlowpan_nd_router.c
index 9c933ac7527373ffa44e2b64b1b30067eb21ad6e..2b5eb055d96076b20f0e5baed578d549a51d1de0 100644
--- a/sys/net/gnrc/network_layer/sixlowpan/nd/router/gnrc_sixlowpan_nd_router.c
+++ b/sys/net/gnrc/network_layer/sixlowpan/nd/router/gnrc_sixlowpan_nd_router.c
@@ -22,41 +22,4 @@
 
 #include "net/gnrc/sixlowpan/nd/router.h"
 
-gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_6ctx_build(uint8_t prefix_len, uint8_t flags, uint16_t ltime,
-                                                 ipv6_addr_t *prefix, gnrc_pktsnip_t *next)
-{
-    gnrc_pktsnip_t *pkt = gnrc_ndp2_opt_build(NDP_OPT_6CTX,
-                                             sizeof(sixlowpan_nd_opt_6ctx_t) + (prefix_len / 8),
-                                             next);
-
-    if (pkt != NULL) {
-        sixlowpan_nd_opt_6ctx_t *ctx_opt = pkt->data;
-        ctx_opt->ctx_len = prefix_len;
-        ctx_opt->resv_c_cid = flags;
-        ctx_opt->resv.u16 = 0;
-        ctx_opt->ltime = byteorder_htons(ltime);
-        /* Bits beyond prefix_len MUST be 0 */
-        memset(ctx_opt + 1, 0, pkt->size - sizeof(sixlowpan_nd_opt_6ctx_t));
-        ipv6_addr_init_prefix((ipv6_addr_t *)(ctx_opt + 1), prefix, prefix_len);
-    }
-
-    return pkt;
-}
-
-gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_abr_build(uint32_t version, uint16_t ltime,
-                                                ipv6_addr_t *braddr, gnrc_pktsnip_t *next)
-{
-    gnrc_pktsnip_t *pkt = gnrc_ndp2_opt_build(NDP_OPT_ABR, sizeof(sixlowpan_nd_opt_abr_t), next);
-
-    if (pkt != NULL) {
-        sixlowpan_nd_opt_abr_t *abr_opt = pkt->data;
-        abr_opt->vlow = byteorder_htons(version & 0xffff);
-        abr_opt->vhigh = byteorder_htons(version >> 16);
-        abr_opt->ltime = byteorder_htons(ltime);
-        abr_opt->braddr.u64[0] = braddr->u64[0];
-        abr_opt->braddr.u64[1] = braddr->u64[1];
-    }
-
-    return pkt;
-}
 /** @} */
diff --git a/tests/driver_enc28j60/Makefile b/tests/driver_enc28j60/Makefile
index df44329a4edc662478c1dd6da4f5d5c6433c030b..2628a8b292b38248a93fd38d23212d3e3ee44fb2 100644
--- a/tests/driver_enc28j60/Makefile
+++ b/tests/driver_enc28j60/Makefile
@@ -5,7 +5,7 @@ FEATURES_REQUIRED = periph_spi periph_gpio
 
 BOARD_INSUFFICIENT_MEMORY := msb-430 msb-430h nucleo32-f031 nucleo32-f042 \
                              nucleo32-l031 nucleo-f334 nucleo-l053 \
-                             stm32f0discovery telosb z1
+                             stm32f0discovery telosb wsn430-v1_3b wsn430-v1_4 z1
 
 USEMODULE += gnrc_netdev_default
 USEMODULE += auto_init_gnrc_netif
diff --git a/tests/driver_encx24j600/Makefile b/tests/driver_encx24j600/Makefile
index 8aa520540a61a052621cc5c33a3d5449dac5dc2c..b5ce8a03da06ead4b06766fc4367d2d524bb75aa 100644
--- a/tests/driver_encx24j600/Makefile
+++ b/tests/driver_encx24j600/Makefile
@@ -5,7 +5,7 @@ FEATURES_REQUIRED = periph_spi periph_gpio
 
 BOARD_INSUFFICIENT_MEMORY := msb-430 msb-430h nucleo32-f031 nucleo32-f042 \
                              nucleo32-l031 nucleo-l053 stm32f0discovery telosb \
-                             z1
+                             wsn430-v1_3b wsn430-v1_4 z1
 
 USEMODULE += gnrc_netdev_default
 USEMODULE += auto_init_gnrc_netif
diff --git a/tests/gnrc_ipv6_nib/Makefile b/tests/gnrc_ipv6_nib/Makefile
index c11f93011d95c3f5a04a89b8147ee1362ce361ee..908369ad8d138f7ed8fc8fe8ef29dd777eb342af 100644
--- a/tests/gnrc_ipv6_nib/Makefile
+++ b/tests/gnrc_ipv6_nib/Makefile
@@ -2,7 +2,8 @@
 APPLICATION = gnrc_ipv6_nib
 include ../Makefile.tests_common
 
-BOARD_INSUFFICIENT_MEMORY := chronos nucleo32-f031 nucleo32-f042 nucleo32-l031
+BOARD_INSUFFICIENT_MEMORY := chronos nucleo32-f031 nucleo32-f042 nucleo32-l031 \
+                             telosb wsn430-v1_3b wsn430-v1_4
 
 USEMODULE += gnrc_ipv6
 USEMODULE += gnrc_ipv6_nib
diff --git a/tests/gnrc_ipv6_nib/main.c b/tests/gnrc_ipv6_nib/main.c
index 68e90aeb64ef762054ecdde3ec077e65acf0e757..a1ee3c8fc553b3cf827759b3aef24c76d686c155 100644
--- a/tests/gnrc_ipv6_nib/main.c
+++ b/tests/gnrc_ipv6_nib/main.c
@@ -29,16 +29,28 @@
 #include "net/gnrc.h"
 #include "net/gnrc/ipv6/nib.h"
 #include "net/gnrc/ipv6/nib/nc.h"
+#include "net/gnrc/netif2/internal.h"
 #include "net/ndp.h"
 #include "sched.h"
 
 #define _BUFFER_SIZE    (128)
+#define _CUR_HL         (155)
+#define _RTR_LTIME      (6612U)
+#define _REACH_TIME     (1210388825UL)
+#define _RETRANS_TIMER  (3691140UL)
+#define _LOC_GB_PFX_LEN (45U)
+#define _REM_GB_PFX_LEN (37U)
+#define _PIO_PFX_LTIME  (0x8476fedf)
 
 static const uint8_t _loc_l2[] = { _LL0, _LL1, _LL2, _LL3, _LL4, _LL5 };
 static const ipv6_addr_t _loc_ll = { {
                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             _LL0 ^ 2, _LL1, _LL2, 0xff, 0xfe, _LL3, _LL4, _LL5
         } };
+static const ipv6_addr_t _loc_gb = { {
+                0x20, 0x01, 0x2b, 0x2e, 0x43, 0x80, 0x00, 0x00,
+            _LL0 ^ 2, _LL1, _LL2, 0xff, 0xfe, _LL3, _LL4, _LL5
+        } };
 static const ipv6_addr_t _loc_sol_nodes = { {
             0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x01, 0xff, _LL3, _LL4, _LL5
@@ -49,6 +61,10 @@ static const ipv6_addr_t _rem_ll = { {
                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             _LL0 ^ 2, _LL1, _LL2, 0xff, 0xfe, _LL3, _LL4, _LL5 + 1
         } };
+static const ipv6_addr_t _rem_gb = { {
+                0x20, 0x01, 0x18, 0xc9, 0xf8, 0x00, 0x00, 0x00,
+            _LL0 ^ 2, _LL1, _LL2, 0xff, 0xfe, _LL3, _LL4, _LL5 + 1
+        } };
 #define _rem_iid    _rem_ll.u64[1].u8
 static uint8_t _buffer[_BUFFER_SIZE];
 static ipv6_hdr_t *ipv6 = (ipv6_hdr_t *)&_buffer[0];
@@ -59,6 +75,12 @@ static inline size_t ceil8(size_t size);
 static void _set_up(void)
 {
     _common_set_up();
+    gnrc_netif2_acquire(_mock_netif);
+    /* reset some fields not set by the nib interface initializer */
+    _mock_netif->ipv6.mtu = ETHERNET_DATA_LEN;
+    _mock_netif->cur_hl = GNRC_NETIF2_DEFAULT_HL;
+    gnrc_netif2_ipv6_addr_remove(_mock_netif, &_loc_gb);
+    gnrc_netif2_release(_mock_netif);
     memset(_buffer, 0, sizeof(_buffer));
     gnrc_pktbuf_init();
     /* remove messages */
@@ -68,24 +90,42 @@ static void _set_up(void)
     }
 }
 
-static void test_get_next_hop_l2addr__link_local_EHOSTUNREACH(gnrc_netif2_t *netif)
+static void test_get_next_hop_l2addr__EHOSTUNREACH(const ipv6_addr_t *dst,
+                                                   gnrc_netif2_t *netif,
+                                                   bool on_link)
 {
+    ipv6_addr_t addr;
     msg_t msg;
     gnrc_ipv6_nib_nc_t nce;
     void *state = NULL;
     gnrc_pktsnip_t *pkt;
 
+    memcpy(&addr, &_rem_gb, sizeof(addr));
+    addr.u8[15]--;
+    if (ipv6_addr_is_link_local(dst)) {
+        on_link = true;
+    }
+    else if (on_link) {
+        /* add _rem_gb prefix as on-link prefix */
+        TEST_ASSERT(gnrc_netif2_ipv6_addr_add(_mock_netif, &addr,
+                            _REM_GB_PFX_LEN,
+                            GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_VALID) >= 0);
+    }
+    else {
+        TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(NULL, 0, &_rem_ll,
+                                                      _mock_netif->pid));
+    }
     TEST_ASSERT_EQUAL_INT(-EHOSTUNREACH,
-                          gnrc_ipv6_nib_get_next_hop_l2addr(&_rem_ll, netif,
+                          gnrc_ipv6_nib_get_next_hop_l2addr(dst, netif,
                                                             NULL, &nce));
-    if (netif != NULL) {
+    if (on_link && (netif != NULL)) {
         ndp_nbr_sol_t *nbr_sol;
         bool contains_sl2ao = false;
 
         TEST_ASSERT_MESSAGE(gnrc_ipv6_nib_nc_iter(0, &state, &nce),
                             "Expected neighbor cache entry");
-        TEST_ASSERT_MESSAGE(ipv6_addr_equal(&_rem_ll, &nce.ipv6),
-                            "_rem_ll != nce->ipv6");
+        TEST_ASSERT_MESSAGE(ipv6_addr_equal(dst, &nce.ipv6),
+                            "dst != nce->ipv6");
         TEST_ASSERT_EQUAL_INT(0, nce.l2addr_len);
         TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE,
                               gnrc_ipv6_nib_nc_get_nud_state(&nce));
@@ -118,16 +158,46 @@ static void test_get_next_hop_l2addr__link_local_EHOSTUNREACH(gnrc_netif2_t *net
         gnrc_pktbuf_release(pkt);
         TEST_ASSERT(gnrc_pktbuf_is_empty());
     }
+    gnrc_netif2_ipv6_addr_remove(_mock_netif, &addr);
 }
 
 static void test_get_next_hop_l2addr__link_local_EHOSTUNREACH_no_iface(void)
 {
-    test_get_next_hop_l2addr__link_local_EHOSTUNREACH(NULL);
+    test_get_next_hop_l2addr__EHOSTUNREACH(&_rem_ll, NULL, false);
 }
 
 static void test_get_next_hop_l2addr__link_local_EHOSTUNREACH_iface(void)
 {
-    test_get_next_hop_l2addr__link_local_EHOSTUNREACH(_mock_netif);
+    test_get_next_hop_l2addr__EHOSTUNREACH(&_rem_ll, _mock_netif, false);
+}
+
+static void test_get_next_hop_l2addr__global_EHOSTUNREACH_no_iface_off_link(void)
+{
+    test_get_next_hop_l2addr__EHOSTUNREACH(&_rem_gb, NULL, false);
+}
+
+static void test_get_next_hop_l2addr__global_EHOSTUNREACH_iface_off_link(void)
+{
+    test_get_next_hop_l2addr__EHOSTUNREACH(&_rem_gb, _mock_netif, false);
+}
+
+static void test_get_next_hop_l2addr__global_EHOSTUNREACH_no_iface_on_link(void)
+{
+    test_get_next_hop_l2addr__EHOSTUNREACH(&_rem_gb, NULL, true);
+}
+
+static void test_get_next_hop_l2addr__global_EHOSTUNREACH_iface_on_link(void)
+{
+    test_get_next_hop_l2addr__EHOSTUNREACH(&_rem_gb, _mock_netif, true);
+}
+
+static void test_get_next_hop_l2addr__ENETUNREACH(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+
+    TEST_ASSERT_EQUAL_INT(-ENETUNREACH,
+                          gnrc_ipv6_nib_get_next_hop_l2addr(&_rem_gb, NULL,
+                                                            NULL, &nce));
 }
 
 static void test_get_next_hop_l2addr__link_local_static_conf(void)
@@ -682,6 +752,470 @@ static void test_handle_pkt__nbr_adv__unsolicited(void)
     TEST_ASSERT_EQUAL_INT(0, msg_avail());
 }
 
+static size_t _set_rtr_sol(const ipv6_addr_t *ipv6_src,
+                           const ipv6_addr_t *ipv6_dst,
+                           uint8_t ipv6_hl, uint8_t rtr_sol_code,
+                           const uint8_t *sl2ao_addr, size_t sl2ao_addr_len)
+{
+    size_t icmpv6_len = sizeof(ndp_rtr_sol_t);
+    ndp_rtr_sol_t *rtr_sol = (ndp_rtr_sol_t *)icmpv6;
+
+    ipv6_hdr_set_version(ipv6);
+    ipv6->hl = ipv6_hl;
+    memcpy(&ipv6->src, ipv6_src, sizeof(ipv6->src));
+    memcpy(&ipv6->dst, ipv6_dst, sizeof(ipv6->dst));
+    rtr_sol->type = ICMPV6_RTR_SOL;
+    rtr_sol->code = rtr_sol_code;
+
+    if ((sl2ao_addr != NULL) && (sl2ao_addr_len > 0)) {
+        ndp_opt_t *sl2ao = (ndp_opt_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                 sizeof(ndp_rtr_sol_t)];
+
+        sl2ao->type = NDP_OPT_SL2A;
+        sl2ao->len = ceil8(sizeof(ndp_opt_t) + sl2ao_addr_len) / 8;
+        memcpy(sl2ao + 1, sl2ao_addr, sl2ao_addr_len);
+        icmpv6_len += ceil8(sizeof(ndp_opt_t) + sl2ao_addr_len);
+    }
+
+    return icmpv6_len;
+}
+
+static void test_handle_pkt__rtr_sol(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_sol(&_rem_ll, &_loc_ll,
+                                     255U, 0U, _rem_l2, sizeof(_rem_l2));
+
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static size_t _set_rtr_adv(const ipv6_addr_t *ipv6_src,
+                           uint8_t ipv6_hl, uint8_t rtr_adv_code,
+                           bool set_rtr_adv_fields,
+                           uint8_t rtr_adv_flags,
+                           const uint8_t *sl2ao_addr, size_t sl2ao_addr_len,
+                           uint16_t mtu,
+                           const ipv6_addr_t *pfx, unsigned pfx_len,
+                           uint8_t pfx_flags)
+{
+    size_t icmpv6_len = sizeof(ndp_rtr_adv_t);
+    ndp_rtr_adv_t *rtr_adv = (ndp_rtr_adv_t *)icmpv6;
+
+    ipv6_hdr_set_version(ipv6);
+    ipv6->hl = ipv6_hl;
+    memcpy(&ipv6->src, ipv6_src, sizeof(ipv6->src));
+    memcpy(&ipv6->dst, &_loc_ll, sizeof(ipv6->dst));
+    rtr_adv->type = ICMPV6_RTR_ADV;
+    rtr_adv->code = rtr_adv_code;
+    rtr_adv->flags = rtr_adv_flags;
+    if (set_rtr_adv_fields) {
+        rtr_adv->cur_hl = _CUR_HL,
+        rtr_adv->ltime = byteorder_htons(_RTR_LTIME);
+        rtr_adv->reach_time = byteorder_htonl(_REACH_TIME);
+        rtr_adv->retrans_timer = byteorder_htonl(_RETRANS_TIMER);
+    }
+
+    if (mtu > 0) {
+        ndp_opt_mtu_t *mtuo = (ndp_opt_mtu_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                        icmpv6_len];
+
+        mtuo->type = NDP_OPT_MTU;
+        mtuo->len = NDP_OPT_MTU_LEN;
+        mtuo->mtu = byteorder_htonl(mtu);
+        icmpv6_len += sizeof(ndp_opt_mtu_t);
+    }
+    if ((pfx != NULL) && (pfx_len > 0)) {
+        ndp_opt_pi_t *pio = (ndp_opt_pi_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                     icmpv6_len];
+
+        pio->type = NDP_OPT_PI;
+        pio->len = NDP_OPT_PI_LEN;
+        pio->prefix_len = pfx_len;
+        pio->flags = pfx_flags;
+        pio->valid_ltime = byteorder_htonl(_PIO_PFX_LTIME);
+        pio->pref_ltime = byteorder_htonl(_PIO_PFX_LTIME);
+        ipv6_addr_init_prefix(&pio->prefix, pfx, pfx_len);
+        icmpv6_len += sizeof(ndp_opt_pi_t);
+    }
+    if ((sl2ao_addr != NULL) && (sl2ao_addr_len > 0)) {
+        ndp_opt_t *sl2ao = (ndp_opt_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                 icmpv6_len];
+
+        sl2ao->type = NDP_OPT_SL2A;
+        sl2ao->len = ceil8(sizeof(ndp_opt_t) + sl2ao_addr_len) / 8;
+        memcpy(sl2ao + 1, sl2ao_addr, sl2ao_addr_len);
+        icmpv6_len += ceil8(sizeof(ndp_opt_t) + sl2ao_addr_len);
+    }
+
+    return icmpv6_len;
+}
+
+typedef struct {
+    uint32_t reach_time_base;
+    uint32_t reach_time;
+    uint32_t retrans_timer;
+    uint16_t mtu;
+    uint8_t addr_count;
+    uint8_t cur_hl;
+} _netif_exp_t;
+
+static uint8_t _netif_addr_count(const gnrc_netif2_t *netif)
+{
+    unsigned count = 0U;
+
+    for (int i = 0; i < GNRC_NETIF2_IPV6_ADDRS_NUMOF; i++) {
+        if (netif->ipv6.addrs_flags[i] != 0) {
+            count++;
+        }
+    }
+    return count;
+}
+
+static inline void _get_netif_exp(const gnrc_netif2_t *netif,
+                                  _netif_exp_t *exp)
+{
+    exp->reach_time_base = netif->ipv6.reach_time_base;
+    exp->reach_time = netif->ipv6.reach_time;
+    exp->retrans_timer = netif->ipv6.retrans_time;
+    exp->mtu = netif->ipv6.mtu;
+    exp->addr_count = _netif_addr_count(netif);
+    exp->cur_hl = netif->cur_hl;
+}
+
+#define TEST_ASSERT_NETIF_UNCHANGED(netif, exp) \
+    TEST_ASSERT_EQUAL_INT(exp.reach_time_base, \
+                          netif->ipv6.reach_time_base); \
+    TEST_ASSERT_EQUAL_INT(exp.reach_time, netif->ipv6.reach_time); \
+    TEST_ASSERT_EQUAL_INT(exp.retrans_timer, netif->ipv6.retrans_time); \
+    TEST_ASSERT_EQUAL_INT(exp.mtu, netif->ipv6.mtu); \
+    TEST_ASSERT_EQUAL_INT(exp.addr_count, _netif_addr_count(netif)); \
+    TEST_ASSERT_EQUAL_INT(exp.cur_hl, netif->cur_hl)
+
+static void test_handle_pkt__rtr_adv__invalid_src(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_gb,
+                                     255U, 0U, true, 0U,
+                                     _loc_l2, sizeof(_loc_l2),
+                                     32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                                     NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_hl(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
+                                     194U, 0U, true, 0U,
+                                     _loc_l2, sizeof(_loc_l2),
+                                     32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                                     NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_code(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
+                                     255U, 201U, true, 0U,
+                                     _loc_l2, sizeof(_loc_l2),
+                                     32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                                     NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_icmpv6_len(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    _set_rtr_adv(&_rem_ll, 255U, 201U, true, 0U, _loc_l2, sizeof(_loc_l2),
+                 32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                 NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6,
+                             sizeof(ndp_rtr_adv_t) - 1);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_opt_len(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
+                                     255U, 201U, true, 0U,
+                                     _loc_l2, sizeof(_loc_l2),
+                                     32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                                     NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
+    ndp_opt_t *opt = (ndp_opt_t *)&_buffer[icmpv6_len];
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    opt->type = NDP_OPT_SL2A;
+    opt->len = 0U;
+    icmpv6_len += sizeof(ndp_opt_t);
+
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__success(uint8_t rtr_adv_flags,
+                                              bool set_rtr_adv_fields,
+                                              bool sl2ao, bool mtuo,
+                                              bool pio, uint8_t pio_flags)
+{
+    gnrc_ipv6_nib_pl_t prefix;
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_ll, 255U, 0U,
+                                     set_rtr_adv_fields, rtr_adv_flags,
+                                     (sl2ao) ? _rem_l2 : NULL, sizeof(_rem_l2),
+                                     (mtuo) ? 32397U : 0U,
+                                     (pio) ? &_loc_gb : NULL, _LOC_GB_PFX_LEN,
+                                     pio_flags);
+    const unsigned exp_addr_count = _netif_addr_count(_mock_netif);
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    TEST_ASSERT(gnrc_netif2_ipv6_addr_idx(_mock_netif, &_loc_gb) < 0);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    if (set_rtr_adv_fields) {
+        while (gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route)) {
+            /* is default route */
+            if (ipv6_addr_is_unspecified(&route.dst)) {
+                break;
+            }
+        }
+        TEST_ASSERT_MESSAGE(ipv6_addr_equal(&_rem_ll, &route.next_hop),
+                            "default route is not via RA's source");
+        TEST_ASSERT_EQUAL_INT(_mock_netif->pid, route.iface);
+        TEST_ASSERT_EQUAL_INT(_REACH_TIME, _mock_netif->ipv6.reach_time_base);
+        TEST_ASSERT_MESSAGE(((_REACH_TIME / 2) <= _mock_netif->ipv6.reach_time) &&
+                            (_mock_netif->ipv6.reach_time <=
+                             (_REACH_TIME + (_REACH_TIME / 2))),
+                    "Randomized reachable time was out of expected range.");
+        TEST_ASSERT_EQUAL_INT(_RETRANS_TIMER, _mock_netif->ipv6.retrans_time);
+        TEST_ASSERT_EQUAL_INT(_CUR_HL, _mock_netif->cur_hl);
+    }
+    else {
+        while (gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route)) {
+            TEST_ASSERT_MESSAGE(!ipv6_addr_is_unspecified(&route.dst),
+                                "There is a default route, "
+                                "though RA's router lifetime was 0.");
+        }
+        TEST_ASSERT_EQUAL_INT(exp_netif.reach_time_base,
+                              _mock_netif->ipv6.reach_time_base);
+        TEST_ASSERT_EQUAL_INT(exp_netif.reach_time,
+                              _mock_netif->ipv6.reach_time);
+        TEST_ASSERT_EQUAL_INT(exp_netif.retrans_timer,
+                              _mock_netif->ipv6.retrans_time);
+        TEST_ASSERT_EQUAL_INT(exp_netif.cur_hl,
+                              _mock_netif->cur_hl);
+    }
+    state = NULL;
+    if (sl2ao) {
+        TEST_ASSERT_MESSAGE(gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                            "No neighbor cache entry found");
+        TEST_ASSERT_MESSAGE((memcmp(&_rem_ll, &nce.ipv6, sizeof(_rem_ll)) == 0),
+                            "_rem_ll != nce.ipv6");
+        TEST_ASSERT_EQUAL_INT(sizeof(_rem_l2), nce.l2addr_len);
+        TEST_ASSERT_MESSAGE((memcmp(&_rem_l2, &nce.l2addr, nce.l2addr_len) == 0),
+                            "_rem_l2 != nce.l2addr");
+        TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE,
+                              gnrc_ipv6_nib_nc_get_nud_state(&nce));
+        TEST_ASSERT_EQUAL_INT(_mock_netif->pid, gnrc_ipv6_nib_nc_get_iface(&nce));
+        TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_AR_STATE_GC,
+                              gnrc_ipv6_nib_nc_get_ar_state(&nce));
+    }
+    else {
+        TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                            "There is an unexpected neighbor cache entry");
+    }
+    if (mtuo) {
+        TEST_ASSERT_EQUAL_INT(32397U, _mock_netif->ipv6.mtu);
+    }
+    else {
+        TEST_ASSERT_EQUAL_INT(exp_netif.mtu, _mock_netif->ipv6.mtu);
+    }
+    state = NULL;
+    if (pio) {
+        if (pio_flags & NDP_OPT_PI_FLAGS_A) {
+            TEST_ASSERT_MESSAGE(gnrc_netif2_ipv6_addr_idx(_mock_netif,
+                                                          &_loc_gb) >= 0,
+                                "Address was not configured by PIO");
+        }
+        else {
+            TEST_ASSERT_MESSAGE(gnrc_netif2_ipv6_addr_idx(_mock_netif,
+                                                          &_loc_gb) < 0,
+                                "Address was configured by PIO, "
+                                "but A flag was set");
+        }
+        if (pio_flags & NDP_OPT_PI_FLAGS_L) {
+            TEST_ASSERT_MESSAGE(gnrc_ipv6_nib_pl_iter(0, &state, &prefix),
+                                "No prefix list entry found");
+            TEST_ASSERT_MESSAGE(ipv6_addr_match_prefix(&_loc_gb,
+                                        &prefix.pfx) >= _LOC_GB_PFX_LEN,
+                                "Unexpected prefix configured");
+            TEST_ASSERT_EQUAL_INT(_LOC_GB_PFX_LEN, prefix.pfx_len);
+            TEST_ASSERT_EQUAL_INT(_mock_netif->pid, prefix.iface);
+            TEST_ASSERT(_PIO_PFX_LTIME < prefix.valid_until);
+            TEST_ASSERT(_PIO_PFX_LTIME < prefix.pref_until);
+        }
+    }
+    if (!pio || !(pio_flags & NDP_OPT_PI_FLAGS_L)) {
+        if (!pio) {
+            TEST_ASSERT_EQUAL_INT(exp_addr_count,
+                                  _netif_addr_count(_mock_netif));
+        }
+        TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_pl_iter(0, &state, &prefix),
+                            "There is an unexpected prefix list entry");
+    }
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__success_all_zero(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, false, false, false, false, 0U);
+}
+
+static void test_handle_pkt__rtr_adv__success_no_flags_no_opt(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, false, 0U);
+}
+
+static void test_handle_pkt__rtr_adv__success_no_opt(void)
+{
+    /* these flags only make sense with SLAAC, so don't further test them below
+     * (except for PIO ;-)) */
+    test_handle_pkt__rtr_adv__success(NDP_RTR_ADV_FLAGS_M | NDP_RTR_ADV_FLAGS_O,
+                                      true, false, false, false, 0U);
+}
+
+static void test_handle_pkt__rtr_adv__success_sl2ao(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, false, false, 0U);
+}
+
+static void test_handle_pkt__rtr_adv__success_mtuo(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, true, false, 0U);
+}
+
+static void test_handle_pkt__rtr_adv__success_pio_00(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true, 0U);
+}
+
+static void test_handle_pkt__rtr_adv__success_pio_L0(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true,
+                                      NDP_OPT_PI_FLAGS_L);
+}
+
+static void test_handle_pkt__rtr_adv__success_pio_0A(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true,
+                                      NDP_OPT_PI_FLAGS_A);
+}
+
+static void test_handle_pkt__rtr_adv__success_pio_LA(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true,
+                                      NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
+}
+
+static void test_handle_pkt__rtr_adv__success_sl2ao_mtuo_pio_00(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, true, true, 0U);
+}
+
+static void test_handle_pkt__rtr_adv__success_sl2ao_mtuo_pio_L0(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, true, true,
+                                      NDP_OPT_PI_FLAGS_L);
+}
+
+static void test_handle_pkt__rtr_adv__success_sl2ao_mtuo_pio_0A(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, true, true,
+                                      NDP_OPT_PI_FLAGS_A);
+}
+
+static void test_handle_pkt__rtr_adv__success_sl2ao_mtuo_pio_LA(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, true, true,
+                                      NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
+}
+
+static void test_change_rtr_adv_iface(void)
+{
+    TEST_ASSERT_MESSAGE(!(_mock_netif->flags & GNRC_NETIF2_FLAGS_IPV6_RTR_ADV),
+                        "RTR_ADV was unexpectedly set");
+    gnrc_ipv6_nib_change_rtr_adv_iface(_mock_netif, true);
+    TEST_ASSERT_MESSAGE(!(_mock_netif->flags & GNRC_NETIF2_FLAGS_IPV6_RTR_ADV),
+                        "RTR_ADV was unexpectedly changed");
+    gnrc_ipv6_nib_change_rtr_adv_iface(_mock_netif, false);
+    TEST_ASSERT_MESSAGE(!(_mock_netif->flags & GNRC_NETIF2_FLAGS_IPV6_RTR_ADV),
+                        "RTR_ADV was unexpectedly changed");
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
 static Test *tests_gnrc_ipv6_nib(void)
 {
     EMB_UNIT_TESTFIXTURES(fixtures) {
@@ -690,6 +1224,11 @@ static Test *tests_gnrc_ipv6_nib(void)
         /* TODO: ENETUNREACH when non-link-local communication is implemented */
         new_TestFixture(test_get_next_hop_l2addr__link_local_EHOSTUNREACH_no_iface),
         new_TestFixture(test_get_next_hop_l2addr__link_local_EHOSTUNREACH_iface),
+        new_TestFixture(test_get_next_hop_l2addr__global_EHOSTUNREACH_no_iface_off_link),
+        new_TestFixture(test_get_next_hop_l2addr__global_EHOSTUNREACH_iface_off_link),
+        new_TestFixture(test_get_next_hop_l2addr__global_EHOSTUNREACH_no_iface_on_link),
+        new_TestFixture(test_get_next_hop_l2addr__global_EHOSTUNREACH_iface_on_link),
+        new_TestFixture(test_get_next_hop_l2addr__ENETUNREACH),
         new_TestFixture(test_get_next_hop_l2addr__link_local_static_conf),
         new_TestFixture(test_get_next_hop_l2addr__link_local_after_handshake_iface),
         new_TestFixture(test_get_next_hop_l2addr__link_local_after_handshake_iface_router),
@@ -716,9 +1255,29 @@ static Test *tests_gnrc_ipv6_nib(void)
         new_TestFixture(test_handle_pkt__nbr_adv__unspecified_src),
         new_TestFixture(test_handle_pkt__nbr_adv__unsolicited),
         /* solicited tested in get_next_hop_l2addr */
+        new_TestFixture(test_handle_pkt__rtr_sol),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_src),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_hl),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_code),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_icmpv6_len),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_opt_len),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_all_zero),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_no_flags_no_opt),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_no_opt),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_sl2ao),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_mtuo),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_pio_00),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_pio_L0),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_pio_0A),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_pio_LA),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_sl2ao_mtuo_pio_00),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_sl2ao_mtuo_pio_L0),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_sl2ao_mtuo_pio_0A),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_sl2ao_mtuo_pio_LA),
         /* gnrc_ipv6_nib_handle_timer_event not testable in this context since
          * we do not have access to the (internally defined) contexts required
          * for it */
+        new_TestFixture(test_change_rtr_adv_iface),
     };
 
     EMB_UNIT_TESTCALLER(tests, _set_up, NULL, fixtures);
diff --git a/tests/gnrc_ipv6_nib/mockup_netif.c b/tests/gnrc_ipv6_nib/mockup_netif.c
index fce45710f470b2e79c3b1021fdfd07fed43ff0ff..d36f9d6b430eb3ec38020feda6b1be2a6c6a2cc9 100644
--- a/tests/gnrc_ipv6_nib/mockup_netif.c
+++ b/tests/gnrc_ipv6_nib/mockup_netif.c
@@ -83,6 +83,11 @@ void _tests_init(void)
             "mockup_eth", &_mock_netdev.netdev
         );
     assert(_mock_netif != NULL);
+    /* we do not want to test for SLAAC here so just assure the configured
+     * address is valid */
+    assert(!ipv6_addr_is_unspecified(&_mock_netif->ipv6.addrs[0]));
+    _mock_netif->ipv6.addrs_flags[0] &= ~GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_MASK;
+    _mock_netif->ipv6.addrs_flags[0] |= GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_VALID;
     gnrc_netreg_entry_init_pid(&dumper, GNRC_NETREG_DEMUX_CTX_ALL,
                                sched_active_pid);
     gnrc_netreg_register(GNRC_NETTYPE_NDP2, &dumper);
diff --git a/tests/gnrc_ipv6_nib_6ln/Makefile b/tests/gnrc_ipv6_nib_6ln/Makefile
index 2d9b05ee300e68536f71e5ed354819dd43d1486a..8642c81a9148b3066adcbe509be41d2a846120e3 100644
--- a/tests/gnrc_ipv6_nib_6ln/Makefile
+++ b/tests/gnrc_ipv6_nib_6ln/Makefile
@@ -3,10 +3,12 @@ APPLICATION = gnrc_ipv6_nib_6ln
 include ../Makefile.tests_common
 
 BOARD_INSUFFICIENT_MEMORY := chronos nucleo-f030 nucleo-l053 nucleo32-f031 \
-                             nucleo32-l031 nucleo32-f042 stm32f0discovery
+                             nucleo32-l031 nucleo32-f042 stm32f0discovery \
+                             telosb wsn430-v1_3b wsn430-v1_4
 
 USEMODULE += gnrc_ipv6
 USEMODULE += gnrc_sixlowpan
+USEMODULE += gnrc_sixlowpan_ctx
 USEMODULE += gnrc_ipv6_nib_6ln
 USEMODULE += gnrc_netif2
 USEMODULE += embunit
diff --git a/tests/gnrc_ipv6_nib_6ln/main.c b/tests/gnrc_ipv6_nib_6ln/main.c
index b9da5942ac952dadf8196206148219372a6c2d19..a034888272eb4e95b961437ca623ed17c2aac9f8 100644
--- a/tests/gnrc_ipv6_nib_6ln/main.c
+++ b/tests/gnrc_ipv6_nib_6ln/main.c
@@ -29,10 +29,25 @@
 #include "net/gnrc.h"
 #include "net/gnrc/ipv6/nib.h"
 #include "net/gnrc/ipv6/nib/nc.h"
+#include "net/gnrc/netif2/internal.h"
+#include "net/gnrc/sixlowpan/ctx.h"
+#include "net/gnrc/sixlowpan/nd.h"
 #include "net/ndp.h"
+#include "net/sixlowpan/nd.h"
 #include "sched.h"
 
-#define _BUFFER_SIZE    (128)
+#define _BUFFER_SIZE    (196)
+#define _ARO_LTIME      (4224)
+#define _CUR_HL         (155)
+#define _RTR_LTIME      (6612U)
+#define _REACH_TIME     (1210388825UL)
+#define _RETRANS_TIMER  (3691140UL)
+#define _LOC_GB_PFX_LEN (45U)
+#define _REM_GB_PFX_LEN (37U)
+#define _PIO_PFX_LTIME  (0x8476fedf)
+#define _CTX_LTIME      (29169U)
+#define _ABR_VERSION    (4065834664U)
+#define _ABR_LIME       (5286U)
 
 static const uint8_t _loc_l2[] = { _LL0, _LL1, _LL2, _LL3,
                                    _LL4, _LL5, _LL6, _LL7 };
@@ -40,6 +55,10 @@ static const ipv6_addr_t _loc_ll = { {
                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             _LL0 ^ 2, _LL1, _LL2, _LL3, _LL4, _LL5, _LL6, _LL7
         } };
+static const ipv6_addr_t _loc_gb = { {
+                0x20, 0x01, 0x2b, 0x2e, 0x43, 0x80, 0x00, 0x00,
+            _LL0 ^ 2, _LL1, _LL2, _LL3, _LL4, _LL5, _LL6, _LL7
+        } };
 #define _loc_iid    _loc_ll.u64[1].u8
 static const uint8_t _rem_l2[] = { _LL0, _LL1, _LL2, _LL3,
                                    _LL4, _LL5, _LL6, _LL7 + 1 };
@@ -47,7 +66,15 @@ static const ipv6_addr_t _rem_ll = { {
                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             _LL0 ^ 2, _LL1, _LL2, _LL3, _LL4, _LL5, _LL6, _LL7 + 1
         } };
+static const ipv6_addr_t _rem_gb = { {
+                0x20, 0x01, 0x18, 0xc9, 0xf8, 0x00, 0x00, 0x00,
+            _LL0 ^ 2, _LL1, _LL2, _LL3, _LL4, _LL5, _LL6, _LL7 + 1
+        } };
 #define _rem_iid    _rem_ll.u64[1].u8
+static const ipv6_addr_t _abr_gb = { {
+                0x20, 0x01, 0x2b, 0x2e, 0x43, 0x80, 0x00, 0x00,
+            _LL0 ^ 2, _LL1, _LL2, _LL3, _LL4, _LL5, _LL6, _LL7 - 1
+        } };
 static uint8_t _buffer[_BUFFER_SIZE];
 static ipv6_hdr_t *ipv6 = (ipv6_hdr_t *)&_buffer[0];
 static icmpv6_hdr_t *icmpv6 = (icmpv6_hdr_t *)&_buffer[sizeof(ipv6_hdr_t)];
@@ -57,6 +84,13 @@ static inline size_t ceil8(size_t size);
 static void _set_up(void)
 {
     _common_set_up();
+    gnrc_netif2_acquire(_mock_netif);
+    /* reset some fields not set by the nib interface initializer */
+    _mock_netif->ipv6.mtu = IPV6_MIN_MTU;
+    _mock_netif->cur_hl = GNRC_NETIF2_DEFAULT_HL;
+    gnrc_netif2_ipv6_addr_remove(_mock_netif, &_loc_gb);
+    _mock_netif->flags &= ~GNRC_NETIF2_FLAGS_6LO_ADDRS_REG;
+    gnrc_netif2_release(_mock_netif);
     memset(_buffer, 0, sizeof(_buffer));
     gnrc_pktbuf_init();
     /* remove messages */
@@ -64,6 +98,7 @@ static void _set_up(void)
         msg_t msg;
         msg_receive(&msg);
     }
+    gnrc_sixlowpan_ctx_reset();
 }
 
 static void test_get_next_hop_l2addr__link_local_EHOSTUNREACH(void)
@@ -71,12 +106,24 @@ static void test_get_next_hop_l2addr__link_local_EHOSTUNREACH(void)
     gnrc_ipv6_nib_nc_t nce;
 
     TEST_ASSERT_EQUAL_INT(-EHOSTUNREACH,
-                          gnrc_ipv6_nib_get_next_hop_l2addr(&_rem_ll, NULL,
+                          gnrc_ipv6_nib_get_next_hop_l2addr(&_rem_ll,
+                                                            NULL,
                                                             NULL, &nce));
     TEST_ASSERT_EQUAL_INT(0, msg_avail());
     TEST_ASSERT(gnrc_pktbuf_is_empty());
 }
 
+static void test_get_next_hop_l2addr__ENETUNREACH(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+
+    TEST_ASSERT_EQUAL_INT(-ENETUNREACH,
+                          gnrc_ipv6_nib_get_next_hop_l2addr(&_rem_gb,
+                                                            NULL, NULL, &nce));
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+    TEST_ASSERT(gnrc_pktbuf_is_empty());
+}
+
 static void test_get_next_hop_l2addr__link_local_static_conf(void)
 {
     gnrc_ipv6_nib_nc_t nce;
@@ -123,6 +170,20 @@ static void test_get_next_hop_l2addr__link_local(void)
     TEST_ASSERT(gnrc_pktbuf_is_empty());
 }
 
+static void test_get_next_hop_l2addr__global_with_default_route(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+
+    /* add _rem_ll as default router */
+    TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(NULL, 0, &_rem_ll,
+                                                  _mock_netif->pid));
+    TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_get_next_hop_l2addr(&_rem_gb,
+                                                               NULL, NULL,
+                                                               &nce));
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+    TEST_ASSERT(gnrc_pktbuf_is_empty());
+}
+
 static void test_handle_pkt__unknown_type(void)
 {
     gnrc_ipv6_nib_nc_t nce;
@@ -397,7 +458,8 @@ static size_t _set_nbr_adv(const ipv6_addr_t *ipv6_src,
                            uint8_t ipv6_hl, uint8_t nbr_adv_code,
                            uint8_t nbr_adv_flags,
                            const ipv6_addr_t *nbr_adv_tgt,
-                           const uint8_t *tl2ao_addr, size_t tl2ao_addr_len)
+                           const uint8_t *tl2ao_addr, size_t tl2ao_addr_len,
+                           eui64_t *aro_eui, uint8_t aro_status)
 {
     size_t icmpv6_len = sizeof(ndp_nbr_adv_t);
     ndp_nbr_adv_t *nbr_adv = (ndp_nbr_adv_t *)icmpv6;
@@ -420,6 +482,17 @@ static size_t _set_nbr_adv(const ipv6_addr_t *ipv6_src,
         memcpy(tl2ao + 1, tl2ao_addr, tl2ao_addr_len);
         icmpv6_len += ceil8(sizeof(ndp_opt_t) + tl2ao_addr_len);
     }
+    if (aro_eui) {
+        sixlowpan_nd_opt_ar_t *aro = (sixlowpan_nd_opt_ar_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                                       icmpv6_len];
+
+        aro->type = NDP_OPT_AR;
+        aro->len = SIXLOWPAN_ND_OPT_AR_LEN;
+        aro->status = aro_status;
+        aro->ltime = byteorder_htons(_ARO_LTIME);
+        aro->eui64.uint64 = aro_eui->uint64;
+        icmpv6_len += sizeof(sixlowpan_nd_opt_ar_t);
+    }
 
     return icmpv6_len;
 }
@@ -430,7 +503,7 @@ static void test_handle_pkt__nbr_adv__invalid_hl(void)
     void *state = NULL;
     size_t icmpv6_len = _set_nbr_adv(&_rem_ll, &_loc_ll, 194U, 0U,
                                      NDP_NBR_ADV_FLAGS_S, &_loc_ll, _rem_l2,
-                                     sizeof(_rem_l2));
+                                     sizeof(_rem_l2), NULL, 0U);
 
     gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
     TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
@@ -445,7 +518,7 @@ static void test_handle_pkt__nbr_adv__invalid_code(void)
     void *state = NULL;
     size_t icmpv6_len = _set_nbr_adv(&_rem_ll, &_loc_ll, 255U, 201U,
                                      NDP_NBR_ADV_FLAGS_S, &_loc_ll, _rem_l2,
-                                     sizeof(_rem_l2));
+                                     sizeof(_rem_l2), NULL, 0U);
 
     gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
     TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
@@ -461,7 +534,7 @@ static void test_handle_pkt__nbr_adv__invalid_icmpv6_len(void)
 
     _set_nbr_adv(&_rem_ll, &_loc_ll, 255U, 0U, NDP_NBR_ADV_FLAGS_S,
                  &_loc_ll, _rem_l2,
-                 sizeof(_rem_l2));
+                 sizeof(_rem_l2), NULL, 0U);
 
     gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6,
                              sizeof(ndp_nbr_adv_t) - 1);
@@ -478,7 +551,7 @@ static void test_handle_pkt__nbr_adv__invalid_tgt(void)
     size_t icmpv6_len = _set_nbr_adv(&_rem_ll, &_loc_ll, 255U, 0U,
                                      NDP_NBR_ADV_FLAGS_S,
                                      &ipv6_addr_all_routers_site_local, _rem_l2,
-                                     sizeof(_rem_l2));
+                                     sizeof(_rem_l2), NULL, 0U);
 
     gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
     TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
@@ -493,7 +566,7 @@ static void test_handle_pkt__nbr_adv__invalid_flags(void)
     void *state = NULL;
     size_t icmpv6_len = _set_nbr_adv(&_rem_ll, &ipv6_addr_all_nodes_link_local,
                                      255U, 0U, NDP_NBR_ADV_FLAGS_S, &_loc_ll,
-                                     NULL, 0);
+                                     NULL, 0, NULL, 0U);
 
     gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
     TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
@@ -508,7 +581,7 @@ static void test_handle_pkt__nbr_adv__invalid_opt_len(void)
     void *state = NULL;
     size_t icmpv6_len = _set_nbr_adv(&_rem_ll, &_loc_ll, 255U, 0U,
                                      NDP_NBR_ADV_FLAGS_S, &_loc_ll, _rem_l2,
-                                     sizeof(_rem_l2));
+                                     sizeof(_rem_l2), NULL, 0U);
     ndp_opt_t *opt = (ndp_opt_t *)&_buffer[icmpv6_len];
 
     opt->type = NDP_OPT_SL2A;
@@ -527,7 +600,7 @@ static void test_handle_pkt__nbr_adv__unspecified_src(void)
     void *state = NULL;
     size_t icmpv6_len = _set_nbr_adv(&ipv6_addr_unspecified, &_loc_ll, 255U, 0U,
                                      NDP_NBR_ADV_FLAGS_S, &_loc_ll, _rem_l2,
-                                     sizeof(_rem_l2));
+                                     sizeof(_rem_l2), NULL, 0U);
 
     gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
     TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
@@ -542,7 +615,7 @@ static void test_handle_pkt__nbr_adv__unsolicited(void)
     void *state = NULL;
     size_t icmpv6_len = _set_nbr_adv(&_rem_ll, &_loc_ll, 255U, 0U,
                                      NDP_NBR_ADV_FLAGS_S, &_loc_ll,
-                                     _rem_l2, sizeof(_rem_l2));
+                                     _rem_l2, sizeof(_rem_l2), NULL, 0U);
 
     gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
     TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
@@ -550,6 +623,612 @@ static void test_handle_pkt__nbr_adv__unsolicited(void)
     TEST_ASSERT_EQUAL_INT(0, msg_avail());
 }
 
+static void test_handle_pkt__nbr_adv__aro_not_my_eui64(void)
+{
+    size_t icmpv6_len = _set_nbr_adv(&_rem_gb, &_loc_gb, 255U, 0U, 0U, &_rem_ll,
+                                     0U, 0U, (eui64_t *)&_rem_l2,
+                                     SIXLOWPAN_ND_STATUS_SUCCESS);
+    int idx;
+
+    idx = gnrc_netif2_ipv6_addr_add(_mock_netif, &_loc_gb, _LOC_GB_PFX_LEN,
+                                    GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_TENTATIVE);
+    TEST_ASSERT(idx >= 0);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT(ipv6_addr_equal(&_loc_gb, &_mock_netif->ipv6.addrs[idx]));
+    TEST_ASSERT(_mock_netif->ipv6.addrs_flags[idx] &
+                GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_TENTATIVE);
+}
+
+static void test_handle_pkt__nbr_adv__aro_duplicate(void)
+{
+    size_t icmpv6_len = _set_nbr_adv(&_rem_gb, &_loc_gb, 255U, 0U, 0U, &_rem_ll,
+                                     NULL, 0U, (eui64_t *)&_loc_l2,
+                                     SIXLOWPAN_ND_STATUS_DUP);
+    int idx;
+
+    TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&_rem_ll, _mock_netif->pid,
+                                                  _rem_l2, sizeof(_rem_l2)));
+    idx = gnrc_netif2_ipv6_addr_add(_mock_netif, &_loc_gb, _LOC_GB_PFX_LEN,
+                                    GNRC_NETIF2_IPV6_ADDRS_FLAGS_STATE_TENTATIVE);
+    TEST_ASSERT(idx >= 0);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT(gnrc_netif2_ipv6_addr_idx(_mock_netif, &_loc_gb) < 0);
+}
+
+static size_t _set_rtr_sol(const ipv6_addr_t *ipv6_src,
+                           const ipv6_addr_t *ipv6_dst,
+                           uint8_t ipv6_hl, uint8_t rtr_sol_code,
+                           const uint8_t *sl2ao_addr, size_t sl2ao_addr_len)
+{
+    size_t icmpv6_len = sizeof(ndp_rtr_sol_t);
+    ndp_rtr_sol_t *rtr_sol = (ndp_rtr_sol_t *)icmpv6;
+
+    ipv6_hdr_set_version(ipv6);
+    ipv6->hl = ipv6_hl;
+    memcpy(&ipv6->src, ipv6_src, sizeof(ipv6->src));
+    memcpy(&ipv6->dst, ipv6_dst, sizeof(ipv6->dst));
+    rtr_sol->type = ICMPV6_RTR_SOL;
+    rtr_sol->code = rtr_sol_code;
+
+    if ((sl2ao_addr != NULL) && (sl2ao_addr_len > 0)) {
+        ndp_opt_t *sl2ao = (ndp_opt_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                 sizeof(ndp_rtr_sol_t)];
+
+        sl2ao->type = NDP_OPT_SL2A;
+        sl2ao->len = ceil8(sizeof(ndp_opt_t) + sl2ao_addr_len) / 8;
+        memcpy(sl2ao + 1, sl2ao_addr, sl2ao_addr_len);
+        icmpv6_len += ceil8(sizeof(ndp_opt_t) + sl2ao_addr_len);
+    }
+
+    return icmpv6_len;
+}
+
+static void test_handle_pkt__rtr_sol(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_sol(&_rem_ll, &_loc_ll,
+                                     255U, 0U, _rem_l2, sizeof(_rem_l2));
+
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static size_t _set_rtr_adv(const ipv6_addr_t *ipv6_src,
+                           uint8_t ipv6_hl, uint8_t rtr_adv_code,
+                           bool set_rtr_adv_fields,
+                           uint8_t rtr_adv_flags,
+                           const uint8_t *sl2ao_addr, size_t sl2ao_addr_len,
+                           uint16_t mtu,
+                           const ipv6_addr_t *pfx, unsigned pfx_len,
+                           uint8_t pfx_flags,
+                           bool include_pfx_6co,
+                           const ipv6_addr_t *abr, uint32_t abr_version)
+{
+    size_t icmpv6_len = sizeof(ndp_rtr_adv_t);
+    ndp_rtr_adv_t *rtr_adv = (ndp_rtr_adv_t *)icmpv6;
+
+    ipv6_hdr_set_version(ipv6);
+    ipv6->hl = ipv6_hl;
+    memcpy(&ipv6->src, ipv6_src, sizeof(ipv6->src));
+    memcpy(&ipv6->dst, &_loc_ll, sizeof(ipv6->dst));
+    rtr_adv->type = ICMPV6_RTR_ADV;
+    rtr_adv->code = rtr_adv_code;
+    rtr_adv->flags = rtr_adv_flags;
+    if (set_rtr_adv_fields) {
+        rtr_adv->cur_hl = _CUR_HL,
+        rtr_adv->ltime = byteorder_htons(_RTR_LTIME);
+        rtr_adv->reach_time = byteorder_htonl(_REACH_TIME);
+        rtr_adv->retrans_timer = byteorder_htonl(_RETRANS_TIMER);
+    }
+
+    if (mtu > 0) {
+        ndp_opt_mtu_t *mtuo = (ndp_opt_mtu_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                        icmpv6_len];
+
+        mtuo->type = NDP_OPT_MTU;
+        mtuo->len = NDP_OPT_MTU_LEN;
+        mtuo->mtu = byteorder_htonl(mtu);
+        icmpv6_len += sizeof(ndp_opt_mtu_t);
+    }
+    if (abr != NULL) {
+        sixlowpan_nd_opt_abr_t *abro = (sixlowpan_nd_opt_abr_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                                          icmpv6_len];
+
+        abro->type = NDP_OPT_ABR;
+        abro->len = SIXLOWPAN_ND_OPT_ABR_LEN;
+        sixlowpan_nd_opt_abr_set_version(abro, abr_version);
+        abro->ltime = byteorder_htons(_ABR_LIME);
+        memcpy(&abro->braddr, abr, sizeof(abro->braddr));
+        icmpv6_len += sizeof(sixlowpan_nd_opt_abr_t);
+    }
+    if ((pfx != NULL) && (pfx_len > 0)) {
+        ndp_opt_pi_t *pio = (ndp_opt_pi_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                     icmpv6_len];
+
+        pio->type = NDP_OPT_PI;
+        pio->len = NDP_OPT_PI_LEN;
+        pio->prefix_len = pfx_len;
+        pio->flags = pfx_flags;
+        pio->valid_ltime = byteorder_htonl(_PIO_PFX_LTIME);
+        pio->pref_ltime = byteorder_htonl(_PIO_PFX_LTIME);
+        ipv6_addr_init_prefix(&pio->prefix, pfx, pfx_len);
+        icmpv6_len += sizeof(ndp_opt_pi_t);
+
+        if (include_pfx_6co) {
+            sixlowpan_nd_opt_6ctx_t *ctx = (sixlowpan_nd_opt_6ctx_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                                               icmpv6_len];
+            ipv6_addr_t *ctx_pfx = (ipv6_addr_t *)(ctx + 1);
+
+            ctx->type = NDP_OPT_6CTX;
+            ctx->len = (pfx_len > 64) ? SIXLOWPAN_ND_OPT_6CTX_LEN_MAX :
+                                        SIXLOWPAN_ND_OPT_6CTX_LEN_MIN;
+            ctx->ctx_len = pfx_len;
+            ctx->resv_c_cid |= SIXLOWPAN_ND_OPT_6CTX_FLAGS_C;
+            ctx->ltime = byteorder_htons(_CTX_LTIME);
+            ipv6_addr_init_prefix(ctx_pfx, pfx, pfx_len);
+            icmpv6_len += ctx->len * 8U;
+        }
+    }
+    if ((sl2ao_addr != NULL) && (sl2ao_addr_len > 0)) {
+        ndp_opt_t *sl2ao = (ndp_opt_t *)&_buffer[sizeof(ipv6_hdr_t) +
+                                                 icmpv6_len];
+
+        sl2ao->type = NDP_OPT_SL2A;
+        sl2ao->len = ceil8(sizeof(ndp_opt_t) + sl2ao_addr_len) / 8;
+        memcpy(sl2ao + 1, sl2ao_addr, sl2ao_addr_len);
+        icmpv6_len += ceil8(sizeof(ndp_opt_t) + sl2ao_addr_len);
+    }
+
+    return icmpv6_len;
+}
+
+typedef struct {
+    uint32_t retrans_timer;
+    uint16_t mtu;
+    uint8_t addr_count;
+    uint8_t cur_hl;
+} _netif_exp_t;
+
+static uint8_t _netif_addr_count(const gnrc_netif2_t *netif)
+{
+    unsigned count = 0U;
+
+    for (int i = 0; i < GNRC_NETIF2_IPV6_ADDRS_NUMOF; i++) {
+        if (netif->ipv6.addrs_flags[i] != 0) {
+            count++;
+        }
+    }
+    return count;
+}
+
+static inline void _get_netif_exp(const gnrc_netif2_t *netif,
+                                  _netif_exp_t *exp)
+{
+    exp->retrans_timer = netif->ipv6.retrans_time;
+    exp->mtu = netif->ipv6.mtu;
+    exp->addr_count = _netif_addr_count(netif);
+    exp->cur_hl = netif->cur_hl;
+}
+
+#define TEST_ASSERT_NETIF_UNCHANGED(netif, exp) \
+    TEST_ASSERT_EQUAL_INT(exp.retrans_timer, netif->ipv6.retrans_time); \
+    TEST_ASSERT_EQUAL_INT(exp.mtu, netif->ipv6.mtu); \
+    TEST_ASSERT_EQUAL_INT(exp.addr_count, _netif_addr_count(netif)); \
+    TEST_ASSERT_EQUAL_INT(exp.cur_hl, netif->cur_hl)
+
+static void test_handle_pkt__rtr_adv__invalid_src(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_gb,
+                                     255U, 0U, true, 0U,
+                                     _loc_l2, sizeof(_loc_l2),
+                                     32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                                     NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
+                                     true, &_abr_gb, _ABR_VERSION);
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_hl(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
+                                     194U, 0U, true, 0U,
+                                     _loc_l2, sizeof(_loc_l2),
+                                     32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                                     NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
+                                     true, &_abr_gb, _ABR_VERSION);
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_code(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
+                                     255U, 201U, true, 0U,
+                                     _loc_l2, sizeof(_loc_l2),
+                                     32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                                     NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
+                                     true, &_abr_gb, _ABR_VERSION);
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_icmpv6_len(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    _set_rtr_adv(&_rem_ll, 255U, 201U, true, 0U, _loc_l2, sizeof(_loc_l2),
+                 32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                 NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
+                 true, &_abr_gb, _ABR_VERSION);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6,
+                             sizeof(ndp_rtr_adv_t) - 1);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_opt_len(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
+                                     255U, 201U, true, 0U,
+                                     _loc_l2, sizeof(_loc_l2),
+                                     32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                                     NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
+                                     true, &_abr_gb, _ABR_VERSION);
+    ndp_opt_t *opt = (ndp_opt_t *)&_buffer[icmpv6_len];
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    opt->type = NDP_OPT_SL2A;
+    opt->len = 0U;
+    icmpv6_len += sizeof(ndp_opt_t);
+
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__invalid_no_abro(void)
+{
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    _set_rtr_adv(&_rem_ll, 255U, 201U, true, 0U, _loc_l2, sizeof(_loc_l2),
+                 32397U, &_loc_gb, _LOC_GB_PFX_LEN,
+                 NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
+                 true, NULL, 0);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6,
+                             sizeof(ndp_rtr_adv_t));
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                        "There is an unexpected neighbor cache entry");
+    state = NULL;
+    TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route),
+                        "There is an unexpected forwarding entry");
+    TEST_ASSERT_NETIF_UNCHANGED(_mock_netif, exp_netif);
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
+static void test_handle_pkt__rtr_adv__success(uint8_t rtr_adv_flags,
+                                              bool set_rtr_adv_fields,
+                                              bool sl2ao, bool mtuo,
+                                              bool pio, uint8_t pio_flags,
+                                              bool ctxo)
+{
+    gnrc_ipv6_nib_pl_t prefix;
+    gnrc_ipv6_nib_nc_t nce;
+    gnrc_ipv6_nib_ft_t route;
+    void *state = NULL;
+    size_t icmpv6_len = _set_rtr_adv(&_rem_ll, 255U, 0U,
+                                     set_rtr_adv_fields, rtr_adv_flags,
+                                     (sl2ao) ? _rem_l2 : NULL, sizeof(_rem_l2),
+                                     (mtuo) ? 32397U : 0U,
+                                     (pio) ? &_loc_gb : NULL, _LOC_GB_PFX_LEN,
+                                     pio_flags,
+                                     ctxo, &_abr_gb, _ABR_VERSION);
+    const unsigned exp_addr_count = _netif_addr_count(_mock_netif);
+    _netif_exp_t exp_netif;
+
+    _get_netif_exp(_mock_netif, &exp_netif);
+    TEST_ASSERT(gnrc_netif2_ipv6_addr_idx(_mock_netif, &_loc_gb) < 0);
+    gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
+    if (set_rtr_adv_fields) {
+        while (gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route)) {
+            /* is default route */
+            if (ipv6_addr_is_unspecified(&route.dst)) {
+                break;
+            }
+        }
+        TEST_ASSERT_MESSAGE(ipv6_addr_equal(&_rem_ll, &route.next_hop),
+                            "default route is not via RA's source");
+        TEST_ASSERT_EQUAL_INT(_mock_netif->pid, route.iface);
+        TEST_ASSERT_EQUAL_INT(_RETRANS_TIMER, _mock_netif->ipv6.retrans_time);
+        TEST_ASSERT_EQUAL_INT(_CUR_HL, _mock_netif->cur_hl);
+    }
+    else {
+        while (gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route)) {
+            TEST_ASSERT_MESSAGE(!ipv6_addr_is_unspecified(&route.dst),
+                                "There is a default route, "
+                                "though RA's router lifetime was 0.");
+        }
+        TEST_ASSERT_EQUAL_INT(exp_netif.retrans_timer,
+                              _mock_netif->ipv6.retrans_time);
+        TEST_ASSERT_EQUAL_INT(exp_netif.cur_hl,
+                              _mock_netif->cur_hl);
+    }
+    state = NULL;
+    if (ctxo) {
+        gnrc_sixlowpan_ctx_t *ctx;
+
+        TEST_ASSERT_NOT_NULL((ctx = gnrc_sixlowpan_ctx_lookup_addr(&_loc_gb)));
+        TEST_ASSERT(ipv6_addr_match_prefix(&_loc_gb,
+                                           &ctx->prefix) >= _LOC_GB_PFX_LEN);
+        TEST_ASSERT_EQUAL_INT(0U, ctx->flags_id & GNRC_SIXLOWPAN_CTX_FLAGS_CID_MASK);
+        TEST_ASSERT(ctx->flags_id & GNRC_SIXLOWPAN_CTX_FLAGS_COMP);
+        TEST_ASSERT_EQUAL_INT(_CTX_LTIME, ctx->ltime);
+    }
+    else {
+        TEST_ASSERT_NULL(gnrc_sixlowpan_ctx_lookup_addr(&_loc_gb));
+    }
+    if (sl2ao) {
+        TEST_ASSERT_MESSAGE(gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                            "No neighbor cache entry found");
+        TEST_ASSERT_MESSAGE((memcmp(&_rem_ll, &nce.ipv6, sizeof(_rem_ll)) == 0),
+                            "_rem_ll != nce.ipv6");
+        TEST_ASSERT_EQUAL_INT(sizeof(_rem_l2), nce.l2addr_len);
+        TEST_ASSERT_MESSAGE((memcmp(&_rem_l2, &nce.l2addr, nce.l2addr_len) == 0),
+                            "_rem_l2 != nce.l2addr");
+        TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE,
+                              gnrc_ipv6_nib_nc_get_nud_state(&nce));
+        TEST_ASSERT_EQUAL_INT(_mock_netif->pid, gnrc_ipv6_nib_nc_get_iface(&nce));
+        TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_AR_STATE_GC,
+                              gnrc_ipv6_nib_nc_get_ar_state(&nce));
+    }
+    else {
+        TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
+                            "There is an unexpected neighbor cache entry");
+    }
+    if (mtuo) {
+        TEST_ASSERT_EQUAL_INT(32397U, _mock_netif->ipv6.mtu);
+    }
+    else {
+        TEST_ASSERT_EQUAL_INT(exp_netif.mtu, _mock_netif->ipv6.mtu);
+    }
+    state = NULL;
+    if (pio) {
+        if (pio_flags & NDP_OPT_PI_FLAGS_A) {
+            TEST_ASSERT_MESSAGE(gnrc_netif2_ipv6_addr_idx(_mock_netif,
+                                                          &_loc_gb) >= 0,
+                                "Address was not configured by PIO");
+        }
+        else {
+            TEST_ASSERT_MESSAGE(gnrc_netif2_ipv6_addr_idx(_mock_netif,
+                                                          &_loc_gb) < 0,
+                                "Address was configured by PIO, "
+                                "but A flag was set");
+        }
+        if (pio_flags & NDP_OPT_PI_FLAGS_L) {
+            TEST_ASSERT_MESSAGE(gnrc_ipv6_nib_pl_iter(0, &state, &prefix),
+                                "No prefix list entry found");
+            TEST_ASSERT_MESSAGE(ipv6_addr_match_prefix(&_loc_gb,
+                                        &prefix.pfx) >= _LOC_GB_PFX_LEN,
+                                "Unexpected prefix configured");
+            TEST_ASSERT_EQUAL_INT(_LOC_GB_PFX_LEN, prefix.pfx_len);
+            TEST_ASSERT_EQUAL_INT(_mock_netif->pid, prefix.iface);
+            TEST_ASSERT(_PIO_PFX_LTIME < prefix.valid_until);
+            TEST_ASSERT(_PIO_PFX_LTIME < prefix.pref_until);
+        }
+    }
+    if (!pio) {
+        if (!pio) {
+            TEST_ASSERT_EQUAL_INT(exp_addr_count,
+                                  _netif_addr_count(_mock_netif));
+        }
+        TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_pl_iter(0, &state, &prefix),
+                            "There is an unexpected prefix list entry");
+    }
+    if (set_rtr_adv_fields) {
+        TEST_ASSERT(msg_avail() > 0);
+        while (msg_avail()) {
+            gnrc_netif_hdr_t *netif_hdr;
+            ipv6_hdr_t *ipv6_hdr;
+            ndp_nbr_sol_t *nbr_sol;
+            gnrc_pktsnip_t *pkt;
+            msg_t msg;
+
+            msg_receive(&msg);
+            TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type);
+            pkt = msg.content.ptr;
+            /* first snip is a netif header to _mock_netif */
+            TEST_ASSERT_NOT_NULL(pkt);
+            TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_NETIF, pkt->type);
+            TEST_ASSERT(sizeof(gnrc_netif_hdr_t) <= pkt->size);
+            netif_hdr = pkt->data;
+            TEST_ASSERT_EQUAL_INT(_mock_netif->pid, netif_hdr->if_pid);
+            /* second snip is an IPv6 header to router (source of RA) */
+            TEST_ASSERT_NOT_NULL(pkt->next);
+            TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_IPV6, pkt->next->type);
+            TEST_ASSERT_EQUAL_INT(sizeof(ipv6_hdr_t), pkt->next->size);
+            ipv6_hdr = pkt->next->data;
+            TEST_ASSERT_MESSAGE(ipv6_addr_equal(&_rem_ll, &ipv6_hdr->dst),
+                                "_rem_ll != ipv6_hdr->dst");
+            TEST_ASSERT_EQUAL_INT(255, ipv6_hdr->hl);
+            /* third snip is a valid solicited neighbor advertisement to tgt */
+            TEST_ASSERT_NOT_NULL(pkt->next->next);
+            TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_ICMPV6, pkt->next->next->type);
+            TEST_ASSERT_EQUAL_INT(sizeof(ndp_nbr_sol_t), pkt->next->next->size);
+            nbr_sol = pkt->next->next->data;
+            TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_SOL, nbr_sol->type);
+            TEST_ASSERT_EQUAL_INT(0, nbr_sol->code);
+            TEST_ASSERT(!ipv6_addr_is_multicast(&nbr_sol->tgt));
+            TEST_ASSERT_MESSAGE(ipv6_addr_equal(&_rem_ll, &nbr_sol->tgt),
+                                "_rem_ll != nbr_sol->tgt");
+            /* ARO and SL2AO (fields not checked here) are also there */
+            TEST_ASSERT_NOT_NULL(pkt->next->next->next);
+            TEST_ASSERT_NOT_NULL(pkt->next->next->next->next);
+            TEST_ASSERT_NULL(pkt->next->next->next->next->next);
+            gnrc_pktbuf_release(pkt);
+        }
+        TEST_ASSERT(gnrc_pktbuf_is_empty());
+    }
+    else {
+        TEST_ASSERT_EQUAL_INT(0, msg_avail());
+    }
+}
+
+static void test_handle_pkt__rtr_adv__success_all_zero(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, false, false, false, false, 0U,
+                                      false);
+}
+
+static void test_handle_pkt__rtr_adv__success_no_flags_no_opt(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, false, 0U, false);
+}
+
+static void test_handle_pkt__rtr_adv__success_no_opt(void)
+{
+    /* these flags only make sense with SLAAC, so don't further test them below
+     * (except for PIO ;-)) */
+    test_handle_pkt__rtr_adv__success(NDP_RTR_ADV_FLAGS_M | NDP_RTR_ADV_FLAGS_O,
+                                      true, false, false, false, 0U, false);
+}
+
+static void test_handle_pkt__rtr_adv__success_sl2ao(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, false, false, 0U, false);
+}
+
+static void test_handle_pkt__rtr_adv__success_mtuo(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, true, false, 0U, false);
+}
+
+static void test_handle_pkt__rtr_adv__success_pio_00(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true, 0U, false);
+}
+
+static void test_handle_pkt__rtr_adv__success_pio_L0(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true,
+                                      NDP_OPT_PI_FLAGS_L, false);
+}
+
+static void test_handle_pkt__rtr_adv__success_pio_0A(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true,
+                                      NDP_OPT_PI_FLAGS_A, false);
+}
+
+static void test_handle_pkt__rtr_adv__success_pio_LA(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true,
+                                      NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
+                                      false);
+}
+
+static void test_handle_pkt__rtr_adv__success_6co_pio_0A(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, false, false, true,
+                                      NDP_OPT_PI_FLAGS_A, true);
+}
+
+static void test_handle_pkt__rtr_adv__success_6co_sl2ao_mtuo_pio_00(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, true, true, 0U, true);
+}
+
+static void test_handle_pkt__rtr_adv__success_6co_sl2ao_mtuo_pio_L0(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, true, true,
+                                      NDP_OPT_PI_FLAGS_L, true);
+}
+
+static void test_handle_pkt__rtr_adv__success_6co_sl2ao_mtuo_pio_0A(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, true, true,
+                                      NDP_OPT_PI_FLAGS_A, true);
+}
+
+static void test_handle_pkt__rtr_adv__success_6co_sl2ao_mtuo_pio_LA(void)
+{
+    test_handle_pkt__rtr_adv__success(0U, true, true, true, true,
+                                      NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
+                                      true);
+}
+
+static void test_change_rtr_adv_iface(void)
+{
+    TEST_ASSERT_MESSAGE(!(_mock_netif->flags & GNRC_NETIF2_FLAGS_IPV6_RTR_ADV),
+                        "RTR_ADV was unexpectedly set");
+    gnrc_ipv6_nib_change_rtr_adv_iface(_mock_netif, true);
+    TEST_ASSERT_MESSAGE(!(_mock_netif->flags & GNRC_NETIF2_FLAGS_IPV6_RTR_ADV),
+                        "RTR_ADV was unexpectedly changed");
+    gnrc_ipv6_nib_change_rtr_adv_iface(_mock_netif, false);
+    TEST_ASSERT_MESSAGE(!(_mock_netif->flags & GNRC_NETIF2_FLAGS_IPV6_RTR_ADV),
+                        "RTR_ADV was unexpectedly changed");
+    TEST_ASSERT_EQUAL_INT(0, msg_avail());
+}
+
 static Test *tests_gnrc_ipv6_nib(void)
 {
     EMB_UNIT_TESTFIXTURES(fixtures) {
@@ -557,8 +1236,10 @@ static Test *tests_gnrc_ipv6_nib(void)
          * set-up (otherwise the following tests wouldn't work) */
         /* TODO: ENETUNREACH when non-link-local communication is implemented */
         new_TestFixture(test_get_next_hop_l2addr__link_local_EHOSTUNREACH),
+        new_TestFixture(test_get_next_hop_l2addr__ENETUNREACH),
         new_TestFixture(test_get_next_hop_l2addr__link_local_static_conf),
         new_TestFixture(test_get_next_hop_l2addr__link_local),
+        new_TestFixture(test_get_next_hop_l2addr__global_with_default_route),
         new_TestFixture(test_handle_pkt__unknown_type),
         new_TestFixture(test_handle_pkt__nbr_sol__invalid_hl),
         new_TestFixture(test_handle_pkt__nbr_sol__invalid_code),
@@ -580,10 +1261,34 @@ static Test *tests_gnrc_ipv6_nib(void)
         new_TestFixture(test_handle_pkt__nbr_adv__invalid_opt_len),
         new_TestFixture(test_handle_pkt__nbr_adv__unspecified_src),
         new_TestFixture(test_handle_pkt__nbr_adv__unsolicited),
+        new_TestFixture(test_handle_pkt__nbr_adv__aro_not_my_eui64),
+        new_TestFixture(test_handle_pkt__nbr_adv__aro_duplicate),
         /* solicited tested in get_next_hop_l2addr */
+        new_TestFixture(test_handle_pkt__rtr_sol),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_src),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_hl),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_code),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_icmpv6_len),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_opt_len),
+        new_TestFixture(test_handle_pkt__rtr_adv__invalid_no_abro),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_all_zero),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_no_flags_no_opt),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_no_opt),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_sl2ao),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_mtuo),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_pio_00),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_pio_L0),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_pio_0A),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_pio_LA),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_6co_pio_0A),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_6co_sl2ao_mtuo_pio_00),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_6co_sl2ao_mtuo_pio_L0),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_6co_sl2ao_mtuo_pio_0A),
+        new_TestFixture(test_handle_pkt__rtr_adv__success_6co_sl2ao_mtuo_pio_LA),
         /* gnrc_ipv6_nib_handle_timer_event not testable in this context since
          * we do not have access to the (internally defined) contexts required
          * for it */
+        new_TestFixture(test_change_rtr_adv_iface),
     };
 
     EMB_UNIT_TESTCALLER(tests, _set_up, NULL, fixtures);
diff --git a/tests/gnrc_ndp2/Makefile b/tests/gnrc_ndp2/Makefile
index fc374964e64c55137c0e65b9dcb17ed860897ab9..90d2dcdfc84627e5db0ad9d524ad805abe7e861c 100644
--- a/tests/gnrc_ndp2/Makefile
+++ b/tests/gnrc_ndp2/Makefile
@@ -2,9 +2,10 @@
 APPLICATION = gnrc_ndp2
 include ../Makefile.tests_common
 
-BOARD_INSUFFICIENT_MEMORY := chronos nucleo32-f031 nucleo32-f042 nucleo32-l031
+BOARD_INSUFFICIENT_MEMORY := chronos nucleo32-f031 nucleo32-f042 nucleo32-l031 \
+                             telosb wsn430-v1_3b wsn430-v1_4
 
-USEMODULE += gnrc_ipv6_nib
+USEMODULE += gnrc_ipv6_nib_router
 USEMODULE += gnrc_ndp2
 USEMODULE += gnrc_netif2
 USEMODULE += embunit
diff --git a/tests/gnrc_sock_dns/Makefile b/tests/gnrc_sock_dns/Makefile
index 8b65f7cc9b0882c799ac338f4632173d2a97cdd4..b6a0c0b46cd4abc09fb6b6a345911355f1db5e97 100644
--- a/tests/gnrc_sock_dns/Makefile
+++ b/tests/gnrc_sock_dns/Makefile
@@ -3,7 +3,9 @@ include ../Makefile.tests_common
 
 RIOTBASE ?= $(CURDIR)/../..
 
-BOARD_INSUFFICIENT_MEMORY := chronos telosb nucleo32-f042 nucleo32-f031 nucleo-f030 nucleo-l053 nucleo32-l031 stm32f0discovery
+BOARD_INSUFFICIENT_MEMORY := chronos telosb nucleo32-f042 nucleo32-f031 \
+                             nucleo-f030 nucleo-l053 nucleo32-l031 \
+                             stm32f0discovery z1
 
 USEMODULE += sock_dns
 USEMODULE += gnrc_sock_udp
diff --git a/tests/gnrc_sock_ip/Makefile b/tests/gnrc_sock_ip/Makefile
index b4ecfa77797177f33b165263e1c1e8cbe4e6d839..d289634d3335248734932b2efbedb6c054ec0f55 100644
--- a/tests/gnrc_sock_ip/Makefile
+++ b/tests/gnrc_sock_ip/Makefile
@@ -1,7 +1,7 @@
 APPLICATION = gnrc_sock_ip
 include ../Makefile.tests_common
 
-BOARD_INSUFFICIENT_MEMORY := nucleo32-f031
+BOARD_INSUFFICIENT_MEMORY := chronos nucleo32-f031 nucleo32-f042 nucleo32-l031
 
 USEMODULE += gnrc_sock_ip
 USEMODULE += gnrc_ipv6
diff --git a/tests/gnrc_sock_udp/Makefile b/tests/gnrc_sock_udp/Makefile
index d502c90b1ccad3984c8bb785f1c2ae9a5f50d587..df172f0e81986fcc016c7fe56328ea8842785ec2 100644
--- a/tests/gnrc_sock_udp/Makefile
+++ b/tests/gnrc_sock_udp/Makefile
@@ -1,7 +1,7 @@
 APPLICATION = gnrc_sock_udp
 include ../Makefile.tests_common
 
-BOARD_INSUFFICIENT_MEMORY := chronos nucleo32-f031 nucleo32-f042
+BOARD_INSUFFICIENT_MEMORY := chronos nucleo32-f031 nucleo32-f042 nucleo32-l031
 
 USEMODULE += gnrc_sock_check_reuse
 USEMODULE += gnrc_sock_udp
diff --git a/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include b/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include
index 54383e241189049ba0e3efc48613477fc19d883c..24fa30541cc48ef900063fb7520d5ecafb4047cc 100644
--- a/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include
+++ b/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include
@@ -1,4 +1,5 @@
 USEMODULE += gnrc_ipv6_nib
+USEMODULE += gnrc_sixlowpan_nd  # required for GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
 
 CFLAGS += -DGNRC_IPV6_NIB_CONF_ROUTER=1
 CFLAGS += -DGNRC_IPV6_NIB_NUMOF=16
diff --git a/tests/unittests/tests-ipv6_nc/Makefile b/tests/unittests/tests-ipv6_nc/Makefile
deleted file mode 100644
index 48422e909a47d7cd428d10fa73825060ccc8d8c2..0000000000000000000000000000000000000000
--- a/tests/unittests/tests-ipv6_nc/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-include $(RIOTBASE)/Makefile.base
diff --git a/tests/unittests/tests-ipv6_nc/Makefile.include b/tests/unittests/tests-ipv6_nc/Makefile.include
deleted file mode 100644
index d7162f43dc69390da4f3aa344b3384eab6e6b4d7..0000000000000000000000000000000000000000
--- a/tests/unittests/tests-ipv6_nc/Makefile.include
+++ /dev/null
@@ -1,2 +0,0 @@
-USEMODULE += gnrc_ipv6_nc
-USEMODULE += gnrc_ipv6_netif
diff --git a/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c b/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c
deleted file mode 100644
index b97f239eeb0155a683bc7bccf4bbec6e87be66d2..0000000000000000000000000000000000000000
--- a/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright (C) 2014 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 <errno.h>
-#include <stdlib.h>
-
-#include "embUnit.h"
-
-#include "net/ipv6/addr.h"
-#include "net/gnrc/ipv6/nc.h"
-#include "net/gnrc/ipv6/netif.h"
-
-#include "unittests-constants.h"
-#include "tests-ipv6_nc.h"
-
-/* default interface for testing */
-#define DEFAULT_TEST_NETIF      (TEST_UINT16)
-/* default IPv6 addr for testing */
-#define DEFAULT_TEST_IPV6_ADDR  { { \
-            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \
-        } \
-    }
-
-/* another interface for testing */
-#define OTHER_TEST_NETIF        (TEST_UINT16 + TEST_UINT8)
-/* another IPv6 addr for testing */
-#define OTHER_TEST_IPV6_ADDR    { { \
-            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
-            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f \
-        } \
-    }
-
-/* a third IPv6 addr for testing */
-#define THIRD_TEST_IPV6_ADDR    { { \
-            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
-            0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f \
-        } \
-    }
-
-static void set_up(void)
-{
-    gnrc_ipv6_nc_init();
-    gnrc_ipv6_netif_add(DEFAULT_TEST_NETIF);
-}
-
-static void tear_down(void)
-{
-    /* remove all ncache entries, this is necesaary in case
-     * the last test initializes timers. */
-    gnrc_ipv6_nc_init();
-    gnrc_ipv6_netif_init();
-}
-
-static void test_ipv6_nc_add__address_registered(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry1, *entry2;
-
-    TEST_ASSERT_NOT_NULL((entry1 = gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4,
-                                                    sizeof(TEST_STRING4), 0)));
-    TEST_ASSERT_NOT_NULL((entry2 = gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4,
-                                                    sizeof(TEST_STRING4), 0)));
-    TEST_ASSERT(entry1 == entry2);
-}
-
-static void test_ipv6_nc_add__address_NULL(void)
-{
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, NULL, TEST_STRING4,
-                                      sizeof(TEST_STRING4), 0));
-}
-
-static void test_ipv6_nc_add__iface_KERNEL_PID_UNDEF(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_add(KERNEL_PID_UNDEF, &addr, TEST_STRING4,
-                                          sizeof(TEST_STRING4), 0));
-}
-
-static void test_ipv6_nc_add__addr_unspecified(void)
-{
-    ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED;
-
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4,
-                                      sizeof(TEST_STRING4), 0));
-}
-
-static void test_ipv6_nc_add__l2addr_too_long(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4,
-                                      GNRC_IPV6_NC_L2_ADDR_MAX + TEST_UINT8, 0));
-}
-
-static void test_ipv6_nc_add__full(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    for (int i = 0; i < GNRC_IPV6_NC_SIZE; i++) {
-        TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4,
-                                              sizeof(TEST_STRING4), 0));
-        addr.u16[7].u16++;
-    }
-
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4,
-                                      sizeof(TEST_STRING4), 0));
-}
-
-static void test_ipv6_nc_add__success(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry1, *entry2;
-
-    TEST_ASSERT_NOT_NULL((entry1 = gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4,
-                                                    sizeof(TEST_STRING4), 0)));
-
-    TEST_ASSERT_NOT_NULL((entry2 = gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT(entry1 == entry2);
-}
-
-static void test_ipv6_nc_add__address_update_despite_free_entry(void)
-{
-    ipv6_addr_t default_addr = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t other_addr = OTHER_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry1, *entry2;
-
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_add(OTHER_TEST_NETIF, &other_addr, TEST_STRING4,
-                                          sizeof(TEST_STRING4), 0));
-    TEST_ASSERT_NOT_NULL((entry1 = gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &default_addr, TEST_STRING4,
-                                                    sizeof(TEST_STRING4), 0)));
-
-    /* create space by removing first entry and see if duplicate is still detected & updated */
-    gnrc_ipv6_nc_remove(OTHER_TEST_NETIF, &other_addr);
-    TEST_ASSERT_NOT_NULL((entry2 = gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &default_addr, TEST_STRING4,
-                                                    sizeof(TEST_STRING4), 0)));
-    TEST_ASSERT(entry1 == entry2);
-}
-
-static void test_ipv6_nc_remove__no_entry_pid(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-    gnrc_ipv6_nc_remove(OTHER_TEST_NETIF, &addr);
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr));
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get(OTHER_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_nc_remove__no_entry_addr1(void)
-{
-    ipv6_addr_t addr = OTHER_TEST_IPV6_ADDR;
-    ipv6_addr_t exp_addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-    gnrc_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr);
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &exp_addr));
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_nc_remove__no_entry_addr2(void)
-{
-    ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED;
-    ipv6_addr_t exp_addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-    gnrc_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr);
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &exp_addr));
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_nc_remove__success(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr));
-    gnrc_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr);
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_nc_get__empty(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_nc_get__different_if(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get(OTHER_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_nc_get__different_addr(void)
-{
-    ipv6_addr_t addr = OTHER_TEST_IPV6_ADDR;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_nc_get__success_if_local(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, entry->iface);
-    TEST_ASSERT(ipv6_addr_equal(&(entry->ipv6_addr), &addr));
-    TEST_ASSERT_EQUAL_STRING(TEST_STRING4, (char *)entry->l2_addr);
-    TEST_ASSERT_EQUAL_INT(sizeof(TEST_STRING4), entry->l2_addr_len);
-    TEST_ASSERT_EQUAL_INT(0, entry->flags);
-}
-
-static void test_ipv6_nc_get__success_if_global(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, &addr)));
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, entry->iface);
-    TEST_ASSERT(ipv6_addr_equal(&(entry->ipv6_addr), &addr));
-    TEST_ASSERT_EQUAL_STRING(TEST_STRING4, (char *)entry->l2_addr);
-    TEST_ASSERT_EQUAL_INT(sizeof(TEST_STRING4), entry->l2_addr_len);
-    TEST_ASSERT_EQUAL_INT(0, entry->flags);
-}
-
-static void test_ipv6_nc_get_next__empty(void)
-{
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get_next(NULL));
-}
-
-static void test_ipv6_nc_get_next__1_entry(void)
-{
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get_next(NULL)));
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get_next(entry));
-}
-
-static void test_ipv6_nc_get_next__2_entries(void)
-{
-    ipv6_addr_t addr = OTHER_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING8,
-                                          sizeof(TEST_STRING8) - 1, 0));
-
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get_next(NULL)));
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get_next(entry)));
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get_next(entry));
-}
-
-static void test_ipv6_nc_get_next__holey(void)
-{
-    ipv6_addr_t addr1 = OTHER_TEST_IPV6_ADDR;
-    ipv6_addr_t addr2 = THIRD_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL, *exp_entry = NULL;
-
-    /* adds DEFAULT_TEST_IPV6_ADDR and OTHER_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-    test_ipv6_nc_get_next__2_entries();
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr2, TEST_STRING8,
-                                          sizeof(TEST_STRING8) - 2, 0));
-    TEST_ASSERT_NOT_NULL((exp_entry = gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr2)));
-    gnrc_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr1);
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get_next(NULL)));
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get_next(entry)));
-    TEST_ASSERT(exp_entry == entry);
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get_next(entry));
-}
-
-static void test_ipv6_nc_get_next_router__empty(void)
-{
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get_next_router(NULL));
-}
-
-static void test_ipv6_nc_get_next_router__first_entry(void)
-{
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    /* adds DEFAULT_TEST_IPV6_ADDR and OTHER_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-    test_ipv6_nc_get_next__2_entries();
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get_next(NULL)));
-    entry->flags = (GNRC_IPV6_NC_STATE_REACHABLE << GNRC_IPV6_NC_STATE_POS);
-    entry->flags |= GNRC_IPV6_NC_IS_ROUTER;
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get_next_router(NULL)));
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get_next_router(entry));
-}
-
-static void test_ipv6_nc_get_next_router__second_entry(void)
-{
-    gnrc_ipv6_nc_t *entry1 = NULL, *entry2 = NULL;
-
-    /* adds DEFAULT_TEST_IPV6_ADDR and OTHER_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-    test_ipv6_nc_get_next__2_entries();
-    TEST_ASSERT_NOT_NULL((entry1 = gnrc_ipv6_nc_get_next(NULL)));
-    TEST_ASSERT_NOT_NULL((entry2 = gnrc_ipv6_nc_get_next(entry1)));
-    entry2->flags = (GNRC_IPV6_NC_STATE_REACHABLE << GNRC_IPV6_NC_STATE_POS);
-    entry2->flags |= GNRC_IPV6_NC_IS_ROUTER;
-
-    TEST_ASSERT_NOT_NULL((entry1 = gnrc_ipv6_nc_get_next_router(NULL)));
-    TEST_ASSERT(entry2 == entry1);
-    TEST_ASSERT_NULL(gnrc_ipv6_nc_get_next_router(entry1));
-}
-
-static void test_ipv6_nc_is_reachable__incomplete(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, &addr)));
-    entry->flags = (GNRC_IPV6_NC_STATE_INCOMPLETE << GNRC_IPV6_NC_STATE_POS);
-    TEST_ASSERT(!gnrc_ipv6_nc_is_reachable(entry));
-}
-
-static void test_ipv6_nc_is_reachable__reachable(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)));
-    entry->flags = (GNRC_IPV6_NC_STATE_REACHABLE << GNRC_IPV6_NC_STATE_POS);
-    TEST_ASSERT(gnrc_ipv6_nc_is_reachable(entry));
-}
-
-static void test_ipv6_nc_is_reachable__unmanaged(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)));
-    entry->flags = (GNRC_IPV6_NC_STATE_UNMANAGED << GNRC_IPV6_NC_STATE_POS);
-    TEST_ASSERT(gnrc_ipv6_nc_is_reachable(entry));
-}
-
-static void test_ipv6_nc_still_reachable__incomplete(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF and sets flags to
-     * (GNRC_IPV6_NC_STATE_INCOMPLETE << GNRC_IPV6_NC_STATE_POS) */
-    test_ipv6_nc_is_reachable__incomplete();
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, &addr)));
-    TEST_ASSERT(!gnrc_ipv6_nc_is_reachable(entry));
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_still_reachable(&addr));
-    TEST_ASSERT(!gnrc_ipv6_nc_is_reachable(entry));
-}
-
-static void test_ipv6_nc_still_reachable__success(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-
-    /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF and sets flags to
-     * (GNRC_IPV6_NC_STATE_REACHABLE << GNRC_IPV6_NC_STATE_POS) */
-    test_ipv6_nc_is_reachable__reachable();
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, &addr)));
-    TEST_ASSERT(gnrc_ipv6_nc_is_reachable(entry));
-
-    entry->flags = (GNRC_IPV6_NC_STATE_STALE << GNRC_IPV6_NC_STATE_POS);
-
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_nc_still_reachable(&addr));
-    TEST_ASSERT(gnrc_ipv6_nc_is_reachable(entry));
-}
-
-static void test_ipv6_nc_get_l2_addr__NULL_entry(void)
-{
-    gnrc_ipv6_nc_t *entry = NULL;
-    uint8_t l2_addr[GNRC_IPV6_NC_L2_ADDR_MAX];
-    uint8_t l2_addr_len = 0;
-
-    TEST_ASSERT_EQUAL_INT(KERNEL_PID_UNDEF,
-                          gnrc_ipv6_nc_get_l2_addr(l2_addr, &l2_addr_len, entry));
-}
-
-static void test_ipv6_nc_get_l2_addr__unreachable(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-    uint8_t l2_addr[GNRC_IPV6_NC_L2_ADDR_MAX];
-    uint8_t l2_addr_len = 0;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, &addr)));
-    entry->flags = (GNRC_IPV6_NC_STATE_INCOMPLETE << GNRC_IPV6_NC_STATE_POS);
-    TEST_ASSERT_EQUAL_INT(KERNEL_PID_UNDEF,
-                          gnrc_ipv6_nc_get_l2_addr(l2_addr, &l2_addr_len, entry));
-}
-
-static void test_ipv6_nc_get_l2_addr__reachable(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    gnrc_ipv6_nc_t *entry = NULL;
-    uint8_t l2_addr[GNRC_IPV6_NC_L2_ADDR_MAX];
-    uint8_t l2_addr_len = 0;
-
-    test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, &addr)));
-    entry->flags = (GNRC_IPV6_NC_STATE_REACHABLE << GNRC_IPV6_NC_STATE_POS);
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF,
-                          gnrc_ipv6_nc_get_l2_addr(l2_addr, &l2_addr_len, entry));
-    TEST_ASSERT_EQUAL_STRING(TEST_STRING4, (char *)l2_addr);
-    TEST_ASSERT_EQUAL_INT(sizeof(TEST_STRING4), l2_addr_len);
-}
-
-Test *tests_ipv6_nc_tests(void)
-{
-    EMB_UNIT_TESTFIXTURES(fixtures) {
-        new_TestFixture(test_ipv6_nc_add__address_registered),
-        new_TestFixture(test_ipv6_nc_add__address_NULL),
-        new_TestFixture(test_ipv6_nc_add__iface_KERNEL_PID_UNDEF),
-        new_TestFixture(test_ipv6_nc_add__addr_unspecified),
-        new_TestFixture(test_ipv6_nc_add__l2addr_too_long),
-        new_TestFixture(test_ipv6_nc_add__full),
-        new_TestFixture(test_ipv6_nc_add__success),
-        new_TestFixture(test_ipv6_nc_add__address_update_despite_free_entry),
-        new_TestFixture(test_ipv6_nc_remove__no_entry_pid),
-        new_TestFixture(test_ipv6_nc_remove__no_entry_addr1),
-        new_TestFixture(test_ipv6_nc_remove__no_entry_addr2),
-        new_TestFixture(test_ipv6_nc_remove__success),
-        new_TestFixture(test_ipv6_nc_get__empty),
-        new_TestFixture(test_ipv6_nc_get__different_if),
-        new_TestFixture(test_ipv6_nc_get__different_addr),
-        new_TestFixture(test_ipv6_nc_get__success_if_local),
-        new_TestFixture(test_ipv6_nc_get__success_if_global),
-        new_TestFixture(test_ipv6_nc_get_next__empty),
-        new_TestFixture(test_ipv6_nc_get_next__1_entry),
-        new_TestFixture(test_ipv6_nc_get_next__2_entries),
-        new_TestFixture(test_ipv6_nc_get_next__holey),
-        new_TestFixture(test_ipv6_nc_get_next_router__empty),
-        new_TestFixture(test_ipv6_nc_get_next_router__first_entry),
-        new_TestFixture(test_ipv6_nc_get_next_router__second_entry),
-        new_TestFixture(test_ipv6_nc_is_reachable__incomplete),
-        new_TestFixture(test_ipv6_nc_is_reachable__reachable),
-        new_TestFixture(test_ipv6_nc_is_reachable__unmanaged),
-        new_TestFixture(test_ipv6_nc_still_reachable__incomplete),
-        new_TestFixture(test_ipv6_nc_still_reachable__success),
-        new_TestFixture(test_ipv6_nc_get_l2_addr__NULL_entry),
-        new_TestFixture(test_ipv6_nc_get_l2_addr__unreachable),
-        new_TestFixture(test_ipv6_nc_get_l2_addr__reachable),
-    };
-
-    EMB_UNIT_TESTCALLER(ipv6_nc_tests, set_up, tear_down, fixtures);
-
-    return (Test *)&ipv6_nc_tests;
-}
-
-void tests_ipv6_nc(void)
-{
-    TESTS_RUN(tests_ipv6_nc_tests());
-}
-/** @} */
diff --git a/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.h b/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.h
deleted file mode 100644
index 457c6baa9a7455cccfc0d1ae3f43efc4472c9681..0000000000000000000000000000000000000000
--- a/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2014 Martin Lenders
- *
- * 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.
- */
-
-/**
- * @addtogroup  unittests
- * @{
- *
- * @file
- * @brief       Unittests for the ``ipv6_nc`` module
- *
- * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
- */
-#ifndef TESTS_IPV6_NC_H
-#define TESTS_IPV6_NC_H
-
-#include "embUnit.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief   The entry point of this test suite.
- */
-void tests_ipv6_nc(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* TESTS_IPV6_NC_H */
-/** @} */
diff --git a/tests/unittests/tests-ipv6_netif/Makefile b/tests/unittests/tests-ipv6_netif/Makefile
deleted file mode 100644
index 48422e909a47d7cd428d10fa73825060ccc8d8c2..0000000000000000000000000000000000000000
--- a/tests/unittests/tests-ipv6_netif/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-include $(RIOTBASE)/Makefile.base
diff --git a/tests/unittests/tests-ipv6_netif/Makefile.include b/tests/unittests/tests-ipv6_netif/Makefile.include
deleted file mode 100644
index 5a15cf42f54d7569f5baa7bae7f2bb8e6edae60d..0000000000000000000000000000000000000000
--- a/tests/unittests/tests-ipv6_netif/Makefile.include
+++ /dev/null
@@ -1,6 +0,0 @@
-USEMODULE += ipv6_addr
-USEMODULE += gnrc_ipv6_netif
-USEMODULE += gnrc_netif
-USEMODULE += gnrc_ndp_node
-
-CFLAGS += -DGNRC_NETIF_NUMOF=3
diff --git a/tests/unittests/tests-ipv6_netif/tests-ipv6_netif.c b/tests/unittests/tests-ipv6_netif/tests-ipv6_netif.c
deleted file mode 100644
index a4150474619e311a0aba8d43e1f022a64e78b4ed..0000000000000000000000000000000000000000
--- a/tests/unittests/tests-ipv6_netif/tests-ipv6_netif.c
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * 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 <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "embUnit/embUnit.h"
-
-#include "byteorder.h"
-#include "net/gnrc/netif.h"
-#include "net/gnrc/ipv6/netif.h"
-
-#include "unittests-constants.h"
-#include "tests-ipv6_netif.h"
-
-/* default interface for testing */
-#define DEFAULT_TEST_NETIF      (TEST_UINT16)
-/* default IPv6 addr for testing */
-#define DEFAULT_TEST_IPV6_ADDR  { { \
-            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \
-        } \
-    }
-/* default IPv6 prefix length */
-#define DEFAULT_TEST_PREFIX_LEN (18)
-
-/* another interface for testing */
-#define OTHER_TEST_NETIF        (TEST_UINT16 + TEST_UINT8)
-/* another IPv6 addr for testing */
-#define OTHER_TEST_IPV6_ADDR    { { \
-            0x0f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \
-        } \
-    }
-/* matches DEFAULT_TEST_IPV6_ADDR with 18 byte */
-#define DEFAULT_TEST_IPV6_PREFIX18  { { \
-            0x00, 0x01, 0x22, 0x03, 0x04, 0x05, 0x06, 0x07, \
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \
-        } \
-    }
-/* matches DEFAULT_TEST_IPV6_ADDR with 23 byte */
-#define DEFAULT_TEST_IPV6_PREFIX23  { { \
-            0x00, 0x01, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, \
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \
-        } \
-    }
-/* matches DEFAULT_TEST_IPV6_ADDR with 64 byte */
-#define DEFAULT_TEST_IPV6_PREFIX64  { { \
-            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
-            0x88, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \
-        } \
-    }
-
-static void set_up(void)
-{
-    gnrc_netif_init();
-    gnrc_ipv6_netif_init();
-}
-
-static void test_ipv6_netif_add__success(void)
-{
-    gnrc_ipv6_netif_t *entry;
-
-    gnrc_ipv6_netif_add(DEFAULT_TEST_NETIF);
-
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_netif_get(DEFAULT_TEST_NETIF)));
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, entry->pid);
-}
-
-static void test_netif_add__success_with_ipv6(void)
-{
-    kernel_pid_t pids[GNRC_NETIF_NUMOF];
-    size_t pid_num;
-    gnrc_ipv6_netif_t *entry;
-    ipv6_addr_t exp_addr = IPV6_ADDR_ALL_NODES_LINK_LOCAL;
-
-    gnrc_netif_add(DEFAULT_TEST_NETIF);
-
-    TEST_ASSERT_EQUAL_INT(1, (pid_num = gnrc_netif_get(pids)));
-    TEST_ASSERT_EQUAL_INT(1, pid_num);
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, pids[0]);
-    TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_netif_get(DEFAULT_TEST_NETIF)));
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, entry->pid);
-    TEST_ASSERT_EQUAL_STRING((char *)exp_addr.u8, (char *)entry->addrs[0].addr.u8);
-}
-
-static void test_ipv6_netif_add__despite_free_entry(void)
-{
-    /* Tests for possible duplicates as described in http://github.com/RIOT-OS/RIOT/issues/2965 */
-
-    gnrc_ipv6_netif_add(OTHER_TEST_NETIF);
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    /* create space by removing first entry */
-    gnrc_ipv6_netif_remove(OTHER_TEST_NETIF);
-
-    /* add DEFAULT_TEST_NETIF yet again and remove it */
-    test_ipv6_netif_add__success();
-    gnrc_ipv6_netif_remove(DEFAULT_TEST_NETIF);
-
-    /* see if there's a duplicate left */
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_get(DEFAULT_TEST_NETIF));
-}
-
-static void test_ipv6_netif_remove__not_allocated(void)
-{
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-    gnrc_ipv6_netif_remove(OTHER_TEST_NETIF);
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_get(OTHER_TEST_NETIF));
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_get(DEFAULT_TEST_NETIF));
-}
-
-static void test_ipv6_netif_remove__success(void)
-{
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-    gnrc_ipv6_netif_remove(DEFAULT_TEST_NETIF);
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_get(DEFAULT_TEST_NETIF));
-}
-
-static void test_ipv6_netif_get__empty(void)
-{
-    for (kernel_pid_t pid = KERNEL_PID_FIRST; pid <= KERNEL_PID_LAST; pid++) {
-        TEST_ASSERT_NULL(gnrc_ipv6_netif_get(pid));
-    }
-}
-
-static void test_ipv6_netif_add_addr__no_iface1(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &addr, DEFAULT_TEST_PREFIX_LEN, 0));
-}
-
-static void test_ipv6_netif_add_addr__no_iface2(void)
-{
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, NULL, DEFAULT_TEST_PREFIX_LEN, 0));
-}
-
-static void test_ipv6_netif_add_addr__addr_NULL(void)
-{
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, NULL, DEFAULT_TEST_PREFIX_LEN, 0));
-}
-
-static void test_ipv6_netif_add_addr__addr_unspecified(void)
-{
-    ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED;
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &addr, DEFAULT_TEST_PREFIX_LEN, 0));
-}
-
-static void test_ipv6_netif_add_addr__full(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR, *res = &addr;
-    int i;
-
-    /* make link local to avoid automatic link local adding */
-    ipv6_addr_set_link_local_prefix(&addr);
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    for (i = 0; res != NULL; i++, addr.u8[15]++) {
-        res =  gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &addr, DEFAULT_TEST_PREFIX_LEN, 0);
-    }
-}
-
-static void test_ipv6_netif_add_addr__success(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &addr,
-                                                  DEFAULT_TEST_PREFIX_LEN, 0));
-}
-
-static void test_ipv6_netif_add_addr__despite_free_entry(void)
-{
-    /* Tests for possible duplicates as described in http://github.com/RIOT-OS/RIOT/issues/2965 */
-    ipv6_addr_t *entry_1;
-    ipv6_addr_t *entry_2;
-
-    ipv6_addr_t default_addr = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t sol_addr;
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    /* add addresses to the interface */
-    TEST_ASSERT_NOT_NULL((entry_1 = gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &default_addr,
-                                                             DEFAULT_TEST_PREFIX_LEN, 0)));
-
-    /* remove default_addr, but not the corresponding solicited-node addr that
-     * came with it */
-    gnrc_ipv6_netif_remove_addr(DEFAULT_TEST_NETIF, &default_addr);
-
-    /* create and re-add corresponding solicited node address and check that it
-     * hasn't taken the old place of default_addr*/
-    ipv6_addr_set_solicited_nodes(&sol_addr, &default_addr);
-    TEST_ASSERT_NOT_NULL((entry_2 = gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &sol_addr,
-                                                             DEFAULT_TEST_PREFIX_LEN, 0)));
-
-    TEST_ASSERT(entry_1 != entry_2);
-}
-
-static void test_ipv6_netif_remove_addr__not_allocated(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t other_addr = OTHER_TEST_IPV6_ADDR;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    gnrc_ipv6_netif_remove_addr(DEFAULT_TEST_NETIF, &other_addr);
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &other_addr));
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_netif_remove_addr__success(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    gnrc_ipv6_netif_remove_addr(DEFAULT_TEST_NETIF, &addr);
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_netif_reset_addr__success(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    gnrc_ipv6_netif_reset_addr(DEFAULT_TEST_NETIF);
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_netif_find_by_addr__empty(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t *out = NULL;
-
-    TEST_ASSERT_EQUAL_INT(KERNEL_PID_UNDEF, gnrc_ipv6_netif_find_by_addr(&out, &addr));
-    TEST_ASSERT_NULL(out);
-}
-
-static void test_ipv6_netif_find_by_addr__success(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, gnrc_ipv6_netif_find_by_addr(&out, &addr));
-    TEST_ASSERT_NOT_NULL(out);
-    TEST_ASSERT(out != &addr);
-    TEST_ASSERT_EQUAL_INT(true, ipv6_addr_equal(out, &addr));
-}
-
-static void test_ipv6_netif_find_addr__no_iface(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_netif_find_addr__wrong_iface(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_find_addr(OTHER_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_netif_find_addr__wrong_addr(void)
-{
-    ipv6_addr_t addr = OTHER_TEST_IPV6_ADDR;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr));
-}
-
-static void test_ipv6_netif_find_addr__success(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT(out != &addr);
-    TEST_ASSERT_EQUAL_INT(true, ipv6_addr_equal(out, &addr));
-
-    /* also test for link local address */
-    ipv6_addr_set_solicited_nodes(&addr, &addr);
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT_EQUAL_INT(true, ipv6_addr_equal(out, &addr));
-}
-
-static void test_ipv6_netif_find_by_prefix__success1(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_PREFIX23;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, gnrc_ipv6_netif_find_by_prefix(&out, &addr));
-    TEST_ASSERT_NOT_NULL(out);
-    TEST_ASSERT(out != &addr);
-    TEST_ASSERT_EQUAL_INT(23, ipv6_addr_match_prefix(out, &addr));
-}
-
-static void test_ipv6_netif_find_by_prefix__success2(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_PREFIX18;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, gnrc_ipv6_netif_find_by_prefix(&out, &addr));
-    TEST_ASSERT_NOT_NULL(out);
-    TEST_ASSERT(out != &addr);
-    TEST_ASSERT_EQUAL_INT(18, ipv6_addr_match_prefix(out, &addr));
-}
-
-static void test_ipv6_netif_find_by_prefix__success3(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_PREFIX64;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, gnrc_ipv6_netif_find_by_prefix(&out, &addr));
-    TEST_ASSERT_NOT_NULL(out);
-    TEST_ASSERT(out != &addr);
-    TEST_ASSERT_EQUAL_INT(64, ipv6_addr_match_prefix(out, &addr));
-}
-
-static void test_ipv6_netif_match_prefix__success1(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_PREFIX23;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_match_prefix(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT(out != &addr);
-    TEST_ASSERT_EQUAL_INT(23, ipv6_addr_match_prefix(out, &addr));
-}
-
-static void test_ipv6_netif_match_prefix__success2(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_PREFIX18;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_match_prefix(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT(out != &addr);
-    TEST_ASSERT_EQUAL_INT(18, ipv6_addr_match_prefix(out, &addr));
-}
-
-static void test_ipv6_netif_match_prefix__success3(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_PREFIX64;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_match_prefix(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT(out != &addr);
-    TEST_ASSERT_EQUAL_INT(64, ipv6_addr_match_prefix(out, &addr));
-}
-
-static void test_ipv6_netif_find_best_src_addr__no_unicast(void)
-{
-    ipv6_addr_t ll_dst_addr = IPV6_ADDR_UNSPECIFIED;
-    ipv6_addr_t mc_addr1 = IPV6_ADDR_ALL_NODES_LINK_LOCAL;
-    ipv6_addr_t mc_addr2 = IPV6_ADDR_ALL_ROUTERS_SITE_LOCAL;
-
-    ll_dst_addr.u8[15] = 1;
-    ipv6_addr_set_link_local_prefix(&ll_dst_addr);
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &mc_addr1,
-                                                  DEFAULT_TEST_PREFIX_LEN, 0));
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &mc_addr2,
-                                                  DEFAULT_TEST_PREFIX_LEN, 0));
-
-    TEST_ASSERT_NULL(gnrc_ipv6_netif_find_best_src_addr(DEFAULT_TEST_NETIF, &ll_dst_addr, false));
-}
-
-static void test_ipv6_netif_find_best_src_addr__success(void)
-{
-    ipv6_addr_t ll_addr1 = IPV6_ADDR_UNSPECIFIED;
-    ipv6_addr_t ll_addr2 = IPV6_ADDR_UNSPECIFIED;
-    ipv6_addr_t mc_addr = IPV6_ADDR_ALL_NODES_LINK_LOCAL;
-    ipv6_addr_t *out = NULL;
-
-    ll_addr1.u8[15] = 1;
-    ipv6_addr_set_link_local_prefix(&ll_addr1);
-    ll_addr2.u8[15] = 2;
-    ipv6_addr_set_link_local_prefix(&ll_addr2);
-
-    TEST_ASSERT_EQUAL_INT(126, ipv6_addr_match_prefix(&ll_addr2, &ll_addr1));
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &mc_addr,
-                                                  DEFAULT_TEST_PREFIX_LEN, 0));
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &ll_addr1,
-                                                  DEFAULT_TEST_PREFIX_LEN, 0));
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_best_src_addr(DEFAULT_TEST_NETIF, &ll_addr2, false)));
-    TEST_ASSERT(out != &ll_addr1);
-    TEST_ASSERT(out != &ll_addr2);
-    TEST_ASSERT_EQUAL_INT(true, ipv6_addr_equal(out, &ll_addr1));
-}
-
-static void test_ipv6_netif_find_best_src_addr__multicast_input(void)
-{
-    ipv6_addr_t mc_addr = IPV6_ADDR_ALL_ROUTERS_LINK_LOCAL;
-    ipv6_addr_t *out = NULL;
-
-    /* Adds DEFAULT_TEST_NETIF as interface and to it fe80::1, fe80::2 and ff02::1 */
-    test_ipv6_netif_find_best_src_addr__success();
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_best_src_addr(DEFAULT_TEST_NETIF, &mc_addr, false)));
-    TEST_ASSERT_EQUAL_INT(false, ipv6_addr_equal(&mc_addr, out));
-    TEST_ASSERT_EQUAL_INT(false, ipv6_addr_is_unspecified(out));
-}
-
-static void test_ipv6_netif_find_best_src_addr__other_subnet(void)
-{
-    ipv6_addr_t addr1 = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t addr2 = OTHER_TEST_IPV6_ADDR;
-
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &addr1, DEFAULT_TEST_PREFIX_LEN,
-                         0));
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_best_src_addr(DEFAULT_TEST_NETIF, &addr2, false)));
-    TEST_ASSERT(out != &addr1);
-    TEST_ASSERT_EQUAL_INT(true, ipv6_addr_equal(out, &addr1));
-}
-
-static void test_ipv6_netif_addr_is_non_unicast__unicast(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add_addr__success(); /* adds DEFAULT_TEST_IPV6_ADDR to
-                                          * DEFAULT_TEST_NETIF */
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT_EQUAL_INT(false, gnrc_ipv6_netif_addr_is_non_unicast(out));
-}
-
-static void test_ipv6_netif_addr_is_non_unicast__anycast(void)
-{
-    ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &addr, DEFAULT_TEST_PREFIX_LEN,
-                         GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST));
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT_EQUAL_INT(true, gnrc_ipv6_netif_addr_is_non_unicast(out));
-}
-
-static void test_ipv6_netif_addr_is_non_unicast__multicast1(void)
-{
-    ipv6_addr_t addr = IPV6_ADDR_ALL_ROUTERS_LINK_LOCAL;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &addr,
-                                                  DEFAULT_TEST_PREFIX_LEN, 0));
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT_EQUAL_INT(true, gnrc_ipv6_netif_addr_is_non_unicast(out));
-}
-
-static void test_ipv6_netif_addr_is_non_unicast__multicast2(void)
-{
-    ipv6_addr_t addr = IPV6_ADDR_ALL_ROUTERS_LINK_LOCAL;
-    ipv6_addr_t *out = NULL;
-
-    test_ipv6_netif_add__success(); /* adds DEFAULT_TEST_NETIF as interface */
-
-    TEST_ASSERT_NOT_NULL(gnrc_ipv6_netif_add_addr(DEFAULT_TEST_NETIF, &addr, DEFAULT_TEST_PREFIX_LEN,
-                                                  GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST));
-
-    TEST_ASSERT_NOT_NULL((out = gnrc_ipv6_netif_find_addr(DEFAULT_TEST_NETIF, &addr)));
-    TEST_ASSERT_EQUAL_INT(true, gnrc_ipv6_netif_addr_is_non_unicast(out));
-}
-
-Test *tests_ipv6_netif_tests(void)
-{
-    EMB_UNIT_TESTFIXTURES(fixtures) {
-        new_TestFixture(test_ipv6_netif_add__success),
-        new_TestFixture(test_netif_add__success_with_ipv6),
-        new_TestFixture(test_ipv6_netif_add__despite_free_entry),
-        new_TestFixture(test_ipv6_netif_remove__not_allocated),
-        new_TestFixture(test_ipv6_netif_remove__success),
-        new_TestFixture(test_ipv6_netif_get__empty),
-        new_TestFixture(test_ipv6_netif_add_addr__no_iface1),
-        new_TestFixture(test_ipv6_netif_add_addr__no_iface2),
-        new_TestFixture(test_ipv6_netif_add_addr__addr_NULL),
-        new_TestFixture(test_ipv6_netif_add_addr__addr_unspecified),
-        new_TestFixture(test_ipv6_netif_add_addr__full),
-        new_TestFixture(test_ipv6_netif_add_addr__success),
-        new_TestFixture(test_ipv6_netif_add_addr__despite_free_entry),
-        new_TestFixture(test_ipv6_netif_remove_addr__not_allocated),
-        new_TestFixture(test_ipv6_netif_remove_addr__success),
-        new_TestFixture(test_ipv6_netif_reset_addr__success),
-        new_TestFixture(test_ipv6_netif_find_by_addr__empty),
-        new_TestFixture(test_ipv6_netif_find_by_addr__success),
-        new_TestFixture(test_ipv6_netif_find_addr__no_iface),
-        new_TestFixture(test_ipv6_netif_find_addr__wrong_iface),
-        new_TestFixture(test_ipv6_netif_find_addr__wrong_addr),
-        new_TestFixture(test_ipv6_netif_find_addr__success),
-        new_TestFixture(test_ipv6_netif_find_by_prefix__success1),
-        new_TestFixture(test_ipv6_netif_find_by_prefix__success2),
-        new_TestFixture(test_ipv6_netif_find_by_prefix__success3),
-        new_TestFixture(test_ipv6_netif_match_prefix__success1),
-        new_TestFixture(test_ipv6_netif_match_prefix__success2),
-        new_TestFixture(test_ipv6_netif_match_prefix__success3),
-        new_TestFixture(test_ipv6_netif_find_best_src_addr__no_unicast),
-        new_TestFixture(test_ipv6_netif_find_best_src_addr__success),
-        new_TestFixture(test_ipv6_netif_find_best_src_addr__multicast_input),
-        new_TestFixture(test_ipv6_netif_find_best_src_addr__other_subnet),
-        new_TestFixture(test_ipv6_netif_addr_is_non_unicast__unicast),
-        new_TestFixture(test_ipv6_netif_addr_is_non_unicast__anycast),
-        new_TestFixture(test_ipv6_netif_addr_is_non_unicast__multicast1),
-        new_TestFixture(test_ipv6_netif_addr_is_non_unicast__multicast2),
-    };
-
-    EMB_UNIT_TESTCALLER(ipv6_netif_tests, set_up, NULL, fixtures);
-
-    return (Test *)&ipv6_netif_tests;
-}
-
-void tests_ipv6_netif(void)
-{
-    TESTS_RUN(tests_ipv6_netif_tests());
-}
-/** @} */
diff --git a/tests/unittests/tests-ipv6_netif/tests-ipv6_netif.h b/tests/unittests/tests-ipv6_netif/tests-ipv6_netif.h
deleted file mode 100644
index 5962a8f925e4e531c99bd0ae25a1b4791889c6dd..0000000000000000000000000000000000000000
--- a/tests/unittests/tests-ipv6_netif/tests-ipv6_netif.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * @addtogroup  unittests
- * @{
- *
- * @file
- * @brief       Unittests for the ``gnrc_ipv6_netif`` module
- *
- * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
- */
-#ifndef TESTS_IPV6_NETIF_H
-#define TESTS_IPV6_NETIF_H
-
-#include "embUnit.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief   The entry point of this test suite.
- */
-void tests_ipv6_netif(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* TESTS_IPV6_NETIF_H */
-/** @} */