44#include "net/routing/rpl-lite/rpl.h"
46#include "net/link-stats.h"
47#include "lib/random.h"
52#define LOG_MODULE "RPL"
53#define LOG_LEVEL LOG_LEVEL_RPL
56#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
57void RPL_CALLBACK_NEW_DIO_INTERVAL(clock_time_t dio_interval);
60#ifdef RPL_PROBING_SELECT_FUNC
64#ifdef RPL_PROBING_DELAY_FUNC
65clock_time_t RPL_PROBING_DELAY_FUNC(
void);
68#define PERIODIC_DELAY_SECONDS 60
69#define PERIODIC_DELAY ((PERIODIC_DELAY_SECONDS) * CLOCK_SECOND)
71static void handle_dis_timer(
void *ptr);
72static void handle_dio_timer(
void *ptr);
73static void handle_unicast_dio_timer(
void *ptr);
74static void send_new_dao(
void *ptr);
76static void resend_dao(
void *ptr);
77static void handle_dao_ack_timer(
void *ptr);
80static void handle_probing_timer(
void *ptr);
82static void handle_periodic_timer(
void *ptr);
83static void handle_state_update(
void *ptr);
86static struct ctimer dis_timer;
87static struct ctimer periodic_timer;
96 clock_time_t expiration_time = RPL_DIS_INTERVAL / 2 + (
random_rand() % (RPL_DIS_INTERVAL));
97 ctimer_set(&dis_timer, expiration_time, handle_dis_timer, NULL);
102handle_dis_timer(
void *ptr)
104 if(!rpl_dag_root_is_root() &&
105 (!curr_instance.used ||
106 curr_instance.dag.preferred_parent == NULL ||
107 curr_instance.dag.rank == RPL_INFINITE_RANK)) {
117new_dio_interval(
void)
122 time = 1UL << curr_instance.dag.dio_intcurrent;
126 curr_instance.dag.dio_next_delay = ticks;
129 ticks = ticks / 2 + (ticks / 2 * (uint32_t)
random_rand()) / RANDOM_RAND_MAX;
136 curr_instance.dag.dio_next_delay -= ticks;
137 curr_instance.dag.dio_send = 1;
139 curr_instance.dag.dio_counter = 0;
142 ctimer_set(&curr_instance.dag.dio_timer, ticks, &handle_dio_timer, NULL);
144#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
145 RPL_CALLBACK_NEW_DIO_INTERVAL((
CLOCK_SECOND * 1UL << curr_instance.dag.dio_intcurrent) / 1000);
153 (curr_instance.dag.dio_intcurrent == 0 ||
154 curr_instance.dag.dio_intcurrent > curr_instance.dio_intmin)) {
159 LOG_INFO(
"reset DIO timer (%s)\n", str);
161 curr_instance.dag.dio_counter = 0;
162 curr_instance.dag.dio_intcurrent = curr_instance.dio_intmin;
169handle_dio_timer(
void *ptr)
175 if(curr_instance.dag.dio_send) {
178 if(rpl_dag_root_is_root() || curr_instance.dio_redundancy == 0 ||
179 curr_instance.dag.dio_counter < curr_instance.dio_redundancy) {
180#if RPL_TRICKLE_REFRESH_DAO_ROUTES
181 if(rpl_dag_root_is_root()) {
182 static int count = 0;
183 if((
count++ % RPL_TRICKLE_REFRESH_DAO_ROUTES) == 0) {
185 RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
186 LOG_INFO(
"trigger DAO updates with a DTSN increment (%u)\n", curr_instance.dtsn_out);
190 curr_instance.dag.last_advertised_rank = curr_instance.dag.rank;
193 curr_instance.dag.dio_send = 0;
194 ctimer_set(&curr_instance.dag.dio_timer, curr_instance.dag.dio_next_delay, handle_dio_timer, NULL);
197 if(curr_instance.dag.dio_intcurrent < curr_instance.dio_intmin + curr_instance.dio_intdoubl) {
198 curr_instance.dag.dio_intcurrent++;
210 if(curr_instance.used) {
211 curr_instance.dag.unicast_dio_target = target;
212 ctimer_set(&curr_instance.dag.unicast_dio_timer, 0,
213 handle_unicast_dio_timer, NULL);
218handle_unicast_dio_timer(
void *ptr)
221 if(target_ipaddr != NULL) {
231schedule_dao_retransmission(
void)
233 clock_time_t expiration_time = RPL_DAO_RETRANSMISSION_TIMEOUT / 2 + (
random_rand() % (RPL_DAO_RETRANSMISSION_TIMEOUT));
234 ctimer_set(&curr_instance.dag.dao_timer, expiration_time, resend_dao, NULL);
239schedule_dao_refresh(
void)
241 if(curr_instance.used && curr_instance.default_lifetime != RPL_INFINITE_LIFETIME) {
244 clock_time_t target_refresh =
CLOCK_SECOND * RPL_LIFETIME(curr_instance.default_lifetime);
247 clock_time_t target_refresh = (
CLOCK_SECOND * RPL_LIFETIME(curr_instance.default_lifetime) / 2);
253 if(target_refresh > safety_margin) {
254 target_refresh -= safety_margin;
258 ctimer_set(&curr_instance.dag.dao_timer, target_refresh, send_new_dao, NULL);
265 if(curr_instance.used && curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
269 clock_time_t expiration_time = RPL_DAO_DELAY / 2 + (
random_rand() % (RPL_DAO_DELAY));
270 ctimer_set(&curr_instance.dag.dao_timer, expiration_time, send_new_dao, NULL);
275send_new_dao(
void *ptr)
279 curr_instance.dag.dao_transmissions = 1;
281 schedule_dao_retransmission();
284 if(curr_instance.dag.state == DAG_JOINED) {
285 curr_instance.dag.state = DAG_REACHABLE;
289 schedule_dao_refresh();
293 RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_last_seqno);
305 if(curr_instance.used) {
307 curr_instance.dag.dao_ack_sequence = sequence;
308 ctimer_set(&curr_instance.dag.dao_ack_timer, 0, handle_dao_ack_timer, NULL);
313handle_dao_ack_timer(
void *ptr)
316 curr_instance.dag.dao_ack_sequence, RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
324 schedule_dao_refresh();
331 curr_instance.dag.dao_transmissions++;
336 if(curr_instance.dag.dao_transmissions < RPL_DAO_MAX_RETRANSMISSIONS) {
337 schedule_dao_retransmission();
340 rpl_local_repair(
"DAO max rtx");
350get_probing_delay(
void)
352 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
356get_probing_target(
void)
367 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
368 clock_time_t probing_target_age = 0;
371 if(curr_instance.used == 0) {
376 if(curr_instance.dag.urgent_probing_target != NULL) {
377 return curr_instance.dag.urgent_probing_target;
381 if(curr_instance.dag.preferred_parent != NULL && !
rpl_neighbor_is_fresh(curr_instance.dag.preferred_parent)) {
382 return curr_instance.dag.preferred_parent;
390 nbr = nbr_table_head(rpl_neighbors);
395 if(probing_target == NULL
396 || nbr_rank < probing_target_rank) {
397 probing_target =
nbr;
398 probing_target_rank = nbr_rank;
401 nbr = nbr_table_next(rpl_neighbors,
nbr);
405 nbr = nbr_table_head(rpl_neighbors);
411 if(probing_target == NULL
412 || clock_now - stats->last_tx_time > probing_target_age) {
413 probing_target =
nbr;
414 probing_target_age = clock_now - stats->last_tx_time;
418 nbr = nbr_table_next(rpl_neighbors,
nbr);
422 return probing_target;
426handle_probing_timer(
void *ptr)
428 rpl_nbr_t *probing_target = RPL_PROBING_SELECT_FUNC();
432 if(target_ipaddr != NULL) {
435 LOG_INFO(
"probing ");
436 LOG_INFO_6ADDR(target_ipaddr);
437 LOG_INFO_(
" %s last tx %u min ago\n",
438 curr_instance.dag.urgent_probing_target != NULL ?
"(urgent)" :
"",
443 RPL_PROBING_SEND_FUNC(target_ipaddr);
446 LOG_INFO(
"no neighbor needs probing\n");
456 if(curr_instance.used) {
457 ctimer_set(&curr_instance.dag.probing_timer, RPL_PROBING_DELAY_FUNC(),
458 handle_probing_timer, NULL);
465 if(curr_instance.used) {
475handle_leaving_timer(
void *ptr)
477 if(curr_instance.used) {
485 if(curr_instance.used) {
495 if(curr_instance.used) {
497 ctimer_set(&curr_instance.dag.leave, RPL_DELAY_BEFORE_LEAVING, handle_leaving_timer, NULL);
507 ctimer_set(&periodic_timer, PERIODIC_DELAY, handle_periodic_timer, NULL);
512handle_periodic_timer(
void *ptr)
514 if(curr_instance.used) {
519 if(!curr_instance.used ||
520 curr_instance.dag.preferred_parent == NULL ||
521 curr_instance.dag.rank == RPL_INFINITE_RANK) {
529 if(LOG_INFO_ENABLED) {
557 if(curr_instance.used) {
558 ctimer_set(&curr_instance.dag.state_update, 0, handle_state_update, NULL);
563handle_state_update(
void *ptr)
Header file for the callback timer.
clock_time_t clock_time(void)
Get the current clock time.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
static volatile uint64_t count
Num.
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
bool ctimer_expired(struct ctimer *c)
Check if a callback timer has expired.
static void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
void rpl_timers_stop_dag_timers(void)
Stop all timers related to the DAG.
void rpl_schedule_probing(void)
Schedule probing with delay RPL_PROBING_DELAY_FUNC()
rpl_rank_t rpl_neighbor_rank_via_nbr(rpl_nbr_t *nbr)
Returns our rank if selecting a given parent as preferred parent.
void rpl_icmp6_dis_output(uip_ipaddr_t *addr)
Creates an ICMPv6 DIS packet and sends it.
void rpl_schedule_probing_now(void)
Schedule probing within a few seconds.
uint8_t rpl_get_leaf_only(void)
Get the value of the rpl_leaf_only flag.
int rpl_neighbor_is_fresh(rpl_nbr_t *nbr)
Tells wether we have fresh link information towards a given neighbor.
void rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr)
Creates an ICMPv6 DIO packet and sends it.
void rpl_dag_root_print_links(const char *str)
Prints a summary of all routing links.
void rpl_dag_update_state(void)
Updates RPL internal state: selects preferred parent, updates rank & metreic container,...
void rpl_dag_periodic(unsigned seconds)
A function called periodically.
void rpl_timers_notify_dao_ack(void)
Let the rpl-timers module know that the last DAO was ACKed.
void rpl_timers_schedule_dao(void)
Schedule a DAO with random delay based on RPL_DAO_DELAY.
void rpl_timers_schedule_leaving(void)
Schedule leaving after RPL_DELAY_BEFORE_LEAVING.
const struct link_stats * rpl_neighbor_get_link_stats(rpl_nbr_t *nbr)
Returns a neighbor's link statistics.
void rpl_timers_dio_reset(const char *str)
Reset DIO Trickle timer.
void rpl_timers_init(void)
Initialize rpl-timers module.
void rpl_icmp6_dao_output(uint8_t lifetime)
Creates an ICMPv6 DAO packet and sends it to the root, advertising the current preferred parent,...
int rpl_dag_ready_to_advertise(void)
Tells whether RPL is ready to advertise the DAG.
void rpl_timers_schedule_dao_ack(uip_ipaddr_t *target, uint16_t sequence)
Schedule a DAO-ACK with no delay.
void rpl_icmp6_dao_ack_output(uip_ipaddr_t *dest, uint8_t sequence, uint8_t status)
Creates an ICMPv6 DAO-ACK packet and sends it to the originator of the ACK.
void rpl_timers_unschedule_leaving(void)
Cancel scheduled leaving if any.
uip_ipaddr_t * rpl_neighbor_get_ipaddr(rpl_nbr_t *nbr)
Returns a neighbor's (link-local) IPv6 address.
void rpl_dag_leave(void)
Leaves the current DAG.
void rpl_neighbor_print_list(const char *str)
Prints a summary of all RPL neighbors and their properties.
void rpl_timers_schedule_periodic_dis(void)
Schedule periodic DIS with a random delay based on RPL_DIS_INTERVAL, until we join a DAG.
void rpl_timers_schedule_state_update(void)
Schedule a state update ASAP.
void rpl_timers_schedule_unicast_dio(rpl_nbr_t *target)
Schedule unicast DIO with no delay.
void uip_sr_periodic(unsigned seconds)
A function called periodically.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Header file for the logging system.
All information related to a RPL neighbor.
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.