From b033ff590b13a5cb8c57e5c60507cbc3175044bf Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 31 Aug 2015 14:25:17 +0200 Subject: [PATCH 1/2] gnrc_ndp_host: initial import --- Makefile.dep | 20 +- sys/include/net/gnrc/ipv6/netif.h | 12 + sys/include/net/gnrc/ndp.h | 66 +++++- sys/include/net/gnrc/ndp/host.h | 54 +++++ sys/include/net/gnrc/ndp/internal.h | 41 ++++ sys/net/gnrc/Makefile | 3 + sys/net/gnrc/network_layer/ndp/gnrc_ndp.c | 124 ++++++++++- sys/net/gnrc/network_layer/ndp/host/Makefile | 3 + .../network_layer/ndp/host/gnrc_ndp_host.c | 56 +++++ .../ndp/internal/gnrc_ndp_internal.c | 206 +++++++++++++----- 10 files changed, 514 insertions(+), 71 deletions(-) create mode 100644 sys/include/net/gnrc/ndp/host.h create mode 100644 sys/net/gnrc/network_layer/ndp/host/Makefile create mode 100644 sys/net/gnrc/network_layer/ndp/host/gnrc_ndp_host.c diff --git a/Makefile.dep b/Makefile.dep index 3a83561f17..0f1bdb16cb 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -80,19 +80,29 @@ endif ifneq (,$(filter gnrc_ipv6_default,$(USEMODULE))) USEMODULE += gnrc_ipv6 USEMODULE += gnrc_icmpv6 - USEMODULE += gnrc_ndp - USEMODULE += gnrc_ndp_internal - USEMODULE += gnrc_ndp_node + USEMODULE += gnrc_ndp_host endif ifneq (,$(filter gnrc_ipv6_router_default,$(USEMODULE))) USEMODULE += gnrc_ipv6_router USEMODULE += gnrc_icmpv6 - USEMODULE += gnrc_ndp - USEMODULE += gnrc_ndp_internal USEMODULE += gnrc_ndp_node endif +ifneq (,$(filter gnrc_ndp_host,$(USEMODULE))) + USEMODULE += gnrc_ndp_node + USEMODULE += random + USEMODULE += vtimer +endif + +ifneq (,$(filter gnrc_ndp_node,$(USEMODULE))) + USEMODULE += gnrc_ndp_internal +endif + +ifneq (,$(filter gnrc_ndp_%,$(USEMODULE))) + USEMODULE += gnrc_ndp +endif + ifneq (,$(filter gnrc_ndp,$(USEMODULE))) USEMODULE += gnrc_icmpv6 USEMODULE += random diff --git a/sys/include/net/gnrc/ipv6/netif.h b/sys/include/net/gnrc/ipv6/netif.h index 8e6c0310ec..ac0e796b51 100644 --- a/sys/include/net/gnrc/ipv6/netif.h +++ b/sys/include/net/gnrc/ipv6/netif.h @@ -194,6 +194,18 @@ extern "C" { */ #define GNRC_IPV6_NETIF_FLAGS_IS_WIRED (0x0080) +/** + * @brief Offset of the router advertisement flags compared to the position in router + * advertisements. + */ +#define GNRC_IPV6_NETIF_FLAGS_RTR_ADV_POS (8U) + +/** + * @brief Mask for flags intended for router advertisements. + * @note Please expand if more router advertisement flags are introduced. + */ +#define GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK (0xc000) + /** * @brief Flag to indicate that the interface has other address * configuration. diff --git a/sys/include/net/gnrc/ndp.h b/sys/include/net/gnrc/ndp.h index bfea5be09e..87fbd39bc2 100644 --- a/sys/include/net/gnrc/ndp.h +++ b/sys/include/net/gnrc/ndp.h @@ -22,6 +22,7 @@ #define GNRC_NDP_H_ #include +#include #include "byteorder.h" #include "net/ndp.h" @@ -31,21 +32,49 @@ #include "net/gnrc/ipv6/nc.h" #include "net/gnrc/ipv6/netif.h" +#include "net/gnrc/ndp/host.h" +#include "net/gnrc/ndp/internal.h" #include "net/gnrc/ndp/node.h" #ifdef __cplusplus extern "C" { #endif -#define GNRC_NDP_MSG_RTR_TIMEOUT (0x0211) /**< Message type for router timeouts */ -#define GNRC_NDP_MSG_ADDR_TIMEOUT (0x0212) /**< Message type for address timeouts */ -#define GNRC_NDP_MSG_NBR_SOL_RETRANS (0x0213) /**< Message type for multicast +#define GNRC_NDP_MSG_RTR_TIMEOUT (0x0210) /**< Message type for router timeouts */ +#define GNRC_NDP_MSG_ADDR_TIMEOUT (0x0211) /**< Message type for address timeouts */ +#define GNRC_NDP_MSG_NBR_SOL_RETRANS (0x0212) /**< Message type for multicast * neighbor solicitation retransmissions */ -#define GNRC_NDP_MSG_NC_STATE_TIMEOUT (0x0214) /**< Message type for neighbor cache state timeouts */ +#define GNRC_NDP_MSG_RTR_SOL_RETRANS (0x0215) /**< Message type for periodic router solicitations */ +#define GNRC_NDP_MSG_NC_STATE_TIMEOUT (0x0216) /**< Message type for neighbor cache state timeouts */ /** + * @name Host constants * @{ + * @see + * RFC 4861, section 10 + * + */ +/** + * @brief Upper bound for randomised delay in seconds for initial + * router solicitation transmissions + */ +#define GNRC_NDP_MAX_RTR_SOL_DELAY (1U) + +/** + * @brief Interval in seconds between initial router solicitation + * transmissions + */ +#define GNRC_NDP_MAX_RTR_SOL_INT (4U) + +/** + * @brief Maximum number of initial router solicitation transmissions + */ +#define GNRC_NDP_MAX_RTR_SOL_NUMOF (3U) +/** @} */ + +/** * @name Node constants + * @{ * @see * RFC 4861, section 10 * @@ -132,6 +161,21 @@ void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, ndp_nbr_adv_t *nbr_adv, size_t icmpv6_size); +/** + * @brief Handles received router advertisements + * + * @todo As router check consistency as described in RFC 4861, section 6.2.3 + * + * @param[in] iface The receiving interface. + * @param[in] pkt The received packet. + * @param[in] ipv6 The IPv6 header in @p pkt. + * @param[in] rtr_adv The router advertisement in @p pkt. + * @param[in] icmpv6_size The overall size of the router advertisement. + */ +void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, + ipv6_hdr_t *ipv6, ndp_rtr_adv_t *rtr_adv, + size_t icmpv6_size); + /** * @brief Retransmits a multicast neighbor solicitation for an incomplete or * probing neighbor cache entry @p nc_entry, @@ -233,6 +277,20 @@ gnrc_pktsnip_t *gnrc_ndp_nbr_sol_build(ipv6_addr_t *tgt, gnrc_pktsnip_t *options gnrc_pktsnip_t *gnrc_ndp_nbr_adv_build(uint8_t flags, ipv6_addr_t *tgt, gnrc_pktsnip_t *options); +/** + * @brief Builds a router solicitation message for sending. + * + * @see + * RFC 4861, section 4.1 + * + * + * @param[in] options Options to append to the router solicitation. + * + * @return The resulting ICMPv6 packet on success. + * @return NULL, on failure. + */ +gnrc_pktsnip_t *gnrc_ndp_rtr_sol_build(gnrc_pktsnip_t *options); + /** * @brief Builds a generic NDP option. * diff --git a/sys/include/net/gnrc/ndp/host.h b/sys/include/net/gnrc/ndp/host.h new file mode 100644 index 0000000000..0fc2edf8e9 --- /dev/null +++ b/sys/include/net/gnrc/ndp/host.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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. + */ + +/** + * @defgroup net_gnrc_ndp_host Host-specific part of router discovery. + * @ingroup net_gnrc_ndp + * @brief Host-specific part for the router discovery in IPv6 + * neighbor discovery. + * @{ + * + * @file + * @brief Host-specific router discovery definitions + * + * @author Martine Lenders + */ +#ifndef GNRC_NDP_HOST_H_ +#define GNRC_NDP_HOST_H_ + +#include "net/gnrc/ipv6/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initializes interface @p iface as host. + * + * @pre iface != NULL + * + * @param[in] iface An IPv6 interface + */ +void gnrc_ndp_host_init(gnrc_ipv6_netif_t *iface); + +/** + * @brief Sends a router solicitation over interface @p iface + * and reset the timer for the next one. + * + * @pre iface != NULL + * + * @param[in] iface An IPv6 interface + */ +void gnrc_ndp_host_retrans_rtr_sol(gnrc_ipv6_netif_t *iface); + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_NDP_HOST_H_ */ +/** @} */ diff --git a/sys/include/net/gnrc/ndp/internal.h b/sys/include/net/gnrc/ndp/internal.h index 52b42dd00b..6765fcea89 100644 --- a/sys/include/net/gnrc/ndp/internal.h +++ b/sys/include/net/gnrc/ndp/internal.h @@ -22,6 +22,7 @@ #ifndef GNRC_NDP_INTERNAL_H_ #define GNRC_NDP_INTERNAL_H_ +#include "kernel_types.h" #include "net/ipv6/addr.h" #include "net/ipv6/hdr.h" #include "net/ndp.h" @@ -88,6 +89,16 @@ void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt, void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_addr_t *dst, bool supply_tl2a, gnrc_pktsnip_t *ext_opts); +/** + * @brief Send precompiled router solicitation to @p dst. + * + * @internal + * + * @param[in] iface Interface to send over. May not be KERNEL_PID_UNDEF. + * @param[in] dst Destination for the router solicitation. ff02::2 if NULL. + */ +void gnrc_ndp_internal_send_rtr_sol(kernel_pid_t iface, ipv6_addr_t *dst); + /** * @brief Handles a SL2A option. * @@ -121,6 +132,36 @@ int gnrc_ndp_internal_tl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, uint8_t icmpv6_type, ndp_opt_t *tl2a_opt, uint8_t *l2addr); +/** + * @brief Handles a MTU option. + * + * @internal + * + * @param[in] iface Interface the MTU option was received on. + * @param[in] icmpv6_type ICMPv6 type of the message carrying the option. + * @param[in] mtu_opt A MTU option. + * + * @return true, on success (or if the node should silently ignore the option). + * @return false, if MTU option was not valid. + */ +bool gnrc_ndp_internal_mtu_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type, + ndp_opt_mtu_t *mtu_opt); + +/** + * @brief Handles a PI option. + * + * @internal + * + * @param[in] iface Interface the PI option was received on. + * @param[in] icmpv6_type ICMPv6 type of the message carrying the option. + * @param[in] pi_opt A PI option. + * + * @return true, on success (or if the node should silently ignore the option). + * @return false, if PIO was not valid. + */ +bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type, + ndp_opt_pi_t *pi_opt); + #ifdef __cplusplus } #endif diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile index 90d84c340b..bee9e79773 100644 --- a/sys/net/gnrc/Makefile +++ b/sys/net/gnrc/Makefile @@ -25,6 +25,9 @@ endif ifneq (,$(filter gnrc_ndp_internal,$(USEMODULE))) DIRS += network_layer/ndp/internal endif +ifneq (,$(filter gnrc_ndp_host,$(USEMODULE))) + DIRS += network_layer/ndp/host +endif ifneq (,$(filter gnrc_ndp_node,$(USEMODULE))) DIRS += network_layer/ndp/node endif diff --git a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c index e79cd12a7b..1d7fa505e8 100644 --- a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c +++ b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c @@ -275,6 +275,111 @@ void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, return; } +static inline void _set_reach_time(gnrc_ipv6_netif_t *if_entry, uint32_t mean) +{ + uint32_t reach_time = genrand_uint32_range(GNRC_NDP_MIN_RAND, GNRC_NDP_MAX_RAND); + + if_entry->reach_time_base = mean; + /* to avoid floating point number computation and have higher value entropy, the + * boundaries for the random value are multiplied by 10 and we need to account for that */ + reach_time = (reach_time * if_entry->reach_time_base) / 10; + if_entry->reach_time = timex_set(0, reach_time); + timex_normalize(&if_entry->reach_time); +} + +void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, + ndp_rtr_adv_t *rtr_adv, size_t icmpv6_size) +{ + uint8_t *buf = (uint8_t *)(rtr_adv + 1); + gnrc_ipv6_nc_t *nc_entry = NULL; + gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface); + uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX]; + int sicmpv6_size = (int)icmpv6_size, l2src_len = 0; + uint16_t opt_offset = 0; + + assert(if_entry != NULL); + if (!ipv6_addr_is_link_local(&ipv6->src) || + ipv6_addr_is_multicast(&ipv6->src) || + (ipv6->hl != 255) || (rtr_adv->code != 0) || + (icmpv6_size < sizeof(ndp_rtr_adv_t))) { + DEBUG("ndp: router advertisement was invalid\n"); + /* ipv6 releases */ + return; + } + /* get source from default router list */ + nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src); + if (nc_entry == NULL) { /* not in default router list */ + /* create default router list entry */ + nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, NULL, 0, + GNRC_IPV6_NC_IS_ROUTER); + if (nc_entry == NULL) { + DEBUG("ndp: error on default router list entry creation\n"); + return; + } + } + else if ((nc_entry->flags & GNRC_IPV6_NC_IS_ROUTER) && (byteorder_ntohs(rtr_adv->ltime) == 0)) { + nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER; + } + else { + nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER; + } + /* set router life timer */ + if (rtr_adv->ltime.u16 != 0) { + vtimer_remove(&nc_entry->rtr_timeout); + vtimer_set_msg(&nc_entry->rtr_timeout, + timex_set(byteorder_ntohs(rtr_adv->ltime), 0), + thread_getpid(), GNRC_NDP_MSG_RTR_TIMEOUT, nc_entry); + } + /* set current hop limit from message if available */ + if (rtr_adv->cur_hl != 0) { + if_entry->cur_hl = rtr_adv->cur_hl; + } + /* set flags from message */ + if_entry->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK; + if_entry->flags |= (rtr_adv->flags << GNRC_IPV6_NETIF_FLAGS_RTR_ADV_POS) & + GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK; + /* set reachable time from message if it is not the same as the random base + * value */ + if ((rtr_adv->reach_time.u32 != 0) && + (if_entry->reach_time_base != byteorder_ntohl(rtr_adv->reach_time))) { + _set_reach_time(if_entry, byteorder_ntohl(rtr_adv->reach_time)); + } + /* set retransmission timer from message */ + if (rtr_adv->retrans_timer.u32 != 0) { + if_entry->retrans_timer = timex_set(0, byteorder_ntohl(rtr_adv->retrans_timer)); + timex_normalize(&if_entry->retrans_timer); + } + mutex_unlock(&if_entry->mutex); + sicmpv6_size -= sizeof(ndp_rtr_adv_t); + /* parse options */ + while (sicmpv6_size > 0) { + ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset); + switch (opt->type) { + case NDP_OPT_SL2A: + if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_adv->type, opt, + l2src)) < 0) { + /* -ENOTSUP can not happen */ + /* invalid source link-layer address option */ + return; + } + break; + case NDP_OPT_MTU: + if (!gnrc_ndp_internal_mtu_opt_handle(iface, rtr_adv->type, (ndp_opt_mtu_t *)opt)) { + /* invalid MTU option */ + return; + } + break; + case NDP_OPT_PI: + if (!gnrc_ndp_internal_pi_opt_handle(iface, rtr_adv->type, (ndp_opt_pi_t *)opt)) { + /* invalid prefix information option */ + return; + } + break; + } + } + _stale_nc(iface, &ipv6->src, l2src, l2src_len); +} + void gnrc_ndp_retrans_nbr_sol(gnrc_ipv6_nc_t *nc_entry) { if ((gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) || @@ -350,14 +455,9 @@ void gnrc_ndp_state_timeout(gnrc_ipv6_nc_t *nc_entry) void gnrc_ndp_netif_add(gnrc_ipv6_netif_t *iface) { - uint32_t reach_time = genrand_uint32_range(GNRC_NDP_MIN_RAND, GNRC_NDP_MAX_RAND); - /* set default values */ mutex_lock(&iface->mutex); - iface->reach_time_base = GNRC_NDP_REACH_TIME; - reach_time = (reach_time * iface->reach_time_base) / 10; - iface->reach_time = timex_set(0, reach_time); - timex_normalize(&iface->reach_time); + _set_reach_time(iface, GNRC_NDP_REACH_TIME); iface->retrans_timer = timex_set(0, GNRC_NDP_RETRANS_TIMER); timex_normalize(&iface->retrans_timer); mutex_unlock(&iface->mutex); @@ -417,6 +517,18 @@ gnrc_pktsnip_t *gnrc_ndp_nbr_adv_build(uint8_t flags, ipv6_addr_t *tgt, return pkt; } +gnrc_pktsnip_t *gnrc_ndp_rtr_sol_build(gnrc_pktsnip_t *options) +{ + gnrc_pktsnip_t *pkt; + DEBUG("ndp: building router solicitation message\n"); + pkt = gnrc_icmpv6_build(options, ICMPV6_RTR_SOL, 0, sizeof(ndp_rtr_sol_t)); + if (pkt != NULL) { + ndp_rtr_sol_t *rtr_sol = pkt->data; + rtr_sol->resv.u32 = 0; + } + return pkt; +} + static inline size_t _ceil8(uint8_t length) { /* NDP options use units of 8 byte for there length field, so round up */ diff --git a/sys/net/gnrc/network_layer/ndp/host/Makefile b/sys/net/gnrc/network_layer/ndp/host/Makefile new file mode 100644 index 0000000000..c3b51fb8da --- /dev/null +++ b/sys/net/gnrc/network_layer/ndp/host/Makefile @@ -0,0 +1,3 @@ +MODULE = gnrc_ndp_host + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/network_layer/ndp/host/gnrc_ndp_host.c b/sys/net/gnrc/network_layer/ndp/host/gnrc_ndp_host.c new file mode 100644 index 0000000000..e1cbd37bcd --- /dev/null +++ b/sys/net/gnrc/network_layer/ndp/host/gnrc_ndp_host.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ + +#include +#include "random.h" +#include "net/gnrc/ipv6.h" +#include "net/gnrc/ndp.h" +#include "net/gnrc/ndp/internal.h" +#include "vtimer.h" + +#include "net/gnrc/ndp/host.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static inline void _reschedule_rtr_sol(gnrc_ipv6_netif_t *iface, timex_t delay) +{ + vtimer_remove(&iface->rtr_sol_timer); + vtimer_set_msg(&iface->rtr_sol_timer, delay, gnrc_ipv6_pid, GNRC_NDP_MSG_RTR_SOL_RETRANS, + iface); +} + +void gnrc_ndp_host_init(gnrc_ipv6_netif_t *iface) +{ + uint32_t interval = genrand_uint32_range(0, GNRC_NDP_MAX_RTR_SOL_DELAY * SEC_IN_USEC); + mutex_lock(&iface->mutex); + iface->rtr_sol_count = GNRC_NDP_MAX_RTR_SOL_NUMOF; + DEBUG("ndp host: delayed initial router solicitation by %" PRIu32 " usec.\n", interval); + _reschedule_rtr_sol(iface, timex_set(0, interval)); + mutex_unlock(&iface->mutex); +} + +void gnrc_ndp_host_retrans_rtr_sol(gnrc_ipv6_netif_t *iface) +{ + mutex_lock(&iface->mutex); + if (iface->rtr_sol_count > 1) { /* regard off-by-one error */ + DEBUG("ndp hst: retransmit rtr sol in %d sec\n", GNRC_NDP_MAX_RTR_SOL_INT); + iface->rtr_sol_count--; + _reschedule_rtr_sol(iface, timex_set(GNRC_NDP_MAX_RTR_SOL_INT, 0)); + } + mutex_unlock(&iface->mutex); + gnrc_ndp_internal_send_rtr_sol(iface->pid, NULL); +} + +/** @} */ 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 5e1650e486..e1af1a8f7f 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 @@ -33,11 +33,9 @@ static gnrc_ipv6_nc_t *_last_router = NULL; /* last router chosen as default * router. Only used if reachability * is suspect (i. e. incomplete or * not at all) */ - -/** - * @brief Get L2 address from interface - */ -static uint16_t _get_l2src(uint8_t *l2src, size_t l2src_size, kernel_pid_t iface); +static gnrc_pktsnip_t *_build_headers(kernel_pid_t iface, gnrc_pktsnip_t *payload, + ipv6_addr_t *dst, ipv6_addr_t *src); +static size_t _get_l2src(kernel_pid_t iface, uint8_t *l2src, size_t l2src_maxlen); /** * @brief Sends @ref GNRC_NETAPI_MSG_TYPE_SND delayed. @@ -160,7 +158,8 @@ void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_a DEBUG("dst: %s, supply_tl2a: %d)\n", ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), supply_tl2a); - if (gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) { + if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) && + (gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) { adv_flags |= NDP_NBR_ADV_FLAGS_R; } @@ -173,9 +172,9 @@ void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_a if (supply_tl2a) { uint8_t l2src[8]; - uint16_t l2src_len; + size_t l2src_len; /* we previously checked if we are the target, so we can take our L2src */ - l2src_len = _get_l2src(l2src, sizeof(l2src), iface); + l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add target address link-layer address option */ @@ -202,32 +201,13 @@ void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_a gnrc_pktbuf_release(pkt); return; } - pkt = hdr; - hdr = gnrc_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)dst, - sizeof(ipv6_addr_t)); - + hdr = _build_headers(iface, pkt, dst, NULL); if (hdr == NULL) { - DEBUG("ndp internal: error allocating IPv6 header.\n"); + DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } - - ((ipv6_hdr_t *)hdr->data)->hl = 255; - - pkt = hdr; - /* add netif header for send interface specification */ - hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0); - - if (hdr == NULL) { - DEBUG("ndp internal: error allocating netif header.\n"); - return; - } - - ((gnrc_netif_hdr_t *)hdr->data)->if_pid = iface; - - LL_PREPEND(pkt, hdr); - if (gnrc_ipv6_netif_addr_is_non_unicast(tgt)) { /* avoid collision for anycast addresses * (see https://tools.ietf.org/html/rfc4861#section-7.2.7) */ @@ -238,10 +218,10 @@ void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_a delay.seconds); /* nc_entry must be set so no need to check it */ - _send_delayed(&nc_entry->nbr_adv_timer, delay, pkt); + _send_delayed(&nc_entry->nbr_adv_timer, delay, hdr); } else { - gnrc_netapi_send(gnrc_ipv6_pid, pkt); + gnrc_netapi_send(gnrc_ipv6_pid, hdr); } } @@ -250,7 +230,6 @@ void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt, { gnrc_pktsnip_t *hdr, *pkt = NULL; ipv6_addr_t *src = NULL; - size_t src_len = 0; DEBUG("ndp internal: send neighbor solicitation (iface: %" PRIkernel_pid ", tgt: %s, ", iface, ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str))); @@ -259,9 +238,8 @@ void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt, /* check if there is a fitting source address to target */ if ((src = gnrc_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) { uint8_t l2src[8]; - uint16_t l2src_len; - src_len = sizeof(ipv6_addr_t); - l2src_len = _get_l2src(l2src, sizeof(l2src), iface); + size_t l2src_len; + l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add source address link-layer address option */ @@ -282,33 +260,55 @@ void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt, gnrc_pktbuf_release(pkt); return; } - pkt = hdr; - hdr = gnrc_ipv6_hdr_build(pkt, (uint8_t *)src, src_len, (uint8_t *)dst, - sizeof(ipv6_addr_t)); - + hdr = _build_headers(iface, pkt, dst, src); if (hdr == NULL) { - DEBUG("ndp internal: error allocating IPv6 header.\n"); + DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } + gnrc_netapi_send(gnrc_ipv6_pid, hdr); +} - ((ipv6_hdr_t *)hdr->data)->hl = 255; - - pkt = hdr; - /* add netif header for send interface specification */ - hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0); +void gnrc_ndp_internal_send_rtr_sol(kernel_pid_t iface, ipv6_addr_t *dst) +{ + gnrc_pktsnip_t *hdr, *pkt = NULL; + ipv6_addr_t *src = NULL, all_routers = IPV6_ADDR_ALL_ROUTERS_LINK_LOCAL; + DEBUG("ndp internal: send router solicitation (iface: %" PRIkernel_pid ", dst: ff02::2)\n", + iface); + if (dst == NULL) { + dst = &all_routers; + } + /* check if there is a fitting source address to target */ + if ((src = gnrc_ipv6_netif_find_best_src_addr(iface, dst)) != NULL) { + uint8_t l2src[8]; + size_t l2src_len; + l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); + if (l2src_len > 0) { + /* add source address link-layer address option */ + pkt = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, NULL); + if (pkt == NULL) { + DEBUG("ndp internal: error allocating Source Link-layer address option.\n"); + gnrc_pktbuf_release(pkt); + return; + } + } + } + hdr = gnrc_ndp_rtr_sol_build(pkt); if (hdr == NULL) { - DEBUG("ndp internal: error allocating netif header.\n"); + DEBUG("ndp internal: error allocating router solicitation.\n"); + gnrc_pktbuf_release(pkt); return; } - - ((gnrc_netif_hdr_t *)hdr->data)->if_pid = iface; - - LL_PREPEND(pkt, hdr); - - gnrc_netapi_send(gnrc_ipv6_pid, pkt); + pkt = hdr; + hdr = _build_headers(iface, pkt, dst, src); + if (hdr == NULL) { + DEBUG("ndp internal: error adding lower-layer headers.\n"); + gnrc_pktbuf_release(pkt); + return; + } + gnrc_netapi_send(gnrc_ipv6_pid, hdr); } int gnrc_ndp_internal_sl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, uint8_t icmpv6_type, @@ -335,6 +335,7 @@ int gnrc_ndp_internal_sl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, uin gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), sl2a, sl2a_len)); switch (icmpv6_type) { + case ICMPV6_RTR_ADV: case ICMPV6_NBR_SOL: if (sl2a_len == 0) { /* in case there was no source address in l2 */ sl2a_len = (sl2a_opt->len / 8) - sizeof(ndp_opt_t); @@ -396,11 +397,81 @@ int gnrc_ndp_internal_tl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, return 0; } } -static uint16_t _get_l2src(uint8_t *l2src, size_t l2src_size, kernel_pid_t iface) + +bool gnrc_ndp_internal_mtu_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type, + ndp_opt_mtu_t *mtu_opt) +{ + gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface); + + assert(if_entry != NULL); + if ((mtu_opt->len != NDP_OPT_MTU_LEN)) { + DEBUG("ndp: invalid MTU option received\n"); + return false; + } + if (icmpv6_type != ICMPV6_RTR_ADV) { + /* else discard silently */ + return true; + } + mutex_lock(&if_entry->mutex); + if_entry->mtu = byteorder_ntohl(mtu_opt->mtu); + mutex_unlock(&if_entry->mutex); + return true; +} + +bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type, + ndp_opt_pi_t *pi_opt) +{ + ipv6_addr_t *prefix; + gnrc_ipv6_netif_addr_t *netif_addr; + + if ((pi_opt->len != NDP_OPT_MTU_LEN)) { + DEBUG("ndp: invalid MTU option received\n"); + return false; + } + if (icmpv6_type != ICMPV6_RTR_ADV || ipv6_addr_is_link_local(&pi_opt->prefix)) { + /* else discard silently */ + return true; + } + prefix = gnrc_ipv6_netif_find_addr(iface, &pi_opt->prefix); + if (((prefix == NULL) || + (gnrc_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) && + (pi_opt->valid_ltime.u32 != 0)) { + prefix = gnrc_ipv6_netif_add_addr(iface, &pi_opt->prefix, + pi_opt->prefix_len, + pi_opt->flags & NDP_OPT_PI_FLAGS_MASK); + if (prefix == NULL) { + DEBUG("ndp: could not add prefix to interface %d\n", iface); + return false; + } + } + netif_addr = gnrc_ipv6_netif_addr_get(prefix); + if (pi_opt->valid_ltime.u32 == 0) { + if (prefix != NULL) { + gnrc_ipv6_netif_remove_addr(iface, &netif_addr->addr); + } + + return true; + } + netif_addr->valid = byteorder_ntohl(pi_opt->valid_ltime); + netif_addr->preferred = byteorder_ntohl(pi_opt->pref_ltime); + vtimer_remove(&netif_addr->valid_timeout); + if (netif_addr->valid != UINT32_MAX) { + vtimer_set_msg(&netif_addr->valid_timeout, + timex_set(byteorder_ntohl(pi_opt->valid_ltime), 0), + thread_getpid(), GNRC_NDP_MSG_ADDR_TIMEOUT, &netif_addr->addr); + } + /* TODO: preferred lifetime for address auto configuration */ + /* on-link flag MUST stay set if it was */ + netif_addr->flags &= ~NDP_OPT_PI_FLAGS_A; + netif_addr->flags |= (pi_opt->flags & NDP_OPT_PI_FLAGS_MASK); + return true; +} + +static size_t _get_l2src(kernel_pid_t iface, uint8_t *l2src, size_t l2src_maxlen) { bool try_long = false; int res; - uint16_t l2src_len; + size_t l2src_len; /* maximum address length that fits into a minimum length (8) S/TL2A option */ const uint16_t max_short_len = 6; @@ -412,11 +483,11 @@ static uint16_t _get_l2src(uint8_t *l2src, size_t l2src_size, kernel_pid_t iface } if (try_long && ((res = gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, - l2src, l2src_size)) > max_short_len)) { + l2src, l2src_maxlen)) > max_short_len)) { l2src_len = (uint16_t)res; } else if ((res = gnrc_netapi_get(iface, NETOPT_ADDRESS, 0, l2src, - l2src_size)) >= 0) { + l2src_maxlen)) >= 0) { l2src_len = (uint16_t)res; } else { @@ -427,4 +498,27 @@ static uint16_t _get_l2src(uint8_t *l2src, size_t l2src_size, kernel_pid_t iface return l2src_len; } +static gnrc_pktsnip_t *_build_headers(kernel_pid_t iface, gnrc_pktsnip_t *payload, + ipv6_addr_t *dst, ipv6_addr_t *src) +{ + gnrc_pktsnip_t *l2hdr; + gnrc_pktsnip_t *iphdr = gnrc_ipv6_hdr_build(payload, (uint8_t *)src, sizeof(ipv6_addr_t), + (uint8_t *)dst, sizeof(ipv6_addr_t)); + if (iphdr == NULL) { + DEBUG("ndp internal: error allocating IPv6 header.\n"); + return NULL; + } + ((ipv6_hdr_t *)iphdr->data)->hl = 255; + /* add netif header for send interface specification */ + l2hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0); + if (l2hdr == NULL) { + DEBUG("ndp internal: error allocating netif header.\n"); + gnrc_pktbuf_remove_snip(iphdr, iphdr); + return NULL; + } + ((gnrc_netif_hdr_t *)l2hdr->data)->if_pid = iface; + LL_PREPEND(iphdr, l2hdr); + return l2hdr; +} + /** @} */ From c367477d44049ba0343ec52d518f5fd0daba22b2 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 31 Aug 2015 14:31:36 +0200 Subject: [PATCH 2/2] gnrc: adapt for gnrc_ndp_host --- sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c | 5 ++++- sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c | 8 +++++++- sys/net/gnrc/network_layer/ipv6/netif/gnrc_ipv6_netif.c | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c index b09cd9616a..c953baf3ee 100644 --- a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c +++ b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c @@ -92,9 +92,11 @@ void gnrc_icmpv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt) /* TODO */ break; +#ifdef MODULE_GNRC_NDP case ICMPV6_RTR_ADV: DEBUG("icmpv6: router advertisement received\n"); - /* TODO */ + gnrc_ndp_rtr_adv_handle(iface, pkt, ipv6->data, (ndp_rtr_adv_t *)hdr, + icmpv6->size); break; case ICMPV6_NBR_SOL: @@ -108,6 +110,7 @@ void gnrc_icmpv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt) gnrc_ndp_nbr_adv_handle(iface, pkt, ipv6->data, (ndp_nbr_adv_t *)hdr, icmpv6->size); break; +#endif case ICMPV6_REDIRECT: DEBUG("icmpv6: redirect message received\n"); diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index daa2c66663..02f3368e09 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -190,6 +190,7 @@ static void *_event_loop(void *args) msg_reply(&msg, &reply); break; +#ifdef MODULE_GNRC_NDP case GNRC_NDP_MSG_RTR_TIMEOUT: DEBUG("ipv6: Router timeout received\n"); ((gnrc_ipv6_nc_t *)msg.content.ptr)->flags &= ~GNRC_IPV6_NC_IS_ROUTER; @@ -201,7 +202,6 @@ static void *_event_loop(void *args) (ipv6_addr_t *)msg.content.ptr); break; -#ifdef MODULE_GNRC_NDP case GNRC_NDP_MSG_NBR_SOL_RETRANS: DEBUG("ipv6: Neigbor solicitation retransmission timer event received\n"); gnrc_ndp_retrans_nbr_sol((gnrc_ipv6_nc_t *)msg.content.ptr); @@ -212,6 +212,12 @@ static void *_event_loop(void *args) gnrc_ndp_state_timeout((gnrc_ipv6_nc_t *)msg.content.ptr); break; #endif +#ifdef MODULE_GNRC_NDP_HOST + case GNRC_NDP_MSG_RTR_SOL_RETRANS: + DEBUG("ipv6: Router solicitation retransmission event received\n"); + gnrc_ndp_host_retrans_rtr_sol((gnrc_ipv6_netif_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 1f21ea1b44..8c8a91084d 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 @@ -763,6 +763,10 @@ void gnrc_ipv6_netif_init_by_dev(void) } mutex_unlock(&ipv6_if->mutex); +#ifdef MODULE_GNRC_NDP_HOST + /* start periodic router solicitations */ + gnrc_ndp_host_init(ipv6_if); +#endif } }