Merge pull request #3749 from authmillenon/gnrc_sixlowpan_nd_router/feat/initial

gnrc_sixlowpan_nd_router: initial import of router behavior of 6LoWPAN-ND
dev/timer
Oleg Hahm 8 years ago
commit 8b16f3ef06

@ -39,13 +39,13 @@ ifneq (,$(filter ieee802154,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan
endif
ifneq (,$(filter gnrc_ipv6_router, $(USEMODULE)))
USEMODULE += gnrc_sixlowpan # TODO: replace with gnrc_sixlowpan_router
USEMODULE += gnrc_sixlowpan_router
endif
ifneq (,$(filter gnrc_ipv6_default, $(USEMODULE)))
USEMODULE += gnrc_sixlowpan_default
endif
ifneq (,$(filter gnrc_ipv6_router_default, $(USEMODULE)))
USEMODULE += gnrc_sixlowpan_default # TODO: replace with gnrc_sixlowpan_router_default
USEMODULE += gnrc_sixlowpan_router_default
endif
endif
@ -57,6 +57,17 @@ ifneq (,$(filter gnrc_sixlowpan_default,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan_iphc
endif
ifneq (,$(filter gnrc_sixlowpan_router_default,$(USEMODULE)))
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_sixlowpan_router
USEMODULE += gnrc_sixlowpan_frag
USEMODULE += gnrc_sixlowpan_iphc
endif
ifneq (,$(filter gnrc_sixlowpan_router,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan
endif
ifneq (,$(filter gnrc_sixlowpan_frag,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan
USEMODULE += vtimer
@ -78,6 +89,10 @@ ifneq (,$(filter gnrc_sixlowpan_ctx,$(USEMODULE)))
USEMODULE += vtimer
endif
ifneq (,$(filter gnrc_sixlowpan_nd_router,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan_nd
endif
ifneq (,$(filter gnrc_sixlowpan_nd,$(USEMODULE)))
USEMODULE += gnrc_ndp
USEMODULE += gnrc_ndp_internal
@ -101,7 +116,13 @@ endif
ifneq (,$(filter gnrc_ipv6_router_default,$(USEMODULE)))
USEMODULE += gnrc_ipv6_router
USEMODULE += gnrc_icmpv6
USEMODULE += gnrc_ndp_router
ifeq (1,$(GNRC_NETIF_NUMOF))
ifeq (,$(filter gnrc_sixlowpan_nd_router,$(USEMODULE)))
USEMODULE += gnrc_ndp_router
endif
else
USEMODULE += gnrc_ndp_router
endif
endif
ifneq (,$(filter gnrc_ndp_host,$(USEMODULE)))

@ -3,6 +3,8 @@ PSEUDOMODULES += gnrc_ipv6_default
PSEUDOMODULES += gnrc_ipv6_router
PSEUDOMODULES += gnrc_ipv6_router_default
PSEUDOMODULES += gnrc_sixlowpan_default
PSEUDOMODULES += gnrc_sixlowpan_router
PSEUDOMODULES += gnrc_sixlowpan_router_default
PSEUDOMODULES += gnrc_pktbuf
PSEUDOMODULES += ieee802154
PSEUDOMODULES += log

@ -2000,7 +2000,8 @@ PREDEFINED = DOXYGEN \
DEVELHELP \
ENABLE_DEBUG \
TEST_SUITES \
MODULE_GNRC_NDP_ROUTER
MODULE_GNRC_NDP_ROUTER \
MODULE_GNRC_SIXLOWPAN_ND_ROUTER
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this

@ -33,6 +33,8 @@
#include "net/sixlowpan/nd.h"
#include "timex.h"
#include "net/gnrc/sixlowpan/nd/router.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -52,6 +54,16 @@ extern "C" {
*/
#define GNRC_SIXLOWPAN_ND_MSG_DELETE_CTX (0x0222)
/**
* @brief Message type for authoritative border router timeout
*/
#define GNRC_SIXLOWPAN_ND_MSG_ABR_TIMEOUT (0x0223)
/**
* @brief Message type for address registration timeout
*/
#define GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT (0x0224)
#ifndef GNRC_SIXLOWPAN_ND_AR_LTIME
/**
* @brief Registration lifetime in minutes for the address registration option
@ -78,6 +90,28 @@ extern "C" {
#define GNRC_SIXLOWPAN_ND_MAX_RTR_SOL_INT (60U) /**< retransmission increment for exponential
* backoff of subsequent RS */
/** @} */
/**
* @name Router constants
* @{
* @see <a href="https://tools.ietf.org/html/rfc6775#section-9">
* RFC 6775, section 9
* </a>
*/
#define GNRC_SIXLOWPAN_ND_MIN_RTR_ADV_DELAY (10U) /**< replacement value (in seconds) for
* @ref GNRC_NDP_MIN_RTR_ADV_DELAY */
/**
* @brief replacement value (in microseconds) for @ref GNRC_NDP_MAX_RTR_ADV_DELAY
*/
#define GNRC_SIXLOWPAN_ND_MAX_RTR_ADV_DELAY (2U * SEC_IN_USEC)
/**
* @brief Lifetime of a tentative address entry in seconds
*/
#define GNRC_SIXLOWPAN_ND_TENTATIVE_NCE_LIFETIME (20U)
/**
* @brief 6LoWPAN Multihop Hoplimit
*/
#define GNRC_SIXLOWPAN_ND_MULTIHOP_HOPLIMIT (64U)
/** @} */
/**
* @brief Initializes 6LoWPAN neighbor discovery for the interface.
@ -182,6 +216,55 @@ bool gnrc_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, sixlowpan_nd_opt_6ct
*/
void gnrc_sixlowpan_nd_wakeup(void);
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
/**
* @brief Handles authoritative border router option.
*
* @param[in] iface Interface the source link-layer option was received
* on.
* @param[in] rtr_adv The router advertisement containing the ABRO.
* @param[in] icmpv6_size The size of the @p rtr_adv.
* @param[in] abr_opt The ABRO.
*
* @note Erroneous ABROs are always ignored silently.
*/
void gnrc_sixlowpan_nd_opt_abr_handle(kernel_pid_t iface, ndp_rtr_adv_t *rtr_adv, int icmpv6_size,
sixlowpan_nd_opt_abr_t *abr_opt);
/**
* @brief Builds the 6LoWPAN context option.
*
* @param[in] prefix_len The length of the context's prefix.
* @param[in] flags Flags + CID for the context.
* @param[in] ltime Lifetime of the context.
* @param[in] prefix The context's prefix
* @param[in] next More options in the packet. NULL, if there are none.
*
* @return The pkt snip list of options, on success
* @return NULL, if packet buffer is full or on error
*/
gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_6ctx_build(uint8_t prefix_len, uint8_t flags, uint16_t ltime,
ipv6_addr_t *prefix, gnrc_pktsnip_t *next);
/**
* @brief Builds the authoritative border router option.
*
* @param[in] version Version of the border router information.
* @param[in] ltime Registration lifetime for the border router.
* @param[in] braddr The IPv6 address of the border router.
* @param[in] next More options in the packet. NULL, if there are none.
*
* @return The pkt snip list of options, on success
* @return NULL, if packet buffer is full or on error
*/
gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_abr_build(uint32_t version, uint16_t ltime,
ipv6_addr_t *braddr, gnrc_pktsnip_t *next);
#else
#define gnrc_sixlowpan_nd_opt_abr_handle(iface, rtr_adv, icmpv6_size, abr_opt)
#define gnrc_sixlowpan_nd_opt_6ctx_build(prefix_len, flags, ltime, prefix, next) (NULL)
#define gnrc_sixlowpan_nd_opt_abr_build(version, ltime, braddr, next) (NULL)
#endif
#ifdef __cplusplus
}
#endif

@ -0,0 +1,164 @@
/*
* 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 gnrc_sixlowpan_nd_router Router-part of 6LoWPAN-ND
* @ingroup gnrc_sixlowpan_nd
* @brief Router-part of 6LoWPAN-ND
* @{
*
* @file
* @brief Router-definitions for 6LoWPAN-ND.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef GNRC_SIXLOWPAN_ND_ROUTER_H_
#define GNRC_SIXLOWPAN_ND_ROUTER_H_
#include <stdbool.h>
#include "bitfield.h"
#include "net/gnrc/sixlowpan/ctx.h"
#include "net/gnrc/ipv6/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Number of registerable border routers
*
* @note More than one border routers require some way of synchronization
* of the context information (see
* [RFC 6775, section 8.1](https://tools.ietf.org/html/rfc6775#section-8.1))
*/
#ifndef GNRC_SIXLOWPAN_ND_ROUTER_ABR_NUMOF
#define GNRC_SIXLOWPAN_ND_ROUTER_ABR_NUMOF (1)
#endif
/**
* @brief The number of non-link-local prefixes associated with border routers
* at maximum.
*/
#ifndef GNRC_SIXLOWPAN_ND_ROUTER_ABR_PRF_NUMOF
#define GNRC_SIXLOWPAN_ND_ROUTER_ABR_PRF_NUMOF (GNRC_SIXLOWPAN_ND_ROUTER_ABR_NUMOF)
#endif
/**
* @brief Representation for prefixes coming from a router
*/
typedef struct gnrc_sixlowpan_nd_router_prf {
struct gnrc_sixlowpan_nd_router_prf *next; /**< next prefix */
gnrc_ipv6_netif_t *iface; /**< interface the prefix is registered too */
gnrc_ipv6_netif_addr_t *prefix; /**< prefix on the interface/in the prefix list */
} gnrc_sixlowpan_nd_router_prf_t;
/**
* @brief Abstract representation of a border router on all (border) routers.
*/
typedef struct {
ipv6_addr_t addr; /**< the IPv6 address of the border router (BR) */
uint32_t version; /**< version of the information dissiminated by the
* BR */
uint16_t ltime; /**< the time in minutes until deletion */
BITFIELD(ctxs, GNRC_SIXLOWPAN_CTX_SIZE);/**< contexts associated with BR */
gnrc_sixlowpan_nd_router_prf_t *prfs; /**< prefixes associated with BR */
vtimer_t ltimer; /**< timer for deletion */
} gnrc_sixlowpan_nd_router_abr_t;
/**
* @brief Removes tentetative neighbor cache entries or sets registered ones to
* garbage-collectible.
*
* @param[in] nc_entry A neighbor cache entry.
*/
static inline void gnrc_sixlowpan_nd_router_gc_nc(gnrc_ipv6_nc_t *nc_entry)
{
switch (gnrc_ipv6_nc_get_type(nc_entry)) {
case GNRC_IPV6_NC_TYPE_TENTATIVE:
case GNRC_IPV6_NC_TYPE_REGISTERED:
gnrc_ipv6_nc_remove(nc_entry->iface, &nc_entry->ipv6_addr);
break;
default:
break;
}
}
/**
* @brief Set @p netif to router mode.
*
* @details This sets/unsets the GNRC_IPV6_NETIF_FLAGS_ROUTER and initializes or ceases router
* behavior for 6LoWPAN neighbor discovery.
*
* @param[in] netif An IPv6 interface. Must not be NULL.
* @param[in] enable Status for the GNRC_IPV6_NETIF_FLAGS_ROUTER flag.
*/
static inline void gnrc_sixlowpan_nd_router_set_router(gnrc_ipv6_netif_t *netif, bool enable)
{
if (enable) {
netif->flags |= GNRC_IPV6_NETIF_FLAGS_ROUTER;
}
else {
netif->flags &= ~GNRC_IPV6_NETIF_FLAGS_ROUTER;
}
}
/**
* @brief Set/Unset GNRC_IPV6_NETIF_FLAGS_RTR_ADV flag for @p netif.
*
* @details GNRC_IPV6_NETIF_FLAGS_RTR_ADV and initializes or ceases
* periodic router advertising behavior for neighbor discovery.
*
* @param[in] netif An IPv6 interface. Must not be NULL.
* @param[in] enable Status for the GNRC_IPV6_NETIF_FLAGS_RTR_ADV flag.
*/
static inline void gnrc_sixlowpan_nd_router_set_rtr_adv(gnrc_ipv6_netif_t *netif, bool enable)
{
if (enable) {
netif->flags |= GNRC_IPV6_NETIF_FLAGS_RTR_ADV;
}
else {
netif->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV;
}
}
/**
* @brief Get's the border router for this router.
*
* @return The border router, if one is specified.
* @return NULL, otherwise.
*/
gnrc_sixlowpan_nd_router_abr_t *gnrc_sixlowpan_nd_router_abr_get(void);
/**
* @brief Checks if the version data @p abr_opt is older than the version of the currently
* registered border router.
*
* @param[in] abr_opt An authoritative border router option containing potentially new
* information on the currently registered border router.
*
* @return true, if the information in @p abr_opt is newer.
* @return false, if the information in @p abr_opt is older.
*/
bool gnrc_sixlowpan_nd_router_abr_older(sixlowpan_nd_opt_abr_t *abr_opt);
/**
* @brief Removes the border router and all the prefixes and contexts it disseminated through
* the network for this node.
*
* @param[in] abr The border router.
*/
void gnrc_sixlowpan_nd_router_abr_remove(gnrc_sixlowpan_nd_router_abr_t *abr);
#ifdef __cplusplus
}
#endif
#endif /* GNRC_SIXLOWPAN_ND_ROUTER_H_ */
/** @} */

@ -82,6 +82,9 @@ endif
ifneq (,$(filter gnrc_sixlowpan_nd,$(USEMODULE)))
DIRS += network_layer/sixlowpan/nd
endif
ifneq (,$(filter gnrc_sixlowpan_nd_router,$(USEMODULE)))
DIRS += network_layer/sixlowpan/nd/router
endif
ifneq (,$(filter gnrc_sixlowpan_netif,$(USEMODULE)))
DIRS += network_layer/sixlowpan/netif
endif

@ -244,6 +244,17 @@ static void *_event_loop(void *args)
gnrc_sixlowpan_ctx_remove(((((gnrc_sixlowpan_ctx_t *)msg.content.ptr)->flags_id) &
GNRC_SIXLOWPAN_CTX_FLAGS_CID_MASK));
break;
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
case GNRC_SIXLOWPAN_ND_MSG_ABR_TIMEOUT:
DEBUG("ipv6: border router timeout event received\n");
gnrc_sixlowpan_nd_router_abr_remove(
(gnrc_sixlowpan_nd_router_abr_t *)msg.content.ptr);
break;
case GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT:
DEBUG("ipv6: address registration timeout received\n");
gnrc_sixlowpan_nd_router_gc_nc((gnrc_ipv6_nc_t *)msg.content.ptr);
break;
#endif
default:
break;

@ -116,7 +116,7 @@ static ipv6_addr_t *_add_addr_to_entry(gnrc_ipv6_netif_t *entry, const ipv6_addr
else {
tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK;
}
#if defined(MODULE_GNRC_NDP_NODE) || defined(MODULE_GNRC_SIXLOWPAN_ND)
#if defined(MODULE_GNRC_NDP_NODE) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER)
/* add solicited-nodes multicast address for new address if interface is not a
* 6LoWPAN host interface (see: https://tools.ietf.org/html/rfc6775#section-5.2) */
if (!(entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) ||
@ -235,14 +235,26 @@ gnrc_ipv6_netif_t *gnrc_ipv6_netif_get(kernel_pid_t pid)
return NULL;
}
#if defined(MODULE_GNRC_NDP_ROUTER)
#if defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER)
void gnrc_ipv6_netif_set_router(gnrc_ipv6_netif_t *netif, bool enable)
{
#if defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER)
if (netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
gnrc_sixlowpan_nd_router_set_router(netif, enable);
return;
}
#endif
gnrc_ndp_router_set_router(netif, enable);
}
void gnrc_ipv6_netif_set_rtr_adv(gnrc_ipv6_netif_t *netif, bool enable)
{
#if defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER)
if (netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
gnrc_sixlowpan_nd_router_set_rtr_adv(netif, enable);
return;
}
#endif
gnrc_ndp_router_set_rtr_adv(netif, enable);
}
#endif

@ -20,6 +20,7 @@
#include "byteorder.h"
#include "net/fib.h"
#include "net/ieee802154.h"
#include "net/ipv6/ext/rh.h"
#include "net/gnrc/icmpv6.h"
#include "net/gnrc/ipv6.h"
@ -53,6 +54,19 @@ static void _stale_nc(kernel_pid_t iface, ipv6_addr_t *ipaddr, uint8_t *l2addr,
if (l2addr_len != -ENOTSUP) {
gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, ipaddr);
if (nc_entry == NULL) {
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
/* tentative type see https://tools.ietf.org/html/rfc6775#section-6.3 */
gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
if ((ipv6_iface == NULL) || (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
timex_t t = { GNRC_SIXLOWPAN_ND_TENTATIVE_NCE_LIFETIME, 0 };
gnrc_ipv6_nc_add(iface, ipaddr, l2addr, (uint16_t)l2addr_len,
GNRC_IPV6_NC_STATE_STALE | GNRC_IPV6_NC_TYPE_TENTATIVE);
vtimer_remove(&nc_entry->type_timeout);
vtimer_set_msg(&nc_entry->type_timeout, t, gnrc_ipv6_pid,
GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT, nc_entry);
return;
}
#endif
gnrc_ipv6_nc_add(iface, ipaddr, l2addr, (uint16_t)l2addr_len,
GNRC_IPV6_NC_STATE_STALE);
}
@ -73,7 +87,12 @@ void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
uint16_t opt_offset = 0;
uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
uint8_t *buf = ((uint8_t *)nbr_sol) + sizeof(ndp_nbr_sol_t);
ipv6_addr_t *tgt;
ipv6_addr_t *tgt, nbr_adv_dst;
gnrc_pktsnip_t *nbr_adv_opts = NULL;
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
ndp_opt_t *sl2a_opt = NULL;
sixlowpan_nd_opt_ar_t *ar_opt = NULL;
#endif
int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
DEBUG("ndp: received neighbor solicitation (src: %s, ",
ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
@ -111,6 +130,13 @@ void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
* is invalid. */
return;
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
sl2a_opt = opt;
break;
case NDP_OPT_AR:
/* actually handling at the end of the function (see below) */
ar_opt = (sixlowpan_nd_opt_ar_t *)opt;
#endif
break;
default:
/* silently discard all other options */
@ -119,9 +145,38 @@ void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
opt_offset += (opt->len * 8);
sicmpv6_size -= (opt->len * 8);
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
assert(ipv6_iface != NULL);
if ((sl2a_opt != NULL) && (ar_opt != NULL) &&
(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
uint8_t status = gnrc_sixlowpan_nd_opt_ar_handle(iface, ipv6, nbr_sol->type, ar_opt,
l2src, l2src_len);
/* check for multihop DAD return */
nbr_adv_opts = gnrc_sixlowpan_nd_opt_ar_build(status, GNRC_SIXLOWPAN_ND_AR_LTIME,
&ar_opt->eui64, NULL);
if (status == 0) {
memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t));
}
else {
/* see https://tools.ietf.org/html/rfc6775#section-6.5.2 */
eui64_t iid;
ieee802154_get_iid(&iid, ar_opt->eui64.uint8, sizeof(eui64_t));
ipv6_addr_set_iid(&nbr_adv_dst, iid.uint64.u64);
ipv6_addr_set_link_local_prefix(&nbr_adv_dst);
}
}
else { /* gnrc_sixlowpan_nd_opt_ar_handle updates neighbor cache */
_stale_nc(iface, &ipv6->src, l2src, l2src_len);
memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t));
}
#else
_stale_nc(iface, &ipv6->src, l2src, l2src_len);
gnrc_ndp_internal_send_nbr_adv(iface, tgt, &ipv6->src, ipv6_addr_is_multicast(&ipv6->dst),
NULL);
memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t));
#endif
gnrc_ndp_internal_send_nbr_adv(iface, tgt, &nbr_adv_dst, ipv6_addr_is_multicast(&ipv6->dst),
nbr_adv_opts);
}
static inline bool _pkt_has_l2addr(gnrc_netif_hdr_t *netif_hdr)
@ -332,7 +387,14 @@ void gnrc_ndp_rtr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
_stale_nc(iface, &ipv6->src, l2src, l2src_len);
/* send delayed */
if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) {
timex_t delay = timex_set(0, genrand_uint32_range(0, GNRC_NDP_MAX_RTR_ADV_DELAY));
timex_t delay;
uint32_t ms = GNRC_NDP_MAX_RTR_ADV_DELAY;
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
ms = GNRC_SIXLOWPAN_ND_MAX_RTR_ADV_DELAY;
}
#endif
delay = timex_set(0, genrand_uint32_range(0, ms));
vtimer_remove(&if_entry->rtr_adv_timer);
if (ipv6_addr_is_unspecified(&ipv6->src)) {
/* either multicast, if source unspecified */
@ -477,8 +539,15 @@ void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t
}
break;
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
case NDP_OPT_ABR:
gnrc_sixlowpan_nd_opt_abr_handle(iface, rtr_adv, icmpv6_size,
(sixlowpan_nd_opt_abr_t *)opt);
break;
#endif
}
sicmpv6_size -= (opt->len * 8);
}
#if ENABLE_DEBUG && defined(MODULE_NG_SIXLOWPAN_ND)
if ((if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (l2src_len <= 0)) {
@ -552,6 +621,18 @@ void gnrc_ndp_retrans_nbr_sol(gnrc_ipv6_nc_t *nc_entry)
}
}
else if (nc_entry->probes_remaining <= 1) {
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
if (nc_entry->iface != KERNEL_PID_UNDEF) {
gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(nc_entry->iface);
if ((ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) &&
(gnrc_ipv6_nc_get_type(nc_entry) != GNRC_IPV6_NC_TYPE_GC)) {
/* don't remove non-gc entrys on 6LRs:
* https://tools.ietf.org/html/rfc6775#section-6 */
return;
}
}
#endif
DEBUG("ndp: Remove nc entry %s for interface %" PRIkernel_pid "\n",
ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)),
nc_entry->iface);

@ -17,6 +17,7 @@
#include "net/eui64.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/ndp.h"
#include "net/gnrc/sixlowpan/ctx.h"
#include "net/gnrc/sixlowpan/nd.h"
#include "random.h"
#include "timex.h"
@ -395,6 +396,9 @@ void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src, ipv6_a
DEBUG("ndp internal: send router advertisement (iface: %" PRIkernel_pid ", dst: %s%s\n",
iface, ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), fin ? ", final" : "");
mutex_lock(&ipv6_iface->mutex);
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) {
#endif
hdr = _add_pios(ipv6_iface, pkt);
if (hdr == NULL) {
/* pkt already released in _add_pios */
@ -402,6 +406,51 @@ void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src, ipv6_a
return;
}
pkt = hdr;
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
}
else {
gnrc_sixlowpan_nd_router_abr_t *abr = gnrc_sixlowpan_nd_router_abr_get();
if (abr != NULL) {
gnrc_sixlowpan_nd_router_prf_t *prf = abr->prfs;
/* add prefixes from border router */
while (prf) {
if (_pio_from_iface_addr(&hdr, prf->prefix, pkt)) {
if (hdr != NULL) {
pkt = hdr;
}
else {
DEBUG("ndp rtr: error allocating PIO\n");
gnrc_pktbuf_release(pkt);
return;
}
}
prf = prf->next;
}
for (unsigned int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) {
gnrc_sixlowpan_ctx_t *ctx;
if (!bf_isset(abr->ctxs, i)) {
continue;
}
ctx = gnrc_sixlowpan_ctx_lookup_id(i);
hdr = gnrc_sixlowpan_nd_opt_6ctx_build(ctx->prefix_len, ctx->flags_id, ctx->ltime,
&ctx->prefix, pkt);
if (hdr == NULL) {
DEBUG("ndp rtr: error allocating 6CO\n");
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
}
hdr = gnrc_sixlowpan_nd_opt_abr_build(abr->version, abr->ltime, &abr->addr, pkt);
if (hdr == NULL) {
DEBUG("ndp internal: error allocating ABRO.\n");
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
}
}
#endif /* MODULE_GNRC_SIXLOWPAN_ND_ROUTER */
if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_MTU) {
if ((hdr = gnrc_ndp_opt_mtu_build(ipv6_iface->mtu, pkt)) == NULL) {
DEBUG("ndp rtr: no space left in packet buffer\n");

@ -79,6 +79,7 @@ void gnrc_ndp_router_retrans_rtr_adv(gnrc_ipv6_netif_t *iface)
void gnrc_ndp_router_send_rtr_adv(gnrc_ipv6_nc_t *neighbor)
{
gnrc_ipv6_netif_t *iface = gnrc_ipv6_netif_get(neighbor->iface);
/* TODO: send one router advertisement per ABR: https://tools.ietf.org/html/rfc6775#section-6.3 */
_send_rtr_adv(iface, &neighbor->ipv6_addr);
}

@ -132,6 +132,13 @@ kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_
next_hop = &next_hop_actual;
}
}
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
/* next hop determination: https://tools.ietf.org/html/rfc6775#section-6.5.4 */
nc_entry = gnrc_ipv6_nc_get(iface, dst);
if ((nc_entry != NULL) && (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_REGISTERED)) {
next_hop = dst;
}
#endif
/* next hop determination according to: https://tools.ietf.org/html/rfc6775#section-5.6 */
if ((next_hop == NULL) && ipv6_addr_is_link_local(dst)) { /* prefix is "on-link" */
@ -143,6 +150,14 @@ kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_
}
/* address resolution of next_hop: https://tools.ietf.org/html/rfc6775#section-5.7 */
if ((nc_entry == NULL) || (next_hop != dst)) {
/* get if not gotten from previous check */
nc_entry = gnrc_ipv6_nc_get(iface, next_hop);
}
if ((nc_entry == NULL) || (!gnrc_ipv6_nc_is_reachable(nc_entry)) ||
(gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) {
return KERNEL_PID_UNDEF;
}
if (ipv6_addr_is_link_local(next_hop)) {
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
size_t ifnum = gnrc_netif_get(ifs);
@ -162,16 +177,12 @@ kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_
return iface;
}
else {
nc_entry = gnrc_ipv6_nc_get(iface, next_hop);
if ((nc_entry == NULL) || (!gnrc_ipv6_nc_is_reachable(nc_entry))) {
return KERNEL_PID_UNDEF;
}
if (nc_entry->l2_addr_len > 0) {
memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len);
}
*l2addr_len = nc_entry->l2_addr_len;
return nc_entry->iface;
}
return nc_entry->iface;
}
void gnrc_sixlowpan_nd_rtr_sol_reschedule(gnrc_ipv6_nc_t *nce, uint32_t sec_delay)
@ -206,6 +217,7 @@ uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, ui
eui64_t eui64;
gnrc_ipv6_netif_t *ipv6_iface;
gnrc_ipv6_nc_t *nc_entry;
uint8_t status = 0;
(void)sl2a;
(void)sl2a_len;
if (ar_opt->len != SIXLOWPAN_ND_OPT_AR_LEN) {
@ -254,11 +266,56 @@ uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, ui
DEBUG("6lo nd: unknown status for registration received\n");
break;
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
case ICMPV6_NBR_SOL:
if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
DEBUG("6lo nd: interface not a 6LoWPAN or forwarding interface\n");
return 0;
}
if ((ar_opt->status != 0) ||
ipv6_addr_is_unspecified(&ipv6->src)) {
/* discard silently */
return 0;
}
/* TODO multihop DAD */
if ((nc_entry != NULL) &&
((gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_REGISTERED) ||
(gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) &&
(ar_opt->eui64.uint64.u64 != nc_entry->eui64.uint64.u64)) {
/* there is already another node with this address */
DEBUG("6lo nd: duplicate address detected\n");
status = SIXLOWPAN_ND_STATUS_DUP;
}
else if ((nc_entry != NULL) && (ar_opt->ltime.u16 == 0)) {
gnrc_ipv6_nc_remove(iface, &ipv6->src);
/* TODO, notify routing protocol */
}
else if (ar_opt->ltime.u16 != 0) {
/* TODO: multihop DAD behavior */
uint16_t reg_ltime;
if (nc_entry == NULL) {
if ((nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len,
GNRC_IPV6_NC_STATE_STALE)) == NULL) {
DEBUG("6lo nd: neighbor cache is full\n");
return SIXLOWPAN_ND_STATUS_NC_FULL;
}
nc_entry->eui64 = ar_opt->eui64;
}
nc_entry->flags &= ~GNRC_IPV6_NC_TYPE_MASK;
nc_entry->flags |= GNRC_IPV6_NC_TYPE_REGISTERED;
reg_ltime = byteorder_ntohs(ar_opt->ltime);
/* TODO: notify routing protocol */
vtimer_remove(&nc_entry->type_timeout);
vtimer_set_msg(&nc_entry->type_timeout, timex_set(reg_ltime * 60, 0),
gnrc_ipv6_pid, GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT, nc_entry);
}
#endif
default:
break;
}
return 0;
return status;
}
bool gnrc_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, sixlowpan_nd_opt_6ctx_t *ctx_opt)
@ -293,4 +350,6 @@ void gnrc_sixlowpan_nd_wakeup(void)
}
}
/* gnrc_sixlowpan_nd_opt_abr_handle etc. implemented in gnrc_sixlowpan_nd_router */
/** @} */

@ -0,0 +1,3 @@
MODULE = gnrc_sixlowpan_nd_router
include $(RIOTBASE)/Makefile.base

@ -0,0 +1,245 @@
/*
* 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 "net/gnrc/ipv6.h"
#include "net/gnrc/ndp.h"
#include "net/gnrc/sixlowpan/ctx.h"
#include "net/gnrc/sixlowpan/nd.h"
#include "net/icmpv6.h"
#include "net/ndp.h"
#include "net/sixlowpan/nd.h"
#include "net/gnrc/sixlowpan/nd/router.h"
static gnrc_sixlowpan_nd_router_abr_t _abrs[GNRC_SIXLOWPAN_ND_ROUTER_ABR_NUMOF];
static gnrc_sixlowpan_nd_router_prf_t _prefixes[GNRC_SIXLOWPAN_ND_ROUTER_ABR_PRF_NUMOF];
static gnrc_sixlowpan_nd_router_abr_t *_get_abr(ipv6_addr_t *addr)
{
gnrc_sixlowpan_nd_router_abr_t *abr = NULL;
for (int i = 0; i < GNRC_SIXLOWPAN_ND_ROUTER_ABR_NUMOF; i++) {
if (ipv6_addr_equal(&_abrs[i].addr, addr)) {
return &_abrs[i];
}
if ((abr == NULL) && ipv6_addr_is_unspecified(&_abrs[i].addr)) {
abr = &_abrs[i];
}
}
return abr;
}
static gnrc_sixlowpan_nd_router_prf_t *_get_free_prefix(ipv6_addr_t *prefix, size_t prefix_len)
{
gnrc_sixlowpan_nd_router_prf_t *prf = NULL;
for (int i = 0; i < GNRC_SIXLOWPAN_ND_ROUTER_ABR_NUMOF; i++) {
if ((ipv6_addr_match_prefix(&_prefixes[i].prefix->addr, prefix) >= prefix_len) &&
(_prefixes[i].prefix->prefix_len == prefix_len)) {
return &_prefixes[i];
}
if ((prf == NULL) && ipv6_addr_is_unspecified(&_prefixes[i].prefix->addr)) {
prf = &_prefixes[i];
}
}
return prf;
}
static void _add_prefix(kernel_pid_t iface, gnrc_sixlowpan_nd_router_abr_t *abr,
ndp_opt_pi_t *pi_opt)
{
gnrc_sixlowpan_nd_router_prf_t *prf_ent;
gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
ipv6_addr_t *prefix;
if ((pi_opt->len != NDP_OPT_PI_LEN) || ipv6_addr_is_link_local(&pi_opt->prefix) ||
(pi_opt->flags & NDP_OPT_PI_FLAGS_A) ||
(pi_opt->flags & NDP_OPT_PI_FLAGS_L) ||
(pi_opt->valid_ltime.u32 == 0)) {
return;
}
prefix = gnrc_ipv6_netif_match_prefix(iface, &pi_opt->prefix);
prf_ent = _get_free_prefix(&pi_opt->prefix, pi_opt->prefix_len);
if (prf_ent != NULL) {
prf_ent->iface = ipv6_iface;
prf_ent->prefix = container_of(prefix, gnrc_ipv6_netif_addr_t, addr);
}
LL_PREPEND(abr->prfs, prf_ent);
}
static void _add_ctx(gnrc_sixlowpan_nd_router_abr_t *abr, sixlowpan_nd_opt_6ctx_t *ctx_opt)
{
if (((ctx_opt->ctx_len < 64) && (ctx_opt->len != 2)) ||
((ctx_opt->ctx_len >= 64) && (ctx_opt->len != 3))) {
return;
}
bf_set(abr->ctxs, sixlowpan_nd_opt_6ctx_get_cid(ctx_opt));
}
gnrc_sixlowpan_nd_router_abr_t *gnrc_sixlowpan_nd_router_abr_get(void)
{
if (ipv6_addr_is_unspecified(&_abrs[0].addr)) {
return NULL;
}
return _abrs;
}
bool gnrc_sixlowpan_nd_router_abr_older(sixlowpan_nd_opt_abr_t *abr_opt)
{
gnrc_sixlowpan_nd_router_abr_t *abr;
uint32_t version;
if (abr_opt->len != SIXLOWPAN_ND_OPT_ABR_LEN) {
/* invalid option received */
return true;
}
abr = _get_abr(&abr_opt->braddr);
if (abr == NULL) {
return false;
}
version = byteorder_ntohs(abr_opt->vlow);
version |= byteorder_ntohs(abr_opt->vhigh) << 16;
return (version < abr->version);
}
void gnrc_sixlowpan_nd_router_abr_remove(gnrc_sixlowpan_nd_router_abr_t *abr)
{
for (int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) {
if (bf_isset(abr->ctxs, i)) {
gnrc_sixlowpan_ctx_remove(i);
bf_unset(abr->ctxs, i);
}
}
while (abr->prfs != NULL) {
gnrc_sixlowpan_nd_router_prf_t *prefix = abr->prfs;
LL_DELETE(abr->prfs, prefix);
gnrc_ipv6_netif_remove_addr(prefix->iface->pid, &prefix->prefix->addr);
prefix->next = NULL;
prefix->iface = NULL;
prefix->prefix = NULL;
}
ipv6_addr_set_unspecified(&abr->addr);
abr->version = 0;
}
/* router-only functions from net/gnrc/sixlowpan/nd.h */
void gnrc_sixlowpan_nd_opt_abr_handle(kernel_pid_t iface, ndp_rtr_adv_t *rtr_adv, int sicmpv6_size,
sixlowpan_nd_opt_abr_t *abr_opt)
{
uint16_t opt_offset = 0;
uint8_t *buf = (uint8_t *)(rtr_adv + 1);
gnrc_sixlowpan_nd_router_abr_t *abr;
timex_t t = { 0, 0 };
/* validity and version was checked in previously called
* gnrc_sixlowpan_nd_router_abr_older() */
abr = _get_abr(&abr_opt->braddr);
if (abr == NULL) {
return;
}
abr->ltime = byteorder_ntohs(abr_opt->ltime);
if (abr->ltime == 0) {
gnrc_sixlowpan_nd_router_abr_remove(abr);
return;
}
sicmpv6_size -= sizeof(ndp_rtr_adv_t);
while (sicmpv6_size > 0) {
ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
switch (opt->type) {
case NDP_OPT_PI:
_add_prefix(iface, abr, (ndp_opt_pi_t *)opt);
case NDP_OPT_6CTX:
_add_ctx(abr, (sixlowpan_nd_opt_6ctx_t *)opt);
default:
break;
}
opt_offset += (opt->len * 8);
sicmpv6_size -= (opt->len * 8);
}
abr->version = byteorder_ntohs(abr_opt->vlow);
abr->version |= byteorder_ntohs(abr_opt->vhigh) << 16;
abr->addr.u64[0] = abr_opt->braddr.u64[0];
abr->addr.u64[1] = abr_opt->braddr.u64[1];
memset(abr->ctxs, 0, sizeof(abr->ctxs));
abr->prfs = NULL;
t.seconds = abr->ltime * 60;
vtimer_set_msg(&abr->ltimer, t, gnrc_ipv6_pid,
GNRC_SIXLOWPAN_ND_MSG_ABR_TIMEOUT, abr);
}
gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_6ctx_build(uint8_t prefix_len, uint8_t flags, uint16_t ltime,
ipv6_addr_t *prefix, gnrc_pktsnip_t *next)
{
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_6CTX,
sizeof(sixlowpan_nd_opt_6ctx_t) + (prefix_len / 8),
next);
if (pkt != NULL) {
sixlowpan_nd_opt_6ctx_t *ctx_opt = pkt->data;
ctx_opt->ctx_len = prefix_len;
ctx_opt->resv_c_cid = flags;
ctx_opt->resv.u16 = 0;
ctx_opt->ltime = byteorder_htons(ltime);
/* Bits beyond prefix_len MUST be 0 */
memset(ctx_opt + 1, 0, pkt->size - sizeof(sixlowpan_nd_opt_6ctx_t));
ipv6_addr_init_prefix((ipv6_addr_t *)(ctx_opt + 1), prefix, prefix_len);
}
return pkt;
}
gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_abr_build(uint32_t version, uint16_t ltime,
ipv6_addr_t *braddr, gnrc_pktsnip_t *next)
{
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_ABR, sizeof(sixlowpan_nd_opt_abr_t), next);
if (pkt != NULL) {
sixlowpan_nd_opt_abr_t *abr_opt = pkt->data;
abr_opt->vlow = byteorder_htons(version & 0xffff);
abr_opt->vhigh = byteorder_htons(version >> 16);
abr_opt->ltime = byteorder_htons(ltime);
abr_opt->braddr.u64[0] = braddr->u64[0];
abr_opt->braddr.u64[1] = braddr->u64[1];
}
return pkt;
}
/** @} */
Loading…
Cancel
Save