From 4df88c89bf2a58895400587c4f90db9388098d80 Mon Sep 17 00:00:00 2001 From: Martine Lenders <m.lenders@fu-berlin.de> Date: Wed, 26 Apr 2017 15:45:04 +0200 Subject: [PATCH] gnrc_ipv6_nib: add neighbor cache component --- Makefile.dep | 1 + sys/include/net/gnrc/ipv6.h | 2 + sys/include/net/gnrc/ipv6/nib.h | 2 + sys/include/net/gnrc/ipv6/nib/nc.h | 198 +++++++++++++++++- .../network_layer/ipv6/nib/_nib-internal.c | 70 ++++++- .../network_layer/ipv6/nib/_nib-internal.h | 64 ++++++ sys/net/gnrc/network_layer/ipv6/nib/nib_nc.c | 151 +++++++++++++ 7 files changed, 474 insertions(+), 14 deletions(-) create mode 100644 sys/net/gnrc/network_layer/ipv6/nib/nib_nc.c diff --git a/Makefile.dep b/Makefile.dep index 949924ec72..f0153a2553 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -316,6 +316,7 @@ ifneq (,$(filter gnrc_ipv6_nc,$(USEMODULE))) endif ifneq (,$(filter gnrc_ipv6_nib,$(USEMODULE))) + USEMODULE += evtimer USEMODULE += ipv6_addr USEMODULE += random endif diff --git a/sys/include/net/gnrc/ipv6.h b/sys/include/net/gnrc/ipv6.h index 11841393b2..ef600fb7e8 100644 --- a/sys/include/net/gnrc/ipv6.h +++ b/sys/include/net/gnrc/ipv6.h @@ -36,7 +36,9 @@ #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/netif.h" #ifdef MODULE_FIB diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h index f132517a4f..56a34b1b46 100644 --- a/sys/include/net/gnrc/ipv6/nib.h +++ b/sys/include/net/gnrc/ipv6/nib.h @@ -22,6 +22,8 @@ #ifndef NET_GNRC_IPV6_NIB_H #define NET_GNRC_IPV6_NIB_H +#include "net/gnrc/ipv6/nib/nc.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/sys/include/net/gnrc/ipv6/nib/nc.h b/sys/include/net/gnrc/ipv6/nib/nc.h index 917e5d1edf..e6cff1a381 100644 --- a/sys/include/net/gnrc/ipv6/nib/nc.h +++ b/sys/include/net/gnrc/ipv6/nib/nc.h @@ -47,22 +47,22 @@ extern "C" { #define GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK (0x0007) /** - * @brief not managed by NUD + * @brief Not managed by NUD */ #define GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED (0x0000) /** - * @brief entry is not reachable + * @brief Entry is not reachable */ #define GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE (0x0001) /** - * @brief address resolution is currently performed + * @brief Address resolution is currently performed */ #define GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE (0x0002) /** - * @brief address might not be reachable + * @brief Address might not be reachable */ #define GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE (0x0003) @@ -77,7 +77,7 @@ extern "C" { #define GNRC_IPV6_NIB_NC_INFO_NUD_STATE_PROBE (0x0005) /** - * @brief entry is reachable + * @brief Entry is reachable */ #define GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE (0x0006) @@ -111,21 +111,201 @@ extern "C" { #define GNRC_IPV6_NIB_NC_INFO_AR_STATE_MASK (0x0600) /** - * @brief not managed by 6Lo-AR (address can be removed when memory is low + * @brief Shift position of address registration states + */ +#define GNRC_IPV6_NIB_NC_INFO_AR_STATE_POS (9) + +/** + * @brief Not managed by 6Lo-AR (address can be removed when memory is low */ #define GNRC_IPV6_NIB_NC_INFO_AR_STATE_GC (0x0000) /** - * @brief address registration still pending at upstream router + * @brief Address registration still pending at upstream router */ #define GNRC_IPV6_NIB_NC_INFO_AR_STATE_TENTATIVE (0x0200) /** - * @brief address is registered + * @brief Address is registered */ -#define GNRC_IPV6_NIB_NC_INFO_AR_STATE_REGISTERED (0x0600) +#define GNRC_IPV6_NIB_NC_INFO_AR_STATE_REGISTERED (0x0400) + +/** + * @brief Address was added manually + */ +#define GNRC_IPV6_NIB_NC_INFO_AR_STATE_MANUAL (0x0600) /** @} */ +/** + * @brief Neighbor cache entry view on NIB + */ +typedef struct { + ipv6_addr_t ipv6; /**< Neighbor's IPv6 address */ + /** + * @brief Neighbor's link-layer address + */ + uint8_t l2addr[GNRC_IPV6_NIB_L2ADDR_MAX_LEN]; + /** + * @brief Neighbor information as defined in + * @ref net_gnrc_ipv6_nib_nc_info "info values" + */ + uint16_t info; + uint8_t l2addr_len; /**< Length of gnrc_ipv6_nib_nc_t::l2addr in bytes */ +} gnrc_ipv6_nib_nc_t; + +/** + * @brief Gets neighbor unreachability state from entry + * + * @param[in] entry A neighbor cache entry. + * + * @return The neighbor unreachability state of @p entry. + */ +static inline unsigned gnrc_ipv6_nib_nc_get_nud_state(const gnrc_ipv6_nib_nc_t *entry) +{ + return (entry->info & GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK); +} + +/** + * @brief Gets router flag of a neighbor. + * + * @param[in] entry A neighbor cache entry. + * + * @return true, if @p entry is a router. + * @return false, if @p entry is not a router. + */ +static inline bool gnrc_ipv6_nib_nc_is_router(const gnrc_ipv6_nib_nc_t *entry) +{ + return (entry->info & GNRC_IPV6_NIB_NC_INFO_IS_ROUTER); +} + +/** + * @brief Gets interface from entry + * + * @param[in] entry A neighbor cache entry + * + * @return The interface identifier of @p entry. + * @return 0 if no interface is identified for @p entry. + */ +static inline unsigned gnrc_ipv6_nib_nc_get_iface(const gnrc_ipv6_nib_nc_t *entry) +{ + return (entry->info & GNRC_IPV6_NIB_NC_INFO_IFACE_MASK) >> + GNRC_IPV6_NIB_NC_INFO_IFACE_POS; +} + +/** + * @brief Gets address registration state of an entry + * + * @param[in] entry A neighbor cache entry + * + * @return The address registration state of @p entry. + */ +static inline unsigned gnrc_ipv6_nib_nc_get_ar_state(const gnrc_ipv6_nib_nc_t *entry) +{ + return (entry->info & GNRC_IPV6_NIB_NC_INFO_AR_STATE_MASK); +} + +/** + * @brief Adds an unmanaged neighbor entry to NIB + * + * @pre `(ipv6 != NULL) && (l2addr != NULL)` + * @pre `l2addr_len <= GNRC_IPV6_NIB_L2ADDR_MAX_LEN` + * @pre `(iface > KERNEL_PID_UNDEF) && (iface <= KERNEL_PID_LAST)` + * + * @param[in] ipv6 The neighbor's IPv6 address. + * @param[in] iface The interface to the neighbor. + * @param[in] l2addr The neighbor's L2 address. + * @param[in] l2addr_len Length of @p l2addr. + * + * A neighbor cache entry created this way is marked as persistent. + * Also, a non-persistent neighbor or destination cache entry already in the + * NIB might be removed to make room for the new entry. + * If an entry pointing to the same IPv6 address as @p ipv6 exists already it + * will be overwritten and marked as unmanaged. + * + * If @ref GNRC_IPV6_NIB_CONF_ARSM != 0 @p l2addr and @p l2addr_len won't be set. + * + * @return 0 on success. + * @return -ENOMEM, if no space is left in neighbor cache. + */ +int gnrc_ipv6_nib_nc_set(const ipv6_addr_t *ipv6, unsigned iface, + const uint8_t *l2addr, size_t l2addr_len); + +/** + * @brief Deletes neighbor with address @p ipv6 from NIB + * + * @pre `ipv6 != NULL` + * + * @param[in] ipv6 The neighbor's IPv6 address. + * + * If the @p ipv6 can't be found for a neighbor in the NIB nothing happens. + */ +void gnrc_ipv6_nib_nc_del(const ipv6_addr_t *ipv6); + +/** + * @brief Mark neighbor with address @p ipv6 as reachable + * + * @pre `ipv6 != NULL` + * + * @param[in] ipv6 A neighbor's IPv6 address. May not be NULL. + * + * This function shall be called if an upper layer gets reachability + * confirmation via its own means (e.g. a TCP connection build-up or + * confirmation). Unmanaged neighbor cache entries (i.e. entries created using + * @ref gnrc_ipv6_nib_nc_set()) or entries whose next-hop are not yet in the + * neighbor cache are ignored. + * + * Entries in state @ref GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED are not + * affected by this, since they are assumed to always be reachable and kept out + * of the NUD state-machine + */ +void gnrc_ipv6_nib_nc_mark_reachable(const ipv6_addr_t *ipv6); + +/** + * @brief Iterates over all neighbor cache entries in the NIB + * + * @pre `(state != NULL) && (nce != NULL)` + * + * @param[in] iface Restrict iteration to entries on this interface. + * 0 for any interface. + * @param[in,out] state Iteration state of the neighbor cache. Must point to + * a NULL pointer to start iteration. + * @param[out] nce The next neighbor cache entry. + * + * Usage example: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * #include "net/gnrc/ipv6/nib/nc.h" + * + * int main(void) { + * void *state = NULL; + * gnrc_ipv6_nib_nc_t nce; + * + * puts("My neighbors:"); + * while (gnrc_ipv6_nib_nc_iter(0, &state, &nce)) { + * gnrc_ipv6_nib_nc_print(&nce); + * } + * return 0; + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @note The list may change during iteration, but no duplicate of already + * traversed entries must be returned. + * + * @return true, if iteration can be continued. + * @return false, if @p nce is the last neighbor cache entry in the NIB. + */ +bool gnrc_ipv6_nib_nc_iter(unsigned iface, void **state, + gnrc_ipv6_nib_nc_t *nce); + +/** + * @brief Prints a neighbor cache entry + * + * @pre `nce != NULL` + * + * @param[in] nce A neighbor cache entry. + */ +void gnrc_ipv6_nib_nc_print(gnrc_ipv6_nib_nc_t *nce); + #ifdef __cplusplus } #endif 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 f366d5ec7c..15349b3af9 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c @@ -41,6 +41,7 @@ static char addr_str[IPV6_ADDR_MAX_STR_LEN]; #endif mutex_t _nib_mutex = MUTEX_INIT; +evtimer_msg_t _nib_evtimer; static void _override_node(const ipv6_addr_t *addr, unsigned iface, _nib_onl_entry_t *node); @@ -55,6 +56,7 @@ void _nib_init(void) memset(_def_routers, 0, sizeof(_def_routers)); memset(_nis, 0, sizeof(_nis)); #endif + evtimer_init_msg(&_nib_evtimer); /* TODO: load ABR information from persistent memory */ } @@ -120,8 +122,9 @@ static inline _nib_onl_entry_t *_cache_out_onl_entry(const ipv6_addr_t *addr, DEBUG("for (addr = %s, iface = %u)\n", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), iface); + /* call _nib_nc_remove to remove timers from _evtimer */ + _nib_nc_remove(tmp); res = tmp; - res->mode = _EMPTY; _override_node(addr, iface, res); /* cstate masked in _nib_nc_add() already */ res->info |= cstate; @@ -204,6 +207,7 @@ _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)); DEBUG("nib: set %s%%%u reachable (reachable time = %u)\n", @@ -211,8 +215,11 @@ void _nib_nc_set_reachable(_nib_onl_entry_t *node) _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; - /* TODO add event for state change to STALE to event timer*/ - (void)iface; + _evtimer_add(node, GNRC_IPV6_NIB_REACH_TIMEOUT, &node->nud_timeout, + iface->reach_time); +#else + (void)node; +#endif } void _nib_nc_remove(_nib_onl_entry_t *node) @@ -221,10 +228,46 @@ void _nib_nc_remove(_nib_onl_entry_t *node) ipv6_addr_to_str(addr_str, &node->ipv6, sizeof(addr_str)), _nib_onl_get_if(node)); node->mode &= ~(_NC); - /* TODO: remove NC related timers */ +#if GNRC_IPV6_NIB_CONF_ARSM + evtimer_del((evtimer_t *)&_nib_evtimer, &node->nud_timeout.event); +#endif _nib_onl_clear(node); } +static inline void _get_l2addr_from_ipv6(uint8_t *l2addr, + const ipv6_addr_t *ipv6) +{ + memcpy(l2addr, &ipv6->u64[1], sizeof(uint64_t)); + l2addr[0] ^= 0x02; +} + +void _nib_nc_get(const _nib_onl_entry_t *node, gnrc_ipv6_nib_nc_t *nce) +{ + assert((node != NULL) && (nce != NULL)); + memcpy(&nce->ipv6, &node->ipv6, sizeof(nce->ipv6)); + nce->info = node->info; +#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)); + assert(netif != NULL); + if ((netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && + !(netif->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { + _get_l2addr_from_ipv6(nce->l2addr, &node->ipv6); + nce->l2addr_len = sizeof(uint64_t); + return; + } + } +#endif + nce->l2addr_len = node->l2addr_len; + memcpy(&nce->l2addr, &node->l2addr, node->l2addr_len); +#else + assert(ipv6_addr_is_link_local(&nce->ipv6)); + _get_l2addr_from_ipv6(nce->l2addr, &node->ipv6); + nce->l2addr_len = sizeof(uint64_t); +#endif +} + _nib_dr_entry_t *_nib_drl_add(const ipv6_addr_t *router_addr, unsigned iface) { _nib_dr_entry_t *def_router = NULL; @@ -312,7 +355,7 @@ _nib_dr_entry_t *_nib_drl_get_dr(void) /* if there is already a default router selected or * its reachability is not suspect */ if (!((_prime_def_router == NULL) || - (_node_unreachable(_prime_def_router->next_hop)))) { + (_node_unreachable(_prime_def_router->next_hop)))) { /* take it */ return _prime_def_router; } @@ -383,4 +426,21 @@ static inline bool _node_unreachable(_nib_onl_entry_t *node) } } +uint32_t _evtimer_lookup(const void *ctx, uint16_t type) +{ + evtimer_msg_event_t *event = (evtimer_msg_event_t *)_nib_evtimer.events; + uint32_t offset = 0; + + DEBUG("nib: lookup ctx = %p, type = %u\n", (void *)ctx, type); + while (event != NULL) { + offset += event->event.offset; + if ((event->msg.type == type) && + ((ctx == NULL) || (event->msg.content.ptr == ctx))) { + return offset; + } + event = (evtimer_msg_event_t *)event->event.next; + } + return UINT32_MAX; +} + /** @} */ 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 980565cc14..a1a9a711db 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h @@ -22,10 +22,14 @@ #include <stdbool.h> #include <stdint.h> +#include "evtimer_msg.h" #include "kernel_types.h" #include "mutex.h" #include "net/eui64.h" #include "net/ipv6/addr.h" +#ifdef MODULE_GNRC_IPV6 +#include "net/gnrc/ipv6.h" +#endif #include "net/gnrc/ipv6/nib/nc.h" #include "net/gnrc/ipv6/nib/conf.h" #include "net/gnrc/pktqueue.h" @@ -98,6 +102,16 @@ typedef struct _nib_onl_entry { * @note Only available if @ref GNRC_IPV6_NIB_CONF_ARSM != 0. */ uint8_t l2addr[GNRC_IPV6_NIB_L2ADDR_MAX_LEN]; + /** + * @brief Event for @ref GNRC_IPV6_NIB_REACH_TIMEOUT and + * @ref GNRC_IPV6_NIB_DELAY_TIMEOUT + * + * @note Events of these types can't be in the event queue at the same + * time (since they only have one NUD state at a time). Because of + * this we can use one event for both of them (but need the + * different types, since the events are handled differently) + */ + evtimer_msg_event_t nud_timeout; #endif /** @@ -199,6 +213,11 @@ typedef struct { */ extern mutex_t _nib_mutex; +/** + * @brief Event timer for the NIB. + */ +extern evtimer_msg_t _nib_evtimer; + /** * @brief Initializes NIB internally */ @@ -312,6 +331,16 @@ _nib_onl_entry_t *_nib_nc_add(const ipv6_addr_t *addr, unsigned iface, */ void _nib_nc_remove(_nib_onl_entry_t *node); +/** + * @brief Gets external neighbor cache entry representation from on-link entry + * + * @pre `(node != NULL) && (nce != NULL)` + * + * @param[in] node On-link entry. + * @param[out] nce External representation of the neighbor cache entry. + */ +void _nib_nc_get(const _nib_onl_entry_t *node, gnrc_ipv6_nib_nc_t *nce); + /** * @brief Sets a NUD-managed neighbor cache entry to reachable and sets the * respective event in @ref _nib_evtimer "event timer" @@ -625,6 +654,41 @@ static inline void _nib_ft_remove(_nib_offl_entry_t *nib_offl) */ _nib_iface_t *_nib_iface_get(unsigned iface); +/** + * @brief Looks up if an event is queued in the event timer + * + * @param[in] ctx Context of the event. May be NULL for any event context. + * @param[in] type [Type of the event](@ref net_gnrc_ipv6_nib_msg). + * + * @return Milliseconds to the event, if event in queue. + * @return UINT32_MAX, event is not in queue. + */ +uint32_t _evtimer_lookup(const void *ctx, uint16_t type); + +/** + * @brief Adds an event to the event timer + * + * @param[in] ctx The context of the event + * @param[in] type [Type of the event](@ref net_gnrc_ipv6_nib_msg). + * @param[in,out] event Representation of the event. + * @param[in] offset Offset in milliseconds to the event. + */ +static inline void _evtimer_add(void *ctx, int16_t type, + evtimer_msg_event_t *event, uint32_t offset) +{ +#ifdef MODULE_GNRC_IPV6 + kernel_pid_t target_pid = gnrc_ipv6_pid; +#else + kernel_pid_t target_pid = KERNEL_PID_LAST; /* just for testing */ +#endif + evtimer_del((evtimer_t *)(&_nib_evtimer), (evtimer_event_t *)event); + event->event.next = NULL; + event->event.offset = offset; + event->msg.type = type; + event->msg.content.ptr = ctx; + evtimer_add_msg(&_nib_evtimer, event, target_pid); +} + #ifdef __cplusplus } #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 new file mode 100644 index 0000000000..4cd920a535 --- /dev/null +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib_nc.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + * @author Martine Lenders <m.lenders@fu-berlin.de> + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> + +#include "net/gnrc/ipv6.h" +#include "net/gnrc/netif.h" + +#include "net/gnrc/ipv6/nib/nc.h" + +#include "_nib-internal.h" + +int gnrc_ipv6_nib_nc_set(const ipv6_addr_t *ipv6, unsigned iface, + const uint8_t *l2addr, size_t l2addr_len) +{ + _nib_onl_entry_t *node; + + assert((ipv6 != NULL) && (l2addr != NULL)); + assert(l2addr_len <= GNRC_IPV6_NIB_L2ADDR_MAX_LEN); + assert((iface > KERNEL_PID_UNDEF) && (iface <= KERNEL_PID_LAST)); + mutex_lock(&_nib_mutex); + node = _nib_nc_add(ipv6, iface, GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED); + if (node == NULL) { + mutex_unlock(&_nib_mutex); + return -ENOMEM; + } +#if GNRC_IPV6_NIB_CONF_ARSM + memcpy(node->l2addr, l2addr, l2addr_len); + node->l2addr_len = l2addr_len; +#else + (void)l2addr; + (void)l2addr_len; +#endif + node->info &= ~(GNRC_IPV6_NIB_NC_INFO_AR_STATE_MASK | + GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK); + node->info |= (GNRC_IPV6_NIB_NC_INFO_AR_STATE_MANUAL | + GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED); + mutex_unlock(&_nib_mutex); + return 0; +} + +void gnrc_ipv6_nib_nc_del(const ipv6_addr_t *ipv6) +{ + _nib_onl_entry_t *node = NULL; + + mutex_lock(&_nib_mutex); + while ((node = _nib_onl_iter(node)) != NULL) { + if (ipv6_addr_equal(ipv6, &node->ipv6)) { + _nib_nc_remove(node); + break; + } + } + mutex_unlock(&_nib_mutex); +} + +void gnrc_ipv6_nib_nc_mark_reachable(const ipv6_addr_t *ipv6) +{ + _nib_onl_entry_t *node = NULL; + + mutex_lock(&_nib_mutex); + while ((node = _nib_onl_iter(node)) != NULL) { + if ((node->mode & _NC) && ipv6_addr_equal(ipv6, &node->ipv6)) { + /* only set reachable if not unmanaged */ + if ((node->info & GNRC_IPV6_NIB_NC_INFO_NUD_STATE_MASK)) { + _nib_nc_set_reachable(node); + } + break; + } + } + mutex_unlock(&_nib_mutex); +} + +bool gnrc_ipv6_nib_nc_iter(unsigned iface, void **state, + gnrc_ipv6_nib_nc_t *entry) +{ + _nib_onl_entry_t *node = *state; + + mutex_lock(&_nib_mutex); + while ((node = _nib_onl_iter(node)) != NULL) { + if ((node->mode & _NC) && + ((iface == 0) || (_nib_onl_get_if(node) == iface))) { + _nib_nc_get(node, entry); + break; + } + } + *state = node; + mutex_unlock(&_nib_mutex); + return (*state != NULL); +} + +#if GNRC_IPV6_NIB_CONF_ARSM +static const char *_nud_str[] = { + [GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED] = "-", + [GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE] = "UNREACHABLE", + [GNRC_IPV6_NIB_NC_INFO_NUD_STATE_INCOMPLETE] = "INCOMPLETE", + [GNRC_IPV6_NIB_NC_INFO_NUD_STATE_STALE] = "STALE", + [GNRC_IPV6_NIB_NC_INFO_NUD_STATE_DELAY] = "DELAY", + [GNRC_IPV6_NIB_NC_INFO_NUD_STATE_PROBE] = "PROBE", + [GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE] = "REACHABLE", +}; +#endif + +#if GNRC_IPV6_NIB_CONF_6LR +#define _AR_STR_IDX(state) ((state) >> GNRC_IPV6_NIB_NC_INFO_AR_STATE_POS) + +static const char *_ar_str[] = { + [_AR_STR_IDX(GNRC_IPV6_NIB_NC_INFO_AR_STATE_GC)] = "GC", + [_AR_STR_IDX(GNRC_IPV6_NIB_NC_INFO_AR_STATE_TENTATIVE)] = "TENTATIVE", + [_AR_STR_IDX(GNRC_IPV6_NIB_NC_INFO_AR_STATE_REGISTERED)] = "REGISTERED", + [_AR_STR_IDX(GNRC_IPV6_NIB_NC_INFO_AR_STATE_MANUAL)] = "MANUAL", +}; +#endif + +void gnrc_ipv6_nib_nc_print(gnrc_ipv6_nib_nc_t *entry) +{ + char addr_str[IPV6_ADDR_MAX_STR_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)); + if (gnrc_ipv6_nib_nc_is_router(entry)) { + printf("router"); + } +#if GNRC_IPV6_NIB_CONF_ARSM + printf(" %s", _nud_str[gnrc_ipv6_nib_nc_get_nud_state(entry)]); +#endif +#if GNRC_IPV6_NIB_CONF_6LR + printf(" %s",_ar_str[_AR_STR_IDX(gnrc_ipv6_nib_nc_get_ar_state(entry))]); +#endif + puts(""); +} + +/** @} */ -- GitLab