mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
ng_ndp: initial import of the address resolution
This commit is contained in:
parent
ad001abbe7
commit
ee11a2ae56
11
Makefile.dep
11
Makefile.dep
@ -72,6 +72,13 @@ ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE)))
|
||||
USEMODULE += vtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ng_ndp,$(USEMODULE)))
|
||||
USEMODULE += ng_icmpv6
|
||||
USEMODULE += random
|
||||
USEMODULE += timex
|
||||
USEMODULE += vtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ng_icmpv6_echo,$(USEMODULE)))
|
||||
USEMODULE += ng_icmpv6
|
||||
USEMODULE += ng_netbase
|
||||
@ -97,7 +104,11 @@ ifneq (,$(filter ng_ipv6,$(USEMODULE)))
|
||||
USEMODULE += ng_ipv6_hdr
|
||||
USEMODULE += ng_ipv6_nc
|
||||
USEMODULE += ng_ipv6_netif
|
||||
USEMODULE += ng_ndp
|
||||
USEMODULE += ng_netbase
|
||||
USEMODULE += random
|
||||
USEMODULE += timex
|
||||
USEMODULE += vtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ng_ipv6_nc,$(USEMODULE)))
|
||||
|
@ -86,6 +86,9 @@ endif
|
||||
ifneq (,$(filter ng_inet_csum,$(USEMODULE)))
|
||||
DIRS += net/crosslayer/ng_inet_csum
|
||||
endif
|
||||
ifneq (,$(filter ng_ndp,$(USEMODULE)))
|
||||
DIRS += net/network_layer/ng_ndp
|
||||
endif
|
||||
ifneq (,$(filter ng_netapi,$(USEMODULE)))
|
||||
DIRS += net/crosslayer/ng_netapi
|
||||
endif
|
||||
|
@ -62,6 +62,16 @@ extern "C" {
|
||||
#define NG_IPV6_MSG_QUEUE_SIZE (8U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The PID to the IPv6 thread.
|
||||
*
|
||||
* @note Use @ref ng_ipv6_init() to initialize. **Do not set by hand**.
|
||||
*
|
||||
* @details This variable is preferred for IPv6 internal communication *only*.
|
||||
* Please use @ref net_ng_netreg for external communication.
|
||||
*/
|
||||
extern kernel_pid_t ng_ipv6_pid;
|
||||
|
||||
/**
|
||||
* @brief Initialization of the IPv6 thread.
|
||||
*
|
||||
|
@ -137,7 +137,7 @@ typedef struct {
|
||||
*/
|
||||
vtimer_t nbr_adv_timer;
|
||||
|
||||
uint8_t unanswered_probes; /**< number of unanswered probes */
|
||||
uint8_t probes_remaining; /**< remaining number of unanswered probes */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -195,6 +195,29 @@ typedef struct {
|
||||
uint16_t mtu; /**< Maximum Transmission Unit (MTU) of the interface */
|
||||
uint8_t cur_hl; /**< current hop limit for the interface */
|
||||
uint16_t flags; /**< flags for 6LoWPAN and Neighbor Discovery */
|
||||
/**
|
||||
* @brief Base value in microseconds for computing random
|
||||
* ng_ipv6_netif_t::reach_time.
|
||||
* The default value is @ref NG_NDP_REACH_TIME.
|
||||
*/
|
||||
uint32_t reach_time_base;
|
||||
|
||||
/**
|
||||
* @brief The time a neighbor is considered reachable after receiving
|
||||
* a reachability confirmation.
|
||||
* Should be uniformly distributed between @ref NG_NDP_MIN_RAND
|
||||
* and NG_NDP_MAX_RAND multiplied with
|
||||
* ng_ipv6_netif_t::reach_time_base microseconds devided by 10.
|
||||
* Can't be greater than 1 hour.
|
||||
*/
|
||||
timex_t reach_time;
|
||||
|
||||
/**
|
||||
* @brief Time between retransmissions of neighbor solicitations to a
|
||||
* neighbor.
|
||||
* The default value is @ref NG_NDP_RETRANS_TIMER.
|
||||
*/
|
||||
timex_t retrans_timer;
|
||||
} ng_ipv6_netif_t;
|
||||
|
||||
/**
|
||||
|
297
sys/include/net/ng_ndp.h
Normal file
297
sys/include/net/ng_ndp.h
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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_ng_ndp IPv6 Neighbor discovery
|
||||
* @ingroup net_ng_icmpv6
|
||||
* @brief IPv6 Neighbor Discovery Implementation
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Neighbor Discovery definitions
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "net/ng_pkt.h"
|
||||
#include "net/ng_icmpv6.h"
|
||||
#include "net/ng_ipv6/addr.h"
|
||||
#include "net/ng_ipv6/nc.h"
|
||||
#include "net/ng_ipv6/netif.h"
|
||||
|
||||
#include "net/ng_ndp/types.h"
|
||||
|
||||
#ifndef NG_NDP_H_
|
||||
#define NG_NDP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NG_NDP_MSG_RTR_TIMEOUT (0x0211) /**< Message type for router timeouts */
|
||||
#define NG_NDP_MSG_ADDR_TIMEOUT (0x0212) /**< Message type for address timeouts */
|
||||
#define NG_NDP_MSG_NBR_SOL_RETRANS (0x0213) /**< Message type for multicast
|
||||
* neighbor solicitation retransmissions */
|
||||
#define NG_NDP_MSG_NC_STATE_TIMEOUT (0x0214) /**< Message type for neighbor cache state timeouts */
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @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 NG_NDP_MAX_MC_NBR_SOL_NUMOF (3U)
|
||||
|
||||
/**
|
||||
* @brief Maximum number of unanswered unicast neighbor solicitations before
|
||||
* an address is considered unreachable.
|
||||
*/
|
||||
#define NG_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 NG_NDP_MAX_AC_TGT_DELAY (1U)
|
||||
|
||||
/**
|
||||
* @brief Maximum number of unsolicited neighbor advertisements before on
|
||||
* link-layer address change.
|
||||
*/
|
||||
#define NG_NDP_MAX_NBR_ADV_NUMOF (3U)
|
||||
|
||||
/**
|
||||
* @brief Base value in mircoseconds for computing randomised
|
||||
* reachable time.
|
||||
*/
|
||||
#define NG_NDP_REACH_TIME (30U * SEC_IN_USEC)
|
||||
|
||||
/**
|
||||
* @brief Time in mircoseconds between retransmissions of neighbor
|
||||
* solicitations to a neighbor.
|
||||
*/
|
||||
#define NG_NDP_RETRANS_TIMER (1U * SEC_IN_USEC)
|
||||
|
||||
/**
|
||||
* @brief Delay in seconds for neighbor cache entry between entering
|
||||
* DELAY state and entering PROBE state if no reachability
|
||||
* confirmation has been received.
|
||||
*/
|
||||
#define NG_NDP_FIRST_PROBE_DELAY (5U)
|
||||
|
||||
/**
|
||||
* @brief Lower bound for randomised reachable time calculation.
|
||||
*/
|
||||
#define NG_NDP_MIN_RAND (5U)
|
||||
|
||||
/**
|
||||
* @brief Upper bound for randomised reachable time calculation.
|
||||
*/
|
||||
#define NG_NDP_MAX_RAND (15U)
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_sol_t *nbr_sol,
|
||||
size_t icmpv6_size);
|
||||
|
||||
/**
|
||||
* @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_adv The neighbor advertisement in @p pkt.
|
||||
* @param[in] icmpv6_size The overall size of the neighbor solicitation
|
||||
*/
|
||||
void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_adv_t *nbr_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 NG_IPV6_NC_STATE_INCOMPLETE or
|
||||
* @ref NG_IPV6_NC_STATE_PROBE.
|
||||
*/
|
||||
void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry);
|
||||
|
||||
/**
|
||||
* @brief Event handler for a neighbor cache state timeout.
|
||||
*
|
||||
* @param[in] nc_entry A neighbor cache entry.
|
||||
*/
|
||||
void ng_ndp_state_timeout(ng_ipv6_nc_t *nc_entry);
|
||||
|
||||
/**
|
||||
* @brief NDP interface initialization.
|
||||
*
|
||||
* @param[in] iface An IPv6 interface descriptor. Must not be NULL.
|
||||
*/
|
||||
void ng_ndp_netif_add(ng_ipv6_netif_t *iface);
|
||||
|
||||
/**
|
||||
* @brief NDP interface removal.
|
||||
*
|
||||
* @param[in] iface An IPv6 interface descriptor. Must not be NULL.
|
||||
*/
|
||||
void ng_ndp_netif_remove(ng_ipv6_netif_t *iface);
|
||||
|
||||
/**
|
||||
* @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 ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
kernel_pid_t iface, ng_ipv6_addr_t *dst,
|
||||
ng_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.
|
||||
*/
|
||||
ng_pktsnip_t *ng_ndp_nbr_sol_build(ng_ipv6_addr_t *tgt, ng_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 Flags as defined above.
|
||||
* @ref NG_NDP_NBR_ADV_FLAGS_R == 1 indicates, that the
|
||||
* sender is a router,
|
||||
* @ref NG_NDP_NBR_ADV_FLAGS_S == 1 indicates that the
|
||||
* advertisement was sent in response to a neighbor
|
||||
* solicitation,
|
||||
* @ref NG_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 addres 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.
|
||||
*/
|
||||
ng_pktsnip_t *ng_ndp_nbr_adv_build(uint8_t flags, ng_ipv6_addr_t *tgt,
|
||||
ng_pktsnip_t *options);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
ng_pktsnip_t *ng_ndp_opt_build(uint8_t type, size_t size, ng_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
|
||||
*/
|
||||
ng_pktsnip_t *ng_ndp_opt_sl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
|
||||
ng_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
|
||||
*/
|
||||
ng_pktsnip_t *ng_ndp_opt_tl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
|
||||
ng_pktsnip_t *next);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NG_NDP_H_ */
|
||||
/**
|
||||
* @}
|
||||
*/
|
250
sys/include/net/ng_ndp/types.h
Normal file
250
sys/include/net/ng_ndp/types.h
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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_ng_ndp_types Types for IPv6 neighbor discovery
|
||||
* @ingroup net_ng_ndp
|
||||
* @brief IPv6 neighbor discovery message types
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief IPv6 neighbor discovery message type definitions
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef NG_NDP_TYPES_H_
|
||||
#define NG_NDP_TYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "byteorder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name Flags for router advertisement messages
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.2">
|
||||
* RFC 4861, section 4.2
|
||||
* </a>
|
||||
*/
|
||||
#define NG_NDP_RTR_ADV_FLAGS_MASK (0xc0)
|
||||
#define NG_NDP_RTR_ADV_FLAGS_M (0x80) /**< managed address configuration */
|
||||
#define NG_NDP_RTR_ADV_FLAGS_O (0x40) /**< other configuration */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name Flags for neighbor advertisement messages
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.4">
|
||||
* RFC 4861, section 4.2
|
||||
* </a>
|
||||
*/
|
||||
#define NG_NDP_NBR_ADV_FLAGS_MASK (0xe0)
|
||||
#define NG_NDP_NBR_ADV_FLAGS_R (0x80) /**< router */
|
||||
#define NG_NDP_NBR_ADV_FLAGS_S (0x40) /**< solicited */
|
||||
#define NG_NDP_NBR_ADV_FLAGS_O (0x20) /**< override */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name NDP option types
|
||||
* @see <a href="http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5">
|
||||
* IANA, IPv6 Neighbor Discovery Option Formats
|
||||
* </a>
|
||||
*/
|
||||
#define NG_NDP_OPT_SL2A (1) /**< source link-layer address option */
|
||||
#define NG_NDP_OPT_TL2A (2) /**< target link-layer address option */
|
||||
#define NG_NDP_OPT_PI (3) /**< prefix information option */
|
||||
#define NG_NDP_OPT_RH (4) /**< redirected option */
|
||||
#define NG_NDP_OPT_MTU (5) /**< MTU option */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name Flags for prefix information option
|
||||
*/
|
||||
#define NG_NDP_OPT_PI_FLAGS_MASK (0xc0)
|
||||
#define NG_NDP_OPT_PI_FLAGS_L (0x80) /**< on-link */
|
||||
#define NG_NDP_OPT_PI_FLAGS_A (0x40) /**< autonomous address configuration */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name Lengths for fixed length options
|
||||
* @brief Options don't use bytes as their length unit, but 8 bytes.
|
||||
*/
|
||||
#define NG_NDP_OPT_PI_LEN (4U)
|
||||
#define NG_NDP_OPT_MTU_LEN (1U)
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Router solicitation message format.
|
||||
* @extends ng_icmpv6_hdr_t
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.1">
|
||||
* RFC 4861, section 4.1
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< message type */
|
||||
uint8_t code; /**< message code */
|
||||
network_uint16_t csum; /**< checksum */
|
||||
network_uint32_t resv; /**< reserved field */
|
||||
} ng_ndp_rtr_sol_t;
|
||||
|
||||
/**
|
||||
* @brief Router advertisement message format.
|
||||
* @extends ng_icmpv6_hdr_t
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.2">
|
||||
* RFC 4861, section 4.2
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< message type */
|
||||
uint8_t code; /**< message code */
|
||||
network_uint16_t csum; /**< checksum */
|
||||
uint8_t cur_hl; /**< current hop limit */
|
||||
uint8_t flags; /**< flags */
|
||||
network_uint16_t ltime; /**< router lifetime */
|
||||
network_uint32_t reach_time; /**< reachable time */
|
||||
network_uint32_t retrans_timer; /**< retransmission timer */
|
||||
} ng_ndp_rtr_adv_t;
|
||||
|
||||
/**
|
||||
* @brief Neighbor solicitation message format.
|
||||
* @extends ng_icmpv6_hdr_t
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.3">
|
||||
* RFC 4861, section 4.3
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< message type */
|
||||
uint8_t code; /**< message code */
|
||||
network_uint16_t csum; /**< checksum */
|
||||
network_uint32_t resv; /**< reserved field */
|
||||
ng_ipv6_addr_t tgt; /**< target address */
|
||||
} ng_ndp_nbr_sol_t;
|
||||
|
||||
/**
|
||||
* @brief Neighbor advertisement message format.
|
||||
* @extends ng_icmpv6_hdr_t
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.4">
|
||||
* RFC 4861, section 4.4
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< message type */
|
||||
uint8_t code; /**< message code */
|
||||
network_uint16_t csum; /**< checksum */
|
||||
uint8_t flags; /**< flags */
|
||||
uint8_t resv[3]; /**< reserved fields */
|
||||
ng_ipv6_addr_t tgt; /**< target address */
|
||||
} ng_ndp_nbr_adv_t;
|
||||
|
||||
/**
|
||||
* @brief Neighbor advertisement message format.
|
||||
* @extends ng_icmpv6_hdr_t
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.5">
|
||||
* RFC 4861, section 4.5
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< message type */
|
||||
uint8_t code; /**< message code */
|
||||
network_uint16_t csum; /**< checksum */
|
||||
network_uint32_t resv; /**< reserved field */
|
||||
ng_ipv6_addr_t tgt; /**< target address */
|
||||
ng_ipv6_addr_t dst; /**< destination address */
|
||||
} ng_ndp_redirect_t;
|
||||
|
||||
/**
|
||||
* @brief General NDP option format
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.6">
|
||||
* RFC 4861, section 4.6
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< option type */
|
||||
uint8_t len; /**< length in units of 8 octets */
|
||||
} ng_ndp_opt_t;
|
||||
|
||||
/* XXX: slla and tlla are just ng_ndp_opt_t with variable link layer address
|
||||
* appended */
|
||||
|
||||
/**
|
||||
* @brief Prefix information option format
|
||||
* @extends ng_ndp_opt_t
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.6.2">
|
||||
* RFC 4861, section 4.6.2
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< option type */
|
||||
uint8_t len; /**< length in units of 8 octets */
|
||||
uint8_t prefix_len; /**< prefix length */
|
||||
uint8_t flags; /**< flags */
|
||||
network_uint32_t valid_ltime; /**< valid lifetime */
|
||||
network_uint32_t pref_ltime; /**< preferred lifetime */
|
||||
network_uint32_t resv; /**< reserved field */
|
||||
ng_ipv6_addr_t prefix; /**< prefix */
|
||||
} ng_ndp_opt_pi_t;
|
||||
|
||||
/**
|
||||
* @brief Redirected header option format
|
||||
* @extends ng_ndp_opt_t
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.6.3">
|
||||
* RFC 4861, section 4.6.3
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< option type */
|
||||
uint8_t len; /**< length in units of 8 octets */
|
||||
uint8_t resv[6]; /**< reserved field */
|
||||
} ng_ndp_opt_rh_t;
|
||||
|
||||
/**
|
||||
* @brief MTU option format
|
||||
* @extends ng_ndp_opt_t
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4861#section-4.6.4">
|
||||
* RFC 4861, section 4.6.4
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< option type */
|
||||
uint8_t len; /**< length in units of 8 octets */
|
||||
network_uint16_t resv; /**< reserved field */
|
||||
network_uint32_t mtu; /**< MTU */
|
||||
} ng_ndp_opt_mtu_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NG_NDP_TYPES_H_ */
|
||||
/** @} */
|
@ -24,6 +24,7 @@
|
||||
#include "net/ng_netbase.h"
|
||||
#include "net/ng_protnum.h"
|
||||
#include "net/ng_ipv6/hdr.h"
|
||||
#include "net/ng_ndp.h"
|
||||
#include "od.h"
|
||||
#include "utlist.h"
|
||||
|
||||
@ -83,16 +84,32 @@ void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt)
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_NG_NDP
|
||||
case NG_ICMPV6_RTR_SOL:
|
||||
case NG_ICMPV6_RTR_ADV:
|
||||
case NG_ICMPV6_NBR_SOL:
|
||||
case NG_ICMPV6_NBR_ADV:
|
||||
case NG_ICMPV6_REDIRECT:
|
||||
DEBUG("icmpv6: neighbor discovery message received\n");
|
||||
DEBUG("icmpv6: router solicitation received\n");
|
||||
/* TODO */
|
||||
break;
|
||||
|
||||
case NG_ICMPV6_RTR_ADV:
|
||||
DEBUG("icmpv6: router advertisement received\n");
|
||||
/* TODO */
|
||||
break;
|
||||
|
||||
case NG_ICMPV6_NBR_SOL:
|
||||
DEBUG("icmpv6: neighbor solicitation received\n");
|
||||
ng_ndp_nbr_sol_handle(iface, pkt, ipv6->data, (ng_ndp_nbr_sol_t *)hdr,
|
||||
icmpv6->size);
|
||||
break;
|
||||
|
||||
case NG_ICMPV6_NBR_ADV:
|
||||
DEBUG("icmpv6: neighbor advertisement received\n");
|
||||
ng_ndp_nbr_adv_handle(iface, pkt, ipv6->data, (ng_ndp_nbr_adv_t *)hdr,
|
||||
icmpv6->size);
|
||||
break;
|
||||
|
||||
case NG_ICMPV6_REDIRECT:
|
||||
DEBUG("icmpv6: redirect message received\n");
|
||||
/* TODO */
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_NG_RPL
|
||||
case NG_ICMPV6_RPL_CTRL:
|
||||
|
@ -15,8 +15,14 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "net/ng_ipv6.h"
|
||||
#include "net/ng_ipv6/addr.h"
|
||||
#include "net/ng_ipv6/nc.h"
|
||||
#include "net/ng_ipv6/netif.h"
|
||||
#include "net/ng_ndp.h"
|
||||
#include "thread.h"
|
||||
#include "timex.h"
|
||||
#include "vtimer.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
@ -110,6 +116,11 @@ ng_ipv6_nc_t *ng_ipv6_nc_add(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr
|
||||
|
||||
DEBUG(" with flags = 0x%0x\n", flags);
|
||||
|
||||
if (ng_ipv6_nc_get_state(free_entry) == NG_IPV6_NC_STATE_INCOMPLETE) {
|
||||
DEBUG("ipv6_nc: Set remaining probes to %" PRIu8 "\n");
|
||||
free_entry->probes_remaining = NG_NDP_MAX_MC_NBR_SOL_NUMOF;
|
||||
}
|
||||
|
||||
return free_entry;
|
||||
}
|
||||
|
||||
@ -192,8 +203,16 @@ ng_ipv6_nc_t *ng_ipv6_nc_still_reachable(const ng_ipv6_addr_t *ipv6_addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (((entry->flags & NG_IPV6_NC_STATE_MASK) >> NG_IPV6_NC_STATE_POS) !=
|
||||
NG_IPV6_NC_STATE_INCOMPLETE) {
|
||||
if (ng_ipv6_nc_get_state(entry) != NG_IPV6_NC_STATE_INCOMPLETE) {
|
||||
#if defined(MODULE_NG_IPV6_NETIF) && defined(MODULE_VTIMER) && defined(MODULE_NG_IPV6)
|
||||
ng_ipv6_netif_t *iface = ng_ipv6_netif_get(entry->iface);
|
||||
timex_t t = iface->reach_time;
|
||||
|
||||
vtimer_remove(&entry->nbr_sol_timer);
|
||||
vtimer_set_msg(&entry->nbr_sol_timer, t, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NC_STATE_TIMEOUT, entry);
|
||||
#endif
|
||||
|
||||
DEBUG("ipv6_nc: Marking entry %s as reachable\n",
|
||||
ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)));
|
||||
entry->flags &= ~(NG_IPV6_NC_STATE_MASK >> NG_IPV6_NC_STATE_POS);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "kernel_types.h"
|
||||
#include "mutex.h"
|
||||
#include "net/ng_ipv6/addr.h"
|
||||
#include "net/ng_ndp.h"
|
||||
#include "net/ng_netif.h"
|
||||
|
||||
#include "net/ng_ipv6/netif.h"
|
||||
@ -119,6 +120,10 @@ void ng_ipv6_netif_add(kernel_pid_t pid)
|
||||
|
||||
mutex_unlock(&ipv6_ifs[i].mutex);
|
||||
|
||||
#ifdef MODULE_NG_NDP
|
||||
ng_ndp_netif_add(&ipv6_ifs[i]);
|
||||
#endif
|
||||
|
||||
DEBUG(" * pid = %" PRIkernel_pid " ", ipv6_ifs[i].pid);
|
||||
DEBUG("cur_hl = %d ", ipv6_ifs[i].cur_hl);
|
||||
DEBUG("mtu = %d ", ipv6_ifs[i].mtu);
|
||||
@ -138,6 +143,10 @@ void ng_ipv6_netif_remove(kernel_pid_t pid)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MODULE_NG_NDP
|
||||
ng_ndp_netif_remove(entry);
|
||||
#endif
|
||||
|
||||
mutex_lock(&entry->mutex);
|
||||
|
||||
_reset_addr_from_entry(entry);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "kernel_types.h"
|
||||
#include "net/ng_icmpv6.h"
|
||||
#include "net/ng_netbase.h"
|
||||
#include "net/ng_ndp.h"
|
||||
#include "net/ng_protnum.h"
|
||||
#include "thread.h"
|
||||
#include "utlist.h"
|
||||
@ -35,12 +36,13 @@
|
||||
#define _MAX_L2_ADDR_LEN (8U)
|
||||
|
||||
static char _stack[NG_IPV6_STACK_SIZE];
|
||||
static kernel_pid_t _pid = KERNEL_PID_UNDEF;
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
kernel_pid_t ng_ipv6_pid = KERNEL_PID_UNDEF;
|
||||
|
||||
/* handles NG_NETAPI_MSG_TYPE_RCV commands */
|
||||
static void _receive(ng_pktsnip_t *pkt);
|
||||
/* dispatches received IPv6 packet for upper layer */
|
||||
@ -58,12 +60,12 @@ static void _decapsulate(ng_pktsnip_t *pkt);
|
||||
|
||||
kernel_pid_t ng_ipv6_init(void)
|
||||
{
|
||||
if (_pid == KERNEL_PID_UNDEF) {
|
||||
_pid = thread_create(_stack, sizeof(_stack), NG_IPV6_PRIO,
|
||||
if (ng_ipv6_pid == KERNEL_PID_UNDEF) {
|
||||
ng_ipv6_pid = thread_create(_stack, sizeof(_stack), NG_IPV6_PRIO,
|
||||
CREATE_STACKTEST, _event_loop, NULL, "ipv6");
|
||||
}
|
||||
|
||||
return _pid;
|
||||
return ng_ipv6_pid;
|
||||
}
|
||||
|
||||
void ng_ipv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt, uint8_t nh)
|
||||
@ -140,6 +142,27 @@ static void *_event_loop(void *args)
|
||||
msg_reply(&msg, &reply);
|
||||
break;
|
||||
|
||||
case NG_NDP_MSG_RTR_TIMEOUT:
|
||||
DEBUG("ipv6: Router timeout received\n");
|
||||
((ng_ipv6_nc_t *)msg.content.ptr)->flags &= ~NG_IPV6_NC_IS_ROUTER;
|
||||
break;
|
||||
|
||||
case NG_NDP_MSG_ADDR_TIMEOUT:
|
||||
DEBUG("ipv6: Router advertisement timer event received\n");
|
||||
ng_ipv6_netif_remove_addr(KERNEL_PID_UNDEF,
|
||||
(ng_ipv6_addr_t *)msg.content.ptr);
|
||||
break;
|
||||
|
||||
case NG_NDP_MSG_NBR_SOL_RETRANS:
|
||||
DEBUG("ipv6: Neigbor solicitation retransmission timer event received\n");
|
||||
ng_ndp_retrans_nbr_sol((ng_ipv6_nc_t *)msg.content.ptr);
|
||||
break;
|
||||
|
||||
case NG_NDP_MSG_NC_STATE_TIMEOUT:
|
||||
DEBUG("ipv6: Neigbor cace state timeout received\n");
|
||||
ng_ndp_state_timeout((ng_ipv6_nc_t *)msg.content.ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -411,8 +434,6 @@ static void _send(ng_pktsnip_t *pkt, bool prep_hdr)
|
||||
kernel_pid_t iface = KERNEL_PID_UNDEF;
|
||||
ng_pktsnip_t *ipv6, *payload;
|
||||
ng_ipv6_hdr_t *hdr;
|
||||
ng_ipv6_nc_t *nc_entry;
|
||||
|
||||
/* seize payload as temporary variable */
|
||||
payload = ng_pktbuf_start_write(pkt);
|
||||
|
||||
@ -442,24 +463,14 @@ static void _send(ng_pktsnip_t *pkt, bool prep_hdr)
|
||||
_send_multicast(iface, pkt, ipv6, payload, prep_hdr);
|
||||
}
|
||||
else {
|
||||
ng_ipv6_addr_t *next_hop = NULL;
|
||||
uint8_t l2addr_len = NG_IPV6_NC_L2_ADDR_MAX;
|
||||
uint8_t l2addr[l2addr_len];
|
||||
|
||||
next_hop = &hdr->dst; /* TODO: next hop determination */
|
||||
|
||||
if (((nc_entry = ng_ipv6_nc_get(iface, next_hop)) == NULL) ||
|
||||
!ng_ipv6_nc_is_reachable(nc_entry)) {
|
||||
DEBUG("ipv6: No link layer address for next_hop %s found.\n",
|
||||
ng_ipv6_addr_to_str(addr_str, next_hop, sizeof(addr_str)));
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
iface = nc_entry->iface;
|
||||
}
|
||||
iface = ng_ndp_next_hop_l2addr(l2addr, &l2addr_len, iface, &hdr->dst,
|
||||
pkt);
|
||||
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
DEBUG("ipv6: no interface for %s registered, dropping packet\n",
|
||||
ng_ipv6_addr_to_str(addr_str, next_hop, sizeof(addr_str)));
|
||||
DEBUG("ipv6: error determining next hop's link layer address\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
@ -472,7 +483,7 @@ static void _send(ng_pktsnip_t *pkt, bool prep_hdr)
|
||||
}
|
||||
}
|
||||
|
||||
_send_unicast(iface, nc_entry->l2_addr, nc_entry->l2_addr_len, pkt);
|
||||
_send_unicast(iface, l2addr, l2addr_len, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
|
1
sys/net/network_layer/ng_ndp/Makefile
Normal file
1
sys/net/network_layer/ng_ndp/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
938
sys/net/network_layer/ng_ndp/ng_ndp.c
Normal file
938
sys/net/network_layer/ng_ndp/ng_ndp.c
Normal file
@ -0,0 +1,938 @@
|
||||
/*
|
||||
* 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_ng_ndp
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "net/ng_icmpv6.h"
|
||||
#include "net/ng_ipv6.h"
|
||||
#include "net/ng_netbase.h"
|
||||
#include "random.h"
|
||||
#include "utlist.h"
|
||||
#include "thread.h"
|
||||
#include "vtimer.h"
|
||||
|
||||
#include "net/ng_ndp.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static ng_pktqueue_node_t _pkt_nodes[NG_IPV6_NC_SIZE * 2];
|
||||
static ng_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) */
|
||||
|
||||
/* random helper function */
|
||||
static inline uint32_t _rand(uint32_t min, uint32_t max)
|
||||
{
|
||||
return (genrand_uint32() % (max - min)) + min;
|
||||
}
|
||||
|
||||
static bool _handle_sl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ng_ndp_opt_t *sl2a_opt);
|
||||
static bool _handle_tl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ng_ndp_opt_t *tl2a_opt, ng_ipv6_addr_t *tgt,
|
||||
uint8_t adv_flags);
|
||||
|
||||
/* send address resolution messages */
|
||||
static void _send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst);
|
||||
static void _send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst, bool supply_tl2a);
|
||||
|
||||
static void _set_state(ng_ipv6_nc_t *nc_entry, uint8_t state);
|
||||
|
||||
/* special netapi helper */
|
||||
static inline void _send_delayed(vtimer_t *t, timex_t interval, ng_pktsnip_t *pkt)
|
||||
{
|
||||
vtimer_set_msg(t, interval, ng_ipv6_pid, NG_NETAPI_MSG_TYPE_SND, pkt);
|
||||
}
|
||||
|
||||
/* packet queue node allocation */
|
||||
static ng_pktqueue_node_t *_alloc_pkt_node(ng_pktsnip_t *pkt);
|
||||
|
||||
void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_sol_t *nbr_sol,
|
||||
size_t icmpv6_size)
|
||||
{
|
||||
uint16_t opt_offset = 0;
|
||||
uint8_t *buf = ((uint8_t *)nbr_sol) + sizeof(ng_ndp_nbr_sol_t);
|
||||
ng_ipv6_addr_t *tgt;
|
||||
int sicmpv6_size = (int)icmpv6_size;
|
||||
|
||||
/* check validity */
|
||||
if ((ipv6->hl != 255) || (nbr_sol->code != 0) ||
|
||||
(icmpv6_size < sizeof(ng_ndp_nbr_sol_t)) ||
|
||||
ng_ipv6_addr_is_multicast(&nbr_sol->tgt) ||
|
||||
(ng_ipv6_addr_is_unspecified(&ipv6->src) &&
|
||||
ng_ipv6_addr_is_solicited_node(&ipv6->dst))) {
|
||||
DEBUG("ndp: neighbor solicitation was invalid.\n");
|
||||
/* ipv6 releases */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((tgt = ng_ipv6_netif_find_addr(iface, &nbr_sol->tgt)) == NULL) {
|
||||
DEBUG("ndp: Target address is not to interface %" PRIkernel_pid "\n",
|
||||
iface);
|
||||
/* ipv6 releases */
|
||||
return;
|
||||
}
|
||||
|
||||
sicmpv6_size -= sizeof(ng_ndp_nbr_sol_t);
|
||||
|
||||
while (sicmpv6_size > 0) {
|
||||
ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset);
|
||||
|
||||
switch (opt->type) {
|
||||
case NG_NDP_OPT_SL2A:
|
||||
if (!_handle_sl2a_opt(iface, pkt, ipv6, nbr_sol->type, opt)) {
|
||||
/* invalid source link-layer address option */
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* silently discard all other options */
|
||||
break;
|
||||
}
|
||||
|
||||
opt_offset += (opt->len * 8);
|
||||
sicmpv6_size -= (opt->len * 8);
|
||||
}
|
||||
|
||||
_send_nbr_adv(iface, tgt, &ipv6->src,
|
||||
ng_ipv6_addr_is_multicast(&ipv6->dst));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_adv_t *nbr_adv,
|
||||
size_t icmpv6_size)
|
||||
{
|
||||
uint16_t opt_offset = 0;
|
||||
uint8_t *buf = ((uint8_t *)nbr_adv) + sizeof(ng_ndp_nbr_adv_t);
|
||||
bool tl2a_supplied = false;
|
||||
int sicmpv6_size = (int)icmpv6_size;
|
||||
|
||||
/* check validity */
|
||||
if ((ipv6->hl != 255) || (nbr_adv->code != 0) ||
|
||||
(icmpv6_size < sizeof(ng_ndp_nbr_adv_t)) ||
|
||||
ng_ipv6_addr_is_multicast(&nbr_adv->tgt)) {
|
||||
DEBUG("ndp: neighbor advertisement was invalid.\n");
|
||||
/* ipv6 releases */
|
||||
return;
|
||||
}
|
||||
|
||||
if (ng_ipv6_nc_get(iface, &nbr_adv->tgt) == NULL) {
|
||||
DEBUG("ndp: no neighbor cache entry found for advertisement's target\n");
|
||||
/* ipv6 releases */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sicmpv6_size -= sizeof(ng_ndp_nbr_adv_t);
|
||||
|
||||
while (sicmpv6_size > 0) {
|
||||
ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset);
|
||||
|
||||
switch (opt->type) {
|
||||
case NG_NDP_OPT_TL2A:
|
||||
if (!_handle_tl2a_opt(iface, pkt, ipv6, nbr_adv->type, opt,
|
||||
&nbr_adv->tgt, nbr_adv->flags)) {
|
||||
/* invalid target link-layer address option */
|
||||
return;
|
||||
}
|
||||
|
||||
tl2a_supplied = true;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* silently discard all other options */
|
||||
break;
|
||||
}
|
||||
|
||||
opt_offset += (opt->len * 8);
|
||||
sicmpv6_size -= (opt->len * 8);
|
||||
}
|
||||
|
||||
if (!tl2a_supplied) {
|
||||
if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_O) {
|
||||
ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, &nbr_adv->tgt);
|
||||
|
||||
if (nc_entry != NULL) {
|
||||
if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
|
||||
}
|
||||
else {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry)
|
||||
{
|
||||
if ((nc_entry->probes_remaining > 1) &&
|
||||
((ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) ||
|
||||
(ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_PROBE))) {
|
||||
ng_ipv6_addr_t dst;
|
||||
|
||||
DEBUG("ndp: Retransmit neighbor solicitation for %s\n",
|
||||
ng_ipv6_addr_to_str(addr_str, nc_entry->ipv6_addr, sizeof(addr_str)));
|
||||
|
||||
/* retransmit neighbor solicatation */
|
||||
if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) {
|
||||
ng_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) {
|
||||
timex_t t = { 0, NG_NDP_RETRANS_TIMER };
|
||||
kernel_pid_t *ifs;
|
||||
size_t ifnum;
|
||||
|
||||
ifs = ng_netif_get(&ifnum);
|
||||
|
||||
for (size_t i = 0; i < ifnum; i++) {
|
||||
_send_nbr_sol(ifs[i], &nc_entry->ipv6_addr, &dst);
|
||||
}
|
||||
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
}
|
||||
else {
|
||||
ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);
|
||||
|
||||
_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, &dst);
|
||||
|
||||
mutex_lock(&ipv6_iface->mutex);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer,
|
||||
ipv6_iface->retrans_timer, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
mutex_unlock(&ipv6_iface->mutex);
|
||||
}
|
||||
}
|
||||
else if (nc_entry->probes_remaining <= 1) {
|
||||
ng_pktqueue_node_t *queue_node;
|
||||
|
||||
/* No need to call ng_ipv6_nc_remove() we know already were the
|
||||
* entry is */
|
||||
|
||||
DEBUG("ndp: Remove nc entry %s for interface %" PRIkernel_pid "\n",
|
||||
ng_ipv6_addr_to_str(addr_str, nc_entry->ipv6_addr, sizeof(addr_str)),
|
||||
nc_entry->iface);
|
||||
|
||||
while ((queue_node = ng_pktqueue_remove_head(&nc_entry->pkts))) {
|
||||
ng_pktbuf_release(queue_node->data);
|
||||
queue_node->data = NULL;
|
||||
}
|
||||
|
||||
ng_ipv6_addr_set_unspecified(&(nc_entry->ipv6_addr));
|
||||
nc_entry->iface = KERNEL_PID_UNDEF;
|
||||
nc_entry->flags = 0;
|
||||
nc_entry->probes_remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ng_ndp_state_timeout(ng_ipv6_nc_t *nc_entry)
|
||||
{
|
||||
switch (ng_ipv6_nc_get_state(nc_entry)) {
|
||||
case NG_IPV6_NC_STATE_REACHABLE:
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
break;
|
||||
|
||||
case NG_IPV6_NC_STATE_DELAY:
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_PROBE);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ng_ndp_netif_add(ng_ipv6_netif_t *iface)
|
||||
{
|
||||
uint32_t reach_time = _rand(NG_NDP_MIN_RAND, NG_NDP_MAX_RAND);
|
||||
|
||||
/* set default values */
|
||||
mutex_lock(&iface->mutex);
|
||||
iface->reach_time_base = NG_NDP_REACH_TIME;
|
||||
reach_time = (reach_time * iface->reach_time_base) / 10;
|
||||
iface->reach_time = timex_set(0, reach_time);
|
||||
timex_normalize(&iface->reach_time);
|
||||
iface->retrans_timer = timex_set(0, NG_NDP_RETRANS_TIMER);
|
||||
timex_normalize(&iface->retrans_timer);
|
||||
mutex_unlock(&iface->mutex);
|
||||
}
|
||||
|
||||
void ng_ndp_netif_remove(ng_ipv6_netif_t *iface)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static ng_ipv6_addr_t *_default_router(void)
|
||||
{
|
||||
ng_ipv6_nc_t *router = ng_ipv6_nc_get_next_router(NULL);
|
||||
|
||||
/* first look if there is any reachable router */
|
||||
while (router != NULL) {
|
||||
if ((ng_ipv6_nc_get_state(router) != NG_IPV6_NC_STATE_INCOMPLETE) &&
|
||||
(ng_ipv6_nc_get_state(router) != NG_IPV6_NC_STATE_UNREACHABLE)) {
|
||||
_last_router = NULL;
|
||||
|
||||
return &router->ipv6_addr;
|
||||
}
|
||||
|
||||
router = ng_ipv6_nc_get_next_router(router);
|
||||
}
|
||||
|
||||
/* else take the first one, but keep round-robin in further selections */
|
||||
router = ng_ipv6_nc_get_next_router(_last_router);
|
||||
|
||||
if (router == NULL) { /* end of router list or there is none => wrap around */
|
||||
router = ng_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;
|
||||
}
|
||||
|
||||
kernel_pid_t ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
kernel_pid_t iface, ng_ipv6_addr_t *dst,
|
||||
ng_pktsnip_t *pkt)
|
||||
{
|
||||
ng_ipv6_addr_t *next_hop_ip = NULL, *prefix = NULL;
|
||||
#ifdef MODULE_FIB
|
||||
size_t next_hop_size;
|
||||
|
||||
if ((fib_get_next_hop(&iface, (uint8_t *)next_hop_ip, &next_hop_size,
|
||||
(uint8_t *)dst, sizeof(ng_ipv6_addr_t),
|
||||
0) < 0) || (next_hop_ip != sizeof(ng_ipv6_addr_t))) {
|
||||
next_hop_ip = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((next_hop_ip == NULL)) { /* no route to host */
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
/* ng_ipv6_netif_t doubles as prefix list */
|
||||
iface = ng_ipv6_netif_find_by_prefix(&prefix, dst);
|
||||
}
|
||||
else {
|
||||
/* ng_ipv6_netif_t doubles as prefix list */
|
||||
prefix = ng_ipv6_netif_match_prefix(iface, dst);
|
||||
}
|
||||
|
||||
if ((prefix != NULL) && /* prefix is on-link */
|
||||
(ng_ipv6_netif_addr_get(prefix)->flags &
|
||||
NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK)) {
|
||||
next_hop_ip = dst;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_hop_ip == NULL) {
|
||||
next_hop_ip = _default_router();
|
||||
}
|
||||
|
||||
if (next_hop_ip != NULL) {
|
||||
ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, next_hop_ip);
|
||||
|
||||
if ((nc_entry != NULL) && ng_ipv6_nc_is_reachable(nc_entry)) {
|
||||
DEBUG("ndp: found reachable neigbor\n");
|
||||
|
||||
if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_STALE) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_DELAY);
|
||||
}
|
||||
|
||||
memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len);
|
||||
*l2addr_len = nc_entry->l2_addr_len;
|
||||
/* TODO: unreachability check */
|
||||
return nc_entry->iface;
|
||||
}
|
||||
else if (nc_entry == NULL) {
|
||||
ng_pktqueue_node_t *pkt_node;
|
||||
ng_ipv6_addr_t dst_sol;
|
||||
|
||||
nc_entry = ng_ipv6_nc_add(iface, next_hop_ip, NULL, 0,
|
||||
NG_IPV6_NC_STATE_INCOMPLETE << NG_IPV6_NC_STATE_POS);
|
||||
|
||||
if (nc_entry == NULL) {
|
||||
DEBUG("ndp: could not create neighbor cache entry\n");
|
||||
return KERNEL_PID_UNDEF;
|
||||
}
|
||||
|
||||
pkt_node = _alloc_pkt_node(pkt);
|
||||
|
||||
if (pkt_node == NULL) {
|
||||
DEBUG("ndp: could not add packet to packet queue\n");
|
||||
}
|
||||
else {
|
||||
/* prevent packet from being released by IPv6 */
|
||||
ng_pktbuf_hold(pkt_node->data, 1);
|
||||
ng_pktqueue_add(&nc_entry->pkts, pkt_node);
|
||||
}
|
||||
|
||||
/* address resolution */
|
||||
ng_ipv6_addr_set_solicited_nodes(&dst_sol, next_hop_ip);
|
||||
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
timex_t t = { 0, NG_NDP_RETRANS_TIMER };
|
||||
kernel_pid_t *ifs;
|
||||
size_t ifnum;
|
||||
|
||||
ifs = ng_netif_get(&ifnum);
|
||||
|
||||
for (size_t i = 0; i < ifnum; i++) {
|
||||
_send_nbr_sol(ifs[i], next_hop_ip, &dst_sol);
|
||||
}
|
||||
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
}
|
||||
else {
|
||||
ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(iface);
|
||||
|
||||
_send_nbr_sol(iface, next_hop_ip, &dst_sol);
|
||||
|
||||
mutex_lock(&ipv6_iface->mutex);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer,
|
||||
ipv6_iface->retrans_timer, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
mutex_unlock(&ipv6_iface->mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return KERNEL_PID_UNDEF;
|
||||
}
|
||||
|
||||
ng_pktsnip_t *ng_ndp_nbr_sol_build(ng_ipv6_addr_t *tgt, ng_pktsnip_t *options)
|
||||
{
|
||||
ng_pktsnip_t *pkt;
|
||||
ng_ndp_nbr_sol_t *nbr_sol;
|
||||
|
||||
DEBUG("ndp: building neighbor solicitation message\n");
|
||||
|
||||
if (ng_ipv6_addr_is_multicast(tgt)) {
|
||||
DEBUG("ndp: tgt must not be multicast\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkt = ng_icmpv6_build(options, NG_ICMPV6_NBR_SOL, 0, sizeof(ng_ndp_nbr_sol_t));
|
||||
|
||||
if (pkt != NULL) {
|
||||
nbr_sol = pkt->data;
|
||||
nbr_sol->resv.u32 = 0;
|
||||
memcpy(&nbr_sol->tgt, tgt, sizeof(ng_ipv6_addr_t));
|
||||
}
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
ng_pktsnip_t *ng_ndp_nbr_adv_build(uint8_t flags, ng_ipv6_addr_t *tgt,
|
||||
ng_pktsnip_t *options)
|
||||
{
|
||||
ng_pktsnip_t *pkt;
|
||||
ng_ndp_nbr_adv_t *nbr_adv;
|
||||
|
||||
DEBUG("ndp: building neighbor advertisement message\n");
|
||||
|
||||
if (ng_ipv6_addr_is_multicast(tgt)) {
|
||||
DEBUG("ndp: tgt must not be multicast\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkt = ng_icmpv6_build(options, NG_ICMPV6_NBR_ADV, 0, sizeof(ng_ndp_nbr_adv_t));
|
||||
|
||||
if (pkt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nbr_adv = pkt->data;
|
||||
nbr_adv->flags = (flags & NG_NDP_NBR_ADV_FLAGS_MASK);
|
||||
nbr_adv->resv[0] = nbr_adv->resv[1] = nbr_adv->resv[2] = 0;
|
||||
memcpy(&nbr_adv->tgt, tgt, sizeof(ng_ipv6_addr_t));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ng_pktsnip_t *ng_ndp_opt_build(uint8_t type, size_t size, ng_pktsnip_t *next)
|
||||
{
|
||||
ng_ndp_opt_t *opt;
|
||||
ng_pktsnip_t *pkt = ng_pktbuf_add(next, NULL, _ceil8(size), NG_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 uint16_t _get_l2src(uint8_t *l2src, size_t l2src_size, kernel_pid_t iface)
|
||||
{
|
||||
bool try_long = false;
|
||||
int res;
|
||||
uint16_t l2src_len;
|
||||
|
||||
/* try getting source address */
|
||||
if ((ng_netapi_get(iface, NETCONF_OPT_SRC_LEN, 0, &l2src_len,
|
||||
sizeof(l2src_len)) >= 0) &&
|
||||
(l2src_len == 8)) {
|
||||
try_long = true;
|
||||
}
|
||||
|
||||
if ((try_long && ((res = ng_netapi_get(iface, NETCONF_OPT_ADDRESS_LONG, 0,
|
||||
l2src, l2src_size)) < 0)) ||
|
||||
((res = ng_netapi_get(iface, NETCONF_OPT_ADDRESS, 0, l2src,
|
||||
l2src_size)) < 0)) {
|
||||
DEBUG("ndp: no link-layer address found.\n");
|
||||
l2src_len = 0;
|
||||
}
|
||||
else {
|
||||
l2src_len = (uint16_t)res;
|
||||
}
|
||||
|
||||
return l2src_len;
|
||||
}
|
||||
|
||||
static void _send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst)
|
||||
{
|
||||
ng_pktsnip_t *hdr, *pkt = NULL;
|
||||
ng_ipv6_addr_t *src = NULL;
|
||||
size_t src_len = 0;
|
||||
uint8_t l2src[8];
|
||||
uint16_t l2src_len;
|
||||
|
||||
/* check if there is a fitting source address to target */
|
||||
if ((src = ng_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) {
|
||||
src_len = sizeof(ng_ipv6_addr_t);
|
||||
l2src_len = _get_l2src(l2src, sizeof(l2src), iface);
|
||||
|
||||
if (l2src_len > 0) {
|
||||
/* add source address link-layer address option */
|
||||
pkt = ng_ndp_opt_sl2a_build(l2src, l2src_len, NULL);
|
||||
|
||||
if (pkt == NULL) {
|
||||
DEBUG("ndp: error allocating Source Link-layer address option.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hdr = ng_ndp_nbr_sol_build(tgt, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating Neighbor solicitation.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = hdr;
|
||||
hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)src, src_len, (uint8_t *)dst,
|
||||
sizeof(ng_ipv6_addr_t));
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating IPv6 header.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_ipv6_hdr_t *)hdr->data)->hl = 255;
|
||||
|
||||
pkt = hdr;
|
||||
/* add netif header for send interface specification */
|
||||
hdr = ng_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating netif header.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LL_PREPEND(pkt, hdr);
|
||||
|
||||
((ng_netif_hdr_t *)hdr->data)->if_pid = iface;
|
||||
|
||||
ng_netapi_send(ng_ipv6_pid, pkt);
|
||||
}
|
||||
|
||||
static void _send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt,
|
||||
ng_ipv6_addr_t *dst, bool supply_tl2a)
|
||||
{
|
||||
ng_pktsnip_t *hdr, *pkt = NULL;
|
||||
uint8_t l2src[8];
|
||||
uint16_t l2src_len;
|
||||
uint8_t adv_flags = 0;
|
||||
|
||||
if (ng_ipv6_netif_get(iface)->flags & NG_IPV6_NETIF_FLAGS_ROUTER) {
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_R;
|
||||
}
|
||||
|
||||
if (ng_ipv6_addr_is_unspecified(dst)) {
|
||||
ng_ipv6_addr_set_all_nodes_multicast(dst,
|
||||
NG_IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
|
||||
}
|
||||
else {
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_S;
|
||||
}
|
||||
|
||||
if (supply_tl2a) {
|
||||
/* we previously checked if we are the target, so we can take our L2src */
|
||||
l2src_len = _get_l2src(l2src, sizeof(l2src), iface);
|
||||
|
||||
if (l2src_len > 0) {
|
||||
/* add target address link-layer address option */
|
||||
pkt = ng_ndp_opt_tl2a_build(l2src, l2src_len, NULL);
|
||||
|
||||
if (pkt == NULL) {
|
||||
DEBUG("ndp: error allocating Target Link-layer address option.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: also check if the node provides proxy servies for tgt */
|
||||
if ((pkt != NULL) && !ng_ipv6_netif_addr_is_non_unicast(tgt)) {
|
||||
/* TL2A is not supplied and tgt is not anycast */
|
||||
adv_flags |= NG_NDP_NBR_ADV_FLAGS_O;
|
||||
}
|
||||
|
||||
hdr = ng_ndp_nbr_adv_build(adv_flags, tgt, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating Neighbor advertisement.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = hdr;
|
||||
hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)dst,
|
||||
sizeof(ng_ipv6_addr_t));
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating IPv6 header.\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
((ng_ipv6_hdr_t *)hdr->data)->hl = 255;
|
||||
|
||||
pkt = hdr;
|
||||
/* add netif header for send interface specification */
|
||||
hdr = ng_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp: error allocating netif header.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LL_PREPEND(pkt, hdr);
|
||||
|
||||
((ng_netif_hdr_t *)hdr->data)->if_pid = iface;
|
||||
|
||||
if (ng_ipv6_netif_addr_is_non_unicast(tgt)) {
|
||||
/* avoid collision for anycast addresses */
|
||||
timex_t delay = { _rand(0, NG_NDP_MAX_AC_TGT_DELAY), 0 };
|
||||
ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, tgt);
|
||||
|
||||
/* nc_entry must be set so no need to check it */
|
||||
_send_delayed(&nc_entry->nbr_adv_timer, delay, pkt);
|
||||
}
|
||||
else {
|
||||
ng_netapi_send(ng_ipv6_pid, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
static inline ng_pktsnip_t *_opt_l2a_build(uint8_t type, const uint8_t *l2addr,
|
||||
uint8_t l2addr_len, ng_pktsnip_t *next)
|
||||
{
|
||||
ng_pktsnip_t *pkt = ng_ndp_opt_build(type, sizeof(ng_ndp_opt_t) + l2addr_len,
|
||||
next);
|
||||
|
||||
if (pkt != NULL) {
|
||||
ng_ndp_opt_t *l2a_opt = pkt->data;
|
||||
|
||||
memset(l2a_opt + 1, 0, pkt->size - sizeof(ng_ndp_opt_t));
|
||||
memcpy(l2a_opt + 1, l2addr, l2addr_len);
|
||||
}
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
ng_pktsnip_t *ng_ndp_opt_sl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
|
||||
ng_pktsnip_t *next)
|
||||
{
|
||||
DEBUG("ndp: building source link-layer address option\n");
|
||||
|
||||
return _opt_l2a_build(NG_NDP_OPT_SL2A, l2addr, l2addr_len, next);
|
||||
}
|
||||
|
||||
ng_pktsnip_t *ng_ndp_opt_tl2a_build(const uint8_t *l2addr, uint8_t l2addr_len,
|
||||
ng_pktsnip_t *next)
|
||||
{
|
||||
DEBUG("ndp: building target link-layer address option\n");
|
||||
|
||||
return _opt_l2a_build(NG_NDP_OPT_TL2A, l2addr, l2addr_len, next);
|
||||
}
|
||||
|
||||
/* internal functions */
|
||||
/* packet queue node allocation */
|
||||
static ng_pktqueue_node_t *_alloc_pkt_node(ng_pktsnip_t *pkt)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(_pkt_nodes); i++) {
|
||||
if (_pkt_nodes[i].data == NULL) {
|
||||
ng_pktqueue_node_init(_pkt_nodes + i);
|
||||
_pkt_nodes[i].data = pkt;
|
||||
|
||||
return &(_pkt_nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool _handle_sl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ng_ndp_opt_t *sl2a_opt)
|
||||
{
|
||||
ng_ipv6_nc_t *nc_entry = NULL;
|
||||
uint8_t sl2a_len = 0;
|
||||
uint8_t *sl2a = (uint8_t *)(sl2a_opt + 1);
|
||||
|
||||
if ((sl2a_opt->len == 0) || ng_ipv6_addr_is_unspecified(&ipv6->src)) {
|
||||
DEBUG("ndp: invalid source link-layer address option received\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (pkt) {
|
||||
if (pkt->type == NG_NETTYPE_NETIF) {
|
||||
ng_netif_hdr_t *hdr = pkt->data;
|
||||
sl2a_len = hdr->src_l2addr_len;
|
||||
break;
|
||||
}
|
||||
pkt = pkt->next;
|
||||
}
|
||||
|
||||
if (sl2a_len == 0) { /* in case there was no source address in l2 */
|
||||
sl2a_len = (sl2a_opt->len / 8) - sizeof(ng_ndp_opt_t);
|
||||
|
||||
/* ignore all zeroes at the end for length */
|
||||
for (; sl2a[sl2a_len - 1] == 0x00; sl2a_len--);
|
||||
}
|
||||
|
||||
switch (icmpv6_type) {
|
||||
case NG_ICMPV6_NBR_SOL:
|
||||
nc_entry = ng_ipv6_nc_get(iface, &ipv6->src);
|
||||
|
||||
if (nc_entry != NULL) {
|
||||
if ((sl2a_len != nc_entry->l2_addr_len) ||
|
||||
(memcmp(sl2a, nc_entry->l2_addr, sl2a_len) != 0)) {
|
||||
/* if entry exists but l2 address differs: set */
|
||||
nc_entry->l2_addr_len = sl2a_len;
|
||||
memcpy(nc_entry->l2_addr, sl2a, sl2a_len);
|
||||
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ng_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len,
|
||||
NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
default: /* wrong encapsulating message: silently discard */
|
||||
DEBUG("ndp: silently discard sl2a_opt for ICMPv6 message type %"
|
||||
PRIu8 "\n", icmpv6_type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _handle_tl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt,
|
||||
ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ng_ndp_opt_t *tl2a_opt, ng_ipv6_addr_t *tgt,
|
||||
uint8_t adv_flags)
|
||||
{
|
||||
ng_ipv6_nc_t *nc_entry = NULL;
|
||||
uint8_t tl2a_len = 0;
|
||||
uint8_t *tl2a = (uint8_t *)(tl2a_opt + 1);
|
||||
|
||||
if ((tl2a_opt->len == 0) || ng_ipv6_addr_is_unspecified(&ipv6->src)) {
|
||||
DEBUG("ndp: invalid target link-layer address option received\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (pkt) {
|
||||
if (pkt->type == NG_NETTYPE_NETIF) {
|
||||
ng_netif_hdr_t *hdr = pkt->data;
|
||||
tl2a_len = hdr->src_l2addr_len;
|
||||
break;
|
||||
}
|
||||
pkt = pkt->next;
|
||||
}
|
||||
|
||||
if (tl2a_len == 0) { /* in case there was no source address in l2 */
|
||||
tl2a_len = (tl2a_opt->len / 8) - sizeof(ng_ndp_opt_t);
|
||||
|
||||
/* ignore all zeroes at the end for length */
|
||||
for (; tl2a[tl2a_len - 1] == 0x00; tl2a_len--);
|
||||
}
|
||||
|
||||
switch (icmpv6_type) {
|
||||
case NG_ICMPV6_NBR_ADV:
|
||||
nc_entry = ng_ipv6_nc_get(iface, tgt);
|
||||
|
||||
/* no need to create an entry in the negative case (see RFC 4861) */
|
||||
if (nc_entry != NULL) {
|
||||
nc_entry->l2_addr_len = tl2a_len;
|
||||
|
||||
if (tl2a_len > 0) {
|
||||
memcpy(nc_entry->l2_addr, tl2a, tl2a_len);
|
||||
}
|
||||
|
||||
if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) {
|
||||
ng_pktqueue_node_t *queued_pkt;
|
||||
|
||||
if (adv_flags & NG_NDP_NBR_ADV_FLAGS_S) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
|
||||
}
|
||||
else {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
if (adv_flags & NG_NDP_NBR_ADV_FLAGS_R) {
|
||||
nc_entry->flags |= NG_IPV6_NC_IS_ROUTER;
|
||||
}
|
||||
else {
|
||||
nc_entry->flags &= ~NG_IPV6_NC_IS_ROUTER;
|
||||
}
|
||||
|
||||
while ((queued_pkt = ng_pktqueue_remove_head(&nc_entry->pkts)) != NULL) {
|
||||
ng_netapi_send(ng_ipv6_pid, queued_pkt->data);
|
||||
queued_pkt->data = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (memcmp(tl2a, nc_entry->l2_addr, tl2a_len) != 0) {
|
||||
if ((adv_flags & NG_NDP_NBR_ADV_FLAGS_O)) {
|
||||
memcpy(nc_entry->l2_addr, tl2a, tl2a_len);
|
||||
}
|
||||
else if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_REACHABLE) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
}
|
||||
|
||||
if ((adv_flags & NG_NDP_NBR_ADV_FLAGS_O)) {
|
||||
if (adv_flags & NG_NDP_NBR_ADV_FLAGS_S) {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
|
||||
}
|
||||
else {
|
||||
_set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
if (adv_flags & NG_NDP_NBR_ADV_FLAGS_R) {
|
||||
nc_entry->flags |= NG_IPV6_NC_IS_ROUTER;
|
||||
}
|
||||
else {
|
||||
nc_entry->flags &= ~NG_IPV6_NC_IS_ROUTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
default: /* wrong encapsulating message: silently discard */
|
||||
DEBUG("ndp: silently discard tl2a_opt for ICMPv6 message type %"
|
||||
PRIu8 "\n", icmpv6_type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void _set_state(ng_ipv6_nc_t *nc_entry, uint8_t state)
|
||||
{
|
||||
ng_ipv6_netif_t *ipv6_iface;
|
||||
timex_t t = { NG_NDP_FIRST_PROBE_DELAY, 0 };
|
||||
|
||||
nc_entry->flags &= ~NG_IPV6_NC_STATE_MASK;
|
||||
nc_entry->flags |= state;
|
||||
|
||||
switch (state) {
|
||||
case NG_IPV6_NC_STATE_REACHABLE:
|
||||
ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);
|
||||
t = ipv6_iface->reach_time;
|
||||
vtimer_remove(&nc_entry->nbr_sol_timer);
|
||||
|
||||
case NG_IPV6_NC_STATE_DELAY:
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NC_STATE_TIMEOUT, nc_entry);
|
||||
break;
|
||||
|
||||
case NG_IPV6_NC_STATE_PROBE:
|
||||
ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);
|
||||
|
||||
nc_entry->probes_remaining = NG_NDP_MAX_UC_NBR_SOL_NUMOF;
|
||||
_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr,
|
||||
&nc_entry->ipv6_addr);
|
||||
|
||||
mutex_lock(&ipv6_iface->mutex);
|
||||
vtimer_set_msg(&nc_entry->nbr_sol_timer,
|
||||
ipv6_iface->retrans_timer, ng_ipv6_pid,
|
||||
NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
|
||||
mutex_unlock(&ipv6_iface->mutex);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
Loading…
Reference in New Issue
Block a user