43#include "net/routing/rpl-classic/rpl-private.h"
44#include "net/link-stats.h"
47#include "lib/random.h"
51#define LOG_MODULE "RPL"
52#define LOG_LEVEL LOG_LEVEL_RPL
55#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
56void RPL_CALLBACK_NEW_DIO_INTERVAL(clock_time_t dio_interval);
59#ifdef RPL_PROBING_SELECT_FUNC
60rpl_parent_t *RPL_PROBING_SELECT_FUNC(
rpl_dag_t *dag);
63#ifdef RPL_PROBING_DELAY_FUNC
64clock_time_t RPL_PROBING_DELAY_FUNC(
rpl_dag_t *dag);
68static struct ctimer periodic_timer;
70static void handle_periodic_timer(
void *ptr);
72static void handle_dio_timer(
void *ptr);
74static uint16_t next_dis;
77static uint8_t dio_send_ok;
81handle_periodic_timer(
void *ptr)
87 if(RPL_IS_STORING(dag->instance)) {
90 if(RPL_IS_NON_STORING(dag->instance)) {
94 rpl_recalculate_ranks();
99 if((dag == NULL || dag->instance->current_dag->rank == RPL_INFINITE_RANK)
100 && next_dis >= RPL_DIS_INTERVAL) {
115 time = 1UL << instance->dio_intcurrent;
119 instance->dio_next_delay = ticks;
122 ticks = ticks / 2 + (ticks / 2 * (uint32_t)
random_rand()) / RANDOM_RAND_MAX;
129 instance->dio_next_delay -= ticks;
130 instance->dio_send = 1;
134 instance->dio_totint++;
135 instance->dio_totrecv += instance->dio_counter;
136 LOG_ANNOTATE(
"#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n",
137 DAG_RANK(instance->current_dag->rank, instance),
138 (10 * (instance->current_dag->rank % instance->min_hoprankinc)) / instance->min_hoprankinc,
139 instance->current_dag->version,
140 instance->dio_totint, instance->dio_totsend,
141 instance->dio_totrecv, instance->dio_intcurrent,
142 instance->current_dag->rank ==
ROOT_RANK(instance) ?
"BLUE" :
"ORANGE");
146 instance->dio_counter = 0;
149 LOG_INFO(
"Scheduling DIO timer %lu ticks in future (Interval)\n", ticks);
150 ctimer_set(&instance->dio_timer, ticks, &handle_dio_timer, instance);
152#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
153 RPL_CALLBACK_NEW_DIO_INTERVAL((
CLOCK_SECOND * 1UL << instance->dio_intcurrent) / 1000);
158handle_dio_timer(
void *ptr)
162 LOG_DBG(
"DIO Timer triggered\n");
164 if(uip_ds6_get_link_local(ADDR_PREFERRED) != NULL) {
167 LOG_WARN(
"Postponing DIO transmission since link local address is not ok\n");
173 if(instance->dio_send) {
175 if(instance->dio_redundancy == 0 || instance->dio_counter < instance->dio_redundancy) {
177 instance->dio_totsend++;
179 dio_output(instance, NULL);
181 LOG_DBG(
"Suppressing DIO transmission (%d >= %d)\n",
182 instance->dio_counter, instance->dio_redundancy);
184 instance->dio_send = 0;
185 LOG_DBG(
"Scheduling DIO timer %lu ticks in future (sent)\n",
186 instance->dio_next_delay);
187 ctimer_set(&instance->dio_timer, instance->dio_next_delay,
188 handle_dio_timer, instance);
191 if(instance->dio_intcurrent <
192 instance->dio_intmin + instance->dio_intdoubl) {
193 instance->dio_intcurrent++;
194 LOG_DBG(
"DIO Timer interval doubled %d\n", instance->dio_intcurrent);
196 new_dio_interval(instance);
199 if(LOG_DBG_ENABLED) {
200 rpl_print_neighbor_list();
205rpl_reset_periodic_timer(
void)
207 next_dis = RPL_DIS_INTERVAL / 2 +
208 ((uint32_t)RPL_DIS_INTERVAL * (uint32_t)
random_rand()) / RANDOM_RAND_MAX -
220 if(instance->dio_intcurrent > instance->dio_intmin) {
221 instance->dio_counter = 0;
222 instance->dio_intcurrent = instance->dio_intmin;
223 new_dio_interval(instance);
231static void handle_dao_timer(
void *ptr);
241 if(instance->default_lifetime != RPL_INFINITE_LIFETIME) {
242 clock_time_t expiration_time;
249 if(instance->default_lifetime == 0 || instance->lifetime_unit == 0) {
252 expiration_time = (clock_time_t)instance->default_lifetime *
253 (clock_time_t)instance->lifetime_unit *
CLOCK_SECOND / 2;
258 expiration_time = expiration_time + (
random_rand() % (expiration_time / 2));
259 LOG_DBG(
"Scheduling DAO lifetime timer %u ticks in the future\n",
260 (
unsigned)expiration_time);
261 ctimer_set(&instance->dao_lifetime_timer, expiration_time,
262 handle_dao_timer, instance);
267handle_dao_timer(
void *ptr)
271#if RPL_WITH_MULTICAST
276 if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) {
277 LOG_INFO(
"Postpone DAO transmission\n");
283 if(instance->current_dag->preferred_parent != NULL) {
284 LOG_INFO(
"handle_dao_timer - sending DAO\n");
286 dao_output(instance->current_dag->preferred_parent,
287 instance->default_lifetime);
289#if RPL_WITH_MULTICAST
291 if(instance->mop == RPL_MOP_STORING_MULTICAST) {
293 for(i = 0; i < UIP_DS6_MADDR_NB; i++) {
296 dao_output_target(instance->current_dag->preferred_parent,
297 &
uip_ds6_if.maddr_list[i].ipaddr, instance->default_lifetime);
303 while(mcast_route != NULL) {
305 if(uip_ds6_maddr_lookup(&mcast_route->
group) == NULL) {
306 dao_output_target(instance->current_dag->preferred_parent,
307 &mcast_route->
group, instance->default_lifetime);
314 LOG_INFO(
"No suitable DAO parent\n");
320 set_dao_lifetime_timer(instance);
327 clock_time_t expiration_time;
336 LOG_DBG(
"DAO timer already scheduled\n");
339 expiration_time = latency / 2 +
344 LOG_DBG(
"Scheduling DAO timer %u ticks in the future\n",
345 (
unsigned)expiration_time);
346 ctimer_set(&instance->dao_timer, expiration_time,
347 handle_dao_timer, instance);
349 set_dao_lifetime_timer(instance);
356 schedule_dao(instance, RPL_DAO_DELAY);
362 schedule_dao(instance, 0);
373handle_unicast_dio_timer(
void *ptr)
376 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(instance->unicast_dio_target);
378 if(target_ipaddr != NULL) {
379 dio_output(instance, target_ipaddr);
387 handle_unicast_dio_timer, instance);
394 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
411 rpl_parent_t *probing_target = NULL;
412 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
413 clock_time_t probing_target_age = 0;
416 if(dag == NULL || dag->instance == NULL) {
421 if(dag->instance->urgent_probing_target != NULL) {
422 return dag->instance->urgent_probing_target;
426 if(dag->preferred_parent != NULL
427 && !rpl_parent_is_fresh(dag->preferred_parent)) {
428 return dag->preferred_parent;
433 p = nbr_table_head(rpl_parents);
435 if(p->dag == dag && !rpl_parent_is_fresh(p)) {
437 rpl_rank_t p_rank = rpl_rank_via_parent(p);
438 if(probing_target == NULL || p_rank < probing_target_rank) {
440 probing_target_rank = p_rank;
443 p = nbr_table_next(rpl_parents, p);
449 if(probing_target == NULL) {
450 p = nbr_table_head(rpl_parents);
452 const struct link_stats *stats = rpl_get_parent_link_stats(p);
453 if(p->dag == dag && stats != NULL) {
454 if(probing_target == NULL
455 || clock_now - stats->last_tx_time > probing_target_age) {
457 probing_target_age = clock_now - stats->last_tx_time;
460 p = nbr_table_next(rpl_parents, p);
464 return probing_target;
471 int new_dag = instance->last_dag;
475 if(new_dag >= RPL_MAX_DAG_PER_INSTANCE) {
478 if(instance->dag_table[new_dag].used) {
479 dag = &instance->dag_table[new_dag];
481 }
while(new_dag != instance->last_dag && dag == NULL);
482 instance->last_dag = new_dag;
487handle_probing_timer(
void *ptr)
490 rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(get_next_dag(instance));
491 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(probing_target);
494 if(target_ipaddr != NULL) {
495 const struct link_stats *stats = rpl_get_parent_link_stats(probing_target);
496 const linkaddr_t *lladdr = rpl_get_parent_lladdr(probing_target);
497 LOG_INFO(
"probing %u %s last tx %u min ago\n",
498 lladdr != NULL ? lladdr->u8[7] : 0x0,
499 instance->urgent_probing_target != NULL ?
"(urgent)" :
"",
500 probing_target != NULL && stats != NULL ?
505 RPL_PROBING_SEND_FUNC(instance, target_ipaddr);
511 if(LOG_DBG_ENABLED) {
512 rpl_print_neighbor_list();
520 RPL_PROBING_DELAY_FUNC(instance->current_dag),
521 handle_probing_timer, instance);
528 handle_probing_timer, instance);
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.
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
clock_time_t etimer_expiration_time(struct etimer *et)
Get the expiration time for the event timer.
void * list_item_next(const void *item)
Get the next item following this item.
void rpl_schedule_probing(void)
Schedule probing with delay RPL_PROBING_DELAY_FUNC()
void rpl_schedule_probing_now(void)
Schedule probing within a few seconds.
#define DAG_RANK(fixpt_rank)
Return DAG RANK as per RFC 6550 (rank divided by min_hoprankinc)
#define ROOT_RANK
Rank of a root node.
uip_mcast6_route_t * uip_mcast6_route_list_head(void)
Retrieve a pointer to the start of the multicast routes list.
rpl_dag_t * rpl_get_any_dag(void)
Returns pointer to any DAG (for compatibility with legagy RPL code)
enum rpl_mode rpl_get_mode(void)
Get the RPL mode.
void uip_sr_periodic(unsigned seconds)
A function called periodically.
#define uip_is_addr_mcast_global(a)
is address a global multicast address (FFxE::/16), a is of type uip_ip6addr_t*
uip_ds6_netif_t uip_ds6_if
The single interface.
Header file for the logging system.
An entry in the multicast routing table.
uip_ipaddr_t group
The multicast group.
This header file contains configuration directives for uIPv6 multicast support.