mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #7064 from miri64/gnrc_ndp2/api/initial
gnrc_ndp2: Provide GNRC abstraction layer for NIB for sending
This commit is contained in:
commit
43283ef16b
@ -251,6 +251,10 @@ ifneq (,$(filter gnrc_ndp,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_ndp2,$(USEMODULE)))
|
||||
USEMODULE += gnrc_icmpv6
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_icmpv6_echo,$(USEMODULE)))
|
||||
USEMODULE += gnrc_icmpv6
|
||||
endif
|
||||
|
367
sys/include/net/gnrc/ndp2.h
Normal file
367
sys/include/net/gnrc/ndp2.h
Normal file
@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Freie Universität Berlin
|
||||
*
|
||||
* 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_ndp2 IPv6 neighbor discovery (v2)
|
||||
* @ingroup net_gnrc_ipv6
|
||||
* @brief Provides build and send functions for neighbor discovery packets
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief GNRC-specific neighbor discovery definitions
|
||||
*
|
||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
#ifndef NET_GNRC_NDP2_H
|
||||
#define NET_GNRC_NDP2_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "kernel_types.h"
|
||||
#include "net/gnrc/pkt.h"
|
||||
#include "net/gnrc/ipv6/netif.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief @ref net_gnrc_nettype to send NDP packets to
|
||||
*/
|
||||
#ifndef GNRC_NETTYPE_NDP2
|
||||
# if defined(MODULE_GNRC_IPV6) || DOXYGEN
|
||||
# define GNRC_NETTYPE_NDP2 (GNRC_NETTYPE_IPV6) /* usual configuration */
|
||||
# else
|
||||
# define GNRC_NETTYPE_NDP2 (GNRC_NETTYPE_UNDEF) /* for testing */
|
||||
# endif
|
||||
#endif /* GNRC_NETTYPE_NDP2 */
|
||||
|
||||
/**
|
||||
* @brief Builds a neighbor solicitation message for sending.
|
||||
*
|
||||
* @pre `(tgt != NULL) && !ipv6_addr_is_multicast(tgt)`
|
||||
*
|
||||
* @see [RFC 4861, section 4.3](https://tools.ietf.org/html/rfc4861#section-4.3)
|
||||
*
|
||||
* @param[in] tgt The target address of the neighbor solicitation.
|
||||
* May not be NULL and **MUST NOT** be multicast.
|
||||
* @param[in] options Options to append to the neighbor solicitation.
|
||||
* May be NULL for none.
|
||||
*
|
||||
* @return The resulting ICMPv6 packet on success.
|
||||
* @return NULL, if packet buffer is full.
|
||||
*/
|
||||
gnrc_pktsnip_t *gnrc_ndp2_nbr_sol_build(const ipv6_addr_t *tgt,
|
||||
gnrc_pktsnip_t *options);
|
||||
|
||||
/**
|
||||
* @brief Builds a neighbor advertisement message for sending.
|
||||
*
|
||||
* @pre `(tgt != NULL) && !ipv6_addr_is_multicast(tgt)`
|
||||
*
|
||||
* @see [RFC 4861, section 4.4](https://tools.ietf.org/html/rfc4861#section-4.4")
|
||||
*
|
||||
* @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.
|
||||
* May not be NULL and **MUST NOT** be multicast.
|
||||
* @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] options Options to append to the neighbor advertisement.
|
||||
* May be NULL for none.
|
||||
*
|
||||
* @return The resulting ICMPv6 packet on success.
|
||||
* @return NULL, if packet buffer is full.
|
||||
*/
|
||||
gnrc_pktsnip_t *gnrc_ndp2_nbr_adv_build(const ipv6_addr_t *tgt, uint8_t flags,
|
||||
gnrc_pktsnip_t *options);
|
||||
|
||||
/**
|
||||
* @brief Builds a router solicitation message for sending.
|
||||
*
|
||||
* @see `[RFC 4861, section 4.1](https://tools.ietf.org/html/rfc4861#section-4.1")
|
||||
*
|
||||
* @param[in] options Options to append to the router solicitation.
|
||||
* May be NULL for none.
|
||||
*
|
||||
* @return The resulting ICMPv6 packet on success.
|
||||
* @return NULL, if packet buffer is full.
|
||||
*/
|
||||
gnrc_pktsnip_t *gnrc_ndp2_rtr_sol_build(gnrc_pktsnip_t *options);
|
||||
|
||||
/**
|
||||
* @brief Builds a router advertisement message for sending.
|
||||
*
|
||||
* @see `[RFC 4861, section 4.2](https://tools.ietf.org/html/rfc4861#section-4.2")
|
||||
*
|
||||
* @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 in net/ndp.h.
|
||||
* - @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.
|
||||
* May be NULL for none.
|
||||
*
|
||||
* @return The resulting ICMPv6 packet on success.
|
||||
* @return NULL, if packet buffer is full.
|
||||
*/
|
||||
gnrc_pktsnip_t *gnrc_ndp2_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);
|
||||
|
||||
/**
|
||||
* @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_ndp2_opt_build(uint8_t type, size_t size,
|
||||
gnrc_pktsnip_t *next);
|
||||
|
||||
/**
|
||||
* @brief Builds the source link-layer address option.
|
||||
*
|
||||
* @pre `(l2addr != NULL) && (l2addr_len != 0)`
|
||||
*
|
||||
* @see [RFC 4861, section 4.6.1](https://tools.ietf.org/html/rfc4861#section-4.6.1)
|
||||
*
|
||||
* @note Should 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.
|
||||
* May not be NULL.
|
||||
* @param[in] l2addr_len Length of @p l2addr. May not be 0.
|
||||
* @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_ndp2_opt_sl2a_build(const uint8_t *l2addr,
|
||||
uint8_t l2addr_len,
|
||||
gnrc_pktsnip_t *next);
|
||||
|
||||
/**
|
||||
* @brief Builds the target link-layer address option.
|
||||
*
|
||||
* @pre `(l2addr != NULL) && (l2addr_len != 0)`
|
||||
*
|
||||
* @see [RFC 4861, section 4.6.1](https://tools.ietf.org/html/rfc4861#section-4.6.1)
|
||||
*
|
||||
* @note Should 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.
|
||||
* May not be NULL.
|
||||
* @param[in] l2addr_len Length of @p l2addr. May not be 0.
|
||||
* @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_ndp2_opt_tl2a_build(const uint8_t *l2addr,
|
||||
uint8_t l2addr_len,
|
||||
gnrc_pktsnip_t *next);
|
||||
|
||||
/**
|
||||
* @brief Builds the prefix information option.
|
||||
*
|
||||
* @pre `prefix != NULL`
|
||||
* @pre `!ipv6_addr_is_link_local(prefix) && !ipv6_addr_is_multicast(prefix)`
|
||||
* @pre `prefix_len <= 128`
|
||||
*
|
||||
* @see [RFC 4861, section 4.6.2](https://tools.ietf.org/html/rfc4861#section-4.6.2)
|
||||
*
|
||||
* @note Should only be used with router advertisemnents. This is not checked
|
||||
* however, since nodes should silently ignore it in other NDP messages.
|
||||
*
|
||||
* @param[in] prefix An IPv6 address or a prefix of an IPv6 address.
|
||||
* May not be NULL and must not be link-local or
|
||||
* multicast.
|
||||
* @param[in] prefix_len The length of @p prefix in bits. Must be between
|
||||
* 0 and 128.
|
||||
* @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] flags Flags as defined in net/ndp.h.
|
||||
* - @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] 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_ndp2_opt_pi_build(const ipv6_addr_t *prefix,
|
||||
uint8_t prefix_len,
|
||||
uint32_t valid_ltime, uint32_t pref_ltime,
|
||||
uint8_t flags, gnrc_pktsnip_t *next);
|
||||
|
||||
/**
|
||||
* @brief Builds the MTU option.
|
||||
*
|
||||
* @see [RFC 4861, section 4.6.4](https://tools.ietf.org/html/rfc4861#section-4.6.4)
|
||||
*
|
||||
* @note Should 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_ndp2_opt_mtu_build(uint32_t mtu, gnrc_pktsnip_t *next);
|
||||
|
||||
/**
|
||||
* @brief Send pre-compiled neighbor solicitation depending on a given network
|
||||
* interface.
|
||||
*
|
||||
* @pre `(tgt != NULL) && !ipv6_addr_is_multicast(tgt)`
|
||||
* @pre `(netif != NULL) && (dst != NULL)`
|
||||
*
|
||||
* @param[in] tgt The target address of the neighbor solicitation.
|
||||
* May not be NULL and **MUST NOT** be multicast.
|
||||
* @param[in] netif Interface to send over. May not be NULL.
|
||||
* @param[in] src Source address for the neighbor solicitation. Will be
|
||||
* chosen from the interface according to @p dst, if NULL.
|
||||
* @param[in] dst Destination address for neighbor solicitation. May not
|
||||
* be NULL.
|
||||
* @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 solicitation so be sure to check that.
|
||||
* **Will be released** in an error case.
|
||||
*/
|
||||
void gnrc_ndp2_nbr_sol_send(const ipv6_addr_t *tgt, gnrc_ipv6_netif_t *netif,
|
||||
const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
||||
gnrc_pktsnip_t *ext_opts);
|
||||
|
||||
/**
|
||||
* @brief Send pre-compiled neighbor advertisement depending on a given
|
||||
* network interface.
|
||||
*
|
||||
* @pre `(tgt != NULL) && !ipv6_addr_is_multicast(tgt)`
|
||||
* @pre `(netif != NULL) && (dst != NULL)`
|
||||
*
|
||||
* If @p netif is a forwarding interface and router advertisements are
|
||||
* activated the @ref NDP_NBR_ADV_FLAGS_R is set in the neighbor advertisement.
|
||||
* If @p dst is @ref IPV6_ADDR_UNSPECIFIED it will be replaced with
|
||||
* @ref IPV6_ADDR_ALL_NODES_LINK_LOCAL and* @p supply_tl2a is set to true
|
||||
* implicitly. Otherwise, the @ref NDP_NBR_ADV_FLAGS_S will be set. If @p tgt
|
||||
* is an anycast address on @p netif the @ref NDP_NBR_ADV_FLAGS_O flag will be
|
||||
* set.
|
||||
*
|
||||
* The source address of the IPv6 packet will be left unspecified, so the
|
||||
* @ref net_gnrc_ipv6 "IPv6 module" selects a fitting IPv6 address.
|
||||
*
|
||||
* @param[in] tgt Target address for the neighbor advertisement. May
|
||||
* not be NULL and **MUST NOT** be multicast.
|
||||
* @param[in] netif Interface to send over. May not be NULL.
|
||||
* @param[in] dst Destination address for neighbor advertisement. May
|
||||
* not be NULL. Is set to
|
||||
* @ref IPV6_ADDR_ALL_NODES_LINK_LOCAL when equal to
|
||||
* @ref IPV6_ADDR_UNSPECIFIED (to allow for simple
|
||||
* reply mechanisms to neighbor solicitations). This
|
||||
* also implies that @p supply_tl2a **must** be true
|
||||
* and the parameter will be reset accordingly. If
|
||||
* @p dst is not @ref IPV6_ADDR_UNSPECIFIED, the
|
||||
* @ref NDP_NBR_ADV_FLAGS_S flag will be set
|
||||
* implicitly.
|
||||
* @param[in] supply_tl2a Add target link-layer address option to neighbor
|
||||
* advertisement if link-layer has addresses.
|
||||
* If @p dst is @ref IPV6_ADDR_UNSPECIFIED, it will be
|
||||
* set to true.
|
||||
* @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_ndp2_nbr_adv_send(const ipv6_addr_t *tgt, gnrc_ipv6_netif_t *netif,
|
||||
const ipv6_addr_t *dst, bool supply_tl2a,
|
||||
gnrc_pktsnip_t *ext_opts);
|
||||
|
||||
/**
|
||||
* @brief Send pre-compiled router solicitation depending on a given
|
||||
* network interface.
|
||||
*
|
||||
* @pre `(netif != NULL)`
|
||||
*
|
||||
* @param[in] netif Interface to send over. May not be NULL.
|
||||
* @param[in] dst Destination for the router solicitation. ff02::2 if NULL.
|
||||
*/
|
||||
void gnrc_ndp2_rtr_sol_send(gnrc_ipv6_netif_t *netif, const ipv6_addr_t *dst);
|
||||
|
||||
/**
|
||||
* @brief Send pre-compiled router advertisement depending on a given network
|
||||
* interface.
|
||||
*
|
||||
* @pre `(netif != NULL)`
|
||||
*
|
||||
* This function does not add the PIOs to the router, since they are highly
|
||||
* dependent on external set-ups (e.g. if multihop prefix distribution is used).
|
||||
* Provide them via @p ext_opts
|
||||
*
|
||||
* @param[in] netif Interface to send over. May not be NULL.
|
||||
* @param[in] src Source address for the router advertisement. May be
|
||||
* NULL to be determined by source address selection
|
||||
* (:: if @p netif has no address).
|
||||
* @param[in] dst Destination address for router advertisement.
|
||||
* ff02::1 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).
|
||||
* @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_ndp2_rtr_adv_send(gnrc_ipv6_netif_t *netif, const ipv6_addr_t *src,
|
||||
const ipv6_addr_t *dst, bool fin,
|
||||
gnrc_pktsnip_t *ext_opts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_GNRC_NDP2_H */
|
||||
/** @} */
|
@ -46,6 +46,9 @@ endif
|
||||
ifneq (,$(filter gnrc_ndp_router,$(USEMODULE)))
|
||||
DIRS += network_layer/ndp/router
|
||||
endif
|
||||
ifneq (,$(filter gnrc_ndp2,$(USEMODULE)))
|
||||
DIRS += network_layer/ndp2
|
||||
endif
|
||||
ifneq (,$(filter gnrc_netapi,$(USEMODULE)))
|
||||
DIRS += netapi
|
||||
endif
|
||||
|
@ -129,6 +129,7 @@ void gnrc_icmpv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt)
|
||||
|
||||
default:
|
||||
DEBUG("icmpv6: unknown type field %u\n", hdr->type);
|
||||
(void)iface;
|
||||
break;
|
||||
}
|
||||
|
||||
|
3
sys/net/gnrc/network_layer/ndp2/Makefile
Normal file
3
sys/net/gnrc/network_layer/ndp2/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_ndp2
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
572
sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c
Normal file
572
sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c
Normal file
@ -0,0 +1,572 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Freie Universität Berlin
|
||||
*
|
||||
* 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
|
||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include "net/gnrc/icmpv6.h"
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_ND
|
||||
#include "net/gnrc/sixlowpan/nd.h"
|
||||
#endif
|
||||
#include "net/ndp.h"
|
||||
|
||||
#include "net/gnrc/ndp2.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
gnrc_pktsnip_t *gnrc_ndp2_nbr_sol_build(const ipv6_addr_t *tgt,
|
||||
gnrc_pktsnip_t *options)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt;
|
||||
|
||||
assert((tgt != NULL) && !ipv6_addr_is_multicast(tgt));
|
||||
DEBUG("ndp2: building neighbor solicitation message\n");
|
||||
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;
|
||||
}
|
||||
#if ENABLE_DEBUG
|
||||
else {
|
||||
DEBUG("ndp2: NS not created due to no space in packet buffer\n");
|
||||
}
|
||||
#endif
|
||||
return pkt;
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *gnrc_ndp2_nbr_adv_build(const ipv6_addr_t *tgt, uint8_t flags,
|
||||
gnrc_pktsnip_t *options)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt;
|
||||
|
||||
assert((tgt != NULL) && !ipv6_addr_is_multicast(tgt));
|
||||
DEBUG("ndp2: building neighbor advertisement message\n");
|
||||
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;
|
||||
}
|
||||
#if ENABLE_DEBUG
|
||||
else {
|
||||
DEBUG("ndp2: NA not created due to no space in packet buffer\n");
|
||||
}
|
||||
#endif
|
||||
return pkt;
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *gnrc_ndp2_rtr_sol_build(gnrc_pktsnip_t *options)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt;
|
||||
|
||||
DEBUG("ndp2: 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;
|
||||
}
|
||||
#if ENABLE_DEBUG
|
||||
else {
|
||||
DEBUG("ndp2: RS not created due to no space in packet buffer\n");
|
||||
}
|
||||
#endif
|
||||
return pkt;
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *gnrc_ndp2_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("ndp2: 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);
|
||||
}
|
||||
#if ENABLE_DEBUG
|
||||
else {
|
||||
DEBUG("ndp2: RA not created due to no space in packet buffer\n");
|
||||
}
|
||||
#endif
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static inline size_t _ceil8(uint8_t length)
|
||||
{
|
||||
/* NDP options use units of 8 byte for their length field, so round up */
|
||||
return (length + 7U) & 0xf8U;
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *gnrc_ndp2_opt_build(uint8_t type, size_t size,
|
||||
gnrc_pktsnip_t *next)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(next, NULL, _ceil8(size),
|
||||
GNRC_NETTYPE_UNDEF);
|
||||
|
||||
if (pkt != NULL) {
|
||||
ndp_opt_t *opt = pkt->data;
|
||||
opt->type = type;
|
||||
opt->len = (uint8_t)(pkt->size / 8);
|
||||
}
|
||||
#if ENABLE_DEBUG
|
||||
else {
|
||||
DEBUG("ndp2: option not created due to no space in packet buffer\n");
|
||||
}
|
||||
#endif
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static inline gnrc_pktsnip_t *_opt_l2a_build(const uint8_t *l2addr,
|
||||
uint8_t l2addr_len,
|
||||
gnrc_pktsnip_t *next,
|
||||
uint8_t type)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_ndp2_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_ndp2_opt_sl2a_build(const uint8_t *l2addr,
|
||||
uint8_t l2addr_len,
|
||||
gnrc_pktsnip_t *next)
|
||||
{
|
||||
assert((l2addr != NULL) && (l2addr_len != 0));
|
||||
DEBUG("ndp2: 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(l2addr, l2addr_len, next, NDP_OPT_SL2A);
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *gnrc_ndp2_opt_tl2a_build(const uint8_t *l2addr,
|
||||
uint8_t l2addr_len,
|
||||
gnrc_pktsnip_t *next)
|
||||
{
|
||||
assert((l2addr != NULL) && (l2addr_len != 0));
|
||||
DEBUG("ndp2: 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(l2addr, l2addr_len, next, NDP_OPT_TL2A);
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *gnrc_ndp2_opt_pi_build(const ipv6_addr_t *prefix,
|
||||
uint8_t prefix_len,
|
||||
uint32_t valid_ltime, uint32_t pref_ltime,
|
||||
uint8_t flags, gnrc_pktsnip_t *next)
|
||||
{
|
||||
assert(prefix != NULL);
|
||||
assert(!ipv6_addr_is_link_local(prefix) && !ipv6_addr_is_multicast(prefix));
|
||||
assert(prefix_len <= 128);
|
||||
gnrc_pktsnip_t *pkt = gnrc_ndp2_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_ndp2_opt_mtu_build(uint32_t mtu, gnrc_pktsnip_t *next)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_ndp2_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;
|
||||
}
|
||||
|
||||
static gnrc_pktsnip_t *_build_headers(gnrc_ipv6_netif_t *netif,
|
||||
const ipv6_addr_t *src,
|
||||
const ipv6_addr_t *dst,
|
||||
gnrc_pktsnip_t *payload);
|
||||
static size_t _get_l2src(gnrc_ipv6_netif_t *netif, uint8_t *l2src,
|
||||
size_t l2src_maxlen);
|
||||
|
||||
void gnrc_ndp2_nbr_sol_send(const ipv6_addr_t *tgt, gnrc_ipv6_netif_t *netif,
|
||||
const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
||||
gnrc_pktsnip_t *ext_opts)
|
||||
{
|
||||
assert((tgt != NULL) && !ipv6_addr_is_multicast(tgt));
|
||||
assert((netif != NULL) && (dst != NULL));
|
||||
gnrc_pktsnip_t *hdr, *pkt = ext_opts;
|
||||
/* cppcheck-suppress variableScope
|
||||
* (reason: also used in MODULE_GNRC_SIXLOWPAN_ND compile path) */
|
||||
uint8_t l2src[8];
|
||||
/* cppcheck-suppress variableScope
|
||||
* (reason: also used in MODULE_GNRC_SIXLOWPAN_ND compile path) */
|
||||
size_t l2src_len = 0;
|
||||
|
||||
DEBUG("ndp2: send neighbor solicitation (iface: %" PRIkernel_pid ", "
|
||||
"src: %s, ", netif->pid,
|
||||
ipv6_addr_to_str(addr_str, (src != NULL) ? 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(netif->pid, tgt, false);
|
||||
}
|
||||
|
||||
/* add SL2AO based on interface and source address */
|
||||
if ((src != NULL) && !ipv6_addr_is_unspecified(src)) {
|
||||
l2src_len = _get_l2src(netif, l2src, sizeof(l2src));
|
||||
|
||||
if (l2src_len > 0) {
|
||||
/* add source address link-layer address option */
|
||||
hdr = gnrc_ndp2_opt_sl2a_build(l2src, l2src_len, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error allocating SL2AO.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
pkt = hdr;
|
||||
}
|
||||
}
|
||||
/* add neighbor solicitation header */
|
||||
hdr = gnrc_ndp2_nbr_sol_build(tgt, pkt);
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error allocating neighbor solicitation.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
pkt = hdr;
|
||||
/* add remaining headers */
|
||||
hdr = _build_headers(netif, src, dst, pkt);
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error adding lower-layer headers.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
else if (gnrc_netapi_dispatch_send(GNRC_NETTYPE_NDP2,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL, hdr) == 0) {
|
||||
DEBUG("ndp2: unable to send neighbor solicitation\n");
|
||||
gnrc_pktbuf_release(hdr);
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_ndp2_nbr_adv_send(const ipv6_addr_t *tgt, gnrc_ipv6_netif_t *netif,
|
||||
const ipv6_addr_t *dst, bool supply_tl2a,
|
||||
gnrc_pktsnip_t *ext_opts)
|
||||
{
|
||||
ipv6_addr_t real_dst;
|
||||
gnrc_pktsnip_t *hdr, *pkt = ext_opts;
|
||||
uint8_t adv_flags = 0;
|
||||
|
||||
assert((tgt != NULL) && !ipv6_addr_is_multicast(tgt));
|
||||
assert((netif != NULL) && (dst != NULL));
|
||||
DEBUG("ndp2: send neighbor advertisement (iface: %" PRIkernel_pid
|
||||
", tgt: %s, ", netif->pid,
|
||||
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 ((netif->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) &&
|
||||
(netif->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) {
|
||||
adv_flags |= NDP_NBR_ADV_FLAGS_R;
|
||||
}
|
||||
if (ipv6_addr_is_unspecified(dst)) {
|
||||
memcpy(&real_dst, &ipv6_addr_all_nodes_link_local, sizeof(ipv6_addr_t));
|
||||
supply_tl2a = true;
|
||||
}
|
||||
else {
|
||||
memcpy(&real_dst, dst, sizeof(real_dst));
|
||||
adv_flags |= NDP_NBR_ADV_FLAGS_S;
|
||||
}
|
||||
/* add SL2AO based on target address */
|
||||
if (supply_tl2a) {
|
||||
uint8_t l2tgt[8];
|
||||
size_t l2tgt_len;
|
||||
/* we previously checked if we are the target, so we can take our L2tgt */
|
||||
l2tgt_len = _get_l2src(netif, l2tgt, sizeof(l2tgt));
|
||||
|
||||
if (l2tgt_len > 0) {
|
||||
/* add target address link-layer address option */
|
||||
hdr = gnrc_ndp2_opt_tl2a_build(l2tgt, l2tgt_len, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error allocating TL2AO.\n");
|
||||
gnrc_pktbuf_release(ext_opts);
|
||||
return;
|
||||
}
|
||||
pkt = hdr;
|
||||
}
|
||||
}
|
||||
/* TODO: also check if the node provides proxy services for tgt */
|
||||
if ((pkt != NULL) &&
|
||||
(!gnrc_ipv6_netif_addr_is_non_unicast(tgt) || supply_tl2a)) {
|
||||
/* TL2A is not supplied and tgt is not anycast */
|
||||
adv_flags |= NDP_NBR_ADV_FLAGS_O;
|
||||
}
|
||||
/* add neighbor advertisement header */
|
||||
hdr = gnrc_ndp2_nbr_adv_build(tgt, adv_flags, pkt);
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error allocating neighbor advertisement.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
pkt = hdr;
|
||||
/* add remaining headers */
|
||||
hdr = _build_headers(netif, NULL, &real_dst, pkt);
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error adding lower-layer headers.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
else if (gnrc_netapi_dispatch_send(GNRC_NETTYPE_NDP2,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL, hdr) == 0) {
|
||||
DEBUG("ndp2: unable to send neighbor advertisement\n");
|
||||
gnrc_pktbuf_release(hdr);
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_ndp2_rtr_sol_send(gnrc_ipv6_netif_t *netif, const ipv6_addr_t *dst)
|
||||
{
|
||||
gnrc_pktsnip_t *hdr, *pkt = NULL;
|
||||
ipv6_addr_t *src = NULL;
|
||||
|
||||
assert(netif != NULL);
|
||||
if (dst == NULL) {
|
||||
dst = &ipv6_addr_all_routers_link_local;
|
||||
}
|
||||
DEBUG("ndp2: send router solicitation (iface: %" PRIkernel_pid
|
||||
", dst: %s)\n", netif->pid,
|
||||
ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
|
||||
/* add SL2AO => check if there is a fitting source address to target */
|
||||
if ((src = gnrc_ipv6_netif_find_best_src_addr(netif->pid, dst,
|
||||
false)) != NULL) {
|
||||
uint8_t l2src[8];
|
||||
size_t l2src_len = _get_l2src(netif, l2src, sizeof(l2src));
|
||||
if (l2src_len > 0) {
|
||||
/* add source address link-layer address option */
|
||||
pkt = gnrc_ndp2_opt_sl2a_build(l2src, l2src_len, NULL);
|
||||
if (pkt == NULL) {
|
||||
DEBUG("ndp2: error allocating SL2AO.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* add router solicitation header */
|
||||
hdr = gnrc_ndp2_rtr_sol_build(pkt);
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error allocating router solicitation.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
pkt = hdr;
|
||||
/* add remaining headers */
|
||||
hdr = _build_headers(netif, src, dst, pkt);
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error adding lower-layer headers.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
else if (gnrc_netapi_dispatch_send(GNRC_NETTYPE_NDP2,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL, hdr) == 0) {
|
||||
DEBUG("ndp2: unable to send router advertisement\n");
|
||||
gnrc_pktbuf_release(hdr);
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_ndp2_rtr_adv_send(gnrc_ipv6_netif_t *netif, const ipv6_addr_t *src,
|
||||
const ipv6_addr_t *dst, bool fin,
|
||||
gnrc_pktsnip_t *ext_opts)
|
||||
{
|
||||
#if GNRC_IPV6_NIB_CONF_ROUTER
|
||||
gnrc_pktsnip_t *hdr = NULL, *pkt = ext_opts;
|
||||
uint32_t reach_time = 0, retrans_timer = 0;
|
||||
uint16_t adv_ltime = 0;
|
||||
uint8_t cur_hl = 0;
|
||||
|
||||
if (dst == NULL) {
|
||||
dst = &ipv6_addr_all_nodes_link_local;
|
||||
}
|
||||
DEBUG("ndp2: send router advertisement (iface: %" PRIkernel_pid ", dst: %s%s\n",
|
||||
netif->pid, ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)),
|
||||
fin ? ", final" : "");
|
||||
if (netif->flags & GNRC_IPV6_NETIF_FLAGS_ADV_MTU) {
|
||||
if ((hdr = gnrc_ndp2_opt_mtu_build(netif->mtu, pkt)) == NULL) {
|
||||
DEBUG("ndp rtr: no space left in packet buffer\n");
|
||||
return;
|
||||
}
|
||||
pkt = hdr;
|
||||
}
|
||||
if (src == NULL) {
|
||||
/* 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(netif->pid, dst, true);
|
||||
}
|
||||
/* 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(netif, l2src, sizeof(l2src));
|
||||
if (l2src_len > 0) {
|
||||
/* add source address link-layer address option */
|
||||
hdr = gnrc_ndp2_opt_sl2a_build(l2src, l2src_len, pkt);
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error allocating Source Link-layer address option.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
pkt = hdr;
|
||||
}
|
||||
}
|
||||
if (netif->flags & GNRC_IPV6_NETIF_FLAGS_ADV_CUR_HL) {
|
||||
cur_hl = netif->cur_hl;
|
||||
}
|
||||
if (netif->flags & GNRC_IPV6_NETIF_FLAGS_ADV_REACH_TIME) {
|
||||
|
||||
if (netif->reach_time > (3600 * US_PER_SEC)) { /* reach_time > 1 hour */
|
||||
reach_time = (3600 * MS_PER_SEC);
|
||||
}
|
||||
else {
|
||||
reach_time = netif->reach_time / US_PER_MS;
|
||||
}
|
||||
}
|
||||
if (netif->flags & GNRC_IPV6_NETIF_FLAGS_ADV_RETRANS_TIMER) {
|
||||
retrans_timer = netif->retrans_timer / US_PER_MS;
|
||||
}
|
||||
if (!fin) {
|
||||
/* TODO set netif dependent adv_ltime */
|
||||
adv_ltime = 1800U;
|
||||
}
|
||||
hdr = gnrc_ndp2_rtr_adv_build(cur_hl,
|
||||
(netif->flags & (GNRC_IPV6_NETIF_FLAGS_OTHER_CONF |
|
||||
GNRC_IPV6_NETIF_FLAGS_MANAGED)) >> 8,
|
||||
adv_ltime, reach_time, retrans_timer, pkt);
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error allocating router advertisement.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
pkt = hdr;
|
||||
hdr = _build_headers(netif, src, dst, pkt);
|
||||
if (hdr == NULL) {
|
||||
DEBUG("ndp2: error adding lower-layer headers.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
else if (gnrc_netapi_dispatch_send(GNRC_NETTYPE_NDP2,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL, hdr) == 0) {
|
||||
DEBUG("ndp2: unable to send router solicitation\n");
|
||||
gnrc_pktbuf_release(hdr);
|
||||
}
|
||||
#else
|
||||
(void)netif;
|
||||
(void)src;
|
||||
(void)dst;
|
||||
(void)fin;
|
||||
DEBUG("ndp2: not a router, dropping ext_opts\n");
|
||||
gnrc_pktbuf_release(ext_opts);
|
||||
#endif /* GNRC_IPV6_NIB_CONF_ROUTER */
|
||||
}
|
||||
|
||||
static gnrc_pktsnip_t *_build_headers(gnrc_ipv6_netif_t *netif,
|
||||
const ipv6_addr_t *src,
|
||||
const ipv6_addr_t *dst,
|
||||
gnrc_pktsnip_t *payload)
|
||||
{
|
||||
gnrc_pktsnip_t *l2hdr;
|
||||
gnrc_pktsnip_t *iphdr = gnrc_ipv6_hdr_build(payload, src, dst);
|
||||
|
||||
if (iphdr == NULL) {
|
||||
DEBUG("ndp2: 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("ndp2: error allocating netif header.\n");
|
||||
gnrc_pktbuf_remove_snip(iphdr, iphdr);
|
||||
return NULL;
|
||||
}
|
||||
((gnrc_netif_hdr_t *)l2hdr->data)->if_pid = netif->pid;
|
||||
LL_PREPEND(iphdr, l2hdr);
|
||||
return l2hdr;
|
||||
}
|
||||
|
||||
static size_t _get_l2src(gnrc_ipv6_netif_t *netif, 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(netif->pid, 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(netif->pid, NETOPT_ADDRESS_LONG, 0,
|
||||
l2src,
|
||||
l2src_maxlen)) > max_short_len)) {
|
||||
l2src_len = (uint16_t)res;
|
||||
}
|
||||
else if ((res = gnrc_netapi_get(netif->pid, NETOPT_ADDRESS, 0, l2src,
|
||||
l2src_maxlen)) >= 0) {
|
||||
l2src_len = (uint16_t)res;
|
||||
}
|
||||
else {
|
||||
DEBUG("ndp2: no link-layer address found.\n");
|
||||
l2src_len = 0;
|
||||
}
|
||||
|
||||
return l2src_len;
|
||||
}
|
||||
|
||||
/** @} */
|
19
tests/gnrc_ndp2/Makefile
Normal file
19
tests/gnrc_ndp2/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
# name of your application
|
||||
APPLICATION = gnrc_ndp2
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := nucleo32-f031 nucleo32-f042
|
||||
|
||||
USEMODULE += gnrc_ndp2
|
||||
USEMODULE += embunit
|
||||
|
||||
CFLAGS += -DGNRC_NETTYPE_NDP2=GNRC_NETTYPE_TEST
|
||||
CFLAGS += -DGNRC_PKTBUF_SIZE=512
|
||||
CFLAGS += -DTEST_SUITES
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
|
||||
test:
|
||||
# `testrunner` calls `make term` recursively, results in duplicated `TERMFLAGS`.
|
||||
# So clears `TERMFLAGS` before run.
|
||||
TERMFLAGS= tests/01-run.py
|
1022
tests/gnrc_ndp2/main.c
Normal file
1022
tests/gnrc_ndp2/main.c
Normal file
File diff suppressed because it is too large
Load Diff
21
tests/gnrc_ndp2/tests/01-run.py
Executable file
21
tests/gnrc_ndp2/tests/01-run.py
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
# Copyright (C) 2016 Takuo Yonezawa <Yonezawa-T2@mail.dnp.co.jp>
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
|
||||
import testrunner
|
||||
|
||||
def testfunc(child):
|
||||
# 1st 6LoWPAN fragment
|
||||
child.expect(r"OK \(\d+ tests\)")
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(testrunner.run(testfunc))
|
Loading…
Reference in New Issue
Block a user