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 5d774118a4bb..b2dd4ed2353f 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c @@ -679,6 +679,38 @@ void _nib_pl_remove(_nib_offl_entry_t *nib_offl) #endif /* CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C */ } +void _nib_offl_remove_prefix(_nib_offl_entry_t *pfx) +{ + gnrc_netif_t *netif; + + /* remove prefix timer */ + evtimer_del(&_nib_evtimer, &pfx->pfx_timeout.event); + + /* get interface associated with prefix */ + netif = gnrc_netif_get_by_pid(_nib_onl_get_if(pfx->next_hop)); + + if (netif != NULL) { + uint8_t best_match_len = pfx->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; + best_match = &netif->ipv6.addrs[i]; + } + } + if (best_match != NULL) { + gnrc_netif_ipv6_addr_remove_internal(netif, + best_match); + } + } + + /* remove prefix */ + _nib_pl_remove(pfx); +} + #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C) _nib_abr_entry_t *_nib_abr_add(const ipv6_addr_t *addr) { 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 602bc3da92a5..11db47d3dfee 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h @@ -683,6 +683,16 @@ _nib_offl_entry_t *_nib_pl_add(unsigned iface, */ void _nib_pl_remove(_nib_offl_entry_t *nib_offl); +/** + * @brief Removes a prefix from the prefix list as well as the addresses + * associated with the prefix. + * + * @param[in,out] nib_offl An entry. + * + * Corresponding on-link entry is removed, too. + */ +void _nib_offl_remove_prefix(_nib_offl_entry_t *pfx); + #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_ROUTER) || DOXYGEN /** * @brief Creates or gets an existing forwarding table entry by its prefix diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c index f1fa76cc6c22..2b6e57629de2 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c @@ -269,6 +269,24 @@ void _set_rtr_adv(gnrc_netif_t *netif) _handle_snd_mc_ra(netif); } +void _snd_rtr_advs_drop_pfx(gnrc_netif_t *netif, const ipv6_addr_t *dst, + _nib_offl_entry_t *pfx) +{ + gnrc_pktsnip_t *ext_opts = NULL; + uint32_t now = evtimer_now_msec(); + + DEBUG("nib: broadcasting removal of %s/%u from %u\n", + ipv6_addr_to_str(addr_str, &pfx->pfx, sizeof(addr_str)), + pfx->pfx_len, netif->pid + ); + + pfx->pref_until = now + 10; /* add some safety margin */ + pfx->valid_until = now + 10; /* will be rounded to sec */ + + ext_opts = _offl_to_pio(pfx, ext_opts); + gnrc_ndp_rtr_adv_send(netif, NULL, dst, false, ext_opts); +} + static void _snd_ra(gnrc_netif_t *netif, const ipv6_addr_t *dst, bool final, _nib_abr_entry_t *abr) { diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.h index 1798ee5c40a7..ba1b484fba1d 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.h +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.h @@ -118,6 +118,16 @@ void _set_rtr_adv(gnrc_netif_t *netif); */ void _snd_rtr_advs(gnrc_netif_t *netif, const ipv6_addr_t *dst, bool final); +/** + * @brief Send router advertisements to remove a prefix + * + * @param[in] netif The interface to send the router advertisement over. + * @param[in] dst Destination address for the router advertisement. + * @param[in] pfx Off-link entry of the prefix that should be removed. + * + */ +void _snd_rtr_advs_drop_pfx(gnrc_netif_t *netif, const ipv6_addr_t *dst, + _nib_offl_entry_t *pfx); #else /* CONFIG_GNRC_IPV6_NIB_ROUTER */ #define _init_iface_router(netif) (void)netif #define _call_route_info_cb(netif, type, ctx_addr, ctx) (void)netif; \ @@ -130,6 +140,9 @@ void _snd_rtr_advs(gnrc_netif_t *netif, const ipv6_addr_t *dst, #define _snd_rtr_advs(netif, dst, final) (void)netif; \ (void)dst; \ (void)final +#define _snd_rtr_advs_drop_pfx(netif, dst, pfx) (void)netif; \ + (void)dst; \ + (void)pfx; #endif /* CONFIG_GNRC_IPV6_NIB_ROUTER */ #ifdef __cplusplus diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c index d5ca625d03cd..438f14085bce 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/nib.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib.c @@ -1331,16 +1331,7 @@ static void _handle_pfx_timeout(_nib_offl_entry_t *pfx) gnrc_netif_acquire(netif); if (now >= pfx->valid_until) { - evtimer_del(&_nib_evtimer, &pfx->pfx_timeout.event); - for (int i = 0; i < CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { - if (ipv6_addr_match_prefix(&netif->ipv6.addrs[i], - &pfx->pfx) >= pfx->pfx_len) { - gnrc_netif_ipv6_addr_remove_internal(netif, - &netif->ipv6.addrs[i]); - } - } - pfx->mode &= ~_PL; - _nib_offl_clear(pfx); + _nib_offl_remove_prefix(pfx); } else if (now >= pfx->pref_until) { for (int i = 0; i < CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { @@ -1495,10 +1486,9 @@ static void _remove_prefix(const ipv6_addr_t *pfx, unsigned pfx_len) if ((offl->mode & _PL) && (offl->pfx_len == pfx_len) && (ipv6_addr_match_prefix(&offl->pfx, pfx) >= pfx_len)) { - _nib_pl_remove(offl); + _nib_offl_remove_prefix(offl); } } - return; } #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C) 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 054c90ead175..720ee6a976c0 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c @@ -104,17 +104,18 @@ void gnrc_ipv6_nib_pl_del(unsigned iface, if ((pfx_len == dst->pfx_len) && ((iface == 0) || (iface == _nib_onl_get_if(dst->next_hop))) && (ipv6_addr_match_prefix(pfx, &dst->pfx) >= pfx_len)) { - _nib_pl_remove(dst); - _nib_release(); + + /* notify downstream nodes about the prefix removal */ #if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_ROUTER) gnrc_netif_t *netif = gnrc_netif_get_by_pid(iface); - if (netif) { - /* update prefixes down-stream */ - _handle_snd_mc_ra(netif); + if (netif && (netif->flags & GNRC_NETIF_FLAGS_IPV6_RTR_ADV)) { + _snd_rtr_advs_drop_pfx(netif, &ipv6_addr_all_nodes_link_local, dst); } #endif - return; + /* remove the prefix & associated address*/ + _nib_offl_remove_prefix(dst); + break; } } _nib_release();