
9 changed files with 591 additions and 10 deletions
@ -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