Contiki 2.6
|
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 /** @} */