mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
Merge pull request #3050 from cgundogan/ng_rpl_fib
ng_rpl: port to the new network stack
This commit is contained in:
commit
e3edf34527
10
Makefile.dep
10
Makefile.dep
@ -258,3 +258,13 @@ endif
|
||||
ifneq (,$(filter hih6130,$(USEMODULE)))
|
||||
USEMODULE += vtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ng_rpl,$(USEMODULE)))
|
||||
USEMODULE += timex
|
||||
USEMODULE += vtimer
|
||||
USEMODULE += ng_ipv6_router_default
|
||||
USEMODULE += trickle
|
||||
USEMODULE += net_help
|
||||
USEMODULE += universal_address
|
||||
USEMODULE += fib
|
||||
endif
|
||||
|
@ -12,7 +12,7 @@ BOARD_INSUFFICIENT_RAM := airfy-beacon chronos msb-430 msb-430h nrf51dongle \
|
||||
stm32f0discovery telosb wsn430-v1_3b wsn430-v1_4 \
|
||||
yunjia-nrf51822 z1
|
||||
|
||||
BOARD_BLACKLIST := arduino-mega2560
|
||||
BOARD_BLACKLIST := arduino-mega2560 spark-core
|
||||
# arduino-mega2560: unknown error types (e.g. -EBADMSG)
|
||||
|
||||
# Include packages that pull up and auto-init the link layer.
|
||||
@ -22,11 +22,12 @@ USEMODULE += auto_init_ng_netif
|
||||
# Specify the mandatory networking modules for IPv6 and UDP
|
||||
USEMODULE += ng_ipv6_router_default
|
||||
USEMODULE += ng_udp
|
||||
# Add a routing protocol
|
||||
USEMODULE += ng_rpl
|
||||
# This application dumps received packets to STDIO using the pktdump module
|
||||
USEMODULE += ng_pktdump
|
||||
# Additional networking modules that can be dropped if not needed
|
||||
USEMODULE += ng_icmpv6_echo
|
||||
USEMODULE += fib
|
||||
# Add also the shell, some shell commands (which are based on uart0 in this app)
|
||||
USEMODULE += uart0
|
||||
USEMODULE += shell
|
||||
|
@ -88,6 +88,9 @@ endif
|
||||
ifneq (,$(filter ng_zep,$(USEMODULE)))
|
||||
DIRS += net/application_layer/ng_zep
|
||||
endif
|
||||
ifneq (,$(filter ng_rpl,$(USEMODULE)))
|
||||
DIRS += net/routing/ng_rpl
|
||||
endif
|
||||
ifneq (,$(filter ng_rpl_srh,$(USEMODULE)))
|
||||
DIRS += net/routing/ng_rpl/srh
|
||||
endif
|
||||
|
@ -42,9 +42,9 @@ extern "C" {
|
||||
*/
|
||||
#ifndef NG_IPV6_NETIF_ADDR_NUMOF
|
||||
#ifdef MODULE_NG_IPV6_ROUTER
|
||||
#define NG_IPV6_NETIF_ADDR_NUMOF (7) /* router needs all-routers multicast address */
|
||||
#define NG_IPV6_NETIF_ADDR_NUMOF (8) /* router needs all-routers multicast address */
|
||||
#else
|
||||
#define NG_IPV6_NETIF_ADDR_NUMOF (6)
|
||||
#define NG_IPV6_NETIF_ADDR_NUMOF (7)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2013 - 2014 INRIA.
|
||||
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*
|
||||
* 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
|
||||
@ -7,27 +9,414 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_ng_rpl New RPL
|
||||
* @defgroup net_ng_rpl RPL
|
||||
* @ingroup net
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief TODO
|
||||
* @brief RPL header. Declaration of global variables and functions needed for
|
||||
* core functionality of RPL.
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
* Header which includes all core RPL-functions.
|
||||
*
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @author Fabian Brandt <fabianbr@zedat.fu-berlin.de>
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef NG_RPL_H_
|
||||
#define NG_RPL_H_
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "net/ng_ipv6.h"
|
||||
#include "net/ng_icmpv6.h"
|
||||
#include "net/ng_nettype.h"
|
||||
#include "net/ng_rpl/structs.h"
|
||||
#include "net/ng_rpl/dodag.h"
|
||||
#include "net/ng_rpl/of_manager.h"
|
||||
#include "inet_ntop.h"
|
||||
#include "net/fib.h"
|
||||
#include "vtimer.h"
|
||||
#include "trickle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default stack size to use for the IPv6 thread
|
||||
*/
|
||||
#ifndef NG_RPL_STACK_SIZE
|
||||
#define NG_RPL_STACK_SIZE (THREAD_STACKSIZE_DEFAULT)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default priority for the RPL thread
|
||||
*/
|
||||
#ifndef NG_RPL_PRIO
|
||||
#define NG_RPL_PRIO (THREAD_PRIORITY_MAIN - 4)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default message queue size to use for the RPL thread.
|
||||
*/
|
||||
#ifndef NG_RPL_MSG_QUEUE_SIZE
|
||||
#define NG_RPL_MSG_QUEUE_SIZE (8U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Static initializer for the all-RPL-nodes multicast IPv6
|
||||
* address (ff02::1a)
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
|
||||
* RFC 6550, section 6
|
||||
* </a>
|
||||
*/
|
||||
#define NG_IPV6_ADDR_ALL_RPL_NODES {{ 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1a }}
|
||||
|
||||
/**
|
||||
* @brief Message type for lifetime updates
|
||||
*/
|
||||
#define NG_RPL_MSG_TYPE_LIFETIME_UPDATE (0x0900)
|
||||
|
||||
/**
|
||||
* @brief Message type for trickle intervals
|
||||
*/
|
||||
#define NG_RPL_MSG_TYPE_TRICKLE_INTERVAL (0x0901)
|
||||
|
||||
/**
|
||||
* @brief Message type for trickle callbacks
|
||||
*/
|
||||
#define NG_RPL_MSG_TYPE_TRICKLE_CALLBACK (0x0902)
|
||||
|
||||
/**
|
||||
* @brief Message type for handling DAO sending
|
||||
*/
|
||||
#define NG_RPL_MSG_TYPE_DAO_HANDLE (0x0903)
|
||||
|
||||
/**
|
||||
* @brief Message type for handling DODAG cleanup
|
||||
*/
|
||||
#define NG_RPL_MSG_TYPE_CLEANUP_HANDLE (0x0904)
|
||||
|
||||
/**
|
||||
* @brief Infinite rank
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-17">
|
||||
* RFC 6550, section 17
|
||||
* </a>
|
||||
*/
|
||||
#define NG_RPL_INFINITE_RANK (0xFFFF)
|
||||
|
||||
/**
|
||||
* @brief Default minimum hop rank increase
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-17">
|
||||
* RFC 6550, section 17
|
||||
* </a>
|
||||
*/
|
||||
#define NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE (256)
|
||||
|
||||
/**
|
||||
* @brief Maximum rank increase
|
||||
*/
|
||||
#define NG_RPL_DEFAULT_MAX_RANK_INCREASE (0)
|
||||
|
||||
/**
|
||||
* @brief Number of implemented Objective Functions
|
||||
*/
|
||||
#define NG_RPL_IMPLEMENTED_OFS_NUMOF (1)
|
||||
|
||||
/**
|
||||
* @brief Default Objective Code Point (OF0)
|
||||
*/
|
||||
#define NG_RPL_DEFAULT_OCP (0)
|
||||
|
||||
/**
|
||||
* @name RPL Mode of Operations
|
||||
* @{
|
||||
*/
|
||||
#define NG_RPL_MOP_NO_DOWNWARD_ROUTES (0x00)
|
||||
#define NG_RPL_MOP_NON_STORING_MODE (0x01)
|
||||
#define NG_RPL_MOP_STORING_MODE_NO_MC (0x02)
|
||||
#define NG_RPL_MOP_STORING_MODE_MC (0x03)
|
||||
/** default MOP set on compile time */
|
||||
#ifndef NG_RPL_DEFAULT_MOP
|
||||
# define NG_RPL_DEFAULT_MOP NG_RPL_MOP_STORING_MODE_NO_MC
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Sequence counter handling
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-7.2">
|
||||
* Sequence Counter Operation
|
||||
* </a>
|
||||
* @{
|
||||
*/
|
||||
#define NG_RPL_COUNTER_MAX (255)
|
||||
#define NG_RPL_COUNTER_LOWER_REGION (127)
|
||||
#define NG_RPL_COUNTER_SEQ_WINDOW (16)
|
||||
#define NG_RPL_COUNTER_INIT (NG_RPL_COUNTER_MAX - NG_RPL_COUNTER_SEQ_WINDOW + 1)
|
||||
|
||||
static inline uint8_t NG_RPL_COUNTER_INCREMENT(uint8_t counter)
|
||||
{
|
||||
return ((counter > NG_RPL_COUNTER_LOWER_REGION) ?
|
||||
((counter == NG_RPL_COUNTER_MAX) ? counter = 0 : ++counter) :
|
||||
((counter == NG_RPL_COUNTER_LOWER_REGION) ? counter = 0 : ++counter));
|
||||
}
|
||||
|
||||
static inline bool NG_RPL_COUNTER_IS_INIT(uint8_t counter)
|
||||
{
|
||||
return (counter > NG_RPL_COUNTER_LOWER_REGION);
|
||||
}
|
||||
|
||||
static inline bool NG_RPL_COUNTER_GREATER_THAN_LOCAL(uint8_t A, uint8_t B)
|
||||
{
|
||||
return (((A < B) && (NG_RPL_COUNTER_LOWER_REGION + 1 - B + A < NG_RPL_COUNTER_SEQ_WINDOW))
|
||||
|| ((A > B) && (A - B < NG_RPL_COUNTER_SEQ_WINDOW)));
|
||||
}
|
||||
|
||||
static inline bool NG_RPL_COUNTER_GREATER_THAN(uint8_t A, uint8_t B)
|
||||
{
|
||||
return ((A > NG_RPL_COUNTER_LOWER_REGION) ? ((B > NG_RPL_COUNTER_LOWER_REGION) ?
|
||||
NG_RPL_COUNTER_GREATER_THAN_LOCAL(A, B) : 0) :
|
||||
((B > NG_RPL_COUNTER_LOWER_REGION) ? 1 : NG_RPL_COUNTER_GREATER_THAN_LOCAL(A, B)));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Trickle parameters
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-8.3.1">
|
||||
* Trickle Parameters
|
||||
* </a>
|
||||
* @{
|
||||
*/
|
||||
#define NG_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS (20)
|
||||
#define NG_RPL_DEFAULT_DIO_INTERVAL_MIN (3)
|
||||
#define NG_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT (10)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Default parent and route entry lifetime
|
||||
* default lifetime will be multiplied by the lifetime unit to obtain the resulting lifetime
|
||||
* @{
|
||||
*/
|
||||
#define NG_RPL_DEFAULT_LIFETIME (60)
|
||||
#define NG_RPL_LIFETIME_UNIT (2)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Interval of the void _update_lifetime() function
|
||||
*/
|
||||
#define NG_RPL_LIFETIME_STEP (2)
|
||||
|
||||
/**
|
||||
* @brief A DODAG can be grounded or floating
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-3.2.4">
|
||||
* Grounded and Floating DODAGs
|
||||
* </a>
|
||||
*/
|
||||
#define NG_RPL_GROUNDED (1)
|
||||
|
||||
/**
|
||||
* @name Parameters used for DAO handling
|
||||
* @{
|
||||
*/
|
||||
#define NG_RPL_DAO_SEND_RETRIES (4)
|
||||
#define NG_RPL_DEFAULT_WAIT_FOR_DAO_ACK (3)
|
||||
#define NG_RPL_REGULAR_DAO_INTERVAL (60)
|
||||
#define NG_RPL_DEFAULT_DAO_DELAY (5)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Cleanup timeout in seconds
|
||||
*/
|
||||
#define NG_RPL_CLEANUP_TIME (30)
|
||||
|
||||
/**
|
||||
* @name Node Status
|
||||
* @{
|
||||
*/
|
||||
#define NG_RPL_NORMAL_NODE (0)
|
||||
#define NG_RPL_ROOT_NODE (1)
|
||||
#define NG_RPL_LEAF_NODE (2)
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @name RPL Control Message Options
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7">
|
||||
* RPL Control Message Options
|
||||
* </a>
|
||||
* @{
|
||||
*/
|
||||
#define NG_RPL_OPT_PAD1 (0)
|
||||
#define NG_RPL_OPT_PADN (1)
|
||||
#define NG_RPL_OPT_DAG_METRIC_CONTAINER (2)
|
||||
#define NG_RPL_OPT_ROUTE_INFO (3)
|
||||
#define NG_RPL_OPT_DODAG_CONF (4)
|
||||
#define NG_RPL_OPT_TARGET (5)
|
||||
#define NG_RPL_OPT_TRANSIT (6)
|
||||
#define NG_RPL_OPT_SOLICITED_INFO (7)
|
||||
#define NG_RPL_OPT_PREFIX_INFO (8)
|
||||
#define NG_RPL_OPT_TARGET_DESC (9)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Rank of the root node
|
||||
*/
|
||||
#define NG_RPL_ROOT_RANK (256)
|
||||
|
||||
/**
|
||||
* @brief DIS ICMPv6 code
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
|
||||
* RFC 6550, section 6
|
||||
* </a>
|
||||
*/
|
||||
#define NG_RPL_ICMPV6_CODE_DIS (0x00)
|
||||
|
||||
/**
|
||||
* @brief DIO ICMPv6 code
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
|
||||
* RFC 6550, section 6
|
||||
* </a>
|
||||
*/
|
||||
#define NG_RPL_ICMPV6_CODE_DIO (0x01)
|
||||
|
||||
/**
|
||||
* @brief DAO ICMPv6 code
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
|
||||
* RFC 6550, section 6
|
||||
* </a>
|
||||
*/
|
||||
#define NG_RPL_ICMPV6_CODE_DAO (0x02)
|
||||
|
||||
/**
|
||||
* @brief DAO ACK ICMPv6 code
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6">
|
||||
* RFC 6550, section 6
|
||||
* </a>
|
||||
*/
|
||||
#define NG_RPL_ICMPV6_CODE_DAO_ACK (0x03)
|
||||
|
||||
/**
|
||||
* @brief Update interval of the lifetime update function
|
||||
*/
|
||||
#define NG_RPL_LIFETIME_UPDATE_STEP (2)
|
||||
|
||||
/**
|
||||
* @brief PID of the RPL thread.
|
||||
*/
|
||||
extern kernel_pid_t ng_rpl_pid;
|
||||
|
||||
/**
|
||||
* @brief Initialization of the RPL thread.
|
||||
*
|
||||
* @param[in] if_pid PID of the interface
|
||||
*
|
||||
* @return The PID of the RPL thread, on success.
|
||||
* @return a negative errno on error.
|
||||
*/
|
||||
kernel_pid_t ng_rpl_init(kernel_pid_t if_pid);
|
||||
|
||||
/**
|
||||
* @brief Initialization of a RPL DODAG as root node. Creates a new instance if necessary.
|
||||
*
|
||||
* @param[in] instance_id Id of the instance
|
||||
* @param[in] dodag_id Id of the DODAG
|
||||
*
|
||||
* @return Pointer to the new DODAG, on success.
|
||||
* @return NULL, otherwise.
|
||||
*/
|
||||
ng_rpl_dodag_t *ng_rpl_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id);
|
||||
|
||||
/**
|
||||
* @brief Send a DIO of the @p dodag to the @p destination.
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG.
|
||||
* @param[in] destination IPv6 addres of the destination.
|
||||
*/
|
||||
void ng_rpl_send_DIO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination);
|
||||
|
||||
/**
|
||||
* @brief Send a DIS of the @p dodag to the @p destination.
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG, optional.
|
||||
* @param[in] destination IPv6 addres of the destination.
|
||||
*/
|
||||
void ng_rpl_send_DIS(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination);
|
||||
|
||||
/**
|
||||
* @brief Send a DAO of the @p dodag to the @p destination.
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG.
|
||||
* @param[in] destination IPv6 addres of the destination.
|
||||
* @param[in] lifetime Lifetime of the route to announce.
|
||||
*/
|
||||
void ng_rpl_send_DAO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_t lifetime);
|
||||
|
||||
/**
|
||||
* @brief Send a DAO-ACK of the @p dodag to the @p destination.
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG, optional.
|
||||
* @param[in] destination IPv6 addres of the destination.
|
||||
* @param[in] seq Sequence number to be acknowledged.
|
||||
*/
|
||||
void ng_rpl_send_DAO_ACK(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_t seq);
|
||||
|
||||
/**
|
||||
* @brief Parse a DIS.
|
||||
*
|
||||
* @param[in] dis Pointer to the DIS message.
|
||||
* @param[in] src Pointer to the source address of the IPv6 packet.
|
||||
* @param[in] dst Pointer to the destination address of the IPv6 packet.
|
||||
* @param[in] len Length of the IPv6 packet.
|
||||
*/
|
||||
void ng_rpl_recv_DIS(ng_rpl_dis_t *dis, ipv6_addr_t *src, ipv6_addr_t *dst, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Parse a DIO.
|
||||
*
|
||||
* @param[in] dio Pointer to the DIO message.
|
||||
* @param[in] src Pointer to the source address of the IPv6 packet.
|
||||
* @param[in] len Length of the IPv6 packet.
|
||||
*/
|
||||
void ng_rpl_recv_DIO(ng_rpl_dio_t *dio, ipv6_addr_t *src, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Parse a DAO.
|
||||
*
|
||||
* @param[in] dao Pointer to the DAO message.
|
||||
* @param[in] src Pointer to the source address of the IPv6 packet.
|
||||
* @param[in] len Length of the IPv6 packet.
|
||||
*/
|
||||
void ng_rpl_recv_DAO(ng_rpl_dao_t *dao, ipv6_addr_t *src, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Parse a DAO-ACK.
|
||||
*
|
||||
* @param[in] dao_ack Pointer to the DAO-ACK message.
|
||||
*/
|
||||
void ng_rpl_recv_DAO_ACK(ng_rpl_dao_ack_t *dao_ack);
|
||||
|
||||
/**
|
||||
* @brief Delay the DAO sending interval
|
||||
*
|
||||
* @param[in] dodag The DODAG of the DAO
|
||||
*/
|
||||
void ng_rpl_delay_dao(ng_rpl_dodag_t *dodag);
|
||||
|
||||
/**
|
||||
* @brief Long delay the DAO sending interval
|
||||
*
|
||||
* @param[in] dodag The DODAG of the DAO
|
||||
*/
|
||||
void ng_rpl_long_delay_dao(ng_rpl_dodag_t *dodag);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NG_RPL_H_ */
|
||||
/** @} */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
216
sys/include/net/ng_rpl/dodag.h
Normal file
216
sys/include/net/ng_rpl/dodag.h
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2013 INRIA.
|
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup net_ng_rpl
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief DODAG-related functions for RPL
|
||||
*
|
||||
* Header file, which defines all public known DODAG-related functions for RPL.
|
||||
*
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef NG_RPL_DODAG_H_
|
||||
#define NG_RPL_DODAG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "net/ng_ipv6.h"
|
||||
#include "trickle.h"
|
||||
#include "net/ng_rpl.h"
|
||||
#include "net/ng_rpl/structs.h"
|
||||
|
||||
/**
|
||||
* @brief Number of RPL instances
|
||||
*/
|
||||
#ifndef NG_RPL_INSTANCES_NUMOF
|
||||
#define NG_RPL_INSTANCES_NUMOF (2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of RPL dodags
|
||||
*/
|
||||
#ifndef NG_RPL_DODAGS_NUMOF
|
||||
#define NG_RPL_DODAGS_NUMOF (4)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of RPL parents
|
||||
*/
|
||||
#ifndef NG_RPL_PARENTS_NUMOF
|
||||
#define NG_RPL_PARENTS_NUMOF (6)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief RPL instance table
|
||||
*/
|
||||
extern ng_rpl_instance_t ng_rpl_instances[NG_RPL_INSTANCES_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief RPL DODAG table
|
||||
*/
|
||||
extern ng_rpl_dodag_t ng_rpl_dodags[NG_RPL_DODAGS_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief RPL parent table
|
||||
*/
|
||||
extern ng_rpl_parent_t ng_rpl_parents[NG_RPL_PARENTS_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief Add a new RPL instance with the id @p instance_id.
|
||||
*
|
||||
* @param[in] instance_id The instance id of the new RPL instance.
|
||||
* @param[out] inst Pointer to an existing or new instance. Otherwise NULL.
|
||||
*
|
||||
* @return true, if instance could be created.
|
||||
* @return false, if instance could not be created or exists already.
|
||||
*/
|
||||
bool ng_rpl_instance_add(uint8_t instance_id, ng_rpl_instance_t **inst);
|
||||
|
||||
/**
|
||||
* @brief Remove a RPL instance with the id @p instance_id.
|
||||
*
|
||||
* @param[in] instance_id The instance id of the RPL instance to remove.
|
||||
*
|
||||
* @return true, on success.
|
||||
* @return false, otherwise.
|
||||
*/
|
||||
bool ng_rpl_instance_remove_by_id(uint8_t instance_id);
|
||||
|
||||
/**
|
||||
* @brief Remove a RPL instance with the pointer @p inst.
|
||||
*
|
||||
* @param[in] inst Pointer to the the RPL instance to remove.
|
||||
*
|
||||
* @return true, on success.
|
||||
* @return false, otherwise.
|
||||
*/
|
||||
bool ng_rpl_instance_remove(ng_rpl_instance_t *inst);
|
||||
|
||||
/**
|
||||
* @brief Get the RPL instance with the id @p instance_id.
|
||||
*
|
||||
* @param[in] instance_id The instance id of the RPL instance to get.
|
||||
*
|
||||
* @return Pointer to the RPL instance, on success.
|
||||
* @return NULL, otherwise.
|
||||
*/
|
||||
ng_rpl_instance_t *ng_rpl_instance_get(uint8_t instance_id);
|
||||
|
||||
/**
|
||||
* @brief Add a new RPL DODAG with the id @p dodag_id to the instance @p instance.
|
||||
*
|
||||
* @param[in] instance Pointer to the instance to add the DODAG to
|
||||
* @param[in] dodag_id The DODAG-ID of the new DODAG
|
||||
* @param[out] dodag Pointer to an existing or new DODAG. Otherwise NULL.
|
||||
*
|
||||
* @return true, if DODAG could be created.
|
||||
* @return false, if DODAG could not be created or exists already.
|
||||
*/
|
||||
bool ng_rpl_dodag_add(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id, ng_rpl_dodag_t **dodag);
|
||||
|
||||
/**
|
||||
* @brief Remove the RPL DODAG @p dodag.
|
||||
*
|
||||
* @param[in] dodag Pointer to the dodag.
|
||||
*
|
||||
* @return true, on success.
|
||||
* @return false, otherwise.
|
||||
*/
|
||||
bool ng_rpl_dodag_remove(ng_rpl_dodag_t *dodag);
|
||||
|
||||
/**
|
||||
* @brief Remove all parents from the @p dodag.
|
||||
*
|
||||
* @param[in] dodag Pointer to the dodag.
|
||||
*/
|
||||
void ng_rpl_dodag_remove_all_parents(ng_rpl_dodag_t *dodag);
|
||||
|
||||
/**
|
||||
* @brief Get the RPL DODAG with the id @p dodag_id to the instance @p instance.
|
||||
*
|
||||
* @param[in] instance Pointer to the instance of the RPL DODAG
|
||||
* @param[in] dodag_id The DODAG-ID of the RPL DODAG
|
||||
*
|
||||
* @return Pointer to the existing RPL DODAG, on success.
|
||||
* @return NULL, otherwise.
|
||||
*/
|
||||
ng_rpl_dodag_t *ng_rpl_dodag_get(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id);
|
||||
|
||||
/**
|
||||
* @brief Add a new parent with the IPv6 address @p addr to the @p dodag.
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG
|
||||
* @param[in] addr IPV6 address of the parent
|
||||
* @param[out] parent Pointer to an existing or new parent. Otherwise NULL.
|
||||
*
|
||||
* @return true. if parent could be created.
|
||||
* @return false, if parent could not be created or exists already.
|
||||
*/
|
||||
bool ng_rpl_parent_add_by_addr(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr, ng_rpl_parent_t **parent);
|
||||
|
||||
/**
|
||||
* @brief Remove the @p parent from its DODAG.
|
||||
*
|
||||
* @param[in] parent Pointer to the parent.
|
||||
*
|
||||
* @return true, on success.
|
||||
* @return false, otherwise.
|
||||
*/
|
||||
bool ng_rpl_parent_remove(ng_rpl_parent_t *parent);
|
||||
|
||||
/**
|
||||
* @brief Get a parent with the IPv6 addr @p addr of the DODAG @p dodag.
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG
|
||||
* @param[in] addr IPv6 address of the parent
|
||||
*
|
||||
* @return Pointer to the existing parent, on success.
|
||||
* @return NULL, otherwise.
|
||||
*/
|
||||
ng_rpl_parent_t *ng_rpl_parent_get(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr);
|
||||
|
||||
/**
|
||||
* @brief Update a @p parent of the @p dodag.
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG
|
||||
* @param[in] parent Pointer to the parent
|
||||
*/
|
||||
void ng_rpl_parent_update(ng_rpl_dodag_t *dodag, ng_rpl_parent_t *parent);
|
||||
|
||||
/**
|
||||
* @brief Find the parent with the lowest rank and update the DODAG's preferred parent
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG
|
||||
*
|
||||
* @return Pointer to the preferred parent, on success.
|
||||
* @return NULL, otherwise.
|
||||
*/
|
||||
ng_rpl_parent_t *ng_rpl_find_preferred_parent(ng_rpl_dodag_t *dodag);
|
||||
|
||||
/**
|
||||
* @brief Start a local repair.
|
||||
*
|
||||
* @param[in] dodag Pointer to the DODAG
|
||||
*/
|
||||
void ng_rpl_local_repair(ng_rpl_dodag_t *dodag);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NG_RPL_DODAG_H_ */
|
||||
/**
|
||||
* @}
|
||||
*/
|
46
sys/include/net/ng_rpl/of_manager.h
Normal file
46
sys/include/net/ng_rpl/of_manager.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 net_ng_rpl
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief RPL Objective functions manager header
|
||||
*
|
||||
* @author Fabian Brandt <fabianbr@zedat.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef RPL_OFM_H
|
||||
#define RPL_OFM_H
|
||||
|
||||
#include "structs.h"
|
||||
#include "net/ng_ipv6.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialization of Manager and of-functions.
|
||||
*/
|
||||
void ng_rpl_of_manager_init(void);
|
||||
|
||||
/**
|
||||
* @brief Returns objective function with a given cope point
|
||||
* @param[in] ocp Objective code point of objective function
|
||||
* @return Pointer of corresponding objective function implementation
|
||||
*/
|
||||
ng_rpl_of_t *ng_rpl_get_of_for_ocp(uint16_t ocp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RPL_OFM_H */
|
||||
/** @} */
|
234
sys/include/net/ng_rpl/structs.h
Normal file
234
sys/include/net/ng_rpl/structs.h
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (C) 2013 INRIA.
|
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup net_ng_rpl
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief RPL data structs
|
||||
*
|
||||
* Header file, which defines all structs used by RPL.
|
||||
*
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef NG_RPL_STRUCTS_H_
|
||||
#define NG_RPL_STRUCTS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "net/ng_ipv6.h"
|
||||
#include "trickle.h"
|
||||
|
||||
/**
|
||||
* @brief RPL-Option Generic Format
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.1">
|
||||
* RPL Control Message Option Generic Format
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< Option Type */
|
||||
uint8_t length; /**< Option Length, does not include the first two byte */
|
||||
} ng_rpl_opt_t;
|
||||
|
||||
/**
|
||||
* @brief DIO Base Object
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.3.1">
|
||||
* Format of the DIO Base Object
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t instance_id; /**< id of the instance */
|
||||
uint8_t version_number; /**< version number of the DODAG */
|
||||
network_uint16_t rank; /**< rank of the parent emitting the DIO */
|
||||
uint8_t g_mop_prf; /**< grounded, MOP, preferred flags */
|
||||
uint8_t dtsn; /**< Destination Advertisement Trigger Sequence Number */
|
||||
uint8_t flags; /**< unused */
|
||||
uint8_t reserved; /**< reserved */
|
||||
ipv6_addr_t dodag_id; /**< id of the dodag */
|
||||
} ng_rpl_dio_t;
|
||||
|
||||
/**
|
||||
* @brief DODAG Configuration Option
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.6">
|
||||
* DODAG Configuration
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< Option Type: 0x04 */
|
||||
uint8_t length; /**< length of option, not including first two bytes */
|
||||
uint8_t flags_a_pcs; /**< flags */
|
||||
uint8_t dio_int_doubl; /**< trickle Imax parameter */
|
||||
uint8_t dio_int_min; /**< trickle Imin parameter */
|
||||
uint8_t dio_redun; /**< trickle k parameter */
|
||||
network_uint16_t max_rank_inc; /**< allowable increase in rank */
|
||||
network_uint16_t min_hop_rank_inc; /**< DAGRank(rank) = floor(rank/MinHopRankIncrease) */
|
||||
network_uint16_t ocp; /**< Objective Code Point */
|
||||
uint8_t reserved; /**< reserved */
|
||||
uint8_t default_lifetime; /**< lifetime of RPL routes (lifetime * lifetime_unit) */
|
||||
network_uint16_t lifetime_unit; /**< unit in seconds */
|
||||
} ng_rpl_opt_dodag_conf_t;
|
||||
|
||||
/**
|
||||
* @brief DODAG Information Solicitation
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.2">
|
||||
* DODAG Information Solicitation
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t flags; /**< unused */
|
||||
uint8_t reserved; /**< reserved */
|
||||
} ng_rpl_dis_t;
|
||||
|
||||
/**
|
||||
* @brief Destination Advertisement Object
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.4">
|
||||
* Destination Advertisement Object
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t instance_id; /**< id of the instance */
|
||||
uint8_t k_d_flags; /**< K and D flags */
|
||||
uint8_t reserved; /**< reserved */
|
||||
uint8_t dao_sequence; /**< sequence of the DAO, needs to be used for DAO-ACK */
|
||||
ipv6_addr_t dodag_id; /**< id of the DODAG */
|
||||
} ng_rpl_dao_t;
|
||||
|
||||
/**
|
||||
* @brief Destination Advertisement Object Acknowledgement
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.5">
|
||||
* Destination Advertisement Object Acknowledgement
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t instance_id; /**< id of the instance */
|
||||
uint8_t d_reserved; /**< if set, indicates that the DODAG id should be included */
|
||||
uint8_t dao_sequence; /**< sequence must be equal to the sequence from the DAO object */
|
||||
uint8_t status; /**< indicates completion */
|
||||
ipv6_addr_t dodag_id; /**< id of the DODAG */
|
||||
} ng_rpl_dao_ack_t;
|
||||
|
||||
/**
|
||||
* @brief Target Option
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.7">
|
||||
* RPL Target
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< option type */
|
||||
uint8_t length; /**< option length without the first two bytes */
|
||||
uint8_t flags; /**< unused */
|
||||
uint8_t prefix_length; /**< number of valid leading bits in the IPv6 prefix */
|
||||
ipv6_addr_t target; /**< IPv6 prefix, address or multicast group */
|
||||
} ng_rpl_opt_target_t;
|
||||
|
||||
/**
|
||||
* @brief Transit Option
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.8">
|
||||
* Transit Information
|
||||
* </a>
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type; /**< option type */
|
||||
uint8_t length; /**< option length without the first two bytes */
|
||||
uint8_t e_flags; /**< external flag indicates external routes */
|
||||
uint8_t path_control; /**< limits the number of DAO parents */
|
||||
uint8_t path_sequence; /**< increased value for route updates */
|
||||
uint8_t path_lifetime; /**< lifetime of routes */
|
||||
} ng_rpl_opt_transit_t;
|
||||
|
||||
typedef struct ng_rpl_dodag ng_rpl_dodag_t;
|
||||
typedef struct ng_rpl_parent ng_rpl_parent_t;
|
||||
|
||||
/**
|
||||
* @brief Parent representation
|
||||
*/
|
||||
struct ng_rpl_parent {
|
||||
ng_rpl_parent_t *next; /**< pointer to the next parent */
|
||||
uint8_t state; /**< 0 for unsued, 1 for used */
|
||||
ipv6_addr_t addr; /**< link-local IPv6 address of this parent */
|
||||
uint16_t rank; /**< rank of the parent */
|
||||
uint8_t dtsn; /**< last seen dtsn of this parent */
|
||||
ng_rpl_dodag_t *dodag; /**< DODAG the parent belongs to */
|
||||
timex_t lifetime; /**< lifetime of this parent */
|
||||
double link_metric; /**< metric of the link */
|
||||
uint8_t link_metric_type; /**< type of the metric */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Objective function representation
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t ocp; /**< objective code point */
|
||||
uint16_t (*calc_rank)(ng_rpl_parent_t *parent, uint16_t base_rank); /**< calculate the rank */
|
||||
ng_rpl_parent_t *(*which_parent)(ng_rpl_parent_t *, ng_rpl_parent_t *); /**< compare for parents */
|
||||
ng_rpl_dodag_t *(*which_dodag)(ng_rpl_dodag_t *, ng_rpl_dodag_t *); /**< compare for dodags */
|
||||
void (*reset)(ng_rpl_dodag_t *); /**< resets the OF */
|
||||
void (*parent_state_callback)(ng_rpl_parent_t *, int, int); /**< retrieves the state of a parent*/
|
||||
void (*init)(void); /**< OF specific init function */
|
||||
void (*process_dio)(void); /**< DIO processing callback (acc. to OF0 spec, chpt 5) */
|
||||
} ng_rpl_of_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Instance representation
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t id; /**< id of the instance */
|
||||
uint8_t state; /**< 0 for unused, 1 for used */
|
||||
ng_rpl_dodag_t *dodags; /**< pointer to the DODAG list of this instance */
|
||||
uint8_t mop; /**< configured Mode of Operation */
|
||||
ng_rpl_of_t *of; /**< configured Objective Function */
|
||||
uint16_t min_hop_rank_inc; /**< minimum hop rank increase */
|
||||
uint16_t max_rank_inc; /**< max increase in the rank */
|
||||
} ng_rpl_instance_t;
|
||||
|
||||
/**
|
||||
* @brief DODAG representation
|
||||
*/
|
||||
struct ng_rpl_dodag {
|
||||
ng_rpl_instance_t *instance; /**< id of the instance */
|
||||
ng_rpl_dodag_t *next; /**< pointer to the next dodag */
|
||||
ng_rpl_parent_t *parents; /**< pointer to the parents list of this DODAG */
|
||||
ipv6_addr_t dodag_id; /**< id of the DODAG */
|
||||
uint8_t state; /**< 0 for unused, 1 for used */
|
||||
uint8_t dtsn; /**< DAO Trigger Sequence Number */
|
||||
uint8_t prf; /**< preferred flag */
|
||||
uint8_t dio_interval_doubl; /**< trickle Imax parameter */
|
||||
uint8_t dio_min; /**< trickle Imin parameter */
|
||||
uint8_t dio_redun; /**< trickle k parameter */
|
||||
uint8_t default_lifetime; /**< lifetime of routes (lifetime * unit) */
|
||||
uint16_t lifetime_unit; /**< unit in seconds of the lifetime */
|
||||
uint8_t version; /**< version of this DODAG */
|
||||
uint8_t grounded; /**< grounded flag */
|
||||
uint16_t my_rank; /**< rank/position in the DODAG */
|
||||
uint8_t node_status; /**< leaf, normal, or root node */
|
||||
uint8_t dao_seq; /**< dao sequence number */
|
||||
uint8_t dao_counter; /**< amount of retried DAOs */
|
||||
bool dao_ack_received; /**< flag to check for DAO-ACK */
|
||||
uint8_t dodag_conf_counter; /**< limitation of the sending of DODAG_CONF options */
|
||||
timex_t dao_time; /**< time to schedule the next DAO */
|
||||
vtimer_t dao_timer; /**< timer to schedule the next DAO */
|
||||
timex_t cleanup_time; /**< time to schedula a DODAG cleanup */
|
||||
vtimer_t cleanup_timer; /**< timer to schedula a DODAG cleanup */
|
||||
trickle_t trickle; /**< trickle representation */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NG_RPL_STRUCTS_H_ */
|
||||
/**
|
||||
* @}
|
||||
*/
|
@ -114,13 +114,6 @@ void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt)
|
||||
/* TODO */
|
||||
break;
|
||||
|
||||
#ifdef MODULE_NG_RPL
|
||||
case NG_ICMPV6_RPL_CTRL:
|
||||
DEBUG("icmpv6: RPL control message received\n");
|
||||
/* TODO */
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
DEBUG("icmpv6: unknown type field %" PRIu8 "\n", hdr->type);
|
||||
break;
|
||||
|
1
sys/net/routing/ng_rpl/Makefile
Normal file
1
sys/net/routing/ng_rpl/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
313
sys/net/routing/ng_rpl/ng_rpl.c
Normal file
313
sys/net/routing/ng_rpl/ng_rpl.c
Normal file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*
|
||||
* 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 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
#include "net/ng_rpl.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if ENABLE_DEBUG && defined(MODULE_IPV6_ADDR)
|
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
static char _stack[NG_RPL_STACK_SIZE];
|
||||
kernel_pid_t ng_rpl_pid = KERNEL_PID_UNDEF;
|
||||
static timex_t _lt_time;
|
||||
static vtimer_t _lt_timer;
|
||||
static msg_t _msg_q[NG_RPL_MSG_QUEUE_SIZE];
|
||||
static ng_netreg_entry_t _me_reg;
|
||||
|
||||
ng_rpl_instance_t ng_rpl_instances[NG_RPL_INSTANCES_NUMOF];
|
||||
ng_rpl_dodag_t ng_rpl_dodags[NG_RPL_DODAGS_NUMOF];
|
||||
ng_rpl_parent_t ng_rpl_parents[NG_RPL_PARENTS_NUMOF];
|
||||
|
||||
static void _update_lifetime(void);
|
||||
static void _dao_handle_send(ng_rpl_dodag_t *dodag);
|
||||
static void _receive(ng_pktsnip_t *pkt);
|
||||
static void *_event_loop(void *args);
|
||||
static ng_rpl_dodag_t *_root_dodag_init(uint8_t instance_id, ipv6_addr_t *dodag_id, uint8_t mop);
|
||||
|
||||
kernel_pid_t ng_rpl_init(kernel_pid_t if_pid)
|
||||
{
|
||||
/* check if RPL was initialized before */
|
||||
if (ng_rpl_pid == KERNEL_PID_UNDEF) {
|
||||
/* start the event loop */
|
||||
ng_rpl_pid = thread_create(_stack, sizeof(_stack), NG_RPL_PRIO, CREATE_STACKTEST,
|
||||
_event_loop, NULL, "RPL");
|
||||
|
||||
if (ng_rpl_pid == KERNEL_PID_UNDEF) {
|
||||
DEBUG("RPL: could not start the event loop\n");
|
||||
return KERNEL_PID_UNDEF;
|
||||
}
|
||||
|
||||
_me_reg.demux_ctx = NG_ICMPV6_RPL_CTRL;
|
||||
_me_reg.pid = ng_rpl_pid;
|
||||
/* register interest in all ICMPv6 packets */
|
||||
ng_netreg_register(NG_NETTYPE_ICMPV6, &_me_reg);
|
||||
|
||||
ng_rpl_of_manager_init();
|
||||
_lt_time = timex_set(NG_RPL_LIFETIME_UPDATE_STEP, 0);
|
||||
vtimer_set_msg(&_lt_timer, _lt_time, ng_rpl_pid, NG_RPL_MSG_TYPE_LIFETIME_UPDATE, NULL);
|
||||
}
|
||||
|
||||
/* register all_RPL_nodes multicast address */
|
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
|
||||
ng_ipv6_netif_add_addr(if_pid, &all_RPL_nodes, IPV6_ADDR_BIT_LEN, 0);
|
||||
|
||||
ng_rpl_send_DIS(NULL, &all_RPL_nodes);
|
||||
return ng_rpl_pid;
|
||||
}
|
||||
|
||||
ng_rpl_dodag_t *ng_rpl_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id)
|
||||
{
|
||||
ng_rpl_dodag_t *dodag = _root_dodag_init(instance_id, dodag_id, NG_RPL_DEFAULT_MOP);
|
||||
|
||||
if (!dodag) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dodag->dtsn = 1;
|
||||
dodag->prf = 0;
|
||||
dodag->dio_interval_doubl = NG_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS;
|
||||
dodag->dio_min = NG_RPL_DEFAULT_DIO_INTERVAL_MIN;
|
||||
dodag->dio_redun = NG_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT;
|
||||
dodag->default_lifetime = NG_RPL_DEFAULT_LIFETIME;
|
||||
dodag->lifetime_unit = NG_RPL_LIFETIME_UNIT;
|
||||
dodag->version = NG_RPL_COUNTER_INIT;
|
||||
dodag->grounded = NG_RPL_GROUNDED;
|
||||
dodag->node_status = NG_RPL_ROOT_NODE;
|
||||
dodag->my_rank = NG_RPL_ROOT_RANK;
|
||||
|
||||
trickle_start(ng_rpl_pid, &dodag->trickle, NG_RPL_MSG_TYPE_TRICKLE_INTERVAL,
|
||||
NG_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min),
|
||||
dodag->dio_interval_doubl, dodag->dio_redun);
|
||||
|
||||
return dodag;
|
||||
}
|
||||
|
||||
static ng_rpl_dodag_t *_root_dodag_init(uint8_t instance_id, ipv6_addr_t *dodag_id, uint8_t mop)
|
||||
{
|
||||
if (ng_rpl_pid == KERNEL_PID_UNDEF) {
|
||||
DEBUG("RPL: RPL thread not started\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipv6_addr_t *configured_addr;
|
||||
ng_rpl_instance_t *inst = NULL;
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
|
||||
if (instance_id == 0) {
|
||||
DEBUG("RPL: instance id (%d) must be a positive number greater than zero\n", instance_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ng_ipv6_netif_find_by_addr(&configured_addr, dodag_id) == KERNEL_PID_UNDEF) {
|
||||
DEBUG("RPL: no IPv6 address configured to match the given dodag id: %s\n",
|
||||
ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ng_rpl_instance_add(instance_id, &inst)) {
|
||||
inst->of = (ng_rpl_of_t *) ng_rpl_get_of_for_ocp(NG_RPL_DEFAULT_OCP);
|
||||
inst->mop = mop;
|
||||
inst->min_hop_rank_inc = NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE;
|
||||
inst->max_rank_inc = NG_RPL_DEFAULT_MAX_RANK_INCREASE;
|
||||
}
|
||||
else if (inst == NULL) {
|
||||
DEBUG("RPL: could not allocate memory for a new instance with id %d", instance_id);
|
||||
return NULL;
|
||||
}
|
||||
else if (inst->mop != mop) {
|
||||
DEBUG("RPL: instance (%d) exists with another MOP", instance_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ng_rpl_dodag_add(inst, dodag_id, &dodag)) {
|
||||
DEBUG("RPL: DODAG with id %s exists or no memory left for a new DODAG",
|
||||
ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dodag;
|
||||
}
|
||||
|
||||
static void _receive(ng_pktsnip_t *icmpv6)
|
||||
{
|
||||
ng_pktsnip_t *ipv6 = NULL;
|
||||
ipv6_hdr_t *ipv6_hdr = NULL;
|
||||
ng_icmpv6_hdr_t *icmpv6_hdr = NULL;
|
||||
|
||||
LL_SEARCH_SCALAR(icmpv6, ipv6, type, NG_NETTYPE_IPV6);
|
||||
ipv6_hdr = (ipv6_hdr_t *)ipv6->data;
|
||||
|
||||
icmpv6_hdr = (ng_icmpv6_hdr_t *)icmpv6->data;
|
||||
switch (icmpv6_hdr->code) {
|
||||
case NG_RPL_ICMPV6_CODE_DIS:
|
||||
DEBUG("RPL: DIS received\n");
|
||||
ng_rpl_recv_DIS((ng_rpl_dis_t *)(icmpv6_hdr + 1), &ipv6_hdr->src, &ipv6_hdr->dst,
|
||||
byteorder_ntohs(ipv6_hdr->len));
|
||||
break;
|
||||
case NG_RPL_ICMPV6_CODE_DIO:
|
||||
DEBUG("RPL: DIO received\n");
|
||||
ng_rpl_recv_DIO((ng_rpl_dio_t *)(icmpv6_hdr + 1), &ipv6_hdr->src,
|
||||
byteorder_ntohs(ipv6_hdr->len));
|
||||
break;
|
||||
case NG_RPL_ICMPV6_CODE_DAO:
|
||||
DEBUG("RPL: DAO received\n");
|
||||
ng_rpl_recv_DAO((ng_rpl_dao_t *)(icmpv6_hdr + 1), &ipv6_hdr->src,
|
||||
byteorder_ntohs(ipv6_hdr->len));
|
||||
break;
|
||||
case NG_RPL_ICMPV6_CODE_DAO_ACK:
|
||||
DEBUG("RPL: DAO-ACK received\n");
|
||||
ng_rpl_recv_DAO_ACK((ng_rpl_dao_ack_t *)(icmpv6_hdr + 1));
|
||||
break;
|
||||
default:
|
||||
DEBUG("RPL: Unknown ICMPV6 code received\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ng_pktbuf_release(icmpv6);
|
||||
}
|
||||
|
||||
static void *_event_loop(void *args)
|
||||
{
|
||||
msg_t msg, reply;
|
||||
|
||||
(void)args;
|
||||
msg_init_queue(_msg_q, NG_RPL_MSG_QUEUE_SIZE);
|
||||
|
||||
/* preinitialize ACK */
|
||||
reply.type = NG_NETAPI_MSG_TYPE_ACK;
|
||||
|
||||
trickle_t *trickle;
|
||||
ng_rpl_dodag_t *dodag;
|
||||
/* start event loop */
|
||||
while (1) {
|
||||
DEBUG("RPL: waiting for incoming message.\n");
|
||||
msg_receive(&msg);
|
||||
|
||||
switch (msg.type) {
|
||||
case NG_RPL_MSG_TYPE_LIFETIME_UPDATE:
|
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_LIFETIME_UPDATE received\n");
|
||||
_update_lifetime();
|
||||
break;
|
||||
case NG_RPL_MSG_TYPE_TRICKLE_INTERVAL:
|
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_TRICKLE_INTERVAL received\n");
|
||||
trickle = (trickle_t *) msg.content.ptr;
|
||||
if (trickle && (trickle->callback.func != NULL)) {
|
||||
trickle_interval(trickle);
|
||||
}
|
||||
break;
|
||||
case NG_RPL_MSG_TYPE_TRICKLE_CALLBACK:
|
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_TRICKLE_CALLBACK received\n");
|
||||
trickle = (trickle_t *) msg.content.ptr;
|
||||
if (trickle && (trickle->callback.func != NULL)) {
|
||||
trickle_callback(trickle);
|
||||
}
|
||||
break;
|
||||
case NG_RPL_MSG_TYPE_DAO_HANDLE:
|
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_DAO_HANDLE received\n");
|
||||
dodag = (ng_rpl_dodag_t *) msg.content.ptr;
|
||||
if (dodag && (dodag->state != 0)) {
|
||||
_dao_handle_send(dodag);
|
||||
}
|
||||
break;
|
||||
case NG_RPL_MSG_TYPE_CLEANUP_HANDLE:
|
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_CLEANUP received\n");
|
||||
dodag = (ng_rpl_dodag_t *) msg.content.ptr;
|
||||
if (dodag && (dodag->state != 0) && (dodag->parents == NULL)) {
|
||||
/* no parents - delete this DODAG */
|
||||
ng_rpl_dodag_remove(dodag);
|
||||
}
|
||||
break;
|
||||
case NG_NETAPI_MSG_TYPE_RCV:
|
||||
DEBUG("RPL: NG_NETAPI_MSG_TYPE_RCV received\n");
|
||||
_receive((ng_pktsnip_t *)msg.content.ptr);
|
||||
break;
|
||||
case NG_NETAPI_MSG_TYPE_SND:
|
||||
case NG_NETAPI_MSG_TYPE_GET:
|
||||
case NG_NETAPI_MSG_TYPE_SET:
|
||||
DEBUG("RPL: reply to unsupported recv/get/set\n");
|
||||
reply.content.value = -ENOTSUP;
|
||||
msg_reply(&msg, &reply);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _update_lifetime(void)
|
||||
{
|
||||
timex_t now;
|
||||
vtimer_now(&now);
|
||||
ng_rpl_parent_t *parent;
|
||||
for (uint8_t i = 0; i < NG_RPL_PARENTS_NUMOF; ++i) {
|
||||
parent = &ng_rpl_parents[i];
|
||||
if (parent->state != 0) {
|
||||
if ((signed)(parent->lifetime.seconds - now.seconds) <= NG_RPL_LIFETIME_UPDATE_STEP) {
|
||||
ng_rpl_dodag_t *dodag = parent->dodag;
|
||||
ng_rpl_parent_remove(parent);
|
||||
ng_rpl_parent_update(dodag, NULL);
|
||||
continue;
|
||||
}
|
||||
else if (((signed)(parent->lifetime.seconds - now.seconds) <=
|
||||
NG_RPL_LIFETIME_UPDATE_STEP * 2)) {
|
||||
ng_rpl_send_DIS(parent->dodag, &parent->addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
vtimer_remove(&_lt_timer);
|
||||
vtimer_set_msg(&_lt_timer, _lt_time, ng_rpl_pid, NG_RPL_MSG_TYPE_LIFETIME_UPDATE, NULL);
|
||||
}
|
||||
|
||||
void ng_rpl_delay_dao(ng_rpl_dodag_t *dodag)
|
||||
{
|
||||
dodag->dao_time = timex_set(NG_RPL_DEFAULT_DAO_DELAY, 0);
|
||||
dodag->dao_counter = 0;
|
||||
dodag->dao_ack_received = false;
|
||||
vtimer_remove(&dodag->dao_timer);
|
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time, ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag);
|
||||
}
|
||||
|
||||
void ng_rpl_long_delay_dao(ng_rpl_dodag_t *dodag)
|
||||
{
|
||||
dodag->dao_time = timex_set(NG_RPL_REGULAR_DAO_INTERVAL, 0);
|
||||
dodag->dao_counter = 0;
|
||||
dodag->dao_ack_received = false;
|
||||
vtimer_remove(&dodag->dao_timer);
|
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time, ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag);
|
||||
}
|
||||
|
||||
void _dao_handle_send(ng_rpl_dodag_t *dodag)
|
||||
{
|
||||
if ((dodag->dao_ack_received == false) && (dodag->dao_counter < NG_RPL_DAO_SEND_RETRIES)) {
|
||||
dodag->dao_counter++;
|
||||
ng_rpl_send_DAO(dodag, NULL, dodag->default_lifetime);
|
||||
dodag->dao_time = timex_set(NG_RPL_DEFAULT_WAIT_FOR_DAO_ACK, 0);
|
||||
vtimer_remove(&dodag->dao_timer);
|
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time,
|
||||
ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag);
|
||||
}
|
||||
else if (dodag->dao_ack_received == false) {
|
||||
ng_rpl_long_delay_dao(dodag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
619
sys/net/routing/ng_rpl/ng_rpl_control_messages.c
Normal file
619
sys/net/routing/ng_rpl/ng_rpl_control_messages.c
Normal file
@ -0,0 +1,619 @@
|
||||
/*
|
||||
* Copyright (C) 2013 - 2014 INRIA.
|
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*
|
||||
* 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 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
|
||||
#include "net/ng_rpl.h"
|
||||
#include "inet_ntop.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if ENABLE_DEBUG && defined(MODULE_IPV6_ADDR)
|
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
#define NG_RPL_GROUNDED_SHIFT (7)
|
||||
#define NG_RPL_MOP_SHIFT (3)
|
||||
#define NG_RPL_OPT_DODAG_CONF_LEN (14)
|
||||
#define NG_RPL_SHIFTED_MOP_MASK (0x7)
|
||||
#define NG_RPL_PRF_MASK (0x7)
|
||||
|
||||
void _ng_rpl_send(ng_pktsnip_t *pkt, ipv6_addr_t *src, ipv6_addr_t *dst,
|
||||
ipv6_addr_t *dodag_id)
|
||||
{
|
||||
ng_pktsnip_t *hdr;
|
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES, ll_addr;
|
||||
kernel_pid_t iface = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
|
||||
if (iface == KERNEL_PID_UNDEF) {
|
||||
DEBUG("RPL: no suitable interface found for this destination address\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src == NULL) {
|
||||
ipv6_addr_t *tmp = NULL;
|
||||
if (dodag_id != NULL) {
|
||||
tmp = ng_ipv6_netif_match_prefix(iface, dodag_id);
|
||||
}
|
||||
else if (dodag_id == NULL) {
|
||||
tmp = ng_ipv6_netif_find_best_src_addr(iface, &all_RPL_nodes);
|
||||
}
|
||||
|
||||
if (tmp == NULL) {
|
||||
DEBUG("RPL: no suitable src address found\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ll_addr, tmp, sizeof(ll_addr));
|
||||
ipv6_addr_set_link_local_prefix(&ll_addr);
|
||||
src = &ll_addr;
|
||||
}
|
||||
|
||||
if (dst == NULL) {
|
||||
dst = &all_RPL_nodes;
|
||||
}
|
||||
|
||||
hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)src, sizeof(ipv6_addr_t), (uint8_t *)dst,
|
||||
sizeof(ipv6_addr_t));
|
||||
|
||||
if (hdr == NULL) {
|
||||
DEBUG("RPL: Send - no space left in packet buffer\n");
|
||||
ng_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ng_netapi_dispatch_send(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL,hdr)) {
|
||||
DEBUG("RPL: cannot send packet: no subscribers found.\n");
|
||||
ng_pktbuf_release(hdr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ng_rpl_send_DIO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination)
|
||||
{
|
||||
if (dodag == NULL) {
|
||||
DEBUG("RPL: Error - trying to send DIO without being part of a dodag.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ng_pktsnip_t *pkt;
|
||||
ng_icmpv6_hdr_t *icmp;
|
||||
ng_rpl_dio_t *dio;
|
||||
uint8_t *pos;
|
||||
int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dio_t);
|
||||
|
||||
if ((dodag->dodag_conf_counter % 3) == 0) {
|
||||
size += sizeof(ng_rpl_opt_dodag_conf_t);
|
||||
}
|
||||
|
||||
if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DIO, size)) == NULL) {
|
||||
DEBUG("RPL: Send DIO - no space left in packet buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
icmp = (ng_icmpv6_hdr_t *)pkt->data;
|
||||
dio = (ng_rpl_dio_t *)(icmp + 1);
|
||||
pos = (uint8_t *) dio;
|
||||
dio->instance_id = dodag->instance->id;
|
||||
dio->version_number = dodag->version;
|
||||
dio->rank = byteorder_htons(dodag->my_rank);
|
||||
dio->g_mop_prf = (dodag->grounded << NG_RPL_GROUNDED_SHIFT) |
|
||||
(dodag->instance->mop << NG_RPL_MOP_SHIFT) | dodag->prf;
|
||||
dio->dtsn = dodag->dtsn;
|
||||
dio->flags = 0;
|
||||
dio->reserved = 0;
|
||||
dio->dodag_id = dodag->dodag_id;
|
||||
|
||||
pos += sizeof(*dio);
|
||||
|
||||
if ((dodag->dodag_conf_counter % 3) == 0) {
|
||||
ng_rpl_opt_dodag_conf_t *dodag_conf;
|
||||
dodag_conf = (ng_rpl_opt_dodag_conf_t *) pos;
|
||||
dodag_conf->type = NG_RPL_OPT_DODAG_CONF;
|
||||
dodag_conf->length = NG_RPL_OPT_DODAG_CONF_LEN;
|
||||
dodag_conf->flags_a_pcs = 0;
|
||||
dodag_conf->dio_int_doubl = dodag->dio_interval_doubl;
|
||||
dodag_conf->dio_int_min = dodag->dio_min;
|
||||
dodag_conf->dio_redun = dodag->dio_redun;
|
||||
dodag_conf->max_rank_inc = byteorder_htons(dodag->instance->max_rank_inc);
|
||||
dodag_conf->min_hop_rank_inc = byteorder_htons(dodag->instance->min_hop_rank_inc);
|
||||
dodag_conf->ocp = byteorder_htons(dodag->instance->of->ocp);
|
||||
dodag_conf->reserved = 0;
|
||||
dodag_conf->default_lifetime = dodag->default_lifetime;
|
||||
dodag_conf->lifetime_unit = byteorder_htons(dodag->lifetime_unit);
|
||||
pos += sizeof(*dodag_conf);
|
||||
}
|
||||
|
||||
dodag->dodag_conf_counter++;
|
||||
_ng_rpl_send(pkt, NULL, destination, &dodag->dodag_id);
|
||||
}
|
||||
|
||||
void ng_rpl_send_DIS(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination)
|
||||
{
|
||||
(void) dodag;
|
||||
ng_pktsnip_t *pkt;
|
||||
ng_icmpv6_hdr_t *icmp;
|
||||
ng_rpl_dis_t *dis;
|
||||
/* TODO: Currently the DIS is too small so that wireshark complains about an incorrect
|
||||
* ethernet frame check sequence. In order to prevent this, 4 PAD1 options are added.
|
||||
* This will be addressed in follow-up PRs */
|
||||
int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dis_t) + 4;
|
||||
|
||||
if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DIS, size)) == NULL) {
|
||||
DEBUG("RPL: Send DIS - no space left in packet buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
icmp = (ng_icmpv6_hdr_t *)pkt->data;
|
||||
dis = (ng_rpl_dis_t *)(icmp + 1);
|
||||
dis->flags = 0;
|
||||
dis->reserved = 0;
|
||||
/* TODO: see above TODO */
|
||||
memset((dis + 1), 0, 4);
|
||||
|
||||
_ng_rpl_send(pkt, NULL, destination, (dodag ? &dodag->dodag_id : NULL));
|
||||
}
|
||||
|
||||
void ng_rpl_recv_DIS(ng_rpl_dis_t *dis, ipv6_addr_t *src, ipv6_addr_t *dst, uint16_t len)
|
||||
{
|
||||
/* TODO handle Solicited Information Option */
|
||||
(void) dis;
|
||||
(void) len;
|
||||
|
||||
if (ipv6_addr_is_multicast(dst)) {
|
||||
for (uint8_t i = 0; i < NG_RPL_DODAGS_NUMOF; ++i) {
|
||||
if (ng_rpl_dodags[i].state != 0) {
|
||||
trickle_reset_timer(&ng_rpl_dodags[i].trickle);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (uint8_t i = 0; i < NG_RPL_DODAGS_NUMOF; ++i) {
|
||||
if (ng_rpl_dodags[i].state != 0) {
|
||||
ng_rpl_dodags[i].dodag_conf_counter = 0;
|
||||
ng_rpl_send_DIO(&ng_rpl_dodags[i], src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @todo allow target prefixes in target options to be of variable length */
|
||||
bool _parse_options(int msg_type, ng_rpl_dodag_t *dodag, ng_rpl_opt_t *opt, uint16_t len,
|
||||
ipv6_addr_t *src)
|
||||
{
|
||||
uint16_t l = 0;
|
||||
ng_rpl_opt_target_t *first_target = NULL;
|
||||
while(l < len) {
|
||||
if ((opt->type != NG_RPL_OPT_PAD1) && (len < opt->length + sizeof(ng_rpl_opt_t) + l)) {
|
||||
/* return false to delete the dodag,
|
||||
* because former options may also contain errors */
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(opt->type) {
|
||||
case (NG_RPL_OPT_PAD1): {
|
||||
DEBUG("RPL: PAD1 option parsed\n");
|
||||
l += 1;
|
||||
opt = (ng_rpl_opt_t *) (((uint8_t *) opt) + 1);
|
||||
continue;
|
||||
}
|
||||
case (NG_RPL_OPT_PADN): {
|
||||
DEBUG("RPL: PADN option parsed\n");
|
||||
break;
|
||||
}
|
||||
case (NG_RPL_OPT_DODAG_CONF): {
|
||||
if (msg_type != NG_RPL_ICMPV6_CODE_DIO) {
|
||||
DEBUG("RPL: Ignore DODAG CONF DIO option\n");
|
||||
return true;
|
||||
}
|
||||
DEBUG("RPL: DODAG CONF DIO option parsed\n");
|
||||
ng_rpl_opt_dodag_conf_t *dc = (ng_rpl_opt_dodag_conf_t *) opt;
|
||||
ng_rpl_of_t *of = ng_rpl_get_of_for_ocp(byteorder_ntohs(dc->ocp));
|
||||
if (of != NULL) {
|
||||
dodag->instance->of = of;
|
||||
}
|
||||
else {
|
||||
DEBUG("RPL: Unsupported OCP 0x%02x\n", byteorder_ntohs(dc->ocp));
|
||||
dodag->instance->of = ng_rpl_get_of_for_ocp(NG_RPL_DEFAULT_OCP);
|
||||
}
|
||||
dodag->dio_interval_doubl = dc->dio_int_doubl;
|
||||
dodag->dio_min = dc->dio_int_min;
|
||||
dodag->dio_redun = dc->dio_redun;
|
||||
dodag->instance->max_rank_inc = byteorder_ntohs(dc->max_rank_inc);
|
||||
dodag->instance->min_hop_rank_inc = byteorder_ntohs(dc->min_hop_rank_inc);
|
||||
dodag->default_lifetime = dc->default_lifetime;
|
||||
dodag->lifetime_unit = byteorder_ntohs(dc->lifetime_unit);
|
||||
dodag->trickle.Imin = (1 << dodag->dio_min);
|
||||
dodag->trickle.Imax = dodag->dio_interval_doubl;
|
||||
dodag->trickle.k = dodag->dio_redun;
|
||||
break;
|
||||
}
|
||||
case (NG_RPL_OPT_TARGET): {
|
||||
if (msg_type != NG_RPL_ICMPV6_CODE_DAO) {
|
||||
DEBUG("RPL: Ignore RPL TARGET DAO option\n");
|
||||
return true;
|
||||
}
|
||||
DEBUG("RPL: RPL TARGET DAO option parsed\n");
|
||||
kernel_pid_t if_id = ng_ipv6_netif_find_by_prefix(NULL, &dodag->dodag_id);
|
||||
if (if_id == KERNEL_PID_UNDEF) {
|
||||
DEBUG("RPL: no interface found for the configured DODAG id\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ng_rpl_opt_target_t *target = (ng_rpl_opt_target_t *) opt;
|
||||
if (first_target == NULL) {
|
||||
first_target = target;
|
||||
}
|
||||
|
||||
fib_add_entry(if_id, target->target.u8, sizeof(ipv6_addr_t), AF_INET6, src->u8,
|
||||
sizeof(ipv6_addr_t), AF_INET6,
|
||||
(dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS);
|
||||
break;
|
||||
}
|
||||
case (NG_RPL_OPT_TRANSIT): {
|
||||
if (msg_type != NG_RPL_ICMPV6_CODE_DAO) {
|
||||
DEBUG("RPL: Ignore RPL TRANSIT INFO DAO option\n");
|
||||
return true;
|
||||
}
|
||||
DEBUG("RPL: RPL TRANSIT INFO DAO option parsed\n");
|
||||
ng_rpl_opt_transit_t *transit = (ng_rpl_opt_transit_t *) opt;
|
||||
if (first_target == NULL) {
|
||||
DEBUG("RPL: Encountered a RPL TRANSIT DAO option without \
|
||||
a preceding RPL TARGET DAO option\n");
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
fib_update_entry(first_target->target.u8, sizeof(ipv6_addr_t),
|
||||
src->u8, sizeof(ipv6_addr_t), AF_INET6,
|
||||
(transit->path_lifetime * dodag->lifetime_unit * SEC_IN_MS));
|
||||
first_target = (ng_rpl_opt_target_t *) (((uint8_t *) (first_target)) +
|
||||
sizeof(ng_rpl_opt_t) + first_target->length);
|
||||
}
|
||||
while (first_target->type == NG_RPL_OPT_TARGET);
|
||||
|
||||
first_target = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
l += opt->length + sizeof(ng_rpl_opt_t);
|
||||
opt = (ng_rpl_opt_t *) (((uint8_t *) (opt + 1)) + opt->length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ng_rpl_recv_DIO(ng_rpl_dio_t *dio, ipv6_addr_t *src, uint16_t len)
|
||||
{
|
||||
ng_rpl_instance_t *inst = NULL;
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
|
||||
len -= (sizeof(ng_rpl_dio_t) + sizeof(ng_icmpv6_hdr_t));
|
||||
|
||||
if (ng_rpl_instance_add(dio->instance_id, &inst)) {
|
||||
inst->mop = (dio->g_mop_prf >> NG_RPL_MOP_SHIFT) & NG_RPL_SHIFTED_MOP_MASK;
|
||||
inst->of = ng_rpl_get_of_for_ocp(NG_RPL_DEFAULT_OCP);
|
||||
}
|
||||
else if (inst == NULL) {
|
||||
DEBUG("RPL: Could not allocate a new instance.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((byteorder_ntohs(dio->rank) == NG_RPL_INFINITE_RANK) &&
|
||||
(ng_rpl_dodag_get(inst, &dio->dodag_id) == NULL)) {
|
||||
DEBUG("RPL: ignore INFINITE_RANK DIO when we are not part of this DODAG\n");
|
||||
ng_rpl_instance_remove(inst);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ng_rpl_dodag_add(inst, &dio->dodag_id, &dodag)) {
|
||||
DEBUG("RPL: Joined DODAG (%s).\n",
|
||||
ipv6_addr_to_str(addr_str, &dio->dodag_id, sizeof(addr_str)));
|
||||
|
||||
ng_rpl_parent_t *parent = NULL;
|
||||
|
||||
if (!ng_rpl_parent_add_by_addr(dodag, src, &parent) && (parent == NULL)) {
|
||||
DEBUG("RPL: Could not allocate new parent.\n");
|
||||
ng_rpl_dodag_remove(dodag);
|
||||
return;
|
||||
}
|
||||
|
||||
dodag->version = dio->version_number;
|
||||
|
||||
parent->rank = byteorder_ntohs(dio->rank);
|
||||
|
||||
if(!_parse_options(NG_RPL_ICMPV6_CODE_DIO, dodag, (ng_rpl_opt_t *)(dio + 1), len, NULL)) {
|
||||
ng_rpl_dodag_remove(dodag);
|
||||
return;
|
||||
}
|
||||
|
||||
ng_rpl_delay_dao(dodag);
|
||||
trickle_start(ng_rpl_pid, &dodag->trickle, NG_RPL_MSG_TYPE_TRICKLE_INTERVAL,
|
||||
NG_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min),
|
||||
dodag->dio_interval_doubl, dodag->dio_redun);
|
||||
|
||||
ng_rpl_parent_update(dodag, parent);
|
||||
return;
|
||||
}
|
||||
else if (dodag == NULL) {
|
||||
DEBUG("RPL: Could not allocate a new DODAG.\n");
|
||||
if (inst->dodags == NULL) {
|
||||
ng_rpl_instance_remove(inst);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (dodag->instance->mop !=
|
||||
((dio->g_mop_prf >> NG_RPL_MOP_SHIFT) & NG_RPL_SHIFTED_MOP_MASK)) {
|
||||
DEBUG("RPL: invalid MOP for this instance.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NG_RPL_COUNTER_GREATER_THAN(dio->version_number, dodag->version)) {
|
||||
if (dodag->node_status == NG_RPL_ROOT_NODE) {
|
||||
dodag->version = NG_RPL_COUNTER_INCREMENT(dio->version_number);
|
||||
trickle_reset_timer(&dodag->trickle);
|
||||
}
|
||||
else {
|
||||
dodag->version = dio->version_number;
|
||||
ng_rpl_local_repair(dodag);
|
||||
}
|
||||
}
|
||||
else if (NG_RPL_COUNTER_GREATER_THAN(dodag->version, dio->version_number)) {
|
||||
trickle_reset_timer(&dodag->trickle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dodag->node_status == NG_RPL_ROOT_NODE) {
|
||||
if (byteorder_ntohs(dio->rank) != NG_RPL_INFINITE_RANK) {
|
||||
trickle_increment_counter(&dodag->trickle);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
dodag->grounded = dio->g_mop_prf >> NG_RPL_GROUNDED_SHIFT;
|
||||
dodag->prf = dio->g_mop_prf & NG_RPL_PRF_MASK;
|
||||
|
||||
ng_rpl_parent_t *parent = NULL;
|
||||
|
||||
if (!ng_rpl_parent_add_by_addr(dodag, src, &parent) && (parent == NULL)) {
|
||||
DEBUG("RPL: Could not allocate new parent.\n");
|
||||
if (dodag->parents == NULL) {
|
||||
ng_rpl_dodag_remove(dodag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* cppcheck-suppress nullPointer */
|
||||
else if (parent != NULL) {
|
||||
trickle_increment_counter(&dodag->trickle);
|
||||
}
|
||||
|
||||
parent->rank = byteorder_ntohs(dio->rank);
|
||||
|
||||
if(!_parse_options(NG_RPL_ICMPV6_CODE_DIO, dodag, (ng_rpl_opt_t *)(dio + 1), len, NULL)) {
|
||||
ng_rpl_dodag_remove(dodag);
|
||||
return;
|
||||
}
|
||||
|
||||
ng_rpl_parent_update(dodag, parent);
|
||||
|
||||
if (parent->state != 0) {
|
||||
if (dodag->parents && (parent == dodag->parents) && (parent->dtsn != dio->dtsn)) {
|
||||
ng_rpl_delay_dao(dodag);
|
||||
}
|
||||
parent->dtsn = dio->dtsn;
|
||||
}
|
||||
}
|
||||
|
||||
void _dao_fill_target(ng_rpl_opt_target_t *target, ipv6_addr_t *addr)
|
||||
{
|
||||
target->type = NG_RPL_OPT_TARGET;
|
||||
target->length = sizeof(target->flags) + sizeof(target->prefix_length) + sizeof(target->target);
|
||||
target->flags = 0;
|
||||
target->prefix_length = 128;
|
||||
target->target = *addr;
|
||||
}
|
||||
|
||||
void ng_rpl_send_DAO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_t lifetime)
|
||||
{
|
||||
size_t dst_size = NG_RPL_PARENTS_NUMOF;
|
||||
fib_destination_set_entry_t fib_dest_set[NG_RPL_PARENTS_NUMOF];
|
||||
|
||||
if (dodag == NULL) {
|
||||
DEBUG("RPL: Error - trying to send DAO without being part of a dodag.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dodag->node_status == NG_RPL_ROOT_NODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (destination == NULL) {
|
||||
if (dodag->parents == NULL) {
|
||||
DEBUG("RPL: dodag has no preferred parent\n");
|
||||
return;
|
||||
}
|
||||
|
||||
destination = &(dodag->parents->addr);
|
||||
}
|
||||
|
||||
ng_pktsnip_t *pkt;
|
||||
ng_icmpv6_hdr_t *icmp;
|
||||
ng_rpl_dao_t *dao;
|
||||
ng_rpl_opt_target_t *target;
|
||||
ng_rpl_opt_transit_t *transit;
|
||||
|
||||
/* find my address */
|
||||
ipv6_addr_t *me = NULL;
|
||||
ng_ipv6_netif_find_by_prefix(&me, &dodag->dodag_id);
|
||||
if (me == NULL) {
|
||||
DEBUG("RPL: no address configured\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ng_ipv6_netif_addr_t *me_netif = ng_ipv6_netif_addr_get(me);
|
||||
if (me_netif == NULL) {
|
||||
DEBUG("RPL: no netif address found for %s\n", ipv6_addr_to_str(addr_str, me,
|
||||
sizeof(addr_str)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* find prefix for my address */
|
||||
ipv6_addr_t prefix;
|
||||
ipv6_addr_init_prefix(&prefix, me, me_netif->prefix_len);
|
||||
fib_get_destination_set(prefix.u8, sizeof(ipv6_addr_t), fib_dest_set, &dst_size);
|
||||
|
||||
int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dao_t) +
|
||||
(sizeof(ng_rpl_opt_target_t) * (dst_size + 1)) + sizeof(ng_rpl_opt_transit_t);
|
||||
|
||||
if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DAO, size)) == NULL) {
|
||||
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
icmp = (ng_icmpv6_hdr_t *)pkt->data;
|
||||
dao = (ng_rpl_dao_t *)(icmp + 1);
|
||||
|
||||
dao->instance_id = dodag->instance->id;
|
||||
/* set the D flag to indicate that a DODAG id is present */
|
||||
/* set the K flag to indicate that a ACKs are required */
|
||||
dao->k_d_flags = ((1 << 6) | (1 << 7));
|
||||
dao->dao_sequence = dodag->dao_seq;
|
||||
dao->dodag_id = dodag->dodag_id;
|
||||
dao->reserved = 0;
|
||||
|
||||
/* add own address */
|
||||
target = (ng_rpl_opt_target_t *) (dao + 1);
|
||||
_dao_fill_target(target, me);
|
||||
/* add children */
|
||||
for (size_t i = 0; i < dst_size; ++i) {
|
||||
target = (target + 1);
|
||||
_dao_fill_target(target, ((ipv6_addr_t *) fib_dest_set[i].dest));
|
||||
}
|
||||
|
||||
transit = (ng_rpl_opt_transit_t *) (target + 1);
|
||||
transit->type = NG_RPL_OPT_TRANSIT;
|
||||
transit->length = sizeof(transit->e_flags) + sizeof(transit->path_control) +
|
||||
sizeof(transit->path_sequence) + sizeof(transit->path_lifetime);
|
||||
transit->e_flags = 0;
|
||||
transit->path_control = 0;
|
||||
transit->path_sequence = 0;
|
||||
transit->path_lifetime = lifetime;
|
||||
|
||||
_ng_rpl_send(pkt, NULL, destination, &dodag->dodag_id);
|
||||
|
||||
NG_RPL_COUNTER_INCREMENT(dodag->dao_seq);
|
||||
}
|
||||
|
||||
void ng_rpl_send_DAO_ACK(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_t seq)
|
||||
{
|
||||
if (dodag == NULL) {
|
||||
DEBUG("RPL: Error - trying to send DAO-ACK without being part of a dodag.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ng_pktsnip_t *pkt;
|
||||
ng_icmpv6_hdr_t *icmp;
|
||||
ng_rpl_dao_ack_t *dao_ack;
|
||||
int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dao_ack_t);
|
||||
|
||||
if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DAO_ACK, size)) == NULL) {
|
||||
DEBUG("RPL: Send DAOACK - no space left in packet buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
icmp = (ng_icmpv6_hdr_t *)pkt->data;
|
||||
dao_ack = (ng_rpl_dao_ack_t *)(icmp + 1);
|
||||
|
||||
dao_ack->instance_id = dodag->instance->id;
|
||||
/* set the D flag to indicate that a DODAG id is present */
|
||||
dao_ack->d_reserved = (1 << 7);
|
||||
dao_ack->dao_sequence = seq;
|
||||
dao_ack->status = 0;
|
||||
dao_ack->dodag_id = dodag->dodag_id;
|
||||
|
||||
_ng_rpl_send(pkt, NULL, destination, &dodag->dodag_id);
|
||||
}
|
||||
|
||||
void ng_rpl_recv_DAO(ng_rpl_dao_t *dao, ipv6_addr_t *src, uint16_t len)
|
||||
{
|
||||
ng_rpl_instance_t *inst = NULL;
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
if ((inst = ng_rpl_instance_get(dao->instance_id)) == NULL) {
|
||||
DEBUG("RPL: DAO with unknown instance id (%d) received\n", dao->instance_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if the D flag is set before accessing the DODAG id */
|
||||
if (!(dao->k_d_flags & (1 << 6))) {
|
||||
DEBUG("RPL: DAO with D flag unset - global instances not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dodag = ng_rpl_dodag_get(inst, &dao->dodag_id)) == NULL) {
|
||||
DEBUG("RPL: DAO with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
|
||||
&dao->dodag_id, sizeof(addr_str)));
|
||||
return;
|
||||
}
|
||||
|
||||
len -= (sizeof(ng_rpl_dao_t) + sizeof(ng_icmpv6_hdr_t));
|
||||
if(!_parse_options(NG_RPL_ICMPV6_CODE_DAO, dodag, (ng_rpl_opt_t *) (dao + 1), len, src)) {
|
||||
ng_rpl_dodag_remove(dodag);
|
||||
return;
|
||||
}
|
||||
|
||||
/* send a DAO-ACK if K flag is set */
|
||||
if (dao->k_d_flags & (1 << 7)) {
|
||||
ng_rpl_send_DAO_ACK(dodag, src, dao->dao_sequence);
|
||||
}
|
||||
|
||||
ng_rpl_delay_dao(dodag);
|
||||
}
|
||||
|
||||
void ng_rpl_recv_DAO_ACK(ng_rpl_dao_ack_t *dao_ack)
|
||||
{
|
||||
ng_rpl_instance_t *inst = NULL;
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
if ((inst = ng_rpl_instance_get(dao_ack->instance_id)) == NULL) {
|
||||
DEBUG("RPL: DAO-ACK with unknown instance id (%d) received\n", dao_ack->instance_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if the D flag is set before accessing the DODAG id */
|
||||
if (!(dao_ack->d_reserved & (1 << 7))) {
|
||||
DEBUG("RPL: DAO-ACK with D flag unset - global instances not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dodag = ng_rpl_dodag_get(inst, &dao_ack->dodag_id)) == NULL) {
|
||||
DEBUG("RPL: DAO-ACK with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
|
||||
&dao_ack->dodag_id, sizeof(addr_str)));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dao_ack->status != 0) && (dao_ack->dao_sequence != dodag->dao_seq)) {
|
||||
DEBUG("RPL: DAO-ACK sequence (%d) does not match expected sequence (%d)\n",
|
||||
dao_ack->dao_sequence, dodag->dao_seq);
|
||||
return;
|
||||
}
|
||||
|
||||
dodag->dao_ack_received = true;
|
||||
ng_rpl_long_delay_dao(dodag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
398
sys/net/routing/ng_rpl/ng_rpl_dodag.c
Normal file
398
sys/net/routing/ng_rpl/ng_rpl_dodag.c
Normal file
@ -0,0 +1,398 @@
|
||||
/**
|
||||
* Copyright (C) 2013, 2014 INRIA.
|
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*
|
||||
* 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 Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "net/ng_rpl/dodag.h"
|
||||
#include "net/ng_rpl/structs.h"
|
||||
#include "utlist.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if ENABLE_DEBUG && defined(MODULE_PV6_ADDR)
|
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
void rpl_trickle_send_dio(void *args)
|
||||
{
|
||||
ng_rpl_dodag_t *dodag = (ng_rpl_dodag_t *) args;
|
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
|
||||
ng_rpl_send_DIO(dodag, &all_RPL_nodes);
|
||||
DEBUG("trickle callback: Instance (%d) | DODAG: (%s)\n", dodag->instance->id,
|
||||
ipv6_addr_to_str(addr_str,&dodag->dodag_id, sizeof(addr_str)));
|
||||
}
|
||||
|
||||
bool ng_rpl_instance_add(uint8_t instance_id, ng_rpl_instance_t **inst)
|
||||
{
|
||||
*inst = NULL;
|
||||
bool first = true;
|
||||
for (uint8_t i = 0; i < NG_RPL_INSTANCES_NUMOF; ++i) {
|
||||
/* save position to the first unused instance */
|
||||
if ((ng_rpl_instances[i].state == 0) && first) {
|
||||
*inst = &ng_rpl_instances[i];
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
else if ((ng_rpl_instances[i].state != 0) && (ng_rpl_instances[i].id == instance_id)) {
|
||||
DEBUG("Instance with id %d exists\n", instance_id);
|
||||
*inst = &ng_rpl_instances[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (*inst != NULL) {
|
||||
(*inst)->id = instance_id;
|
||||
(*inst)->state = 1;
|
||||
(*inst)->max_rank_inc = NG_RPL_DEFAULT_MAX_RANK_INCREASE;
|
||||
(*inst)->min_hop_rank_inc = NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE;
|
||||
(*inst)->dodags = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* no space available to allocate a new instance */
|
||||
DEBUG("Could not allocate a new RPL instance\n");
|
||||
*inst = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ng_rpl_instance_remove_by_id(uint8_t instance_id)
|
||||
{
|
||||
for(uint8_t i = 0; i < NG_RPL_INSTANCES_NUMOF; ++i) {
|
||||
if (ng_rpl_instances[i].id == instance_id) {
|
||||
ng_rpl_dodag_t *elt, *tmp;
|
||||
LL_FOREACH_SAFE(ng_rpl_instances[i].dodags, elt, tmp) {
|
||||
ng_rpl_dodag_remove(elt);
|
||||
}
|
||||
memset(&ng_rpl_instances[i], 0, sizeof(ng_rpl_instance_t));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ng_rpl_instance_remove(ng_rpl_instance_t *inst)
|
||||
{
|
||||
ng_rpl_dodag_t *elt, *tmp;
|
||||
LL_FOREACH_SAFE(inst->dodags, elt, tmp) {
|
||||
ng_rpl_dodag_remove(elt);
|
||||
}
|
||||
memset(inst, 0, sizeof(ng_rpl_instance_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
ng_rpl_instance_t *ng_rpl_instance_get(uint8_t instance_id)
|
||||
{
|
||||
for (uint8_t i = 0; i < NG_RPL_INSTANCES_NUMOF; ++i) {
|
||||
if (ng_rpl_instances[i].id == instance_id) {
|
||||
return &ng_rpl_instances[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ng_rpl_dodag_add(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id, ng_rpl_dodag_t **dodag)
|
||||
{
|
||||
if ((instance == NULL) || instance->state == 0) {
|
||||
DEBUG("Instance is NULL or unused\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
*dodag = NULL;
|
||||
bool first = true;
|
||||
for (uint8_t i = 0; i < NG_RPL_DODAGS_NUMOF; ++i) {
|
||||
/* save position to the first unused instance */
|
||||
if ((ng_rpl_dodags[i].state == 0) && first) {
|
||||
*dodag = &ng_rpl_dodags[i];
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
else if ((ng_rpl_dodags[i].state != 0) &&
|
||||
(ng_rpl_dodags[i].instance->id == instance->id) &&
|
||||
ipv6_addr_equal(&ng_rpl_dodags[i].dodag_id, dodag_id)) {
|
||||
DEBUG("DODAG with id: %s does exist\n", ipv6_addr_to_str(addr_str, dodag_id,
|
||||
sizeof(addr_str)));
|
||||
*dodag = &ng_rpl_dodags[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (*dodag != NULL) {
|
||||
(*dodag)->instance = instance;
|
||||
LL_APPEND(instance->dodags, *dodag);
|
||||
(*dodag)->state = 1;
|
||||
(*dodag)->dodag_id = *dodag_id;
|
||||
(*dodag)->my_rank = NG_RPL_INFINITE_RANK;
|
||||
(*dodag)->trickle.callback.func = &rpl_trickle_send_dio;
|
||||
(*dodag)->trickle.callback.args = *dodag;
|
||||
(*dodag)->dio_interval_doubl = NG_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS;
|
||||
(*dodag)->dio_min = NG_RPL_DEFAULT_DIO_INTERVAL_MIN;
|
||||
(*dodag)->dio_redun = NG_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT;
|
||||
(*dodag)->default_lifetime = NG_RPL_DEFAULT_LIFETIME;
|
||||
(*dodag)->lifetime_unit = NG_RPL_LIFETIME_UNIT;
|
||||
(*dodag)->node_status = NG_RPL_NORMAL_NODE;
|
||||
(*dodag)->dao_seq = NG_RPL_COUNTER_INIT;
|
||||
(*dodag)->dtsn = 0;
|
||||
(*dodag)->dao_ack_received = false;
|
||||
(*dodag)->dao_counter = 0;
|
||||
(*dodag)->parents = NULL;
|
||||
(*dodag)->cleanup_time = timex_set(NG_RPL_CLEANUP_TIME, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* no space available to allocate a new dodag */
|
||||
DEBUG("Could not allocate a new RPL DODAG\n");
|
||||
*dodag = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ng_rpl_dodag_remove(ng_rpl_dodag_t *dodag)
|
||||
{
|
||||
ng_rpl_dodag_remove_all_parents(dodag);
|
||||
ng_rpl_instance_t *inst = dodag->instance;
|
||||
LL_DELETE(inst->dodags, dodag);
|
||||
trickle_stop(&dodag->trickle);
|
||||
vtimer_remove(&dodag->dao_timer);
|
||||
vtimer_remove(&dodag->cleanup_timer);
|
||||
memset(dodag, 0, sizeof(ng_rpl_dodag_t));
|
||||
if (inst->dodags == NULL) {
|
||||
ng_rpl_instance_remove(inst);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ng_rpl_dodag_remove_all_parents(ng_rpl_dodag_t *dodag)
|
||||
{
|
||||
ng_rpl_parent_t *elt, *tmp;
|
||||
LL_FOREACH_SAFE(dodag->parents, elt, tmp) {
|
||||
ng_rpl_parent_remove(elt);
|
||||
}
|
||||
vtimer_remove(&dodag->cleanup_timer);
|
||||
vtimer_set_msg(&dodag->cleanup_timer, dodag->cleanup_time, ng_rpl_pid,
|
||||
NG_RPL_MSG_TYPE_CLEANUP_HANDLE, dodag);
|
||||
}
|
||||
|
||||
ng_rpl_dodag_t *ng_rpl_dodag_get(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id)
|
||||
{
|
||||
if ((instance == NULL) || (instance->state == 0)) {
|
||||
DEBUG("Instance is NULL or unused\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
LL_FOREACH(instance->dodags, dodag) {
|
||||
if (ipv6_addr_equal(&dodag->dodag_id, dodag_id)) {
|
||||
return dodag;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ng_rpl_parent_add_by_addr(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr, ng_rpl_parent_t **parent)
|
||||
{
|
||||
if ((dodag == NULL) || (dodag->state == 0)) {
|
||||
DEBUG("DODAG is NULL or unused\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
*parent = NULL;
|
||||
bool first = true;
|
||||
for (uint8_t i = 0; i < NG_RPL_PARENTS_NUMOF; ++i) {
|
||||
/* save position to the first unused instance */
|
||||
if ((ng_rpl_parents[i].state == 0) && first) {
|
||||
*parent = &ng_rpl_parents[i];
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
/* return false if parent exists */
|
||||
else if ((ng_rpl_parents[i].state != 0) &&
|
||||
(ng_rpl_parents[i].dodag->instance->id == dodag->instance->id) &&
|
||||
ipv6_addr_equal(&ng_rpl_parents[i].dodag->dodag_id, &dodag->dodag_id) &&
|
||||
ipv6_addr_equal(&ng_rpl_parents[i].addr, addr)) {
|
||||
DEBUG("parent with addr: %s does exist\n", ipv6_addr_to_str(addr_str, addr,
|
||||
sizeof(addr_str)));
|
||||
*parent = &ng_rpl_parents[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (*parent != NULL) {
|
||||
(*parent)->dodag = dodag;
|
||||
LL_APPEND(dodag->parents, *parent);
|
||||
(*parent)->state = 1;
|
||||
(*parent)->addr = *addr;
|
||||
if ((*parent) == (*parent)->dodag->parents) {
|
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
|
||||
ipv6_addr_t def = IPV6_ADDR_UNSPECIFIED;
|
||||
kernel_pid_t if_id = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
|
||||
if (if_id == KERNEL_PID_UNDEF) {
|
||||
DEBUG("RPL: no interface found for the parent addres\n");
|
||||
return false;
|
||||
}
|
||||
if (fib_add_entry(if_id, def.u8, sizeof(ipv6_addr_t), AF_INET6, dodag->parents->addr.u8,
|
||||
sizeof(ipv6_addr_t), AF_INET6,
|
||||
(dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS) != 0) {
|
||||
DEBUG("RPL: error adding parent to FIB\n");
|
||||
ng_rpl_parent_remove(*parent);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* no space available to allocate a new parent */
|
||||
DEBUG("Could not allocate a new parent\n");
|
||||
*parent = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ng_rpl_parent_t *ng_rpl_parent_get(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr)
|
||||
{
|
||||
if ((dodag == NULL) || (dodag->state == 0)) {
|
||||
DEBUG("DODAG is NULL or unused\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ng_rpl_parent_t *parent = NULL;
|
||||
LL_FOREACH(dodag->parents, parent) {
|
||||
if (ipv6_addr_equal(&parent->addr, addr)) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ng_rpl_parent_remove(ng_rpl_parent_t *parent)
|
||||
{
|
||||
if (parent == parent->dodag->parents) {
|
||||
ipv6_addr_t def = { .u64 = {{0}, {0}} };
|
||||
fib_remove_entry(def.u8, sizeof(ipv6_addr_t));
|
||||
}
|
||||
ng_rpl_dodag_t *dodag = parent->dodag;
|
||||
LL_DELETE(dodag->parents, parent);
|
||||
memset(parent, 0, sizeof(ng_rpl_parent_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ng_rpl_local_repair(ng_rpl_dodag_t *dodag)
|
||||
{
|
||||
DEBUG("RPL: [INFO] Local Repair started\n");
|
||||
|
||||
dodag->dtsn++;
|
||||
|
||||
if (dodag->parents) {
|
||||
ng_rpl_dodag_remove_all_parents(dodag);
|
||||
ipv6_addr_t def = IPV6_ADDR_UNSPECIFIED;
|
||||
fib_remove_entry(def.u8, sizeof(ipv6_addr_t));
|
||||
}
|
||||
|
||||
if (dodag->my_rank != NG_RPL_INFINITE_RANK) {
|
||||
trickle_reset_timer(&dodag->trickle);
|
||||
vtimer_remove(&dodag->cleanup_timer);
|
||||
vtimer_set_msg(&dodag->cleanup_timer, dodag->cleanup_time, ng_rpl_pid,
|
||||
NG_RPL_MSG_TYPE_CLEANUP_HANDLE, dodag);
|
||||
}
|
||||
|
||||
dodag->my_rank = NG_RPL_INFINITE_RANK;
|
||||
}
|
||||
|
||||
void ng_rpl_parent_update(ng_rpl_dodag_t *dodag, ng_rpl_parent_t *parent)
|
||||
{
|
||||
uint16_t old_rank = dodag->my_rank;
|
||||
timex_t now;
|
||||
vtimer_now(&now);
|
||||
ipv6_addr_t def = IPV6_ADDR_UNSPECIFIED;
|
||||
|
||||
/* update Parent lifetime */
|
||||
if (parent != NULL) {
|
||||
parent->lifetime.seconds = now.seconds + (dodag->default_lifetime * dodag->lifetime_unit);
|
||||
parent->lifetime.microseconds = 0;
|
||||
if (parent == dodag->parents) {
|
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
|
||||
kernel_pid_t if_id;
|
||||
if ((if_id = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes)) != KERNEL_PID_UNDEF) {
|
||||
fib_add_entry(if_id, def.u8, sizeof(ipv6_addr_t), AF_INET6,
|
||||
dodag->parents->addr.u8, sizeof(ipv6_addr_t), AF_INET6,
|
||||
(dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ng_rpl_find_preferred_parent(dodag) == NULL) {
|
||||
ng_rpl_local_repair(dodag);
|
||||
}
|
||||
|
||||
if (dodag->parents && (old_rank != dodag->my_rank)) {
|
||||
trickle_reset_timer(&dodag->trickle);
|
||||
}
|
||||
}
|
||||
|
||||
int _compare_parents(ng_rpl_parent_t *p1, ng_rpl_parent_t *p2)
|
||||
{
|
||||
return p1->dodag->instance->of->which_parent(p1, p2) == p1 ? -1 : 1;
|
||||
}
|
||||
|
||||
ng_rpl_parent_t *ng_rpl_find_preferred_parent(ng_rpl_dodag_t *dodag)
|
||||
{
|
||||
ipv6_addr_t def = IPV6_ADDR_UNSPECIFIED;
|
||||
ng_rpl_parent_t *old_best = dodag->parents;
|
||||
|
||||
LL_SORT(dodag->parents, _compare_parents);
|
||||
|
||||
if (dodag->parents == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
else if (dodag->parents->rank >= dodag->my_rank) {
|
||||
ng_rpl_parent_remove(dodag->parents);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dodag->my_rank = dodag->instance->of->calc_rank(dodag->parents, 0);
|
||||
ng_rpl_parent_t *elt, *tmp;
|
||||
LL_FOREACH_SAFE(dodag->parents, elt, tmp) {
|
||||
if (dodag->parents->rank < elt->rank) {
|
||||
ng_rpl_parent_remove(elt);
|
||||
}
|
||||
}
|
||||
|
||||
if (old_best != dodag->parents) {
|
||||
if (dodag->instance->mop != NG_RPL_MOP_NO_DOWNWARD_ROUTES) {
|
||||
ng_rpl_send_DAO(dodag, &old_best->addr, 0);
|
||||
ng_rpl_delay_dao(dodag);
|
||||
}
|
||||
trickle_reset_timer(&dodag->trickle);
|
||||
|
||||
fib_remove_entry(def.u8, sizeof(ipv6_addr_t));
|
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
|
||||
|
||||
kernel_pid_t if_id = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
|
||||
|
||||
if (if_id == KERNEL_PID_UNDEF) {
|
||||
DEBUG("RPL: no interface found for the parent addres\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fib_add_entry(if_id, def.u8, sizeof(ipv6_addr_t), AF_INET6, dodag->parents->addr.u8,
|
||||
sizeof(ipv6_addr_t), AF_INET6,
|
||||
(dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS);
|
||||
}
|
||||
|
||||
return dodag->parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
94
sys/net/routing/ng_rpl/of0.c
Normal file
94
sys/net/routing/ng_rpl/of0.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Oliver Hahm <oliver.hahm@inria.fr>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup net_ng_rpl
|
||||
* @{
|
||||
* @file
|
||||
* @brief Objective Function Zero.
|
||||
*
|
||||
* Implementation of Objective Function Zero.
|
||||
*
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "of0.h"
|
||||
#include "net/ng_rpl.h"
|
||||
#include "net/ng_rpl/structs.h"
|
||||
|
||||
static uint16_t calc_rank(ng_rpl_parent_t *, uint16_t);
|
||||
static ng_rpl_parent_t *which_parent(ng_rpl_parent_t *, ng_rpl_parent_t *);
|
||||
static ng_rpl_dodag_t *which_dodag(ng_rpl_dodag_t *, ng_rpl_dodag_t *);
|
||||
static void reset(ng_rpl_dodag_t *);
|
||||
|
||||
static ng_rpl_of_t ng_rpl_of0 = {
|
||||
0x0,
|
||||
calc_rank,
|
||||
which_parent,
|
||||
which_dodag,
|
||||
reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
ng_rpl_of_t *ng_rpl_get_of0(void)
|
||||
{
|
||||
return &ng_rpl_of0;
|
||||
}
|
||||
|
||||
void reset(ng_rpl_dodag_t *dodag)
|
||||
{
|
||||
/* Nothing to do in OF0 */
|
||||
(void) dodag;
|
||||
}
|
||||
|
||||
uint16_t calc_rank(ng_rpl_parent_t *parent, uint16_t base_rank)
|
||||
{
|
||||
if (base_rank == 0) {
|
||||
if (parent == NULL) {
|
||||
return NG_RPL_INFINITE_RANK;
|
||||
}
|
||||
|
||||
base_rank = parent->rank;
|
||||
}
|
||||
|
||||
uint16_t add;
|
||||
|
||||
if (parent != NULL) {
|
||||
add = parent->dodag->instance->min_hop_rank_inc;
|
||||
}
|
||||
else {
|
||||
add = NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE;
|
||||
}
|
||||
|
||||
if ((base_rank + add) < base_rank) {
|
||||
return NG_RPL_INFINITE_RANK;
|
||||
}
|
||||
|
||||
return base_rank + add;
|
||||
}
|
||||
|
||||
/* We simply return the Parent with lower rank */
|
||||
ng_rpl_parent_t *which_parent(ng_rpl_parent_t *p1, ng_rpl_parent_t *p2)
|
||||
{
|
||||
if (p1->rank <= p2->rank) {
|
||||
return p1;
|
||||
}
|
||||
|
||||
return p2;
|
||||
}
|
||||
|
||||
/* Not used yet, as the implementation only makes use of one dodag for now. */
|
||||
ng_rpl_dodag_t *which_dodag(ng_rpl_dodag_t *d1, ng_rpl_dodag_t *d2)
|
||||
{
|
||||
(void) d2;
|
||||
return d1;
|
||||
}
|
43
sys/net/routing/ng_rpl/of0.h
Normal file
43
sys/net/routing/ng_rpl/of0.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Oliver Hahm <oliver.hahm@inria.fr>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup net_ng_rpl
|
||||
* @{
|
||||
* @file
|
||||
* @brief Objective Function Zero.
|
||||
*
|
||||
* Header-file, which defines all functions for the implementation of Objective Function Zero.
|
||||
*
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef OF0_H
|
||||
#define OF0_H
|
||||
|
||||
#include "net/ng_rpl/structs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return the address to the of0 objective function
|
||||
*
|
||||
* @return Address of the of0 objective function
|
||||
*/
|
||||
ng_rpl_of_t *ng_rpl_get_of0(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OF0_H */
|
||||
/**
|
||||
* @}
|
||||
*/
|
54
sys/net/routing/ng_rpl/rpl_of_manager.c
Normal file
54
sys/net/routing/ng_rpl/rpl_of_manager.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* RPL dodag implementation
|
||||
*
|
||||
* Copyright (C) 2014 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 rpl
|
||||
* @{
|
||||
* @file
|
||||
* @brief RPL Objective functions manager
|
||||
* @author Fabian Brandt <fabianbr@zedat.fu-berlin.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "net/ng_rpl.h"
|
||||
#include "net/ng_rpl/of_manager.h"
|
||||
#include "of0.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
/* !!! TODO: port etx/mrhof to the new network stack */
|
||||
|
||||
static ng_rpl_of_t *objective_functions[NG_RPL_IMPLEMENTED_OFS_NUMOF];
|
||||
|
||||
void ng_rpl_of_manager_init(void)
|
||||
{
|
||||
/* insert new objective functions here */
|
||||
objective_functions[0] = ng_rpl_get_of0();
|
||||
/*objective_functions[1] = ng_rpl_get_of_mrhof(); */
|
||||
}
|
||||
|
||||
/* find implemented OF via objective code point */
|
||||
ng_rpl_of_t *ng_rpl_get_of_for_ocp(uint16_t ocp)
|
||||
{
|
||||
for (uint16_t i = 0; i < NG_RPL_IMPLEMENTED_OFS_NUMOF; i++) {
|
||||
if (objective_functions[i] == NULL) {
|
||||
/* fallback if something goes wrong */
|
||||
return ng_rpl_get_of0();
|
||||
}
|
||||
else if (ocp == objective_functions[i]->ocp) {
|
||||
return objective_functions[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
@ -53,6 +53,9 @@ endif
|
||||
ifneq (,$(filter ng_zep ipv6_addr,$(USEMODULE)))
|
||||
SRC += sc_zep.c
|
||||
endif
|
||||
ifneq (,$(filter ng_rpl,$(USEMODULE)))
|
||||
SRC += sc_ng_rpl.c
|
||||
endif
|
||||
|
||||
# TODO
|
||||
# Conditional building not possible at the moment due to
|
||||
|
396
sys/shell/commands/sc_ng_rpl.c
Normal file
396
sys/shell/commands/sc_ng_rpl.c
Normal file
@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_shell_commands.h
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "net/ng_rpl.h"
|
||||
#include "net/ng_rpl/structs.h"
|
||||
#include "net/ng_rpl/dodag.h"
|
||||
#include "utlist.h"
|
||||
#include "trickle.h"
|
||||
|
||||
int _ng_rpl_init(char *arg)
|
||||
{
|
||||
ng_ipv6_netif_t *entry = NULL;
|
||||
kernel_pid_t iface_pid = (kernel_pid_t) atoi(arg);
|
||||
entry = ng_ipv6_netif_get(iface_pid);
|
||||
|
||||
if (entry == NULL) {
|
||||
puts("unknown interface specified");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ng_rpl_init(iface_pid);
|
||||
printf("successfully initialized RPL on interface %d\n", iface_pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl_dodag_root(char *arg1, char *arg2)
|
||||
{
|
||||
uint8_t instance_id = (uint8_t) atoi(arg1);
|
||||
ipv6_addr_t dodag_id;
|
||||
|
||||
if (instance_id == 0) {
|
||||
puts("<instance_id> must be a positive number greater than zero");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ipv6_addr_from_str(&dodag_id, arg2) == NULL) {
|
||||
puts("<dodag_id> must be a valid IPv6 address");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
dodag = ng_rpl_root_init(instance_id, &dodag_id);
|
||||
if (dodag == NULL) {
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
printf("error: could not add DODAG (%s) to instance (%d)\n",
|
||||
ipv6_addr_to_str(addr_str, &dodag_id, sizeof(addr_str)), instance_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("successfully added a new RPL DODAG\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl_instance_remove(char *arg1)
|
||||
{
|
||||
uint8_t instance_id = 0;
|
||||
ng_rpl_instance_t *inst;
|
||||
|
||||
instance_id = (uint8_t) atoi(arg1);
|
||||
if (instance_id == 0) {
|
||||
puts("error: <instance_id> must be a positive number greater than zero");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((inst = ng_rpl_instance_get(instance_id)) == NULL) {
|
||||
printf("error: could not find the instance (%d)\n", instance_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ng_rpl_instance_remove(inst) == false) {
|
||||
printf("error: could not remove instance (%d)\n", instance_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("success: removed instance (%d)\n", instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl_dodag_remove(char *arg1, char *arg2)
|
||||
{
|
||||
uint8_t instance_id = 0;
|
||||
ipv6_addr_t dodag_id;
|
||||
ng_rpl_instance_t *inst;
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
|
||||
instance_id = (uint8_t) atoi(arg1);
|
||||
if (instance_id == 0) {
|
||||
puts("error: <instance_id> must be a positive number greater than zero");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ipv6_addr_from_str(&dodag_id, arg2) == NULL) {
|
||||
puts("error: <dodag_id> must be a valid IPv6 address");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((inst = ng_rpl_instance_get(instance_id)) == NULL) {
|
||||
puts("error: could not find the <instance_id>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((dodag = ng_rpl_dodag_get(inst, &dodag_id)) == NULL) {
|
||||
puts("error: <dodag_id> does not exist for the given <instance_id>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ng_rpl_dodag_remove(dodag) == false) {
|
||||
printf("error: could not remove DODAG (%s) from instance (%d)\n",
|
||||
ipv6_addr_to_str(addr_str, &dodag_id, sizeof(addr_str)),
|
||||
instance_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("success: removed DODAG (%s) from instance (%d)\n",
|
||||
ipv6_addr_to_str(addr_str, &dodag_id, sizeof(addr_str)),
|
||||
instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl_trickle_reset(char *arg1, char *arg2)
|
||||
{
|
||||
uint8_t instance_id = 0;
|
||||
ipv6_addr_t dodag_id;
|
||||
ng_rpl_instance_t *inst;
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
|
||||
instance_id = (uint8_t) atoi(arg1);
|
||||
if (instance_id == 0) {
|
||||
puts("error: <instance_id> must be a positive number greater than zero");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ipv6_addr_from_str(&dodag_id, arg2) == NULL) {
|
||||
puts("error: <dodag_id> must be a valid IPv6 address");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((inst = ng_rpl_instance_get(instance_id)) == NULL) {
|
||||
puts("error: could not find the <instance_id>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((dodag = ng_rpl_dodag_get(inst, &dodag_id)) == NULL) {
|
||||
puts("error: <dodag_id> does not exist for the given <instance_id>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
trickle_reset_timer(&dodag->trickle);
|
||||
|
||||
printf("success: resetted trickle timer of DODAG (%s) from instance (%d)\n",
|
||||
ipv6_addr_to_str(addr_str, &dodag_id, sizeof(addr_str)),
|
||||
instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl_trickle_stop(char *arg1, char *arg2)
|
||||
{
|
||||
uint8_t instance_id = 0;
|
||||
ipv6_addr_t dodag_id;
|
||||
ng_rpl_instance_t *inst;
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
|
||||
instance_id = (uint8_t) atoi(arg1);
|
||||
if (instance_id == 0) {
|
||||
puts("error: <instance_id> must be a positive number greater than zero");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ipv6_addr_from_str(&dodag_id, arg2) == NULL) {
|
||||
puts("error: <dodag_id> must be a valid IPv6 address");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((inst = ng_rpl_instance_get(instance_id)) == NULL) {
|
||||
puts("error: could not find the <instance_id>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((dodag = ng_rpl_dodag_get(inst, &dodag_id)) == NULL) {
|
||||
puts("error: <dodag_id> does not exist for the given <instance_id>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
trickle_stop(&dodag->trickle);
|
||||
|
||||
printf("success: stopped trickle timer of DODAG (%s) from instance (%d)\n",
|
||||
ipv6_addr_to_str(addr_str, &dodag_id, sizeof(addr_str)),
|
||||
instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl_trickle_start(char *arg1, char *arg2)
|
||||
{
|
||||
uint8_t instance_id = 0;
|
||||
ipv6_addr_t dodag_id;
|
||||
ng_rpl_instance_t *inst;
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
|
||||
instance_id = (uint8_t) atoi(arg1);
|
||||
if (instance_id == 0) {
|
||||
puts("error: <instance_id> must be a positive number greater than zero");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ipv6_addr_from_str(&dodag_id, arg2) == NULL) {
|
||||
puts("error: <dodag_id> must be a valid IPv6 address");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((inst = ng_rpl_instance_get(instance_id)) == NULL) {
|
||||
puts("error: could not find the <instance_id>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((dodag = ng_rpl_dodag_get(inst, &dodag_id)) == NULL) {
|
||||
puts("error: <dodag_id> does not exist for the given <instance_id>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
trickle_start(ng_rpl_pid, &dodag->trickle, NG_RPL_MSG_TYPE_TRICKLE_INTERVAL,
|
||||
NG_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min),
|
||||
dodag->dio_interval_doubl, dodag->dio_redun);
|
||||
|
||||
printf("success: started trickle timer of DODAG (%s) from instance (%d)\n",
|
||||
ipv6_addr_to_str(addr_str, &dodag_id, sizeof(addr_str)),
|
||||
instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl_send_dis(void)
|
||||
{
|
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES;
|
||||
ng_rpl_send_DIS(NULL, &all_RPL_nodes);
|
||||
|
||||
puts("success: send a DIS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl_dodag_show(void)
|
||||
{
|
||||
printf("instance table:\t");
|
||||
for (uint8_t i = 0; i < NG_RPL_INSTANCES_NUMOF; ++i) {
|
||||
if (ng_rpl_instances[i].state == 0) {
|
||||
printf("[ ]");
|
||||
}
|
||||
else {
|
||||
printf("[X]");
|
||||
}
|
||||
if (i < (NG_RPL_INSTANCES_NUMOF - 1)) {
|
||||
printf("\t");
|
||||
}
|
||||
else {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
printf("dodag table:\t");
|
||||
for (uint8_t i = 0; i < NG_RPL_DODAGS_NUMOF; ++i) {
|
||||
if (ng_rpl_dodags[i].state == 0) {
|
||||
printf("[ ]");
|
||||
}
|
||||
else {
|
||||
printf("[X]");
|
||||
}
|
||||
if (i < (NG_RPL_DODAGS_NUMOF - 1)) {
|
||||
putchar('\t');
|
||||
}
|
||||
else {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
printf("parent table:\t");
|
||||
for (uint8_t i = 0; i < NG_RPL_PARENTS_NUMOF; ++i) {
|
||||
if (ng_rpl_parents[i].state == 0) {
|
||||
printf("[ ]");
|
||||
}
|
||||
else {
|
||||
printf("[X]");
|
||||
}
|
||||
if (i < (NG_RPL_PARENTS_NUMOF - 1)) {
|
||||
putchar('\t');
|
||||
}
|
||||
}
|
||||
putchar('\n');
|
||||
putchar('\n');
|
||||
|
||||
ng_rpl_dodag_t *dodag = NULL;
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
timex_t now, tc, ti, cleanup;
|
||||
vtimer_now(&now);
|
||||
for (uint8_t i = 0; i < NG_RPL_INSTANCES_NUMOF; ++i) {
|
||||
if (ng_rpl_instances[i].state == 0) {
|
||||
continue;
|
||||
}
|
||||
printf("instance [%d | mop: %d | ocp: %d | mhri: %d | mri %d]\n", ng_rpl_instances[i].id,
|
||||
ng_rpl_instances[i].mop, ng_rpl_instances[i].of->ocp,
|
||||
ng_rpl_instances[i].min_hop_rank_inc, ng_rpl_instances[i].max_rank_inc);
|
||||
LL_FOREACH(ng_rpl_instances[i].dodags, dodag) {
|
||||
tc = timex_sub(dodag->trickle.msg_callback_timer.absolute, now);
|
||||
ti = timex_sub(dodag->trickle.msg_interval_timer.absolute, now);
|
||||
cleanup = timex_sub(dodag->cleanup_timer.absolute, now);
|
||||
timex_normalize(&tc);
|
||||
timex_normalize(&ti);
|
||||
timex_normalize(&cleanup);
|
||||
printf("\tdodag [%s | R: %d | CL: %" PRIu32 "s | \
|
||||
TR(I=[%d,%d], k=%d, c=%d, TC=%" PRIu32 "s, TI=%" PRIu32 "s)]\n",
|
||||
ipv6_addr_to_str(addr_str, &dodag->dodag_id, sizeof(addr_str)),
|
||||
dodag->my_rank, ((int32_t) cleanup.seconds) > 0 ? cleanup.seconds : 0,
|
||||
(1 << dodag->dio_min), dodag->dio_interval_doubl,
|
||||
dodag->trickle.k, dodag->trickle.c,
|
||||
((int32_t) tc.seconds) > 0 ? tc.seconds : 0,
|
||||
((int32_t) ti.seconds) > 0 ? ti.seconds : 0);
|
||||
ng_rpl_parent_t *parent;
|
||||
LL_FOREACH(dodag->parents, parent) {
|
||||
printf("\t\tparent [addr: %s | rank: %d | lifetime: %" PRIu32 "s]\n",
|
||||
ipv6_addr_to_str(addr_str, &parent->addr, sizeof(addr_str)),
|
||||
parent->rank, (parent->lifetime.seconds - now.seconds));
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _ng_rpl(int argc, char **argv)
|
||||
{
|
||||
if ((argc < 2) || (strcmp(argv[1], "show") == 0)) {
|
||||
return _ng_rpl_dodag_show();
|
||||
}
|
||||
else if ((argc == 3) && strcmp(argv[1], "init") == 0) {
|
||||
return _ng_rpl_init(argv[2]);
|
||||
}
|
||||
else if ((argc == 4) && strcmp(argv[1], "root") == 0) {
|
||||
return _ng_rpl_dodag_root(argv[2], argv[3]);
|
||||
}
|
||||
else if (strcmp(argv[1], "rm") == 0) {
|
||||
if (argc == 4) {
|
||||
return _ng_rpl_dodag_remove(argv[2], argv[3]);
|
||||
}
|
||||
else if (argc == 3) {
|
||||
return _ng_rpl_instance_remove(argv[2]);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[1], "trickle") == 0) {
|
||||
if ((argc == 5) && (strcmp(argv[2], "reset") == 0)) {
|
||||
return _ng_rpl_trickle_reset(argv[3], argv[4]);
|
||||
}
|
||||
else if ((argc == 5) && (strcmp(argv[2], "stop") == 0)) {
|
||||
return _ng_rpl_trickle_stop(argv[3], argv[4]);
|
||||
}
|
||||
else if ((argc == 5) && (strcmp(argv[2], "start") == 0)) {
|
||||
return _ng_rpl_trickle_start(argv[3], argv[4]);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[1], "send") == 0) {
|
||||
if ((argc == 3) && (strcmp(argv[2], "dis") == 0)) {
|
||||
return _ng_rpl_send_dis();
|
||||
}
|
||||
}
|
||||
|
||||
printf("usage: %s [help|init|rm|root|show]\n", argv[0]);
|
||||
puts("* help\t\t\t\t\t\t- show usage");
|
||||
puts("* init <if_id>\t\t\t\t\t- initialize RPL on the given interface");
|
||||
puts("* trickle reset <instance_id> <dodag_id>\t- reset the trickle timer");
|
||||
puts("* trickle start <instance_id> <dodag_id>\t- start the trickle timer");
|
||||
puts("* trickle stop <instance_id> <dodag_id>\t\t- stop the trickle timer");
|
||||
puts("* rm <instance_id>\t\t\t\t- delete the given instance and all related dodags");
|
||||
puts("* rm <instance_id> <dodag_id>\t\t\t- delete the dodag in the given instance");
|
||||
puts("* root <instance_id> <dodag_id>\t\t\t- add a dodag to a new or existing instance");
|
||||
puts("* send dis\t\t\t\t\t- send a multicast DIS");
|
||||
puts("* show\t\t\t\t\t\t- show instance and dodag tables");
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @}
|
||||
*/
|
@ -116,6 +116,10 @@ extern int _zep_init(int argc, char **argv);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_NG_RPL
|
||||
extern int _ng_rpl(int argc, char **argv);
|
||||
#endif
|
||||
|
||||
const shell_command_t _shell_command_list[] = {
|
||||
{"reboot", "Reboot the node", _reboot_handler},
|
||||
#ifdef MODULE_CONFIG
|
||||
@ -190,6 +194,9 @@ const shell_command_t _shell_command_list[] = {
|
||||
#ifdef MODULE_IPV6_ADDR
|
||||
{"zep_init", "initializes ZEP (Zigbee Encapsulation Protocol)", _zep_init },
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MODULE_NG_RPL
|
||||
{"rpl", "rpl configuration tool [help|init|rm|root|show]", _ng_rpl },
|
||||
#endif
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user