Contiki 3.x
rpl-timers.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  */
31 
32 /**
33  * \file
34  * RPL timer management.
35  *
36  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
37  */
38 
39 /**
40  * \addtogroup uip6
41  * @{
42  */
43 
44 #include "contiki-conf.h"
45 #include "net/rpl/rpl-private.h"
47 #include "lib/random.h"
48 #include "sys/ctimer.h"
49 
50 #if UIP_CONF_IPV6
51 
52 #define DEBUG DEBUG_NONE
53 #include "net/ip/uip-debug.h"
54 
55 /*---------------------------------------------------------------------------*/
56 static struct ctimer periodic_timer;
57 
58 static void handle_periodic_timer(void *ptr);
59 static void new_dio_interval(rpl_instance_t *instance);
60 static void handle_dio_timer(void *ptr);
61 
62 static uint16_t next_dis;
63 
64 /* dio_send_ok is true if the node is ready to send DIOs */
65 static uint8_t dio_send_ok;
66 
67 /*---------------------------------------------------------------------------*/
68 static void
69 handle_periodic_timer(void *ptr)
70 {
71  rpl_purge_routes();
72  rpl_recalculate_ranks();
73 
74  /* handle DIS */
75 #if RPL_DIS_SEND
76  next_dis++;
77  if(rpl_get_any_dag() == NULL && next_dis >= RPL_DIS_INTERVAL) {
78  next_dis = 0;
79  dis_output(NULL);
80  }
81 #endif
82  ctimer_reset(&periodic_timer);
83 }
84 /*---------------------------------------------------------------------------*/
85 static void
86 new_dio_interval(rpl_instance_t *instance)
87 {
88  uint32_t time;
89  clock_time_t ticks;
90 
91  /* TODO: too small timer intervals for many cases */
92  time = 1UL << instance->dio_intcurrent;
93 
94  /* Convert from milliseconds to CLOCK_TICKS. */
95  ticks = (time * CLOCK_SECOND) / 1000;
96  instance->dio_next_delay = ticks;
97 
98  /* random number between I/2 and I */
99  ticks = ticks / 2 + (ticks / 2 * (uint32_t)random_rand()) / RANDOM_RAND_MAX;
100 
101  /*
102  * The intervals must be equally long among the nodes for Trickle to
103  * operate efficiently. Therefore we need to calculate the delay between
104  * the randomized time and the start time of the next interval.
105  */
106  instance->dio_next_delay -= ticks;
107  instance->dio_send = 1;
108 
109 #if RPL_CONF_STATS
110  /* keep some stats */
111  instance->dio_totint++;
112  instance->dio_totrecv += instance->dio_counter;
113  ANNOTATE("#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n",
114  DAG_RANK(instance->current_dag->rank, instance),
115  (10 * (instance->current_dag->rank % instance->min_hoprankinc)) / instance->min_hoprankinc,
116  instance->current_dag->version,
117  instance->dio_totint, instance->dio_totsend,
118  instance->dio_totrecv,instance->dio_intcurrent,
119  instance->current_dag->rank == ROOT_RANK(instance) ? "BLUE" : "ORANGE");
120 #endif /* RPL_CONF_STATS */
121 
122  /* reset the redundancy counter */
123  instance->dio_counter = 0;
124 
125  /* schedule the timer */
126  PRINTF("RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", ticks);
127  ctimer_set(&instance->dio_timer, ticks, &handle_dio_timer, instance);
128 }
129 /*---------------------------------------------------------------------------*/
130 static void
131 handle_dio_timer(void *ptr)
132 {
133  rpl_instance_t *instance;
134 
135  instance = (rpl_instance_t *)ptr;
136 
137  PRINTF("RPL: DIO Timer triggered\n");
138  if(!dio_send_ok) {
139  if(uip_ds6_get_link_local(ADDR_PREFERRED) != NULL) {
140  dio_send_ok = 1;
141  } else {
142  PRINTF("RPL: Postponing DIO transmission since link local address is not ok\n");
143  ctimer_set(&instance->dio_timer, CLOCK_SECOND, &handle_dio_timer, instance);
144  return;
145  }
146  }
147 
148  if(instance->dio_send) {
149  /* send DIO if counter is less than desired redundancy */
150  if(instance->dio_counter < instance->dio_redundancy) {
151 #if RPL_CONF_STATS
152  instance->dio_totsend++;
153 #endif /* RPL_CONF_STATS */
154  dio_output(instance, NULL);
155  } else {
156  PRINTF("RPL: Supressing DIO transmission (%d >= %d)\n",
157  instance->dio_counter, instance->dio_redundancy);
158  }
159  instance->dio_send = 0;
160  PRINTF("RPL: Scheduling DIO timer %lu ticks in future (sent)\n",
161  instance->dio_next_delay);
162  ctimer_set(&instance->dio_timer, instance->dio_next_delay, handle_dio_timer, instance);
163  } else {
164  /* check if we need to double interval */
165  if(instance->dio_intcurrent < instance->dio_intmin + instance->dio_intdoubl) {
166  instance->dio_intcurrent++;
167  PRINTF("RPL: DIO Timer interval doubled %d\n", instance->dio_intcurrent);
168  }
169  new_dio_interval(instance);
170  }
171 }
172 /*---------------------------------------------------------------------------*/
173 void
174 rpl_reset_periodic_timer(void)
175 {
176  next_dis = RPL_DIS_INTERVAL / 2 +
177  ((uint32_t)RPL_DIS_INTERVAL * (uint32_t)random_rand()) / RANDOM_RAND_MAX -
178  RPL_DIS_START_DELAY;
179  ctimer_set(&periodic_timer, CLOCK_SECOND, handle_periodic_timer, NULL);
180 }
181 /*---------------------------------------------------------------------------*/
182 /* Resets the DIO timer in the instance to its minimal interval. */
183 void
184 rpl_reset_dio_timer(rpl_instance_t *instance)
185 {
186 #if !RPL_LEAF_ONLY
187  /* Do not reset if we are already on the minimum interval,
188  unless forced to do so. */
189  if(instance->dio_intcurrent > instance->dio_intmin) {
190  instance->dio_counter = 0;
191  instance->dio_intcurrent = instance->dio_intmin;
192  new_dio_interval(instance);
193  }
194 #if RPL_CONF_STATS
195  rpl_stats.resets++;
196 #endif /* RPL_CONF_STATS */
197 #endif /* RPL_LEAF_ONLY */
198 }
199 /*---------------------------------------------------------------------------*/
200 static void handle_dao_timer(void *ptr);
201 static void
202 set_dao_lifetime_timer(rpl_instance_t *instance)
203 {
204  if(rpl_get_mode() == RPL_MODE_FEATHER) {
205  return;
206  }
207 
208  /* Set up another DAO within half the expiration time, if such a
209  time has been configured */
210  if(instance->lifetime_unit != 0xffff && instance->default_lifetime != 0xff) {
211  clock_time_t expiration_time;
212  expiration_time = (clock_time_t)instance->default_lifetime *
213  (clock_time_t)instance->lifetime_unit *
214  CLOCK_SECOND / 2;
215  PRINTF("RPL: Scheduling DAO lifetime timer %u ticks in the future\n",
216  (unsigned)expiration_time);
217  ctimer_set(&instance->dao_lifetime_timer, expiration_time,
218  handle_dao_timer, instance);
219  }
220 }
221 /*---------------------------------------------------------------------------*/
222 static void
223 handle_dao_timer(void *ptr)
224 {
225  rpl_instance_t *instance;
226 #if RPL_CONF_MULTICAST
227  uip_mcast6_route_t *mcast_route;
228  uint8_t i;
229 #endif
230 
231  instance = (rpl_instance_t *)ptr;
232 
233  if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) {
234  PRINTF("RPL: Postpone DAO transmission\n");
235  ctimer_set(&instance->dao_timer, CLOCK_SECOND, handle_dao_timer, instance);
236  return;
237  }
238 
239  /* Send the DAO to the DAO parent set -- the preferred parent in our case. */
240  if(instance->current_dag->preferred_parent != NULL) {
241  PRINTF("RPL: handle_dao_timer - sending DAO\n");
242  /* Set the route lifetime to the default value. */
243  dao_output(instance->current_dag->preferred_parent, instance->default_lifetime);
244 
245 #if RPL_CONF_MULTICAST
246  /* Send DAOs for multicast prefixes only if the instance is in MOP 3 */
247  if(instance->mop == RPL_MOP_STORING_MULTICAST) {
248  /* Send a DAO for own multicast addresses */
249  for(i = 0; i < UIP_DS6_MADDR_NB; i++) {
250  if(uip_ds6_if.maddr_list[i].isused
251  && uip_is_addr_mcast_global(&uip_ds6_if.maddr_list[i].ipaddr)) {
252  dao_output_target(instance->current_dag->preferred_parent,
253  &uip_ds6_if.maddr_list[i].ipaddr, RPL_MCAST_LIFETIME);
254  }
255  }
256 
257  /* Iterate over multicast routes and send DAOs */
258  mcast_route = uip_mcast6_route_list_head();
259  while(mcast_route != NULL) {
260  /* Don't send if it's also our own address, done that already */
261  if(uip_ds6_maddr_lookup(&mcast_route->group) == NULL) {
262  dao_output_target(instance->current_dag->preferred_parent,
263  &mcast_route->group, RPL_MCAST_LIFETIME);
264  }
265  mcast_route = list_item_next(mcast_route);
266  }
267  }
268 #endif
269  } else {
270  PRINTF("RPL: No suitable DAO parent\n");
271  }
272 
273  ctimer_stop(&instance->dao_timer);
274 
275  if(etimer_expired(&instance->dao_lifetime_timer.etimer)) {
276  set_dao_lifetime_timer(instance);
277  }
278 }
279 /*---------------------------------------------------------------------------*/
280 static void
281 schedule_dao(rpl_instance_t *instance, clock_time_t latency)
282 {
283  clock_time_t expiration_time;
284 
285  if(rpl_get_mode() == RPL_MODE_FEATHER) {
286  return;
287  }
288 
289  expiration_time = etimer_expiration_time(&instance->dao_timer.etimer);
290 
291  if(!etimer_expired(&instance->dao_timer.etimer)) {
292  PRINTF("RPL: DAO timer already scheduled\n");
293  } else {
294  if(latency != 0) {
295  expiration_time = latency / 2 +
296  (random_rand() % (latency));
297  } else {
298  expiration_time = 0;
299  }
300  PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n",
301  (unsigned)expiration_time);
302  ctimer_set(&instance->dao_timer, expiration_time,
303  handle_dao_timer, instance);
304 
305  set_dao_lifetime_timer(instance);
306  }
307 }
308 /*---------------------------------------------------------------------------*/
309 void
310 rpl_schedule_dao(rpl_instance_t *instance)
311 {
312  schedule_dao(instance, RPL_DAO_LATENCY);
313 }
314 /*---------------------------------------------------------------------------*/
315 void
316 rpl_schedule_dao_immediately(rpl_instance_t *instance)
317 {
318  schedule_dao(instance, 0);
319 }
320 /*---------------------------------------------------------------------------*/
321 void
322 rpl_cancel_dao(rpl_instance_t *instance)
323 {
324  ctimer_stop(&instance->dao_timer);
325  ctimer_stop(&instance->dao_lifetime_timer);
326 }
327 /*---------------------------------------------------------------------------*/
328 #endif /* UIP_CONF_IPV6 */
329 
330 /** @}*/
clock_time_t etimer_expiration_time(struct etimer *et)
Get the expiration time for the event timer.
Definition: etimer.c:211
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:205
This header file contains configuration directives for uIPv6 multicast support.
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
#define NULL
The null pointer.
An entry in the multicast routing table.
#define uip_is_addr_mcast_global(a)
is address a global multicast address (FFxE::/16), a is of type uip_ip6addr_t*
Definition: uip.h:2102
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
enum rpl_mode rpl_get_mode(void)
Get the RPL mode.
Definition: rpl.c:67
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
Definition: ctimer.c:118
Header file for the callback timer
A set of debugging macros.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:142
unsigned short random_rand(void)
Generate the next state and return the upper part of it.
Definition: random.c:47
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82