From 7027519f28e9fc3d07018e59e024a39c0a471463 Mon Sep 17 00:00:00 2001
From: Martine Lenders <mlenders@inf.fu-berlin.de>
Date: Wed, 11 Feb 2015 14:10:34 +0100
Subject: [PATCH] ng_ipv6: provide support for ng_netif

---
 Makefile.dep                                  |   5 +
 sys/Makefile                                  |   3 +
 sys/include/net/ng_ipv6.h                     |  10 +-
 sys/include/net/ng_ipv6/netif.h               | 254 ++++++++++++
 sys/net/crosslayer/ng_netif/ng_netif.c        |  12 +-
 sys/net/network_layer/ng_ipv6/netif/Makefile  |   3 +
 .../ng_ipv6/netif/ng_ipv6_netif.c             | 382 ++++++++++++++++++
 7 files changed, 664 insertions(+), 5 deletions(-)
 create mode 100644 sys/include/net/ng_ipv6/netif.h
 create mode 100644 sys/net/network_layer/ng_ipv6/netif/Makefile
 create mode 100644 sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c

diff --git a/Makefile.dep b/Makefile.dep
index a0bb4b074b..ab88197f2b 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -52,6 +52,11 @@ ifneq (,$(filter ng_ipv6_nc,$(USEMODULE)))
   USEMODULE += ng_ipv6_addr
 endif
 
+ifneq (,$(filter ng_ipv6_netif,$(USEMODULE)))
+  USEMODULE += ng_ipv6_addr
+  USEMODULE += ng_netif
+endif
+
 ifneq (,$(filter ng_netbase,$(USEMODULE)))
   USEMODULE += ng_netapi
   USEMODULE += ng_netreg
diff --git a/sys/Makefile b/sys/Makefile
index 230a0296ac..8596ac3adc 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -68,6 +68,9 @@ endif
 ifneq (,$(filter ng_ipv6_nc,$(USEMODULE)))
     DIRS += net/network_layer/ng_ipv6/nc
 endif
+ifneq (,$(filter ng_ipv6_netif,$(USEMODULE)))
+    DIRS += net/network_layer/ng_ipv6/netif
+endif
 ifneq (,$(filter ng_netapi,$(USEMODULE)))
     DIRS += net/crosslayer/ng_netapi
 endif
diff --git a/sys/include/net/ng_ipv6.h b/sys/include/net/ng_ipv6.h
index 8990be2d35..0b0086918f 100644
--- a/sys/include/net/ng_ipv6.h
+++ b/sys/include/net/ng_ipv6.h
@@ -23,12 +23,20 @@
 #define NG_IPV6_H_
 
 #include "net/ng_ipv6/addr.h"
+#include "net/ng_ipv6/netif.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-
+/**
+ * @brief   Default maximum transition unit
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc2460#section-5">
+ *          RFC 2460, section 5
+ *      </a>
+ */
+#define NG_IPV6_DEFAULT_MTU (1280)
 
 #ifdef __cplusplus
 }
diff --git a/sys/include/net/ng_ipv6/netif.h b/sys/include/net/ng_ipv6/netif.h
new file mode 100644
index 0000000000..2608cfa67f
--- /dev/null
+++ b/sys/include/net/ng_ipv6/netif.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2014 Martine Lenders <mlenders@inf.fu-berlin.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for
+ * more details.
+ */
+
+/**
+ * @defgroup    net_ng_ipv6_netif IPv6 network interfaces
+ * @ingroup     net_ng_ipv6
+ * @brief       IPv6 specific information on @ref net_ng_netif.
+ * @{
+ *
+ * @file
+ * @brief       Definitions for IPv6 specific information of network interfaces.
+ *
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#ifndef NG_IPV6_NETIF_H_
+#define NG_IPV6_NETIF_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "kernel_macros.h"
+#include "kernel_types.h"
+#include "mutex.h"
+#include "net/ng_ipv6/addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @def NG_IPV6_NETIF_ADDR_NUMOF
+ *
+ * @brief   Number of IPv6 addresses per interface.
+ */
+#ifndef NG_IPV6_NETIF_ADDR_NUMOF
+#ifdef MODULE_NG_IPV6_ROUTER
+#define NG_IPV6_NETIF_ADDR_NUMOF    (5) /* router needs all-routers multicast address */
+#else
+#define NG_IPV6_NETIF_ADDR_NUMOF    (4)
+#endif
+#endif
+
+/**
+ * @{
+ * @name Flags for a registered IPv6 address.
+ * @brief   Needed primarily to identify addresses as either anycast or unicast.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4291#section-2.6">
+ *          RFC 4291, section 2.6
+ *      </a>
+ */
+#define NG_IPV6_NETIF_FLAGS_UNICAST     (0x00)  /**< unicast address */
+#define NG_IPV6_NETIF_FLAGS_NON_UNICAST (0x01)  /**< non-unicast address */
+/**
+ * @}
+ */
+
+/**
+ * @brief   Type to represent an IPv6 address registered to an interface.
+ */
+typedef struct {
+    ng_ipv6_addr_t addr;    /**< The address data */
+    uint8_t flags;          /**< flags */
+} ng_ipv6_netif_addr_t;
+
+/**
+ * @brief   Definition of IPv6 interface type.
+ */
+typedef struct {
+    ng_ipv6_netif_addr_t addrs[NG_IPV6_NETIF_ADDR_NUMOF];   /**< addresses registered
+                                                             *   to the interface */
+    mutex_t mutex;          /**< mutex for the interface */
+    kernel_pid_t pid;       /**< PID of the interface */
+    uint16_t mtu;           /**< Maximum Transmission Unit (MTU) of the interface */
+} ng_ipv6_netif_t;
+
+/**
+ * @brief Initializes the module.
+ */
+void ng_ipv6_netif_init(void);
+
+/**
+ * @brief   Add interface to IPv6.
+ *
+ * @details This function will be called by @ref ng_netif_add().
+ *
+ * @param[in] pid   The PID to the interface.
+ */
+void ng_ipv6_netif_add(kernel_pid_t pid);
+
+/**
+ * @brief   Remove interface from IPv6.
+ *
+ * @details This function will be called by @ref ng_netif_remove().
+ *
+ * @param[in] pid   The PID to the interface.
+ */
+void ng_ipv6_netif_remove(kernel_pid_t pid);
+
+/**
+ * @brief   Get interface.
+ *
+ * @param[in] pid   The PID to the interface.
+ *
+ * @return  The interface describing structure, on success.
+ * @return  NULL, if there is no interface with PID @p pid.
+ */
+ng_ipv6_netif_t *ng_ipv6_netif_get(kernel_pid_t pid);
+
+/**
+ * @brief   Adds an address to an interface.
+ *
+ * @param[in] pid       The PID to the interface.
+ * @param[in] addr      An address you want to add to the interface.
+ * @param[in] anycast   If @p addr should be an anycast address, @p anycast
+ *                      must be true. Otherwise set it false.
+ *                      If @p addr is a multicast address, @p anycast will be
+ *                      ignored.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4291#section-2.6">
+ *          RFC 4291, section 2.6
+ *      </a>
+ *
+ * @return  0, on success.
+ * @return  -EINVAL, if @p addr is NULL or unspecified address.
+ * @return  -ENOENT, if @p pid is no interface.
+ * @return  -ENOMEM, if there is no space left to store @p addr.
+ */
+int ng_ipv6_netif_add_addr(kernel_pid_t pid, const ng_ipv6_addr_t *addr,
+                           bool anycast);
+
+/**
+ * @brief   Remove an address from the interface.
+ *
+ * @param[in] pid       The PID to the interface.
+ * @param[in] addr      An address you want to remove from interface.
+ */
+void ng_ipv6_netif_remove_addr(kernel_pid_t pid, ng_ipv6_addr_t *addr);
+
+/**
+ * @brief   Removes all addresses from the interface.
+ *
+ * @param[in] pid       The PID to the interface.
+ */
+void ng_ipv6_netif_reset_addr(kernel_pid_t pid);
+
+/**
+ * @brief   Searches for an address on all interfaces.
+ *
+ * @param[out] out  The reference to the address on the interface.
+ * @param[in] addr  The address you want to search for.
+ *
+ * @return  The PID to the interface the address is registered to.
+ * @return  KERNEL_PID_UNDEF, if the address can not be found on any interface.
+ */
+kernel_pid_t ng_ipv6_netif_find_by_addr(ng_ipv6_addr_t **out,
+                                        const ng_ipv6_addr_t *addr);
+
+/**
+ * @brief   Searches for an address on an interface.
+ *
+ * @param[in] pid   The PID to the interface.
+ * @param[in] addr  The address you want to search for.
+ *
+ * @return  The reference to the address on the interface.
+ * @return  NULL, if the address can not be found on the interface.
+ * @return  NULL, if @p pid is no interface.
+ */
+ng_ipv6_addr_t *ng_ipv6_netif_find_addr(kernel_pid_t pid,
+                                        const ng_ipv6_addr_t *addr);
+
+/**
+ * @brief   Searches for the first address matching a prefix best on all
+ *          interfaces.
+ *
+ * @param[out] out      The reference to the found address on the interface.
+ * @param[in] prefix    The prefix you want to search for.
+ *
+ * @return  The PID to the interface the address is registered to.
+ * @return  KERNEL_PID_UNDEF, if no matching address can not be found on any
+ *          interface.
+ */
+kernel_pid_t ng_ipv6_netif_find_by_prefix(ng_ipv6_addr_t **out,
+        const ng_ipv6_addr_t *prefix);
+
+/**
+ * @brief   Searches for the first address matching a prefix best on an
+ *          interfaces.
+ *
+ * @param[in] pid       The PID to the interface.
+ * @param[in] prefix    The prefix you want to search for.
+ *
+ * @return  The reference to the found address on the interface.
+ * @return  NULL, if no matching address can be found on the interface.
+ * @return  NULL, if @p pid is no interface.
+ */
+ng_ipv6_addr_t *ng_ipv6_netif_match_prefix(kernel_pid_t pid,
+        const ng_ipv6_addr_t *prefix);
+
+/**
+ * @brief   Searches for the best address on an interface usable as a
+ *          source address for a given destination address.
+ *
+ * @param[in] pid   The PID to the interface.
+ * @param[in] dest  The destination address you want to find a destination
+ *                  address for.
+ *
+ * @return  The reference to the found address on the interface.
+ * @return  NULL, if no matching address can be found on the interface.
+ * @return  NULL, if @p pid is no interface.
+ */
+ng_ipv6_addr_t *ng_ipv6_netif_find_best_src_addr(kernel_pid_t pid, const ng_ipv6_addr_t *dest);
+
+/**
+ * @brief   Checks if an address is non-unicast.
+ *
+ * @details This only works with addresses you retrieved via the following
+ *          functions:
+ *
+ * * ng_ipv6_find_addr()
+ * * ng_ipv6_find_addr_local()
+ * * ng_ipv6_find_prefix_match()
+ * * ng_ipv6_find_prefix_match_local()
+ * * ng_ipv6_find_best_src_address
+ *
+ * The behaviour for other addresses is undefined.
+ *
+ * @param[in] addr  The address you want to check.
+ *
+ * @return true, if address is anycast or multicast.
+ * @return false, if address is unicast.
+ */
+static inline bool ng_ipv6_netif_addr_is_non_unicast(const ng_ipv6_addr_t *addr)
+{
+    return (bool)(container_of(addr, ng_ipv6_netif_addr_t, addr)->flags &
+                  NG_IPV6_NETIF_FLAGS_NON_UNICAST);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETIF_H_ */
+/**
+ * @}
+ */
diff --git a/sys/net/crosslayer/ng_netif/ng_netif.c b/sys/net/crosslayer/ng_netif/ng_netif.c
index fe70a0381e..a42a26867d 100644
--- a/sys/net/crosslayer/ng_netif/ng_netif.c
+++ b/sys/net/crosslayer/ng_netif/ng_netif.c
@@ -18,12 +18,16 @@
 #include "kernel_types.h"
 #include "net/ng_netif.h"
 
+#ifdef MODULE_NG_IPV6_NETIF
+#include "net/ng_ipv6/netif.h"
+#endif
+
 static ng_netif_handler_t if_handler[] = {
-#ifdef MODULE_NG_IPV6
-    { ipv6_if_add, ipv6_if_remove },
+#ifdef MODULE_NG_IPV6_NETIF
+    { ng_ipv6_netif_add, ng_ipv6_netif_remove },
 #endif
-    /* #ifdef MODULE_NG_IPV4
-     *  { ipv4_if_add, ipv4_if_remove },
+    /* #ifdef MODULE_NG_IPV4_NETIF
+     *  { ipv4_netif_add, ipv4_netif_remove },
      * #endif ... you get the idea
      */
     { NULL, NULL }
diff --git a/sys/net/network_layer/ng_ipv6/netif/Makefile b/sys/net/network_layer/ng_ipv6/netif/Makefile
new file mode 100644
index 0000000000..70b24d5231
--- /dev/null
+++ b/sys/net/network_layer/ng_ipv6/netif/Makefile
@@ -0,0 +1,3 @@
+MODULE = ng_ipv6_netif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c b/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c
new file mode 100644
index 0000000000..2add7223e0
--- /dev/null
+++ b/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2014 Martin Lenders <mlenders@inf.fu-berlin.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for
+ * more details.
+ */
+
+/**
+ * @addtogroup  sys_net_ng_ipv6_netif
+ * @{
+ *
+ * @file
+ *
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "kernel_types.h"
+#include "mutex.h"
+#include "net/ng_ipv6.h"
+#include "net/ng_ipv6/addr.h"
+#include "net/ng_netif.h"
+
+#include "net/ng_ipv6/netif.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+static ng_ipv6_netif_t ipv6_ifs[NG_NETIF_NUMOF];
+
+#if ENABLE_DEBUG
+static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN];
+#endif
+
+static int _add_addr_to_entry(ng_ipv6_netif_t *entry, const ng_ipv6_addr_t *addr,
+                              bool anycast)
+{
+    for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) {
+        if (ng_ipv6_addr_equal(&(entry->addrs[i].addr), addr)) {
+            return 0;
+        }
+
+        if (ng_ipv6_addr_is_unspecified(&(entry->addrs[i].addr))) {
+            DEBUG("Add %s to interface %" PRIkernel_pid "\n",
+                  ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)),
+                  entry->pid);
+            memcpy(&(entry->addrs[i].addr), addr, sizeof(ng_ipv6_addr_t));
+
+            if (anycast || ng_ipv6_addr_is_multicast(addr)) {
+                entry->addrs[i].flags = NG_IPV6_NETIF_FLAGS_NON_UNICAST;
+            }
+            else {
+                entry->addrs[i].flags = NG_IPV6_NETIF_FLAGS_UNICAST;
+            }
+
+            return 0;
+        }
+    }
+
+    return -ENOMEM;
+}
+
+static void _reset_addr_from_entry(ng_ipv6_netif_t *entry)
+{
+    DEBUG("Reset IPv6 addresses on interface %" PRIkernel_pid "\n", entry->pid);
+    memset(entry->addrs, 0, sizeof(entry->addrs));
+}
+
+void ng_ipv6_netif_init(void)
+{
+    for (int i = 0; i < NG_NETIF_NUMOF; i++) {
+        mutex_init(&(ipv6_ifs[i].mutex));
+        mutex_lock(&(ipv6_ifs[i].mutex));
+        _reset_addr_from_entry(&ipv6_ifs[i]);
+        ipv6_ifs[i].pid = KERNEL_PID_UNDEF;
+        mutex_unlock(&(ipv6_ifs[i].mutex));
+    }
+}
+
+void ng_ipv6_netif_add(kernel_pid_t pid)
+{
+    for (int i = 0; i < NG_NETIF_NUMOF; i++) {
+        if (ipv6_ifs[i].pid == pid) {
+            return; /* prevent duplicates */
+        }
+        else if (ipv6_ifs[i].pid == KERNEL_PID_UNDEF) {
+            ng_ipv6_addr_t addr = NG_IPV6_ADDR_ALL_NODES_LINK_LOCAL;
+            mutex_lock(&ipv6_ifs[i].mutex);
+
+            DEBUG("Add IPv6 interface %" PRIkernel_pid " (i = %d)\n", pid, i);
+            ipv6_ifs[i].pid = pid;
+            DEBUG(" * pid = %" PRIkernel_pid "\n", ipv6_ifs[i].pid);
+            ipv6_ifs[i].mtu = NG_IPV6_DEFAULT_MTU;
+            DEBUG(" * mtu = %d\n", ipv6_ifs[i].mtu);
+
+            _add_addr_to_entry(&ipv6_ifs[i], &addr, 0);
+
+            mutex_unlock(&ipv6_ifs[i].mutex);
+
+            return;
+        }
+    }
+
+    DEBUG("Could not add %" PRIkernel_pid " to IPv6: No space left.\n", pid);
+}
+
+void ng_ipv6_netif_remove(kernel_pid_t pid)
+{
+    ng_ipv6_netif_t *entry = ng_ipv6_netif_get(pid);
+
+    if (entry == NULL) {
+        return;
+    }
+
+    mutex_lock(&entry->mutex);
+
+    _reset_addr_from_entry(entry);
+    DEBUG("Remove IPv6 interface %" PRIkernel_pid "\n", pid);
+    entry->pid = KERNEL_PID_UNDEF;
+
+    mutex_unlock(&entry->mutex);
+}
+
+ng_ipv6_netif_t *ng_ipv6_netif_get(kernel_pid_t pid)
+{
+    for (int i = 0; i < NG_NETIF_NUMOF; i++) {
+        if (ipv6_ifs[i].pid == pid) {
+            DEBUG("Get IPv6 interface %" PRIkernel_pid " (%p, i = %d)\n", pid,
+                  (void *)(&(ipv6_ifs[i])), i);
+            return &(ipv6_ifs[i]);
+        }
+    }
+
+    return NULL;
+}
+
+int ng_ipv6_netif_add_addr(kernel_pid_t pid, const ng_ipv6_addr_t *addr,
+                           bool anycast)
+{
+    ng_ipv6_netif_t *entry = ng_ipv6_netif_get(pid);
+    int res;
+
+    if (entry == NULL) {
+        return -ENOENT;
+    }
+
+    if ((addr == NULL) || (ng_ipv6_addr_is_unspecified(addr))) {
+        return -EINVAL;
+    }
+
+    mutex_lock(&entry->mutex);
+
+    res = _add_addr_to_entry(entry, addr, anycast);
+
+    mutex_unlock(&entry->mutex);
+
+    return res;
+}
+
+void ng_ipv6_netif_remove_addr(kernel_pid_t pid, ng_ipv6_addr_t *addr)
+{
+    ng_ipv6_netif_t *entry = ng_ipv6_netif_get(pid);
+
+    if (entry == NULL) {
+        return;
+    }
+
+    mutex_lock(&entry->mutex);
+
+    for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) {
+        if (ng_ipv6_addr_equal(&(entry->addrs[i].addr), addr)) {
+            DEBUG("Remove %s to interface %" PRIkernel_pid "\n",
+                  ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), pid);
+            ng_ipv6_addr_set_unspecified(&(entry->addrs[i].addr));
+            entry->addrs[i].flags = 0;
+
+            mutex_unlock(&entry->mutex);
+            return;
+        }
+    }
+
+    mutex_unlock(&entry->mutex);
+}
+
+void ng_ipv6_netif_reset_addr(kernel_pid_t pid)
+{
+    ng_ipv6_netif_t *entry = ng_ipv6_netif_get(pid);
+
+    if (entry == NULL) {
+        return;
+    }
+
+    mutex_lock(&entry->mutex);
+
+    _reset_addr_from_entry(entry);
+
+    mutex_unlock(&entry->mutex);
+}
+
+kernel_pid_t ng_ipv6_netif_find_by_addr(ng_ipv6_addr_t **out, const ng_ipv6_addr_t *addr)
+{
+    for (int i = 0; i < NG_NETIF_NUMOF; i++) {
+        if (out != NULL) {
+            *out = ng_ipv6_netif_find_addr(ipv6_ifs[i].pid, addr);
+
+            if (*out != NULL) {
+                DEBUG("Found %s on interface %" PRIkernel_pid "\n",
+                      ng_ipv6_addr_to_str(addr_str, *out, sizeof(addr_str)),
+                      ipv6_ifs[i].pid);
+                return ipv6_ifs[i].pid;
+            }
+        }
+        else {
+            if (ng_ipv6_netif_find_addr(ipv6_ifs[i].pid, addr) != NULL) {
+                DEBUG("Found %s on interface %" PRIkernel_pid "\n",
+                      ng_ipv6_addr_to_str(addr_str, *out, sizeof(addr_str)),
+                      ipv6_ifs[i].pid);
+                return ipv6_ifs[i].pid;
+            }
+        }
+    }
+
+    if (out != NULL) {
+        *out = NULL;
+    }
+
+    return KERNEL_PID_UNDEF;
+}
+
+ng_ipv6_addr_t *ng_ipv6_netif_find_addr(kernel_pid_t pid, const ng_ipv6_addr_t *addr)
+{
+    ng_ipv6_netif_t *entry = ng_ipv6_netif_get(pid);
+
+    if (entry == NULL) {
+        return NULL;
+    }
+
+    mutex_lock(&entry->mutex);
+
+    for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) {
+        if (ng_ipv6_addr_equal(&(entry->addrs[i].addr), addr)) {
+            mutex_unlock(&entry->mutex);
+            DEBUG("Found %s on interface %" PRIkernel_pid "\n",
+                  ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)),
+                  pid);
+            return &(entry->addrs[i].addr);
+        }
+    }
+
+    mutex_unlock(&entry->mutex);
+
+    return NULL;
+}
+
+static uint8_t _find_by_prefix_unsafe(ng_ipv6_addr_t **res, ng_ipv6_netif_t *iface,
+        const ng_ipv6_addr_t *addr, bool only_unicast)
+{
+    uint8_t best_match = 0;
+
+    for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) {
+        uint8_t match;
+
+        if ((only_unicast &&
+             ng_ipv6_netif_addr_is_non_unicast(&(iface->addrs[i].addr))) ||
+            ng_ipv6_addr_is_unspecified(&(iface->addrs[i].addr))) {
+            continue;
+        }
+
+        match = ng_ipv6_addr_match_prefix(&(iface->addrs[i].addr), addr);
+
+        if (match > best_match) {
+            if (res != NULL) {
+                *res = &(iface->addrs[i].addr);
+            }
+
+            best_match = match;
+        }
+    }
+
+#if ENABLE_DEBUG
+
+    if (*res != NULL) {
+        DEBUG("Found %s on interface %" PRIkernel_pid " matching ",
+              ng_ipv6_addr_to_str(addr_str, *res, sizeof(addr_str)),
+              iface->pid);
+        DEBUG("%s by %" PRIu8 " bits (used as source address = %s)\n",
+              ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)),
+              best_match,
+              (only_unicast) ? "true" : "false");
+    }
+    else {
+        DEBUG("Did not found any address on interface %" PRIkernel_pid
+              " matching %s (used as source address = %s)\n",
+              iface->pid,
+              ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)),
+              (only_unicast) ? "true" : "false");
+    }
+
+#endif
+    return best_match;
+}
+
+kernel_pid_t ng_ipv6_netif_find_by_prefix(ng_ipv6_addr_t **out, const ng_ipv6_addr_t *prefix)
+{
+    uint8_t best_match = 0;
+    ng_ipv6_addr_t *tmp_res = NULL;
+    kernel_pid_t res = KERNEL_PID_UNDEF;
+
+    for (int i = 0; i < NG_NETIF_NUMOF; i++) {
+        uint8_t match;
+
+        mutex_lock(&(ipv6_ifs[i].mutex));
+
+        match = _find_by_prefix_unsafe(&tmp_res, ipv6_ifs + i, prefix, false);
+
+        if (match > best_match) {
+            if (out != NULL) {
+                *out = tmp_res;
+            }
+
+            res = ipv6_ifs[i].pid;
+            best_match = match;
+        }
+
+        mutex_unlock(&(ipv6_ifs[i].mutex));
+    }
+
+#if ENABLE_DEBUG
+
+    if (res != KERNEL_PID_UNDEF) {
+        DEBUG("Found %s on interface %" PRIkernel_pid " globally matching ",
+              ng_ipv6_addr_to_str(addr_str, *out, sizeof(addr_str)),
+              res);
+        DEBUG("%s by %" PRIu8 " bits\n",
+              ng_ipv6_addr_to_str(addr_str, prefix, sizeof(addr_str)),
+              best_match);
+    }
+    else {
+        DEBUG("Did not found any address globally matching %s\n",
+              ng_ipv6_addr_to_str(addr_str, prefix, sizeof(addr_str)));
+    }
+
+#endif
+
+    return res;
+}
+
+static ng_ipv6_addr_t *_match_prefix(kernel_pid_t pid, const ng_ipv6_addr_t *addr,
+        bool only_unicast)
+{
+    ng_ipv6_addr_t *res = NULL;
+    ng_ipv6_netif_t *iface = ng_ipv6_netif_get(pid);
+
+    mutex_lock(&(iface->mutex));
+
+    if (_find_by_prefix_unsafe(&res, iface, addr, only_unicast) > 0) {
+        mutex_unlock(&(iface->mutex));
+        return res;
+    }
+
+    mutex_unlock(&(iface->mutex));
+
+    return NULL;
+}
+
+ng_ipv6_addr_t *ng_ipv6_netif_match_prefix(kernel_pid_t pid,
+        const ng_ipv6_addr_t *prefix)
+{
+    return _match_prefix(pid, prefix, false);
+}
+
+ng_ipv6_addr_t *ng_ipv6_netif_find_best_src_addr(kernel_pid_t pid, const ng_ipv6_addr_t *dest)
+{
+    return _match_prefix(pid, dest, true);
+}
+
+/**
+ * @}
+ */
-- 
GitLab