Merge pull request #3749 from authmillenon/gnrc_sixlowpan_nd_router/feat/initial
gnrc_sixlowpan_nd_router: initial import of router behavior of 6LoWPAN-NDdev/timer
commit
8b16f3ef06
@ -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_ */
|
||||
/** @} */
|
@ -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…
Reference in New Issue