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