1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

gnrc: remove legacy neighbor discovery code

This commit is contained in:
Martine Lenders 2017-11-16 17:02:52 +01:00
parent 71a7dbf918
commit 636ef2a498
No known key found for this signature in database
GPG Key ID: 8E97A9FE55F25D62
30 changed files with 10 additions and 4217 deletions

View File

@ -193,20 +193,6 @@ ifneq (,$(filter gnrc_ipv6_router_default,$(USEMODULE)))
USEMODULE += gnrc_icmpv6
endif
ifneq (,$(filter gnrc_ndp_router,$(USEMODULE)))
USEMODULE += gnrc_ndp_node
USEMODULE += random
USEMODULE += xtimer
endif
ifneq (,$(filter gnrc_ndp_node,$(USEMODULE)))
USEMODULE += gnrc_ndp_internal
endif
ifneq (,$(filter gnrc_ndp_%,$(USEMODULE)))
USEMODULE += gnrc_ndp
endif
ifneq (,$(filter gnrc_ndp2,$(USEMODULE)))
USEMODULE += gnrc_icmpv6
USEMODULE += gnrc_netif2
@ -273,10 +259,6 @@ ifneq (,$(filter ipv6_hdr,$(USEMODULE)))
USEMODULE += ipv6_addr
endif
ifneq (,$(filter gnrc_ipv6_nc,$(USEMODULE)))
USEMODULE += ipv6_addr
endif
ifneq (,$(filter gnrc_ipv6_nib_6lbr,$(USEMODULE)))
USEMODULE += gnrc_ipv6_nib_6lr
endif

View File

@ -20,7 +20,6 @@ USEMODULE += gnrc_netdev_default
USEMODULE += auto_init_gnrc_netif
# Specify the minimum networking modules for IPv6
USEMODULE += gnrc_ipv6
USEMODULE += gnrc_ndp
# Additional networking modules that can be dropped if not needed
USEMODULE += gnrc_icmpv6_echo
# Use minimal standard PRNG

View File

@ -241,11 +241,10 @@
* USEMODULE += gnrc_ipv6_router
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* respectively. Those modules provide the bare minimum of IPv6
* functionalities (no @ref net_gnrc_icmpv6, no @ref net_gnrc_ndp). Because
* of that, the @ref net_gnrc_ipv6_nc needs to be configured manually. If an
* IEEE 802.15.4 device is present @ref net_gnrc_sixlowpan will be included
* automatically, but no fragmentation or header compression support will be
* provided.
* functionalities (no @ref net_gnrc_icmpv6). Because of that, the
* @ref net_gnrc_ipv6_nib needs to be configured manually. If an IEEE 802.15.4
* device is present @ref net_gnrc_sixlowpan will be included automatically,
* but no fragmentation or header compression support will be provided.
*
* - For @ref net_gnrc_icmpv6_echo "ICMPv6 echo request/reply (ping)"
* functionality:

View File

@ -1,318 +0,0 @@
/*
* 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_ipv6_nc IPv6 neighbor cache
* @ingroup net_gnrc_ipv6
* @brief Translates IPv6 addresses to link layer addresses.
* @{
*
* @file
* @brief Neighbor cache definitions.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NET_GNRC_IPV6_NC_H
#define NET_GNRC_IPV6_NC_H
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "kernel_types.h"
#include "net/eui64.h"
#include "net/ipv6/addr.h"
#include "net/gnrc/pktqueue.h"
#include "xtimer.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef GNRC_IPV6_NC_SIZE
/**
* @brief The size of the neighbor cache
*/
#define GNRC_IPV6_NC_SIZE (GNRC_NETIF_NUMOF * 8)
#endif
#ifndef GNRC_IPV6_NC_L2_ADDR_MAX
/**
* @brief The maximum size of a link layer address
*/
#define GNRC_IPV6_NC_L2_ADDR_MAX (8)
#endif
/**
* @{
* @name Flag definitions for gnrc_ipv6_nc_t
*/
/**
* @{
* @brief States of a neighbor cache entry.
*
* @see <a href="http://tools.ietf.org/html/rfc4861#section-7.3.2">
* RFC 4861, section 7.3.2
* </a>
*/
#define GNRC_IPV6_NC_STATE_MASK (0x07) /**< Mask for neighbor cache state */
#define GNRC_IPV6_NC_STATE_POS (0) /**< Shift of neighbor cache state */
#define GNRC_IPV6_NC_STATE_UNMANAGED (0x00) /**< The entry is not manage by NDP */
/**
* @brief The entry is unreachable
*
* @see <a href="http://tools.ietf.org/html/rfc7048#section-3">
* RFC 7048, section 3
* </a>
*/
#define GNRC_IPV6_NC_STATE_UNREACHABLE (0x01)
#define GNRC_IPV6_NC_STATE_INCOMPLETE (0x02) /**< Address resolution is performed */
#define GNRC_IPV6_NC_STATE_STALE (0x03) /**< The entry is stale */
#define GNRC_IPV6_NC_STATE_DELAY (0x04) /**< The entry was stale but packet was sent out */
#define GNRC_IPV6_NC_STATE_PROBE (0x05) /**< Periodic reachabality confirmation */
#define GNRC_IPV6_NC_STATE_REACHABLE (0x07) /**< The entry is reachable */
/**
* @}
*/
#define GNRC_IPV6_NC_IS_ROUTER (0x08) /**< The neighbor is a router */
#define GNRC_IPV6_NC_TYPE_MASK (0x30) /**< Mask for neighbor cache state */
/**
* @{
* @brief States of a neighbor cache entry.
*
* @see <a href="http://tools.ietf.org/html/rfc6775#section-3.5">
* RFC 6775, section 3.5
* </a>
*/
/**
* @brief The entry has no type
*
* @details The node sents multicast Neighbor Solicitations for hosts.
*/
#define GNRC_IPV6_NC_TYPE_NONE (0x00)
#define GNRC_IPV6_NC_TYPE_GC (0x10) /**< The entry is marked for removal */
#define GNRC_IPV6_NC_TYPE_TENTATIVE (0x20) /**< The entry is temporary */
#define GNRC_IPV6_NC_TYPE_REGISTERED (0x30) /**< The entry is registered */
/**
* @}
*/
/**
* @}
*/
/**
* @brief Neighbor cache entry as defined in
* <a href="http://tools.ietf.org/html/rfc4861#section-5.1">
* RFC 4861, section 5.1
* </a>.
*/
typedef struct {
#ifdef MODULE_GNRC_NDP_NODE
gnrc_pktqueue_t *pkts; /**< Packets waiting for address resolution */
#endif
ipv6_addr_t ipv6_addr; /**< IPv6 address of the neighbor */
uint8_t l2_addr[GNRC_IPV6_NC_L2_ADDR_MAX]; /**< Link layer address of the neighbor */
uint8_t l2_addr_len; /**< Length of gnrc_ipv6_nc_t::l2_addr */
uint8_t flags; /**< Flags as defined above */
kernel_pid_t iface; /**< PID to the interface where the neighbor is */
xtimer_t rtr_timeout; /**< timeout timer for router flag */
msg_t rtr_timeout_msg; /**< msg_t for gnrc_ipv6_nc_t::rtr_timeout */
/**
* @brief (Re)Transmission timer for neighbor solicitations of this entry and
* timeout for states.
*/
xtimer_t nbr_sol_timer;
msg_t nbr_sol_msg; /**< msg_t for gnrc_ipv6_nc_t::nbr_sol_timer */
/**
* @brief Delay timer for neighbor advertisements of this entry.
*
* @note Only needed for delayed anycast neighbor advertisements
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-7.2.7">
* RFC 4861, section 7.2.7
* </a>
*/
xtimer_t nbr_adv_timer;
msg_t nbr_adv_msg; /**< msg_t for gnrc_ipv6_nc_t::nbr_adv_timer */
#if defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER)
xtimer_t rtr_adv_timer; /**< Timer for periodic router advertisements */
msg_t rtr_adv_msg; /**< msg_t for gnrc_ipv6_nc_t::rtr_adv_timer */
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
xtimer_t type_timeout; /**< Timer for type transmissions */
msg_t type_timeout_msg; /**< msg_t for gnrc_ipv6_nc_t::type_timeout */
eui64_t eui64; /**< the unique EUI-64 of the neighbor (might be
* different from L2 address, if l2_addr_len == 2) */
#endif
uint8_t probes_remaining; /**< remaining number of unanswered probes */
/**
* @}
*/
} gnrc_ipv6_nc_t;
/**
* @brief Initializes neighbor cache
*/
void gnrc_ipv6_nc_init(void);
/**
* @brief Adds a neighbor to the neighbor cache
*
* @param[in] iface PID to the interface where the neighbor is.
* @param[in] ipv6_addr IPv6 address of the neighbor. Must not be NULL.
* @param[in] l2_addr Link layer address of the neighbor. NULL if unknown.
* @param[in] l2_addr_len Length of @p l2_addr, must be lesser than or equal
* to GNRC_IPV6_L2_ADDR_MAX. 0 if unknown.
* @param[in] flags Flags for the entry
*
* @return Pointer to new neighbor cache entry on success
* @return NULL, on failure
*/
gnrc_ipv6_nc_t *gnrc_ipv6_nc_add(kernel_pid_t iface, const ipv6_addr_t *ipv6_addr,
const void *l2_addr, size_t l2_addr_len, uint8_t flags);
/**
* @brief Removes a neighbor from the neighbor cache
*
* @param[in] iface PID to the interface where the neighbor is. If it
* is KERNEL_PID_UNDEF it will be removed for all
* interfaces.
* @param[in] ipv6_addr IPv6 address of the neighbor
*/
void gnrc_ipv6_nc_remove(kernel_pid_t iface, const ipv6_addr_t *ipv6_addr);
/**
* @brief Searches for any neighbor cache entry fitting the @p ipv6_addr.
*
* @param[in] iface PID to the interface where the neighbor is. If it
* is KERNEL_PID_UNDEF it will be searched on all
* interfaces.
* @param[in] ipv6_addr An IPv6 address
*
* @return The neighbor cache entry, if one is found.
* @return NULL, if none is found.
*/
gnrc_ipv6_nc_t *gnrc_ipv6_nc_get(kernel_pid_t iface, const ipv6_addr_t *ipv6_addr);
/**
* @brief Gets next entry in neighbor cache after @p prev.
*
* @param[in] prev Previous entry. NULL to start iteration.
*
* @return The next entry in neighbor cache.
*/
gnrc_ipv6_nc_t *gnrc_ipv6_nc_get_next(gnrc_ipv6_nc_t *prev);
/**
* @brief Gets next reachable router entry in neighbor cache after @p prev.
*
* @param[in] prev Previous router entry. NULL to start iteration.
*
* @return The next reachable router entry in neighbor cache.
*/
gnrc_ipv6_nc_t *gnrc_ipv6_nc_get_next_router(gnrc_ipv6_nc_t *prev);
/**
* @brief Returns the state of a neighbor cache entry.
*
* @param[in] entry A neighbor cache entry
*
* @return The state of the neighbor cache entry as defined by its flags.
*/
static inline uint8_t gnrc_ipv6_nc_get_state(const gnrc_ipv6_nc_t *entry)
{
return (entry->flags & GNRC_IPV6_NC_STATE_MASK);
}
/**
* @brief Returns the type of a neighbor cache entry.
*
* @param[in] entry A neighbor cache entry
*
* @return The type of the neighbor cache entry as defined by its flags.
*/
static inline uint8_t gnrc_ipv6_nc_get_type(const gnrc_ipv6_nc_t *entry)
{
return (entry->flags & GNRC_IPV6_NC_TYPE_MASK);
}
/**
* @brief Checks if an entry is reachable (do not confuse with
* @ref GNRC_IPV6_NC_STATE_REACHABLE).
*
* @param[in] entry A neighbor cache entry
*
* @return true, if you can send packets to @p entry
* @return false, if you can't send packets to @p entry
*/
static inline bool gnrc_ipv6_nc_is_reachable(const gnrc_ipv6_nc_t *entry)
{
switch (gnrc_ipv6_nc_get_state(entry)) {
case GNRC_IPV6_NC_STATE_UNREACHABLE:
case GNRC_IPV6_NC_STATE_INCOMPLETE:
return false;
default:
return true;
}
}
/**
* @brief Marks an entry as still reachable, if one with a fitting @p ipv6_addr
* can be found.
*
* @details This function can be used by upper layer protocols for neighbor
* discovery optimization to confirm that there was a reachability
* confirmation (e. g. an ACK in TCP) from the neighbor.
*
* @see <a href="http://tools.ietf.org/html/rfc4861#section-7.3.1">
* RFC 4861, section 7.3.1
* </a>
*
* @param[in] ipv6_addr An IPv6 address
*
* @return The neighbor cache entry, if one is found.
* @return NULL, if none is found.
*/
gnrc_ipv6_nc_t *gnrc_ipv6_nc_still_reachable(const ipv6_addr_t *ipv6_addr);
/**
* @brief Gets link-layer address from neighbor cache entry if neighbor is reachable.
*
* @pre (l2_addr != NULL) && (l2_addr_len != NULL)
*
* @param[out] l2_addr The link layer address of @p entry. Must not be NULL.
* @param[out] l2_addr_len Length of @p l2_addr. Must not be NULL.
* @param[in] entry A neighbor cache entry
*
* @return PID to the interface where the neighbor is.
* @return KERNEL_PID_UNDEF, if @p entry == NULL or the neighbor is not reachable.
*/
kernel_pid_t gnrc_ipv6_nc_get_l2_addr(uint8_t *l2_addr, uint8_t *l2_addr_len,
const gnrc_ipv6_nc_t *entry);
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_IPV6_NC_H */
/**
* @}
*/

View File

@ -1,548 +0,0 @@
/*
* 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_ndp IPv6 Neighbor discovery
* @ingroup net_gnrc_icmpv6
* @brief GNRC's IPv6 Neighbor Discovery implementation
* @{
*
* @file
* @brief Definitions for GNRC's IPv6 Neighbor Discovery
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NET_GNRC_NDP_H
#define NET_GNRC_NDP_H
#include <inttypes.h>
#include <stdlib.h>
#include "byteorder.h"
#include "net/ndp.h"
#include "net/gnrc/pkt.h"
#include "net/gnrc/icmpv6.h"
#include "net/ipv6/addr.h"
#include "net/gnrc/ipv6/nc.h"
#include "net/gnrc/ndp/host.h"
#include "net/gnrc/ndp/internal.h"
#include "net/gnrc/ndp/router.h"
#include "net/gnrc/ndp/node.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Message type for router timeouts */
#define GNRC_NDP_MSG_RTR_TIMEOUT (0x0210)
/** Message type for address timeouts */
#define GNRC_NDP_MSG_ADDR_TIMEOUT (0x0211)
/** Message type for multicast neighbor solicitation retransmissions */
#define GNRC_NDP_MSG_NBR_SOL_RETRANS (0x0212)
/** Message type for periodic router advertisements */
#define GNRC_NDP_MSG_RTR_ADV_RETRANS (0x0213)
/** Message type for delayed router advertisements */
#define GNRC_NDP_MSG_RTR_ADV_DELAY (0x0214)
/** Message type for delayed router advertisements in a 6LoWPAN
* 6LoWPAN needs a special handling, because router advertisements are only
* sent after a short randomized delay, but not periodically. */
#define GNRC_NDP_MSG_RTR_ADV_SIXLOWPAN_DELAY (0x0215)
/** Message type for periodic router solicitations */
#define GNRC_NDP_MSG_RTR_SOL_RETRANS (0x0216)
/** Message type for neighbor cache state timeouts */
#define GNRC_NDP_MSG_NC_STATE_TIMEOUT (0x0217)
/**
* @name Host constants
* @{
* @see <a href="https://tools.ietf.org/html/rfc4861#section-10">
* RFC 4861, section 10
* </a>
*/
/**
* @brief Upper bound for randomised delay in seconds for initial
* router solicitation transmissions
*/
#define GNRC_NDP_MAX_RTR_SOL_DELAY (1U)
/**
* @brief Interval in seconds between initial router solicitation
* transmissions
*/
#define GNRC_NDP_MAX_RTR_SOL_INT (4U)
/**
* @brief Maximum number of initial router solicitation transmissions
*/
#define GNRC_NDP_MAX_RTR_SOL_NUMOF (3U)
/** @} */
/**
* @name Node constants
* @{
* @see <a href="https://tools.ietf.org/html/rfc4861#section-10">
* RFC 4861, section 10
* </a>
*/
/**
* @brief Maximum number of unanswered multicast neighbor solicitations
* before address resolution is considered failed.
*/
#define GNRC_NDP_MAX_MC_NBR_SOL_NUMOF (3U)
/**
* @brief Maximum number of unanswered unicast neighbor solicitations before
* an address is considered unreachable.
*/
#define GNRC_NDP_MAX_UC_NBR_SOL_NUMOF (3U)
/**
* @brief Upper bound of randomized delay in seconds for a solicited
* neighbor advertisement transmission for an anycast target.
*/
#define GNRC_NDP_MAX_AC_TGT_DELAY (1U)
/**
* @brief Maximum number of unsolicited neighbor advertisements before on
* link-layer address change.
*/
#define GNRC_NDP_MAX_NBR_ADV_NUMOF (3U)
/**
* @brief Base value in mircoseconds for computing randomised
* reachable time.
*/
#define GNRC_NDP_REACH_TIME (30U * US_PER_SEC)
/**
* @brief Time in mircoseconds between retransmissions of neighbor
* solicitations to a neighbor.
*/
#define GNRC_NDP_RETRANS_TIMER (1U * US_PER_SEC)
/**
* @brief Delay in seconds for neighbor cache entry between entering
* DELAY state and entering PROBE state if no reachability
* confirmation has been received.
*/
#define GNRC_NDP_FIRST_PROBE_DELAY (5U)
/**
* @brief Lower bound for randomised reachable time calculation.
*/
#define GNRC_NDP_MIN_RAND (5U)
/**
* @brief Upper bound for randomised reachable time calculation.
*/
#define GNRC_NDP_MAX_RAND (15U)
/** @} */
/**
* @name Router constants
* @{
* @see <a href="https://tools.ietf.org/html/rfc4861#section-10">
* RFC 4861, section 10
* </a>
*/
/**
* @brief Initial router advertisement interval in seconds
*/
#define GNRC_NDP_MAX_INIT_RTR_ADV_INT (16U)
/**
* @brief Maximum number of initial router advertisement transmissions
*/
#define GNRC_NDP_MAX_INIT_RTR_ADV_NUMOF (3U)
/**
* @brief Maximum number of final router advertisement transmissions
*/
#define GNRC_NDP_MAX_FIN_RTR_ADV_NUMOF (3U)
/**
* @brief Minimum delay in seconds between router advertisement
* transmissions
*/
#define GNRC_NDP_MIN_RTR_ADV_DELAY (3U)
/**
* @brief Upper bound for randomised delay in microseconds between router
* solicitation reception and responding router advertisement
* transmission.
*/
#define GNRC_NDP_MAX_RTR_ADV_DELAY (500U * US_PER_MS)
/** @} */
/**
* @brief Handles received neighbor solicitations.
*
* @param[in] iface The receiving interface.
* @param[in] pkt The received packet.
* @param[in] ipv6 The IPv6 header in @p pkt.
* @param[in] nbr_sol The neighbor solicitation in @p pkt.
* @param[in] icmpv6_size The overall size of the neighbor solicitation.
*/
void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
ipv6_hdr_t *ipv6, ndp_nbr_sol_t *nbr_sol,
size_t icmpv6_size);
/**
* @brief Handles received neighbor advertisements.
*
* @param[in] iface The receiving interface.
* @param[in] pkt The received packet.
* @param[in] ipv6 The IPv6 header in @p pkt.
* @param[in] nbr_adv The neighbor advertisement in @p pkt.
* @param[in] icmpv6_size The overall size of the neighbor advertisement.
*/
void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
ipv6_hdr_t *ipv6, ndp_nbr_adv_t *nbr_adv,
size_t icmpv6_size);
#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
/**
* @brief Handles received router solicitations.
*
* @param[in] iface The receiving interface.
* @param[in] pkt The received packet.
* @param[in] ipv6 The IPv6 header in @p pkt.
* @param[in] rtr_sol The router solicitation in @p pkt.
* @param[in] icmpv6_size The overall size of the router solicitation.
*/
void gnrc_ndp_rtr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
ipv6_hdr_t *ipv6, ndp_rtr_sol_t *rtr_sol,
size_t icmpv6_size);
#else
/**
* @brief A host *must* silently discard all received router solicitations.
* @see <a href="https://tools.ietf.org/html/rfc4861#section-6.2.6">
* RFC 4861, section 6.2.6
* </a>
*
* This macro is primarily an optimization to not go into the function defined
* above.
*/
#define gnrc_ndp_rtr_sol_handle(iface, pkt, ipv6, rtr_sol, size)
#endif
/**
* @brief Handles received router advertisements
*
* @todo As router check consistency as described in RFC 4861, section 6.2.3
*
* @param[in] iface The receiving interface.
* @param[in] pkt The received packet.
* @param[in] ipv6 The IPv6 header in @p pkt.
* @param[in] rtr_adv The router advertisement in @p pkt.
* @param[in] icmpv6_size The overall size of the router advertisement.
*/
void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
ipv6_hdr_t *ipv6, ndp_rtr_adv_t *rtr_adv,
size_t icmpv6_size);
/**
* @brief Retransmits a multicast neighbor solicitation for an incomplete or
* probing neighbor cache entry @p nc_entry,
* if nc_entry::probes_remaining > 0.
*
* @details If nc_entry::probes_remaining > 0 it will be decremented. If it
* reaches 0 it the entry @p nc_entry will be removed from the
* neighbor cache.
*
* @param[in] nc_entry A neighbor cache entry. Will be ignored if its state
* is not @ref GNRC_IPV6_NC_STATE_INCOMPLETE or
* @ref GNRC_IPV6_NC_STATE_PROBE.
*/
void gnrc_ndp_retrans_nbr_sol(gnrc_ipv6_nc_t *nc_entry);
/**
* @brief Event handler for a neighbor cache state timeout.
*
* @param[in] nc_entry A neighbor cache entry.
*/
void gnrc_ndp_state_timeout(gnrc_ipv6_nc_t *nc_entry);
/**
* @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 gnrc_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
kernel_pid_t iface, ipv6_addr_t *dst,
gnrc_pktsnip_t *pkt);
/**
* @brief Builds a neighbor solicitation message for sending.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.3">
* RFC 4861, section 4.3
* </a>
*
* @param[in] tgt The target address.
* @param[in] options Options to append to the router solicitation.
*
* @return The resulting ICMPv6 packet on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_ndp_nbr_sol_build(ipv6_addr_t *tgt, gnrc_pktsnip_t *options);
/**
* @brief Builds a neighbor advertisement message for sending.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.4">
* RFC 4861, section 4.4
* </a>
*
* @param[in] flags Neighbor advertisement flags:
* @ref NDP_NBR_ADV_FLAGS_R == 1 indicates, that the
* sender is a router,
* @ref NDP_NBR_ADV_FLAGS_S == 1 indicates that the
* advertisement was sent in response to a neighbor
* solicitation,
* @ref NDP_NBR_ADV_FLAGS_O == 1 indicates that the
* advertisement should override an existing cache entry
* and update the cached link-layer address.
* @param[in] tgt For solicited advertisements, the Target Address field
* in the neighbor solicitaton.
* For and unsolicited advertisement, the address whose
* link-layer address has changed.
* MUST NOT be multicast.
* @param[in] options Options to append to the neighbor advertisement.
*
* @return The resulting ICMPv6 packet on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_ndp_nbr_adv_build(uint8_t flags, ipv6_addr_t *tgt,
gnrc_pktsnip_t *options);
/**
* @brief Builds a router solicitation message for sending.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.1">
* RFC 4861, section 4.1
* </a>
*
* @param[in] options Options to append to the router solicitation.
*
* @return The resulting ICMPv6 packet on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_ndp_rtr_sol_build(gnrc_pktsnip_t *options);
/**
* @brief Builds a router solicitation message for sending.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.1">
* RFC 4861, section 4.1
* </a>
*
* @param[in] options Options to append to the router solicitation.
*
* @return The resulting ICMPv6 packet on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_ndp_rtr_sol_build(gnrc_pktsnip_t *options);
#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
/**
* @brief Builds a router advertisement message for sending.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.2">
* RFC 4861, section 4.2
* </a>
*
* @note The source address for the packet MUST be the link-local address
* of the interface.
*
* @param[in] cur_hl Default hop limit for outgoing IP packets, 0 if
* unspecified by this router.
* @param[in] flags Flags as defined above.
* @ref NDP_RTR_ADV_FLAGS_M == 1 indicates, that the
* addresses are managed by DHCPv6,
* @ref NDP_RTR_ADV_FLAGS_O == 1 indicates that other
* configuration information is available via DHCPv6.
* @param[in] ltime Lifetime of the default router in seconds.
* @param[in] reach_time Time in milliseconds a node should assume a neighbor
* reachable. 0 means unspecified by the router.
* @param[in] retrans_timer Time in milliseconds between retransmitted
* neighbor solicitations. 0 means unspecified by
* the router.
* @param[in] options Options to append to the router advertisement.
*
* @return The resulting ICMPv6 packet on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_ndp_rtr_adv_build(uint8_t cur_hl, uint8_t flags, uint16_t ltime,
uint32_t reach_time, uint32_t retrans_timer,
gnrc_pktsnip_t *options);
#else
/**
* @brief A host *must not* send router advertisements at any time (so why build them?)
* @see <a href="https://tools.ietf.org/html/rfc4861#section-6.3.4">
* RFC 4861, section 6.3.4
* </a>
*
* This macro is primarily an optimization to not go into the function defined
* above.
*/
#define gnrc_ndp_rtr_adv_build(cur_hl, flags, ltime, reach_time, retrans_timer, options) (NULL)
#endif
/**
* @brief Builds a generic NDP option.
*
* @param[in] type Type of the option.
* @param[in] size Size in byte of the option (will be rounded up to the next
* multiple of 8).
* @param[in] next More options in the packet. NULL, if there are none.
*
* @return The packet snip list of options, on success
* @return NULL, if packet buffer is full
*/
gnrc_pktsnip_t *gnrc_ndp_opt_build(uint8_t type, size_t size, gnrc_pktsnip_t *next);
/**
* @brief Builds the source link-layer address option.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.6.1">
* RFC 4861, section 4.6.1
* </a>
*
* @note Must only be used with neighbor solicitations, router solicitations,
* and router advertisements. This is not checked however, since
* hosts should silently ignore it in other NDP messages.
*
* @param[in] l2addr A link-layer address of variable length.
* @param[in] l2addr_len Length of @p l2addr.
* @param[in] next More options in the packet. NULL, if there are none.
*
* @return The packet snip list of options, on success
* @return NULL, if packet buffer is full
*/
gnrc_pktsnip_t *gnrc_ndp_opt_sl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
gnrc_pktsnip_t *next);
/**
* @brief Builds the target link-layer address option.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.6.1">
* RFC 4861, section 4.6.1
* </a>
*
* @note Must only be used with neighbor advertisemnents and redirect packets.
* This is not checked however, since hosts should silently ignore it
* in other NDP messages.
*
* @param[in] l2addr A link-layer address of variable length.
* @param[in] l2addr_len Length of @p l2addr.
* @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_ndp_opt_tl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
gnrc_pktsnip_t *next);
#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
/**
* @brief Builds the prefix information option.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.6.2">
* RFC 4861, section 4.6.2
* </a>
*
* @note Must only be used with router advertisemnents. This is not checked
* however, since nodes should silently ignore it in other NDP messages.
*
* @param[in] prefix_len The length of @p prefix in bits. Must be between
* 0 and 128.
* @param[in] flags Flags as defined above.
* @ref NDP_OPT_PI_FLAGS_L == 1 indicates, that
* @p prefix can be used for on-link determination,
* @ref NDP_OPT_PI_FLAGS_A == 1 indicates, that
* @p prefix can be used for stateless address
* configuration.
* @param[in] valid_ltime Length of time in seconds that @p prefix is valid.
* UINT32_MAX represents infinity.
* @param[in] pref_ltime Length of time in seconds that addresses using
* @p prefix remain prefered. UINT32_MAX represents
* infinity.
* @param[in] prefix An IPv6 address or a prefix of an IPv6 address.
* @param[in] next More options in the packet. NULL, if there are none.
*
* @return The packet snip list of options, on success
* @return NULL, if packet buffer is full
*/
gnrc_pktsnip_t *gnrc_ndp_opt_pi_build(uint8_t prefix_len, uint8_t flags,
uint32_t valid_ltime, uint32_t pref_ltime,
ipv6_addr_t *prefix, gnrc_pktsnip_t *next);
/**
* @brief Builds the MTU option.
*
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.6.4">
* RFC 4861, section 4.6.4
* </a>
*
* @note Must only be used with router advertisemnents. This is not checked
* however, since nodes should silently ignore it in other NDP messages.
*
* @param[in] mtu The recommended MTU for the link.
* @param[in] next More options in the packet. NULL, if there are none.
*
* @return The packet snip list of options, on success
* @return NULL, if packet buffer is full
*/
gnrc_pktsnip_t *gnrc_ndp_opt_mtu_build(uint32_t mtu, gnrc_pktsnip_t *next);
#else
/**
* @brief A host *must not* send router advertisements at any time (so why build their options?)
* @see <a href="https://tools.ietf.org/html/rfc4861#section-6.3.4">
* RFC 4861, section 6.3.4
* </a>
*
* This macro is primarily an optimization to not go into the function defined
* above.
*/
#define gnrc_ndp_opt_pi_build(prefix_len, flags, valid_ltime, pref_ltime, prefix, next) (NULL)
/**
* @brief A host *must not* send router advertisements at any time (so why build their options?)
* @see <a href="https://tools.ietf.org/html/rfc4861#section-6.3.4">
* RFC 4861, section 6.3.4
* </a>
*
* This macro is primarily an optimization to not go into the function defined
* above.
*/
#define gnrc_ndp_opt_mtu_build(mtu, next) (NULL)
#endif
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_NDP_H */
/**
* @}
*/

View File

@ -1,33 +0,0 @@
/*
* 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_ndp_host Host-specific part of router discovery.
* @ingroup net_gnrc_ndp
* @brief Host-specific part for the router discovery in IPv6
* neighbor discovery.
* @{
*
* @file
* @brief Host-specific router discovery definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NET_GNRC_NDP_HOST_H
#define NET_GNRC_NDP_HOST_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_NDP_HOST_H */
/** @} */

View File

@ -1,215 +0,0 @@
/*
* 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_ndp_internal Internal functions for neighbor discovery.
* @ingroup net_gnrc_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 NET_GNRC_NDP_INTERNAL_H
#define NET_GNRC_NDP_INTERNAL_H
#include "kernel_types.h"
#include "net/gnrc/ipv6/nc.h"
#include "net/ipv6/addr.h"
#include "net/ipv6/hdr.h"
#include "net/ndp.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.
*/
ipv6_addr_t *gnrc_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 gnrc_ndp_internal_set_state(gnrc_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] src Source address for the neighbor solicitation. Will be chosen from the
* interface according to @p dst, if NULL.
* @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 gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *tgt,
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.
* @param[in] ext_opts External options for the neighbor advertisement. Leave NULL for none.
* **Warning:** these are not tested if they are suitable for a
* neighbor advertisement so be sure to check that.
* **Will be released** in an error case.
*/
void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_addr_t *dst,
bool supply_tl2a, gnrc_pktsnip_t *ext_opts);
/**
* @brief Send precompiled router solicitation to @p dst.
*
* @internal
*
* @param[in] iface Interface to send over. May not be KERNEL_PID_UNDEF.
* @param[in] dst Destination for the router solicitation. ff02::2 if NULL.
*/
void gnrc_ndp_internal_send_rtr_sol(kernel_pid_t iface, ipv6_addr_t *dst);
#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
/**
* @brief Handles received router solicitations.
*
* @param[in] iface Interface to send over. May not be KERNEL_PID_UNDEF.
* @param[in] src Source address for the router advertisement. May be NULL to be determined
* by source address selection (:: if no @p iface has no address).
* @param[in] dst Destination address for router advertisement.
* @ref IPV6_ADDR_ALL_NODES_LINK_LOCAL if NULL.
* @param[in] fin This is part of the router's final batch of router advertisements
* before ceising to be a router (set's router lifetime field to 0).
*/
void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src,
ipv6_addr_t *dst, bool fin);
#else
/**
* @brief A host *must not* send router advertisements at any time.
*
* This macro is primarily an optimization to not go into the function defined
* above.
*/
#define gnrc_ndp_internal_send_rtr_adv(iface, src, dst, fin)
#endif
/**
* @brief Handles a SL2A option.
*
* @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 SL2A option.
*
* @return length of the L2 address, on success.
* @return -EINVAL, if SL2A was not valid.
* @return -ENOTSUP, if node should silently ignore the option.
*/
int gnrc_ndp_internal_sl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
ndp_opt_t *sl2a_opt, uint8_t *l2addr);
/**
* @brief Handles a TL2A option.
*
* @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.
* @return -ENOTSUP, if node should silently ignore the option.
*/
int gnrc_ndp_internal_tl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6,
uint8_t icmpv6_type, ndp_opt_t *tl2a_opt,
uint8_t *l2addr);
/**
* @brief Handles a MTU option.
*
* @internal
*
* @param[in] iface Interface the MTU option was received on.
* @param[in] icmpv6_type ICMPv6 type of the message carrying the option.
* @param[in] mtu_opt A MTU option.
*
* @return true, on success (or if the node should silently ignore the option).
* @return false, if MTU option was not valid.
*/
bool gnrc_ndp_internal_mtu_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type,
ndp_opt_mtu_t *mtu_opt);
/**
* @brief Handles a PI option.
*
* @internal
*
* @param[in] iface Interface the PI option was received on.
* @param[in] icmpv6_type ICMPv6 type of the message carrying the option.
* @param[in] pi_opt A PI option.
*
* @return true, on success (or if the node should silently ignore the option).
* @return false, if PIO was not valid.
*/
bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type,
ndp_opt_pi_t *pi_opt);
/**
* @brief Resets the gnrc_ipv6_nc_t::nbr_sol_timer.
*
* @internal
*
* @param[in] nc_entry A neighbor cache entry.
* @param[in] delay The delay when the timer should fire.
* @param[in] type The msg_t::type for the timer.
* @param[in] pid The pid of the receiver thread of the msg_t
*/
static inline void gnrc_ndp_internal_reset_nbr_sol_timer(gnrc_ipv6_nc_t *nc_entry, uint32_t delay,
uint16_t type, kernel_pid_t pid)
{
xtimer_remove(&nc_entry->nbr_sol_timer);
nc_entry->nbr_sol_msg.type = type;
xtimer_set_msg(&nc_entry->nbr_sol_timer, delay, &nc_entry->nbr_sol_msg, pid);
}
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_NDP_INTERNAL_H */
/** @} */

View File

@ -1,53 +0,0 @@
/*
* 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_ndp_node Neighbor discovery for pure IPv6 nodes
* @ingroup net_gnrc_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 NET_GNRC_NDP_NODE_H
#define NET_GNRC_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 gnrc_ndp_node_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
kernel_pid_t iface, ipv6_addr_t *dst,
gnrc_pktsnip_t *pkt);
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_NDP_NODE_H */
/** @} */

View File

@ -1,49 +0,0 @@
/*
* 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_ndp_router Router-specific part of router discovery.
* @ingroup net_gnrc_ndp
* @brief Router-specific part for the router discovery in IPv6
* neighbor discovery.
* @{
*
* @file
* @brief Router-specific router discovery definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NET_GNRC_NDP_ROUTER_H
#define NET_GNRC_NDP_ROUTER_H
#include <stdbool.h>
#include "kernel_types.h"
#include "net/ipv6/hdr.h"
#include "net/ndp.h"
#include "net/gnrc/ipv6/nc.h"
#include "timex.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Send an solicited router advertisement to IPv6 address of
* @p neighbor.
*
* @param[in] neighbor A neighbor cache entry.
*/
void gnrc_ndp_router_send_rtr_adv(gnrc_ipv6_nc_t *neighbor);
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_NDP_ROUTER_H */
/** @} */

View File

@ -1,223 +0,0 @@
/*
* 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_router Router-part of 6LoWPAN-ND
* @ingroup net_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 NET_GNRC_SIXLOWPAN_ND_ROUTER_H
#define NET_GNRC_SIXLOWPAN_ND_ROUTER_H
#include <stdbool.h>
#include "bitfield.h"
#include "net/gnrc/sixlowpan/ctx.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
/* One prefix per interface */
#define GNRC_SIXLOWPAN_ND_ROUTER_ABR_PRF_NUMOF \
(GNRC_SIXLOWPAN_ND_ROUTER_ABR_NUMOF * GNRC_NETIF_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_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 */
#ifdef MODULE_GNRC_SIXLOWPAN_CTX
BITFIELD(ctxs, GNRC_SIXLOWPAN_CTX_SIZE);/**< contexts associated with BR */
#endif
gnrc_sixlowpan_nd_router_prf_t *prfs; /**< prefixes associated with BR */
xtimer_t ltimer; /**< timer for deletion */
msg_t ltimer_msg; /**< msg_t for gnrc_sixlowpan_nd_router_abr_t::ltimer */
} 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.
*/
void gnrc_sixlowpan_nd_router_set_rtr_adv(gnrc_ipv6_netif_t *netif, bool enable);
/**
* @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 MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER
/**
* @brief Makes this node a new border router.
*
* @pre addr != NULL
*
* @param[in] addr The local address to use in the ABROs
* @param[in] ltime The lifetime to advertise in the ABROs. 0 assumes a default value of
* @ref GNRC_SIXLOWPAN_ND_BORDER_ROUTER_DEFAULT_LTIME
*
* @return The new border router object.
* @return NULL, on error.
*/
gnrc_sixlowpan_nd_router_abr_t *gnrc_sixlowpan_nd_router_abr_create(ipv6_addr_t *addr,
unsigned int ltime);
/**
* @brief Adds a prefix for this border router to manage.
*
* @pre iface != NULL && prefix != NULL
*
* @param[in] abr The local border router.
* @param[in] iface The IPv6 interface the prefix was added to.
* @param[in] prefix The prefix.
*
* @return 0, on success
* @return -ENOMEM, if no space for the new prefix is available.
* @return -ENOENT, if @p abr is not registered.
*/
int gnrc_sixlowpan_nd_router_abr_add_prf(gnrc_sixlowpan_nd_router_abr_t* abr,
gnrc_ipv6_netif_t *iface, gnrc_ipv6_netif_addr_t *prefix);
/**
* @brief Removes a prefix from this border router.
*
* @param[in] abr The local border router.
* @param[in] iface The IPv6 interface the prefix was added to.
* @param[in] prefix The prefix.
*/
void gnrc_sixlowpan_nd_router_abr_rem_prf(gnrc_sixlowpan_nd_router_abr_t *abr,
gnrc_ipv6_netif_t *iface, gnrc_ipv6_netif_addr_t *prefix);
/**
* @brief Adds a context for this border router to manage.
*
* @param[in] abr The local border router
* @param[in] cid The context to be add.
*
* @return 0, on success
* @return -EINVAL, if @p ctx is greater than 15.
* @return -ENOENT, if @p abr is not registered.
*/
int gnrc_sixlowpan_nd_router_abr_add_ctx(gnrc_sixlowpan_nd_router_abr_t *abr, uint8_t cid);
/**
* @brief Removes a context from this border router.
*
* @param[in] abr The local border router.
* @param[in] cid The context to be remove.
*/
void gnrc_sixlowpan_nd_router_abr_rem_ctx(gnrc_sixlowpan_nd_router_abr_t *abr, uint8_t cid);
#else
#define gnrc_sixlowpan_nd_router_abr_create(addr, ltime) (NULL)
#endif
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_SIXLOWPAN_ND_ROUTER_H */
/** @} */

View File

@ -16,9 +16,6 @@ endif
ifneq (,$(filter gnrc_ipv6_hdr,$(USEMODULE)))
DIRS += network_layer/ipv6/hdr
endif
ifneq (,$(filter gnrc_ipv6_nc,$(USEMODULE)))
DIRS += network_layer/ipv6/nc
endif
ifneq (,$(filter gnrc_ipv6_nib,$(USEMODULE)))
DIRS += network_layer/ipv6/nib
endif
@ -28,21 +25,6 @@ endif
ifneq (,$(filter gnrc_ipv6_blacklist,$(USEMODULE)))
DIRS += network_layer/ipv6/blacklist
endif
ifneq (,$(filter gnrc_ndp,$(USEMODULE)))
DIRS += network_layer/ndp
endif
ifneq (,$(filter gnrc_ndp_internal,$(USEMODULE)))
DIRS += network_layer/ndp/internal
endif
ifneq (,$(filter gnrc_ndp_host,$(USEMODULE)))
DIRS += network_layer/ndp/host
endif
ifneq (,$(filter gnrc_ndp_node,$(USEMODULE)))
DIRS += network_layer/ndp/node
endif
ifneq (,$(filter gnrc_ndp_router,$(USEMODULE)))
DIRS += network_layer/ndp/router
endif
ifneq (,$(filter gnrc_ndp2,$(USEMODULE)))
DIRS += network_layer/ndp2
endif
@ -106,9 +88,6 @@ 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_sock,$(USEMODULE)))
DIRS += sock
endif

View File

@ -73,8 +73,7 @@ void gnrc_icmpv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt)
return;
}
/* Note: size will be checked again in gnrc_icmpv6_echo_req_handle,
gnrc_ndp_rtr_sol_handle, and others */
/* Note: size will be checked again in packet handlers */
hdr = (icmpv6_hdr_t *)icmpv6->data;

View File

@ -21,10 +21,8 @@
#include "kernel_types.h"
#include "net/gnrc.h"
#include "net/gnrc/icmpv6.h"
#include "net/gnrc/ndp.h"
#include "net/gnrc/sixlowpan/ctx.h"
#include "net/gnrc/sixlowpan/nd.h"
#include "net/gnrc/sixlowpan/nd/router.h"
#include "net/protnum.h"
#include "thread.h"
#include "utlist.h"

View File

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

View File

@ -1,295 +0,0 @@
/*
* 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 <errno.h>
#include <string.h>
#include "net/gnrc/ipv6.h"
#include "net/ipv6/addr.h"
#include "net/gnrc/ipv6/nc.h"
#include "net/gnrc/ipv6/netif.h"
#include "net/gnrc/ndp.h"
#include "net/gnrc/pktbuf.h"
#include "net/gnrc/sixlowpan/nd.h"
#include "thread.h"
#include "xtimer.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if ENABLE_DEBUG
/* For PRIu8 etc. */
#include <inttypes.h>
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
#endif
static gnrc_ipv6_nc_t ncache[GNRC_IPV6_NC_SIZE];
static void _nc_remove(kernel_pid_t iface, gnrc_ipv6_nc_t *entry)
{
(void) iface;
if (entry == NULL) {
return;
}
DEBUG("ipv6_nc: Remove %s for interface %" PRIkernel_pid "\n",
ipv6_addr_to_str(addr_str, &(entry->ipv6_addr), sizeof(addr_str)),
iface);
#ifdef MODULE_GNRC_NDP_NODE
while (entry->pkts != NULL) {
gnrc_pktbuf_release(entry->pkts->pkt);
entry->pkts->pkt = NULL;
gnrc_pktqueue_remove_head(&entry->pkts);
}
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
xtimer_remove(&entry->type_timeout);
gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);
if ((if_entry != NULL) && (if_entry->rtr_adv_msg.content.ptr == entry)) {
/* cancel timer set by gnrc_ndp_rtr_sol_handle */
xtimer_remove(&if_entry->rtr_adv_timer);
}
#endif
#if defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER)
xtimer_remove(&entry->rtr_adv_timer);
#endif
xtimer_remove(&entry->rtr_timeout);
xtimer_remove(&entry->nbr_sol_timer);
xtimer_remove(&entry->nbr_adv_timer);
ipv6_addr_set_unspecified(&(entry->ipv6_addr));
entry->iface = KERNEL_PID_UNDEF;
entry->flags = 0;
}
void gnrc_ipv6_nc_init(void)
{
gnrc_ipv6_nc_t *entry;
for (entry = ncache; entry < (ncache + GNRC_IPV6_NC_SIZE); entry++) {
_nc_remove(entry->iface, entry);
}
memset(ncache, 0, sizeof(ncache));
}
gnrc_ipv6_nc_t *_find_free_entry(void)
{
for (int i = 0; i < GNRC_IPV6_NC_SIZE; i++) {
if (ipv6_addr_is_unspecified(&(ncache[i].ipv6_addr))) {
return ncache + i;
}
}
return NULL;
}
gnrc_ipv6_nc_t *gnrc_ipv6_nc_add(kernel_pid_t iface, const ipv6_addr_t *ipv6_addr,
const void *l2_addr, size_t l2_addr_len, uint8_t flags)
{
gnrc_ipv6_nc_t *free_entry = NULL;
if (ipv6_addr == NULL) {
DEBUG("ipv6_nc: address was NULL\n");
return NULL;
}
if ((l2_addr_len > GNRC_IPV6_NC_L2_ADDR_MAX) || ipv6_addr_is_unspecified(ipv6_addr)) {
DEBUG("ipv6_nc: invalid parameters\n");
return NULL;
}
for (int i = 0; i < GNRC_IPV6_NC_SIZE; i++) {
if (ipv6_addr_equal(&(ncache[i].ipv6_addr), ipv6_addr)) {
DEBUG("ipv6_nc: Address %s already registered.\n",
ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)));
if ((l2_addr != NULL) && (l2_addr_len > 0)) {
DEBUG("ipv6_nc: Update to L2 address %s",
gnrc_netif_addr_to_str(addr_str, sizeof(addr_str),
l2_addr, l2_addr_len));
memcpy(&(ncache[i].l2_addr), l2_addr, l2_addr_len);
ncache[i].l2_addr_len = l2_addr_len;
ncache[i].flags = flags;
DEBUG(" with flags = 0x%0x\n", flags);
}
return &ncache[i];
}
if (ipv6_addr_is_unspecified(&(ncache[i].ipv6_addr)) && !free_entry) {
/* found the first free entry */
free_entry = &ncache[i];
}
}
if (!free_entry) {
/* reached end of NC without finding updateable or free entry */
DEBUG("ipv6_nc: neighbor cache full.\n");
return NULL;
}
/* Otherwise, fill free entry with your fresh information */
free_entry->iface = iface;
#ifdef MODULE_GNRC_NDP_NODE
free_entry->pkts = NULL;
#endif
memcpy(&(free_entry->ipv6_addr), ipv6_addr, sizeof(ipv6_addr_t));
DEBUG("ipv6_nc: Register %s for interface %" PRIkernel_pid,
ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)),
iface);
if ((l2_addr != NULL) && (l2_addr_len > 0)) {
DEBUG(" to L2 address %s",
gnrc_netif_addr_to_str(addr_str, sizeof(addr_str),
l2_addr, l2_addr_len));
memcpy(&(free_entry->l2_addr), l2_addr, l2_addr_len);
free_entry->l2_addr_len = l2_addr_len;
}
free_entry->flags = flags;
DEBUG(" with flags = 0x%0x\n", flags);
if (gnrc_ipv6_nc_get_state(free_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) {
DEBUG("ipv6_nc: Set remaining probes to %" PRIu8 "\n", (uint8_t) GNRC_NDP_MAX_MC_NBR_SOL_NUMOF);
free_entry->probes_remaining = GNRC_NDP_MAX_MC_NBR_SOL_NUMOF;
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
free_entry->type_timeout_msg.type = GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT;
free_entry->type_timeout_msg.content.ptr = free_entry;
#endif
free_entry->rtr_timeout_msg.type = GNRC_NDP_MSG_RTR_TIMEOUT;
free_entry->rtr_timeout_msg.content.ptr = free_entry;
#if defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER)
free_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_DELAY;
free_entry->rtr_adv_msg.content.ptr = free_entry;
#endif
free_entry->nbr_sol_msg.content.ptr = free_entry;
return free_entry;
}
void gnrc_ipv6_nc_remove(kernel_pid_t iface, const ipv6_addr_t *ipv6_addr)
{
gnrc_ipv6_nc_t *entry = gnrc_ipv6_nc_get(iface, ipv6_addr);
_nc_remove(iface, entry);
}
gnrc_ipv6_nc_t *gnrc_ipv6_nc_get(kernel_pid_t iface, const ipv6_addr_t *ipv6_addr)
{
if ((ipv6_addr == NULL) || (ipv6_addr_is_unspecified(ipv6_addr))) {
DEBUG("ipv6_nc: address was NULL or ::\n");
return NULL;
}
for (int i = 0; i < GNRC_IPV6_NC_SIZE; i++) {
if (((ncache[i].iface == KERNEL_PID_UNDEF) || (iface == KERNEL_PID_UNDEF) ||
(iface == ncache[i].iface)) &&
ipv6_addr_equal(&(ncache[i].ipv6_addr), ipv6_addr)) {
DEBUG("ipv6_nc: Found entry for %s on interface %" PRIkernel_pid
" (0 = all interfaces) [%p]\n",
ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)),
iface, (void *)(ncache + i));
return ncache + i;
}
}
return NULL;
}
gnrc_ipv6_nc_t *gnrc_ipv6_nc_get_next(gnrc_ipv6_nc_t *prev)
{
if (prev == NULL) {
prev = ncache;
}
else {
prev++; /* get next entry */
}
while (prev < (ncache + GNRC_IPV6_NC_SIZE)) { /* while not reached end */
if (!ipv6_addr_is_unspecified(&(prev->ipv6_addr))) {
return prev;
}
prev++;
}
return NULL;
}
gnrc_ipv6_nc_t *gnrc_ipv6_nc_get_next_router(gnrc_ipv6_nc_t *prev)
{
for (gnrc_ipv6_nc_t *router = gnrc_ipv6_nc_get_next(prev); router != NULL;
router = gnrc_ipv6_nc_get_next(router)) {
if (router->flags & GNRC_IPV6_NC_IS_ROUTER) {
return router;
}
}
return NULL;
}
gnrc_ipv6_nc_t *gnrc_ipv6_nc_still_reachable(const ipv6_addr_t *ipv6_addr)
{
gnrc_ipv6_nc_t *entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, ipv6_addr);
if (entry == NULL) {
DEBUG("ipv6_nc: No entry found for %s\n",
ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)));
return NULL;
}
if ((gnrc_ipv6_nc_get_state(entry) != GNRC_IPV6_NC_STATE_INCOMPLETE) &&
(gnrc_ipv6_nc_get_state(entry) != GNRC_IPV6_NC_STATE_UNMANAGED)) {
#if defined(MODULE_GNRC_IPV6_NETIF) && defined(MODULE_XTIMER) && defined(MODULE_GNRC_IPV6)
gnrc_ipv6_netif_t *iface = gnrc_ipv6_netif_get(entry->iface);
gnrc_ndp_internal_reset_nbr_sol_timer(entry, iface->reach_time,
GNRC_NDP_MSG_NC_STATE_TIMEOUT, gnrc_ipv6_pid);
#endif
DEBUG("ipv6_nc: Marking entry %s as reachable\n",
ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)));
entry->flags &= ~(GNRC_IPV6_NC_STATE_MASK >> GNRC_IPV6_NC_STATE_POS);
entry->flags |= (GNRC_IPV6_NC_STATE_REACHABLE >> GNRC_IPV6_NC_STATE_POS);
}
return entry;
}
kernel_pid_t gnrc_ipv6_nc_get_l2_addr(uint8_t *l2_addr, uint8_t *l2_addr_len,
const gnrc_ipv6_nc_t *entry)
{
assert((l2_addr != NULL) && (l2_addr_len != NULL));
if ((entry == NULL) || !gnrc_ipv6_nc_is_reachable(entry)) {
return KERNEL_PID_UNDEF;
}
*l2_addr_len = entry->l2_addr_len;
memcpy(l2_addr, entry->l2_addr, entry->l2_addr_len);
return entry->iface;
}
/** @} */

View File

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

View File

@ -1,900 +0,0 @@
/*
* 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.
*/
/**
* @ingroup net_gnrc_ndp
* @{
*
* @file
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <errno.h>
#include <string.h>
#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"
#include "net/gnrc/sixlowpan/nd.h"
#include "net/gnrc.h"
#include "net/sixlowpan/nd.h"
#include "random.h"
#include "utlist.h"
#include "thread.h"
#include "xtimer.h"
#include "net/gnrc/ndp/internal.h"
#include "net/gnrc/ndp.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if ENABLE_DEBUG
/* For PRIu8 etc. */
#include <inttypes.h>
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
#endif
/* sets an entry to stale if its l2addr differs from the given one or creates it stale if it
* does not exist */
static void _stale_nc(kernel_pid_t iface, ipv6_addr_t *ipaddr, uint8_t *l2addr,
int l2addr_len)
{
if (l2addr_len != -ENOTSUP) {
gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, ipaddr);
if (nc_entry == NULL) {
gnrc_ipv6_nc_add(iface, ipaddr, l2addr, (uint16_t)l2addr_len,
GNRC_IPV6_NC_STATE_STALE);
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
/* unreachable set in gnrc_ndp_retrans_nbr_sol() will just be staled */
else if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_UNREACHABLE) {
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
}
#endif
else if (((uint16_t)l2addr_len != nc_entry->l2_addr_len) ||
(memcmp(l2addr, nc_entry->l2_addr, l2addr_len) != 0)) {
/* if entry exists but l2 address differs: set */
nc_entry->l2_addr_len = (uint16_t)l2addr_len;
memcpy(nc_entry->l2_addr, l2addr, l2addr_len);
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
}
}
}
void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
ipv6_hdr_t *ipv6, ndp_nbr_sol_t *nbr_sol,
size_t icmpv6_size)
{
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, 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)));
DEBUG("dst: %s, ",
ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
DEBUG("tgt: %s)\n",
ipv6_addr_to_str(addr_str, &nbr_sol->tgt, sizeof(addr_str)));
/* check validity */
if ((ipv6->hl != 255) || (nbr_sol->code != 0) ||
(icmpv6_size < sizeof(ndp_nbr_sol_t)) ||
ipv6_addr_is_multicast(&nbr_sol->tgt) ||
(ipv6_addr_is_unspecified(&ipv6->src) &&
ipv6_addr_is_solicited_node(&ipv6->dst))) {
DEBUG("ndp: neighbor solicitation was invalid.\n");
/* icmpv6 releases */
return;
}
if ((tgt = gnrc_ipv6_netif_find_addr(iface, &nbr_sol->tgt)) == NULL) {
DEBUG("ndp: Target address is not to interface %" PRIkernel_pid "\n",
iface);
/* icmpv6 releases */
return;
}
sicmpv6_size -= sizeof(ndp_nbr_sol_t);
while (sicmpv6_size > 0) {
ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
switch (opt->type) {
case NDP_OPT_SL2A:
if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, nbr_sol->type, opt,
l2src)) < 0) {
/* -ENOTSUP can not happen, since the function only returns this for invalid
* message types containing the SL2A. Neighbor solicitations are not an
* invalid message type for SL2A. According to that, we don't need to watch
* out for that here, but regardless, the source link-layer address option
* 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 */
break;
}
opt_offset += (opt->len * 8);
sicmpv6_size -= (opt->len * 8);
#if ENABLE_DEBUG
if (sicmpv6_size < 0) {
DEBUG("ndp: Option parsing out of sync.\n");
}
#endif
}
#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,
&ipv6->src, 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_aiid(&nbr_adv_dst, iid.uint8);
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);
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)
{
return (netif_hdr != NULL) && (netif_hdr->src_l2addr_len != 0) &&
(netif_hdr->dst_l2addr_len != 0);
}
void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
ipv6_hdr_t *ipv6, ndp_nbr_adv_t *nbr_adv,
size_t icmpv6_size)
{
uint16_t opt_offset = 0;
uint8_t *buf = ((uint8_t *)nbr_adv) + sizeof(ndp_nbr_adv_t);
int l2tgt_len = 0;
uint8_t l2tgt[GNRC_IPV6_NC_L2_ADDR_MAX];
int sicmpv6_size = (int)icmpv6_size;
gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &nbr_adv->tgt);
gnrc_pktsnip_t *netif;
gnrc_netif_hdr_t *netif_hdr = NULL;
DEBUG("ndp: received neighbor advertisement (src: %s, ",
ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
DEBUG("dst: %s, ",
ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
DEBUG("tgt: %s)\n",
ipv6_addr_to_str(addr_str, &nbr_adv->tgt, sizeof(addr_str)));
/* check validity */
if ((ipv6->hl != 255) || (nbr_adv->code != 0) ||
(icmpv6_size < sizeof(ndp_nbr_adv_t)) ||
ipv6_addr_is_multicast(&nbr_adv->tgt)) {
DEBUG("ndp: neighbor advertisement was invalid.\n");
/* icmpv6 releases */
return;
}
if (nc_entry == NULL) {
/* see https://tools.ietf.org/html/rfc4861#section-7.2.5 */
DEBUG("ndp: no neighbor cache entry found for advertisement's target\n");
/* icmpv6 releases */
return;
}
sicmpv6_size -= sizeof(ndp_nbr_adv_t);
while (sicmpv6_size > 0) {
ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
switch (opt->type) {
case NDP_OPT_TL2A:
if ((l2tgt_len = gnrc_ndp_internal_tl2a_opt_handle(pkt, ipv6, nbr_adv->type, opt, l2tgt)) < 0) {
/* invalid target link-layer address option */
return;
}
break;
#ifdef MODULE_GNRC_SIXLOWPAN_ND
case NDP_OPT_AR:
/* address registration option is always ignored when invalid */
gnrc_sixlowpan_nd_opt_ar_handle(iface, ipv6, nbr_adv->type,
&nbr_adv->tgt,
(sixlowpan_nd_opt_ar_t *)opt,
NULL, 0);
break;
#endif
default:
/* silently discard all other options */
break;
}
opt_offset += (opt->len * 8);
sicmpv6_size -= (opt->len * 8);
#if ENABLE_DEBUG
if (sicmpv6_size < 0) {
DEBUG("ndp: Option parsing out of sync.\n");
}
#endif
}
netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
if (netif != NULL) {
netif_hdr = netif->data;
}
if (l2tgt_len != -ENOTSUP) {
#ifdef MODULE_GNRC_SIXLOWPAN_ND
/* check if entry wasn't removed by ARO, ideally there should not be any TL2A in here */
nc_entry = gnrc_ipv6_nc_get(iface, &nbr_adv->tgt);
if (nc_entry == NULL) {
return;
}
#endif
if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) {
if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) {
/* link-layer has addresses, but no TLLAO supplied: discard silently
* (see https://tools.ietf.org/html/rfc4861#section-7.2.5) */
return;
}
nc_entry->iface = iface;
nc_entry->l2_addr_len = l2tgt_len;
memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) {
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE);
}
else {
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
}
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_R) {
nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER;
}
else {
nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
/* TODO: update state of neighbor as router in FIB? */
}
#ifdef MODULE_GNRC_NDP_NODE
gnrc_pktqueue_t *queued_pkt;
while ((queued_pkt = gnrc_pktqueue_remove_head(&nc_entry->pkts)) != NULL) {
if (gnrc_netapi_send(gnrc_ipv6_pid, queued_pkt->pkt) < 1) {
DEBUG("ndp: unable to send queued packet\n");
gnrc_pktbuf_release(queued_pkt->pkt);
}
queued_pkt->pkt = NULL;
}
#endif
}
else {
/* first or-term: no link-layer, but nc_entry has l2addr,
* second or-term: different l2addr cached */
bool l2tgt_changed = false;
if ((!_pkt_has_l2addr(netif_hdr)) && (l2tgt_len == 0)) {
/* there was previously a L2 address registered */
l2tgt_changed = (nc_entry->l2_addr_len != 0);
}
/* link-layer has addresses and TLLAO with different address */
else if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len != 0)) {
l2tgt_changed = (!(l2tgt_len == nc_entry->l2_addr_len)) &&
(memcmp(nc_entry->l2_addr, l2tgt, l2tgt_len) == 0);
}
if ((nbr_adv->flags & NDP_NBR_ADV_FLAGS_O) || !l2tgt_changed ||
(l2tgt_len == 0)) {
if (l2tgt_len != 0) {
nc_entry->iface = iface;
nc_entry->l2_addr_len = l2tgt_len;
memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);
}
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) {
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE);
}
else if (l2tgt_changed) {
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
}
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_R) {
nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER;
}
else {
nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
/* TODO: update state of neighbor as router in FIB? */
}
}
else if (l2tgt_changed &&
gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_REACHABLE) {
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
}
}
}
return;
}
#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
void gnrc_ndp_rtr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
ipv6_hdr_t *ipv6, ndp_rtr_sol_t *rtr_sol,
size_t icmpv6_size)
{
gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);
if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) {
gnrc_ipv6_nc_t *nc_entry;
int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
uint16_t opt_offset = 0;
uint8_t *buf = (uint8_t *)(rtr_sol + 1);
/* check validity */
if ((ipv6->hl != 255) || (rtr_sol->code != 0) ||
(icmpv6_size < sizeof(ndp_rtr_sol_t))) {
DEBUG("ndp: router solicitation was invalid\n");
return;
}
sicmpv6_size -= sizeof(ndp_rtr_sol_t);
while (sicmpv6_size > 0) {
ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
switch (opt->type) {
case NDP_OPT_SL2A:
l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6,
rtr_sol->type,
opt, l2src);
if (l2src_len < 0) {
/* -ENOTSUP can not happen */
/* invalid source link-layer address option */
return;
}
_stale_nc(iface, &ipv6->src, l2src, l2src_len);
break;
default:
/* silently discard all other options */
break;
}
opt_offset += (opt->len * 8);
sicmpv6_size -= (opt->len * 8);
#if ENABLE_DEBUG
if (sicmpv6_size < 0) {
DEBUG("ndp: Option parsing out of sync.\n");
}
#endif
}
/* send delayed */
if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) {
uint32_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 = random_uint32_range(0, ms);
xtimer_remove(&if_entry->rtr_adv_timer);
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
/* in case of a 6LBR we have to check if the interface is actually
* the 6lo interface */
if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
if (nc_entry != NULL) {
if_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_SIXLOWPAN_DELAY;
if_entry->rtr_adv_msg.content.ptr = nc_entry;
xtimer_set_msg(&if_entry->rtr_adv_timer, delay, &if_entry->rtr_adv_msg,
gnrc_ipv6_pid);
}
}
#elif defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER)
if (ipv6_addr_is_unspecified(&ipv6->src)) {
/* either multicast, if source unspecified */
if_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_RETRANS;
if_entry->rtr_adv_msg.content.ptr = if_entry;
xtimer_set_msg(&if_entry->rtr_adv_timer, delay, &if_entry->rtr_adv_msg,
gnrc_ipv6_pid);
}
else {
/* or unicast, if source is known */
/* XXX: can't just use GNRC_NETAPI_MSG_TYPE_SND, since the next retransmission
* must also be set. */
nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
if (nc_entry) {
xtimer_set_msg(&nc_entry->rtr_adv_timer, delay, &nc_entry->rtr_adv_msg,
gnrc_ipv6_pid);
}
}
#endif
}
nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
if (nc_entry != NULL) {
/* unset isRouter flag
* (https://tools.ietf.org/html/rfc4861#section-6.2.6) */
nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
}
}
/* otherwise ignore silently */
}
#endif
static inline void _set_reach_time(gnrc_ipv6_netif_t *if_entry, uint32_t mean)
{
uint32_t reach_time = random_uint32_range(GNRC_NDP_MIN_RAND, GNRC_NDP_MAX_RAND);
if_entry->reach_time_base = mean;
/* to avoid floating point number computation and have higher value entropy, the
* boundaries for the random value are multiplied by 10 and we need to account for that */
reach_time = (reach_time * if_entry->reach_time_base) / 10;
if_entry->reach_time = reach_time;
}
void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6,
ndp_rtr_adv_t *rtr_adv, size_t icmpv6_size)
{
uint8_t *buf = (uint8_t *)(rtr_adv + 1);
gnrc_ipv6_nc_t *nc_entry = NULL;
gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);
uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
#ifdef MODULE_GNRC_SIXLOWPAN_ND
uint32_t next_rtr_sol = 0;
#endif
int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
uint16_t opt_offset = 0;
if (!ipv6_addr_is_link_local(&ipv6->src) ||
ipv6_addr_is_multicast(&ipv6->src) ||
(ipv6->hl != 255) || (rtr_adv->code != 0) ||
(icmpv6_size < sizeof(ndp_rtr_adv_t))) {
DEBUG("ndp: router advertisement was invalid\n");
/* icmpv6 releases */
return;
}
/* get source from default router list */
nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
if (nc_entry == NULL) { /* not in default router list */
/* create default router list entry */
nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, NULL, 0,
GNRC_IPV6_NC_STATE_STALE | GNRC_IPV6_NC_IS_ROUTER);
if (nc_entry == NULL) {
DEBUG("ndp: error on default router list entry creation\n");
return;
}
}
else if ((nc_entry->flags & GNRC_IPV6_NC_IS_ROUTER) && (byteorder_ntohs(rtr_adv->ltime) == 0)) {
nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
}
else {
nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER;
}
/* set router life timer */
if (rtr_adv->ltime.u16 != 0) {
uint16_t ltime = byteorder_ntohs(rtr_adv->ltime);
#ifdef MODULE_GNRC_SIXLOWPAN_ND
next_rtr_sol = ltime;
#endif
xtimer_set_msg(&nc_entry->rtr_timeout, (ltime * US_PER_SEC),
&nc_entry->rtr_timeout_msg, thread_getpid());
}
/* set current hop limit from message if available */
if (rtr_adv->cur_hl != 0) {
if_entry->cur_hl = rtr_adv->cur_hl;
}
/* set flags from message */
if_entry->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK;
if_entry->flags |= (rtr_adv->flags << GNRC_IPV6_NETIF_FLAGS_RTR_ADV_POS) &
GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK;
/* set reachable time from message if it is not the same as the random base
* value */
if ((rtr_adv->reach_time.u32 != 0) &&
(if_entry->reach_time_base != byteorder_ntohl(rtr_adv->reach_time))) {
_set_reach_time(if_entry, byteorder_ntohl(rtr_adv->reach_time));
}
/* set retransmission timer from message */
if (rtr_adv->retrans_timer.u32 != 0) {
if_entry->retrans_timer = byteorder_ntohl(rtr_adv->retrans_timer);
}
mutex_unlock(&if_entry->mutex);
sicmpv6_size -= sizeof(ndp_rtr_adv_t);
/* parse options */
while (sicmpv6_size > 0) {
ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
switch (opt->type) {
case NDP_OPT_SL2A:
if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_adv->type, opt,
l2src)) < 0) {
/* -ENOTSUP can not happen */
/* invalid source link-layer address option */
return;
}
break;
case NDP_OPT_MTU:
if (!gnrc_ndp_internal_mtu_opt_handle(iface, rtr_adv->type, (ndp_opt_mtu_t *)opt)) {
/* invalid MTU option */
return;
}
break;
case NDP_OPT_PI:
if (!gnrc_ndp_internal_pi_opt_handle(iface, rtr_adv->type, (ndp_opt_pi_t *)opt)) {
/* invalid prefix information option */
return;
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND
uint32_t valid_ltime = byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime);
if ((valid_ltime != 0) && (valid_ltime < next_rtr_sol)) {
next_rtr_sol = valid_ltime;
}
#endif
break;
#ifdef MODULE_GNRC_SIXLOWPAN_ND
case NDP_OPT_6CTX:
if (!gnrc_sixlowpan_nd_opt_6ctx_handle(rtr_adv->type,
(sixlowpan_nd_opt_6ctx_t *)opt)) {
/* invalid 6LoWPAN context option */
return;
}
uint16_t ltime = byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime);
if ((ltime != 0) && (ltime < (next_rtr_sol / 60))) {
next_rtr_sol = ltime * 60;
}
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
}
opt_offset += (opt->len * 8);
sicmpv6_size -= (opt->len * 8);
#if ENABLE_DEBUG
if (sicmpv6_size < 0) {
DEBUG("ndp: Option parsing out of sync.\n");
}
#endif
}
#if ENABLE_DEBUG && defined(MODULE_GNRC_SIXLOWPAN_ND)
if ((if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (l2src_len <= 0)) {
DEBUG("ndp: Router advertisement did not contain any source address information\n");
}
#endif
_stale_nc(iface, &ipv6->src, l2src, l2src_len);
/* stop multicast router solicitation retransmission timer */
xtimer_remove(&if_entry->rtr_sol_timer);
#ifdef MODULE_GNRC_SIXLOWPAN_ND
if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
/* 3/4 of the time should be "well before" enough the respective timeout
* not to run out; see https://tools.ietf.org/html/rfc6775#section-5.4.3 */
next_rtr_sol *= 3;
next_rtr_sol = (next_rtr_sol > 4) ? (next_rtr_sol >> 2) : 1;
/* according to https://tools.ietf.org/html/rfc6775#section-5.3:
* "In all cases, the RS retransmissions are terminated when an RA is
* received."
* Hence, reset router solicitation counter and reset timer. */
if_entry->rtr_sol_count = 0;
gnrc_sixlowpan_nd_rtr_sol_reschedule(nc_entry, next_rtr_sol);
gnrc_ndp_internal_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr,
&nc_entry->ipv6_addr);
if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) {
gnrc_ipv6_netif_set_rtr_adv(if_entry, true);
}
}
#endif
}
void gnrc_ndp_retrans_nbr_sol(gnrc_ipv6_nc_t *nc_entry)
{
if ((gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) ||
(gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_PROBE)) {
if (nc_entry->probes_remaining > 1) {
ipv6_addr_t dst;
DEBUG("ndp: Retransmit neighbor solicitation for %s\n",
ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)));
/* retransmit neighbor solicatation */
if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) {
ipv6_addr_set_solicited_nodes(&dst, &nc_entry->ipv6_addr);
}
else {
dst.u64[0] = nc_entry->ipv6_addr.u64[0];
dst.u64[1] = nc_entry->ipv6_addr.u64[1];
}
nc_entry->probes_remaining--;
if (nc_entry->iface == KERNEL_PID_UNDEF) {
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
size_t ifnum = gnrc_netif_get(ifs);
for (size_t i = 0; i < ifnum; i++) {
gnrc_ndp_internal_send_nbr_sol(ifs[i], NULL, &nc_entry->ipv6_addr, &dst);
}
gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, GNRC_NDP_RETRANS_TIMER,
GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid);
}
else {
gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(nc_entry->iface);
gnrc_ndp_internal_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr, &dst);
mutex_lock(&ipv6_iface->mutex);
gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, ipv6_iface->retrans_timer,
GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid);
mutex_unlock(&ipv6_iface->mutex);
}
}
/* cppcheck-suppress knownConditionTrueFalse
* cppcheck bug: probes_remaining is initialized to a value > 1 */
else if (nc_entry->probes_remaining <= 1) {
/* For a 6LoWPAN router entries may be set to UNREACHABLE instead
* of removing them, since RFC6775, section 6
* (https://tools.ietf.org/html/rfc6775#section-6) says: "if NUD on
* the router determines that the host is UNREACHABLE (based on the
* logic in [RFC4861]), the NCE SHOULD NOT be deleted but rather
* retained until the Registration Lifetime expires." However, this
* "SHOULD NOT" is not implemented to circumvent NCEs going into
* UNREACHABLE forever and in order to save some memory in the
* neighbor cache. */
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);
gnrc_ipv6_nc_remove(nc_entry->iface, &nc_entry->ipv6_addr);
}
}
}
void gnrc_ndp_state_timeout(gnrc_ipv6_nc_t *nc_entry)
{
switch (gnrc_ipv6_nc_get_state(nc_entry)) {
case GNRC_IPV6_NC_STATE_REACHABLE:
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
break;
case GNRC_IPV6_NC_STATE_DELAY:
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_PROBE);
break;
default:
break;
}
}
void gnrc_ndp_netif_add(gnrc_ipv6_netif_t *iface)
{
/* set default values */
mutex_lock(&iface->mutex);
_set_reach_time(iface, GNRC_NDP_REACH_TIME);
iface->retrans_timer = GNRC_NDP_RETRANS_TIMER;
mutex_unlock(&iface->mutex);
}
void gnrc_ndp_netif_remove(gnrc_ipv6_netif_t *iface)
{
/* TODO */
(void) iface;
}
gnrc_pktsnip_t *gnrc_ndp_nbr_sol_build(ipv6_addr_t *tgt, gnrc_pktsnip_t *options)
{
gnrc_pktsnip_t *pkt;
DEBUG("ndp: building neighbor solicitation message\n");
if (ipv6_addr_is_multicast(tgt)) {
DEBUG("ndp: tgt must not be multicast\n");
return NULL;
}
pkt = gnrc_icmpv6_build(options, ICMPV6_NBR_SOL, 0, sizeof(ndp_nbr_sol_t));
if (pkt != NULL) {
ndp_nbr_sol_t *nbr_sol = pkt->data;
nbr_sol->resv.u32 = 0;
nbr_sol->tgt.u64[0].u64 = tgt->u64[0].u64;
nbr_sol->tgt.u64[1].u64 = tgt->u64[1].u64;
}
return pkt;
}
gnrc_pktsnip_t *gnrc_ndp_nbr_adv_build(uint8_t flags, ipv6_addr_t *tgt,
gnrc_pktsnip_t *options)
{
gnrc_pktsnip_t *pkt;
DEBUG("ndp: building neighbor advertisement message\n");
if (ipv6_addr_is_multicast(tgt)) {
DEBUG("ndp: tgt must not be multicast\n");
return NULL;
}
pkt = gnrc_icmpv6_build(options, ICMPV6_NBR_ADV, 0, sizeof(ndp_nbr_adv_t));
if (pkt != NULL) {
ndp_nbr_adv_t *nbr_adv = pkt->data;
nbr_adv->flags = (flags & NDP_NBR_ADV_FLAGS_MASK);
nbr_adv->resv[0] = nbr_adv->resv[1] = nbr_adv->resv[2] = 0;
nbr_adv->tgt.u64[0].u64 = tgt->u64[0].u64;
nbr_adv->tgt.u64[1].u64 = tgt->u64[1].u64;
}
return pkt;
}
gnrc_pktsnip_t *gnrc_ndp_rtr_sol_build(gnrc_pktsnip_t *options)
{
gnrc_pktsnip_t *pkt;
DEBUG("ndp: building router solicitation message\n");
pkt = gnrc_icmpv6_build(options, ICMPV6_RTR_SOL, 0, sizeof(ndp_rtr_sol_t));
if (pkt != NULL) {
ndp_rtr_sol_t *rtr_sol = pkt->data;
rtr_sol->resv.u32 = 0;
}
return pkt;
}
static inline size_t _ceil8(uint8_t length)
{
/* NDP options use units of 8 byte for there length field, so round up */
return (length + 7U) & 0xf8U;
}
gnrc_pktsnip_t *gnrc_ndp_opt_build(uint8_t type, size_t size, gnrc_pktsnip_t *next)
{
ndp_opt_t *opt;
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(next, NULL, _ceil8(size), GNRC_NETTYPE_UNDEF);
if (pkt == NULL) {
DEBUG("ndp: no space left in packet buffer\n");
return NULL;
}
opt = pkt->data;
opt->type = type;
opt->len = (uint8_t)(pkt->size / 8);
return pkt;
}
static inline gnrc_pktsnip_t *_opt_l2a_build(uint8_t type, const uint8_t *l2addr,
uint8_t l2addr_len, gnrc_pktsnip_t *next)
{
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(type, sizeof(ndp_opt_t) + l2addr_len, next);
if (pkt != NULL) {
ndp_opt_t *l2a_opt = pkt->data;
memset(l2a_opt + 1, 0, pkt->size - sizeof(ndp_opt_t));
memcpy(l2a_opt + 1, l2addr, l2addr_len);
}
return pkt;
}
gnrc_pktsnip_t *gnrc_ndp_opt_sl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
gnrc_pktsnip_t *next)
{
DEBUG("ndp: building source link-layer address option (l2addr: %s)\n",
gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), l2addr, l2addr_len));
return _opt_l2a_build(NDP_OPT_SL2A, l2addr, l2addr_len, next);
}
gnrc_pktsnip_t *gnrc_ndp_opt_tl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
gnrc_pktsnip_t *next)
{
DEBUG("ndp: building target link-layer address option (l2addr: %s)\n",
gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), l2addr, l2addr_len));
return _opt_l2a_build(NDP_OPT_TL2A, l2addr, l2addr_len, next);
}
#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
gnrc_pktsnip_t *gnrc_ndp_rtr_adv_build(uint8_t cur_hl, uint8_t flags,
uint16_t ltime, uint32_t reach_time,
uint32_t retrans_timer, gnrc_pktsnip_t *options)
{
gnrc_pktsnip_t *pkt;
DEBUG("ndp rtr: building router advertisement message\n");
pkt = gnrc_icmpv6_build(options, ICMPV6_RTR_ADV, 0, sizeof(ndp_rtr_adv_t));
if (pkt != NULL) {
ndp_rtr_adv_t *rtr_adv = pkt->data;
rtr_adv->cur_hl = cur_hl;
rtr_adv->flags = (flags & NDP_RTR_ADV_FLAGS_MASK);
rtr_adv->ltime = byteorder_htons(ltime);
rtr_adv->reach_time = byteorder_htonl(reach_time);
rtr_adv->retrans_timer = byteorder_htonl(retrans_timer);
}
return pkt;
}
gnrc_pktsnip_t *gnrc_ndp_opt_pi_build(uint8_t prefix_len, uint8_t flags,
uint32_t valid_ltime, uint32_t pref_ltime,
ipv6_addr_t *prefix, gnrc_pktsnip_t *next)
{
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_PI, sizeof(ndp_opt_pi_t),
next);
if (pkt != NULL) {
ndp_opt_pi_t *pi_opt = pkt->data;
pi_opt->prefix_len = prefix_len;
pi_opt->flags = (flags & NDP_OPT_PI_FLAGS_MASK);
pi_opt->valid_ltime = byteorder_htonl(valid_ltime);
pi_opt->pref_ltime = byteorder_htonl(pref_ltime);
pi_opt->resv.u32 = 0;
/* Bits beyond prefix_len MUST be 0 */
ipv6_addr_set_unspecified(&pi_opt->prefix);
ipv6_addr_init_prefix(&pi_opt->prefix, prefix, prefix_len);
}
return pkt;
}
gnrc_pktsnip_t *gnrc_ndp_opt_mtu_build(uint32_t mtu, gnrc_pktsnip_t *next)
{
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_MTU, sizeof(ndp_opt_mtu_t),
next);
if (pkt != NULL) {
ndp_opt_mtu_t *mtu_opt = pkt->data;
mtu_opt->resv.u16 = 0;
mtu_opt->mtu = byteorder_htonl(mtu);
}
return pkt;
}
#endif
/**
* @}
*/

View File

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

View File

@ -1,57 +0,0 @@
/*
* 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 <inttypes.h>
#include "random.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/ndp.h"
#include "net/gnrc/ndp/internal.h"
#include "xtimer.h"
#include "net/gnrc/ndp/host.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static inline void _reschedule_rtr_sol(gnrc_ipv6_netif_t *iface, uint32_t delay)
{
xtimer_remove(&iface->rtr_sol_timer);
iface->rtr_sol_msg.type = GNRC_NDP_MSG_RTR_SOL_RETRANS;
iface->rtr_sol_msg.content.ptr = iface;
xtimer_set_msg(&iface->rtr_sol_timer, delay, &iface->rtr_sol_msg, gnrc_ipv6_pid);
}
void gnrc_ndp_host_init(gnrc_ipv6_netif_t *iface)
{
uint32_t interval = random_uint32_range(0, GNRC_NDP_MAX_RTR_SOL_DELAY * US_PER_SEC);
mutex_lock(&iface->mutex);
iface->rtr_sol_count = GNRC_NDP_MAX_RTR_SOL_NUMOF;
DEBUG("ndp host: delayed initial router solicitation by %" PRIu32 " usec.\n", interval);
_reschedule_rtr_sol(iface, interval);
mutex_unlock(&iface->mutex);
}
void gnrc_ndp_host_retrans_rtr_sol(gnrc_ipv6_netif_t *iface)
{
mutex_lock(&iface->mutex);
if (iface->rtr_sol_count > 1) { /* regard off-by-one error */
DEBUG("ndp hst: retransmit rtr sol in %d sec\n", GNRC_NDP_MAX_RTR_SOL_INT);
iface->rtr_sol_count--;
_reschedule_rtr_sol(iface, GNRC_NDP_MAX_RTR_SOL_INT * US_PER_SEC);
}
mutex_unlock(&iface->mutex);
gnrc_ndp_internal_send_rtr_sol(iface->pid, NULL);
}
/** @} */

View File

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

View File

@ -1,860 +0,0 @@
/*
* 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/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 "xtimer.h"
#include "net/gnrc/ndp/internal.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if ENABLE_DEBUG
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
#endif
static gnrc_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) */
static gnrc_pktsnip_t *_build_headers(kernel_pid_t iface, gnrc_pktsnip_t *payload,
ipv6_addr_t *dst, ipv6_addr_t *src);
static size_t _get_l2src(kernel_pid_t iface, uint8_t *l2src, size_t l2src_maxlen);
/**
* @brief Sends @ref GNRC_NETAPI_MSG_TYPE_SND delayed.
*
* @param[in] t Timer for the delay.
* @param[in] msg Msg for the timer.
* @param[in] interval Delay interval.
* @param[in] pkt Packet to send delayed.
*/
static inline void _send_delayed(xtimer_t *t, msg_t *msg, uint32_t interval, gnrc_pktsnip_t *pkt)
{
xtimer_remove(t);
msg->type = GNRC_NETAPI_MSG_TYPE_SND;
msg->content.ptr = pkt;
xtimer_set_msg(t, interval, msg, gnrc_ipv6_pid);
}
ipv6_addr_t *gnrc_ndp_internal_default_router(void)
{
gnrc_ipv6_nc_t *router = gnrc_ipv6_nc_get_next_router(NULL);
/* first look if there is any reachable router */
while (router != NULL) {
if ((gnrc_ipv6_nc_get_state(router) != GNRC_IPV6_NC_STATE_INCOMPLETE) &&
(gnrc_ipv6_nc_get_state(router) != GNRC_IPV6_NC_STATE_UNREACHABLE)) {
_last_router = NULL;
return &router->ipv6_addr;
}
router = gnrc_ipv6_nc_get_next_router(router);
}
/* else take the first one, but keep round-robin in further selections */
router = gnrc_ipv6_nc_get_next_router(_last_router);
if (router == NULL) { /* end of router list or there is none => wrap around */
router = gnrc_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 gnrc_ndp_internal_set_state(gnrc_ipv6_nc_t *nc_entry, uint8_t state)
{
gnrc_ipv6_netif_t *ipv6_iface;
uint32_t t = GNRC_NDP_FIRST_PROBE_DELAY * US_PER_SEC;
nc_entry->flags &= ~GNRC_IPV6_NC_STATE_MASK;
nc_entry->flags |= state;
DEBUG("ndp internal: set %s state to ",
ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)));
switch (state) {
case GNRC_IPV6_NC_STATE_REACHABLE:
ipv6_iface = gnrc_ipv6_netif_get(nc_entry->iface);
DEBUG("REACHABLE (reachable time = %" PRIu32 " us)\n", ipv6_iface->reach_time);
t = ipv6_iface->reach_time;
/* Falls through. */
/* this is intentional to set the desired timeout t */
case GNRC_IPV6_NC_STATE_DELAY:
#if ENABLE_DEBUG
if (state == GNRC_IPV6_NC_STATE_DELAY) {
DEBUG("DELAY (probe with unicast NS in %u seconds)\n",
GNRC_NDP_FIRST_PROBE_DELAY);
}
#endif
gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, t, GNRC_NDP_MSG_NC_STATE_TIMEOUT,
gnrc_ipv6_pid);
break;
case GNRC_IPV6_NC_STATE_PROBE:
ipv6_iface = gnrc_ipv6_netif_get(nc_entry->iface);
nc_entry->probes_remaining = GNRC_NDP_MAX_UC_NBR_SOL_NUMOF;
DEBUG("PROBE (probe with %" PRIu8 " unicast NS every %" PRIu32 " us)\n",
nc_entry->probes_remaining, ipv6_iface->retrans_timer);
gnrc_ndp_internal_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr,
&nc_entry->ipv6_addr);
mutex_lock(&ipv6_iface->mutex);
gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, ipv6_iface->retrans_timer,
GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid);
mutex_unlock(&ipv6_iface->mutex);
break;
#ifdef ENABLE_DEBUG
case GNRC_IPV6_NC_STATE_STALE:
DEBUG("STALE (go into DELAY on next packet)\n");
break;
#endif
default:
DEBUG("errorneous or unknown\n");
break;
}
}
void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_addr_t *dst,
bool supply_tl2a, gnrc_pktsnip_t *ext_opts)
{
gnrc_pktsnip_t *hdr, *pkt = ext_opts;
uint8_t adv_flags = 0;
DEBUG("ndp internal: send neighbor advertisement (iface: %" PRIkernel_pid ", tgt: %s, ",
iface, ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str)));
DEBUG("dst: %s, supply_tl2a: %d)\n",
ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), supply_tl2a);
if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) &&
(gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) {
adv_flags |= NDP_NBR_ADV_FLAGS_R;
}
if (ipv6_addr_is_unspecified(dst)) {
ipv6_addr_set_all_nodes_multicast(dst, IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
}
else {
adv_flags |= NDP_NBR_ADV_FLAGS_S;
}
if (supply_tl2a) {
uint8_t l2src[8];
size_t l2src_len;
/* we previously checked if we are the target, so we can take our L2src */
l2src_len = _get_l2src(iface, l2src, sizeof(l2src));
if (l2src_len > 0) {
/* add target address link-layer address option */
pkt = gnrc_ndp_opt_tl2a_build(l2src, l2src_len, pkt);
if (pkt == NULL) {
DEBUG("ndp internal: error allocating Target Link-layer address option.\n");
gnrc_pktbuf_release(ext_opts);
return;
}
}
}
/* TODO: also check if the node provides proxy servies for tgt */
if ((pkt != NULL) && !gnrc_ipv6_netif_addr_is_non_unicast(tgt)) {
/* TL2A is not supplied and tgt is not anycast */
adv_flags |= NDP_NBR_ADV_FLAGS_O;
}
hdr = gnrc_ndp_nbr_adv_build(adv_flags, tgt, pkt);
if (hdr == NULL) {
DEBUG("ndp internal: error allocating Neighbor advertisement.\n");
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
hdr = _build_headers(iface, pkt, dst, NULL);
if (hdr == NULL) {
DEBUG("ndp internal: error adding lower-layer headers.\n");
gnrc_pktbuf_release(pkt);
return;
}
if (gnrc_ipv6_netif_addr_is_non_unicast(tgt)) {
/* avoid collision for anycast addresses
* (see https://tools.ietf.org/html/rfc4861#section-7.2.7) */
uint32_t delay = random_uint32_range(0, GNRC_NDP_MAX_AC_TGT_DELAY * US_PER_SEC);
gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, dst);
DEBUG("ndp internal: delay neighbor advertisement for %" PRIu32 " sec.",
(delay / US_PER_SEC));
/* nc_entry must be set so no need to check it */
assert(nc_entry);
_send_delayed(&nc_entry->nbr_adv_timer, &nc_entry->nbr_adv_msg, delay, hdr);
}
else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) {
DEBUG("ndp internal: unable to send neighbor advertisement\n");
gnrc_pktbuf_release(hdr);
}
}
void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *tgt,
ipv6_addr_t *dst)
{
#ifdef MODULE_GNRC_SIXLOWPAN_ND
gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
assert(ipv6_iface != NULL);
#endif
gnrc_pktsnip_t *hdr, *pkt = NULL;
/* cppcheck-suppress variableScope
* (reason: they are needed in the MODULE_GNRC_SIXLOWPAN_ND branch) */
uint8_t l2src[8];
/* cppcheck-suppress variableScope
* (reason: they are needed in the MODULE_GNRC_SIXLOWPAN_ND branch) */
size_t l2src_len = 0;
DEBUG("ndp internal: send neighbor solicitation (iface: %" PRIkernel_pid ", src: %s, ",
iface, ipv6_addr_to_str(addr_str, src ? src : &ipv6_addr_unspecified, sizeof(addr_str)));
DEBUG(" tgt: %s, ", ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str)));
DEBUG("dst: %s)\n", ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
/* check if there is a fitting source address to target */
if (src == NULL) {
src = gnrc_ipv6_netif_find_best_src_addr(iface, tgt, false);
}
if (src != NULL) {
l2src_len = _get_l2src(iface, l2src, sizeof(l2src));
if (l2src_len > 0) {
/* add source address link-layer address option */
pkt = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, NULL);
if (pkt == NULL) {
DEBUG("ndp internal: error allocating Source Link-layer address option.\n");
gnrc_pktbuf_release(pkt);
return;
}
}
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND
if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
if (l2src_len != sizeof(eui64_t)) {
l2src_len = (uint16_t)gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, l2src,
sizeof(l2src));
if (l2src_len != sizeof(eui64_t)) {
DEBUG("ndp internal: can't get EUI-64 of the interface\n");
gnrc_pktbuf_release(pkt);
return;
}
}
hdr = gnrc_sixlowpan_nd_opt_ar_build(0, GNRC_SIXLOWPAN_ND_AR_LTIME, (eui64_t *)l2src, pkt);
if (hdr == NULL) {
DEBUG("ndp internal: error allocatin Address Registration option.\n");
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
}
#endif
hdr = gnrc_ndp_nbr_sol_build(tgt, pkt);
if (hdr == NULL) {
DEBUG("ndp internal: error allocating Neighbor solicitation.\n");
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
hdr = _build_headers(iface, pkt, dst, src);
if (hdr == NULL) {
DEBUG("ndp internal: error adding lower-layer headers.\n");
gnrc_pktbuf_release(pkt);
return;
}
else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) {
DEBUG("ndp internal: unable to send neighbor solicitation\n");
gnrc_pktbuf_release(hdr);
}
}
void gnrc_ndp_internal_send_rtr_sol(kernel_pid_t iface, ipv6_addr_t *dst)
{
gnrc_pktsnip_t *hdr, *pkt = NULL;
ipv6_addr_t *src = NULL;
DEBUG("ndp internal: send router solicitation (iface: %" PRIkernel_pid ", dst: ff02::2)\n",
iface);
if (dst == NULL) {
/* isn't changed afterwards so discarding const should be alright */
dst = (ipv6_addr_t *)&ipv6_addr_all_routers_link_local;
}
/* check if there is a fitting source address to target */
if ((src = gnrc_ipv6_netif_find_best_src_addr(iface, dst, false)) != NULL) {
uint8_t l2src[8];
size_t l2src_len;
l2src_len = _get_l2src(iface, l2src, sizeof(l2src));
if (l2src_len > 0) {
/* add source address link-layer address option */
pkt = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, NULL);
if (pkt == NULL) {
DEBUG("ndp internal: error allocating Source Link-layer address option.\n");
gnrc_pktbuf_release(pkt);
return;
}
}
}
hdr = gnrc_ndp_rtr_sol_build(pkt);
if (hdr == NULL) {
DEBUG("ndp internal: error allocating router solicitation.\n");
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
hdr = _build_headers(iface, pkt, dst, src);
if (hdr == NULL) {
DEBUG("ndp internal: error adding lower-layer headers.\n");
gnrc_pktbuf_release(pkt);
return;
}
else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) {
DEBUG("ndp internal: unable to send router solicitation\n");
gnrc_pktbuf_release(hdr);
}
}
#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
static bool _pio_from_iface_addr(gnrc_pktsnip_t **res, gnrc_ipv6_netif_t *iface,
gnrc_ipv6_netif_addr_t *addr, gnrc_pktsnip_t *next)
{
assert(((uint8_t) addr->prefix_len) <= 128U);
if (!ipv6_addr_is_unspecified(&addr->addr) &&
!ipv6_addr_is_link_local(&addr->addr) &&
!gnrc_ipv6_netif_addr_is_non_unicast(&addr->addr)) {
uint8_t flags = 0;
DEBUG(" - PIO for %s/%" PRIu8 "\n", ipv6_addr_to_str(addr_str, &addr->addr,
sizeof(addr_str)),
addr->prefix_len);
#ifdef MODULE_GNRC_SIXLOWPAN_ND
if (!(iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) {
flags = GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK;
}
#else
(void) iface;
#endif
*res = gnrc_ndp_opt_pi_build(addr->prefix_len, addr->flags | flags, addr->valid,
addr->preferred, &addr->addr, next);
return true;
}
return false;
}
static inline bool _check_prefixes(gnrc_ipv6_netif_addr_t *a, gnrc_ipv6_netif_addr_t *b)
{
if ((a->prefix_len == b->prefix_len) &&
(ipv6_addr_match_prefix(&a->addr, &b->addr) >= a->prefix_len)) {
return true;
}
return false;
}
static bool _add_pios(gnrc_pktsnip_t **res, gnrc_ipv6_netif_t *ipv6_iface, gnrc_pktsnip_t *pkt)
{
for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) {
/* skip if prefix has been processed already */
bool processed_before = false;
for (int j = 0; j < i; j++) {
if ((processed_before =
_check_prefixes(&ipv6_iface->addrs[i], &ipv6_iface->addrs[j]))) {
break;
}
}
if (processed_before) {
continue;
}
if (_pio_from_iface_addr(res, ipv6_iface, &ipv6_iface->addrs[i], pkt)) {
if (*res != NULL) {
pkt = *res;
}
else {
DEBUG("ndp rtr: error allocating PIO\n");
gnrc_pktbuf_release(pkt);
return false;
}
}
}
return true;
}
void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst,
bool fin)
{
gnrc_pktsnip_t *hdr = NULL, *pkt = NULL;
gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
uint32_t reach_time = 0, retrans_timer = 0;
uint16_t adv_ltime = 0;
uint8_t cur_hl = 0;
if (dst == NULL) {
/* isn't changed afterwards so discarding const should be fine */
dst = (ipv6_addr_t *)&ipv6_addr_all_nodes_link_local;
}
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
if (!_add_pios(&hdr, ipv6_iface, pkt)) {
/* pkt already released in _add_pios */
mutex_unlock(&ipv6_iface->mutex);
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) {
bool processed_before = false;
/* skip if prefix does not belong to iface */
if (prf->iface != ipv6_iface) {
prf = prf->next;
continue;
}
/* skip if prefix has been processed already */
for (gnrc_sixlowpan_nd_router_prf_t *tmp = abr->prfs; tmp != prf; tmp = tmp->next) {
if ((processed_before =
_check_prefixes(prf->prefix, tmp->prefix))) {
break;
}
}
if (processed_before) {
prf = prf->next;
continue;
}
if (_pio_from_iface_addr(&hdr, ipv6_iface, prf->prefix, pkt)) {
if (hdr != NULL) {
pkt = hdr;
}
else {
DEBUG("ndp rtr: error allocating PIO\n");
gnrc_pktbuf_release(pkt);
mutex_unlock(&ipv6_iface->mutex);
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");
mutex_unlock(&ipv6_iface->mutex);
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");
mutex_unlock(&ipv6_iface->mutex);
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");
mutex_unlock(&ipv6_iface->mutex);
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
}
if (src == NULL) {
mutex_unlock(&ipv6_iface->mutex);
/* get address from source selection algorithm.
* Only link local addresses may be used (RFC 4861 section 4.1) */
src = gnrc_ipv6_netif_find_best_src_addr(iface, dst, true);
mutex_lock(&ipv6_iface->mutex);
}
/* add SL2A for source address */
if (src != NULL) {
DEBUG(" - SL2A\n");
uint8_t l2src[8];
size_t l2src_len;
/* optimization note: MAY also be omitted to facilitate in-bound load balancing over
* replicated interfaces.
* source: https://tools.ietf.org/html/rfc4861#section-6.2.3 */
l2src_len = _get_l2src(iface, l2src, sizeof(l2src));
if (l2src_len > 0) {
/* add source address link-layer address option */
hdr = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, pkt);
if (hdr == NULL) {
DEBUG("ndp internal: error allocating Source Link-layer address option.\n");
mutex_unlock(&ipv6_iface->mutex);
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
}
}
if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_CUR_HL) {
cur_hl = ipv6_iface->cur_hl;
}
if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_REACH_TIME) {
if (ipv6_iface->reach_time > (3600 * US_PER_SEC)) { /* reach_time > 1 hour */
reach_time = (3600 * MS_PER_SEC);
}
else {
reach_time = ipv6_iface->reach_time / US_PER_MS;
}
}
if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_RETRANS_TIMER) {
retrans_timer = ipv6_iface->retrans_timer / US_PER_MS;
}
if (!fin) {
adv_ltime = ipv6_iface->adv_ltime;
}
mutex_unlock(&ipv6_iface->mutex);
hdr = gnrc_ndp_rtr_adv_build(cur_hl,
(ipv6_iface->flags & (GNRC_IPV6_NETIF_FLAGS_OTHER_CONF |
GNRC_IPV6_NETIF_FLAGS_MANAGED)) >> 8,
adv_ltime, reach_time, retrans_timer, pkt);
if (hdr == NULL) {
DEBUG("ndp internal: error allocating router advertisement.\n");
gnrc_pktbuf_release(pkt);
return;
}
pkt = hdr;
hdr = _build_headers(iface, pkt, dst, src);
if (hdr == NULL) {
DEBUG("ndp internal: error adding lower-layer headers.\n");
gnrc_pktbuf_release(pkt);
return;
}
else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) {
DEBUG("ndp internal: unable to send router advertisement\n");
gnrc_pktbuf_release(hdr);
}
}
#endif
int gnrc_ndp_internal_sl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
ndp_opt_t *sl2a_opt, uint8_t *l2src)
{
int sl2a_len = 0;
uint8_t *sl2a = (uint8_t *)(sl2a_opt + 1);
if ((sl2a_opt->len == 0) || ipv6_addr_is_unspecified(&ipv6->src)) {
DEBUG("ndp: invalid source link-layer address option received\n");
return -EINVAL;
}
while (pkt) {
if (pkt->type == GNRC_NETTYPE_NETIF) {
gnrc_netif_hdr_t *hdr = pkt->data;
sl2a_len = hdr->src_l2addr_len;
break;
}
pkt = pkt->next;
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND
if ((sl2a_len == 2) || (sl2a_len == 8)) {
/* The link-layer seems to be IEEE 802.15.4.
* Determining address length from the option length:
* https://tools.ietf.org/html/rfc4944#section-8 */
if (sl2a_opt->len == 1) {
sl2a_len = 2;
}
else if (sl2a_opt->len == 2) {
sl2a_len = 8;
}
else {
DEBUG("ndp: invalid source link-layer address option received\n");
return -EINVAL;
}
}
#endif
DEBUG("ndp: received SL2A (link-layer address: %s)\n",
gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), sl2a, sl2a_len));
switch (icmpv6_type) {
case ICMPV6_RTR_SOL:
case ICMPV6_RTR_ADV:
case ICMPV6_NBR_SOL:
if (sl2a_len == 0) { /* in case there was no source address in l2 */
sl2a_len = (sl2a_opt->len * 8) - sizeof(ndp_opt_t);
/* ignore all zeroes at the end for length */
for (; sl2a[sl2a_len - 1] == 0x00; sl2a_len--);
}
memcpy(l2src, sl2a, sl2a_len);
return sl2a_len;
default: /* wrong encapsulating message: silently discard */
DEBUG("ndp: silently discard sl2a_opt for ICMPv6 message type %"
PRIu8 "\n", icmpv6_type);
return -ENOTSUP;
}
}
int gnrc_ndp_internal_tl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6,
uint8_t icmpv6_type, 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) || ipv6_addr_is_unspecified(&ipv6->src)) {
DEBUG("ndp: invalid target link-layer address option received\n");
return -EINVAL;
}
switch (icmpv6_type) {
case ICMPV6_NBR_ADV:
while (pkt) {
if (pkt->type == GNRC_NETTYPE_NETIF) {
gnrc_netif_hdr_t *hdr = pkt->data;
tl2a_len = hdr->src_l2addr_len;
break;
}
pkt = pkt->next;
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND
if ((tl2a_len == 2) || (tl2a_len == 8)) {
/* The link-layer seems to be IEEE 802.15.4.
* Determining address length from the option length:
* https://tools.ietf.org/html/rfc4944#section-8 */
if (tl2a_opt->len == 1) {
tl2a_len = 2;
}
else if (tl2a_opt->len == 2) {
tl2a_len = 8;
}
else {
DEBUG("ndp: invalid target link-layer address option received\n");
return -EINVAL;
}
}
#endif
if (tl2a_len == 0) { /* in case there was no source address in l2 */
tl2a_len = (tl2a_opt->len / 8) - sizeof(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",
gnrc_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;
}
}
bool gnrc_ndp_internal_mtu_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type,
ndp_opt_mtu_t *mtu_opt)
{
gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);
if ((mtu_opt->len != NDP_OPT_MTU_LEN)) {
DEBUG("ndp: invalid MTU option received\n");
return false;
}
if (icmpv6_type != ICMPV6_RTR_ADV) {
/* else discard silently */
return true;
}
mutex_lock(&if_entry->mutex);
if_entry->mtu = byteorder_ntohl(mtu_opt->mtu);
mutex_unlock(&if_entry->mutex);
return true;
}
bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type,
ndp_opt_pi_t *pi_opt)
{
ipv6_addr_t *prefix;
gnrc_ipv6_netif_addr_t *netif_addr;
if ((pi_opt->len != NDP_OPT_PI_LEN)) {
DEBUG("ndp: invalid PI option received\n");
return false;
}
if (icmpv6_type != ICMPV6_RTR_ADV || ipv6_addr_is_link_local(&pi_opt->prefix)) {
/* else discard silently */
return true;
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND
if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
(pi_opt->flags & NDP_OPT_PI_FLAGS_L)) {
/* ignore: see https://tools.ietf.org/html/rfc6775#section-5.4 */
return true;
}
#endif
prefix = gnrc_ipv6_netif_find_addr(iface, &pi_opt->prefix);
if (((prefix == NULL) ||
(gnrc_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) &&
(pi_opt->valid_ltime.u32 != 0)) {
ipv6_addr_t pref_addr = IPV6_ADDR_UNSPECIFIED;
if (pi_opt->flags & NDP_OPT_PI_FLAGS_A) {
if ((gnrc_netapi_get(iface, NETOPT_IPV6_IID, 0, &pref_addr.u64[1],
sizeof(eui64_t)) < 0)) {
DEBUG("ndp: could not get IID from interface %d\n", iface);
return false;
}
}
ipv6_addr_init_prefix(&pref_addr, &pi_opt->prefix, pi_opt->prefix_len);
prefix = gnrc_ipv6_netif_add_addr(iface, &pref_addr,
pi_opt->prefix_len,
pi_opt->flags & NDP_OPT_PI_FLAGS_MASK);
if (prefix == NULL) {
DEBUG("ndp: could not add prefix to interface %d\n", iface);
return false;
}
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
gnrc_sixlowpan_nd_router_set_rtr_adv(gnrc_ipv6_netif_get(iface), true);
#endif
}
netif_addr = gnrc_ipv6_netif_addr_get(prefix);
if (pi_opt->valid_ltime.u32 == 0) {
if (prefix != NULL) {
gnrc_ipv6_netif_remove_addr(iface, &netif_addr->addr);
}
return true;
}
netif_addr->valid = byteorder_ntohl(pi_opt->valid_ltime);
netif_addr->preferred = byteorder_ntohl(pi_opt->pref_ltime);
if (netif_addr->valid != UINT32_MAX) {
xtimer_set_msg(&netif_addr->valid_timeout,
(byteorder_ntohl(pi_opt->valid_ltime) * US_PER_SEC),
&netif_addr->valid_timeout_msg, thread_getpid());
}
/* TODO: preferred lifetime for address auto configuration */
/* on-link flag MUST stay set if it was */
netif_addr->flags &= NDP_OPT_PI_FLAGS_L;
netif_addr->flags |= (pi_opt->flags & NDP_OPT_PI_FLAGS_MASK);
return true;
}
static size_t _get_l2src(kernel_pid_t iface, uint8_t *l2src, size_t l2src_maxlen)
{
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 ((gnrc_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 = gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0,
l2src, l2src_maxlen)) > max_short_len)) {
l2src_len = (uint16_t)res;
}
else if ((res = gnrc_netapi_get(iface, NETOPT_ADDRESS, 0, l2src,
l2src_maxlen)) >= 0) {
l2src_len = (uint16_t)res;
}
else {
DEBUG("ndp internal: no link-layer address found.\n");
l2src_len = 0;
}
return l2src_len;
}
static gnrc_pktsnip_t *_build_headers(kernel_pid_t iface, gnrc_pktsnip_t *payload,
ipv6_addr_t *dst, ipv6_addr_t *src)
{
gnrc_pktsnip_t *l2hdr;
gnrc_pktsnip_t *iphdr = gnrc_ipv6_hdr_build(payload, src, dst);
if (iphdr == NULL) {
DEBUG("ndp internal: error allocating IPv6 header.\n");
return NULL;
}
((ipv6_hdr_t *)iphdr->data)->hl = 255;
/* add netif header for send interface specification */
l2hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
if (l2hdr == NULL) {
DEBUG("ndp internal: error allocating netif header.\n");
gnrc_pktbuf_remove_snip(iphdr, iphdr);
return NULL;
}
((gnrc_netif_hdr_t *)l2hdr->data)->if_pid = iface;
LL_PREPEND(iphdr, l2hdr);
return l2hdr;
}
/** @} */

View File

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

View File

@ -1,182 +0,0 @@
/*
* 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/gnrc/ipv6.h"
#include "net/gnrc/ndp.h"
#include "net/gnrc/pkt.h"
#include "net/gnrc/pktqueue.h"
#include "net/gnrc/ndp/internal.h"
#include "net/gnrc/ndp/node.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if ENABLE_DEBUG
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
#endif
static gnrc_pktqueue_t _pkt_nodes[GNRC_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 gnrc_pktqueue_t *_alloc_pkt_node(gnrc_pktsnip_t *pkt)
{
for (size_t i = 0; i < sizeof(_pkt_nodes) / sizeof(gnrc_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 gnrc_ndp_node_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
kernel_pid_t iface, ipv6_addr_t *dst,
gnrc_pktsnip_t *pkt)
{
gnrc_ipv6_nc_t *nc_entry;
ipv6_addr_t *next_hop_ip = NULL, *prefix = NULL;
bool dst_link_local = ipv6_addr_is_link_local(dst);
#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 (!dst_link_local) {
size_t next_hop_size = sizeof(ipv6_addr_t);
uint32_t next_hop_flags = 0;
if ((next_hop_ip == 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_ip = &next_hop_actual;
}
}
#endif
/* cppcheck-suppress knownConditionTrueFalse
* cppcheck bug: next_hop_ip might be initialized if a FIB is available */
if (next_hop_ip == NULL) { /* no route to host */
if (!dst_link_local) {
if (iface == KERNEL_PID_UNDEF) {
/* gnrc_ipv6_netif_t doubles as prefix list */
iface = gnrc_ipv6_netif_find_by_prefix(&prefix, dst);
}
else {
/* gnrc_ipv6_netif_t doubles as prefix list */
prefix = gnrc_ipv6_netif_match_prefix(iface, dst);
}
}
if (dst_link_local || ((prefix != NULL) &&
(gnrc_ipv6_netif_addr_get(prefix)->flags & /* prefix is on-link */
GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK))) {
next_hop_ip = dst;
}
}
/* dst has not an on-link prefix */
if (next_hop_ip == NULL) {
next_hop_ip = gnrc_ndp_internal_default_router();
}
if (next_hop_ip == NULL) {
next_hop_ip = dst; /* Just look if it's in the neighbor cache
* (aka on-link but not registered in prefix list as such) */
}
/* start address resolution */
nc_entry = gnrc_ipv6_nc_get(iface, next_hop_ip);
if ((nc_entry != NULL) && gnrc_ipv6_nc_is_reachable(nc_entry)) {
DEBUG("ndp node: found reachable neighbor (%s => ",
ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)));
DEBUG("%s)\n",
gnrc_netif_addr_to_str(addr_str, sizeof(addr_str),
nc_entry->l2_addr, nc_entry->l2_addr_len));
if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_STALE) {
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_DELAY);
}
return gnrc_ipv6_nc_get_l2_addr(l2addr, l2addr_len, nc_entry);
}
else if (nc_entry == NULL) {
gnrc_pktqueue_t *pkt_node;
ipv6_addr_t dst_sol;
nc_entry = gnrc_ipv6_nc_add(iface, next_hop_ip, NULL, 0,
GNRC_IPV6_NC_STATE_INCOMPLETE << GNRC_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 */
gnrc_pktbuf_hold(pkt_node->pkt, 1);
gnrc_pktqueue_add(&nc_entry->pkts, pkt_node);
}
/* address resolution */
ipv6_addr_set_solicited_nodes(&dst_sol, next_hop_ip);
if (iface == KERNEL_PID_UNDEF) {
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
size_t ifnum = gnrc_netif_get(ifs);
for (size_t i = 0; i < ifnum; i++) {
gnrc_ndp_internal_send_nbr_sol(ifs[i], NULL, next_hop_ip, &dst_sol);
}
gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, GNRC_NDP_RETRANS_TIMER,
GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid);
}
else {
gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
gnrc_ndp_internal_send_nbr_sol(iface, NULL, next_hop_ip, &dst_sol);
mutex_lock(&ipv6_iface->mutex);
gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, ipv6_iface->retrans_timer,
GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid);
mutex_unlock(&ipv6_iface->mutex);
}
}
return KERNEL_PID_UNDEF;
}
/** @} */

View File

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

View File

@ -1,125 +0,0 @@
/*
* 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/ndp/internal.h"
#include "random.h"
#include "xtimer.h"
#include "net/gnrc/ndp/router.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static void _send_rtr_adv(gnrc_ipv6_netif_t *iface, ipv6_addr_t *dst);
void gnrc_ndp_router_set_router(gnrc_ipv6_netif_t *iface, bool enable)
{
if (enable && !(iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
gnrc_ipv6_netif_add_addr(iface->pid, &ipv6_addr_all_routers_link_local,
128, GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST);
mutex_lock(&iface->mutex);
iface->flags |= GNRC_IPV6_NETIF_FLAGS_ROUTER;
iface->max_adv_int = GNRC_IPV6_NETIF_DEFAULT_MAX_ADV_INT;
iface->min_adv_int = GNRC_IPV6_NETIF_DEFAULT_MIN_ADV_INT;
iface->adv_ltime = GNRC_IPV6_NETIF_DEFAULT_ROUTER_LTIME;
mutex_unlock(&iface->mutex);
gnrc_ndp_router_set_rtr_adv(iface, enable);
}
else if (!enable && (iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
gnrc_ipv6_netif_remove_addr(iface->pid, (ipv6_addr_t *)&ipv6_addr_all_routers_link_local);
gnrc_ndp_router_set_rtr_adv(iface, enable);
}
}
void gnrc_ndp_router_set_rtr_adv(gnrc_ipv6_netif_t *iface, bool enable)
{
if (enable && !(iface->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) {
mutex_lock(&iface->mutex);
iface->flags |= GNRC_IPV6_NETIF_FLAGS_RTR_ADV;
iface->rtr_adv_count = GNRC_NDP_MAX_INIT_RTR_ADV_NUMOF;
mutex_unlock(&iface->mutex);
_send_rtr_adv(iface, NULL);
}
else if (!enable && (iface->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) {
mutex_lock(&iface->mutex);
iface->rtr_adv_count = GNRC_NDP_MAX_FIN_RTR_ADV_NUMOF;
iface->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV;
iface->adv_ltime = 0;
#ifdef MODULE_GNRC_NDP_HOST
iface->rtr_sol_count = GNRC_NDP_MAX_RTR_SOL_NUMOF;
#endif
mutex_unlock(&iface->mutex);
_send_rtr_adv(iface, NULL);
#ifdef MODULE_GNRC_NDP_HOST
gnrc_ndp_host_retrans_rtr_sol(iface);
#endif
}
}
void gnrc_ndp_router_retrans_rtr_adv(gnrc_ipv6_netif_t *iface)
{
_send_rtr_adv(iface, NULL);
}
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);
}
static void _send_rtr_adv(gnrc_ipv6_netif_t *iface, ipv6_addr_t *dst)
{
bool fin;
uint32_t interval;
mutex_lock(&iface->mutex);
fin = (iface->adv_ltime == 0);
assert((iface->min_adv_int != 0) && (iface->max_adv_int != 0));
interval = random_uint32_range(iface->min_adv_int, iface->max_adv_int);
if (!fin && !((iface->flags | GNRC_IPV6_NETIF_FLAGS_ROUTER) &&
(iface->flags | GNRC_IPV6_NETIF_FLAGS_RTR_ADV))) {
DEBUG("ndp rtr: interface %" PRIkernel_pid " is not an advertising interface\n",
iface->pid);
return;
}
if (iface->rtr_adv_count > 1) { /* regard for off-by-one error */
iface->rtr_adv_count--;
if (!fin && (interval > GNRC_NDP_MAX_INIT_RTR_ADV_INT)) {
interval = GNRC_NDP_MAX_INIT_RTR_ADV_INT;
}
}
if (!fin || (iface->rtr_adv_count > 1)) { /* regard for off-by-one-error */
/* reset timer for next router advertisement */
xtimer_remove(&iface->rtr_adv_timer);
iface->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_RETRANS;
iface->rtr_adv_msg.content.ptr = iface;
xtimer_set_msg(&iface->rtr_adv_timer, interval * US_PER_SEC, &iface->rtr_adv_msg,
gnrc_ipv6_pid);
}
mutex_unlock(&iface->mutex);
for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) {
ipv6_addr_t *src = &iface->addrs[i].addr;
if (!ipv6_addr_is_unspecified(src) && ipv6_addr_is_link_local(src) &&
!gnrc_ipv6_netif_addr_is_non_unicast(src)) {
/* send one for every link local address (ideally there is only one) */
gnrc_ndp_internal_send_rtr_adv(iface->pid, src, dst, fin);
}
}
}
/** @} */

View File

@ -29,9 +29,6 @@ endif
ifneq (,$(filter fib,$(USEMODULE)))
SRC += sc_fib.c
endif
ifneq (,$(filter gnrc_ipv6_nc,$(USEMODULE)))
SRC += sc_ipv6_nc.c
endif
ifneq (,$(filter gnrc_ipv6_nib,$(USEMODULE)))
SRC += sc_gnrc_ipv6_nib.c
endif

View File

@ -20,7 +20,6 @@
#include <string.h>
#include "net/ipv6/addr.h"
#include "net/gnrc/ndp/internal.h"
#include "net/gnrc/sixlowpan/ctx.h"
#include "net/gnrc/sixlowpan/nd.h"
#include "timex.h"

View File

@ -24,7 +24,9 @@
#include "byteorder.h"
#include "net/gnrc/icmpv6.h"
#include "net/ipv6/addr.h"
#include "net/gnrc/ipv6/nc.h"
#ifdef MODULE_GNRC_IPV6_NIB
#include "net/gnrc/ipv6/nib/nc.h"
#endif
#include "net/gnrc/ipv6/hdr.h"
#include "net/gnrc/netif2.h"
#include "net/gnrc.h"
@ -109,8 +111,8 @@ int _handle_reply(gnrc_pktsnip_t *pkt, uint32_t time)
ipv6_addr_to_str(ipv6_str, &(ipv6_hdr->src), sizeof(ipv6_str)),
byteorder_ntohs(icmpv6_hdr->id), seq, (unsigned)ipv6_hdr->hl,
time / US_PER_MS, time % US_PER_MS);
#ifdef MODULE_GNRC_IPV6_NC
gnrc_ipv6_nc_still_reachable(&ipv6_hdr->src);
#ifdef MODULE_GNRC_IPV6_NIB
gnrc_ipv6_nib_nc_mark_reachable(&ipv6_hdr->src);
#endif
}
else {

View File

@ -1,281 +0,0 @@
/*
* 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.
*/
/**
* @ingroup sys_shell_commands.h
* @{
*
* @file
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <stdio.h>
#include <string.h>
#include "kernel_types.h"
#include "net/ipv6/addr.h"
#include "net/gnrc/ipv6/nc.h"
#include "thread.h"
/* maximum length of L2 address */
#define MAX_L2_ADDR_LEN (8U)
static void _print_nc_state(gnrc_ipv6_nc_t *entry)
{
switch (entry->flags & GNRC_IPV6_NC_STATE_MASK) {
case GNRC_IPV6_NC_STATE_UNMANAGED:
printf("UNMANAGED ");
break;
case GNRC_IPV6_NC_STATE_UNREACHABLE:
printf("UNREACHABLE ");
break;
case GNRC_IPV6_NC_STATE_INCOMPLETE:
printf("INCOMPLETE ");
break;
case GNRC_IPV6_NC_STATE_STALE:
printf("STALE ");
break;
case GNRC_IPV6_NC_STATE_DELAY:
printf("DELAY ");
break;
case GNRC_IPV6_NC_STATE_PROBE:
printf("PROBE ");
break;
case GNRC_IPV6_NC_STATE_REACHABLE:
printf("REACHABLE ");
break;
default:
printf("UNKNOWN ");
break;
}
}
static void _print_nc_type(gnrc_ipv6_nc_t *entry)
{
switch (entry->flags & GNRC_IPV6_NC_TYPE_MASK) {
case GNRC_IPV6_NC_TYPE_GC:
printf("GC");
break;
case GNRC_IPV6_NC_TYPE_TENTATIVE:
printf("TENT");
break;
case GNRC_IPV6_NC_TYPE_REGISTERED:
printf("REG");
break;
default:
printf("-");
break;
}
}
static bool _is_iface(kernel_pid_t iface)
{
return (thread_get(iface) != NULL);
}
static int _ipv6_nc_list(void)
{
char ipv6_str[IPV6_ADDR_MAX_STR_LEN];
char l2addr_str[3 * MAX_L2_ADDR_LEN];
puts("IPv6 address if L2 address state type");
puts("------------------------------------------------------------------------------");
for (gnrc_ipv6_nc_t *entry = gnrc_ipv6_nc_get_next(NULL);
entry != NULL;
entry = gnrc_ipv6_nc_get_next(entry)) {
printf("%-30s %2" PRIkernel_pid " %-24s ",
ipv6_addr_to_str(ipv6_str, &entry->ipv6_addr, sizeof(ipv6_str)),
entry->iface,
gnrc_netif_addr_to_str(l2addr_str, sizeof(l2addr_str),
entry->l2_addr, entry->l2_addr_len));
_print_nc_state(entry);
_print_nc_type(entry);
puts("");
}
return 0;
}
static inline kernel_pid_t _get_iface(void)
{
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
size_t ifnum = gnrc_netif_get(ifs);
return (ifnum > 1) ? KERNEL_PID_UNDEF : ifs[0];
}
static int _ipv6_nc_add(int argc, char **argv)
{
char *ipv6_addr_str;
char *l2_addr_str = NULL;
kernel_pid_t iface = KERNEL_PID_UNDEF;
ipv6_addr_t ipv6_addr;
uint8_t l2_addr[MAX_L2_ADDR_LEN];
size_t l2_addr_len = 0;
switch (argc) {
case 1:
iface = _get_iface();
ipv6_addr_str = argv[0]; /* store for output */
l2_addr_len = 0;
break;
case 2:
ipv6_addr_str = argv[0]; /* store for output */
if (ipv6_addr_from_str(&ipv6_addr, ipv6_addr_str) == NULL) {
iface = atoi(argv[0]);
ipv6_addr_str = argv[1];
l2_addr_len = 0;
}
else {
iface = _get_iface();
l2_addr_str = argv[1];
}
break;
default:
iface = atoi(argv[0]);
ipv6_addr_str = argv[1];
l2_addr_str = argv[2];
break;
}
if (!_is_iface(iface)) {
puts("error: invalid interface given.");
return 1;
}
if (ipv6_addr_from_str(&ipv6_addr, ipv6_addr_str) == NULL) {
puts("error: unable to parse IPv6 address.");
return 1;
}
if ((l2_addr_str != NULL) && (l2_addr_len = gnrc_netif_addr_from_str(l2_addr, sizeof(l2_addr),
l2_addr_str)) == 0) {
puts("error: unable to parse link-layer address.");
return 1;
}
if (gnrc_ipv6_nc_add(iface, &ipv6_addr, l2_addr, l2_addr_len, 0) == NULL) {
puts("error: unable to add address to neighbor cache.");
return 1;
}
printf("success: added IPv6 address %s to neighbor cache\n", ipv6_addr_str);
return 0;
}
static int _ipv6_nc_del(char *ipv6_addr_str)
{
ipv6_addr_t ipv6_addr;
if (ipv6_addr_from_str(&ipv6_addr, ipv6_addr_str) == NULL) {
puts("error: unable to parse IPv6 address.");
return 1;
}
gnrc_ipv6_nc_remove(KERNEL_PID_UNDEF, &ipv6_addr);
printf("success: removed %s from neighbor cache\n", ipv6_addr_str);
return 0;
}
static int _ipv6_nc_reset(void)
{
gnrc_ipv6_nc_t *tmp = NULL;
for (gnrc_ipv6_nc_t *entry = gnrc_ipv6_nc_get_next(NULL);
entry != NULL;
tmp = entry, entry = gnrc_ipv6_nc_get_next(entry)) {
if (tmp) {
gnrc_ipv6_nc_remove(tmp->iface, &tmp->ipv6_addr);
}
}
/* remove last entry */
if (tmp) {
gnrc_ipv6_nc_remove(tmp->iface, &tmp->ipv6_addr);
}
printf("success: reset neighbor cache\n");
return 0;
}
int _ipv6_nc_manage(int argc, char **argv)
{
if ((argc == 1) || (strcmp("list", argv[1]) == 0)) {
return _ipv6_nc_list();
}
if (argc > 1) {
if ((argc > 2) && (strcmp("add", argv[1]) == 0)) {
return _ipv6_nc_add(argc - 2, &argv[2]);
}
if ((argc > 2) && (strcmp("del", argv[1]) == 0)) {
return _ipv6_nc_del(argv[2]);
}
if (strcmp("reset", argv[1]) == 0) {
return _ipv6_nc_reset();
}
}
printf("usage: %s [list]\n"
" or: %s add [<iface pid>] <ipv6_addr> <l2_addr>\n"
" * <iface pid> is optional if only one interface exists.\n"
" or: %s del <ipv6_addr>\n"
" or: %s reset\n", argv[0], argv[0], argv[0], argv[0]);
return 1;
}
int _ipv6_nc_routers(int argc, char **argv)
{
kernel_pid_t iface = KERNEL_PID_UNDEF;
char ipv6_str[IPV6_ADDR_MAX_STR_LEN];
if (argc > 1) {
iface = atoi(argv[1]);
if (!_is_iface(iface)) {
printf("usage: %s [<iface pid>]\n", argv[0]);
return 1;
}
}
puts("if Router state type");
puts("---------------------------------------------------");
for (gnrc_ipv6_nc_t *entry = gnrc_ipv6_nc_get_next_router(NULL);
entry != NULL;
entry = gnrc_ipv6_nc_get_next_router(entry)) {
if ((iface != KERNEL_PID_UNDEF) && (iface != entry->iface)) {
continue;
}
printf("%2" PRIkernel_pid " %-30s ", entry->iface,
ipv6_addr_to_str(ipv6_str, &entry->ipv6_addr, sizeof(ipv6_str)));
_print_nc_state(entry);
_print_nc_type(entry);
puts("");
}
return 0;
}
/**
* @}
*/

View File

@ -200,10 +200,6 @@ const shell_command_t _shell_command_list[] = {
#ifdef MODULE_FIB
{"fibroute", "Manipulate the FIB (info: 'fibroute [add|del]')", _fib_route_handler},
#endif
#ifdef MODULE_GNRC_IPV6_NC
{"ncache", "manage neighbor cache by hand", _ipv6_nc_manage },
{"routers", "IPv6 default router list", _ipv6_nc_routers },
#endif
#ifdef MODULE_GNRC_IPV6_WHITELIST
{"whitelist", "whitelists an address for receival ('whitelist [add|del|help]')", _whitelist },
#endif