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 LOG_INFO(
"reset DIO timer (%s)\n", str);
155 curr_instance.dag.dio_counter = 0;
156 curr_instance.dag.dio_intcurrent = curr_instance.dio_intmin;
163 handle_dio_timer(
void *ptr)
169 if(curr_instance.dag.dio_send) {
173 curr_instance.dag.dio_counter < curr_instance.dio_redundancy) {
174 #if RPL_TRICKLE_REFRESH_DAO_ROUTES 176 static int count = 0;
177 if((count++ % RPL_TRICKLE_REFRESH_DAO_ROUTES) == 0) {
179 RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
180 LOG_INFO(
"trigger DAO updates with a DTSN increment (%u)\n", curr_instance.dtsn_out);
184 curr_instance.dag.last_advertised_rank = curr_instance.dag.rank;
187 curr_instance.dag.dio_send = 0;
188 ctimer_set(&curr_instance.dag.dio_timer, curr_instance.dag.dio_next_delay, handle_dio_timer, NULL);
191 if(curr_instance.dag.dio_intcurrent < curr_instance.dio_intmin + curr_instance.dio_intdoubl) {
192 curr_instance.dag.dio_intcurrent++;
204 if(curr_instance.used) {
205 curr_instance.dag.unicast_dio_target = target;
206 ctimer_set(&curr_instance.dag.unicast_dio_timer, 0,
207 handle_unicast_dio_timer, NULL);
212 handle_unicast_dio_timer(
void *ptr)
215 if(target_ipaddr != NULL) {
225 schedule_dao_retransmission(
void)
227 clock_time_t expiration_time = RPL_DAO_RETRANSMISSION_TIMEOUT / 2 + (
random_rand() % (RPL_DAO_RETRANSMISSION_TIMEOUT));
228 ctimer_set(&curr_instance.dag.dao_timer, expiration_time, resend_dao, NULL);
233 schedule_dao_refresh(
void)
235 if(curr_instance.used && curr_instance.default_lifetime != RPL_INFINITE_LIFETIME) {
247 if(target_refresh > safety_margin) {
248 target_refresh -= safety_margin;
252 ctimer_set(&curr_instance.dag.dao_timer, target_refresh, send_new_dao, NULL);
259 if(curr_instance.used && curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
263 clock_time_t expiration_time = RPL_DAO_DELAY / 2 + (
random_rand() % (RPL_DAO_DELAY));
264 ctimer_set(&curr_instance.dag.dao_timer, expiration_time, send_new_dao, NULL);
269 send_new_dao(
void *ptr)
273 curr_instance.dag.dao_transmissions = 1;
275 schedule_dao_retransmission();
278 if(curr_instance.dag.state == DAG_JOINED) {
279 curr_instance.dag.state = DAG_REACHABLE;
283 schedule_dao_refresh();
287 RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_last_seqno);
299 if(curr_instance.used) {
301 curr_instance.dag.dao_ack_sequence = sequence;
302 ctimer_set(&curr_instance.dag.dao_ack_timer, 0, handle_dao_ack_timer, NULL);
307 handle_dao_ack_timer(
void *ptr)
310 curr_instance.dag.dao_ack_sequence, RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
318 schedule_dao_refresh();
322 resend_dao(
void *ptr)
325 curr_instance.dag.dao_transmissions++;
330 if(curr_instance.dag.dao_transmissions < RPL_DAO_MAX_RETRANSMISSIONS) {
331 schedule_dao_retransmission();
344 get_probing_delay(
void)
346 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
350 get_probing_target(
void)
361 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
362 clock_time_t probing_target_age = 0;
365 if(curr_instance.used == 0) {
370 if(curr_instance.dag.urgent_probing_target != NULL) {
371 return curr_instance.dag.urgent_probing_target;
375 if(curr_instance.dag.preferred_parent != NULL && !
rpl_neighbor_is_fresh(curr_instance.dag.preferred_parent)) {
376 return curr_instance.dag.preferred_parent;
384 nbr = nbr_table_head(rpl_neighbors);
389 if(probing_target == NULL
390 || nbr_rank < probing_target_rank) {
391 probing_target =
nbr;
392 probing_target_rank = nbr_rank;
395 nbr = nbr_table_next(rpl_neighbors, nbr);
399 nbr = nbr_table_head(rpl_neighbors);
405 if(probing_target == NULL
406 || clock_now - stats->last_tx_time > probing_target_age) {
407 probing_target =
nbr;
408 probing_target_age = clock_now - stats->last_tx_time;
412 nbr = nbr_table_next(rpl_neighbors, nbr);
416 return probing_target;
420 handle_probing_timer(
void *ptr)
422 rpl_nbr_t *probing_target = RPL_PROBING_SELECT_FUNC();
426 if(target_ipaddr != NULL) {
429 LOG_INFO(
"probing ");
430 LOG_INFO_6ADDR(target_ipaddr);
431 LOG_INFO_(
" %s last tx %u min ago\n",
432 curr_instance.dag.urgent_probing_target != NULL ?
"(urgent)" :
"",
437 RPL_PROBING_SEND_FUNC(target_ipaddr);
440 LOG_INFO(
"no neighbor needs probing\n");
450 if(curr_instance.used) {
451 ctimer_set(&curr_instance.dag.probing_timer, RPL_PROBING_DELAY_FUNC(),
452 handle_probing_timer, NULL);
459 if(curr_instance.used) {
469 handle_leaving_timer(
void *ptr)
471 if(curr_instance.used) {
479 if(curr_instance.used) {
489 if(curr_instance.used) {
491 ctimer_set(&curr_instance.dag.leave, RPL_DELAY_BEFORE_LEAVING, handle_leaving_timer, NULL);
501 ctimer_set(&periodic_timer, PERIODIC_DELAY, handle_periodic_timer, NULL);
506 handle_periodic_timer(
void *ptr)
508 if(curr_instance.used) {
513 if(!curr_instance.used ||
514 curr_instance.dag.preferred_parent == NULL ||
515 curr_instance.dag.rank == RPL_INFINITE_RANK) {
523 if(LOG_INFO_ENABLED) {
551 if(curr_instance.used) {
559 if(curr_instance.used) {
560 ctimer_set(&curr_instance.dag.state_update, 0, handle_state_update, NULL);
565 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.
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()