rpl-dag.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup uip6
00003  * @{
00004  */
00005 /*
00006  * Copyright (c) 2010, Swedish Institute of Computer Science.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions
00011  * are met:
00012  * 1. Redistributions of source code must retain the above copyright
00013  *    notice, this list of conditions and the following disclaimer.
00014  * 2. Redistributions in binary form must reproduce the above copyright
00015  *    notice, this list of conditions and the following disclaimer in the
00016  *    documentation and/or other materials provided with the distribution.
00017  * 3. Neither the name of the Institute nor the names of its contributors
00018  *    may be used to endorse or promote products derived from this software
00019  *    without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00025  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * This file is part of the Contiki operating system.
00034  *
00035  */
00036 /**
00037  * \file
00038  *         Logic for Directed Acyclic Graphs in RPL.
00039  *
00040  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
00041  */
00042 
00043 
00044 #include "contiki.h"
00045 #include "net/rpl/rpl-private.h"
00046 #include "net/uip.h"
00047 #include "net/uip-nd6.h"
00048 #include "lib/list.h"
00049 #include "lib/memb.h"
00050 #include "sys/ctimer.h"
00051 
00052 #include <limits.h>
00053 #include <string.h>
00054 
00055 #define DEBUG DEBUG_NONE
00056 #include "net/uip-debug.h"
00057 
00058 #include "net/neighbor-info.h"
00059 
00060 /************************************************************************/
00061 extern rpl_of_t RPL_OF;
00062 static rpl_of_t * const objective_functions[] = {&RPL_OF};
00063 /************************************************************************/
00064 
00065 #ifndef RPL_CONF_MAX_DAG_ENTRIES
00066 #define RPL_MAX_DAG_ENTRIES     2
00067 #else
00068 #define RPL_MAX_DAG_ENTRIES     RPL_CONF_MAX_DAG_ENTRIES
00069 #endif /* !RPL_CONF_MAX_DAG_ENTRIES */
00070 
00071 #ifndef RPL_CONF_MAX_PARENTS
00072 #define RPL_MAX_PARENTS       8
00073 #else
00074 #define RPL_MAX_PARENTS       RPL_CONF_MAX_PARENTS
00075 #endif /* !RPL_CONF_MAX_PARENTS */
00076 /************************************************************************/
00077 /* RPL definitions. */
00078 
00079 #ifndef RPL_CONF_GROUNDED
00080 #define RPL_GROUNDED                    0
00081 #else
00082 #define RPL_GROUNDED                    RPL_CONF_GROUNDED
00083 #endif /* !RPL_CONF_GROUNDED */
00084 
00085 #ifndef RPL_CONF_DIO_INTERVAL_MIN
00086 #define RPL_DIO_INTERVAL_MIN            DEFAULT_DIO_INTERVAL_MIN
00087 #else
00088 #define RPL_DIO_INTERVAL_MIN            RPL_CONF_DIO_INTERVAL_MIN
00089 #endif /* !RPL_CONF_DIO_INTERVAL_MIN */
00090 
00091 #ifndef RPL_CONF_DIO_INTERVAL_DOUBLINGS
00092 #define RPL_DIO_INTERVAL_DOUBLINGS      DEFAULT_DIO_INTERVAL_DOUBLINGS
00093 #else
00094 #define RPL_DIO_INTERVAL_DOUBLINGS      RPL_CONF_DIO_INTERVAL_DOUBLINGS
00095 #endif /* !RPL_CONF_DIO_INTERVAL_DOUBLINGS */
00096 
00097 /************************************************************************/
00098 /* Allocate parents from the same static MEMB chunk to reduce memory waste. */
00099 MEMB(parent_memb, struct rpl_parent, RPL_MAX_PARENTS);
00100 
00101 static rpl_dag_t dag_table[RPL_MAX_DAG_ENTRIES];
00102 /************************************************************************/
00103 /* Remove DAG parents with a rank that is at least the same as minimum_rank. */
00104 static void
00105 remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
00106 {
00107   rpl_parent_t *p, *p2;
00108 
00109   PRINTF("RPL: Removing parents (minimum rank %u)\n",
00110         minimum_rank);
00111 
00112   for(p = list_head(dag->parents); p != NULL; p = p2) {
00113     p2 = p->next;
00114     if(p->rank >= minimum_rank) {
00115       rpl_remove_parent(dag, p);
00116     }
00117   }
00118 }
00119 /************************************************************************/
00120 static void
00121 remove_worst_parent(rpl_dag_t *dag, rpl_rank_t min_worst_rank)
00122 {
00123   rpl_parent_t *p, *worst;
00124 
00125   PRINTF("RPL: Removing the worst parent\n");
00126 
00127   /* Find the parent with the highest rank. */
00128   worst = NULL;
00129   for(p = list_head(dag->parents); p != NULL; p = list_item_next(p)) {
00130     if(p != dag->preferred_parent &&
00131        (worst == NULL || p->rank > worst->rank)) {
00132       worst = p;
00133     }
00134   }
00135   /* Remove the neighbor if its rank is worse than the minimum worst
00136      rank. */
00137   if(worst != NULL && worst->rank > min_worst_rank) {
00138     rpl_remove_parent(dag, worst);
00139   }
00140 }
00141 /************************************************************************/
00142 static int
00143 should_send_dao(rpl_dag_t *dag, rpl_dio_t *dio, rpl_parent_t *p)
00144 {
00145   /* if MOP is set to no downward routes no DAO should be sent */
00146   if(dag->mop == RPL_MOP_NO_DOWNWARD_ROUTES) return 0;
00147   return dio->dtsn > p->dtsn && p == dag->preferred_parent;
00148 }
00149 /************************************************************************/
00150 static int
00151 acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank)
00152 {
00153   return rank != INFINITE_RANK &&
00154     (dag->max_rankinc == 0 ||
00155      DAG_RANK(rank, dag) <= DAG_RANK(dag->min_rank + dag->max_rankinc, dag));
00156 }
00157 /************************************************************************/
00158 rpl_dag_t *
00159 rpl_set_root(uip_ipaddr_t *dag_id)
00160 {
00161   rpl_dag_t *dag;
00162   int version;
00163 
00164   version = -1;
00165   dag = rpl_get_dag(RPL_DEFAULT_INSTANCE);
00166   if(dag != NULL) {
00167     PRINTF("RPL: Dropping a joined DAG when setting this node as root");
00168     version = dag->version;
00169     rpl_free_dag(dag);
00170   }
00171 
00172   dag = rpl_alloc_dag(RPL_DEFAULT_INSTANCE);
00173   if(dag == NULL) {
00174     PRINTF("RPL: Failed to allocate a DAG\n");
00175     return NULL;
00176   }
00177 
00178   dag->joined = 1;
00179   dag->version = version + 1;
00180   dag->grounded = RPL_GROUNDED;
00181   dag->mop = RPL_MOP_DEFAULT;
00182   dag->of = &RPL_OF;
00183   dag->preferred_parent = NULL;
00184   dag->dtsn_out = 1; /* Trigger DAOs from the beginning. */
00185 
00186   memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id));
00187 
00188   dag->dio_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS;
00189   dag->dio_intmin = DEFAULT_DIO_INTERVAL_MIN;
00190   dag->dio_redundancy = DEFAULT_DIO_REDUNDANCY;
00191   dag->max_rankinc = DEFAULT_MAX_RANKINC;
00192   dag->min_hoprankinc = DEFAULT_MIN_HOPRANKINC;
00193 
00194   dag->default_lifetime = DEFAULT_RPL_DEF_LIFETIME;
00195   dag->lifetime_unit = DEFAULT_RPL_LIFETIME_UNIT;
00196 
00197   dag->rank = ROOT_RANK(dag);
00198 
00199   dag->of->update_metric_container(dag);
00200 
00201   PRINTF("RPL: Node set to be a DAG root with DAG ID ");
00202   PRINT6ADDR(&dag->dag_id);
00203   PRINTF("\n");
00204 
00205   ANNOTATE("#A root=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
00206 
00207 
00208   rpl_reset_dio_timer(dag, 1);
00209 
00210   return dag;
00211 }
00212 /************************************************************************/
00213 int
00214 rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, int len)
00215 {
00216   if(len <= 128) {
00217     memset(&dag->prefix_info.prefix, 0, 16);
00218     memcpy(&dag->prefix_info.prefix, prefix, (len + 7) / 8);
00219     dag->prefix_info.length = len;
00220     dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS;
00221     PRINTF("RPL: Prefix set - will announce this in DIOs\n");
00222     return 1;
00223   }
00224   return 0;
00225 }
00226 /************************************************************************/
00227 int
00228 rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from)
00229 {
00230   if(dag->def_route != NULL) {
00231     PRINTF("RPL: Removing default route through ");
00232     PRINT6ADDR(&dag->def_route->ipaddr);
00233     PRINTF("\n");
00234     uip_ds6_defrt_rm(dag->def_route);
00235   }
00236 
00237   if(from != NULL) {
00238     PRINTF("RPL: Adding default route through ");
00239     PRINT6ADDR(from);
00240     PRINTF("\n");
00241     if(DEFAULT_ROUTE_LIFETIME == INFINITE_LIFETIME) {
00242       dag->def_route = uip_ds6_defrt_add(from, 0);
00243     } else {
00244       dag->def_route = uip_ds6_defrt_add(from, DEFAULT_ROUTE_LIFETIME);
00245     }
00246     if(dag->def_route == NULL) {
00247       return 0;
00248     }
00249   }
00250 
00251   return 1;
00252 }
00253 /************************************************************************/
00254 rpl_dag_t *
00255 rpl_alloc_dag(uint8_t instance_id)
00256 {
00257   rpl_dag_t *dag;
00258   rpl_dag_t *end;
00259 
00260   for(dag = &dag_table[0], end = dag + RPL_MAX_DAG_ENTRIES; dag < end; dag++) {
00261     if(dag->used == 0) {
00262       memset(dag, 0, sizeof(*dag));
00263       dag->parents = &dag->parent_list;
00264       list_init(dag->parents);
00265       dag->instance_id = instance_id;
00266       dag->def_route = NULL;
00267       dag->rank = INFINITE_RANK;
00268       dag->min_rank = INFINITE_RANK;
00269       return dag;
00270     }
00271   }
00272 
00273   RPL_STAT(rpl_stats.mem_overflows++);
00274   return NULL;
00275 }
00276 /************************************************************************/
00277 void
00278 rpl_free_dag(rpl_dag_t *dag)
00279 {
00280   PRINTF("RPL: Leaving the DAG ");
00281   PRINT6ADDR(&dag->dag_id);
00282   PRINTF("\n");
00283 
00284   /* Remove routes installed by DAOs. */
00285   rpl_remove_routes(dag);
00286 
00287   /* Remove parents and the default route. */
00288   remove_parents(dag, 0);
00289   rpl_set_default_route(dag, NULL);
00290 
00291   ctimer_stop(&dag->dio_timer);
00292   ctimer_stop(&dag->dao_timer);
00293 
00294   dag->used = 0;
00295   dag->joined = 0;
00296 }
00297 /************************************************************************/
00298 rpl_parent_t *
00299 rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
00300 {
00301   rpl_parent_t *p;
00302 
00303   p = memb_alloc(&parent_memb);
00304   if(p == NULL) {
00305     RPL_STAT(rpl_stats.mem_overflows++);
00306     return NULL;
00307   }
00308 
00309   memcpy(&p->addr, addr, sizeof(p->addr));
00310   p->dag = dag;
00311   p->rank = dio->rank;
00312   p->link_metric = INITIAL_LINK_METRIC;
00313   p->dtsn = 0;
00314 
00315   memcpy(&p->mc, &dio->mc, sizeof(p->mc));
00316 
00317   list_add(dag->parents, p);
00318 
00319   return p;
00320 }
00321 /************************************************************************/
00322 rpl_parent_t *
00323 rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr)
00324 {
00325   rpl_parent_t *p;
00326 
00327   for(p = list_head(dag->parents); p != NULL; p = p->next) {
00328     if(uip_ipaddr_cmp(&p->addr, addr)) {
00329       return p;
00330     }
00331   }
00332 
00333   return NULL;
00334 }
00335 
00336 /************************************************************************/
00337 rpl_parent_t *
00338 rpl_select_parent(rpl_dag_t *dag)
00339 {
00340   rpl_parent_t *p;
00341   rpl_parent_t *best;
00342 
00343   best = NULL;
00344   for(p = list_head(dag->parents); p != NULL; p = p->next) {
00345     if(p->rank == INFINITE_RANK) {
00346       /* ignore this neighbor */
00347     } else if(best == NULL) {
00348       best = p;
00349     } else {
00350       best = dag->of->best_parent(best, p);
00351     }
00352   }
00353 
00354   if(best == NULL) {
00355     /* need to handle update of best... */
00356     return NULL;
00357   }
00358 
00359   if(dag->preferred_parent != best) {
00360     dag->preferred_parent = best; /* Cache the value. */
00361     dag->of->update_metric_container(dag);
00362     rpl_set_default_route(dag, &best->addr);
00363     /* The DAO parent set changed - schedule a DAO transmission. */
00364     if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
00365       rpl_schedule_dao(dag);
00366     }
00367     rpl_reset_dio_timer(dag, 1);
00368     PRINTF("RPL: New preferred parent, rank changed from %u to %u\n",
00369            (unsigned)dag->rank, dag->of->calculate_rank(best, 0));
00370     RPL_STAT(rpl_stats.parent_switch++);
00371   }
00372 
00373   /* Update the DAG rank, since link-layer information may have changed
00374      the local confidence. */
00375   dag->rank = dag->of->calculate_rank(best, 0);
00376   if(dag->rank < dag->min_rank) {
00377     dag->min_rank = dag->rank;
00378   } else if(!acceptable_rank(dag, best->rank)) {
00379     /* Send a No-Path DAO to the soon-to-be-removed preferred parent. */
00380     dao_output(p, ZERO_LIFETIME);
00381 
00382     remove_parents(dag, 0);
00383     return NULL;
00384   }
00385 
00386   return best;
00387 }
00388 /************************************************************************/
00389 int
00390 rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t *parent)
00391 {
00392   uip_ds6_defrt_t *defrt;
00393 
00394   /* Remove uIPv6 routes that have this parent as the next hop. **/
00395   uip_ds6_route_rm_by_nexthop(&parent->addr);
00396   defrt = uip_ds6_defrt_lookup(&parent->addr);
00397   if(defrt != NULL) {
00398     PRINTF("RPL: Removing default route ");
00399     PRINT6ADDR(&parent->addr);
00400     PRINTF("\n");
00401     uip_ds6_defrt_rm(defrt);
00402     dag->def_route = NULL;
00403   }
00404 
00405   PRINTF("RPL: Removing parent ");
00406   PRINT6ADDR(&parent->addr);
00407   PRINTF("\n");
00408 
00409   if(parent == dag->preferred_parent) {
00410     dag->preferred_parent = NULL;
00411   }
00412 
00413   list_remove(dag->parents, parent);
00414   memb_free(&parent_memb, parent);
00415   return 0;
00416 }
00417 /************************************************************************/
00418 rpl_dag_t *
00419 rpl_get_dag(int instance_id)
00420 {
00421   int i;
00422 
00423   for(i = 0; i < RPL_MAX_DAG_ENTRIES; i++) {
00424     if(dag_table[i].joined && (instance_id == RPL_ANY_INSTANCE ||
00425                                dag_table[i].instance_id == instance_id)) {
00426       return &dag_table[i];
00427     }
00428   }
00429   return NULL;
00430 }
00431 /************************************************************************/
00432 rpl_of_t *
00433 rpl_find_of(rpl_ocp_t ocp)
00434 {
00435   unsigned int i;
00436 
00437   for(i = 0;
00438       i < sizeof(objective_functions) / sizeof(objective_functions[0]); 
00439       i++) {
00440     if(objective_functions[i]->ocp == ocp) {
00441       return objective_functions[i];
00442     }
00443   }
00444 
00445   return NULL;
00446 }
00447 /************************************************************************/
00448 static void
00449 join_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
00450 {
00451   rpl_dag_t *dag;
00452   rpl_parent_t *p;
00453   rpl_of_t *of;
00454 
00455   dag = rpl_alloc_dag(dio->instance_id);
00456   if(dag == NULL) {
00457     PRINTF("RPL: Failed to allocate a DAG object!\n");
00458     return;
00459   }
00460 
00461   p = rpl_add_parent(dag, dio, from);
00462   PRINTF("RPL: Adding ");
00463   PRINT6ADDR(from);
00464   PRINTF(" as a parent: ");
00465   if(p == NULL) {
00466     PRINTF("failed\n");
00467     return;
00468   }
00469   PRINTF("succeeded\n");
00470 
00471   /* Determine the objective function by using the
00472      objective code point of the DIO. */
00473   of = rpl_find_of(dio->ocp);
00474   if(of == NULL) {
00475     PRINTF("RPL: DIO for DAG instance %u does not specify a supported OF\n",
00476         dio->instance_id);
00477     return;
00478   }
00479 
00480   /* Autoconfigure an address if this node does not already have an address
00481      with this prefix. */
00482   if((dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
00483     uip_ipaddr_t ipaddr;
00484     /* assume that the prefix ends with zeros! */
00485     memcpy(&ipaddr, &dio->prefix_info.prefix, 16);
00486     uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
00487     if(uip_ds6_addr_lookup(&ipaddr) == NULL) {
00488       PRINTF("RPL: adding global IP address ");
00489       PRINT6ADDR(&ipaddr);
00490       PRINTF("\n");
00491       uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
00492     }
00493   }
00494 
00495   dag->joined = 1;
00496   dag->used = 1;
00497   dag->of = of;
00498   dag->grounded = dio->grounded;
00499   dag->mop = dio->mop;
00500   dag->preference = dio->preference;
00501   dag->instance_id = dio->instance_id;
00502 
00503   dag->max_rankinc = dio->dag_max_rankinc;
00504   dag->min_hoprankinc = dio->dag_min_hoprankinc;
00505 
00506   dag->version = dio->version;
00507   dag->preferred_parent = p;
00508   dag->of->update_metric_container(dag);
00509 
00510   dag->dio_intdoubl = dio->dag_intdoubl;
00511   dag->dio_intmin = dio->dag_intmin;
00512   dag->dio_redundancy = dio->dag_redund;
00513 
00514   memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id));
00515 
00516   /* copy prefix information into the dag */
00517   memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t));
00518 
00519   dag->rank = dag->of->calculate_rank(p, dio->rank);
00520   dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */
00521 
00522   PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
00523          dio->instance_id, dag->rank);
00524   PRINT6ADDR(&dag->dag_id);
00525   PRINTF("\n");
00526 
00527   ANNOTATE("#A join=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
00528 
00529 
00530   dag->default_lifetime = dio->default_lifetime;
00531   dag->lifetime_unit = dio->lifetime_unit;
00532 
00533   rpl_reset_dio_timer(dag, 1);
00534   rpl_set_default_route(dag, from);
00535 
00536   if(should_send_dao(dag, dio, p)) {
00537     rpl_schedule_dao(dag);
00538   } else {
00539     PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n");
00540   }
00541 }
00542 /************************************************************************/
00543 static void
00544 global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio)
00545 {
00546   rpl_parent_t *p;
00547 
00548   remove_parents(dag, 0);
00549   dag->version = dio->version;
00550   dag->dtsn_out = 1;
00551   dag->of->reset(dag);
00552   if((p = rpl_add_parent(dag, dio, from)) == NULL) {
00553     PRINTF("RPL: Failed to add a parent during the global repair\n");
00554     dag->rank = INFINITE_RANK;
00555   } else {
00556     rpl_set_default_route(dag, from);
00557     dag->rank = dag->of->calculate_rank(NULL, dio->rank);
00558     dag->min_rank = dag->rank;
00559     rpl_reset_dio_timer(dag, 1);
00560     if(should_send_dao(dag, dio, p)) {
00561       rpl_schedule_dao(dag);
00562     }
00563   }
00564   PRINTF("RPL: Participating in a global repair (version=%u, rank=%hu)\n",
00565          dag->version, dag->rank);
00566 
00567   RPL_STAT(rpl_stats.global_repairs++);
00568 }
00569 /************************************************************************/
00570 int
00571 rpl_repair_dag(rpl_dag_t *dag)
00572 {
00573   if(dag->rank == ROOT_RANK(dag)) {
00574     dag->version++;
00575     dag->dtsn_out = 1;
00576     rpl_reset_dio_timer(dag, 1);
00577     return 1;
00578   }
00579   return 0;
00580 }
00581 /************************************************************************/
00582 void
00583 rpl_local_repair(rpl_dag_t *dag)
00584 {
00585   PRINTF("RPL: Starting a local DAG repair\n");
00586 
00587   dag->rank = INFINITE_RANK;
00588   remove_parents(dag, 0);
00589   rpl_reset_dio_timer(dag, 1);
00590 
00591   RPL_STAT(rpl_stats.local_repairs++);
00592 }
00593 /************************************************************************/
00594 void
00595 rpl_recalculate_ranks(void)
00596 {
00597   rpl_dag_t *dag;
00598   rpl_parent_t *p;
00599 
00600   /*
00601    * We recalculate ranks when we receive feedback from the system rather
00602    * than RPL protocol messages. This periodical recalculation is called
00603    * from a timer in order to keep the stack depth reasonably low.
00604    */
00605   dag = rpl_get_dag(RPL_ANY_INSTANCE);
00606   if(dag != NULL) {
00607     for(p = list_head(dag->parents); p != NULL; p = p->next) {
00608       if(p->updated) {
00609         p->updated = 0;
00610         rpl_process_parent_event(dag, p);
00611         /*
00612          * Stop calculating here because the parent list may have changed.
00613          * If more ranks need to be recalculated, it will be taken care of
00614          * in subsequent calls to this functions.
00615          */
00616         break;
00617       }
00618     }
00619   }
00620 }
00621 /************************************************************************/
00622 int
00623 rpl_process_parent_event(rpl_dag_t *dag, rpl_parent_t *p)
00624 {
00625   rpl_rank_t parent_rank;
00626   rpl_rank_t old_rank;
00627 
00628   /* Update the parent rank. */
00629   parent_rank = p->rank;
00630   old_rank = dag->rank;
00631 
00632   if(rpl_select_parent(dag) == NULL) {
00633     /* No suitable parent; trigger a local repair. */
00634     PRINTF("RPL: No parents found in a DAG\n");
00635     rpl_local_repair(dag);
00636     return 1;
00637   }
00638 
00639   if(DAG_RANK(old_rank, dag) != DAG_RANK(dag->rank, dag)) {
00640     if(dag->rank < dag->min_rank) {
00641       dag->min_rank = dag->rank;
00642     }
00643     PRINTF("RPL: Moving in the DAG from rank %hu to %hu\n",
00644            DAG_RANK(old_rank, dag), DAG_RANK(dag->rank, dag));
00645     PRINTF("RPL: The preferred parent is ");
00646     PRINT6ADDR(&dag->preferred_parent->addr);
00647     PRINTF(" (rank %u)\n",
00648            (unsigned)DAG_RANK(dag->preferred_parent->rank, dag));
00649     rpl_reset_dio_timer(dag, 1);
00650   }
00651 
00652   if(parent_rank == INFINITE_RANK ||
00653      !acceptable_rank(dag, dag->of->calculate_rank(NULL, parent_rank))) {
00654     /* The candidate parent is no longer valid: the rank increase resulting
00655        from the choice of it as a parent would be too high. */
00656     return 0;
00657   }
00658 
00659   return 1;
00660 }
00661 /************************************************************************/
00662 void
00663 rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
00664 {
00665   rpl_dag_t *dag;
00666   rpl_parent_t *p;
00667 
00668   if(dio->mop != RPL_MOP_DEFAULT) {
00669     PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop);
00670     return;
00671   }
00672 
00673   dag = rpl_get_dag(dio->instance_id);
00674   if(dag == NULL) {
00675     /* Join the first possible DAG of this RPL instance. */
00676     if(dio->rank != INFINITE_RANK) {
00677       join_dag(from, dio);
00678     } else {
00679       PRINTF("RPL: Ignoring DIO from node with infinite rank: ");
00680       PRINT6ADDR(from);
00681       PRINTF("\n");
00682     }
00683     return;
00684   }
00685 
00686   if(memcmp(&dag->dag_id, &dio->dag_id, sizeof(dag->dag_id))) {
00687     PRINTF("RPL: Ignoring DIO for another DAG within our instance\n");
00688     return;
00689   }
00690 
00691   if(dio->version > dag->version) {
00692     if(dag->rank == ROOT_RANK(dag)) {
00693       PRINTF("RPL: Root received inconsistent DIO version number\n");
00694       dag->version = dio->version + 1;
00695       rpl_reset_dio_timer(dag, 1);
00696     } else {
00697       global_repair(from, dag, dio);
00698     }
00699     return;
00700   } else if(dio->version < dag->version) {
00701     /* Inconsistency detected - someone is still on old version */
00702     PRINTF("RPL: old version received => inconsistency detected\n");
00703     rpl_reset_dio_timer(dag, 1);
00704     return;
00705   }
00706 
00707   if(dio->rank == INFINITE_RANK) {
00708     rpl_reset_dio_timer(dag, 1);
00709   } else if(dio->rank < ROOT_RANK(dag)) {
00710     PRINTF("RPL: Ignoring DIO with too low rank: %u\n",
00711            (unsigned)dio->rank);
00712     return;
00713   }
00714 
00715   if(dag->rank == ROOT_RANK(dag)) {
00716     if(dio->rank != INFINITE_RANK) {
00717       dag->dio_counter++;
00718     }
00719     return;
00720   }
00721 
00722   /*
00723    * At this point, we know that this DIO pertains to a DAG that
00724    * we are already part of. We consider the sender of the DIO to be
00725    * a candidate parent, and let rpl_process_parent_event decide
00726    * whether to keep it in the set.
00727    */
00728 
00729   p = rpl_find_parent(dag, from);
00730   if(p == NULL) {
00731     if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS) {
00732       /* Make room for a new parent. */
00733       remove_worst_parent(dag, dio->rank);
00734     }
00735     
00736     /* Add the DIO sender as a candidate parent. */
00737     p = rpl_add_parent(dag, dio, from);
00738     if(p == NULL) {
00739       PRINTF("RPL: Failed to add a new parent (");
00740       PRINT6ADDR(from);
00741       PRINTF(")\n");
00742       return;
00743     }
00744 
00745     PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank);
00746     PRINT6ADDR(from);
00747     PRINTF("\n");
00748   } else if(DAG_RANK(p->rank, dag) == DAG_RANK(dio->rank, dag)) {
00749     PRINTF("RPL: Received consistent DIO\n");
00750     dag->dio_counter++;
00751   }
00752   
00753   /* We have allocated a candidate parent; process the DIO further. */
00754 
00755   memcpy(&p->mc, &dio->mc, sizeof(p->mc));    
00756   p->rank = dio->rank;
00757   if(rpl_process_parent_event(dag, p) == 0) {
00758     /* The candidate parent no longer exists. */
00759     return;
00760   }
00761   
00762   if(should_send_dao(dag, dio, p)) {
00763     rpl_schedule_dao(dag);
00764   }
00765   
00766   p->dtsn = dio->dtsn;
00767 }
00768 /************************************************************************/
00769 
00770 /** \} */

Generated on Mon Apr 11 14:23:31 2011 for Contiki 2.5 by  doxygen 1.6.1