mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
gnrc_ndp_host: initial import
This commit is contained in:
parent
df21f1b59d
commit
b033ff590b
20
Makefile.dep
20
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
|
||||
|
@ -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.
|
||||
|
@ -22,6 +22,7 @@
|
||||
#define GNRC_NDP_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 <a href="https://tools.ietf.org/html/rfc4861#section-10">
|
||||
* RFC 4861, section 10
|
||||
* </a>
|
||||
*/
|
||||
/**
|
||||
* @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 <a href="https://tools.ietf.org/html/rfc4861#section-10">
|
||||
* RFC 4861, section 10
|
||||
* </a>
|
||||
@ -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 <a href="https://tools.ietf.org/html/rfc4861#section-4.1">
|
||||
* RFC 4861, section 4.1
|
||||
* </a>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
|
54
sys/include/net/gnrc/ndp/host.h
Normal file
54
sys/include/net/gnrc/ndp/host.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*
|
||||
* 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 <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#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_ */
|
||||
/** @} */
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
3
sys/net/gnrc/network_layer/ndp/host/Makefile
Normal file
3
sys/net/gnrc/network_layer/ndp/host/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_ndp_host
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
56
sys/net/gnrc/network_layer/ndp/host/gnrc_ndp_host.c
Normal file
56
sys/net/gnrc/network_layer/ndp/host/gnrc_ndp_host.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*
|
||||
* 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 <inttypes.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
/** @} */
|
@ -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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
Loading…
Reference in New Issue
Block a user