Contiki-NG
uip-ds6-nbr.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *
30  */
31 
32 /**
33  * \addtogroup uip
34  * @{
35  */
36 
37 /**
38  * \file
39  * IPv6 Neighbor cache (link-layer/IPv6 address mapping)
40  * \author Mathilde Durvy <mdurvy@cisco.com>
41  * \author Julien Abeille <jabeille@cisco.com>
42  * \author Simon Duquennoy <simonduq@sics.se>
43  *
44  */
45 
46 #include <string.h>
47 #include <stdlib.h>
48 #include <stddef.h>
49 #include "lib/list.h"
50 #include "net/link-stats.h"
51 #include "net/linkaddr.h"
52 #include "net/packetbuf.h"
53 #include "net/ipv6/uip-ds6.h"
54 #include "net/ipv6/uip-ds6-nbr.h"
55 #include "net/ipv6/uip-nd6.h"
56 #include "net/routing/routing.h"
57 
58 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
59 #include "lib/memb.h"
60 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
61 
62 /* Log configuration */
63 #include "sys/log.h"
64 #define LOG_MODULE "IPv6 Nbr"
65 #define LOG_LEVEL LOG_LEVEL_IPV6
66 
67 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
68 /**
69  * Add nbr to the list in nbr_entry. In other words, this function associates an
70  * IPv6 address in nbr with a link-layer address in nbr_entry.
71  * \param nbr the neighbor cache entry for an IPv6 address
72  * \param nbr_entry the nbr_table entry for an link-layer address
73  */
74 static void add_uip_ds6_nbr_to_nbr_entry(uip_ds6_nbr_t *nbr,
75  uip_ds6_nbr_entry_t *nbr_entry);
76 
77 /**
78  * Remove nbr from the list of the corresponding nbr_entry
79  * \param nbr a neighbor cache entry (nbr) to be removed
80  */
81 static void remove_uip_ds6_nbr_from_nbr_entry(uip_ds6_nbr_t *nbr);
82 
83 /**
84  * Remove nbr_etnry from nbr_table
85  * \param nbr_entry a nbr_table entry (nbr_entry) to be removed
86  */
87 static void remove_nbr_entry(uip_ds6_nbr_entry_t *nbr_entry);
88 
89 /**
90  * Free memory for a specified neighbor cache entry
91  * \param nbr a neighbor cache entry to be freed
92  */
93 static void free_uip_ds6_nbr(uip_ds6_nbr_t *nbr);
94 
95 /**
96  * Callback function called when a nbr_table entry is removed
97  * \param nbr_entry a nbr_entry to be removed
98  */
99 static void callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry);
100 
101 NBR_TABLE(uip_ds6_nbr_entry_t, uip_ds6_nbr_entries);
103 #else
104 NBR_TABLE(uip_ds6_nbr_t, ds6_neighbors);
105 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
106 
107 /*---------------------------------------------------------------------------*/
108 void
109 uip_ds6_neighbors_init(void)
110 {
111  link_stats_init();
112 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
113  memb_init(&uip_ds6_nbr_memb);
114  nbr_table_register(uip_ds6_nbr_entries,
115  (nbr_table_callback *)callback_nbr_entry_removal);
116 #else
117  nbr_table_register(ds6_neighbors, (nbr_table_callback *)uip_ds6_nbr_rm);
118 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
119 }
120 /*---------------------------------------------------------------------------*/
122 uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
123  uint8_t isrouter, uint8_t state, nbr_table_reason_t reason,
124  void *data)
125 {
127 
128 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
129  uip_ds6_nbr_entry_t *nbr_entry;
130 
131  assert(uip_ds6_nbr_lookup(ipaddr) == NULL);
132  if(uip_ds6_nbr_lookup(ipaddr)) {
133  LOG_ERR("%s: uip_ds6_nbr for ", __func__);
134  LOG_ERR_6ADDR(ipaddr);
135  LOG_ERR_("has already existed\n");
136  return NULL;
137  }
138 
139  /* firstly, allocate memory for a new nbr cache entry */
140  if((nbr = (uip_ds6_nbr_t *)memb_alloc(&uip_ds6_nbr_memb)) == NULL) {
141  LOG_ERR("%s: cannot allocate a new uip_ds6_nbr\n", __func__);
142  return NULL;
143  }
144 
145  /* secondly, get or allocate nbr_entry for the link-layer address */
146  nbr_entry = nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
147  (const linkaddr_t *)lladdr);
148  if(nbr_entry == NULL) {
149  if((nbr_entry =
150  nbr_table_add_lladdr(uip_ds6_nbr_entries,
151  (linkaddr_t*)lladdr, reason, data)) == NULL) {
152  LOG_ERR("%s: cannot allocate a new uip_ds6_nbr_entry\n", __func__);
153  /* return from this function later */
154  } else {
155  LIST_STRUCT_INIT(nbr_entry, uip_ds6_nbrs);
156  }
157  }
158 
159  /* free nbr and return if nbr_entry is not available */
160  if((nbr_entry == NULL) ||
161  (list_length(nbr_entry->uip_ds6_nbrs) == UIP_DS6_NBR_MAX_6ADDRS_PER_NBR)) {
162  if(list_length(nbr_entry->uip_ds6_nbrs) == UIP_DS6_NBR_MAX_6ADDRS_PER_NBR) {
163  /*
164  * it's already had the maximum number of IPv6 addresses; cannot
165  * add another.
166  */
167  LOG_ERR("%s: no room in nbr_entry for ", __func__);
168  LOG_ERR_LLADDR((const linkaddr_t *)lladdr);
169  LOG_ERR_("\n");
170  }
171  /* free the newly allocated memory in this function call */
172  memb_free(&uip_ds6_nbr_memb, nbr);
173  return NULL;
174  } else {
175  /* everything is fine; nbr is ready to be used */
176  /* it has room to add another IPv6 address */
177  add_uip_ds6_nbr_to_nbr_entry(nbr, nbr_entry);
178  }
179 #else
180  nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr, reason, data);
181 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
182 
183  if(nbr) {
184  uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
185 #if UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
186  nbr->isrouter = isrouter;
187 #endif /* UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
188  nbr->state = state;
189 #if UIP_CONF_IPV6_QUEUE_PKT
190  uip_packetqueue_new(&nbr->packethandle);
191 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
192 #if UIP_ND6_SEND_NS
193  if(nbr->state == NBR_REACHABLE) {
194  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
195  } else {
196  /* We set the timer in expired state */
197  stimer_set(&nbr->reachable, 0);
198  }
199  stimer_set(&nbr->sendns, 0);
200  nbr->nscount = 0;
201 #endif /* UIP_ND6_SEND_NS */
202  LOG_INFO("Adding neighbor with ip addr ");
203  LOG_INFO_6ADDR(ipaddr);
204  LOG_INFO_(" link addr ");
205  LOG_INFO_LLADDR((linkaddr_t*)lladdr);
206  LOG_INFO_(" state %u\n", state);
207  NETSTACK_ROUTING.neighbor_state_changed(nbr);
208  return nbr;
209  } else {
210  LOG_INFO("Add drop ip addr ");
211  LOG_INFO_6ADDR(ipaddr);
212  LOG_INFO_(" link addr (%p) ", lladdr);
213  LOG_INFO_LLADDR((linkaddr_t*)lladdr);
214  LOG_INFO_(" state %u\n", state);
215  return NULL;
216  }
217 }
218 
219 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
220 /*---------------------------------------------------------------------------*/
221 static void
222 add_uip_ds6_nbr_to_nbr_entry(uip_ds6_nbr_t *nbr,
223  uip_ds6_nbr_entry_t *nbr_entry)
224 {
225  LOG_DBG("%s: add nbr(%p) to nbr_entry (%p)\n",
226  __func__, nbr, nbr_entry);
227  nbr->nbr_entry = nbr_entry;
228  list_add(nbr_entry->uip_ds6_nbrs, nbr);
229 }
230 /*---------------------------------------------------------------------------*/
231 static void
232 remove_uip_ds6_nbr_from_nbr_entry(uip_ds6_nbr_t *nbr)
233 {
234  if(nbr == NULL) {
235  return;
236  }
237  LOG_DBG("%s: remove nbr(%p) from nbr_entry (%p)\n",
238  __func__, nbr, nbr->nbr_entry);
239  list_remove(nbr->nbr_entry->uip_ds6_nbrs, nbr);
240 }
241 /*---------------------------------------------------------------------------*/
242 static void
243 remove_nbr_entry(uip_ds6_nbr_entry_t *nbr_entry)
244 {
245  if(nbr_entry == NULL) {
246  return;
247  }
248  LOG_DBG("%s: remove nbr_entry (%p) from nbr_table\n",
249  __func__, nbr_entry);
250  (void)nbr_table_remove(uip_ds6_nbr_entries, nbr_entry);
251 }
252 /*---------------------------------------------------------------------------*/
253 static void
254 free_uip_ds6_nbr(uip_ds6_nbr_t *nbr)
255 {
256  if(nbr == NULL) {
257  return;
258  }
259 #if UIP_CONF_IPV6_QUEUE_PKT
260  uip_packetqueue_free(&nbr->packethandle);
261 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
262  NETSTACK_ROUTING.neighbor_state_changed(nbr);
263  assert(nbr->nbr_entry != NULL);
264  if(nbr->nbr_entry == NULL) {
265  LOG_ERR("%s: unexpected error nbr->nbr_entry is NULL\n", __func__);
266  } else {
267  remove_uip_ds6_nbr_from_nbr_entry(nbr);
268  if(list_length(nbr->nbr_entry->uip_ds6_nbrs) == 0) {
269  remove_nbr_entry(nbr->nbr_entry);
270  }
271  }
272  LOG_DBG("%s: free memory for nbr(%p)\n", __func__, nbr);
273  memb_free(&uip_ds6_nbr_memb, nbr);
274 }
275 /*---------------------------------------------------------------------------*/
276 static void
277 callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry)
278 {
280  uip_ds6_nbr_t *next_nbr;
281  if(nbr_entry == NULL) {
282  return;
283  }
284  for(nbr = (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
285  nbr != NULL;
286  nbr = next_nbr) {
287  next_nbr = (uip_ds6_nbr_t *)list_item_next(nbr);
288  free_uip_ds6_nbr(nbr);
289  }
290 }
291 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
292 /*---------------------------------------------------------------------------*/
293 int
295 {
296 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
297  if(nbr == NULL) {
298  return 0;
299  } else {
300  free_uip_ds6_nbr(nbr);
301  return 1;
302  }
303 #else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
304  if(nbr != NULL) {
305 #if UIP_CONF_IPV6_QUEUE_PKT
306  uip_packetqueue_free(&nbr->packethandle);
307 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
308  NETSTACK_ROUTING.neighbor_state_changed(nbr);
309  return nbr_table_remove(ds6_neighbors, nbr);
310  }
311  return 0;
312 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
313 }
314 
315 /*---------------------------------------------------------------------------*/
316 int
317 uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr_pp, const uip_lladdr_t *new_ll_addr)
318 {
319 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
320  uip_ds6_nbr_entry_t *nbr_entry;
322 #else
323  uip_ds6_nbr_t nbr_backup;
324 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
325 
326  if(nbr_pp == NULL || new_ll_addr == NULL) {
327  LOG_ERR("%s: invalid argument\n", __func__);
328  return -1;
329  }
330 
331 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
332 
333  if((nbr_entry =
334  nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
335  (const linkaddr_t *)new_ll_addr)) == NULL) {
336  if((nbr_entry =
337  nbr_table_add_lladdr(uip_ds6_nbr_entries,
338  (const linkaddr_t*)new_ll_addr,
339  NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
340  LOG_ERR("%s: cannot allocate a nbr_entry for", __func__);
341  LOG_ERR_LLADDR((const linkaddr_t *)new_ll_addr);
342  return -1;
343  } else {
344  LIST_STRUCT_INIT(nbr_entry, uip_ds6_nbrs);
345  }
346  }
347 
348  nbr = *nbr_pp;
349 
350  remove_uip_ds6_nbr_from_nbr_entry(nbr);
351  if(list_length(nbr->nbr_entry->uip_ds6_nbrs) == 0) {
352  remove_nbr_entry(nbr->nbr_entry);
353  }
354  add_uip_ds6_nbr_to_nbr_entry(nbr, nbr_entry);
355 
356 #else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
357 
358  /* make sure new_ll_addr is not used in some other nbr */
359  if(uip_ds6_nbr_ll_lookup(new_ll_addr) != NULL) {
360  LOG_ERR("%s: new_ll_addr, ", __func__);
361  LOG_ERR_LLADDR((const linkaddr_t *)new_ll_addr);
362  LOG_ERR_(", is already used in another nbr\n");
363  return -1;
364  }
365 
366  memcpy(&nbr_backup, *nbr_pp, sizeof(uip_ds6_nbr_t));
367  if(uip_ds6_nbr_rm(*nbr_pp) == 0) {
368  LOG_ERR("%s: input nbr cannot be removed\n", __func__);
369  return -1;
370  }
371 
372  if((*nbr_pp = uip_ds6_nbr_add(&nbr_backup.ipaddr, new_ll_addr,
373  nbr_backup.isrouter, nbr_backup.state,
374  NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
375  LOG_ERR("%s: cannot allocate a new nbr for new_ll_addr\n", __func__);
376  return -1;
377  }
378  memcpy(*nbr_pp, &nbr_backup, sizeof(uip_ds6_nbr_t));
379 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
380 
381  return 0;
382 }
383 /*---------------------------------------------------------------------------*/
384 const uip_ipaddr_t *
386 {
387  return (nbr != NULL) ? &nbr->ipaddr : NULL;
388 }
389 
390 /*---------------------------------------------------------------------------*/
391 const uip_lladdr_t *
393 {
394 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
395  if(nbr == NULL) {
396  return NULL;
397  }
398  return (const uip_lladdr_t *)nbr_table_get_lladdr(uip_ds6_nbr_entries,
399  nbr->nbr_entry);
400 #else
401  return (const uip_lladdr_t *)nbr_table_get_lladdr(ds6_neighbors, nbr);
402 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
403 }
404 /*---------------------------------------------------------------------------*/
405 int
407 {
408  int num = 0;
409 
410 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
411  uip_ds6_nbr_entry_t *nbr_entry;
412  for(nbr_entry = nbr_table_head(uip_ds6_nbr_entries);
413  nbr_entry != NULL;
414  nbr_entry = nbr_table_next(uip_ds6_nbr_entries, nbr_entry)) {
415  num += list_length(nbr_entry->uip_ds6_nbrs);
416  }
417 #else
419  for(nbr = nbr_table_head(ds6_neighbors);
420  nbr != NULL;
421  nbr = nbr_table_next(ds6_neighbors, nbr)) {
422  num++;
423  }
424 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
425  return num;
426 }
427 /*---------------------------------------------------------------------------*/
430 {
431 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
432  uip_ds6_nbr_entry_t *nbr_entry;
433  if((nbr_entry = nbr_table_head(uip_ds6_nbr_entries)) == NULL) {
434  return NULL;
435  }
436  assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
437  return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
438 #else
439  return nbr_table_head(ds6_neighbors);
440 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
441 }
442 /*---------------------------------------------------------------------------*/
445 {
446 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
447  uip_ds6_nbr_entry_t *nbr_entry;
448  if(nbr == NULL) {
449  return NULL;
450  }
451  if(list_item_next(nbr) != NULL) {
452  return list_item_next(nbr);
453  }
454  nbr_entry = nbr_table_next(uip_ds6_nbr_entries, nbr->nbr_entry);
455  if(nbr_entry == NULL) {
456  return NULL;
457  } else {
458  assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
459  return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
460  }
461 #else
462  return nbr_table_next(ds6_neighbors, nbr);
463 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
464 }
465 /*---------------------------------------------------------------------------*/
467 uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
468 {
470  if(ipaddr == NULL) {
471  return NULL;
472  }
473  for(nbr = uip_ds6_nbr_head(); nbr != NULL; nbr = uip_ds6_nbr_next(nbr)) {
474  if(uip_ipaddr_cmp(&nbr->ipaddr, ipaddr)) {
475  return nbr;
476  }
477  }
478  return NULL;
479 }
480 /*---------------------------------------------------------------------------*/
482 uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr)
483 {
484 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
485  uip_ds6_nbr_entry_t *nbr_entry;
486  /*
487  * we cannot determine which entry should return by lladdr alone;
488  * return the first entry associated with lladdr.
489  */
490  nbr_entry =
491  (uip_ds6_nbr_entry_t *)nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
492  (linkaddr_t*)lladdr);
493  if(nbr_entry == NULL) {
494  return NULL;
495  }
496  assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
497  return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
498 #else
499  return nbr_table_get_from_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
500 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
501 }
502 
503 /*---------------------------------------------------------------------------*/
504 uip_ipaddr_t *
505 uip_ds6_nbr_ipaddr_from_lladdr(const uip_lladdr_t *lladdr)
506 {
507  uip_ds6_nbr_t *nbr = uip_ds6_nbr_ll_lookup(lladdr);
508  return nbr ? &nbr->ipaddr : NULL;
509 }
510 
511 /*---------------------------------------------------------------------------*/
512 const uip_lladdr_t *
514 {
515  uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr);
516  return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
517 }
518 #if UIP_DS6_LL_NUD
519 /*---------------------------------------------------------------------------*/
520 static void
521 update_nbr_reachable_state_by_ack(uip_ds6_nbr_t *nbr, const linkaddr_t *lladdr)
522 {
523  if(nbr != NULL && nbr->state != NBR_INCOMPLETE) {
524  nbr->state = NBR_REACHABLE;
525  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
526  LOG_INFO("received a link layer ACK : ");
527  LOG_INFO_LLADDR(lladdr);
528  LOG_INFO_(" is reachable.\n");
529  }
530 }
531 #endif /* UIP_DS6_LL_NUD */
532 /*---------------------------------------------------------------------------*/
533 void
534 uip_ds6_link_callback(int status, int numtx)
535 {
536 #if UIP_DS6_LL_NUD
537  const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
538  if(linkaddr_cmp(dest, &linkaddr_null)) {
539  return;
540  }
541 
542  /* From RFC4861, page 72, last paragraph of section 7.3.3:
543  *
544  * "In some cases, link-specific information may indicate that a path to
545  * a neighbor has failed (e.g., the resetting of a virtual circuit). In
546  * such cases, link-specific information may be used to purge Neighbor
547  * Cache entries before the Neighbor Unreachability Detection would do
548  * so. However, link-specific information MUST NOT be used to confirm
549  * the reachability of a neighbor; such information does not provide
550  * end-to-end confirmation between neighboring IP layers."
551  *
552  * However, we assume that receiving a link layer ack ensures the delivery
553  * of the transmitted packed to the IP stack of the neighbour. This is a
554  * fair assumption and allows battery powered nodes save some battery by
555  * not re-testing the state of a neighbour periodically if it
556  * acknowledges link packets. */
557  if(status == MAC_TX_OK) {
559 #if UIP_DS6_NBR_MULTI_IPV6_ADDRS
560  uip_ds6_nbr_entry_t *nbr_entry;
561  if((nbr_entry =
562  (uip_ds6_nbr_entry_t *)nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
563  dest)) == NULL) {
564  return;
565  }
566  for(nbr = (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
567  nbr != NULL;
568  nbr = (uip_ds6_nbr_t *)list_item_next(nbr)) {
569  update_nbr_reachable_state_by_ack(nbr, dest);
570  }
571 #else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
572  nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
573  update_nbr_reachable_state_by_ack(nbr, dest);
574 #endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
575  }
576 #endif /* UIP_DS6_LL_NUD */
577 }
578 #if UIP_ND6_SEND_NS
579 /*---------------------------------------------------------------------------*/
580 /** Periodic processing on neighbors */
581 void
583 {
585  while(nbr != NULL) {
586  switch(nbr->state) {
587  case NBR_REACHABLE:
588  if(stimer_expired(&nbr->reachable)) {
589 #if UIP_CONF_ROUTER
590  /* when a neighbor leave its REACHABLE state and is a default router,
591  instead of going to STALE state it enters DELAY state in order to
592  force a NUD on it. Otherwise, if there is no upward traffic, the
593  node never knows if the default router is still reachable. This
594  mimics the 6LoWPAN-ND behavior.
595  */
596  if(uip_ds6_defrt_lookup(&nbr->ipaddr) != NULL) {
597  LOG_INFO("REACHABLE: defrt moving to DELAY (");
598  LOG_INFO_6ADDR(&nbr->ipaddr);
599  LOG_INFO_(")\n");
600  nbr->state = NBR_DELAY;
601  stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME);
602  nbr->nscount = 0;
603  } else {
604  LOG_INFO("REACHABLE: moving to STALE (");
605  LOG_INFO_6ADDR(&nbr->ipaddr);
606  LOG_INFO_(")\n");
607  nbr->state = NBR_STALE;
608  }
609 #else /* UIP_CONF_ROUTER */
610  LOG_INFO("REACHABLE: moving to STALE (");
611  LOG_INFO_6ADDR(&nbr->ipaddr);
612  LOG_INFO_(")\n");
613  nbr->state = NBR_STALE;
614 #endif /* UIP_CONF_ROUTER */
615  }
616  break;
617  case NBR_INCOMPLETE:
618  if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
619  uip_ds6_nbr_rm(nbr);
620  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
621  nbr->nscount++;
622  LOG_INFO("NBR_INCOMPLETE: NS %u\n", nbr->nscount);
623  uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr);
624  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
625  }
626  break;
627  case NBR_DELAY:
628  if(stimer_expired(&nbr->reachable)) {
629  nbr->state = NBR_PROBE;
630  nbr->nscount = 0;
631  LOG_INFO("DELAY: moving to PROBE\n");
632  stimer_set(&nbr->sendns, 0);
633  }
634  break;
635  case NBR_PROBE:
636  if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
637  uip_ds6_defrt_t *locdefrt;
638  LOG_INFO("PROBE END\n");
639  if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) {
640  if (!locdefrt->isinfinite) {
641  uip_ds6_defrt_rm(locdefrt);
642  }
643  }
644  uip_ds6_nbr_rm(nbr);
645  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
646  nbr->nscount++;
647  LOG_INFO("PROBE: NS %u\n", nbr->nscount);
648  uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr);
649  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
650  }
651  break;
652  default:
653  break;
654  }
655  nbr = uip_ds6_nbr_next(nbr);
656  }
657 }
658 /*---------------------------------------------------------------------------*/
659 void
660 uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr)
661 {
663  nbr = uip_ds6_nbr_lookup(ipaddr);
664  if(nbr != NULL) {
665  nbr->state = NBR_REACHABLE;
666  nbr->nscount = 0;
667  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
668  }
669 }
670 /*---------------------------------------------------------------------------*/
673 {
675  uip_ds6_nbr_t *nbr_expiring = NULL;
676  while(nbr != NULL) {
677  if(nbr_expiring != NULL) {
678  clock_time_t curr = stimer_remaining(&nbr->reachable);
679  if(curr < stimer_remaining(&nbr->reachable)) {
680  nbr_expiring = nbr;
681  }
682  } else {
683  nbr_expiring = nbr;
684  }
685  nbr = uip_ds6_nbr_next(nbr);
686  }
687  return nbr_expiring;
688 }
689 #endif /* UIP_ND6_SEND_NS */
690 /*---------------------------------------------------------------------------*/
691 /** @} */
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:116
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:125
An entry in the default router list.
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:106
unsigned long stimer_remaining(struct stimer *t)
The time until the timer expires.
Definition: stimer.c:143
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
uip_ds6_nbr_t * uip_ds6_nbr_head(void)
Get the first neighbor cache in nbr_table.
Definition: uip-ds6-nbr.c:429
Header file for the link-layer address representation
uip_ds6_nbr_t * uip_ds6_get_least_lifetime_neighbor(void)
This searches inside the neighbor table for the neighbor that is about to expire the next...
IPv6 Neighbor cache (link-layer/IPv6 address mapping)
int stimer_expired(struct stimer *t)
Check if a timer has expired.
Definition: stimer.c:127
void uip_ds6_link_callback(int status, int numtx)
The callback function to update link-layer stats in a neighbor cache.
Definition: uip-ds6-nbr.c:534
const linkaddr_t linkaddr_null
The null link-layer address.
The MAC layer transmission was OK.
Definition: mac.h:87
int uip_ds6_nbr_num(void)
Return the number of neighbor caches.
Definition: uip-ds6-nbr.c:406
Header file for IPv6-related data structures.
void(* neighbor_state_changed)(uip_ds6_nbr_t *nbr)
Called by uIP to notify addition/removal of IPv6 neighbor entries.
Definition: routing.h:178
void uip_nd6_ns_output(uip_ipaddr_t *src, uip_ipaddr_t *dest, uip_ipaddr_t *tgt)
Send a neighbor solicitation, send a Neighbor Advertisement.
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition: stimer.c:67
void uip_ds6_neighbor_periodic(void)
The housekeeping function called periodically.
uip_ipaddr_t * uip_ds6_nbr_ipaddr_from_lladdr(const uip_lladdr_t *lladdr)
Get an IPv6 address associated with a specified link-layer address.
Definition: uip-ds6-nbr.c:505
Linked list manipulation routines.
#define UIP_DS6_NBR_MAX_6ADDRS_PER_NBR
Set the maximum number of IPv6 addresses per link-layer address.
Definition: uip-ds6-nbr.h:83
const uip_ipaddr_t * uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr)
Get an IPv6 address of a neighbor cache.
Definition: uip-ds6-nbr.c:385
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
uip_ds6_nbr_t * uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
Get the neighbor cache associated with a specified IPv6 address.
Definition: uip-ds6-nbr.c:467
Routing driver header file
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1015
const uip_lladdr_t * uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr)
Get the link-layer address associated with a specified IPv6 address.
Definition: uip-ds6-nbr.c:513
Memory block allocation routines.
#define NBR_INCOMPLETE
Possible states for the nbr cache entries.
Definition: uip-ds6-nbr.h:64
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
uip_ds6_nbr_t * uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr, uint8_t isrouter, uint8_t state, nbr_table_reason_t reason, void *data)
Add a neighbor cache for a specified IPv6 address, which is associated with a specified link-layer ad...
Definition: uip-ds6-nbr.c:122
Header file for IPv6 Neighbor discovery (RFC 4861)
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
uip_ds6_nbr_t * uip_ds6_nbr_next(uip_ds6_nbr_t *nbr)
Get the next neighbor cache of a specified one.
Definition: uip-ds6-nbr.c:444
int uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr_pp, const uip_lladdr_t *new_ll_addr)
Update the link-layer address associated with an IPv6 address.
Definition: uip-ds6-nbr.c:317
int uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr)
Remove a neighbor cache.
Definition: uip-ds6-nbr.c:294
uip_ds6_nbr_t * uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr)
Get the neighbor cache associated with a specified link-layer address.
Definition: uip-ds6-nbr.c:482
const uip_lladdr_t * uip_ds6_nbr_get_ll(const uip_ds6_nbr_t *nbr)
Get the link-layer address associated with a specified nbr cache.
Definition: uip-ds6-nbr.c:392
Header file for the Packet buffer (packetbuf) management
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
Header file for the logging system
#define UIP_DS6_NBR_MAX_NEIGHBOR_CACHES
Set the maximum number of neighbor cache entries.
Definition: uip-ds6-nbr.h:90
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:237
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:322
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:90
int list_length(list_t list)
Get the length of a list.
Definition: list.c:272
The default nbr_table entry (when UIP_DS6_NBR_MULTI_IPV6_ADDRS is disabled), that implements nbr cach...
Definition: uip-ds6-nbr.h:105