Contiki 2.6

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