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",
150 (
unsigned long)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)
163 LOG_DBG(
"DIO Timer triggered\n");
165 if(uip_ds6_get_link_local(ADDR_PREFERRED) != NULL) {
168 LOG_WARN(
"Postponing DIO transmission since link local address is not ok\n");
174 if(instance->dio_send) {
176 if(instance->dio_redundancy == 0 || instance->dio_counter < instance->dio_redundancy) {
178 instance->dio_totsend++;
180 dio_output(instance, NULL);
182 LOG_DBG(
"Suppressing DIO transmission (%d >= %d)\n",
183 instance->dio_counter, instance->dio_redundancy);
185 instance->dio_send = 0;
186 LOG_DBG(
"Scheduling DIO timer %lu ticks in future (sent)\n",
187 (
unsigned long)instance->dio_next_delay);
188 ctimer_set(&instance->dio_timer, instance->dio_next_delay,
189 handle_dio_timer, instance);
192 if(instance->dio_intcurrent <
193 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;
259 expiration_time = expiration_time + (
random_rand() % (expiration_time / 2));
260 LOG_DBG(
"Scheduling DAO lifetime timer %u ticks in the future\n",
261 (
unsigned)expiration_time);
262 ctimer_set(&instance->dao_lifetime_timer, expiration_time,
263 handle_dao_timer, instance);
268handle_dao_timer(
void *ptr)
272#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,
288 instance->default_lifetime);
290#if RPL_WITH_MULTICAST
292 if(instance->mop == RPL_MOP_STORING_MULTICAST) {
294 for(i = 0; i < UIP_DS6_MADDR_NB; i++) {
297 dao_output_target(instance->current_dag->preferred_parent,
298 &
uip_ds6_if.maddr_list[i].ipaddr, instance->default_lifetime);
304 while(mcast_route != NULL) {
306 if(uip_ds6_maddr_lookup(&mcast_route->
group) == NULL) {
307 dao_output_target(instance->current_dag->preferred_parent,
308 &mcast_route->
group, instance->default_lifetime);
315 LOG_INFO(
"No suitable DAO parent\n");
321 set_dao_lifetime_timer(instance);
328 clock_time_t expiration_time;
335 LOG_DBG(
"DAO timer already scheduled\n");
338 expiration_time = latency / 2 +
343 LOG_DBG(
"Scheduling DAO timer %u ticks in the future\n",
344 (
unsigned)expiration_time);
345 ctimer_set(&instance->dao_timer, expiration_time,
346 handle_dao_timer, instance);
348 set_dao_lifetime_timer(instance);
355 schedule_dao(instance, RPL_DAO_DELAY);
361 schedule_dao(instance, 0);
372handle_unicast_dio_timer(
void *ptr)
375 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(instance->unicast_dio_target);
377 if(target_ipaddr != NULL) {
378 dio_output(instance, target_ipaddr);
386 handle_unicast_dio_timer, instance);
393 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
410 rpl_parent_t *probing_target = NULL;
411 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
412 clock_time_t probing_target_age = 0;
415 if(dag == NULL || dag->instance == NULL) {
420 if(dag->instance->urgent_probing_target != NULL) {
421 return dag->instance->urgent_probing_target;
425 if(dag->preferred_parent != NULL
426 && !rpl_parent_is_fresh(dag->preferred_parent)) {
427 return dag->preferred_parent;
432 p = nbr_table_head(rpl_parents);
434 if(p->dag == dag && !rpl_parent_is_fresh(p)) {
436 rpl_rank_t p_rank = rpl_rank_via_parent(p);
437 if(probing_target == NULL || p_rank < probing_target_rank) {
439 probing_target_rank = p_rank;
442 p = nbr_table_next(rpl_parents, p);
448 if(probing_target == NULL) {
449 p = nbr_table_head(rpl_parents);
451 const struct link_stats *stats = rpl_get_parent_link_stats(p);
452 if(p->dag == dag && stats != NULL) {
453 if(probing_target == NULL
454 || clock_now - stats->last_tx_time > probing_target_age) {
456 probing_target_age = clock_now - stats->last_tx_time;
459 p = nbr_table_next(rpl_parents, p);
463 return probing_target;
470 int new_dag = instance->last_dag;
474 if(new_dag >= RPL_MAX_DAG_PER_INSTANCE) {
477 if(instance->dag_table[new_dag].used) {
478 dag = &instance->dag_table[new_dag];
480 }
while(new_dag != instance->last_dag && dag == NULL);
481 instance->last_dag = new_dag;
486handle_probing_timer(
void *ptr)
489 rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(get_next_dag(instance));
490 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(probing_target);
493 if(target_ipaddr != NULL) {
494 const struct link_stats *stats = rpl_get_parent_link_stats(probing_target);
495 const linkaddr_t *lladdr = rpl_get_parent_lladdr(probing_target);
496 LOG_INFO(
"probing %u %s last tx %u min ago\n",
497 lladdr != NULL ? lladdr->u8[7] : 0x0,
498 instance->urgent_probing_target != NULL ?
"(urgent)" :
"",
499 probing_target != NULL && stats != NULL ?
504 RPL_PROBING_SEND_FUNC(instance, target_ipaddr);
510 if(LOG_DBG_ENABLED) {
511 rpl_print_neighbor_list();
519 RPL_PROBING_DELAY_FUNC(instance->current_dag),
520 handle_probing_timer, instance);
527 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_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
static void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
static bool etimer_expired(struct etimer *et)
Check if an event timer has expired.
static 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.
uip_mcast6_route_t * uip_mcast6_route_list_head(void)
Retrieve a pointer to the start of the multicast routes list.
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.