49#include "net/link-stats.h"
57#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
63#define LOG_MODULE "IPv6 Nbr"
64#define LOG_LEVEL LOG_LEVEL_IPV6
66#if BUILD_WITH_ORCHESTRA
69#ifndef NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK
70#define NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK orchestra_callback_neighbor_updated
72void NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK(
const linkaddr_t *, uint8_t is_added);
76#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
84 uip_ds6_nbr_entry_t *nbr_entry);
96static void remove_nbr_entry(uip_ds6_nbr_entry_t *nbr_entry);
108static void callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry);
110NBR_TABLE(uip_ds6_nbr_entry_t, uip_ds6_nbr_entries);
118uip_ds6_neighbors_init(
void)
121#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
123 nbr_table_register(uip_ds6_nbr_entries,
124 (nbr_table_callback *)callback_nbr_entry_removal);
126 nbr_table_register(ds6_neighbors, (nbr_table_callback *)
uip_ds6_nbr_rm);
132 uint8_t isrouter, uint8_t state, nbr_table_reason_t reason,
137#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
138 uip_ds6_nbr_entry_t *nbr_entry;
142 LOG_ERR(
"%s: uip_ds6_nbr for ", __func__);
144 LOG_ERR_(
"has already existed\n");
150 LOG_ERR(
"%s: cannot allocate a new uip_ds6_nbr\n", __func__);
155 nbr_entry = nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
156 (
const linkaddr_t *)lladdr);
157 if(nbr_entry == NULL) {
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__);
169 if((nbr_entry == NULL) ||
176 LOG_ERR(
"%s: no room in nbr_entry for ", __func__);
177 LOG_ERR_LLADDR((
const linkaddr_t *)lladdr);
186 add_uip_ds6_nbr_to_nbr_entry(
nbr, nbr_entry);
189 nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr, reason, data);
193#ifdef NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK
194 NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK((
const linkaddr_t *)lladdr, 1);
197#if UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
198 nbr->isrouter = isrouter;
201#if UIP_CONF_IPV6_QUEUE_PKT
202 uip_packetqueue_new(&
nbr->packethandle);
205 if(
nbr->state == NBR_REACHABLE) {
214 LOG_INFO(
"Adding neighbor with ip addr ");
216 LOG_INFO_(
" link addr ");
217 LOG_INFO_LLADDR((linkaddr_t*)lladdr);
218 LOG_INFO_(
" state %u\n", state);
222 LOG_INFO(
"Add drop ip addr ");
224 LOG_INFO_(
" link addr (%p) ", lladdr);
225 LOG_INFO_LLADDR((linkaddr_t*)lladdr);
226 LOG_INFO_(
" state %u\n", state);
231#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
235 uip_ds6_nbr_entry_t *nbr_entry)
237 LOG_DBG(
"%s: add nbr(%p) to nbr_entry (%p)\n",
238 __func__,
nbr, nbr_entry);
239 nbr->nbr_entry = nbr_entry;
249 LOG_DBG(
"%s: remove nbr(%p) from nbr_entry (%p)\n",
250 __func__,
nbr,
nbr->nbr_entry);
255remove_nbr_entry(uip_ds6_nbr_entry_t *nbr_entry)
257 if(nbr_entry == NULL) {
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);
271#if UIP_CONF_IPV6_QUEUE_PKT
272 uip_packetqueue_free(&
nbr->packethandle);
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__);
279 remove_uip_ds6_nbr_from_nbr_entry(
nbr);
281 remove_nbr_entry(
nbr->nbr_entry);
284 LOG_DBG(
"%s: free memory for nbr(%p)\n", __func__,
nbr);
289callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry)
293 if(nbr_entry == NULL) {
300 free_uip_ds6_nbr(
nbr);
313#ifdef NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK
314 linkaddr_t lladdr = {0};
317 if(plladdr != NULL) {
318 memcpy(&lladdr, plladdr,
sizeof(lladdr));
322#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
324 free_uip_ds6_nbr(
nbr);
329#if UIP_CONF_IPV6_QUEUE_PKT
330 uip_packetqueue_free(&
nbr->packethandle);
334 ret = nbr_table_remove(ds6_neighbors,
nbr);
337#ifdef NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK
338 NETSTACK_CONF_DS6_NEIGHBOR_UPDATED_CALLBACK(&lladdr, 0);
348#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
349 uip_ds6_nbr_entry_t *nbr_entry;
355 if(nbr_pp == NULL || new_ll_addr == NULL) {
356 LOG_ERR(
"%s: invalid argument\n", __func__);
360#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
363 nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
364 (
const linkaddr_t *)new_ll_addr)) == NULL) {
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);
379 remove_uip_ds6_nbr_from_nbr_entry(
nbr);
381 remove_nbr_entry(
nbr->nbr_entry);
383 add_uip_ds6_nbr_to_nbr_entry(
nbr, nbr_entry);
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");
397 LOG_ERR(
"%s: input nbr cannot be removed\n", __func__);
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__);
416 return (
nbr != NULL) ? &
nbr->ipaddr : NULL;
423#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
427 return (
const uip_lladdr_t *)nbr_table_get_lladdr(uip_ds6_nbr_entries,
430 return (
const uip_lladdr_t *)nbr_table_get_lladdr(ds6_neighbors,
nbr);
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);
443 nbr_entry = nbr_table_next(uip_ds6_nbr_entries, nbr_entry)) {
448 for(
nbr = nbr_table_head(ds6_neighbors);
450 nbr = nbr_table_next(ds6_neighbors,
nbr)) {
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) {
465 assert(
list_head(nbr_entry->uip_ds6_nbrs) != NULL);
468 return nbr_table_head(ds6_neighbors);
475#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
476 uip_ds6_nbr_entry_t *nbr_entry;
483 nbr_entry = nbr_table_next(uip_ds6_nbr_entries,
nbr->nbr_entry);
484 if(nbr_entry == NULL) {
487 assert(
list_head(nbr_entry->uip_ds6_nbrs) != NULL);
491 return nbr_table_next(ds6_neighbors,
nbr);
503 if(uip_ipaddr_cmp(&
nbr->ipaddr,
ipaddr)) {
513#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
514 uip_ds6_nbr_entry_t *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) {
525 assert(
list_head(nbr_entry->uip_ds6_nbrs) != NULL);
528 return nbr_table_get_from_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
537 return nbr ? &
nbr->ipaddr : NULL;
550update_nbr_reachable_state_by_ack(
uip_ds6_nbr_t *
nbr,
const linkaddr_t *lladdr)
553 nbr->state = NBR_REACHABLE;
555 LOG_INFO(
"received a link layer ACK : ");
556 LOG_INFO_LLADDR(lladdr);
557 LOG_INFO_(
" is reachable.\n");
566 const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
588#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
589 uip_ds6_nbr_entry_t *nbr_entry;
591 (uip_ds6_nbr_entry_t *)nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
598 update_nbr_reachable_state_by_ack(
nbr, dest);
602 update_nbr_reachable_state_by_ack(
nbr, dest);
625 if(uip_ds6_defrt_lookup(&
nbr->ipaddr) != NULL) {
626 LOG_INFO(
"REACHABLE: defrt moving to DELAY (");
627 LOG_INFO_6ADDR(&
nbr->ipaddr);
629 nbr->state = NBR_DELAY;
633 LOG_INFO(
"REACHABLE: moving to STALE (");
634 LOG_INFO_6ADDR(&
nbr->ipaddr);
636 nbr->state = NBR_STALE;
639 LOG_INFO(
"REACHABLE: moving to STALE (");
640 LOG_INFO_6ADDR(&
nbr->ipaddr);
642 nbr->state = NBR_STALE;
647 if(
nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
651 LOG_INFO(
"NBR_INCOMPLETE: NS %u\n",
nbr->nscount);
658 nbr->state = NBR_PROBE;
660 LOG_INFO(
"DELAY: moving to PROBE\n");
665 if(
nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
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);
676 LOG_INFO(
"PROBE: NS %u\n",
nbr->nscount);
689uip_ds6_nbr_refresh_reachable_state(
const uip_ipaddr_t *
ipaddr)
694 nbr->state = NBR_REACHABLE;
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
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.
int list_length(const_list_t list)
Get the length of a list.
void list_add(list_t list, void *item)
Add an item at the end of a list.
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
static void * list_head(const_list_t list)
Get a pointer to the first element of a list.
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
#define MEMB(name, structure, num)
Declare a memory block.
static void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
bool stimer_expired(struct stimer *t)
Check if a timer has expired.
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.
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.
#define NBR_INCOMPLETE
Possible states for the nbr cache entries.
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.
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.
uint16_t uip_len
The length of the packet in the uip_buf buffer.
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.
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.
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.
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Header file for IPv6 Neighbor discovery (RFC 4861)