uip-ds6.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup uip6
00003  * @{
00004  */
00005 
00006 /**
00007  * \file
00008  *         IPv6 data structures handling functions
00009  *         Comprises part of the Neighbor discovery (RFC 4861)
00010  *         and auto configuration (RFC 4862 )state machines
00011  * \author Mathilde Durvy <mdurvy@cisco.com>
00012  * \author Julien Abeille <jabeille@cisco.com>
00013  */
00014 /*
00015  * Copyright (c) 2006, Swedish Institute of Computer Science.
00016  * All rights reserved.
00017  *
00018  * Redistribution and use in source and binary forms, with or without
00019  * modification, are permitted provided that the following conditions
00020  * are met:
00021  * 1. Redistributions of source code must retain the above copyright
00022  *   notice, this list of conditions and the following disclaimer.
00023  * 2. Redistributions in binary form must reproduce the above copyright
00024  *   notice, this list of conditions and the following disclaimer in the
00025  *   documentation and/or other materials provided with the distribution.
00026  * 3. Neither the name of the Institute nor the names of its contributors
00027  *   may be used to endorse or promote products derived from this software
00028  *   without specific prior written permission.
00029  *
00030  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00031  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00032  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00033  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00034  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00035  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00036  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00037  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00038  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00039  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00040  * SUCH DAMAGE.
00041  *
00042  */
00043 #include <string.h>
00044 #include <stdlib.h>
00045 #include "lib/random.h"
00046 #include "net/uip-nd6.h"
00047 #include "net/uip-ds6.h"
00048 #include "net/uip-packetqueue.h"
00049 
00050 #define DEBUG DEBUG_NONE
00051 #include "net/uip-debug.h"
00052 
00053 #ifdef UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED
00054 #define NEIGHBOR_STATE_CHANGED(n) UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED(n)
00055 void NEIGHBOR_STATE_CHANGED(uip_ds6_nbr_t *n);
00056 #else
00057 #define NEIGHBOR_STATE_CHANGED(n)
00058 #endif /* UIP_DS6_CONF_NEIGHBOR_STATE_CHANGED */
00059 
00060 struct etimer uip_ds6_timer_periodic;                           /** \brief Timer for maintenance of data structures */
00061 
00062 #if UIP_CONF_ROUTER
00063 struct stimer uip_ds6_timer_ra;                                 /** \brief RA timer, to schedule RA sending */
00064 #if UIP_ND6_SEND_RA
00065 static uint8_t racount;                                         /** \brief number of RA already sent */
00066 static uint16_t rand_time;                                      /** \brief random time value for timers */
00067 #endif
00068 #else /* UIP_CONF_ROUTER */
00069 struct etimer uip_ds6_timer_rs;                                 /** \brief RS timer, to schedule RS sending */
00070 static uint8_t rscount;                                         /** \brief number of rs already sent */
00071 #endif /* UIP_CONF_ROUTER */
00072 
00073 /** \name "DS6" Data structures */
00074 /** @{ */
00075 uip_ds6_netif_t uip_ds6_if;                                       /** \brief The single interface */
00076 uip_ds6_nbr_t uip_ds6_nbr_cache[UIP_DS6_NBR_NB];                  /** \brief Neighor cache */
00077 uip_ds6_defrt_t uip_ds6_defrt_list[UIP_DS6_DEFRT_NB];             /** \brief Default rt list */
00078 uip_ds6_prefix_t uip_ds6_prefix_list[UIP_DS6_PREFIX_NB];          /** \brief Prefix list */
00079 uip_ds6_route_t uip_ds6_routing_table[UIP_DS6_ROUTE_NB];          /** \brief Routing table */
00080 
00081 /** @} */
00082 
00083 /* "full" (as opposed to pointer) ip address used in this file,  */
00084 static uip_ipaddr_t loc_fipaddr;
00085 
00086 /* Pointers used in this file */
00087 static uip_ipaddr_t *locipaddr;
00088 static uip_ds6_addr_t *locaddr;
00089 static uip_ds6_maddr_t *locmaddr;
00090 static uip_ds6_aaddr_t *locaaddr;
00091 static uip_ds6_prefix_t *locprefix;
00092 static uip_ds6_nbr_t *locnbr;
00093 static uip_ds6_defrt_t *locdefrt;
00094 static uip_ds6_route_t *locroute;
00095 
00096 /*---------------------------------------------------------------------------*/
00097 void
00098 uip_ds6_init(void)
00099 {
00100   PRINTF("Init of IPv6 data structures\n");
00101   PRINTF("%u neighbors\n%u default routers\n%u prefixes\n%u routes\n%u unicast addresses\n%u multicast addresses\n%u anycast addresses\n",
00102      UIP_DS6_NBR_NB, UIP_DS6_DEFRT_NB, UIP_DS6_PREFIX_NB, UIP_DS6_ROUTE_NB,
00103      UIP_DS6_ADDR_NB, UIP_DS6_MADDR_NB, UIP_DS6_AADDR_NB);
00104   memset(uip_ds6_nbr_cache, 0, sizeof(uip_ds6_nbr_cache));
00105   memset(uip_ds6_defrt_list, 0, sizeof(uip_ds6_defrt_list));
00106   memset(uip_ds6_prefix_list, 0, sizeof(uip_ds6_prefix_list));
00107   memset(&uip_ds6_if, 0, sizeof(uip_ds6_if));
00108   memset(uip_ds6_routing_table, 0, sizeof(uip_ds6_routing_table));
00109 
00110   /* Set interface parameters */
00111   uip_ds6_if.link_mtu = UIP_LINK_MTU;
00112   uip_ds6_if.cur_hop_limit = UIP_TTL;
00113   uip_ds6_if.base_reachable_time = UIP_ND6_REACHABLE_TIME;
00114   uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time();
00115   uip_ds6_if.retrans_timer = UIP_ND6_RETRANS_TIMER;
00116   uip_ds6_if.maxdadns = UIP_ND6_DEF_MAXDADNS;
00117 
00118   /* Create link local address, prefix, multicast addresses, anycast addresses */
00119   uip_create_linklocal_prefix(&loc_fipaddr);
00120 #if UIP_CONF_ROUTER
00121   uip_ds6_prefix_add(&loc_fipaddr, UIP_DEFAULT_PREFIX_LEN, 0, 0, 0, 0);
00122 #else /* UIP_CONF_ROUTER */
00123   uip_ds6_prefix_add(&loc_fipaddr, UIP_DEFAULT_PREFIX_LEN, 0);
00124 #endif /* UIP_CONF_ROUTER */
00125   uip_ds6_set_addr_iid(&loc_fipaddr, &uip_lladdr);
00126   uip_ds6_addr_add(&loc_fipaddr, 0, ADDR_AUTOCONF);
00127 
00128   uip_create_linklocal_allnodes_mcast(&loc_fipaddr);
00129   uip_ds6_maddr_add(&loc_fipaddr);
00130 #if UIP_CONF_ROUTER
00131   uip_create_linklocal_allrouters_mcast(&loc_fipaddr);
00132   uip_ds6_maddr_add(&loc_fipaddr);
00133 #if UIP_ND6_SEND_RA
00134   stimer_set(&uip_ds6_timer_ra, 2);     /* wait to have a link local IP address */
00135 #endif /* UIP_ND6_SEND_RA */
00136 #else /* UIP_CONF_ROUTER */
00137   etimer_set(&uip_ds6_timer_rs,
00138              random_rand() % (UIP_ND6_MAX_RTR_SOLICITATION_DELAY *
00139                               CLOCK_SECOND));
00140 #endif /* UIP_CONF_ROUTER */
00141   etimer_set(&uip_ds6_timer_periodic, UIP_DS6_PERIOD);
00142 
00143   return;
00144 }
00145 
00146 
00147 /*---------------------------------------------------------------------------*/
00148 void
00149 uip_ds6_periodic(void)
00150 {
00151   /* Periodic processing on unicast addresses */
00152   for(locaddr = uip_ds6_if.addr_list;
00153       locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) {
00154     if(locaddr->isused) {
00155       if((!locaddr->isinfinite) && (stimer_expired(&locaddr->vlifetime))) {
00156         uip_ds6_addr_rm(locaddr);
00157       } else if((locaddr->state == ADDR_TENTATIVE)
00158                 && (locaddr->dadnscount <= uip_ds6_if.maxdadns)
00159                 && (timer_expired(&locaddr->dadtimer))) {
00160         uip_ds6_dad(locaddr);
00161       }
00162     }
00163   }
00164 
00165   /* Periodic processing on default routers */
00166   for(locdefrt = uip_ds6_defrt_list;
00167       locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) {
00168     if((locdefrt->isused) && (!locdefrt->isinfinite) &&
00169        (stimer_expired(&(locdefrt->lifetime)))) {
00170       uip_ds6_defrt_rm(locdefrt);
00171     }
00172   }
00173 
00174 #if !UIP_CONF_ROUTER
00175   /* Periodic processing on prefixes */
00176   for(locprefix = uip_ds6_prefix_list;
00177       locprefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB;
00178       locprefix++) {
00179     if(locprefix->isused && !locprefix->isinfinite
00180        && stimer_expired(&(locprefix->vlifetime))) {
00181       uip_ds6_prefix_rm(locprefix);
00182     }
00183   }
00184 #endif /* !UIP_CONF_ROUTER */
00185 
00186   /* Periodic processing on neighbors */
00187   for(locnbr = uip_ds6_nbr_cache;
00188       locnbr < uip_ds6_nbr_cache + UIP_DS6_NBR_NB;
00189       locnbr++) {
00190     if(locnbr->isused) {
00191       switch(locnbr->state) {
00192       case NBR_INCOMPLETE:
00193         if(locnbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
00194           uip_ds6_nbr_rm(locnbr);
00195         } else if(stimer_expired(&locnbr->sendns)) {
00196           locnbr->nscount++;
00197           PRINTF("NBR_INCOMPLETE: NS %u\n", locnbr->nscount);
00198           uip_nd6_ns_output(NULL, NULL, &locnbr->ipaddr);
00199           stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000);
00200         }
00201         break;
00202       case NBR_REACHABLE:
00203         if(stimer_expired(&locnbr->reachable)) {
00204           PRINTF("REACHABLE: moving to STALE (");
00205           PRINT6ADDR(&locnbr->ipaddr);
00206           PRINTF(")\n");
00207           locnbr->state = NBR_STALE;
00208         }
00209         break;
00210       case NBR_DELAY:
00211         if(stimer_expired(&locnbr->reachable)) {
00212           locnbr->state = NBR_PROBE;
00213           locnbr->nscount = 1;
00214           PRINTF("DELAY: moving to PROBE + NS %u\n", locnbr->nscount);
00215           uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr);
00216           stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000);
00217         }
00218         break;
00219       case NBR_PROBE:
00220         if(locnbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
00221           PRINTF("PROBE END\n");
00222           if((locdefrt = uip_ds6_defrt_lookup(&locnbr->ipaddr)) != NULL) {
00223             uip_ds6_defrt_rm(locdefrt);
00224           }
00225           uip_ds6_nbr_rm(locnbr);
00226         } else if(stimer_expired(&locnbr->sendns)) {
00227           locnbr->nscount++;
00228           PRINTF("PROBE: NS %u\n", locnbr->nscount);
00229           uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr);
00230           stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000);
00231         }
00232         break;
00233       default:
00234         break;
00235       }
00236     }
00237   }
00238 
00239 #if UIP_CONF_ROUTER & UIP_ND6_SEND_RA
00240   /* Periodic RA sending */
00241   if(stimer_expired(&uip_ds6_timer_ra)) {
00242     uip_ds6_send_ra_periodic();
00243   }
00244 #endif /* UIP_CONF_ROUTER & UIP_ND6_SEND_RA */
00245   etimer_reset(&uip_ds6_timer_periodic);
00246   return;
00247 }
00248 
00249 /*---------------------------------------------------------------------------*/
00250 uint8_t
00251 uip_ds6_list_loop(uip_ds6_element_t *list, uint8_t size,
00252                   uint16_t elementsize, uip_ipaddr_t *ipaddr,
00253                   uint8_t ipaddrlen, uip_ds6_element_t **out_element)
00254 {
00255   uip_ds6_element_t *element;
00256 
00257   *out_element = NULL;
00258 
00259   for(element = list;
00260       element <
00261       (uip_ds6_element_t *)((uint8_t *)list + (size * elementsize));
00262       element = (uip_ds6_element_t *)((uint8_t *)element + elementsize)) {
00263     if(element->isused) {
00264       if(uip_ipaddr_prefixcmp(&element->ipaddr, ipaddr, ipaddrlen)) {
00265         *out_element = element;
00266         return FOUND;
00267       }
00268     } else {
00269       *out_element = element;
00270     }
00271   }
00272 
00273   return *out_element != NULL ? FREESPACE : NOSPACE;
00274 }
00275 
00276 /*---------------------------------------------------------------------------*/
00277 uip_ds6_nbr_t *
00278 uip_ds6_nbr_add(uip_ipaddr_t *ipaddr, uip_lladdr_t * lladdr,
00279                 uint8_t isrouter, uint8_t state)
00280 {
00281   int r;
00282 
00283   r = uip_ds6_list_loop
00284      ((uip_ds6_element_t *)uip_ds6_nbr_cache, UIP_DS6_NBR_NB,
00285       sizeof(uip_ds6_nbr_t), ipaddr, 128,
00286       (uip_ds6_element_t **)&locnbr);
00287 
00288   if(r == FREESPACE) {
00289     locnbr->isused = 1;
00290     uip_ipaddr_copy(&locnbr->ipaddr, ipaddr);
00291     if(lladdr != NULL) {
00292       memcpy(&locnbr->lladdr, lladdr, UIP_LLADDR_LEN);
00293     } else {
00294       memset(&locnbr->lladdr, 0, UIP_LLADDR_LEN);
00295     }
00296     locnbr->isrouter = isrouter;
00297     locnbr->state = state;
00298 #if UIP_CONF_IPV6_QUEUE_PKT
00299     uip_packetqueue_new(&locnbr->packethandle);
00300 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
00301     /* timers are set separately, for now we put them in expired state */
00302     stimer_set(&locnbr->reachable, 0);
00303     stimer_set(&locnbr->sendns, 0);
00304     locnbr->nscount = 0;
00305     PRINTF("Adding neighbor with ip addr ");
00306     PRINT6ADDR(ipaddr);
00307     PRINTF("link addr ");
00308     PRINTLLADDR((&(locnbr->lladdr)));
00309     PRINTF("state %u\n", state);
00310     NEIGHBOR_STATE_CHANGED(locnbr);
00311 
00312     locnbr->last_lookup = clock_time();
00313     return locnbr;
00314   } else if(r == NOSPACE) {
00315     /* We did not find any empty slot on the neighbor list, so we need
00316        to remove one old entry to make room. */
00317     uip_ds6_nbr_t *n, *oldest;
00318     clock_time_t oldest_time;
00319 
00320     oldest = NULL;
00321     oldest_time = clock_time();
00322 
00323     for(n = uip_ds6_nbr_cache;
00324         n < &uip_ds6_nbr_cache[UIP_DS6_NBR_NB];
00325         n++) {
00326       if(n->isused) {
00327         if(n->last_lookup < oldest_time) {
00328           oldest = n;
00329           oldest_time = n->last_lookup;
00330         }
00331       }
00332     }
00333     if(oldest != NULL) {
00334       uip_ds6_nbr_rm(oldest);
00335       return uip_ds6_nbr_add(ipaddr, lladdr, isrouter, state);
00336     }
00337   }
00338   PRINTF("uip_ds6_nbr_add drop\n");
00339   return NULL;
00340 }
00341 
00342 /*---------------------------------------------------------------------------*/
00343 void
00344 uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr)
00345 {
00346   if(nbr != NULL) {
00347     nbr->isused = 0;
00348 #if UIP_CONF_IPV6_QUEUE_PKT
00349     uip_packetqueue_free(&nbr->packethandle);
00350 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
00351     NEIGHBOR_STATE_CHANGED(nbr);
00352   }
00353   return;
00354 }
00355 
00356 /*---------------------------------------------------------------------------*/
00357 uip_ds6_nbr_t *
00358 uip_ds6_nbr_lookup(uip_ipaddr_t *ipaddr)
00359 {
00360   if(uip_ds6_list_loop
00361      ((uip_ds6_element_t *)uip_ds6_nbr_cache, UIP_DS6_NBR_NB,
00362       sizeof(uip_ds6_nbr_t), ipaddr, 128,
00363       (uip_ds6_element_t **)&locnbr) == FOUND) {
00364     return locnbr;
00365   }
00366   return NULL;
00367 }
00368 
00369 /*---------------------------------------------------------------------------*/
00370 uip_ds6_defrt_t *
00371 uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval)
00372 {
00373   if(uip_ds6_list_loop
00374      ((uip_ds6_element_t *)uip_ds6_defrt_list, UIP_DS6_DEFRT_NB,
00375       sizeof(uip_ds6_defrt_t), ipaddr, 128,
00376       (uip_ds6_element_t **)&locdefrt) == FREESPACE) {
00377     locdefrt->isused = 1;
00378     uip_ipaddr_copy(&locdefrt->ipaddr, ipaddr);
00379     if(interval != 0) {
00380       stimer_set(&locdefrt->lifetime, interval);
00381       locdefrt->isinfinite = 0;
00382     } else {
00383       locdefrt->isinfinite = 1;
00384     }
00385 
00386     PRINTF("Adding defrouter with ip addr ");
00387     PRINT6ADDR(&locdefrt->ipaddr);
00388     PRINTF("\n");
00389 
00390     ANNOTATE("#L %u 1\n", ipaddr->u8[sizeof(uip_ipaddr_t) - 1]);
00391 
00392     return locdefrt;
00393   }
00394   return NULL;
00395 }
00396 
00397 /*---------------------------------------------------------------------------*/
00398 void
00399 uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt)
00400 {
00401   if(defrt != NULL) {
00402     defrt->isused = 0;
00403     ANNOTATE("#L %u 0\n", defrt->ipaddr.u8[sizeof(uip_ipaddr_t) - 1]);
00404   }
00405   return;
00406 }
00407 
00408 /*---------------------------------------------------------------------------*/
00409 uip_ds6_defrt_t *
00410 uip_ds6_defrt_lookup(uip_ipaddr_t *ipaddr)
00411 {
00412   if(uip_ds6_list_loop((uip_ds6_element_t *)uip_ds6_defrt_list,
00413                        UIP_DS6_DEFRT_NB, sizeof(uip_ds6_defrt_t), ipaddr, 128,
00414                        (uip_ds6_element_t **)&locdefrt) == FOUND) {
00415     return locdefrt;
00416   }
00417   return NULL;
00418 }
00419 
00420 /*---------------------------------------------------------------------------*/
00421 uip_ipaddr_t *
00422 uip_ds6_defrt_choose(void)
00423 {
00424   uip_ds6_nbr_t *bestnbr;
00425 
00426   locipaddr = NULL;
00427   for(locdefrt = uip_ds6_defrt_list;
00428       locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) {
00429     if(locdefrt->isused) {
00430       PRINTF("Defrt, IP address ");
00431       PRINT6ADDR(&locdefrt->ipaddr);
00432       PRINTF("\n");
00433       bestnbr = uip_ds6_nbr_lookup(&locdefrt->ipaddr);
00434       if(bestnbr != NULL && bestnbr->state != NBR_INCOMPLETE) {
00435         PRINTF("Defrt found, IP address ");
00436         PRINT6ADDR(&locdefrt->ipaddr);
00437         PRINTF("\n");
00438         return &locdefrt->ipaddr;
00439       } else {
00440         locipaddr = &locdefrt->ipaddr;
00441         PRINTF("Defrt INCOMPLETE found, IP address ");
00442         PRINT6ADDR(&locdefrt->ipaddr);
00443         PRINTF("\n");
00444       }
00445     }
00446   }
00447   return locipaddr;
00448 }
00449 
00450 #if UIP_CONF_ROUTER
00451 /*---------------------------------------------------------------------------*/
00452 uip_ds6_prefix_t *
00453 uip_ds6_prefix_add(uip_ipaddr_t *ipaddr, uint8_t ipaddrlen,
00454                    uint8_t advertise, uint8_t flags, unsigned long vtime,
00455                    unsigned long ptime)
00456 {
00457   if(uip_ds6_list_loop
00458      ((uip_ds6_element_t *)uip_ds6_prefix_list, UIP_DS6_PREFIX_NB,
00459       sizeof(uip_ds6_prefix_t), ipaddr, ipaddrlen,
00460       (uip_ds6_element_t **)&locprefix) == FREESPACE) {
00461     locprefix->isused = 1;
00462     uip_ipaddr_copy(&locprefix->ipaddr, ipaddr);
00463     locprefix->length = ipaddrlen;
00464     locprefix->advertise = advertise;
00465     locprefix->l_a_reserved = flags;
00466     locprefix->vlifetime = vtime;
00467     locprefix->plifetime = ptime;
00468     PRINTF("Adding prefix ");
00469     PRINT6ADDR(&locprefix->ipaddr);
00470     PRINTF("length %u, flags %x, Valid lifetime %lx, Preffered lifetime %lx\n",
00471        ipaddrlen, flags, vtime, ptime);
00472     return locprefix;
00473   } else {
00474     PRINTF("No more space in Prefix list\n");
00475   }
00476   return NULL;
00477 }
00478 
00479 
00480 #else /* UIP_CONF_ROUTER */
00481 uip_ds6_prefix_t *
00482 uip_ds6_prefix_add(uip_ipaddr_t *ipaddr, uint8_t ipaddrlen,
00483                    unsigned long interval)
00484 {
00485   if(uip_ds6_list_loop
00486      ((uip_ds6_element_t *)uip_ds6_prefix_list, UIP_DS6_PREFIX_NB,
00487       sizeof(uip_ds6_prefix_t), ipaddr, ipaddrlen,
00488       (uip_ds6_element_t **)&locprefix) == FREESPACE) {
00489     locprefix->isused = 1;
00490     uip_ipaddr_copy(&locprefix->ipaddr, ipaddr);
00491     locprefix->length = ipaddrlen;
00492     if(interval != 0) {
00493       stimer_set(&(locprefix->vlifetime), interval);
00494       locprefix->isinfinite = 0;
00495     } else {
00496       locprefix->isinfinite = 1;
00497     }
00498     PRINTF("Adding prefix ");
00499     PRINT6ADDR(&locprefix->ipaddr);
00500     PRINTF("length %u, vlifetime%lu\n", ipaddrlen, interval);
00501   }
00502   return NULL;
00503 }
00504 #endif /* UIP_CONF_ROUTER */
00505 
00506 /*---------------------------------------------------------------------------*/
00507 void
00508 uip_ds6_prefix_rm(uip_ds6_prefix_t * prefix)
00509 {
00510   if(prefix != NULL) {
00511     prefix->isused = 0;
00512   }
00513   return;
00514 }
00515 /*---------------------------------------------------------------------------*/
00516 uip_ds6_prefix_t *
00517 uip_ds6_prefix_lookup(uip_ipaddr_t *ipaddr, uint8_t ipaddrlen)
00518 {
00519   if(uip_ds6_list_loop((uip_ds6_element_t *)uip_ds6_prefix_list,
00520                        UIP_DS6_PREFIX_NB, sizeof(uip_ds6_prefix_t),
00521                        ipaddr, ipaddrlen,
00522                        (uip_ds6_element_t **)&locprefix) == FOUND) {
00523     return locprefix;
00524   }
00525   return NULL;
00526 }
00527 
00528 /*---------------------------------------------------------------------------*/
00529 uint8_t
00530 uip_ds6_is_addr_onlink(uip_ipaddr_t *ipaddr)
00531 {
00532   for(locprefix = uip_ds6_prefix_list;
00533       locprefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; locprefix++) {
00534     if(locprefix->isused &&
00535        uip_ipaddr_prefixcmp(&locprefix->ipaddr, ipaddr, locprefix->length)) {
00536       return 1;
00537     }
00538   }
00539   return 0;
00540 }
00541 
00542 /*---------------------------------------------------------------------------*/
00543 uip_ds6_addr_t *
00544 uip_ds6_addr_add(uip_ipaddr_t *ipaddr, unsigned long vlifetime, uint8_t type)
00545 {
00546   if(uip_ds6_list_loop
00547      ((uip_ds6_element_t *)uip_ds6_if.addr_list, UIP_DS6_ADDR_NB,
00548       sizeof(uip_ds6_addr_t), ipaddr, 128,
00549       (uip_ds6_element_t **)&locaddr) == FREESPACE) {
00550     locaddr->isused = 1;
00551     uip_ipaddr_copy(&locaddr->ipaddr, ipaddr);
00552     locaddr->state = ADDR_TENTATIVE;
00553     locaddr->type = type;
00554     if(vlifetime == 0) {
00555       locaddr->isinfinite = 1;
00556     } else {
00557       locaddr->isinfinite = 0;
00558       stimer_set(&(locaddr->vlifetime), vlifetime);
00559     }
00560     timer_set(&locaddr->dadtimer,
00561               random_rand() % (UIP_ND6_MAX_RTR_SOLICITATION_DELAY *
00562                                CLOCK_SECOND));
00563     locaddr->dadnscount = 0;
00564     uip_create_solicited_node(ipaddr, &loc_fipaddr);
00565     uip_ds6_maddr_add(&loc_fipaddr);
00566     return locaddr;
00567   }
00568   return NULL;
00569 }
00570 
00571 /*---------------------------------------------------------------------------*/
00572 void
00573 uip_ds6_addr_rm(uip_ds6_addr_t *addr)
00574 {
00575   if(addr != NULL) {
00576     uip_create_solicited_node(&addr->ipaddr, &loc_fipaddr);
00577     if((locmaddr = uip_ds6_maddr_lookup(&loc_fipaddr)) != NULL) {
00578       uip_ds6_maddr_rm(locmaddr);
00579     }
00580     addr->isused = 0;
00581   }
00582   return;
00583 }
00584 
00585 /*---------------------------------------------------------------------------*/
00586 uip_ds6_addr_t *
00587 uip_ds6_addr_lookup(uip_ipaddr_t *ipaddr)
00588 {
00589   if(uip_ds6_list_loop
00590      ((uip_ds6_element_t *)uip_ds6_if.addr_list, UIP_DS6_ADDR_NB,
00591       sizeof(uip_ds6_addr_t), ipaddr, 128,
00592       (uip_ds6_element_t **)&locaddr) == FOUND) {
00593     return locaddr;
00594   }
00595   return NULL;
00596 }
00597 
00598 /*---------------------------------------------------------------------------*/
00599 /*
00600  * get a link local address -
00601  * state = -1 => any address is ok. Otherwise state = desired state of addr.
00602  * (TENTATIVE, PREFERRED, DEPRECATED)
00603  */
00604 uip_ds6_addr_t *
00605 uip_ds6_get_link_local(int8_t state)
00606 {
00607   for(locaddr = uip_ds6_if.addr_list;
00608       locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) {
00609     if(locaddr->isused && (state == -1 || locaddr->state == state)
00610        && (uip_is_addr_link_local(&locaddr->ipaddr))) {
00611       return locaddr;
00612     }
00613   }
00614   return NULL;
00615 }
00616 
00617 /*---------------------------------------------------------------------------*/
00618 /*
00619  * get a global address -
00620  * state = -1 => any address is ok. Otherwise state = desired state of addr.
00621  * (TENTATIVE, PREFERRED, DEPRECATED)
00622  */
00623 uip_ds6_addr_t *
00624 uip_ds6_get_global(int8_t state)
00625 {
00626   for(locaddr = uip_ds6_if.addr_list;
00627       locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) {
00628     if(locaddr->isused && (state == -1 || locaddr->state == state)
00629        && !(uip_is_addr_link_local(&locaddr->ipaddr))) {
00630       return locaddr;
00631     }
00632   }
00633   return NULL;
00634 }
00635 
00636 /*---------------------------------------------------------------------------*/
00637 uip_ds6_maddr_t *
00638 uip_ds6_maddr_add(uip_ipaddr_t *ipaddr)
00639 {
00640   if(uip_ds6_list_loop
00641      ((uip_ds6_element_t *)uip_ds6_if.maddr_list, UIP_DS6_MADDR_NB,
00642       sizeof(uip_ds6_maddr_t), ipaddr, 128,
00643       (uip_ds6_element_t **)&locmaddr) == FREESPACE) {
00644     locmaddr->isused = 1;
00645     uip_ipaddr_copy(&locmaddr->ipaddr, ipaddr);
00646     return locmaddr;
00647   }
00648   return NULL;
00649 }
00650 
00651 /*---------------------------------------------------------------------------*/
00652 void
00653 uip_ds6_maddr_rm(uip_ds6_maddr_t * maddr)
00654 {
00655   if(maddr != NULL) {
00656     maddr->isused = 0;
00657   }
00658   return;
00659 }
00660 
00661 /*---------------------------------------------------------------------------*/
00662 uip_ds6_maddr_t *
00663 uip_ds6_maddr_lookup(uip_ipaddr_t *ipaddr)
00664 {
00665   if(uip_ds6_list_loop
00666      ((uip_ds6_element_t *)uip_ds6_if.maddr_list, UIP_DS6_MADDR_NB,
00667       sizeof(uip_ds6_maddr_t), ipaddr, 128,
00668       (uip_ds6_element_t **)&locmaddr) == FOUND) {
00669     return locmaddr;
00670   }
00671   return NULL;
00672 }
00673 
00674 
00675 /*---------------------------------------------------------------------------*/
00676 uip_ds6_aaddr_t *
00677 uip_ds6_aaddr_add(uip_ipaddr_t *ipaddr)
00678 {
00679   if(uip_ds6_list_loop
00680      ((uip_ds6_element_t *)uip_ds6_if.aaddr_list, UIP_DS6_AADDR_NB,
00681       sizeof(uip_ds6_aaddr_t), ipaddr, 128,
00682       (uip_ds6_element_t **)&locaaddr) == FREESPACE) {
00683     locaaddr->isused = 1;
00684     uip_ipaddr_copy(&locaaddr->ipaddr, ipaddr);
00685     return locaaddr;
00686   }
00687   return NULL;
00688 }
00689 
00690 /*---------------------------------------------------------------------------*/
00691 void
00692 uip_ds6_aaddr_rm(uip_ds6_aaddr_t * aaddr)
00693 {
00694   if(aaddr != NULL) {
00695     aaddr->isused = 0;
00696   }
00697   return;
00698 }
00699 
00700 /*---------------------------------------------------------------------------*/
00701 uip_ds6_aaddr_t *
00702 uip_ds6_aaddr_lookup(uip_ipaddr_t *ipaddr)
00703 {
00704   if(uip_ds6_list_loop((uip_ds6_element_t *)uip_ds6_if.aaddr_list,
00705                        UIP_DS6_AADDR_NB, sizeof(uip_ds6_aaddr_t), ipaddr, 128,
00706                        (uip_ds6_element_t **)&locaaddr) == FOUND) {
00707     return locaaddr;
00708   }
00709   return NULL;
00710 }
00711 
00712 /*---------------------------------------------------------------------------*/
00713 uip_ds6_route_t *
00714 uip_ds6_route_lookup(uip_ipaddr_t *destipaddr)
00715 {
00716   uip_ds6_route_t *locrt = NULL;
00717   uint8_t longestmatch = 0;
00718 
00719   PRINTF("DS6: Looking up route for ");
00720   PRINT6ADDR(destipaddr);
00721   PRINTF("\n");
00722 
00723   for(locroute = uip_ds6_routing_table;
00724       locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB; locroute++) {
00725     if((locroute->isused) && (locroute->length >= longestmatch)
00726        &&
00727        (uip_ipaddr_prefixcmp
00728         (destipaddr, &locroute->ipaddr, locroute->length))) {
00729       longestmatch = locroute->length;
00730       locrt = locroute;
00731     }
00732   }
00733 
00734   if(locrt != NULL) {
00735     PRINTF("DS6: Found route:");
00736     PRINT6ADDR(destipaddr);
00737     PRINTF(" via ");
00738     PRINT6ADDR(&locrt->nexthop);
00739     PRINTF("\n");
00740   } else {
00741     PRINTF("DS6: No route found\n");
00742   }
00743 
00744   return locrt;
00745 }
00746 
00747 /*---------------------------------------------------------------------------*/
00748 uip_ds6_route_t *
00749 uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop,
00750                   uint8_t metric)
00751 {
00752   if(uip_ds6_list_loop
00753      ((uip_ds6_element_t *)uip_ds6_routing_table, UIP_DS6_ROUTE_NB,
00754       sizeof(uip_ds6_route_t), ipaddr, length,
00755       (uip_ds6_element_t **)&locroute) == FREESPACE) {
00756     locroute->isused = 1;
00757     uip_ipaddr_copy(&(locroute->ipaddr), ipaddr);
00758     locroute->length = length;
00759     uip_ipaddr_copy(&(locroute->nexthop), nexthop);
00760     locroute->metric = metric;
00761 
00762     PRINTF("DS6: adding route: ");
00763     PRINT6ADDR(ipaddr);
00764     PRINTF(" via ");
00765     PRINT6ADDR(nexthop);
00766     PRINTF("\n");
00767     ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
00768   }
00769 
00770   return locroute;
00771 }
00772 
00773 /*---------------------------------------------------------------------------*/
00774 void
00775 uip_ds6_route_rm(uip_ds6_route_t *route)
00776 {
00777   route->isused = 0;
00778 #if (DEBUG & DEBUG_ANNOTATE) == DEBUG_ANNOTATE
00779   /* we need to check if this was the last route towards "nexthop" */
00780   /* if so - remove that link (annotation) */
00781   for(locroute = uip_ds6_routing_table;
00782       locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB;
00783       locroute++) {
00784     if(locroute->isused && uip_ipaddr_cmp(&locroute->nexthop, &route->nexthop))      {
00785       /* we found another link using the specific nexthop, so keep the #L */
00786       return;
00787     }
00788   }
00789   ANNOTATE("#L %u 0\n",route->nexthop.u8[sizeof(uip_ipaddr_t) - 1]);
00790 #endif
00791 }
00792 /*---------------------------------------------------------------------------*/
00793 void
00794 uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
00795 {
00796   for(locroute = uip_ds6_routing_table;
00797       locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB;
00798       locroute++) {
00799     if(locroute->isused && uip_ipaddr_cmp(&locroute->nexthop, nexthop)) {
00800       locroute->isused = 0;
00801     }
00802   }
00803   ANNOTATE("#L %u 0\n",nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
00804 }
00805 
00806 /*---------------------------------------------------------------------------*/
00807 void
00808 uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
00809 {
00810   uint8_t best = 0;             /* number of bit in common with best match */
00811   uint8_t n = 0;
00812   uip_ds6_addr_t *matchaddr = NULL;
00813 
00814   if(!uip_is_addr_link_local(dst) && !uip_is_addr_mcast(dst)) {
00815     /* find longest match */
00816     for(locaddr = uip_ds6_if.addr_list;
00817         locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) {
00818       /* Only preferred global (not link-local) addresses */
00819       if(locaddr->isused && locaddr->state == ADDR_PREFERRED &&
00820          !uip_is_addr_link_local(&locaddr->ipaddr)) {
00821         n = get_match_length(dst, &locaddr->ipaddr);
00822         if(n >= best) {
00823           best = n;
00824           matchaddr = locaddr;
00825         }
00826       }
00827     }
00828   } else {
00829     matchaddr = uip_ds6_get_link_local(ADDR_PREFERRED);
00830   }
00831 
00832   /* use the :: (unspecified address) as source if no match found */
00833   if(matchaddr == NULL) {
00834     uip_create_unspecified(src);
00835   } else {
00836     uip_ipaddr_copy(src, &matchaddr->ipaddr);
00837   }
00838 }
00839 
00840 /*---------------------------------------------------------------------------*/
00841 void
00842 uip_ds6_set_addr_iid(uip_ipaddr_t *ipaddr, uip_lladdr_t * lladdr)
00843 {
00844   /* We consider only links with IEEE EUI-64 identifier or
00845    * IEEE 48-bit MAC addresses */
00846 #if (UIP_LLADDR_LEN == 8)
00847   memcpy(ipaddr->u8 + 8, lladdr, UIP_LLADDR_LEN);
00848   ipaddr->u8[8] ^= 0x02;
00849 #elif (UIP_LLADDR_LEN == 6)
00850   memcpy(ipaddr->u8 + 8, lladdr, 3);
00851   ipaddr->u8[11] = 0xff;
00852   ipaddr->u8[12] = 0xfe;
00853   memcpy(ipaddr->u8 + 13, (uint8_t *)lladdr + 3, 3);
00854   ipaddr->u8[8] ^= 0x02;
00855 #else
00856 #error uip-ds6.c cannot build interface address when UIP_LLADDR_LEN is not 6 or 8
00857 #endif
00858 }
00859 
00860 /*---------------------------------------------------------------------------*/
00861 uint8_t
00862 get_match_length(uip_ipaddr_t *src, uip_ipaddr_t *dst)
00863 {
00864   uint8_t j, k, x_or;
00865   uint8_t len = 0;
00866 
00867   for(j = 0; j < 16; j++) {
00868     if(src->u8[j] == dst->u8[j]) {
00869       len += 8;
00870     } else {
00871       x_or = src->u8[j] ^ dst->u8[j];
00872       for(k = 0; k < 8; k++) {
00873         if((x_or & 0x80) == 0) {
00874           len++;
00875           x_or <<= 1;
00876         } else {
00877           break;
00878         }
00879       }
00880       break;
00881     }
00882   }
00883   return len;
00884 }
00885 
00886 /*---------------------------------------------------------------------------*/
00887 void
00888 uip_ds6_dad(uip_ds6_addr_t *addr)
00889 {
00890   /* send maxdadns NS for DAD  */
00891   if(addr->dadnscount < uip_ds6_if.maxdadns) {
00892     uip_nd6_ns_output(NULL, NULL, &addr->ipaddr);
00893     addr->dadnscount++;
00894     timer_set(&addr->dadtimer,
00895               uip_ds6_if.retrans_timer / 1000 * CLOCK_SECOND);
00896     return;
00897   }
00898   /*
00899    * If we arrive here it means DAD succeeded, otherwise the dad process
00900    * would have been interrupted in ds6_dad_ns/na_input
00901    */
00902   PRINTF("DAD succeeded, ipaddr:");
00903   PRINT6ADDR(&addr->ipaddr);
00904   PRINTF("\n");
00905 
00906   addr->state = ADDR_PREFERRED;
00907   return;
00908 }
00909 
00910 /*---------------------------------------------------------------------------*/
00911 /*
00912  * Calling code must handle when this returns 0 (e.g. link local
00913  * address can not be used).
00914  */
00915 int
00916 uip_ds6_dad_failed(uip_ds6_addr_t * addr)
00917 {
00918   if(uip_is_addr_link_local(&addr->ipaddr)) {
00919     PRINTF("Contiki shutdown, DAD for link local address failed\n");
00920     return 0;
00921   }
00922   uip_ds6_addr_rm(addr);
00923   return 1;
00924 }
00925 
00926 #if UIP_CONF_ROUTER
00927 #if UIP_ND6_SEND_RA
00928 /*---------------------------------------------------------------------------*/
00929 void
00930 uip_ds6_send_ra_sollicited(void)
00931 {
00932   /* We have a pb here: RA timer max possible value is 1800s,
00933    * hence we have to use stimers. However, when receiving a RS, we
00934    * should delay the reply by a random value between 0 and 500ms timers.
00935    * stimers are in seconds, hence we cannot do this. Therefore we just send
00936    * the RA (setting the timer to 0 below). We keep the code logic for
00937    * the days contiki will support appropriate timers */
00938   rand_time = 0;
00939   PRINTF("Solicited RA, random time %u\n", rand_time);
00940 
00941   if(stimer_remaining(&uip_ds6_timer_ra) > rand_time) {
00942     if(stimer_elapsed(&uip_ds6_timer_ra) < UIP_ND6_MIN_DELAY_BETWEEN_RAS) {
00943       /* Ensure that the RAs are rate limited */
00944 /*      stimer_set(&uip_ds6_timer_ra, rand_time +
00945                  UIP_ND6_MIN_DELAY_BETWEEN_RAS -
00946                  stimer_elapsed(&uip_ds6_timer_ra));
00947   */ } else {
00948       stimer_set(&uip_ds6_timer_ra, rand_time);
00949     }
00950   }
00951 }
00952 
00953 /*---------------------------------------------------------------------------*/
00954 void
00955 uip_ds6_send_ra_periodic(void)
00956 {
00957   if(racount > 0) {
00958     /* send previously scheduled RA */
00959     uip_nd6_ra_output(NULL);
00960     PRINTF("Sending periodic RA\n");
00961   }
00962 
00963   rand_time = UIP_ND6_MIN_RA_INTERVAL + random_rand() %
00964     (uint16_t) (UIP_ND6_MAX_RA_INTERVAL - UIP_ND6_MIN_RA_INTERVAL);
00965   PRINTF("Random time 1 = %u\n", rand_time);
00966 
00967   if(racount < UIP_ND6_MAX_INITIAL_RAS) {
00968     if(rand_time > UIP_ND6_MAX_INITIAL_RA_INTERVAL) {
00969       rand_time = UIP_ND6_MAX_INITIAL_RA_INTERVAL;
00970       PRINTF("Random time 2 = %u\n", rand_time);
00971     }
00972     racount++;
00973   }
00974   PRINTF("Random time 3 = %u\n", rand_time);
00975   stimer_set(&uip_ds6_timer_ra, rand_time);
00976 }
00977 
00978 #endif /* UIP_ND6_SEND_RA */
00979 #else /* UIP_CONF_ROUTER */
00980 /*---------------------------------------------------------------------------*/
00981 void
00982 uip_ds6_send_rs(void)
00983 {
00984   if((uip_ds6_defrt_choose() == NULL)
00985      && (rscount < UIP_ND6_MAX_RTR_SOLICITATIONS)) {
00986     PRINTF("Sending RS %u\n", rscount);
00987     uip_nd6_rs_output();
00988     rscount++;
00989     etimer_set(&uip_ds6_timer_rs,
00990                UIP_ND6_RTR_SOLICITATION_INTERVAL * CLOCK_SECOND);
00991   } else {
00992     PRINTF("Router found ? (boolean): %u\n",
00993            (uip_ds6_defrt_choose() != NULL));
00994     etimer_stop(&uip_ds6_timer_rs);
00995   }
00996   return;
00997 }
00998 
00999 #endif /* UIP_CONF_ROUTER */
01000 /*---------------------------------------------------------------------------*/
01001 uint32_t
01002 uip_ds6_compute_reachable_time(void)
01003 {
01004   return (uint32_t) (UIP_ND6_MIN_RANDOM_FACTOR
01005                      (uip_ds6_if.base_reachable_time)) +
01006     ((uint16_t) (random_rand() << 8) +
01007      (uint16_t) random_rand()) %
01008     (uint32_t) (UIP_ND6_MAX_RANDOM_FACTOR(uip_ds6_if.base_reachable_time) -
01009                 UIP_ND6_MIN_RANDOM_FACTOR(uip_ds6_if.base_reachable_time));
01010 }
01011 
01012 
01013 /** @} */

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