Merge pull request #3441 from authmillenon/gnrc/enh/prepare-multi-ndp
ng_ndp: prepare for parallel NDP implementations
This commit is contained in:
commit
9aa96509ee
@ -78,12 +78,16 @@ ifneq (,$(filter ng_ipv6_default,$(USEMODULE)))
|
||||
USEMODULE += ng_ipv6
|
||||
USEMODULE += ng_icmpv6
|
||||
USEMODULE += ng_ndp
|
||||
USEMODULE += ng_ndp_internal
|
||||
USEMODULE += ng_ndp_node
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ng_ipv6_router_default,$(USEMODULE)))
|
||||
USEMODULE += ng_ipv6_router
|
||||
USEMODULE += ng_icmpv6
|
||||
USEMODULE += ng_ndp
|
||||
USEMODULE += ng_ndp_internal
|
||||
USEMODULE += ng_ndp_node
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ng_ndp,$(USEMODULE)))
|
||||
|
||||
@ -130,6 +130,14 @@ endif
|
||||
include $(RIOTBASE)/Makefile.modules
|
||||
include $(RIOTBOARD)/$(BOARD)/Makefile.include
|
||||
include $(RIOTCPU)/$(CPU)/Makefile.include
|
||||
|
||||
# get number of interfaces straight before resolving dependencies
|
||||
NG_NETIF_NUMOF ?= 1
|
||||
|
||||
ifneq ($(NG_NETIF_NUMOF),1)
|
||||
CFLAGS += -DNG_NETIF_NUMOF=$(NG_NETIF_NUMOF)
|
||||
endif
|
||||
|
||||
include $(RIOTBASE)/Makefile.dep
|
||||
|
||||
USEMODULE += $(filter-out $(DISABLE_MODULE), $(DEFAULT_MODULE))
|
||||
|
||||
@ -49,6 +49,12 @@ endif
|
||||
ifneq (,$(filter ng_ndp,$(USEMODULE)))
|
||||
DIRS += net/network_layer/ng_ndp
|
||||
endif
|
||||
ifneq (,$(filter ng_ndp_internal,$(USEMODULE)))
|
||||
DIRS += net/network_layer/ng_ndp/internal
|
||||
endif
|
||||
ifneq (,$(filter ng_ndp_node,$(USEMODULE)))
|
||||
DIRS += net/network_layer/ng_ndp/node
|
||||
endif
|
||||
ifneq (,$(filter ng_netapi,$(USEMODULE)))
|
||||
DIRS += net/crosslayer/ng_netapi
|
||||
endif
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#ifndef FIB_H_
|
||||
#define FIB_H_
|
||||
|
||||
#include "kernel_types.h"
|
||||
#include "timex.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -253,6 +253,52 @@ void ng_ipv6_netif_remove(kernel_pid_t pid);
|
||||
*/
|
||||
ng_ipv6_netif_t *ng_ipv6_netif_get(kernel_pid_t pid);
|
||||
|
||||
/**
|
||||
* @brief Set interface to router mode.
|
||||
*
|
||||
* @details This sets/unsets the NG_IPV6_NETIF_FLAGS_ROUTER and initializes
|
||||
* or ceases router behavior for neighbor discovery.
|
||||
*
|
||||
* @param[in] The interface.
|
||||
* @param[in] Status for the NG_IPV6_NETIF_FLAGS_ROUTER flag.
|
||||
*/
|
||||
static inline void ng_ipv6_netif_set_rtr(ng_ipv6_netif_t *netif, bool enable)
|
||||
{
|
||||
(void)netif; /* Don't do anything for non-routers */
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set interface to router advertisement mode.
|
||||
*
|
||||
* @details If NG_IPV6_NETIF_FLAGS_ROUTER is set this sets/unsets the
|
||||
* NG_IPV6_NETIF_FLAGS_RTR_ADV and initializes or ceases router
|
||||
* advertising behavior for neighbor discovery.
|
||||
*
|
||||
* @param[in] The interface.
|
||||
* @param[in] Status for the NG_IPV6_NETIF_FLAGS_RTR flag.
|
||||
*/
|
||||
static inline void ng_ipv6_netif_set_rtr_adv(ng_ipv6_netif_t *netif, bool enable)
|
||||
{
|
||||
(void)netif; /* Don't do anything for non-routers */
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Solicitates an advertisement of a neighboring router on this
|
||||
* interface.
|
||||
*
|
||||
* @param[in] netif The interface.
|
||||
* @param[in] dst The address of the neighboring router.
|
||||
* May be NULL for @ref NG_IPV6_ADDR_ALL_ROUTERS_LINK_LOCAL.
|
||||
*/
|
||||
static inline void ng_ipv6_netif_sol_router(ng_ipv6_netif_t *netif,
|
||||
ng_ipv6_addr_t *dst)
|
||||
{
|
||||
(void)netif; /* TODO */
|
||||
(void)dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an address to an interface.
|
||||
*
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "net/ng_ipv6/nc.h"
|
||||
#include "net/ng_ipv6/netif.h"
|
||||
|
||||
#include "net/ng_ndp/node.h"
|
||||
#include "net/ng_ndp/types.h"
|
||||
|
||||
#ifndef NG_NDP_H_
|
||||
@ -167,27 +168,6 @@ void ng_ndp_netif_add(ng_ipv6_netif_t *iface);
|
||||
*/
|
||||
void ng_ndp_netif_remove(ng_ipv6_netif_t *iface);
|
||||
|
||||
/**
|
||||
* @brief Get link-layer address and interface for next hop to destination
|
||||
* IPv6 address.
|
||||
*
|
||||
* @param[out] l2addr The link-layer for the next hop to @p dst.
|
||||
* @param[out] l2addr_len Length of @p l2addr.
|
||||
* @param[in] iface The interface to search the next hop on.
|
||||
* May be @ref KERNEL_PID_UNDEF if not specified.
|
||||
* @param[in] dst An IPv6 address to search the next hop for.
|
||||
* @param[in] pkt Packet to send to @p dst. Leave NULL if you
|
||||
* just want to get the addresses.
|
||||
*
|
||||
* @return The PID of the interface, on success.
|
||||
* @return -EHOSTUNREACH, if @p dst is not reachable.
|
||||
* @return -ENOBUFS, if @p l2addr_len was smaller than the resulting @p l2addr
|
||||
* would be long.
|
||||
*/
|
||||
kernel_pid_t ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
kernel_pid_t iface, ng_ipv6_addr_t *dst,
|
||||
ng_pktsnip_t *pkt);
|
||||
|
||||
/**
|
||||
* @brief Builds a neighbor solicitation message for sending.
|
||||
*
|
||||
|
||||
124
sys/include/net/ng_ndp/internal.h
Normal file
124
sys/include/net/ng_ndp/internal.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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_ng_ndp_internal Internal functions for neighbor discovery.
|
||||
* @ingroup net_ng_ndp
|
||||
* @brief Internal functions for neighbor discovery.
|
||||
* @internal
|
||||
* @note Only for use with a neighbor discovery implementations.
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Internal neighbor discovery functions for neighbor discovery.
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef INTERNAL_H_
|
||||
#define INTERNAL_H_
|
||||
|
||||
#include "net/ng_ipv6/addr.h"
|
||||
#include "net/ng_ndp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get best match from default router list.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-6.3.6">
|
||||
* RFC 4861, section 6.3.6
|
||||
* </a>
|
||||
*
|
||||
* @return Address to a default router.
|
||||
* @return NULL, if the default router list is empty.
|
||||
*/
|
||||
ng_ipv6_addr_t *ng_ndp_internal_default_router(void);
|
||||
|
||||
/**
|
||||
* @brief Sets state of a neighbor cache entry and triggers required actions.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param[in] nc_entry A neighbor cache entry.
|
||||
* @param[in] state The new state for the neighbor cache entry.
|
||||
*/
|
||||
void ng_ndp_internal_set_state(ng_ipv6_nc_t *nc_entry, uint8_t state);
|
||||
|
||||
/**
|
||||
* @brief Send precompiled neighbor solicitation.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param[in] iface Interface to send over. May not be KERNEL_PID_UNDEF.
|
||||
* @param[in] tgt Target address for the neighbor solicitation. May not be
|
||||
* NULL.
|
||||
* @param[in] dst Destination address for neighbor solicitation. May not be
|
||||
* NULL.
|
||||
*/
|
||||
void ng_ndp_internal_send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst);
|
||||
|
||||
/**
|
||||
* @brief Send precompiled neighbor advertisement.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param[in] iface Interface to send over. May not be KERNEL_PID_UNDEF.
|
||||
* @param[in] tgt Target address for the neighbor solicitation. May
|
||||
* not be NULL.
|
||||
* @param[in] dst Destination address for neighbor solicitation. May
|
||||
* not be NULL.
|
||||
* @param[in] supply_tl2a Add target link-layer address option to neighbor
|
||||
* advertisement if link-layer has addresses.
|
||||
*/
|
||||
void ng_ndp_internal_send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst, bool supply_tl2a);
|
||||
|
||||
/**
|
||||
* @brief Handles a SL2A option.
|
||||
*
|
||||
* @param[in] iface Interface the option was received on.
|
||||
* @param[in] pkt Packet the option was received in.
|
||||
* @param[in] ipv6 IPv6 header of @p pkt
|
||||
* @param[in] icmpv6_type ICMPv6 type of the message carrying the option.
|
||||
* @param[in] sl2a_opt The SL2A option.
|
||||
*
|
||||
* @return true, on success.
|
||||
* @return false, if SL2A was not valid.
|
||||
*/
|
||||
bool ng_ndp_internal_sl2a_opt_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ng_ndp_opt_t *sl2a_opt);
|
||||
|
||||
/**
|
||||
* @brief Handles a TL2A option.
|
||||
*
|
||||
* @param[in] iface Interface the option was received on.
|
||||
* @param[in] pkt Packet the option was received in.
|
||||
* @param[in] ipv6 IPv6 header of @p pkt
|
||||
* @param[in] icmpv6_type ICMPv6 type of the message carrying the option.
|
||||
* @param[in] tl2a_opt The TL2A option.
|
||||
* @param[out] l2addr The L2 address carried in the TL2A option.
|
||||
*
|
||||
* @return length of the L2 address, on success.
|
||||
* @return -EINVAL, if TL2A was not valid.
|
||||
*/
|
||||
int ng_ndp_internal_tl2a_opt_handle(ng_pktsnip_t *pkt, ng_ipv6_hdr_t *ipv6,
|
||||
uint8_t icmpv6_type, ng_ndp_opt_t *tl2a_opt,
|
||||
uint8_t *l2addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INTERNAL_H_ */
|
||||
/** @} */
|
||||
53
sys/include/net/ng_ndp/node.h
Normal file
53
sys/include/net/ng_ndp/node.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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_ng_ndp_node Neighbor discovery for pure IPv6 nodes
|
||||
* @ingroup net_ng_ndp
|
||||
* @brief Used for pure IPv6 nodes (without 6LoWPAN).
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief IPv6-node neighbor discovery definitions
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef NG_NDP_NODE_H_
|
||||
#define NG_NDP_NODE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get link-layer address and interface for next hop to destination
|
||||
* IPv6 address.
|
||||
*
|
||||
* @param[out] l2addr The link-layer for the next hop to @p dst.
|
||||
* @param[out] l2addr_len Length of @p l2addr.
|
||||
* @param[in] iface The interface to search the next hop on.
|
||||
* May be @ref KERNEL_PID_UNDEF if not specified.
|
||||
* @param[in] dst An IPv6 address to search the next hop for.
|
||||
* @param[in] pkt Packet to send to @p dst. Leave NULL if you
|
||||
* just want to get the addresses.
|
||||
*
|
||||
* @return The PID of the interface, on success.
|
||||
* @return -EHOSTUNREACH, if @p dst is not reachable.
|
||||
* @return -ENOBUFS, if @p l2addr_len was smaller than the resulting @p l2addr
|
||||
* would be long.
|
||||
*/
|
||||
kernel_pid_t ng_ndp_node_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
kernel_pid_t iface, ng_ipv6_addr_t *dst,
|
||||
ng_pktsnip_t *pkt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NG_NDP_NODE_H_ */
|
||||
/** @} */
|
||||
@ -450,6 +450,22 @@ static void _send_multicast(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
#endif /* NG_NETIF_NUMOF */
|
||||
}
|
||||
|
||||
static inline kernel_pid_t _next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
kernel_pid_t iface, ng_ipv6_addr_t *dst,
|
||||
ng_pktsnip_t *pkt)
|
||||
{
|
||||
#ifdef MODULE_NG_NDP_NODE
|
||||
return ng_ndp_node_next_hop_l2addr(l2addr, l2addr_len, iface, dst, pkt);
|
||||
#else
|
||||
(void)l2addr;
|
||||
(void)iface;
|
||||
(void)dst;
|
||||
(void)pkt;
|
||||
*l2addr_len = 0;
|
||||
return KERNEL_PID_UNDEF;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _send(ng_pktsnip_t *pkt, bool prep_hdr)
|
||||
{
|
||||
kernel_pid_t iface = KERNEL_PID_UNDEF;
|
||||
@ -537,8 +553,7 @@ static void _send(ng_pktsnip_t *pkt, bool prep_hdr)
|
||||
uint8_t l2addr_len = NG_IPV6_NC_L2_ADDR_MAX;
|
||||
uint8_t l2addr[l2addr_len];
|
||||
|
||||
iface = ng_ndp_next_hop_l2addr(l2addr, &l2addr_len, iface, &hdr->dst,
|
||||
pkt);
|
||||
iface = _next_hop_l2addr(l2addr, &l2addr_len, iface, &hdr->dst, pkt);
|
||||
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
DEBUG("ipv6: error determining next hop's link layer address\n");
|
||||
|
||||
3
sys/net/network_layer/ng_ndp/internal/Makefile
Normal file
3
sys/net/network_layer/ng_ndp/internal/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = ng_ndp_internal
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
449
sys/net/network_layer/ng_ndp/internal/ng_ndp_internal.c
Normal file
449
sys/net/network_layer/ng_ndp/internal/ng_ndp_internal.c
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "net/ng_ipv6.h"
|
||||
#include "net/ng_ndp.h"
|
||||
#include "random.h"
|
||||
#include "timex.h"
|
||||
#include "vtimer.h"
|
||||
|
||||
#include "net/ng_ndp/internal.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
static ng_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);
|
||||
|
||||
/**
|
||||
* @brief Sends @ref NG_NETAPI_MSG_TYPE_SND delayed.
|
||||
*
|
||||
* @param[in] t Timer for the delay.
|
||||
* @param[in] interval Delay interval.
|
||||
* @param[in] pkt Packet to send delayed.
|
||||
*/
|
||||
static inline void _send_delayed(vtimer_t *t, timex_t interval, ng_pktsnip_t *pkt)
|
||||
{
|
||||
vtimer_remove(t);
|
||||
vtimer_set_msg(t, interval, ng_ipv6_pid, NG_NETAPI_MSG_TYPE_SND, pkt);
|
||||
}
|
||||
|
||||
|
||||
ng_ipv6_addr_t *ng_ndp_internal_default_router(void)
|
||||
{
|
||||
ng_ipv6_nc_t *router = ng_ipv6_nc_get_next_router(NULL);
|
||||
|
||||
/* first look if there is any reachable router */
|
||||
while (router != NULL) {
|
||||
if ((ng_ipv6_nc_get_state(router) != NG_IPV6_NC_STATE_INCOMPLETE) &&
|
||||
(ng_ipv6_nc_get_state(router) != NG_IPV6_NC_STATE_UNREACHABLE)) {
|
||||
_last_router = NULL;
|
||||
|
||||
return &router->ipv6_addr;
|
||||
}
|
||||
|
||||
router = ng_ipv6_nc_get_next_router(router);
|
||||
}
|
||||
|
||||
/* else take the first one, but keep round-robin in further selections */
|
||||
router = ng_ipv6_nc_get_next_router(_last_router);
|
||||
|
||||
if (router == NULL) { /* end of router list or there is none => wrap around */
|
||||
router = ng_ipv6_nc_get_next_router(router);
|
||||
|
||||
if (router == NULL) { /* still nothing found => no router in list */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_last_router = router;
|
||||
|
||||
return &router->ipv6_addr;
|
||||
}
|
||||
|
||||
void ng_ndp_internal_set_state(ng_ipv6_nc_t *nc_entry, uint8_t state)
|
||||
{
|
||||
ng_ipv6_netif_t *ipv6_iface;
|
||||
timex_t t = { NG_NDP_FIRST_PROBE_DELAY, 0 };
|
||||
|
||||
nc_entry->flags &= ~NG_IPV6_NC_STATE_MASK;
|
||||
nc_entry->flags |= state;
|
||||
|
||||
DEBUG("ndp internal: set %s state to ",
|
||||
ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)));
|
||||
|
||||
switch (state) {
|
||||
case NG_IPV6_NC_STATE_REACHABLE:
|
||||
ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);
|
||||
DEBUG("REACHABLE (reachable time = %" PRIu32 ".%06" PRIu32 ")\n",
|
||||
ipv6_iface->reach_time.seconds,
|
||||
ipv6_iface->reach_time.microseconds);
|
||||
t = ipv6_iface->reach_time;
|
||||
|
||||
/* we intentionally fall through here to set the desired timeout t */
|
||||
case NG_IPV6_NC_STATE_DELAY:
|
||||
#if ENABLE_DEBUG
|
||||
if (state == NG_IPV6_NC_STATE_DELAY) {
|
||||
DEBUG("DELAY (probe with unicast NS in %u seconds)\n",
|
||||
NG_NDP_FIRST_PROBE_DELAY);
|
||||
}
|
||||
#endif
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NC_STATE_TIMEOUT, nc_entry);
|
||||
break;
|
||||
|
||||
case NG_IPV6_NC_STATE_PROBE:
|
||||
ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);
|
||||
|
||||
nc_entry->probes_remaining = NG_NDP_MAX_UC_NBR_SOL_NUMOF;
|
||||
DEBUG("PROBE (probe with %" PRIu8 " unicast NS every %" PRIu32
|
||||
".%06" PRIu32 " seconds)\n", nc_entry->probes_remaining,
|
||||
ipv6_iface->retrans_timer.seconds,
|
||||
ipv6_iface->retrans_timer.microseconds);
|
||||
|
||||
ng_ndp_internal_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr,
|
||||
&nc_entry->ipv6_addr);
|
||||
|
||||
mutex_lock(&ipv6_iface->mutex);
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer,
|
||||
ipv6_iface->retrans_timer, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
mutex_unlock(&ipv6_iface->mutex);
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
case NG_IPV6_NC_STATE_STALE:
|
||||
DEBUG("STALE (go into DELAY on next packet)\n");
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
DEBUG("errorneous or unknown\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ng_ndp_internal_send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst, bool supply_tl2a)
|
||||
{
|
||||
ng_pktsnip_t *hdr, *pkt = NULL;
|
||||
uint8_t adv_flags = 0;
|
||||
|
||||
DEBUG("ndp internal: send neighbor advertisement (iface: %" PRIkernel_pid ", tgt: %s, ",
|
||||
iface, ng_ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str)));
|
||||
DEBUG("dst: %s, supply_tl2a: %d)\n",
|
||||
ng_ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), supply_tl2a);
|
||||
|
||||
if (ng_ipv6_netif_get(iface)->flags & NG_IPV6_NETIF_FLAGS_ROUTER) {
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_R;
|
||||
}
|
||||
|
||||
if (ng_ipv6_addr_is_unspecified(dst)) {
|
||||
ng_ipv6_addr_set_all_nodes_multicast(dst,
|
||||
NG_IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
|
||||
}
|
||||
else {
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_S;
|
||||
}
|
||||
|
||||
if (supply_tl2a) {
|
||||
uint8_t l2src[8];
|
||||
uint16_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);
|
||||
|
||||
if (l2src_len > 0) {
|
||||
/* add target address link-layer address option */
|
||||
pkt = ng_ndp_opt_tl2a_build(l2src, l2src_len, NULL);
|
||||
|
||||
if (pkt == NULL) {
|
||||
DEBUG("ndp internal: error allocating Target Link-layer address option.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: also check if the node provides proxy servies for tgt */
|
||||
if ((pkt != NULL) && !ng_ipv6_netif_addr_is_non_unicast(tgt)) {
|
||||
/* TL2A is not supplied and tgt is not anycast */
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_O;
|
||||
}
|
||||
|
||||
hdr = ng_ndp_nbr_adv_build(adv_flags, tgt, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp internal: error allocating Neighbor advertisement.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = hdr;
|
||||
hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)dst,
|
||||
sizeof(ng_ipv6_addr_t));
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp internal: error allocating IPv6 header.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_ipv6_hdr_t *)hdr->data)->hl = 255;
|
||||
|
||||
pkt = hdr;
|
||||
/* add netif header for send interface specification */
|
||||
hdr = ng_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp internal: error allocating netif header.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_netif_hdr_t *)hdr->data)->if_pid = iface;
|
||||
|
||||
LL_PREPEND(pkt, hdr);
|
||||
|
||||
if (ng_ipv6_netif_addr_is_non_unicast(tgt)) {
|
||||
/* avoid collision for anycast addresses
|
||||
* (see https://tools.ietf.org/html/rfc4861#section-7.2.7) */
|
||||
timex_t delay = { 0, genrand_uint32_range(0, NG_NDP_MAX_AC_TGT_DELAY * SEC_IN_USEC) };
|
||||
timex_normalize(&delay);
|
||||
ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, tgt);
|
||||
DEBUG("ndp internal: delay neighbor advertisement for %" PRIu32 " sec.",
|
||||
delay.seconds);
|
||||
|
||||
/* nc_entry must be set so no need to check it */
|
||||
_send_delayed(&nc_entry->nbr_adv_timer, delay, pkt);
|
||||
}
|
||||
else {
|
||||
ng_netapi_send(ng_ipv6_pid, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
void ng_ndp_internal_send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst)
|
||||
{
|
||||
ng_pktsnip_t *hdr, *pkt = NULL;
|
||||
ng_ipv6_addr_t *src = NULL;
|
||||
size_t src_len = 0;
|
||||
|
||||
DEBUG("ndp internal: send neighbor solicitation (iface: %" PRIkernel_pid ", tgt: %s, ",
|
||||
iface, ng_ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str)));
|
||||
DEBUG("dst: %s)\n", ng_ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
|
||||
|
||||
/* check if there is a fitting source address to target */
|
||||
if ((src = ng_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) {
|
||||
uint8_t l2src[8];
|
||||
uint16_t l2src_len;
|
||||
src_len = sizeof(ng_ipv6_addr_t);
|
||||
l2src_len = _get_l2src(l2src, sizeof(l2src), iface);
|
||||
|
||||
if (l2src_len > 0) {
|
||||
/* add source address link-layer address option */
|
||||
pkt = ng_ndp_opt_sl2a_build(l2src, l2src_len, NULL);
|
||||
|
||||
if (pkt == NULL) {
|
||||
DEBUG("ndp internal: error allocating Source Link-layer address option.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hdr = ng_ndp_nbr_sol_build(tgt, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp internal: error allocating Neighbor solicitation.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = hdr;
|
||||
hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)src, src_len, (uint8_t *)dst,
|
||||
sizeof(ng_ipv6_addr_t));
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp internal: error allocating IPv6 header.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_ipv6_hdr_t *)hdr->data)->hl = 255;
|
||||
|
||||
pkt = hdr;
|
||||
/* add netif header for send interface specification */
|
||||
hdr = ng_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp internal: error allocating netif header.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_netif_hdr_t *)hdr->data)->if_pid = iface;
|
||||
|
||||
LL_PREPEND(pkt, hdr);
|
||||
|
||||
ng_netapi_send(ng_ipv6_pid, pkt);
|
||||
}
|
||||
|
||||
bool ng_ndp_internal_sl2a_opt_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ng_ndp_opt_t *sl2a_opt)
|
||||
{
|
||||
ng_ipv6_nc_t *nc_entry = NULL;
|
||||
uint8_t sl2a_len = 0;
|
||||
uint8_t *sl2a = (uint8_t *)(sl2a_opt + 1);
|
||||
|
||||
if ((sl2a_opt->len == 0) || ng_ipv6_addr_is_unspecified(&ipv6->src)) {
|
||||
DEBUG("ndp: invalid source link-layer address option received\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (pkt) {
|
||||
if (pkt->type == NG_NETTYPE_NETIF) {
|
||||
ng_netif_hdr_t *hdr = pkt->data;
|
||||
sl2a_len = hdr->src_l2addr_len;
|
||||
break;
|
||||
}
|
||||
pkt = pkt->next;
|
||||
}
|
||||
|
||||
if (sl2a_len == 0) { /* in case there was no source address in l2 */
|
||||
sl2a_len = (sl2a_opt->len / 8) - sizeof(ng_ndp_opt_t);
|
||||
|
||||
/* ignore all zeroes at the end for length */
|
||||
for (; sl2a[sl2a_len - 1] == 0x00; sl2a_len--);
|
||||
}
|
||||
|
||||
DEBUG("ndp: received SL2A (link-layer address: %s)\n",
|
||||
ng_netif_addr_to_str(addr_str, sizeof(addr_str), sl2a, sl2a_len));
|
||||
|
||||
switch (icmpv6_type) {
|
||||
case NG_ICMPV6_NBR_SOL:
|
||||
nc_entry = ng_ipv6_nc_get(iface, &ipv6->src);
|
||||
|
||||
if (nc_entry != NULL) {
|
||||
if ((sl2a_len != nc_entry->l2_addr_len) ||
|
||||
(memcmp(sl2a, nc_entry->l2_addr, sl2a_len) != 0)) {
|
||||
/* if entry exists but l2 address differs: set */
|
||||
nc_entry->l2_addr_len = sl2a_len;
|
||||
memcpy(nc_entry->l2_addr, sl2a, sl2a_len);
|
||||
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ng_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len,
|
||||
NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
default: /* wrong encapsulating message: silently discard */
|
||||
DEBUG("ndp: silently discard sl2a_opt for ICMPv6 message type %"
|
||||
PRIu8 "\n", icmpv6_type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int ng_ndp_internal_tl2a_opt_handle(ng_pktsnip_t *pkt, ng_ipv6_hdr_t *ipv6,
|
||||
uint8_t icmpv6_type, ng_ndp_opt_t *tl2a_opt,
|
||||
uint8_t *l2addr)
|
||||
{
|
||||
uint8_t tl2a_len = 0;
|
||||
uint8_t *tl2a = (uint8_t *)(tl2a_opt + 1);
|
||||
|
||||
if ((tl2a_opt->len == 0) || ng_ipv6_addr_is_unspecified(&ipv6->src)) {
|
||||
DEBUG("ndp: invalid target link-layer address option received\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (icmpv6_type) {
|
||||
case NG_ICMPV6_NBR_ADV:
|
||||
while (pkt) {
|
||||
if (pkt->type == NG_NETTYPE_NETIF) {
|
||||
ng_netif_hdr_t *hdr = pkt->data;
|
||||
tl2a_len = hdr->src_l2addr_len;
|
||||
break;
|
||||
}
|
||||
pkt = pkt->next;
|
||||
}
|
||||
|
||||
if (tl2a_len == 0) { /* in case there was no source address in l2 */
|
||||
tl2a_len = (tl2a_opt->len / 8) - sizeof(ng_ndp_opt_t);
|
||||
|
||||
/* ignore all zeroes at the end for length */
|
||||
for (; tl2a[tl2a_len - 1] == 0x00; tl2a_len--);
|
||||
}
|
||||
|
||||
DEBUG("ndp: received TL2A (link-layer address: %s)\n",
|
||||
ng_netif_addr_to_str(addr_str, sizeof(addr_str), tl2a, tl2a_len));
|
||||
|
||||
memcpy(l2addr, tl2a, tl2a_len);
|
||||
|
||||
return (int)tl2a_len;
|
||||
|
||||
default: /* wrong encapsulating message: silently discard */
|
||||
DEBUG("ndp: silently discard tl2a_opt for ICMPv6 message type %"
|
||||
PRIu8 "\n", icmpv6_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static uint16_t _get_l2src(uint8_t *l2src, size_t l2src_size, kernel_pid_t iface)
|
||||
{
|
||||
bool try_long = false;
|
||||
int res;
|
||||
uint16_t l2src_len;
|
||||
/* maximum address length that fits into a minimum length (8) S/TL2A option */
|
||||
const uint16_t max_short_len = 6;
|
||||
|
||||
/* try getting source address */
|
||||
if ((ng_netapi_get(iface, NETOPT_SRC_LEN, 0, &l2src_len,
|
||||
sizeof(l2src_len)) >= 0) &&
|
||||
(l2src_len > max_short_len)) {
|
||||
try_long = true;
|
||||
}
|
||||
|
||||
if (try_long && ((res = ng_netapi_get(iface, NETOPT_ADDRESS_LONG, 0,
|
||||
l2src, l2src_size)) > max_short_len)) {
|
||||
l2src_len = (uint16_t)res;
|
||||
}
|
||||
else if ((res = ng_netapi_get(iface, NETOPT_ADDRESS, 0, l2src,
|
||||
l2src_size)) >= 0) {
|
||||
l2src_len = (uint16_t)res;
|
||||
}
|
||||
else {
|
||||
DEBUG("ndp internal: no link-layer address found.\n");
|
||||
l2src_len = 0;
|
||||
}
|
||||
|
||||
return l2src_len;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@ -19,6 +19,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "net/fib.h"
|
||||
#include "net/ng_icmpv6.h"
|
||||
#include "net/ng_ipv6.h"
|
||||
#include "net/ng_ipv6/ext/rh.h"
|
||||
@ -28,8 +29,9 @@
|
||||
#include "thread.h"
|
||||
#include "vtimer.h"
|
||||
|
||||
#include "net/ng_ndp/internal.h"
|
||||
|
||||
#include "net/ng_ndp.h"
|
||||
#include "net/fib.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
@ -41,43 +43,7 @@
|
||||
static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
static ng_pktqueue_t _pkt_nodes[NG_IPV6_NC_SIZE * 2];
|
||||
static ng_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) */
|
||||
|
||||
/* random helper function */
|
||||
static inline uint32_t _rand(uint32_t min, uint32_t max)
|
||||
{
|
||||
return (genrand_uint32() % (max - min)) + min;
|
||||
}
|
||||
|
||||
static bool _handle_sl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ng_ndp_opt_t *sl2a_opt);
|
||||
static int _handle_tl2a_opt(ng_pktsnip_t *pkt, ng_ipv6_hdr_t *ipv6,
|
||||
uint8_t icmpv6_type, ng_ndp_opt_t *tl2a_opt,
|
||||
uint8_t *l2addr);
|
||||
|
||||
/* send address resolution messages */
|
||||
static void _send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst);
|
||||
static void _send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst, bool supply_tl2a);
|
||||
|
||||
static void _set_state(ng_ipv6_nc_t *nc_entry, uint8_t state);
|
||||
|
||||
/* special netapi helper */
|
||||
static inline void _send_delayed(vtimer_t *t, timex_t interval, ng_pktsnip_t *pkt)
|
||||
{
|
||||
vtimer_remove(t);
|
||||
vtimer_set_msg(t, interval, ng_ipv6_pid, NG_NETAPI_MSG_TYPE_SND, pkt);
|
||||
}
|
||||
|
||||
/* packet queue node allocation */
|
||||
static ng_pktqueue_t *_alloc_pkt_node(ng_pktsnip_t *pkt);
|
||||
|
||||
void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_sol_t *nbr_sol,
|
||||
size_t icmpv6_size)
|
||||
@ -119,7 +85,7 @@ void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
|
||||
switch (opt->type) {
|
||||
case NG_NDP_OPT_SL2A:
|
||||
if (!_handle_sl2a_opt(iface, pkt, ipv6, nbr_sol->type, opt)) {
|
||||
if (!ng_ndp_internal_sl2a_opt_handle(iface, pkt, ipv6, nbr_sol->type, opt)) {
|
||||
/* invalid source link-layer address option */
|
||||
return;
|
||||
}
|
||||
@ -135,8 +101,8 @@ void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
sicmpv6_size -= (opt->len * 8);
|
||||
}
|
||||
|
||||
_send_nbr_adv(iface, tgt, &ipv6->src,
|
||||
ng_ipv6_addr_is_multicast(&ipv6->dst));
|
||||
ng_ndp_internal_send_nbr_adv(iface, tgt, &ipv6->src,
|
||||
ng_ipv6_addr_is_multicast(&ipv6->dst));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -190,8 +156,7 @@ void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
|
||||
switch (opt->type) {
|
||||
case NG_NDP_OPT_TL2A:
|
||||
if ((l2tgt_len = _handle_tl2a_opt(pkt, ipv6, nbr_adv->type, opt,
|
||||
l2tgt)) < 0) {
|
||||
if ((l2tgt_len = ng_ndp_internal_tl2a_opt_handle(pkt, ipv6, nbr_adv->type, opt, l2tgt)) < 0) {
|
||||
/* invalid target link-layer address option */
|
||||
return;
|
||||
}
|
||||
@ -227,10 +192,10 @@ void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);
|
||||
|
||||
if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
|
||||
}
|
||||
else {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_R) {
|
||||
@ -270,10 +235,10 @@ void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
}
|
||||
|
||||
if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
|
||||
}
|
||||
else if (l2tgt_changed && (l2tgt_len != 0)) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_R) {
|
||||
@ -286,7 +251,7 @@ void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
}
|
||||
else if (l2tgt_changed) {
|
||||
if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_REACHABLE) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
|
||||
}
|
||||
}
|
||||
@ -322,7 +287,7 @@ void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry)
|
||||
size_t ifnum = ng_netif_get(ifs);
|
||||
|
||||
for (size_t i = 0; i < ifnum; i++) {
|
||||
_send_nbr_sol(ifs[i], &nc_entry->ipv6_addr, &dst);
|
||||
ng_ndp_internal_send_nbr_sol(ifs[i], &nc_entry->ipv6_addr, &dst);
|
||||
}
|
||||
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
@ -332,7 +297,7 @@ void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry)
|
||||
else {
|
||||
ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);
|
||||
|
||||
_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, &dst);
|
||||
ng_ndp_internal_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, &dst);
|
||||
|
||||
mutex_lock(&ipv6_iface->mutex);
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
@ -359,11 +324,11 @@ void ng_ndp_state_timeout(ng_ipv6_nc_t *nc_entry)
|
||||
{
|
||||
switch (ng_ipv6_nc_get_state(nc_entry)) {
|
||||
case NG_IPV6_NC_STATE_REACHABLE:
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
break;
|
||||
|
||||
case NG_IPV6_NC_STATE_DELAY:
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_PROBE);
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_PROBE);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -373,7 +338,7 @@ void ng_ndp_state_timeout(ng_ipv6_nc_t *nc_entry)
|
||||
|
||||
void ng_ndp_netif_add(ng_ipv6_netif_t *iface)
|
||||
{
|
||||
uint32_t reach_time = _rand(NG_NDP_MIN_RAND, NG_NDP_MAX_RAND);
|
||||
uint32_t reach_time = genrand_uint32_range(NG_NDP_MIN_RAND, NG_NDP_MAX_RAND);
|
||||
|
||||
/* set default values */
|
||||
mutex_lock(&iface->mutex);
|
||||
@ -392,173 +357,6 @@ void ng_ndp_netif_remove(ng_ipv6_netif_t *iface)
|
||||
(void) iface;
|
||||
}
|
||||
|
||||
static ng_ipv6_addr_t *_default_router(void)
|
||||
{
|
||||
ng_ipv6_nc_t *router = ng_ipv6_nc_get_next_router(NULL);
|
||||
|
||||
/* first look if there is any reachable router */
|
||||
while (router != NULL) {
|
||||
if ((ng_ipv6_nc_get_state(router) != NG_IPV6_NC_STATE_INCOMPLETE) &&
|
||||
(ng_ipv6_nc_get_state(router) != NG_IPV6_NC_STATE_UNREACHABLE)) {
|
||||
_last_router = NULL;
|
||||
|
||||
return &router->ipv6_addr;
|
||||
}
|
||||
|
||||
router = ng_ipv6_nc_get_next_router(router);
|
||||
}
|
||||
|
||||
/* else take the first one, but keep round-robin in further selections */
|
||||
router = ng_ipv6_nc_get_next_router(_last_router);
|
||||
|
||||
if (router == NULL) { /* end of router list or there is none => wrap around */
|
||||
router = ng_ipv6_nc_get_next_router(router);
|
||||
|
||||
if (router == NULL) { /* still nothing found => no router in list */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_last_router = router;
|
||||
|
||||
return &router->ipv6_addr;
|
||||
}
|
||||
|
||||
kernel_pid_t ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
kernel_pid_t iface, ng_ipv6_addr_t *dst,
|
||||
ng_pktsnip_t *pkt)
|
||||
{
|
||||
ng_ipv6_addr_t *next_hop_ip = NULL, *prefix = NULL;
|
||||
|
||||
#ifdef MODULE_NG_IPV6_EXT_RH
|
||||
next_hop_ip = ng_ipv6_ext_rh_next_hop(hdr);
|
||||
#endif
|
||||
#ifdef MODULE_FIB
|
||||
size_t next_hop_size = sizeof(ng_ipv6_addr_t);
|
||||
uint32_t next_hop_flags = 0;
|
||||
ng_ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */
|
||||
|
||||
if ((next_hop_ip == NULL) &&
|
||||
(fib_get_next_hop(&iface, next_hop_actual.u8, &next_hop_size,
|
||||
&next_hop_flags, (uint8_t *)dst,
|
||||
sizeof(ng_ipv6_addr_t), 0) >= 0) &&
|
||||
(next_hop_size == sizeof(ng_ipv6_addr_t))) {
|
||||
next_hop_ip = &next_hop_actual;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (next_hop_ip == NULL) { /* no route to host */
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
/* ng_ipv6_netif_t doubles as prefix list */
|
||||
iface = ng_ipv6_netif_find_by_prefix(&prefix, dst);
|
||||
}
|
||||
else {
|
||||
/* ng_ipv6_netif_t doubles as prefix list */
|
||||
prefix = ng_ipv6_netif_match_prefix(iface, dst);
|
||||
}
|
||||
|
||||
if ((prefix != NULL) && /* prefix is on-link */
|
||||
(ng_ipv6_netif_addr_get(prefix)->flags &
|
||||
NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK)) {
|
||||
next_hop_ip = dst;
|
||||
#ifdef MODULE_FIB
|
||||
/* We don't care if FIB is full, this is just for efficiency
|
||||
* for later sends */
|
||||
fib_add_entry(iface, (uint8_t *)dst, sizeof(ng_ipv6_addr_t), 0,
|
||||
(uint8_t *)next_hop_ip, sizeof(ng_ipv6_addr_t), 0,
|
||||
FIB_LIFETIME_NO_EXPIRE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (next_hop_ip == NULL) {
|
||||
next_hop_ip = _default_router();
|
||||
#ifdef MODULE_FIB
|
||||
/* We don't care if FIB is full, this is just for efficiency for later
|
||||
* sends */
|
||||
fib_add_entry(iface, (uint8_t *)dst, sizeof(ng_ipv6_addr_t), 0,
|
||||
(uint8_t *)next_hop_ip, sizeof(ng_ipv6_addr_t), 0,
|
||||
FIB_LIFETIME_NO_EXPIRE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (next_hop_ip != NULL) {
|
||||
ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, next_hop_ip);
|
||||
|
||||
if ((nc_entry != NULL) && ng_ipv6_nc_is_reachable(nc_entry)) {
|
||||
DEBUG("ndp: found reachable neighbor (%s => ",
|
||||
ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)));
|
||||
DEBUG("%s)\n",
|
||||
ng_netif_addr_to_str(addr_str, sizeof(addr_str),
|
||||
nc_entry->l2_addr, nc_entry->l2_addr_len));
|
||||
|
||||
if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_STALE) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_DELAY);
|
||||
}
|
||||
|
||||
memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len);
|
||||
*l2addr_len = nc_entry->l2_addr_len;
|
||||
/* TODO: unreachability check */
|
||||
return nc_entry->iface;
|
||||
}
|
||||
else if (nc_entry == NULL) {
|
||||
ng_pktqueue_t *pkt_node;
|
||||
ng_ipv6_addr_t dst_sol;
|
||||
|
||||
nc_entry = ng_ipv6_nc_add(iface, next_hop_ip, NULL, 0,
|
||||
NG_IPV6_NC_STATE_INCOMPLETE << NG_IPV6_NC_STATE_POS);
|
||||
|
||||
if (nc_entry == NULL) {
|
||||
DEBUG("ndp: could not create neighbor cache entry\n");
|
||||
return KERNEL_PID_UNDEF;
|
||||
}
|
||||
|
||||
pkt_node = _alloc_pkt_node(pkt);
|
||||
|
||||
if (pkt_node == NULL) {
|
||||
DEBUG("ndp: could not add packet to packet queue\n");
|
||||
}
|
||||
else {
|
||||
/* prevent packet from being released by IPv6 */
|
||||
ng_pktbuf_hold(pkt_node->pkt, 1);
|
||||
ng_pktqueue_add(&nc_entry->pkts, pkt_node);
|
||||
}
|
||||
|
||||
/* address resolution */
|
||||
ng_ipv6_addr_set_solicited_nodes(&dst_sol, next_hop_ip);
|
||||
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
timex_t t = { 0, NG_NDP_RETRANS_TIMER };
|
||||
kernel_pid_t ifs[NG_NETIF_NUMOF];
|
||||
size_t ifnum = ng_netif_get(ifs);
|
||||
|
||||
for (size_t i = 0; i < ifnum; i++) {
|
||||
_send_nbr_sol(ifs[i], next_hop_ip, &dst_sol);
|
||||
}
|
||||
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
}
|
||||
else {
|
||||
ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(iface);
|
||||
|
||||
_send_nbr_sol(iface, next_hop_ip, &dst_sol);
|
||||
|
||||
mutex_lock(&ipv6_iface->mutex);
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer,
|
||||
ipv6_iface->retrans_timer, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
mutex_unlock(&ipv6_iface->mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return KERNEL_PID_UNDEF;
|
||||
}
|
||||
|
||||
ng_pktsnip_t *ng_ndp_nbr_sol_build(ng_ipv6_addr_t *tgt, ng_pktsnip_t *options)
|
||||
{
|
||||
ng_pktsnip_t *pkt;
|
||||
@ -631,199 +429,6 @@ ng_pktsnip_t *ng_ndp_opt_build(uint8_t type, size_t size, ng_pktsnip_t *next)
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static uint16_t _get_l2src(uint8_t *l2src, size_t l2src_size, kernel_pid_t iface)
|
||||
{
|
||||
bool try_long = false;
|
||||
int res;
|
||||
uint16_t l2src_len;
|
||||
/* maximum address length that fits into a minimum length (8) S/TL2A option */
|
||||
const uint16_t max_short_len = 6;
|
||||
|
||||
/* try getting source address */
|
||||
if ((ng_netapi_get(iface, NETOPT_SRC_LEN, 0, &l2src_len,
|
||||
sizeof(l2src_len)) >= 0) &&
|
||||
(l2src_len > max_short_len)) {
|
||||
try_long = true;
|
||||
}
|
||||
|
||||
if (try_long && ((res = ng_netapi_get(iface, NETOPT_ADDRESS_LONG, 0,
|
||||
l2src, l2src_size)) > max_short_len)) {
|
||||
l2src_len = (uint16_t)res;
|
||||
}
|
||||
else if ((res = ng_netapi_get(iface, NETOPT_ADDRESS, 0, l2src,
|
||||
l2src_size)) >= 0) {
|
||||
l2src_len = (uint16_t)res;
|
||||
}
|
||||
else {
|
||||
DEBUG("ndp: no link-layer address found.\n");
|
||||
l2src_len = 0;
|
||||
}
|
||||
|
||||
return l2src_len;
|
||||
}
|
||||
|
||||
static void _send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst)
|
||||
{
|
||||
ng_pktsnip_t *hdr, *pkt = NULL;
|
||||
ng_ipv6_addr_t *src = NULL;
|
||||
size_t src_len = 0;
|
||||
|
||||
DEBUG("ndp: send neighbor solicitation (iface: %" PRIkernel_pid ", tgt: %s, ",
|
||||
iface, ng_ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str)));
|
||||
DEBUG("dst: %s)\n", ng_ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
|
||||
|
||||
/* check if there is a fitting source address to target */
|
||||
if ((src = ng_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) {
|
||||
uint8_t l2src[8];
|
||||
uint16_t l2src_len;
|
||||
src_len = sizeof(ng_ipv6_addr_t);
|
||||
l2src_len = _get_l2src(l2src, sizeof(l2src), iface);
|
||||
|
||||
if (l2src_len > 0) {
|
||||
/* add source address link-layer address option */
|
||||
pkt = ng_ndp_opt_sl2a_build(l2src, l2src_len, NULL);
|
||||
|
||||
if (pkt == NULL) {
|
||||
DEBUG("ndp: error allocating Source Link-layer address option.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hdr = ng_ndp_nbr_sol_build(tgt, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating Neighbor solicitation.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = hdr;
|
||||
hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)src, src_len, (uint8_t *)dst,
|
||||
sizeof(ng_ipv6_addr_t));
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating IPv6 header.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_ipv6_hdr_t *)hdr->data)->hl = 255;
|
||||
|
||||
pkt = hdr;
|
||||
/* add netif header for send interface specification */
|
||||
hdr = ng_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating netif header.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_netif_hdr_t *)hdr->data)->if_pid = iface;
|
||||
|
||||
LL_PREPEND(pkt, hdr);
|
||||
|
||||
ng_netapi_send(ng_ipv6_pid, pkt);
|
||||
}
|
||||
|
||||
static void _send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst, bool supply_tl2a)
|
||||
{
|
||||
ng_pktsnip_t *hdr, *pkt = NULL;
|
||||
uint8_t adv_flags = 0;
|
||||
|
||||
DEBUG("ndp: send neighbor advertisement (iface: %" PRIkernel_pid ", tgt: %s, ",
|
||||
iface, ng_ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str)));
|
||||
DEBUG("dst: %s, supply_tl2a: %d)\n",
|
||||
ng_ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), supply_tl2a);
|
||||
|
||||
if (ng_ipv6_netif_get(iface)->flags & NG_IPV6_NETIF_FLAGS_ROUTER) {
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_R;
|
||||
}
|
||||
|
||||
if (ng_ipv6_addr_is_unspecified(dst)) {
|
||||
ng_ipv6_addr_set_all_nodes_multicast(dst,
|
||||
NG_IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
|
||||
}
|
||||
else {
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_S;
|
||||
}
|
||||
|
||||
if (supply_tl2a) {
|
||||
uint8_t l2src[8];
|
||||
uint16_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);
|
||||
|
||||
if (l2src_len > 0) {
|
||||
/* add target address link-layer address option */
|
||||
pkt = ng_ndp_opt_tl2a_build(l2src, l2src_len, NULL);
|
||||
|
||||
if (pkt == NULL) {
|
||||
DEBUG("ndp: error allocating Target Link-layer address option.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: also check if the node provides proxy servies for tgt */
|
||||
if ((pkt != NULL) && !ng_ipv6_netif_addr_is_non_unicast(tgt)) {
|
||||
/* TL2A is not supplied and tgt is not anycast */
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_O;
|
||||
}
|
||||
|
||||
hdr = ng_ndp_nbr_adv_build(adv_flags, tgt, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating Neighbor advertisement.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = hdr;
|
||||
hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)dst,
|
||||
sizeof(ng_ipv6_addr_t));
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating IPv6 header.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_ipv6_hdr_t *)hdr->data)->hl = 255;
|
||||
|
||||
pkt = hdr;
|
||||
/* add netif header for send interface specification */
|
||||
hdr = ng_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating netif header.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_netif_hdr_t *)hdr->data)->if_pid = iface;
|
||||
|
||||
LL_PREPEND(pkt, hdr);
|
||||
|
||||
if (ng_ipv6_netif_addr_is_non_unicast(tgt)) {
|
||||
/* avoid collision for anycast addresses
|
||||
* (see https://tools.ietf.org/html/rfc4861#section-7.2.7) */
|
||||
timex_t delay = { _rand(0, NG_NDP_MAX_AC_TGT_DELAY), 0 };
|
||||
ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, tgt);
|
||||
DEBUG("ndp: delay neighbor advertisement for %" PRIu32 " sec.",
|
||||
delay.seconds);
|
||||
|
||||
/* nc_entry must be set so no need to check it */
|
||||
_send_delayed(&nc_entry->nbr_adv_timer, delay, pkt);
|
||||
}
|
||||
else {
|
||||
ng_netapi_send(ng_ipv6_pid, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
static inline ng_pktsnip_t *_opt_l2a_build(uint8_t type, const uint8_t *l2addr,
|
||||
uint8_t l2addr_len, ng_pktsnip_t *next)
|
||||
{
|
||||
@ -858,188 +463,6 @@ ng_pktsnip_t *ng_ndp_opt_tl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
|
||||
return _opt_l2a_build(NG_NDP_OPT_TL2A, l2addr, l2addr_len, next);
|
||||
}
|
||||
|
||||
/* internal functions */
|
||||
/* packet queue node allocation */
|
||||
static ng_pktqueue_t *_alloc_pkt_node(ng_pktsnip_t *pkt)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(_pkt_nodes) / sizeof(ng_pktqueue_t); i++) {
|
||||
if ((_pkt_nodes[i].pkt == NULL) && (_pkt_nodes[i].next == NULL)) {
|
||||
_pkt_nodes[i].pkt = pkt;
|
||||
|
||||
return &(_pkt_nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool _handle_sl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ng_ndp_opt_t *sl2a_opt)
|
||||
{
|
||||
ng_ipv6_nc_t *nc_entry = NULL;
|
||||
uint8_t sl2a_len = 0;
|
||||
uint8_t *sl2a = (uint8_t *)(sl2a_opt + 1);
|
||||
|
||||
if ((sl2a_opt->len == 0) || ng_ipv6_addr_is_unspecified(&ipv6->src)) {
|
||||
DEBUG("ndp: invalid source link-layer address option received\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (pkt) {
|
||||
if (pkt->type == NG_NETTYPE_NETIF) {
|
||||
ng_netif_hdr_t *hdr = pkt->data;
|
||||
sl2a_len = hdr->src_l2addr_len;
|
||||
break;
|
||||
}
|
||||
pkt = pkt->next;
|
||||
}
|
||||
|
||||
if (sl2a_len == 0) { /* in case there was no source address in l2 */
|
||||
sl2a_len = (sl2a_opt->len / 8) - sizeof(ng_ndp_opt_t);
|
||||
|
||||
/* ignore all zeroes at the end for length */
|
||||
for (; sl2a[sl2a_len - 1] == 0x00; sl2a_len--);
|
||||
}
|
||||
|
||||
DEBUG("ndp: received SL2A (link-layer address: %s)\n",
|
||||
ng_netif_addr_to_str(addr_str, sizeof(addr_str), sl2a, sl2a_len));
|
||||
|
||||
switch (icmpv6_type) {
|
||||
case NG_ICMPV6_NBR_SOL:
|
||||
nc_entry = ng_ipv6_nc_get(iface, &ipv6->src);
|
||||
|
||||
if (nc_entry != NULL) {
|
||||
if ((sl2a_len != nc_entry->l2_addr_len) ||
|
||||
(memcmp(sl2a, nc_entry->l2_addr, sl2a_len) != 0)) {
|
||||
/* if entry exists but l2 address differs: set */
|
||||
nc_entry->l2_addr_len = sl2a_len;
|
||||
memcpy(nc_entry->l2_addr, sl2a, sl2a_len);
|
||||
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ng_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len,
|
||||
NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
default: /* wrong encapsulating message: silently discard */
|
||||
DEBUG("ndp: silently discard sl2a_opt for ICMPv6 message type %"
|
||||
PRIu8 "\n", icmpv6_type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static int _handle_tl2a_opt(ng_pktsnip_t *pkt, ng_ipv6_hdr_t *ipv6,
|
||||
uint8_t icmpv6_type, ng_ndp_opt_t *tl2a_opt,
|
||||
uint8_t *l2addr)
|
||||
{
|
||||
uint8_t tl2a_len = 0;
|
||||
uint8_t *tl2a = (uint8_t *)(tl2a_opt + 1);
|
||||
|
||||
if ((tl2a_opt->len == 0) || ng_ipv6_addr_is_unspecified(&ipv6->src)) {
|
||||
DEBUG("ndp: invalid target link-layer address option received\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (icmpv6_type) {
|
||||
case NG_ICMPV6_NBR_ADV:
|
||||
while (pkt) {
|
||||
if (pkt->type == NG_NETTYPE_NETIF) {
|
||||
ng_netif_hdr_t *hdr = pkt->data;
|
||||
tl2a_len = hdr->src_l2addr_len;
|
||||
break;
|
||||
}
|
||||
pkt = pkt->next;
|
||||
}
|
||||
|
||||
if (tl2a_len == 0) { /* in case there was no source address in l2 */
|
||||
tl2a_len = (tl2a_opt->len / 8) - sizeof(ng_ndp_opt_t);
|
||||
|
||||
/* ignore all zeroes at the end for length */
|
||||
for (; tl2a[tl2a_len - 1] == 0x00; tl2a_len--);
|
||||
}
|
||||
|
||||
DEBUG("ndp: received TL2A (link-layer address: %s)\n",
|
||||
ng_netif_addr_to_str(addr_str, sizeof(addr_str), tl2a, tl2a_len));
|
||||
|
||||
memcpy(l2addr, tl2a, tl2a_len);
|
||||
|
||||
return (int)tl2a_len;
|
||||
|
||||
default: /* wrong encapsulating message: silently discard */
|
||||
DEBUG("ndp: silently discard tl2a_opt for ICMPv6 message type %"
|
||||
PRIu8 "\n", icmpv6_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void _set_state(ng_ipv6_nc_t *nc_entry, uint8_t state)
|
||||
{
|
||||
ng_ipv6_netif_t *ipv6_iface;
|
||||
timex_t t = { NG_NDP_FIRST_PROBE_DELAY, 0 };
|
||||
|
||||
nc_entry->flags &= ~NG_IPV6_NC_STATE_MASK;
|
||||
nc_entry->flags |= state;
|
||||
|
||||
DEBUG("ndp: set %s state to ",
|
||||
ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)));
|
||||
|
||||
switch (state) {
|
||||
case NG_IPV6_NC_STATE_REACHABLE:
|
||||
ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);
|
||||
DEBUG("REACHABLE (reachable time = %" PRIu32 ".%06" PRIu32 ")\n",
|
||||
ipv6_iface->reach_time.seconds,
|
||||
ipv6_iface->reach_time.microseconds);
|
||||
t = ipv6_iface->reach_time;
|
||||
/* we intentionally fall through here to set the desired timeout t */
|
||||
case NG_IPV6_NC_STATE_DELAY:
|
||||
#if ENABLE_DEBUG
|
||||
if (state == NG_IPV6_NC_STATE_DELAY) {
|
||||
DEBUG("DELAY (probe with unicast NS in %u seconds)\n",
|
||||
NG_NDP_FIRST_PROBE_DELAY);
|
||||
}
|
||||
#endif
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NC_STATE_TIMEOUT, nc_entry);
|
||||
break;
|
||||
|
||||
case NG_IPV6_NC_STATE_PROBE:
|
||||
ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);
|
||||
|
||||
nc_entry->probes_remaining = NG_NDP_MAX_UC_NBR_SOL_NUMOF;
|
||||
DEBUG("PROBE (probe with %" PRIu8 " unicast NS every %" PRIu32
|
||||
".%06" PRIu32 " seconds)\n", nc_entry->probes_remaining,
|
||||
ipv6_iface->retrans_timer.seconds,
|
||||
ipv6_iface->retrans_timer.microseconds);
|
||||
|
||||
_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr,
|
||||
&nc_entry->ipv6_addr);
|
||||
|
||||
mutex_lock(&ipv6_iface->mutex);
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer,
|
||||
ipv6_iface->retrans_timer, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
mutex_unlock(&ipv6_iface->mutex);
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
case NG_IPV6_NC_STATE_STALE:
|
||||
DEBUG("STALE (go into DELAY on next packet)\n");
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
DEBUG("errorneous or unknown\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
3
sys/net/network_layer/ng_ndp/node/Makefile
Normal file
3
sys/net/network_layer/ng_ndp/node/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = ng_ndp_node
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
194
sys/net/network_layer/ng_ndp/node/ng_ndp_node.c
Normal file
194
sys/net/network_layer/ng_ndp/node/ng_ndp_node.c
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "kernel_types.h"
|
||||
#include "net/fib.h"
|
||||
#include "net/ng_ipv6.h"
|
||||
#include "net/ng_ndp.h"
|
||||
#include "net/ng_pkt.h"
|
||||
#include "net/ng_pktqueue.h"
|
||||
|
||||
#include "net/ng_ndp/internal.h"
|
||||
|
||||
#include "net/ng_ndp/node.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
static ng_pktqueue_t _pkt_nodes[NG_IPV6_NC_SIZE * 2];
|
||||
|
||||
/**
|
||||
* @brief Allocates a node for the packet queue.
|
||||
*
|
||||
* @param[in] pkt Packet to add to the packet queue.
|
||||
*
|
||||
* @return A packet queue node.
|
||||
*/
|
||||
static ng_pktqueue_t *_alloc_pkt_node(ng_pktsnip_t *pkt)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(_pkt_nodes) / sizeof(ng_pktqueue_t); i++) {
|
||||
if ((_pkt_nodes[i].pkt == NULL) && (_pkt_nodes[i].next == NULL)) {
|
||||
_pkt_nodes[i].pkt = pkt;
|
||||
|
||||
return &(_pkt_nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kernel_pid_t ng_ndp_node_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
kernel_pid_t iface, ng_ipv6_addr_t *dst,
|
||||
ng_pktsnip_t *pkt)
|
||||
{
|
||||
ng_ipv6_addr_t *next_hop_ip = NULL, *prefix = NULL;
|
||||
|
||||
#ifdef MODULE_NG_IPV6_EXT_RH
|
||||
next_hop_ip = ng_ipv6_ext_rh_next_hop(hdr);
|
||||
#endif
|
||||
#ifdef MODULE_FIB
|
||||
size_t next_hop_size;
|
||||
uint32_t next_hop_flags = 0;
|
||||
ng_ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */
|
||||
|
||||
if ((next_hop_ip == NULL) &&
|
||||
(fib_get_next_hop(&iface, next_hop_actual.u8, &next_hop_size,
|
||||
&next_hop_flags, (uint8_t *)dst,
|
||||
sizeof(ng_ipv6_addr_t), 0) >= 0) &&
|
||||
(next_hop_size == sizeof(ng_ipv6_addr_t))) {
|
||||
next_hop_ip = &next_hop_actual;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ((next_hop_ip == NULL)) { /* no route to host */
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
/* ng_ipv6_netif_t doubles as prefix list */
|
||||
iface = ng_ipv6_netif_find_by_prefix(&prefix, dst);
|
||||
}
|
||||
else {
|
||||
/* ng_ipv6_netif_t doubles as prefix list */
|
||||
prefix = ng_ipv6_netif_match_prefix(iface, dst);
|
||||
}
|
||||
|
||||
if ((prefix != NULL) && /* prefix is on-link */
|
||||
(ng_ipv6_netif_addr_get(prefix)->flags &
|
||||
NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK)) {
|
||||
next_hop_ip = dst;
|
||||
#ifdef MODULE_FIB
|
||||
/* We don't care if FIB is full, this is just for efficiency
|
||||
* for later sends */
|
||||
fib_add_entry(iface, (uint8_t *)dst, sizeof(ng_ipv6_addr_t), 0,
|
||||
(uint8_t *)next_hop_ip, sizeof(ng_ipv6_addr_t), 0,
|
||||
FIB_LIFETIME_NO_EXPIRE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (next_hop_ip == NULL) {
|
||||
next_hop_ip = ng_ndp_internal_default_router();
|
||||
#ifdef MODULE_FIB
|
||||
/* We don't care if FIB is full, this is just for efficiency for later
|
||||
* sends */
|
||||
fib_add_entry(iface, (uint8_t *)dst, sizeof(ng_ipv6_addr_t), 0,
|
||||
(uint8_t *)next_hop_ip, sizeof(ng_ipv6_addr_t), 0,
|
||||
FIB_LIFETIME_NO_EXPIRE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (next_hop_ip != NULL) {
|
||||
ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, next_hop_ip);
|
||||
|
||||
if ((nc_entry != NULL) && ng_ipv6_nc_is_reachable(nc_entry)) {
|
||||
DEBUG("ndp node: found reachable neighbor (%s => ",
|
||||
ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)));
|
||||
DEBUG("%s)\n",
|
||||
ng_netif_addr_to_str(addr_str, sizeof(addr_str),
|
||||
nc_entry->l2_addr, nc_entry->l2_addr_len));
|
||||
|
||||
if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_STALE) {
|
||||
ng_ndp_internal_set_state(nc_entry, NG_IPV6_NC_STATE_DELAY);
|
||||
}
|
||||
|
||||
memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len);
|
||||
*l2addr_len = nc_entry->l2_addr_len;
|
||||
/* TODO: unreachability check */
|
||||
return nc_entry->iface;
|
||||
}
|
||||
else if (nc_entry == NULL) {
|
||||
ng_pktqueue_t *pkt_node;
|
||||
ng_ipv6_addr_t dst_sol;
|
||||
|
||||
nc_entry = ng_ipv6_nc_add(iface, next_hop_ip, NULL, 0,
|
||||
NG_IPV6_NC_STATE_INCOMPLETE << NG_IPV6_NC_STATE_POS);
|
||||
|
||||
if (nc_entry == NULL) {
|
||||
DEBUG("ndp node: could not create neighbor cache entry\n");
|
||||
return KERNEL_PID_UNDEF;
|
||||
}
|
||||
|
||||
pkt_node = _alloc_pkt_node(pkt);
|
||||
|
||||
if (pkt_node == NULL) {
|
||||
DEBUG("ndp node: could not add packet to packet queue\n");
|
||||
}
|
||||
else {
|
||||
/* prevent packet from being released by IPv6 */
|
||||
ng_pktbuf_hold(pkt_node->pkt, 1);
|
||||
ng_pktqueue_add(&nc_entry->pkts, pkt_node);
|
||||
}
|
||||
|
||||
/* address resolution */
|
||||
ng_ipv6_addr_set_solicited_nodes(&dst_sol, next_hop_ip);
|
||||
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
timex_t t = { 0, NG_NDP_RETRANS_TIMER };
|
||||
kernel_pid_t ifs[NG_NETIF_NUMOF];
|
||||
size_t ifnum = ng_netif_get(ifs);
|
||||
|
||||
for (size_t i = 0; i < ifnum; i++) {
|
||||
ng_ndp_internal_send_nbr_sol(ifs[i], next_hop_ip, &dst_sol);
|
||||
}
|
||||
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
}
|
||||
else {
|
||||
ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(iface);
|
||||
|
||||
ng_ndp_internal_send_nbr_sol(iface, next_hop_ip, &dst_sol);
|
||||
|
||||
mutex_lock(&ipv6_iface->mutex);
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer,
|
||||
ipv6_iface->retrans_timer, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
mutex_unlock(&ipv6_iface->mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return KERNEL_PID_UNDEF;
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
Loading…
x
Reference in New Issue
Block a user