Contiki 3.x
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 uip6
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-nbr.h"
54 
55 #define DEBUG DEBUG_NONE
56 #include "net/ip/uip-debug.h"
57 
58 #ifdef UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED
59 #define NEIGHBOR_STATE_CHANGED(n) UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED(n)
60 void NEIGHBOR_STATE_CHANGED(uip_ds6_nbr_t *n);
61 #else
62 #define NEIGHBOR_STATE_CHANGED(n)
63 #endif /* UIP_DS6_CONF_NEIGHBOR_STATE_CHANGED */
64 
65 #ifdef UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK
66 #define LINK_NEIGHBOR_CALLBACK(addr, status, numtx) UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK(addr, status, numtx)
67 void LINK_NEIGHBOR_CALLBACK(const linkaddr_t *addr, int status, int numtx);
68 #else
69 #define LINK_NEIGHBOR_CALLBACK(addr, status, numtx)
70 #endif /* UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK */
71 
72 NBR_TABLE_GLOBAL(uip_ds6_nbr_t, ds6_neighbors);
73 
74 /*---------------------------------------------------------------------------*/
75 void
76 uip_ds6_neighbors_init(void)
77 {
78  link_stats_init();
79  nbr_table_register(ds6_neighbors, (nbr_table_callback *)uip_ds6_nbr_rm);
80 }
81 /*---------------------------------------------------------------------------*/
83 uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
84  uint8_t isrouter, uint8_t state, nbr_table_reason_t reason,
85  void *data)
86 {
87  uip_ds6_nbr_t *nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr
88  , reason, data);
89  if(nbr) {
90  uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
91 #if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
92  nbr->isrouter = isrouter;
93 #endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
94  nbr->state = state;
95 #if UIP_CONF_IPV6_QUEUE_PKT
96  uip_packetqueue_new(&nbr->packethandle);
97 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
98 #if UIP_ND6_SEND_NA
99  /* timers are set separately, for now we put them in expired state */
100  stimer_set(&nbr->reachable, 0);
101  stimer_set(&nbr->sendns, 0);
102  nbr->nscount = 0;
103 #endif /* UIP_ND6_SEND_NA */
104  PRINTF("Adding neighbor with ip addr ");
105  PRINT6ADDR(ipaddr);
106  PRINTF(" link addr ");
107  PRINTLLADDR(lladdr);
108  PRINTF(" state %u\n", state);
109  NEIGHBOR_STATE_CHANGED(nbr);
110  return nbr;
111  } else {
112  PRINTF("uip_ds6_nbr_add drop ip addr ");
113  PRINT6ADDR(ipaddr);
114  PRINTF(" link addr (%p) ", lladdr);
115  PRINTLLADDR(lladdr);
116  PRINTF(" state %u\n", state);
117  return NULL;
118  }
119 }
120 
121 /*---------------------------------------------------------------------------*/
122 int
123 uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr)
124 {
125  if(nbr != NULL) {
126 #if UIP_CONF_IPV6_QUEUE_PKT
127  uip_packetqueue_free(&nbr->packethandle);
128 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
129  NEIGHBOR_STATE_CHANGED(nbr);
130  return nbr_table_remove(ds6_neighbors, nbr);
131  }
132  return 0;
133 }
134 
135 /*---------------------------------------------------------------------------*/
136 const uip_ipaddr_t *
137 uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr)
138 {
139  return (nbr != NULL) ? &nbr->ipaddr : NULL;
140 }
141 
142 /*---------------------------------------------------------------------------*/
143 const uip_lladdr_t *
144 uip_ds6_nbr_get_ll(const uip_ds6_nbr_t *nbr)
145 {
146  return (const uip_lladdr_t *)nbr_table_get_lladdr(ds6_neighbors, nbr);
147 }
148 /*---------------------------------------------------------------------------*/
149 int
150 uip_ds6_nbr_num(void)
151 {
153  int num;
154 
155  num = 0;
156  for(nbr = nbr_table_head(ds6_neighbors);
157  nbr != NULL;
158  nbr = nbr_table_next(ds6_neighbors, nbr)) {
159  num++;
160  }
161  return num;
162 }
163 /*---------------------------------------------------------------------------*/
165 uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
166 {
167  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
168  if(ipaddr != NULL) {
169  while(nbr != NULL) {
170  if(uip_ipaddr_cmp(&nbr->ipaddr, ipaddr)) {
171  return nbr;
172  }
173  nbr = nbr_table_next(ds6_neighbors, nbr);
174  }
175  }
176  return NULL;
177 }
178 /*---------------------------------------------------------------------------*/
180 uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr)
181 {
182  return nbr_table_get_from_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
183 }
184 
185 /*---------------------------------------------------------------------------*/
186 uip_ipaddr_t *
187 uip_ds6_nbr_ipaddr_from_lladdr(const uip_lladdr_t *lladdr)
188 {
189  uip_ds6_nbr_t *nbr = uip_ds6_nbr_ll_lookup(lladdr);
190  return nbr ? &nbr->ipaddr : NULL;
191 }
192 
193 /*---------------------------------------------------------------------------*/
194 const uip_lladdr_t *
195 uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr)
196 {
197  uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr);
198  return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
199 }
200 /*---------------------------------------------------------------------------*/
201 void
202 uip_ds6_link_neighbor_callback(int status, int numtx)
203 {
204  const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
205  if(linkaddr_cmp(dest, &linkaddr_null)) {
206  return;
207  }
208 
209  /* Update neighbor link statistics */
210  link_stats_packet_sent(dest, status, numtx);
211  /* Call upper-layer callback (e.g. RPL) */
212  LINK_NEIGHBOR_CALLBACK(dest, status, numtx);
213 
214 #if UIP_DS6_LL_NUD
215  /* From RFC4861, page 72, last paragraph of section 7.3.3:
216  *
217  * "In some cases, link-specific information may indicate that a path to
218  * a neighbor has failed (e.g., the resetting of a virtual circuit). In
219  * such cases, link-specific information may be used to purge Neighbor
220  * Cache entries before the Neighbor Unreachability Detection would do
221  * so. However, link-specific information MUST NOT be used to confirm
222  * the reachability of a neighbor; such information does not provide
223  * end-to-end confirmation between neighboring IP layers."
224  *
225  * However, we assume that receiving a link layer ack ensures the delivery
226  * of the transmitted packed to the IP stack of the neighbour. This is a
227  * fair assumption and allows battery powered nodes save some battery by
228  * not re-testing the state of a neighbour periodically if it
229  * acknowledges link packets. */
230  if(status == MAC_TX_OK) {
232  nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
233  if(nbr != NULL && nbr->state != NBR_INCOMPLETE) {
234  nbr->state = NBR_REACHABLE;
235  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
236  PRINTF("uip-ds6-neighbor : received a link layer ACK : ");
237  PRINTLLADDR((uip_lladdr_t *)dest);
238  PRINTF(" is reachable.\n");
239  }
240  }
241 #endif /* UIP_DS6_LL_NUD */
242 
243 }
244 #if UIP_ND6_SEND_NA
245 /*---------------------------------------------------------------------------*/
246 /** Periodic processing on neighbors */
247 void
248 uip_ds6_neighbor_periodic(void)
249 {
250  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
251  while(nbr != NULL) {
252  switch(nbr->state) {
253  case NBR_REACHABLE:
254  if(stimer_expired(&nbr->reachable)) {
255 #if UIP_CONF_IPV6_RPL
256  /* when a neighbor leave its REACHABLE state and is a default router,
257  instead of going to STALE state it enters DELAY state in order to
258  force a NUD on it. Otherwise, if there is no upward traffic, the
259  node never knows if the default router is still reachable. This
260  mimics the 6LoWPAN-ND behavior.
261  */
262  if(uip_ds6_defrt_lookup(&nbr->ipaddr) != NULL) {
263  PRINTF("REACHABLE: defrt moving to DELAY (");
264  PRINT6ADDR(&nbr->ipaddr);
265  PRINTF(")\n");
266  nbr->state = NBR_DELAY;
267  stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME);
268  nbr->nscount = 0;
269  } else {
270  PRINTF("REACHABLE: moving to STALE (");
271  PRINT6ADDR(&nbr->ipaddr);
272  PRINTF(")\n");
273  nbr->state = NBR_STALE;
274  }
275 #else /* UIP_CONF_IPV6_RPL */
276  PRINTF("REACHABLE: moving to STALE (");
277  PRINT6ADDR(&nbr->ipaddr);
278  PRINTF(")\n");
279  nbr->state = NBR_STALE;
280 #endif /* UIP_CONF_IPV6_RPL */
281  }
282  break;
283  case NBR_INCOMPLETE:
284  if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
285  uip_ds6_nbr_rm(nbr);
286  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
287  nbr->nscount++;
288  PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount);
289  uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr);
290  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
291  }
292  break;
293  case NBR_DELAY:
294  if(stimer_expired(&nbr->reachable)) {
295  nbr->state = NBR_PROBE;
296  nbr->nscount = 0;
297  PRINTF("DELAY: moving to PROBE\n");
298  stimer_set(&nbr->sendns, 0);
299  }
300  break;
301  case NBR_PROBE:
302  if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
303  uip_ds6_defrt_t *locdefrt;
304  PRINTF("PROBE END\n");
305  if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) {
306  if (!locdefrt->isinfinite) {
307  uip_ds6_defrt_rm(locdefrt);
308  }
309  }
310  uip_ds6_nbr_rm(nbr);
311  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
312  nbr->nscount++;
313  PRINTF("PROBE: NS %u\n", nbr->nscount);
314  uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr);
315  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
316  }
317  break;
318  default:
319  break;
320  }
321  nbr = nbr_table_next(ds6_neighbors, nbr);
322  }
323 }
324 /*---------------------------------------------------------------------------*/
327 {
328  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
329  uip_ds6_nbr_t *nbr_expiring = NULL;
330  while(nbr != NULL) {
331  if(nbr_expiring != NULL) {
332  clock_time_t curr = stimer_remaining(&nbr->reachable);
333  if(curr < stimer_remaining(&nbr->reachable)) {
334  nbr_expiring = nbr;
335  }
336  } else {
337  nbr_expiring = nbr;
338  }
339  nbr = nbr_table_next(ds6_neighbors, nbr);
340  }
341  return nbr_expiring;
342 }
343 #endif /* UIP_ND6_SEND_NA */
344 /*---------------------------------------------------------------------------*/
345 /** @} */
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:129
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
uip_ds6_nbr_t * uip_ds6_get_least_lifetime_neighbor(void)
This searches inside the neighbor table for the neighbor that is about to expire the next...
int stimer_expired(struct stimer *t)
Check if a timer has expired.
Definition: stimer.c:124
An entry in the default router list.
const linkaddr_t linkaddr_null
The null Rime address.
Definition: eth-conf.c:37
#define NBR_INCOMPLETE
Possible states for the nbr cache entries.
Definition: uip-ds6-nbr.h:61
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1027
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:70
IPv6 Neighbor cache (link-layer/IPv6 address mapping)
Header file for the Rime buffer (packetbuf) management
Header file for the Rime address representation
The MAC layer transmission was OK.
Definition: mac.h:79
#define NULL
The null pointer.
802.3 address
Definition: uip.h:129
unsigned long stimer_remaining(struct stimer *t)
The time until the timer expires.
Definition: stimer.c:140
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:122
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition: stimer.c:67
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)
Neighbor Cache basic routines.
Definition: uip-ds6-nbr.c:83
Linked list manipulation routines.
void uip_nd6_ns_output(uip_ipaddr_t *src, uip_ipaddr_t *dest, uip_ipaddr_t *tgt)
Send a neighbor solicitation, send a Neighbor Advertisement.
Definition: uip-nd6.c:352
A set of debugging macros for the IP stack
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:71