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 58 void RPL_CALLBACK_NEW_DIO_INTERVAL(clock_time_t dio_interval);
61 #ifdef RPL_PROBING_SELECT_FUNC 62 rpl_parent_t *RPL_PROBING_SELECT_FUNC(
rpl_dag_t *dag);
65 #ifdef RPL_PROBING_DELAY_FUNC 66 clock_time_t RPL_PROBING_DELAY_FUNC(
rpl_dag_t *dag);
70 static struct ctimer periodic_timer;
72 static void handle_periodic_timer(
void *ptr);
74 static void handle_dio_timer(
void *ptr);
76 static uint16_t next_dis;
79 static uint8_t dio_send_ok;
83 handle_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 && 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);
159 handle_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();
206 rpl_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);
232 static void handle_dao_timer(
void *ptr);
242 if(instance->default_lifetime != RPL_INFINITE_LIFETIME) {
243 clock_time_t expiration_time;
244 expiration_time = (clock_time_t)instance->default_lifetime *
245 (clock_time_t)instance->lifetime_unit *
248 expiration_time = expiration_time + (
random_rand() % (expiration_time / 2));
249 LOG_DBG(
"Scheduling DAO lifetime timer %u ticks in the future\n",
250 (
unsigned)expiration_time);
251 ctimer_set(&instance->dao_lifetime_timer, expiration_time,
252 handle_dao_timer, instance);
257 handle_dao_timer(
void *ptr)
260 #if RPL_WITH_MULTICAST 267 if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) {
268 LOG_INFO(
"Postpone DAO transmission\n");
274 if(instance->current_dag->preferred_parent != NULL) {
275 LOG_INFO(
"handle_dao_timer - sending DAO\n");
277 dao_output(instance->current_dag->preferred_parent, instance->default_lifetime);
279 #if RPL_WITH_MULTICAST 281 if(instance->mop == RPL_MOP_STORING_MULTICAST) {
283 for(i = 0; i < UIP_DS6_MADDR_NB; i++) {
286 dao_output_target(instance->current_dag->preferred_parent,
287 &
uip_ds6_if.maddr_list[i].ipaddr, instance->default_lifetime);
293 while(mcast_route != NULL) {
295 if(uip_ds6_maddr_lookup(&mcast_route->
group) == NULL) {
296 dao_output_target(instance->current_dag->preferred_parent,
297 &mcast_route->
group, instance->default_lifetime);
304 LOG_INFO(
"No suitable DAO parent\n");
310 set_dao_lifetime_timer(instance);
317 clock_time_t expiration_time;
326 LOG_DBG(
"DAO timer already scheduled\n");
329 expiration_time = latency / 2 +
334 LOG_DBG(
"Scheduling DAO timer %u ticks in the future\n",
335 (
unsigned)expiration_time);
336 ctimer_set(&instance->dao_timer, expiration_time,
337 handle_dao_timer, instance);
339 set_dao_lifetime_timer(instance);
346 schedule_dao(instance, RPL_DAO_DELAY);
352 schedule_dao(instance, 0);
363 handle_unicast_dio_timer(
void *ptr)
366 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(instance->unicast_dio_target);
368 if(target_ipaddr != NULL) {
369 dio_output(instance, target_ipaddr);
377 handle_unicast_dio_timer, instance);
384 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
398 rpl_parent_t *probing_target = NULL;
399 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
400 clock_time_t probing_target_age = 0;
404 dag->instance == NULL) {
409 if(dag->instance->urgent_probing_target != NULL) {
410 return dag->instance->urgent_probing_target;
414 if(dag->preferred_parent != NULL && !rpl_parent_is_fresh(dag->preferred_parent)) {
415 return dag->preferred_parent;
420 p = nbr_table_head(rpl_parents);
422 if(p->dag == dag && !rpl_parent_is_fresh(p)) {
424 rpl_rank_t p_rank = rpl_rank_via_parent(p);
425 if(probing_target == NULL
426 || p_rank < probing_target_rank) {
428 probing_target_rank = p_rank;
431 p = nbr_table_next(rpl_parents, p);
436 if(probing_target == NULL) {
437 p = nbr_table_head(rpl_parents);
439 const struct link_stats *stats =rpl_get_parent_link_stats(p);
440 if(p->dag == dag && stats != NULL) {
441 if(probing_target == NULL
442 || clock_now - stats->last_tx_time > probing_target_age) {
444 probing_target_age = clock_now - stats->last_tx_time;
447 p = nbr_table_next(rpl_parents, p);
451 return probing_target;
458 int new_dag = instance->last_dag;
461 if(new_dag >= RPL_MAX_DAG_PER_INSTANCE) {
464 if(instance->dag_table[new_dag].used) {
465 dag = &instance->dag_table[new_dag];
467 }
while(new_dag != instance->last_dag && dag == NULL);
468 instance->last_dag = new_dag;
473 handle_probing_timer(
void *ptr)
476 rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(get_next_dag(instance));
477 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(probing_target);
480 if(target_ipaddr != NULL) {
481 const struct link_stats *stats = rpl_get_parent_link_stats(probing_target);
482 const linkaddr_t *lladdr = rpl_get_parent_lladdr(probing_target);
483 LOG_INFO(
"probing %u %s last tx %u min ago\n",
484 lladdr != NULL ? lladdr->u8[7] : 0x0,
485 instance->urgent_probing_target != NULL ?
"(urgent)" :
"",
486 probing_target != NULL && stats != NULL ?
491 RPL_PROBING_SEND_FUNC(instance, target_ipaddr);
497 if(LOG_DBG_ENABLED) {
498 rpl_print_neighbor_list();
505 ctimer_set(&instance->probing_timer, RPL_PROBING_DELAY_FUNC(instance->current_dag),
506 handle_probing_timer, instance);
513 handle_probing_timer, instance);
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
#define ROOT_RANK
Rank of a root node.
#define uip_is_addr_mcast_global(a)
is address a global multicast address (FFxE::/16), a is of type uip_ip6addr_t*
void rpl_schedule_probing_now(void)
Schedule probing within a few seconds.
enum rpl_mode rpl_get_mode(void)
Get the RPL mode.
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
This header file contains configuration directives for uIPv6 multicast support.
#define CLOCK_SECOND
A second, measured in system clock time.
#define DAG_RANK(fixpt_rank)
Return DAG RANK as per RFC 6550 (rank divided by min_hoprankinc)
Header file for the callback timer
void uip_sr_periodic(unsigned seconds)
A function called periodically.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
rpl_dag_t * rpl_get_any_dag(void)
Returns pointer to any DAG (for compatibility with legagy RPL code)
clock_time_t clock_time(void)
Get the current clock time.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
An entry in the multicast routing table.
uip_ds6_netif_t uip_ds6_if
The single interface.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Header file for the logging system
uip_ipaddr_t group
The multicast group.
void * list_item_next(void *item)
Get the next item following this item.
uip_mcast6_route_t * uip_mcast6_route_list_head(void)
Retrieve a pointer to the start of the multicast routes list.
void rpl_schedule_probing(void)
Schedule probing with delay RPL_PROBING_DELAY_FUNC()
clock_time_t etimer_expiration_time(struct etimer *et)
Get the expiration time for the event timer.