From 1da599cce2b9d6c1ea7831e1d8815936856d95d7 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sun, 31 May 2015 22:08:53 +0200 Subject: [PATCH] ng_ndp/ng_sixlowpan: import 6LoWPAN-ND host behavior --- Makefile.dep | 31 +- Makefile.pseudomodules | 5 + sys/Makefile | 6 + sys/include/net/ng_ipv6/nc.h | 17 + sys/include/net/ng_ipv6/netif.h | 21 ++ sys/include/net/ng_ndp.h | 4 +- sys/include/net/ng_ndp/hst.h | 5 +- sys/include/net/ng_sixlowpan.h | 13 + sys/include/net/ng_sixlowpan/ctx.h | 9 +- sys/include/net/ng_sixlowpan/nd.h | 137 +++++++ sys/include/net/ng_sixlowpan/nd/rtr.h | 181 +++++++++ sys/include/net/ng_sixlowpan/nd/types.h | 218 +++++++++++ .../ng_ipv6/netif/ng_ipv6_netif.c | 66 +++- sys/net/network_layer/ng_ipv6/ng_ipv6.c | 31 +- sys/net/network_layer/ng_ndp/common.c | 20 +- sys/net/network_layer/ng_ndp/common.h | 13 +- sys/net/network_layer/ng_ndp/hst/ng_ndp_hst.c | 33 +- sys/net/network_layer/ng_ndp/ng_ndp.c | 357 +++++++++++++++--- sys/net/network_layer/ng_ndp/rtr/ng_ndp_rtr.c | 85 +++++ .../ng_sixlowpan/ctx/ng_sixlowpan_ctx.c | 7 +- .../network_layer/ng_sixlowpan/nd/Makefile | 3 + .../ng_sixlowpan/nd/ng_sixlowpan_nd.c | 236 ++++++++++++ .../ng_sixlowpan/nd/rtr/Makefile | 3 + .../ng_sixlowpan/nd/rtr/ng_sixlowpan_nd_rtr.c | 255 +++++++++++++ .../network_layer/ng_sixlowpan/ng_sixlowpan.c | 24 +- 25 files changed, 1702 insertions(+), 78 deletions(-) create mode 100644 sys/include/net/ng_sixlowpan/nd.h create mode 100644 sys/include/net/ng_sixlowpan/nd/rtr.h create mode 100644 sys/include/net/ng_sixlowpan/nd/types.h create mode 100644 sys/net/network_layer/ng_sixlowpan/nd/Makefile create mode 100644 sys/net/network_layer/ng_sixlowpan/nd/ng_sixlowpan_nd.c create mode 100644 sys/net/network_layer/ng_sixlowpan/nd/rtr/Makefile create mode 100644 sys/net/network_layer/ng_sixlowpan/nd/rtr/ng_sixlowpan_nd_rtr.c diff --git a/Makefile.dep b/Makefile.dep index e3117a8c834b0..8864c599fc410 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -74,20 +74,26 @@ ifneq (,$(filter ng_ieee802154,$(USEMODULE))) USEMODULE += ng_sixlowpan endif ifneq (,$(filter ng_ipv6_router, $(USEMODULE))) - USEMODULE += ng_sixlowpan # TODO: replace with ng_sixlowpan_router + USEMODULE += ng_sixlowpan_router endif ifneq (,$(filter ng_ipv6_default, $(USEMODULE))) USEMODULE += ng_sixlowpan_default endif ifneq (,$(filter ng_ipv6_router_default, $(USEMODULE))) - USEMODULE += ng_sixlowpan_default # TODO: replace with ng_sixlowpan_router_default + USEMODULE += ng_sixlowpan_router_default endif endif +ifneq (,$(filter ng_sixlowpan_router_default,$(USEMODULE))) + USEMODULE += ng_sixlowpan_default + USEMODULE += ng_sixlowpan_router +endif + ifneq (,$(filter ng_sixlowpan_default,$(USEMODULE))) USEMODULE += ng_ipv6_default USEMODULE += ng_sixlowpan USEMODULE += ng_sixlowpan_frag + USEMODULE += ng_sixlowpan_nd endif ifneq (,$(filter ng_sixlowpan_frag,$(USEMODULE))) @@ -100,6 +106,27 @@ ifneq (,$(filter ng_sixlowpan_iphc,$(USEMODULE))) USEMODULE += ng_sixlowpan_ctx endif +ifneq (,$(filter ng_sixlowpan_router,$(USEMODULE))) + USEMODULE += ng_ipv6_router + USEMODULE += ng_sixlowpan + USEMODULE += ng_sixlowpan_nd_rtr +endif + +ifneq (,$(filter ng_sixlowpan_nd_br,$(USEMODULE))) + USEMODULE += ng_sixlowpan_nd_br +endif + +ifneq (,$(filter ng_sixlowpan_nd_rtr,$(USEMODULE))) + USEMODULE += ng_ndp_rtr + USEMODULE += ng_sixlowpan_nd +endif + +ifneq (,$(filter ng_sixlowpan_nd,$(USEMODULE))) + USEMODULE += ng_ndp_hst + USEMODULE += ng_sixlowpan + USEMODULE += random +endif + ifneq (,$(filter ng_sixlowpan,$(USEMODULE))) USEMODULE += ng_ipv6 USEMODULE += ng_sixlowpan_netif diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules index f9d4dc52636af..95fe431a31c15 100644 --- a/Makefile.pseudomodules +++ b/Makefile.pseudomodules @@ -4,6 +4,11 @@ PSEUDOMODULES += ng_ieee802154 PSEUDOMODULES += ng_ipv6_default PSEUDOMODULES += ng_ipv6_router PSEUDOMODULES += ng_ipv6_router_default +PSEUDOMODULES += ng_sixlowpan_nd_br # border router +PSEUDOMODULES += ng_sixlowpan_router +PSEUDOMODULES += ng_sixlowpan_router_default +PSEUDOMODULES += ng_sixlowpan_border_router +PSEUDOMODULES += ng_sixlowpan_border_router_default PSEUDOMODULES += pktqueue PSEUDOMODULES += ng_netbase PSEUDOMODULES += newlib diff --git a/sys/Makefile b/sys/Makefile index 1b1436c66646d..5f3c0d8adabd2 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -134,6 +134,12 @@ endif ifneq (,$(filter ng_sixlowpan_iphc,$(USEMODULE))) DIRS += net/network_layer/ng_sixlowpan/iphc endif +ifneq (,$(filter ng_sixlowpan_nd,$(USEMODULE))) + DIRS += net/network_layer/ng_sixlowpan/nd +endif +ifneq (,$(filter ng_sixlowpan_nd_rtr,$(USEMODULE))) + DIRS += net/network_layer/ng_sixlowpan/nd/rtr +endif ifneq (,$(filter ng_sixlowpan_netif,$(USEMODULE))) DIRS += net/network_layer/ng_sixlowpan/netif endif diff --git a/sys/include/net/ng_ipv6/nc.h b/sys/include/net/ng_ipv6/nc.h index e256ae60df966..7cb0880409294 100644 --- a/sys/include/net/ng_ipv6/nc.h +++ b/sys/include/net/ng_ipv6/nc.h @@ -25,6 +25,7 @@ #include #include "kernel_types.h" +#include "net/eui64.h" #include "net/ng_ipv6/addr.h" #include "net/ng_netif.h" #include "net/ng_pktqueue.h" @@ -141,6 +142,22 @@ typedef struct { /** * @} */ +#ifdef MODULE_NG_SIXLOWPAN_ND + vtimer_t rtr_sol_timer; /**< timer for next router solicitation */ +#endif +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + vtimer_t type_timeout; /**< timeout for types */ + /** + * @name 6LoWPAN specific variables. + * @see [RFC 6775, section 6.5.3](https://tools.ietf.org/html/rfc6775#section-6.5.3) + * @{ + */ + uint16_t reg_ltime; /**< registration lifetime */ + eui64_t eui64; /**< the identifying EUI-64 */ + /** + * @} + */ +#endif } ng_ipv6_nc_t; /** diff --git a/sys/include/net/ng_ipv6/netif.h b/sys/include/net/ng_ipv6/netif.h index 6060524ce11be..35a631540dc7e 100644 --- a/sys/include/net/ng_ipv6/netif.h +++ b/sys/include/net/ng_ipv6/netif.h @@ -166,6 +166,23 @@ extern "C" { */ #define NG_IPV6_NETIF_FLAGS_ADV_RETRANS_TIMER (0x0040) +/** + * @brief Flag to indicate that the interface sends periodic router + * advertisements. + * + * @details On most nodes this flag is set. However, for mesh-under topologies + * in 6LoWPANs it can be deactivated, also for route-over topologies + * this can be deactivated too in certain cases. + * The difference to @ref NG_IPV6_NETIF_FLAGS_RTR_ADV is that it only + * applies for periodic advertisements and not advertisements in + * response to router solicitations. If @ref NG_IPV6_NETIF_FLAGS_ROUTER + * or @ref NG_IPV6_NETIF_FLAGS_RTR_ADV are unset, this flag will be + * ignored. + * + * @see [RFC 6775](https://tools.ietf.org/html/rfc6775#section-6.4) + */ +#define NG_IPV6_NETIF_FLAGS_ADV_PERIODIC (0x0100) + /** * @brief Flag to indicate that the interface has other address * configuration. @@ -284,6 +301,10 @@ typedef struct { vtimer_t rtr_adv_timer; /**< Timer for periodic router advertisements */ #endif +#ifdef MODULE_NG_SIXLOWPAN_ND + uint8_t backoff_exp; /**< exponent for the truncated exponential binary + * backoff */ +#endif } ng_ipv6_netif_t; /** diff --git a/sys/include/net/ng_ndp.h b/sys/include/net/ng_ndp.h index 95e987c8465c6..6087973c52a30 100644 --- a/sys/include/net/ng_ndp.h +++ b/sys/include/net/ng_ndp.h @@ -186,8 +186,10 @@ void ng_ndp_rtr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, * @param[in] nc_entry A neighbor cache entry. Will be ignored if its state * is not @ref NG_IPV6_NC_STATE_INCOMPLETE or * @ref NG_IPV6_NC_STATE_PROBE. + * @param[in] src The source for the neigbor solicitation. Is chosen + * from the interface, if `src == NULL`. */ -void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry); +void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry, ng_ipv6_addr_t *src); /** * @brief Event handler for a neighbor cache state timeout. diff --git a/sys/include/net/ng_ndp/hst.h b/sys/include/net/ng_ndp/hst.h index 2b591bba660dd..a3f97c683637b 100644 --- a/sys/include/net/ng_ndp/hst.h +++ b/sys/include/net/ng_ndp/hst.h @@ -51,8 +51,11 @@ extern "C" { * @brief Sends a router solicitation for interface @p iface * * @param[in] iface An IPv6 interface + * @param[in] rtr The address of the router to solicitate. If `rtr == NULL` + * it will be send to @p NG_IPV6_ADDR_ALL_ROUTERS_LINK_LOCAL. */ -void ng_ndp_hst_solicitate_router(ng_ipv6_netif_t *iface); +void ng_ndp_hst_solicitate_router(ng_ipv6_netif_t *iface, + ng_ipv6_addr_t *rtr); /** * @brief Initiates the interface to send router solicitations. diff --git a/sys/include/net/ng_sixlowpan.h b/sys/include/net/ng_sixlowpan.h index b58bf1b8ab967..5f31a1ec159e5 100644 --- a/sys/include/net/ng_sixlowpan.h +++ b/sys/include/net/ng_sixlowpan.h @@ -26,11 +26,14 @@ #include "net/ng_sixlowpan/frag.h" #include "net/ng_sixlowpan/iphc.h" +#include "net/ng_sixlowpan/nd.h" #ifdef __cplusplus extern "C" { #endif +#define NG_SIXLOWPAN_MSG_DELETE_CTX (0x0220) /**< Message type for IPHC removal */ + /** * @brief Default stack size to use for the 6LoWPAN thread */ @@ -57,6 +60,16 @@ extern "C" { */ #define NG_SIXLOWPAN_UNCOMPRESSED (0x41) +/** + * @brief The PID to the 6LoWPAN thread. + * + * @note Use @ref ng_sixlowpan_init() to initialize. **Do not set by hand**. + * + * @details This variable is preferred for 6LoWPAN internal communication *only*. + * Please use @ref net_ng_netreg for external communication. + */ +kernel_pid_t ng_sixlowpan_pid; + /** * @brief Checks if dispatch indicats that fram is not a 6LoWPAN (NALP) frame. * diff --git a/sys/include/net/ng_sixlowpan/ctx.h b/sys/include/net/ng_sixlowpan/ctx.h index 6d5b7a14837a2..2c3ef6712abb9 100644 --- a/sys/include/net/ng_sixlowpan/ctx.h +++ b/sys/include/net/ng_sixlowpan/ctx.h @@ -32,6 +32,8 @@ #include #include +#include "vtimer.h" + #include "net/ng_ipv6/addr.h" #ifdef __cplusplus @@ -75,6 +77,9 @@ typedef struct { * */ uint16_t ltime; +#ifdef MODULE_NG_SIXLOWPAN_ND + vtimer_t delete_timer; /**< timer for context deletion */ +#endif } ng_sixlowpan_ctx_t; /** @@ -104,8 +109,8 @@ ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_lookup_id(uint8_t id); * Must be < @ref NG_SIXLOWPAN_CTX_SIZE. * @param[in] prefix The prefix for the context. * @param[in] prefix_len Length of @p prefix in bits. Must be > 0. - * @param[in] ltime New lifetime of the context. @p comp will be - * implicitly set to `false` if @p ltime == 0. + * @param[in] ltime New lifetime of the context. Entry will be implicitly + * deleted if @p ltime == 0. * @param[in] comp Use for compression if true, do not use for * compression, but still for decompression if false. * diff --git a/sys/include/net/ng_sixlowpan/nd.h b/sys/include/net/ng_sixlowpan/nd.h new file mode 100644 index 0000000000000..a7eb9f7485a71 --- /dev/null +++ b/sys/include/net/ng_sixlowpan/nd.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_ng_sixlowpan_nd Neighbor Discovery Optimization for 6LoWPAN + * @ingroup net_ng_sixlowpan + * @brief Implements Neighbor Discovery Optimization for 6LoWPAN. + * @see + * RFC 6775 + * + * @{ + * + * @file + * @brief 6LoWPAN Neighbor Discovery definitions. + * + * @author Martine Lenders + */ +#ifndef NG_SIXLOWPAN_ND_H_ +#define NG_SIXLOWPAN_ND_H_ + +#include + +#include "net/eui64.h" +#include "net/ng_ipv6/addr.h" +#include "net/ng_netapi.h" +#include "net/ng_netconf.h" + +#include "net/ng_sixlowpan/nd/rtr.h" +#include "net/ng_sixlowpan/nd/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Message type for next unicast router solicitation. + */ +#define NG_SIXLOWPAN_ND_MSG_UC_RTR_SOL (0x0221) + +/** + * @brief Registration Lifetime of an address in minutes. + * This lifetime is highly depenent on the sleep cycles of the node and should + * be set to a value bigger than these sleep cycles. + * + * @see + * RFC 6775, section 5.8.1 + * + */ +#ifndef NG_SIXLOWPAN_ND_REG_LTIME +#define NG_SIXLOWPAN_ND_REG_LTIME (5U) +#endif + +/** + * @brief Interval in seconds between initial router solicitation + * transmissions + * + * @see @ref NG_NDP_MAX_RTR_SOL_INT + */ +#define NG_SIXLOWPAN_ND_MAX_RTR_SOL_INT (10U) + +/** + * @brief Truncation for truncated binary exponential backoff after initial + * resends. + * + * @note The RFC is a little ambiguous since the truncation should be a + * binary exponent, while the + * + * @see + * RFC 6775, section 5.3 + * + */ +#define NG_SIXLOWPAN_ND_MAX_RTR_SOL_INT_TRUNC (6U) + +/** + * @brief Binary exponential backoff for router solicitation + * re-sends. + * + * @param[in] base_sec Base time in seconds for the backoff. + * @param[in] exp Exponent for the factor of the backoff. + * + * @return The resulting backoff time in seconds. + */ +uint32_t ng_sixlowpan_nd_beb(uint32_t base_sec, uint8_t exp); + +void ng_sixlowpan_nd_l2addr_resolution(uint8_t *l2addr, uint8_t *l2addr_len, + ng_ipv6_addr_t *next_hop_ip); + +/** + * @brief Handles 6LoWPAN context option. + * + * @param[in] icmpv6_type Message type of the ICMPv6 message that contained. + * this message. + * @param[in] 6ctx_opt The 6LoWPAN context option. + * + * @return true, when 6LoWPAN context option was correct. + * @return false, when it was incorrect. + */ +bool ng_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, + ng_sixlowpan_nd_opt_6ctx_t *ctx_opt, + uint16_t rtr_ltime); + +uint8_t ng_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ng_ipv6_hdr_t *ipv6, + uint8_t icmpv6_type, + ng_sixlowpan_nd_opt_ar_t *ar_opt, + ng_ndp_opt_t *sl2a_opt); + +ng_pktsnip_t *ng_sixlowpan_nd_opt_ar_build(uint8_t status, uint16_t ltime, + eui64_t *eui64, + ng_pktsnip_t *next); + +static inline ng_pktsnip_t *ng_sixlowpan_nd_opt_ar_iface_build(kernel_pid_t iface, + uint8_t status, ng_pktsnip_t *next) +{ + eui64_t eui64; + + if (ng_netapi_get(iface, NETCONF_OPT_ADDRESS_LONG, 0, &eui64, + sizeof(eui64)) < 0) { + return NULL; + } + + return ng_sixlowpan_nd_opt_ar_build(0, NG_SIXLOWPAN_ND_REG_LTIME, &eui64, + next); +} + +/* TODO: wake-up behavior */ + +#ifdef __cplusplus +} +#endif + +#endif /* NG_SIXLOWPAN_ND_H_ */ +/** @} */ diff --git a/sys/include/net/ng_sixlowpan/nd/rtr.h b/sys/include/net/ng_sixlowpan/nd/rtr.h new file mode 100644 index 0000000000000..e12a631e48435 --- /dev/null +++ b/sys/include/net/ng_sixlowpan/nd/rtr.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_ng_sixlowpan_nd_rtr Router behavior + * @ingroup net_ng_sixlowpan_nd + * @brief Router behavior for Neighbor Discovery optimization for 6LoWPAN + * @{ + * + * @file + * @brief Router behavior definitions for Neighbor Discovery optimizations + * for 6LoWPAN + * + * @author Martine Lenders + */ +#ifndef NG_SIXLOWPAN_ND_RTR_H_ +#define NG_SIXLOWPAN_ND_RTR_H_ + +#include + +#include "bitfield.h" +#include "kernel_types.h" +#include "net/ng_ipv6/addr.h" +#include "net/ng_ndp/types.h" +#include "net/ng_sixlowpan/nd/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Message type for authoritative border router timeout + */ +#define NG_SIXLOWPAN_ND_RTR_MSG_ABR_TIMEOUT (0x0222) + +/** + * @brief Message type for address registration timeout + */ +#define NG_SIXLOWPAN_ND_RTR_MSG_AR_TIMEOUT (0x0223) + +/** + * @brief Number of registerable border routers + * + * @note More than one border routers require some way of synchronization + * of the context information (see + * [RFC 6775, section 8.1](https://tools.ietf.org/html/rfc6775#section-8.1)) + */ +#ifndef NG_SIXLOWPAN_ND_RTR_ABR_NUMOF +#define NG_SIXLOWPAN_ND_RTR_ABR_NUMOF (1) +#endif + +/** + * @brief The number of non-link-local prefixes associated with border routers + * at maximum. + */ +#ifndef NG_SIXLOWPAN_ND_RTR_ABR_PRF_NUMOF +#define NG_SIXLOWPAN_ND_RTR_ABR_PRF_NUMOF (NG_SIXLOWPAN_ND_RTR_ABR_NUMOF * 1) +#endif + +/** + * @brief Representation for prefixes comming from a router + */ +typedef struct ng_sixlowpan_nd_rtr_abr_prf { + struct ng_sixlowpan_nd_rtr_abr_prf *next; /**< next prefix */ + ng_ipv6_addr_t *prefix; /**< prefix */ + uint16_t prefix_len; + kernel_pid_t iface; +} ng_sixlowpan_nd_rtr_abr_prf_t; + +/** + * @brief Abstract representation of a border router on all (border) routers. + */ +typedef struct { + ng_ipv6_addr_t addr; /**< the IPv6 address of the + * border router (BR) */ + uint32_t version; /**< version of the information + * dissiminated by the BR */ + vtimer_t ltimer; /**< timer for deletion */ + uint16_t ltime; /**< the time in minutes until + * deletion */ + BITFIELD(contexts, 16); /**< contexts associated with BR */ + ng_sixlowpan_nd_rtr_abr_prf_t *prefixes; /**< prefixes associated with BR */ +} ng_sixlowpan_nd_rtr_abr_t; + +/** + * @brief Handles authoritative border router option. + * + * @param[in] iface Interface the source link-layer option was received + * on. + * @param[in] rtr_adv The router advertisement containing the ABRO. + * @param[in] icmpv6_size The size of the @p rtr_adv. + * @param[in] abr_opt The ABRO. + * + * @note Erroneous ABROs are always ignored silently. + */ +void ng_sixlowpan_nd_rtr_opt_abr_handle(kernel_pid_t iface, ng_ndp_rtr_adv_t *rtr_adv, + int icmpv6_size, ng_sixlowpan_nd_opt_abr_t *abr_opt); + +/** + * @brief Get authoritative border router for sending. + * + * @note For now the authoritative is singular to simplify the sending of + * router advertisements. + * + * @return The authoritative border router. + */ +ng_sixlowpan_nd_rtr_abr_t *ng_sixlowpan_nd_rtr_abr_get(void); + +/** + * @brief Checks if the authoritative border router entry identified by + * @p abr_opt has a higher version number than the version number in + * @p abr_opt + * + * @param[in] abr_opt An authoritative border router option. + * + * @return true, if the version number is lower (the option is older) + * @return false, if the version number is higher (the option is new to this + * node) + */ +bool ng_sixlowpan_nd_rtr_abr_older(ng_sixlowpan_nd_opt_abr_t *abr_opt); + +/** + * @brief Removes an authoritative border router and all information related + * to it. + * + * @param[in] abr The border router. + */ +void ng_sixlowpan_nd_rtr_abr_remove(ng_sixlowpan_nd_rtr_abr_t *abr); + +#ifdef MODULE_NG_SIXLOWPAN_ND_BR +/** + * @brief Increments the version number of the authoritative border router + * + * @param[in] abr The border router. + */ +static inline void ng_sixlowpan_nd_rtr_abr_inc_version(ng_sixlowpan_nd_rtr_abr_t *abr) +{ + abr->version++; +} +#endif + +/** + * @brief + * + * @param[in] prefix_len + * @param[in] flags + * @param[in] ltime + * @param[in] prefix + * @param[in] next + * + * @return + */ +ng_pktsnip_t *ng_sixlowpan_nd_rtr_6ctx_opt_build(uint8_t prefix_len, uint8_t flags, + uint16_t ltime, ng_ipv6_addr_t *prefix, + ng_pktsnip_t *next); + +/** + * @brief + * + * @param[in] version + * @param[in] ltime + * @param[in] braddr + * @param[in] next + * + * @return + */ +ng_pktsnip_t *ng_sixlowpan_nd_rtr_abr_opt_build(uint32_t version, uint16_t ltime, + ng_ipv6_addr_t *braddr, + ng_pktsnip_t *next); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_SIXLOWPAN_ND_RTR_H_ */ +/** @} */ diff --git a/sys/include/net/ng_sixlowpan/nd/types.h b/sys/include/net/ng_sixlowpan/nd/types.h new file mode 100644 index 0000000000000..332a2c65b9404 --- /dev/null +++ b/sys/include/net/ng_sixlowpan/nd/types.h @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_ng_sixlowpan_nd_types Types for 6LoWPAN-ND + * @ingroup net_ng_sixlowpan_nd + * @brief Types for neighbor discovery optimization for 6LoWPAN + * @{ + * + * @file + * @brief Type definitions for neighbor discovery optimization for 6LoWPAN + * + * @author Martine Lenders + */ +#ifndef NG_SIXLOWPAN_ND_TYPES_H_ +#define NG_SIXLOWPAN_ND_TYPES_H_ + +#include "byteorder.h" +#include "net/eui64.h" +#include "net/ng_ipv6/addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @{ + * @name New option types + * @see + * IANA, IPv6 Neighbor Discovery Option Formats + * + */ +#define NG_SIXLOWPAN_ND_OPT_AR (33) /* address registration option */ +#define NG_SIXLOWPAN_ND_OPT_6CTX (34) /* 6LoWPAN context option */ +#define NG_SIXLOWPAN_ND_OPT_ABR (35) /* authoritative border router option */ +/** + * @} + */ + +/** + * @{ + * @name Lengths for fixed length options + * @brief Options don't use bytes as their length unit, but 8 bytes. + */ +#define NG_SIXLOWPAN_ND_OPT_AR_LEN (2U) +#define NG_SIXLOWPAN_ND_OPT_ABR_LEN (3U) +/** + * @} + */ + +/** + * @{ + * @name Status values for address registration option and DARs + * + * @see + * RFC 6775, section 4.1 + * + */ +#define NG_SIXLOWPAN_ND_STATUS_SUCCESS (0) /**< success */ +#define NG_SIXLOWPAN_ND_STATUS_DUP (1) /**< duplicate address */ +#define NG_SIXLOWPAN_ND_STATUS_NC_FULL (2) /**< neighbor cache full */ +/** + * @} + */ + +/** + * @{ + * @name Flags for 6LoWPAN context option + */ +#define NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_MASK (0x1f) +#define NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_C (0x10) /**< valid for compression */ +#define NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_CID_MASK (0x0f) /**< mask for CID */ +/** + * @} + */ + +/** + * @brief Address registration option format + * @extends ng_ndp_opt_t + * + * @see + * RFC 6775, section 4.1 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< option type */ + uint8_t len; /**< length in units of 8 octets */ + uint8_t status; /**< Indicates registration status in NA response; + * must be 0 in NS messages */ + uint8_t resv[3]; /**< reserved fields */ + network_uint16_t ltime; /**< registration lifetime */ + eui64_t eui64; /**< EUI-64 */ +} ng_sixlowpan_nd_opt_ar_t; + +/** + * @brief 6LoWPAN context option format + * @extends ng_ndp_opt_t + * + * @see + * RFC 6775, section 4.2 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< option type */ + uint8_t len; /**< length in units of 8 octets */ + uint8_t ctx_len; /**< context length */ + uint8_t resv_c_cid; /**< 3-bit reserved, 1-bit c flag, 4 bit CID */ + network_uint16_t resv; /**< reserved field */ + network_uint16_t ltime; /**< valid lifetime */ +} ng_sixlowpan_nd_opt_6ctx_t; + +/** + * @brief Authoritative border router option format + * @extends ng_ndp_opt_t + * + * @see + * RFC 6775, section 4.3 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< option type */ + uint8_t len; /**< length in units of 8 octets */ + network_uint16_t vlow; /**< version low */ + network_uint16_t vhigh; /**< version high */ + network_uint16_t ltime; /**< valid lifetime */ + ng_ipv6_addr_t braddr; /**< 6LoWPAN border router address */ +} ng_sixlowpan_nd_opt_abr_t; + +/** + * @brief Duplicate address message format. + * @extends ng_icmpv6_hdr_t + * + * @details Used for both duplicate address request and confirmation. + * + * @see + * RFC 4861, section 4.1 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< message type */ + uint8_t code; /**< message code */ + network_uint16_t csum; /**< checksum */ + uint8_t status; /**< Indicates registration status in DAC; + * must be 0 in DARs */ + uint8_t resv; /**< reserved field */ + network_uint16_t ltime; /**< registration lifetime */ + network_uint64_t eui64; /**< EUI-64 */ + ng_ipv6_addr_t addr; /**< registered address */ +} ng_sixlowpan_nd_da_t; + +/** + * @brief Checks if a 6LoWPAN context in an 6LoWPAN context option is + * valid for compression. + * + * @param[in] ctx_opt A 6LoWPAN context option. + * + * @return true, if C bit is set in @p ctx_opt. + * @return false, if C bit is unset in @p ctx_opt. + */ +static inline bool ng_sixlowpan_nd_opt_6ctx_is_comp(const ng_sixlowpan_nd_opt_6ctx_t *ctx_opt) +{ + return (ctx_opt->resv_c_cid & NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_C); +} + +/** + * @brief Sets the C bit of a 6LoWPAN context option. + * + * @param[out] ctx_opt A 6LoWPAN context option. + * @param[in] valid The value for the C bit in @p ctx_opt. + */ +static inline void ng_sixlowpan_nd_opt_6ctx_set_comp(ng_sixlowpan_nd_opt_6ctx_t *ctx_opt, + bool valid) +{ + if (valid) { + ctx_opt->resv_c_cid |= NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_C; + } + else { + ctx_opt->resv_c_cid &= ~NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_C; + } +} + +/** + * @brief Gets a CID (context identifier) from a 6LoWPAN context option. + * + * @param[in] ctx_opt A 6LoWPAN context option. + * + * @return The CID in the 6LoWPAN context option @p ctx_opt. + */ +static inline uint8_t ng_sixlowpan_nd_opt_6ctx_get_cid(const ng_sixlowpan_nd_opt_6ctx_t *ctx_opt) +{ + return (ctx_opt->resv_c_cid & NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_CID_MASK); +} + +/** + * @brief Sets a CID (context identifier) for a 6LoWPAN context option. + * + * @param[out] ctx_opt A 6LoWPAN context option. + * @param[in] cid The CID for the 6LoWPAN context option. + */ +static inline void ng_sixlowpan_nd_opt_6ctx_set_cid(ng_sixlowpan_nd_opt_6ctx_t *ctx_opt, + uint8_t cid) +{ + ctx_opt->resv_c_cid &= ~NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_CID_MASK; + ctx_opt->resv_c_cid |= (NG_SIXLOWPAN_ND_OPT_6CTX_FLAGS_CID_MASK & cid); +} + + +#ifdef __cplusplus +} +#endif + +#endif /* NG_SIXLOWPAN_ND_TYPES_H_ */ +/** @} */ diff --git a/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c b/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c index af4f02459b475..5ac7898b029fb 100644 --- a/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c +++ b/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c @@ -22,6 +22,7 @@ #include "mutex.h" #include "net/eui64.h" #include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/nc.h" #include "net/ng_ndp.h" #include "net/ng_ndp/hst.h" #include "net/ng_netapi.h" @@ -73,31 +74,61 @@ static ng_ipv6_addr_t *_add_addr_to_entry(ng_ipv6_netif_t *entry, const ng_ipv6_ tmp_addr->flags |= NG_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST; } else { - ng_ipv6_addr_t sol_node; - if (!ng_ipv6_addr_is_link_local(addr)) { - /* add also corresponding link-local address */ ng_ipv6_addr_t ll_addr; +#ifdef MODULE_NG_SIXLOWPAN_ND_BR + ng_sixlowpan_nd_rtr_abr_inc_version(ng_sixlowpan_nd_rtr_abr_get()); +#endif + + /* add also corresponding link-local address */ ll_addr.u64[1] = addr->u64[1]; ng_ipv6_addr_set_link_local_prefix(&ll_addr); _add_addr_to_entry(entry, &ll_addr, 64, flags | NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK); #ifdef MODULE_NG_NDP_RTR - if (entry->flags & NG_IPV6_NETIF_FLAGS_ROUTER) { - ng_ndp_rtr_advertise_periodically(entry); - } + if ((entry->flags & NG_IPV6_NETIF_FLAGS_ROUTER) && + !(entry->flags & NG_IPV6_NETIF_FLAGS_ADV_PERIODIC)) { + ng_ndp_rtr_advertise_periodically(entry); + } #endif } else { tmp_addr->flags |= NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK; } +#ifdef MODULE_NG_SIXLOWPAN_ND + /* https://tools.ietf.org/html/rfc6775#section-5.2 states a join to + * the solicited nodes address is not necessary for 6LoWPAN */ + if (!(entry->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN)) { + ng_ipv6_addr_t sol_node; + + ng_ipv6_addr_set_solicited_nodes(&sol_node, addr); + _add_addr_to_entry(entry, &sol_node, NG_IPV6_ADDR_BIT_LEN, 0); + } +#else + ng_ipv6_addr_t sol_node; + ng_ipv6_addr_set_solicited_nodes(&sol_node, addr); _add_addr_to_entry(entry, &sol_node, NG_IPV6_ADDR_BIT_LEN, 0); +#endif } +#ifdef MODULE_NG_SIXLOWPAN_ND + ng_ipv6_nc_t *router = ng_ipv6_nc_get_next_router(NULL); + + /* first look if there is any reachable router */ + while (router != NULL) { + if ((ng_ipv6_nc_get_state(router) != NG_IPV6_NC_STATE_INCOMPLETE) && + (ng_ipv6_nc_get_state(router) != NG_IPV6_NC_STATE_UNREACHABLE)) { + ng_ndp_retrans_nbr_sol(router, &(tmp_addr)->addr); + } + + router = ng_ipv6_nc_get_next_router(router); + } +#endif + return &(tmp_addr->addr); } @@ -468,6 +499,10 @@ void ng_ipv6_netif_init_by_dev(void) mutex_lock(&ipv6_if->mutex); +#ifdef MODULE_NG_NDP_RTR + ipv6_ifs->flags |= NG_IPV6_NETIF_FLAGS_ADV_PERIODIC; +#endif + #ifdef MODULE_NG_SIXLOWPAN ng_nettype_t if_type = NG_NETTYPE_UNDEF; @@ -478,7 +513,19 @@ void ng_ipv6_netif_init_by_dev(void) ipv6_ifs->flags |= NG_IPV6_NETIF_FLAGS_SIXLOWPAN; } -#endif + +#ifdef MODULE_NG_SIXLOWPAN_ND + uint16_t hwaddr_len = 8; + /* https://tools.ietf.org/html/rfc6775#section-5.2 states that the + * link-local addresses are formed by the EUI-64 */ + ng_netapi_set(ifs[i], NETCONF_OPT_SRC_LEN, 0, &hwaddr_len, + sizeof(hwaddr_len)); +#endif /* MODULE_NG_SIXLOWPAN_ND */ +#if defined(MODULE_NG_SIXLOWPAN_ND_RTR) && !defined(MODULE_NG_SIXLOWPAN_ND_BR) + /* deactivate advertisement for now: https://tools.ietf.org/html/rfc6775#section-6.2 */ + ng_ndp_rtr_netif_rtr_adv(ipv6_if, false); +#endif /* MODULE_NG_SIXLOWPAN_ND_RTR */ +#endif /* MODULE_NG_SIXLOWPAN */ if ((ng_netapi_get(ifs[i], NETCONF_OPT_IPV6_IID, 0, &iid, sizeof(eui64_t)) < 0)) { @@ -497,7 +544,10 @@ void ng_ipv6_netif_init_by_dev(void) #ifdef MODULE_NG_NDP_RTR /* start periodic advertisements */ - ng_ndp_rtr_advertise_periodically(ipv6_if); + if ((ipv6_if->flags & NG_IPV6_NETIF_FLAGS_ROUTER) && + !(ipv6_if->flags & NG_IPV6_NETIF_FLAGS_ADV_PERIODIC)) { + ng_ndp_rtr_advertise_periodically(ipv6_if); + } #endif } } diff --git a/sys/net/network_layer/ng_ipv6/ng_ipv6.c b/sys/net/network_layer/ng_ipv6/ng_ipv6.c index 9abd0603a0347..060cc3b50752f 100644 --- a/sys/net/network_layer/ng_ipv6/ng_ipv6.c +++ b/sys/net/network_layer/ng_ipv6/ng_ipv6.c @@ -22,6 +22,8 @@ #include "net/ng_netbase.h" #include "net/ng_ndp.h" #include "net/ng_protnum.h" +#include "net/ng_sixlowpan/nd.h" +#include "net/ng_sixlowpan/nd/rtr.h" #include "thread.h" #include "utlist.h" @@ -66,7 +68,7 @@ kernel_pid_t ng_ipv6_init(void) { if (ng_ipv6_pid == KERNEL_PID_UNDEF) { ng_ipv6_pid = thread_create(_stack, sizeof(_stack), NG_IPV6_PRIO, - CREATE_STACKTEST, _event_loop, NULL, "ipv6"); + CREATE_STACKTEST, _event_loop, NULL, "ipv6"); } return ng_ipv6_pid; @@ -173,7 +175,7 @@ static void *_event_loop(void *args) case NG_NDP_MSG_NBR_SOL_RETRANS: DEBUG("ipv6: Neigbor solicitation retransmission timer event received\n"); - ng_ndp_retrans_nbr_sol((ng_ipv6_nc_t *)msg.content.ptr); + ng_ndp_retrans_nbr_sol((ng_ipv6_nc_t *)msg.content.ptr, NULL); break; case NG_NDP_MSG_NC_STATE_TIMEOUT: @@ -192,10 +194,33 @@ static void *_event_loop(void *args) #ifdef MODULE_NG_NDP_HST case NG_NDP_MSG_RTR_SOL: DEBUG("ipv6: Router solicitation retransmission timer event received\n"); - ng_ndp_hst_solicitate_router((ng_ipv6_netif_t *)msg.content.ptr); + ng_ndp_hst_solicitate_router((ng_ipv6_netif_t *)msg.content.ptr, + NULL); break; #endif +#ifdef MODULE_NG_SIXLOWPAN_ND + case NG_SIXLOWPAN_ND_MSG_UC_RTR_SOL: + DEBUG("ipv6: Unicast router solicitation retransmission timer event\n"); + ng_ndp_hst_solicitate_router( + ng_ipv6_netif_get(((ng_ipv6_nc_t *)msg.content.ptr)->iface), + &(((ng_ipv6_nc_t *)msg.content.ptr)->ipv6_addr)); + break; +#endif + +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + case NG_SIXLOWPAN_ND_RTR_MSG_ABR_TIMEOUT: + DEBUG("ipv6: Remove authoritative border router event\n"); + ng_sixlowpan_nd_rtr_abr_remove( + (ng_sixlowpan_nd_rtr_abr_t *)msg.content.ptr); + break; + case NG_SIXLOWPAN_ND_RTR_MSG_AR_TIMEOUT: + DEBUG("ipv6: Remove authoritative border router event\n"); + ng_ipv6_nc_remove( + ((ng_ipv6_nc_t *)msg.content.ptr)->iface, + &(((ng_ipv6_nc_t *)msg.content.ptr)->ipv6_addr)); + /* TODO: notify routing protocol */ +#endif default: break; diff --git a/sys/net/network_layer/ng_ndp/common.c b/sys/net/network_layer/ng_ndp/common.c index 2a971406ed4a5..aa578d6d8be18 100644 --- a/sys/net/network_layer/ng_ndp/common.c +++ b/sys/net/network_layer/ng_ndp/common.c @@ -19,6 +19,7 @@ #include "net/ng_ndp.h" #include "net/ng_netif/hdr.h" #include "net/ng_icmpv6.h" +#include "net/ng_sixlowpan/nd.h" #include "vtimer.h" #include "common.h" @@ -129,6 +130,7 @@ void _ndp_set_state(ng_ipv6_nc_t *nc_entry, uint8_t state) { ng_ipv6_netif_t *ipv6_iface; timex_t t = { NG_NDP_FIRST_PROBE_DELAY, 0 }; + ng_pktsnip_t *extra_opts = NULL; nc_entry->flags &= ~NG_IPV6_NC_STATE_MASK; nc_entry->flags |= state; @@ -148,8 +150,13 @@ void _ndp_set_state(ng_ipv6_nc_t *nc_entry, uint8_t state) ipv6_iface = ng_ipv6_netif_get(nc_entry->iface); nc_entry->probes_remaining = NG_NDP_MAX_UC_NBR_SOL_NUMOF; - _ndp_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, - &nc_entry->ipv6_addr); +#ifdef MODULE_NG_SIXLOWPAN_ND + extra_opts = ng_sixlowpan_nd_opt_ar_iface_build(nc_entry->iface, 0, + extra_opts); +#endif + + _ndp_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr, + &nc_entry->ipv6_addr, extra_opts); mutex_lock(&ipv6_iface->mutex); vtimer_set_msg(&nc_entry->nbr_sol_timer, @@ -192,14 +199,15 @@ ng_pktsnip_t *_ndp_iface_rtr_sol_build(ng_ipv6_netif_t *iface) return pkt; } -void _ndp_send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt, ng_ipv6_addr_t *dst) +void _ndp_send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt, + ng_ipv6_addr_t *src, ng_ipv6_addr_t *dst, + ng_pktsnip_t *extra_opts) { ng_pktsnip_t *hdr, *pkt = NULL; - ng_ipv6_addr_t *src = NULL; size_t src_len = 0; /* check if there is a fitting source address to target */ - if ((src = ng_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) { + if ((src != NULL) && (src = ng_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) { uint8_t l2src[8]; uint16_t l2src_len; src_len = sizeof(ng_ipv6_addr_t); @@ -207,7 +215,7 @@ void _ndp_send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt, ng_ipv6_addr_t * if (l2src_len > 0) { /* add source address link-layer address option */ - pkt = ng_ndp_opt_sl2a_build(l2src, l2src_len, NULL); + pkt = ng_ndp_opt_sl2a_build(l2src, l2src_len, extra_opts); if (pkt == NULL) { DEBUG("ndp: error allocating Source Link-layer address option.\n"); diff --git a/sys/net/network_layer/ng_ndp/common.h b/sys/net/network_layer/ng_ndp/common.h index b84920aad3a56..f04ad7e167dd1 100644 --- a/sys/net/network_layer/ng_ndp/common.h +++ b/sys/net/network_layer/ng_ndp/common.h @@ -112,11 +112,16 @@ ng_pktsnip_t *_ndp_iface_rtr_sol_build(ng_ipv6_netif_t *iface); * * @internal * - * @param[in] iface The interface to send the neighbor solicitation over. - * @param[in] tgt The target address for the neighbor solicitation. - * @param[in] dst The destination address for the neighbor solicitation. + * @param[in] iface The interface to send the neighbor solicitation over. + * @param[in] tgt The target address for the neighbor solicitation. + * @param[in] src The source address for the neighbor solicitation. May + * be NULL. + * @param[in] dst The destination address for the neighbor solicitation. + * @param[in] extra_opts Extra options to use in the neighbor solicitation. */ -void _ndp_send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt, ng_ipv6_addr_t *dst); +void _ndp_send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt, + ng_ipv6_addr_t *src, ng_ipv6_addr_t *dst, + ng_pktsnip_t *extra_opts); #ifdef __cplusplus } diff --git a/sys/net/network_layer/ng_ndp/hst/ng_ndp_hst.c b/sys/net/network_layer/ng_ndp/hst/ng_ndp_hst.c index b22c71a3b3e05..fc7324000a43e 100644 --- a/sys/net/network_layer/ng_ndp/hst/ng_ndp_hst.c +++ b/sys/net/network_layer/ng_ndp/hst/ng_ndp_hst.c @@ -18,6 +18,7 @@ #include "net/ng_netapi.h" #include "net/ng_netif/hdr.h" #include "net/ng_pktbuf.h" +#include "net/ng_sixlowpan/nd.h" #include "vtimer.h" #include "net/ng_ndp/hst.h" @@ -35,7 +36,8 @@ void ng_ndp_hst_init(ng_ipv6_netif_t *iface) ng_ipv6_pid, NG_NDP_MSG_RTR_SOL, iface); } -void ng_ndp_hst_solicitate_router(ng_ipv6_netif_t *iface) +void ng_ndp_hst_solicitate_router(ng_ipv6_netif_t *iface, + ng_ipv6_addr_t *rtr) { ng_pktsnip_t *hdr, *pkt = _ndp_iface_rtr_sol_build(iface); ng_ipv6_addr_t *src, dst = NG_IPV6_ADDR_ALL_ROUTERS_LINK_LOCAL; @@ -44,17 +46,42 @@ void ng_ndp_hst_solicitate_router(ng_ipv6_netif_t *iface) return; } + if (rtr != NULL) { + dst.u64[0].u64 = rtr->u64[0].u64; + dst.u64[1].u64 = rtr->u64[1].u64; + } + mutex_lock(&iface->mutex); if (iface->initial_phase > 0) { - DEBUG("ndp hst: retransmit rtr sol in %d sec\n", NG_NDP_MAX_RTR_SOL_INT); + uint32_t interval = NG_NDP_MAX_RTR_SOL_INT; + +#ifdef MODULE_NG_SIXLOWPAN_ND + if (iface->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN) { + interval = NG_SIXLOWPAN_ND_MAX_RTR_SOL_INT; + } +#endif + + DEBUG("ndp hst: retransmit rtr sol in %d sec\n", interval); iface->initial_phase--; vtimer_remove(&iface->rtr_sol_timer); - vtimer_set_msg(&iface->rtr_sol_timer, timex_set(NG_NDP_MAX_RTR_SOL_INT, 0), + vtimer_set_msg(&iface->rtr_sol_timer, timex_set(interval, 0), ng_ipv6_pid, NG_NDP_MSG_RTR_SOL, iface); } +#ifdef MODULE_NG_SIXLOWPAN_ND + else if (iface->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN) { + vtimer_remove(&iface->rtr_sol_timer); + vtimer_set_msg(&iface->rtr_sol_timer, + timer_set(ng_sixlowpan_nd_tbeb(1, iface->backoff_exp++), 0), + ng_ipv6_pid, NG_NDP_MSG_RTR_SOL, iface); + + if (iface->backoff_exp > NG_SIXLOWPAN_ND_MAX_RTR_SOL_INT_TRUNC) { + iface->backoff_exp = NG_SIXLOWPAN_ND_MAX_RTR_SOL_INT_TRUNC; + } + } +#endif if ((src = ng_ipv6_netif_find_best_src_addr(iface->pid, &dst)) == NULL) { hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)&dst, diff --git a/sys/net/network_layer/ng_ndp/ng_ndp.c b/sys/net/network_layer/ng_ndp/ng_ndp.c index 70f68d8f07f3e..a8d015b2b319b 100644 --- a/sys/net/network_layer/ng_ndp/ng_ndp.c +++ b/sys/net/network_layer/ng_ndp/ng_ndp.c @@ -18,10 +18,13 @@ #include #include "byteorder.h" +#include "eui64.h" #include "net/ng_icmpv6.h" #include "net/ng_ipv6.h" #include "net/ng_ipv6/ext/rh.h" #include "net/ng_netbase.h" +#include "net/ng_sixlowpan/nd.h" +#include "net/ng_sixlowpan/nd/rtr.h" #include "utlist.h" #include "thread.h" #include "vtimer.h" @@ -46,13 +49,14 @@ static bool _handle_tl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt, ng_ndp_opt_t *tl2a_opt, ng_ipv6_addr_t *tgt, uint8_t adv_flags); static bool _handle_pi_opt(kernel_pid_t iface, uint8_t icmpv6_type, - ng_ndp_opt_pi_t *pi_opt); + ng_ndp_opt_pi_t *pi_opt, ng_ipv6_addr_t *rtr_addr); static bool _handle_mtu_opt(kernel_pid_t iface, uint8_t icmpv6_type, ng_ndp_opt_mtu_t *mtu_opt); /* send address resolution messages */ static void _send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt, - ng_ipv6_addr_t *dst, bool supply_tl2a); + ng_ipv6_addr_t *dst, bool supply_tl2a, + ng_pktsnip_t *extra_opts); /* special netapi helper */ static inline void _send_delayed(vtimer_t *t, timex_t interval, ng_pktsnip_t *pkt) @@ -105,6 +109,15 @@ void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, break; +#ifdef MODULE_NG_SIXLOWPAN_ND + + case NG_SIXLOWPAN_ND_OPT_AR: + /* address registration option is always ignored if invalid */ + ng_sixlowpan_nd_opt_ar_handle(iface, ipv6, nbr_adv->type, + (ng_sixlowpan_nd_opt_ar_t *)opt, NULL); + break; +#endif + default: /* silently discard all other options */ break; @@ -138,8 +151,17 @@ void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, { uint16_t opt_offset = 0; uint8_t *buf = ((uint8_t *)nbr_sol) + sizeof(ng_ndp_nbr_sol_t); - ng_ipv6_addr_t *tgt; + ng_ipv6_addr_t *tgt, adv_dst; int sicmpv6_size = (int)icmpv6_size; + ng_pktsnip_t *extra_adv_opt = NULL; +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + /* address registration option needs SLLAO, so we need to store it */ + ng_sixlowpan_nd_opt_ar_t *ar_opt = NULL; + uint8_t status = 0; +#endif + + adv_dst.u64[0] = ipv6->src.u64[0]; + adv_dst.u64[1] = ipv6->src.u64[1]; /* check validity */ if ((ipv6->hl != 255) || (nbr_sol->code != 0) || @@ -159,6 +181,30 @@ void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, return; } +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + /* search ARO */ + sicmpv6_size -= sizeof(ng_ndp_nbr_sol_t); + + while (sicmpv6_size > 0) { + ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset); + + switch (opt->type) { + case NG_SIXLOWPAN_ND_OPT_AR: + /* address registration option is always ignored if invalid */ + ar_opt = (ng_sixlowpan_nd_opt_ar_t *)opt; + break; + + default: + break; + } + + opt_offset += (opt->len * 8); + sicmpv6_size -= (opt->len * 8); + } + + sicmpv6_size = (int)icmpv6_size; +#endif + sicmpv6_size -= sizeof(ng_ndp_nbr_sol_t); while (sicmpv6_size > 0) { @@ -166,10 +212,41 @@ void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, switch (opt->type) { case NG_NDP_OPT_SL2A: +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + if (ar_opt != NULL) { + status = ng_sixlowpan_nd_opt_ar_handle(iface, ipv6, nbr_sol->type, + (ng_sixlowpan_nd_opt_ar_t *)ar_opt, opt); + + extra_adv_opt = ng_sixlowpan_nd_opt_ar_build(status, + byteorder_ntohs(ar_opt->ltime), &ar_opt->eui64, + NULL); + + if (extra_adv_opt == NULL) { + DEBUG("ndp: error allocating address registration option"); + /* XXX: do not leave */ + } + + if (status != NG_SIXLOWPAN_ND_STATUS_SUCCESS) { + eui64_t eui64 = { ar_opt->eui64.uint64 }; + eui64.uint8[0] ^= 0x02; + ng_ipv6_addr_set_iid(&adv_dst, eui64.uint64); + ng_ipv6_addr_set_link_local(&adv_dst); + } + } + + if (status == 0) { + if (!_ndp_sl2a_opt_handle(iface, pkt, ipv6, nbr_sol->type, opt)) { + /* invalid source link-layer address option */ + return; + } + } +#else if (!_ndp_sl2a_opt_handle(iface, pkt, ipv6, nbr_sol->type, opt)) { /* invalid source link-layer address option */ return; } +#endif + break; @@ -182,8 +259,10 @@ void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, sicmpv6_size -= (opt->len * 8); } - _send_nbr_adv(iface, tgt, &ipv6->src, - ng_ipv6_addr_is_multicast(&ipv6->dst)); + _send_nbr_adv(iface, tgt, &adv_dst, + ng_ipv6_addr_is_multicast(&ipv6->dst) && + !(ng_ipv6_netif_get(iface)->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN), + extra_adv_opt); return; } @@ -197,6 +276,14 @@ void ng_ndp_rtr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, ng_ipv6_nc_t *nc_entry = NULL; ng_ipv6_netif_t *if_entry = ng_ipv6_netif_get(iface); int sicmpv6_size = (int)icmpv6_size; +#ifdef MODULE_NG_SIXLOWPAN_ND + /* to determine and schedule next unicast router solicitation */ + timex_t next_rtr_sol = { 0, 0 }; +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + /* ABRO versions the RA so we need to store it */ + ng_sixlowpan_nd_opt_abr_t *abr_opt = NULL; +#endif +#endif /* check validity */ if (!ng_ipv6_addr_is_link_local(&ipv6->src) || @@ -208,6 +295,35 @@ void ng_ndp_rtr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, return; } +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + /* search for version first */ + sicmpv6_size -= sizeof(ng_ndp_rtr_adv_t); + + while (sicmpv6_size > 0) { + ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset); + + switch (opt->type) { + case NG_SIXLOWPAN_ND_OPT_ABR: + abr_opt = (ng_sixlowpan_nd_opt_abr_t *)opt; + + if (ng_sixlowpan_nd_rtr_abr_older(abr_opt)) { + DEBUG("ndp: old or invalid ABRO received, discard RA\n"); + return; + } + + break; + + default: + break; + } + + opt_offset += (opt->len * 8); + sicmpv6_size -= (opt->len * 8); + } + + sicmpv6_size = icmpv6_size; +#endif + nc_entry = ng_ipv6_nc_get(iface, &ipv6->src); if (nc_entry == NULL) { /* if still not found */ @@ -232,10 +348,13 @@ void ng_ndp_rtr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, } if (rtr_adv->ltime.u16 != 0) { +#ifdef MODULE_NG_SIXLOWPAN_ND + next_rtr_sol.seconds = byteorder_ntohs(rtr_adv->ltime); +#endif vtimer_remove(&nc_entry->rtr_timeout); vtimer_set_msg(&nc_entry->rtr_timeout, timex_set(byteorder_ntohs(rtr_adv->ltime), 0), - thread_getpid(), NG_NDP_MSG_RTR_TIMEOUT, nc_entry); + ng_ipv6_pid, NG_NDP_MSG_RTR_TIMEOUT, nc_entry); } mutex_lock(&if_entry->mutex); @@ -289,12 +408,33 @@ void ng_ndp_rtr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, break; case NG_NDP_OPT_PI: - if (!_handle_pi_opt(iface, rtr_adv->type, (ng_ndp_opt_pi_t *)opt)) { + if (!_handle_pi_opt(iface, rtr_adv->type, (ng_ndp_opt_pi_t *)opt, + &ipv6->src)) { /* invalid prefix information option */ return; } +#ifdef MODULE_NG_SIXLOWPAN_ND + if (byteorder_ntohl(((ng_ndp_opt_pi_t *)opt)->valid_ltime) < + next_rtr_sol.seconds) { + next_rtr_sol.seconds = byteorder_ntohl(((ng_ndp_opt_pi_t *)opt)->valid_ltime); + } +#endif + break; + +#ifdef MODULE_NG_SIXLOWPAN_ND + case NG_SIXLOWPAN_ND_OPT_6CTX: + if (!ng_sixlowpan_nd_opt_6ctx_handle(rtr_adv->type, (ng_sixlowpan_nd_opt_6ctx_t *)opt, + byteorder_ntohs(rtr_adv->ltime))) { + /* invalid 6LoWPAN context option */ + return; + } + if (byteorder_ntohs(((ng_sixlowpan_nd_opt_6ctx_t *)opt)->ltime) < + (next_rtr_sol.seconds / 60)) { + next_rtr_sol.seconds = byteorder_ntohs(((ng_sixlowpan_nd_opt_6ctx_t *)opt)->ltime) * 60; + } break; +#endif default: /* silently discard all other options */ @@ -305,21 +445,43 @@ void ng_ndp_rtr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, sicmpv6_size -= (opt->len * 8); } + /* stop multicast router solicitation retransmission timer */ + vtimer_remove(&if_entry->rtr_sol_timer); +#ifdef MODULE_NG_SIXLOWPAN_ND +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + if (abr_opt) { + ng_sixlowpan_nd_rtr_opt_abr_handle(iface, rtr_adv, icmpv6_size, abr_opt); + if (byteorder_ntohs(abr_opt->ltime) < + (next_rtr_sol.seconds / 60)) { + next_rtr_sol.seconds = byteorder_ntohs(abr_opt->ltime) * 60; + } + } +#endif + /* 3/4 of the time should be "well before" enough the respective timeout + * not to run out; see https://tools.ietf.org/html/rfc6775#section-5.4.3 */ + next_rtr_sol.seconds *= 3; + next_rtr_sol.seconds >>= 2; + vtimer_remove(&nc_entry->rtr_sol_timer); + vtimer_set_msg(&nc_entry->rtr_sol_timer, next_rtr_sol, ng_ipv6_pid, + NG_SIXLOWPAN_ND_MSG_UC_RTR_SOL, nc_entry); +#endif + return; } -void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry) +void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry, ng_ipv6_addr_t *src) { if ((nc_entry->probes_remaining > 1) && ((ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) || (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_PROBE))) { ng_ipv6_addr_t dst; - DEBUG("ndp: Retransmit neighbor solicitation for %s\n", + DEBUG("ndp: Transmit neighbor solicitation for %s\n", ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str))); /* retransmit neighbor solicatation */ if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) { + /* should never be the case for 6LoWPAN networks */ ng_ipv6_addr_set_solicited_nodes(&dst, &nc_entry->ipv6_addr); } else { @@ -335,24 +497,74 @@ void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry) size_t ifnum = ng_netif_get(ifs); for (size_t i = 0; i < ifnum; i++) { - _ndp_send_nbr_sol(ifs[i], &nc_entry->ipv6_addr, &dst); + _ndp_send_nbr_sol(ifs[i], &nc_entry->ipv6_addr, NULL, &dst, NULL); } + vtimer_remove(&nc_entry->nbr_sol_timer); vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid, NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); } else { ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(nc_entry->iface); + ng_pktsnip_t *extra_opts = NULL; - _ndp_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, &dst); +#ifdef MODULE_NG_SIXLOWPAN_ND + if (ng_ipv6_netif_get(nc_entry->iface)->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN) { + extra_opts = ng_sixlowpan_nd_opt_ar_iface_build(nc_entry->iface, + 0, NULL); + } +#endif + + _ndp_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, src, &dst, extra_opts); mutex_lock(&ipv6_iface->mutex); + vtimer_remove(&nc_entry->nbr_sol_timer); vtimer_set_msg(&nc_entry->nbr_sol_timer, ipv6_iface->retrans_timer, ng_ipv6_pid, NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); mutex_unlock(&ipv6_iface->mutex); } } + +#ifdef MODULE_NG_SIXLOWPAN_ND + else if ((nc_entry->probes_remaining > 1) && + (ng_ipv6_netif_get(nc_entry->iface)->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN)) { + timex_t next_ns = { 60 * (NG_SIXLOWPAN_ND_REG_LTIME - 1), 0 }; + ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(nc_entry->iface); + ng_pktsnip_t *ar_opt = ng_sixlowpan_nd_opt_ar_iface_build( + nc_entry->iface, 0, NULL); + + if (ar_opt == NULL) { + DEBUG("ndp: could not optain long address from 6LoWPAN interface\n"); + } + + nc_entry->probes_remaining--; + + _ndp_send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, src, + &nc_entry->ipv6_addr, ar_opt); + + mutex_lock(&ipv6_iface->mutex); + vtimer_remove(&nc_entry->nbr_sol_timer); + vtimer_set_msg(&nc_entry->nbr_sol_timer, next_ns, + ng_ipv6_pid, NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); + mutex_unlock(&ipv6_iface->mutex); + } + +#endif +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + else if ((nc_entry->probes_remaining <= 1) && + (ng_ipv6_nc_get_type(nc_entry) == NG_IPV6_NC_TYPE_REGISTERED) && + (ng_ipv6_netif_get(nc_entry->iface)->flags & (NG_IPV6_NETIF_FLAGS_SIXLOWPAN)) && + (ng_ipv6_netif_get(nc_entry->iface)->flags & (NG_IPV6_NETIF_FLAGS_ROUTER))) { + /* see https://tools.ietf.org/html/rfc6775#section-6 */ + _ndp_set_state(nc_entry, NG_IPV6_NC_STATE_UNREACHABLE); + + while ((queue_node = ng_pktqueue_remove_head(&nc_entry->pkts))) { + ng_pktbuf_release(queue_node->data); + queue_node->data = NULL; + } + } +#endif else if (nc_entry->probes_remaining <= 1) { ng_pktqueue_node_t *queue_node; @@ -405,6 +617,9 @@ void ng_ndp_netif_add(ng_ipv6_netif_t *iface) timex_normalize(&iface->retrans_timer); #ifndef MODULE_NG_NDP_RTR iface->initial_phase = NG_NDP_INIT_RTR_ADV_NUMOF - 1; +#endif +#ifdef MODULE_NG_SIXLOWPAN_ND + iface->backoff_exp = 0; #endif mutex_unlock(&iface->mutex); @@ -454,6 +669,40 @@ static ng_ipv6_addr_t *_default_router(void) return &router->ipv6_addr; } + +static void _l2addr_resolution(uint8_t *l2addr, uint8_t *l2addr_len, + kernel_pid_t iface, ng_ipv6_addr_t *next_hop_ip, + ng_ipv6_nc_t *nc_entry) +{ + ng_ipv6_addr_t dst_sol; + + ng_ipv6_addr_set_solicited_nodes(&dst_sol, next_hop_ip); + + if (iface == KERNEL_PID_UNDEF) { + timex_t t = { 0, NG_NDP_RETRANS_TIMER }; + kernel_pid_t ifs[NG_NETIF_NUMOF]; + size_t ifnum = ng_netif_get(ifs); + + for (size_t i = 0; i < ifnum; i++) { + _ndp_send_nbr_sol(ifs[i], next_hop_ip, NULL, &dst_sol, NULL); + } + + vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid, + NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); + } + else { + ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(iface); + + _ndp_send_nbr_sol(iface, next_hop_ip, NULL, &dst_sol, NULL); + + mutex_lock(&ipv6_iface->mutex); + vtimer_set_msg(&nc_entry->nbr_sol_timer, + ipv6_iface->retrans_timer, ng_ipv6_pid, + NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); + mutex_unlock(&ipv6_iface->mutex); + } +} + kernel_pid_t ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, kernel_pid_t iface, ng_ipv6_addr_t *dst, ng_pktsnip_t *pkt) @@ -468,13 +717,27 @@ kernel_pid_t ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, uint32_t next_hop_flags = 0; if ((next_hop_ip == NULL) && ((fib_get_next_hop(&iface, (uint8_t *)next_hop_ip, &next_hop_size, - &next_hop_flags, (uint8_t *)dst, - sizeof(ng_ipv6_addr_t), 0) < 0) || - (next_hop_size != sizeof(ng_ipv6_addr_t)))) { + &next_hop_flags, (uint8_t *)dst, + sizeof(ng_ipv6_addr_t), 0) < 0) || + (next_hop_size != sizeof(ng_ipv6_addr_t)))) { next_hop_ip = NULL; } #endif +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + if (next_hop_ip == NULL) { + ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, dst); + ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(nc_entry->iface); + + if ((ipv6_iface->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN) && + (ipv6_iface->flags & NG_IPV6_NETIF_FLAGS_ROUTER) && + (ng_ipv6_nc_get_type(nc_entry) == NG_IPV6_NC_TYPE_REGISTERED)) { + /* see https://tools.ietf.org/html/rfc6775#section-6.5.4 */ + next_hop_ip = dst; + } + } +#endif + if (next_hop_ip == NULL) { /* no route to host */ if (iface == KERNEL_PID_UNDEF) { /* ng_ipv6_netif_t doubles as prefix list */ @@ -513,7 +776,6 @@ kernel_pid_t ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, } else if (nc_entry == NULL) { ng_pktqueue_node_t *pkt_node; - ng_ipv6_addr_t dst_sol; nc_entry = ng_ipv6_nc_add(iface, next_hop_ip, NULL, 0, NG_IPV6_NC_STATE_INCOMPLETE << NG_IPV6_NC_STATE_POS); @@ -535,31 +797,19 @@ kernel_pid_t ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, } /* address resolution */ - ng_ipv6_addr_set_solicited_nodes(&dst_sol, next_hop_ip); +#ifdef MODULE_NG_SIXLOWPAN_ND + ng_ipv6_netif_t *iface_entry = ng_ipv6_netif_get(iface); - if (iface == KERNEL_PID_UNDEF) { - timex_t t = { 0, NG_NDP_RETRANS_TIMER }; - kernel_pid_t ifs[NG_NETIF_NUMOF]; - size_t ifnum = ng_netif_get(ifs); - - for (size_t i = 0; i < ifnum; i++) { - _ndp_send_nbr_sol(ifs[i], next_hop_ip, &dst_sol); - } - - vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid, - NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); + if (iface_entry->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN) { + ng_sixlowpan_nd_l2addr_resolution(l2addr, l2addr_len, next_hop_ip); } else { - ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(iface); - - _ndp_send_nbr_sol(iface, next_hop_ip, &dst_sol); - - mutex_lock(&ipv6_iface->mutex); - vtimer_set_msg(&nc_entry->nbr_sol_timer, - ipv6_iface->retrans_timer, ng_ipv6_pid, - NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); - mutex_unlock(&ipv6_iface->mutex); + _l2addr_resolution(l2addr, l2addr_len, iface, next_hop_ip, + nc_entry); } +#else + _l2addr_resolution(l2addr, l2addr_len, iface, next_hop_ip, nc_entry); +#endif } } @@ -664,7 +914,8 @@ ng_pktsnip_t *ng_ndp_opt_build(uint8_t type, size_t size, ng_pktsnip_t *next) } static void _send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt, - ng_ipv6_addr_t *dst, bool supply_tl2a) + ng_ipv6_addr_t *dst, bool supply_tl2a, + ng_pktsnip_t *extra_opts) { ng_pktsnip_t *hdr, *pkt = NULL; uint8_t adv_flags = 0; @@ -705,6 +956,8 @@ static void _send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt, adv_flags |= NG_NDP_NBR_ADV_FLAGS_O; } + LL_PREPEND(pkt, extra_opts); + hdr = ng_ndp_nbr_adv_build(adv_flags, tgt, pkt); if (hdr == NULL) { @@ -901,7 +1154,7 @@ static bool _handle_tl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt, } static bool _handle_pi_opt(kernel_pid_t iface, uint8_t icmpv6_type, - ng_ndp_opt_pi_t *pi_opt) + ng_ndp_opt_pi_t *pi_opt, ng_ipv6_addr_t *rtr_addr) { ng_ipv6_addr_t *prefix; ng_ipv6_netif_addr_t *a; @@ -912,18 +1165,38 @@ static bool _handle_pi_opt(kernel_pid_t iface, uint8_t icmpv6_type, } if ((icmpv6_type != NG_ICMPV6_RTR_ADV) || - ng_ipv6_addr_is_link_local(&pi_opt->prefix)) { + ng_ipv6_addr_is_link_local(&pi_opt->prefix) || + (pi_opt->flags & NG_NDP_OPT_PI_FLAGS_A)) { /* discard silently */ + /* A-flag according to https://tools.ietf.org/html/rfc4862#section-5.5.3 */ return true; } +#ifdef MODULE_NG_SIXLOWPAN_ND + if ((ng_ipv6_netif_get(iface)->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN) && + (pi_opt->flags & NG_NDP_OPT_PI_FLAGS_L)) { + /* see https://tools.ietf.org/html/rfc6775#section-5.4 */ + DEBUG("ndp: prefix can't be on-link for a LoWPAN, ignoring prefix option\n"); + return true; + } +#endif + prefix = ng_ipv6_netif_find_addr(iface, &pi_opt->prefix); if (((prefix == NULL) || (ng_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) && (pi_opt->valid_ltime.u32 != 0)) { - prefix = ng_ipv6_netif_add_addr(iface, &pi_opt->prefix, - pi_opt->prefix_len, + ng_ipv6_addr_t addr = NG_IPV6_ADDR_UNSPECIFIED; + + if (ng_netapi_get(iface, NETCONF_OPT_IPV6_IID, 0, &addr.u64[1], + sizeof(uint64_t)) < 0) { + DEBUG("ndp: can not obtain IID from interface %" PRIkernel_pid "\n", + iface); + } + + ng_ipv6_addr_init_prefix(&addr, &pi_opt->prefix, pi_opt->prefix_len); + + prefix = ng_ipv6_netif_add_addr(iface, &addr, pi_opt->prefix_len, pi_opt->flags & NG_NDP_OPT_PI_FLAGS_MASK); if (prefix == NULL) { @@ -950,7 +1223,7 @@ static bool _handle_pi_opt(kernel_pid_t iface, uint8_t icmpv6_type, if (a->valid != UINT32_MAX) { vtimer_set_msg(&a->valid_timeout, timex_set(byteorder_ntohl(pi_opt->valid_ltime), 0), - thread_getpid(), NG_NDP_MSG_ADDR_TIMEOUT, &a->addr); + ng_ipv6_pid, NG_NDP_MSG_ADDR_TIMEOUT, &a->addr); } /* TODO: preferred lifetime for address auto configuration */ diff --git a/sys/net/network_layer/ng_ndp/rtr/ng_ndp_rtr.c b/sys/net/network_layer/ng_ndp/rtr/ng_ndp_rtr.c index 23a7e30013083..8e87f768bdfc6 100644 --- a/sys/net/network_layer/ng_ndp/rtr/ng_ndp_rtr.c +++ b/sys/net/network_layer/ng_ndp/rtr/ng_ndp_rtr.c @@ -14,6 +14,7 @@ #include +#include "bitfield.h" #include "kernel_types.h" #include "net/ng_ipv6.h" #include "net/ng_ipv6/addr.h" @@ -25,6 +26,8 @@ #include "net/ng_netconf.h" #include "net/ng_netif/hdr.h" #include "net/ng_pkt.h" +#include "net/ng_sixlowpan/ctx.h" +#include "net/ng_sixlowpan/nd/rtr.h" #include "../common.h" @@ -325,6 +328,9 @@ static ng_pktsnip_t *_iface_rtr_adv_build(ng_ipv6_netif_t *iface, bool final) uint8_t cur_hl = 0, l2addr[NG_IPV6_NC_L2_ADDR_MAX]; uint16_t adv_ltime = 0, l2addr_len; uint32_t reach_time = 0, retrans_timer = 0; +#ifdef MODULE_NG_SIXLOWPAN_RTR + ng_sixlowpan_nd_rtr_abr_t *abr = ng_sixlowpan_nd_rtr_abr_get(); +#endif mutex_lock(&iface->mutex); @@ -381,6 +387,84 @@ static ng_pktsnip_t *_iface_rtr_adv_build(ng_ipv6_netif_t *iface, bool final) } } +#ifdef MODULE_NG_SIXLOWPAN_RTR + + if ((abr != NULL) && (iface->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN)) { + ng_ipv6_addr_t *prefix = abr->prefixes; + + pkt = opt; + + if ((opt = ng_sixlowpan_nd_rtr_abr_opt_build(abr->version, abr->ltime, + &abr->addr, pkt))) { + DEBUG("ndp rtr: no space left in packet buffer\n"); + mutex_unlock(&iface->mutex); + ng_pktbuf_release(pkt); + return NULL; + } + + while (prefix != NULL) { + ng_ipv6_netif_addr_t *addr = ng_ipv6_netif_get_addr(prefix); + + pkt = opt; + + if ((opt = ng_ndp_rtr_opt_pi_build(addr->prefix_len, + (addr->flags & + (NG_IPV6_NETIF_ADDR_FLAGS_NDP_AUTO)), + addr->valid, + addr->preferred, + &addr->addr, pkt)) == NULL) { + DEBUG("ndp rtr: no space left in packet buffer\n"); + mutex_unlock(&iface->mutex); + ng_pktbuf_release(pkt); + return NULL; + } + + prefix = prefix->next; + } + + for (int i = 0; i < NG_SIXLOWPAN_CTX_SIZE; i++) { + if (bf_isset(abr->contexts, i)) { + ng_sixlowpan_ctx_t *ctx = ng_sixlowpan_ctx_lookup_id(i); + + pkt = opt; + + if ((opt = ng_sixlowpan_nd_rtr_6ctx_opt_build( + ctx->prefix_len, ctx->flags_id, + ctx->ltime, &ctx->prefix, pkt))) { + DEBUG("ndp rtr: no space left in packet buffer\n"); + mutex_unlock(&iface->mutex); + ng_pktbuf_release(pkt); + return NULL; + } + } + } + } + else { + for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { + ng_ipv6_netif_addr_t *addr = &iface->addrs[i]; + + pkt = opt; + + if (((addr->prefix_len - 1) > 127) && /* prefix_len < 1 || > 128 */ + !ng_ipv6_addr_is_unspecified(&addr->addr) && + !ng_ipv6_addr_is_link_local(&addr->addr) && + !ng_ipv6_netif_addr_is_non_unicast(&addr->addr)) { + if ((opt = ng_ndp_rtr_opt_pi_build(addr->prefix_len, + (addr->flags & + (NG_IPV6_NETIF_ADDR_FLAGS_NDP_AUTO | + NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK)), + addr->valid, + addr->preferred, + &addr->addr, pkt)) == NULL) { + DEBUG("ndp rtr: no space left in packet buffer\n"); + mutex_unlock(&iface->mutex); + ng_pktbuf_release(pkt); + return NULL; + } + } + } + } +#else /* MODULE_NG_SIXLOWPAN_RTR */ for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { ng_ipv6_netif_addr_t *addr = &iface->addrs[i]; @@ -404,6 +488,7 @@ static ng_pktsnip_t *_iface_rtr_adv_build(ng_ipv6_netif_t *iface, bool final) } } } +#endif /* MODULE_NG_SIXLOWPAN_RTR */ pkt = ng_ndp_rtr_rtr_adv_build(cur_hl, (iface->flags & (NG_IPV6_NETIF_FLAGS_OTHER_CONF | diff --git a/sys/net/network_layer/ng_sixlowpan/ctx/ng_sixlowpan_ctx.c b/sys/net/network_layer/ng_sixlowpan/ctx/ng_sixlowpan_ctx.c index 5f7cf765d8108..3ba6c2c1094b1 100644 --- a/sys/net/network_layer/ng_sixlowpan/ctx/ng_sixlowpan_ctx.c +++ b/sys/net/network_layer/ng_sixlowpan/ctx/ng_sixlowpan_ctx.c @@ -105,7 +105,8 @@ ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_update(uint8_t id, const ng_ipv6_addr_t *pr _ctxs[id].ltime = ltime; if (ltime == 0) { - comp = false; + ng_sixlowpan_ctx_remove(id); + return NULL; } if (prefix_len > NG_IPV6_ADDR_BIT_LEN) { @@ -129,6 +130,10 @@ ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_update(uint8_t id, const ng_ipv6_addr_t *pr mutex_unlock(&_ctx_mutex); +#ifdef MODULE_NG_SIXLOWPAN_ND_BR + ng_sixlowpan_nd_rtr_abr_inc_version(ng_sixlowpan_nd_rtr_abr_get()); +#endif + return &(_ctxs[id]); } diff --git a/sys/net/network_layer/ng_sixlowpan/nd/Makefile b/sys/net/network_layer/ng_sixlowpan/nd/Makefile new file mode 100644 index 0000000000000..6069c326bd72b --- /dev/null +++ b/sys/net/network_layer/ng_sixlowpan/nd/Makefile @@ -0,0 +1,3 @@ +MODULE = ng_sixlowpan_nd + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ng_sixlowpan/nd/ng_sixlowpan_nd.c b/sys/net/network_layer/ng_sixlowpan/nd/ng_sixlowpan_nd.c new file mode 100644 index 0000000000000..a26cb7dd9e8e6 --- /dev/null +++ b/sys/net/network_layer/ng_sixlowpan/nd/ng_sixlowpan_nd.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + */ + +#include + +#include "byteorder.h" +#include "random.h" +#include "net/eui64.h" +#include "net/ng_icmpv6/types.h" +#include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6.h" +#include "net/ng_ndp.h" +#include "net/ng_sixlowpan.h" +#include "net/ng_sixlowpan/ctx.h" +#include "vtimer.h" + +#include "net/ng_sixlowpan/nd.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +uint32_t ng_sixlowpan_nd_beb(uint32_t base_sec, uint8_t exp) +{ + uint32_t k; + + k = genrand_uint32() % ((1 << exp) - 1); + + return k * base_sec; +} + +void ng_sixlowpan_nd_l2addr_resolution(uint8_t *l2addr, uint8_t *l2addr_len, + ng_ipv6_addr_t *next_hop_ip) +{ + if (ng_ipv6_addr_is_link_local(next_hop_ip)) { + /* link-local addresses are assumed to be generated from EUI-64 + * see https://tools.ietf.org/html/rfc6775#section-5.6 */ + memcpy(l2addr, &next_hop_ip->u64[1], sizeof(eui64_t)); + l2addr[0] ^= 0x02; + *l2addr_len = 8; + } + else { + *l2addr_len = 0; + } +} + +bool ng_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, + ng_sixlowpan_nd_opt_6ctx_t *ctx_opt, + uint16_t rtr_ltime) +{ + if (((ctx_opt->ctx_len < 64) && (ctx_opt->len != 2)) || + ((ctx_opt->ctx_len >= 64) && (ctx_opt->len != 3))) { + DEBUG("6lo nd: invalid 6LoWPAN context option received\n"); + return false; + } + + if (icmpv6_type != NG_ICMPV6_RTR_ADV) { + /* discard silently */ + return true; + } + +#ifdef MODULE_NG_SIXLOWPAN_CTX + timex_t t = { (byteorder_ntohs(ctx_opt->ltime) * 60) + (2 * rtr_ltime) }; + ng_sixlowpan_ctx_t *ctx = ng_sixlowpan_ctx_update(ng_sixlowpan_nd_opt_6ctx_get_cid(ctx_opt), + (ng_ipv6_addr_t *)(ctx_opt + 1), ctx_opt->ctx_len, byteorder_ntohs(ctx_opt->ltime), + ng_sixlowpan_nd_opt_6ctx_is_comp(ctx_opt)); + + vtimer_remove(&ctx->delete_timer); + vtimer_set_msg(&ctx->delete_timer, t, ng_sixlowpan_pid, NG_SIXLOWPAN_MSG_DELETE_CTX, + ctx); +#endif + + return true; +} + +uint8_t ng_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ng_ipv6_hdr_t *ipv6, + uint8_t icmpv6_type, + ng_sixlowpan_nd_opt_ar_t *ar_opt, + ng_ndp_opt_t *sl2a_opt) +{ + eui64_t eui64; + ng_ipv6_netif_t *ipv6_iface; + ng_ipv6_nc_t *nc_entry; +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + uint8_t status = 0; + uint8_t sl2a_len = 0; + uint8_t *sl2a = (uint8_t *)(sl2a_opt + 1); +#endif + + if (ar_opt->len != NG_SIXLOWPAN_ND_OPT_AR_LEN) { + /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ + return 0; + } + + if (ng_netapi_get(iface, NETCONF_OPT_ADDRESS_LONG, 0, &eui64, + sizeof(eui64)) < 0) { + /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ + return 0; + } + + if (eui64.uint64.u64 != ar_opt->eui64.uint64.u64) { + /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ + return 0; + } + + ipv6_iface = ng_ipv6_netif_get(iface); + nc_entry = ng_ipv6_nc_get(iface, &ipv6->src); + + switch (icmpv6_type) { + case NG_ICMPV6_NBR_ADV: + if (!(ipv6_iface->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN)) { + DEBUG("6lo nd: interface not a 6LoWPAN interface\n"); + return 0; + } + + switch (ar_opt->status) { + case NG_SIXLOWPAN_ND_STATUS_SUCCESS: + DEBUG("6lo nd: address registration successful\n"); + mutex_lock(&ipv6_iface->mutex); + vtimer_remove(&nc_entry->nbr_sol_timer); + vtimer_set_msg(&nc_entry->nbr_sol_timer, ipv6_iface->retrans_timer, + ng_ipv6_pid, NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); + mutex_unlock(&ipv6_iface->mutex); + break; + + case NG_SIXLOWPAN_ND_STATUS_DUP: + DEBUG("6lo nd: address registration determined duplicated\n"); + /* TODO: DAD failed */ + ng_ipv6_netif_remove_addr(iface, &ipv6->dst); + /* address should not be used anymore */ + break; + + case NG_SIXLOWPAN_ND_STATUS_NC_FULL: + DEBUG("6lo nd: neighbor cache on router is full\n"); + ng_ipv6_nc_remove(iface, &ipv6->src); + break; + + default: + DEBUG("6lo nd: unknown status for registration received\n"); + break; + } + +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + case NG_ICMPV6_NBR_SOL: + if (!(ipv6_iface->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN) && + !(ipv6_iface->flags & NG_IPV6_NETIF_FLAGS_ROUTER)) { + DEBUG("6lo nd: interface not a 6LoWPAN or forwarding interface\n"); + return 0; + } + if ((ar_opt->status != 0) || + (sl2a_opt == NULL) || + ng_ipv6_addr_is_unspecified(&ipv6->src)) { + /* discard silently */ + return 0; + } + + /* TODO multihop DAD */ + if ((nc_entry != NULL) && + ((ng_ipv6_nc_get_type(nc_entry) == NG_IPV6_NC_TYPE_REGISTERED) || + (ng_ipv6_nc_get_type(nc_entry) == NG_IPV6_NC_TYPE_TENTATIVE)) && + (ar_opt->eui64.uint64.u64 != nc_entry->eui64.uint64.u64)) { + /* there is already another node with this address */ + DEBUG("6lo nd: duplicate address detected\n"); + status = NG_SIXLOWPAN_ND_STATUS_DUP; + } + else if ((nc_entry != NULL) && (ar_opt->ltime.u16 == 0)) { + ng_ipv6_nc_remove(iface, &ipv6->src); + /* TODO, notify routing protocol */ + } + else if (ar_opt->ltime.u16 != 0) { + /* TODO: multihop DAD behavior */ + if (nc_entry == NULL) { + if ((nc_entry = ng_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len, + NG_IPV6_NC_STATE_STALE)) == NULL) { + DEBUG("6lo nd: neighbor cache is full\n"); + status = NG_SIXLOWPAN_ND_STATUS_NC_FULL; + } + + nc_entry->eui64 = ar_opt->eui64; + } + + nc_entry->flags &= ~NG_IPV6_NC_TYPE_MASK; + nc_entry->flags |= NG_IPV6_NC_TYPE_REGISTERED; + nc_entry->reg_ltime = byteorder_ntohs(ar_opt->ltime); + + /* TODO: notify routing protocol */ + + vtimer_remove(&nc_entry->type_timeout); + vtimer_set_msg(&nc_entry->type_timeout, + timex_set(nc_entry->reg_ltime * 60, 0), + ng_ipv6_pid, NG_SIXLOWPAN_ND_RTR_MSG_AR_TIMEOUT, nc_entry); + } + +#endif + + default: + break; + } + +#ifdef MODULE_NG_SIXLOWPAN_ND_RTR + return status; +#else + return 0; +#endif +} + +ng_pktsnip_t *ng_sixlowpan_nd_opt_ar_build(uint8_t status, uint16_t ltime, + eui64_t *eui64, + ng_pktsnip_t *next) +{ + ng_pktsnip_t *pkt = ng_ndp_opt_build(NG_SIXLOWPAN_ND_OPT_AR, + sizeof(ng_sixlowpan_nd_opt_ar_t), + next); + + if (pkt != NULL) { + ng_sixlowpan_nd_opt_ar_t *ar_opt = pkt->data; + ar_opt->status = status; + ar_opt->resv[0] = ar_opt->resv[1] = ar_opt->resv[2] = 0; + ar_opt->ltime = byteorder_htons(ltime); + memcpy(&ar_opt->eui64, eui64, sizeof(eui64_t)); + } + + return pkt; +} + +/** @} */ diff --git a/sys/net/network_layer/ng_sixlowpan/nd/rtr/Makefile b/sys/net/network_layer/ng_sixlowpan/nd/rtr/Makefile new file mode 100644 index 0000000000000..68a8bc77a995e --- /dev/null +++ b/sys/net/network_layer/ng_sixlowpan/nd/rtr/Makefile @@ -0,0 +1,3 @@ +MODULE = ng_sixlowpan_nd_rtr + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ng_sixlowpan/nd/rtr/ng_sixlowpan_nd_rtr.c b/sys/net/network_layer/ng_sixlowpan/nd/rtr/ng_sixlowpan_nd_rtr.c new file mode 100644 index 0000000000000..882e43bfdb18e --- /dev/null +++ b/sys/net/network_layer/ng_sixlowpan/nd/rtr/ng_sixlowpan_nd_rtr.c @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + */ + +#include "bitfield.h" +#include "byteorder.h" +#include "net/ng_icmpv6/types.h" +#include "net/ng_ipv6.h" +#include "net/ng_ipv6/netif.h" +#include "net/ng_ndp.h" +#include "net/ng_sixlowpan/nd/types.h" +#include "net/ng_sixlowpan/ctx.h" +#include "utlist.h" +#include "vtimer.h" + +#include "net/ng_sixlowpan/nd/rtr.h" + +static ng_sixlowpan_nd_rtr_abr_t _abrs[NG_SIXLOWPAN_ND_RTR_ABR_NUMOF]; +static ng_sixlowpan_nd_rtr_abr_prf_t _prefixes[NG_SIXLOWPAN_ND_RTR_ABR_PRF_NUMOF]; + +static ng_sixlowpan_nd_rtr_abr_t *_get_abr(ng_ipv6_addr_t *addr) +{ + ng_sixlowpan_nd_rtr_abr_t *abr = NULL; + + for (int i = 0; i < NG_SIXLOWPAN_ND_RTR_ABR_NUMOF; i++) { + if (ng_ipv6_addr_equal(&_abrs[i].addr, addr)) { + return &_abrs[i]; + } + + if ((abr == NULL) && ng_ipv6_addr_is_unspecified(&_abrs[i].addr)) { + abr = &_abrs[i]; + } + } + + return abr; +} + +static ng_sixlowpan_nd_rtr_abr_prf_t *_get_prefix(ng_ipv6_addr_t *prefix, + size_t prefix_len) +{ + ng_sixlowpan_nd_rtr_abr_prf_t *prf = NULL; + + for (int i = 0; i < NG_SIXLOWPAN_ND_RTR_ABR_NUMOF; i++) { + if (ng_ipv6_addr_equal(_prefixes[i].prefix, prefix) && + (_prefixes[i].prefix_len == prefix_len)) { + return NULL; + } + + if ((prf == NULL) && ng_ipv6_addr_is_unspecified(_prefixes[i].prefix)) { + prf = &_prefixes[i]; + } + } + + return prf; +} + +static void _add_prefix(kernel_pid_t iface, ng_sixlowpan_nd_rtr_abr_t *abr, + ng_ndp_opt_pi_t *pi_opt) +{ + ng_sixlowpan_nd_rtr_abr_prf_t *prf_ent; + ng_ipv6_addr_t *prefix; + + if ((pi_opt->len != NG_NDP_OPT_PI_LEN) || + ng_ipv6_addr_is_link_local(&pi_opt->prefix) || + (pi_opt->flags & NG_NDP_OPT_PI_FLAGS_A) || + (pi_opt->flags & NG_NDP_OPT_PI_FLAGS_L) || + (pi_opt->valid_ltime.u32 == 0)) { + return; + } + + prefix = ng_ipv6_netif_find_addr(iface, &pi_opt->prefix); + + prf_ent = _get_prefix(&pi_opt->prefix, pi_opt->prefix_len); + + if (prf_ent != NULL) { + prf_ent->iface = iface; + prf_ent->prefix = prefix; + prf_ent->prefix_len = pi_opt->prefix_len; + LL_PREPEND(abr->prefixes, prf_ent); + } +} + +static void _add_ctx(ng_sixlowpan_nd_rtr_abr_t *abr, + ng_sixlowpan_nd_opt_6ctx_t *ctx_opt) +{ + if (((ctx_opt->ctx_len < 64) && (ctx_opt->len != 2)) || + ((ctx_opt->ctx_len >= 64) && (ctx_opt->len != 3))) { + return; + } + + bf_set(abr->contexts, ng_sixlowpan_nd_opt_6ctx_get_cid(ctx_opt)); +} + +void ng_sixlowpan_nd_rtr_opt_abr_handle(kernel_pid_t iface, ng_ndp_rtr_adv_t *rtr_adv, + int sicmpv6_size, ng_sixlowpan_nd_opt_abr_t *abr_opt) +{ + uint32_t version; + uint16_t opt_offset = 0; + uint8_t *buf = (uint8_t *)(rtr_adv + 1); + ng_sixlowpan_nd_rtr_abr_t *abr; + timex_t t = { 0, 0 }; + + /* validity and version was checked in previously called + * ng_sixlowpan_nd_rtr_abr_older() */ + + abr = _get_abr(&abr_opt->braddr); + + if (abr == NULL) { + return; + } + + abr->ltime = byteorder_ntohs(abr_opt->ltime); + + if (abr->ltime == 0) { + ng_sixlowpan_nd_rtr_abr_remove(abr); + return; + } + + sicmpv6_size -= sizeof(ng_ndp_rtr_adv_t); + + while (sicmpv6_size > 0) { + ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset); + + switch (opt->type) { + case NG_NDP_OPT_PI: + _add_prefix(iface, abr, (ng_ndp_opt_pi_t *)opt); + + case NG_SIXLOWPAN_ND_OPT_6CTX: + _add_ctx(abr, (ng_sixlowpan_nd_opt_6ctx_t *)opt); + + default: + break; + } + + opt_offset += (opt->len * 8); + sicmpv6_size -= (opt->len * 8); + } + + abr->version = byteorder_ntohs(abr_opt->vlow); + abr->version |= byteorder_ntohs(abr_opt->vhigh) << 16; + abr->addr.u64[0] = abr_opt->braddr.u64[0]; + abr->addr.u64[1] = abr_opt->braddr.u64[1]; + + t.seconds = abr->ltime * 60; + + vtimer_set_msg(&abr->ltimer, t, ng_ipv6_pid, + NG_SIXLOWPAN_ND_RTR_MSG_ABR_TIMEOUT, abr); +} + +ng_sixlowpan_nd_rtr_abr_t *ng_sixlowpan_nd_rtr_abr_get(void) +{ + return _abrs; +} + +bool ng_sixlowpan_nd_rtr_abr_older(ng_sixlowpan_nd_opt_abr_t *abr_opt) +{ + ng_sixlowpan_nd_rtr_abr_t *abr; + uint32_t version; + + if (abr_opt->len != NG_SIXLOWPAN_ND_OPT_ABR_LEN) { + /* invalid option received */ + return true; + } + + abr = _get_abr(&abr_opt->braddr); + + if (abr == NULL) { + return false; + } + + version = byteorder_ntohs(abr_opt->vlow); + version |= byteorder_ntohs(abr_opt->vhigh) << 16; + + return (version < abr->version); +} + +void ng_sixlowpan_nd_rtr_abr_remove(ng_sixlowpan_nd_rtr_abr_t *abr) +{ + ng_sixlowpan_nd_rtr_abr_prf_t *prefix = abr->prefixes; + + ng_ipv6_addr_set_unspecified(&abr->addr); + abr->version = 0; + + for (int i = 0; i < NG_SIXLOWPAN_CTX_SIZE; i++) { + if (bf_isset(abr->contexts, i)) { + ng_sixlowpan_ctx_remove(i); + bf_unset(abr->contexts, i); + } + } + + while (prefix != NULL) { + LL_DELETE(abr->prefixes, prefix); + ng_ipv6_netif_remove_addr(prefix->iface, prefix->prefix); + prefix->next = NULL; + prefix->prefix = NULL; + } +} + +ng_pktsnip_t *ng_sixlowpan_nd_rtr_6ctx_opt_build(uint8_t prefix_len, uint8_t flags, + uint16_t ltime, ng_ipv6_addr_t *prefix, + ng_pktsnip_t *next) +{ + ng_pktsnip_t *pkt = ng_ndp_opt_build(NG_SIXLOWPAN_ND_OPT_6CTX, + sizeof(ng_sixlowpan_nd_opt_6ctx_t) + + (prefix_len / 8), next); + + if (pkt != NULL) { + ng_sixlowpan_nd_opt_6ctx_t *ctx_opt = pkt->data; + + ctx_opt->ctx_len = prefix_len; + ctx_opt->resv_c_cid = (flags & (NG_SIXLOWPAN_CTX_FLAGS_CID_MASK | + NG_SIXLOWPAN_CTX_FLAGS_COMP)); + ctx_opt->resv.u16 = 0; + ctx_opt->ltime = byteorder_htons(ltime); + /* Bits beyond prefix_len MUST be 0 */ + memset(ctx_opt + 1, 0, pkt->size - sizeof(ng_sixlowpan_nd_opt_6ctx_t)); + ng_ipv6_addr_init_prefix((ng_ipv6_addr_t *)(ctx_opt + 1), prefix, + prefix_len); + } + + return pkt; +} + +ng_pktsnip_t *ng_sixlowpan_nd_rtr_abr_opt_build(uint32_t version, uint16_t ltime, + ng_ipv6_addr_t *braddr, + ng_pktsnip_t *next) +{ + ng_pktsnip_t *pkt = ng_ndp_opt_build(NG_SIXLOWPAN_ND_OPT_ABR, + sizeof(ng_sixlowpan_nd_opt_abr_t), + next); + + if (pkt != NULL) { + ng_sixlowpan_nd_opt_abr_t *abr_opt = pkt->data; + + abr_opt->vlow = byteorder_htons(version & 0xffff); + abr_opt->vhigh = byteorder_htons(version >> 16); + abr_opt->ltime = byteorder_htons(ltime); + abr_opt->braddr.u64[0] = braddr->u64[0]; + abr_opt->braddr.u64[1] = braddr->u64[1]; + } + + return pkt; +} + +/** @} */ diff --git a/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c b/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c index 5e244c8126074..4456ed4d80704 100644 --- a/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c +++ b/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c @@ -18,6 +18,7 @@ #include "utlist.h" #include "net/ng_sixlowpan.h" +#include "net/ng_sixlowpan/ctx.h" #include "net/ng_sixlowpan/frag.h" #include "net/ng_sixlowpan/iphc.h" #include "net/ng_sixlowpan/netif.h" @@ -25,7 +26,7 @@ #define ENABLE_DEBUG (0) #include "debug.h" -static kernel_pid_t _pid = KERNEL_PID_UNDEF; +kernel_pid_t ng_sixlowpan_pid = KERNEL_PID_UNDEF; #if ENABLE_DEBUG static char _stack[NG_SIXLOWPAN_STACK_SIZE + THREAD_EXTRA_STACKSIZE_PRINTF]; @@ -43,14 +44,14 @@ static void *_event_loop(void *args); kernel_pid_t ng_sixlowpan_init(void) { - if (_pid > KERNEL_PID_UNDEF) { - return _pid; + if (ng_sixlowpan_pid > KERNEL_PID_UNDEF) { + return ng_sixlowpan_pid; } - _pid = thread_create(_stack, sizeof(_stack), NG_SIXLOWPAN_PRIO, + ng_sixlowpan_pid = thread_create(_stack, sizeof(_stack), NG_SIXLOWPAN_PRIO, CREATE_STACKTEST, _event_loop, NULL, "6lo"); - return _pid; + return ng_sixlowpan_pid; } void _receive(ng_pktsnip_t *pkt) @@ -271,6 +272,14 @@ void _send(ng_pktsnip_t *pkt) #endif } +#ifdef MODULE_NG_SIXLOWPAN_CTX +static inline void _delete_ctx(ng_sixlowpan_ctx_t *ctx) +{ + DEBUG("6lo: remove context %" PRIu8 "\n", ctx->flags_id & NG_SIXLOWPAN_CTX_FLAGS_CID_MASK); + ng_sixlowpan_ctx_remove(ctx->flags_id & NG_SIXLOWPAN_CTX_FLAGS_CID_MASK); +} +#endif + static void *_event_loop(void *args) { msg_t msg, reply, msg_q[NG_SIXLOWPAN_MSG_QUEUE_SIZE]; @@ -311,6 +320,11 @@ static void *_event_loop(void *args) msg_reply(&msg, &reply); break; +#ifdef MODULE_NG_SIXLOWPAN_CTX + case NG_SIXLOWPAN_MSG_DELETE_CTX: + _delete_ctx((ng_sixlowpan_ctx_t *)msg.content.ptr); +#endif + default: DEBUG("6lo: operation not supported\n"); break;