Contiki-NG
rpl-dag.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 /**
34  * \addtogroup rpl-lite
35  * @{
36  *
37  * \file
38  * Logic for Directed Acyclic Graphs in RPL.
39  *
40  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
41  * Simon Duquennoy <simon.duquennoy@inria.fr>
42  * Contributors: George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
43  */
44 
45 #include "net/routing/rpl-lite/rpl.h"
46 #include "net/ipv6/uip-sr.h"
47 #include "net/nbr-table.h"
48 #include "net/link-stats.h"
49 
50 /* Log configuration */
51 #include "sys/log.h"
52 #define LOG_MODULE "RPL"
53 #define LOG_LEVEL LOG_LEVEL_RPL
54 
55 /*---------------------------------------------------------------------------*/
56 extern rpl_of_t rpl_of0, rpl_mrhof;
57 static rpl_of_t * const objective_functions[] = RPL_SUPPORTED_OFS;
58 static int init_dag_from_dio(rpl_dio_t *dio);
59 
60 /*---------------------------------------------------------------------------*/
61 /* Allocate instance table. */
62 rpl_instance_t curr_instance;
63 
64 /*---------------------------------------------------------------------------*/
65 const char *
67 {
68  switch(state) {
69  case DAG_INITIALIZED:
70  return "initialized";
71  case DAG_JOINED:
72  return "joined";
73  case DAG_REACHABLE:
74  return "reachable";
75  case DAG_POISONING:
76  return "poisoning";
77  default:
78  return "unknown";
79  }
80 }
81 /*---------------------------------------------------------------------------*/
82 int
84 {
85  if(curr_instance.used && ipaddr != NULL) {
86  uip_ipaddr_copy(ipaddr, &curr_instance.dag.dag_id);
87  return 1;
88  }
89  return 0;
90 }
91 /*---------------------------------------------------------------------------*/
92 void
94 {
95  LOG_INFO("leaving DAG ");
96  LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
97  LOG_INFO_(", instance %u\n", curr_instance.instance_id);
98 
99  /* Issue a no-path DAO */
100  if(!rpl_dag_root_is_root()) {
101  RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
103  }
104 
105  /* Forget past link statistics */
106  link_stats_reset();
107 
108  /* Remove all neighbors and lnks */
110  uip_sr_free_all();
111 
112  /* Stop all timers */
114 
115  /* Remove autoconfigured address */
116  if((curr_instance.dag.prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
117  rpl_reset_prefix(&curr_instance.dag.prefix_info);
118  }
119 
120  /* Mark instance as unused */
121  curr_instance.used = 0;
122 }
123 /*---------------------------------------------------------------------------*/
124 void
126 {
127  curr_instance.dag.state = DAG_POISONING;
129 }
130 /*---------------------------------------------------------------------------*/
131 void
132 rpl_dag_periodic(unsigned seconds)
133 {
134  if(curr_instance.used) {
135  if(curr_instance.dag.lifetime != RPL_LIFETIME(RPL_INFINITE_LIFETIME)) {
136  curr_instance.dag.lifetime =
137  curr_instance.dag.lifetime > seconds ? curr_instance.dag.lifetime - seconds : 0;
138  if(curr_instance.dag.lifetime == 0) {
139  LOG_WARN("DAG expired, poison and leave\n");
140  curr_instance.dag.state = DAG_POISONING;
142  } else if(curr_instance.dag.lifetime < 300 && curr_instance.dag.preferred_parent != NULL) {
143  /* Five minutes before expiring, start sending unicast DIS to get an update */
144  LOG_WARN("DAG expiring in %u seconds, send DIS to preferred parent\n", (unsigned)curr_instance.dag.lifetime);
145  rpl_icmp6_dis_output(rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent));
146  }
147  }
148  }
149 }
150 /*---------------------------------------------------------------------------*/
151 int
152 rpl_is_addr_in_our_dag(const uip_ipaddr_t *addr)
153 {
154  return curr_instance.used
155  && uip_ipaddr_prefixcmp(&curr_instance.dag.dag_id, addr, curr_instance.dag.prefix_info.length);
156 }
157 /*---------------------------------------------------------------------------*/
160 {
161  return curr_instance.used ? &curr_instance : NULL;
162 }
163 /*---------------------------------------------------------------------------*/
164 rpl_dag_t *
166 {
167  return curr_instance.used ? &curr_instance.dag : NULL;
168 }
169 /*---------------------------------------------------------------------------*/
170 static rpl_of_t *
171 find_objective_function(rpl_ocp_t ocp)
172 {
173  unsigned int i;
174  for(i = 0; i < sizeof(objective_functions) / sizeof(objective_functions[0]); i++) {
175  if(objective_functions[i]->ocp == ocp) {
176  return objective_functions[i];
177  }
178  }
179  return NULL;
180 }
181 /*---------------------------------------------------------------------------*/
182 void
183 rpl_refresh_routes(const char *str)
184 {
185  if(rpl_dag_root_is_root()) {
186  /* Increment DTSN */
187  RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
188 
189  LOG_WARN("incremented DTSN (%s), current %u\n",
190  str, curr_instance.dtsn_out);
191  if(LOG_INFO_ENABLED) {
192  rpl_neighbor_print_list("Refresh routes (before)");
193  }
194  }
195 }
196 /*---------------------------------------------------------------------------*/
197 void
198 rpl_global_repair(const char *str)
199 {
200  if(rpl_dag_root_is_root()) {
201  RPL_LOLLIPOP_INCREMENT(curr_instance.dag.version); /* New DAG version */
202  curr_instance.dtsn_out = RPL_LOLLIPOP_INIT; /* Re-initialize DTSN */
203 
204  LOG_WARN("initiating global repair (%s), version %u, rank %u\n",
205  str, curr_instance.dag.version, curr_instance.dag.rank);
206  if(LOG_INFO_ENABLED) {
207  rpl_neighbor_print_list("Global repair (before)");
208  }
209 
210  /* Now do a local repair to disseminate the new version */
211  rpl_local_repair("Global repair");
212  }
213 }
214 /*---------------------------------------------------------------------------*/
215 static void
216 global_repair_non_root(rpl_dio_t *dio)
217 {
218  if(!rpl_dag_root_is_root()) {
219  LOG_WARN("participating in global repair, version %u, rank %u\n",
220  dio->version, curr_instance.dag.rank);
221  if(LOG_INFO_ENABLED) {
222  rpl_neighbor_print_list("Global repair (before)");
223  }
224  /* Re-initialize configuration from DIO */
226  init_dag_from_dio(dio);
227  rpl_local_repair("Global repair");
228  }
229 }
230 /*---------------------------------------------------------------------------*/
231 void
232 rpl_local_repair(const char *str)
233 {
234  if(curr_instance.used) { /* Check needed because this is a public function */
235  LOG_WARN("local repair (%s)\n", str);
236  if(!rpl_dag_root_is_root()) {
237  curr_instance.dag.state = DAG_INITIALIZED; /* Reset DAG state */
238  }
239  curr_instance.of->reset(); /* Reset OF */
240  rpl_neighbor_remove_all(); /* Remove all neighbors */
241  rpl_timers_dio_reset("Local repair"); /* Reset Trickle timer */
243  }
244 }
245 /*---------------------------------------------------------------------------*/
246 int
248 {
249  if(curr_instance.mop == RPL_MOP_NO_DOWNWARD_ROUTES) {
250  return curr_instance.used && curr_instance.dag.state >= DAG_INITIALIZED;
251  } else {
252  return curr_instance.used && curr_instance.dag.state >= DAG_REACHABLE;
253  }
254 }
255 /*---------------------------------------------------------------------------*/
256 /* Updates rank and parent */
257 void
259 {
260  rpl_rank_t old_rank;
261 
262  if(!curr_instance.used) {
263  return;
264  }
265 
266  old_rank = curr_instance.dag.rank;
267  /* Any scheduled state update is no longer needed */
269 
270  if(curr_instance.dag.state == DAG_POISONING) {
272  curr_instance.dag.rank = RPL_INFINITE_RANK;
273  if(old_rank != RPL_INFINITE_RANK) {
274  /* Advertise that we are leaving, and leave after a delay */
275  LOG_WARN("poisoning and leaving after a delay\n");
276  rpl_timers_dio_reset("Poison routes");
278  }
279  } else if(!rpl_dag_root_is_root()) {
280  rpl_nbr_t *old_parent = curr_instance.dag.preferred_parent;
281  rpl_nbr_t *nbr;
282 
283  /* Select and set preferred parent */
285  /* Update rank */
286  curr_instance.dag.rank = rpl_neighbor_rank_via_nbr(curr_instance.dag.preferred_parent);
287 
288  /* Update better_parent_since flag for each neighbor */
289  nbr = nbr_table_head(rpl_neighbors);
290  while(nbr != NULL) {
291  if(rpl_neighbor_rank_via_nbr(nbr) < curr_instance.dag.rank) {
292  /* This neighbor would be a better parent than our current.
293  Set 'better_parent_since' if not already set. */
294  if(nbr->better_parent_since == 0) {
295  nbr->better_parent_since = clock_time(); /* Initialize */
296  }
297  } else {
298  nbr->better_parent_since = 0; /* Not a better parent */
299  }
300  nbr = nbr_table_next(rpl_neighbors, nbr);
301  }
302 
303  if(old_parent == NULL || curr_instance.dag.rank < curr_instance.dag.lowest_rank) {
304  /* This is a slight departure from RFC6550: if we had no preferred parent before,
305  * reset lowest_rank. This helps recovering from temporary bad link conditions. */
306  curr_instance.dag.lowest_rank = curr_instance.dag.rank;
307  }
308 
309  /* Reset DIO timer in case of significant rank update */
310  if(curr_instance.dag.last_advertised_rank != RPL_INFINITE_RANK
311  && curr_instance.dag.rank != RPL_INFINITE_RANK
312  && ABS((int32_t)curr_instance.dag.rank - curr_instance.dag.last_advertised_rank) > RPL_SIGNIFICANT_CHANGE_THRESHOLD) {
313  LOG_WARN("significant rank update %u->%u\n",
314  curr_instance.dag.last_advertised_rank, curr_instance.dag.rank);
315  /* Update already here to avoid multiple resets in a row */
316  curr_instance.dag.last_advertised_rank = curr_instance.dag.rank;
317  rpl_timers_dio_reset("Significant rank update");
318  }
319 
320  /* Parent switch */
321  if(curr_instance.dag.preferred_parent != old_parent) {
322  /* We just got a parent (was NULL), reset trickle timer to advertise this */
323  if(old_parent == NULL) {
324  curr_instance.dag.state = DAG_JOINED;
325  rpl_timers_dio_reset("Got parent");
326  LOG_WARN("found parent: ");
327  LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent));
328  LOG_WARN_(", staying in DAG\n");
330  }
331 
332  /* Schedule a DAO */
333  if(curr_instance.dag.preferred_parent != NULL) {
335  } else {
336  /* We have no more parent, schedule DIS to get a chance to hear updated state */
337  curr_instance.dag.state = DAG_INITIALIZED;
338  LOG_WARN("no parent, scheduling periodic DIS, will leave if no parent is found\n");
339  rpl_timers_dio_reset("Poison routes");
342  }
343 
344  if(LOG_INFO_ENABLED) {
345  rpl_neighbor_print_list("Parent switch");
346  }
347  }
348  }
349 
350  /* Finally, update metric container */
351  curr_instance.of->update_metric_container();
352 }
353 /*---------------------------------------------------------------------------*/
354 static rpl_nbr_t *
355 update_nbr_from_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
356 {
357  rpl_nbr_t *nbr = NULL;
358  const uip_lladdr_t *lladdr;
359 
360  nbr = rpl_neighbor_get_from_ipaddr(from);
361  /* Neighbor not in RPL neighbor table, add it */
362  if(nbr == NULL) {
363  /* Is the neighbor known by ds6? Drop this request if not.
364  * Typically, the neighbor is added upon receiving a DIO. */
365  lladdr = uip_ds6_nbr_lladdr_from_ipaddr(from);
366  if(lladdr == NULL) {
367  return NULL;
368  }
369 
370  /* Add neighbor to RPL table */
371  nbr = nbr_table_add_lladdr(rpl_neighbors, (linkaddr_t *)lladdr,
372  NBR_TABLE_REASON_RPL_DIO, dio);
373  if(nbr == NULL) {
374  LOG_ERR("failed to add neighbor\n");
375  return NULL;
376  }
377  }
378 
379  /* Update neighbor info from DIO */
380  nbr->rank = dio->rank;
381  nbr->dtsn = dio->dtsn;
382 #if RPL_WITH_MC
383  memcpy(&nbr->mc, &dio->mc, sizeof(nbr->mc));
384 #endif /* RPL_WITH_MC */
385 
386  return nbr;
387 }
388 /*---------------------------------------------------------------------------*/
389 static void
390 process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
391 {
392  rpl_nbr_t *nbr;
393  uint8_t last_dtsn;
394 
395  /* Does the rank make sense at all? */
396  if(dio->rank < ROOT_RANK) {
397  return;
398  }
399 
400  /* If the DIO sender is on an older version of the DAG, do not process it
401  * further. The sender will eventually hear the global repair and catch up. */
402  if(rpl_lollipop_greater_than(curr_instance.dag.version, dio->version)) {
403  if(dio->rank == ROOT_RANK) {
404  /* Before returning, if the DIO was from the root, an old DAG versions
405  * likely incidates a root reboot. Reset our DIO timer to make sure the
406  * root hears our version ASAP, and in turn triggers a global repair. */
407  rpl_timers_dio_reset("Heard old version from root");
408  }
409  return;
410  }
411 
412  /* The DIO is valid, proceed further */
413 
414  /* Update DIO counter for redundancy mngt */
415  if(dio->rank != RPL_INFINITE_RANK) {
416  curr_instance.dag.dio_counter++;
417  }
418 
419  /* The DIO has a newer version: global repair.
420  * Must come first, as it might remove all neighbors, and we then need
421  * to re-add this source of the DIO to the neighbor table */
422  if(rpl_lollipop_greater_than(dio->version, curr_instance.dag.version)) {
423  if(curr_instance.dag.rank == ROOT_RANK) {
424  /* The root should not hear newer versions unless it just rebooted */
425  LOG_ERR("inconsistent DIO version (current: %u, received: %u), initiate global repair\n",
426  curr_instance.dag.version, dio->version);
427  /* Update version and trigger global repair */
428  curr_instance.dag.version = dio->version;
429  rpl_global_repair("Inconsistent DIO version");
430  } else {
431  LOG_WARN("new DIO version (current: %u, received: %u), apply global repair\n",
432  curr_instance.dag.version, dio->version);
433  global_repair_non_root(dio);
434  }
435  }
436 
437  /* Update IPv6 neighbor cache */
438  if(!rpl_icmp6_update_nbr_table(from, NBR_TABLE_REASON_RPL_DIO, dio)) {
439  LOG_ERR("IPv6 cache full, dropping DIO\n");
440  return;
441  }
442 
443  /* Add neighbor to RPL neighbor table */
444  nbr = rpl_neighbor_get_from_ipaddr(from);
445  last_dtsn = nbr != NULL ? nbr->dtsn : RPL_LOLLIPOP_INIT;
446 
447  if(!update_nbr_from_dio(from, dio)) {
448  LOG_ERR("neighbor table full, dropping DIO\n");
449  return;
450  }
451 
452  /* Init lifetime if not set yet. Refresh it at every DIO from preferred parent. */
453  if(curr_instance.dag.lifetime == 0 ||
454  (nbr != NULL && nbr == curr_instance.dag.preferred_parent)) {
455  LOG_INFO("refreshing lifetime\n");
456  curr_instance.dag.lifetime = RPL_LIFETIME(RPL_DAG_LIFETIME);
457  }
458 
459  /* If the source is our preferred parent and it increased DTSN, we increment
460  * our DTSN in turn and schedule a DAO (see RFC6550 section 9.6.) */
461  if(curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
462  if(nbr != NULL && nbr == curr_instance.dag.preferred_parent && rpl_lollipop_greater_than(dio->dtsn, last_dtsn)) {
463  RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
464  LOG_WARN("DTSN increment %u->%u, schedule new DAO with DTSN %u\n",
465  last_dtsn, dio->dtsn, curr_instance.dtsn_out);
467  }
468  }
469 }
470 /*---------------------------------------------------------------------------*/
471 static int
472 init_dag(uint8_t instance_id, uip_ipaddr_t *dag_id, rpl_ocp_t ocp,
473  uip_ipaddr_t *prefix, unsigned prefix_len, uint8_t prefix_flags)
474 {
475  rpl_of_t *of;
476 
477  memset(&curr_instance, 0, sizeof(curr_instance));
478 
479  /* OF */
480  of = find_objective_function(ocp);
481  if(of == NULL) {
482  LOG_ERR("ignoring DIO with an unsupported OF: %u\n", ocp);
483  return 0;
484  }
485 
486  /* Prefix */
487  if(!rpl_set_prefix_from_addr(prefix, prefix_len, prefix_flags)) {
488  LOG_ERR("failed to set prefix\n");
489  return 0;
490  }
491 
492  /* Instnace */
493  curr_instance.instance_id = instance_id;
494  curr_instance.of = of;
495  curr_instance.dtsn_out = RPL_LOLLIPOP_INIT;
496  curr_instance.used = 1;
497 
498  /* DAG */
499  curr_instance.dag.rank = RPL_INFINITE_RANK;
500  curr_instance.dag.last_advertised_rank = RPL_INFINITE_RANK;
501  curr_instance.dag.lowest_rank = RPL_INFINITE_RANK;
502  curr_instance.dag.dao_last_seqno = RPL_LOLLIPOP_INIT;
503  curr_instance.dag.dao_last_acked_seqno = RPL_LOLLIPOP_INIT;
504  curr_instance.dag.dao_curr_seqno = RPL_LOLLIPOP_INIT;
505  memcpy(&curr_instance.dag.dag_id, dag_id, sizeof(curr_instance.dag.dag_id));
506 
507  return 1;
508 }
509 /*---------------------------------------------------------------------------*/
510 static int
511 init_dag_from_dio(rpl_dio_t *dio)
512 {
513  if(!init_dag(dio->instance_id, &dio->dag_id, dio->ocp,
514  &dio->prefix_info.prefix, dio->prefix_info.length, dio->prefix_info.flags)) {
515  return 0;
516  }
517 
518  /* Instnace */
519  curr_instance.mop = dio->mop;
520  curr_instance.mc.type = dio->mc.type;
521  curr_instance.mc.flags = dio->mc.flags;
522  curr_instance.mc.aggr = dio->mc.aggr;
523  curr_instance.mc.prec = dio->mc.prec;
524  curr_instance.max_rankinc = dio->dag_max_rankinc;
525  curr_instance.min_hoprankinc = dio->dag_min_hoprankinc;
526  curr_instance.dio_intdoubl = dio->dag_intdoubl;
527  curr_instance.dio_intmin = dio->dag_intmin;
528  curr_instance.dio_redundancy = dio->dag_redund;
529  curr_instance.default_lifetime = dio->default_lifetime;
530  curr_instance.lifetime_unit = dio->lifetime_unit;
531 
532  /* DAG */
533  curr_instance.dag.state = DAG_INITIALIZED;
534  curr_instance.dag.preference = dio->preference;
535  curr_instance.dag.grounded = dio->grounded;
536  curr_instance.dag.version = dio->version;
537  curr_instance.dag.dio_intcurrent = dio->dag_intmin;
538 
539  return 1;
540 }
541 /*---------------------------------------------------------------------------*/
542 static int
543 process_dio_init_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
544 {
545  /* Check MOP */
546  if(dio->mop != RPL_MOP_NO_DOWNWARD_ROUTES && dio->mop != RPL_MOP_NON_STORING) {
547  LOG_WARN("ignoring DIO with an unsupported MOP: %d\n", dio->mop);
548  return 0;
549  }
550 
551  /* Initialize instance and DAG data structures */
552  if(!init_dag_from_dio(dio)) {
553  LOG_WARN("failed to initialize DAG\n");
554  return 0;
555  }
556 
557  /* Init OF and timers */
558  curr_instance.of->reset();
559  rpl_timers_dio_reset("Join");
560 #if RPL_WITH_PROBING
562 #endif /* RPL_WITH_PROBING */
563  /* Leave the network after RPL_DELAY_BEFORE_LEAVING in case we do not
564  find a parent */
565  LOG_INFO("initialized DAG with instance ID %u, DAG ID ",
566  curr_instance.instance_id);
567  LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
568  LOG_INFO_(", prexix ");
569  LOG_INFO_6ADDR(&dio->prefix_info.prefix);
570  LOG_INFO_("/%u, rank %u\n", dio->prefix_info.length, curr_instance.dag.rank);
571 
572  LOG_ANNOTATE("#A init=%u\n", curr_instance.dag.dag_id.u8[sizeof(curr_instance.dag.dag_id) - 1]);
573 
574  LOG_WARN("just joined, no parent yet, setting timer for leaving\n");
576 
577  return 1;
578 }
579 /*---------------------------------------------------------------------------*/
580 void
581 rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
582 {
583  if(!curr_instance.used && !rpl_dag_root_is_root()) {
584  /* Attempt to init our DAG from this DIO */
585  if(!process_dio_init_dag(from, dio)) {
586  LOG_WARN("failed to init DAG\n");
587  return;
588  }
589  }
590 
591  if(curr_instance.used
592  && curr_instance.instance_id == dio->instance_id
593  && uip_ipaddr_cmp(&curr_instance.dag.dag_id, &dio->dag_id)) {
594  process_dio_from_current_dag(from, dio);
596  }
597 }
598 /*---------------------------------------------------------------------------*/
599 void
600 rpl_process_dis(uip_ipaddr_t *from, int is_multicast)
601 {
602  if(is_multicast) {
603  rpl_timers_dio_reset("Multicast DIS");
604  } else {
605  /* Add neighbor to cache and reply to the unicast DIS with a unicast DIO*/
606  if(rpl_icmp6_update_nbr_table(from, NBR_TABLE_REASON_RPL_DIS, NULL) != NULL) {
607  LOG_INFO("unicast DIS, reply to sender\n");
608  rpl_icmp6_dio_output(from);
609  }
610  }
611 }
612 /*---------------------------------------------------------------------------*/
613 void
614 rpl_process_dao(uip_ipaddr_t *from, rpl_dao_t *dao)
615 {
616  if(dao->lifetime == 0) {
617  uip_sr_expire_parent(NULL, from, &dao->parent_addr);
618  } else {
619  if(!uip_sr_update_node(NULL, from, &dao->parent_addr, RPL_LIFETIME(dao->lifetime))) {
620  LOG_ERR("failed to add link on incoming DAO\n");
621  return;
622  }
623  }
624 
625 #if RPL_WITH_DAO_ACK
626  if(dao->flags & RPL_DAO_K_FLAG) {
627  rpl_timers_schedule_dao_ack(from, dao->sequence);
628  }
629 #endif /* RPL_WITH_DAO_ACK */
630 }
631 /*---------------------------------------------------------------------------*/
632 #if RPL_WITH_DAO_ACK
633 void
634 rpl_process_dao_ack(uint8_t sequence, uint8_t status)
635 {
636  /* Update dao_last_acked_seqno */
637  if(rpl_lollipop_greater_than(sequence, curr_instance.dag.dao_last_acked_seqno)) {
638  curr_instance.dag.dao_last_acked_seqno = sequence;
639  }
640  /* Is this an ACK for our last DAO? */
641  if(sequence == curr_instance.dag.dao_last_seqno) {
642  int status_ok = status < RPL_DAO_ACK_UNABLE_TO_ACCEPT;
643  if(curr_instance.dag.state == DAG_JOINED && status_ok) {
644  curr_instance.dag.state = DAG_REACHABLE;
645  rpl_timers_dio_reset("Reachable");
646  }
647 
648  if(!status_ok) {
649  /* We got a NACK, start poisoning and leave */
650  LOG_WARN("DAO-NACK received with seqno %u, status %u, poison and leave\n",
651  sequence, status);
652  curr_instance.dag.state = DAG_POISONING;
653  }
654  }
655 }
656 #endif /* RPL_WITH_DAO_ACK */
657 /*---------------------------------------------------------------------------*/
658 int
659 rpl_process_hbh(rpl_nbr_t *sender, uint16_t sender_rank, int loop_detected, int rank_error_signaled)
660 {
661  int drop = 0;
662 
663  if(loop_detected) {
664  if(rank_error_signaled) {
665 #if RPL_LOOP_ERROR_DROP
666  /* Drop packet and reset trickle timer, as per RFC6550 - 11.2.2.2 */
667  rpl_timers_dio_reset("HBH error");
668  LOG_WARN("rank error and loop detected, dropping\n");
669  drop = 1;
670 #endif /* RPL_LOOP_ERROR_DROP */
671  }
672  /* Attempt to repair the loop by sending a unicast DIO back to the sender
673  * so that it gets a fresh update of our rank. */
675  }
676 
677  if(rank_error_signaled) {
678  /* A rank error was signalled, attempt to repair it by updating
679  * the sender's rank from ext header */
680  if(sender != NULL) {
681  sender->rank = sender_rank;
682  /* Select DAG and preferred parent. In case of a parent switch,
683  the new parent will be used to forward the current packet. */
685  }
686  }
687 
688  return !drop;
689 }
690 /*---------------------------------------------------------------------------*/
691 void
692 rpl_dag_init_root(uint8_t instance_id, uip_ipaddr_t *dag_id,
693  uip_ipaddr_t *prefix, unsigned prefix_len, uint8_t prefix_flags)
694 {
695  uint8_t version = RPL_LOLLIPOP_INIT;
696 
697  /* If we're in an instance, first leave it */
698  if(curr_instance.used) {
699  /* We were already root. Increment version */
700  if(uip_ipaddr_cmp(&curr_instance.dag.dag_id, dag_id)) {
701  version = curr_instance.dag.version;
702  RPL_LOLLIPOP_INCREMENT(version);
703  }
704  rpl_dag_leave();
705  }
706 
707  /* Init DAG and instance */
708  init_dag(instance_id, dag_id, RPL_OF_OCP, prefix, prefix_len, prefix_flags);
709 
710  /* Instance */
711  curr_instance.mop = RPL_MOP_DEFAULT;
712  curr_instance.max_rankinc = RPL_MAX_RANKINC;
713  curr_instance.min_hoprankinc = RPL_MIN_HOPRANKINC;
714  curr_instance.dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
715  curr_instance.dio_intmin = RPL_DIO_INTERVAL_MIN;
716  curr_instance.dio_redundancy = RPL_DIO_REDUNDANCY;
717  curr_instance.default_lifetime = RPL_DEFAULT_LIFETIME;
718  curr_instance.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
719 
720  /* DAG */
721  curr_instance.dag.preference = RPL_PREFERENCE;
722  curr_instance.dag.grounded = RPL_GROUNDED;
723  curr_instance.dag.version = version;
724  curr_instance.dag.rank = ROOT_RANK;
725  curr_instance.dag.lifetime = RPL_LIFETIME(RPL_INFINITE_LIFETIME);
726  curr_instance.dag.dio_intcurrent = RPL_DIO_INTERVAL_MIN;
727  curr_instance.dag.state = DAG_REACHABLE;
728 
729  rpl_timers_dio_reset("Init root");
730 
731  LOG_INFO("created DAG with instance ID %u, DAG ID ",
732  curr_instance.instance_id);
733  LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
734  LOG_INFO_(", rank %u\n", curr_instance.dag.rank);
735 
736  LOG_ANNOTATE("#A root=%u\n", curr_instance.dag.dag_id.u8[sizeof(curr_instance.dag.dag_id) - 1]);
737 }
738 /*---------------------------------------------------------------------------*/
739 void
741 {
742  memset(&curr_instance, 0, sizeof(curr_instance));
743 }
744 /*---------------------------------------------------------------------------*/
745 /** @} */
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:124
void rpl_dag_poison_and_leave(void)
Start poisoning and leave the DAG after a delay.
Definition: rpl-dag.c:125
RPL DAG structure.
Definition: rpl.h:135
uip_ipaddr_t * rpl_neighbor_get_ipaddr(rpl_nbr_t *nbr)
Returns a neighbor&#39;s (link-local) IPv6 address.
Definition: rpl-neighbor.c:245
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:114
void rpl_process_dao(uip_ipaddr_t *from, rpl_dao_t *dao)
Processes incoming DAO.
Definition: rpl-dag.c:614
RPL instance structure.
Definition: rpl.h:219
void rpl_timers_schedule_unicast_dio(rpl_nbr_t *target)
Schedule unicast DIO with no delay.
Definition: rpl-timers.c:201
#define ROOT_RANK
Rank of a root node.
Definition: rpl-types.h:78
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:115
int rpl_lollipop_greater_than(int a, int b)
Greater-than function for a lollipop counter.
Definition: rpl.c:57
void rpl_global_repair(const char *str)
Triggers a RPL global repair.
Definition: rpl-dag.c:198
void rpl_neighbor_remove_all(void)
Empty the RPL neighbor table.
Definition: rpl-neighbor.c:318
rpl_nbr_t * rpl_neighbor_get_from_ipaddr(uip_ipaddr_t *addr)
Returns a neighbor from its link-local IPv6 address.
Definition: rpl-neighbor.c:336
void uip_sr_free_all(void)
Deallocate all neighbors.
Definition: uip-sr.c:239
int rpl_is_addr_in_our_dag(const uip_ipaddr_t *addr)
Tells whether a given global IPv6 address is in our current DAG.
Definition: rpl-dag.c:152
#define RPL_LIFETIME(lifetime)
Compute lifetime, accounting for the lifetime unit.
Definition: rpl-types.h:72
void rpl_dag_init_root(uint8_t instance_id, uip_ipaddr_t *dag_id, uip_ipaddr_t *prefix, unsigned prefix_len, uint8_t prefix_flags)
Initializes DAG internal structure for a root node.
Definition: rpl-dag.c:692
void uip_sr_expire_parent(void *graph, const uip_ipaddr_t *child, const uip_ipaddr_t *parent)
Expires a given child-parent link.
Definition: uip-sr.c:113
int rpl_dag_root_is_root(void)
Tells whether we are DAG root or not.
Definition: rpl-dag-root.c:142
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...
Definition: rpl-icmp6.c:547
Source routing support.
void rpl_process_dao_ack(uint8_t sequence, uint8_t status)
Processes incoming DAO-ACK.
API for RPL objective functions (OF)
Definition: rpl.h:201
const char * rpl_dag_state_to_str(enum rpl_dag_state state)
Returns a textual description of the current DAG state.
Definition: rpl-dag.c:66
int rpl_set_prefix_from_addr(uip_ipaddr_t *addr, unsigned len, uint8_t flags)
Set prefix from an IPv6 address.
Definition: rpl.c:154
void rpl_timers_schedule_state_update(void)
Schedule a state update ASAP.
Definition: rpl-timers.c:556
void rpl_timers_dio_reset(const char *str)
Reset DIO Trickle timer.
Definition: rpl-timers.c:149
void rpl_timers_unschedule_leaving(void)
Cancel scheduled leaving if any.
Definition: rpl-timers.c:476
void rpl_timers_stop_dag_timers(void)
Stop all timers related to the DAG.
Definition: rpl-timers.c:531
void rpl_dag_leave(void)
Leaves the current DAG.
Definition: rpl-dag.c:93
void rpl_process_dis(uip_ipaddr_t *from, int is_multicast)
Processes incoming DIS.
Definition: rpl-dag.c:600
rpl_dag_state
RPL DAG states.
Definition: rpl-types.h:177
All information related to a RPL neighbor.
Definition: rpl-types.h:136
rpl_dag_t * rpl_get_any_dag(void)
Returns pointer to any DAG (for compatibility with legagy RPL code)
Definition: rpl-dag.c:1051
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1018
clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:118
int rpl_dag_ready_to_advertise(void)
Tells whether RPL is ready to advertise the DAG.
Definition: rpl-dag.c:247
void rpl_timers_schedule_periodic_dis(void)
Schedule periodic DIS with a random delay based on RPL_DIS_INTERVAL, until we join a DAG...
Definition: rpl-timers.c:92
uip_ds6_nbr_t * rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void *data)
Updates IPv6 neighbor cache on incoming link-local RPL ICMPv6 messages.
Definition: rpl-icmp6.c:196
void rpl_timers_schedule_dao(void)
Schedule a DAO with random delay based on RPL_DAO_DELAY.
Definition: rpl-timers.c:257
void rpl_dag_periodic(unsigned seconds)
A function called periodically.
Definition: rpl-dag.c:132
void rpl_neighbor_print_list(const char *str)
Prints a summary of all RPL neighbors and their properties.
Definition: rpl-neighbor.c:139
void rpl_refresh_routes(const char *str)
Triggers a route fresh via DTSN increment.
Definition: rpl-dag.c:183
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.
Definition: rpl-dag.c:258
void rpl_timers_schedule_leaving(void)
Schedule leaving after RPL_DELAY_BEFORE_LEAVING.
Definition: rpl-timers.c:486
int rpl_dag_get_root_ipaddr(uip_ipaddr_t *ipaddr)
Returns the IPv6 address of the RPL DAG root, if any.
Definition: rpl-dag.c:83
uip_sr_node_t * uip_sr_update_node(void *graph, const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime)
Updates a child-parent link.
Definition: uip-sr.c:123
void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
Processes incoming DIO.
Definition: rpl-dag.c:1455
int rpl_process_hbh(rpl_nbr_t *sender, uint16_t sender_rank, int loop_detected, int rank_error_signaled)
Processes Hop-by-Hop (HBH) Extension Header of a packet currently being forwrded. ...
Definition: rpl-dag.c:659
void rpl_timers_unschedule_state_update(void)
Cancelled any scheduled state update.
Definition: rpl-timers.c:548
rpl_rank_t rpl_neighbor_rank_via_nbr(rpl_nbr_t *nbr)
Returns our rank if selecting a given parent as preferred parent.
Definition: rpl-neighbor.c:230
void rpl_local_repair(const char *str)
Triggers a RPL local repair.
Definition: rpl-dag.c:232
void rpl_reset_prefix(rpl_prefix_t *last_prefix)
Removes current prefx.
Definition: rpl.c:138
void rpl_neighbor_set_preferred_parent(rpl_nbr_t *nbr)
Set current RPL preferred parent and update DS6 default route accordingly.
Definition: rpl-neighbor.c:289
void rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr)
Creates an ICMPv6 DIO packet and sends it.
Definition: rpl-icmp6.c:336
Header file for the logging system
rpl_nbr_t * rpl_neighbor_select_best(void)
Returns the best candidate for preferred parent.
Definition: rpl-neighbor.c:384
rpl_instance_t * rpl_get_default_instance(void)
Returns pointer to the default instance (for compatibility with legagy RPL code)
Definition: rpl-dag.c:624
void rpl_dag_init(void)
Initializes rpl-dag module.
Definition: rpl-dag.c:141
void rpl_icmp6_dis_output(uip_ipaddr_t *addr)
Creates an ICMPv6 DIS packet and sends it.
Definition: rpl-icmp6.c:154
void rpl_schedule_probing(void)
Schedule probing with delay RPL_PROBING_DELAY_FUNC()