diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h index a119d4d6ca28429451bdd33fbd59b143d1111735..facc9e6ccffefbb7df5fb97e373b6b0339d32fde 100644 --- a/sys/include/net/gnrc/ipv6/nib.h +++ b/sys/include/net/gnrc/ipv6/nib.h @@ -202,6 +202,26 @@ extern "C" { * @note Only handled with @ref GNRC_IPV6_NIB_CONF_ROUTER != 0 */ #define GNRC_IPV6_NIB_ROUTE_TIMEOUT (0x4fd0U) + +/** + * @brief Perform DAD event. + * + * This message type is for performing DAD for a given address. The expected + * message context is a TENTATIVE IPv6 address. + * + * @note Only handled with @ref GNRC_IPV6_NIB_CONF_SLAAC != 0 + */ +#define GNRC_IPV6_NIB_DAD (0x4fd1U) + +/** + * @brief Validate a tentative address event. + * + * Moves a TENTATIVE address to VALID state. The expected message context is a + * TENTATIVE IPv6 address. + * + * @note Only handled with @ref GNRC_IPV6_NIB_CONF_SLAAC != 0 + */ +#define GNRC_IPV6_NIB_VALID_ADDR (0x4fd2U) /** @} */ /** diff --git a/sys/include/net/gnrc/netif/ipv6.h b/sys/include/net/gnrc/netif/ipv6.h index cc77981d08bbdf0194e13e816cad48e1277b9ed6..94edf3b59254e57266c183bca19a9b573251f2bf 100644 --- a/sys/include/net/gnrc/netif/ipv6.h +++ b/sys/include/net/gnrc/netif/ipv6.h @@ -151,13 +151,14 @@ typedef struct { * and @ref net_gnrc_ipv6_nib "NIB" */ evtimer_msg_event_t search_rtr; -#if GNRC_IPV6_NIB_CONF_6LN || DOXYGEN +#if GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC || DOXYGEN /** * @brief Timers for address re-registration * * @note Only available with module @ref net_gnrc_ipv6 "gnrc_ipv6" and * @ref net_gnrc_ipv6_nib "NIB" and if - * @ref GNRC_IPV6_NIB_CONF_6LN != 0 + * @ref GNRC_IPV6_NIB_CONF_6LN != 0 or + * @ref GNRC_IPV6_NIB_CONF_SLAAC != 0 * @note Might also be usable in the later default SLAAC implementation * for NS retransmission timers. */ diff --git a/sys/net/gnrc/netif/gnrc_netif.c b/sys/net/gnrc/netif/gnrc_netif.c index 79f2c239448161c5eafca96c9008ae8e061451e0..e507a3f9fb5632e674deabf7c71b5b4802873bca 100644 --- a/sys/net/gnrc/netif/gnrc_netif.c +++ b/sys/net/gnrc/netif/gnrc_netif.c @@ -21,6 +21,7 @@ #include "net/gnrc.h" #ifdef MODULE_GNRC_IPV6_NIB #include "net/gnrc/ipv6/nib.h" +#include "net/gnrc/ipv6.h" #endif /* MODULE_GNRC_IPV6_NIB */ #ifdef MODULE_NETSTATS_IPV6 #include "net/netstats.h" @@ -589,8 +590,13 @@ int gnrc_netif_ipv6_addr_add_internal(gnrc_netif_t *netif, } } #if GNRC_IPV6_NIB_CONF_SLAAC - else { - /* TODO: send out NS to solicited nodes for DAD probing */ + else if (!gnrc_netif_is_6ln(netif)) { + /* cast to remove const qualifier (will still be used NIB internally as + * const) */ + msg_t msg = { .type = GNRC_IPV6_NIB_DAD, + .content = { .ptr = &netif->ipv6.addrs[idx] } }; + + msg_send(&msg, gnrc_ipv6_pid); } #endif #else @@ -961,8 +967,7 @@ static int _create_candidate_set(const gnrc_netif_t *netif, * be included in a candidate set." */ if ((netif->ipv6.addrs_flags[i] == 0) || - (gnrc_netif_ipv6_addr_get_state(netif, i) == - GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE)) { + gnrc_netif_ipv6_addr_dad_trans(netif, i)) { continue; } /* Check if we only want link local addresses */ diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index 0daddc216902102d6031db275532427324615f6d..68fffe6d386b2e2c31721fdf44aeee1b1147a4bb 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -297,7 +297,8 @@ static void *_event_loop(void *args) case GNRC_IPV6_NIB_RTR_TIMEOUT: case GNRC_IPV6_NIB_RECALC_REACH_TIME: case GNRC_IPV6_NIB_REREG_ADDRESS: - case GNRC_IPV6_NIB_ROUTE_TIMEOUT: + case GNRC_IPV6_NIB_DAD: + case GNRC_IPV6_NIB_VALID_ADDR: DEBUG("ipv6: NIB timer event received\n"); gnrc_ipv6_nib_handle_timer_event(msg.content.ptr, msg.type); break; diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.c new file mode 100644 index 0000000000000000000000000000000000000000..f34f88c5ced11409c68e9b56a07979ea9ba5e1e9 --- /dev/null +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2018 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 <stdbool.h> + +#include "luid.h" +#include "net/gnrc/netif/internal.h" + +#include "_nib-6ln.h" +#include "_nib-arsm.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static char addr_str[IPV6_ADDR_MAX_STR_LEN]; + +#if GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC +void _auto_configure_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, + uint8_t pfx_len) +{ + ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED; + int idx; + uint8_t flags = GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE; + + DEBUG("nib: add address based on %s/%u automatically to interface %u\n", + ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)), + pfx_len, netif->pid); +#if GNRC_IPV6_NIB_CONF_6LN + bool new_address = false; +#endif /* GNRC_IPV6_NIB_CONF_6LN */ + gnrc_netif_ipv6_get_iid(netif, (eui64_t *)&addr.u64[1]); + ipv6_addr_init_prefix(&addr, pfx, pfx_len); + if ((idx = gnrc_netif_ipv6_addr_idx(netif, &addr)) < 0) { + if ((idx = gnrc_netif_ipv6_addr_add_internal(netif, &addr, pfx_len, + flags)) < 0) { + DEBUG("nib: Can't add link-local address on interface %u\n", + netif->pid); + return; + } +#if GNRC_IPV6_NIB_CONF_6LN + new_address = true; +#endif /* GNRC_IPV6_NIB_CONF_6LN */ + } + +#if GNRC_IPV6_NIB_CONF_6LN + /* mark link-local addresses as valid on 6LN */ + if (gnrc_netif_is_6ln(netif) && ipv6_addr_is_link_local(pfx)) { + /* don't do this beforehand or risk a deadlock: + * - gnrc_netif_ipv6_addr_add_internal() adds VALID (i.e. manually configured + * addresses to the prefix list locking the NIB's mutex which is already + * locked here) */ + netif->ipv6.addrs_flags[idx] &= ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK; + netif->ipv6.addrs_flags[idx] |= GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID; + } +#endif /* GNRC_IPV6_NIB_CONF_6LN */ +#if GNRC_IPV6_NIB_CONF_6LN + if (new_address && gnrc_netif_is_6ln(netif) && + !gnrc_netif_is_6lbr(netif)) { + _handle_rereg_address(&netif->ipv6.addrs[idx]); + } +#else /* GNRC_IPV6_NIB_CONF_6LN */ + (void)idx; +#endif /* GNRC_IPV6_NIB_CONF_6LN */ +} +#endif /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */ + +#if GNRC_IPV6_NIB_CONF_SLAAC +static bool _try_l2addr_reconfiguration(gnrc_netif_t *netif) +{ + uint8_t hwaddr[GNRC_NETIF_L2ADDR_MAXLEN]; + uint16_t hwaddr_len; + + if (gnrc_netapi_get(netif->pid, NETOPT_SRC_LEN, 0, &hwaddr_len, + sizeof(hwaddr_len)) < 0) { + return false; + } + luid_get(hwaddr, hwaddr_len); +#if GNRC_IPV6_NIB_CONF_6LN + if (hwaddr_len == IEEE802154_LONG_ADDRESS_LEN) { + if (gnrc_netapi_set(netif->pid, NETOPT_ADDRESS_LONG, 0, hwaddr, + hwaddr_len) < 0) { + return false; + } + } + else +#endif + if (gnrc_netapi_set(netif->pid, NETOPT_ADDRESS, 0, hwaddr, + hwaddr_len) < 0) { + return false; + } + return true; +} + +static bool _try_addr_reconfiguration(gnrc_netif_t *netif) +{ + eui64_t orig_iid; + bool remove_old = false, hwaddr_reconf; + + if (gnrc_netif_ipv6_get_iid(netif, &orig_iid) == 0) { + remove_old = true; + } + /* seize netif to netif thread since _try_l2addr_reconfiguration uses + * gnrc_netapi_get()/gnrc_netapi_set(). Since these are synchronous this is + * safe */ + gnrc_netif_release(netif); + /* reacquire netif for IPv6 address reconfiguraton */ + hwaddr_reconf = _try_l2addr_reconfiguration(netif); + gnrc_netif_acquire(netif); + if (hwaddr_reconf) { + if (remove_old) { + for (unsigned i = 0; i < GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { + ipv6_addr_t *addr = &netif->ipv6.addrs[i]; + if (addr->u64[1].u64 == orig_iid.uint64.u64) { + gnrc_netif_ipv6_addr_remove_internal(netif, addr); + } + } + } + DEBUG("nib: Changed hardware address, due to DAD\n"); + _auto_configure_addr(netif, &ipv6_addr_link_local_prefix, 64U); + } + return hwaddr_reconf; +} + +void _remove_tentative_addr(gnrc_netif_t *netif, const ipv6_addr_t *addr) +{ + DEBUG("nib: other node has TENTATIVE address %s assigned " + "=> removing that address\n", + ipv6_addr_to_str(addr_str, addr, sizeof(addr_str))); + gnrc_netif_ipv6_addr_remove_internal(netif, addr); + + if (!ipv6_addr_is_link_local(addr) || + !_try_addr_reconfiguration(netif)) { + /* Cannot use target address as personal address and can + * not change hardware address to retry SLAAC => use purely + * DHCPv6 instead */ + /* TODO: implement IA_NA for DHCPv6 */ + /* then => tgt_netif->aac_mode = GNRC_NETIF_AAC_DHCP; */ + DEBUG("nib: would set interface %i to DHCPv6, " + "but is not implemented yet", netif->pid); + } +} + +static int _get_netif_state(gnrc_netif_t **netif, const ipv6_addr_t *addr) +{ + *netif = gnrc_netif_get_by_ipv6_addr(addr); + if (*netif != NULL) { + int idx; + + gnrc_netif_acquire(*netif); + idx = gnrc_netif_ipv6_addr_idx(*netif, addr); + return ((idx >= 0) && gnrc_netif_ipv6_addr_dad_trans(*netif, idx)) ? + idx : -1; + } + return -1; +} + +void _handle_dad(const ipv6_addr_t *addr) +{ + ipv6_addr_t sol_nodes; + gnrc_netif_t *netif = NULL; + int idx = _get_netif_state(&netif, addr); + if (idx >= 0) { + ipv6_addr_set_solicited_nodes(&sol_nodes, addr); + _snd_ns(addr, netif, &ipv6_addr_unspecified, &sol_nodes); + _evtimer_add((void *)addr, GNRC_IPV6_NIB_VALID_ADDR, + &netif->ipv6.addrs_timers[idx], + netif->ipv6.retrans_time); + } + if (netif != NULL) { + /* was acquired in `_get_netif_state()` */ + gnrc_netif_release(netif); + } +} + +void _handle_valid_addr(const ipv6_addr_t *addr) +{ + gnrc_netif_t *netif = NULL; + int idx = _get_netif_state(&netif, addr); + + if (idx >= 0) { + netif->ipv6.addrs_flags[idx] &= ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK; + netif->ipv6.addrs_flags[idx] |= GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID; + } + if (netif != NULL) { + /* was acquired in `_get_netif_state()` */ + gnrc_netif_release(netif); + } +} +#else /* GNRC_IPV6_NIB_CONF_SLAAC */ +typedef int dont_be_pedantic; +#endif /* GNRC_IPV6_NIB_CONF_SLAAC */ + +/** @} */ diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.h new file mode 100644 index 0000000000000000000000000000000000000000..76264c82ce2acf2a753be82646e7fe66c5b14056 --- /dev/null +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 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. + */ + +/** + * @ingroup net_gnrc_ipv6_nib + * @brief + * @{ + * + * @file + * @brief Definions related to SLAAC functionality of the NIB + * @see @ref GNRC_IPV6_NIB_CONF_SLAAC + * @internal + * + * @author Martine Lenders <m.lenders@fu-berlin.de> + */ +#ifndef PRIV_NIB_SLAAC_H +#define PRIV_NIB_SLAAC_H + +#include <stdint.h> + +#include "net/gnrc/ipv6/nib/conf.h" +#include "net/gnrc/netif.h" +#include "net/ipv6/addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC || defined(DOXYGEN) +/** + * @brief Auto-configures an address from a given prefix + * + * @param[in] netif The network interface the address should be added to. + * @param[in] pfx The prefix for the address. + * @param[in] pfx_len Length of @p pfx in bits. + */ +void _auto_configure_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, + uint8_t pfx_len); +#else /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */ +#define _auto_configure_addr(netif, pfx, pfx_len) \ + (void)netif; (void)pfx; (void)pfx_len; +#endif /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */ +#if GNRC_IPV6_NIB_CONF_SLAAC || defined(DOXYGE) +/** + * @brief Removes a tentative address from the interface and tries to + * reconfigure a new address + * + * @param[in] netif The network interface the address is to be removed from. + * @param[in] addr The address to remove. + */ +void _remove_tentative_addr(gnrc_netif_t *netif, const ipv6_addr_t *addr); + +/** + * @brief Handle @ref GNRC_IPV6_NIB_DAD event + * + * @param[in] addr A TENTATIVE address. + */ +void _handle_dad(const ipv6_addr_t *addr); + +/** + * @brief Handle @ref GNRC_IPV6_NIB_VALID_ADDR event + * + * @param[in] addr A TENTATIVE address. + */ +void _handle_valid_addr(const ipv6_addr_t *addr); +#else /* GNRC_IPV6_NIB_CONF_SLAAC */ +#define _remove_tentative_addr(netif, addr) \ + (void)netif; (void)addr +#define _handle_dad(addr) (void)addr +#define _handle_valid_addr(addr) (void)addr +#endif /* GNRC_IPV6_NIB_CONF_SLAAC */ + +#ifdef __cplusplus +} +#endif + +#endif /* PRIV_NIB_SLAAC_H */ +/** @} */ diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c index 50b90e0f976ae049de930aa7d3c608fd5f24df4e..4bc923948a5680ae9a5e20942bb9204b55596208 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/nib.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib.c @@ -32,6 +32,7 @@ #include "_nib-router.h" #include "_nib-6ln.h" #include "_nib-6lr.h" +#include "_nib-slaac.h" #define ENABLE_DEBUG (0) #include "debug.h" @@ -67,14 +68,6 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif_t *netif, static void _handle_pfx_timeout(_nib_offl_entry_t *pfx); static void _handle_rtr_timeout(_nib_dr_entry_t *router); static void _handle_snd_na(gnrc_pktsnip_t *pkt); -#if GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC -static void _auto_configure_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, - uint8_t pfx_len); -#else /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */ -#define _auto_configure_addr(netif, pfx, pfx_len) (void)netif; \ - (void)pfx; \ - (void)pfx_len -#endif /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */ /* needs to be exported for 6LN's ARO handling */ void _handle_search_rtr(gnrc_netif_t *netif); /** @} */ @@ -356,6 +349,12 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type) _handle_rereg_address(ctx); break; #endif /* GNRC_IPV6_NIB_CONF_6LN */ + case GNRC_IPV6_NIB_DAD: + _handle_dad(ctx); + break; + case GNRC_IPV6_NIB_VALID_ADDR: + _handle_valid_addr(ctx); + break; default: break; } @@ -838,9 +837,30 @@ static void _handle_nbr_sol(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6, DEBUG(" - Destination address: %s\n", ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str))); #if GNRC_IPV6_NIB_CONF_SLAAC - /* TODO SLAAC behavior */ + gnrc_netif_t *tgt_netif = gnrc_netif_get_by_ipv6_addr(&nbr_sol->tgt); + + if (tgt_netif != NULL) { + int idx = gnrc_netif_ipv6_addr_idx(tgt_netif, &nbr_sol->tgt); + + if (gnrc_netif_ipv6_addr_dad_trans(tgt_netif, idx)) { + if (!ipv6_addr_is_unspecified(&ipv6->src)) { + /* (see https://tools.ietf.org/html/rfc4862#section-5.4.3) */ + DEBUG("nib: Neighbor is performing AR, but target address is " + "still TENTATIVE for us => Ignoring NS\n"); + return; + } + /* cancel validation timer */ + evtimer_del(&_nib_evtimer, + &tgt_netif->ipv6.addrs_timers[idx].event); + _remove_tentative_addr(tgt_netif, &nbr_sol->tgt); + return; + } + } #endif /* GNRC_IPV6_NIB_CONF_SLAAC */ - if (!ipv6_addr_is_unspecified(&ipv6->src)) { + if (ipv6_addr_is_unspecified(&ipv6->src)) { + gnrc_ndp_nbr_adv_send(&nbr_sol->tgt, netif, &ipv6->src, false, NULL); + } + else { gnrc_pktsnip_t *reply_aro = NULL; #if GNRC_IPV6_NIB_CONF_6LR ndp_opt_t *sl2ao = NULL; @@ -948,7 +968,21 @@ static void _handle_nbr_adv(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6, (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) ? 'S' : '-', (nbr_adv->flags & NDP_NBR_ADV_FLAGS_O) ? 'O' : '-'); #if GNRC_IPV6_NIB_CONF_SLAAC - /* TODO SLAAC behavior */ + gnrc_netif_t *tgt_netif = gnrc_netif_get_by_ipv6_addr(&nbr_adv->tgt); + + if (tgt_netif != NULL) { + int idx = gnrc_netif_ipv6_addr_idx(tgt_netif, &nbr_adv->tgt); + + if (gnrc_netif_ipv6_addr_dad_trans(tgt_netif, idx)) { + /* cancel validation timer */ + evtimer_del(&_nib_evtimer, + &tgt_netif->ipv6.addrs_timers[idx].event); + _remove_tentative_addr(tgt_netif, &nbr_adv->tgt); + return; + } + /* else case beyond scope of RFC4862: + * https://tools.ietf.org/html/rfc4862#section-5.4.4 */ + } #endif /* GNRC_IPV6_NIB_CONF_SLAAC */ if (((nce = _nib_onl_get(&nbr_adv->tgt, netif->pid)) != NULL) && (nce->mode & _NC)) { @@ -1246,11 +1280,9 @@ static uint32_t _handle_pio(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, DEBUG(" - Preferred lifetime: %" PRIu32 "\n", byteorder_ntohl(pio->pref_ltime)); -#if GNRC_IPV6_NIB_CONF_SLAAC || GNRC_IPV6_NIB_CONF_6LN if (pio->flags & NDP_OPT_PI_FLAGS_A) { _auto_configure_addr(netif, &pio->prefix, pio->prefix_len); } -#endif /* GNRC_IPV6_NIB_CONF_SLAAC || GNRC_IPV6_NIB_CONF_6LN */ if ((pio->flags & NDP_OPT_PI_FLAGS_L) || gnrc_netif_is_6lr(netif)) { _nib_offl_entry_t *pfx; @@ -1293,60 +1325,4 @@ static uint32_t _handle_pio(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, return UINT32_MAX; } -#if GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC -static void _auto_configure_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, - uint8_t pfx_len) -{ - ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED; - int idx; - uint8_t flags = GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE; - - DEBUG("nib: add address based on %s/%u automatically to interface %u\n", - ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)), - pfx_len, netif->pid); -#if GNRC_IPV6_NIB_CONF_6LN - bool new_address = false; -#endif /* GNRC_IPV6_NIB_CONF_6LN */ - gnrc_netif_ipv6_get_iid(netif, (eui64_t *)&addr.u64[1]); - ipv6_addr_init_prefix(&addr, pfx, pfx_len); - if ((idx = gnrc_netif_ipv6_addr_idx(netif, &addr)) < 0) { - if ((idx = gnrc_netif_ipv6_addr_add_internal(netif, &addr, pfx_len, - flags)) < 0) { - DEBUG("nib: Can't add link-local address on interface %u\n", - netif->pid); - return; - } -#if GNRC_IPV6_NIB_CONF_6LN - new_address = true; -#endif /* GNRC_IPV6_NIB_CONF_6LN */ - } - -#if GNRC_IPV6_NIB_CONF_6LN - /* mark link-local addresses as valid on 6LN */ - if (gnrc_netif_is_6ln(netif) && ipv6_addr_is_link_local(pfx)) { - /* don't do this beforehand or risk a deadlock: - * * gnrc_netif_ipv6_addr_add_internal() adds VALID (i.e. manually configured - * addresses to the prefix list locking the NIB's mutex which is already - * locked here) */ - netif->ipv6.addrs_flags[idx] &= ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK; - netif->ipv6.addrs_flags[idx] |= GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID; - } -#endif /* GNRC_IPV6_NIB_CONF_6LN */ - /* TODO: make this line conditional on 6LN when there is a SLAAC - * implementation */ -#if GNRC_IPV6_NIB_CONF_6LN - if (new_address && gnrc_netif_is_6ln(netif) && - !gnrc_netif_is_6lbr(netif)) { - _handle_rereg_address(&netif->ipv6.addrs[idx]); - } -#else /* GNRC_IPV6_NIB_CONF_6LN */ - (void)idx; -#endif /* GNRC_IPV6_NIB_CONF_6LN */ -#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 /* GNRC_IPV6_NIB_CONF_SLAAC */ -} -#endif /* GNRC_IPV6_NIB_CONF_6LN || GNRC_IPV6_NIB_CONF_SLAAC */ - /** @} */ diff --git a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c index 7373d454be2fa1829e97de2829e300cee934c8cd..afce23dac935626f401d143f7f98385b0839bb72 100644 --- a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c +++ b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c @@ -475,6 +475,11 @@ void gnrc_ndp_rtr_adv_send(gnrc_netif_t *netif, const ipv6_addr_t *src, /* get address from source selection algorithm. * Only link local addresses may be used (RFC 4861 section 4.1) */ src = gnrc_netif_ipv6_addr_best_src(netif, dst, true); + + if (src == NULL) { + DEBUG("ndp rtr: no VALID source address found for RA\n"); + break; + } } /* add SL2A for source address */ if (src != NULL) { diff --git a/tests/gnrc_ipv6_nib/main.c b/tests/gnrc_ipv6_nib/main.c index 3e699ee4017fd8a138982753e8ab99ceb95cf55d..f430b3f2a4d978828dd7d9e745d340ef8e621479 100644 --- a/tests/gnrc_ipv6_nib/main.c +++ b/tests/gnrc_ipv6_nib/main.c @@ -449,45 +449,15 @@ static void test_handle_pkt__nbr_sol__invalid_dst(void) TEST_ASSERT_EQUAL_INT(0, msg_avail()); } -static void test_handle_pkt__nbr_sol__invalid_sl2ao(void) -{ - gnrc_ipv6_nib_nc_t nce; - void *state = NULL; - size_t icmpv6_len = _set_nbr_sol(&ipv6_addr_unspecified, &_loc_sol_nodes, - 255U, 0U, &_loc_ll, _rem_l2, - sizeof(_rem_l2)); - - gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len); - TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce), - "There is an unexpected neighbor cache entry"); - /* TODO: check other views as well */ - TEST_ASSERT_EQUAL_INT(0, msg_avail()); -} - -static void test_handle_pkt__nbr_sol__tgt_not_assigned(void) -{ - gnrc_ipv6_nib_nc_t nce; - void *state = NULL; - size_t icmpv6_len = _set_nbr_sol(&_rem_ll, &_loc_sol_nodes, - 255U, 0U, &_rem_ll, _rem_l2, - sizeof(_rem_l2)); - - gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len); - TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce), - "There is an unexpected neighbor cache entry"); - /* TODO: check other views as well */ - TEST_ASSERT_EQUAL_INT(0, msg_avail()); -} - static void test_pkt_is_nbr_adv(gnrc_pktsnip_t *pkt, const ipv6_addr_t *dst, const ipv6_addr_t *tgt, const uint8_t *tgt_l2addr, size_t tgt_l2addr_len) { + gnrc_pktsnip_t *options; gnrc_netif_hdr_t *netif_hdr; ipv6_hdr_t *ipv6_hdr; ndp_nbr_adv_t *nbr_adv; - ndp_opt_t *tl2ao; /* first snip is a netif header to _mock_netif */ TEST_ASSERT_NOT_NULL(pkt); @@ -500,7 +470,9 @@ static void test_pkt_is_nbr_adv(gnrc_pktsnip_t *pkt, const ipv6_addr_t *dst, TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_IPV6, pkt->next->type); TEST_ASSERT_EQUAL_INT(sizeof(ipv6_hdr_t), pkt->next->size); ipv6_hdr = pkt->next->data; - TEST_ASSERT(!ipv6_addr_is_multicast(&ipv6_hdr->dst)); + if ((tgt_l2addr != NULL) && (tgt_l2addr_len > 0)) { + TEST_ASSERT(!ipv6_addr_is_multicast(&ipv6_hdr->dst)); + } TEST_ASSERT_MESSAGE(ipv6_addr_equal(dst, &ipv6_hdr->dst), "dst != ipv6_hdr->dst"); TEST_ASSERT_EQUAL_INT(255, ipv6_hdr->hl); @@ -514,19 +486,65 @@ static void test_pkt_is_nbr_adv(gnrc_pktsnip_t *pkt, const ipv6_addr_t *dst, TEST_ASSERT(!ipv6_addr_is_multicast(&nbr_adv->tgt)); TEST_ASSERT_MESSAGE(ipv6_addr_equal(tgt, &nbr_adv->tgt), "tgt != nbr_adv->tgt"); - TEST_ASSERT(nbr_adv->flags & NDP_NBR_ADV_FLAGS_S); - /* fourth snip is a TL2AO for tgt_l2addr */ - TEST_ASSERT_NOT_NULL(pkt->next->next->next); - TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); - TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_t) + tgt_l2addr_len), - pkt->next->next->next->size); - tl2ao = pkt->next->next->next->data; - TEST_ASSERT_EQUAL_INT(NDP_OPT_TL2A, tl2ao->type); - TEST_ASSERT_EQUAL_INT(1, tl2ao->len); - TEST_ASSERT_MESSAGE(memcmp(tl2ao + 1, tgt_l2addr, tgt_l2addr_len) == 0, - "tl2ao.l2addr != tgt_l2addr"); + options = pkt->next->next->next; + if ((tgt_l2addr != NULL) && (tgt_l2addr_len > 0)) { + ndp_opt_t *tl2ao; + + TEST_ASSERT(nbr_adv->flags & NDP_NBR_ADV_FLAGS_S); + + /* fourth snip is a TL2AO for tgt_l2addr */ + TEST_ASSERT_NOT_NULL(options); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, options->type); + TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_t) + tgt_l2addr_len), + options->size); + tl2ao = options->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_TL2A, tl2ao->type); + TEST_ASSERT_EQUAL_INT(1, tl2ao->len); + TEST_ASSERT_MESSAGE(memcmp(tl2ao + 1, tgt_l2addr, tgt_l2addr_len) == 0, + "tl2ao.l2addr != tgt_l2addr"); + } /* no further options */ - TEST_ASSERT_NULL(pkt->next->next->next->next); + TEST_ASSERT_NULL(options->next); +} + +static void test_handle_pkt__nbr_sol__invalid_sl2ao(void) +{ + msg_t msg; + gnrc_ipv6_nib_nc_t nce; + void *state = NULL; + size_t icmpv6_len = _set_nbr_sol(&ipv6_addr_unspecified, &_loc_sol_nodes, + 255U, 0U, &_loc_ll, _rem_l2, + sizeof(_rem_l2)); + + gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len); + TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce), + "There is an unexpected neighbor cache entry"); + /* TODO: check other views as well */ + + /* check if SLAAC generated neighbor advertisement */ + TEST_ASSERT_EQUAL_INT(1, msg_avail()); + msg_receive(&msg); + TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); + test_pkt_is_nbr_adv(msg.content.ptr, &ipv6_addr_all_nodes_link_local, + &_loc_ll, NULL, 0); + gnrc_pktbuf_release(msg.content.ptr); + + TEST_ASSERT_EQUAL_INT(0, msg_avail()); +} + +static void test_handle_pkt__nbr_sol__tgt_not_assigned(void) +{ + gnrc_ipv6_nib_nc_t nce; + void *state = NULL; + size_t icmpv6_len = _set_nbr_sol(&_rem_ll, &_loc_sol_nodes, + 255U, 0U, &_rem_ll, _rem_l2, + sizeof(_rem_l2)); + + gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len); + TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce), + "There is an unexpected neighbor cache entry"); + /* TODO: check other views as well */ + TEST_ASSERT_EQUAL_INT(0, msg_avail()); } static void test_handle_pkt__nbr_sol__ll_src(unsigned exp_nud_state, @@ -1096,9 +1114,50 @@ static void test_handle_pkt__rtr_adv__success(uint8_t rtr_adv_flags, state = NULL; if (pio) { if (pio_flags & NDP_OPT_PI_FLAGS_A) { + msg_t msg; + gnrc_pktsnip_t *pkt; + gnrc_netif_hdr_t *netif_hdr; + ipv6_hdr_t *ipv6_hdr; + ndp_nbr_adv_t *nbr_sol; + TEST_ASSERT_MESSAGE(gnrc_netif_ipv6_addr_idx(_mock_netif, &_loc_gb) >= 0, "Address was not configured by PIO"); + + /* Check if SLAAC generated a neighbor solicitation */ + TEST_ASSERT_EQUAL_INT(1, msg_avail()); + msg_receive(&msg); + TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); + pkt = msg.content.ptr; + /* first snip is a netif header to _mock_netif */ + TEST_ASSERT_NOT_NULL(pkt); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_NETIF, pkt->type); + TEST_ASSERT(sizeof(gnrc_netif_hdr_t) <= pkt->size); + netif_hdr = pkt->data; + TEST_ASSERT_EQUAL_INT(_mock_netif->pid, netif_hdr->if_pid); + /* second snip is an IPv6 header to solicited nodes of _loc_gb */ + TEST_ASSERT_NOT_NULL(pkt->next); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_IPV6, pkt->next->type); + TEST_ASSERT_EQUAL_INT(sizeof(ipv6_hdr_t), pkt->next->size); + ipv6_hdr = pkt->next->data; + TEST_ASSERT_MESSAGE(ipv6_addr_equal(&ipv6_hdr->dst, + &_loc_sol_nodes), + "ipv6_hdr->dst != _loc_sol_nodes"); + TEST_ASSERT_EQUAL_INT(255, ipv6_hdr->hl); + /* third snip is a valid solicited neighbor solicitation to + * _loc_gb */ + TEST_ASSERT_NOT_NULL(pkt->next->next); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_ICMPV6, pkt->next->next->type); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_nbr_sol_t), pkt->next->next->size); + nbr_sol = pkt->next->next->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_SOL, nbr_sol->type); + TEST_ASSERT_EQUAL_INT(0, nbr_sol->code); + TEST_ASSERT(!ipv6_addr_is_multicast(&nbr_sol->tgt)); + TEST_ASSERT_MESSAGE(ipv6_addr_equal(&_loc_gb, &nbr_sol->tgt), + "_loc_gb != nbr_sol->tgt"); + /* no further options */ + TEST_ASSERT_NULL(pkt->next->next->next); + gnrc_pktbuf_release(pkt); } else { TEST_ASSERT_MESSAGE(gnrc_netif_ipv6_addr_idx(_mock_netif, diff --git a/tests/gnrc_udp/Makefile b/tests/gnrc_udp/Makefile index d5f4e65a8d1d20f589d314ee4f5d914a79e2d544..9496288ee718ca40a5eec6690d9db3bd4187a77f 100644 --- a/tests/gnrc_udp/Makefile +++ b/tests/gnrc_udp/Makefile @@ -1,6 +1,6 @@ include ../Makefile.tests_common -BOARD_INSUFFICIENT_MEMORY := calliope-mini chronos microbit msb-430 msb-430h \ +BOARD_INSUFFICIENT_MEMORY := calliope-mini chronos hifive1 microbit msb-430 msb-430h \ nucleo-f031k6 nucleo-f042k6 nucleo-f303k8 nucleo-l031k6 \ nucleo-f030r8 nucleo-f070rb nucleo-f072rb nucleo-f103rb nucleo-f302r8 \ nucleo-f334r8 nucleo-l053r8 spark-core stm32f0discovery telosb \