45 #include "net/routing/rpl-classic/rpl-private.h" 46 #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(clock_time_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);
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)
88 if(RPL_IS_STORING(dag->instance)) {
91 if(RPL_IS_NON_STORING(dag->instance)) {
95 rpl_recalculate_ranks();
100 if(dag == NULL && 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 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 PRINTF(
"RPL: 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);
158 handle_dio_timer(
void *ptr)
164 PRINTF(
"RPL: DIO Timer triggered\n");
166 if(uip_ds6_get_link_local(ADDR_PREFERRED) != NULL) {
169 PRINTF(
"RPL: Postponing DIO transmission since link local address is not ok\n");
175 if(instance->dio_send) {
177 if(instance->dio_redundancy == 0 || instance->dio_counter < instance->dio_redundancy) {
179 instance->dio_totsend++;
181 dio_output(instance, NULL);
183 PRINTF(
"RPL: Suppressing DIO transmission (%d >= %d)\n",
184 instance->dio_counter, instance->dio_redundancy);
186 instance->dio_send = 0;
187 PRINTF(
"RPL: Scheduling DIO timer %lu ticks in future (sent)\n",
188 instance->dio_next_delay);
189 ctimer_set(&instance->dio_timer, instance->dio_next_delay, handle_dio_timer, instance);
192 if(instance->dio_intcurrent < instance->dio_intmin + instance->dio_intdoubl) {
193 instance->dio_intcurrent++;
194 PRINTF(
"RPL: DIO Timer interval doubled %d\n", instance->dio_intcurrent);
196 new_dio_interval(instance);
200 rpl_print_neighbor_list();
205 rpl_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);
231 static void handle_dao_timer(
void *ptr);
241 if(instance->default_lifetime != RPL_INFINITE_LIFETIME) {
242 clock_time_t expiration_time;
243 expiration_time = (clock_time_t)instance->default_lifetime *
244 (clock_time_t)instance->lifetime_unit *
247 expiration_time = expiration_time + (
random_rand() % (expiration_time / 2));
248 PRINTF(
"RPL: Scheduling DAO lifetime timer %u ticks in the future\n",
249 (
unsigned)expiration_time);
250 ctimer_set(&instance->dao_lifetime_timer, expiration_time,
251 handle_dao_timer, instance);
256 handle_dao_timer(
void *ptr)
259 #if RPL_WITH_MULTICAST 266 if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) {
267 PRINTF(
"RPL: Postpone DAO transmission\n");
273 if(instance->current_dag->preferred_parent != NULL) {
274 PRINTF(
"RPL: handle_dao_timer - sending DAO\n");
276 dao_output(instance->current_dag->preferred_parent, instance->default_lifetime);
278 #if RPL_WITH_MULTICAST 280 if(instance->mop == RPL_MOP_STORING_MULTICAST) {
282 for(i = 0; i < UIP_DS6_MADDR_NB; i++) {
285 dao_output_target(instance->current_dag->preferred_parent,
286 &
uip_ds6_if.maddr_list[i].ipaddr, instance->default_lifetime);
292 while(mcast_route != NULL) {
294 if(uip_ds6_maddr_lookup(&mcast_route->
group) == NULL) {
295 dao_output_target(instance->current_dag->preferred_parent,
296 &mcast_route->
group, instance->default_lifetime);
303 PRINTF(
"RPL: No suitable DAO parent\n");
309 set_dao_lifetime_timer(instance);
316 clock_time_t expiration_time;
325 PRINTF(
"RPL: DAO timer already scheduled\n");
328 expiration_time = latency / 2 +
333 PRINTF(
"RPL: Scheduling DAO timer %u ticks in the future\n",
334 (
unsigned)expiration_time);
335 ctimer_set(&instance->dao_timer, expiration_time,
336 handle_dao_timer, instance);
338 set_dao_lifetime_timer(instance);
345 schedule_dao(instance, RPL_DAO_DELAY);
351 schedule_dao(instance, 0);
362 handle_unicast_dio_timer(
void *ptr)
365 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(instance->unicast_dio_target);
367 if(target_ipaddr != NULL) {
368 dio_output(instance, target_ipaddr);
376 handle_unicast_dio_timer, instance);
383 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
397 rpl_parent_t *probing_target = NULL;
398 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
399 clock_time_t probing_target_age = 0;
403 dag->instance == NULL) {
408 if(dag->instance->urgent_probing_target != NULL) {
409 return dag->instance->urgent_probing_target;
413 if(dag->preferred_parent != NULL && !rpl_parent_is_fresh(dag->preferred_parent)) {
414 return dag->preferred_parent;
419 p = nbr_table_head(rpl_parents);
421 if(p->dag == dag && !rpl_parent_is_fresh(p)) {
423 rpl_rank_t p_rank = rpl_rank_via_parent(p);
424 if(probing_target == NULL
425 || p_rank < probing_target_rank) {
427 probing_target_rank = p_rank;
430 p = nbr_table_next(rpl_parents, p);
435 if(probing_target == NULL) {
436 p = nbr_table_head(rpl_parents);
438 const struct link_stats *stats =rpl_get_parent_link_stats(p);
439 if(p->dag == dag && stats != NULL) {
440 if(probing_target == NULL
441 || clock_now - stats->last_tx_time > probing_target_age) {
443 probing_target_age = clock_now - stats->last_tx_time;
446 p = nbr_table_next(rpl_parents, p);
450 return probing_target;
457 int new_dag = instance->last_dag;
460 if(new_dag >= RPL_MAX_DAG_PER_INSTANCE) {
463 if(instance->dag_table[new_dag].used) {
464 dag = &instance->dag_table[new_dag];
466 }
while(new_dag != instance->last_dag && dag == NULL);
467 instance->last_dag = new_dag;
472 handle_probing_timer(
void *ptr)
475 rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(get_next_dag(instance));
476 uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(probing_target);
479 if(target_ipaddr != NULL) {
480 const struct link_stats *stats = rpl_get_parent_link_stats(probing_target);
482 PRINTF(
"RPL: probing %u %s last tx %u min ago\n",
483 rpl_get_parent_lladdr(probing_target)->u8[7],
484 instance->urgent_probing_target != NULL ?
"(urgent)" :
"",
485 probing_target != NULL ?
489 RPL_PROBING_SEND_FUNC(instance, target_ipaddr);
496 rpl_print_neighbor_list();
503 ctimer_set(&instance->probing_timer, RPL_PROBING_DELAY_FUNC(instance->current_dag),
504 handle_probing_timer, instance);
511 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.
A set of debugging macros for the IP stack
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.
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.