diff --git a/Makefile.dep b/Makefile.dep index 85076fee24..730597589b 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -32,6 +32,7 @@ ifneq (,$(filter sixlowborder,$(USEMODULE))) endif ifneq (,$(filter rpl,$(USEMODULE))) + USEMODULE += trickle USEMODULE += routing endif diff --git a/sys/Makefile b/sys/Makefile index 27c2ef30a6..537c8c43be 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -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}))) diff --git a/sys/include/trickle.h b/sys/include/trickle.h new file mode 100644 index 0000000000..92658509f5 --- /dev/null +++ b/sys/include/trickle.h @@ -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 + * @author Cenk Gündoğan + */ + +#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 */ +/** @} */ diff --git a/sys/net/include/rpl/rpl_config.h b/sys/net/include/rpl/rpl_config.h index 90e28484c6..e55eda0b31 100644 --- a/sys/net/include/rpl/rpl_config.h +++ b/sys/net/include/rpl/rpl_config.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 diff --git a/sys/net/include/rpl/rpl_dodag.h b/sys/net/include/rpl/rpl_dodag.h index 07bb3b5d03..2b1ddf8c0c 100644 --- a/sys/net/include/rpl/rpl_dodag.h +++ b/sys/net/include/rpl/rpl_dodag.h @@ -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); diff --git a/sys/net/include/rpl/rpl_structs.h b/sys/net/include/rpl/rpl_structs.h index c607215011..3f5fd4a747 100644 --- a/sys/net/include/rpl/rpl_structs.h +++ b/sys/net/include/rpl/rpl_structs.h @@ -18,9 +18,6 @@ * @} */ -#include -#include "ipv6.h" - #ifndef RPL_STRUCTS_H_INCLUDED #define RPL_STRUCTS_H_INCLUDED @@ -28,6 +25,10 @@ extern "C" { #endif +#include +#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 { diff --git a/sys/net/network_layer/sixlowpan/ip.c b/sys/net/network_layer/sixlowpan/ip.c index 1a53e2f025..982d7bcbac 100644 --- a/sys/net/network_layer/sixlowpan/ip.c +++ b/sys/net/network_layer/sixlowpan/ip.c @@ -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 { diff --git a/sys/net/routing/rpl/rpl.c b/sys/net/routing/rpl/rpl.c index 890dec3e1e..7db945142f 100644 --- a/sys/net/routing/rpl/rpl.c +++ b/sys/net/routing/rpl/rpl.c @@ -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 diff --git a/sys/net/routing/rpl/rpl_dodag.c b/sys/net/routing/rpl/rpl_dodag.c index 19477c4634..cd444e8da6 100644 --- a/sys/net/routing/rpl/rpl_dodag.c +++ b/sys/net/routing/rpl/rpl_dodag.c @@ -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); } diff --git a/sys/net/routing/rpl/rpl_nonstoring/rpl_nonstoring.c b/sys/net/routing/rpl/rpl_nonstoring/rpl_nonstoring.c index f1fa58af4b..d7a4884437 100644 --- a/sys/net/routing/rpl/rpl_nonstoring/rpl_nonstoring.c +++ b/sys/net/routing/rpl/rpl_nonstoring/rpl_nonstoring.c @@ -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); } diff --git a/sys/net/routing/rpl/rpl_storing/rpl_storing.c b/sys/net/routing/rpl/rpl_storing/rpl_storing.c index a9a8611491..4d09e8433f 100644 --- a/sys/net/routing/rpl/rpl_storing/rpl_storing.c +++ b/sys/net/routing/rpl/rpl_storing/rpl_storing.c @@ -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); } diff --git a/sys/net/routing/rpl/trickle.c b/sys/net/routing/rpl/trickle.c deleted file mode 100644 index af05fe7a5e..0000000000 --- a/sys/net/routing/rpl/trickle.c +++ /dev/null @@ -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 - * @} - */ - -#include -#include -#include -#include - -#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; -} diff --git a/sys/net/routing/rpl/trickle.h b/sys/net/routing/rpl/trickle.h deleted file mode 100644 index dd2f7b8562..0000000000 --- a/sys/net/routing/rpl/trickle.h +++ /dev/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 - * @} - */ - -#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 diff --git a/sys/trickle/Makefile b/sys/trickle/Makefile new file mode 100644 index 0000000000..9f9b64b8e8 --- /dev/null +++ b/sys/trickle/Makefile @@ -0,0 +1,3 @@ +MODULE = trickle + +include $(RIOTBASE)/Makefile.base diff --git a/sys/trickle/trickle.c b/sys/trickle/trickle.c new file mode 100644 index 0000000000..5e17b638ae --- /dev/null +++ b/sys/trickle/trickle.c @@ -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 + * @author Cenk Gündoğan + */ + +#include +#include +#include + +#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++; +}