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"
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 */
74static 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 */
81static 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 */
87static 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 */
93static 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 */
99static void callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry);
100
101NBR_TABLE(uip_ds6_nbr_entry_t, uip_ds6_nbr_entries);
103#else
104NBR_TABLE(uip_ds6_nbr_t, ds6_neighbors);
105#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
106
107/*---------------------------------------------------------------------------*/
108void
109uip_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/*---------------------------------------------------------------------------*/
122uip_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);
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/*---------------------------------------------------------------------------*/
221static void
222add_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/*---------------------------------------------------------------------------*/
231static void
232remove_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/*---------------------------------------------------------------------------*/
242static void
243remove_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/*---------------------------------------------------------------------------*/
253static void
254free_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/*---------------------------------------------------------------------------*/
276static void
277callback_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/*---------------------------------------------------------------------------*/
293int
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/*---------------------------------------------------------------------------*/
316int
317uip_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/*---------------------------------------------------------------------------*/
384const uip_ipaddr_t *
386{
387 return (nbr != NULL) ? &nbr->ipaddr : NULL;
388}
389
390/*---------------------------------------------------------------------------*/
391const 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/*---------------------------------------------------------------------------*/
405int
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/*---------------------------------------------------------------------------*/
467uip_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/*---------------------------------------------------------------------------*/
482uip_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/*---------------------------------------------------------------------------*/
504uip_ipaddr_t *
505uip_ds6_nbr_ipaddr_from_lladdr(const uip_lladdr_t *lladdr)
506{
508 return nbr ? &nbr->ipaddr : NULL;
509}
510
511/*---------------------------------------------------------------------------*/
512const uip_lladdr_t *
514{
516 return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
517}
518#if UIP_DS6_LL_NUD
519/*---------------------------------------------------------------------------*/
520static void
521update_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/*---------------------------------------------------------------------------*/
533void
534uip_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;
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 */
581void
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) {
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 }
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 }
656 }
657}
658/*---------------------------------------------------------------------------*/
659void
660uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr)
661{
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#endif /* UIP_ND6_SEND_NS */
671/*---------------------------------------------------------------------------*/
672/** @} */
const linkaddr_t linkaddr_null
The null link-layer address.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
void * list_head(const list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
int list_length(const list_t list)
Get the length of a list.
Definition: list.c:272
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition: list.c:237
void * list_item_next(const void *item)
Get the next item following this item.
Definition: list.c:322
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:125
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:90
int stimer_expired(struct stimer *t)
Check if a timer has expired.
Definition: stimer.c:127
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition: stimer.c:67
void uip_nd6_ns_output(const uip_ipaddr_t *src, const uip_ipaddr_t *dest, uip_ipaddr_t *tgt)
Send a neighbor solicitation, send a Neighbor Advertisement.
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
#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
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
uip_ds6_nbr_t * uip_ds6_nbr_head(void)
Get the first neighbor cache in nbr_table.
Definition: uip-ds6-nbr.c:429
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
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
#define UIP_DS6_NBR_MAX_NEIGHBOR_CACHES
Set the maximum number of neighbor cache entries.
Definition: uip-ds6-nbr.h:90
#define NBR_INCOMPLETE
Possible states for the nbr cache entries.
Definition: uip-ds6-nbr.h:64
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_lookup(const uip_ipaddr_t *ipaddr)
Get the neighbor cache associated with a specified IPv6 address.
Definition: uip-ds6-nbr.c:467
void uip_ds6_neighbor_periodic(void)
The housekeeping function called periodically.
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
int uip_ds6_nbr_num(void)
Return the number of neighbor caches.
Definition: uip-ds6-nbr.c:406
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
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
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
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
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
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:969
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
Header file for the link-layer address representation.
Linked list manipulation routines.
Header file for the logging system.
@ MAC_TX_OK
The MAC layer transmission was OK.
Definition: mac.h:87
Memory block allocation routines.
Header file for the Packet buffer (packetbuf) management.
Routing driver header file.
void(* neighbor_state_changed)(uip_ds6_nbr_t *nbr)
Called by uIP to notify addition/removal of IPv6 neighbor entries.
Definition: routing.h:178
An entry in the default router list.
The default nbr_table entry (when UIP_DS6_NBR_MULTI_IPV6_ADDRS is disabled), that implements nbr cach...
Definition: uip-ds6-nbr.h:105
IPv6 Neighbor cache (link-layer/IPv6 address mapping)
Header file for IPv6-related data structures.
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:106
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:116
Header file for IPv6 Neighbor discovery (RFC 4861)