47 #include "net/link-stats.h"
48 #include "net/rpl/rpl-private.h"
52 #include "net/nbr-table.h"
61 #define DEBUG DEBUG_NONE
65 #ifdef RPL_CALLBACK_PARENT_SWITCH
66 void RPL_CALLBACK_PARENT_SWITCH(rpl_parent_t *old, rpl_parent_t *
new);
70 extern rpl_of_t rpl_of0, rpl_mrhof;
71 static rpl_of_t *
const objective_functions[] = RPL_SUPPORTED_OFS;
76 #ifndef RPL_CONF_GROUNDED
77 #define RPL_GROUNDED 0
79 #define RPL_GROUNDED RPL_CONF_GROUNDED
84 NBR_TABLE_GLOBAL(rpl_parent_t, rpl_parents);
87 rpl_instance_t instance_table[RPL_MAX_INSTANCES];
88 rpl_instance_t *default_instance;
92 rpl_print_neighbor_list(
void)
94 if(default_instance !=
NULL && default_instance->current_dag !=
NULL &&
95 default_instance->of !=
NULL) {
96 int curr_dio_interval = default_instance->dio_intcurrent;
97 int curr_rank = default_instance->current_dag->rank;
98 rpl_parent_t *p = nbr_table_head(rpl_parents);
101 printf(
"RPL: MOP %u OCP %u rank %u dioint %u, nbr count %u\n",
102 default_instance->mop, default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num());
104 const struct link_stats *stats = rpl_get_parent_link_stats(p);
105 printf(
"RPL: nbr %3u %5u, %5u => %5u -- %2u %c%c (last tx %u min ago)\n",
106 rpl_get_parent_ipaddr(p)->u8[15],
108 rpl_get_parent_link_metric(p),
109 rpl_rank_via_parent(p),
110 stats !=
NULL ? stats->freshness : 0,
111 link_stats_is_fresh(stats) ?
'f' :
' ',
112 p == default_instance->current_dag->preferred_parent ?
'p' :
' ',
113 (
unsigned)((clock_now - stats->last_tx_time) / (60 *
CLOCK_SECOND))
115 p = nbr_table_next(rpl_parents, p);
117 printf(
"RPL: end of list\n");
122 rpl_get_nbr(rpl_parent_t *parent)
124 const linkaddr_t *lladdr = rpl_get_parent_lladdr(parent);
126 return nbr_table_get_from_lladdr(ds6_neighbors, lladdr);
133 nbr_callback(
void *ptr)
135 rpl_remove_parent(ptr);
141 nbr_table_register(rpl_parents, (nbr_table_callback *)nbr_callback);
147 rpl_parent_t *p = nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)addr);
154 rpl_parent_t *p = nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)addr);
158 return INFINITE_RANK;
163 rpl_get_parent_link_metric(rpl_parent_t *p)
166 rpl_instance_t *instance = p->dag->instance;
167 if(instance !=
NULL && instance->of !=
NULL && instance->of->parent_link_metric !=
NULL) {
168 return instance->of->parent_link_metric(p);
175 rpl_rank_via_parent(rpl_parent_t *p)
178 rpl_instance_t *instance = p->dag->instance;
179 if(instance !=
NULL && instance->of !=
NULL && instance->of->rank_via_parent !=
NULL) {
180 return instance->of->rank_via_parent(p);
183 return INFINITE_RANK;
187 rpl_get_parent_lladdr(rpl_parent_t *p)
189 return nbr_table_get_lladdr(rpl_parents, p);
193 rpl_get_parent_ipaddr(rpl_parent_t *p)
195 const linkaddr_t *lladdr = rpl_get_parent_lladdr(p);
196 return uip_ds6_nbr_ipaddr_from_lladdr((
uip_lladdr_t *)lladdr);
199 const struct link_stats *
200 rpl_get_parent_link_stats(rpl_parent_t *p)
202 const linkaddr_t *lladdr = rpl_get_parent_lladdr(p);
203 return link_stats_from_lladdr(lladdr);
207 rpl_parent_is_fresh(rpl_parent_t *p)
209 const struct link_stats *stats = rpl_get_parent_link_stats(p);
210 return link_stats_is_fresh(stats);
214 rpl_parent_is_reachable(rpl_parent_t *p) {
215 if(p ==
NULL || p->dag ==
NULL || p->dag->instance ==
NULL || p->dag->instance->of ==
NULL) {
218 #ifndef UIP_CONF_ND6_SEND_NA
221 if(nbr ==
NULL || nbr->state != NBR_REACHABLE) {
226 return !rpl_parent_is_fresh(p) || p->dag->instance->of->parent_has_usable_link(p);
231 rpl_set_preferred_parent(rpl_dag_t *dag, rpl_parent_t *p)
233 if(dag !=
NULL && dag->preferred_parent != p) {
234 PRINTF(
"RPL: rpl_set_preferred_parent ");
236 PRINT6ADDR(rpl_get_parent_ipaddr(p));
240 PRINTF(
" used to be ");
241 if(dag->preferred_parent !=
NULL) {
242 PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
248 #ifdef RPL_CALLBACK_PARENT_SWITCH
249 RPL_CALLBACK_PARENT_SWITCH(dag->preferred_parent, p);
254 nbr_table_unlock(rpl_parents, dag->preferred_parent);
255 nbr_table_lock(rpl_parents, p);
256 dag->preferred_parent = p;
263 lollipop_greater_than(
int a,
int b)
266 if(a > RPL_LOLLIPOP_CIRCULAR_REGION && b <= RPL_LOLLIPOP_CIRCULAR_REGION) {
267 return (RPL_LOLLIPOP_MAX_VALUE + 1 + b - a) > RPL_LOLLIPOP_SEQUENCE_WINDOWS;
271 return (a > b && (a - b) < RPL_LOLLIPOP_SEQUENCE_WINDOWS) ||
272 (a < b && (b - a) > (RPL_LOLLIPOP_CIRCULAR_REGION + 1-
273 RPL_LOLLIPOP_SEQUENCE_WINDOWS));
278 remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
282 PRINTF(
"RPL: Removing parents (minimum rank %u)\n",
285 p = nbr_table_head(rpl_parents);
287 if(dag == p->dag && p->rank >= minimum_rank) {
288 rpl_remove_parent(p);
290 p = nbr_table_next(rpl_parents, p);
295 nullify_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
299 PRINTF(
"RPL: Nullifying parents (minimum rank %u)\n",
302 p = nbr_table_head(rpl_parents);
304 if(dag == p->dag && p->rank >= minimum_rank) {
305 rpl_nullify_parent(p);
307 p = nbr_table_next(rpl_parents, p);
312 should_send_dao(rpl_instance_t *instance, rpl_dio_t *dio, rpl_parent_t *p)
315 if(instance->mop == RPL_MOP_NO_DOWNWARD_ROUTES) {
319 return p == instance->current_dag->preferred_parent &&
320 (lollipop_greater_than(dio->dtsn, p->dtsn));
324 acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank)
326 return rank != INFINITE_RANK &&
327 ((dag->instance->max_rankinc == 0) ||
328 DAG_RANK(rank, dag->instance) <= DAG_RANK(dag->min_rank + dag->instance->max_rankinc, dag->instance));
332 get_dag(uint8_t instance_id, uip_ipaddr_t *dag_id)
334 rpl_instance_t *instance;
338 instance = rpl_get_instance(instance_id);
339 if(instance ==
NULL) {
343 for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) {
344 dag = &instance->dag_table[i];
345 if(dag->used && uip_ipaddr_cmp(&dag->dag_id, dag_id)) {
354 rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
357 rpl_instance_t *instance;
361 version = RPL_LOLLIPOP_INIT;
362 instance = rpl_get_instance(instance_id);
363 if(instance !=
NULL) {
364 for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) {
365 dag = &instance->dag_table[i];
367 if(uip_ipaddr_cmp(&dag->dag_id, dag_id)) {
368 version = dag->version;
369 RPL_LOLLIPOP_INCREMENT(version);
371 if(dag == dag->instance->current_dag) {
372 PRINTF(
"RPL: Dropping a joined DAG when setting this node as root");
373 dag->instance->current_dag =
NULL;
375 PRINTF(
"RPL: Dropping a DAG when setting this node as root");
382 dag = rpl_alloc_dag(instance_id, dag_id);
384 PRINTF(
"RPL: Failed to allocate a DAG\n");
388 instance = dag->instance;
390 dag->version = version;
392 dag->grounded = RPL_GROUNDED;
393 dag->preference = RPL_PREFERENCE;
394 instance->mop = RPL_MOP_DEFAULT;
395 instance->of = rpl_find_of(RPL_OF_OCP);
396 if(instance->of ==
NULL) {
397 PRINTF(
"RPL: OF with OCP %u not supported\n", RPL_OF_OCP);
401 rpl_set_preferred_parent(dag,
NULL);
403 memcpy(&dag->dag_id, dag_id,
sizeof(dag->dag_id));
405 instance->dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
406 instance->dio_intmin = RPL_DIO_INTERVAL_MIN;
409 instance->dio_intcurrent = RPL_DIO_INTERVAL_MIN +
410 RPL_DIO_INTERVAL_DOUBLINGS;
411 instance->dio_redundancy = RPL_DIO_REDUNDANCY;
412 instance->max_rankinc = RPL_MAX_RANKINC;
413 instance->min_hoprankinc = RPL_MIN_HOPRANKINC;
414 instance->default_lifetime = RPL_DEFAULT_LIFETIME;
415 instance->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
417 dag->rank = ROOT_RANK(instance);
419 if(instance->current_dag != dag && instance->current_dag !=
NULL) {
421 if(RPL_IS_STORING(instance)) {
422 rpl_remove_routes(instance->current_dag);
425 instance->current_dag->joined = 0;
428 instance->current_dag = dag;
429 instance->dtsn_out = RPL_LOLLIPOP_INIT;
430 instance->of->update_metric_container(instance);
431 default_instance = instance;
433 PRINTF(
"RPL: Node set to be a DAG root with DAG ID ");
434 PRINT6ADDR(&dag->dag_id);
437 ANNOTATE(
"#A root=%u\n", dag->dag_id.u8[
sizeof(dag->dag_id) - 1]);
439 rpl_reset_dio_timer(instance);
445 rpl_repair_root(uint8_t instance_id)
447 rpl_instance_t *instance;
449 instance = rpl_get_instance(instance_id);
450 if(instance ==
NULL ||
451 instance->current_dag->rank != ROOT_RANK(instance)) {
452 PRINTF(
"RPL: rpl_repair_root triggered but not root\n");
455 RPL_STAT(rpl_stats.root_repairs++);
457 RPL_LOLLIPOP_INCREMENT(instance->current_dag->version);
458 RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
459 PRINTF(
"RPL: rpl_repair_root initiating global repair with version %d\n", instance->current_dag->version);
460 rpl_reset_dio_timer(instance);
465 set_ip_from_prefix(uip_ipaddr_t *
ipaddr, rpl_prefix_t *prefix)
467 memset(ipaddr, 0,
sizeof(uip_ipaddr_t));
468 memcpy(ipaddr, &prefix->prefix, (prefix->length + 7) / 8);
473 check_prefix(rpl_prefix_t *last_prefix, rpl_prefix_t *new_prefix)
478 if(last_prefix !=
NULL && new_prefix !=
NULL &&
479 last_prefix->length == new_prefix->length &&
480 uip_ipaddr_prefixcmp(&last_prefix->prefix, &new_prefix->prefix, new_prefix->length) &&
481 last_prefix->flags == new_prefix->flags) {
486 if(last_prefix !=
NULL) {
487 set_ip_from_prefix(&ipaddr, last_prefix);
488 rep = uip_ds6_addr_lookup(&ipaddr);
490 PRINTF(
"RPL: removing global IP address ");
493 uip_ds6_addr_rm(rep);
497 if(new_prefix !=
NULL) {
498 set_ip_from_prefix(&ipaddr, new_prefix);
499 if(uip_ds6_addr_lookup(&ipaddr) ==
NULL) {
500 PRINTF(
"RPL: adding global IP address ");
509 rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix,
unsigned len)
511 rpl_prefix_t last_prefix;
512 uint8_t last_len = dag->prefix_info.length;
517 if(dag->prefix_info.length != 0) {
518 memcpy(&last_prefix, &dag->prefix_info,
sizeof(rpl_prefix_t));
520 memset(&dag->prefix_info.prefix, 0,
sizeof(dag->prefix_info.prefix));
521 memcpy(&dag->prefix_info.prefix, prefix, (len + 7) / 8);
522 dag->prefix_info.length = len;
523 dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS;
524 PRINTF(
"RPL: Prefix set - will announce this in DIOs\n");
528 PRINTF(
"rpl_set_prefix - prefix NULL\n");
529 check_prefix(
NULL, &dag->prefix_info);
531 PRINTF(
"rpl_set_prefix - prefix NON-NULL\n");
532 check_prefix(&last_prefix, &dag->prefix_info);
538 rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from)
540 if(instance->def_route !=
NULL) {
541 PRINTF(
"RPL: Removing default route through ");
542 PRINT6ADDR(&instance->def_route->ipaddr);
544 uip_ds6_defrt_rm(instance->def_route);
545 instance->def_route =
NULL;
549 PRINTF(
"RPL: Adding default route through ");
552 instance->def_route = uip_ds6_defrt_add(from,
553 RPL_DEFAULT_ROUTE_INFINITE_LIFETIME ? 0 : RPL_LIFETIME(instance, instance->default_lifetime));
554 if(instance->def_route ==
NULL) {
558 PRINTF(
"RPL: Removing default route\n");
559 if(instance->def_route !=
NULL) {
560 uip_ds6_defrt_rm(instance->def_route);
562 PRINTF(
"RPL: Not actually removing default route, since instance had no default route\n");
569 rpl_alloc_instance(uint8_t instance_id)
571 rpl_instance_t *instance, *end;
573 for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
574 instance < end; ++instance) {
575 if(instance->used == 0) {
576 memset(instance, 0,
sizeof(*instance));
577 instance->instance_id = instance_id;
578 instance->def_route =
NULL;
581 rpl_schedule_probing(instance);
590 rpl_alloc_dag(uint8_t instance_id, uip_ipaddr_t *dag_id)
592 rpl_dag_t *dag, *end;
593 rpl_instance_t *instance;
595 instance = rpl_get_instance(instance_id);
596 if(instance ==
NULL) {
597 instance = rpl_alloc_instance(instance_id);
598 if(instance ==
NULL) {
599 RPL_STAT(rpl_stats.mem_overflows++);
604 for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
606 memset(dag, 0,
sizeof(*dag));
608 dag->rank = INFINITE_RANK;
609 dag->min_rank = INFINITE_RANK;
610 dag->instance = instance;
615 RPL_STAT(rpl_stats.mem_overflows++);
620 rpl_set_default_instance(rpl_instance_t *instance)
622 default_instance = instance;
626 rpl_get_default_instance(
void)
628 return default_instance;
632 rpl_free_instance(rpl_instance_t *instance)
637 PRINTF(
"RPL: Leaving the instance %u\n", instance->instance_id);
640 for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
646 rpl_set_default_route(instance,
NULL);
655 if(default_instance == instance) {
656 default_instance =
NULL;
663 rpl_free_dag(rpl_dag_t *dag)
666 PRINTF(
"RPL: Leaving the DAG ");
667 PRINT6ADDR(&dag->dag_id);
672 if(RPL_IS_STORING(dag->instance)) {
673 rpl_remove_routes(dag);
677 if((dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
678 check_prefix(&dag->prefix_info,
NULL);
681 remove_parents(dag, 0);
687 rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
689 rpl_parent_t *p =
NULL;
692 const uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr);
694 PRINTF(
"RPL: rpl_add_parent lladdr %p ", lladdr);
699 p = nbr_table_add_lladdr(rpl_parents, (linkaddr_t *)lladdr,
700 NBR_TABLE_REASON_RPL_DIO, dio);
702 PRINTF(
"RPL: rpl_add_parent p NULL\n");
708 memcpy(&p->mc, &dio->mc,
sizeof(p->mc));
716 static rpl_parent_t *
717 find_parent_any_dag_any_instance(uip_ipaddr_t *addr)
720 const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(ds6_nbr);
721 return nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)lladdr);
725 rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr)
727 rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
728 if(p !=
NULL && p->dag == dag) {
736 find_parent_dag(rpl_instance_t *instance, uip_ipaddr_t *addr)
738 rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
747 rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr)
749 rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
750 if(p && p->dag && p->dag->instance == instance) {
758 rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
760 rpl_parent_t *last_parent;
761 rpl_dag_t *dag, *end, *best_dag;
764 old_rank = instance->current_dag->rank;
765 last_parent = instance->current_dag->preferred_parent;
767 best_dag = instance->current_dag;
768 if(best_dag->rank != ROOT_RANK(instance)) {
769 if(rpl_select_parent(p->dag) !=
NULL) {
770 if(p->dag != best_dag) {
771 best_dag = instance->of->best_dag(best_dag, p->dag);
773 }
else if(p->dag == best_dag) {
775 for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
776 if(dag->used && dag->preferred_parent !=
NULL && dag->preferred_parent->rank != INFINITE_RANK) {
777 if(best_dag ==
NULL) {
780 best_dag = instance->of->best_dag(best_dag, dag);
787 if(best_dag ==
NULL) {
792 if(instance->current_dag != best_dag) {
794 if(RPL_IS_STORING(instance)) {
795 rpl_remove_routes(instance->current_dag);
798 PRINTF(
"RPL: New preferred DAG: ");
799 PRINT6ADDR(&best_dag->dag_id);
802 if(best_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
803 check_prefix(&instance->current_dag->prefix_info, &best_dag->prefix_info);
804 }
else if(instance->current_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
805 check_prefix(&instance->current_dag->prefix_info,
NULL);
808 best_dag->joined = 1;
809 instance->current_dag->joined = 0;
810 instance->current_dag = best_dag;
813 instance->of->update_metric_container(instance);
815 best_dag->rank = rpl_rank_via_parent(best_dag->preferred_parent);
816 if(last_parent ==
NULL || best_dag->rank < best_dag->min_rank) {
819 best_dag->min_rank = best_dag->rank;
822 if(!acceptable_rank(best_dag, best_dag->rank)) {
823 PRINTF(
"RPL: New rank unacceptable!\n");
824 rpl_set_preferred_parent(instance->current_dag,
NULL);
825 if(RPL_IS_STORING(instance) && last_parent !=
NULL) {
827 dao_output(last_parent, RPL_ZERO_LIFETIME);
832 if(best_dag->preferred_parent != last_parent) {
833 rpl_set_default_route(instance, rpl_get_parent_ipaddr(best_dag->preferred_parent));
834 PRINTF(
"RPL: Changed preferred parent, rank changed from %u to %u\n",
835 (
unsigned)old_rank, best_dag->rank);
836 RPL_STAT(rpl_stats.parent_switch++);
837 if(RPL_IS_STORING(instance) && last_parent !=
NULL) {
839 dao_output(last_parent, RPL_ZERO_LIFETIME);
842 RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
843 rpl_schedule_dao(instance);
844 rpl_reset_dio_timer(instance);
846 rpl_print_neighbor_list();
848 }
else if(best_dag->rank != old_rank) {
849 PRINTF(
"RPL: Preferred parent update, rank changed from %u to %u\n",
850 (
unsigned)old_rank, best_dag->rank);
855 static rpl_parent_t *
856 best_parent(rpl_dag_t *dag,
int fresh_only)
860 rpl_parent_t *best =
NULL;
862 if(dag ==
NULL || dag->instance ==
NULL || dag->instance->of ==
NULL) {
866 of = dag->instance->of;
868 for(p = nbr_table_head(rpl_parents); p !=
NULL; p = nbr_table_next(rpl_parents, p)) {
871 if(p->dag != dag || p->rank == INFINITE_RANK) {
875 if(fresh_only && !rpl_parent_is_fresh(p)) {
880 #ifndef UIP_CONF_ND6_SEND_NA
884 if(nbr ==
NULL || nbr->state != NBR_REACHABLE) {
891 best = of->best_parent(best, p);
898 rpl_select_parent(rpl_dag_t *dag)
901 rpl_parent_t *best = best_parent(dag, 0);
905 if(rpl_parent_is_fresh(best)) {
906 rpl_set_preferred_parent(dag, best);
909 rpl_parent_t *best_fresh = best_parent(dag, 1);
910 if(best_fresh ==
NULL) {
912 rpl_set_preferred_parent(dag, best);
915 rpl_set_preferred_parent(dag, best_fresh);
918 dag->instance->urgent_probing_target = best;
919 rpl_schedule_probing(dag->instance);
921 rpl_set_preferred_parent(dag, best);
922 dag->rank = rpl_rank_via_parent(dag->preferred_parent);
926 rpl_set_preferred_parent(dag,
NULL);
929 dag->rank = rpl_rank_via_parent(dag->preferred_parent);
930 return dag->preferred_parent;
934 rpl_remove_parent(rpl_parent_t *parent)
936 PRINTF(
"RPL: Removing parent ");
937 PRINT6ADDR(rpl_get_parent_ipaddr(parent));
940 rpl_nullify_parent(parent);
942 nbr_table_remove(rpl_parents, parent);
946 rpl_nullify_parent(rpl_parent_t *parent)
948 rpl_dag_t *dag = parent->dag;
951 if(parent == dag->preferred_parent || dag->preferred_parent ==
NULL) {
952 dag->rank = INFINITE_RANK;
954 if(dag->instance->def_route !=
NULL) {
955 PRINTF(
"RPL: Removing default route ");
956 PRINT6ADDR(rpl_get_parent_ipaddr(parent));
958 uip_ds6_defrt_rm(dag->instance->def_route);
959 dag->instance->def_route =
NULL;
962 if(parent == dag->preferred_parent) {
963 if(RPL_IS_STORING(dag->instance)) {
964 dao_output(parent, RPL_ZERO_LIFETIME);
966 rpl_set_preferred_parent(dag,
NULL);
971 PRINTF(
"RPL: Nullifying parent ");
972 PRINT6ADDR(rpl_get_parent_ipaddr(parent));
977 rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
979 if(parent == dag_src->preferred_parent) {
980 rpl_set_preferred_parent(dag_src,
NULL);
981 dag_src->rank = INFINITE_RANK;
982 if(dag_src->joined && dag_src->instance->def_route !=
NULL) {
983 PRINTF(
"RPL: Removing default route ");
984 PRINT6ADDR(rpl_get_parent_ipaddr(parent));
986 PRINTF(
"rpl_move_parent\n");
987 uip_ds6_defrt_rm(dag_src->instance->def_route);
988 dag_src->instance->def_route =
NULL;
990 }
else if(dag_src->joined) {
991 if(RPL_IS_STORING(dag_src->instance)) {
993 rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(parent), dag_src);
997 PRINTF(
"RPL: Moving parent ");
998 PRINT6ADDR(rpl_get_parent_ipaddr(parent));
1001 parent->dag = dag_dst;
1008 for(i = 0; i < RPL_MAX_INSTANCES; ++i) {
1009 if(instance_table[i].used && instance_table[i].has_downward_route) {
1017 rpl_get_dag(
const uip_ipaddr_t *addr)
1021 for(i = 0; i < RPL_MAX_INSTANCES; ++i) {
1022 if(instance_table[i].used) {
1023 for(j = 0; j < RPL_MAX_DAG_PER_INSTANCE; ++j) {
1024 if(instance_table[i].dag_table[j].joined
1025 && uip_ipaddr_prefixcmp(&instance_table[i].dag_table[j].dag_id, addr,
1026 instance_table[i].dag_table[j].prefix_info.length)) {
1027 return &instance_table[i].dag_table[j];
1036 rpl_get_any_dag(
void)
1040 for(i = 0; i < RPL_MAX_INSTANCES; ++i) {
1041 if(instance_table[i].used && instance_table[i].current_dag->joined) {
1042 return instance_table[i].current_dag;
1049 rpl_get_instance(uint8_t instance_id)
1053 for(i = 0; i < RPL_MAX_INSTANCES; ++i) {
1054 if(instance_table[i].used && instance_table[i].instance_id == instance_id) {
1055 return &instance_table[i];
1062 rpl_find_of(rpl_ocp_t ocp)
1067 i <
sizeof(objective_functions) /
sizeof(objective_functions[0]);
1069 if(objective_functions[i]->ocp == ocp) {
1070 return objective_functions[i];
1078 rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
1080 rpl_instance_t *instance;
1085 if((!RPL_WITH_NON_STORING && dio->mop == RPL_MOP_NON_STORING)
1086 || (!RPL_WITH_STORING && (dio->mop == RPL_MOP_STORING_NO_MULTICAST
1087 || dio->mop == RPL_MOP_STORING_MULTICAST))) {
1088 PRINTF(
"RPL: DIO advertising a non-supported MOP %u\n", dio->mop);
1093 of = rpl_find_of(dio->ocp);
1095 PRINTF(
"RPL: DIO for DAG instance %u does not specify a supported OF: %u\n",
1096 dio->instance_id, dio->ocp);
1100 dag = rpl_alloc_dag(dio->instance_id, &dio->dag_id);
1102 PRINTF(
"RPL: Failed to allocate a DAG object!\n");
1106 instance = dag->instance;
1108 p = rpl_add_parent(dag, dio, from);
1109 PRINTF(
"RPL: Adding ");
1111 PRINTF(
" as a parent: ");
1117 p->dtsn = dio->dtsn;
1118 PRINTF(
"succeeded\n");
1122 if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
1123 check_prefix(
NULL, &dio->prefix_info);
1127 dag->preference = dio->preference;
1128 dag->grounded = dio->grounded;
1129 dag->version = dio->version;
1132 instance->mop = dio->mop;
1133 instance->mc.type = dio->mc.type;
1134 instance->mc.flags = dio->mc.flags;
1135 instance->mc.aggr = dio->mc.aggr;
1136 instance->mc.prec = dio->mc.prec;
1137 instance->current_dag = dag;
1138 instance->dtsn_out = RPL_LOLLIPOP_INIT;
1140 instance->max_rankinc = dio->dag_max_rankinc;
1141 instance->min_hoprankinc = dio->dag_min_hoprankinc;
1142 instance->dio_intdoubl = dio->dag_intdoubl;
1143 instance->dio_intmin = dio->dag_intmin;
1144 instance->dio_intcurrent = instance->dio_intmin + instance->dio_intdoubl;
1145 instance->dio_redundancy = dio->dag_redund;
1146 instance->default_lifetime = dio->default_lifetime;
1147 instance->lifetime_unit = dio->lifetime_unit;
1149 memcpy(&dag->dag_id, &dio->dag_id,
sizeof(dio->dag_id));
1152 memcpy(&dag->prefix_info, &dio->prefix_info,
sizeof(rpl_prefix_t));
1154 rpl_set_preferred_parent(dag, p);
1155 instance->of->update_metric_container(instance);
1156 dag->rank = rpl_rank_via_parent(p);
1158 dag->min_rank = dag->rank;
1160 if(default_instance ==
NULL) {
1161 default_instance = instance;
1164 PRINTF(
"RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
1165 dio->instance_id, dag->rank);
1166 PRINT6ADDR(&dag->dag_id);
1169 ANNOTATE(
"#A join=%u\n", dag->dag_id.u8[
sizeof(dag->dag_id) - 1]);
1171 rpl_reset_dio_timer(instance);
1172 rpl_set_default_route(instance, from);
1174 if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
1175 rpl_schedule_dao(instance);
1177 PRINTF(
"RPL: The DIO does not meet the prerequisites for sending a DAO\n");
1180 instance->of->reset(dag);
1183 #if RPL_MAX_DAG_PER_INSTANCE > 1
1186 rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
1188 rpl_instance_t *instance;
1189 rpl_dag_t *dag, *previous_dag;
1193 dag = rpl_alloc_dag(dio->instance_id, &dio->dag_id);
1195 PRINTF(
"RPL: Failed to allocate a DAG object!\n");
1199 instance = dag->instance;
1201 previous_dag = find_parent_dag(instance, from);
1202 if(previous_dag ==
NULL) {
1203 PRINTF(
"RPL: Adding ");
1205 PRINTF(
" as a parent: ");
1206 p = rpl_add_parent(dag, dio, from);
1212 PRINTF(
"succeeded\n");
1214 p = rpl_find_parent(previous_dag, from);
1216 rpl_move_parent(previous_dag, dag, p);
1219 p->rank = dio->rank;
1223 of = rpl_find_of(dio->ocp);
1224 if(of != instance->of ||
1225 instance->mop != dio->mop ||
1226 instance->max_rankinc != dio->dag_max_rankinc ||
1227 instance->min_hoprankinc != dio->dag_min_hoprankinc ||
1228 instance->dio_intdoubl != dio->dag_intdoubl ||
1229 instance->dio_intmin != dio->dag_intmin ||
1230 instance->dio_redundancy != dio->dag_redund ||
1231 instance->default_lifetime != dio->default_lifetime ||
1232 instance->lifetime_unit != dio->lifetime_unit) {
1233 PRINTF(
"RPL: DIO for DAG instance %u incompatible with previous DIO\n",
1235 rpl_remove_parent(p);
1241 dag->grounded = dio->grounded;
1242 dag->preference = dio->preference;
1243 dag->version = dio->version;
1245 memcpy(&dag->dag_id, &dio->dag_id,
sizeof(dio->dag_id));
1248 memcpy(&dag->prefix_info, &dio->prefix_info,
sizeof(rpl_prefix_t));
1250 rpl_set_preferred_parent(dag, p);
1251 dag->rank = rpl_rank_via_parent(p);
1252 dag->min_rank = dag->rank;
1254 PRINTF(
"RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
1255 dio->instance_id, dag->rank);
1256 PRINT6ADDR(&dag->dag_id);
1259 ANNOTATE(
"#A join=%u\n", dag->dag_id.u8[
sizeof(dag->dag_id) - 1]);
1261 rpl_process_parent_event(instance, p);
1262 p->dtsn = dio->dtsn;
1270 global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio)
1274 remove_parents(dag, 0);
1275 dag->version = dio->version;
1278 dag->instance->dio_intdoubl = dio->dag_intdoubl;
1279 dag->instance->dio_intmin = dio->dag_intmin;
1280 dag->instance->dio_redundancy = dio->dag_redund;
1281 dag->instance->default_lifetime = dio->default_lifetime;
1282 dag->instance->lifetime_unit = dio->lifetime_unit;
1284 dag->instance->of->reset(dag);
1285 dag->min_rank = INFINITE_RANK;
1286 RPL_LOLLIPOP_INCREMENT(dag->instance->dtsn_out);
1288 p = rpl_add_parent(dag, dio, from);
1290 PRINTF(
"RPL: Failed to add a parent during the global repair\n");
1291 dag->rank = INFINITE_RANK;
1293 dag->rank = rpl_rank_via_parent(p);
1294 dag->min_rank = dag->rank;
1295 PRINTF(
"RPL: rpl_process_parent_event global repair\n");
1296 rpl_process_parent_event(dag->instance, p);
1299 PRINTF(
"RPL: Participating in a global repair (version=%u, rank=%hu)\n",
1300 dag->version, dag->rank);
1302 RPL_STAT(rpl_stats.global_repairs++);
1307 rpl_local_repair(rpl_instance_t *instance)
1311 if(instance ==
NULL) {
1312 PRINTF(
"RPL: local repair requested for instance NULL\n");
1315 PRINTF(
"RPL: Starting a local instance repair\n");
1316 for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; i++) {
1317 if(instance->dag_table[i].used) {
1318 instance->dag_table[i].rank = INFINITE_RANK;
1319 nullify_parents(&instance->dag_table[i], 0);
1324 instance->has_downward_route = 0;
1326 rpl_reset_dio_timer(instance);
1328 RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
1330 RPL_STAT(rpl_stats.local_repairs++);
1334 rpl_recalculate_ranks(
void)
1343 p = nbr_table_head(rpl_parents);
1345 if(p->dag !=
NULL && p->dag->instance && (p->flags & RPL_PARENT_FLAG_UPDATED)) {
1346 p->flags &= ~RPL_PARENT_FLAG_UPDATED;
1347 PRINTF(
"RPL: rpl_process_parent_event recalculate_ranks\n");
1348 if(!rpl_process_parent_event(p->dag->instance, p)) {
1349 PRINTF(
"RPL: A parent was dropped\n");
1352 p = nbr_table_next(rpl_parents, p);
1357 rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
1360 rpl_parent_t *last_parent = instance->current_dag->preferred_parent;
1363 rpl_rank_t old_rank;
1364 old_rank = instance->current_dag->rank;
1369 if(RPL_IS_STORING(instance)
1370 && uip_ds6_route_is_nexthop(rpl_get_parent_ipaddr(p))
1371 && !rpl_parent_is_reachable(p) && instance->mop > RPL_MOP_NON_STORING) {
1372 PRINTF(
"RPL: Unacceptable link %u, removing routes via: ", rpl_get_parent_link_metric(p));
1373 PRINT6ADDR(rpl_get_parent_ipaddr(p));
1375 rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(p), p->dag);
1378 if(!acceptable_rank(p->dag, p->rank)) {
1381 PRINTF(
"RPL: Unacceptable rank %u (Current min %u, MaxRankInc %u)\n", (
unsigned)p->rank,
1382 p->dag->min_rank, p->dag->instance->max_rankinc);
1383 rpl_nullify_parent(p);
1384 if(p != instance->current_dag->preferred_parent) {
1391 if(rpl_select_dag(instance, p) ==
NULL) {
1392 if(last_parent !=
NULL) {
1394 PRINTF(
"RPL: No parents found in any DAG\n");
1395 rpl_local_repair(instance);
1401 if(DAG_RANK(old_rank, instance) != DAG_RANK(instance->current_dag->rank, instance)) {
1402 PRINTF(
"RPL: Moving in the instance from rank %hu to %hu\n",
1403 DAG_RANK(old_rank, instance), DAG_RANK(instance->current_dag->rank, instance));
1404 if(instance->current_dag->rank != INFINITE_RANK) {
1405 PRINTF(
"RPL: The preferred parent is ");
1406 PRINT6ADDR(rpl_get_parent_ipaddr(instance->current_dag->preferred_parent));
1407 PRINTF(
" (rank %u)\n",
1408 (
unsigned)DAG_RANK(instance->current_dag->preferred_parent->rank, instance));
1410 PRINTF(
"RPL: We don't have any parent");
1415 return return_value;
1419 add_nbr_from_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
1422 if(rpl_icmp6_update_nbr_table(from, NBR_TABLE_REASON_RPL_DIO, dio) ==
NULL) {
1423 PRINTF(
"RPL: Out of memory, dropping DIO from ");
1432 rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
1434 rpl_instance_t *instance;
1435 rpl_dag_t *dag, *previous_dag;
1438 #if RPL_CONF_MULTICAST
1441 if(dio->mop < RPL_MOP_STORING_NO_MULTICAST) {
1443 if(dio->mop != RPL_MOP_DEFAULT) {
1445 PRINTF(
"RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop);
1449 dag = get_dag(dio->instance_id, &dio->dag_id);
1450 instance = rpl_get_instance(dio->instance_id);
1452 if(dag !=
NULL && instance !=
NULL) {
1453 if(lollipop_greater_than(dio->version, dag->version)) {
1454 if(dag->rank == ROOT_RANK(instance)) {
1455 PRINTF(
"RPL: Root received inconsistent DIO version number (current: %u, received: %u)\n", dag->version, dio->version);
1456 dag->version = dio->version;
1457 RPL_LOLLIPOP_INCREMENT(dag->version);
1458 rpl_reset_dio_timer(instance);
1460 PRINTF(
"RPL: Global repair\n");
1461 if(dio->prefix_info.length != 0) {
1462 if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
1463 PRINTF(
"RPL: Prefix announced in DIO\n");
1464 rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length);
1467 global_repair(from, dag, dio);
1472 if(lollipop_greater_than(dag->version, dio->version)) {
1474 PRINTF(
"RPL: old version received => inconsistency detected\n");
1476 rpl_reset_dio_timer(instance);
1482 if(instance ==
NULL) {
1483 PRINTF(
"RPL: New instance detected (ID=%u): Joining...\n", dio->instance_id);
1484 if(add_nbr_from_dio(from, dio)) {
1485 rpl_join_instance(from, dio);
1487 PRINTF(
"RPL: Not joining since could not add parent\n");
1492 if(instance->current_dag->rank == ROOT_RANK(instance) && instance->current_dag != dag) {
1493 PRINTF(
"RPL: Root ignored DIO for different DAG\n");
1498 #if RPL_MAX_DAG_PER_INSTANCE > 1
1499 PRINTF(
"RPL: Adding new DAG to known instance.\n");
1500 if(!add_nbr_from_dio(from, dio)) {
1501 PRINTF(
"RPL: Could not add new DAG, could not add parent\n");
1504 dag = rpl_add_dag(from, dio);
1506 PRINTF(
"RPL: Failed to add DAG.\n");
1510 PRINTF(
"RPL: Only one instance supported.\n");
1516 if(dio->rank < ROOT_RANK(instance)) {
1517 PRINTF(
"RPL: Ignoring DIO with too low rank: %u\n",
1518 (
unsigned)dio->rank);
1523 if(dio->prefix_info.length != 0) {
1524 if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
1525 PRINTF(
"RPL: Prefix announced in DIO\n");
1526 rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length);
1530 if(!add_nbr_from_dio(from, dio)) {
1531 PRINTF(
"RPL: Could not add parent based on DIO\n");
1535 if(dag->rank == ROOT_RANK(instance)) {
1536 if(dio->rank != INFINITE_RANK) {
1537 instance->dio_counter++;
1543 dag->lifetime = (1UL << (instance->dio_intmin + instance->dio_intdoubl)) / 1000;
1545 PRINT6ADDR(&dag->dag_id);
1546 PRINTF(
" lifetime to %ld\n", dag->lifetime);
1555 p = rpl_find_parent(dag, from);
1557 previous_dag = find_parent_dag(instance, from);
1558 if(previous_dag ==
NULL) {
1560 p = rpl_add_parent(dag, dio, from);
1562 PRINTF(
"RPL: Failed to add a new parent (");
1567 PRINTF(
"RPL: New candidate parent with rank %u: ", (
unsigned)p->rank);
1571 p = rpl_find_parent(previous_dag, from);
1573 rpl_move_parent(previous_dag, dag, p);
1577 if(p->rank == dio->rank) {
1578 PRINTF(
"RPL: Received consistent DIO\n");
1580 instance->dio_counter++;
1584 p->rank = dio->rank;
1586 if(dio->rank == INFINITE_RANK && p == dag->preferred_parent) {
1588 rpl_reset_dio_timer(instance);
1592 p->flags |= RPL_PARENT_FLAG_UPDATED;
1594 PRINTF(
"RPL: preferred DAG ");
1595 PRINT6ADDR(&instance->current_dag->dag_id);
1596 PRINTF(
", rank %u, min_rank %u, ",
1597 instance->current_dag->rank, instance->current_dag->min_rank);
1598 PRINTF(
"parent rank %u, link metric %u\n",
1599 p->rank, rpl_get_parent_link_metric(p));
1604 memcpy(&p->mc, &dio->mc,
sizeof(p->mc));
1606 if(rpl_process_parent_event(instance, p) == 0) {
1607 PRINTF(
"RPL: The candidate parent is rejected\n");
1612 if(dag->joined && p == dag->preferred_parent) {
1613 if(should_send_dao(instance, dio, p)) {
1614 RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
1615 rpl_schedule_dao(instance);
1619 uip_ds6_defrt_add(from, RPL_DEFAULT_ROUTE_INFINITE_LIFETIME ? 0 : RPL_LIFETIME(instance, instance->default_lifetime));
1621 p->dtsn = dio->dtsn;
Header file for IPv6 Neighbor discovery (RFC 4861)
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
static uip_ds6_addr_t * addr
Pointer to a router list entry.
CCIF clock_time_t clock_time(void)
Get the current clock time.
An entry in the nbr cache.
IPv6 Neighbor cache (link-layer/IPv6 address mapping)
int rpl_has_downward_route(void)
Get the RPL's best guess on if we have downward route or not.
Unicast address structure.
This header file contains configuration directives for uIPv6 multicast support.
Header file for the callback timer
#define NULL
The null pointer.
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
#define CLOCK_SECOND
A second, measured in system clock time.
Linked list manipulation routines.
Header file for the uIP TCP/IP stack.
uip_ds6_addr_t * uip_ds6_addr_add(uip_ipaddr_t *ipaddr, unsigned long vlifetime, uint8_t type)
Add a unicast address to the interface.
Memory block allocation routines.
A set of debugging macros for the IP stack
CCIF uip_lladdr_t uip_lladdr
Host L2 address.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
void uip_ds6_set_addr_iid(uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr)
set the last 64 bits of an IP address based on the MAC address