From aff854d412a66cb1bc11861be4de3a9f5042adfc Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Thu, 11 May 2017 16:33:05 +0200 Subject: [PATCH 1/6] gnrc_ndp2: Provide GNRC abstraction layer for NIB for sending --- Makefile.dep | 4 + sys/include/net/gnrc/ndp2.h | 355 +++++++++++ sys/net/gnrc/Makefile | 3 + .../gnrc/network_layer/icmpv6/gnrc_icmpv6.c | 1 + sys/net/gnrc/network_layer/ndp2/Makefile | 3 + sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c | 566 ++++++++++++++++++ 6 files changed, 932 insertions(+) create mode 100644 sys/include/net/gnrc/ndp2.h create mode 100644 sys/net/gnrc/network_layer/ndp2/Makefile create mode 100644 sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c diff --git a/Makefile.dep b/Makefile.dep index 6654a948fbf42..20e265b6c367d 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -254,6 +254,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 diff --git a/sys/include/net/gnrc/ndp2.h b/sys/include/net/gnrc/ndp2.h new file mode 100644 index 0000000000000..e830a72356148 --- /dev/null +++ b/sys/include/net/gnrc/ndp2.h @@ -0,0 +1,355 @@ +/* + * 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 + */ +#ifndef GNRC_NDP2_H +#define GNRC_NDP2_H + +#include + +#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) +# else +# define GNRC_NETTYPE_NDP2 (GNRC_NETTYPE_UNDEF) +# 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 above. + * @ref NDP_RTR_ADV_FLAGS_M == 1 indicates, that the + * addresses are managed by DHCPv6, + * @ref NDP_RTR_ADV_FLAGS_O == 1 indicates that other + * configuration information is available via DHCPv6. + * @param[in] ltime Lifetime of the default router in seconds. + * @param[in] reach_time Time in milliseconds a node should assume a neighbor + * reachable. 0 means unspecified by the router. + * @param[in] retrans_timer Time in milliseconds between retransmitted + * neighbor solicitations. 0 means unspecified by + * the router. + * @param[in] options Options to append to the router advertisement. + * 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 above. + * @ref NDP_OPT_PI_FLAGS_L == 1 indicates, that + * @p prefix can be used for on-link determination, + * @ref NDP_OPT_PI_FLAGS_A == 1 indicates, that + * @p prefix can be used for stateless address + * configuration. + * @param[in] 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. + */ +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); + +/** + * @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 the unspecified address it will be replaced with ff02::1 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 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 ff02::1 when equal to :: + * (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 ::, the + * @ref NDP_NBR_ADV_FLAGS_S flag will be set. + * @param[in] supply_tl2a Add target link-layer address option to neighbor + * advertisement if link-layer has addresses. + * @param[in] ext_opts External options for the neighbor advertisement. + * Leave NULL for none. + * **Warning:** these are not tested if they are + * suitable for a neighbor advertisement so be sure to + * check that. + * **Will be released** in an error case. + */ +void gnrc_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 /* GNRC_NDP2_H */ +/** @} */ diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile index 601ada6ca0d19..a5af24a5525cb 100644 --- a/sys/net/gnrc/Makefile +++ b/sys/net/gnrc/Makefile @@ -52,6 +52,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 diff --git a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c index d76ad3aca0a71..539019b247928 100644 --- a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c +++ b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c @@ -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; } diff --git a/sys/net/gnrc/network_layer/ndp2/Makefile b/sys/net/gnrc/network_layer/ndp2/Makefile new file mode 100644 index 0000000000000..2961e140f5c0b --- /dev/null +++ b/sys/net/gnrc/network_layer/ndp2/Makefile @@ -0,0 +1,3 @@ +MODULE = gnrc_ndp2 + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c b/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c new file mode 100644 index 0000000000000..af74c95039dc3 --- /dev/null +++ b/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c @@ -0,0 +1,566 @@ +/* + * 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 + */ + +#include "net/gnrc/icmpv6.h" +#include "net/gnrc/ipv6.h" +#include "net/gnrc/netif.h" +#include "net/ndp.h" + +#include "net/gnrc/ndp2.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +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; + } + 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; + } + 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; + } + 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); + } + return pkt; +} + +static inline size_t _ceil8(uint8_t length) +{ + /* NDP options use units of 8 byte for there length field, so round up */ + return (length + 7U) & 0xf8U; +} + +gnrc_pktsnip_t *gnrc_ndp2_opt_build(uint8_t type, size_t size, + gnrc_pktsnip_t *next) +{ + ndp_opt_t *opt; + gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(next, NULL, _ceil8(size), + GNRC_NETTYPE_UNDEF); + + if (pkt == NULL) { + DEBUG("ndp2: no space left in packet buffer\n"); + return NULL; + } + opt = pkt->data; + opt->type = type; + opt->len = (uint8_t)(pkt->size / 8); + return pkt; +} + +static inline gnrc_pktsnip_t *_opt_l2a_build(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) +{ + assert((tgt != NULL) && !ipv6_addr_is_multicast(tgt)); + assert((netif != NULL) && (dst != NULL)); + gnrc_pktsnip_t *hdr, *pkt = NULL; + /* 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 */ + pkt = gnrc_ndp2_opt_sl2a_build(l2src, l2src_len, NULL); + + if (pkt == NULL) { + DEBUG("ndp2: error allocating SL2AO.\n"); + gnrc_pktbuf_release(pkt); + return; + } + } + } +#ifdef MODULE_GNRC_SIXLOWPAN_ND + /* add ARO based on interface */ + if (netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { + if (l2src_len != sizeof(eui64_t)) { + l2src_len = (uint16_t)gnrc_netapi_get(netif->pid, + NETOPT_ADDRESS_LONG, 0, + l2src, sizeof(l2src)); + if (l2src_len != sizeof(eui64_t)) { + DEBUG("ndp2: can't get EUI-64 of the interface\n"); + gnrc_pktbuf_release(pkt); + return; + } + } + hdr = gnrc_sixlowpan_nd_opt_ar_build(0, GNRC_SIXLOWPAN_ND_AR_LTIME, + (eui64_t *)l2src, pkt); + if (hdr == NULL) { + DEBUG("ndp2: error allocating ARO.\n"); + gnrc_pktbuf_release(pkt); + return; + } + pkt = hdr; + } +#endif /* MODULE_GNRC_SIXLOWPAN_ND */ + /* 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 servies for tgt */ + if ((pkt != NULL) && !gnrc_ipv6_netif_addr_is_non_unicast(tgt)) { + /* TL2A is not supplied and tgt is not anycast */ + adv_flags |= NDP_NBR_ADV_FLAGS_O; + } + /* 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 SLLAO => 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); + } +} + +/* interface supports multihop prefix and 6LoWPAN context distribution */ +static inline bool _multihop_6lp(gnrc_ipv6_netif_t *netif) +{ +#if defined(MODULE_GNRC_SIXLOWPAN_ND) && defined(MODULE_GNRC_IPV6_ROUTER) + return (netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && + (netif->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER); +#else + (void)netif; + return false; +#endif +} + +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) +{ + 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); + } +} + +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; +} + +/** @} */ From 563e99de6760758c992ea7bf3ae112031f3db603 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Fri, 12 May 2017 19:20:03 +0200 Subject: [PATCH 2/6] tests: provide tests for gnrc_ndp2 --- tests/gnrc_ndp2/Makefile | 19 + tests/gnrc_ndp2/main.c | 1039 +++++++++++++++++++++++++++++++ tests/gnrc_ndp2/tests/01-run.py | 21 + 3 files changed, 1079 insertions(+) create mode 100644 tests/gnrc_ndp2/Makefile create mode 100644 tests/gnrc_ndp2/main.c create mode 100755 tests/gnrc_ndp2/tests/01-run.py diff --git a/tests/gnrc_ndp2/Makefile b/tests/gnrc_ndp2/Makefile new file mode 100644 index 0000000000000..69d58c4924ef3 --- /dev/null +++ b/tests/gnrc_ndp2/Makefile @@ -0,0 +1,19 @@ +# name of your application +APPLICATION = gnrc_ndp2 +include ../Makefile.tests_common + +BOARD_INSUFFICIENT_MEMORY := + +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 diff --git a/tests/gnrc_ndp2/main.c b/tests/gnrc_ndp2/main.c new file mode 100644 index 0000000000000..dc8c66b31f90d --- /dev/null +++ b/tests/gnrc_ndp2/main.c @@ -0,0 +1,1039 @@ +/* + * Copyright (C) 2015 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. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Tests extension header handling of gnrc stack. + * + * @author Hauke Petersen + * @author Takuo Yonezawa + * + * @} + */ + +#include + +#include "byteorder.h" +#include "embUnit.h" +#include "embUnit/embUnit.h" +#include "msg.h" +#include "net/gnrc/netapi.h" +#include "net/gnrc/netdev.h" +#include "net/gnrc/netreg.h" +#include "net/gnrc/pktbuf.h" +#include "net/icmpv6.h" +#include "net/ndp.h" +#include "net/netopt.h" +#include "sched.h" + +#include "net/gnrc/ndp2.h" + +#define TEST_CUR_HL (194U) +#define TEST_LTIME (894U) +#define TEST_REACH_TIME (1597495062U) +#define TEST_RETRANS_TIMER (1819101160U) +#define TEST_PFX_LEN (42U) +#define TEST_VALID_LTIME (223526372U) +#define TEST_PREF_LTIME (2056660713U) +#define TEST_NDP_OPT_SIZE (14U) +#define TEST_NDP_OPT_TYPE (142U) +#define TEST_MTU (669256124U) + +static const ipv6_addr_t test_dst = { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x73, 0x25, 0x22, 0xc6, 0xdf, 0x05, 0xf2, 0x6b } }; +static const ipv6_addr_t test_src = { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe5, 0x43, 0xb7, 0x74, 0xd7, 0xa9, 0x30, 0x74 } }; +static const ipv6_addr_t test_tgt = { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x78, 0x95, 0x84, 0x71, 0x5f, 0x47, 0x53 } }; +static const ipv6_addr_t test_pfx = { { 0x47, 0x25, 0xd9, 0x3b, 0x7f, 0xcc, 0x15, 0x6c, + 0x64, 0x3e, 0x76, 0x0d, 0x30, 0x10, 0x0d, 0xc8 } }; +static const uint8_t test_src_l2[] = { 0xe7, 0x43, 0xb7, 0x74, 0xd7, 0xa9, 0x30, 0x74 }; + +static kernel_pid_t test_iface = KERNEL_PID_UNDEF; + +static void init_pkt_handler(void); +static inline size_t ceil8(size_t size); + +static void set_up(void) +{ + gnrc_pktbuf_init(); +} + +static void fill_pktbuf(void) +{ + gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, + GNRC_PKTBUF_SIZE - sizeof(gnrc_pktsnip_t), + GNRC_NETTYPE_UNDEF); + TEST_ASSERT_NOT_NULL(pkt); + TEST_ASSERT(gnrc_pktbuf_is_sane()); +} + +static void test_nbr_sol_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_nbr_sol_build(&test_tgt, NULL)); +} + +static void test_nbr_sol_build__success(void) +{ + gnrc_pktsnip_t *pkt; + ndp_nbr_sol_t *nbr_sol; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_nbr_sol_build(&test_tgt, NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_nbr_sol_t), pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_ICMPV6, pkt->type); + /* check packet content */ + nbr_sol = pkt->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_SOL, nbr_sol->type); + TEST_ASSERT_EQUAL_INT(0, nbr_sol->code); + TEST_ASSERT_EQUAL_INT(0, nbr_sol->resv.u32); + TEST_ASSERT_MESSAGE(ipv6_addr_equal(&test_tgt, &nbr_sol->tgt), + "nbr_sol->tgt != test_tgt"); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_nbr_adv_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_nbr_adv_build(&test_tgt, 0, NULL)); +} + +static void test_nbr_adv_build__success(uint8_t flags) +{ + gnrc_pktsnip_t *pkt; + ndp_nbr_adv_t *nbr_adv; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_nbr_adv_build(&test_tgt, flags, + NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_nbr_adv_t), pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_ICMPV6, pkt->type); + /* check packet content */ + nbr_adv = pkt->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_ADV, nbr_adv->type); + TEST_ASSERT_EQUAL_INT(0, nbr_adv->code); + TEST_ASSERT_EQUAL_INT(flags, nbr_adv->flags); + TEST_ASSERT_EQUAL_INT(0, nbr_adv->resv[0]); + TEST_ASSERT_EQUAL_INT(0, nbr_adv->resv[1]); + TEST_ASSERT_EQUAL_INT(0, nbr_adv->resv[2]); + TEST_ASSERT_MESSAGE(ipv6_addr_equal(&test_tgt, &nbr_adv->tgt), + "nbr_adv->tgt != test_tgt"); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_nbr_adv_build__success_without_flags(void) +{ + test_nbr_adv_build__success(0); +} + +static void test_nbr_adv_build__success_with_flags(void) +{ + test_nbr_adv_build__success(NDP_NBR_ADV_FLAGS_S); +} + +static void test_rtr_sol_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_rtr_sol_build(NULL)); +} + +static void test_rtr_sol_build__success(void) +{ + gnrc_pktsnip_t *pkt; + ndp_rtr_sol_t *rtr_sol; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_rtr_sol_build(NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_rtr_sol_t), pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_ICMPV6, pkt->type); + /* check packet content */ + rtr_sol = pkt->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_RTR_SOL, rtr_sol->type); + TEST_ASSERT_EQUAL_INT(0, rtr_sol->code); + TEST_ASSERT_EQUAL_INT(0, rtr_sol->resv.u32); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_rtr_adv_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_rtr_adv_build(TEST_CUR_HL, 0, TEST_LTIME, + TEST_REACH_TIME, + TEST_RETRANS_TIMER, NULL)); +} + +static void test_rtr_adv_build__success(uint8_t flags) +{ + gnrc_pktsnip_t *pkt; + ndp_rtr_adv_t *rtr_adv; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_rtr_adv_build(TEST_CUR_HL, flags, + TEST_LTIME, + TEST_REACH_TIME, + TEST_RETRANS_TIMER, + NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_rtr_adv_t), pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_ICMPV6, pkt->type); + /* check packet content */ + rtr_adv = pkt->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_RTR_ADV, rtr_adv->type); + TEST_ASSERT_EQUAL_INT(0, rtr_adv->code); + TEST_ASSERT_EQUAL_INT(TEST_CUR_HL, rtr_adv->cur_hl); + TEST_ASSERT_EQUAL_INT(flags, rtr_adv->flags); + TEST_ASSERT_EQUAL_INT(TEST_LTIME, byteorder_ntohs(rtr_adv->ltime)); + TEST_ASSERT_EQUAL_INT(TEST_REACH_TIME, + byteorder_ntohl(rtr_adv->reach_time)); + TEST_ASSERT_EQUAL_INT(TEST_RETRANS_TIMER, + byteorder_ntohl(rtr_adv->retrans_timer)); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_rtr_adv_build__success_without_flags(void) +{ + test_rtr_adv_build__success(0); +} + +static void test_rtr_adv_build__success_with_flags(void) +{ + test_rtr_adv_build__success(NDP_RTR_ADV_FLAGS_M); +} + +static void test_opt_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_opt_build(TEST_NDP_OPT_TYPE, TEST_NDP_OPT_SIZE, + NULL)); +} + +static void test_opt_build__success(void) +{ + gnrc_pktsnip_t *pkt; + ndp_opt_t *opt; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_build(TEST_NDP_OPT_TYPE, + TEST_NDP_OPT_SIZE, + NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(ceil8(TEST_NDP_OPT_SIZE), pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->type); + /* check packet content */ + opt = pkt->data; + TEST_ASSERT_EQUAL_INT(TEST_NDP_OPT_TYPE, opt->type); + TEST_ASSERT_EQUAL_INT(ceil8(TEST_NDP_OPT_SIZE) / 8, opt->len); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_opt_sl2a_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_opt_sl2a_build(test_src_l2, sizeof(test_src_l2), + NULL)); +} + +static void test_opt_sl2a_build__success(void) +{ + gnrc_pktsnip_t *pkt; + ndp_opt_t *opt; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_sl2a_build(test_src_l2, + sizeof(test_src_l2), + NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_t) + sizeof(test_src_l2)), + pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->type); + /* check packet content */ + opt = pkt->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_SL2A, opt->type); + TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_t) + sizeof(test_src_l2)) / 8, + opt->len); + TEST_ASSERT_MESSAGE(memcmp(test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, + "opt->l2addr != test_src_l2"); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_opt_tl2a_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_opt_tl2a_build(test_src_l2, sizeof(test_src_l2), + NULL)); +} + +static void test_opt_tl2a_build__success(void) +{ + gnrc_pktsnip_t *pkt; + ndp_opt_t *opt; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_tl2a_build(test_src_l2, + sizeof(test_src_l2), + NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_t) + sizeof(test_src_l2)), + pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->type); + /* check packet content */ + opt = pkt->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_TL2A, opt->type); + TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_t) + sizeof(test_src_l2)) / 8, + opt->len); + TEST_ASSERT_MESSAGE(memcmp(test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, + "opt->l2addr != test_src_l2"); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_opt_pi_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_opt_pi_build(&test_pfx, TEST_PFX_LEN, + TEST_VALID_LTIME, TEST_PREF_LTIME, + 0, NULL)); +} + +static void test_opt_pi_build__success(uint8_t flags) +{ + gnrc_pktsnip_t *pkt; + ndp_opt_pi_t *opt; + ipv6_addr_t exp_pfx = IPV6_ADDR_UNSPECIFIED; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_pi_build(&test_pfx, TEST_PFX_LEN, + TEST_VALID_LTIME, + TEST_PREF_LTIME, flags, + NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_pi_t)), + pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->type); + /* check packet content */ + /* prepare expected prefix (the function MUST remove all the garbage after + * the prefix) */ + ipv6_addr_init_prefix(&exp_pfx, &test_pfx, TEST_PFX_LEN); + opt = pkt->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_PI, opt->type); + TEST_ASSERT_EQUAL_INT(NDP_OPT_PI_LEN, opt->len); + TEST_ASSERT_EQUAL_INT(TEST_PFX_LEN, opt->prefix_len); + TEST_ASSERT_EQUAL_INT(flags, opt->flags); + TEST_ASSERT_EQUAL_INT(TEST_VALID_LTIME, + byteorder_ntohl(opt->valid_ltime)); + TEST_ASSERT_EQUAL_INT(TEST_PREF_LTIME, + byteorder_ntohl(opt->pref_ltime)); + TEST_ASSERT_EQUAL_INT(0, opt->resv.u32); + TEST_ASSERT_MESSAGE(ipv6_addr_equal(&exp_pfx, &opt->prefix), + "opt->prefix != exp_pfx"); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_opt_pi_build__success_without_flags(void) +{ + test_opt_pi_build__success(0); +} + +static void test_opt_pi_build__success_with_flags(void) +{ + test_opt_pi_build__success(NDP_OPT_PI_FLAGS_L); +} + +static void test_opt_mtu_build__pktbuf_full(void) +{ + fill_pktbuf(); + TEST_ASSERT_NULL(gnrc_ndp2_opt_mtu_build(TEST_MTU, NULL)); +} + +static void test_opt_mtu_build__success(void) +{ + gnrc_pktsnip_t *pkt; + ndp_opt_mtu_t *opt; + + TEST_ASSERT(gnrc_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_mtu_build(TEST_MTU, NULL))); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + /* check packet meta-data */ + TEST_ASSERT_NULL(pkt->next); + TEST_ASSERT_NOT_NULL(pkt->data); + TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_mtu_t)), pkt->size); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->type); + /* check packet content */ + opt = pkt->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_MTU, opt->type); + TEST_ASSERT_EQUAL_INT(NDP_OPT_MTU_LEN, opt->len); + TEST_ASSERT_EQUAL_INT(0, opt->resv.u16); + TEST_ASSERT_EQUAL_INT(TEST_MTU, byteorder_ntohl(opt->mtu)); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static inline kernel_pid_t _get_iface(gnrc_netif_hdr_t *hdr) +{ + return hdr->if_pid; +} + +static inline ipv6_addr_t *_get_ipv6_src(ipv6_hdr_t *hdr) +{ + return &hdr->src; +} + +static inline ipv6_addr_t *_get_ipv6_dst(ipv6_hdr_t *hdr) +{ + return &hdr->dst; +} + +#define ASSERT_NETIF_HDR(iface, pkt) \ + TEST_ASSERT_NOT_NULL(pkt); \ + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_NETIF, pkt->type); \ + TEST_ASSERT_NOT_NULL(pkt->data); \ + TEST_ASSERT_EQUAL_INT(iface, _get_iface(pkt->data)) + +#define ASSERT_IPV6_HDR(src, dst, pkt) \ + TEST_ASSERT_NOT_NULL(pkt); \ + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_IPV6, pkt->type); \ + TEST_ASSERT_NOT_NULL(pkt->data); \ + TEST_ASSERT_MESSAGE(memcmp(src, _get_ipv6_src(pkt->data), \ + sizeof(ipv6_addr_t)) == 0, "src != pkt->src"); \ + TEST_ASSERT_MESSAGE(memcmp(dst, _get_ipv6_dst(pkt->data), \ + sizeof(ipv6_addr_t)) == 0, "dst != pkt->dst") + +#define ASSERT_ICMPV6_HDR(pkt) \ + TEST_ASSERT_NOT_NULL(pkt); \ + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_ICMPV6, pkt->type); \ + TEST_ASSERT_NOT_NULL(pkt->data) + +static void test_nbr_sol_send(const ipv6_addr_t *src) +{ + msg_t msg; + gnrc_ipv6_netif_t *test_netif = gnrc_ipv6_netif_get(test_iface); + gnrc_pktsnip_t *pkt; + ndp_nbr_sol_t *nbr_sol; + + TEST_ASSERT_NOT_NULL(test_netif); + gnrc_ndp2_nbr_sol_send(&test_tgt, test_netif, src, &test_dst); + msg_receive(&msg); + TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); + pkt = msg.content.ptr; + /* check packet */ + ASSERT_NETIF_HDR(test_iface, pkt); + if ((src != NULL) && ipv6_addr_is_unspecified(src)) { + ASSERT_IPV6_HDR(&ipv6_addr_unspecified, &test_dst, pkt->next); + } + else { + ASSERT_IPV6_HDR(&test_src, &test_dst, pkt->next); + } + ASSERT_ICMPV6_HDR(pkt->next->next); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_nbr_sol_t), pkt->next->next->size); + nbr_sol = pkt->next->next->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_SOL, nbr_sol->type); + TEST_ASSERT_MESSAGE(memcmp(&test_tgt, &nbr_sol->tgt, sizeof(ipv6_addr_t)) == 0, + "tgt != nbr_sol->tgt"); + if ((src != NULL) && ipv6_addr_is_unspecified(src)) { + TEST_ASSERT_NULL(pkt->next->next->next); + } + else { + TEST_ASSERT_NOT_NULL(pkt->next->next->next); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); + TEST_ASSERT_NOT_NULL(pkt->next->next->next->data); + ndp_opt_t *opt = pkt->next->next->next->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_SL2A, opt->type); + TEST_ASSERT_MESSAGE(memcmp(&test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, + "src_l2 != pkt->l2"); + TEST_ASSERT_NULL(pkt->next->next->next->next); + } + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_nbr_sol_send__src_NULL(void) +{ + test_nbr_sol_send(NULL); +} + +static void test_nbr_sol_send__src_unspecified(void) +{ + test_nbr_sol_send(&ipv6_addr_unspecified); +} + +static void test_nbr_sol_send__src_NOT_NULL(void) +{ + test_nbr_sol_send(&test_src); +} + +static void test_nbr_adv_send(const ipv6_addr_t *tgt, const ipv6_addr_t *dst, + bool supply_tl2a, gnrc_pktsnip_t *exp_ext_opts) +{ + msg_t msg; + gnrc_ipv6_netif_t *test_netif = gnrc_ipv6_netif_get(test_iface); + gnrc_pktsnip_t *pkt; + ndp_nbr_adv_t *nbr_adv; + + TEST_ASSERT_NOT_NULL(test_netif); + gnrc_ndp2_nbr_adv_send(tgt, test_netif, dst, supply_tl2a, exp_ext_opts); + msg_receive(&msg); + TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); + pkt = msg.content.ptr; + /* check packet */ + ASSERT_NETIF_HDR(test_iface, pkt); + if (ipv6_addr_is_unspecified(dst)) { + ASSERT_IPV6_HDR(&ipv6_addr_unspecified, &ipv6_addr_all_nodes_link_local, + pkt->next); + } + else { + ASSERT_IPV6_HDR(&ipv6_addr_unspecified, &test_dst, pkt->next); + } + ASSERT_ICMPV6_HDR(pkt->next->next); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_nbr_adv_t), pkt->next->next->size); + nbr_adv = pkt->next->next->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_ADV, nbr_adv->type); + TEST_ASSERT_MESSAGE(memcmp(tgt, &nbr_adv->tgt, sizeof(ipv6_addr_t)) == 0, + "tgt != nbr_adv->tgt"); + if (supply_tl2a || ipv6_addr_is_unspecified(dst) || (exp_ext_opts != NULL)) { + gnrc_pktsnip_t *ext_opts = NULL; + + TEST_ASSERT_NOT_NULL(pkt->next->next->next); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); + TEST_ASSERT_NOT_NULL(pkt->next->next->next->data); + /* implicitly this is the same */ + if (supply_tl2a || ipv6_addr_is_unspecified(dst)) { + ndp_opt_t *opt = pkt->next->next->next->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_TL2A, opt->type); + TEST_ASSERT_MESSAGE(memcmp(&test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, + "src_l2 != pkt->l2"); + if (exp_ext_opts == NULL) { + TEST_ASSERT_NULL(pkt->next->next->next->next); + } + else { + /* extra option comes after TL2AO */ + ext_opts = pkt->next->next->next->next; + } + } + else { + /* extra option comes directly after neighbor advertisement */ + ext_opts = pkt->next->next->next; + } + TEST_ASSERT(exp_ext_opts == ext_opts); + } + else { + TEST_ASSERT_NULL(pkt->next->next->next); + } + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_nbr_adv_send__foreign_tgt_unspecified_dst_no_supply_tl2a_no_ext_opts(void) +{ + test_nbr_adv_send(&test_tgt, &ipv6_addr_unspecified, false, NULL); +} + +static void test_nbr_adv_send__foreign_tgt_unspecified_dst_no_supply_tl2a_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_nbr_adv_send(&test_tgt, &ipv6_addr_unspecified, false, ext_opts); +} + +static void test_nbr_adv_send__foreign_tgt_unspecified_dst_supply_tl2a_no_ext_opts(void) +{ + test_nbr_adv_send(&test_tgt, &ipv6_addr_unspecified, true, NULL); +} + +static void test_nbr_adv_send__foreign_tgt_unspecified_dst_supply_tl2a_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_nbr_adv_send(&test_tgt, &ipv6_addr_unspecified, true, ext_opts); +} + +static void test_nbr_adv_send__foreign_tgt_specified_dst_no_supply_tl2a_no_ext_opts(void) +{ + test_nbr_adv_send(&test_tgt, &test_dst, false, NULL); +} + +static void test_nbr_adv_send__foreign_tgt_specified_dst_no_supply_tl2a_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_nbr_adv_send(&test_tgt, &test_dst, false, ext_opts); +} + +static void test_nbr_adv_send__foreign_tgt_specified_dst_supply_tl2a_no_ext_opts(void) +{ + test_nbr_adv_send(&test_tgt, &test_dst, true, NULL); +} + +static void test_nbr_adv_send__foreign_tgt_specified_dst_supply_tl2a_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_nbr_adv_send(&test_tgt, &test_dst, true, ext_opts); +} + +static void test_nbr_adv_send__src_tgt_unspecified_dst_no_supply_tl2a_no_ext_opts(void) +{ + test_nbr_adv_send(&test_src, &ipv6_addr_unspecified, false, NULL); +} + +static void test_nbr_adv_send__src_tgt_unspecified_dst_no_supply_tl2a_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_nbr_adv_send(&test_src, &ipv6_addr_unspecified, false, ext_opts); +} + +static void test_nbr_adv_send__src_tgt_unspecified_dst_supply_tl2a_no_ext_opts(void) +{ + test_nbr_adv_send(&test_src, &ipv6_addr_unspecified, true, NULL); +} + +static void test_nbr_adv_send__src_tgt_unspecified_dst_supply_tl2a_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_nbr_adv_send(&test_src, &ipv6_addr_unspecified, true, ext_opts); +} + +static void test_nbr_adv_send__src_tgt_specified_dst_no_supply_tl2a_no_ext_opts(void) +{ + test_nbr_adv_send(&test_src, &test_dst, false, NULL); +} + +static void test_nbr_adv_send__src_tgt_specified_dst_no_supply_tl2a_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_nbr_adv_send(&test_src, &test_dst, false, ext_opts); +} + +static void test_nbr_adv_send__src_tgt_specified_dst_supply_tl2a_no_ext_opts(void) +{ + test_nbr_adv_send(&test_src, &test_dst, true, NULL); +} + +static void test_nbr_adv_send__src_tgt_specified_dst_supply_tl2a_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_nbr_adv_send(&test_src, &test_dst, true, ext_opts); +} + +static void test_rtr_sol_send(const ipv6_addr_t *dst) +{ + msg_t msg; + gnrc_ipv6_netif_t *test_netif = gnrc_ipv6_netif_get(test_iface); + gnrc_pktsnip_t *pkt; + ndp_rtr_sol_t *rtr_sol; + + TEST_ASSERT_NOT_NULL(test_netif); + gnrc_ndp2_rtr_sol_send(test_netif, dst); + msg_receive(&msg); + TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); + pkt = msg.content.ptr; + /* check packet */ + ASSERT_NETIF_HDR(test_iface, pkt); + if (dst != NULL) { + ASSERT_IPV6_HDR(&test_src, dst, pkt->next); + } + else { + ASSERT_IPV6_HDR(&test_src, &ipv6_addr_all_routers_link_local, + pkt->next); + } + ASSERT_ICMPV6_HDR(pkt->next->next); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_rtr_sol_t), pkt->next->next->size); + rtr_sol = pkt->next->next->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_RTR_SOL, rtr_sol->type); + if ((dst == NULL) || ipv6_addr_is_link_local(dst)) { + TEST_ASSERT_NOT_NULL(pkt->next->next->next); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); + TEST_ASSERT_NOT_NULL(pkt->next->next->next->data); + ndp_opt_t *opt = pkt->next->next->next->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_SL2A, opt->type); + TEST_ASSERT_MESSAGE(memcmp(&test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, + "src_l2 != pkt->l2"); + TEST_ASSERT_NULL(pkt->next->next->next->next); + } + else { + TEST_ASSERT_NULL(pkt->next->next->next); + } + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_rtr_sol_send__dst_NULL(void) +{ + test_rtr_sol_send(NULL); +} + +static void test_rtr_sol_send__dst_local(void) +{ + test_rtr_sol_send(&test_dst); +} + +static void test_rtr_sol_send__dst_global(void) +{ + ipv6_addr_t dst; + + memcpy(&dst, &test_dst, sizeof(dst)); + ipv6_addr_init_prefix(&dst, &test_pfx, 64); + test_rtr_sol_send(&test_dst); +} + +static void test_rtr_adv_send(const ipv6_addr_t *src, const ipv6_addr_t *dst, + bool fin, gnrc_pktsnip_t *exp_ext_opts) +{ + msg_t msg; + gnrc_ipv6_netif_t *test_netif = gnrc_ipv6_netif_get(test_iface); + gnrc_pktsnip_t *pkt; + ndp_rtr_adv_t *rtr_adv; + + TEST_ASSERT_NOT_NULL(test_netif); + gnrc_ndp2_rtr_adv_send(test_netif, src, dst, fin, exp_ext_opts); + msg_receive(&msg); + TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); + pkt = msg.content.ptr; + /* check packet */ + ASSERT_NETIF_HDR(test_iface, pkt); + /* testing for unspecified source is complicated so we skip it here and + * do it in later integration tests */ + if (dst != NULL) { + ASSERT_IPV6_HDR(&test_src, dst, pkt->next); + } + else { + ASSERT_IPV6_HDR(&test_src, &ipv6_addr_all_nodes_link_local, + pkt->next); + } + ASSERT_ICMPV6_HDR(pkt->next->next); + TEST_ASSERT_EQUAL_INT(sizeof(ndp_rtr_adv_t), pkt->next->next->size); + rtr_adv = pkt->next->next->data; + TEST_ASSERT_EQUAL_INT(ICMPV6_RTR_ADV, rtr_adv->type); + if (fin) { + TEST_ASSERT_EQUAL_INT(0, rtr_adv->ltime.u16); + } + else { + TEST_ASSERT_MESSAGE(rtr_adv->ltime.u16 != 0, "rtr_adv->ltime == 0"); + } + /* check for SLLAO */ + TEST_ASSERT_NOT_NULL(pkt->next->next->next); + TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); + TEST_ASSERT_NOT_NULL(pkt->next->next->next->data); + ndp_opt_t *opt = pkt->next->next->next->data; + TEST_ASSERT_EQUAL_INT(NDP_OPT_SL2A, opt->type); + TEST_ASSERT_MESSAGE(memcmp(&test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, + "src_l2 != pkt->l2"); + TEST_ASSERT_MESSAGE(pkt->next->next->next->next == exp_ext_opts, + "ext_opts set wrong"); + gnrc_pktbuf_release(pkt); + TEST_ASSERT(gnrc_pktbuf_is_sane()); + TEST_ASSERT(gnrc_pktbuf_is_empty()); +} + +static void test_rtr_adv_send__src_NULL_dst_NULL_no_fin_no_ext_opts(void) +{ + test_rtr_adv_send(NULL, NULL, false, NULL); +} + +static void test_rtr_adv_send__src_NULL_dst_NULL_no_fin_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_rtr_adv_send(NULL, NULL, false, ext_opts); +} + +static void test_rtr_adv_send__src_NULL_dst_NULL_fin_no_ext_opts(void) +{ + test_rtr_adv_send(NULL, NULL, true, NULL); +} + +static void test_rtr_adv_send__src_NULL_dst_NULL_fin_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_rtr_adv_send(NULL, NULL, true, ext_opts); +} + +static void test_rtr_adv_send__src_NULL_dst_no_fin_no_ext_opts(void) +{ + test_rtr_adv_send(NULL, &test_dst, false, NULL); +} + +static void test_rtr_adv_send__src_NULL_dst_no_fin_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_rtr_adv_send(NULL, &test_dst, false, ext_opts); +} + +static void test_rtr_adv_send__src_NULL_dst_fin_no_ext_opts(void) +{ + test_rtr_adv_send(NULL, &test_dst, true, NULL); +} + +static void test_rtr_adv_send__src_NULL_dst_fin_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_rtr_adv_send(NULL, &test_dst, true, ext_opts); +} + +static void test_rtr_adv_send__src_dst_NULL_no_fin_no_ext_opts(void) +{ + test_rtr_adv_send(&test_src, NULL, false, NULL); +} + +static void test_rtr_adv_send__src_dst_NULL_no_fin_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_rtr_adv_send(&test_src, NULL, false, ext_opts); +} + +static void test_rtr_adv_send__src_dst_NULL_fin_no_ext_opts(void) +{ + test_rtr_adv_send(&test_src, NULL, true, NULL); +} + +static void test_rtr_adv_send__src_dst_NULL_fin_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_rtr_adv_send(&test_src, NULL, true, ext_opts); +} + +static void test_rtr_adv_send__src_dst_no_fin_no_ext_opts(void) +{ + test_rtr_adv_send(&test_src, &test_dst, false, NULL); +} + +static void test_rtr_adv_send__src_dst_no_fin_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_rtr_adv_send(&test_src, &test_dst, false, ext_opts); +} + +static void test_rtr_adv_send__src_dst_fin_no_ext_opts(void) +{ + test_rtr_adv_send(&test_src, &test_dst, true, NULL); +} + +static void test_rtr_adv_send__src_dst_fin_ext_opts(void) +{ + gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); + test_rtr_adv_send(&test_src, &test_dst, true, ext_opts); +} + +static Test *tests_gnrc_ndp2_build(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_nbr_sol_build__pktbuf_full), + new_TestFixture(test_nbr_sol_build__success), + new_TestFixture(test_nbr_adv_build__pktbuf_full), + new_TestFixture(test_nbr_adv_build__success_without_flags), + new_TestFixture(test_nbr_adv_build__success_with_flags), + new_TestFixture(test_rtr_sol_build__pktbuf_full), + new_TestFixture(test_rtr_sol_build__success), + new_TestFixture(test_rtr_adv_build__pktbuf_full), + new_TestFixture(test_rtr_adv_build__success_without_flags), + new_TestFixture(test_rtr_adv_build__success_with_flags), + new_TestFixture(test_opt_build__pktbuf_full), + new_TestFixture(test_opt_build__success), + new_TestFixture(test_opt_sl2a_build__pktbuf_full), + new_TestFixture(test_opt_sl2a_build__success), + new_TestFixture(test_opt_tl2a_build__pktbuf_full), + new_TestFixture(test_opt_tl2a_build__success), + new_TestFixture(test_opt_pi_build__pktbuf_full), + new_TestFixture(test_opt_pi_build__success_without_flags), + new_TestFixture(test_opt_pi_build__success_with_flags), + new_TestFixture(test_opt_mtu_build__pktbuf_full), + new_TestFixture(test_opt_mtu_build__success), + }; + + EMB_UNIT_TESTCALLER(tests, set_up, NULL, fixtures); + + return (Test *)&tests; +} + +static Test *tests_gnrc_ndp2_send(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_nbr_sol_send__src_NULL), + new_TestFixture(test_nbr_sol_send__src_unspecified), + new_TestFixture(test_nbr_sol_send__src_NOT_NULL), + new_TestFixture(test_nbr_adv_send__foreign_tgt_unspecified_dst_no_supply_tl2a_no_ext_opts), + new_TestFixture(test_nbr_adv_send__foreign_tgt_unspecified_dst_no_supply_tl2a_ext_opts), + new_TestFixture(test_nbr_adv_send__foreign_tgt_unspecified_dst_supply_tl2a_no_ext_opts), + new_TestFixture(test_nbr_adv_send__foreign_tgt_unspecified_dst_supply_tl2a_ext_opts), + new_TestFixture(test_nbr_adv_send__foreign_tgt_specified_dst_no_supply_tl2a_no_ext_opts), + new_TestFixture(test_nbr_adv_send__foreign_tgt_specified_dst_no_supply_tl2a_ext_opts), + new_TestFixture(test_nbr_adv_send__foreign_tgt_specified_dst_supply_tl2a_no_ext_opts), + new_TestFixture(test_nbr_adv_send__foreign_tgt_specified_dst_supply_tl2a_ext_opts), + new_TestFixture(test_nbr_adv_send__src_tgt_unspecified_dst_no_supply_tl2a_no_ext_opts), + new_TestFixture(test_nbr_adv_send__src_tgt_unspecified_dst_no_supply_tl2a_ext_opts), + new_TestFixture(test_nbr_adv_send__src_tgt_unspecified_dst_supply_tl2a_no_ext_opts), + new_TestFixture(test_nbr_adv_send__src_tgt_unspecified_dst_supply_tl2a_ext_opts), + new_TestFixture(test_nbr_adv_send__src_tgt_specified_dst_no_supply_tl2a_no_ext_opts), + new_TestFixture(test_nbr_adv_send__src_tgt_specified_dst_no_supply_tl2a_ext_opts), + new_TestFixture(test_nbr_adv_send__src_tgt_specified_dst_supply_tl2a_no_ext_opts), + new_TestFixture(test_nbr_adv_send__src_tgt_specified_dst_supply_tl2a_ext_opts), + new_TestFixture(test_rtr_sol_send__dst_NULL), + new_TestFixture(test_rtr_sol_send__dst_local), + new_TestFixture(test_rtr_sol_send__dst_global), + new_TestFixture(test_rtr_adv_send__src_NULL_dst_NULL_no_fin_no_ext_opts), + new_TestFixture(test_rtr_adv_send__src_NULL_dst_NULL_no_fin_ext_opts), + new_TestFixture(test_rtr_adv_send__src_NULL_dst_NULL_fin_no_ext_opts), + new_TestFixture(test_rtr_adv_send__src_NULL_dst_NULL_fin_ext_opts), + new_TestFixture(test_rtr_adv_send__src_NULL_dst_no_fin_no_ext_opts), + new_TestFixture(test_rtr_adv_send__src_NULL_dst_no_fin_ext_opts), + new_TestFixture(test_rtr_adv_send__src_NULL_dst_fin_no_ext_opts), + new_TestFixture(test_rtr_adv_send__src_NULL_dst_fin_ext_opts), + new_TestFixture(test_rtr_adv_send__src_dst_NULL_no_fin_no_ext_opts), + new_TestFixture(test_rtr_adv_send__src_dst_NULL_no_fin_ext_opts), + new_TestFixture(test_rtr_adv_send__src_dst_NULL_fin_no_ext_opts), + new_TestFixture(test_rtr_adv_send__src_dst_NULL_fin_ext_opts), + new_TestFixture(test_rtr_adv_send__src_dst_no_fin_no_ext_opts), + new_TestFixture(test_rtr_adv_send__src_dst_no_fin_ext_opts), + new_TestFixture(test_rtr_adv_send__src_dst_fin_no_ext_opts), + new_TestFixture(test_rtr_adv_send__src_dst_fin_ext_opts), + }; + + EMB_UNIT_TESTCALLER(tests, set_up, NULL, fixtures); + return (Test *)&tests; +} + +int main(void) +{ + TESTS_START(); + TESTS_RUN(tests_gnrc_ndp2_build()); + init_pkt_handler(); + TESTS_RUN(tests_gnrc_ndp2_send()); + TESTS_END(); + + return 0; +} + +#define MSG_QUEUE_SIZE (2) + +static char test_netif_stack[THREAD_STACKSIZE_DEFAULT]; +static msg_t msg_queue_main[MSG_QUEUE_SIZE]; +static msg_t msg_queue_netif[MSG_QUEUE_SIZE]; +static gnrc_netreg_entry_t netreg_entry; + +int test_iface_get(gnrc_netapi_opt_t *opt) +{ + switch (opt->opt) { + case NETOPT_ADDRESS_LONG: + if (opt->data_len < sizeof(test_src_l2)) { + return -EOVERFLOW; + } + memcpy(opt->data, test_src_l2, sizeof(test_src_l2)); + return sizeof(test_src_l2); + case NETOPT_SRC_LEN: { + uint16_t *val = opt->data; + if (opt->data_len != sizeof(uint16_t)) { + return -EOVERFLOW; + } + *val = sizeof(test_src_l2); + return sizeof(uint16_t); + } + case NETOPT_IPV6_IID: + if (opt->data_len < sizeof(uint64_t)) { + return -EOVERFLOW; + } + memcpy(opt->data, &test_src.u64[1], sizeof(uint64_t)); + return sizeof(uint64_t); + case NETOPT_IS_WIRED: + return 1; + case NETOPT_MAX_PACKET_SIZE: { + uint16_t *val = opt->data; + if (opt->data_len != sizeof(uint16_t)) { + return -EOVERFLOW; + } + *val = 100U; + return sizeof(uint16_t); + } + default: + return -ENOTSUP; + } +} + +static void *test_iface_thread(void *args) +{ + msg_t msg, reply = { .type = GNRC_NETAPI_MSG_TYPE_ACK }; + + (void)args; + msg_init_queue(msg_queue_netif, MSG_QUEUE_SIZE); + while (1) { + msg_receive(&msg); + switch (msg.type) { + case GNRC_NETAPI_MSG_TYPE_SND: + case GNRC_NETAPI_MSG_TYPE_RCV: + gnrc_pktbuf_release(msg.content.ptr); + continue; + case GNRC_NETAPI_MSG_TYPE_GET: + reply.content.value = (uint32_t)test_iface_get(msg.content.ptr); + break; + case GNRC_NETAPI_MSG_TYPE_SET: + reply.content.value = (uint32_t)(-ENOTSUP); + break; + } + msg_reply(&msg, &reply); + } + return NULL; +} + +static void init_pkt_handler(void) +{ + msg_init_queue(msg_queue_main, MSG_QUEUE_SIZE); + gnrc_netreg_entry_init_pid(&netreg_entry, GNRC_NETREG_DEMUX_CTX_ALL, + sched_active_pid); + gnrc_netreg_register(GNRC_NETTYPE_NDP2, &netreg_entry); + test_iface = thread_create(test_netif_stack, sizeof(test_netif_stack), + GNRC_NETDEV_MAC_PRIO, THREAD_CREATE_STACKTEST, + test_iface_thread, NULL, "test-iface"); + TEST_ASSERT_MESSAGE(test_iface > KERNEL_PID_UNDEF, + "Unable to start test interface"); + gnrc_netif_add(test_iface); + gnrc_ipv6_netif_init_by_dev(); +} + +static inline size_t ceil8(size_t size) +{ + if (size % 8) { + return ((size / 8) + 1) * 8; + } + else { + return size; + } +} diff --git a/tests/gnrc_ndp2/tests/01-run.py b/tests/gnrc_ndp2/tests/01-run.py new file mode 100755 index 0000000000000..decad68b6f7cf --- /dev/null +++ b/tests/gnrc_ndp2/tests/01-run.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2016 Kaspar Schleiser +# Copyright (C) 2016 Takuo Yonezawa +# +# 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)) From 593e98b4cd6c11ad8ed2e62b188d91a1f92fcb0a Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 22 May 2017 17:22:09 +0200 Subject: [PATCH 3/6] fixup! gnrc_ndp2: Provide GNRC abstraction layer for NIB for sending --- sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c b/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c index af74c95039dc3..139b88ee07abb 100644 --- a/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c +++ b/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c @@ -16,6 +16,9 @@ #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" From 36144c3cc06ba7c006ba839666f56afa3a7990d7 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Tue, 13 Jun 2017 11:42:48 +0200 Subject: [PATCH 4/6] fixup! gnrc_ndp2: Provide GNRC abstraction layer for NIB for sending --- sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c b/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c index 139b88ee07abb..19395d00ef23b 100644 --- a/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c +++ b/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c @@ -334,7 +334,8 @@ void gnrc_ndp2_nbr_adv_send(const ipv6_addr_t *tgt, gnrc_ipv6_netif_t *netif, } } /* TODO: also check if the node provides proxy servies for tgt */ - if ((pkt != NULL) && !gnrc_ipv6_netif_addr_is_non_unicast(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; } From 331e9b7578d75f13e2099a14cc7d580adb71f3af Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Tue, 27 Jun 2017 11:59:00 +0200 Subject: [PATCH 5/6] fixup! gnrc_ndp2: Provide GNRC abstraction layer for NIB for sending Fix doc --- sys/include/net/gnrc/ndp2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/include/net/gnrc/ndp2.h b/sys/include/net/gnrc/ndp2.h index e830a72356148..e9e09397d6ccd 100644 --- a/sys/include/net/gnrc/ndp2.h +++ b/sys/include/net/gnrc/ndp2.h @@ -282,7 +282,7 @@ void gnrc_ndp2_nbr_sol_send(const ipv6_addr_t *tgt, gnrc_ipv6_netif_t *netif, * 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 gnrc_ipv6 "IPv6 module" selects a fitting IPv6 address. + * @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. From 08287897fbe107aae9c2f728f8b8e2a58eae2b50 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Tue, 1 Aug 2017 15:19:14 +0200 Subject: [PATCH 6/6] fixup! gnrc_ndp2: Provide GNRC abstraction layer for NIB for sending Some late clean-up --- sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c b/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c index 19395d00ef23b..03d6107d87092 100644 --- a/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c +++ b/sys/net/gnrc/network_layer/ndp2/gnrc_ndp2.c @@ -408,22 +408,11 @@ void gnrc_ndp2_rtr_sol_send(gnrc_ipv6_netif_t *netif, const ipv6_addr_t *dst) } } -/* interface supports multihop prefix and 6LoWPAN context distribution */ -static inline bool _multihop_6lp(gnrc_ipv6_netif_t *netif) -{ -#if defined(MODULE_GNRC_SIXLOWPAN_ND) && defined(MODULE_GNRC_IPV6_ROUTER) - return (netif->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && - (netif->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER); -#else - (void)netif; - return false; -#endif -} - 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; @@ -507,6 +496,14 @@ void gnrc_ndp2_rtr_adv_send(gnrc_ipv6_netif_t *netif, const ipv6_addr_t *src, 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,