44 #include "net/routing/rpl-lite/rpl.h" 46 #include "net/link-stats.h" 47 #include "lib/random.h" 52 #define LOG_MODULE "RPL" 53 #define LOG_LEVEL LOG_LEVEL_RPL 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 64 #ifdef RPL_PROBING_DELAY_FUNC 65 clock_time_t RPL_PROBING_DELAY_FUNC(
void);
68 #define PERIODIC_DELAY_SECONDS 60 69 #define PERIODIC_DELAY ((PERIODIC_DELAY_SECONDS) * CLOCK_SECOND) 71 static void handle_dis_timer(
void *ptr);
72 static void handle_dio_timer(
void *ptr);
73 static void handle_unicast_dio_timer(
void *ptr);
74 static void send_new_dao(
void *ptr);
76 static void resend_dao(
void *ptr);
77 static void handle_dao_ack_timer(
void *ptr);
80 static void handle_probing_timer(
void *ptr);
82 static void handle_periodic_timer(
void *ptr);
83 static void handle_state_update(
void *ptr);
86 static struct ctimer dis_timer;
87 static struct ctimer periodic_timer;
96 clock_time_t expiration_time = RPL_DIS_INTERVAL / 2 + (
random_rand() % (RPL_DIS_INTERVAL));
97 ctimer_set(&dis_timer, expiration_time, handle_dis_timer, NULL);
102 handle_dis_timer(
void *ptr)
105 (!curr_instance.used ||
106 curr_instance.dag.preferred_parent == NULL ||
107 curr_instance.dag.rank == RPL_INFINITE_RANK)) {
117 new_dio_interval(
void)
122 time = 1UL << curr_instance.dag.dio_intcurrent;
126 curr_instance.dag.dio_next_delay = ticks;
129 ticks = ticks / 2 + (ticks / 2 * (uint32_t)
random_rand()) / RANDOM_RAND_MAX;
136 curr_instance.dag.dio_next_delay -= ticks;
137 curr_instance.dag.dio_send = 1;
139 curr_instance.dag.dio_counter = 0;
142 ctimer_set(&curr_instance.dag.dio_timer, ticks, &handle_dio_timer, NULL);
144 #ifdef RPL_CALLBACK_NEW_DIO_INTERVAL 145 RPL_CALLBACK_NEW_DIO_INTERVAL((
CLOCK_SECOND * 1UL << curr_instance.dag.dio_intcurrent) / 1000);
153 (curr_instance.dag.dio_intcurrent == 0 ||
154 curr_instance.dag.dio_intcurrent > curr_instance.dio_intmin)) {
159 LOG_INFO(
"reset DIO timer (%s)\n", str);
161 curr_instance.dag.dio_counter = 0;
162 curr_instance.dag.dio_intcurrent = curr_instance.dio_intmin;
169 handle_dio_timer(
void *ptr)
175 if(curr_instance.dag.dio_send) {
179 curr_instance.dag.dio_counter < curr_instance.dio_redundancy) {
180 #if RPL_TRICKLE_REFRESH_DAO_ROUTES 182 static int count = 0;
183 if((count++ % RPL_TRICKLE_REFRESH_DAO_ROUTES) == 0) {
185 RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
186 LOG_INFO(
"trigger DAO updates with a DTSN increment (%u)\n", curr_instance.dtsn_out);
190 curr_instance.dag.last_advertised_rank = curr_instance.dag.rank;
193 curr_instance.dag.dio_send = 0;
194 ctimer_set(&curr_instance.dag.dio_timer, curr_instance.dag.dio_next_delay, handle_dio_timer, NULL);
197 if(curr_instance.dag.dio_intcurrent < curr_instance.dio_intmin + curr_instance.dio_intdoubl) {
198 curr_instance.dag.dio_intcurrent++;
210 if(curr_instance.used) {
211 curr_instance.dag.unicast_dio_target = target;
212 ctimer_set(&curr_instance.dag.unicast_dio_timer, 0,
213 handle_unicast_dio_timer, NULL);
218 handle_unicast_dio_timer(
void *ptr)
221 if(target_ipaddr != NULL) {
231 schedule_dao_retransmission(
void)
233 clock_time_t expiration_time = RPL_DAO_RETRANSMISSION_TIMEOUT / 2 + (
random_rand() % (RPL_DAO_RETRANSMISSION_TIMEOUT));
234 ctimer_set(&curr_instance.dag.dao_timer, expiration_time, resend_dao, NULL);
239 schedule_dao_refresh(
void)
241 if(curr_instance.used && curr_instance.default_lifetime != RPL_INFINITE_LIFETIME) {
253 if(target_refresh > safety_margin) {
254 target_refresh -= safety_margin;
258 ctimer_set(&curr_instance.dag.dao_timer, target_refresh, send_new_dao, NULL);
265 if(curr_instance.used && curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
269 clock_time_t expiration_time = RPL_DAO_DELAY / 2 + (
random_rand() % (RPL_DAO_DELAY));
270 ctimer_set(&curr_instance.dag.dao_timer, expiration_time, send_new_dao, NULL);
275 send_new_dao(
void *ptr)
279 curr_instance.dag.dao_transmissions = 1;
281 schedule_dao_retransmission();
284 if(curr_instance.dag.state == DAG_JOINED) {
285 curr_instance.dag.state = DAG_REACHABLE;
289 schedule_dao_refresh();
293 RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_last_seqno);
305 if(curr_instance.used) {
307 curr_instance.dag.dao_ack_sequence = sequence;
308 ctimer_set(&curr_instance.dag.dao_ack_timer, 0, handle_dao_ack_timer, NULL);
313 handle_dao_ack_timer(
void *ptr)
316 curr_instance.dag.dao_ack_sequence, RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
324 schedule_dao_refresh();
328 resend_dao(
void *ptr)
331 curr_instance.dag.dao_transmissions++;
336 if(curr_instance.dag.dao_transmissions < RPL_DAO_MAX_RETRANSMISSIONS) {
337 schedule_dao_retransmission();
350 get_probing_delay(
void)
352 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
356 get_probing_target(
void)
367 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
368 clock_time_t probing_target_age = 0;
371 if(curr_instance.used == 0) {
376 if(curr_instance.dag.urgent_probing_target != NULL) {
377 return curr_instance.dag.urgent_probing_target;
381 if(curr_instance.dag.preferred_parent != NULL && !
rpl_neighbor_is_fresh(curr_instance.dag.preferred_parent)) {
382 return curr_instance.dag.preferred_parent;
390 nbr = nbr_table_head(rpl_neighbors);
395 if(probing_target == NULL
396 || nbr_rank < probing_target_rank) {
397 probing_target =
nbr;
398 probing_target_rank = nbr_rank;
401 nbr = nbr_table_next(rpl_neighbors, nbr);
405 nbr = nbr_table_head(rpl_neighbors);
411 if(probing_target == NULL
412 || clock_now - stats->last_tx_time > probing_target_age) {
413 probing_target =
nbr;
414 probing_target_age = clock_now - stats->last_tx_time;
418 nbr = nbr_table_next(rpl_neighbors, nbr);
422 return probing_target;
426 handle_probing_timer(
void *ptr)
428 rpl_nbr_t *probing_target = RPL_PROBING_SELECT_FUNC();
432 if(target_ipaddr != NULL) {
435 LOG_INFO(
"probing ");
436 LOG_INFO_6ADDR(target_ipaddr);
437 LOG_INFO_(
" %s last tx %u min ago\n",
438 curr_instance.dag.urgent_probing_target != NULL ?
"(urgent)" :
"",
443 RPL_PROBING_SEND_FUNC(target_ipaddr);
446 LOG_INFO(
"no neighbor needs probing\n");
456 if(curr_instance.used) {
457 ctimer_set(&curr_instance.dag.probing_timer, RPL_PROBING_DELAY_FUNC(),
458 handle_probing_timer, NULL);
465 if(curr_instance.used) {
475 handle_leaving_timer(
void *ptr)
477 if(curr_instance.used) {
485 if(curr_instance.used) {
495 if(curr_instance.used) {
497 ctimer_set(&curr_instance.dag.leave, RPL_DELAY_BEFORE_LEAVING, handle_leaving_timer, NULL);
507 ctimer_set(&periodic_timer, PERIODIC_DELAY, handle_periodic_timer, NULL);
512 handle_periodic_timer(
void *ptr)
514 if(curr_instance.used) {
519 if(!curr_instance.used ||
520 curr_instance.dag.preferred_parent == NULL ||
521 curr_instance.dag.rank == RPL_INFINITE_RANK) {
529 if(LOG_INFO_ENABLED) {
557 if(curr_instance.used) {
565 if(curr_instance.used) {
566 ctimer_set(&curr_instance.dag.state_update, 0, handle_state_update, NULL);
571 handle_state_update(
void *ptr)
int ctimer_expired(struct ctimer *c)
Check if a callback timer has expired.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
static volatile uint64_t count
Num.
uip_ipaddr_t * rpl_neighbor_get_ipaddr(rpl_nbr_t *nbr)
Returns a neighbor's (link-local) IPv6 address.
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
void rpl_timers_schedule_unicast_dio(rpl_nbr_t *target)
Schedule unicast DIO with no delay.
void rpl_timers_notify_dao_ack(void)
Let the rpl-timers module know that the last DAO was ACKed.
void rpl_schedule_probing_now(void)
Schedule probing within a few seconds.
int rpl_neighbor_is_fresh(rpl_nbr_t *nbr)
Tells wether we have fresh link information towards a given neighbor.
void rpl_timers_init(void)
Initialize rpl-timers module.
uint8_t rpl_get_leaf_only(void)
Get the value of the rpl_leaf_only flag.
#define RPL_LIFETIME(lifetime)
Compute lifetime, accounting for the lifetime unit.
void rpl_dag_root_print_links(const char *str)
Prints a summary of all routing links.
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
int rpl_dag_root_is_root(void)
Tells whether we are DAG root or not.
void rpl_timers_schedule_dao_ack(uip_ipaddr_t *target, uint16_t sequence)
Schedule a DAO-ACK with no delay.
void rpl_icmp6_dao_output(uint8_t lifetime)
Creates an ICMPv6 DAO packet and sends it to the root, advertising the current preferred parent...
void rpl_timers_schedule_state_update(void)
Schedule a state update ASAP.
void rpl_timers_dio_reset(const char *str)
Reset DIO Trickle timer.
#define CLOCK_SECOND
A second, measured in system clock time.
void rpl_timers_unschedule_leaving(void)
Cancel scheduled leaving if any.
Header file for the callback timer
void uip_sr_periodic(unsigned seconds)
A function called periodically.
void rpl_timers_stop_dag_timers(void)
Stop all timers related to the DAG.
void rpl_dag_leave(void)
Leaves the current DAG.
const struct link_stats * rpl_neighbor_get_link_stats(rpl_nbr_t *nbr)
Returns a neighbor's link statistics.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
All information related to a RPL neighbor.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
clock_time_t clock_time(void)
Get the current clock time.
int rpl_dag_ready_to_advertise(void)
Tells whether RPL is ready to advertise the DAG.
void rpl_timers_schedule_periodic_dis(void)
Schedule periodic DIS with a random delay based on RPL_DIS_INTERVAL, until we join a DAG...
void rpl_timers_schedule_dao(void)
Schedule a DAO with random delay based on RPL_DAO_DELAY.
void rpl_dag_periodic(unsigned seconds)
A function called periodically.
void rpl_neighbor_print_list(const char *str)
Prints a summary of all RPL neighbors and their properties.
void rpl_icmp6_dao_ack_output(uip_ipaddr_t *dest, uint8_t sequence, uint8_t status)
Creates an ICMPv6 DAO-ACK packet and sends it to the originator of the ACK.
void rpl_dag_update_state(void)
Updates RPL internal state: selects preferred parent, updates rank & metreic container, triggers control traffic accordingly and updates uIP6 internal state.
void rpl_timers_schedule_leaving(void)
Schedule leaving after RPL_DELAY_BEFORE_LEAVING.
void rpl_timers_unschedule_state_update(void)
Cancelled any scheduled state update.
rpl_rank_t rpl_neighbor_rank_via_nbr(rpl_nbr_t *nbr)
Returns our rank if selecting a given parent as preferred parent.
void rpl_local_repair(const char *str)
Triggers a RPL local repair.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
void rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr)
Creates an ICMPv6 DIO packet and sends it.
Header file for the logging system
void rpl_icmp6_dis_output(uip_ipaddr_t *addr)
Creates an ICMPv6 DIS packet and sends it.
void rpl_schedule_probing(void)
Schedule probing with delay RPL_PROBING_DELAY_FUNC()