diff --git a/Makefile.dep b/Makefile.dep index 1aff898994da4e0c59572888fa8f16ae6cb95618..6e6551f0032d0ad9f5c88f29fb45472e8f3fbc87 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -48,6 +48,10 @@ ifneq (,$(filter sixlowpan,$(USEMODULE))) USEMODULE += vtimer endif +ifneq (,$(filter ng_ipv6_nc,$(USEMODULE))) + USEMODULE += ng_ipv6_addr +endif + ifneq (,$(filter aodvv2,$(USEMODULE))) USEMODULE += vtimer USEMODULE += sixlowpan diff --git a/sys/Makefile b/sys/Makefile index f91df0d1afe5fbb7a31edcb91c9836140587a715..230a0296acebaa48cdb22602f06620ec849542c4 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -65,6 +65,9 @@ endif ifneq (,$(filter ng_ipv6_addr,$(USEMODULE))) DIRS += net/network_layer/ng_ipv6/addr endif +ifneq (,$(filter ng_ipv6_nc,$(USEMODULE))) + DIRS += net/network_layer/ng_ipv6/nc +endif ifneq (,$(filter ng_netapi,$(USEMODULE))) DIRS += net/crosslayer/ng_netapi endif diff --git a/sys/include/net/ng_ipv6/nc.h b/sys/include/net/ng_ipv6/nc.h new file mode 100644 index 0000000000000000000000000000000000000000..0421705bfe1810779b8639b3b6b69ee24686d943 --- /dev/null +++ b/sys/include/net/ng_ipv6/nc.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for + * more details. + */ + +/** + * @defgroup net_ng_ipv6_nc IPv6 neighbor cache + * @ingroup net_ng_ipv6 + * @brief Translates IPv6 addresses to link layer addresses. + * @{ + * + * @file + * @brief Neighbor cache definitions. + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ + +#ifndef NG_IPV6_NC_H_ +#define NG_IPV6_NC_H_ + +#include <stdint.h> + +#include "kernel_types.h" +#include "net/ng_ipv6/addr.h" +#include "net/ng_netif.h" +#include "net/ng_pktqueue.h" +#include "timex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NG_IPV6_NC_SIZE +/** + * @brief The size of the neighbor cache + */ +#define NG_IPV6_NC_SIZE (NG_NETIF_NUMOF * 8) +#endif + +#ifndef NG_IPV6_NC_L2_ADDR_MAX +/** + * @brief The maximum size of a link layer address + */ +#define NG_IPV6_NC_L2_ADDR_MAX (8) +#endif + +/** + * @{ + * @name Flag definitions for ng_ipv6_nc_t + */ +/** + * @{ + * @brief States of a neighbor cache entry. + * + * @see <a href="http://tools.ietf.org/html/rfc4861#section-7.3.2"> + * RFC 4861, section 7.3.2 + * </a> + */ +#define NG_IPV6_NC_STATE_MASK (0x07) /**< Mask for neighbor cache state */ +#define NG_IPV6_NC_STATE_POS (0) /**< Shift of neighbor cache state */ + +#define NG_IPV6_NC_STATE_UNMANAGED (0x00) /**< The entry is not manage by NDP */ + +/** + * @brief The entry is unreachable + * + * @see <a href="http://tools.ietf.org/html/rfc7048#section-3"> + * RFC 7048, section 3 + * </a> + */ +#define NG_IPV6_NC_STATE_UNREACHABLE (0x01) +#define NG_IPV6_NC_STATE_INCOMPLETE (0x02) /**< Address resolution is performed */ +#define NG_IPV6_NC_STATE_STALE (0x03) /**< The entry is stale */ +#define NG_IPV6_NC_STATE_DELAY (0x04) /**< The entry was stale but packet was sent out */ +#define NG_IPV6_NC_STATE_PROBE (0x05) /**< Periodic reachabality confirmation */ +#define NG_IPV6_NC_STATE_REACHABLE (0x07) /**< The entry is reachable */ +/** + * @} + */ + +#define NG_IPV6_NC_IS_ROUTER (0x08) /**< The neighbor is a router */ + +#define NG_IPV6_NC_TYPE_MASK (0x30) /**< Mask for neighbor cache state */ +#define NG_IPV6_NC_TYPE_POS (4) /**< Shift of neighbor cache state */ + +/** + * @{ + * @brief States of a neighbor cache entry. + * + * @see <a href="http://tools.ietf.org/html/rfc6775#section-3.5"> + * RFC 6775, section 3.5 + * </a> + */ +/** + * @brief The entry has no type + * + * @details The node sents multicast Neighbor Solicitations for hosts. + */ +#define NG_IPV6_NC_TYPE_NONE (0x00) +#define NG_IPV6_NC_TYPE_GC (0x10) /**< The entry is marked for removal */ +#define NG_IPV6_NC_TYPE_TENTATIVE (0x20) /**< The entry is temporary */ +#define NG_IPV6_NC_TYPE_REGISTERED (0x30) /**< The entry is registered */ +/** + * @} + */ +/** + * @} + */ + +/** + * @brief Neighbor cache entry as defined in + * <a href="http://tools.ietf.org/html/rfc4861#section-5.1"> + * RFC 4861, section 5.1 + * </a>. + */ +typedef struct { + ng_pktqueue_t pkts; /**< Packets waiting for address resolution */ + ng_ipv6_addr_t ipv6_addr; /**< IPv6 address of the neighbor */ + uint8_t l2_addr[NG_IPV6_NC_L2_ADDR_MAX];/**< Link layer address of the neighbor */ + uint8_t l2_addr_len; /**< Length of ng_ipv6_nc_t::l2_addr */ + uint8_t flags; /**< Flags as defined above */ + kernel_pid_t iface; /**< PID to the interface where the neighbor is */ +} ng_ipv6_nc_t; + +/** + * @brief Initializes neighbor cache + */ +void ng_ipv6_nc_init(void); + +/** + * @brief Adds a neighbor to the neighbor cache + * + * @param[in] iface PID to the interface where the neighbor is. + * Must not be KERNEL_PID_UNDEF. + * @param[in] ipv6_addr IPv6 address of the neighbor. Must not be NULL. + * @param[in] l2_addr Link layer address of the neighbor. NULL if unknown. + * @param[in] l2_addr_len Length of @p l2_addr, must be lesser than or equal + * to NG_IPV6_L2_ADDR_MAX. 0 if unknown. + * @param[in] flags Flags for the entry + * + * @return 0 on success + * @return -EADDRINUSE, if @p ipv6_addr is already registered to the neighbor + * cache. + * @return -EFAULT, if @p ipv6_addr was NULL. + * @return -EINVAL, if @p l2_addr_len is greater then @ref NG_IPV6_NC_L2_ADDR_MAX, + * @p ipv6_addr is unspecified or @p iface is KERNEL_PID_UNDEF. + * @return -ENOMEM, if no space is left to store entry. + */ +int ng_ipv6_nc_add(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr, + const void *l2_addr, size_t l2_addr_len, uint8_t flags); + +/** + * @brief Removes a neighbor from the neighbor cache + * + * @param[in] iface PID to the interface where the neighbor is. If it + * is KERNEL_PID_UNDEF it will be removed for all + * interfaces. + * @param[in] ipv6_addr IPv6 address of the neighbor + */ +void ng_ipv6_nc_remove(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr); + +/** + * @brief Searches for any neighbor cache entry fitting the @p ipv6_addr. + * + * @param[in] iface PID to the interface where the neighbor is. If it + * is KERNEL_PID_UNDEF it will be searched on all + * interfaces. + * @param[in] ipv6_addr An IPv6 address + * + * @return The neighbor cache entry, if one is found. + * @return NULL, if none is found. + */ +ng_ipv6_nc_t *ng_ipv6_nc_get(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr); + +/** + * @brief Searches for any neighbor cache entry fitting the @p ipv6_addr, + * where you currently can send a packet to (do not confuse with + * NG_IPV6_NC_STATE_REACHABLE). + * + * @param[in] iface PID to the interface where the neighbor is. If it + * is KERNEL_PID_UNDEF it will be searched on all + * interfaces. + * @param[in] ipv6_addr An IPv6 address + * + * @return The neighbor cache entry, if one is found. + * @return NULL, if none is found. + */ +ng_ipv6_nc_t *ng_ipv6_nc_get_reachable(kernel_pid_t iface, + const ng_ipv6_addr_t *ipv6_addr); + +/** + * @brief Marks an entry as still reachable, if one with a fitting @p ipv6_addr + * can be found. + * + * @details This function can be used by upper layer protocols for neighbor + * discovery optimization to confirm that there was a reachability + * confirmation (e. g. an ACK in TCP) from the neighbor. + * + * @see <a href="http://tools.ietf.org/html/rfc4861#section-7.3.1"> + * RFC 4861, section 7.3.1 + * </a> + * + * @param[in] ipv6_addr An IPv6 address + * + * @return The neighbor cache entry, if one is found. + * @return NULL, if none is found. + */ +ng_ipv6_nc_t *ng_ipv6_nc_still_reachable(const ng_ipv6_addr_t *ipv6_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_IPV6_NC_H_ */ +/** + * @} + */ diff --git a/sys/net/network_layer/ng_ipv6/nc/Makefile b/sys/net/network_layer/ng_ipv6/nc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9349ccc16f426f40838e51cdb32d20bab630e76c --- /dev/null +++ b/sys/net/network_layer/ng_ipv6/nc/Makefile @@ -0,0 +1,3 @@ +MODULE = ng_ipv6_nc + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ng_ipv6/nc/ng_ipv6_nc.c b/sys/net/network_layer/ng_ipv6/nc/ng_ipv6_nc.c new file mode 100644 index 0000000000000000000000000000000000000000..6aeb5fec0b78ae3e61f03479688b891d54aaf8bd --- /dev/null +++ b/sys/net/network_layer/ng_ipv6/nc/ng_ipv6_nc.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + */ + +#include <errno.h> +#include <string.h> + +#include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/nc.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#if ENABLE_DEBUG +static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN]; +#endif + +static ng_ipv6_nc_t ncache[NG_IPV6_NC_SIZE]; + +void ng_ipv6_nc_init(void) +{ + memset(ncache, 0, sizeof(ncache)); +} + +ng_ipv6_nc_t *_find_free_entry(void) +{ + for (int i = 0; i < NG_IPV6_NC_SIZE; i++) { + if (ng_ipv6_addr_is_unspecified(&(ncache[i].ipv6_addr))) { + return ncache + i; + } + } + + return NULL; +} + +int ng_ipv6_nc_add(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr, + const void *l2_addr, size_t l2_addr_len, uint8_t flags) +{ + if (ipv6_addr == NULL) { + DEBUG("ipv6_nc: address was NULL\n"); + return -EFAULT; + } + + if ((l2_addr_len > NG_IPV6_NC_L2_ADDR_MAX) || (iface == KERNEL_PID_UNDEF) || + ng_ipv6_addr_is_unspecified(ipv6_addr)) { + return -EINVAL; + } + + for (int i = 0; i < NG_IPV6_NC_SIZE; i++) { + if (ng_ipv6_addr_equal(&(ncache[i].ipv6_addr), ipv6_addr)) { + DEBUG("ipv6_nc: Address %s already registered\n", + ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str))); + return -EADDRINUSE; + } + + if (ncache[i].iface == KERNEL_PID_UNDEF) { + ncache[i].iface = iface; + + ng_pktqueue_init(&(ncache[i].pkts)); + memcpy(&(ncache[i].ipv6_addr), ipv6_addr, sizeof(ng_ipv6_addr_t)); + DEBUG("ipv6_nc: Register %s for interface %" PRIkernel_pid, + ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)), + iface); + + if ((l2_addr != NULL) && (l2_addr_len > 0)) { +#if ENABLE_DEBUG + DEBUG(" to L2 address "); + + for (size_t i = 0; i < l2_addr_len; i++) { + if (i > 0) { + putchar(':'); + } + + DEBUG("%02x", ((uint8_t *)l2_addr)[i]); + } + +#endif + memcpy(&(ncache[i].l2_addr), l2_addr, l2_addr_len); + ncache[i].l2_addr_len = l2_addr_len; + } + + ncache[i].flags = flags; + DEBUG(" with flags = 0x%0x\n", flags); + + return 0; + } + } + + return -ENOMEM; +} + +void ng_ipv6_nc_remove(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr) +{ + ng_ipv6_nc_t *entry = ng_ipv6_nc_get(iface, ipv6_addr); + + if (entry != NULL) { + DEBUG("ipv6_nc: Remove %s for interface %" PRIkernel_pid "\n", + ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)), + iface); + + ng_ipv6_addr_set_unspecified(&(entry->ipv6_addr)); + entry->iface = KERNEL_PID_UNDEF; + entry->flags = 0; + } +} + +ng_ipv6_nc_t *ng_ipv6_nc_get(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr) +{ + if (ipv6_addr == NULL) { + DEBUG("ipv6_nc: address was NULL\n"); + return NULL; + } + + for (int i = 0; i < NG_IPV6_NC_SIZE; i++) { + if (((iface == KERNEL_PID_UNDEF) || (iface == ncache[i].iface)) && + ng_ipv6_addr_equal(&(ncache[i].ipv6_addr), ipv6_addr)) { + DEBUG("ipv6_nc: Found entry for %s on interface %" PRIkernel_pid + " (0 = all interfaces) [%p]\n", + ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)), + iface, (void *)(ncache + i)); + + return ncache + i; + } + } + + return NULL; +} + +ng_ipv6_nc_t *ng_ipv6_nc_get_reachable(kernel_pid_t iface, + const ng_ipv6_addr_t *ipv6_addr) +{ + ng_ipv6_nc_t *entry = ng_ipv6_nc_get(iface, ipv6_addr); + + if (entry == NULL) { + DEBUG("ipv6_nc: No entry found for %s on interface %" PRIkernel_pid "\n", + ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)), + iface); + return NULL; + } + + switch ((entry->flags & NG_IPV6_NC_STATE_MASK) >> NG_IPV6_NC_STATE_POS) { + case NG_IPV6_NC_STATE_UNREACHABLE: + case NG_IPV6_NC_STATE_INCOMPLETE: + DEBUG("ipv6_nc: Entry %s is unreachable (flags = 0x%02x)\n", + ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)), + entry->flags); + return NULL; + + default: + return entry; + } +} + +ng_ipv6_nc_t *ng_ipv6_nc_still_reachable(const ng_ipv6_addr_t *ipv6_addr) +{ + ng_ipv6_nc_t *entry = ng_ipv6_nc_get(KERNEL_PID_UNDEF, ipv6_addr); + + if (entry == NULL) { + DEBUG("ipv6_nc: No entry found for %s\n", + ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str))); + return NULL; + } + + if (((entry->flags & NG_IPV6_NC_STATE_MASK) >> NG_IPV6_NC_STATE_POS) != + NG_IPV6_NC_STATE_INCOMPLETE) { + DEBUG("ipv6_nc: Marking entry %s as reachable\n", + ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str))); + entry->flags &= ~(NG_IPV6_NC_STATE_MASK >> NG_IPV6_NC_STATE_POS); + entry->flags |= (NG_IPV6_NC_STATE_REACHABLE >> NG_IPV6_NC_STATE_POS); + } + + return entry; +} + +/** @} */ diff --git a/tests/unittests/tests-ipv6_nc/Makefile b/tests/unittests/tests-ipv6_nc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2 --- /dev/null +++ b/tests/unittests/tests-ipv6_nc/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-ipv6_nc/Makefile.include b/tests/unittests/tests-ipv6_nc/Makefile.include new file mode 100644 index 0000000000000000000000000000000000000000..ccd9f9b52dee45360b8d405477f40e37335d5375 --- /dev/null +++ b/tests/unittests/tests-ipv6_nc/Makefile.include @@ -0,0 +1 @@ +USEMODULE += ng_ipv6_nc diff --git a/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c b/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c new file mode 100644 index 0000000000000000000000000000000000000000..a718ee1dd8c070a9d5712ab6c166b3f5ddd848bf --- /dev/null +++ b/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2014 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + */ +#include <errno.h> +#include <stdlib.h> + +#include "embUnit.h" + +#include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/nc.h" + +#include "tests-ipv6_nc.h" + +/* default interface for testing */ +#define DEFAULT_TEST_NETIF (TEST_UINT16) +/* default IPv6 addr for testing */ +#define DEFAULT_TEST_IPV6_ADDR { { \ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \ + } \ + } + +/* another interface for testing */ +#define OTHER_TEST_NETIF (TEST_UINT16 + TEST_UINT8) +/* another IPv6 addr for testing */ +#define OTHER_TEST_IPV6_ADDR { { \ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f \ + } \ + } + +static void set_up(void) +{ + ng_ipv6_nc_init(); +} + +static void test_ipv6_nc_add__EADDRINUSE(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, + TEST_STRING4, sizeof(TEST_STRING4), + 0)); + TEST_ASSERT_EQUAL_INT(-EADDRINUSE, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, + TEST_STRING4, sizeof(TEST_STRING4), 0)); +} + +static void test_ipv6_nc_add__EFAULT(void) +{ + TEST_ASSERT_EQUAL_INT(-EFAULT, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, NULL, + TEST_STRING4, sizeof(TEST_STRING4), 0)); +} + +static void test_ipv6_nc_add__EINVAL_KERNEL_PID_UNDEF(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + TEST_ASSERT_EQUAL_INT(-EINVAL, ng_ipv6_nc_add(KERNEL_PID_UNDEF, &addr, + TEST_STRING4, sizeof(TEST_STRING4), 0)); +} + +static void test_ipv6_nc_add__EINVAL_ipv6_addr_unspecified(void) +{ + ng_ipv6_addr_t addr = NG_IPV6_ADDR_UNSPECIFIED; + + TEST_ASSERT_EQUAL_INT(-EINVAL, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, + TEST_STRING4, sizeof(TEST_STRING4), 0)); +} + +static void test_ipv6_nc_add__EINVAL_l2addr_too_long(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + TEST_ASSERT_EQUAL_INT(-EINVAL, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, + TEST_STRING4, NG_IPV6_NC_L2_ADDR_MAX + TEST_UINT8, 0)); +} + +static void test_ipv6_nc_add__ENOMEM(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + for (int i = 0; i < NG_IPV6_NC_SIZE; i++) { + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, + TEST_STRING4, sizeof(TEST_STRING4), 0)); + addr.u16[7].u16++; + } + + TEST_ASSERT_EQUAL_INT(-ENOMEM, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, + TEST_STRING4, sizeof(TEST_STRING4), 0)); +} + +static void test_ipv6_nc_add__success(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, + TEST_STRING4, sizeof(TEST_STRING4), 0)); + + TEST_ASSERT_NOT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_remove__no_entry_pid(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + ng_ipv6_nc_remove(OTHER_TEST_NETIF, &addr); + TEST_ASSERT_NOT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)); + TEST_ASSERT_NULL(ng_ipv6_nc_get(OTHER_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_remove__no_entry_addr1(void) +{ + ng_ipv6_addr_t addr = OTHER_TEST_IPV6_ADDR; + ng_ipv6_addr_t exp_addr = DEFAULT_TEST_IPV6_ADDR; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + ng_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr); + TEST_ASSERT_NOT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &exp_addr)); + TEST_ASSERT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_remove__no_entry_addr2(void) +{ + ng_ipv6_addr_t addr = NG_IPV6_ADDR_UNSPECIFIED; + ng_ipv6_addr_t exp_addr = DEFAULT_TEST_IPV6_ADDR; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + ng_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr); + TEST_ASSERT_NOT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &exp_addr)); + TEST_ASSERT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_remove__success(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + TEST_ASSERT_NOT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)); + ng_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr); + TEST_ASSERT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_get__empty(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + TEST_ASSERT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_get__different_if(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NULL(ng_ipv6_nc_get(OTHER_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_get__different_addr(void) +{ + ng_ipv6_addr_t addr = OTHER_TEST_IPV6_ADDR; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NULL(ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_get__success_if_local(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr))); + TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, entry->iface); + TEST_ASSERT(ng_ipv6_addr_equal(&(entry->ipv6_addr), &addr)); + TEST_ASSERT_EQUAL_STRING(TEST_STRING4, (char *)entry->l2_addr); + TEST_ASSERT_EQUAL_INT(sizeof(TEST_STRING4), entry->l2_addr_len); + TEST_ASSERT_EQUAL_INT(0, entry->flags); +} + +static void test_ipv6_nc_get__success_if_global(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get(KERNEL_PID_UNDEF, &addr))); + TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, entry->iface); + TEST_ASSERT(ng_ipv6_addr_equal(&(entry->ipv6_addr), &addr)); + TEST_ASSERT_EQUAL_STRING(TEST_STRING4, (char *)entry->l2_addr); + TEST_ASSERT_EQUAL_INT(sizeof(TEST_STRING4), entry->l2_addr_len); + TEST_ASSERT_EQUAL_INT(0, entry->flags); +} + +static void test_ipv6_nc_get_reachable__incomplete_if_local(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr))); + entry->flags = (NG_IPV6_NC_STATE_INCOMPLETE << NG_IPV6_NC_STATE_POS); + TEST_ASSERT_NULL(ng_ipv6_nc_get_reachable(DEFAULT_TEST_NETIF, &addr)); +} + +static void test_ipv6_nc_get_reachable__incomplete_if_global(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get(KERNEL_PID_UNDEF, &addr))); + entry->flags = (NG_IPV6_NC_STATE_INCOMPLETE << NG_IPV6_NC_STATE_POS); + TEST_ASSERT_NULL(ng_ipv6_nc_get_reachable(KERNEL_PID_UNDEF, &addr)); +} + +static void test_ipv6_nc_get_reachable__reachable_if_local(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr))); + entry->flags = (NG_IPV6_NC_STATE_REACHABLE << NG_IPV6_NC_STATE_POS); + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_reachable(DEFAULT_TEST_NETIF, &addr))); + TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, entry->iface); + TEST_ASSERT(ng_ipv6_addr_equal(&(entry->ipv6_addr), &addr)); + TEST_ASSERT_EQUAL_STRING(TEST_STRING4, (char *)entry->l2_addr); + TEST_ASSERT_EQUAL_INT(sizeof(TEST_STRING4), entry->l2_addr_len); + TEST_ASSERT_EQUAL_INT((NG_IPV6_NC_STATE_REACHABLE << NG_IPV6_NC_STATE_POS), + entry->flags); +} + +static void test_ipv6_nc_get_reachable__reachable_if_global(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get(KERNEL_PID_UNDEF, &addr))); + entry->flags = (NG_IPV6_NC_STATE_REACHABLE << NG_IPV6_NC_STATE_POS); + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_reachable(KERNEL_PID_UNDEF, &addr))); + TEST_ASSERT_EQUAL_INT(DEFAULT_TEST_NETIF, entry->iface); + TEST_ASSERT(ng_ipv6_addr_equal(&(entry->ipv6_addr), &addr)); + TEST_ASSERT_EQUAL_STRING(TEST_STRING4, (char *)entry->l2_addr); + TEST_ASSERT_EQUAL_INT(sizeof(TEST_STRING4), entry->l2_addr_len); + TEST_ASSERT_EQUAL_INT((NG_IPV6_NC_STATE_REACHABLE << NG_IPV6_NC_STATE_POS), + entry->flags); +} + +static void test_ipv6_nc_still_reachable__incomplete(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + + /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF and sets flags to + * (NG_IPV6_NC_STATE_INCOMPLETE << NG_IPV6_NC_STATE_POS) */ + test_ipv6_nc_get_reachable__incomplete_if_global(); + + TEST_ASSERT_NULL(ng_ipv6_nc_get_reachable(KERNEL_PID_UNDEF, &addr)); + TEST_ASSERT_NOT_NULL(ng_ipv6_nc_still_reachable(&addr)); + TEST_ASSERT_NULL(ng_ipv6_nc_get_reachable(KERNEL_PID_UNDEF, &addr)); +} + +static void test_ipv6_nc_still_reachable__success(void) +{ + ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL; + + /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF and sets flags to + * (NG_IPV6_NC_STATE_REACHABLE << NG_IPV6_NC_STATE_POS) */ + test_ipv6_nc_get_reachable__reachable_if_global(); + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_reachable(KERNEL_PID_UNDEF, &addr))); + + entry->flags = (NG_IPV6_NC_STATE_STALE << NG_IPV6_NC_STATE_POS); + + TEST_ASSERT_NOT_NULL(ng_ipv6_nc_still_reachable(&addr)); + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_reachable(KERNEL_PID_UNDEF, &addr))); + TEST_ASSERT_EQUAL_INT((NG_IPV6_NC_STATE_REACHABLE << NG_IPV6_NC_STATE_POS), + entry->flags); +} + +Test *tests_ipv6_nc_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_ipv6_nc_add__EADDRINUSE), + new_TestFixture(test_ipv6_nc_add__EFAULT), + new_TestFixture(test_ipv6_nc_add__EINVAL_KERNEL_PID_UNDEF), + new_TestFixture(test_ipv6_nc_add__EINVAL_ipv6_addr_unspecified), + new_TestFixture(test_ipv6_nc_add__EINVAL_l2addr_too_long), + new_TestFixture(test_ipv6_nc_add__ENOMEM), + new_TestFixture(test_ipv6_nc_add__success), + new_TestFixture(test_ipv6_nc_remove__no_entry_pid), + new_TestFixture(test_ipv6_nc_remove__no_entry_addr1), + new_TestFixture(test_ipv6_nc_remove__no_entry_addr2), + new_TestFixture(test_ipv6_nc_remove__success), + new_TestFixture(test_ipv6_nc_get__empty), + new_TestFixture(test_ipv6_nc_get__different_if), + new_TestFixture(test_ipv6_nc_get__different_addr), + new_TestFixture(test_ipv6_nc_get__success_if_local), + new_TestFixture(test_ipv6_nc_get__success_if_global), + new_TestFixture(test_ipv6_nc_get_reachable__incomplete_if_local), + new_TestFixture(test_ipv6_nc_get_reachable__incomplete_if_global), + new_TestFixture(test_ipv6_nc_get_reachable__reachable_if_local), + new_TestFixture(test_ipv6_nc_get_reachable__reachable_if_global), + new_TestFixture(test_ipv6_nc_still_reachable__incomplete), + new_TestFixture(test_ipv6_nc_still_reachable__success), + }; + + EMB_UNIT_TESTCALLER(ipv6_nc_tests, set_up, NULL, fixtures); + + return (Test *)&ipv6_nc_tests; +} + +void tests_ipv6_nc(void) +{ + TESTS_RUN(tests_ipv6_nc_tests()); +} +/** @} */ diff --git a/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.h b/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.h new file mode 100644 index 0000000000000000000000000000000000000000..152e18f5cf0cdf77c5c8075765c6c05b014bc189 --- /dev/null +++ b/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file tests-ipv6_nc.h + * @brief Unittests for the ``ipv6_nc`` module + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef __TESTS_NETREG_H_ +#define __TESTS_NETREG_H_ + +#include "embUnit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The entry point of this test suite. + */ +void tests_ipv6_nc(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __TESTS_NETREG_H_ */ +/** @} */