Contiki 2.5
rpl-dag.c
Go to the documentation of this file.
1 /**
2  * \addtogroup uip6
3  * @{
4  */
5 /*
6  * Copyright (c) 2010, Swedish Institute of Computer Science.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the Institute nor the names of its contributors
18  * may be used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * This file is part of the Contiki operating system.
34  *
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  */
42 
43 
44 #include "contiki.h"
45 #include "net/rpl/rpl-private.h"
46 #include "net/uip.h"
47 #include "net/uip-nd6.h"
48 #include "lib/list.h"
49 #include "lib/memb.h"
50 #include "sys/ctimer.h"
51 
52 #include <limits.h>
53 #include <string.h>
54 
55 #define DEBUG DEBUG_NONE
56 #include "net/uip-debug.h"
57 
58 #include "net/neighbor-info.h"
59 
60 /************************************************************************/
61 extern rpl_of_t RPL_OF;
62 static rpl_of_t * const objective_functions[] = {&RPL_OF};
63 /************************************************************************/
64 
65 #ifndef RPL_CONF_MAX_DAG_ENTRIES
66 #define RPL_MAX_DAG_ENTRIES 2
67 #else
68 #define RPL_MAX_DAG_ENTRIES RPL_CONF_MAX_DAG_ENTRIES
69 #endif /* !RPL_CONF_MAX_DAG_ENTRIES */
70 
71 #ifndef RPL_CONF_MAX_PARENTS
72 #define RPL_MAX_PARENTS 8
73 #else
74 #define RPL_MAX_PARENTS RPL_CONF_MAX_PARENTS
75 #endif /* !RPL_CONF_MAX_PARENTS */
76 /************************************************************************/
77 /* RPL definitions. */
78 
79 #ifndef RPL_CONF_GROUNDED
80 #define RPL_GROUNDED 0
81 #else
82 #define RPL_GROUNDED RPL_CONF_GROUNDED
83 #endif /* !RPL_CONF_GROUNDED */
84 
85 #ifndef RPL_CONF_DIO_INTERVAL_MIN
86 #define RPL_DIO_INTERVAL_MIN DEFAULT_DIO_INTERVAL_MIN
87 #else
88 #define RPL_DIO_INTERVAL_MIN RPL_CONF_DIO_INTERVAL_MIN
89 #endif /* !RPL_CONF_DIO_INTERVAL_MIN */
90 
91 #ifndef RPL_CONF_DIO_INTERVAL_DOUBLINGS
92 #define RPL_DIO_INTERVAL_DOUBLINGS DEFAULT_DIO_INTERVAL_DOUBLINGS
93 #else
94 #define RPL_DIO_INTERVAL_DOUBLINGS RPL_CONF_DIO_INTERVAL_DOUBLINGS
95 #endif /* !RPL_CONF_DIO_INTERVAL_DOUBLINGS */
96 
97 /************************************************************************/
98 /* Allocate parents from the same static MEMB chunk to reduce memory waste. */
99 MEMB(parent_memb, struct rpl_parent, RPL_MAX_PARENTS);
100 
101 static rpl_dag_t dag_table[RPL_MAX_DAG_ENTRIES];
102 /************************************************************************/
103 /* Remove DAG parents with a rank that is at least the same as minimum_rank. */
104 static void
105 remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
106 {
107  rpl_parent_t *p, *p2;
108 
109  PRINTF("RPL: Removing parents (minimum rank %u)\n",
110  minimum_rank);
111 
112  for(p = list_head(dag->parents); p != NULL; p = p2) {
113  p2 = p->next;
114  if(p->rank >= minimum_rank) {
115  rpl_remove_parent(dag, p);
116  }
117  }
118 }
119 /************************************************************************/
120 static void
121 remove_worst_parent(rpl_dag_t *dag, rpl_rank_t min_worst_rank)
122 {
123  rpl_parent_t *p, *worst;
124 
125  PRINTF("RPL: Removing the worst parent\n");
126 
127  /* Find the parent with the highest rank. */
128  worst = NULL;
129  for(p = list_head(dag->parents); p != NULL; p = list_item_next(p)) {
130  if(p != dag->preferred_parent &&
131  (worst == NULL || p->rank > worst->rank)) {
132  worst = p;
133  }
134  }
135  /* Remove the neighbor if its rank is worse than the minimum worst
136  rank. */
137  if(worst != NULL && worst->rank > min_worst_rank) {
138  rpl_remove_parent(dag, worst);
139  }
140 }
141 /************************************************************************/
142 static int
143 should_send_dao(rpl_dag_t *dag, rpl_dio_t *dio, rpl_parent_t *p)
144 {
145  /* if MOP is set to no downward routes no DAO should be sent */
146  if(dag->mop == RPL_MOP_NO_DOWNWARD_ROUTES) return 0;
147  return dio->dtsn != p->dtsn && p == dag->preferred_parent;
148 }
149 /************************************************************************/
150 static int
151 acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank)
152 {
153  return rank != INFINITE_RANK &&
154  (dag->max_rankinc == 0 ||
155  DAG_RANK(rank, dag) <= DAG_RANK(dag->min_rank + dag->max_rankinc, dag));
156 }
157 /************************************************************************/
158 rpl_dag_t *
159 rpl_set_root(uip_ipaddr_t *dag_id)
160 {
161  rpl_dag_t *dag;
162  int version;
163 
164  version = -1;
165  dag = rpl_get_dag(RPL_DEFAULT_INSTANCE);
166  if(dag != NULL) {
167  PRINTF("RPL: Dropping a joined DAG when setting this node as root");
168  version = dag->version;
169  rpl_free_dag(dag);
170  }
171 
172  dag = rpl_alloc_dag(RPL_DEFAULT_INSTANCE);
173  if(dag == NULL) {
174  PRINTF("RPL: Failed to allocate a DAG\n");
175  return NULL;
176  }
177 
178  dag->joined = 1;
179  dag->version = version + 1;
180  dag->grounded = RPL_GROUNDED;
181  dag->mop = RPL_MOP_DEFAULT;
182  dag->of = &RPL_OF;
183  dag->preferred_parent = NULL;
184  dag->dtsn_out = 1; /* Trigger DAOs from the beginning. */
185 
186  memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id));
187 
188  dag->dio_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS;
189  dag->dio_intmin = DEFAULT_DIO_INTERVAL_MIN;
190  dag->dio_redundancy = DEFAULT_DIO_REDUNDANCY;
191  dag->max_rankinc = DEFAULT_MAX_RANKINC;
192  dag->min_hoprankinc = DEFAULT_MIN_HOPRANKINC;
193 
194  dag->default_lifetime = RPL_DEFAULT_LIFETIME;
195  dag->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
196 
197  dag->rank = ROOT_RANK(dag);
198 
199  dag->of->update_metric_container(dag);
200 
201  PRINTF("RPL: Node set to be a DAG root with DAG ID ");
202  PRINT6ADDR(&dag->dag_id);
203  PRINTF("\n");
204 
205  ANNOTATE("#A root=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
206 
207 
208  rpl_reset_dio_timer(dag, 1);
209 
210  return dag;
211 }
212 /************************************************************************/
213 int
214 rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, int len)
215 {
216  if(len <= 128) {
217  memset(&dag->prefix_info.prefix, 0, 16);
218  memcpy(&dag->prefix_info.prefix, prefix, (len + 7) / 8);
219  dag->prefix_info.length = len;
220  dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS;
221  PRINTF("RPL: Prefix set - will announce this in DIOs\n");
222  return 1;
223  }
224  return 0;
225 }
226 /************************************************************************/
227 int
228 rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from)
229 {
230  if(dag->def_route != NULL) {
231  PRINTF("RPL: Removing default route through ");
232  PRINT6ADDR(&dag->def_route->ipaddr);
233  PRINTF("\n");
234  uip_ds6_defrt_rm(dag->def_route);
235  }
236 
237  if(from != NULL) {
238  PRINTF("RPL: Adding default route through ");
239  PRINT6ADDR(from);
240  PRINTF("\n");
241  dag->def_route = uip_ds6_defrt_add(from,
242  RPL_LIFETIME(dag,
243  dag->default_lifetime));
244  if(dag->def_route == NULL) {
245  return 0;
246  }
247  }
248 
249  return 1;
250 }
251 /************************************************************************/
252 rpl_dag_t *
253 rpl_alloc_dag(uint8_t instance_id)
254 {
255  rpl_dag_t *dag;
256  rpl_dag_t *end;
257 
258  for(dag = &dag_table[0], end = dag + RPL_MAX_DAG_ENTRIES; dag < end; dag++) {
259  if(dag->used == 0) {
260  memset(dag, 0, sizeof(*dag));
261  dag->parents = &dag->parent_list;
262  list_init(dag->parents);
263  dag->instance_id = instance_id;
264  dag->def_route = NULL;
265  dag->rank = INFINITE_RANK;
266  dag->min_rank = INFINITE_RANK;
267  return dag;
268  }
269  }
270 
271  RPL_STAT(rpl_stats.mem_overflows++);
272  return NULL;
273 }
274 /************************************************************************/
275 void
276 rpl_free_dag(rpl_dag_t *dag)
277 {
278  PRINTF("RPL: Leaving the DAG ");
279  PRINT6ADDR(&dag->dag_id);
280  PRINTF("\n");
281 
282  /* Remove routes installed by DAOs. */
283  rpl_remove_routes(dag);
284 
285  /* Remove parents and the default route. */
286  remove_parents(dag, 0);
287  rpl_set_default_route(dag, NULL);
288 
289  ctimer_stop(&dag->dio_timer);
290  ctimer_stop(&dag->dao_timer);
291 
292  dag->used = 0;
293  dag->joined = 0;
294 }
295 /************************************************************************/
296 rpl_parent_t *
297 rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
298 {
299  rpl_parent_t *p;
300 
301  p = memb_alloc(&parent_memb);
302  if(p == NULL) {
303  RPL_STAT(rpl_stats.mem_overflows++);
304  return NULL;
305  }
306 
307  memcpy(&p->addr, addr, sizeof(p->addr));
308  p->dag = dag;
309  p->rank = dio->rank;
310  p->link_metric = INITIAL_LINK_METRIC;
311  p->dtsn = 0;
312 
313  memcpy(&p->mc, &dio->mc, sizeof(p->mc));
314 
315  list_add(dag->parents, p);
316 
317  return p;
318 }
319 /************************************************************************/
320 rpl_parent_t *
321 rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr)
322 {
323  rpl_parent_t *p;
324 
325  for(p = list_head(dag->parents); p != NULL; p = p->next) {
326  if(uip_ipaddr_cmp(&p->addr, addr)) {
327  return p;
328  }
329  }
330 
331  return NULL;
332 }
333 
334 /************************************************************************/
335 rpl_parent_t *
336 rpl_select_parent(rpl_dag_t *dag)
337 {
338  rpl_parent_t *p;
339  rpl_parent_t *best;
340 
341  best = NULL;
342  for(p = list_head(dag->parents); p != NULL; p = p->next) {
343  if(p->rank == INFINITE_RANK) {
344  /* ignore this neighbor */
345  } else if(best == NULL) {
346  best = p;
347  } else {
348  best = dag->of->best_parent(best, p);
349  }
350  }
351 
352  if(best == NULL) {
353  /* need to handle update of best... */
354  return NULL;
355  }
356 
357  if(dag->preferred_parent != best) {
358  PRINTF("RPL: Sending a No-Path DAO to old DAO parent\n");
359  dao_output(dag->preferred_parent, ZERO_LIFETIME);
360 
361  dag->preferred_parent = best; /* Cache the value. */
362  dag->of->update_metric_container(dag);
363  rpl_set_default_route(dag, &best->addr);
364  /* The DAO parent set changed - schedule a DAO transmission. */
365  if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
366  rpl_schedule_dao(dag);
367  }
368  rpl_reset_dio_timer(dag, 1);
369  PRINTF("RPL: New preferred parent, rank changed from %u to %u\n",
370  (unsigned)dag->rank, dag->of->calculate_rank(best, 0));
371  RPL_STAT(rpl_stats.parent_switch++);
372  }
373 
374  /* Update the DAG rank, since link-layer information may have changed
375  the local confidence. */
376  dag->rank = dag->of->calculate_rank(best, 0);
377  if(dag->rank < dag->min_rank) {
378  dag->min_rank = dag->rank;
379  } else if(!acceptable_rank(dag, best->rank)) {
380  /* Send a No-Path DAO to the soon-to-be-removed preferred parent. */
381  dao_output(best, ZERO_LIFETIME);
382 
383  remove_parents(dag, 0);
384  return NULL;
385  }
386 
387  return best;
388 }
389 /************************************************************************/
390 int
391 rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t *parent)
392 {
393  uip_ds6_defrt_t *defrt;
394 
395  /* Remove uIPv6 routes that have this parent as the next hop. **/
396  uip_ds6_route_rm_by_nexthop(&parent->addr);
397  defrt = uip_ds6_defrt_lookup(&parent->addr);
398  if(defrt != NULL) {
399  PRINTF("RPL: Removing default route ");
400  PRINT6ADDR(&parent->addr);
401  PRINTF("\n");
402  uip_ds6_defrt_rm(defrt);
403  dag->def_route = NULL;
404  }
405 
406  PRINTF("RPL: Removing parent ");
407  PRINT6ADDR(&parent->addr);
408  PRINTF("\n");
409 
410  if(parent == dag->preferred_parent) {
411  dag->preferred_parent = NULL;
412  }
413 
414  list_remove(dag->parents, parent);
415  memb_free(&parent_memb, parent);
416  return 0;
417 }
418 /************************************************************************/
419 rpl_dag_t *
420 rpl_get_dag(int instance_id)
421 {
422  int i;
423 
424  for(i = 0; i < RPL_MAX_DAG_ENTRIES; i++) {
425  if(dag_table[i].joined && (instance_id == RPL_ANY_INSTANCE ||
426  dag_table[i].instance_id == instance_id)) {
427  return &dag_table[i];
428  }
429  }
430  return NULL;
431 }
432 /************************************************************************/
433 rpl_of_t *
434 rpl_find_of(rpl_ocp_t ocp)
435 {
436  unsigned int i;
437 
438  for(i = 0;
439  i < sizeof(objective_functions) / sizeof(objective_functions[0]);
440  i++) {
441  if(objective_functions[i]->ocp == ocp) {
442  return objective_functions[i];
443  }
444  }
445 
446  return NULL;
447 }
448 /************************************************************************/
449 static void
450 join_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
451 {
452  rpl_dag_t *dag;
453  rpl_parent_t *p;
454  rpl_of_t *of;
455 
456  dag = rpl_alloc_dag(dio->instance_id);
457  if(dag == NULL) {
458  PRINTF("RPL: Failed to allocate a DAG object!\n");
459  return;
460  }
461 
462  p = rpl_add_parent(dag, dio, from);
463  PRINTF("RPL: Adding ");
464  PRINT6ADDR(from);
465  PRINTF(" as a parent: ");
466  if(p == NULL) {
467  PRINTF("failed\n");
468  return;
469  }
470  PRINTF("succeeded\n");
471 
472  /* Determine the objective function by using the
473  objective code point of the DIO. */
474  of = rpl_find_of(dio->ocp);
475  if(of == NULL) {
476  PRINTF("RPL: DIO for DAG instance %u does not specify a supported OF\n",
477  dio->instance_id);
478  return;
479  }
480 
481  /* Autoconfigure an address if this node does not already have an address
482  with this prefix. */
483  if((dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
484  uip_ipaddr_t ipaddr;
485  /* assume that the prefix ends with zeros! */
486  memcpy(&ipaddr, &dio->prefix_info.prefix, 16);
487  uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
488  if(uip_ds6_addr_lookup(&ipaddr) == NULL) {
489  PRINTF("RPL: adding global IP address ");
490  PRINT6ADDR(&ipaddr);
491  PRINTF("\n");
492  uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
493  }
494  }
495 
496  dag->joined = 1;
497  dag->used = 1;
498  dag->of = of;
499  dag->grounded = dio->grounded;
500  dag->mop = dio->mop;
501  dag->preference = dio->preference;
502  dag->instance_id = dio->instance_id;
503 
504  dag->max_rankinc = dio->dag_max_rankinc;
505  dag->min_hoprankinc = dio->dag_min_hoprankinc;
506 
507  dag->version = dio->version;
508  dag->preferred_parent = p;
509  dag->of->update_metric_container(dag);
510 
511  dag->dio_intdoubl = dio->dag_intdoubl;
512  dag->dio_intmin = dio->dag_intmin;
513  dag->dio_redundancy = dio->dag_redund;
514 
515  memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id));
516 
517  /* copy prefix information into the dag */
518  memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t));
519 
520  dag->rank = dag->of->calculate_rank(p, dio->rank);
521  dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */
522 
523  PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
524  dio->instance_id, dag->rank);
525  PRINT6ADDR(&dag->dag_id);
526  PRINTF("\n");
527 
528  ANNOTATE("#A join=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
529 
530 
531  dag->default_lifetime = dio->default_lifetime;
532  dag->lifetime_unit = dio->lifetime_unit;
533 
534  rpl_reset_dio_timer(dag, 1);
535  rpl_set_default_route(dag, from);
536 
537  if(should_send_dao(dag, dio, p)) {
538  rpl_schedule_dao(dag);
539  } else {
540  PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n");
541  }
542 }
543 /************************************************************************/
544 static void
545 global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio)
546 {
547  rpl_parent_t *p;
548 
549  remove_parents(dag, 0);
550  dag->version = dio->version;
551  dag->dtsn_out = 1;
552  dag->of->reset(dag);
553  if((p = rpl_add_parent(dag, dio, from)) == NULL) {
554  PRINTF("RPL: Failed to add a parent during the global repair\n");
555  dag->rank = INFINITE_RANK;
556  } else {
557  rpl_set_default_route(dag, from);
558  dag->rank = dag->of->calculate_rank(NULL, dio->rank);
559  dag->min_rank = dag->rank;
560  rpl_reset_dio_timer(dag, 1);
561  if(should_send_dao(dag, dio, p)) {
562  rpl_schedule_dao(dag);
563  }
564  }
565  PRINTF("RPL: Participating in a global repair (version=%u, rank=%hu)\n",
566  dag->version, dag->rank);
567 
568  RPL_STAT(rpl_stats.global_repairs++);
569 }
570 /************************************************************************/
571 int
572 rpl_repair_dag(rpl_dag_t *dag)
573 {
574  if(dag->rank == ROOT_RANK(dag)) {
575  dag->version++;
576  dag->dtsn_out = 1;
577  rpl_reset_dio_timer(dag, 1);
578  return 1;
579  }
580  return 0;
581 }
582 /************************************************************************/
583 void
584 rpl_local_repair(rpl_dag_t *dag)
585 {
586  PRINTF("RPL: Starting a local DAG repair\n");
587 
588  dag->rank = INFINITE_RANK;
589  remove_parents(dag, 0);
590  rpl_reset_dio_timer(dag, 1);
591 
592  RPL_STAT(rpl_stats.local_repairs++);
593 }
594 /************************************************************************/
595 void
596 rpl_recalculate_ranks(void)
597 {
598  rpl_dag_t *dag;
599  rpl_parent_t *p;
600 
601  /*
602  * We recalculate ranks when we receive feedback from the system rather
603  * than RPL protocol messages. This periodical recalculation is called
604  * from a timer in order to keep the stack depth reasonably low.
605  */
606  dag = rpl_get_dag(RPL_ANY_INSTANCE);
607  if(dag != NULL) {
608  for(p = list_head(dag->parents); p != NULL; p = p->next) {
609  if(p->updated) {
610  p->updated = 0;
611  rpl_process_parent_event(dag, p);
612  /*
613  * Stop calculating here because the parent list may have changed.
614  * If more ranks need to be recalculated, it will be taken care of
615  * in subsequent calls to this functions.
616  */
617  break;
618  }
619  }
620  }
621 }
622 /************************************************************************/
623 int
624 rpl_process_parent_event(rpl_dag_t *dag, rpl_parent_t *p)
625 {
626  rpl_rank_t parent_rank;
627  rpl_rank_t old_rank;
628 
629  /* Update the parent rank. */
630  parent_rank = p->rank;
631  old_rank = dag->rank;
632 
633  if(rpl_select_parent(dag) == NULL) {
634  /* No suitable parent; trigger a local repair. */
635  PRINTF("RPL: No parents found in a DAG\n");
636  rpl_local_repair(dag);
637  return 1;
638  }
639 
640  if(DAG_RANK(old_rank, dag) != DAG_RANK(dag->rank, dag)) {
641  if(dag->rank < dag->min_rank) {
642  dag->min_rank = dag->rank;
643  }
644  PRINTF("RPL: Moving in the DAG from rank %hu to %hu\n",
645  DAG_RANK(old_rank, dag), DAG_RANK(dag->rank, dag));
646  PRINTF("RPL: The preferred parent is ");
647  PRINT6ADDR(&dag->preferred_parent->addr);
648  PRINTF(" (rank %u)\n",
649  (unsigned)DAG_RANK(dag->preferred_parent->rank, dag));
650  rpl_reset_dio_timer(dag, 1);
651  }
652 
653  if(parent_rank == INFINITE_RANK ||
654  !acceptable_rank(dag, dag->of->calculate_rank(NULL, parent_rank))) {
655  /* The candidate parent is no longer valid: the rank increase resulting
656  from the choice of it as a parent would be too high. */
657  return 0;
658  }
659 
660  return 1;
661 }
662 /************************************************************************/
663 void
664 rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
665 {
666  rpl_dag_t *dag;
667  rpl_parent_t *p;
668 
669  if(dio->mop != RPL_MOP_DEFAULT) {
670  PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop);
671  return;
672  }
673 
674  dag = rpl_get_dag(dio->instance_id);
675  if(dag == NULL) {
676  /* Join the first possible DAG of this RPL instance. */
677  if(dio->rank != INFINITE_RANK) {
678  join_dag(from, dio);
679  } else {
680  PRINTF("RPL: Ignoring DIO from node with infinite rank: ");
681  PRINT6ADDR(from);
682  PRINTF("\n");
683  }
684  return;
685  }
686 
687  if(memcmp(&dag->dag_id, &dio->dag_id, sizeof(dag->dag_id))) {
688  PRINTF("RPL: Ignoring DIO for another DAG within our instance\n");
689  return;
690  }
691 
692  if(dio->version > dag->version) {
693  if(dag->rank == ROOT_RANK(dag)) {
694  PRINTF("RPL: Root received inconsistent DIO version number\n");
695  dag->version = dio->version + 1;
696  rpl_reset_dio_timer(dag, 1);
697  } else {
698  global_repair(from, dag, dio);
699  }
700  return;
701  } else if(dio->version < dag->version) {
702  /* Inconsistency detected - someone is still on old version */
703  PRINTF("RPL: old version received => inconsistency detected\n");
704  rpl_reset_dio_timer(dag, 1);
705  return;
706  }
707 
708  if(dio->rank == INFINITE_RANK) {
709  rpl_reset_dio_timer(dag, 1);
710  } else if(dio->rank < ROOT_RANK(dag)) {
711  PRINTF("RPL: Ignoring DIO with too low rank: %u\n",
712  (unsigned)dio->rank);
713  return;
714  }
715 
716  if(dag->rank == ROOT_RANK(dag)) {
717  if(dio->rank != INFINITE_RANK) {
718  dag->dio_counter++;
719  }
720  return;
721  }
722 
723  /*
724  * At this point, we know that this DIO pertains to a DAG that
725  * we are already part of. We consider the sender of the DIO to be
726  * a candidate parent, and let rpl_process_parent_event decide
727  * whether to keep it in the set.
728  */
729 
730  p = rpl_find_parent(dag, from);
731  if(p == NULL) {
732  if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS) {
733  /* Make room for a new parent. */
734  remove_worst_parent(dag, dio->rank);
735  }
736 
737  /* Add the DIO sender as a candidate parent. */
738  p = rpl_add_parent(dag, dio, from);
739  if(p == NULL) {
740  PRINTF("RPL: Failed to add a new parent (");
741  PRINT6ADDR(from);
742  PRINTF(")\n");
743  return;
744  }
745 
746  PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank);
747  PRINT6ADDR(from);
748  PRINTF("\n");
749  } else if(DAG_RANK(p->rank, dag) == DAG_RANK(dio->rank, dag)) {
750  PRINTF("RPL: Received consistent DIO\n");
751  dag->dio_counter++;
752  }
753 
754  /* We have allocated a candidate parent; process the DIO further. */
755 
756  memcpy(&p->mc, &dio->mc, sizeof(p->mc));
757  p->rank = dio->rank;
758  if(rpl_process_parent_event(dag, p) == 0) {
759  /* The candidate parent no longer exists. */
760  return;
761  }
762 
763  if(should_send_dao(dag, dio, p)) {
764  rpl_schedule_dao(dag);
765  }
766 
767  p->dtsn = dio->dtsn;
768 }
769 /************************************************************************/
770