45#include "net/routing/rpl-classic/rpl-private.h"
46#include "net/link-stats.h"
49#include "lib/random.h"
53#define LOG_MODULE "RPL"
54#define LOG_LEVEL LOG_LEVEL_RPL
57#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
58void RPL_CALLBACK_NEW_DIO_INTERVAL(clock_time_t dio_interval);
61#ifdef RPL_PROBING_SELECT_FUNC
62rpl_parent_t *RPL_PROBING_SELECT_FUNC(
rpl_dag_t *dag);
65#ifdef RPL_PROBING_DELAY_FUNC
66clock_time_t RPL_PROBING_DELAY_FUNC(
rpl_dag_t *dag);
70static struct ctimer periodic_timer;
72static void handle_periodic_timer(
void *ptr);
74static void handle_dio_timer(
void *ptr);
76static uint16_t next_dis;
79static uint8_t dio_send_ok;
83handle_periodic_timer(
void *ptr)
89 if(RPL_IS_STORING(dag->instance)) {
92 if(RPL_IS_NON_STORING(dag->instance)) {
96 rpl_recalculate_ranks();
101 if((dag == NULL || dag->instance->current_dag->rank == RPL_INFINITE_RANK) && next_dis >= RPL_DIS_INTERVAL) {
116 time = 1UL << instance->dio_intcurrent;
120 instance->dio_next_delay = ticks;
123 ticks = ticks / 2 + (ticks / 2 * (uint32_t)
random_rand()) / RANDOM_RAND_MAX;
130 instance->dio_next_delay -= ticks;
131 instance->dio_send = 1;
135 instance->dio_totint++;
136 instance->dio_totrecv += instance->dio_counter;
137 LOG_ANNOTATE(
"#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n",
138 DAG_RANK(instance->current_dag->rank, instance),
139 (10 * (instance->current_dag->rank % instance->min_hoprankinc)) / instance->min_hoprankinc,
140 instance->current_dag->version,
141 instance->dio_totint, instance->dio_totsend,
142 instance->dio_totrecv,instance->dio_intcurrent,
143 instance->current_dag->rank ==
ROOT_RANK(instance) ?
"BLUE" :
"ORANGE");
147 instance->dio_counter = 0;
150 LOG_INFO(
"Scheduling DIO timer %lu ticks in future (Interval)\n", ticks);
151 ctimer_set(&instance->dio_timer, ticks, &handle_dio_timer, instance);
153#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
154 RPL_CALLBACK_NEW_DIO_INTERVAL((
CLOCK_SECOND * 1UL << instance->dio_intcurrent) / 1000);
159handle_dio_timer(
void *ptr)
165 LOG_DBG(
"DIO Timer triggered\n");
167 if(uip_ds6_get_link_local(ADDR_PREFERRED) != NULL) {
170 LOG_WARN(
"Postponing DIO transmission since link local address is not ok\n");
176 if(instance->dio_send) {
178 if(instance->dio_redundancy == 0 || instance->dio_counter < instance->dio_redundancy) {
180 instance->dio_totsend++;
182 dio_output(instance, NULL);
184 LOG_DBG(
"Suppressing DIO transmission (%d >= %d)\n",
185 instance->dio_counter, instance->dio_redundancy);
187 instance->dio_send = 0;
188 LOG_DBG(
"Scheduling DIO timer %lu ticks in future (sent)\n",
189 instance->dio_next_delay);
190 ctimer_set(&instance->dio_timer, instance->dio_next_delay, handle_dio_timer, instance);
193 if(instance->dio_intcurrent < instance->dio_intmin + instance->dio_intdoubl) {
194 instance->dio_intcurrent++;
195 LOG_DBG(
"DIO Timer interval doubled %d\n", instance->dio_intcurrent);
197 new_dio_interval(instance);
200 if(LOG_DBG_ENABLED) {
201 rpl_print_neighbor_list();
206rpl_reset_periodic_timer(
void)
208 next_dis = RPL_DIS_INTERVAL / 2 +
209 ((uint32_t)RPL_DIS_INTERVAL * (uint32_t)
random_rand()) / RANDOM_RAND_MAX -
221 if(instance->dio_intcurrent > instance->dio_intmin) {
222 instance->dio_counter = 0;
223 instance->dio_intcurrent = instance->dio_intmin;
224 new_dio_interval(instance);
232static void handle_dao_timer(
void *ptr);
242 if(instance->default_lifetime != RPL_INFINITE_LIFETIME) {
243 clock_time_t expiration_time;
250 if(instance->default_lifetime == 0 || instance->lifetime_unit == 0) {
253 expiration_time = (clock_time_t)instance->default_lifetime *
254 (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)
270#if RPL_WITH_MULTICAST
277 if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) {
278 LOG_INFO(
"Postpone DAO transmission\n");
284 if(instance->current_dag->preferred_parent != NULL) {
285 LOG_INFO(
"handle_dao_timer - sending DAO\n");
287 dao_output(instance->current_dag->preferred_parent, 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);
408 rpl_parent_t *probing_target = NULL;
409 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
410 clock_time_t probing_target_age = 0;
414 dag->instance == NULL) {
419 if(dag->instance->urgent_probing_target != NULL) {
420 return dag->instance->urgent_probing_target;
424 if(dag->preferred_parent != NULL && !rpl_parent_is_fresh(dag->preferred_parent)) {
425 return dag->preferred_parent;
430 p = nbr_table_head(rpl_parents);
432 if(p->dag == dag && !rpl_parent_is_fresh(p)) {
434 rpl_rank_t p_rank = rpl_rank_via_parent(p);
435 if(probing_target == NULL
436 || p_rank < probing_target_rank) {
438 probing_target_rank = p_rank;
441 p = nbr_table_next(rpl_parents, p);
446 if(probing_target == NULL) {
447 p = nbr_table_head(rpl_parents);
449 const struct link_stats *stats =rpl_get_parent_link_stats(p);
450 if(p->dag == dag && stats != NULL) {
451 if(probing_target == NULL
452 || clock_now - stats->last_tx_time > probing_target_age) {
454 probing_target_age = clock_now - stats->last_tx_time;
457 p = nbr_table_next(rpl_parents, p);
461 return probing_target;
468 int new_dag = instance->last_dag;
471 if(new_dag >= RPL_MAX_DAG_PER_INSTANCE) {
474 if(instance->dag_table[new_dag].used) {
475 dag = &instance->dag_table[new_dag];
477 }
while(new_dag != instance->last_dag && dag == NULL);
478 instance->last_dag = new_dag;
483handle_probing_timer(
void *ptr)
486 rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(get_next_dag(instance));
487 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(probing_target);
490 if(target_ipaddr != NULL) {
491 const struct link_stats *stats = rpl_get_parent_link_stats(probing_target);
492 const linkaddr_t *lladdr = rpl_get_parent_lladdr(probing_target);
493 LOG_INFO(
"probing %u %s last tx %u min ago\n",
494 lladdr != NULL ? lladdr->u8[7] : 0x0,
495 instance->urgent_probing_target != NULL ?
"(urgent)" :
"",
496 probing_target != NULL && stats != NULL ?
501 RPL_PROBING_SEND_FUNC(instance, target_ipaddr);
507 if(LOG_DBG_ENABLED) {
508 rpl_print_neighbor_list();
515 ctimer_set(&instance->probing_timer, RPL_PROBING_DELAY_FUNC(instance->current_dag),
516 handle_probing_timer, instance);
523 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.