Contiki 2.5
uip-ds6.c
Go to the documentation of this file.
1 /**
2  * \addtogroup uip6
3  * @{
4  */
5 
6 /**
7  * \file
8  * IPv6 data structures handling functions
9  * Comprises part of the Neighbor discovery (RFC 4861)
10  * and auto configuration (RFC 4862 )state machines
11  * \author Mathilde Durvy <mdurvy@cisco.com>
12  * \author Julien Abeille <jabeille@cisco.com>
13  */
14 /*
15  * Copyright (c) 2006, Swedish Institute of Computer Science.
16  * All rights reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  * notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  * notice, this list of conditions and the following disclaimer in the
25  * documentation and/or other materials provided with the distribution.
26  * 3. Neither the name of the Institute nor the names of its contributors
27  * may be used to endorse or promote products derived from this software
28  * without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  */
43 #include <string.h>
44 #include <stdlib.h>
45 #include "lib/random.h"
46 #include "net/uip-nd6.h"
47 #include "net/uip-ds6.h"
48 #include "net/uip-packetqueue.h"
49 
50 #define DEBUG DEBUG_NONE
51 #include "net/uip-debug.h"
52 
53 #ifdef UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED
54 #define NEIGHBOR_STATE_CHANGED(n) UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED(n)
55 void NEIGHBOR_STATE_CHANGED(uip_ds6_nbr_t *n);
56 #else
57 #define NEIGHBOR_STATE_CHANGED(n)
58 #endif /* UIP_DS6_CONF_NEIGHBOR_STATE_CHANGED */
59 
60 struct etimer uip_ds6_timer_periodic; /** \brief Timer for maintenance of data structures */
61 
62 #if UIP_CONF_ROUTER
63 struct stimer uip_ds6_timer_ra; /** \brief RA timer, to schedule RA sending */
64 #if UIP_ND6_SEND_RA
65 static uint8_t racount; /** \brief number of RA already sent */
66 static uint16_t rand_time; /** \brief random time value for timers */
67 #endif
68 #else /* UIP_CONF_ROUTER */
69 struct etimer uip_ds6_timer_rs; /** \brief RS timer, to schedule RS sending */
70 static uint8_t rscount; /** \brief number of rs already sent */
71 #endif /* UIP_CONF_ROUTER */
72 
73 /** \name "DS6" Data structures */
74 /** @{ */
75 uip_ds6_netif_t uip_ds6_if; /** \brief The single interface */
76 uip_ds6_nbr_t uip_ds6_nbr_cache[UIP_DS6_NBR_NB]; /** \brief Neighor cache */
77 uip_ds6_defrt_t uip_ds6_defrt_list[UIP_DS6_DEFRT_NB]; /** \brief Default rt list */
78 uip_ds6_prefix_t uip_ds6_prefix_list[UIP_DS6_PREFIX_NB]; /** \brief Prefix list */
79 uip_ds6_route_t uip_ds6_routing_table[UIP_DS6_ROUTE_NB]; /** \brief Routing table */
80 
81 /** @} */
82 
83 /* "full" (as opposed to pointer) ip address used in this file, */
84 static uip_ipaddr_t loc_fipaddr;
85 
86 /* Pointers used in this file */
87 static uip_ipaddr_t *locipaddr;
88 static uip_ds6_addr_t *locaddr;
89 static uip_ds6_maddr_t *locmaddr;
90 static uip_ds6_aaddr_t *locaaddr;
91 static uip_ds6_prefix_t *locprefix;
92 static uip_ds6_nbr_t *locnbr;
93 static uip_ds6_defrt_t *locdefrt;
94 static uip_ds6_route_t *locroute;
95 
96 /*---------------------------------------------------------------------------*/
97 void
99 {
100  PRINTF("Init of IPv6 data structures\n");
101  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",
102  UIP_DS6_NBR_NB, UIP_DS6_DEFRT_NB, UIP_DS6_PREFIX_NB, UIP_DS6_ROUTE_NB,
103  UIP_DS6_ADDR_NB, UIP_DS6_MADDR_NB, UIP_DS6_AADDR_NB);
104  memset(uip_ds6_nbr_cache, 0, sizeof(uip_ds6_nbr_cache));
105  memset(uip_ds6_defrt_list, 0, sizeof(uip_ds6_defrt_list));
106  memset(uip_ds6_prefix_list, 0, sizeof(uip_ds6_prefix_list));
107  memset(&uip_ds6_if, 0, sizeof(uip_ds6_if));
108  memset(uip_ds6_routing_table, 0, sizeof(uip_ds6_routing_table));
109 
110  /* Set interface parameters */
111  uip_ds6_if.link_mtu = UIP_LINK_MTU;
112  uip_ds6_if.cur_hop_limit = UIP_TTL;
113  uip_ds6_if.base_reachable_time = UIP_ND6_REACHABLE_TIME;
114  uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time();
115  uip_ds6_if.retrans_timer = UIP_ND6_RETRANS_TIMER;
116  uip_ds6_if.maxdadns = UIP_ND6_DEF_MAXDADNS;
117 
118  /* Create link local address, prefix, multicast addresses, anycast addresses */
119  uip_create_linklocal_prefix(&loc_fipaddr);
120 #if UIP_CONF_ROUTER
121  uip_ds6_prefix_add(&loc_fipaddr, UIP_DEFAULT_PREFIX_LEN, 0, 0, 0, 0);
122 #else /* UIP_CONF_ROUTER */
123  uip_ds6_prefix_add(&loc_fipaddr, UIP_DEFAULT_PREFIX_LEN, 0);
124 #endif /* UIP_CONF_ROUTER */
125  uip_ds6_set_addr_iid(&loc_fipaddr, &uip_lladdr);
126  uip_ds6_addr_add(&loc_fipaddr, 0, ADDR_AUTOCONF);
127 
128  uip_create_linklocal_allnodes_mcast(&loc_fipaddr);
129  uip_ds6_maddr_add(&loc_fipaddr);
130 #if UIP_CONF_ROUTER
131  uip_create_linklocal_allrouters_mcast(&loc_fipaddr);
132  uip_ds6_maddr_add(&loc_fipaddr);
133 #if UIP_ND6_SEND_RA
134  stimer_set(&uip_ds6_timer_ra, 2); /* wait to have a link local IP address */
135 #endif /* UIP_ND6_SEND_RA */
136 #else /* UIP_CONF_ROUTER */
138  random_rand() % (UIP_ND6_MAX_RTR_SOLICITATION_DELAY *
139  CLOCK_SECOND));
140 #endif /* UIP_CONF_ROUTER */
141  etimer_set(&uip_ds6_timer_periodic, UIP_DS6_PERIOD);
142 
143  return;
144 }
145 
146 
147 /*---------------------------------------------------------------------------*/
148 void
150 {
151  /* Periodic processing on unicast addresses */
152  for(locaddr = uip_ds6_if.addr_list;
153  locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) {
154  if(locaddr->isused) {
155  if((!locaddr->isinfinite) && (stimer_expired(&locaddr->vlifetime))) {
156  uip_ds6_addr_rm(locaddr);
157  } else if((locaddr->state == ADDR_TENTATIVE)
158  && (locaddr->dadnscount <= uip_ds6_if.maxdadns)
159  && (timer_expired(&locaddr->dadtimer))) {
160  uip_ds6_dad(locaddr);
161  }
162  }
163  }
164 
165  /* Periodic processing on default routers */
166  for(locdefrt = uip_ds6_defrt_list;
167  locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) {
168  if((locdefrt->isused) && (!locdefrt->isinfinite) &&
169  (stimer_expired(&(locdefrt->lifetime)))) {
170  uip_ds6_defrt_rm(locdefrt);
171  }
172  }
173 
174 #if !UIP_CONF_ROUTER
175  /* Periodic processing on prefixes */
176  for(locprefix = uip_ds6_prefix_list;
177  locprefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB;
178  locprefix++) {
179  if(locprefix->isused && !locprefix->isinfinite
180  && stimer_expired(&(locprefix->vlifetime))) {
181  uip_ds6_prefix_rm(locprefix);
182  }
183  }
184 #endif /* !UIP_CONF_ROUTER */
185 
186  /* Periodic processing on neighbors */
187  for(locnbr = uip_ds6_nbr_cache;
188  locnbr < uip_ds6_nbr_cache + UIP_DS6_NBR_NB;
189  locnbr++) {
190  if(locnbr->isused) {
191  switch(locnbr->state) {
192  case NBR_INCOMPLETE:
193  if(locnbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
194  uip_ds6_nbr_rm(locnbr);
195  } else if(stimer_expired(&locnbr->sendns)) {
196  locnbr->nscount++;
197  PRINTF("NBR_INCOMPLETE: NS %u\n", locnbr->nscount);
198  uip_nd6_ns_output(NULL, NULL, &locnbr->ipaddr);
199  stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000);
200  }
201  break;
202  case NBR_REACHABLE:
203  if(stimer_expired(&locnbr->reachable)) {
204  PRINTF("REACHABLE: moving to STALE (");
205  PRINT6ADDR(&locnbr->ipaddr);
206  PRINTF(")\n");
207  locnbr->state = NBR_STALE;
208  }
209  break;
210  case NBR_DELAY:
211  if(stimer_expired(&locnbr->reachable)) {
212  locnbr->state = NBR_PROBE;
213  locnbr->nscount = 1;
214  PRINTF("DELAY: moving to PROBE + NS %u\n", locnbr->nscount);
215  uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr);
216  stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000);
217  }
218  break;
219  case NBR_PROBE:
220  if(locnbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
221  PRINTF("PROBE END\n");
222  if((locdefrt = uip_ds6_defrt_lookup(&locnbr->ipaddr)) != NULL) {
223  uip_ds6_defrt_rm(locdefrt);
224  }
225  uip_ds6_nbr_rm(locnbr);
226  } else if(stimer_expired(&locnbr->sendns)) {
227  locnbr->nscount++;
228  PRINTF("PROBE: NS %u\n", locnbr->nscount);
229  uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr);
230  stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000);
231  }
232  break;
233  default:
234  break;
235  }
236  }
237  }
238 
239 #if UIP_CONF_ROUTER & UIP_ND6_SEND_RA
240  /* Periodic RA sending */
241  if(stimer_expired(&uip_ds6_timer_ra)) {
242  uip_ds6_send_ra_periodic();
243  }
244 #endif /* UIP_CONF_ROUTER & UIP_ND6_SEND_RA */
245  etimer_reset(&uip_ds6_timer_periodic);
246  return;
247 }
248 
249 /*---------------------------------------------------------------------------*/
250 uint8_t
252  uint16_t elementsize, uip_ipaddr_t *ipaddr,
253  uint8_t ipaddrlen, uip_ds6_element_t **out_element)
254 {
255  uip_ds6_element_t *element;
256 
257  *out_element = NULL;
258 
259  for(element = list;
260  element <
261  (uip_ds6_element_t *)((uint8_t *)list + (size * elementsize));
262  element = (uip_ds6_element_t *)((uint8_t *)element + elementsize)) {
263  if(element->isused) {
264  if(uip_ipaddr_prefixcmp(&element->ipaddr, ipaddr, ipaddrlen)) {
265  *out_element = element;
266  return FOUND;
267  }
268  } else {
269  *out_element = element;
270  }
271  }
272 
273  return *out_element != NULL ? FREESPACE : NOSPACE;
274 }
275 
276 /*---------------------------------------------------------------------------*/
278 uip_ds6_nbr_add(uip_ipaddr_t *ipaddr, uip_lladdr_t * lladdr,
279  uint8_t isrouter, uint8_t state)
280 {
281  int r;
282 
284  ((uip_ds6_element_t *)uip_ds6_nbr_cache, UIP_DS6_NBR_NB,
285  sizeof(uip_ds6_nbr_t), ipaddr, 128,
286  (uip_ds6_element_t **)&locnbr);
287 
288  if(r == FREESPACE) {
289  locnbr->isused = 1;
290  uip_ipaddr_copy(&locnbr->ipaddr, ipaddr);
291  if(lladdr != NULL) {
292  memcpy(&locnbr->lladdr, lladdr, UIP_LLADDR_LEN);
293  } else {
294  memset(&locnbr->lladdr, 0, UIP_LLADDR_LEN);
295  }
296  locnbr->isrouter = isrouter;
297  locnbr->state = state;
298 #if UIP_CONF_IPV6_QUEUE_PKT
299  uip_packetqueue_new(&locnbr->packethandle);
300 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
301  /* timers are set separately, for now we put them in expired state */
302  stimer_set(&locnbr->reachable, 0);
303  stimer_set(&locnbr->sendns, 0);
304  locnbr->nscount = 0;
305  PRINTF("Adding neighbor with ip addr ");
306  PRINT6ADDR(ipaddr);
307  PRINTF("link addr ");
308  PRINTLLADDR((&(locnbr->lladdr)));
309  PRINTF("state %u\n", state);
310  NEIGHBOR_STATE_CHANGED(locnbr);
311 
312  locnbr->last_lookup = clock_time();
313  return locnbr;
314  } else if(r == NOSPACE) {
315  /* We did not find any empty slot on the neighbor list, so we need
316  to remove one old entry to make room. */
317  uip_ds6_nbr_t *n, *oldest;
318  clock_time_t oldest_time;
319 
320  oldest = NULL;
321  oldest_time = clock_time();
322 
323  for(n = uip_ds6_nbr_cache;
324  n < &uip_ds6_nbr_cache[UIP_DS6_NBR_NB];
325  n++) {
326  if(n->isused) {
327  if(n->last_lookup < oldest_time) {
328  oldest = n;
329  oldest_time = n->last_lookup;
330  }
331  }
332  }
333  if(oldest != NULL) {
334  uip_ds6_nbr_rm(oldest);
335  return uip_ds6_nbr_add(ipaddr, lladdr, isrouter, state);
336  }
337  }
338  PRINTF("uip_ds6_nbr_add drop\n");
339  return NULL;
340 }
341 
342 /*---------------------------------------------------------------------------*/
343 void
344 uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr)
345 {
346  if(nbr != NULL) {
347  nbr->isused = 0;
348 #if UIP_CONF_IPV6_QUEUE_PKT
349  uip_packetqueue_free(&nbr->packethandle);
350 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
351  NEIGHBOR_STATE_CHANGED(nbr);
352  }
353  return;
354 }
355 
356 /*---------------------------------------------------------------------------*/
358 uip_ds6_nbr_lookup(uip_ipaddr_t *ipaddr)
359 {
361  ((uip_ds6_element_t *)uip_ds6_nbr_cache, UIP_DS6_NBR_NB,
362  sizeof(uip_ds6_nbr_t), ipaddr, 128,
363  (uip_ds6_element_t **)&locnbr) == FOUND) {
364  return locnbr;
365  }
366  return NULL;
367 }
368 
369 /*---------------------------------------------------------------------------*/
371 uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval)
372 {
374  ((uip_ds6_element_t *)uip_ds6_defrt_list, UIP_DS6_DEFRT_NB,
375  sizeof(uip_ds6_defrt_t), ipaddr, 128,
376  (uip_ds6_element_t **)&locdefrt) == FREESPACE) {
377  locdefrt->isused = 1;
378  uip_ipaddr_copy(&locdefrt->ipaddr, ipaddr);
379  if(interval != 0) {
380  stimer_set(&locdefrt->lifetime, interval);
381  locdefrt->isinfinite = 0;
382  } else {
383  locdefrt->isinfinite = 1;
384  }
385 
386  PRINTF("Adding defrouter with ip addr ");
387  PRINT6ADDR(&locdefrt->ipaddr);
388  PRINTF("\n");
389 
390  ANNOTATE("#L %u 1\n", ipaddr->u8[sizeof(uip_ipaddr_t) - 1]);
391 
392  return locdefrt;
393  }
394  return NULL;
395 }
396 
397 /*---------------------------------------------------------------------------*/
398 void
399 uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt)
400 {
401  if(defrt != NULL) {
402  defrt->isused = 0;
403  ANNOTATE("#L %u 0\n", defrt->ipaddr.u8[sizeof(uip_ipaddr_t) - 1]);
404  }
405  return;
406 }
407 
408 /*---------------------------------------------------------------------------*/
410 uip_ds6_defrt_lookup(uip_ipaddr_t *ipaddr)
411 {
412  if(uip_ds6_list_loop((uip_ds6_element_t *)uip_ds6_defrt_list,
413  UIP_DS6_DEFRT_NB, sizeof(uip_ds6_defrt_t), ipaddr, 128,
414  (uip_ds6_element_t **)&locdefrt) == FOUND) {
415  return locdefrt;
416  }
417  return NULL;
418 }
419 
420 /*---------------------------------------------------------------------------*/
421 uip_ipaddr_t *
422 uip_ds6_defrt_choose(void)
423 {
424  uip_ds6_nbr_t *bestnbr;
425 
426  locipaddr = NULL;
427  for(locdefrt = uip_ds6_defrt_list;
428  locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) {
429  if(locdefrt->isused) {
430  PRINTF("Defrt, IP address ");
431  PRINT6ADDR(&locdefrt->ipaddr);
432  PRINTF("\n");
433  bestnbr = uip_ds6_nbr_lookup(&locdefrt->ipaddr);
434  if(bestnbr != NULL && bestnbr->state != NBR_INCOMPLETE) {
435  PRINTF("Defrt found, IP address ");
436  PRINT6ADDR(&locdefrt->ipaddr);
437  PRINTF("\n");
438  return &locdefrt->ipaddr;
439  } else {
440  locipaddr = &locdefrt->ipaddr;
441  PRINTF("Defrt INCOMPLETE found, IP address ");
442  PRINT6ADDR(&locdefrt->ipaddr);
443  PRINTF("\n");
444  }
445  }
446  }
447  return locipaddr;
448 }
449 
450 #if UIP_CONF_ROUTER
451 /*---------------------------------------------------------------------------*/
453 uip_ds6_prefix_add(uip_ipaddr_t *ipaddr, uint8_t ipaddrlen,
454  uint8_t advertise, uint8_t flags, unsigned long vtime,
455  unsigned long ptime)
456 {
458  ((uip_ds6_element_t *)uip_ds6_prefix_list, UIP_DS6_PREFIX_NB,
459  sizeof(uip_ds6_prefix_t), ipaddr, ipaddrlen,
460  (uip_ds6_element_t **)&locprefix) == FREESPACE) {
461  locprefix->isused = 1;
462  uip_ipaddr_copy(&locprefix->ipaddr, ipaddr);
463  locprefix->length = ipaddrlen;
464  locprefix->advertise = advertise;
465  locprefix->l_a_reserved = flags;
466  locprefix->vlifetime = vtime;
467  locprefix->plifetime = ptime;
468  PRINTF("Adding prefix ");
469  PRINT6ADDR(&locprefix->ipaddr);
470  PRINTF("length %u, flags %x, Valid lifetime %lx, Preffered lifetime %lx\n",
471  ipaddrlen, flags, vtime, ptime);
472  return locprefix;
473  } else {
474  PRINTF("No more space in Prefix list\n");
475  }
476  return NULL;
477 }
478 
479 
480 #else /* UIP_CONF_ROUTER */
482 uip_ds6_prefix_add(uip_ipaddr_t *ipaddr, uint8_t ipaddrlen,
483  unsigned long interval)
484 {
486  ((uip_ds6_element_t *)uip_ds6_prefix_list, UIP_DS6_PREFIX_NB,
487  sizeof(uip_ds6_prefix_t), ipaddr, ipaddrlen,
488  (uip_ds6_element_t **)&locprefix) == FREESPACE) {
489  locprefix->isused = 1;
490  uip_ipaddr_copy(&locprefix->ipaddr, ipaddr);
491  locprefix->length = ipaddrlen;
492  if(interval != 0) {
493  stimer_set(&(locprefix->vlifetime), interval);
494  locprefix->isinfinite = 0;
495  } else {
496  locprefix->isinfinite = 1;
497  }
498  PRINTF("Adding prefix ");
499  PRINT6ADDR(&locprefix->ipaddr);
500  PRINTF("length %u, vlifetime%lu\n", ipaddrlen, interval);
501  }
502  return NULL;
503 }
504 #endif /* UIP_CONF_ROUTER */
505 
506 /*---------------------------------------------------------------------------*/
507 void
508 uip_ds6_prefix_rm(uip_ds6_prefix_t * prefix)
509 {
510  if(prefix != NULL) {
511  prefix->isused = 0;
512  }
513  return;
514 }
515 /*---------------------------------------------------------------------------*/
517 uip_ds6_prefix_lookup(uip_ipaddr_t *ipaddr, uint8_t ipaddrlen)
518 {
519  if(uip_ds6_list_loop((uip_ds6_element_t *)uip_ds6_prefix_list,
520  UIP_DS6_PREFIX_NB, sizeof(uip_ds6_prefix_t),
521  ipaddr, ipaddrlen,
522  (uip_ds6_element_t **)&locprefix) == FOUND) {
523  return locprefix;
524  }
525  return NULL;
526 }
527 
528 /*---------------------------------------------------------------------------*/
529 uint8_t
530 uip_ds6_is_addr_onlink(uip_ipaddr_t *ipaddr)
531 {
532  for(locprefix = uip_ds6_prefix_list;
533  locprefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; locprefix++) {
534  if(locprefix->isused &&
535  uip_ipaddr_prefixcmp(&locprefix->ipaddr, ipaddr, locprefix->length)) {
536  return 1;
537  }
538  }
539  return 0;
540 }
541 
542 /*---------------------------------------------------------------------------*/
544 uip_ds6_addr_add(uip_ipaddr_t *ipaddr, unsigned long vlifetime, uint8_t type)
545 {
547  ((uip_ds6_element_t *)uip_ds6_if.addr_list, UIP_DS6_ADDR_NB,
548  sizeof(uip_ds6_addr_t), ipaddr, 128,
549  (uip_ds6_element_t **)&locaddr) == FREESPACE) {
550  locaddr->isused = 1;
551  uip_ipaddr_copy(&locaddr->ipaddr, ipaddr);
552  locaddr->state = ADDR_TENTATIVE;
553  locaddr->type = type;
554  if(vlifetime == 0) {
555  locaddr->isinfinite = 1;
556  } else {
557  locaddr->isinfinite = 0;
558  stimer_set(&(locaddr->vlifetime), vlifetime);
559  }
560  timer_set(&locaddr->dadtimer,
561  random_rand() % (UIP_ND6_MAX_RTR_SOLICITATION_DELAY *
562  CLOCK_SECOND));
563  locaddr->dadnscount = 0;
564  uip_create_solicited_node(ipaddr, &loc_fipaddr);
565  uip_ds6_maddr_add(&loc_fipaddr);
566  return locaddr;
567  }
568  return NULL;
569 }
570 
571 /*---------------------------------------------------------------------------*/
572 void
573 uip_ds6_addr_rm(uip_ds6_addr_t *addr)
574 {
575  if(addr != NULL) {
576  uip_create_solicited_node(&addr->ipaddr, &loc_fipaddr);
577  if((locmaddr = uip_ds6_maddr_lookup(&loc_fipaddr)) != NULL) {
578  uip_ds6_maddr_rm(locmaddr);
579  }
580  addr->isused = 0;
581  }
582  return;
583 }
584 
585 /*---------------------------------------------------------------------------*/
587 uip_ds6_addr_lookup(uip_ipaddr_t *ipaddr)
588 {
590  ((uip_ds6_element_t *)uip_ds6_if.addr_list, UIP_DS6_ADDR_NB,
591  sizeof(uip_ds6_addr_t), ipaddr, 128,
592  (uip_ds6_element_t **)&locaddr) == FOUND) {
593  return locaddr;
594  }
595  return NULL;
596 }
597 
598 /*---------------------------------------------------------------------------*/
599 /*
600  * get a link local address -
601  * state = -1 => any address is ok. Otherwise state = desired state of addr.
602  * (TENTATIVE, PREFERRED, DEPRECATED)
603  */
605 uip_ds6_get_link_local(int8_t state)
606 {
607  for(locaddr = uip_ds6_if.addr_list;
608  locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) {
609  if(locaddr->isused && (state == -1 || locaddr->state == state)
610  && (uip_is_addr_link_local(&locaddr->ipaddr))) {
611  return locaddr;
612  }
613  }
614  return NULL;
615 }
616 
617 /*---------------------------------------------------------------------------*/
618 /*
619  * get a global address -
620  * state = -1 => any address is ok. Otherwise state = desired state of addr.
621  * (TENTATIVE, PREFERRED, DEPRECATED)
622  */
624 uip_ds6_get_global(int8_t state)
625 {
626  for(locaddr = uip_ds6_if.addr_list;
627  locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) {
628  if(locaddr->isused && (state == -1 || locaddr->state == state)
629  && !(uip_is_addr_link_local(&locaddr->ipaddr))) {
630  return locaddr;
631  }
632  }
633  return NULL;
634 }
635 
636 /*---------------------------------------------------------------------------*/
638 uip_ds6_maddr_add(uip_ipaddr_t *ipaddr)
639 {
641  ((uip_ds6_element_t *)uip_ds6_if.maddr_list, UIP_DS6_MADDR_NB,
642  sizeof(uip_ds6_maddr_t), ipaddr, 128,
643  (uip_ds6_element_t **)&locmaddr) == FREESPACE) {
644  locmaddr->isused = 1;
645  uip_ipaddr_copy(&locmaddr->ipaddr, ipaddr);
646  return locmaddr;
647  }
648  return NULL;
649 }
650 
651 /*---------------------------------------------------------------------------*/
652 void
653 uip_ds6_maddr_rm(uip_ds6_maddr_t * maddr)
654 {
655  if(maddr != NULL) {
656  maddr->isused = 0;
657  }
658  return;
659 }
660 
661 /*---------------------------------------------------------------------------*/
663 uip_ds6_maddr_lookup(uip_ipaddr_t *ipaddr)
664 {
666  ((uip_ds6_element_t *)uip_ds6_if.maddr_list, UIP_DS6_MADDR_NB,
667  sizeof(uip_ds6_maddr_t), ipaddr, 128,
668  (uip_ds6_element_t **)&locmaddr) == FOUND) {
669  return locmaddr;
670  }
671  return NULL;
672 }
673 
674 
675 /*---------------------------------------------------------------------------*/
677 uip_ds6_aaddr_add(uip_ipaddr_t *ipaddr)
678 {
680  ((uip_ds6_element_t *)uip_ds6_if.aaddr_list, UIP_DS6_AADDR_NB,
681  sizeof(uip_ds6_aaddr_t), ipaddr, 128,
682  (uip_ds6_element_t **)&locaaddr) == FREESPACE) {
683  locaaddr->isused = 1;
684  uip_ipaddr_copy(&locaaddr->ipaddr, ipaddr);
685  return locaaddr;
686  }
687  return NULL;
688 }
689 
690 /*---------------------------------------------------------------------------*/
691 void
692 uip_ds6_aaddr_rm(uip_ds6_aaddr_t * aaddr)
693 {
694  if(aaddr != NULL) {
695  aaddr->isused = 0;
696  }
697  return;
698 }
699 
700 /*---------------------------------------------------------------------------*/
702 uip_ds6_aaddr_lookup(uip_ipaddr_t *ipaddr)
703 {
704  if(uip_ds6_list_loop((uip_ds6_element_t *)uip_ds6_if.aaddr_list,
705  UIP_DS6_AADDR_NB, sizeof(uip_ds6_aaddr_t), ipaddr, 128,
706  (uip_ds6_element_t **)&locaaddr) == FOUND) {
707  return locaaddr;
708  }
709  return NULL;
710 }
711 
712 /*---------------------------------------------------------------------------*/
714 uip_ds6_route_lookup(uip_ipaddr_t *destipaddr)
715 {
716  uip_ds6_route_t *locrt = NULL;
717  uint8_t longestmatch = 0;
718 
719  PRINTF("DS6: Looking up route for ");
720  PRINT6ADDR(destipaddr);
721  PRINTF("\n");
722 
723  for(locroute = uip_ds6_routing_table;
724  locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB; locroute++) {
725  if((locroute->isused) && (locroute->length >= longestmatch)
726  &&
727  (uip_ipaddr_prefixcmp
728  (destipaddr, &locroute->ipaddr, locroute->length))) {
729  longestmatch = locroute->length;
730  locrt = locroute;
731  }
732  }
733 
734  if(locrt != NULL) {
735  PRINTF("DS6: Found route:");
736  PRINT6ADDR(destipaddr);
737  PRINTF(" via ");
738  PRINT6ADDR(&locrt->nexthop);
739  PRINTF("\n");
740  } else {
741  PRINTF("DS6: No route found\n");
742  }
743 
744  return locrt;
745 }
746 
747 /*---------------------------------------------------------------------------*/
749 uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop,
750  uint8_t metric)
751 {
753  ((uip_ds6_element_t *)uip_ds6_routing_table, UIP_DS6_ROUTE_NB,
754  sizeof(uip_ds6_route_t), ipaddr, length,
755  (uip_ds6_element_t **)&locroute) == FREESPACE) {
756  locroute->isused = 1;
757  uip_ipaddr_copy(&(locroute->ipaddr), ipaddr);
758  locroute->length = length;
759  uip_ipaddr_copy(&(locroute->nexthop), nexthop);
760  locroute->metric = metric;
761 
762  PRINTF("DS6: adding route: ");
763  PRINT6ADDR(ipaddr);
764  PRINTF(" via ");
765  PRINT6ADDR(nexthop);
766  PRINTF("\n");
767  ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
768  }
769 
770  return locroute;
771 }
772 
773 /*---------------------------------------------------------------------------*/
774 void
775 uip_ds6_route_rm(uip_ds6_route_t *route)
776 {
777  route->isused = 0;
778 #if (DEBUG & DEBUG_ANNOTATE) == DEBUG_ANNOTATE
779  /* we need to check if this was the last route towards "nexthop" */
780  /* if so - remove that link (annotation) */
781  for(locroute = uip_ds6_routing_table;
782  locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB;
783  locroute++) {
784  if(locroute->isused && uip_ipaddr_cmp(&locroute->nexthop, &route->nexthop)) {
785  /* we found another link using the specific nexthop, so keep the #L */
786  return;
787  }
788  }
789  ANNOTATE("#L %u 0\n",route->nexthop.u8[sizeof(uip_ipaddr_t) - 1]);
790 #endif
791 }
792 /*---------------------------------------------------------------------------*/
793 void
794 uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
795 {
796  for(locroute = uip_ds6_routing_table;
797  locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB;
798  locroute++) {
799  if(locroute->isused && uip_ipaddr_cmp(&locroute->nexthop, nexthop)) {
800  locroute->isused = 0;
801  }
802  }
803  ANNOTATE("#L %u 0\n",nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
804 }
805 
806 /*---------------------------------------------------------------------------*/
807 void
809 {
810  uint8_t best = 0; /* number of bit in common with best match */
811  uint8_t n = 0;
812  uip_ds6_addr_t *matchaddr = NULL;
813 
814  if(!uip_is_addr_link_local(dst) && !uip_is_addr_mcast(dst)) {
815  /* find longest match */
816  for(locaddr = uip_ds6_if.addr_list;
817  locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) {
818  /* Only preferred global (not link-local) addresses */
819  if(locaddr->isused && locaddr->state == ADDR_PREFERRED &&
820  !uip_is_addr_link_local(&locaddr->ipaddr)) {
821  n = get_match_length(dst, &locaddr->ipaddr);
822  if(n >= best) {
823  best = n;
824  matchaddr = locaddr;
825  }
826  }
827  }
828  } else {
829  matchaddr = uip_ds6_get_link_local(ADDR_PREFERRED);
830  }
831 
832  /* use the :: (unspecified address) as source if no match found */
833  if(matchaddr == NULL) {
834  uip_create_unspecified(src);
835  } else {
836  uip_ipaddr_copy(src, &matchaddr->ipaddr);
837  }
838 }
839 
840 /*---------------------------------------------------------------------------*/
841 void
843 {
844  /* We consider only links with IEEE EUI-64 identifier or
845  * IEEE 48-bit MAC addresses */
846 #if (UIP_LLADDR_LEN == 8)
847  memcpy(ipaddr->u8 + 8, lladdr, UIP_LLADDR_LEN);
848  ipaddr->u8[8] ^= 0x02;
849 #elif (UIP_LLADDR_LEN == 6)
850  memcpy(ipaddr->u8 + 8, lladdr, 3);
851  ipaddr->u8[11] = 0xff;
852  ipaddr->u8[12] = 0xfe;
853  memcpy(ipaddr->u8 + 13, (uint8_t *)lladdr + 3, 3);
854  ipaddr->u8[8] ^= 0x02;
855 #else
856 #error uip-ds6.c cannot build interface address when UIP_LLADDR_LEN is not 6 or 8
857 #endif
858 }
859 
860 /*---------------------------------------------------------------------------*/
861 uint8_t
863 {
864  uint8_t j, k, x_or;
865  uint8_t len = 0;
866 
867  for(j = 0; j < 16; j++) {
868  if(src->u8[j] == dst->u8[j]) {
869  len += 8;
870  } else {
871  x_or = src->u8[j] ^ dst->u8[j];
872  for(k = 0; k < 8; k++) {
873  if((x_or & 0x80) == 0) {
874  len++;
875  x_or <<= 1;
876  } else {
877  break;
878  }
879  }
880  break;
881  }
882  }
883  return len;
884 }
885 
886 /*---------------------------------------------------------------------------*/
887 void
889 {
890  /* send maxdadns NS for DAD */
891  if(addr->dadnscount < uip_ds6_if.maxdadns) {
892  uip_nd6_ns_output(NULL, NULL, &addr->ipaddr);
893  addr->dadnscount++;
894  timer_set(&addr->dadtimer,
895  uip_ds6_if.retrans_timer / 1000 * CLOCK_SECOND);
896  return;
897  }
898  /*
899  * If we arrive here it means DAD succeeded, otherwise the dad process
900  * would have been interrupted in ds6_dad_ns/na_input
901  */
902  PRINTF("DAD succeeded, ipaddr:");
903  PRINT6ADDR(&addr->ipaddr);
904  PRINTF("\n");
905 
906  addr->state = ADDR_PREFERRED;
907  return;
908 }
909 
910 /*---------------------------------------------------------------------------*/
911 /*
912  * Calling code must handle when this returns 0 (e.g. link local
913  * address can not be used).
914  */
915 int
917 {
918  if(uip_is_addr_link_local(&addr->ipaddr)) {
919  PRINTF("Contiki shutdown, DAD for link local address failed\n");
920  return 0;
921  }
922  uip_ds6_addr_rm(addr);
923  return 1;
924 }
925 
926 #if UIP_CONF_ROUTER
927 #if UIP_ND6_SEND_RA
928 /*---------------------------------------------------------------------------*/
929 void
930 uip_ds6_send_ra_sollicited(void)
931 {
932  /* We have a pb here: RA timer max possible value is 1800s,
933  * hence we have to use stimers. However, when receiving a RS, we
934  * should delay the reply by a random value between 0 and 500ms timers.
935  * stimers are in seconds, hence we cannot do this. Therefore we just send
936  * the RA (setting the timer to 0 below). We keep the code logic for
937  * the days contiki will support appropriate timers */
938  rand_time = 0;
939  PRINTF("Solicited RA, random time %u\n", rand_time);
940 
941  if(stimer_remaining(&uip_ds6_timer_ra) > rand_time) {
942  if(stimer_elapsed(&uip_ds6_timer_ra) < UIP_ND6_MIN_DELAY_BETWEEN_RAS) {
943  /* Ensure that the RAs are rate limited */
944 /* stimer_set(&uip_ds6_timer_ra, rand_time +
945  UIP_ND6_MIN_DELAY_BETWEEN_RAS -
946  stimer_elapsed(&uip_ds6_timer_ra));
947  */ } else {
948  stimer_set(&uip_ds6_timer_ra, rand_time);
949  }
950  }
951 }
952 
953 /*---------------------------------------------------------------------------*/
954 void
955 uip_ds6_send_ra_periodic(void)
956 {
957  if(racount > 0) {
958  /* send previously scheduled RA */
959  uip_nd6_ra_output(NULL);
960  PRINTF("Sending periodic RA\n");
961  }
962 
963  rand_time = UIP_ND6_MIN_RA_INTERVAL + random_rand() %
964  (uint16_t) (UIP_ND6_MAX_RA_INTERVAL - UIP_ND6_MIN_RA_INTERVAL);
965  PRINTF("Random time 1 = %u\n", rand_time);
966 
967  if(racount < UIP_ND6_MAX_INITIAL_RAS) {
968  if(rand_time > UIP_ND6_MAX_INITIAL_RA_INTERVAL) {
969  rand_time = UIP_ND6_MAX_INITIAL_RA_INTERVAL;
970  PRINTF("Random time 2 = %u\n", rand_time);
971  }
972  racount++;
973  }
974  PRINTF("Random time 3 = %u\n", rand_time);
975  stimer_set(&uip_ds6_timer_ra, rand_time);
976 }
977 
978 #endif /* UIP_ND6_SEND_RA */
979 #else /* UIP_CONF_ROUTER */
980 /*---------------------------------------------------------------------------*/
981 void
983 {
984  if((uip_ds6_defrt_choose() == NULL)
985  && (rscount < UIP_ND6_MAX_RTR_SOLICITATIONS)) {
986  PRINTF("Sending RS %u\n", rscount);
988  rscount++;
990  UIP_ND6_RTR_SOLICITATION_INTERVAL * CLOCK_SECOND);
991  } else {
992  PRINTF("Router found ? (boolean): %u\n",
993  (uip_ds6_defrt_choose() != NULL));
995  }
996  return;
997 }
998 
999 #endif /* UIP_CONF_ROUTER */
1000 /*---------------------------------------------------------------------------*/
1001 uint32_t
1003 {
1004  return (uint32_t) (UIP_ND6_MIN_RANDOM_FACTOR
1005  (uip_ds6_if.base_reachable_time)) +
1006  ((uint16_t) (random_rand() << 8) +
1007  (uint16_t) random_rand()) %
1008  (uint32_t) (UIP_ND6_MAX_RANDOM_FACTOR(uip_ds6_if.base_reachable_time) -
1009  UIP_ND6_MIN_RANDOM_FACTOR(uip_ds6_if.base_reachable_time));
1010 }
1011 
1012 
1013 /** @} */