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 handle_dao_timer(
void *ptr);
76 static void handle_dao_ack_timer(
void *ptr);
79 static void handle_probing_timer(
void *ptr);
81 static void handle_periodic_timer(
void *ptr);
82 static void handle_state_update(
void *ptr);
85 static struct ctimer dis_timer;
86 static struct ctimer periodic_timer;
95 clock_time_t expiration_time = RPL_DIS_INTERVAL / 2 + (
random_rand() % (RPL_DIS_INTERVAL));
96 ctimer_set(&dis_timer, expiration_time, handle_dis_timer, NULL);
101 handle_dis_timer(
void *ptr)
104 (!curr_instance.used ||
105 curr_instance.dag.preferred_parent == NULL ||
106 curr_instance.dag.rank == RPL_INFINITE_RANK)) {
116 new_dio_interval(
void)
121 time = 1UL << curr_instance.dag.dio_intcurrent;
125 curr_instance.dag.dio_next_delay = ticks;
128 ticks = ticks / 2 + (ticks / 2 * (uint32_t)
random_rand()) / RANDOM_RAND_MAX;
135 curr_instance.dag.dio_next_delay -= ticks;
136 curr_instance.dag.dio_send = 1;
138 curr_instance.dag.dio_counter = 0;
141 ctimer_set(&curr_instance.dag.dio_timer, ticks, &handle_dio_timer, NULL);
143 #ifdef RPL_CALLBACK_NEW_DIO_INTERVAL 144 RPL_CALLBACK_NEW_DIO_INTERVAL((
CLOCK_SECOND * 1UL << curr_instance.dag.dio_intcurrent) / 1000);
152 LOG_INFO(
"reset DIO timer (%s)\n", str);
154 curr_instance.dag.dio_counter = 0;
155 curr_instance.dag.dio_intcurrent = curr_instance.dio_intmin;
162 handle_dio_timer(
void *ptr)
168 if(curr_instance.dag.dio_send) {
172 curr_instance.dag.dio_counter < curr_instance.dio_redundancy) {
173 #if RPL_TRICKLE_REFRESH_DAO_ROUTES 175 static int count = 0;
176 if((count++ % RPL_TRICKLE_REFRESH_DAO_ROUTES) == 0) {
178 RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
179 LOG_INFO(
"trigger DAO updates with a DTSN increment (%u)\n", curr_instance.dtsn_out);
183 curr_instance.dag.last_advertised_rank = curr_instance.dag.rank;
186 curr_instance.dag.dio_send = 0;
187 ctimer_set(&curr_instance.dag.dio_timer, curr_instance.dag.dio_next_delay, handle_dio_timer, NULL);
190 if(curr_instance.dag.dio_intcurrent < curr_instance.dio_intmin + curr_instance.dio_intdoubl) {
191 curr_instance.dag.dio_intcurrent++;
203 if(curr_instance.used) {
204 curr_instance.dag.unicast_dio_target = target;
205 ctimer_set(&curr_instance.dag.unicast_dio_timer, 0,
206 handle_unicast_dio_timer, NULL);
211 handle_unicast_dio_timer(
void *ptr)
214 if(target_ipaddr != NULL) {
224 schedule_dao_retransmission(
void)
226 clock_time_t expiration_time = RPL_DAO_RETRANSMISSION_TIMEOUT / 2 + (
random_rand() % (RPL_DAO_RETRANSMISSION_TIMEOUT));
227 ctimer_set(&curr_instance.dag.dao_timer, expiration_time, handle_dao_timer, NULL);
232 schedule_dao_refresh(
void)
234 if(curr_instance.used && curr_instance.default_lifetime != RPL_INFINITE_LIFETIME) {
246 if(target_refresh > safety_margin) {
247 target_refresh -= safety_margin;
251 RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
252 ctimer_set(&curr_instance.dag.dao_timer, target_refresh, handle_dao_timer, 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));
265 RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
266 ctimer_set(&curr_instance.dag.dao_timer, expiration_time, handle_dao_timer, NULL);
271 handle_dao_timer(
void *ptr)
275 curr_instance.dag.dao_last_seqno)) {
277 curr_instance.dag.dao_transmissions = 0;
280 if(curr_instance.dag.dao_last_acked_seqno == curr_instance.dag.dao_last_seqno) {
282 schedule_dao_refresh();
286 if(curr_instance.dag.dao_transmissions >= RPL_DAO_MAX_RETRANSMISSIONS) {
293 curr_instance.dag.dao_transmissions++;
295 schedule_dao_retransmission();
298 if(curr_instance.dag.state == DAG_JOINED) {
299 curr_instance.dag.state = DAG_REACHABLE;
304 curr_instance.dag.dao_last_seqno = curr_instance.dag.dao_curr_seqno;
308 #if !RPL_WITH_DAO_ACK 313 schedule_dao_refresh();
324 if(curr_instance.used) {
326 curr_instance.dag.dao_ack_sequence = sequence;
327 ctimer_set(&curr_instance.dag.dao_ack_timer, 0, handle_dao_ack_timer, NULL);
332 handle_dao_ack_timer(
void *ptr)
335 curr_instance.dag.dao_ack_sequence, RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
343 get_probing_delay(
void)
345 return ((RPL_PROBING_INTERVAL) / 2) +
random_rand() % (RPL_PROBING_INTERVAL);
349 get_probing_target(
void)
360 rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
361 clock_time_t probing_target_age = 0;
364 if(curr_instance.used == 0) {
369 if(curr_instance.dag.urgent_probing_target != NULL) {
370 return curr_instance.dag.urgent_probing_target;
374 if(curr_instance.dag.preferred_parent != NULL && !
rpl_neighbor_is_fresh(curr_instance.dag.preferred_parent)) {
375 return curr_instance.dag.preferred_parent;
383 nbr = nbr_table_head(rpl_neighbors);
388 if(probing_target == NULL
389 || nbr_rank < probing_target_rank) {
390 probing_target =
nbr;
391 probing_target_rank = nbr_rank;
394 nbr = nbr_table_next(rpl_neighbors, nbr);
398 nbr = nbr_table_head(rpl_neighbors);
404 if(probing_target == NULL
405 || clock_now - stats->last_tx_time > probing_target_age) {
406 probing_target =
nbr;
407 probing_target_age = clock_now - stats->last_tx_time;
411 nbr = nbr_table_next(rpl_neighbors, nbr);
415 return probing_target;
419 handle_probing_timer(
void *ptr)
421 rpl_nbr_t *probing_target = RPL_PROBING_SELECT_FUNC();
425 if(target_ipaddr != NULL) {
428 LOG_INFO(
"probing ");
429 LOG_INFO_6ADDR(target_ipaddr);
430 LOG_INFO_(
" %s last tx %u min ago\n",
431 curr_instance.dag.urgent_probing_target != NULL ?
"(urgent)" :
"",
436 RPL_PROBING_SEND_FUNC(target_ipaddr);
439 LOG_INFO(
"no neighbor needs probing\n");
449 if(curr_instance.used) {
450 ctimer_set(&curr_instance.dag.probing_timer, RPL_PROBING_DELAY_FUNC(),
451 handle_probing_timer, NULL);
458 if(curr_instance.used) {
468 handle_leaving_timer(
void *ptr)
470 if(curr_instance.used) {
478 if(curr_instance.used) {
488 if(curr_instance.used) {
490 ctimer_set(&curr_instance.dag.leave, RPL_DELAY_BEFORE_LEAVING, handle_leaving_timer, NULL);
500 ctimer_set(&periodic_timer, PERIODIC_DELAY, handle_periodic_timer, NULL);
505 handle_periodic_timer(
void *ptr)
507 if(curr_instance.used) {
512 if(!curr_instance.used ||
513 curr_instance.dag.preferred_parent == NULL ||
514 curr_instance.dag.rank == RPL_INFINITE_RANK) {
522 if(LOG_INFO_ENABLED) {
550 if(curr_instance.used) {
558 if(curr_instance.used) {
559 ctimer_set(&curr_instance.dag.state_update, 0, handle_state_update, NULL);
564 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.
int rpl_lollipop_greater_than(int a, int b)
Greater-than function for a lollipop counter.
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()