44 #include "contiki-conf.h"
45 #include "net/rpl/rpl-private.h"
47 #include "net/link-stats.h"
49 #include "lib/random.h"
52 #define DEBUG DEBUG_NONE
56 #ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
57 void RPL_CALLBACK_NEW_DIO_INTERVAL(uint8_t dio_interval);
60 #ifdef RPL_PROBING_SELECT_FUNC
61 rpl_parent_t *RPL_PROBING_SELECT_FUNC(rpl_dag_t *dag);
64 #ifdef RPL_PROBING_DELAY_FUNC
65 clock_time_t RPL_PROBING_DELAY_FUNC(rpl_dag_t *dag);
69 static struct ctimer periodic_timer;
71 static void handle_periodic_timer(
void *ptr);
72 static void new_dio_interval(rpl_instance_t *instance);
73 static void handle_dio_timer(
void *ptr);
75 static uint16_t next_dis;
78 static uint8_t dio_send_ok;
82 handle_periodic_timer(
void *ptr)
84 rpl_dag_t *dag = rpl_get_any_dag();
87 if(dag !=
NULL && RPL_IS_STORING(dag->instance)) {
90 if(dag !=
NULL && RPL_IS_NON_STORING(dag->instance)) {
93 rpl_recalculate_ranks();
98 if(dag ==
NULL && next_dis >= RPL_DIS_INTERVAL) {
107 new_dio_interval(rpl_instance_t *instance)
113 time = 1UL << instance->dio_intcurrent;
117 instance->dio_next_delay = ticks;
120 ticks = ticks / 2 + (ticks / 2 * (uint32_t)
random_rand()) / RANDOM_RAND_MAX;
127 instance->dio_next_delay -= ticks;
128 instance->dio_send = 1;
132 instance->dio_totint++;
133 instance->dio_totrecv += instance->dio_counter;
134 ANNOTATE(
"#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n",
135 DAG_RANK(instance->current_dag->rank, instance),
136 (10 * (instance->current_dag->rank % instance->min_hoprankinc)) / instance->min_hoprankinc,
137 instance->current_dag->version,
138 instance->dio_totint, instance->dio_totsend,
139 instance->dio_totrecv,instance->dio_intcurrent,
140 instance->current_dag->rank == ROOT_RANK(instance) ?
"BLUE" :
"ORANGE");
144 instance->dio_counter = 0;
147 PRINTF(
"RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", ticks);
148 ctimer_set(&instance->dio_timer, ticks, &handle_dio_timer, instance);
150 #ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
151 RPL_CALLBACK_NEW_DIO_INTERVAL(instance->dio_intcurrent);
156 handle_dio_timer(
void *ptr)
158 rpl_instance_t *instance;
160 instance = (rpl_instance_t *)ptr;
162 PRINTF(
"RPL: DIO Timer triggered\n");
164 if(uip_ds6_get_link_local(ADDR_PREFERRED) !=
NULL) {
167 PRINTF(
"RPL: 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 PRINTF(
"RPL: Suppressing DIO transmission (%d >= %d)\n",
182 instance->dio_counter, instance->dio_redundancy);
184 instance->dio_send = 0;
185 PRINTF(
"RPL: Scheduling DIO timer %lu ticks in future (sent)\n",
186 instance->dio_next_delay);
187 ctimer_set(&instance->dio_timer, instance->dio_next_delay, handle_dio_timer, instance);
190 if(instance->dio_intcurrent < instance->dio_intmin + instance->dio_intdoubl) {
191 instance->dio_intcurrent++;
192 PRINTF(
"RPL: DIO Timer interval doubled %d\n", instance->dio_intcurrent);
194 new_dio_interval(instance);
198 rpl_print_neighbor_list();
203 rpl_reset_periodic_timer(
void)
205 next_dis = RPL_DIS_INTERVAL / 2 +
206 ((uint32_t)RPL_DIS_INTERVAL * (uint32_t)
random_rand()) / RANDOM_RAND_MAX -
213 rpl_reset_dio_timer(rpl_instance_t *instance)
218 if(instance->dio_intcurrent > instance->dio_intmin) {
219 instance->dio_counter = 0;
220 instance->dio_intcurrent = instance->dio_intmin;
221 new_dio_interval(instance);
229 static void handle_dao_timer(
void *ptr);
231 set_dao_lifetime_timer(rpl_instance_t *instance)
239 if(instance->lifetime_unit != 0xffff && instance->default_lifetime != 0xff) {
240 clock_time_t expiration_time;
241 expiration_time = (clock_time_t)instance->default_lifetime *
242 (clock_time_t)instance->lifetime_unit *
245 expiration_time = expiration_time + (
random_rand() % (expiration_time / 2));
246 PRINTF(
"RPL: Scheduling DAO lifetime timer %u ticks in the future\n",
247 (
unsigned)expiration_time);
248 ctimer_set(&instance->dao_lifetime_timer, expiration_time,
249 handle_dao_timer, instance);
254 handle_dao_timer(
void *ptr)
256 rpl_instance_t *instance;
257 #if RPL_CONF_MULTICAST
262 instance = (rpl_instance_t *)ptr;
264 if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) ==
NULL) {
265 PRINTF(
"RPL: Postpone DAO transmission\n");
271 if(instance->current_dag->preferred_parent !=
NULL) {
272 PRINTF(
"RPL: handle_dao_timer - sending DAO\n");
274 dao_output(instance->current_dag->preferred_parent, instance->default_lifetime);
276 #if RPL_CONF_MULTICAST
278 if(instance->mop == RPL_MOP_STORING_MULTICAST) {
280 for(i = 0; i < UIP_DS6_MADDR_NB; i++) {
283 dao_output_target(instance->current_dag->preferred_parent,
284 &
uip_ds6_if.maddr_list[i].ipaddr, RPL_MCAST_LIFETIME);
290 while(mcast_route !=
NULL) {
292 if(uip_ds6_maddr_lookup(&mcast_route->
group) ==
NULL) {
293 dao_output_target(instance->current_dag->preferred_parent,
294 &mcast_route->
group, RPL_MCAST_LIFETIME);
301 PRINTF(
"RPL: No suitable DAO parent\n");
307 set_dao_lifetime_timer(instance);
312 schedule_dao(rpl_instance_t *instance, clock_time_t latency)
314 clock_time_t expiration_time;
323 PRINTF(
"RPL: DAO timer already scheduled\n");
326 expiration_time = latency / 2 +
331 PRINTF(
"RPL: Scheduling DAO timer %u ticks in the future\n",
332 (
unsigned)expiration_time);
333 ctimer_set(&instance->dao_timer, expiration_time,
334 handle_dao_timer, instance);
336 set_dao_lifetime_timer(instance);
341 rpl_schedule_dao(rpl_instance_t *instance)
343 schedule_dao(instance, RPL_DAO_DELAY);
347 rpl_schedule_dao_immediately(rpl_instance_t *instance)
349 schedule_dao(instance, 0);
353 rpl_cancel_dao(rpl_instance_t *instance)
360 handle_unicast_dio_timer(
void *ptr)
362 rpl_instance_t *instance = (rpl_instance_t *)ptr;
363 uip_ipaddr_t *target_ipaddr = rpl_get_parent_ipaddr(instance->unicast_dio_target);
365 if(target_ipaddr !=
NULL) {
366 dio_output(instance, target_ipaddr);
371 rpl_schedule_unicast_dio_immediately(rpl_instance_t *instance)
374 handle_unicast_dio_timer, instance);
379 get_probing_delay(rpl_dag_t *dag)
381 if(dag !=
NULL && dag->instance !=
NULL
382 && dag->instance->urgent_probing_target !=
NULL) {
387 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
392 get_probing_target(rpl_dag_t *dag)
402 rpl_parent_t *probing_target =
NULL;
403 rpl_rank_t probing_target_rank = INFINITE_RANK;
404 clock_time_t probing_target_age = 0;
408 dag->instance ==
NULL) {
413 if(dag->instance->urgent_probing_target !=
NULL) {
414 return dag->instance->urgent_probing_target;
418 if(dag->preferred_parent !=
NULL && !rpl_parent_is_fresh(dag->preferred_parent)) {
419 return dag->preferred_parent;
424 p = nbr_table_head(rpl_parents);
426 if(p->dag == dag && !rpl_parent_is_fresh(p)) {
428 rpl_rank_t p_rank = rpl_rank_via_parent(p);
429 if(probing_target ==
NULL
430 || p_rank < probing_target_rank) {
432 probing_target_rank = p_rank;
435 p = nbr_table_next(rpl_parents, p);
440 if(probing_target ==
NULL) {
441 p = nbr_table_head(rpl_parents);
443 const struct link_stats *stats =rpl_get_parent_link_stats(p);
444 if(p->dag == dag && stats !=
NULL) {
445 if(probing_target ==
NULL
446 || clock_now - stats->last_tx_time > probing_target_age) {
448 probing_target_age = clock_now - stats->last_tx_time;
451 p = nbr_table_next(rpl_parents, p);
455 return probing_target;
459 handle_probing_timer(
void *ptr)
461 rpl_instance_t *instance = (rpl_instance_t *)ptr;
462 rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(instance->current_dag);
463 uip_ipaddr_t *target_ipaddr = rpl_get_parent_ipaddr(probing_target);
466 if(target_ipaddr !=
NULL) {
467 const struct link_stats *stats = rpl_get_parent_link_stats(probing_target);
469 PRINTF(
"RPL: probing %u %s last tx %u min ago\n",
470 rpl_get_parent_lladdr(probing_target)->u8[7],
471 instance->urgent_probing_target !=
NULL ?
"(urgent)" :
"",
472 probing_target !=
NULL ?
476 RPL_PROBING_SEND_FUNC(instance, target_ipaddr);
477 instance->urgent_probing_target =
NULL;
481 rpl_schedule_probing(instance);
484 rpl_print_neighbor_list();
489 rpl_schedule_probing(rpl_instance_t *instance)
491 ctimer_set(&instance->probing_timer, RPL_PROBING_DELAY_FUNC(instance->current_dag),
492 handle_probing_timer, instance);
#define uip_is_addr_mcast_global(a)
is address a global multicast address (FFxE::/16), a is of type uip_ip6addr_t*
CCIF clock_time_t clock_time(void)
Get the current clock time.
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.
This header file contains configuration directives for uIPv6 multicast support.
Header file for the callback timer
#define NULL
The null pointer.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
#define CLOCK_SECOND
A second, measured in system clock time.
uip_ipaddr_t group
The multicast group.
An entry in the multicast routing table.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
A set of debugging macros for the IP stack
enum rpl_mode rpl_get_mode(void)
Get the RPL mode.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
uip_ds6_netif_t uip_ds6_if
The single interface.
RPL non-storing mode specific functions.
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
clock_time_t etimer_expiration_time(struct etimer *et)
Get the expiration time for the event timer.