Contiki-Inga 3.x
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  * \file
35  * Logic for Directed Acyclic Graphs in RPL.
36  *
37  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
38  * Contributors: George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
39  */
40 
41 /**
42  * \addtogroup uip6
43  * @{
44  */
45 
46 #include "contiki.h"
47 #include "net/rpl/rpl-private.h"
48 #include "net/ip/uip.h"
49 #include "net/ipv6/uip-nd6.h"
50 #include "net/nbr-table.h"
52 #include "lib/list.h"
53 #include "lib/memb.h"
54 #include "sys/ctimer.h"
55 
56 #include <limits.h>
57 #include <string.h>
58 
59 #define DEBUG DEBUG_NONE
60 #include "net/ip/uip-debug.h"
61 
62 #if UIP_CONF_IPV6
63 /*---------------------------------------------------------------------------*/
64 extern rpl_of_t RPL_OF;
65 static rpl_of_t * const objective_functions[] = {&RPL_OF};
66 
67 /*---------------------------------------------------------------------------*/
68 /* RPL definitions. */
69 
70 #ifndef RPL_CONF_GROUNDED
71 #define RPL_GROUNDED 0
72 #else
73 #define RPL_GROUNDED RPL_CONF_GROUNDED
74 #endif /* !RPL_CONF_GROUNDED */
75 
76 /*---------------------------------------------------------------------------*/
77 /* Per-parent RPL information */
78 NBR_TABLE(rpl_parent_t, rpl_parents);
79 /*---------------------------------------------------------------------------*/
80 /* Allocate instance table. */
81 rpl_instance_t instance_table[RPL_MAX_INSTANCES];
82 rpl_instance_t *default_instance;
83 /*---------------------------------------------------------------------------*/
84 static void
85 nbr_callback(void *ptr)
86 {
87  rpl_remove_parent(ptr);
88 }
89 
90 void
91 rpl_dag_init(void)
92 {
93  nbr_table_register(rpl_parents, (nbr_table_callback *)nbr_callback);
94 }
95 /*---------------------------------------------------------------------------*/
96 rpl_rank_t
97 rpl_get_parent_rank(uip_lladdr_t *addr)
98 {
99  rpl_parent_t *p = nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)addr);
100  if(p != NULL) {
101  return p->rank;
102  } else {
103  return 0;
104  }
105 }
106 /*---------------------------------------------------------------------------*/
107 uint16_t
108 rpl_get_parent_link_metric(const uip_lladdr_t *addr)
109 {
110  rpl_parent_t *p = nbr_table_get_from_lladdr(rpl_parents, (const linkaddr_t *)addr);
111  if(p != NULL) {
112  return p->link_metric;
113  } else {
114  return 0;
115  }
116 }
117 /*---------------------------------------------------------------------------*/
118 uip_ipaddr_t *
119 rpl_get_parent_ipaddr(rpl_parent_t *p)
120 {
121  linkaddr_t *lladdr = nbr_table_get_lladdr(rpl_parents, p);
123 }
124 /*---------------------------------------------------------------------------*/
125 static void
126 rpl_set_preferred_parent(rpl_dag_t *dag, rpl_parent_t *p)
127 {
128  if(dag != NULL && dag->preferred_parent != p) {
129  PRINTF("RPL: rpl_set_preferred_parent ");
130  if(p != NULL) {
131  PRINT6ADDR(rpl_get_parent_ipaddr(p));
132  } else {
133  PRINTF("NULL");
134  }
135  PRINTF(" used to be ");
136  if(dag->preferred_parent != NULL) {
137  PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
138  } else {
139  PRINTF("NULL");
140  }
141  PRINTF("\n");
142 
143  /* Always keep the preferred parent locked, so it remains in the
144  * neighbor table. */
145  nbr_table_unlock(rpl_parents, dag->preferred_parent);
146  nbr_table_lock(rpl_parents, p);
147  dag->preferred_parent = p;
148  }
149 }
150 /*---------------------------------------------------------------------------*/
151 /* Greater-than function for the lollipop counter. */
152 /*---------------------------------------------------------------------------*/
153 static int
154 lollipop_greater_than(int a, int b)
155 {
156  /* Check if we are comparing an initial value with an old value */
157  if(a > RPL_LOLLIPOP_CIRCULAR_REGION && b <= RPL_LOLLIPOP_CIRCULAR_REGION) {
158  return (RPL_LOLLIPOP_MAX_VALUE + 1 + b - a) > RPL_LOLLIPOP_SEQUENCE_WINDOWS;
159  }
160  /* Otherwise check if a > b and comparable => ok, or
161  if they have wrapped and are still comparable */
162  return (a > b && (a - b) < RPL_LOLLIPOP_SEQUENCE_WINDOWS) ||
163  (a < b && (b - a) > (RPL_LOLLIPOP_CIRCULAR_REGION + 1-
164  RPL_LOLLIPOP_SEQUENCE_WINDOWS));
165 }
166 /*---------------------------------------------------------------------------*/
167 /* Remove DAG parents with a rank that is at least the same as minimum_rank. */
168 static void
169 remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
170 {
171  rpl_parent_t *p;
172 
173  PRINTF("RPL: Removing parents (minimum rank %u)\n",
174  minimum_rank);
175 
176  p = nbr_table_head(rpl_parents);
177  while(p != NULL) {
178  if(dag == p->dag && p->rank >= minimum_rank) {
179  rpl_remove_parent(p);
180  }
181  p = nbr_table_next(rpl_parents, p);
182  }
183 }
184 /*---------------------------------------------------------------------------*/
185 static void
186 nullify_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
187 {
188  rpl_parent_t *p;
189 
190  PRINTF("RPL: Nullifying parents (minimum rank %u)\n",
191  minimum_rank);
192 
193  p = nbr_table_head(rpl_parents);
194  while(p != NULL) {
195  if(dag == p->dag && p->rank >= minimum_rank) {
196  rpl_nullify_parent(p);
197  }
198  p = nbr_table_next(rpl_parents, p);
199  }
200 }
201 /*---------------------------------------------------------------------------*/
202 static int
203 should_send_dao(rpl_instance_t *instance, rpl_dio_t *dio, rpl_parent_t *p)
204 {
205  /* if MOP is set to no downward routes no DAO should be sent */
206  if(instance->mop == RPL_MOP_NO_DOWNWARD_ROUTES) {
207  return 0;
208  }
209  /* check if the new DTSN is more recent */
210  return p == instance->current_dag->preferred_parent &&
211  (lollipop_greater_than(dio->dtsn, p->dtsn));
212 }
213 /*---------------------------------------------------------------------------*/
214 static int
215 acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank)
216 {
217  return rank != INFINITE_RANK &&
218  ((dag->instance->max_rankinc == 0) ||
219  DAG_RANK(rank, dag->instance) <= DAG_RANK(dag->min_rank + dag->instance->max_rankinc, dag->instance));
220 }
221 /*---------------------------------------------------------------------------*/
222 static rpl_dag_t *
223 get_dag(uint8_t instance_id, uip_ipaddr_t *dag_id)
224 {
225  rpl_instance_t *instance;
226  rpl_dag_t *dag;
227  int i;
228 
229  instance = rpl_get_instance(instance_id);
230  if(instance == NULL) {
231  return NULL;
232  }
233 
234  for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) {
235  dag = &instance->dag_table[i];
236  if(dag->used && uip_ipaddr_cmp(&dag->dag_id, dag_id)) {
237  return dag;
238  }
239  }
240 
241  return NULL;
242 }
243 /*---------------------------------------------------------------------------*/
244 rpl_dag_t *
245 rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
246 {
247  rpl_dag_t *dag;
248  rpl_instance_t *instance;
249  uint8_t version;
250 
251  version = RPL_LOLLIPOP_INIT;
252  dag = get_dag(instance_id, dag_id);
253  if(dag != NULL) {
254  version = dag->version;
255  RPL_LOLLIPOP_INCREMENT(version);
256  PRINTF("RPL: Dropping a joined DAG when setting this node as root");
257  if(dag == dag->instance->current_dag) {
258  dag->instance->current_dag = NULL;
259  }
260  rpl_free_dag(dag);
261  }
262 
263  dag = rpl_alloc_dag(instance_id, dag_id);
264  if(dag == NULL) {
265  PRINTF("RPL: Failed to allocate a DAG\n");
266  return NULL;
267  }
268 
269  instance = dag->instance;
270 
271  dag->version = version;
272  dag->joined = 1;
273  dag->grounded = RPL_GROUNDED;
274  instance->mop = RPL_MOP_DEFAULT;
275  instance->of = &RPL_OF;
276  rpl_set_preferred_parent(dag, NULL);
277 
278  memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id));
279 
280  instance->dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
281  instance->dio_intmin = RPL_DIO_INTERVAL_MIN;
282  /* The current interval must differ from the minimum interval in order to
283  trigger a DIO timer reset. */
284  instance->dio_intcurrent = RPL_DIO_INTERVAL_MIN +
285  RPL_DIO_INTERVAL_DOUBLINGS;
286  instance->dio_redundancy = RPL_DIO_REDUNDANCY;
287  instance->max_rankinc = RPL_MAX_RANKINC;
288  instance->min_hoprankinc = RPL_MIN_HOPRANKINC;
289  instance->default_lifetime = RPL_DEFAULT_LIFETIME;
290  instance->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
291 
292  dag->rank = ROOT_RANK(instance);
293 
294  if(instance->current_dag != dag && instance->current_dag != NULL) {
295  /* Remove routes installed by DAOs. */
296  rpl_remove_routes(instance->current_dag);
297 
298  instance->current_dag->joined = 0;
299  }
300 
301  instance->current_dag = dag;
302  instance->dtsn_out = RPL_LOLLIPOP_INIT;
303  instance->of->update_metric_container(instance);
304  default_instance = instance;
305 
306  PRINTF("RPL: Node set to be a DAG root with DAG ID ");
307  PRINT6ADDR(&dag->dag_id);
308  PRINTF("\n");
309 
310  ANNOTATE("#A root=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
311 
312  rpl_reset_dio_timer(instance);
313 
314  return dag;
315 }
316 /*---------------------------------------------------------------------------*/
317 int
318 rpl_repair_root(uint8_t instance_id)
319 {
320  rpl_instance_t *instance;
321 
322  instance = rpl_get_instance(instance_id);
323  if(instance == NULL ||
324  instance->current_dag->rank != ROOT_RANK(instance)) {
325  PRINTF("RPL: rpl_repair_root triggered but not root\n");
326  return 0;
327  }
328 
329  RPL_LOLLIPOP_INCREMENT(instance->current_dag->version);
330  RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
331  PRINTF("RPL: rpl_repair_root initiating global repair with version %d\n", instance->current_dag->version);
332  rpl_reset_dio_timer(instance);
333  return 1;
334 }
335 /*---------------------------------------------------------------------------*/
336 static void
337 set_ip_from_prefix(uip_ipaddr_t *ipaddr, rpl_prefix_t *prefix)
338 {
339  memset(ipaddr, 0, sizeof(uip_ipaddr_t));
340  memcpy(ipaddr, &prefix->prefix, (prefix->length + 7) / 8);
342 }
343 /*---------------------------------------------------------------------------*/
344 static void
345 check_prefix(rpl_prefix_t *last_prefix, rpl_prefix_t *new_prefix)
346 {
347  uip_ipaddr_t ipaddr;
348  uip_ds6_addr_t *rep;
349 
350  if(last_prefix != NULL && new_prefix != NULL &&
351  last_prefix->length == new_prefix->length &&
352  uip_ipaddr_prefixcmp(&last_prefix->prefix, &new_prefix->prefix, new_prefix->length) &&
353  last_prefix->flags == new_prefix->flags) {
354  /* Nothing has changed. */
355  return;
356  }
357 
358  if(last_prefix != NULL) {
359  set_ip_from_prefix(&ipaddr, last_prefix);
360  rep = uip_ds6_addr_lookup(&ipaddr);
361  if(rep != NULL) {
362  PRINTF("RPL: removing global IP address ");
363  PRINT6ADDR(&ipaddr);
364  PRINTF("\n");
365  uip_ds6_addr_rm(rep);
366  }
367  }
368 
369  if(new_prefix != NULL) {
370  set_ip_from_prefix(&ipaddr, new_prefix);
371  if(uip_ds6_addr_lookup(&ipaddr) == NULL) {
372  PRINTF("RPL: adding global IP address ");
373  PRINT6ADDR(&ipaddr);
374  PRINTF("\n");
375  uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
376  }
377  }
378 }
379 /*---------------------------------------------------------------------------*/
380 int
381 rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len)
382 {
383  rpl_prefix_t last_prefix;
384  uint8_t last_len = dag->prefix_info.length;
385 
386  if(len > 128) {
387  return 0;
388  }
389  if(dag->prefix_info.length != 0) {
390  memcpy(&last_prefix, &dag->prefix_info, sizeof(rpl_prefix_t));
391  }
392  memset(&dag->prefix_info.prefix, 0, sizeof(dag->prefix_info.prefix));
393  memcpy(&dag->prefix_info.prefix, prefix, (len + 7) / 8);
394  dag->prefix_info.length = len;
395  dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS;
396  PRINTF("RPL: Prefix set - will announce this in DIOs\n");
397  /* Autoconfigure an address if this node does not already have an address
398  with this prefix. Otherwise, update the prefix */
399  if(last_len == 0) {
400  PRINTF("rpl_set_prefix - prefix NULL\n");
401  check_prefix(NULL, &dag->prefix_info);
402  } else {
403  PRINTF("rpl_set_prefix - prefix NON-NULL\n");
404  check_prefix(&last_prefix, &dag->prefix_info);
405  }
406  return 1;
407 }
408 /*---------------------------------------------------------------------------*/
409 int
410 rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from)
411 {
412  if(instance->def_route != NULL) {
413  PRINTF("RPL: Removing default route through ");
414  PRINT6ADDR(&instance->def_route->ipaddr);
415  PRINTF("\n");
416  uip_ds6_defrt_rm(instance->def_route);
417  instance->def_route = NULL;
418  }
419 
420  if(from != NULL) {
421  PRINTF("RPL: Adding default route through ");
422  PRINT6ADDR(from);
423  PRINTF("\n");
424  instance->def_route = uip_ds6_defrt_add(from,
425  RPL_LIFETIME(instance,
426  instance->default_lifetime));
427  if(instance->def_route == NULL) {
428  return 0;
429  }
430  } else {
431  PRINTF("RPL: Removing default route\n");
432  if(instance->def_route != NULL) {
433  uip_ds6_defrt_rm(instance->def_route);
434  } else {
435  PRINTF("RPL: Not actually removing default route, since instance had no default route\n");
436  }
437  }
438  return 1;
439 }
440 /*---------------------------------------------------------------------------*/
442 rpl_alloc_instance(uint8_t instance_id)
443 {
444  rpl_instance_t *instance, *end;
445 
446  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
447  instance < end; ++instance) {
448  if(instance->used == 0) {
449  memset(instance, 0, sizeof(*instance));
450  instance->instance_id = instance_id;
451  instance->def_route = NULL;
452  instance->used = 1;
453  return instance;
454  }
455  }
456  return NULL;
457 }
458 /*---------------------------------------------------------------------------*/
459 rpl_dag_t *
460 rpl_alloc_dag(uint8_t instance_id, uip_ipaddr_t *dag_id)
461 {
462  rpl_dag_t *dag, *end;
463  rpl_instance_t *instance;
464 
465  instance = rpl_get_instance(instance_id);
466  if(instance == NULL) {
467  instance = rpl_alloc_instance(instance_id);
468  if(instance == NULL) {
469  RPL_STAT(rpl_stats.mem_overflows++);
470  return NULL;
471  }
472  }
473 
474  for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
475  if(!dag->used) {
476  memset(dag, 0, sizeof(*dag));
477  dag->used = 1;
478  dag->rank = INFINITE_RANK;
479  dag->min_rank = INFINITE_RANK;
480  dag->instance = instance;
481  return dag;
482  }
483  }
484 
485  RPL_STAT(rpl_stats.mem_overflows++);
486  rpl_free_instance(instance);
487  return NULL;
488 }
489 /*---------------------------------------------------------------------------*/
490 void
491 rpl_set_default_instance(rpl_instance_t *instance)
492 {
493  default_instance = instance;
494 }
495 /*---------------------------------------------------------------------------*/
496 void
497 rpl_free_instance(rpl_instance_t *instance)
498 {
499  rpl_dag_t *dag;
500  rpl_dag_t *end;
501 
502  PRINTF("RPL: Leaving the instance %u\n", instance->instance_id);
503 
504  /* Remove any DAG inside this instance */
505  for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
506  if(dag->used) {
507  rpl_free_dag(dag);
508  }
509  }
510 
511  rpl_set_default_route(instance, NULL);
512 
513  ctimer_stop(&instance->dio_timer);
514  ctimer_stop(&instance->dao_timer);
515 
516  if(default_instance == instance) {
517  default_instance = NULL;
518  }
519 
520  instance->used = 0;
521 }
522 /*---------------------------------------------------------------------------*/
523 void
524 rpl_free_dag(rpl_dag_t *dag)
525 {
526  if(dag->joined) {
527  PRINTF("RPL: Leaving the DAG ");
528  PRINT6ADDR(&dag->dag_id);
529  PRINTF("\n");
530  dag->joined = 0;
531 
532  /* Remove routes installed by DAOs. */
533  rpl_remove_routes(dag);
534 
535  /* Remove autoconfigured address */
536  if((dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
537  check_prefix(&dag->prefix_info, NULL);
538  }
539 
540  remove_parents(dag, 0);
541  }
542  dag->used = 0;
543 }
544 /*---------------------------------------------------------------------------*/
545 rpl_parent_t *
546 rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
547 {
548  rpl_parent_t *p = NULL;
549  /* Is the parent known by ds6? Drop this request if not.
550  * Typically, the parent is added upon receiving a DIO. */
551  const uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr);
552 
553  PRINTF("RPL: rpl_add_parent lladdr %p ", lladdr);
554  PRINT6ADDR(addr);
555  PRINTF("\n");
556  if(lladdr != NULL) {
557  /* Add parent in rpl_parents */
558  p = nbr_table_add_lladdr(rpl_parents, (linkaddr_t *)lladdr);
559  if(p == NULL) {
560  PRINTF("RPL: rpl_add_parent p NULL\n");
561  } else {
562  p->dag = dag;
563  p->rank = dio->rank;
564  p->dtsn = dio->dtsn;
565  p->link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
566 #if RPL_DAG_MC != RPL_DAG_MC_NONE
567  memcpy(&p->mc, &dio->mc, sizeof(p->mc));
568 #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
569  }
570  }
571 
572  return p;
573 }
574 /*---------------------------------------------------------------------------*/
575 static rpl_parent_t *
576 find_parent_any_dag_any_instance(uip_ipaddr_t *addr)
577 {
578  uip_ds6_nbr_t *ds6_nbr = uip_ds6_nbr_lookup(addr);
579  const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(ds6_nbr);
580  return nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)lladdr);
581 }
582 /*---------------------------------------------------------------------------*/
583 rpl_parent_t *
584 rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr)
585 {
586  rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
587  if(p != NULL && p->dag == dag) {
588  return p;
589  } else {
590  return NULL;
591  }
592 }
593 /*---------------------------------------------------------------------------*/
594 static rpl_dag_t *
595 find_parent_dag(rpl_instance_t *instance, uip_ipaddr_t *addr)
596 {
597  rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
598  if(p != NULL) {
599  return p->dag;
600  } else {
601  return NULL;
602  }
603 }
604 /*---------------------------------------------------------------------------*/
605 rpl_parent_t *
606 rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr)
607 {
608  rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
609  if(p && p->dag && p->dag->instance == instance) {
610  return p;
611  } else {
612  return NULL;
613  }
614 }
615 /*---------------------------------------------------------------------------*/
616 rpl_dag_t *
617 rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
618 {
619  rpl_parent_t *last_parent;
620  rpl_dag_t *dag, *end, *best_dag;
621  rpl_rank_t old_rank;
622 
623  old_rank = instance->current_dag->rank;
624  last_parent = instance->current_dag->preferred_parent;
625 
626  best_dag = instance->current_dag;
627  if(best_dag->rank != ROOT_RANK(instance)) {
628  if(rpl_select_parent(p->dag) != NULL) {
629  if(p->dag != best_dag) {
630  best_dag = instance->of->best_dag(best_dag, p->dag);
631  }
632  } else if(p->dag == best_dag) {
633  best_dag = NULL;
634  for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
635  if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != INFINITE_RANK) {
636  if(best_dag == NULL) {
637  best_dag = dag;
638  } else {
639  best_dag = instance->of->best_dag(best_dag, dag);
640  }
641  }
642  }
643  }
644  }
645 
646  if(best_dag == NULL) {
647  /* No parent found: the calling function handle this problem. */
648  return NULL;
649  }
650 
651  if(instance->current_dag != best_dag) {
652  /* Remove routes installed by DAOs. */
653  rpl_remove_routes(instance->current_dag);
654 
655  PRINTF("RPL: New preferred DAG: ");
656  PRINT6ADDR(&best_dag->dag_id);
657  PRINTF("\n");
658 
659  if(best_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
660  check_prefix(&instance->current_dag->prefix_info, &best_dag->prefix_info);
661  } else if(instance->current_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
662  check_prefix(&instance->current_dag->prefix_info, NULL);
663  }
664 
665  best_dag->joined = 1;
666  instance->current_dag->joined = 0;
667  instance->current_dag = best_dag;
668  }
669 
670  instance->of->update_metric_container(instance);
671  /* Update the DAG rank. */
672  best_dag->rank = instance->of->calculate_rank(best_dag->preferred_parent, 0);
673  if(last_parent == NULL || best_dag->rank < best_dag->min_rank) {
674  best_dag->min_rank = best_dag->rank;
675  } else if(!acceptable_rank(best_dag, best_dag->rank)) {
676  PRINTF("RPL: New rank unacceptable!\n");
677  rpl_set_preferred_parent(instance->current_dag, NULL);
678  if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) {
679  /* Send a No-Path DAO to the removed preferred parent. */
680  dao_output(last_parent, RPL_ZERO_LIFETIME);
681  }
682  return NULL;
683  }
684 
685  if(best_dag->preferred_parent != last_parent) {
686  rpl_set_default_route(instance, rpl_get_parent_ipaddr(best_dag->preferred_parent));
687  PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n",
688  (unsigned)old_rank, best_dag->rank);
689  RPL_STAT(rpl_stats.parent_switch++);
690  if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
691  if(last_parent != NULL) {
692  /* Send a No-Path DAO to the removed preferred parent. */
693  dao_output(last_parent, RPL_ZERO_LIFETIME);
694  }
695  /* The DAO parent set changed - schedule a DAO transmission. */
696  RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
697  rpl_schedule_dao(instance);
698  }
699  rpl_reset_dio_timer(instance);
700  } else if(best_dag->rank != old_rank) {
701  PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n",
702  (unsigned)old_rank, best_dag->rank);
703  }
704  return best_dag;
705 }
706 /*---------------------------------------------------------------------------*/
707 static rpl_parent_t *
708 best_parent(rpl_dag_t *dag)
709 {
710  rpl_parent_t *p, *best;
711 
712  best = NULL;
713 
714  p = nbr_table_head(rpl_parents);
715  while(p != NULL) {
716  if(p->rank == INFINITE_RANK) {
717  /* ignore this neighbor */
718  } else if(best == NULL) {
719  best = p;
720  } else {
721  best = dag->instance->of->best_parent(best, p);
722  }
723  p = nbr_table_next(rpl_parents, p);
724  }
725 
726  return best;
727 }
728 /*---------------------------------------------------------------------------*/
729 rpl_parent_t *
730 rpl_select_parent(rpl_dag_t *dag)
731 {
732  rpl_parent_t *best = best_parent(dag);
733 
734  if(best != NULL) {
735  rpl_set_preferred_parent(dag, best);
736  }
737 
738  return best;
739 }
740 /*---------------------------------------------------------------------------*/
741 void
742 rpl_remove_parent(rpl_parent_t *parent)
743 {
744  PRINTF("RPL: Removing parent ");
745  PRINT6ADDR(rpl_get_parent_ipaddr(parent));
746  PRINTF("\n");
747 
748  rpl_nullify_parent(parent);
749 
750  nbr_table_remove(rpl_parents, parent);
751 }
752 /*---------------------------------------------------------------------------*/
753 void
754 rpl_nullify_parent(rpl_parent_t *parent)
755 {
756  rpl_dag_t *dag = parent->dag;
757  /* This function can be called when the preferred parent is NULL, so we
758  need to handle this condition in order to trigger uip_ds6_defrt_rm. */
759  if(parent == dag->preferred_parent || dag->preferred_parent == NULL) {
760  rpl_set_preferred_parent(dag, NULL);
761  dag->rank = INFINITE_RANK;
762  if(dag->joined) {
763  if(dag->instance->def_route != NULL) {
764  PRINTF("RPL: Removing default route ");
765  PRINT6ADDR(rpl_get_parent_ipaddr(parent));
766  PRINTF("\n");
767  uip_ds6_defrt_rm(dag->instance->def_route);
768  dag->instance->def_route = NULL;
769  }
770  dao_output(parent, RPL_ZERO_LIFETIME);
771  }
772  }
773 
774  PRINTF("RPL: Nullifying parent ");
775  PRINT6ADDR(rpl_get_parent_ipaddr(parent));
776  PRINTF("\n");
777 }
778 /*---------------------------------------------------------------------------*/
779 void
780 rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
781 {
782  if(parent == dag_src->preferred_parent) {
783  rpl_set_preferred_parent(dag_src, NULL);
784  dag_src->rank = INFINITE_RANK;
785  if(dag_src->joined && dag_src->instance->def_route != NULL) {
786  PRINTF("RPL: Removing default route ");
787  PRINT6ADDR(rpl_get_parent_ipaddr(parent));
788  PRINTF("\n");
789  PRINTF("rpl_move_parent\n");
790  uip_ds6_defrt_rm(dag_src->instance->def_route);
791  dag_src->instance->def_route = NULL;
792  }
793  } else if(dag_src->joined) {
794  /* Remove uIPv6 routes that have this parent as the next hop. */
795  rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(parent), dag_src);
796  }
797 
798  PRINTF("RPL: Moving parent ");
799  PRINT6ADDR(rpl_get_parent_ipaddr(parent));
800  PRINTF("\n");
801 
802  parent->dag = dag_dst;
803 }
804 /*---------------------------------------------------------------------------*/
805 rpl_dag_t *
806 rpl_get_any_dag(void)
807 {
808  int i;
809 
810  for(i = 0; i < RPL_MAX_INSTANCES; ++i) {
811  if(instance_table[i].used && instance_table[i].current_dag->joined) {
812  return instance_table[i].current_dag;
813  }
814  }
815  return NULL;
816 }
817 /*---------------------------------------------------------------------------*/
819 rpl_get_instance(uint8_t instance_id)
820 {
821  int i;
822 
823  for(i = 0; i < RPL_MAX_INSTANCES; ++i) {
824  if(instance_table[i].used && instance_table[i].instance_id == instance_id) {
825  return &instance_table[i];
826  }
827  }
828  return NULL;
829 }
830 /*---------------------------------------------------------------------------*/
831 rpl_of_t *
832 rpl_find_of(rpl_ocp_t ocp)
833 {
834  unsigned int i;
835 
836  for(i = 0;
837  i < sizeof(objective_functions) / sizeof(objective_functions[0]);
838  i++) {
839  if(objective_functions[i]->ocp == ocp) {
840  return objective_functions[i];
841  }
842  }
843 
844  return NULL;
845 }
846 /*---------------------------------------------------------------------------*/
847 void
848 rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
849 {
850  rpl_instance_t *instance;
851  rpl_dag_t *dag;
852  rpl_parent_t *p;
853  rpl_of_t *of;
854 
855  dag = rpl_alloc_dag(dio->instance_id, &dio->dag_id);
856  if(dag == NULL) {
857  PRINTF("RPL: Failed to allocate a DAG object!\n");
858  return;
859  }
860 
861  instance = dag->instance;
862 
863  p = rpl_add_parent(dag, dio, from);
864  PRINTF("RPL: Adding ");
865  PRINT6ADDR(from);
866  PRINTF(" as a parent: ");
867  if(p == NULL) {
868  PRINTF("failed\n");
869  instance->used = 0;
870  return;
871  }
872  p->dtsn = dio->dtsn;
873  PRINTF("succeeded\n");
874 
875  /* Determine the objective function by using the
876  objective code point of the DIO. */
877  of = rpl_find_of(dio->ocp);
878  if(of == NULL) {
879  PRINTF("RPL: DIO for DAG instance %u does not specify a supported OF\n",
880  dio->instance_id);
881  rpl_remove_parent(p);
882  instance->used = 0;
883  return;
884  }
885 
886  /* Autoconfigure an address if this node does not already have an address
887  with this prefix. */
888  if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
889  check_prefix(NULL, &dio->prefix_info);
890  }
891 
892  dag->joined = 1;
893  dag->preference = dio->preference;
894  dag->grounded = dio->grounded;
895  dag->version = dio->version;
896 
897  instance->of = of;
898  instance->mop = dio->mop;
899  instance->current_dag = dag;
900  instance->dtsn_out = RPL_LOLLIPOP_INIT;
901 
902  instance->max_rankinc = dio->dag_max_rankinc;
903  instance->min_hoprankinc = dio->dag_min_hoprankinc;
904  instance->dio_intdoubl = dio->dag_intdoubl;
905  instance->dio_intmin = dio->dag_intmin;
906  instance->dio_intcurrent = instance->dio_intmin + instance->dio_intdoubl;
907  instance->dio_redundancy = dio->dag_redund;
908  instance->default_lifetime = dio->default_lifetime;
909  instance->lifetime_unit = dio->lifetime_unit;
910 
911  memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id));
912 
913  /* Copy prefix information from the DIO into the DAG object. */
914  memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t));
915 
916  rpl_set_preferred_parent(dag, p);
917  instance->of->update_metric_container(instance);
918  dag->rank = instance->of->calculate_rank(p, 0);
919  /* So far this is the lowest rank we are aware of. */
920  dag->min_rank = dag->rank;
921 
922  if(default_instance == NULL) {
923  default_instance = instance;
924  }
925 
926  PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
927  dio->instance_id, dag->rank);
928  PRINT6ADDR(&dag->dag_id);
929  PRINTF("\n");
930 
931  ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
932 
933  rpl_reset_dio_timer(instance);
934  rpl_set_default_route(instance, from);
935 
936  if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
937  rpl_schedule_dao(instance);
938  } else {
939  PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n");
940  }
941 }
942 
943 /*---------------------------------------------------------------------------*/
944 void
945 rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
946 {
947  rpl_instance_t *instance;
948  rpl_dag_t *dag, *previous_dag;
949  rpl_parent_t *p;
950  rpl_of_t *of;
951 
952  dag = rpl_alloc_dag(dio->instance_id, &dio->dag_id);
953  if(dag == NULL) {
954  PRINTF("RPL: Failed to allocate a DAG object!\n");
955  return;
956  }
957 
958  instance = dag->instance;
959 
960  previous_dag = find_parent_dag(instance, from);
961  if(previous_dag == NULL) {
962  PRINTF("RPL: Adding ");
963  PRINT6ADDR(from);
964  PRINTF(" as a parent: ");
965  p = rpl_add_parent(dag, dio, from);
966  if(p == NULL) {
967  PRINTF("failed\n");
968  dag->used = 0;
969  return;
970  }
971  PRINTF("succeeded\n");
972  } else {
973  p = rpl_find_parent(previous_dag, from);
974  if(p != NULL) {
975  rpl_move_parent(previous_dag, dag, p);
976  }
977  }
978 
979  /* Determine the objective function by using the
980  objective code point of the DIO. */
981  of = rpl_find_of(dio->ocp);
982  if(of != instance->of ||
983  instance->mop != dio->mop ||
984  instance->max_rankinc != dio->dag_max_rankinc ||
985  instance->min_hoprankinc != dio->dag_min_hoprankinc ||
986  instance->dio_intdoubl != dio->dag_intdoubl ||
987  instance->dio_intmin != dio->dag_intmin ||
988  instance->dio_redundancy != dio->dag_redund ||
989  instance->default_lifetime != dio->default_lifetime ||
990  instance->lifetime_unit != dio->lifetime_unit) {
991  PRINTF("RPL: DIO for DAG instance %u incompatible with previous DIO\n",
992  dio->instance_id);
993  rpl_remove_parent(p);
994  dag->used = 0;
995  return;
996  }
997 
998  dag->used = 1;
999  dag->grounded = dio->grounded;
1000  dag->preference = dio->preference;
1001  dag->version = dio->version;
1002 
1003  memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id));
1004 
1005  /* copy prefix information into the dag */
1006  memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t));
1007 
1008  rpl_set_preferred_parent(dag, p);
1009  dag->rank = instance->of->calculate_rank(p, 0);
1010  dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */
1011 
1012  PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
1013  dio->instance_id, dag->rank);
1014  PRINT6ADDR(&dag->dag_id);
1015  PRINTF("\n");
1016 
1017  ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
1018 
1019  rpl_process_parent_event(instance, p);
1020  p->dtsn = dio->dtsn;
1021 }
1022 
1023 /*---------------------------------------------------------------------------*/
1024 static void
1025 global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio)
1026 {
1027  rpl_parent_t *p;
1028 
1029  remove_parents(dag, 0);
1030  dag->version = dio->version;
1031  dag->instance->of->reset(dag);
1032  dag->min_rank = INFINITE_RANK;
1033  RPL_LOLLIPOP_INCREMENT(dag->instance->dtsn_out);
1034 
1035  p = rpl_add_parent(dag, dio, from);
1036  if(p == NULL) {
1037  PRINTF("RPL: Failed to add a parent during the global repair\n");
1038  dag->rank = INFINITE_RANK;
1039  } else {
1040  dag->rank = dag->instance->of->calculate_rank(p, 0);
1041  dag->min_rank = dag->rank;
1042  PRINTF("RPL: rpl_process_parent_event global repair\n");
1043  rpl_process_parent_event(dag->instance, p);
1044  }
1045 
1046  PRINTF("RPL: Participating in a global repair (version=%u, rank=%hu)\n",
1047  dag->version, dag->rank);
1048 
1049  RPL_STAT(rpl_stats.global_repairs++);
1050 }
1051 /*---------------------------------------------------------------------------*/
1052 void
1053 rpl_local_repair(rpl_instance_t *instance)
1054 {
1055  int i;
1056 
1057  if(instance == NULL) {
1058  PRINTF("RPL: local repair requested for instance NULL\n");
1059  return;
1060  }
1061  PRINTF("RPL: Starting a local instance repair\n");
1062  for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; i++) {
1063  if(instance->dag_table[i].used) {
1064  instance->dag_table[i].rank = INFINITE_RANK;
1065  nullify_parents(&instance->dag_table[i], 0);
1066  }
1067  }
1068 
1069  rpl_reset_dio_timer(instance);
1070 
1071  RPL_STAT(rpl_stats.local_repairs++);
1072 }
1073 /*---------------------------------------------------------------------------*/
1074 void
1075 rpl_recalculate_ranks(void)
1076 {
1077  rpl_parent_t *p;
1078 
1079  /*
1080  * We recalculate ranks when we receive feedback from the system rather
1081  * than RPL protocol messages. This periodical recalculation is called
1082  * from a timer in order to keep the stack depth reasonably low.
1083  */
1084  p = nbr_table_head(rpl_parents);
1085  while(p != NULL) {
1086  if(p->dag != NULL && p->dag->instance && p->updated) {
1087  p->updated = 0;
1088  PRINTF("RPL: rpl_process_parent_event recalculate_ranks\n");
1089  if(!rpl_process_parent_event(p->dag->instance, p)) {
1090  PRINTF("RPL: A parent was dropped\n");
1091  }
1092  }
1093  p = nbr_table_next(rpl_parents, p);
1094  }
1095 }
1096 /*---------------------------------------------------------------------------*/
1097 int
1098 rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
1099 {
1100  int return_value;
1101 
1102 #if DEBUG
1103  rpl_rank_t old_rank;
1104  old_rank = instance->current_dag->rank;
1105 #endif /* DEBUG */
1106 
1107  return_value = 1;
1108 
1109  if(!acceptable_rank(p->dag, p->rank)) {
1110  /* The candidate parent is no longer valid: the rank increase resulting
1111  from the choice of it as a parent would be too high. */
1112  PRINTF("RPL: Unacceptable rank %u\n", (unsigned)p->rank);
1113  rpl_nullify_parent(p);
1114  if(p != instance->current_dag->preferred_parent) {
1115  return 0;
1116  } else {
1117  return_value = 0;
1118  }
1119  }
1120 
1121  if(rpl_select_dag(instance, p) == NULL) {
1122  /* No suitable parent; trigger a local repair. */
1123  PRINTF("RPL: No parents found in any DAG\n");
1124  rpl_local_repair(instance);
1125  return 0;
1126  }
1127 
1128 #if DEBUG
1129  if(DAG_RANK(old_rank, instance) != DAG_RANK(instance->current_dag->rank, instance)) {
1130  PRINTF("RPL: Moving in the instance from rank %hu to %hu\n",
1131  DAG_RANK(old_rank, instance), DAG_RANK(instance->current_dag->rank, instance));
1132  if(instance->current_dag->rank != INFINITE_RANK) {
1133  PRINTF("RPL: The preferred parent is ");
1134  PRINT6ADDR(rpl_get_parent_ipaddr(instance->current_dag->preferred_parent));
1135  PRINTF(" (rank %u)\n",
1136  (unsigned)DAG_RANK(instance->current_dag->preferred_parent->rank, instance));
1137  } else {
1138  PRINTF("RPL: We don't have any parent");
1139  }
1140  }
1141 #endif /* DEBUG */
1142 
1143  return return_value;
1144 }
1145 /*---------------------------------------------------------------------------*/
1146 void
1147 rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
1148 {
1149  rpl_instance_t *instance;
1150  rpl_dag_t *dag, *previous_dag;
1151  rpl_parent_t *p;
1152 
1153 #if RPL_CONF_MULTICAST
1154  /* If the root is advertising MOP 2 but we support MOP 3 we can still join
1155  * In that scenario, we suppress DAOs for multicast targets */
1156  if(dio->mop < RPL_MOP_STORING_NO_MULTICAST) {
1157 #else
1158  if(dio->mop != RPL_MOP_DEFAULT) {
1159 #endif
1160  PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop);
1161  return;
1162  }
1163 
1164  dag = get_dag(dio->instance_id, &dio->dag_id);
1165  instance = rpl_get_instance(dio->instance_id);
1166 
1167  if(dag != NULL && instance != NULL) {
1168  if(lollipop_greater_than(dio->version, dag->version)) {
1169  if(dag->rank == ROOT_RANK(instance)) {
1170  PRINTF("RPL: Root received inconsistent DIO version number\n");
1171  dag->version = dio->version;
1172  RPL_LOLLIPOP_INCREMENT(dag->version);
1173  rpl_reset_dio_timer(instance);
1174  } else {
1175  PRINTF("RPL: Global repair\n");
1176  if(dio->prefix_info.length != 0) {
1177  if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
1178  PRINTF("RPL : Prefix announced in DIO\n");
1179  rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length);
1180  }
1181  }
1182  global_repair(from, dag, dio);
1183  }
1184  return;
1185  }
1186 
1187  if(lollipop_greater_than(dag->version, dio->version)) {
1188  /* The DIO sender is on an older version of the DAG. */
1189  PRINTF("RPL: old version received => inconsistency detected\n");
1190  if(dag->joined) {
1191  rpl_reset_dio_timer(instance);
1192  return;
1193  }
1194  }
1195  }
1196 
1197  if(instance == NULL) {
1198  PRINTF("RPL: New instance detected: Joining...\n");
1199  rpl_join_instance(from, dio);
1200  return;
1201  }
1202 
1203  if(instance->current_dag->rank == ROOT_RANK(instance) && instance->current_dag != dag) {
1204  PRINTF("RPL: Root ignored DIO for different DAG\n");
1205  return;
1206  }
1207 
1208  if(dag == NULL) {
1209  PRINTF("RPL: Adding new DAG to known instance.\n");
1210  rpl_add_dag(from, dio);
1211  return;
1212  }
1213 
1214 
1215  if(dio->rank < ROOT_RANK(instance)) {
1216  PRINTF("RPL: Ignoring DIO with too low rank: %u\n",
1217  (unsigned)dio->rank);
1218  return;
1219  } else if(dio->rank == INFINITE_RANK && dag->joined) {
1220  rpl_reset_dio_timer(instance);
1221  }
1222 
1223  /* Prefix Information Option treated to add new prefix */
1224  if(dio->prefix_info.length != 0) {
1225  if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
1226  PRINTF("RPL : Prefix announced in DIO\n");
1227  rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length);
1228  }
1229  }
1230 
1231  if(dag->rank == ROOT_RANK(instance)) {
1232  if(dio->rank != INFINITE_RANK) {
1233  instance->dio_counter++;
1234  }
1235  return;
1236  }
1237 
1238  /*
1239  * At this point, we know that this DIO pertains to a DAG that
1240  * we are already part of. We consider the sender of the DIO to be
1241  * a candidate parent, and let rpl_process_parent_event decide
1242  * whether to keep it in the set.
1243  */
1244 
1245  p = rpl_find_parent(dag, from);
1246  if(p == NULL) {
1247  previous_dag = find_parent_dag(instance, from);
1248  if(previous_dag == NULL) {
1249  /* Add the DIO sender as a candidate parent. */
1250  p = rpl_add_parent(dag, dio, from);
1251  if(p == NULL) {
1252  PRINTF("RPL: Failed to add a new parent (");
1253  PRINT6ADDR(from);
1254  PRINTF(")\n");
1255  return;
1256  }
1257  PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank);
1258  PRINT6ADDR(from);
1259  PRINTF("\n");
1260  } else {
1261  p = rpl_find_parent(previous_dag, from);
1262  if(p != NULL) {
1263  rpl_move_parent(previous_dag, dag, p);
1264  }
1265  }
1266  } else {
1267  if(p->rank == dio->rank) {
1268  PRINTF("RPL: Received consistent DIO\n");
1269  if(dag->joined) {
1270  instance->dio_counter++;
1271  }
1272  } else {
1273  p->rank=dio->rank;
1274  }
1275  }
1276 
1277  PRINTF("RPL: preferred DAG ");
1278  PRINT6ADDR(&instance->current_dag->dag_id);
1279  PRINTF(", rank %u, min_rank %u, ",
1280  instance->current_dag->rank, instance->current_dag->min_rank);
1281  PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n",
1282  p->rank, -1/*p->mc.obj.etx*/, p->link_metric, instance->mc.obj.etx);
1283 
1284  /* We have allocated a candidate parent; process the DIO further. */
1285 
1286 #if RPL_DAG_MC != RPL_DAG_MC_NONE
1287  memcpy(&p->mc, &dio->mc, sizeof(p->mc));
1288 #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
1289  if(rpl_process_parent_event(instance, p) == 0) {
1290  PRINTF("RPL: The candidate parent is rejected\n");
1291  return;
1292  }
1293 
1294  /* We don't use route control, so we can have only one official parent. */
1295  if(dag->joined && p == dag->preferred_parent) {
1296  if(should_send_dao(instance, dio, p)) {
1297  RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
1298  rpl_schedule_dao(instance);
1299  }
1300  /* We received a new DIO from our preferred parent.
1301  * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */
1302  uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime));
1303  }
1304  p->dtsn = dio->dtsn;
1305 }
1306 /*---------------------------------------------------------------------------*/
1307 void
1308 rpl_lock_parent(rpl_parent_t *p)
1309 {
1310  nbr_table_lock(rpl_parents, p);
1311 }
1312 /*---------------------------------------------------------------------------*/
1313 #endif /* UIP_CONF_IPV6 */