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"
54 #include "net/ipv6/uip-ds6-nbr.h"
55 #include "net/ipv6/uip-nd6.h"
56 #include "net/routing/routing.h"
57 
58 /* Log configuration */
59 #include "sys/log.h"
60 #define LOG_MODULE "IPv6 Nbr"
61 #define LOG_LEVEL LOG_LEVEL_IPV6
62 
63 NBR_TABLE_GLOBAL(uip_ds6_nbr_t, ds6_neighbors);
64 
65 /*---------------------------------------------------------------------------*/
66 void
67 uip_ds6_neighbors_init(void)
68 {
69  link_stats_init();
70  nbr_table_register(ds6_neighbors, (nbr_table_callback *)uip_ds6_nbr_rm);
71 }
72 /*---------------------------------------------------------------------------*/
74 uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
75  uint8_t isrouter, uint8_t state, nbr_table_reason_t reason,
76  void *data)
77 {
78  uip_ds6_nbr_t *nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr
79  , reason, data);
80  if(nbr) {
81  uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
82 #if UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
83  nbr->isrouter = isrouter;
84 #endif /* UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
85  nbr->state = state;
86 #if UIP_CONF_IPV6_QUEUE_PKT
87  uip_packetqueue_new(&nbr->packethandle);
88 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
89 #if UIP_ND6_SEND_NS
90  if(nbr->state == NBR_REACHABLE) {
91  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
92  } else {
93  /* We set the timer in expired state */
94  stimer_set(&nbr->reachable, 0);
95  }
96  stimer_set(&nbr->sendns, 0);
97  nbr->nscount = 0;
98 #endif /* UIP_ND6_SEND_NS */
99  LOG_INFO("Adding neighbor with ip addr ");
100  LOG_INFO_6ADDR(ipaddr);
101  LOG_INFO_(" link addr ");
102  LOG_INFO_LLADDR((linkaddr_t*)lladdr);
103  LOG_INFO_(" state %u\n", state);
104  NETSTACK_ROUTING.neighbor_state_changed(nbr);
105  return nbr;
106  } else {
107  LOG_INFO("Add drop ip addr ");
108  LOG_INFO_6ADDR(ipaddr);
109  LOG_INFO_(" link addr (%p) ", lladdr);
110  LOG_INFO_LLADDR((linkaddr_t*)lladdr);
111  LOG_INFO_(" state %u\n", state);
112  return NULL;
113  }
114 }
115 
116 /*---------------------------------------------------------------------------*/
117 int
118 uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr)
119 {
120  if(nbr != NULL) {
121 #if UIP_CONF_IPV6_QUEUE_PKT
122  uip_packetqueue_free(&nbr->packethandle);
123 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
124  NETSTACK_ROUTING.neighbor_state_changed(nbr);
125  return nbr_table_remove(ds6_neighbors, nbr);
126  }
127  return 0;
128 }
129 
130 /*---------------------------------------------------------------------------*/
131 int
132 uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr_pp, const uip_lladdr_t *new_ll_addr)
133 {
134  uip_ds6_nbr_t nbr_backup;
135 
136  if(nbr_pp == NULL || new_ll_addr == NULL) {
137  LOG_ERR("%s: invalid argument\n", __func__);
138  return -1;
139  }
140 
141  /* make sure new_ll_addr is not used in some other nbr */
142  if(uip_ds6_nbr_ll_lookup(new_ll_addr) != NULL) {
143  LOG_ERR("%s: new_ll_addr, ", __func__);
144  LOG_ERR_LLADDR((const linkaddr_t *)new_ll_addr);
145  LOG_ERR_(", is already used in another nbr\n");
146  return -1;
147  }
148 
149  memcpy(&nbr_backup, *nbr_pp, sizeof(uip_ds6_nbr_t));
150  if(uip_ds6_nbr_rm(*nbr_pp) == 0) {
151  LOG_ERR("%s: input nbr cannot be removed\n", __func__);
152  return -1;
153  }
154 
155  if((*nbr_pp = uip_ds6_nbr_add(&nbr_backup.ipaddr, new_ll_addr,
156  nbr_backup.isrouter, nbr_backup.state,
157  NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
158  LOG_ERR("%s: cannot allocate a new nbr for new_ll_addr\n", __func__);
159  return -1;
160  }
161  memcpy(*nbr_pp, &nbr_backup, sizeof(uip_ds6_nbr_t));
162 
163  return 0;
164 }
165 /*---------------------------------------------------------------------------*/
166 const uip_ipaddr_t *
167 uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr)
168 {
169  return (nbr != NULL) ? &nbr->ipaddr : NULL;
170 }
171 
172 /*---------------------------------------------------------------------------*/
173 const uip_lladdr_t *
174 uip_ds6_nbr_get_ll(const uip_ds6_nbr_t *nbr)
175 {
176  return (const uip_lladdr_t *)nbr_table_get_lladdr(ds6_neighbors, nbr);
177 }
178 /*---------------------------------------------------------------------------*/
179 int
180 uip_ds6_nbr_num(void)
181 {
183  int num;
184 
185  num = 0;
186  for(nbr = nbr_table_head(ds6_neighbors);
187  nbr != NULL;
188  nbr = nbr_table_next(ds6_neighbors, nbr)) {
189  num++;
190  }
191  return num;
192 }
193 /*---------------------------------------------------------------------------*/
195 uip_ds6_nbr_head(void)
196 {
197  return nbr_table_head(ds6_neighbors);
198 }
199 /*---------------------------------------------------------------------------*/
201 uip_ds6_nbr_next(uip_ds6_nbr_t *nbr)
202 {
203  return nbr_table_next(ds6_neighbors, nbr);
204 }
205 /*---------------------------------------------------------------------------*/
207 uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
208 {
209  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
210  if(ipaddr != NULL) {
211  while(nbr != NULL) {
212  if(uip_ipaddr_cmp(&nbr->ipaddr, ipaddr)) {
213  return nbr;
214  }
215  nbr = nbr_table_next(ds6_neighbors, nbr);
216  }
217  }
218  return NULL;
219 }
220 /*---------------------------------------------------------------------------*/
222 uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr)
223 {
224  return nbr_table_get_from_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
225 }
226 
227 /*---------------------------------------------------------------------------*/
228 uip_ipaddr_t *
229 uip_ds6_nbr_ipaddr_from_lladdr(const uip_lladdr_t *lladdr)
230 {
231  uip_ds6_nbr_t *nbr = uip_ds6_nbr_ll_lookup(lladdr);
232  return nbr ? &nbr->ipaddr : NULL;
233 }
234 
235 /*---------------------------------------------------------------------------*/
236 const uip_lladdr_t *
237 uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr)
238 {
239  uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr);
240  return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
241 }
242 /*---------------------------------------------------------------------------*/
243 void
244 uip_ds6_link_callback(int status, int numtx)
245 {
246 #if UIP_DS6_LL_NUD
247  const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
248  if(linkaddr_cmp(dest, &linkaddr_null)) {
249  return;
250  }
251 
252  /* From RFC4861, page 72, last paragraph of section 7.3.3:
253  *
254  * "In some cases, link-specific information may indicate that a path to
255  * a neighbor has failed (e.g., the resetting of a virtual circuit). In
256  * such cases, link-specific information may be used to purge Neighbor
257  * Cache entries before the Neighbor Unreachability Detection would do
258  * so. However, link-specific information MUST NOT be used to confirm
259  * the reachability of a neighbor; such information does not provide
260  * end-to-end confirmation between neighboring IP layers."
261  *
262  * However, we assume that receiving a link layer ack ensures the delivery
263  * of the transmitted packed to the IP stack of the neighbour. This is a
264  * fair assumption and allows battery powered nodes save some battery by
265  * not re-testing the state of a neighbour periodically if it
266  * acknowledges link packets. */
267  if(status == MAC_TX_OK) {
269  nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
270  if(nbr != NULL && nbr->state != NBR_INCOMPLETE) {
271  nbr->state = NBR_REACHABLE;
272  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
273  LOG_INFO("received a link layer ACK : ");
274  LOG_INFO_LLADDR((uip_lladdr_t *)dest);
275  LOG_INFO_(" is reachable.\n");
276  }
277  }
278 #endif /* UIP_DS6_LL_NUD */
279 }
280 #if UIP_ND6_SEND_NS
281 /*---------------------------------------------------------------------------*/
282 /** Periodic processing on neighbors */
283 void
284 uip_ds6_neighbor_periodic(void)
285 {
286  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
287  while(nbr != NULL) {
288  switch(nbr->state) {
289  case NBR_REACHABLE:
290  if(stimer_expired(&nbr->reachable)) {
291 #if UIP_CONF_ROUTER
292  /* when a neighbor leave its REACHABLE state and is a default router,
293  instead of going to STALE state it enters DELAY state in order to
294  force a NUD on it. Otherwise, if there is no upward traffic, the
295  node never knows if the default router is still reachable. This
296  mimics the 6LoWPAN-ND behavior.
297  */
298  if(uip_ds6_defrt_lookup(&nbr->ipaddr) != NULL) {
299  LOG_INFO("REACHABLE: defrt moving to DELAY (");
300  LOG_INFO_6ADDR(&nbr->ipaddr);
301  LOG_INFO_(")\n");
302  nbr->state = NBR_DELAY;
303  stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME);
304  nbr->nscount = 0;
305  } else {
306  LOG_INFO("REACHABLE: moving to STALE (");
307  LOG_INFO_6ADDR(&nbr->ipaddr);
308  LOG_INFO_(")\n");
309  nbr->state = NBR_STALE;
310  }
311 #else /* UIP_CONF_ROUTER */
312  LOG_INFO("REACHABLE: moving to STALE (");
313  LOG_INFO_6ADDR(&nbr->ipaddr);
314  LOG_INFO_(")\n");
315  nbr->state = NBR_STALE;
316 #endif /* UIP_CONF_ROUTER */
317  }
318  break;
319  case NBR_INCOMPLETE:
320  if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
321  uip_ds6_nbr_rm(nbr);
322  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
323  nbr->nscount++;
324  LOG_INFO("NBR_INCOMPLETE: NS %u\n", nbr->nscount);
325  uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr);
326  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
327  }
328  break;
329  case NBR_DELAY:
330  if(stimer_expired(&nbr->reachable)) {
331  nbr->state = NBR_PROBE;
332  nbr->nscount = 0;
333  LOG_INFO("DELAY: moving to PROBE\n");
334  stimer_set(&nbr->sendns, 0);
335  }
336  break;
337  case NBR_PROBE:
338  if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
339  uip_ds6_defrt_t *locdefrt;
340  LOG_INFO("PROBE END\n");
341  if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) {
342  if (!locdefrt->isinfinite) {
343  uip_ds6_defrt_rm(locdefrt);
344  }
345  }
346  uip_ds6_nbr_rm(nbr);
347  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
348  nbr->nscount++;
349  LOG_INFO("PROBE: NS %u\n", nbr->nscount);
350  uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr);
351  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
352  }
353  break;
354  default:
355  break;
356  }
357  nbr = nbr_table_next(ds6_neighbors, nbr);
358  }
359 }
360 /*---------------------------------------------------------------------------*/
361 void
362 uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr)
363 {
365  nbr = uip_ds6_nbr_lookup(ipaddr);
366  if(nbr != NULL) {
367  nbr->state = NBR_REACHABLE;
368  nbr->nscount = 0;
369  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
370  }
371 }
372 /*---------------------------------------------------------------------------*/
375 {
376  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
377  uip_ds6_nbr_t *nbr_expiring = NULL;
378  while(nbr != NULL) {
379  if(nbr_expiring != NULL) {
380  clock_time_t curr = stimer_remaining(&nbr->reachable);
381  if(curr < stimer_remaining(&nbr->reachable)) {
382  nbr_expiring = nbr;
383  }
384  } else {
385  nbr_expiring = nbr;
386  }
387  nbr = nbr_table_next(ds6_neighbors, nbr);
388  }
389  return nbr_expiring;
390 }
391 #endif /* UIP_ND6_SEND_NS */
392 /*---------------------------------------------------------------------------*/
393 /** @} */
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:125
An entry in the default router list.
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:115
unsigned long stimer_remaining(struct stimer *t)
The time until the timer expires.
Definition: stimer.c:143
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:179
Header file for the link-layer address representation
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...
IPv6 Neighbor cache (link-layer/IPv6 address mapping)
int stimer_expired(struct stimer *t)
Check if a timer has expired.
Definition: stimer.c:127
const linkaddr_t linkaddr_null
The null link-layer address.
Header file for IPv6-related data structures.
void(* neighbor_state_changed)(uip_ds6_nbr_t *nbr)
Called by uIP to notify addition/removal of IPv6 neighbor entries.
Definition: routing.h:168
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.
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition: stimer.c:67
Linked list manipulation routines.
The MAC layer transmission was OK.
Definition: mac.h:84
Routing driver header file
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1018
#define NBR_INCOMPLETE
Possible states for the nbr cache entries.
Definition: uip-ds6-nbr.h:60
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
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:74
Header file for IPv6 Neighbor discovery (RFC 4861)
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
Header file for the Packet buffer (packetbuf) management
Header file for the logging system
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:69