Contiki-NG
Loading...
Searching...
No Matches
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 <stddef.h>
48#include "lib/list.h"
49#include "net/link-stats.h"
50#include "net/linkaddr.h"
51#include "net/packetbuf.h"
52#include "net/ipv6/uip-ds6.h"
54#include "net/ipv6/uip-nd6.h"
55#include "net/routing/routing.h"
56
57#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
58#include "lib/memb.h"
59#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
60
61/* Log configuration */
62#include "sys/log.h"
63#define LOG_MODULE "IPv6 Nbr"
64#define LOG_LEVEL LOG_LEVEL_IPV6
65
66#if BUILD_WITH_ORCHESTRA
67
68/* A configurable function called after adding a new neighbor, or removing one */
69#ifndef NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK
70#define NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK orchestra_callback_neighbor_updated
71#endif /* NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK */
72void NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK(const linkaddr_t *, uint8_t is_added);
73
74#endif /* BUILD_WITH_ORCHESTRA */
75
76#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
77/**
78 * Add nbr to the list in nbr_entry. In other words, this function associates an
79 * IPv6 address in nbr with a link-layer address in nbr_entry.
80 * \param nbr the neighbor cache entry for an IPv6 address
81 * \param nbr_entry the nbr_table entry for an link-layer address
82 */
83static void add_uip_ds6_nbr_to_nbr_entry(uip_ds6_nbr_t *nbr,
84 uip_ds6_nbr_entry_t *nbr_entry);
85
86/**
87 * Remove nbr from the list of the corresponding nbr_entry
88 * \param nbr a neighbor cache entry (nbr) to be removed
89 */
90static void remove_uip_ds6_nbr_from_nbr_entry(uip_ds6_nbr_t *nbr);
91
92/**
93 * Remove nbr_etnry from nbr_table
94 * \param nbr_entry a nbr_table entry (nbr_entry) to be removed
95 */
96static void remove_nbr_entry(uip_ds6_nbr_entry_t *nbr_entry);
97
98/**
99 * Free memory for a specified neighbor cache entry
100 * \param nbr a neighbor cache entry to be freed
101 */
102static void free_uip_ds6_nbr(uip_ds6_nbr_t *nbr);
103
104/**
105 * Callback function called when a nbr_table entry is removed
106 * \param nbr_entry a nbr_entry to be removed
107 */
108static void callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry);
109
110NBR_TABLE(uip_ds6_nbr_entry_t, uip_ds6_nbr_entries);
112#else
113NBR_TABLE(uip_ds6_nbr_t, ds6_neighbors);
114#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
115
116/*---------------------------------------------------------------------------*/
117void
118uip_ds6_neighbors_init(void)
119{
120 link_stats_init();
121#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
122 memb_init(&uip_ds6_nbr_memb);
123 nbr_table_register(uip_ds6_nbr_entries,
124 (nbr_table_callback *)callback_nbr_entry_removal);
125#else
126 nbr_table_register(ds6_neighbors, (nbr_table_callback *)uip_ds6_nbr_rm);
127#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
128}
129/*---------------------------------------------------------------------------*/
131uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
132 uint8_t isrouter, uint8_t state, nbr_table_reason_t reason,
133 void *data)
134{
136
137#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
138 uip_ds6_nbr_entry_t *nbr_entry;
139
140 assert(uip_ds6_nbr_lookup(ipaddr) == NULL);
142 LOG_ERR("%s: uip_ds6_nbr for ", __func__);
143 LOG_ERR_6ADDR(ipaddr);
144 LOG_ERR_("has already existed\n");
145 return NULL;
146 }
147
148 /* firstly, allocate memory for a new nbr cache entry */
149 if((nbr = (uip_ds6_nbr_t *)memb_alloc(&uip_ds6_nbr_memb)) == NULL) {
150 LOG_ERR("%s: cannot allocate a new uip_ds6_nbr\n", __func__);
151 return NULL;
152 }
153
154 /* secondly, get or allocate nbr_entry for the link-layer address */
155 nbr_entry = nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
156 (const linkaddr_t *)lladdr);
157 if(nbr_entry == NULL) {
158 if((nbr_entry =
159 nbr_table_add_lladdr(uip_ds6_nbr_entries,
160 (linkaddr_t*)lladdr, reason, data)) == NULL) {
161 LOG_ERR("%s: cannot allocate a new uip_ds6_nbr_entry\n", __func__);
162 /* return from this function later */
163 } else {
164 LIST_STRUCT_INIT(nbr_entry, uip_ds6_nbrs);
165 }
166 }
167
168 /* free nbr and return if nbr_entry is not available */
169 if((nbr_entry == NULL) ||
170 (list_length(nbr_entry->uip_ds6_nbrs) == UIP_DS6_NBR_MAX_6ADDRS_PER_NBR)) {
171 if(list_length(nbr_entry->uip_ds6_nbrs) == UIP_DS6_NBR_MAX_6ADDRS_PER_NBR) {
172 /*
173 * it's already had the maximum number of IPv6 addresses; cannot
174 * add another.
175 */
176 LOG_ERR("%s: no room in nbr_entry for ", __func__);
177 LOG_ERR_LLADDR((const linkaddr_t *)lladdr);
178 LOG_ERR_("\n");
179 }
180 /* free the newly allocated memory in this function call */
181 memb_free(&uip_ds6_nbr_memb, nbr);
182 return NULL;
183 } else {
184 /* everything is fine; nbr is ready to be used */
185 /* it has room to add another IPv6 address */
186 add_uip_ds6_nbr_to_nbr_entry(nbr, nbr_entry);
187 }
188#else
189 nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr, reason, data);
190#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
191
192 if(nbr) {
193#ifdef NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK
194 NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK((const linkaddr_t *)lladdr, 1);
195#endif /* NETSTACK_CONF_DS6_NEIGHBOR_ADDED_CALLBACK */
196 uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
197#if UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
198 nbr->isrouter = isrouter;
199#endif /* UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
200 nbr->state = state;
201#if UIP_CONF_IPV6_QUEUE_PKT
202 uip_packetqueue_new(&nbr->packethandle);
203#endif /* UIP_CONF_IPV6_QUEUE_PKT */
204#if UIP_ND6_SEND_NS
205 if(nbr->state == NBR_REACHABLE) {
206 stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
207 } else {
208 /* We set the timer in expired state */
209 stimer_set(&nbr->reachable, 0);
210 }
211 stimer_set(&nbr->sendns, 0);
212 nbr->nscount = 0;
213#endif /* UIP_ND6_SEND_NS */
214 LOG_INFO("Adding neighbor with ip addr ");
215 LOG_INFO_6ADDR(ipaddr);
216 LOG_INFO_(" link addr ");
217 LOG_INFO_LLADDR((linkaddr_t*)lladdr);
218 LOG_INFO_(" state %u\n", state);
219 NETSTACK_ROUTING.neighbor_state_changed(nbr);
220 return nbr;
221 } else {
222 LOG_INFO("Add drop ip addr ");
223 LOG_INFO_6ADDR(ipaddr);
224 LOG_INFO_(" link addr (%p) ", lladdr);
225 LOG_INFO_LLADDR((linkaddr_t*)lladdr);
226 LOG_INFO_(" state %u\n", state);
227 return NULL;
228 }
229}
230
231#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
232/*---------------------------------------------------------------------------*/
233static void
234add_uip_ds6_nbr_to_nbr_entry(uip_ds6_nbr_t *nbr,
235 uip_ds6_nbr_entry_t *nbr_entry)
236{
237 LOG_DBG("%s: add nbr(%p) to nbr_entry (%p)\n",
238 __func__, nbr, nbr_entry);
239 nbr->nbr_entry = nbr_entry;
240 list_add(nbr_entry->uip_ds6_nbrs, nbr);
241}
242/*---------------------------------------------------------------------------*/
243static void
244remove_uip_ds6_nbr_from_nbr_entry(uip_ds6_nbr_t *nbr)
245{
246 if(nbr == NULL) {
247 return;
248 }
249 LOG_DBG("%s: remove nbr(%p) from nbr_entry (%p)\n",
250 __func__, nbr, nbr->nbr_entry);
251 list_remove(nbr->nbr_entry->uip_ds6_nbrs, nbr);
252}
253/*---------------------------------------------------------------------------*/
254static void
255remove_nbr_entry(uip_ds6_nbr_entry_t *nbr_entry)
256{
257 if(nbr_entry == NULL) {
258 return;
259 }
260 LOG_DBG("%s: remove nbr_entry (%p) from nbr_table\n",
261 __func__, nbr_entry);
262 (void)nbr_table_remove(uip_ds6_nbr_entries, nbr_entry);
263}
264/*---------------------------------------------------------------------------*/
265static void
266free_uip_ds6_nbr(uip_ds6_nbr_t *nbr)
267{
268 if(nbr == NULL) {
269 return;
270 }
271#if UIP_CONF_IPV6_QUEUE_PKT
272 uip_packetqueue_free(&nbr->packethandle);
273#endif /* UIP_CONF_IPV6_QUEUE_PKT */
274 NETSTACK_ROUTING.neighbor_state_changed(nbr);
275 assert(nbr->nbr_entry != NULL);
276 if(nbr->nbr_entry == NULL) {
277 LOG_ERR("%s: unexpected error nbr->nbr_entry is NULL\n", __func__);
278 } else {
279 remove_uip_ds6_nbr_from_nbr_entry(nbr);
280 if(list_length(nbr->nbr_entry->uip_ds6_nbrs) == 0) {
281 remove_nbr_entry(nbr->nbr_entry);
282 }
283 }
284 LOG_DBG("%s: free memory for nbr(%p)\n", __func__, nbr);
285 memb_free(&uip_ds6_nbr_memb, nbr);
286}
287/*---------------------------------------------------------------------------*/
288static void
289callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry)
290{
292 uip_ds6_nbr_t *next_nbr;
293 if(nbr_entry == NULL) {
294 return;
295 }
296 for(nbr = (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
297 nbr != NULL;
298 nbr = next_nbr) {
299 next_nbr = (uip_ds6_nbr_t *)list_item_next(nbr);
300 free_uip_ds6_nbr(nbr);
301 }
302}
303#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
304/*---------------------------------------------------------------------------*/
305int
307{
308 int ret;
309 if(nbr == NULL) {
310 return 0;
311 }
312
313#ifdef NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK
314 linkaddr_t lladdr = {0};
315
316 const uip_lladdr_t *plladdr = uip_ds6_nbr_get_ll(nbr);
317 if(plladdr != NULL) {
318 memcpy(&lladdr, plladdr, sizeof(lladdr));
319 }
320#endif /* NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK */
321
322#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
323
324 free_uip_ds6_nbr(nbr);
325 ret = 1;
326
327#else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
328
329#if UIP_CONF_IPV6_QUEUE_PKT
330 uip_packetqueue_free(&nbr->packethandle);
331#endif /* UIP_CONF_IPV6_QUEUE_PKT */
332
333 NETSTACK_ROUTING.neighbor_state_changed(nbr);
334 ret = nbr_table_remove(ds6_neighbors, nbr);
335#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
336
337#ifdef NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK
338 NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK(&lladdr, 0);
339#endif /* NETSTACK_CONF_DS6_NEIGHBOR_ADDED_CALLBACK */
340
341 return ret;
342}
343
344/*---------------------------------------------------------------------------*/
345int
346uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr_pp, const uip_lladdr_t *new_ll_addr)
347{
348#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
349 uip_ds6_nbr_entry_t *nbr_entry;
351#else
352 uip_ds6_nbr_t nbr_backup;
353#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
354
355 if(nbr_pp == NULL || new_ll_addr == NULL) {
356 LOG_ERR("%s: invalid argument\n", __func__);
357 return -1;
358 }
359
360#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
361
362 if((nbr_entry =
363 nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
364 (const linkaddr_t *)new_ll_addr)) == NULL) {
365 if((nbr_entry =
366 nbr_table_add_lladdr(uip_ds6_nbr_entries,
367 (const linkaddr_t*)new_ll_addr,
368 NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
369 LOG_ERR("%s: cannot allocate a nbr_entry for", __func__);
370 LOG_ERR_LLADDR((const linkaddr_t *)new_ll_addr);
371 return -1;
372 } else {
373 LIST_STRUCT_INIT(nbr_entry, uip_ds6_nbrs);
374 }
375 }
376
377 nbr = *nbr_pp;
378
379 remove_uip_ds6_nbr_from_nbr_entry(nbr);
380 if(list_length(nbr->nbr_entry->uip_ds6_nbrs) == 0) {
381 remove_nbr_entry(nbr->nbr_entry);
382 }
383 add_uip_ds6_nbr_to_nbr_entry(nbr, nbr_entry);
384
385#else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
386
387 /* make sure new_ll_addr is not used in some other nbr */
388 if(uip_ds6_nbr_ll_lookup(new_ll_addr) != NULL) {
389 LOG_ERR("%s: new_ll_addr, ", __func__);
390 LOG_ERR_LLADDR((const linkaddr_t *)new_ll_addr);
391 LOG_ERR_(", is already used in another nbr\n");
392 return -1;
393 }
394
395 memcpy(&nbr_backup, *nbr_pp, sizeof(uip_ds6_nbr_t));
396 if(uip_ds6_nbr_rm(*nbr_pp) == 0) {
397 LOG_ERR("%s: input nbr cannot be removed\n", __func__);
398 return -1;
399 }
400
401 if((*nbr_pp = uip_ds6_nbr_add(&nbr_backup.ipaddr, new_ll_addr,
402 nbr_backup.isrouter, nbr_backup.state,
403 NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
404 LOG_ERR("%s: cannot allocate a new nbr for new_ll_addr\n", __func__);
405 return -1;
406 }
407 memcpy(*nbr_pp, &nbr_backup, sizeof(uip_ds6_nbr_t));
408#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
409
410 return 0;
411}
412/*---------------------------------------------------------------------------*/
413const uip_ipaddr_t *
415{
416 return (nbr != NULL) ? &nbr->ipaddr : NULL;
417}
418
419/*---------------------------------------------------------------------------*/
420const uip_lladdr_t *
422{
423#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
424 if(nbr == NULL) {
425 return NULL;
426 }
427 return (const uip_lladdr_t *)nbr_table_get_lladdr(uip_ds6_nbr_entries,
428 nbr->nbr_entry);
429#else
430 return (const uip_lladdr_t *)nbr_table_get_lladdr(ds6_neighbors, nbr);
431#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
432}
433/*---------------------------------------------------------------------------*/
434int
436{
437 int num = 0;
438
439#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
440 uip_ds6_nbr_entry_t *nbr_entry;
441 for(nbr_entry = nbr_table_head(uip_ds6_nbr_entries);
442 nbr_entry != NULL;
443 nbr_entry = nbr_table_next(uip_ds6_nbr_entries, nbr_entry)) {
444 num += list_length(nbr_entry->uip_ds6_nbrs);
445 }
446#else
448 for(nbr = nbr_table_head(ds6_neighbors);
449 nbr != NULL;
450 nbr = nbr_table_next(ds6_neighbors, nbr)) {
451 num++;
452 }
453#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
454 return num;
455}
456/*---------------------------------------------------------------------------*/
459{
460#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
461 uip_ds6_nbr_entry_t *nbr_entry;
462 if((nbr_entry = nbr_table_head(uip_ds6_nbr_entries)) == NULL) {
463 return NULL;
464 }
465 assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
466 return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
467#else
468 return nbr_table_head(ds6_neighbors);
469#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
470}
471/*---------------------------------------------------------------------------*/
474{
475#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
476 uip_ds6_nbr_entry_t *nbr_entry;
477 if(nbr == NULL) {
478 return NULL;
479 }
480 if(list_item_next(nbr) != NULL) {
481 return list_item_next(nbr);
482 }
483 nbr_entry = nbr_table_next(uip_ds6_nbr_entries, nbr->nbr_entry);
484 if(nbr_entry == NULL) {
485 return NULL;
486 } else {
487 assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
488 return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
489 }
490#else
491 return nbr_table_next(ds6_neighbors, nbr);
492#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
493}
494/*---------------------------------------------------------------------------*/
496uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
497{
499 if(ipaddr == NULL) {
500 return NULL;
501 }
502 for(nbr = uip_ds6_nbr_head(); nbr != NULL; nbr = uip_ds6_nbr_next(nbr)) {
503 if(uip_ipaddr_cmp(&nbr->ipaddr, ipaddr)) {
504 return nbr;
505 }
506 }
507 return NULL;
508}
509/*---------------------------------------------------------------------------*/
511uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr)
512{
513#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
514 uip_ds6_nbr_entry_t *nbr_entry;
515 /*
516 * we cannot determine which entry should return by lladdr alone;
517 * return the first entry associated with lladdr.
518 */
519 nbr_entry =
520 (uip_ds6_nbr_entry_t *)nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
521 (linkaddr_t*)lladdr);
522 if(nbr_entry == NULL) {
523 return NULL;
524 }
525 assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
526 return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
527#else
528 return nbr_table_get_from_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
529#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
530}
531
532/*---------------------------------------------------------------------------*/
533uip_ipaddr_t *
534uip_ds6_nbr_ipaddr_from_lladdr(const uip_lladdr_t *lladdr)
535{
537 return nbr ? &nbr->ipaddr : NULL;
538}
539
540/*---------------------------------------------------------------------------*/
541const uip_lladdr_t *
543{
545 return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
546}
547#if UIP_DS6_LL_NUD
548/*---------------------------------------------------------------------------*/
549static void
550update_nbr_reachable_state_by_ack(uip_ds6_nbr_t *nbr, const linkaddr_t *lladdr)
551{
552 if(nbr != NULL && nbr->state != NBR_INCOMPLETE) {
553 nbr->state = NBR_REACHABLE;
554 stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
555 LOG_INFO("received a link layer ACK : ");
556 LOG_INFO_LLADDR(lladdr);
557 LOG_INFO_(" is reachable.\n");
558 }
559}
560#endif /* UIP_DS6_LL_NUD */
561/*---------------------------------------------------------------------------*/
562void
563uip_ds6_link_callback(int status, int numtx)
564{
565#if UIP_DS6_LL_NUD
566 const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
567 if(linkaddr_cmp(dest, &linkaddr_null)) {
568 return;
569 }
570
571 /* From RFC4861, page 72, last paragraph of section 7.3.3:
572 *
573 * "In some cases, link-specific information may indicate that a path to
574 * a neighbor has failed (e.g., the resetting of a virtual circuit). In
575 * such cases, link-specific information may be used to purge Neighbor
576 * Cache entries before the Neighbor Unreachability Detection would do
577 * so. However, link-specific information MUST NOT be used to confirm
578 * the reachability of a neighbor; such information does not provide
579 * end-to-end confirmation between neighboring IP layers."
580 *
581 * However, we assume that receiving a link layer ack ensures the delivery
582 * of the transmitted packed to the IP stack of the neighbour. This is a
583 * fair assumption and allows battery powered nodes save some battery by
584 * not re-testing the state of a neighbour periodically if it
585 * acknowledges link packets. */
586 if(status == MAC_TX_OK) {
588#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
589 uip_ds6_nbr_entry_t *nbr_entry;
590 if((nbr_entry =
591 (uip_ds6_nbr_entry_t *)nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
592 dest)) == NULL) {
593 return;
594 }
595 for(nbr = (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
596 nbr != NULL;
598 update_nbr_reachable_state_by_ack(nbr, dest);
599 }
600#else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
601 nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
602 update_nbr_reachable_state_by_ack(nbr, dest);
603#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
604 }
605#endif /* UIP_DS6_LL_NUD */
606}
607#if UIP_ND6_SEND_NS
608/*---------------------------------------------------------------------------*/
609/** Periodic processing on neighbors */
610void
612{
614 while(nbr != NULL) {
615 switch(nbr->state) {
616 case NBR_REACHABLE:
617 if(stimer_expired(&nbr->reachable)) {
618#if UIP_CONF_ROUTER
619 /* when a neighbor leave its REACHABLE state and is a default router,
620 instead of going to STALE state it enters DELAY state in order to
621 force a NUD on it. Otherwise, if there is no upward traffic, the
622 node never knows if the default router is still reachable. This
623 mimics the 6LoWPAN-ND behavior.
624 */
625 if(uip_ds6_defrt_lookup(&nbr->ipaddr) != NULL) {
626 LOG_INFO("REACHABLE: defrt moving to DELAY (");
627 LOG_INFO_6ADDR(&nbr->ipaddr);
628 LOG_INFO_(")\n");
629 nbr->state = NBR_DELAY;
630 stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME);
631 nbr->nscount = 0;
632 } else {
633 LOG_INFO("REACHABLE: moving to STALE (");
634 LOG_INFO_6ADDR(&nbr->ipaddr);
635 LOG_INFO_(")\n");
636 nbr->state = NBR_STALE;
637 }
638#else /* UIP_CONF_ROUTER */
639 LOG_INFO("REACHABLE: moving to STALE (");
640 LOG_INFO_6ADDR(&nbr->ipaddr);
641 LOG_INFO_(")\n");
642 nbr->state = NBR_STALE;
643#endif /* UIP_CONF_ROUTER */
644 }
645 break;
646 case NBR_INCOMPLETE:
647 if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
649 } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
650 nbr->nscount++;
651 LOG_INFO("NBR_INCOMPLETE: NS %u\n", nbr->nscount);
652 uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr);
653 stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
654 }
655 break;
656 case NBR_DELAY:
657 if(stimer_expired(&nbr->reachable)) {
658 nbr->state = NBR_PROBE;
659 nbr->nscount = 0;
660 LOG_INFO("DELAY: moving to PROBE\n");
661 stimer_set(&nbr->sendns, 0);
662 }
663 break;
664 case NBR_PROBE:
665 if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
666 uip_ds6_defrt_t *locdefrt;
667 LOG_INFO("PROBE END\n");
668 if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) {
669 if (!locdefrt->isinfinite) {
670 uip_ds6_defrt_rm(locdefrt);
671 }
672 }
674 } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
675 nbr->nscount++;
676 LOG_INFO("PROBE: NS %u\n", nbr->nscount);
677 uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr);
678 stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
679 }
680 break;
681 default:
682 break;
683 }
685 }
686}
687/*---------------------------------------------------------------------------*/
688void
689uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr)
690{
693 if(nbr != NULL) {
694 nbr->state = NBR_REACHABLE;
695 nbr->nscount = 0;
696 stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
697 }
698}
699#endif /* UIP_ND6_SEND_NS */
700/*---------------------------------------------------------------------------*/
701/** @} */
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition linkaddr.c:69
const linkaddr_t linkaddr_null
The null link-layer address.
static void * list_item_next(const void *item)
Get the next item following this item.
Definition list.h:294
int list_length(const_list_t list)
Get the length of a list.
Definition list.c:160
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition list.c:71
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition list.c:134
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition list.h:126
static void * list_head(const_list_t list)
Get a pointer to the first element of a list.
Definition list.h:169
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:91
static void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition stimer.h:100
bool stimer_expired(struct stimer *t)
Check if a timer has expired.
Definition stimer.c:109
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.
#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...
uip_ds6_nbr_t * uip_ds6_nbr_head(void)
Get the first neighbor cache in nbr_table.
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.
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.
#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.
uip_ds6_nbr_t * uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
Get the neighbor cache associated with a specified IPv6 address.
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.
int uip_ds6_nbr_num(void)
Return the number of neighbor caches.
void uip_ds6_link_callback(int status, int numtx)
The callback function to update link-layer stats in a neighbor cache.
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition uip-ds6.c:74
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.
uip_ds6_nbr_t * uip_ds6_nbr_next(uip_ds6_nbr_t *nbr)
Get the next neighbor cache of a specified one.
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.
#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:93
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:176
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...
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)