From a7d2c65b362a85a28beae3af187d92f1ab7f3951 Mon Sep 17 00:00:00 2001
From: Martine Lenders <m.lenders@fu-berlin.de>
Date: Mon, 31 Jul 2017 17:51:20 +0200
Subject: [PATCH] gnrc_ipv6_nib: port to gnrc_netif2

---
 Makefile.dep                                  |  57 +---
 sys/include/net/gnrc/ipv6.h                   |   4 +-
 sys/include/net/gnrc/ipv6/nib.h               |  94 +++++-
 sys/include/net/gnrc/ipv6/nib/conf.h          |   6 +-
 sys/include/net/gnrc/netif2/conf.h            |   5 +-
 sys/include/net/gnrc/netif2/ipv6.h            |   5 +-
 sys/net/gnrc/netif2/gnrc_netif2.c             |  13 +-
 .../gnrc/network_layer/icmpv6/gnrc_icmpv6.c   |  42 +--
 sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c   | 141 +--------
 .../ipv6/netif/gnrc_ipv6_netif.c              |   9 -
 .../gnrc/network_layer/ipv6/nib/_nib-6ln.c    | 106 ++++---
 .../gnrc/network_layer/ipv6/nib/_nib-6ln.h    |  26 +-
 .../gnrc/network_layer/ipv6/nib/_nib-6lr.c    |  14 +-
 .../gnrc/network_layer/ipv6/nib/_nib-6lr.h    |  30 +-
 .../gnrc/network_layer/ipv6/nib/_nib-arsm.c   | 206 +++++++++----
 .../gnrc/network_layer/ipv6/nib/_nib-arsm.h   |  59 ++--
 .../network_layer/ipv6/nib/_nib-internal.c    |  61 +---
 .../network_layer/ipv6/nib/_nib-internal.h    |  74 -----
 sys/net/gnrc/network_layer/ipv6/nib/nib.c     | 279 +++++++++++-------
 sys/net/gnrc/network_layer/ipv6/nib/nib_nc.c  |  11 +-
 sys/shell/commands/sc_gnrc_ipv6_nib.c         |   5 +-
 21 files changed, 571 insertions(+), 676 deletions(-)

diff --git a/Makefile.dep b/Makefile.dep
index b350a9a1f7..d7b244c58a 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -136,29 +136,30 @@ endif
 
 ifneq (,$(filter gnrc_sixlowpan_default,$(USEMODULE)))
   USEMODULE += gnrc_ipv6_default
+  USEMODULE += gnrc_ipv6_nib_6ln
   USEMODULE += gnrc_sixlowpan
-  USEMODULE += gnrc_sixlowpan_nd
   USEMODULE += gnrc_sixlowpan_frag
   USEMODULE += gnrc_sixlowpan_iphc
 endif
 
 ifneq (,$(filter gnrc_sixlowpan_router_default,$(USEMODULE)))
   USEMODULE += gnrc_ipv6_router_default
+  USEMODULE += gnrc_ipv6_nib_6lr
   USEMODULE += gnrc_sixlowpan_router
   USEMODULE += gnrc_sixlowpan_frag
   USEMODULE += gnrc_sixlowpan_iphc
 endif
 
 ifneq (,$(filter gnrc_sixlowpan_border_router_default,$(USEMODULE)))
+  USEMODULE += gnrc_ipv6_nib_6lbr
   USEMODULE += gnrc_ipv6_router_default
-  USEMODULE += gnrc_sixlowpan_nd_border_router
   USEMODULE += gnrc_sixlowpan_router
   USEMODULE += gnrc_sixlowpan_frag
   USEMODULE += gnrc_sixlowpan_iphc
 endif
 
 ifneq (,$(filter gnrc_sixlowpan_router,$(USEMODULE)))
-  USEMODULE += gnrc_sixlowpan_nd_router
+  USEMODULE += gnrc_ipv6_router
 endif
 
 ifneq (,$(filter gnrc_sixlowpan_frag,$(USEMODULE)))
@@ -182,50 +183,14 @@ ifneq (,$(filter gnrc_sixlowpan_ctx,$(USEMODULE)))
   USEMODULE += xtimer
 endif
 
-ifneq (,$(filter gnrc_sixlowpan_nd_border_router,$(USEMODULE)))
-  USEMODULE += gnrc_sixlowpan_nd_router
-endif
-
-ifneq (,$(filter gnrc_sixlowpan_nd_router,$(USEMODULE)))
-  USEMODULE += gnrc_sixlowpan_nd
-endif
-
-ifneq (,$(filter gnrc_sixlowpan_nd,$(USEMODULE)))
-  USEMODULE += gnrc_ndp
-  USEMODULE += gnrc_ndp_internal
-  USEMODULE += gnrc_sixlowpan_ctx
-  USEMODULE += random
-  USEMODULE += xtimer
-endif
-
 ifneq (,$(filter gnrc_ipv6_default,$(USEMODULE)))
   USEMODULE += gnrc_ipv6
   USEMODULE += gnrc_icmpv6
-  ifeq (1,$(GNRC_NETIF_NUMOF))
-    ifeq (,$(filter gnrc_sixlowpan_nd,$(USEMODULE)))
-      USEMODULE += gnrc_ndp_host
-    endif
-  else
-    USEMODULE += gnrc_ndp_host
-  endif
 endif
 
 ifneq (,$(filter gnrc_ipv6_router_default,$(USEMODULE)))
   USEMODULE += gnrc_ipv6_router
   USEMODULE += gnrc_icmpv6
-  ifeq (1,$(GNRC_NETIF_NUMOF))
-    ifeq (,$(filter gnrc_sixlowpan_nd_router,$(USEMODULE)))
-      USEMODULE += gnrc_ndp_router
-    endif
-  else
-    USEMODULE += gnrc_ndp_router
-  endif
-endif
-
-ifneq (,$(filter gnrc_ndp_host,$(USEMODULE)))
-  USEMODULE += gnrc_ndp_node
-  USEMODULE += random
-  USEMODULE += xtimer
 endif
 
 ifneq (,$(filter gnrc_ndp_router,$(USEMODULE)))
@@ -242,18 +207,6 @@ ifneq (,$(filter gnrc_ndp_%,$(USEMODULE)))
   USEMODULE += gnrc_ndp
 endif
 
-ifneq (,$(filter gnrc_ndp,$(USEMODULE)))
-  ifneq (,$(filter gnrc_sixlowpan,$(USEMODULE)))
-    USEMODULE += gnrc_sixlowpan_nd
-  else
-    USEMODULE += gnrc_ndp_node
-  endif
-  USEMODULE += gnrc_ndp_internal
-  USEMODULE += gnrc_icmpv6
-  USEMODULE += random
-  USEMODULE += xtimer
-endif
-
 ifneq (,$(filter gnrc_ndp2,$(USEMODULE)))
   USEMODULE += gnrc_icmpv6
   USEMODULE += gnrc_netif2
@@ -302,7 +255,7 @@ ifneq (,$(filter gnrc_ipv6,$(USEMODULE)))
   USEMODULE += inet_csum
   USEMODULE += ipv6_addr
   USEMODULE += gnrc_ipv6_hdr
-  USEMODULE += gnrc_ipv6_nc
+  USEMODULE += gnrc_ipv6_nib
   USEMODULE += gnrc_netif2
 endif
 
diff --git a/sys/include/net/gnrc/ipv6.h b/sys/include/net/gnrc/ipv6.h
index 0b9704b247..661531b4da 100644
--- a/sys/include/net/gnrc/ipv6.h
+++ b/sys/include/net/gnrc/ipv6.h
@@ -36,9 +36,7 @@
 #include "net/ipv6.h"
 #include "net/gnrc/ipv6/ext.h"
 #include "net/gnrc/ipv6/hdr.h"
-#ifndef MODULE_GNRC_IPV6_NIB
-#include "net/gnrc/ipv6/nc.h"
-#endif
+#include "net/gnrc/ipv6/nib.h"
 
 #ifdef MODULE_FIB
 #include "net/fib.h"
diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h
index 0883a2cc58..43fe775635 100644
--- a/sys/include/net/gnrc/ipv6/nib.h
+++ b/sys/include/net/gnrc/ipv6/nib.h
@@ -33,6 +33,7 @@
 #include "net/ipv6/addr.h"
 #include "net/ipv6/hdr.h"
 #include "net/gnrc/ipv6/nib/nc.h"
+#include "net/gnrc/netif2.h"
 #include "net/gnrc/pkt.h"
 
 #ifdef __cplusplus
@@ -194,13 +195,67 @@ extern "C" {
  * @brief   Recalculate reachability timeout time.
  *
  * This message type is for the event of recalculating the reachability timeout
- * time. The expected message context is a valid interface.
+ * time. The expected message context is a valid
+ * [interface](@ref net_gnrc_netif2).
  *
  * @note    Only handled with @ref GNRC_IPV6_NIB_CONF_ARSM != 0
  */
 #define GNRC_IPV6_NIB_RECALC_REACH_TIME     (0x4fceU)
 /** @} */
 
+/**
+ * @brief   Types for gnrc_netif2_ipv6_t::route_info_cb
+ * @anchor  net_gnrc_ipv6_nib_route_info_type
+ */
+enum {
+    GNRC_IPV6_NIB_ROUTE_INFO_TYPE_UNDEF = 0,    /**< undefined */
+    /**
+     * @brief   reactive routing query
+     *
+     * A reactive routing query is issued when a route is unknown to the NIB.
+     * A reactive routing protocol can use this call to search for a route in a
+     * reactive manner.
+     *
+     * The `ctx_addr` will be the destination address of the unknown route,
+     * `ctx` a pointer to the packet as `gnrc_pktsnip_t` that caused the route
+     * look-up (to possibly queue it for later sending).
+     */
+    GNRC_IPV6_NIB_ROUTE_INFO_TYPE_RRQ,
+
+    /**
+     * @brief   route notification
+     *
+     * A route notification is issued when an already established route is
+     * taken. A routing protocol can use this call to update its information on
+     * the route.
+     *
+     * The `ctx_addr` is the prefix of the route, `ctx` is set to a value equal
+     * to the length of the prefix in bits.
+     */
+    GNRC_IPV6_NIB_ROUTE_INFO_TYPE_RN,
+
+    /**
+     * @brief   neighbor state change
+     *
+     * A neighbor state change is issued when ever the NUD state of a neighbor
+     * changes. A routing protocol can use this call to update its information
+     * on routes via this neighbor.
+     *
+     * The `ctx_addr` is the address of the neighbor, `ctx` is a value equal
+     * to the new NUD state as defined in [the NC info flags](@ref
+     * net_gnrc_ipv6_nib_nc_info). If the entry is deleted, `ctx` will be set
+     * to @ref GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE (except if it was
+     * already in the `UNREACHABLE` state). This does not include cache-outs,
+     * since they give no information about the neighbor's reachability (you
+     * might however get an INCOMPLETE or STALE notification due to that, as
+     * soon as the neighbor enters the neighbor cache again).
+     *
+     * Be adviced to only use `ctx_addr` in the context of the callback, since
+     * it might be overwritten, after the callback was left.
+     */
+    GNRC_IPV6_NIB_ROUTE_INFO_TYPE_NSC,
+};
+
 /**
  * @brief   Initialize NIB
  */
@@ -209,11 +264,11 @@ void gnrc_ipv6_nib_init(void);
 /**
  * @brief   Adds an interface to be managed by the NIB.
  *
- * @pre `(KERNEL_PID_UNDEF < iface)`
+ * @pre `netif != NULL`
  *
- * @param[in] iface The interface to be managed by the NIB
+ * @param[in,out] netif The interface to be managed by the NIB
  */
-void gnrc_ipv6_nib_init_iface(kernel_pid_t iface);
+void gnrc_ipv6_nib_init_iface(gnrc_netif2_t *netif);
 
 /**
  * @brief   Gets link-layer address of next hop to a destination address
@@ -221,8 +276,8 @@ void gnrc_ipv6_nib_init_iface(kernel_pid_t iface);
  * @pre `(dst != NULL) && (nce != NULL)`
  *
  * @param[in] dst       Destination address of a packet.
- * @param[in] iface     Restrict search to this interface. May be
- *                      `KERNEL_PID_UNDEF` for any interface.
+ * @param[in] netif     Restrict search to this interface. May be `NULL` for any
+ *                      interface.
  * @param[in] pkt       The IPv6 packet in sending order for which the next hop
  *                      is searched. Needed for queuing for with reactive
  *                      routing or address resolution. May be `NULL`.
@@ -237,13 +292,13 @@ void gnrc_ipv6_nib_init_iface(kernel_pid_t iface);
  *          solicitation sent).
  */
 int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
-                                      kernel_pid_t iface, gnrc_pktsnip_t *pkt,
+                                      gnrc_netif2_t *netif, gnrc_pktsnip_t *pkt,
                                       gnrc_ipv6_nib_nc_t *nce);
 
 /**
  * @brief   Handles a received ICMPv6 packet
  *
- * @pre `iface != KERNEL_PID_UNDEF`
+ * @pre `netif != NULL`
  * @pre `ipv6 != NULL`
  * @pre `icmpv6 != NULL`
  * @pre `icmpv6_len > sizeof(icmpv6_hdr_t)`
@@ -274,13 +329,13 @@ int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
  * @see [RFC 6775, section 8.2.4](https://tools.ietf.org/html/rfc6775#section-8.2.4)
  * @see [RFC 6775, section 8.2.5](https://tools.ietf.org/html/rfc6775#section-8.2.5)
  *
- * @param[in] iface         The interface the packet came over.
+ * @param[in] netif         The interface the packet came over.
  * @param[in] ipv6          The IPv6 header of the received packet.
  * @param[in] icmpv6        The ICMPv6 header and payload of the received
  *                          packet.
  * @param[in] icmpv6_len    The number of bytes at @p icmpv6.
  */
-void gnrc_ipv6_nib_handle_pkt(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+void gnrc_ipv6_nib_handle_pkt(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                               const icmpv6_hdr_t *icmpv6, size_t icmpv6_len);
 
 /**
@@ -292,6 +347,25 @@ void gnrc_ipv6_nib_handle_pkt(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
  */
 void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type);
 
+#if GNRC_IPV6_NIB_CONF_ROUTER || defined(DOXYGEN)
+/**
+ * @brief   Changes the state if an interface advertises itself as a router
+ *          or not
+ *
+ * @param[in] netif     The interface for which the state should be changed.
+ * @param[in] enable    `true`, to enable advertising the interface as a router.
+ *                      `false`, to disable advertising the interface as a
+ *                      router.
+ */
+void gnrc_ipv6_nib_change_rtr_adv_iface(gnrc_netif2_t *netif, bool enable);
+#else
+/**
+ * @brief   Optimization to NOP for non-routers
+ */
+#define gnrc_ipv6_nib_change_rtr_adv_iface(netif, enable) \
+    (void)netif; (void)enable
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/sys/include/net/gnrc/ipv6/nib/conf.h b/sys/include/net/gnrc/ipv6/nib/conf.h
index e3c28286e0..90992df165 100644
--- a/sys/include/net/gnrc/ipv6/nib/conf.h
+++ b/sys/include/net/gnrc/ipv6/nib/conf.h
@@ -199,10 +199,8 @@ extern "C" {
 /**
  * @brief   Maximum link-layer address length (aligned)
  */
-#if (GNRC_NETIF_HDR_L2ADDR_MAX_LEN % 8)
-#define GNRC_IPV6_NIB_L2ADDR_MAX_LEN        (((GNRC_NETIF_HDR_L2ADDR_MAX_LEN >> 3) + 1) << 3)
-#else
-#define GNRC_IPV6_NIB_L2ADDR_MAX_LEN        (GNRC_NETIF_HDR_L2ADDR_MAX_LEN)
+#ifndef GNRC_IPV6_NIB_L2ADDR_MAX_LEN
+#define GNRC_IPV6_NIB_L2ADDR_MAX_LEN        (8U)
 #endif
 
 /**
diff --git a/sys/include/net/gnrc/netif2/conf.h b/sys/include/net/gnrc/netif2/conf.h
index 80544f7169..085f622a25 100644
--- a/sys/include/net/gnrc/netif2/conf.h
+++ b/sys/include/net/gnrc/netif2/conf.h
@@ -20,6 +20,7 @@
 
 #include "net/ieee802154.h"
 #include "net/ethernet/hdr.h"
+#include "net/gnrc/ipv6/nib/conf.h"
 #include "thread.h"
 
 #ifdef __cplusplus
@@ -60,7 +61,7 @@ extern "C" {
  *
  * @note    Used for calculation of @ref GNRC_NETIF2_IPV6_GROUPS_NUMOF
  */
-#ifdef MODULE_GNRC_IPV6_ROUTER
+#if GNRC_IPV6_NIB_CONF_ROUTER
 #define GNRC_NETIF2_IPV6_RTR_ADDR   (1)
 #else
 #define GNRC_NETIF2_IPV6_RTR_ADDR   (0)
@@ -109,7 +110,7 @@ extern "C" {
 #elif   MODULE_CC110X
 #define GNRC_NETIF2_L2ADDR_MAXLEN   (1U)
 #else
-#define GNRC_NETIF2_L2ADDR_MAXLEN   (8U)
+#define GNRC_NETIF2_L2ADDR_MAXLEN   (GNRC_IPV6_NIB_L2ADDR_MAX_LEN)
 #endif
 #endif
 
diff --git a/sys/include/net/gnrc/netif2/ipv6.h b/sys/include/net/gnrc/netif2/ipv6.h
index ba9b9811dc..4357ddcf5b 100644
--- a/sys/include/net/gnrc/netif2/ipv6.h
+++ b/sys/include/net/gnrc/netif2/ipv6.h
@@ -115,9 +115,8 @@ typedef struct {
      * The callback may be `NULL` if no such behavior is required by the routing
      * protocol (or no routing protocol is present).
      *
-     * @todo    Define types (RRQ, RRN, NSC) in NIB
-     *
-     * @param[in] type      Type of the route info.
+     * @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.
      */
diff --git a/sys/net/gnrc/netif2/gnrc_netif2.c b/sys/net/gnrc/netif2/gnrc_netif2.c
index a72c2f9939..18ea7ec008 100644
--- a/sys/net/gnrc/netif2/gnrc_netif2.c
+++ b/sys/net/gnrc/netif2/gnrc_netif2.c
@@ -19,6 +19,9 @@
 #include "net/ethernet.h"
 #include "net/ipv6.h"
 #include "net/gnrc.h"
+#ifdef MODULE_GNRC_IPV6_NIB
+#include "net/gnrc/ipv6/nib.h"
+#endif /* MODULE_GNRC_IPV6_NIB */
 #ifdef MODULE_NETSTATS_IPV6
 #include "net/netstats.h"
 #endif
@@ -278,7 +281,7 @@ int gnrc_netif2_set_from_netdev(gnrc_netif2_t *netif,
             }
             else {
                 if (gnrc_netif2_is_rtr_adv(netif)) {
-                    gnrc_ipv6_nib_iface_cease_rtr_adv(netif);
+                    gnrc_ipv6_nib_change_rtr_adv_iface(netif, false);
                 }
                 netif->flags &= ~GNRC_NETIF2_FLAGS_IPV6_FORWARDING;
             }
@@ -286,12 +289,8 @@ int gnrc_netif2_set_from_netdev(gnrc_netif2_t *netif,
             break;
         case NETOPT_IPV6_SND_RTR_ADV:
             assert(opt->data_len == sizeof(netopt_enable_t));
-            if (*(((netopt_enable_t *)opt->data)) == NETOPT_ENABLE) {
-                gnrc_ipv6_nib_iface_start_rtr_adv(netif);
-            }
-            else {
-                gnrc_ipv6_nib_iface_cease_rtr_adv(netif);
-            }
+            gnrc_ipv6_nib_change_rtr_adv_iface(netif,
+                    (*(((netopt_enable_t *)opt->data)) == NETOPT_ENABLE));
             res = sizeof(netopt_enable_t);
             break;
 #endif  /* GNRC_IPV6_NIB_CONF_ROUTER */
diff --git a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c
index 1ce69e48ac..9184a29b88 100644
--- a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c
+++ b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c
@@ -23,11 +23,7 @@
 #include "kernel_types.h"
 #include "net/ipv6/hdr.h"
 #include "net/gnrc.h"
-#ifndef MODULE_GNRC_IPV6_NIB
-#include "net/gnrc/ndp.h"
-#else
 #include "net/gnrc/ipv6/nib.h"
-#endif
 #include "net/protnum.h"
 #include "od.h"
 #include "utlist.h"
@@ -98,40 +94,6 @@ void gnrc_icmpv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt)
             break;
 #endif
 
-#ifndef MODULE_GNRC_IPV6_NIB
-#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
-        case ICMPV6_RTR_SOL:
-            DEBUG("icmpv6: router solicitation received\n");
-            gnrc_ndp_rtr_sol_handle(iface, pkt, ipv6->data, (ndp_rtr_sol_t *)hdr,
-                                    icmpv6->size);
-            break;
-#endif
-
-#ifdef MODULE_GNRC_NDP
-        case ICMPV6_RTR_ADV:
-            DEBUG("icmpv6: router advertisement received\n");
-            gnrc_ndp_rtr_adv_handle(iface, pkt, ipv6->data, (ndp_rtr_adv_t *)hdr,
-                                    icmpv6->size);
-            break;
-
-        case ICMPV6_NBR_SOL:
-            DEBUG("icmpv6: neighbor solicitation received\n");
-            gnrc_ndp_nbr_sol_handle(iface, pkt, ipv6->data, (ndp_nbr_sol_t *)hdr,
-                                    icmpv6->size);
-            break;
-
-        case ICMPV6_NBR_ADV:
-            DEBUG("icmpv6: neighbor advertisement received\n");
-            gnrc_ndp_nbr_adv_handle(iface, pkt, ipv6->data, (ndp_nbr_adv_t *)hdr,
-                                    icmpv6->size);
-            break;
-#endif
-
-        case ICMPV6_REDIRECT:
-            DEBUG("icmpv6: redirect message received\n");
-            /* TODO */
-            break;
-#else   /* MODULE_GNRC_IPV6_NIB */
         case ICMPV6_RTR_SOL:
         case ICMPV6_RTR_ADV:
         case ICMPV6_NBR_SOL:
@@ -140,9 +102,9 @@ void gnrc_icmpv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt)
         case ICMPV6_DAR:
         case ICMPV6_DAC:
             DEBUG("icmpv6: NDP message received. Handle with gnrc_ipv6_nib\n");
-            gnrc_ipv6_nib_handle_pkt(iface, ipv6->data, hdr, icmpv6->size);
+            gnrc_ipv6_nib_handle_pkt(gnrc_netif2_get_by_pid(iface),
+                                     ipv6->data, hdr, icmpv6->size);
             break;
-#endif  /* MODULE_GNRC_IPV6_NIB */
 
         default:
             DEBUG("icmpv6: unknown type field %u\n", hdr->type);
diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
index ffa95c1ccb..e70da32d35 100644
--- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
+++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
@@ -29,11 +29,7 @@
 #include "thread.h"
 #include "utlist.h"
 
-#ifndef MODULE_GNRC_IPV6_NIB
-#include "net/gnrc/ipv6/nc.h"
-#else
 #include "net/gnrc/ipv6/nib.h"
-#endif
 #include "net/gnrc/netif2/internal.h"
 #include "net/gnrc/ipv6/whitelist.h"
 #include "net/gnrc/ipv6/blacklist.h"
@@ -290,83 +286,6 @@ static void *_event_loop(void *args)
                 msg_reply(&msg, &reply);
                 break;
 
-#ifndef MODULE_GNRC_IPV6_NIB
-#ifdef MODULE_GNRC_NDP
-            case GNRC_NDP_MSG_RTR_TIMEOUT:
-                DEBUG("ipv6: Router timeout received\n");
-                ((gnrc_ipv6_nc_t *)msg.content.ptr)->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
-                break;
-
-            /* XXX reactivate when https://github.com/RIOT-OS/RIOT/issues/5122 is
-             * solved properly */
-            /* case GNRC_NDP_MSG_ADDR_TIMEOUT: */
-            /*     DEBUG("ipv6: Router advertisement timer event received\n"); */
-            /*     gnrc_ipv6_netif_remove_addr(KERNEL_PID_UNDEF, */
-            /*                                 msg.content.ptr); */
-            /*     break; */
-
-            case GNRC_NDP_MSG_NBR_SOL_RETRANS:
-                DEBUG("ipv6: Neigbor solicitation retransmission timer event received\n");
-                gnrc_ndp_retrans_nbr_sol(msg.content.ptr);
-                break;
-
-            case GNRC_NDP_MSG_NC_STATE_TIMEOUT:
-                DEBUG("ipv6: Neigbor cache state timeout received\n");
-                gnrc_ndp_state_timeout(msg.content.ptr);
-                break;
-#endif
-#ifdef MODULE_GNRC_NDP_ROUTER
-            case GNRC_NDP_MSG_RTR_ADV_RETRANS:
-                DEBUG("ipv6: Router advertisement retransmission event received\n");
-                gnrc_ndp_router_retrans_rtr_adv(msg.content.ptr);
-                break;
-            case GNRC_NDP_MSG_RTR_ADV_DELAY:
-                DEBUG("ipv6: Delayed router advertisement event received\n");
-                gnrc_ndp_router_send_rtr_adv(msg.content.ptr);
-                break;
-#endif
-#ifdef MODULE_GNRC_NDP_HOST
-            case GNRC_NDP_MSG_RTR_SOL_RETRANS:
-                DEBUG("ipv6: Router solicitation retransmission event received\n");
-                gnrc_ndp_host_retrans_rtr_sol(msg.content.ptr);
-                break;
-#endif
-#ifdef MODULE_GNRC_SIXLOWPAN_ND
-            case GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL:
-                DEBUG("ipv6: Multicast router solicitation event received\n");
-                gnrc_sixlowpan_nd_mc_rtr_sol(msg.content.ptr);
-                break;
-            case GNRC_SIXLOWPAN_ND_MSG_UC_RTR_SOL:
-                DEBUG("ipv6: Unicast router solicitation event received\n");
-                gnrc_sixlowpan_nd_uc_rtr_sol(msg.content.ptr);
-                break;
-#   ifdef MODULE_GNRC_SIXLOWPAN_CTX
-            case GNRC_SIXLOWPAN_ND_MSG_DELETE_CTX:
-                DEBUG("ipv6: Delete 6LoWPAN context event received\n");
-                gnrc_sixlowpan_ctx_remove(((((gnrc_sixlowpan_ctx_t *)msg.content.ptr)->flags_id) &
-                                           GNRC_SIXLOWPAN_CTX_FLAGS_CID_MASK));
-                break;
-#   endif
-#endif
-#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
-            case GNRC_SIXLOWPAN_ND_MSG_ABR_TIMEOUT:
-                DEBUG("ipv6: border router timeout event received\n");
-                gnrc_sixlowpan_nd_router_abr_remove(msg.content.ptr);
-                break;
-            /* XXX reactivate when https://github.com/RIOT-OS/RIOT/issues/5122 is
-             * solved properly */
-            /* case GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT: */
-            /*     DEBUG("ipv6: address registration timeout received\n"); */
-            /*     gnrc_sixlowpan_nd_router_gc_nc(msg.content.ptr); */
-            /*     break; */
-            case GNRC_NDP_MSG_RTR_ADV_SIXLOWPAN_DELAY:
-                DEBUG("ipv6: Delayed router advertisement event received\n");
-                gnrc_ipv6_nc_t *nc_entry = msg.content.ptr;
-                gnrc_ndp_internal_send_rtr_adv(nc_entry->iface, NULL,
-                                               &(nc_entry->ipv6_addr), false);
-                break;
-#endif
-#else   /* MODULE_GNRC_IPV6_NIB */
             case GNRC_IPV6_NIB_SND_UC_NS:
             case GNRC_IPV6_NIB_SND_MC_NS:
             case GNRC_IPV6_NIB_SND_NA:
@@ -385,7 +304,6 @@ static void *_event_loop(void *args)
                 DEBUG("ipv6: NIB timer event received\n");
                 gnrc_ipv6_nib_handle_timer_event(msg.content.ptr, msg.type);
                 break;
-#endif  /* MODULE_GNRC_IPV6_NIB */
             default:
                 break;
         }
@@ -646,38 +564,6 @@ static void _send_multicast(gnrc_netif2_t *netif, gnrc_pktsnip_t *pkt,
 #endif  /* GNRC_NETIF_NUMOF */
 }
 
-#ifndef MODULE_GNRC_IPV6_NIB
-static inline kernel_pid_t _next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
-                                            kernel_pid_t iface, ipv6_addr_t *dst,
-                                            gnrc_pktsnip_t *pkt)
-{
-    kernel_pid_t found_iface;
-#if defined(MODULE_GNRC_SIXLOWPAN_ND)
-    (void)pkt;
-    found_iface = gnrc_sixlowpan_nd_next_hop_l2addr(l2addr, l2addr_len, iface, dst);
-    if (found_iface > KERNEL_PID_UNDEF) {
-        return found_iface;
-    }
-#endif
-#if defined(MODULE_GNRC_NDP_NODE)
-    found_iface = gnrc_ndp_node_next_hop_l2addr(l2addr, l2addr_len, iface, dst, pkt);
-#elif !defined(MODULE_GNRC_SIXLOWPAN_ND) && defined(MODULE_GNRC_IPV6_NC)
-    (void)pkt;
-    gnrc_ipv6_nc_t *nc = gnrc_ipv6_nc_get(iface, dst);
-    found_iface = gnrc_ipv6_nc_get_l2_addr(l2addr, l2addr_len, nc);
-#elif !defined(MODULE_GNRC_SIXLOWPAN_ND)
-    found_iface = KERNEL_PID_UNDEF;
-    (void)l2addr;
-    (void)l2addr_len;
-    (void)iface;
-    (void)dst;
-    (void)pkt;
-    *l2addr_len = 0;
-#endif
-    return found_iface;
-}
-#endif   /* MODULE_GNRC_IPV6_NIB */
-
 static void _send(gnrc_pktsnip_t *pkt, bool prep_hdr)
 {
     kernel_pid_t iface = KERNEL_PID_UNDEF;
@@ -771,32 +657,10 @@ static void _send(gnrc_pktsnip_t *pkt, bool prep_hdr)
         }
     }
     else {
-#ifndef MODULE_GNRC_IPV6_NIB
-        uint8_t l2addr_len = GNRC_IPV6_NC_L2_ADDR_MAX;
-        uint8_t l2addr[l2addr_len];
-
-        iface = _next_hop_l2addr(l2addr, &l2addr_len, iface, &hdr->dst, pkt);
-
-        if (iface == KERNEL_PID_UNDEF) {
-            DEBUG("ipv6: error determining next hop's link layer address\n");
-            gnrc_pktbuf_release(pkt);
-            return;
-        }
-        netif = gnrc_netif2_get_by_pid(iface);
-        assert(netif != NULL);
-        if (prep_hdr) {
-            if (_fill_ipv6_hdr(netif, ipv6, payload) < 0) {
-                /* error on filling up header */
-                gnrc_pktbuf_release(pkt);
-                return;
-            }
-        }
-
-        _send_unicast(netif, l2addr, l2addr_len, pkt);
-#else   /* MODULE_GNRC_IPV6_NIB */
         gnrc_ipv6_nib_nc_t nce;
+        gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(iface);
 
-        if (gnrc_ipv6_nib_get_next_hop_l2addr(&hdr->dst, iface, pkt,
+        if (gnrc_ipv6_nib_get_next_hop_l2addr(&hdr->dst, netif, pkt,
                                               &nce) < 0) {
             /* packet is released by NIB */
             return;
@@ -814,7 +678,6 @@ static void _send(gnrc_pktsnip_t *pkt, bool prep_hdr)
 
         _send_unicast(netif, nce.l2addr,
                       nce.l2addr_len, pkt);
-#endif  /* MODULE_GNRC_IPV6_NIB */
     }
 }
 
diff --git a/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c b/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c
index 8d71d9092e..b9bf3934d4 100644
--- a/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c
+++ b/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c
@@ -25,9 +25,6 @@
 
 #include "net/eui64.h"
 #include "net/ipv6/addr.h"
-#ifdef MODULE_GNRC_IPV6_NIB
-#include "net/gnrc/ipv6/nib.h"
-#endif
 #include "net/gnrc/ndp.h"
 #include "net/gnrc/netapi.h"
 #include "net/gnrc/netif.h"
@@ -176,11 +173,9 @@ static void _ipv6_netif_remove(gnrc_ipv6_netif_t *entry)
         return;
     }
 
-#ifndef MODULE_GNRC_IPV6_NIB
 #ifdef MODULE_GNRC_NDP
     gnrc_ndp_netif_remove(entry);
 #endif
-#endif  /* MODULE_GNRC_IPV6_NIB */
 
     mutex_lock(&entry->mutex);
     xtimer_remove(&entry->rtr_sol_timer);
@@ -240,13 +235,9 @@ void gnrc_ipv6_netif_add(kernel_pid_t pid)
 
     mutex_unlock(&free_entry->mutex);
 
-#ifndef MODULE_GNRC_IPV6_NIB
 #ifdef MODULE_GNRC_NDP
     gnrc_ndp_netif_add(free_entry);
 #endif
-#else   /* MODULE_GNRC_IPV6_NIB */
-    gnrc_ipv6_nib_init_iface(pid);
-#endif  /* MODULE_GNRC_IPV6_NIB */
 
     DEBUG(" * pid = %" PRIkernel_pid "  ", free_entry->pid);
     DEBUG("cur_hl = %d  ", free_entry->cur_hl);
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 8f0908bdde..e4beb0e09f 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.c
@@ -13,6 +13,7 @@
  * @author  Martine Lenders <m.lenders@fu-berlin.de>
  */
 
+#include "net/gnrc/netif2/internal.h"
 #include "net/gnrc/ipv6/nib.h"
 
 #include "_nib-6ln.h"
@@ -26,49 +27,88 @@
 static char addr_str[IPV6_ADDR_MAX_STR_LEN];
 #endif
 
-static bool _is_iface_eui64(kernel_pid_t iface, const eui64_t *eui64)
+static inline bool _is_iface_eui64(gnrc_netif2_t *netif, const eui64_t *eui64)
 {
-    eui64_t iface_eui64;
+    /* TODO: adapt for short addresses */
+    return (netif->l2addr_len == sizeof(eui64_t)) &&
+            (memcmp(&netif->l2addr, eui64, netif->l2addr_len) == 0);
+}
 
-    /* XXX: this *should* return successful so don't test it ;-) */
-    gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0,
-                    &iface_eui64, sizeof(iface_eui64));
-    return (memcmp(&iface_eui64, eui64, sizeof(iface_eui64)) != 0);
+static inline uint8_t _reverse_iid(const ipv6_addr_t *dst,
+                                   const gnrc_netif2_t *netif, uint8_t *l2addr)
+{
+    switch (netif->device_type) {
+#ifdef MODULE_NETDEV_ETH
+        case NETDEV_TYPE_ETHERNET:
+            l2addr[0] = dst->u8[8] ^ 0x02;
+            l2addr[1] = dst->u8[9];
+            l2addr[2] = dst->u8[10];
+            l2addr[3] = dst->u8[13];
+            l2addr[4] = dst->u8[14];
+            l2addr[5] = dst->u8[15];
+            return ETHERNET_ADDR_LEN;
+#endif
+#ifdef MODULE_NETDEV_IEEE802154
+        case NETDEV_TYPE_IEEE802154:
+            /* assume address was based on EUI-64
+             * (see https://tools.ietf.org/html/rfc6775#section-5.2) */
+            memcpy(l2addr, &dst->u64[1], sizeof(dst->u64[1]));
+            l2addr[0] ^= 0x02;
+            return sizeof(dst->u64[1]);
+#endif
+#ifdef MODULE_CC110X
+        case NETDEV_TYPE_CC110X:
+            l2addr[0] = dst->u8[15];
+            return sizeof(uint8_t);
+#endif
+        default:
+            (void)dst;
+            (void)l2addr;
+            return 0;
+    }
 }
 
-bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, kernel_pid_t iface,
+bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
                              gnrc_ipv6_nib_nc_t *nce)
 {
-    gnrc_ipv6_netif_t *netif = gnrc_ipv6_netif_get(iface);
-    bool res = (netif != NULL) && _is_6ln(netif) &&
+    bool res = (netif != NULL) && gnrc_netif2_is_6ln(netif) &&
                ipv6_addr_is_link_local(dst);
 
     if (res) {
-        memcpy(&nce->ipv6, dst, sizeof(nce->ipv6));
-        memcpy(&nce->l2addr, &dst->u64[1], sizeof(dst->u64[1]));
-        nce->l2addr[0] ^= 0x02;
-        nce->info = 0;
-        nce->info |= (iface << GNRC_IPV6_NIB_NC_INFO_IFACE_POS) &
-                     GNRC_IPV6_NIB_NC_INFO_IFACE_MASK;
-        nce->info |= GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE;
-        nce->info |= GNRC_IPV6_NIB_NC_INFO_AR_STATE_REGISTERED;
-        nce->l2addr_len = sizeof(dst->u64[1]);
+        uint8_t l2addr_len;
+
+        if ((l2addr_len = _reverse_iid(dst, netif, nce->l2addr)) > 0) {
+            DEBUG("nib: resolve address %s%%%u by reverse translating to ",
+                  ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)),
+                  (unsigned)netif->pid);
+            nce->l2addr_len = l2addr_len;
+            DEBUG("%s\n",
+                  gnrc_netif2_addr_to_str(nce->l2addr, nce->l2addr_len,
+                                          addr_str));
+            memcpy(&nce->ipv6, dst, sizeof(nce->ipv6));
+            nce->info = 0;
+            nce->info |= (netif->pid << GNRC_IPV6_NIB_NC_INFO_IFACE_POS) &
+                         GNRC_IPV6_NIB_NC_INFO_IFACE_MASK;
+            nce->info |= GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE;
+            nce->info |= GNRC_IPV6_NIB_NC_INFO_AR_STATE_REGISTERED;
+        }
+        else {
+            res = false;
+        }
     }
     return res;
 }
 
-uint8_t _handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+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)
 {
-    gnrc_ipv6_netif_t *netif = gnrc_ipv6_netif_get(iface);
-
 #if !GNRC_IPV6_NIB_CONF_6LR
     (void)sl2ao;
 #endif
     assert(netif != NULL);
-    if (_is_6ln(netif) && (aro->len == SIXLOWPAN_ND_OPT_AR_LEN)) {
+    if (gnrc_netif2_is_6ln(netif) && (aro->len == SIXLOWPAN_ND_OPT_AR_LEN)) {
         DEBUG("nib: valid ARO received\n");
         DEBUG(" - length: %u\n", aro->len);
         DEBUG(" - status: %u\n", aro->status);
@@ -78,7 +118,7 @@ uint8_t _handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
               aro->eui64.uint8[3], aro->eui64.uint8[4], aro->eui64.uint8[5],
               aro->eui64.uint8[6], aro->eui64.uint8[7]);
         if (icmpv6->type == ICMPV6_NBR_ADV) {
-            if (!_is_iface_eui64(iface, &aro->eui64)) {
+            if (!_is_iface_eui64(netif, &aro->eui64)) {
                 DEBUG("nib: ARO EUI-64 is not mine, ignoring ARO\n");
                 return _ADDR_REG_STATUS_IGNORE;
             }
@@ -92,7 +132,7 @@ uint8_t _handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
                                 (byteorder_ntohs(aro->ltime) - 1U) *
                                 SEC_PER_MIN * MS_PER_SEC;
                     DEBUG("nib: Address registration successful. "
-                               "Scheduling re-registration in %ums\n",
+                               "Scheduling re-registration in %" PRIu32 "ms\n",
                           next_ns);
                     assert(nce != NULL);
                     _evtimer_add(nce, GNRC_IPV6_NIB_SND_UC_NS, &nce->nud_timeout,
@@ -103,22 +143,19 @@ uint8_t _handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
                     DEBUG("nib: Address registration reports duplicate. "
                                "Removing address %s%%%u\n",
                           ipv6_addr_to_str(addr_str,
-                                           &((ndp_nbr_adv_t *)icmpv6)->tgt,
-                                           sizeof(addr_str)),
-                          iface);
-                    gnrc_ipv6_netif_remove_addr(iface,
-                                                &((ndp_nbr_adv_t *)icmpv6)->tgt);
+                                           &ipv6->dst,
+                                           sizeof(addr_str)), netif->pid);
+                    gnrc_netif2_ipv6_addr_remove(netif, &ipv6->dst);
                     /* TODO: generate new address */
                     break;
                 case SIXLOWPAN_ND_STATUS_NC_FULL: {
                         DEBUG("nib: Router's neighbor cache is full. "
                                    "Searching new router for DAD\n");
-                        _nib_dr_entry_t *dr = _nib_drl_get(&ipv6->src, iface);
+                        _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 */
-                            _nib_iface_t *nib_iface = _nib_iface_get(iface);
-                            nib_iface->rs_sent = 0;
+                            netif->ipv6.rs_sent = 0;
                             /* TODO: search new router */
                         }
                         else {
@@ -131,8 +168,9 @@ uint8_t _handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
             return aro->status;
         }
 #if GNRC_IPV6_NIB_CONF_6LR
-        else if (_is_6lr(netif) && (icmpv6->type == ICMPV6_NBR_SOL)) {
-            return _reg_addr_upstream(iface, ipv6, icmpv6, aro, sl2ao);
+        else if (gnrc_netif2_is_6lr(netif) &&
+                 (icmpv6->type == ICMPV6_NBR_SOL)) {
+            return _reg_addr_upstream(netif, ipv6, icmpv6, aro, sl2ao);
         }
 #endif
     }
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 6967c3a8d9..1ba822bf58 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.h
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6ln.h
@@ -44,38 +44,23 @@ extern "C" {
  */
 #define _ADDR_REG_STATUS_IGNORE         (4)
 
-/**
- * @brief   Checks if interface represents a 6LN
- *
- * @todo    Use corresponding function in `gnrc_netif2` instead.
- *
- * @param[in] netif A network interface.
- *
- * @return  true, when the @p netif represents a 6LN.
- * @return  false, when the @p netif does not represent a 6LN.
- */
-static inline bool _is_6ln(const gnrc_ipv6_netif_t *netif)
-{
-    return (netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN);
-}
-
 /**
  * @brief   Resolves address statically from destination address using reverse
  *          translation of the IID
  *
  * @param[in] dst   A destination address.
- * @param[in] iface The interface to @p dst.
+ * @param[in] netif The interface to @p dst.
  * @param[out] nce  Neighbor cache entry to resolve into
  *
  * @return  true when @p nce was set, false when not.
  */
-bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, kernel_pid_t iface,
+bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, gnrc_netif2_t *netif,
                              gnrc_ipv6_nib_nc_t *nce);
 
 /**
  * @brief   Handles ARO
  *
- * @param[in] iface     The interface the ARO-carrying message came over.
+ * @param[in] netif     The interface the ARO-carrying message came over.
  * @param[in] ipv6      The IPv6 header of the message carrying the ARO.
  * @param[in] icmpv6    The message carrying the ARO.
  * @param[in] aro       ARO that carries the address registration information.
@@ -85,13 +70,12 @@ bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, kernel_pid_t iface,
  * @return  registration status of the address (including
  *          @ref _ADDR_REG_STATUS_TENTATIVE and @ref _ADDR_REG_STATUS_IGNORE).
  */
-uint8_t _handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+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);
 #else   /* GNRC_IPV6_NIB_CONF_6LN || defined(DOXYGEN) */
-#define _is_6ln(netif)                              (false)
-#define _resolve_addr_from_ipv6(dst, iface, nce)    (false)
+#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
  */
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 b85ed57558..9cfaf55f0a 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.c
@@ -14,6 +14,7 @@
  */
 
 #include "net/gnrc/ipv6/nib.h"
+#include "net/gnrc/netif2/internal.h"
 #include "net/gnrc/sixlowpan/nd.h"
 
 #include "_nib-6lr.h"
@@ -47,13 +48,13 @@ static uint8_t _update_nce_ar_state(const sixlowpan_nd_opt_ar_t *aro,
     }
 }
 
-uint8_t _reg_addr_upstream(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+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)
 {
     if (!ipv6_addr_is_unspecified(&ipv6->src) && (sl2ao != NULL)) {
-        _nib_onl_entry_t *nce = _nib_onl_get(&ipv6->src, iface);
+        _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",
@@ -66,8 +67,8 @@ uint8_t _reg_addr_upstream(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
 #if GNRC_IPV6_NIB_CONF_MULTIHOP_DAD
             /* TODO */
 #endif
-            if (byteorder_ntohs(aro->ltime) != 0) {
-                _handle_sl2ao(iface, ipv6, icmpv6, sl2ao);
+            if (aro->ltime.u16 != 0) {
+                _handle_sl2ao(netif, ipv6, icmpv6, sl2ao);
                 return _update_nce_ar_state(aro, nce);
             }
             else if (nce != NULL) {
@@ -88,7 +89,8 @@ uint8_t _reg_addr_upstream(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
     return _ADDR_REG_STATUS_IGNORE;
 }
 
-gnrc_pktsnip_t *_copy_and_handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+gnrc_pktsnip_t *_copy_and_handle_aro(gnrc_netif2_t *netif,
+                                     const ipv6_hdr_t *ipv6,
                                      const ndp_nbr_sol_t *nbr_sol,
                                      const sixlowpan_nd_opt_ar_t *aro,
                                      const ndp_opt_t *sl2ao)
@@ -96,7 +98,7 @@ gnrc_pktsnip_t *_copy_and_handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
     gnrc_pktsnip_t *reply_aro = NULL;
 
     if (aro != NULL) {
-        uint8_t status = _handle_aro(iface, ipv6, (icmpv6_hdr_t *)nbr_sol, aro,
+        uint8_t status = _handle_aro(netif, ipv6, (icmpv6_hdr_t *)nbr_sol, aro,
                                      sl2ao, NULL);
 
         if ((status != _ADDR_REG_STATUS_TENTATIVE) &&
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 0fc0049e58..6248600e69 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.h
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-6lr.h
@@ -33,21 +33,6 @@ extern "C" {
 #endif
 
 #if GNRC_IPV6_NIB_CONF_6LR || defined(DOXYGEN)
-/**
- * @brief   Checks if interface represents a 6LR
- *
- * @todo    Use corresponding function in `gnrc_netif2` instead.
- *
- * @param[in] netif A network interface.
- *
- * @return  true, when the @p netif represents a 6LR.
- * @return  false, when the @p netif does not represent a 6LR.
- */
-static inline bool _is_6lr(const gnrc_ipv6_netif_t *netif)
-{
-    return _is_6ln(netif) && (netif->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER);
-}
-
 /**
  * @brief   Gets address registration state of a neighbor
  *
@@ -81,17 +66,17 @@ static inline void _set_ar_state(_nib_onl_entry_t *entry, uint16_t state)
  * @param[in] netif     A network interface.
  * @param[in] icmpv6    An ICMPv6 message.
  */
-static inline bool _rtr_sol_on_6lr(const gnrc_ipv6_netif_t *netif,
+static inline bool _rtr_sol_on_6lr(const gnrc_netif2_t *netif,
                                    const icmpv6_hdr_t *icmpv6)
 {
-    return _is_6lr(netif) && (icmpv6->type == ICMPV6_RTR_SOL);
+    return gnrc_netif2_is_6lr(netif) && (icmpv6->type == ICMPV6_RTR_SOL);
 }
 
 /**
  * @brief   Registers an address to the (upstream; in case of multihop DAD)
  *          router
  *
- * @param[in] iface     The interface the ARO-carrying NS came over.
+ * @param[in] netif     The interface the ARO-carrying NS came over.
  * @param[in] ipv6      The IPv6 header of the message carrying the ARO.
  * @param[in] icmpv6    The neighbor solicitation carrying the ARO
  *                      (handed over as @ref icmpv6_hdr_t, since it is just
@@ -102,7 +87,7 @@ static inline bool _rtr_sol_on_6lr(const gnrc_ipv6_netif_t *netif,
  * @return  registration status of the address (including
  *          @ref _ADDR_REG_STATUS_TENTATIVE and @ref _ADDR_REG_STATUS_IGNORE).
  */
-uint8_t _reg_addr_upstream(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+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);
@@ -111,7 +96,7 @@ uint8_t _reg_addr_upstream(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
 /**
  * @brief   Handles and copies ARO from NS to NA
  *
- * @param[in] iface     The interface the ARO-carrying NS came over.
+ * @param[in] netif     The interface the ARO-carrying NS came over.
  * @param[in] ipv6      The IPv6 header of the message carrying the original
  *                      ARO.
  * @param[in] nbr_sol   The neighbor solicitation carrying the original ARO
@@ -123,16 +108,15 @@ uint8_t _reg_addr_upstream(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
  * @return  registration status of the address (including
  *          @ref _ADDR_REG_STATUS_TENTATIVE and @ref _ADDR_REG_STATUS_IGNORE).
  */
-gnrc_pktsnip_t *_copy_and_handle_aro(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+gnrc_pktsnip_t *_copy_and_handle_aro(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                                      const ndp_nbr_sol_t *nbr_sol,
                                      const sixlowpan_nd_opt_ar_t *aro,
                                      const ndp_opt_t *sl2ao);
 #else   /* GNRC_IPV6_NIB_CONF_6LR || defined(DOXYGEN) */
-#define _is_6lr(netif)                  (false)
 #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(iface, ipv6, icmpv6, aro, sl2ao) \
+#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
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 c678f3cecb..22ac8c2ce1 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c
@@ -16,6 +16,10 @@
 #include "xtimer.h"
 #include "net/gnrc/ndp2.h"
 #include "net/gnrc/ipv6/nib.h"
+#include "net/gnrc/netif2/internal.h"
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+#include "net/gnrc/sixlowpan/nd.h"
+#endif
 
 #include "_nib-arsm.h"
 #include "_nib-6lr.h"
@@ -36,26 +40,50 @@ static char addr_str[IPV6_ADDR_MAX_STR_LEN];
  *
  * @return  The length of the L2 address carried in @p opt.
  */
-static inline unsigned _get_l2addr_len(gnrc_ipv6_netif_t *netif,
+static inline unsigned _get_l2addr_len(gnrc_netif2_t *netif,
                                        const ndp_opt_t *opt);
 
-void _snd_ns(const ipv6_addr_t *tgt, gnrc_ipv6_netif_t *netif,
+void _snd_ns(const ipv6_addr_t *tgt, gnrc_netif2_t *netif,
              const ipv6_addr_t *src, const ipv6_addr_t *dst)
 {
     gnrc_pktsnip_t *ext_opt = NULL;
 
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+    _nib_dr_entry_t *dr = _nib_drl_get_dr();
+
+    assert(netif != NULL);
+    /* add ARO based on interface */
+    if ((src != NULL) && gnrc_netif2_is_6ln(netif) &&
+        (_nib_onl_get_if(dr->next_hop) == (unsigned)netif->pid) &&
+        ipv6_addr_equal(&dr->next_hop->ipv6, dst)) {
+        netdev_t *dev = netif->dev;
+        uint8_t l2src[GNRC_NETIF2_L2ADDR_MAXLEN];
+        size_t l2src_len = (uint16_t)dev->driver->get(dev, NETOPT_ADDRESS_LONG,
+                                                      l2src, sizeof(l2src));
+        if (l2src_len != sizeof(eui64_t)) {
+            DEBUG("nib: can't get EUI-64 of the interface for ARO\n");
+            return;
+        }
+        ext_opt = gnrc_sixlowpan_nd_opt_ar_build(0, GNRC_SIXLOWPAN_ND_AR_LTIME,
+                                                 (eui64_t *)l2src, NULL);
+        if (ext_opt == NULL) {
+            DEBUG("nib: error allocating ARO.\n");
+            return;
+        }
+    }
+#endif  /* MODULE_GNRC_SIXLOWPAN_ND */
     gnrc_ndp2_nbr_sol_send(tgt, netif, src, dst, ext_opt);
 }
 
 void _snd_uc_ns(_nib_onl_entry_t *nbr, bool reset)
 {
-    gnrc_ipv6_netif_t *netif = gnrc_ipv6_netif_get(_nib_onl_get_if(nbr));
-    _nib_iface_t *iface = _nib_iface_get(_nib_onl_get_if(nbr));
+    gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(_nib_onl_get_if(nbr));
 
-    DEBUG("unicast to %s (retrans. timer = %ums)\n",
+    assert(netif != NULL);
+    gnrc_netif2_acquire(netif);
+    DEBUG("nib: unicast to %s (retrans. timer = %ums)\n",
           ipv6_addr_to_str(addr_str, &nbr->ipv6, sizeof(addr_str)),
-          (unsigned)iface->retrans_time);
-    assert((netif != NULL) && (iface != NULL));
+          (unsigned)netif->ipv6.retrans_time);
 #if GNRC_IPV6_NIB_CONF_ARSM
     if (reset) {
         nbr->ns_sent = 0;
@@ -65,20 +93,20 @@ void _snd_uc_ns(_nib_onl_entry_t *nbr, bool reset)
 #endif
     _snd_ns(&nbr->ipv6, netif, NULL, &nbr->ipv6);
     _evtimer_add(nbr, GNRC_IPV6_NIB_SND_UC_NS, &nbr->nud_timeout,
-                 iface->retrans_time);
+                 netif->ipv6.retrans_time);
+    gnrc_netif2_release(netif);
 #if GNRC_IPV6_NIB_CONF_ARSM
     nbr->ns_sent++;
 #endif
 }
 
-void _handle_sl2ao(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+void _handle_sl2ao(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                    const icmpv6_hdr_t *icmpv6, const ndp_opt_t *sl2ao)
 {
-    _nib_onl_entry_t *nce = _nib_onl_get(&ipv6->src, iface);
-    gnrc_ipv6_netif_t *netif = gnrc_ipv6_netif_get(iface);
+    assert(netif != NULL);
+    _nib_onl_entry_t *nce = _nib_onl_get(&ipv6->src, netif->pid);
     unsigned l2addr_len;
 
-    assert(netif != NULL);
     l2addr_len = _get_l2addr_len(netif, sl2ao);
     if (l2addr_len == 0U) {
         DEBUG("nib: Unexpected SL2AO length. Ignoring SL2AO\n");
@@ -93,13 +121,14 @@ void _handle_sl2ao(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
          !_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(nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
+        _set_nud_state(netif, nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
     }
 #endif  /* GNRC_IPV6_NIB_CONF_ARSM */
     if ((nce == NULL) || !(nce->mode & _NC)) {
         DEBUG("nib: Creating NCE for (ipv6 = %s, iface = %u, nud_state = STALE)\n",
-              ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)), iface);
-        nce = _nib_nc_add(&ipv6->src, iface,
+              ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)),
+              netif->pid);
+        nce = _nib_nc_add(&ipv6->src, netif->pid,
                           GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
         if (nce != NULL) {
             if (icmpv6->type == ICMPV6_NBR_SOL) {
@@ -126,13 +155,13 @@ void _handle_sl2ao(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
         if (icmpv6->type == ICMPV6_RTR_ADV) {
             DEBUG("nib: %s%%%u is a router\n",
                   ipv6_addr_to_str(addr_str, &nce->ipv6, sizeof(addr_str)),
-                  iface);
+                  netif->pid);
             nce->info |= GNRC_IPV6_NIB_NC_INFO_IS_ROUTER;
         }
         else if (icmpv6->type != ICMPV6_NBR_SOL) {
             DEBUG("nib: %s%%%u is probably not a router\n",
                   ipv6_addr_to_str(addr_str, &nce->ipv6, sizeof(addr_str)),
-                  iface);
+                  netif->pid);
             nce->info &= ~GNRC_IPV6_NIB_NC_INFO_IS_ROUTER;
         }
 #if GNRC_IPV6_NIB_CONF_ARSM
@@ -146,27 +175,40 @@ void _handle_sl2ao(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
     }
 }
 
-static inline unsigned _get_l2addr_len(gnrc_ipv6_netif_t *netif,
+static inline unsigned _get_l2addr_len(gnrc_netif2_t *netif,
                                        const ndp_opt_t *opt)
 {
-#if GNRC_IPV6_NIB_CONF_6LN
-    if (_is_6ln(netif)) {
-        switch (opt->len) {
-            case 1U:
-                return 2U;
-            case 2U:
-                return 8U;
-            default:
-                return 0U;
-        }
-    }
-#else
-    (void)netif;
-#endif /* GNRC_IPV6_NIB_CONF_6LN */
-    if (opt->len == 1U) {
-        return 6U;
+    switch (netif->device_type) {
+#ifdef MODULE_CC110X
+        case NETDEV_TYPE_CC110X:
+            (void)opt;
+            return sizeof(uint8_t);
+#endif
+#ifdef MODULE_NETDEV_ETH
+        case NETDEV_TYPE_ETHERNET:
+            (void)opt;
+            return ETHERNET_ADDR_LEN;
+#endif
+#ifdef MODULE_NETDEV_NRFMIN
+        case NETDEV_TYPE_NRFMIN:
+            (void)opt;
+            return sizeof(uint16_t);
+#endif
+#ifdef MODULE_NETDEV_IEEE802154
+        case NETDEV_TYPE_IEEE802154:
+            switch (opt->len) {
+                case 1U:
+                    return IEEE802154_SHORT_ADDRESS_LEN;
+                case 2U:
+                    return IEEE802154_LONG_ADDRESS_LEN;
+                default:
+                    return 0U;
+            }
+#endif
+        default:
+            (void)opt;
+            return 0U;
     }
-    return 0U;
 }
 
 #if GNRC_IPV6_NIB_CONF_ARSM
@@ -207,7 +249,7 @@ static inline bool _rflag_set(const ndp_nbr_adv_t *nbr_adv);
  *
  * @param[in] nce               A neighbor cache entry.
  * @param[in] tl2ao             The TL2AO.
- * @param[in] iface             The interface the TL2AO came over.
+ * @param[in] netif             The interface the TL2AO came over.
  * @param[in] tl2ao_addr_len    Length of the L2 address in the TL2AO.
  *
  * @return  `true`, if the TL2AO changes the NCE.
@@ -215,7 +257,7 @@ static inline bool _rflag_set(const ndp_nbr_adv_t *nbr_adv);
  */
 static inline bool _tl2ao_changes_nce(_nib_onl_entry_t *nce,
                                       const ndp_opt_t *tl2ao,
-                                      kernel_pid_t iface,
+                                      gnrc_netif2_t *netif,
                                       unsigned tl2ao_addr_len);
 
 void _handle_snd_ns(_nib_onl_entry_t *nbr)
@@ -233,7 +275,10 @@ void _handle_snd_ns(_nib_onl_entry_t *nbr)
             break;
         case GNRC_IPV6_NIB_NC_INFO_NUD_STATE_PROBE:
             if (nbr->ns_sent >= NDP_MAX_UC_SOL_NUMOF) {
-                _set_nud_state(nbr, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE);
+                gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(_nib_onl_get_if(nbr));
+
+                _set_nud_state(netif, nbr,
+                               GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE);
             }
             /* falls through intentionally */
         case GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE:
@@ -253,13 +298,16 @@ void _handle_state_timeout(_nib_onl_entry_t *nbr)
             DEBUG("nib: Timeout reachability\n");
             new_state = GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE;
             /* falls through intentionally */
-        case GNRC_IPV6_NIB_NC_INFO_NUD_STATE_DELAY:
-            _set_nud_state(nbr, new_state);
+        case GNRC_IPV6_NIB_NC_INFO_NUD_STATE_DELAY: {
+            gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(_nib_onl_get_if(nbr));
+
+            _set_nud_state(netif, nbr, new_state);
             if (new_state == GNRC_IPV6_NIB_NC_INFO_NUD_STATE_PROBE) {
                 DEBUG("nib: Timeout DELAY state\n");
                 _probe_nbr(nbr, true);
             }
             break;
+        }
     }
 }
 
@@ -274,24 +322,25 @@ void _probe_nbr(_nib_onl_entry_t *nbr, bool reset)
             break;
         case GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE:
         case GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE: {
-                _nib_iface_t *iface = _nib_iface_get(_nib_onl_get_if(nbr));
+                gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(_nib_onl_get_if(nbr));
                 uint32_t next_ns = _evtimer_lookup(nbr,
                                                    GNRC_IPV6_NIB_SND_MC_NS);
-                if (next_ns > iface->retrans_time) {
-                    gnrc_ipv6_netif_t *netif = gnrc_ipv6_netif_get(_nib_onl_get_if(nbr));
+
+                assert(netif != NULL);
+                gnrc_netif2_acquire(netif);
+                if (next_ns > netif->ipv6.retrans_time) {
                     ipv6_addr_t sol_nodes;
-                    uint32_t retrans_time = iface->retrans_time;
+                    uint32_t retrans_time = netif->ipv6.retrans_time;
 
                     DEBUG("multicast to %s's solicited nodes ",
                           ipv6_addr_to_str(addr_str, &nbr->ipv6,
                                            sizeof(addr_str)));
-                    assert(netif != NULL);
                     if (reset) {
                         nbr->ns_sent = 0;
                     }
                     if (state == GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE) {
                         /* first 3 retransmissions in PROBE, assume 1 higher to
-                         * not send after iface->retrans_timer sec again,
+                         * not send after netif->ipv6.retrans_timer sec again,
                          * but the next backoff after that => subtract 2 */
                         retrans_time = _exp_backoff_retrans_timer(nbr->ns_sent - 2,
                                                                   retrans_time);
@@ -312,9 +361,10 @@ void _probe_nbr(_nib_onl_entry_t *nbr, bool reset)
                           "a multicast NS within %ums)\n",
                           ipv6_addr_to_str(addr_str, &nbr->ipv6,
                                            sizeof(addr_str)),
-                          (unsigned)iface->retrans_time);
+                          (unsigned)netif->ipv6.retrans_time);
                 }
 #endif
+                gnrc_netif2_release(netif);
             }
             break;
         case GNRC_IPV6_NIB_NC_INFO_NUD_STATE_PROBE:
@@ -324,10 +374,9 @@ void _probe_nbr(_nib_onl_entry_t *nbr, bool reset)
     }
 }
 
-void _handle_adv_l2(kernel_pid_t iface, _nib_onl_entry_t *nce,
+void _handle_adv_l2(gnrc_netif2_t *netif, _nib_onl_entry_t *nce,
                     const icmpv6_hdr_t *icmpv6, const ndp_opt_t *tl2ao)
 {
-    gnrc_ipv6_netif_t *netif = gnrc_ipv6_netif_get(iface);
     unsigned l2addr_len = 0;
 
     assert(nce != NULL);
@@ -342,7 +391,7 @@ void _handle_adv_l2(kernel_pid_t iface, _nib_onl_entry_t *nce,
     if ((_get_nud_state(nce) == GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE) ||
         _oflag_set((ndp_nbr_adv_t *)icmpv6) ||
         _redirect_with_tl2ao(icmpv6, tl2ao) ||
-        _tl2ao_changes_nce(nce, tl2ao, iface, l2addr_len)) {
+        _tl2ao_changes_nce(nce, tl2ao, netif, l2addr_len)) {
         bool nce_was_incomplete =
             (_get_nud_state(nce) == GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE);
         if (tl2ao != NULL) {
@@ -353,17 +402,17 @@ void _handle_adv_l2(kernel_pid_t iface, _nib_onl_entry_t *nce,
             nce->l2addr_len = 0;
         }
         if (_sflag_set((ndp_nbr_adv_t *)icmpv6)) {
-            _set_reachable(iface, nce);
+            _set_reachable(netif, nce);
         }
         else if ((icmpv6->type != ICMPV6_NBR_ADV) ||
                  !_sflag_set((ndp_nbr_adv_t *)icmpv6) ||
                  (!nce_was_incomplete &&
-                  _tl2ao_changes_nce(nce, tl2ao, iface, l2addr_len))) {
+                  _tl2ao_changes_nce(nce, tl2ao, netif, l2addr_len))) {
             DEBUG("nib: Set %s%%%u to STALE\n",
                   ipv6_addr_to_str(addr_str, &nce->ipv6, sizeof(addr_str)),
-                  iface);
+                  (unsigned)netif->pid);
             evtimer_del(&_nib_evtimer, &nce->nud_timeout.event);
-            _set_nud_state(nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
+            _set_nud_state(netif, nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
         }
         if (_oflag_set((ndp_nbr_adv_t *)icmpv6) ||
             ((icmpv6->type == ICMPV6_NBR_ADV) && nce_was_incomplete)) {
@@ -391,30 +440,57 @@ void _handle_adv_l2(kernel_pid_t iface, _nib_onl_entry_t *nce,
         if ((icmpv6->type == ICMPV6_NBR_ADV) &&
             !_sflag_set((ndp_nbr_adv_t *)icmpv6) &&
             (_get_nud_state(nce) == GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE) &&
-            _tl2ao_changes_nce(nce, tl2ao, iface, l2addr_len)) {
+            _tl2ao_changes_nce(nce, tl2ao, netif, l2addr_len)) {
             evtimer_del(&_nib_evtimer, &nce->nud_timeout.event);
-            _set_nud_state(nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
+            _set_nud_state(netif, nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
         }
     }
     else if ((icmpv6->type == ICMPV6_NBR_ADV) &&
              (_get_nud_state(nce) != GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE) &&
              (_get_nud_state(nce) != GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED) &&
              _sflag_set((ndp_nbr_adv_t *)icmpv6) &&
-             !_tl2ao_changes_nce(nce, tl2ao, iface, l2addr_len)) {
-        _set_reachable(iface, nce);
+             !_tl2ao_changes_nce(nce, tl2ao, netif, l2addr_len)) {
+        _set_reachable(netif, nce);
     }
 }
 
-void _set_reachable(unsigned iface, _nib_onl_entry_t *nce)
+void _recalc_reach_time(gnrc_netif2_ipv6_t *netif)
 {
-    _nib_iface_t *nib_netif = _nib_iface_get(iface);
+    const uint32_t half = (netif->reach_time_base >> 1);
+
+    netif->reach_time = random_uint32_range(half,
+                                            netif->reach_time_base + half);
+    _evtimer_add(netif, GNRC_IPV6_NIB_RECALC_REACH_TIME,
+                 &netif->recalc_reach_time,
+                 GNRC_IPV6_NIB_CONF_REACH_TIME_RESET);
+}
 
+void _set_reachable(gnrc_netif2_t *netif, _nib_onl_entry_t *nce)
+{
     DEBUG("nib: Set %s%%%u to REACHABLE for %ums\n",
           ipv6_addr_to_str(addr_str, &nce->ipv6, sizeof(addr_str)),
-          iface, (unsigned)nib_netif->reach_time);
-    _set_nud_state(nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE);
+          netif->pid, (unsigned)netif->ipv6.reach_time);
+    _set_nud_state(netif, nce, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE);
     _evtimer_add(nce, GNRC_IPV6_NIB_REACH_TIMEOUT, &nce->nud_timeout,
-                 nib_netif->reach_time);
+                 netif->ipv6.reach_time);
+}
+
+void _set_nud_state(gnrc_netif2_t *netif, _nib_onl_entry_t *nce,
+                    uint16_t state)
+{
+    nce->info &= ~GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK;
+    nce->info |= state;
+
+#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));
+    }
+    gnrc_netif2_release(netif);
+#else
+    (void)netif;
+#endif
 }
 
 /* internal functions */
@@ -443,13 +519,13 @@ static inline bool _redirect_with_tl2ao(icmpv6_hdr_t *icmpv6, ndp_opt_t *tl2ao)
 
 static inline bool _tl2ao_changes_nce(_nib_onl_entry_t *nce,
                                       const ndp_opt_t *tl2ao,
-                                      kernel_pid_t iface,
+                                      gnrc_netif2_t *netif,
                                       unsigned tl2ao_addr_len)
 {
     return ((tl2ao != NULL) &&
             (((nce->l2addr_len != tl2ao_addr_len) &&
               (memcmp(nce->l2addr, tl2ao + 1, tl2ao_addr_len) != 0)) ||
-             (_nib_onl_get_if(nce) != (unsigned)iface)));
+             (_nib_onl_get_if(nce) != (unsigned)netif->pid)));
 }
 
 static inline bool _oflag_set(const ndp_nbr_adv_t *nbr_adv)
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.h
index 44b681273d..b0c356f3c4 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.h
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.h
@@ -24,6 +24,7 @@
 #include <stdint.h>
 
 #include "net/gnrc/ipv6/nib/conf.h"
+#include "net/gnrc/netif2.h"
 #include "net/ndp.h"
 #include "net/icmpv6.h"
 
@@ -47,7 +48,7 @@ extern "C" {
  * @param[in] dst       Destination address for neighbor solicitation. May not
  *                      be NULL.
  */
-void _snd_ns(const ipv6_addr_t *tgt, gnrc_ipv6_netif_t *netif,
+void _snd_ns(const ipv6_addr_t *tgt, gnrc_netif2_t *netif,
              const ipv6_addr_t *src, const ipv6_addr_t *dst);
 
 /**
@@ -72,12 +73,12 @@ void _snd_uc_ns(_nib_onl_entry_t *nbr, bool reset);
  *          to the ARSM, but ARSM isn't the only mechanism using it (e.g. the
  *          6Lo address registration uses it).
  *
- * @param[in] iface     Interface the SL2AO was sent over.
+ * @param[in] netif     Interface the SL2AO was sent over.
  * @param[in] ipv6      IPv6 header of the message carrying the SL2AO.
  * @param[in] icmpv6    ICMPv6 header of the message carrying the SL2AO.
  * @param[in] sl2ao     The SL2AO
  */
-void _handle_sl2ao(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+void _handle_sl2ao(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                    const icmpv6_hdr_t *icmpv6, const ndp_opt_t *sl2ao);
 
 #if GNRC_IPV6_NIB_CONF_ARSM || defined(DOXYGEN)
@@ -111,7 +112,7 @@ void _probe_nbr(_nib_onl_entry_t *nbr, bool reset);
  * This can either be an TL2AO or for a link-layer without addresses just a
  * neighbor advertisement.
  *
- * @param[in] iface     Interface the link-layer information was advertised
+ * @param[in] netif     Interface the link-layer information was advertised
  *                      over.
  * @param[in] nce       Neighbor cache entry that is updated by the advertised
  *                      link-layer information.
@@ -120,53 +121,62 @@ void _probe_nbr(_nib_onl_entry_t *nbr, bool reset);
  * @param[in] tl2ao     The TL2AO carrying the link-layer information. May be
  *                      NULL for link-layers without addresses.
  */
-void _handle_adv_l2(kernel_pid_t iface, _nib_onl_entry_t *nce,
+void _handle_adv_l2(gnrc_netif2_t *netif, _nib_onl_entry_t *nce,
                     const icmpv6_hdr_t *icmpv6, const ndp_opt_t *tl2ao);
 
+
+/**
+ * @brief   Recalculates the (randomized) reachable time of on a network
+ *          interface.
+ *
+ * @see [RFC 4861, section 6.3.4](https://tools.ietf.org/html/rfc4861#section-6.3.4)
+ *
+ * @param[in] netif Interface to set reachable time for.
+ */
+void _recalc_reach_time(gnrc_netif2_ipv6_t *netif);
+
 /**
  * @brief   Sets a neighbor cache entry reachable and starts the required
  *          event timers
  *
- * @param[in] iface Interface to the NCE
+ * @param[in] netif Interface to the NCE
  * @param[in] nce   The neighbor cache entry to set reachable
  */
-void _set_reachable(unsigned iface, _nib_onl_entry_t *nce);
+void _set_reachable(gnrc_netif2_t *netif, _nib_onl_entry_t *nce);
 
 /**
  * @brief   Initializes interface for address registration state machine
  *
- * @param[in] nib_iface An interface
+ * @param[in] netif An interface
  */
-static inline void _init_iface_arsm(_nib_iface_t *nib_iface)
+static inline void _init_iface_arsm(gnrc_netif2_t *netif)
 {
-    nib_iface->reach_time_base = NDP_REACH_MS;
-    nib_iface->retrans_time = NDP_RETRANS_TIMER_MS;
-    _nib_iface_recalc_reach_time(nib_iface);
+    netif->ipv6.reach_time_base = NDP_REACH_MS;
+    _recalc_reach_time(&netif->ipv6);
 }
 
 /**
  * @brief   Gets neighbor unreachability state of a neighbor
  *
- * @param[in] entry Neighbor cache entry representing the neighbor.
+ * @param[in] nbr   Neighbor cache entry representing the neighbor.
  *
- * @return  Neighbor unreachability state of the @p entry.
+ * @return  Neighbor unreachability state of the @p nbr.
  */
-static inline uint16_t _get_nud_state(_nib_onl_entry_t *entry)
+static inline uint16_t _get_nud_state(_nib_onl_entry_t *nbr)
 {
-    return (entry->info & GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK);
+    return (nbr->info & GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK);
 }
 
 /**
  * @brief   Sets neighbor unreachablility state of a neighbor
  *
- * @param[in] entry Neighbor cache entry representing the neighbor.
+ * @param[in] netif The network interface (to signal routing protocol using
+ *                  gnrc_netif_t::ipv6::route_info_cb())
+ * @param[in] nbr   Neighbor cache entry representing the neighbor.
  * @param[in] state Neighbor unreachability state for the neighbor.
  */
-static inline void _set_nud_state(_nib_onl_entry_t *entry, uint16_t state)
-{
-    entry->info &= ~GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK;
-    entry->info |= state;
-}
+void _set_nud_state(gnrc_netif2_t *netif, _nib_onl_entry_t *nbr,
+                    uint16_t state);
 
 #else   /* GNRC_IPV6_NIB_CONF_ARSM || defined(DOXYGEN) */
 #define _handle_snd_ns(ctx)                         (void)ctx
@@ -175,11 +185,12 @@ static inline void _set_nud_state(_nib_onl_entry_t *entry, uint16_t state)
 #define _init_iface_arsm(netif)                     (void)netif
 #define _handle_adv_l2(netif, nce, icmpv6, tl2ao)   (void)netif; (void)nce; \
                                                     (void)icmpv6; (void)tl2ao
+#define _recalc_reach_time(netif)                   (void)netif;
 #define _set_reachable(netif, nce)                  (void)netif; (void)nce
 #define _init_iface_arsm(netif)                     (void)netif
 
-#define _get_nud_state(entry)         (GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED)
-#define _set_nud_state(entry, state)  (void)entry; (void)state
+#define _get_nud_state(nbr)                 (GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED)
+#define _set_nud_state(netif, nce, state)   (void)netif; (void)nbr; (void)state
 #endif  /* GNRC_IPV6_NIB_CONF_ARSM || defined(DOXYGEN) */
 
 #ifdef __cplusplus
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 854d5e8e5b..4b1be07f50 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c
@@ -21,7 +21,7 @@
 #include "net/gnrc/ipv6/nib/conf.h"
 #include "net/gnrc/ipv6/nib/nc.h"
 #include "net/gnrc/ipv6/nib.h"
-#include "net/gnrc/netif.h"
+#include "net/gnrc/netif2/internal.h"
 #include "random.h"
 
 #include "_nib-internal.h"
@@ -36,7 +36,6 @@ static clist_node_t _next_removable = { NULL };
 static _nib_onl_entry_t _nodes[GNRC_IPV6_NIB_NUMOF];
 static _nib_offl_entry_t _dsts[GNRC_IPV6_NIB_OFFL_NUMOF];
 static _nib_dr_entry_t _def_routers[GNRC_IPV6_NIB_DEFAULT_ROUTER_NUMOF];
-static _nib_iface_t _nis[GNRC_NETIF_NUMOF];
 
 #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
 static _nib_abr_entry_t _abrs[GNRC_IPV6_NIB_ABR_NUMOF];
@@ -61,7 +60,6 @@ void _nib_init(void)
     memset(_nodes, 0, sizeof(_nodes));
     memset(_def_routers, 0, sizeof(_def_routers));
     memset(_dsts, 0, sizeof(_dsts));
-    memset(_nis, 0, sizeof(_nis));
 #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
     memset(_abrs, 0, sizeof(_abrs));
 #endif
@@ -226,15 +224,21 @@ _nib_onl_entry_t *_nib_onl_get(const ipv6_addr_t *addr, unsigned iface)
 void _nib_nc_set_reachable(_nib_onl_entry_t *node)
 {
 #if GNRC_IPV6_NIB_CONF_ARSM
-    _nib_iface_t *iface = _nib_iface_get(_nib_onl_get_if(node));
+    gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(_nib_onl_get_if(node));
 
-    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), iface->reach_time);
     node->info &= ~GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK;
     node->info |= GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE;
+#ifdef TEST_SUITES
+    /* exit early for unittests */
+    if (netif == NULL) {
+        return;
+    }
+#endif
+    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,
-                 iface->reach_time);
+                 netif->ipv6.reach_time);
 #else
     (void)node;
 #endif
@@ -281,10 +285,9 @@ void _nib_nc_get(const _nib_onl_entry_t *node, gnrc_ipv6_nib_nc_t *nce)
 #if GNRC_IPV6_NIB_CONF_ARSM
 #if GNRC_IPV6_NIB_CONF_6LN
     if (ipv6_addr_is_link_local(&nce->ipv6)) {
-        gnrc_ipv6_netif_t *netif = gnrc_ipv6_netif_get(_nib_onl_get_if(node));
+        gnrc_netif2_t *netif = gnrc_netif2_get_by_pid(_nib_onl_get_if(node));
         assert(netif != NULL);
-        if ((netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
-            !(netif->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
+        if (gnrc_netif2_is_6ln(netif) && !gnrc_netif2_is_rtr(netif)) {
             _get_l2addr_from_ipv6(nce->l2addr, &node->ipv6);
             nce->l2addr_len = sizeof(uint64_t);
             return;
@@ -768,42 +771,6 @@ _nib_offl_entry_t *_nib_pl_add(unsigned iface,
     return dst;
 }
 
-_nib_iface_t *_nib_iface_get(unsigned iface)
-{
-    _nib_iface_t *ni = NULL;
-
-    assert(iface <= _NIB_IF_MAX);
-    for (unsigned i = 0; i < GNRC_NETIF_NUMOF; i++) {
-        _nib_iface_t *tmp = &_nis[i];
-        if (((unsigned)tmp->pid) == iface) {
-            return tmp;
-        }
-        if ((ni == NULL) && (tmp->pid == KERNEL_PID_UNDEF)) {
-            ni = tmp;
-        }
-    }
-    if (ni != NULL) {
-        memset(ni, 0, sizeof(_nib_iface_t));
-        /* TODO: set random reachable time using constants from #6220 */
-        ni->pid = (kernel_pid_t)iface;
-    }
-    return ni;
-}
-
-#if GNRC_IPV6_NIB_CONF_ARSM
-void _nib_iface_recalc_reach_time(_nib_iface_t *iface)
-{
-    uint32_t factor = random_uint32_range(NDP_MIN_RANDOM_FACTOR,
-                                          NDP_MAX_RANDOM_FACTOR);
-
-    /* random factor was times 1000 so we need to divide it again */
-    iface->reach_time = (iface->reach_time_base * factor) / 1000;
-    _evtimer_add(iface, GNRC_IPV6_NIB_RECALC_REACH_TIME,
-                 &iface->recalc_reach_time,
-                 GNRC_IPV6_NIB_CONF_REACH_TIME_RESET);
-}
-#endif
-
 static void _override_node(const ipv6_addr_t *addr, unsigned iface,
                            _nib_onl_entry_t *node)
 {
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 24e39f4234..97af9ec93e 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h
+++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h
@@ -193,56 +193,6 @@ typedef struct {
                                      preferred (UINT32_MAX means forever) */
 } _nib_offl_entry_t;
 
-/**
- * @brief   Interface specific information for Neighbor Discovery
- */
-typedef struct {
-#if GNRC_IPV6_NIB_CONF_ARSM
-    /**
-     * @brief   base for random reachable time calculation
-     */
-    uint32_t reach_time_base;
-    uint32_t reach_time;                /**< reachable time (in ms) */
-#endif
-    uint32_t retrans_time;              /**< retransmission time (in ms) */
-#if GNRC_IPV6_NIB_CONF_ROUTER || defined(DOXYGEN)
-    /**
-     * @brief   timestamp in milliseconds of last unsolicited router
-     *          advertisement
-     *
-     * @note    Only available if @ref GNRC_IPV6_NIB_CONF_ROUTER.
-     */
-    uint32_t last_ra;
-#endif
-#if GNRC_IPV6_NIB_CONF_ARSM || defined(DOXYGEN)
-    /**
-     * @brief   Event for @ref GNRC_IPV6_NIB_RECALC_REACH_TIME
-     */
-    evtimer_msg_event_t recalc_reach_time;
-#endif
-    kernel_pid_t pid;                   /**< identifier of the interface */
-#if GNRC_IPV6_NIB_CONF_ROUTER || defined(DOXYGEN)
-    /**
-     * @brief   number of unsolicited router advertisements sent
-     *
-     * This only counts up to the first @ref NDP_MAX_INIT_RA_NUMOF on interface
-     * initialization. The last @ref NDP_MAX_FIN_RA_NUMOF of an advertising
-     * interface are counted from UINT8_MAX - @ref NDP_MAX_FIN_RA_NUMOF + 1.
-     *
-     * @note    Only available if @ref GNRC_IPV6_NIB_CONF_ROUTER.
-     */
-    uint8_t ra_sent;
-#endif
-    /**
-     * @brief   number of unsolicited router solicitations scheduled
-     */
-    uint8_t rs_sent;
-    /**
-     * @brief   number of unsolicited neighbor advertisements scheduled
-     */
-    uint8_t na_sent;
-} _nib_iface_t;
-
 /**
  * @brief   Internal NIB-representation of the authoritative border router
  *          for multihop prefix and 6LoWPAN context dissemination
@@ -795,30 +745,6 @@ void _nib_ft_get(const _nib_offl_entry_t *dst, gnrc_ipv6_nib_ft_t *fte);
 int _nib_get_route(const ipv6_addr_t *dst, gnrc_pktsnip_t *ctx,
                    gnrc_ipv6_nib_ft_t *entry);
 
-/**
- * @brief   Gets (or creates if it not exists) interface information for
- *          neighbor discovery
- *
- * @pre `(iface <= _NIB_IF_MAX)`
- *
- * @param[in] iface Interface identifier to get information for.
- *
- * @return  Interface information on @p iface.
- * @return  NULL, if no space left for interface.
- */
-_nib_iface_t *_nib_iface_get(unsigned iface);
-
-/**
- * @brief   Recalculates randomized reachable time of an interface.
- *
- * @param[in] iface An interface.
- */
-#if GNRC_IPV6_NIB_CONF_ARSM
-void _nib_iface_recalc_reach_time(_nib_iface_t *iface);
-#else
-#define _nib_iface_recalc_reach_time(iface) (void)iface
-#endif
-
 /**
  * @brief   Looks up if an event is queued in the event timer
  *
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c
index e36a1f5536..e1a6533524 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/nib.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/nib.c
@@ -16,9 +16,10 @@
 #include <errno.h>
 #include <stdbool.h>
 
+#include "log.h"
 #include "net/ipv6/addr.h"
 #include "net/gnrc/nettype.h"
-#include "net/gnrc/ipv6/netif.h"
+#include "net/gnrc/netif2/internal.h"
 #include "net/gnrc/ipv6/nib.h"
 #include "net/gnrc/ndp2.h"
 #include "net/gnrc/pktqueue.h"
@@ -49,24 +50,16 @@ static gnrc_pktqueue_t _queue_pool[GNRC_IPV6_NIB_NUMOF];
  * @internal
  * @{
  */
-static void _handle_nbr_sol(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+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(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+static void _handle_nbr_adv(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                             const ndp_nbr_adv_t *nbr_adv, size_t icmpv6_len);
 
-static bool _resolve_addr(const ipv6_addr_t *dst, kernel_pid_t iface,
+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_snd_na(gnrc_pktsnip_t *pkt);
-
-/* interface flag checks */
-#if GNRC_IPV6_NIB_CONF_ROUTER
-static inline bool _is_rtr(const gnrc_ipv6_netif_t *netif)
-{
-    return (netif->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER);
-}
-#endif
 /** @} */
 
 void gnrc_ipv6_nib_init(void)
@@ -83,27 +76,13 @@ void gnrc_ipv6_nib_init(void)
     mutex_unlock(&_nib_mutex);
 }
 
-void gnrc_ipv6_nib_init_iface(kernel_pid_t iface)
+void gnrc_ipv6_nib_init_iface(gnrc_netif2_t *netif)
 {
-    _nib_iface_t *nib_iface;
+    ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED;
 
-    assert(iface > KERNEL_PID_UNDEF);
-    DEBUG("nib: Initialize interface %u\n", (unsigned)iface);
-    mutex_lock(&_nib_mutex);
-    nib_iface = _nib_iface_get(iface);
-#ifdef TEST_SUITES
-    if (nib_iface == NULL) {
-        /* in the unittests old NC and NIB are mixed, so this function leads to
-         * crashes. To prevent this we early exit here, if the interface was
-         * not found
-         * TODO: remove when gnrc_ipv6_nc is removed.
-         */
-        mutex_unlock(&_nib_mutex);
-        return;
-    }
-#else
-    assert(nib_iface != NULL);
-#endif
+    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
@@ -112,46 +91,116 @@ void gnrc_ipv6_nib_init_iface(kernel_pid_t iface)
      * - 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(nib_iface);
-    nib_iface->rs_sent = 0;
-    nib_iface->na_sent = 0;
+    _init_iface_arsm(netif);
+    netif->ipv6.retrans_time = NDP_RETRANS_TIMER_MS;
+    netif->ipv6.na_sent = 0;
 #if GNRC_IPV6_NIB_CONF_ROUTER
-    nib_iface->last_ra = UINT32_MAX;
-    nib_iface->ra_sent = 0;
+    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
-    mutex_unlock(&_nib_mutex);
+#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_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;
+        gnrc_netapi_opt_t opt = { .opt = NETOPT_SRC_LEN,
+                                  .data = &src_len,
+                                  .data_len = sizeof(src_len) };
+
+        /* XXX we are supposed to be in interface context here, so use driver
+         * 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);
+        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;
+    }
+#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
+    gnrc_netif2_release(netif);
 }
 
 int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
-                                      kernel_pid_t iface, gnrc_pktsnip_t *pkt,
+                                      gnrc_netif2_t *netif, gnrc_pktsnip_t *pkt,
                                       gnrc_ipv6_nib_nc_t *nce)
 {
     int res = 0;
 
+    DEBUG("nib: get next hop link-layer address of %s%%%u\n",
+          ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)),
+          (netif != NULL) ? (unsigned)netif->pid : 0U);
+    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 */
-            if ((iface == KERNEL_PID_UNDEF) ||
-                !_resolve_addr(dst, iface, pkt, nce,
-                               _nib_onl_get(dst, iface))) {
+            if ((netif == NULL) ||
+                !_resolve_addr(dst, netif, pkt, nce,
+                               _nib_onl_get(dst, netif->pid))) {
                 res = -EHOSTUNREACH;
                 break;
             }
         }
         else {
-            /* TODO: Off-link next hop determination */
+            /* TODO: Off-link next hop determination;
+             *       might need netif locking */
             res = -EHOSTUNREACH;
         }
     } while (0);
     mutex_unlock(&_nib_mutex);
+    gnrc_netif2_release(netif);
     return res;
 }
 
-void gnrc_ipv6_nib_handle_pkt(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+void gnrc_ipv6_nib_handle_pkt(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                               const icmpv6_hdr_t *icmpv6, size_t icmpv6_len)
 {
     DEBUG("nib: Handle packet (icmpv6->type = %u)\n", icmpv6->type);
+    assert(netif != NULL);
+    gnrc_netif2_acquire(netif);
     mutex_lock(&_nib_mutex);
     switch (icmpv6->type) {
 #if GNRC_IPV6_NIB_CONF_ROUTER
@@ -163,10 +212,10 @@ void gnrc_ipv6_nib_handle_pkt(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
             /* TODO */
             break;
         case ICMPV6_NBR_SOL:
-            _handle_nbr_sol(iface, ipv6, (ndp_nbr_sol_t *)icmpv6, icmpv6_len);
+            _handle_nbr_sol(netif, ipv6, (ndp_nbr_sol_t *)icmpv6, icmpv6_len);
             break;
         case ICMPV6_NBR_ADV:
-            _handle_nbr_adv(iface, ipv6, (ndp_nbr_adv_t *)icmpv6, icmpv6_len);
+            _handle_nbr_adv(netif, ipv6, (ndp_nbr_adv_t *)icmpv6, icmpv6_len);
             break;
 #if GNRC_IPV6_NIB_CONF_REDIRECT
         case ICMPV6_REDIRECT:
@@ -183,6 +232,7 @@ void gnrc_ipv6_nib_handle_pkt(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
 #endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_DAD */
     }
     mutex_unlock(&_nib_mutex);
+    gnrc_netif2_release(netif);
 }
 
 void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type)
@@ -191,6 +241,7 @@ 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:
@@ -201,7 +252,7 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type)
             _handle_state_timeout(ctx);
             break;
         case GNRC_IPV6_NIB_RECALC_REACH_TIME:
-            _nib_iface_recalc_reach_time(ctx);
+            _recalc_reach_time(ctx);
             break;
 #endif  /* GNRC_IPV6_NIB_CONF_ARSM */
         case GNRC_IPV6_NIB_SND_NA:
@@ -246,6 +297,22 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type)
     mutex_unlock(&_nib_mutex);
 }
 
+#if GNRC_IPV6_NIB_CONF_ROUTER
+void gnrc_ipv6_nib_change_rtr_adv_iface(gnrc_netif2_t *netif, bool enable)
+{
+    if (enable) {
+        netif->flags |= GNRC_NETIF2_FLAGS_IPV6_RTR_ADV;
+        /* TODO: start router advertisements */
+    }
+    else {
+        netif->flags &= ~GNRC_NETIF2_FLAGS_IPV6_RTR_ADV;
+        /* TODO:
+         *  - start final router advertisements,
+         *  - start router solicitations? */
+    }
+}
+#endif
+
 /* Iterator for NDP options in a packet */
 #define FOREACH_OPT(ndp_pkt, opt, icmpv6_len) \
     for (opt = (ndp_opt_t *)(ndp_pkt + 1); \
@@ -253,40 +320,19 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type)
          icmpv6_len -= (opt->len << 3), \
          opt = (ndp_opt_t *)(((uint8_t *)opt) + (opt->len << 3)))
 
-static size_t _get_l2src(kernel_pid_t iface, uint8_t *l2src,
-                         size_t l2src_maxlen)
+static inline size_t _get_l2src(const gnrc_netif2_t *netif, uint8_t *l2src)
 {
-    bool try_long = false;
-    int res;
-    uint16_t l2src_len;
-    /* maximum address length that fits into a minimum length (8) S/TL2A
-     * option */
-    const uint16_t max_short_len = 6;
-
-    /* try getting source address */
-    if ((gnrc_netapi_get(iface, NETOPT_SRC_LEN, 0, &l2src_len,
-                         sizeof(l2src_len)) >= 0) &&
-        (l2src_len > max_short_len)) {
-        try_long = true;
-    }
-
-    if (try_long && ((res = gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0,
-                                            l2src, l2src_maxlen)) > max_short_len)) {
-        l2src_len = (uint16_t)res;
-    }
-    else if ((res = gnrc_netapi_get(iface, NETOPT_ADDRESS, 0, l2src,
-                                    l2src_maxlen)) >= 0) {
-        l2src_len = (uint16_t)res;
-    }
-    else {
-        DEBUG("nib: No link-layer address found.\n");
-        l2src_len = 0;
-    }
-
-    return l2src_len;
+#if GNRC_NETIF2_L2ADDR_MAXLEN > 0
+    memcpy(l2src, netif->l2addr, netif->l2addr_len);
+    return netif->l2addr_len;
+#else
+    (void)netif;
+    (void)l2src;
+    return 0;
+#endif
 }
 
-static void _send_delayed_nbr_adv(const gnrc_ipv6_netif_t *netif,
+static void _send_delayed_nbr_adv(const gnrc_netif2_t *netif,
                                   const ipv6_addr_t *tgt,
                                   const ipv6_addr_t *dst,
                                   gnrc_pktsnip_t *reply_aro)
@@ -296,13 +342,15 @@ static void _send_delayed_nbr_adv(const gnrc_ipv6_netif_t *netif,
     uint8_t reply_flags = NDP_NBR_ADV_FLAGS_S;
 
 #if GNRC_IPV6_NIB_CONF_ROUTER
-    if (_is_rtr(netif)) {
+    if (gnrc_netif2_is_rtr(netif)) {
         reply_flags |= NDP_NBR_ADV_FLAGS_R;
     }
 #endif
+#if GNRC_NETIF2_L2ADDR_MAXLEN > 0
     if (ipv6_addr_is_multicast(dst)) {
-        uint8_t l2addr[GNRC_IPV6_NIB_L2ADDR_MAX_LEN];
-        size_t l2addr_len = _get_l2src(netif->pid, l2addr, sizeof(l2addr));
+        uint8_t l2addr[GNRC_NETIF2_L2ADDR_MAXLEN];
+        size_t l2addr_len = _get_l2src(netif, l2addr);
+
         if (l2addr_len > 0) {
             extra_opts = gnrc_ndp2_opt_tl2a_build(l2addr, l2addr_len,
                                                   extra_opts);
@@ -319,6 +367,10 @@ static void _send_delayed_nbr_adv(const gnrc_ipv6_netif_t *netif,
     else {
         reply_flags |= NDP_NBR_ADV_FLAGS_O;
     }
+#else /* GNRC_NETIF2_L2ADDR_MAXLEN > 0 */
+    reply_flags |= NDP_NBR_ADV_FLAGS_O;
+#endif
+    /* discard const qualifier */
     nbr_adv = gnrc_ndp2_nbr_adv_build(tgt, reply_flags, extra_opts);
     if (nbr_adv == NULL) {
         DEBUG("nib: No space left in packet buffer. Not replying NS");
@@ -336,12 +388,12 @@ static void _send_delayed_nbr_adv(const gnrc_ipv6_netif_t *netif,
     }
 }
 
-static void _handle_nbr_sol(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+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)
 {
     size_t tmp_len = icmpv6_len - sizeof(ndp_nbr_sol_t);
+    int tgt_idx;
     ndp_opt_t *opt;
-    ipv6_addr_t *local;
 
     /* check validity, see: https://tools.ietf.org/html/rfc4861#section-7.1.1 */
     /* checksum is checked by GNRC's ICMPv6 module */
@@ -365,9 +417,9 @@ static void _handle_nbr_sol(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
         return;
     }
     /* check if target is assigned only now in case the length was wrong */
-    local = gnrc_ipv6_netif_find_addr(iface, &nbr_sol->tgt);
-    if (local == NULL) {
-        DEBUG("nib: Target address %s is not assigned to a local interface\n",
+    tgt_idx = gnrc_netif2_ipv6_addr_idx(netif, &nbr_sol->tgt);
+    if (tgt_idx < 0) {
+        DEBUG("nib: Target address %s is not assigned to the local interface\n",
               ipv6_addr_to_str(addr_str, &nbr_sol->tgt, sizeof(addr_str)));
         return;
     }
@@ -395,6 +447,7 @@ static void _handle_nbr_sol(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
     /* TODO SLAAC behavior */
 #endif  /* GNRC_IPV6_NIB_CONF_SLAAC */
     if (!ipv6_addr_is_unspecified(&ipv6->src)) {
+        gnrc_pktsnip_t *reply_aro = NULL;
 #if GNRC_IPV6_NIB_CONF_6LR
         ndp_opt_t *sl2ao = NULL;
         sixlowpan_nd_opt_ar_t *aro = NULL;
@@ -402,23 +455,24 @@ static void _handle_nbr_sol(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
 #define sl2ao   (NULL)
 #define aro     (NULL)
 #endif  /* GNRC_IPV6_NIB_CONF_6LR */
-        gnrc_ipv6_netif_t *netif;
-        gnrc_pktsnip_t *reply_aro = NULL;
         tmp_len = icmpv6_len - sizeof(ndp_nbr_sol_t);
 
-        netif = gnrc_ipv6_netif_get(iface);
-        /* TODO: Set STALE NCE if link-layer has no addresses */
+        if (!(netif->flags & GNRC_NETIF2_FLAGS_HAS_L2ADDR)) {
+            /* Set STALE NCE if link-layer has no addresses */
+            _nib_nc_add(&ipv6->src, netif->pid,
+                        GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE);
+        }
         FOREACH_OPT(nbr_sol, opt, tmp_len) {
             switch (opt->type) {
                 case NDP_OPT_SL2A:
 #if GNRC_IPV6_NIB_CONF_6LR
-                    if (_is_6lr(netif)) {
+                    if (gnrc_netif2_is_6lr(netif)) {
                         DEBUG("nib: Storing SL2AO for later handling\n");
                         sl2ao = opt;
                         break;
                     }
 #endif  /* GNRC_IPV6_NIB_CONF_6LR */
-                    _handle_sl2ao(iface, ipv6, (const icmpv6_hdr_t *)nbr_sol,
+                    _handle_sl2ao(netif, ipv6, (const icmpv6_hdr_t *)nbr_sol,
                                   opt);
                     break;
 #if GNRC_IPV6_NIB_CONF_6LR
@@ -432,9 +486,9 @@ static void _handle_nbr_sol(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
                           opt->type);
             }
         }
-        reply_aro = _copy_and_handle_aro(iface, ipv6, nbr_sol, aro, sl2ao);
+        reply_aro = _copy_and_handle_aro(netif, ipv6, nbr_sol, aro, sl2ao);
         /* check if target address is anycast */
-        if (gnrc_ipv6_netif_addr_is_non_unicast(local)) {
+        if (netif->ipv6.addrs_flags[tgt_idx] & GNRC_NETIF2_IPV6_ADDRS_FLAGS_ANYCAST) {
             _send_delayed_nbr_adv(netif, &nbr_sol->tgt, &ipv6->dst, reply_aro);
         }
         else {
@@ -445,7 +499,7 @@ static void _handle_nbr_sol(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
     }
 }
 
-static void _handle_nbr_adv(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
+static void _handle_nbr_adv(gnrc_netif2_t *netif, const ipv6_hdr_t *ipv6,
                             const ndp_nbr_adv_t *nbr_adv, size_t icmpv6_len)
 {
     size_t tmp_len = icmpv6_len - sizeof(ndp_nbr_adv_t);
@@ -501,7 +555,7 @@ static void _handle_nbr_adv(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
 #if GNRC_IPV6_NIB_CONF_SLAAC
     /* TODO SLAAC behavior */
 #endif
-    if (((nce = _nib_onl_get(&nbr_adv->tgt, iface)) != NULL) &&
+    if (((nce = _nib_onl_get(&nbr_adv->tgt, netif->pid)) != NULL) &&
         (nce->mode & _NC)) {
 #if GNRC_IPV6_NIB_CONF_ARSM
         bool tl2ao_avail = false;
@@ -512,13 +566,13 @@ static void _handle_nbr_adv(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
             switch (opt->type) {
 #if GNRC_IPV6_NIB_CONF_ARSM
                 case NDP_OPT_TL2A:
-                    _handle_adv_l2(iface, nce, (icmpv6_hdr_t *)nbr_adv, opt);
+                    _handle_adv_l2(netif, nce, (icmpv6_hdr_t *)nbr_adv, opt);
                     tl2ao_avail = true;
                     break;
 #endif
 #if GNRC_IPV6_NIB_CONF_6LN
                 case NDP_OPT_AR:
-                    _handle_aro(iface, ipv6, (const icmpv6_hdr_t *)nbr_adv,
+                    _handle_aro(netif, ipv6, (const icmpv6_hdr_t *)nbr_adv,
                                 (const sixlowpan_nd_opt_ar_t *)opt, opt, nce);
                     break;
 #endif
@@ -531,11 +585,11 @@ static void _handle_nbr_adv(kernel_pid_t iface, const ipv6_hdr_t *ipv6,
         if (!tl2ao_avail && (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) &&
             (_get_nud_state(nce) != GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE)) {
             /* reachability confirmed without TL2AO */
-            _set_reachable(iface, nce);
+            _set_reachable(netif, nce);
+        }
+        if (!(netif->flags & GNRC_NETIF2_FLAGS_HAS_L2ADDR)) {
+            _handle_adv_l2(netif, nce, (icmpv6_hdr_t *)nbr_adv, NULL);
         }
-        /* TODO: handling for of advertised link-layer with link-layers without
-         * addresses */
-        /* _handle_adv_l2(iface, nce, (icmpv6_hdr_t *)nbr_adv, NULL); */
 #endif
     }
 }
@@ -567,7 +621,7 @@ static gnrc_pktqueue_t *_alloc_queue_entry(gnrc_pktsnip_t *pkt)
 }
 #endif
 
-static bool _resolve_addr(const ipv6_addr_t *dst, kernel_pid_t iface,
+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)
 {
@@ -575,29 +629,44 @@ static bool _resolve_addr(const ipv6_addr_t *dst, kernel_pid_t iface,
 #if GNRC_IPV6_NIB_CONF_ARSM
     if ((entry != NULL) && (entry->mode & _NC) && _is_reachable(entry)) {
         if (_get_nud_state(entry) == GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE) {
-            _set_nud_state(entry, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_DELAY);
+            _set_nud_state(netif, entry, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_DELAY);
             _evtimer_add(entry, GNRC_IPV6_NIB_DELAY_TIMEOUT,
                          &entry->nud_timeout, NDP_DELAY_FIRST_PROBE_MS);
         }
+        DEBUG("nib: resolve address %s%%%u from neighbor cache\n",
+              ipv6_addr_to_str(addr_str, &entry->ipv6, sizeof(addr_str)),
+              _nib_onl_get_if(entry));
         _nib_nc_get(entry, nce);
         res = true;
     }
 #else
     if (entry != NULL) {
+        DEBUG("nib: resolve address %s%%%u from neighbor cache\n",
+              ipv6_addr_to_str(addr_str, &entry->ipv6, sizeof(addr_str)),
+              _nib_onl_get_if(entry));
         _nib_nc_get(entry, nce);
         res = true;
     }
 #endif
-    else if (!(res = _resolve_addr_from_ipv6(dst, iface, nce))) {
+    else if (!(res = _resolve_addr_from_ipv6(dst, netif, nce))) {
 #if GNRC_IPV6_NIB_CONF_ARSM
         bool reset = false;
 #endif
+
+        DEBUG("nib: resolve address %s by probing neighbors\n",
+              ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
         if ((entry == NULL) || !(entry->mode & _NC)) {
-            entry = _nib_nc_add(dst, iface,
+            entry = _nib_nc_add(dst, (netif != NULL) ? netif->pid : 0,
                                 GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE);
             if (entry == NULL) {
                 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);
+            }
+#endif
 #if GNRC_IPV6_NIB_CONF_ARSM
             reset = true;
 #endif
diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib_nc.c b/sys/net/gnrc/network_layer/ipv6/nib/nib_nc.c
index 4cd920a535..09b7245f91 100644
--- a/sys/net/gnrc/network_layer/ipv6/nib/nib_nc.c
+++ b/sys/net/gnrc/network_layer/ipv6/nib/nib_nc.c
@@ -18,7 +18,7 @@
 #include <stdio.h>
 
 #include "net/gnrc/ipv6.h"
-#include "net/gnrc/netif.h"
+#include "net/gnrc/netif2.h"
 
 #include "net/gnrc/ipv6/nib/nc.h"
 
@@ -127,15 +127,16 @@ static const char *_ar_str[] = {
 
 void gnrc_ipv6_nib_nc_print(gnrc_ipv6_nib_nc_t *entry)
 {
-    char addr_str[IPV6_ADDR_MAX_STR_LEN];
+    char addr_str[(IPV6_ADDR_MAX_STR_LEN > GNRC_IPV6_NIB_L2ADDR_MAX_LEN) ?
+                   IPV6_ADDR_MAX_STR_LEN : GNRC_IPV6_NIB_L2ADDR_MAX_LEN];
 
     printf("%s ", ipv6_addr_to_str(addr_str, &entry->ipv6, sizeof(addr_str)));
     if (gnrc_ipv6_nib_nc_get_iface(entry) != KERNEL_PID_UNDEF) {
         printf("dev #%u ", gnrc_ipv6_nib_nc_get_iface(entry));
     }
-    printf("lladdr %s ", gnrc_netif_addr_to_str(addr_str, sizeof(addr_str),
-                                                entry->l2addr,
-                                                entry->l2addr_len));
+    printf("lladdr %s ", gnrc_netif2_addr_to_str(entry->l2addr,
+                                                 entry->l2addr_len,
+                                                 addr_str));
     if (gnrc_ipv6_nib_nc_is_router(entry)) {
         printf("router");
     }
diff --git a/sys/shell/commands/sc_gnrc_ipv6_nib.c b/sys/shell/commands/sc_gnrc_ipv6_nib.c
index 4c7c2f34b7..83f6c5c698 100644
--- a/sys/shell/commands/sc_gnrc_ipv6_nib.c
+++ b/sys/shell/commands/sc_gnrc_ipv6_nib.c
@@ -106,8 +106,7 @@ static int _nib_neigh(int argc, char **argv)
             return 1;
         }
         if ((argc > 5) && /* TODO also check if interface supports link-layers or not */
-            (l2addr_len = gnrc_netif_addr_from_str(l2addr, sizeof(l2addr),
-                                                   argv[5])) == 0) {
+            (l2addr_len = gnrc_netif2_addr_from_str(argv[5], l2addr)) == 0) {
             _usage_nib_neigh(argv);
             return 1;
         }
@@ -150,7 +149,7 @@ static int _nib_prefix(int argc, char **argv)
         ipv6_addr_t pfx;
         unsigned iface = atoi(argv[3]);
         unsigned pfx_len = ipv6_addr_split_prefix(argv[4]);
-        unsigned valid_ltime = UINT32_MAX, pref_ltime = UINT32_MAX;
+        uint32_t valid_ltime = UINT32_MAX, pref_ltime = UINT32_MAX;
 
         if (ipv6_addr_from_str(&pfx, argv[4]) == NULL) {
             _usage_nib_prefix(argv);
-- 
GitLab