1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

ng_ipv6: provide support for ng_netif

This commit is contained in:
Martine Lenders 2015-02-11 14:10:34 +01:00
parent 89a10f2630
commit 7027519f28
7 changed files with 665 additions and 6 deletions

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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_ */
/**
* @}
*/

View File

@ -18,12 +18,16 @@
#include "kernel_types.h"
#include "net/ng_netif.h"
static ng_netif_handler_t if_handler[] = {
#ifdef MODULE_NG_IPV6
{ ipv6_if_add, ipv6_if_remove },
#ifdef MODULE_NG_IPV6_NETIF
#include "net/ng_ipv6/netif.h"
#endif
/* #ifdef MODULE_NG_IPV4
* { ipv4_if_add, ipv4_if_remove },
static ng_netif_handler_t if_handler[] = {
#ifdef MODULE_NG_IPV6_NETIF
{ ng_ipv6_netif_add, ng_ipv6_netif_remove },
#endif
/* #ifdef MODULE_NG_IPV4_NETIF
* { ipv4_netif_add, ipv4_netif_remove },
* #endif ... you get the idea
*/
{ NULL, NULL }

View File

@ -0,0 +1,3 @@
MODULE = ng_ipv6_netif
include $(RIOTBASE)/Makefile.base

View File

@ -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);
}
/**
* @}
*/