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  * \file
34  * IPv6 Neighbor cache (link-layer/IPv6 address mapping)
35  * \author Mathilde Durvy <mdurvy@cisco.com>
36  * \author Julien Abeille <jabeille@cisco.com>
37  * \author Simon Duquennoy <simonduq@sics.se>
38  *
39  */
40 
41 /**
42  * \addtogroup uip6
43  * @{
44  */
45 
46 #include <string.h>
47 #include <stdlib.h>
48 #include <stddef.h>
49 #include "lib/list.h"
50 #include "net/linkaddr.h"
51 #include "net/packetbuf.h"
52 #include "net/ipv6/uip-ds6-nbr.h"
53 
54 #define DEBUG DEBUG_NONE
55 #include "net/ip/uip-debug.h"
56 
57 #ifdef UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED
58 #define NEIGHBOR_STATE_CHANGED(n) UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED(n)
59 void NEIGHBOR_STATE_CHANGED(uip_ds6_nbr_t *n);
60 #else
61 #define NEIGHBOR_STATE_CHANGED(n)
62 #endif /* UIP_DS6_CONF_NEIGHBOR_STATE_CHANGED */
63 
64 #ifdef UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK
65 #define LINK_NEIGHBOR_CALLBACK(addr, status, numtx) UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK(addr, status, numtx)
66 void LINK_NEIGHBOR_CALLBACK(const linkaddr_t *addr, int status, int numtx);
67 #else
68 #define LINK_NEIGHBOR_CALLBACK(addr, status, numtx)
69 #endif /* UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK */
70 
71 NBR_TABLE_GLOBAL(uip_ds6_nbr_t, ds6_neighbors);
72 
73 /*---------------------------------------------------------------------------*/
74 void
75 uip_ds6_neighbors_init(void)
76 {
77  nbr_table_register(ds6_neighbors, (nbr_table_callback *)uip_ds6_nbr_rm);
78 }
79 /*---------------------------------------------------------------------------*/
81 uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
82  uint8_t isrouter, uint8_t state)
83 {
84  uip_ds6_nbr_t *nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
85  if(nbr) {
86  uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
87  nbr->isrouter = isrouter;
88  nbr->state = state;
89  #if UIP_CONF_IPV6_QUEUE_PKT
90  uip_packetqueue_new(&nbr->packethandle);
91  #endif /* UIP_CONF_IPV6_QUEUE_PKT */
92  /* timers are set separately, for now we put them in expired state */
93  stimer_set(&nbr->reachable, 0);
94  stimer_set(&nbr->sendns, 0);
95  nbr->nscount = 0;
96  PRINTF("Adding neighbor with ip addr ");
97  PRINT6ADDR(ipaddr);
98  PRINTF(" link addr ");
99  PRINTLLADDR(lladdr);
100  PRINTF(" state %u\n", state);
101  NEIGHBOR_STATE_CHANGED(nbr);
102  return nbr;
103  } else {
104  PRINTF("uip_ds6_nbr_add drop ip addr ");
105  PRINT6ADDR(ipaddr);
106  PRINTF(" link addr (%p) ", lladdr);
107  PRINTLLADDR(lladdr);
108  PRINTF(" state %u\n", state);
109  return NULL;
110  }
111 }
112 
113 /*---------------------------------------------------------------------------*/
114 void
115 uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr)
116 {
117  if(nbr != NULL) {
118 #if UIP_CONF_IPV6_QUEUE_PKT
119  uip_packetqueue_free(&nbr->packethandle);
120 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
121  NEIGHBOR_STATE_CHANGED(nbr);
122  nbr_table_remove(ds6_neighbors, nbr);
123  }
124  return;
125 }
126 
127 /*---------------------------------------------------------------------------*/
128 const uip_ipaddr_t *
129 uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr)
130 {
131  return (nbr != NULL) ? &nbr->ipaddr : NULL;
132 }
133 
134 /*---------------------------------------------------------------------------*/
135 const uip_lladdr_t *
136 uip_ds6_nbr_get_ll(const uip_ds6_nbr_t *nbr)
137 {
138  return (const uip_lladdr_t *)nbr_table_get_lladdr(ds6_neighbors, nbr);
139 }
140 /*---------------------------------------------------------------------------*/
141 int
142 uip_ds6_nbr_num(void)
143 {
144  uip_ds6_nbr_t *nbr;
145  int num;
146 
147  num = 0;
148  for(nbr = nbr_table_head(ds6_neighbors);
149  nbr != NULL;
150  nbr = nbr_table_next(ds6_neighbors, nbr)) {
151  num++;
152  }
153  return num;
154 }
155 /*---------------------------------------------------------------------------*/
157 uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
158 {
159  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
160  if(ipaddr != NULL) {
161  while(nbr != NULL) {
162  if(uip_ipaddr_cmp(&nbr->ipaddr, ipaddr)) {
163  return nbr;
164  }
165  nbr = nbr_table_next(ds6_neighbors, nbr);
166  }
167  }
168  return NULL;
169 }
170 /*---------------------------------------------------------------------------*/
172 uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr)
173 {
174  return nbr_table_get_from_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
175 }
176 
177 /*---------------------------------------------------------------------------*/
178 uip_ipaddr_t *
179 uip_ds6_nbr_ipaddr_from_lladdr(const uip_lladdr_t *lladdr)
180 {
181  uip_ds6_nbr_t *nbr = uip_ds6_nbr_ll_lookup(lladdr);
182  return nbr ? &nbr->ipaddr : NULL;
183 }
184 
185 /*---------------------------------------------------------------------------*/
186 const uip_lladdr_t *
187 uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr)
188 {
189  uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr);
190  return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
191 }
192 /*---------------------------------------------------------------------------*/
193 void
194 uip_ds6_link_neighbor_callback(int status, int numtx)
195 {
196  const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
197  if(linkaddr_cmp(dest, &linkaddr_null)) {
198  return;
199  }
200 
201  LINK_NEIGHBOR_CALLBACK(dest, status, numtx);
202 
203 #if UIP_DS6_LL_NUD
204  if(status == MAC_TX_OK) {
205  uip_ds6_nbr_t *nbr;
206  nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
207  if(nbr != NULL &&
208  (nbr->state == NBR_STALE || nbr->state == NBR_DELAY ||
209  nbr->state == NBR_PROBE)) {
210  nbr->state = NBR_REACHABLE;
211  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
212  PRINTF("uip-ds6-neighbor : received a link layer ACK : ");
213  PRINTLLADDR((uip_lladdr_t *)dest);
214  PRINTF(" is reachable.\n");
215  }
216  }
217 #endif /* UIP_DS6_LL_NUD */
218 
219 }
220 /*---------------------------------------------------------------------------*/
221 void
222 uip_ds6_neighbor_periodic(void)
223 {
224  /* Periodic processing on neighbors */
225  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
226  while(nbr != NULL) {
227  switch(nbr->state) {
228  case NBR_REACHABLE:
229  if(stimer_expired(&nbr->reachable)) {
230  PRINTF("REACHABLE: moving to STALE (");
231  PRINT6ADDR(&nbr->ipaddr);
232  PRINTF(")\n");
233  nbr->state = NBR_STALE;
234  }
235  break;
236 #if UIP_ND6_SEND_NA
237  case NBR_INCOMPLETE:
238  if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
239  uip_ds6_nbr_rm(nbr);
240  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
241  nbr->nscount++;
242  PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount);
243  uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr);
244  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
245  }
246  break;
247  case NBR_DELAY:
248  if(stimer_expired(&nbr->reachable)) {
249  nbr->state = NBR_PROBE;
250  nbr->nscount = 0;
251  PRINTF("DELAY: moving to PROBE\n");
252  stimer_set(&nbr->sendns, 0);
253  }
254  break;
255  case NBR_PROBE:
256  if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
257  uip_ds6_defrt_t *locdefrt;
258  PRINTF("PROBE END\n");
259  if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) {
260  if (!locdefrt->isinfinite) {
261  uip_ds6_defrt_rm(locdefrt);
262  }
263  }
264  uip_ds6_nbr_rm(nbr);
265  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
266  nbr->nscount++;
267  PRINTF("PROBE: NS %u\n", nbr->nscount);
268  uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr);
269  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
270  }
271  break;
272 #endif /* UIP_ND6_SEND_NA */
273  default:
274  break;
275  }
276  nbr = nbr_table_next(ds6_neighbors, nbr);
277  }
278 }
279 /*---------------------------------------------------------------------------*/
282 {
283  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
284  uip_ds6_nbr_t *nbr_expiring = NULL;
285  while(nbr != NULL) {
286  if(nbr_expiring != NULL) {
287  clock_time_t curr = stimer_remaining(&nbr->reachable);
288  if(curr < stimer_remaining(&nbr->reachable)) {
289  nbr_expiring = nbr;
290  }
291  } else {
292  nbr_expiring = nbr;
293  }
294  nbr = nbr_table_next(ds6_neighbors, nbr);
295  }
296  return nbr_expiring;
297 }
298 /*---------------------------------------------------------------------------*/
299 /** @} */
Linked list manipulation routines.
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
int stimer_expired(struct stimer *t)
Check if a timer has expired.
Definition: stimer.c:124
const linkaddr_t linkaddr_null
The null Rime address.
Header file for the Rime buffer (packetbuf) management
#define NULL
The null pointer.
#define NBR_INCOMPLETE
Possible states for the nbr cache entries.
Definition: uip-ds6-nbr.h:61
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition: stimer.c:67
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1026
802.3 address
Definition: uip.h:135
The MAC layer transmission was OK.
Definition: mac.h:79
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
IPv6 Neighbor cache (link-layer/IPv6 address mapping)
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...
Definition: uip-ds6-nbr.c:281
A set of debugging macros.
An entry in the default router list.
uip_ds6_nbr_t * uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr, uint8_t isrouter, uint8_t state)
Neighbor Cache basic routines.
Definition: uip-ds6-nbr.c:81
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:328
Header file for the Rime address representation
unsigned long stimer_remaining(struct stimer *t)
The time until the timer expires.
Definition: stimer.c:140
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:70