diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h index 2fbcf9ee67ba..44221252584d 100644 --- a/sys/include/net/gnrc/ipv6/nib.h +++ b/sys/include/net/gnrc/ipv6/nib.h @@ -243,6 +243,18 @@ extern "C" { * @brief Interface down event */ #define GNRC_IPV6_NIB_IFACE_DOWN (0x4fd5U) + +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) || defined(DOXYGEN) +/** + * @brief Temporary address: regenerate + * + * This message type is for the event of a regeneration of a temporary address. + * The expected message context is a valid off-link entry representing the temporary address prefix. + * + * @see "REGEN_ADVANCE time units before" - https://www.rfc-editor.org/rfc/rfc8981.html#section-3.6 + */ +#define GNRC_IPV6_NIB_REGEN_TEMP_ADDR (0x4fd6U) +#endif /** @} */ /** diff --git a/sys/include/net/gnrc/ipv6/nib/conf.h b/sys/include/net/gnrc/ipv6/nib/conf.h index fddbc03e8005..48f030bde42c 100644 --- a/sys/include/net/gnrc/ipv6/nib/conf.h +++ b/sys/include/net/gnrc/ipv6/nib/conf.h @@ -65,7 +65,7 @@ extern "C" { # endif # ifndef CONFIG_GNRC_IPV6_NIB_NUMOF /* only needs to store default router */ -# define CONFIG_GNRC_IPV6_NIB_NUMOF (1) +# define CONFIG_GNRC_IPV6_NIB_NUMOF (1 + IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES)) # endif #endif #endif @@ -186,6 +186,14 @@ extern "C" { #define CONFIG_GNRC_IPV6_NIB_SLAAC 1 #endif +/** + * @brief Use temporary addresses (rfc8981) + * @see [RFC 8981](https://www.rfc-editor.org/rfc/rfc8981.html) + */ +#ifndef CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES +#define CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES 0 +#endif + /** * @brief handle Redirect Messages */ diff --git a/sys/include/net/gnrc/ipv6/nib/pl.h b/sys/include/net/gnrc/ipv6/nib/pl.h index 5ca899c64d4e..bf8cf88dd52d 100644 --- a/sys/include/net/gnrc/ipv6/nib/pl.h +++ b/sys/include/net/gnrc/ipv6/nib/pl.h @@ -90,6 +90,19 @@ int gnrc_ipv6_nib_pl_set(unsigned iface, void gnrc_ipv6_nib_pl_del(unsigned iface, const ipv6_addr_t *pfx, unsigned pfx_len); +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) || defined(DOXYGEN) +/** + * @brief Check whether the prefix list has a prefix as specified + * @param[in] iface The interface @p pfx is expected to be on (0 for any). + * @param[in] pfx The prefix to check for. + * @param[in] pfx_len Length of @p pfx in bits. + * @return true if such prefix is present, false otherwise + */ +bool gnrc_ipv6_nib_pl_has_prefix(const unsigned int iface, const ipv6_addr_t *pfx, + const uint8_t pfx_len); + +#endif + /** * @brief Iterates over all prefix list entries in the NIB. * diff --git a/sys/include/net/gnrc/netif/conf.h b/sys/include/net/gnrc/netif/conf.h index f7af784e5887..92202d40d408 100644 --- a/sys/include/net/gnrc/netif/conf.h +++ b/sys/include/net/gnrc/netif/conf.h @@ -102,6 +102,33 @@ extern "C" { #define GNRC_NETIF_IPV6_RTR_ADDR (0) #endif +/** + * @brief Maximum assumed number of valid (preferred or deprecated) temporary addresses. + * (see _nib-slaac.h) + * + * This value is not enforced but only used to increase + * the amount of configurable addresses, to make space for temporary addresses. + * + * Assuming continued use of the same prefix, + * the number of simultaneous temporary addresses + * can be expressed by the following (not considering REGEN_ADVANCE): + * @ref TEMP_VALID_LIFETIME / min_pref_lft=(@ref TEMP_PREFERRED_LIFETIME - @ref MAX_DESYNC_FACTOR) + * (Calculates the addresses that are generated within an address's lifetime.) + * -> floor(...) to only consider already generated addresses + * -> +1 to also account for the first address itself + * + * @see CONFIG_GNRC_IPV6_NIB_OFFL_NUMOF + * May need to be increased; each temporary address has a /128 prefix + * to manage its maximum total lifetimes. + */ +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) || defined(DOXYGEN) +#ifndef MAX_TEMP_ADDRESSES +#define MAX_TEMP_ADDRESSES (4) +#endif +#else +#define MAX_TEMP_ADDRESSES (0) +#endif + /** * @brief Maximum number of unicast and anycast addresses per interface * @@ -110,11 +137,12 @@ extern "C" { * addresses' solicited nodes multicast addresses. * * Default: 2 (1 link-local + 1 global address) + any additional address via - * configuration protocol (e.g. DHCPv6 leases). + * configuration protocol (e.g. DHCPv6 leases) + temporary addresses. */ #ifndef CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF #define CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF (2 + \ - DHCPV6_CLIENT_ADDRS_NUMOF) + DHCPV6_CLIENT_ADDRS_NUMOF + \ + MAX_TEMP_ADDRESSES) #endif /** diff --git a/sys/include/net/gnrc/netif/internal.h b/sys/include/net/gnrc/netif/internal.h index 5e0de86c2b60..9e74ac004367 100644 --- a/sys/include/net/gnrc/netif/internal.h +++ b/sys/include/net/gnrc/netif/internal.h @@ -130,6 +130,28 @@ void gnrc_netif_ipv6_addr_remove_internal(gnrc_netif_t *netif, int gnrc_netif_ipv6_addr_idx(gnrc_netif_t *netif, const ipv6_addr_t *addr); +/** + * @brief Returns the index of the first addr + * in gnrc_netif_t::ipv6_addrs of @p netif + * where the first @p pfx_len bits match with @p pfx + * + * @pre `(netif != NULL) && (pfx != NULL)` + * + * Can be used to check if an address is assigned to an interface. + * + * @param[in] netif the network interface + * @param[in] pfx the prefix to match + * @param[in] pfx_len the amount of bits to compare + * + * @note Only available with @ref net_gnrc_ipv6 "gnrc_ipv6". + * + * @return index of the first matching address + * in gnrc_netif_t::ipv6_addrs of @p netif + * @return -1, if no matching address found for @p netif + */ +int gnrc_netif_ipv6_addr_pfx_idx(gnrc_netif_t *netif, + const ipv6_addr_t *pfx, uint8_t pfx_len); + /** * @brief Gets state from address flags * @@ -160,6 +182,24 @@ static inline uint8_t gnrc_netif_ipv6_addr_dad_trans(const gnrc_netif_t *netif, return netif->ipv6.addrs_flags[idx] & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE; } +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) || defined(DOXYGEN) +/** + * @brief Gets number of address generation retries already performed for an address + * + * @param[in] netif the network interface + * @param[in] idx index of the address (and its flags) + * + * @return the number of address generation retries already + * performed + */ +static inline uint8_t gnrc_netif_ipv6_addr_gen_retries(const gnrc_netif_t *netif, + int idx) +{ + return (netif->ipv6.addrs_flags[idx] & GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES) + >> GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES_POS; +} +#endif + /** * @brief Returns the index of an address in gnrc_netif_t::ipv6_addrs of @p * netif that matches @p addr best @@ -201,9 +241,6 @@ int gnrc_netif_ipv6_addr_match(gnrc_netif_t *netif, * @todo Rule 6 from RFC 6724 is currently not implemented. Has to updated as * soon as gnrc supports flow labels. * - * @todo Rule 7 from RFC 6724 is currently not implemented. Has to updated as - * soon as gnrc supports temporary addresses. - * * @return The best source address for a packet addressed to @p dst * @return NULL, if no matching address can be found on the interface. */ @@ -563,6 +600,17 @@ void gnrc_netif_init_6ln(gnrc_netif_t *netif); */ void gnrc_netif_ipv6_init_mtu(gnrc_netif_t *netif); +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) || defined(DOXYGEN) +/** + * @brief Get DupAddrDetectTransmits + * @see https://datatracker.ietf.org/doc/html/rfc4862#section-5.1 + * @return DupAddrDetectTransmits + * @return `-ENOTSUP`, when unimplemented for + * gnrc_netif_t::device_type of @p netif +*/ +int gnrc_netif_ipv6_dad_transmits(const gnrc_netif_t *netif); +#endif + /** * @brief Converts a given hardware address to an IPv6 IID. * diff --git a/sys/include/net/gnrc/netif/ipv6.h b/sys/include/net/gnrc/netif/ipv6.h index d58c708017d8..2de365bfbdb2 100644 --- a/sys/include/net/gnrc/netif/ipv6.h +++ b/sys/include/net/gnrc/netif/ipv6.h @@ -68,6 +68,18 @@ extern "C" { * @brief Address is an anycast address */ #define GNRC_NETIF_IPV6_ADDRS_FLAGS_ANYCAST (0x20U) + +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) || defined(DOXYGEN) +/** + * @brief Number of address generation retries + * Used for temporary addresses, where the upper limit is defined by @ref TEMP_IDGEN_RETRIES + */ +#define GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES (0xC0U) +/** + * @brief Shift position of address generation retries + */ +#define GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES_POS (6) +#endif /** @} */ /** diff --git a/sys/net/gnrc/netif/gnrc_netif.c b/sys/net/gnrc/netif/gnrc_netif.c index 8ececfad0356..5e0c913ed2de 100644 --- a/sys/net/gnrc/netif/gnrc_netif.c +++ b/sys/net/gnrc/netif/gnrc_netif.c @@ -46,6 +46,9 @@ #include "net/gnrc/netif.h" #include "net/gnrc/netif/internal.h" #include "net/gnrc/tx_sync.h" +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +#include "../network_layer/ipv6/nib/_nib-slaac.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" @@ -502,6 +505,9 @@ void gnrc_netif_release(gnrc_netif_t *netif) #if IS_USED(MODULE_GNRC_NETIF_IPV6) static int _addr_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr); +static int _addr_pfx_idx(const gnrc_netif_t *netif, + const ipv6_addr_t *pfx, + uint8_t pfx_len); static int _group_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr); static char addr_str[IPV6_ADDR_MAX_STR_LEN]; @@ -689,6 +695,9 @@ void gnrc_netif_ipv6_addr_remove_internal(gnrc_netif_t *netif, { bool remove_sol_nodes = true; ipv6_addr_t sol_nodes; +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + ipv6_addr_t addr_backup = *addr; +#endif assert((netif != NULL) && (addr != NULL)); ipv6_addr_set_solicited_nodes(&sol_nodes, addr); @@ -713,6 +722,15 @@ void gnrc_netif_ipv6_addr_remove_internal(gnrc_netif_t *netif, gnrc_netif_ipv6_group_leave_internal(netif, &sol_nodes); } gnrc_netif_release(netif); + +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + // for temporary addresses (deleted on DAD failure or manually), + // also their prefix needs to be removed + gnrc_ipv6_nib_pl_del(netif->pid, &addr_backup, IPV6_ADDR_BIT_LEN); + // only expected to find a prefix if it's a temporary address. + // on prefix deletion, it won't find an address to delete + // this is fine, to avoid infinite loop +#endif } int gnrc_netif_ipv6_addr_idx(gnrc_netif_t *netif, @@ -730,6 +748,23 @@ int gnrc_netif_ipv6_addr_idx(gnrc_netif_t *netif, return idx; } +int gnrc_netif_ipv6_addr_pfx_idx(gnrc_netif_t *netif, + const ipv6_addr_t *pfx, uint8_t pfx_len) +{ + int idx; + + assert((netif != NULL) && (pfx != NULL)); + DEBUG("gnrc_netif: get index of first address matching %s/%u" + " from interface %" PRIkernel_pid "\n", + ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)), + pfx_len, + netif->pid); + gnrc_netif_acquire(netif); + idx = _addr_pfx_idx(netif, pfx, pfx_len); + gnrc_netif_release(netif); + return idx; +} + int gnrc_netif_ipv6_addr_match(gnrc_netif_t *netif, const ipv6_addr_t *addr) { @@ -947,11 +982,35 @@ static int _idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr, bool mcast) return -1; } +static int _pfx_idx(const gnrc_netif_t *netif, const ipv6_addr_t *pfx, uint8_t pfx_len, bool mcast) +{ + //same as function @ref _idx above, but with generalized condition + if (!ipv6_addr_is_unspecified(pfx)) { + const ipv6_addr_t *iplist = (mcast) ? netif->ipv6.groups : + netif->ipv6.addrs; + unsigned ipmax = (mcast) ? GNRC_NETIF_IPV6_GROUPS_NUMOF : + CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF; + for (unsigned i = 0; i < ipmax; i++) { + if (ipv6_addr_match_prefix(&iplist[i], pfx) >= pfx_len) { + return i; + } + } + } + return -1; +} + static inline int _addr_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr) { return _idx(netif, addr, false); } +static inline int _addr_pfx_idx(const gnrc_netif_t *netif, + const ipv6_addr_t *pfx, + uint8_t pfx_len) +{ + return _pfx_idx(netif, pfx, pfx_len, false); +} + static inline int _group_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr) { return _idx(netif, addr, true); @@ -1110,6 +1169,8 @@ static int _create_candidate_set(const gnrc_netif_t *netif, /* number of "points" assigned to an source address candidate in preferred * state */ #define RULE_3_PTS (1) +/* number of "points" assigned to a temporary source address candidate */ +#define RULE_7_PTS (1) /** * @brief Caps the match at a source addresses prefix length @@ -1234,10 +1295,13 @@ static ipv6_addr_t *_src_addr_selection(gnrc_netif_t *netif, * TODO: update as soon as gnrc supports flow labels */ - /* Rule 7: Prefer temporary addresses. - * Temporary addresses are currently not supported by gnrc. - * TODO: update as soon as gnrc supports temporary addresses - */ + /* Rule 7: Prefer temporary addresses. */ +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + if (is_temporary_addr(netif, ptr)) { + DEBUG("winner for rule 7 found\n"); + winner_set[i] += RULE_7_PTS; + } +#endif if (winner_set[i] > max_pts) { idx = i; diff --git a/sys/net/gnrc/netif/gnrc_netif_device_type.c b/sys/net/gnrc/netif/gnrc_netif_device_type.c index 654ed31b5843..e68a99046f44 100644 --- a/sys/net/gnrc/netif/gnrc_netif_device_type.c +++ b/sys/net/gnrc/netif/gnrc_netif_device_type.c @@ -24,6 +24,7 @@ #include "net/eui48.h" #include "net/gnrc/netif.h" #include "net/ieee802154.h" +#include "net/sixlowpan/nd.h" #include "net/l2util.h" #if IS_USED(MODULE_GNRC_NETIF_IPV6) @@ -219,6 +220,24 @@ void gnrc_netif_ipv6_init_mtu(gnrc_netif_t *netif) } } +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +int gnrc_netif_ipv6_dad_transmits(const gnrc_netif_t *netif) +{ + switch (netif->device_type) { + #if defined(MODULE_NETDEV_IEEE802154) + case NETDEV_TYPE_IEEE802154: + return SIXLOWPAN_ND_REG_TRANSMIT_NUMOF; + #endif + #if defined(MODULE_NETDEV_ETH) + case NETDEV_TYPE_ETHERNET: + return NDP_DAD_TRANSMIT_NUMOF; + #endif + default: + return -ENOTSUP; + } +} +#endif + int gnrc_netif_ipv6_iid_from_addr(const gnrc_netif_t *netif, const uint8_t *addr, size_t addr_len, eui64_t *iid) diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index fea9c412b603..a8cfc681e40c 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -237,6 +237,9 @@ static void *_event_loop(void *args) case GNRC_IPV6_NIB_ADDR_REG_TIMEOUT: case GNRC_IPV6_NIB_ABR_TIMEOUT: case GNRC_IPV6_NIB_PFX_TIMEOUT: +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + case GNRC_IPV6_NIB_REGEN_TEMP_ADDR: +#endif case GNRC_IPV6_NIB_RTR_TIMEOUT: case GNRC_IPV6_NIB_RECALC_REACH_TIME: case GNRC_IPV6_NIB_REREG_ADDRESS: diff --git a/sys/net/gnrc/network_layer/ipv6/nib/Kconfig b/sys/net/gnrc/network_layer/ipv6/nib/Kconfig index bf87ffdcd224..11b78db3bac7 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/Kconfig +++ b/sys/net/gnrc/network_layer/ipv6/nib/Kconfig @@ -38,6 +38,10 @@ config GNRC_IPV6_NIB_SLAAC default n if USEMODULE_GNRC_IPV6_NIB_6LR || USEMODULE_GNRC_IPV6_NIB_6LN default y +config GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES + bool "Use temporary addresses (rfc8981)" + depends on GNRC_IPV6_NIB_SLAAC + config GNRC_IPV6_NIB_QUEUE_PKT bool "Use packet queue with address resolution" default n if USEMODULE_GNRC_IPV6_NIB_6LN || GNRC_IPV6_NIB_6LN 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 8b9ed0e23f80..fedfe34c8150 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c @@ -30,6 +30,9 @@ #include "_nib-internal.h" #include "_nib-router.h" +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +#include "_nib-slaac.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" @@ -693,6 +696,10 @@ int _nib_get_route(const ipv6_addr_t *dst, gnrc_pktsnip_t *pkt, void _nib_pl_remove(_nib_offl_entry_t *nib_offl) { _evtimer_del(&nib_offl->pfx_timeout); +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + /* remove temporary address timer (not present if not a temporary address) */ + _evtimer_del(&nib_offl->regen_temp_addr); +#endif _nib_offl_remove(nib_offl, _PL); #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C) unsigned idx = _idx_dsts(nib_offl); @@ -716,21 +723,45 @@ void _nib_offl_remove_prefix(_nib_offl_entry_t *pfx) { gnrc_netif_t *netif; + /* get interface associated with prefix */ + netif = gnrc_netif_get_by_pid(_nib_onl_get_if(pfx->next_hop)); + /* back up values */ + uint8_t pfx_len = pfx->pfx_len; + ipv6_addr_t pfx_value = pfx->pfx; +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + bool is_slaac_prefix = (pfx->flags & _PFX_SLAAC); +#endif + /* remove prefix timer */ evtimer_del(&_nib_evtimer, &pfx->pfx_timeout.event); +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + /* remove temporary address timer (not present if not a temporary address) */ + evtimer_del(&_nib_evtimer, &pfx->regen_temp_addr.event); +#endif - /* get interface associated with prefix */ - netif = gnrc_netif_get_by_pid(_nib_onl_get_if(pfx->next_hop)); + /* remove prefix */ + _nib_pl_remove(pfx); if (netif != NULL) { - uint8_t best_match_len = pfx->pfx_len; +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + if (is_slaac_prefix) { + /* remove prefixes that manage a temporary address */ + ipv6_addr_t temp_addr; + void *state = NULL; + while (_iter_slaac_prefix_to_temp_addr(netif, &pfx_value, state, &temp_addr)) { + gnrc_ipv6_nib_pl_del(netif->pid, &temp_addr, IPV6_ADDR_BIT_LEN); + } + } +#endif + + uint8_t best_match_len = pfx_len; ipv6_addr_t *best_match = NULL; /* remove address associated with prefix */ for (int i = 0; i < CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { if (ipv6_addr_match_prefix(&netif->ipv6.addrs[i], - &pfx->pfx) >= best_match_len) { - best_match_len = pfx->pfx_len; + &pfx_value) >= best_match_len) { + best_match_len = pfx_len; best_match = &netif->ipv6.addrs[i]; } } @@ -739,9 +770,6 @@ void _nib_offl_remove_prefix(_nib_offl_entry_t *pfx) best_match); } } - - /* remove prefix */ - _nib_pl_remove(pfx); } #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C) 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 59d48591855c..69e94b14b938 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h @@ -208,6 +208,12 @@ typedef struct { * @brief Event for @ref GNRC_IPV6_NIB_ROUTE_TIMEOUT */ evtimer_msg_event_t route_timeout; +#endif +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + /** + * @brief Event for @ref GNRC_IPV6_NIB_REGEN_TEMP_ADDR + */ + evtimer_msg_event_t regen_temp_addr; #endif uint8_t mode; /**< [mode](@ref net_gnrc_ipv6_nib_mode) of the * off-link entry */ diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.c index a76cb03778ec..c5c5fe64a129 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.c @@ -23,6 +23,10 @@ #include "_nib-6ln.h" #include "_nib-arsm.h" +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +#include "_nib-slaac.h" +#include "evtimer.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" @@ -96,6 +100,174 @@ void _auto_configure_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, } #endif /* CONFIG_GNRC_IPV6_NIB_6LN || CONFIG_GNRC_IPV6_NIB_SLAAC */ +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +int32_t _generate_temporary_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, + const uint32_t pfx_pref_ltime, + const uint8_t retries, + int *idx) +{ + DEBUG("nib: add temporary address based on %s/%u automatically to interface %u\n", + ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)), + 64, netif->pid); + + if (pfx_pref_ltime <= _get_netif_regen_advance(netif)) { + /* While RIOT's implementation design differs from the RFC implementation design, + * this check is here to fulfill the constraints imposed by + * https://www.rfc-editor.org/rfc/rfc8981.html#section-3.4-3.4.2.2 + * in combination with the next bullet point ("5.") + * + * It also covers/fulfills the requirement + * "Note that if a temporary address becomes deprecated as result of + * processing a Prefix Information option with a zero preferred lifetime, + * then a new temporary address MUST NOT be generated" + */ + LOG_WARNING("nib: Abort adding temporary address " + "because prefix's preferred lifetime too short (%"PRIu32" <= %"PRIu32")\n", + pfx_pref_ltime, _get_netif_regen_advance(netif)); + return -1; + } + const uint32_t ta_max_pref_lft = TEMP_PREFERRED_LIFETIME + - random_uint32_range(0, MAX_DESYNC_FACTOR + 1); + if (ta_max_pref_lft <= MS_PER_SEC * _get_netif_regen_advance(netif)) { + /* https://www.rfc-editor.org/rfc/rfc8981.html#section-3.4-3.5 */ + LOG_ERROR("nib: Abort adding temporary address because configured " + "TEMP_PREFERRED_LIFETIME (%lu) too short or MAX_DESYNC_FACTOR too high (%lu)\n", + TEMP_PREFERRED_LIFETIME, MAX_DESYNC_FACTOR); + + /* in other words, as per + * https://www.rfc-editor.org/rfc/rfc8981.html#section-3.8-7.2 */ + assert(MAX_DESYNC_FACTOR < TEMP_PREFERRED_LIFETIME + - MS_PER_SEC * _get_netif_regen_advance(netif)); + + return -1; + } + + ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED; + ipv6_addr_init_prefix(&addr, pfx, SLAAC_PREFIX_LENGTH); + do { + _ipv6_get_random_iid((eui64_t *) &addr.u64[1]); + } while (gnrc_netif_ipv6_addr_idx(netif, &addr) >= 0); + + _nib_offl_entry_t *ta_pfx = _nib_pl_add(netif->pid, &addr, + IPV6_ADDR_BIT_LEN, + TEMP_VALID_LIFETIME, + ta_max_pref_lft); + if (ta_pfx == NULL) { + LOG_WARNING("nib: Abort adding temporary address because prefix list full\n"); + return -1; + } + _evtimer_add(ta_pfx, GNRC_IPV6_NIB_REGEN_TEMP_ADDR, &ta_pfx->regen_temp_addr, + ta_max_pref_lft - _get_netif_regen_advance(netif)); //add next regen timer + + int index; + uint8_t flags = GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE + | (retries << GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES_POS); + if ((index = gnrc_netif_ipv6_addr_add_internal(netif, + &addr, + IPV6_ADDR_BIT_LEN, + flags)) < 0) { + LOG_WARNING("nib: Abort adding temporary address, adding address failed\n"); + //remove the just created prefix again + gnrc_ipv6_nib_pl_del(netif->pid, &addr, IPV6_ADDR_BIT_LEN); + return -1; + } + if (idx != NULL) { + *idx = index; + } + +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_6LN) + if (gnrc_netif_is_6ln(netif) && + !gnrc_netif_is_6lbr(netif)) { + _handle_rereg_address(&netif->ipv6.addrs[index]); + } +#endif + + return 0; +} + +int _regen_temp_addr(gnrc_netif_t *netif, const ipv6_addr_t *addr, uint8_t retries, + const char *caller_description) { + //find associated prefix + uint32_t slaac_prefix_pref_until; + if (!_get_slaac_prefix_pref_until(netif, addr, &slaac_prefix_pref_until)) { + // at least one match is expected, + LOG_WARNING("nib: The temporary address smh outlived the SLAAC prefix valid lft."); + assert(false); + return -1; + } + + uint32_t now = evtimer_now_msec(); + assert(now < slaac_prefix_pref_until); + // else the temporary address smh outlived the SLAAC prefix preferred lft + + if (_generate_temporary_addr(netif, addr, + slaac_prefix_pref_until - now, + retries, + NULL) < 0) { + LOG_WARNING("nib: Temporary address regeneration failed%s.\n", caller_description); + return -1; + } + + return 0; +} + +bool is_temporary_addr(const gnrc_netif_t *netif, const ipv6_addr_t *addr) { + return gnrc_ipv6_nib_pl_has_prefix(netif->pid, addr, IPV6_ADDR_BIT_LEN); +} + +bool _iid_is_iana_reserved(const eui64_t *iid) +{ + return (iid->uint64.u64 == htonll(0)) + || (iid->uint32[0].u32 == htonl(0x02005eff) && iid->uint8[4] == 0xfe) + || (iid->uint32[0].u32 == htonl(0xfdffffff) + && iid->uint16[2].u16 == htons(0xffff) + && iid->uint8[6] == 0xff && (iid->uint8[7] & 0x80)); +} + +void _ipv6_get_random_iid(eui64_t *iid) +{ + do { + random_bytes(iid->uint8, 8); + } while (_iid_is_iana_reserved(iid)); +} + +uint32_t _get_netif_regen_advance(const gnrc_netif_t *netif) +{ + return 2 + (TEMP_IDGEN_RETRIES * + (gnrc_netif_ipv6_dad_transmits(netif) * (netif->ipv6.retrans_time / 1000)) + ); +} + +bool _get_slaac_prefix_pref_until(const gnrc_netif_t *netif, + const ipv6_addr_t *addr, + uint32_t *slaac_prefix_pref_until) { + void *state = NULL; + gnrc_ipv6_nib_pl_t ple; + while (gnrc_ipv6_nib_pl_iter(netif->pid, &state, &ple)) { + if (ple.pfx_len == SLAAC_PREFIX_LENGTH + && ipv6_addr_match_prefix(&ple.pfx, addr) >= ple.pfx_len) { + *slaac_prefix_pref_until = ple.pref_until; + return true; + } + } + return false; +} + +bool _iter_slaac_prefix_to_temp_addr(const gnrc_netif_t *netif, + const ipv6_addr_t *slaac_pfx, void *state, + ipv6_addr_t *next_temp_addr) { + gnrc_ipv6_nib_pl_t ple; + while (gnrc_ipv6_nib_pl_iter(netif->pid, &state, &ple)) { + if (ple.pfx_len == IPV6_ADDR_BIT_LEN /* is temp addr. prefix */ + && ipv6_addr_match_prefix(&ple.pfx, slaac_pfx) >= SLAAC_PREFIX_LENGTH) { + *next_temp_addr = ple.pfx; + return true; + } + } + return false; +} +#endif + #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC) static bool _try_l2addr_reconfiguration(gnrc_netif_t *netif) { @@ -158,8 +330,34 @@ 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))); +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + bool is_temp_addr = is_temporary_addr(netif, addr); + //need to determine before addr removal, + //because it deletes the prefix which is used to determine whether it's a temp addr + uint8_t retries; + if (is_temp_addr) { + int idx = gnrc_netif_ipv6_addr_idx(netif, addr); + assert(idx >= 0); + retries = gnrc_netif_ipv6_addr_gen_retries(netif, idx); + } +#endif gnrc_netif_ipv6_addr_remove_internal(netif, addr); +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + if (is_temp_addr) { + if (retries >= TEMP_IDGEN_RETRIES) { + //https://www.rfc-editor.org/rfc/rfc8981.html#section-3.4-3.7 + LOG_ERROR("nib: Not regenerating temporary address, retried often enough.\n"); + return; + } + retries++; + DEBUG("Trying regeneration of temporary address. (%u/%u)\n", retries, TEMP_IDGEN_RETRIES); + + _regen_temp_addr(netif, addr, retries, " after DAD failure"); + return; + } +#endif + if (!ipv6_addr_is_link_local(addr) || !_try_addr_reconfiguration(netif)) { /* Cannot use target address as personal address and can diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.h index 1736f69cc7d2..b5940232f4c0 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.h +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-slaac.h @@ -32,6 +32,72 @@ extern "C" { #endif +/** + * > An IPv6 address prefix used for stateless autoconfiguration [ACONF] + * of an Ethernet interface must have a length of 64 bits. + * - https://datatracker.ietf.org/doc/html/rfc2464 + * + * > An IPv6 address prefix used for stateless autoconfiguration [RFC4862] + * of an IEEE 802.15.4 interface MUST have a length of 64 bits. + * - https://datatracker.ietf.org/doc/html/rfc4944 + * + * Also see + * @ref INTERFACE_IDENTIFIER_LENGTH + * in combination with "sum" "does not equal 128 bits" + * from https://datatracker.ietf.org/doc/html/rfc4862#section-5.5.3 d) + */ +#define SLAAC_PREFIX_LENGTH (64U) + +/** + * "the address architecture [RFC4291] also defines the length of the interface identifiers" + * - https://datatracker.ietf.org/doc/html/rfc4862#section-2 + * + * "Interface IDs are required to be 64 bits long" + * - https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.1 + */ +#define INTERFACE_IDENTIFIER_LENGTH (64U) + +/** + * @name Temporary address parameters + * @see [RFC 8981, section 3.8](https://www.rfc-editor.org/rfc/rfc8981.html#section-3.8) + * @{ + */ +/** + * @brief Maximum valid lifetime [ms] of a temporary address + * @ref MAX_TEMP_ADDRESSES depends on this value + */ +#ifndef TEMP_VALID_LIFETIME +#define TEMP_VALID_LIFETIME MS_PER_HOUR * HOURS_PER_DAY * (2U) /*default value*/ +#endif + +/** + * @brief Maximum preferred lifetime [ms] of a temporary address + * + * @note "MUST be smaller than the TEMP_VALID_LIFETIME value" + * @ref MAX_TEMP_ADDRESSES depends on this value + */ +#ifndef TEMP_PREFERRED_LIFETIME +#define TEMP_PREFERRED_LIFETIME MS_PER_HOUR * HOURS_PER_DAY * (1U) /*default value*/ +#endif + +/** + * @brief Maximum time to randomly subtract from TEMP_PREFERRED_LIFETIME + * for a temporary address + * @ref MAX_TEMP_ADDRESSES depends on this value + */ +#define MAX_DESYNC_FACTOR (TEMP_PREFERRED_LIFETIME / 10 * 4) + +/** + * @brief Maximum number of retries for generating a temporary address + * in case a duplicate addresses was detected (DAD failure) + * + * @ref GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES must be able to store this number + */ +#ifndef TEMP_IDGEN_RETRIES +#define TEMP_IDGEN_RETRIES (3U) /*default value*/ +#endif +/** @} */ + #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_6LN) || IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC) || defined(DOXYGEN) /** * @brief Auto-configures an address from a given prefix @@ -46,6 +112,101 @@ void _auto_configure_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, #define _auto_configure_addr(netif, pfx, pfx_len) \ (void)netif; (void)pfx; (void)pfx_len; #endif /* CONFIG_GNRC_IPV6_NIB_6LN || CONFIG_GNRC_IPV6_NIB_SLAAC */ + +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) || defined(DOXYGEN) +/** + * @brief Create a temporary address for the given prefix. + * + * @param[in] netif The network interface on which to create the temporary address on. + * Untested behavior if not the same as for the prefix. + * @param[in] pfx The prefix which is to be used in the temporary address. + * The prefix length is assumed to be @ref SLAAC_PREFIX_LENGTH + * @param[in] pfx_pref_ltime Lifetime of the prefix for which an address shall be created. + * Needed to determine whether it is worth creating a temporary address. + * @param[in] retries Number of address generation retries + * that is to be stored in the address flags. + * @param[out] idx The index of the generated address. + * Optional, leave NULL if not needed. + * + * @return -1 on failure + * @return 0 on success + */ +int32_t _generate_temporary_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, + const uint32_t pfx_pref_ltime, + const uint8_t retries, + int *idx); + +/** + * @brief Regenerate a temporary address + * @param netif Network interface of the temporary address and the SLAAC prefix. + * @param addr Current temporary address (or any address in the SLAAC prefix for that matter) + * @param retries passed as-is to @ref _generate_temporary_addr + * @param caller_description Text detail for logging + * @return -1 on failure, 0 on success + */ +int _regen_temp_addr(gnrc_netif_t *netif, const ipv6_addr_t *addr, uint8_t retries, + const char *caller_description); + +/** + * @brief Check if the address is a temporary address. + * (Assuming the provided address is a configured address. + * This function only checks for prefix existence.) + */ +bool is_temporary_addr(const gnrc_netif_t *netif, const ipv6_addr_t *addr); + +/** + * @brief Check if an interface identifier of an IPv6 address + * is reserved by IANA, i.e. it shouldn't be used + * This is should be checked when the interface identifier is randomly generated. + * @see [RFC5453], https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml + * @param[in] iid The interface identifier to check for + * @return whether the IID is IANA reserved + */ +bool _iid_is_iana_reserved(const eui64_t *iid); + +/** + * @brief Generate a random interface identifier + * that is not IANA reserved (@ref _iid_is_iana_reserved) + * @param[out] iid The interface identifier to write to. + */ +void _ipv6_get_random_iid(eui64_t *iid); + +/** + * @brief Get the duration in seconds at which regeneration of a temporary address + * should be started before deprecation of the current one. + * @see https://www.rfc-editor.org/rfc/rfc8981.html#section-3.8-3.2 + * @param[in] netif The interface, as the value depends on this. + * @return REGEN_ADVANCE [seconds] + */ +uint32_t _get_netif_regen_advance(const gnrc_netif_t *netif); + +/** + * @brief For an address, get the corresponding SLAAC prefix's preferred lifetime + * @param[in] netif The network interface the prefix is configured on. + * @param[in] addr An IP address in the SLAAC prefix + * @param[out] slaac_prefix_pref_until pref_until time of the SLAAC prefix + * @return true if a corresponding prefix was found, otherwise false + */ +bool _get_slaac_prefix_pref_until(const gnrc_netif_t *netif, + const ipv6_addr_t *addr, + uint32_t *slaac_prefix_pref_until); + +/** + * @brief For a given SLAAC prefix, get the first-best temporary address prefix. + * @param[in] netif The interface on which to find the @p slaac_pfc on (0 for any) + * @param[in] slaac_pfx The SLAAC prefix to find a configured temporary address for. + * @param[in, out] state Internal iteration state for the prefix list. + * Can be optionally provided to not start checking all prefixes from the beginning. + * Otherwise NULL. + * @param[out] next_temp_addr The temporary address that was configured from the given @p slaac_pfx. + * @return true if a temporary address was found, false otherwise + */ +bool _iter_slaac_prefix_to_temp_addr(const gnrc_netif_t *netif, + const ipv6_addr_t *slaac_pfx, + void *state, + ipv6_addr_t *next_temp_addr); +#endif + #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC) || defined(DOXYGEN) /** * @brief Removes a tentative address from the interface and tries to diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c index ac7e3fcfa2e6..dfc740c1439f 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/nib.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib.c @@ -80,6 +80,9 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif_t *netif, gnrc_pktsnip_t *pkt, gnrc_ipv6_nib_nc_t *nce, _nib_onl_entry_t *entry); +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) || defined(DOXYGEN) +static void _handle_regen_temp_addr(_nib_offl_entry_t *pfx); +#endif 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); @@ -473,6 +476,11 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type) case GNRC_IPV6_NIB_PFX_TIMEOUT: _handle_pfx_timeout(ctx); break; +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + case GNRC_IPV6_NIB_REGEN_TEMP_ADDR: + _handle_regen_temp_addr(ctx); + break; +#endif case GNRC_IPV6_NIB_RTR_TIMEOUT: _handle_rtr_timeout(ctx); break; @@ -1444,6 +1452,18 @@ static void _handle_snd_na(gnrc_pktsnip_t *pkt) #endif /* MODULE_GNRC_IPV6 */ } +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +static void _handle_regen_temp_addr(_nib_offl_entry_t *pfx) { + DEBUG("nib: Temporary address regeneration event for temporary address prefix %s/%u\n", + ipv6_addr_to_str(addr_str, &pfx->pfx, sizeof(addr_str)), + pfx->pfx_len); + gnrc_netif_t *netif = gnrc_netif_get_by_pid(_nib_onl_get_if(pfx->next_hop)); + assert(netif != NULL); + + _regen_temp_addr(netif, &pfx->pfx, 0, ""); +} +#endif + static void _handle_pfx_timeout(_nib_offl_entry_t *pfx) { gnrc_netif_t *netif = gnrc_netif_get_by_pid(_nib_onl_get_if(pfx->next_hop)); @@ -1465,6 +1485,31 @@ static void _handle_pfx_timeout(_nib_offl_entry_t *pfx) netif->ipv6.addrs_flags[i] |= GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_DEPRECATED; } } +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + if (pfx->flags & _PFX_SLAAC) { + /* Remove regen event from temporary addresses (the current temporary address should have one scheduled). + * It would log a warning because pref_lft too short, + * or - if the SLAAC prefix became preferred again meanwhile - + * regenerate an address, + * but at whatever time the event is currently scheduled for. + * -> Definitely cleaner to not even call the event. */ + + /* Get ta_pfx (_nib_offl_entry_t), delete evtimer + * do not remove the temporary address (itself or through its prefix), + * but only the regen event, + * because the temporary address is deprecated but not invalidated/removed yet. + */ + + //alternative way to get ta_pfx: _iter_slaac_prefix_to_temp_addr + _nib_offl_get_match + _nib_offl_entry_t *ptr = (_nib_offl_entry_t *)NULL; + while ((ptr = _nib_offl_iter(ptr))) { + if (ptr->pfx_len == IPV6_ADDR_BIT_LEN + && ipv6_addr_match_prefix(&ptr->pfx, &pfx->pfx) >= SLAAC_PREFIX_LENGTH) { + _evtimer_del(&ptr->regen_temp_addr); + } + } + } +#endif _evtimer_add(pfx, GNRC_IPV6_NIB_PFX_TIMEOUT, &pfx->pfx_timeout, pfx->valid_until - now); } @@ -1657,8 +1702,20 @@ 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 (pio->flags & NDP_OPT_PI_FLAGS_A) { + if (pio->flags & NDP_OPT_PI_FLAGS_A + && pio->prefix_len == SLAAC_PREFIX_LENGTH +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + && (gnrc_netif_ipv6_addr_pfx_idx(netif, &pio->prefix, pio->prefix_len) < 0) + /* do not cause generation of another temporary address + * if the prefix is already known */ +#endif + ) { _auto_configure_addr(netif, &pio->prefix, pio->prefix_len); +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + if (_generate_temporary_addr(netif, &pio->prefix, pref_ltime, 0, NULL) < 0) { + LOG_WARNING("nib: Temporary address generation failed when handling PIO.\n"); + } +#endif } if ((pio->flags & (NDP_OPT_PI_FLAGS_A | NDP_OPT_PI_FLAGS_L)) || _multihop_p6c(netif, abr)) { diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c b/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c index 0ea9be0620e2..7dfbb6772a4a 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c @@ -25,6 +25,9 @@ #include "_nib-internal.h" #include "_nib-router.h" +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +#include "_nib-slaac.h" +#endif int gnrc_ipv6_nib_pl_set(unsigned iface, const ipv6_addr_t *pfx, unsigned pfx_len, @@ -120,6 +123,23 @@ void gnrc_ipv6_nib_pl_del(unsigned iface, _nib_release(); } +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +bool gnrc_ipv6_nib_pl_has_prefix(const unsigned int iface, const ipv6_addr_t *pfx, + const uint8_t pfx_len) +{ + void *state = NULL; + gnrc_ipv6_nib_pl_t ple; + + while (gnrc_ipv6_nib_pl_iter(iface, &state, &ple)) { + if (ple.pfx_len == pfx_len + && ipv6_addr_match_prefix(&ple.pfx, pfx) >= pfx_len) { + return true; + } + } + return false; +} +#endif + bool gnrc_ipv6_nib_pl_iter(unsigned iface, void **state, gnrc_ipv6_nib_pl_t *entry) { diff --git a/sys/shell/cmds/gnrc_netif.c b/sys/shell/cmds/gnrc_netif.c index c827939a1f7d..9b35ec20a78a 100644 --- a/sys/shell/cmds/gnrc_netif.c +++ b/sys/shell/cmds/gnrc_netif.c @@ -34,6 +34,9 @@ #include "net/loramac.h" #include "net/netif.h" #include "shell.h" +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) +#include "../../net/gnrc/network_layer/ipv6/nib/_nib-slaac.h" +#endif #ifdef MODULE_NETSTATS #include "net/netstats.h" @@ -581,7 +584,7 @@ static unsigned _netif_list_flag(netif_t *iface, netopt_t opt, char *str, } #ifdef MODULE_IPV6 -static void _netif_list_ipv6(ipv6_addr_t *addr, uint8_t flags) +static void _netif_list_ipv6(ipv6_addr_t *addr, uint8_t flags, netif_t *netif) { char addr_str[IPV6_ADDR_MAX_STR_LEN]; @@ -621,6 +624,14 @@ static void _netif_list_ipv6(ipv6_addr_t *addr, uint8_t flags) break; } } +#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_SLAAC_TEMPORARY_ADDRESSES) + const gnrc_netif_t *gnrc_netif = container_of(netif, gnrc_netif_t, netif); + if (is_temporary_addr(gnrc_netif, addr)) { + printf(" TMP"); + } +#else + (void)netif; +#endif #endif _newline(0U, _LINE_THRESHOLD); } @@ -916,7 +927,7 @@ static void _netif_list(netif_t *iface) sizeof(ipv6_addrs_flags)); /* yes, the res of NETOPT_IPV6_ADDR is meant to be here ;-) */ for (unsigned i = 0; i < (res / sizeof(ipv6_addr_t)); i++) { - _netif_list_ipv6(&ipv6_addrs[i], ipv6_addrs_flags[i]); + _netif_list_ipv6(&ipv6_addrs[i], ipv6_addrs_flags[i], iface); } } res = netif_get_opt(iface, NETOPT_IPV6_GROUP, 0, ipv6_groups, diff --git a/tests/net/gnrc_ipv6_nib/main.c b/tests/net/gnrc_ipv6_nib/main.c index 3233aa96c564..d18097ce7973 100644 --- a/tests/net/gnrc_ipv6_nib/main.c +++ b/tests/net/gnrc_ipv6_nib/main.c @@ -39,7 +39,7 @@ #define _RTR_LTIME (6612U) #define _REACH_TIME (1210388825UL) #define _RETRANS_TIMER (3691140UL) -#define _LOC_GB_PFX_LEN (45U) +#define _LOC_GB_PFX_LEN (64U) #define _REM_GB_PFX_LEN (37U) #define _PIO_PFX_LTIME (0x8476fedf) diff --git a/tests/net/gnrc_ipv6_nib_6ln/main.c b/tests/net/gnrc_ipv6_nib_6ln/main.c index 96aa995e055a..339339ac4d2e 100644 --- a/tests/net/gnrc_ipv6_nib_6ln/main.c +++ b/tests/net/gnrc_ipv6_nib_6ln/main.c @@ -43,7 +43,7 @@ #define _RTR_LTIME (6612U) #define _REACH_TIME (1210388825UL) #define _RETRANS_TIMER (3691140UL) -#define _LOC_GB_PFX_LEN (45U) +#define _LOC_GB_PFX_LEN (64U) #define _REM_GB_PFX_LEN (37U) #define _PIO_PFX_LTIME (0x8476fedf) #define _CTX_LTIME (29169U)