
5 changed files with 508 additions and 1 deletions
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_sixlowpan_nd 6LoWPAN neighbor discovery |
||||
* @ingroup net_gnrc_sixlowpan |
||||
* @brief Neighbor Discovery Optimization for 6LoWPAN |
||||
* @see <a href="https://tools.ietf.org/html/rfc6775"> |
||||
* RFC 6775 |
||||
* </a> |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief General 6LoWPAN ND definitions |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
#ifndef GNRC_SIXLOWPAN_ND_H_ |
||||
#define GNRC_SIXLOWPAN_ND_H_ |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "kernel_types.h" |
||||
#include "net/gnrc/ipv6/nc.h" |
||||
#include "net/gnrc/ipv6/netif.h" |
||||
#include "net/ipv6/addr.h" |
||||
#include "net/ndp.h" |
||||
#include "net/sixlowpan/nd.h" |
||||
#include "timex.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Message type for next multicast router solicitation. |
||||
*/ |
||||
#define GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL (0x0220) |
||||
|
||||
/**
|
||||
* @brief Message type for next unicast router solicitation. |
||||
*/ |
||||
#define GNRC_SIXLOWPAN_ND_MSG_UC_RTR_SOL (0x0221) |
||||
|
||||
/**
|
||||
* @brief Message type for removing 6LoWPAN contexts. |
||||
*/ |
||||
#define GNRC_SIXLOWPAN_ND_MSG_DELETE_CTX (0x0222) |
||||
|
||||
#ifndef GNRC_SIXLOWPAN_ND_AR_LTIME |
||||
/**
|
||||
* @brief Registration lifetime in minutes for the address registration option |
||||
* |
||||
* This value should be adapted to the devices power-lifecycle so that it is greater than the |
||||
* time the device spends sleeping. |
||||
* |
||||
* @see <a href="https://tools.ietf.org/html/rfc6775#section-5.8.1"> |
||||
* RFC 6775, section 5.8.1 |
||||
* </a> |
||||
*/ |
||||
#define GNRC_SIXLOWPAN_ND_AR_LTIME (15U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @name Host constants |
||||
* @{ |
||||
* @see <a href="https://tools.ietf.org/html/rfc6775#section-9"> |
||||
* RFC 6775, section 9 |
||||
* </a> |
||||
*/ |
||||
#define GNRC_SIXLOWPAN_ND_RTR_SOL_INT (10U) /**< replacement value (in seconds) for |
||||
* @ref GNRC_NDP_MAX_RTR_SOL_INT */ |
||||
#define GNRC_SIXLOWPAN_ND_MAX_RTR_SOL_INT (60U) /**< retransmission increment for exponential |
||||
* backoff of subsequent RS */ |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Initializes 6LoWPAN neighbor discovery for the interface. |
||||
* @pre @p iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN |
||||
* @param[in] iface An IPv6 interface. |
||||
*/ |
||||
void gnrc_sixlowpan_nd_init(gnrc_ipv6_netif_t *iface); |
||||
|
||||
/**
|
||||
* @brief Multicasts a router solicitation over @p iface |
||||
* @pre @p iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN |
||||
* @param[in] iface An IPv6 interface. |
||||
*/ |
||||
void gnrc_sixlowpan_nd_mc_rtr_sol(gnrc_ipv6_netif_t *iface); |
||||
|
||||
/**
|
||||
* @brief Unicasts a router solicitation to the neighbor represented by @p nce |
||||
* @pre @p nce->iface is an IPv6 interface and @ref GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN is set |
||||
* in its flags. |
||||
* @param[in] nce The neighbor to send the router solicitation to. |
||||
*/ |
||||
void gnrc_sixlowpan_nd_uc_rtr_sol(gnrc_ipv6_nc_t *nce); |
||||
|
||||
/**
|
||||
* @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. |
||||
* |
||||
* @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 gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, |
||||
kernel_pid_t iface, ipv6_addr_t *dst); |
||||
|
||||
/**
|
||||
* @brief Reschedules the next router advertisement for a neighboring router. |
||||
* |
||||
* @pre nce != NULL && sec_delay != 0U |
||||
* |
||||
* @param[in] nce Neighbor cache entry representing the neighboring router. |
||||
* @param[in] sec_delay The delay for the next router solicitation in seconds. |
||||
*/ |
||||
void gnrc_sixlowpan_nd_rtr_sol_reschedule(gnrc_ipv6_nc_t *nce, uint32_t sec_delay); |
||||
|
||||
/**
|
||||
* @brief Builds the address registration option. |
||||
* |
||||
* @param[in] status Status for the ARO. |
||||
* @param[in] ltime Registration lifetime for the ARO. |
||||
* @param[in] eui64 The EUI-64 for the ARO |
||||
* @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 |
||||
*/ |
||||
gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_ar_build(uint8_t status, uint16_t ltime, eui64_t *eui64, |
||||
gnrc_pktsnip_t *next); |
||||
|
||||
/**
|
||||
* @brief Handles address registration option. |
||||
* |
||||
* @param[in] iface The interface the ARO was received on. |
||||
* @param[in] ipv6 The IPv6 header the ARO was received in. |
||||
* @param[in] icmpv6_type Message type of the ICMPv6 message that contained. |
||||
* this message. |
||||
* @param[in] ar_opt The address registration option. |
||||
* @param[in] sl2a The link-layer source address contained in SL2A accompanying this |
||||
* option. May be NULL for icmpv6_type == ICMPV6_NBR_ADV. |
||||
* @param[in] sl2a_len Length of @p sl2a. May be 0 if sl2a == NULL. |
||||
* |
||||
* @return Status for the ARO in the replying NA (always 0 if icmpv6_type == ICMPV6_NBR_ADV). |
||||
*/ |
||||
uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, |
||||
uint8_t icmpv6_type, sixlowpan_nd_opt_ar_t *ar_opt, |
||||
uint8_t *sl2a, size_t sl2a_len); |
||||
|
||||
/**
|
||||
* @brief Handles 6LoWPAN context option. |
||||
* |
||||
* @param[in] icmpv6_type Message type of the ICMPv6 message that contained. |
||||
* this message. |
||||
* @param[in] ctx_opt The 6LoWPAN context option. |
||||
* |
||||
* @return true, when 6LoWPAN context option was correct. |
||||
* @return false, when it was incorrect. |
||||
*/ |
||||
bool gnrc_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, sixlowpan_nd_opt_6ctx_t *ctx_opt); |
||||
|
||||
/**
|
||||
* @brief Handles registration calls after node-wakeup. |
||||
* |
||||
* @see <a href="https://tools.ietf.org/html/rfc6775#section-5.8.2"> |
||||
* RFC 6776, section 5.8.2 |
||||
* </a> |
||||
*/ |
||||
void gnrc_sixlowpan_nd_wakeup(void); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* GNRC_SIXLOWPAN_ND_H_ */ |
||||
/** @} */ |
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_sixlowpan_nd
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,296 @@
|
||||
/*
|
||||
* 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/eui64.h" |
||||
#include "net/gnrc/ipv6.h" |
||||
#include "net/gnrc/ndp.h" |
||||
#include "net/gnrc/ndp/internal.h" |
||||
#include "net/gnrc/netif.h" |
||||
#include "net/gnrc/sixlowpan.h" |
||||
#include "net/gnrc/sixlowpan/ctx.h" |
||||
#include "random.h" |
||||
#include "timex.h" |
||||
|
||||
#include "net/gnrc/sixlowpan/nd.h" |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
static inline void _rtr_sol_reschedule(gnrc_ipv6_netif_t *iface, uint32_t sec_delay) |
||||
{ |
||||
vtimer_remove(&iface->rtr_sol_timer); |
||||
vtimer_set_msg(&iface->rtr_sol_timer, timex_set(sec_delay, 0), gnrc_ipv6_pid, |
||||
GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL, iface); |
||||
} |
||||
|
||||
static inline uint32_t _binary_exp_backoff(uint32_t base_sec, unsigned int exp) |
||||
{ |
||||
return genrand_uint32_range(0, (1 << exp) - 1) * base_sec; |
||||
} |
||||
|
||||
static inline void _revert_iid(uint8_t *iid) |
||||
{ |
||||
iid[0] ^= 0x02; |
||||
} |
||||
|
||||
void gnrc_sixlowpan_nd_init(gnrc_ipv6_netif_t *iface) |
||||
{ |
||||
assert(iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN); |
||||
mutex_lock(&iface->mutex); |
||||
iface->rtr_sol_count = 0; /* first will be send immediately */ |
||||
|
||||
DEBUG("6lo nd: retransmit multicast rtr sol in 10 sec\n"); |
||||
_rtr_sol_reschedule(iface, GNRC_SIXLOWPAN_ND_RTR_SOL_INT); |
||||
mutex_unlock(&iface->mutex); |
||||
gnrc_ndp_internal_send_rtr_sol(iface->pid, NULL); |
||||
} |
||||
|
||||
void gnrc_sixlowpan_nd_mc_rtr_sol(gnrc_ipv6_netif_t *iface) |
||||
{ |
||||
uint32_t interval; |
||||
assert(iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN); |
||||
mutex_lock(&iface->mutex); |
||||
if (iface->rtr_sol_count < GNRC_NDP_MAX_RTR_SOL_NUMOF) { |
||||
DEBUG("6lo nd: retransmit multicast rtr sol in 10 sec\n"); |
||||
iface->rtr_sol_count++; |
||||
interval = GNRC_SIXLOWPAN_ND_RTR_SOL_INT; |
||||
} |
||||
else { |
||||
unsigned int exp = (unsigned int)(iface->rtr_sol_count - GNRC_NDP_MAX_RTR_SOL_NUMOF); |
||||
interval = _binary_exp_backoff(1, exp); |
||||
if (((1U << exp) - 1U) < GNRC_SIXLOWPAN_ND_MAX_RTR_SOL_INT) { |
||||
/* XXX Not sure if this is the correct interpretation of the truncation described in
|
||||
* https://tools.ietf.org/html/rfc6775#section-5.3. In every source I've read the
|
||||
* truncating value was the exponent, not the target value, so I'm very confused |
||||
* about this sentencing. Anyway, since 60 sec is a maximum value this should only |
||||
* affect the energy consumption of the implementation by sending the next RS too fast |
||||
* but not its interoperability. */ |
||||
iface->rtr_sol_count++; |
||||
} |
||||
|
||||
DEBUG("6lo nd: retransmit multicast rtr sol in %" PRIu32 " sec\n", interval); |
||||
iface->rtr_sol_count--; |
||||
} |
||||
_rtr_sol_reschedule(iface, interval); |
||||
mutex_unlock(&iface->mutex); |
||||
gnrc_ndp_internal_send_rtr_sol(iface->pid, NULL); |
||||
} |
||||
|
||||
void gnrc_sixlowpan_nd_uc_rtr_sol(gnrc_ipv6_nc_t *nce) |
||||
{ |
||||
assert(gnrc_ipv6_netif_get(nce->iface)->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN); |
||||
/* neighbor is not a router anymore */ |
||||
if (!(nce->flags & GNRC_IPV6_NC_IS_ROUTER) || ipv6_addr_is_unspecified(&nce->ipv6_addr)) { |
||||
/* and there are no routers anymore */ |
||||
if (gnrc_ipv6_nc_get_next_router(NULL) == NULL) { |
||||
/* start search for routers */ |
||||
gnrc_sixlowpan_nd_init(gnrc_ipv6_netif_get(nce->iface)); |
||||
} |
||||
/* otherwise ignore this call */ |
||||
return; |
||||
} |
||||
/* next RS is rescheduled by RA handle function */ |
||||
gnrc_ndp_internal_send_rtr_sol(nce->iface, &nce->ipv6_addr); |
||||
} |
||||
|
||||
kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, |
||||
kernel_pid_t iface, ipv6_addr_t *dst) |
||||
{ |
||||
ipv6_addr_t *next_hop = NULL; |
||||
gnrc_ipv6_nc_t *nc_entry = NULL; |
||||
|
||||
#ifdef MODULE_GNRC_IPV6_EXT_RH |
||||
ipv6_hdr_t *hdr; |
||||
gnrc_pktsnip_t *ipv6; |
||||
LL_SEARCH_SCALAR(pkt, ipv6, type, GNRC_NETTYPE_IPV6); |
||||
assert(ipv6); |
||||
hdr = ipv6->data; |
||||
next_hop = ipv6_ext_rh_next_hop(hdr); |
||||
#endif |
||||
#ifdef MODULE_FIB |
||||
ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */ |
||||
/* don't look-up link local addresses in FIB */ |
||||
if ((next_hop == NULL) && !ipv6_addr_is_link_local(dst)) { |
||||
size_t next_hop_size = sizeof(ipv6_addr_t); |
||||
uint32_t next_hop_flags = 0; |
||||
if ((next_hop == NULL) && |
||||
(fib_get_next_hop(&gnrc_ipv6_fib_table, &iface, next_hop_actual.u8, &next_hop_size, |
||||
&next_hop_flags, (uint8_t *)dst, |
||||
sizeof(ipv6_addr_t), 0) >= 0) && |
||||
(next_hop_size == sizeof(ipv6_addr_t))) { |
||||
next_hop = &next_hop_actual; |
||||
} |
||||
} |
||||
#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" */ |
||||
/* multicast is not handled here anyway so we don't need to check that */ |
||||
next_hop = dst; |
||||
} |
||||
else if (next_hop == NULL) { /* prefix is off-link */ |
||||
next_hop = gnrc_ndp_internal_default_router(); |
||||
} |
||||
|
||||
/* address resolution of next_hop: https://tools.ietf.org/html/rfc6775#section-5.7 */ |
||||
if (ipv6_addr_is_link_local(next_hop)) { |
||||
kernel_pid_t ifs[GNRC_NETIF_NUMOF]; |
||||
size_t ifnum = gnrc_netif_get(ifs); |
||||
/* we don't need address resolution, the EUI-64 is in next_hop's IID */ |
||||
*l2addr_len = sizeof(eui64_t); |
||||
memcpy(l2addr, &next_hop->u8[8], sizeof(eui64_t)); |
||||
_revert_iid(l2addr); |
||||
if (iface == KERNEL_PID_UNDEF) { |
||||
for (unsigned i = 0; i < ifnum; i++) { |
||||
gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(ifs[i]); |
||||
if ((ipv6_if != NULL) && (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { |
||||
/* always take the first 6LoWPAN interface we can find */ |
||||
return ifs[i]; |
||||
} |
||||
} |
||||
} |
||||
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; |
||||
} |
||||
} |
||||
|
||||
void gnrc_sixlowpan_nd_rtr_sol_reschedule(gnrc_ipv6_nc_t *nce, uint32_t sec_delay) |
||||
{ |
||||
assert(nce != NULL); |
||||
assert(sec_delay != 0U); |
||||
vtimer_remove(&nce->rtr_sol_timer); |
||||
vtimer_set_msg(&nce->rtr_sol_timer, timex_set(sec_delay, 0), gnrc_ipv6_pid, |
||||
GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL, nce); |
||||
} |
||||
|
||||
gnrc_pktsnip_t *gnrc_sixlowpan_nd_opt_ar_build(uint8_t status, uint16_t ltime, eui64_t *eui64, |
||||
gnrc_pktsnip_t *next) |
||||
{ |
||||
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_AR, sizeof(sixlowpan_nd_opt_ar_t), next); |
||||
|
||||
if (pkt != NULL) { |
||||
sixlowpan_nd_opt_ar_t *ar_opt = pkt->data; |
||||
ar_opt->status = status; |
||||
ar_opt->resv[0] = ar_opt->resv[1] = ar_opt->resv[2] = 0; |
||||
ar_opt->ltime = byteorder_htons(ltime); |
||||
memcpy(&ar_opt->eui64, eui64, sizeof(eui64_t)); |
||||
} |
||||
|
||||
return pkt; |
||||
} |
||||
|
||||
uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, uint8_t icmpv6_type, |
||||
sixlowpan_nd_opt_ar_t *ar_opt, uint8_t *sl2a, |
||||
size_t sl2a_len) |
||||
{ |
||||
eui64_t eui64; |
||||
gnrc_ipv6_netif_t *ipv6_iface; |
||||
gnrc_ipv6_nc_t *nc_entry; |
||||
(void)sl2a; |
||||
(void)sl2a_len; |
||||
if (ar_opt->len != SIXLOWPAN_ND_OPT_AR_LEN) { |
||||
/* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ |
||||
return 0; |
||||
} |
||||
if (gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, &eui64, |
||||
sizeof(eui64)) < 0) { |
||||
/* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ |
||||
return 0; |
||||
} |
||||
ipv6_iface = gnrc_ipv6_netif_get(iface); |
||||
nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src); |
||||
switch (icmpv6_type) { |
||||
case ICMPV6_NBR_ADV: |
||||
if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { |
||||
DEBUG("6lo nd: interface not a 6LoWPAN interface\n"); |
||||
return 0; |
||||
} |
||||
if (eui64.uint64.u64 != ar_opt->eui64.uint64.u64) { |
||||
/* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ |
||||
return 0; |
||||
} |
||||
switch (ar_opt->status) { |
||||
case SIXLOWPAN_ND_STATUS_SUCCESS: |
||||
DEBUG("6lo nd: address registration successful\n"); |
||||
mutex_lock(&ipv6_iface->mutex); |
||||
vtimer_remove(&nc_entry->nbr_sol_timer); |
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer, ipv6_iface->retrans_timer, |
||||
gnrc_ipv6_pid, GNRC_NDP_MSG_NBR_SOL_RETRANS, nc_entry); |
||||
mutex_unlock(&ipv6_iface->mutex); |
||||
break; |
||||
case SIXLOWPAN_ND_STATUS_DUP: |
||||
DEBUG("6lo nd: address registration determined duplicated\n"); |
||||
/* TODO: handle DAD failed case */ |
||||
gnrc_ipv6_netif_remove_addr(iface, &ipv6->dst); |
||||
/* address should not be used anymore */ |
||||
break; |
||||
case SIXLOWPAN_ND_STATUS_NC_FULL: |
||||
DEBUG("6lo nd: neighbor cache on router is full\n"); |
||||
gnrc_ipv6_nc_remove(iface, &ipv6->src); |
||||
/* try to find another router */ |
||||
gnrc_sixlowpan_nd_init(ipv6_iface); |
||||
break; |
||||
default: |
||||
DEBUG("6lo nd: unknown status for registration received\n"); |
||||
break; |
||||
} |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
bool gnrc_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, 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))) { |
||||
DEBUG("6lo nd: invalid 6LoWPAN context option received\n"); |
||||
return false; |
||||
} |
||||
if (icmpv6_type != ICMPV6_RTR_ADV) { |
||||
/* discard silently */ |
||||
return true; |
||||
} |
||||
/* don't care for result */ |
||||
gnrc_sixlowpan_ctx_update(sixlowpan_nd_opt_6ctx_get_cid(ctx_opt), (ipv6_addr_t *)(ctx_opt + 1), |
||||
ctx_opt->ctx_len, byteorder_ntohs(ctx_opt->ltime), |
||||
sixlowpan_nd_opt_6ctx_is_comp(ctx_opt)); |
||||
return true; |
||||
} |
||||
|
||||
void gnrc_sixlowpan_nd_wakeup(void) |
||||
{ |
||||
gnrc_ipv6_nc_t *router = gnrc_ipv6_nc_get_next_router(NULL); |
||||
while (router) { |
||||
timex_t t = { 0, GNRC_NDP_RETRANS_TIMER }; |
||||
vtimer_remove(&router->rtr_sol_timer); |
||||
gnrc_sixlowpan_nd_uc_rtr_sol(router); |
||||
gnrc_ndp_internal_send_nbr_sol(router->iface, &router->ipv6_addr, &router->ipv6_addr); |
||||
vtimer_remove(&router->nbr_sol_timer); |
||||
vtimer_set_msg(&router->nbr_sol_timer, t, gnrc_ipv6_pid, GNRC_NDP_MSG_NBR_SOL_RETRANS, |
||||
router); |
||||
} |
||||
} |
||||
|
||||
/** @} */ |
Loading…
Reference in new issue