From 40912d3d663c7c755ffdaa8d8efbe65c2dd7e2f2 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sun, 30 Aug 2015 18:51:50 +0200 Subject: [PATCH] gnrc: adapt for gnrc_sixlowpan_nd_router --- sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c | 11 +++ .../ipv6/netif/gnrc_ipv6_netif.c | 16 +++- sys/net/gnrc/network_layer/ndp/gnrc_ndp.c | 89 ++++++++++++++++++- .../ndp/internal/gnrc_ndp_internal.c | 49 ++++++++++ .../ndp/router/gnrc_ndp_router.c | 1 + 5 files changed, 160 insertions(+), 6 deletions(-) diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index 19edf024ff..ddfce4be36 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -244,6 +244,17 @@ static void *_event_loop(void *args) gnrc_sixlowpan_ctx_remove(((((gnrc_sixlowpan_ctx_t *)msg.content.ptr)->flags_id) & GNRC_SIXLOWPAN_CTX_FLAGS_CID_MASK)); break; +#endif +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + case GNRC_SIXLOWPAN_ND_MSG_ABR_TIMEOUT: + DEBUG("ipv6: border router timeout event received\n"); + gnrc_sixlowpan_nd_router_abr_remove( + (gnrc_sixlowpan_nd_router_abr_t *)msg.content.ptr); + break; + case GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT: + DEBUG("ipv6: address registration timeout received\n"); + gnrc_sixlowpan_nd_router_gc_nc((gnrc_ipv6_nc_t *)msg.content.ptr); + break; #endif default: break; diff --git a/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c b/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c index cc7d7fb9f5..cc8b967f06 100644 --- a/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c +++ b/sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c @@ -116,7 +116,7 @@ static ipv6_addr_t *_add_addr_to_entry(gnrc_ipv6_netif_t *entry, const ipv6_addr else { tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK; } -#if defined(MODULE_GNRC_NDP_NODE) || defined(MODULE_GNRC_SIXLOWPAN_ND) +#if defined(MODULE_GNRC_NDP_NODE) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER) /* add solicited-nodes multicast address for new address if interface is not a * 6LoWPAN host interface (see: https://tools.ietf.org/html/rfc6775#section-5.2) */ if (!(entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) || @@ -235,14 +235,26 @@ gnrc_ipv6_netif_t *gnrc_ipv6_netif_get(kernel_pid_t pid) return NULL; } -#if defined(MODULE_GNRC_NDP_ROUTER) +#if defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER) void gnrc_ipv6_netif_set_router(gnrc_ipv6_netif_t *netif, bool enable) { +#if defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER) + if (netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { + gnrc_sixlowpan_nd_router_set_router(netif, enable); + return; + } +#endif gnrc_ndp_router_set_router(netif, enable); } void gnrc_ipv6_netif_set_rtr_adv(gnrc_ipv6_netif_t *netif, bool enable) { +#if defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER) + if (netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { + gnrc_sixlowpan_nd_router_set_rtr_adv(netif, enable); + return; + } +#endif gnrc_ndp_router_set_rtr_adv(netif, enable); } #endif diff --git a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c index 4b246e9cae..598329b61a 100644 --- a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c +++ b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c @@ -20,6 +20,7 @@ #include "byteorder.h" #include "net/fib.h" +#include "net/ieee802154.h" #include "net/ipv6/ext/rh.h" #include "net/gnrc/icmpv6.h" #include "net/gnrc/ipv6.h" @@ -53,6 +54,19 @@ static void _stale_nc(kernel_pid_t iface, ipv6_addr_t *ipaddr, uint8_t *l2addr, if (l2addr_len != -ENOTSUP) { gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, ipaddr); if (nc_entry == NULL) { +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + /* tentative type see https://tools.ietf.org/html/rfc6775#section-6.3 */ + gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface); + if ((ipv6_iface == NULL) || (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { + timex_t t = { GNRC_SIXLOWPAN_ND_TENTATIVE_NCE_LIFETIME, 0 }; + gnrc_ipv6_nc_add(iface, ipaddr, l2addr, (uint16_t)l2addr_len, + GNRC_IPV6_NC_STATE_STALE | GNRC_IPV6_NC_TYPE_TENTATIVE); + vtimer_remove(&nc_entry->type_timeout); + vtimer_set_msg(&nc_entry->type_timeout, t, gnrc_ipv6_pid, + GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT, nc_entry); + return; + } +#endif gnrc_ipv6_nc_add(iface, ipaddr, l2addr, (uint16_t)l2addr_len, GNRC_IPV6_NC_STATE_STALE); } @@ -73,7 +87,12 @@ void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint16_t opt_offset = 0; uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX]; uint8_t *buf = ((uint8_t *)nbr_sol) + sizeof(ndp_nbr_sol_t); - ipv6_addr_t *tgt; + ipv6_addr_t *tgt, nbr_adv_dst; + gnrc_pktsnip_t *nbr_adv_opts = NULL; +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + ndp_opt_t *sl2a_opt = NULL; + sixlowpan_nd_opt_ar_t *ar_opt = NULL; +#endif int sicmpv6_size = (int)icmpv6_size, l2src_len = 0; DEBUG("ndp: received neighbor solicitation (src: %s, ", ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str))); @@ -111,6 +130,13 @@ void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, * is invalid. */ return; } +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + sl2a_opt = opt; + break; + case NDP_OPT_AR: + /* actually handling at the end of the function (see below) */ + ar_opt = (sixlowpan_nd_opt_ar_t *)opt; +#endif break; default: /* silently discard all other options */ @@ -119,9 +145,38 @@ void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); } +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface); + assert(ipv6_iface != NULL); + if ((sl2a_opt != NULL) && (ar_opt != NULL) && + (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && + (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { + uint8_t status = gnrc_sixlowpan_nd_opt_ar_handle(iface, ipv6, nbr_sol->type, ar_opt, + l2src, l2src_len); + /* check for multihop DAD return */ + nbr_adv_opts = gnrc_sixlowpan_nd_opt_ar_build(status, GNRC_SIXLOWPAN_ND_AR_LTIME, + &ar_opt->eui64, NULL); + if (status == 0) { + memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t)); + } + else { + /* see https://tools.ietf.org/html/rfc6775#section-6.5.2 */ + eui64_t iid; + ieee802154_get_iid(&iid, ar_opt->eui64.uint8, sizeof(eui64_t)); + ipv6_addr_set_iid(&nbr_adv_dst, iid.uint64.u64); + ipv6_addr_set_link_local_prefix(&nbr_adv_dst); + } + } + else { /* gnrc_sixlowpan_nd_opt_ar_handle updates neighbor cache */ + _stale_nc(iface, &ipv6->src, l2src, l2src_len); + memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t)); + } +#else _stale_nc(iface, &ipv6->src, l2src, l2src_len); - gnrc_ndp_internal_send_nbr_adv(iface, tgt, &ipv6->src, ipv6_addr_is_multicast(&ipv6->dst), - NULL); + memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t)); +#endif + gnrc_ndp_internal_send_nbr_adv(iface, tgt, &nbr_adv_dst, ipv6_addr_is_multicast(&ipv6->dst), + nbr_adv_opts); } static inline bool _pkt_has_l2addr(gnrc_netif_hdr_t *netif_hdr) @@ -332,7 +387,14 @@ void gnrc_ndp_rtr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, _stale_nc(iface, &ipv6->src, l2src, l2src_len); /* send delayed */ if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) { - timex_t delay = timex_set(0, genrand_uint32_range(0, GNRC_NDP_MAX_RTR_ADV_DELAY)); + timex_t delay; + uint32_t ms = GNRC_NDP_MAX_RTR_ADV_DELAY; +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { + ms = GNRC_SIXLOWPAN_ND_MAX_RTR_ADV_DELAY; + } +#endif + delay = timex_set(0, genrand_uint32_range(0, ms)); vtimer_remove(&if_entry->rtr_adv_timer); if (ipv6_addr_is_unspecified(&ipv6->src)) { /* either multicast, if source unspecified */ @@ -477,8 +539,15 @@ void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t } break; +#endif +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + case NDP_OPT_ABR: + gnrc_sixlowpan_nd_opt_abr_handle(iface, rtr_adv, icmpv6_size, + (sixlowpan_nd_opt_abr_t *)opt); + break; #endif } + sicmpv6_size -= (opt->len * 8); } #if ENABLE_DEBUG && defined(MODULE_NG_SIXLOWPAN_ND) if ((if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (l2src_len <= 0)) { @@ -552,6 +621,18 @@ void gnrc_ndp_retrans_nbr_sol(gnrc_ipv6_nc_t *nc_entry) } } else if (nc_entry->probes_remaining <= 1) { +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + if (nc_entry->iface != KERNEL_PID_UNDEF) { + gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(nc_entry->iface); + if ((ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && + (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) && + (gnrc_ipv6_nc_get_type(nc_entry) != GNRC_IPV6_NC_TYPE_GC)) { + /* don't remove non-gc entrys on 6LRs: + * https://tools.ietf.org/html/rfc6775#section-6 */ + return; + } + } +#endif DEBUG("ndp: Remove nc entry %s for interface %" PRIkernel_pid "\n", ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)), nc_entry->iface); diff --git a/sys/net/gnrc/network_layer/ndp/internal/gnrc_ndp_internal.c b/sys/net/gnrc/network_layer/ndp/internal/gnrc_ndp_internal.c index 32016c4387..7a49fddf20 100644 --- a/sys/net/gnrc/network_layer/ndp/internal/gnrc_ndp_internal.c +++ b/sys/net/gnrc/network_layer/ndp/internal/gnrc_ndp_internal.c @@ -17,6 +17,7 @@ #include "net/eui64.h" #include "net/gnrc/ipv6.h" #include "net/gnrc/ndp.h" +#include "net/gnrc/sixlowpan/ctx.h" #include "net/gnrc/sixlowpan/nd.h" #include "random.h" #include "timex.h" @@ -395,6 +396,9 @@ void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src, ipv6_a DEBUG("ndp internal: send router advertisement (iface: %" PRIkernel_pid ", dst: %s%s\n", iface, ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), fin ? ", final" : ""); mutex_lock(&ipv6_iface->mutex); +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { +#endif hdr = _add_pios(ipv6_iface, pkt); if (hdr == NULL) { /* pkt already released in _add_pios */ @@ -402,6 +406,51 @@ void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src, ipv6_a return; } pkt = hdr; +#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER + } + else { + gnrc_sixlowpan_nd_router_abr_t *abr = gnrc_sixlowpan_nd_router_abr_get(); + if (abr != NULL) { + gnrc_sixlowpan_nd_router_prf_t *prf = abr->prfs; + /* add prefixes from border router */ + while (prf) { + if (_pio_from_iface_addr(&hdr, prf->prefix, pkt)) { + if (hdr != NULL) { + pkt = hdr; + } + else { + DEBUG("ndp rtr: error allocating PIO\n"); + gnrc_pktbuf_release(pkt); + return; + } + } + prf = prf->next; + } + for (unsigned int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) { + gnrc_sixlowpan_ctx_t *ctx; + if (!bf_isset(abr->ctxs, i)) { + continue; + } + ctx = gnrc_sixlowpan_ctx_lookup_id(i); + hdr = gnrc_sixlowpan_nd_opt_6ctx_build(ctx->prefix_len, ctx->flags_id, ctx->ltime, + &ctx->prefix, pkt); + if (hdr == NULL) { + DEBUG("ndp rtr: error allocating 6CO\n"); + gnrc_pktbuf_release(pkt); + return; + } + pkt = hdr; + } + hdr = gnrc_sixlowpan_nd_opt_abr_build(abr->version, abr->ltime, &abr->addr, pkt); + if (hdr == NULL) { + DEBUG("ndp internal: error allocating ABRO.\n"); + gnrc_pktbuf_release(pkt); + return; + } + pkt = hdr; + } + } +#endif /* MODULE_GNRC_SIXLOWPAN_ND_ROUTER */ if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_MTU) { if ((hdr = gnrc_ndp_opt_mtu_build(ipv6_iface->mtu, pkt)) == NULL) { DEBUG("ndp rtr: no space left in packet buffer\n"); diff --git a/sys/net/gnrc/network_layer/ndp/router/gnrc_ndp_router.c b/sys/net/gnrc/network_layer/ndp/router/gnrc_ndp_router.c index ac51e3d48e..ab01e8b8ae 100644 --- a/sys/net/gnrc/network_layer/ndp/router/gnrc_ndp_router.c +++ b/sys/net/gnrc/network_layer/ndp/router/gnrc_ndp_router.c @@ -79,6 +79,7 @@ void gnrc_ndp_router_retrans_rtr_adv(gnrc_ipv6_netif_t *iface) void gnrc_ndp_router_send_rtr_adv(gnrc_ipv6_nc_t *neighbor) { gnrc_ipv6_netif_t *iface = gnrc_ipv6_netif_get(neighbor->iface); + /* TODO: send one router advertisement per ABR: https://tools.ietf.org/html/rfc6775#section-6.3 */ _send_rtr_adv(iface, &neighbor->ipv6_addr); }