mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #2155 from cgundogan/rpl_one_thread
rpl: RPL/trickle with only *one* thread
This commit is contained in:
commit
cadea97760
@ -32,6 +32,7 @@ ifneq (,$(filter sixlowborder,$(USEMODULE)))
|
||||
endif
|
||||
|
||||
ifneq (,$(filter rpl,$(USEMODULE)))
|
||||
USEMODULE += trickle
|
||||
USEMODULE += routing
|
||||
endif
|
||||
|
||||
|
@ -71,6 +71,9 @@ endif
|
||||
ifneq (,$(filter netapi,$(USEMODULE)))
|
||||
DIRS += net/crosslayer/netapi
|
||||
endif
|
||||
ifneq (,$(filter trickle,$(USEMODULE)))
|
||||
DIRS += trickle
|
||||
endif
|
||||
|
||||
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))
|
||||
|
||||
|
114
sys/include/trickle.h
Normal file
114
sys/include/trickle.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Trickle constants and prototypes
|
||||
*
|
||||
* Copyright (C) 2013, 2014 INRIA.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sys_trickle Trickle Timer
|
||||
* @ingroup sys
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file trickle.h
|
||||
* @brief Implementation of a generic Trickle Algorithm (RFC 6206)
|
||||
*
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TRICKLE_H
|
||||
#define _TRICKLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "vtimer.h"
|
||||
#include "thread.h"
|
||||
|
||||
/** @brief a generic callback function with arguments that is called by trickle periodically */
|
||||
typedef struct {
|
||||
void (*func)(void *); /**< a generic callback function pointer */
|
||||
void *args; /**< a generic parameter for the callback function pointer */
|
||||
} trickle_callback_t;
|
||||
|
||||
/** @brief all state variables for a trickle timer */
|
||||
typedef struct {
|
||||
uint8_t k; /**< redundancy constant */
|
||||
uint32_t Imin; /**< minimum interval size */
|
||||
uint8_t Imax; /**< maximum interval size, described as a number of doublings */
|
||||
uint32_t I; /**< current interval size */
|
||||
uint32_t t; /**< time within the current interval */
|
||||
uint16_t c; /**< counter */
|
||||
kernel_pid_t pid; /**< pid of trickles target thread */
|
||||
trickle_callback_t callback; /**< the callback function and parameter that trickle is calling
|
||||
after each interval */
|
||||
uint16_t interval_msg_type; /**< the msg_t.type that trickle should use after an interval */
|
||||
timex_t msg_interval_time; /**< interval represented as timex_t */
|
||||
vtimer_t msg_interval_timer; /**< vtimer to send a msg_t to the target thread for a new interval */
|
||||
uint16_t callback_msg_type; /**< the msg_t.type that trickle should use after a callback */
|
||||
timex_t msg_callback_time; /**< callback interval represented as timex_t */
|
||||
vtimer_t msg_callback_timer; /**< vtimer to send a msg_t to the target thread for a callback */
|
||||
} trickle_t;
|
||||
|
||||
/**
|
||||
* @brief resets the trickle timer
|
||||
*
|
||||
* @param[in] trickle the trickle timer
|
||||
*/
|
||||
void trickle_reset_timer(trickle_t *trickle);
|
||||
|
||||
/**
|
||||
* @brief start the trickle timer
|
||||
*
|
||||
* @param[in] pid target thread
|
||||
* @param[in] trickle trickle timer
|
||||
* @param[in] interval_msg_type msg_t.type for interval messages
|
||||
* @param[in] callback_msg_type msg_t.type for callback messages
|
||||
* @param[in] Imin minimum interval
|
||||
* @param[in] Imax maximum interval
|
||||
* @param[in] k redundancy constant
|
||||
*/
|
||||
void trickle_start(kernel_pid_t pid, trickle_t *trickle, uint16_t interval_msg_type,
|
||||
uint16_t callback_msg_type, uint32_t Imin, uint8_t Imax, uint8_t k);
|
||||
|
||||
/**
|
||||
* @brief stops the trickle timer
|
||||
*
|
||||
* @param[in] trickle trickle timer
|
||||
*/
|
||||
void trickle_stop(trickle_t *trickle);
|
||||
|
||||
/**
|
||||
* @brief increments the counter by one
|
||||
*
|
||||
* @param[in] trickle trickle timer
|
||||
*/
|
||||
void trickle_increment_counter(trickle_t *trickle);
|
||||
|
||||
/**
|
||||
* @brief is called after the interval is over and calculates the next interval
|
||||
*
|
||||
* @param[in] trickle trickle timer
|
||||
*/
|
||||
void trickle_interval(trickle_t *trickle);
|
||||
|
||||
/**
|
||||
* @brief is called after the callback interval is over and calls the callback function
|
||||
*
|
||||
* @param[in] trickle trickle timer
|
||||
*/
|
||||
void trickle_callback(trickle_t *trickle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TRICKLE_H */
|
||||
/** @} */
|
@ -32,12 +32,21 @@ extern "C" {
|
||||
#define RPL_STORING_MODE_NO_MC 0x02
|
||||
#define RPL_STORING_MODE_MC 0x03
|
||||
|
||||
/* ICMP type */
|
||||
#define RPL_SEQUENCE_WINDOW 16
|
||||
#define ICMP_CODE_DIS 0x00
|
||||
#define ICMP_CODE_DIO 0x01
|
||||
#define ICMP_CODE_DAO 0x02
|
||||
#define ICMP_CODE_DAO_ACK 0x03
|
||||
/* RPL Message type */
|
||||
enum RPL_MSG_CODE {
|
||||
ICMP_CODE_DIS = 0,
|
||||
ICMP_CODE_DIO,
|
||||
ICMP_CODE_DAO,
|
||||
ICMP_CODE_DAO_ACK,
|
||||
/* put all ICMP codes before the end marker */
|
||||
ICMP_CODE_END,
|
||||
RPL_MSG_TYPE_DAO_HANDLE,
|
||||
RPL_MSG_TYPE_ROUTING_ENTRY_UPDATE,
|
||||
RPL_MSG_TYPE_TRICKLE_INTERVAL,
|
||||
RPL_MSG_TYPE_TRICKLE_CALLBACK
|
||||
};
|
||||
|
||||
/* packet base lengths */
|
||||
#define DIO_BASE_LEN 24
|
||||
#define DIS_BASE_LEN 2
|
||||
@ -147,6 +156,7 @@ static inline bool RPL_COUNTER_GREATER_THAN(uint8_t A, uint8_t B)
|
||||
#define RPL_ROOT_RANK 256
|
||||
#define RPL_DEFAULT_LIFETIME 0xff
|
||||
#define RPL_LIFETIME_UNIT 2
|
||||
#define RPL_LIFETIME_STEP 2
|
||||
#define RPL_GROUNDED 1
|
||||
#define RPL_PRF_MASK 0x7
|
||||
#define RPL_MOP_SHIFT 3
|
||||
|
@ -26,6 +26,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void rpl_dao_ack_received(rpl_dodag_t *dodag);
|
||||
void rpl_delay_dao(rpl_dodag_t *dodag);
|
||||
void rpl_instances_init(void);
|
||||
rpl_instance_t *rpl_new_instance(uint8_t instanceid);
|
||||
rpl_instance_t *rpl_get_instance(uint8_t instanceid);
|
||||
|
@ -18,9 +18,6 @@
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "ipv6.h"
|
||||
|
||||
#ifndef RPL_STRUCTS_H_INCLUDED
|
||||
#define RPL_STRUCTS_H_INCLUDED
|
||||
|
||||
@ -28,6 +25,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "ipv6.h"
|
||||
#include "trickle.h"
|
||||
|
||||
/* Modes of Operation */
|
||||
|
||||
/* DIO Base Object (RFC 6550 Fig. 14) */
|
||||
@ -167,6 +168,11 @@ typedef struct rpl_dodag_t {
|
||||
uint8_t joined;
|
||||
rpl_parent_t *my_preferred_parent;
|
||||
struct rpl_of_t *of;
|
||||
trickle_t trickle;
|
||||
bool ack_received;
|
||||
uint8_t dao_counter;
|
||||
timex_t dao_time;
|
||||
vtimer_t dao_timer;
|
||||
} rpl_dodag_t;
|
||||
|
||||
typedef struct rpl_of_t {
|
||||
|
@ -282,6 +282,7 @@ int icmpv6_demultiplex(const icmpv6_hdr_t *hdr)
|
||||
if (_rpl_process_pid != KERNEL_PID_UNDEF) {
|
||||
msg_t m_send;
|
||||
m_send.content.ptr = (char *) ipv6_buf;
|
||||
m_send.type = ((icmpv6_hdr_t *)(m_send.content.ptr + IPV6_HDR_LEN))->code;
|
||||
msg_send(&m_send, _rpl_process_pid);
|
||||
}
|
||||
else {
|
||||
|
@ -45,8 +45,6 @@
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#if ENABLE_DEBUG
|
||||
#undef TRICKLE_TIMER_STACKSIZE
|
||||
#define TRICKLE_TIMER_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
|
||||
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
||||
#endif
|
||||
#include "debug.h"
|
||||
@ -57,6 +55,11 @@ mutex_t rpl_send_mutex = MUTEX_INIT;
|
||||
msg_t rpl_msg_queue[RPL_PKT_RECV_BUF_SIZE];
|
||||
char rpl_process_buf[RPL_PROCESS_STACKSIZE];
|
||||
uint8_t rpl_buffer[BUFFER_SIZE - LL_HDR_LEN];
|
||||
static timex_t rt_time;
|
||||
static vtimer_t rt_timer;
|
||||
|
||||
static void _dao_handle_send(rpl_dodag_t *dodag);
|
||||
static void _rpl_update_routing_table(void);
|
||||
|
||||
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
|
||||
uint8_t srh_buffer[BUFFER_SIZE];
|
||||
@ -74,7 +77,6 @@ ipv6_addr_t my_address;
|
||||
|
||||
/* IPv6 message buffer */
|
||||
ipv6_hdr_t *ipv6_buf;
|
||||
icmpv6_hdr_t *icmp_buf;
|
||||
|
||||
uint8_t rpl_init(int if_id)
|
||||
{
|
||||
@ -86,7 +88,6 @@ uint8_t rpl_init(int if_id)
|
||||
rpl_clear_routing_table();
|
||||
#endif
|
||||
|
||||
init_trickle();
|
||||
rpl_process_pid = thread_create(rpl_process_buf, RPL_PROCESS_STACKSIZE,
|
||||
PRIORITY_MAIN - 1, CREATE_STACKTEST,
|
||||
rpl_process, NULL, "rpl_process");
|
||||
@ -106,6 +107,10 @@ uint8_t rpl_init(int if_id)
|
||||
/* initialize objective function manager */
|
||||
rpl_of_manager_init(&my_address);
|
||||
rpl_init_mode(&my_address);
|
||||
|
||||
rt_time = timex_set(RPL_LIFETIME_STEP, 0);
|
||||
vtimer_set_msg(&rt_timer, rt_time, rpl_process_pid, RPL_MSG_TYPE_ROUTING_ENTRY_UPDATE, NULL);
|
||||
|
||||
return SIXLOWERROR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -133,7 +138,9 @@ uint8_t rpl_is_root(void)
|
||||
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
|
||||
void internal_srh_process(ipv6_srh_t *srh_header)
|
||||
{
|
||||
/* modify it accordingly - the number of entries is not depending on padding, because there is none. */
|
||||
/* modify it accordingly - the number of entries is not depending on padding,
|
||||
* because there is none.
|
||||
*/
|
||||
uint8_t n = srh_header->hdrextlen / sizeof(ipv6_addr_t);
|
||||
|
||||
if (srh_header->segments_left > n) {
|
||||
@ -146,7 +153,8 @@ void internal_srh_process(ipv6_srh_t *srh_header)
|
||||
down_next_hop = &srh_header->route[n - segs];
|
||||
srh_header->segments_left = segs - 1;
|
||||
DEBUGF("Segments left after reduction: %d\n", srh_header->segments_left);
|
||||
DEBUGF("Next hop is: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, down_next_hop));
|
||||
DEBUGF("Next hop is: %s\n",
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, down_next_hop));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -158,81 +166,122 @@ void *rpl_process(void *arg)
|
||||
msg_t m_recv;
|
||||
msg_init_queue(rpl_msg_queue, RPL_PKT_RECV_BUF_SIZE);
|
||||
|
||||
rpl_dodag_t *dodag;
|
||||
trickle_t *trickle;
|
||||
|
||||
while (1) {
|
||||
msg_receive(&m_recv);
|
||||
|
||||
/* differentiate packet types */
|
||||
ipv6_buf = ((ipv6_hdr_t *)m_recv.content.ptr);
|
||||
memcpy(&rpl_buffer, ipv6_buf, NTOHS(ipv6_buf->length) + IPV6_HDR_LEN);
|
||||
|
||||
/* This is an RPL-related message. */
|
||||
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_ICMPV6) {
|
||||
icmp_buf = ((icmpv6_hdr_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
||||
|
||||
/* get code for message-interpretation and process message */
|
||||
DEBUGF("Received RPL information of type %04X and length %u\n", icmp_buf->code, NTOHS(ipv6_buf->length));
|
||||
|
||||
switch (icmp_buf->code) {
|
||||
case (ICMP_CODE_DIS): {
|
||||
rpl_recv_DIS();
|
||||
if (m_recv.type > ICMP_CODE_END) {
|
||||
switch (m_recv.type) {
|
||||
case RPL_MSG_TYPE_DAO_HANDLE:
|
||||
dodag = (rpl_dodag_t *) m_recv.content.ptr;
|
||||
if (dodag->joined) {
|
||||
_dao_handle_send(dodag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case (ICMP_CODE_DIO): {
|
||||
rpl_recv_DIO();
|
||||
case RPL_MSG_TYPE_ROUTING_ENTRY_UPDATE:
|
||||
_rpl_update_routing_table();
|
||||
break;
|
||||
}
|
||||
|
||||
case (ICMP_CODE_DAO): {
|
||||
rpl_recv_DAO();
|
||||
case RPL_MSG_TYPE_TRICKLE_INTERVAL:
|
||||
trickle = (trickle_t *) m_recv.content.ptr;
|
||||
if (trickle->callback.func != NULL) {
|
||||
trickle_interval(trickle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case (ICMP_CODE_DAO_ACK): {
|
||||
rpl_recv_DAO_ACK();
|
||||
case RPL_MSG_TYPE_TRICKLE_CALLBACK:
|
||||
trickle = (trickle_t *) m_recv.content.ptr;
|
||||
if (trickle->callback.func != NULL) {
|
||||
trickle_callback(trickle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
/* This is an RPL-related message. */
|
||||
else {
|
||||
/* differentiate packet types */
|
||||
ipv6_buf = (ipv6_hdr_t *) m_recv.content.ptr;
|
||||
memcpy(&rpl_buffer, ipv6_buf, NTOHS(ipv6_buf->length) + IPV6_HDR_LEN);
|
||||
|
||||
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_ICMPV6) {
|
||||
|
||||
/* get code for message-interpretation and process message */
|
||||
DEBUGF("Received RPL information of type %04X and length %u\n",
|
||||
m_recv.type, NTOHS(ipv6_buf->length));
|
||||
|
||||
switch (m_recv.type) {
|
||||
case (ICMP_CODE_DIS): {
|
||||
rpl_recv_DIS();
|
||||
break;
|
||||
}
|
||||
|
||||
case (ICMP_CODE_DIO): {
|
||||
rpl_recv_DIO();
|
||||
break;
|
||||
}
|
||||
|
||||
case (ICMP_CODE_DAO): {
|
||||
rpl_recv_DAO();
|
||||
break;
|
||||
}
|
||||
|
||||
case (ICMP_CODE_DAO_ACK): {
|
||||
rpl_recv_DAO_ACK();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
|
||||
/* If the message is not RPL-type, it relates to non-storing mode */
|
||||
else if (RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) {
|
||||
/* If the message is not RPL-type, it relates to non-storing mode */
|
||||
else if (RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) {
|
||||
|
||||
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_SRH) {
|
||||
srh_header = ((ipv6_srh_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
||||
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_SRH) {
|
||||
srh_header = ((ipv6_srh_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
||||
|
||||
/* if there are no segments left, the routing is finished */
|
||||
if (srh_header->segments_left == 0) {
|
||||
DEBUGF("Source routing finished with next header: %02X.\n", srh_header->nextheader);
|
||||
DEBUGF("Size of srh: %d\n", srh_header->hdrextlen);
|
||||
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN + sizeof(ipv6_srh_t)+srh_header->hdrextlen));
|
||||
rpl_remove_srh_header(ipv6_buf, payload, srh_header->nextheader);
|
||||
}
|
||||
else {
|
||||
internal_srh_process(srh_header);
|
||||
if (down_next_hop != NULL) {
|
||||
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
||||
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length), &ipv6_buf->srcaddr, down_next_hop, srh_header, 0);
|
||||
/* if there are no segments left, the routing is finished */
|
||||
if (srh_header->segments_left == 0) {
|
||||
DEBUGF("Source routing finished with next header: %02X.\n",
|
||||
srh_header->nextheader);
|
||||
DEBUGF("Size of srh: %d\n", srh_header->hdrextlen);
|
||||
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr +
|
||||
IPV6_HDR_LEN + sizeof(ipv6_srh_t)+srh_header->hdrextlen));
|
||||
rpl_remove_srh_header(ipv6_buf, payload, srh_header->nextheader);
|
||||
}
|
||||
else {
|
||||
internal_srh_process(srh_header);
|
||||
if (down_next_hop != NULL) {
|
||||
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
||||
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length), &ipv6_buf->srcaddr,
|
||||
down_next_hop, srh_header, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if RPL_MAX_ROUTING_ENTRIES != 0
|
||||
else {
|
||||
srh_header = rpl_get_srh_header(ipv6_buf);
|
||||
else {
|
||||
srh_header = rpl_get_srh_header(ipv6_buf);
|
||||
|
||||
if (srh_header != NULL) {
|
||||
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
||||
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length), &ipv6_buf->srcaddr, &ipv6_buf->destaddr, srh_header, srh_header->hdrextlen + sizeof(ipv6_srh_t));
|
||||
if (srh_header != NULL) {
|
||||
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
||||
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length),
|
||||
&ipv6_buf->srcaddr, &ipv6_buf->destaddr, srh_header,
|
||||
srh_header->hdrextlen + sizeof(ipv6_srh_t));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +296,8 @@ void rpl_send_DIO(ipv6_addr_t *destination)
|
||||
mutex_unlock(&rpl_send_mutex);
|
||||
}
|
||||
|
||||
void rpl_send_DAO(ipv6_addr_t *destination, uint8_t lifetime, bool default_lifetime, uint8_t start_index)
|
||||
void rpl_send_DAO(ipv6_addr_t *destination, uint8_t lifetime,
|
||||
bool default_lifetime, uint8_t start_index)
|
||||
{
|
||||
if (destination) {
|
||||
DEBUGF("Send DAO to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
|
||||
@ -272,7 +322,8 @@ void rpl_send_DIS(ipv6_addr_t *destination)
|
||||
void rpl_send_DAO_ACK(ipv6_addr_t *destination)
|
||||
{
|
||||
if (destination) {
|
||||
DEBUGF("Send DAO ACK to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
|
||||
DEBUGF("Send DAO ACK to %s\n",
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
|
||||
}
|
||||
|
||||
mutex_lock(&rpl_send_mutex);
|
||||
@ -309,26 +360,109 @@ void rpl_recv_DAO_ACK(void)
|
||||
rpl_recv_dao_ack_mode();
|
||||
}
|
||||
|
||||
void _rpl_update_routing_table(void) {
|
||||
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
||||
rpl_routing_entry_t *rt;
|
||||
if (my_dodag != NULL) {
|
||||
rt = rpl_get_routing_table();
|
||||
|
||||
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
||||
if (rt[i].used) {
|
||||
if (rt[i].lifetime <= 1) {
|
||||
memset(&rt[i], 0, sizeof(rt[i]));
|
||||
}
|
||||
else {
|
||||
rt[i].lifetime = rt[i].lifetime - RPL_LIFETIME_STEP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parent is NULL for root too */
|
||||
if (my_dodag->my_preferred_parent != NULL) {
|
||||
if (my_dodag->my_preferred_parent->lifetime <= 1) {
|
||||
DEBUGF("parent lifetime timeout\n");
|
||||
rpl_parent_update(NULL);
|
||||
}
|
||||
else {
|
||||
my_dodag->my_preferred_parent->lifetime =
|
||||
my_dodag->my_preferred_parent->lifetime - RPL_LIFETIME_STEP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vtimer_remove(&rt_timer);
|
||||
vtimer_set_msg(&rt_timer, rt_time, rpl_process_pid, RPL_MSG_TYPE_ROUTING_ENTRY_UPDATE, NULL);
|
||||
}
|
||||
|
||||
void rpl_delay_dao(rpl_dodag_t *dodag)
|
||||
{
|
||||
dodag->dao_time = timex_set(DEFAULT_DAO_DELAY, 0);
|
||||
dodag->dao_counter = 0;
|
||||
dodag->ack_received = false;
|
||||
vtimer_remove(&dodag->dao_timer);
|
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time,
|
||||
rpl_process_pid, RPL_MSG_TYPE_DAO_HANDLE, dodag);
|
||||
}
|
||||
|
||||
/* This function is used for regular update of the routes.
|
||||
* The Timer can be overwritten, as the normal delay_dao function gets called
|
||||
*/
|
||||
void long_delay_dao(rpl_dodag_t *dodag)
|
||||
{
|
||||
dodag->dao_time = timex_set(REGULAR_DAO_INTERVAL, 0);
|
||||
dodag->dao_counter = 0;
|
||||
dodag->ack_received = false;
|
||||
vtimer_remove(&dodag->dao_timer);
|
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time,
|
||||
rpl_process_pid, RPL_MSG_TYPE_DAO_HANDLE, dodag);
|
||||
}
|
||||
|
||||
void rpl_dao_ack_received(rpl_dodag_t *dodag)
|
||||
{
|
||||
dodag->ack_received = true;
|
||||
long_delay_dao(dodag);
|
||||
}
|
||||
|
||||
void _dao_handle_send(rpl_dodag_t *dodag) {
|
||||
if ((dodag->ack_received == false) && (dodag->dao_counter < DAO_SEND_RETRIES)) {
|
||||
dodag->dao_counter++;
|
||||
rpl_send_DAO(NULL, 0, true, 0);
|
||||
dodag->dao_time = timex_set(DEFAULT_WAIT_FOR_DAO_ACK, 0);
|
||||
vtimer_remove(&dodag->dao_timer);
|
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time,
|
||||
rpl_process_pid, RPL_MSG_TYPE_DAO_HANDLE, dodag);
|
||||
}
|
||||
else if (dodag->ack_received == false) {
|
||||
long_delay_dao(dodag);
|
||||
}
|
||||
}
|
||||
|
||||
ipv6_addr_t *rpl_get_next_hop(ipv6_addr_t *addr)
|
||||
{
|
||||
|
||||
DEBUGF("Looking up the next hop to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
|
||||
DEBUGF("Looking up the next hop to %s\n",
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
|
||||
|
||||
#if RPL_MAX_ROUTING_ENTRIES != 0
|
||||
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
||||
if (rpl_routing_table[i].used) {
|
||||
DEBUGF("checking %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
|
||||
DEBUGF("checking %d: %s\n", i,
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
|
||||
}
|
||||
|
||||
if ((RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) && rpl_is_root()) {
|
||||
if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
|
||||
DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
|
||||
DEBUGF("found %d: %s\n", i,
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
|
||||
&rpl_routing_table[i].address));
|
||||
return &rpl_routing_table[i].address;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
|
||||
DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop));
|
||||
DEBUGF("found %d: %s\n", i,
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
|
||||
&rpl_routing_table[i].next_hop));
|
||||
return &rpl_routing_table[i].next_hop;
|
||||
}
|
||||
}
|
||||
@ -437,13 +571,16 @@ void rpl_add_srh_entry(ipv6_addr_t *child, ipv6_addr_t *parent, uint16_t lifetim
|
||||
}
|
||||
}
|
||||
|
||||
/* This maybe a bit confusing since the root also using the standard routing table, but in this case
|
||||
* the code stays cleaner - especially for rt_over_timer from trickle.c. Just keep in mind that
|
||||
* address is now child (unique, iteration variable) and parent is now next_hop. The whole routing table
|
||||
* transforms to a list of children and their parents, so that route aggregation can be done properly.
|
||||
/* This maybe a bit confusing since the root also using the standard routing table,
|
||||
* but in this case the code stays cleaner - especially for rt_over_timer from trickle.c.
|
||||
* Just keep in mind that address is now child (unique, iteration variable) and parent is
|
||||
* now next_hop. The whole routing table transforms to a list of children and their parents,
|
||||
* so that route aggregation can be done properly.
|
||||
*/
|
||||
DEBUGF("Adding source-routing entry child: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, child));
|
||||
DEBUGF("Adding source-routing entry parent: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, parent));
|
||||
DEBUGF("Adding source-routing entry child: %s\n",
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, child));
|
||||
DEBUGF("Adding source-routing entry parent: %s\n",
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, parent));
|
||||
|
||||
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
||||
if (!rpl_routing_table[i].used) {
|
||||
@ -486,13 +623,18 @@ ipv6_srh_t *rpl_get_srh_header(ipv6_hdr_t *act_ipv6_hdr)
|
||||
DEBUGF("DESTINATION NODE: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));
|
||||
|
||||
while (!(rpl_equal_id(actual_node, &my_address))) {
|
||||
/* set check variable - this is reversed, if a child/parent-relation is found in one iteration of the routing table */
|
||||
/* set check variable - this is reversed,
|
||||
* if a child/parent-relation is found in one iteration of the routing table */
|
||||
traceable = 0;
|
||||
|
||||
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
||||
if (rpl_routing_table[i].used && ipv6_suffix_is_equal(&rpl_routing_table[i].address, actual_node)) {
|
||||
DEBUGF("[INFO] Found parent-child relation with P: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop));
|
||||
DEBUGF(" and C: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));
|
||||
if (rpl_routing_table[i].used
|
||||
&& ipv6_suffix_is_equal(&rpl_routing_table[i].address, actual_node)) {
|
||||
DEBUGF("[INFO] Found parent-child relation with P: %s\n",
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
|
||||
&rpl_routing_table[i].next_hop));
|
||||
DEBUGF(" and C: %s\n",
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));
|
||||
memcpy(&rev_route[counter], actual_node, sizeof(ipv6_addr_t));
|
||||
|
||||
actual_node = &rpl_routing_table[i].next_hop;
|
||||
@ -514,7 +656,9 @@ ipv6_srh_t *rpl_get_srh_header(ipv6_hdr_t *act_ipv6_hdr)
|
||||
}
|
||||
}
|
||||
|
||||
/* build real route based on reversed route. After building it starts with the node next to destination */
|
||||
/* build real route based on reversed route.
|
||||
* After building it starts with the node next to destination
|
||||
*/
|
||||
if (counter > 1) {
|
||||
for (uint8_t i = 0; i < counter-1; i++) {
|
||||
memcpy(&srh_header->route[i], &rev_route[counter-i-2], sizeof(ipv6_addr_t));
|
||||
@ -552,12 +696,14 @@ void rpl_remove_srh_header(ipv6_hdr_t *ipv6_header, const void *buf, uint8_t nex
|
||||
temp_ipv6_header->nextheader = nextheader;
|
||||
memcpy(payload, buf, msg_length);
|
||||
DEBUGF("Source routing header extraction finished.\n");
|
||||
DEBUGF("Dest is now: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &temp_ipv6_header->destaddr));
|
||||
DEBUGF("Dest is now: %s\n",
|
||||
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &temp_ipv6_header->destaddr));
|
||||
srh_m_send.content.ptr = (char *) srh_send_buffer;
|
||||
msg_send_receive(&srh_m_send, &srh_m_recv, ip_process_pid);
|
||||
}
|
||||
|
||||
int rpl_srh_sendto(const void *buf, uint16_t len, ipv6_addr_t *src, ipv6_addr_t *dest, ipv6_srh_t *srh_header, uint8_t srh_length)
|
||||
int rpl_srh_sendto(const void *buf, uint16_t len,
|
||||
ipv6_addr_t *src, ipv6_addr_t *dest, ipv6_srh_t *srh_header, uint8_t srh_length)
|
||||
{
|
||||
ipv6_hdr_t *temp_ipv6_header = ((ipv6_hdr_t *)(&srh_send_buffer));
|
||||
ipv6_srh_t *current_packet = ((ipv6_srh_t *)(&srh_send_buffer[IPV6_HDR_LEN]));
|
||||
@ -572,6 +718,7 @@ int rpl_srh_sendto(const void *buf, uint16_t len, ipv6_addr_t *src, ipv6_addr_t
|
||||
DEBUGF("SRH-length: %d\n", current_packet->hdrextlen);
|
||||
DEBUGF("My payload length: %d\n", plength);
|
||||
|
||||
return ipv6_sendto(&temp_ipv6_header->destaddr, IPV6_PROTO_NUM_SRH, (uint8_t *)current_packet, plength, &temp_ipv6_header->destaddr);
|
||||
return ipv6_sendto(&temp_ipv6_header->destaddr, IPV6_PROTO_NUM_SRH,
|
||||
(uint8_t *)current_packet, plength, &temp_ipv6_header->destaddr);
|
||||
}
|
||||
#endif
|
||||
|
@ -31,10 +31,19 @@ char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
||||
#endif
|
||||
#include "debug.h"
|
||||
|
||||
kernel_pid_t rpl_process_pid;
|
||||
rpl_instance_t instances[RPL_MAX_INSTANCES];
|
||||
rpl_dodag_t dodags[RPL_MAX_DODAGS];
|
||||
rpl_parent_t parents[RPL_MAX_PARENTS];
|
||||
|
||||
void rpl_trickle_send_dio(void *args) {
|
||||
(void) args;
|
||||
ipv6_addr_t mcast;
|
||||
|
||||
ipv6_addr_set_all_nodes_addr(&mcast);
|
||||
rpl_send_DIO(&mcast);
|
||||
}
|
||||
|
||||
void rpl_instances_init(void)
|
||||
{
|
||||
memset(instances, 0, sizeof(rpl_instance_t) * RPL_MAX_INSTANCES);
|
||||
@ -98,6 +107,9 @@ rpl_dodag_t *rpl_new_dodag(uint8_t instanceid, ipv6_addr_t *dodagid)
|
||||
dodag->instance = inst;
|
||||
dodag->my_rank = INFINITE_RANK;
|
||||
dodag->used = 1;
|
||||
dodag->ack_received = true;
|
||||
dodag->dao_counter = 0;
|
||||
dodag->trickle.callback.func = &rpl_trickle_send_dio;
|
||||
memcpy(&dodag->dodag_id, dodagid, sizeof(*dodagid));
|
||||
return dodag;
|
||||
}
|
||||
@ -129,6 +141,7 @@ rpl_dodag_t *rpl_get_my_dodag(void)
|
||||
}
|
||||
void rpl_del_dodag(rpl_dodag_t *dodag)
|
||||
{
|
||||
rpl_leave_dodag(dodag);
|
||||
memset(dodag, 0, sizeof(*dodag));
|
||||
}
|
||||
|
||||
@ -137,6 +150,8 @@ void rpl_leave_dodag(rpl_dodag_t *dodag)
|
||||
dodag->joined = 0;
|
||||
dodag->my_preferred_parent = NULL;
|
||||
rpl_delete_all_parents();
|
||||
trickle_stop(&dodag->trickle);
|
||||
vtimer_remove(&dodag->dao_timer);
|
||||
}
|
||||
|
||||
bool rpl_equal_id(ipv6_addr_t *id1, ipv6_addr_t *id2)
|
||||
@ -279,10 +294,10 @@ rpl_parent_t *rpl_find_preferred_parent(void)
|
||||
my_dodag->my_preferred_parent = best;
|
||||
|
||||
if (my_dodag->mop != RPL_NO_DOWNWARD_ROUTES) {
|
||||
delay_dao();
|
||||
rpl_delay_dao(my_dodag);
|
||||
}
|
||||
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
}
|
||||
|
||||
return best;
|
||||
@ -315,7 +330,7 @@ void rpl_parent_update(rpl_parent_t *parent)
|
||||
my_dodag->min_rank = my_dodag->my_rank;
|
||||
}
|
||||
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,8 +382,10 @@ void rpl_join_dodag(rpl_dodag_t *dodag, ipv6_addr_t *parent, uint16_t parent_ran
|
||||
DEBUG("\tmy_preferred_parent rank\t%02X\n", my_dodag->my_preferred_parent->rank);
|
||||
DEBUG("\tmy_preferred_parent lifetime\t%04X\n", my_dodag->my_preferred_parent->lifetime);
|
||||
|
||||
start_trickle(my_dodag->dio_min, my_dodag->dio_interval_doubling, my_dodag->dio_redundancy);
|
||||
delay_dao();
|
||||
trickle_start(rpl_process_pid, &my_dodag->trickle, RPL_MSG_TYPE_TRICKLE_INTERVAL,
|
||||
RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << my_dodag->dio_min), my_dodag->dio_interval_doubling,
|
||||
my_dodag->dio_redundancy);
|
||||
rpl_delay_dao(my_dodag);
|
||||
}
|
||||
|
||||
void rpl_global_repair(rpl_dodag_t *dodag, ipv6_addr_t *p_addr, uint16_t rank)
|
||||
@ -395,8 +412,8 @@ void rpl_global_repair(rpl_dodag_t *dodag, ipv6_addr_t *p_addr, uint16_t rank)
|
||||
my_dodag->my_rank = my_dodag->of->calc_rank(my_dodag->my_preferred_parent,
|
||||
my_dodag->my_rank);
|
||||
my_dodag->min_rank = my_dodag->my_rank;
|
||||
reset_trickletimer();
|
||||
delay_dao();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
rpl_delay_dao(my_dodag);
|
||||
}
|
||||
|
||||
DEBUGF("Migrated to DODAG Version %d. My new Rank: %d\n", my_dodag->version,
|
||||
@ -416,7 +433,7 @@ void rpl_local_repair(void)
|
||||
my_dodag->my_rank = INFINITE_RANK;
|
||||
my_dodag->dtsn++;
|
||||
rpl_delete_all_parents();
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
|
||||
}
|
||||
|
||||
|
@ -213,8 +213,10 @@ void rpl_init_root_mode(void)
|
||||
return;
|
||||
}
|
||||
|
||||
trickle_start(rpl_process_pid, &dodag->trickle, RPL_MSG_TYPE_TRICKLE_INTERVAL,
|
||||
RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min), dodag->dio_interval_doubling,
|
||||
dodag->dio_redundancy);
|
||||
DEBUGF("Root init finished.\n");
|
||||
start_trickle(dodag->dio_min, dodag->dio_interval_doubling, dodag->dio_redundancy);
|
||||
}
|
||||
|
||||
uint8_t rpl_is_root_mode(void)
|
||||
@ -548,7 +550,7 @@ void rpl_recv_DIO_mode(void)
|
||||
if (my_dodag->my_rank == ROOT_RANK) {
|
||||
DEBUGF("[Warning] Inconsistent Dodag Version\n");
|
||||
my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version);
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
}
|
||||
else {
|
||||
DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n");
|
||||
@ -558,20 +560,20 @@ void rpl_recv_DIO_mode(void)
|
||||
return;
|
||||
}
|
||||
else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) {
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* version matches, DODAG matches */
|
||||
if (rpl_dio_buf->rank == INFINITE_RANK) {
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
}
|
||||
|
||||
/* We are root, all done!*/
|
||||
if (my_dodag->my_rank == ROOT_RANK) {
|
||||
if (rpl_dio_buf->rank != INFINITE_RANK) {
|
||||
trickle_increment_counter();
|
||||
trickle_increment_counter(&my_dodag->trickle);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -592,7 +594,7 @@ void rpl_recv_DIO_mode(void)
|
||||
}
|
||||
else {
|
||||
/* DIO OK */
|
||||
trickle_increment_counter();
|
||||
trickle_increment_counter(&my_dodag->trickle);
|
||||
}
|
||||
|
||||
/* update parent rank */
|
||||
@ -604,7 +606,7 @@ void rpl_recv_DIO_mode(void)
|
||||
}
|
||||
else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) &&
|
||||
(parent->dtsn != rpl_dio_buf->dtsn)) {
|
||||
delay_dao();
|
||||
rpl_delay_dao(my_dodag);
|
||||
}
|
||||
|
||||
parent->dtsn = rpl_dio_buf->dtsn;
|
||||
@ -699,7 +701,7 @@ void rpl_recv_DAO_mode(void)
|
||||
|
||||
if (increment_seq) {
|
||||
RPL_COUNTER_INCREMENT(my_dodag->dao_seq);
|
||||
delay_dao();
|
||||
rpl_delay_dao(my_dodag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -788,7 +790,7 @@ void rpl_recv_dao_ack_mode(void)
|
||||
return;
|
||||
}
|
||||
|
||||
dao_ack_received();
|
||||
rpl_dao_ack_received(my_dodag);
|
||||
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,9 @@ void rpl_init_root_mode(void)
|
||||
}
|
||||
|
||||
i_am_root = 1;
|
||||
start_trickle(dodag->dio_min, dodag->dio_interval_doubling, dodag->dio_redundancy);
|
||||
trickle_start(rpl_process_pid, &dodag->trickle, RPL_MSG_TYPE_TRICKLE_INTERVAL,
|
||||
RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min), dodag->dio_interval_doubling,
|
||||
dodag->dio_redundancy);
|
||||
DEBUGF("ROOT INIT FINISHED\n");
|
||||
|
||||
}
|
||||
@ -570,7 +572,7 @@ void rpl_recv_DIO_mode(void)
|
||||
if (my_dodag->my_rank == ROOT_RANK) {
|
||||
DEBUGF("[Warning] Inconsistent Dodag Version\n");
|
||||
my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version);
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
}
|
||||
else {
|
||||
DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n");
|
||||
@ -581,20 +583,20 @@ void rpl_recv_DIO_mode(void)
|
||||
}
|
||||
else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) {
|
||||
/* lower version number detected -> send more DIOs */
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* version matches, DODAG matches */
|
||||
if (rpl_dio_buf->rank == INFINITE_RANK) {
|
||||
reset_trickletimer();
|
||||
trickle_reset_timer(&my_dodag->trickle);
|
||||
}
|
||||
|
||||
/* We are root, all done!*/
|
||||
if (my_dodag->my_rank == ROOT_RANK) {
|
||||
if (rpl_dio_buf->rank != INFINITE_RANK) {
|
||||
trickle_increment_counter();
|
||||
trickle_increment_counter(&my_dodag->trickle);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -615,7 +617,7 @@ void rpl_recv_DIO_mode(void)
|
||||
}
|
||||
else {
|
||||
/* DIO OK */
|
||||
trickle_increment_counter();
|
||||
trickle_increment_counter(&my_dodag->trickle);
|
||||
}
|
||||
|
||||
/* update parent rank */
|
||||
@ -627,7 +629,7 @@ void rpl_recv_DIO_mode(void)
|
||||
}
|
||||
else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) &&
|
||||
(parent->dtsn != rpl_dio_buf->dtsn)) {
|
||||
delay_dao();
|
||||
rpl_delay_dao(my_dodag);
|
||||
}
|
||||
|
||||
parent->dtsn = rpl_dio_buf->dtsn;
|
||||
@ -722,7 +724,7 @@ void rpl_recv_DAO_mode(void)
|
||||
|
||||
if (increment_seq) {
|
||||
RPL_COUNTER_INCREMENT(my_dodag->dao_seq);
|
||||
delay_dao();
|
||||
rpl_delay_dao(my_dodag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -811,7 +813,7 @@ void rpl_recv_dao_ack_mode(void)
|
||||
return;
|
||||
}
|
||||
|
||||
dao_ack_received();
|
||||
rpl_dao_ack_received(my_dodag);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,288 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2013 INRIA.
|
||||
*
|
||||
* 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 trickle.c
|
||||
* @brief Trickle
|
||||
*
|
||||
* Implementation of Trickle-Algorithm for RPL.
|
||||
*
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "inttypes.h"
|
||||
#include "trickle.h"
|
||||
#include "rpl.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* thread stacks */
|
||||
static char timer_over_buf[TRICKLE_TIMER_STACKSIZE];
|
||||
static char interval_over_buf[TRICKLE_INTERVAL_STACKSIZE];
|
||||
static char dao_delay_over_buf[DAO_DELAY_STACKSIZE];
|
||||
static char routing_table_buf[RT_STACKSIZE];
|
||||
|
||||
kernel_pid_t timer_over_pid = KERNEL_PID_UNDEF;
|
||||
kernel_pid_t interval_over_pid = KERNEL_PID_UNDEF;
|
||||
kernel_pid_t dao_delay_over_pid = KERNEL_PID_UNDEF;
|
||||
kernel_pid_t rt_timer_over_pid = KERNEL_PID_UNDEF;
|
||||
|
||||
bool ack_received;
|
||||
uint8_t dao_counter;
|
||||
|
||||
uint8_t k;
|
||||
uint32_t Imin;
|
||||
uint8_t Imax;
|
||||
uint32_t I;
|
||||
uint32_t t;
|
||||
uint16_t c;
|
||||
vtimer_t trickle_t_timer;
|
||||
vtimer_t trickle_I_timer;
|
||||
vtimer_t dao_timer;
|
||||
vtimer_t rt_timer;
|
||||
timex_t t_time;
|
||||
timex_t I_time;
|
||||
timex_t dao_time;
|
||||
timex_t rt_time;
|
||||
|
||||
static void *trickle_timer_over(void *arg);
|
||||
static void *trickle_interval_over(void *arg);
|
||||
static void *dao_delay_over(void *arg);
|
||||
static void *rt_timer_over(void *arg);
|
||||
|
||||
void reset_trickletimer(void)
|
||||
{
|
||||
I = Imin;
|
||||
c = 0;
|
||||
/* start timer */
|
||||
t = (I / 2) + (rand() % (I - (I / 2) + 1));
|
||||
t_time = timex_set(0, t * 1000);
|
||||
I_time = timex_set(0, I * 1000);
|
||||
timex_normalize(&t_time);
|
||||
timex_normalize(&I_time);
|
||||
vtimer_remove(&trickle_t_timer);
|
||||
vtimer_remove(&trickle_I_timer);
|
||||
vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid);
|
||||
vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid);
|
||||
|
||||
}
|
||||
|
||||
void init_trickle(void)
|
||||
{
|
||||
/* Create threads */
|
||||
ack_received = true;
|
||||
dao_counter = 0;
|
||||
timer_over_pid = thread_create(timer_over_buf, TRICKLE_TIMER_STACKSIZE,
|
||||
PRIORITY_MAIN - 1, CREATE_STACKTEST,
|
||||
trickle_timer_over, NULL, "trickle_timer_over");
|
||||
|
||||
interval_over_pid = thread_create(interval_over_buf, TRICKLE_INTERVAL_STACKSIZE,
|
||||
PRIORITY_MAIN - 1, CREATE_STACKTEST,
|
||||
trickle_interval_over, NULL, "trickle_interval_over");
|
||||
dao_delay_over_pid = thread_create(dao_delay_over_buf, DAO_DELAY_STACKSIZE,
|
||||
PRIORITY_MAIN - 1, CREATE_STACKTEST,
|
||||
dao_delay_over, NULL, "dao_delay_over");
|
||||
rt_timer_over_pid = thread_create(routing_table_buf, RT_STACKSIZE,
|
||||
PRIORITY_MAIN - 1, CREATE_STACKTEST,
|
||||
rt_timer_over, NULL, "rt_timer_over");
|
||||
}
|
||||
|
||||
void start_trickle(uint8_t DIOIntMin, uint8_t DIOIntDoubl,
|
||||
uint8_t DIORedundancyConstant)
|
||||
{
|
||||
c = 0;
|
||||
k = DIORedundancyConstant;
|
||||
Imin = (1 << DIOIntMin);
|
||||
Imax = DIOIntDoubl;
|
||||
/* Eigentlich laut Spezifikation erste Bestimmung von I wie auskommentiert: */
|
||||
/* I = Imin + ( rand() % ( (Imin << Imax) - Imin + 1 ) ); */
|
||||
I = Imin + (rand() % (4 * Imin)) ;
|
||||
|
||||
t = (I / 2) + (rand() % (I - (I / 2) + 1));
|
||||
t_time = timex_set(0, t * 1000);
|
||||
timex_normalize(&t_time);
|
||||
I_time = timex_set(0, I * 1000);
|
||||
timex_normalize(&I_time);
|
||||
vtimer_remove(&trickle_t_timer);
|
||||
vtimer_remove(&trickle_I_timer);
|
||||
vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid);
|
||||
vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid);
|
||||
}
|
||||
|
||||
void trickle_increment_counter(void)
|
||||
{
|
||||
/* call this function, when received DIO message */
|
||||
c++;
|
||||
}
|
||||
|
||||
static void *trickle_timer_over(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
ipv6_addr_t mcast;
|
||||
ipv6_addr_set_all_nodes_addr(&mcast);
|
||||
|
||||
while (1) {
|
||||
thread_sleep();
|
||||
|
||||
/* Handle k=0 like k=infinity (according to RFC6206, section 6.5) */
|
||||
if ((c < k) || (k == 0)) {
|
||||
rpl_send_DIO(&mcast);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *trickle_interval_over(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
while (1) {
|
||||
thread_sleep();
|
||||
I = I * 2;
|
||||
DEBUG("TRICKLE new Interval %" PRIu32 "\n", I);
|
||||
|
||||
if (I == 0) {
|
||||
DEBUGF("[WARNING] Interval was 0\n");
|
||||
|
||||
if (Imax == 0) {
|
||||
DEBUGF("[WARNING] Imax == 0\n");
|
||||
}
|
||||
|
||||
I = (Imin << Imax);
|
||||
}
|
||||
|
||||
if (I > (Imin << Imax)) {
|
||||
I = (Imin << Imax);
|
||||
}
|
||||
|
||||
c = 0;
|
||||
t = (I / 2) + (rand() % (I - (I / 2) + 1));
|
||||
/* start timer */
|
||||
t_time = timex_set(0, t * 1000);
|
||||
timex_normalize(&t_time);
|
||||
I_time = timex_set(0, I * 1000);
|
||||
timex_normalize(&I_time);
|
||||
|
||||
vtimer_remove(&trickle_t_timer);
|
||||
|
||||
if (vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid) != 0) {
|
||||
DEBUGF("[ERROR] setting Wakeup\n");
|
||||
}
|
||||
|
||||
vtimer_remove(&trickle_I_timer);
|
||||
|
||||
if (vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid) != 0) {
|
||||
DEBUGF("[ERROR] setting Wakeup\n");
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void delay_dao(void)
|
||||
{
|
||||
dao_time = timex_set(DEFAULT_DAO_DELAY, 0);
|
||||
dao_counter = 0;
|
||||
ack_received = false;
|
||||
vtimer_remove(&dao_timer);
|
||||
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
|
||||
}
|
||||
|
||||
/* This function is used for regular update of the routes. The Timer can be overwritten, as the normal delay_dao function gets called */
|
||||
void long_delay_dao(void)
|
||||
{
|
||||
dao_time = timex_set(REGULAR_DAO_INTERVAL, 0);
|
||||
dao_counter = 0;
|
||||
ack_received = false;
|
||||
vtimer_remove(&dao_timer);
|
||||
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
|
||||
}
|
||||
|
||||
static void *dao_delay_over(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
while (1) {
|
||||
thread_sleep();
|
||||
|
||||
if ((ack_received == false) && (dao_counter < DAO_SEND_RETRIES)) {
|
||||
dao_counter++;
|
||||
rpl_send_DAO(NULL, 0, true, 0);
|
||||
dao_time = timex_set(DEFAULT_WAIT_FOR_DAO_ACK, 0);
|
||||
vtimer_remove(&dao_timer);
|
||||
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
|
||||
}
|
||||
else if (ack_received == false) {
|
||||
long_delay_dao();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dao_ack_received(void)
|
||||
{
|
||||
ack_received = true;
|
||||
long_delay_dao();
|
||||
}
|
||||
|
||||
static void *rt_timer_over(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
#if RPL_MAX_ROUTING_ENTRIES != 0
|
||||
rpl_routing_entry_t *rt;
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
||||
|
||||
if (my_dodag != NULL) {
|
||||
#if RPL_MAX_ROUTING_ENTRIES != 0
|
||||
rt = rpl_get_routing_table();
|
||||
|
||||
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
||||
if (rt[i].used) {
|
||||
if (rt[i].lifetime <= 1) {
|
||||
memset(&rt[i], 0, sizeof(rt[i]));
|
||||
}
|
||||
else {
|
||||
rt[i].lifetime--;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Parent is NULL for root too */
|
||||
if (my_dodag->my_preferred_parent != NULL) {
|
||||
if (my_dodag->my_preferred_parent->lifetime <= 1) {
|
||||
DEBUGF("parent lifetime timeout\n");
|
||||
rpl_parent_update(NULL);
|
||||
}
|
||||
else {
|
||||
my_dodag->my_preferred_parent->lifetime--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Wake up every second */
|
||||
vtimer_usleep(1000000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2013 INRIA.
|
||||
*
|
||||
* 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 trickle.h
|
||||
* @brief Trickle
|
||||
*
|
||||
* Header-file, which defines all Trickle constants and prototypes
|
||||
*
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "vtimer.h"
|
||||
#include "thread.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TRICKLE_TIMER_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
|
||||
#define TRICKLE_INTERVAL_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
|
||||
#define DAO_DELAY_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
|
||||
#define RT_STACKSIZE (KERNEL_CONF_STACKSIZE_DEFAULT)
|
||||
|
||||
void reset_trickletimer(void);
|
||||
void init_trickle(void);
|
||||
void start_trickle(uint8_t DIOINtMin, uint8_t DIOIntDoubl, uint8_t DIORedundancyConstatnt);
|
||||
void trickle_increment_counter(void);
|
||||
void delay_dao(void);
|
||||
void dao_ack_received(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
3
sys/trickle/Makefile
Normal file
3
sys/trickle/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = trickle
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
102
sys/trickle/trickle.c
Normal file
102
sys/trickle/trickle.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Trickle implementation
|
||||
*
|
||||
* Copyright (C) 2013, 2014 INRIA.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Eric Engel <eric.engel@fu-berlin.de>
|
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "inttypes.h"
|
||||
#include "trickle.h"
|
||||
#include "rpl.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
void trickle_callback(trickle_t *trickle)
|
||||
{
|
||||
/* Handle k=0 like k=infinity (according to RFC6206, section 6.5) */
|
||||
if ((trickle->c < trickle->k) || (trickle->k == 0)) {
|
||||
(*trickle->callback.func)(trickle->callback.args);
|
||||
}
|
||||
}
|
||||
|
||||
void trickle_interval(trickle_t *trickle)
|
||||
{
|
||||
trickle->I = trickle->I * 2;
|
||||
DEBUG("TRICKLE new Interval %" PRIu32 "\n", trickle->I);
|
||||
|
||||
if (trickle->I == 0) {
|
||||
DEBUGF("[WARNING] Interval was 0\n");
|
||||
|
||||
if (trickle->Imax == 0) {
|
||||
DEBUGF("[WARNING] Imax == 0\n");
|
||||
}
|
||||
|
||||
trickle->I = (trickle->Imin << trickle->Imax);
|
||||
}
|
||||
|
||||
if (trickle->I > (trickle->Imin << trickle->Imax)) {
|
||||
trickle->I = (trickle->Imin << trickle->Imax);
|
||||
}
|
||||
|
||||
trickle->c = 0;
|
||||
trickle->t = (trickle->I / 2) + (rand() % ((trickle->I / 2) + 1));
|
||||
|
||||
vtimer_remove(&trickle->msg_callback_timer);
|
||||
trickle->msg_callback_time = timex_set(0, trickle->t * 1000);
|
||||
vtimer_set_msg(&trickle->msg_callback_timer, trickle->msg_callback_time, trickle->pid,
|
||||
trickle->callback_msg_type, trickle);
|
||||
|
||||
vtimer_remove(&trickle->msg_interval_timer);
|
||||
trickle->msg_interval_time = timex_set(0, trickle->I * 1000);
|
||||
vtimer_set_msg(&trickle->msg_interval_timer, trickle->msg_interval_time, trickle->pid,
|
||||
trickle->interval_msg_type, trickle);
|
||||
}
|
||||
|
||||
void trickle_reset_timer(trickle_t *trickle)
|
||||
{
|
||||
vtimer_remove(&trickle->msg_interval_timer);
|
||||
vtimer_remove(&trickle->msg_callback_timer);
|
||||
trickle_start(trickle->pid, trickle, trickle->interval_msg_type, trickle->callback_msg_type,
|
||||
trickle->Imin, trickle->Imax, trickle->k);
|
||||
}
|
||||
|
||||
void trickle_start(kernel_pid_t pid, trickle_t *trickle, uint16_t interval_msg_type,
|
||||
uint16_t callback_msg_type, uint32_t Imin, uint8_t Imax, uint8_t k)
|
||||
{
|
||||
trickle->pid = pid;
|
||||
|
||||
trickle->c = 0;
|
||||
trickle->k = k;
|
||||
trickle->Imin = Imin;
|
||||
trickle->Imax = Imax;
|
||||
trickle->I = trickle->Imin + (rand() % (4 * trickle->Imin));
|
||||
trickle->pid = pid;
|
||||
trickle->interval_msg_type = interval_msg_type;
|
||||
trickle->callback_msg_type = callback_msg_type;
|
||||
|
||||
trickle_interval(trickle);
|
||||
}
|
||||
|
||||
void trickle_stop(trickle_t *trickle)
|
||||
{
|
||||
vtimer_remove(&trickle->msg_interval_timer);
|
||||
vtimer_remove(&trickle->msg_callback_timer);
|
||||
}
|
||||
|
||||
void trickle_increment_counter(trickle_t *trickle)
|
||||
{
|
||||
trickle->c++;
|
||||
}
|
Loading…
Reference in New Issue
Block a user