Contiki-Inga 3.x
uip-ds6-nbr.c
1 /**
2  * \addtogroup uip6
3  * @{
4  */
5 
6 /*
7  * Copyright (c) 2013, Swedish Institute of Computer Science.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the Institute nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  */
36 
37 /**
38  * \file IPv6 Neighbor cache (link-layer/IPv6 address mapping)
39  *
40  * \author Mathilde Durvy <mdurvy@cisco.com>
41  * \author Julien Abeille <jabeille@cisco.com>
42  * \author Simon Duquennoy <simonduq@sics.se>
43  */
44 
45 #include <string.h>
46 #include <stdlib.h>
47 #include <stddef.h>
48 #include "lib/list.h"
49 #include "net/linkaddr.h"
50 #include "net/packetbuf.h"
51 #include "net/ipv6/uip-ds6-nbr.h"
52 
53 #define DEBUG DEBUG_NONE
54 #include "net/ip/uip-debug.h"
55 
56 #ifdef UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED
57 #define NEIGHBOR_STATE_CHANGED(n) UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED(n)
58 void NEIGHBOR_STATE_CHANGED(uip_ds6_nbr_t *n);
59 #else
60 #define NEIGHBOR_STATE_CHANGED(n)
61 #endif /* UIP_DS6_CONF_NEIGHBOR_STATE_CHANGED */
62 
63 #ifdef UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK
64 #define LINK_NEIGHBOR_CALLBACK(addr, status, numtx) UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK(addr, status, numtx)
65 void LINK_NEIGHBOR_CALLBACK(const linkaddr_t *addr, int status, int numtx);
66 #else
67 #define LINK_NEIGHBOR_CALLBACK(addr, status, numtx)
68 #endif /* UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK */
69 
70 NBR_TABLE_GLOBAL(uip_ds6_nbr_t, ds6_neighbors);
71 
72 /*---------------------------------------------------------------------------*/
73 void
75 {
76  nbr_table_register(ds6_neighbors, (nbr_table_callback *)uip_ds6_nbr_rm);
77 }
78 /*---------------------------------------------------------------------------*/
80 uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
81  uint8_t isrouter, uint8_t state)
82 {
83  uip_ds6_nbr_t *nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
84  if(nbr) {
85  uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
86  nbr->isrouter = isrouter;
87  nbr->state = state;
88  #if UIP_CONF_IPV6_QUEUE_PKT
89  uip_packetqueue_new(&nbr->packethandle);
90  #endif /* UIP_CONF_IPV6_QUEUE_PKT */
91  /* timers are set separately, for now we put them in expired state */
92  stimer_set(&nbr->reachable, 0);
93  stimer_set(&nbr->sendns, 0);
94  nbr->nscount = 0;
95  PRINTF("Adding neighbor with ip addr ");
96  PRINT6ADDR(ipaddr);
97  PRINTF(" link addr ");
98  PRINTLLADDR(lladdr);
99  PRINTF(" state %u\n", state);
100  NEIGHBOR_STATE_CHANGED(nbr);
101  return nbr;
102  } else {
103  PRINTF("uip_ds6_nbr_add drop ip addr ");
104  PRINT6ADDR(ipaddr);
105  PRINTF(" link addr (%p) ", lladdr);
106  PRINTLLADDR(lladdr);
107  PRINTF(" state %u\n", state);
108  return NULL;
109  }
110 }
111 
112 /*---------------------------------------------------------------------------*/
113 void
115 {
116  if(nbr != NULL) {
117 #if UIP_CONF_IPV6_QUEUE_PKT
118  uip_packetqueue_free(&nbr->packethandle);
119 #endif /* UIP_CONF_IPV6_QUEUE_PKT */
120  NEIGHBOR_STATE_CHANGED(nbr);
121  nbr_table_remove(ds6_neighbors, nbr);
122  }
123  return;
124 }
125 
126 /*---------------------------------------------------------------------------*/
127 const uip_ipaddr_t *
129 {
130  return (nbr != NULL) ? &nbr->ipaddr : NULL;
131 }
132 
133 /*---------------------------------------------------------------------------*/
134 const uip_lladdr_t *
136 {
137  return (const uip_lladdr_t *)nbr_table_get_lladdr(ds6_neighbors, nbr);
138 }
139 /*---------------------------------------------------------------------------*/
140 int
142 {
143  uip_ds6_nbr_t *nbr;
144  int num;
145 
146  num = 0;
147  for(nbr = nbr_table_head(ds6_neighbors);
148  nbr != NULL;
149  nbr = nbr_table_next(ds6_neighbors, nbr)) {
150  num++;
151  }
152  return num;
153 }
154 /*---------------------------------------------------------------------------*/
156 uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
157 {
158  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
159  if(ipaddr != NULL) {
160  while(nbr != NULL) {
161  if(uip_ipaddr_cmp(&nbr->ipaddr, ipaddr)) {
162  return nbr;
163  }
164  nbr = nbr_table_next(ds6_neighbors, nbr);
165  }
166  }
167  return NULL;
168 }
169 /*---------------------------------------------------------------------------*/
172 {
173  return nbr_table_get_from_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
174 }
175 
176 /*---------------------------------------------------------------------------*/
177 uip_ipaddr_t *
179 {
180  uip_ds6_nbr_t *nbr = uip_ds6_nbr_ll_lookup(lladdr);
181  return nbr ? &nbr->ipaddr : NULL;
182 }
183 
184 /*---------------------------------------------------------------------------*/
185 const uip_lladdr_t *
186 uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr)
187 {
188  uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr);
189  return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
190 }
191 /*---------------------------------------------------------------------------*/
192 void
193 uip_ds6_link_neighbor_callback(int status, int numtx)
194 {
195  const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
196  if(linkaddr_cmp(dest, &linkaddr_null)) {
197  return;
198  }
199 
200  LINK_NEIGHBOR_CALLBACK(dest, status, numtx);
201 
202 #if UIP_DS6_LL_NUD
203  if(status == MAC_TX_OK) {
204  uip_ds6_nbr_t *nbr;
205  nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
206  if(nbr != NULL &&
207  (nbr->state == NBR_STALE || nbr->state == NBR_DELAY ||
208  nbr->state == NBR_PROBE)) {
209  nbr->state = NBR_REACHABLE;
210  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
211  PRINTF("uip-ds6-neighbor : received a link layer ACK : ");
212  PRINTLLADDR((uip_lladdr_t *)dest);
213  PRINTF(" is reachable.\n");
214  }
215  }
216 #endif /* UIP_DS6_LL_NUD */
217 
218 }
219 /*---------------------------------------------------------------------------*/
220 void
222 {
223  /* Periodic processing on neighbors */
224  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
225  while(nbr != NULL) {
226  switch(nbr->state) {
227  case NBR_REACHABLE:
228  if(stimer_expired(&nbr->reachable)) {
229  PRINTF("REACHABLE: moving to STALE (");
230  PRINT6ADDR(&nbr->ipaddr);
231  PRINTF(")\n");
232  nbr->state = NBR_STALE;
233  }
234  break;
235 #if UIP_ND6_SEND_NA
236  case NBR_INCOMPLETE:
237  if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
238  uip_ds6_nbr_rm(nbr);
239  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
240  nbr->nscount++;
241  PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount);
242  uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr);
243  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
244  }
245  break;
246  case NBR_DELAY:
247  if(stimer_expired(&nbr->reachable)) {
248  nbr->state = NBR_PROBE;
249  nbr->nscount = 0;
250  PRINTF("DELAY: moving to PROBE\n");
251  stimer_set(&nbr->sendns, 0);
252  }
253  break;
254  case NBR_PROBE:
255  if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
256  uip_ds6_defrt_t *locdefrt;
257  PRINTF("PROBE END\n");
258  if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) {
259  if (!locdefrt->isinfinite) {
260  uip_ds6_defrt_rm(locdefrt);
261  }
262  }
263  uip_ds6_nbr_rm(nbr);
264  } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) {
265  nbr->nscount++;
266  PRINTF("PROBE: NS %u\n", nbr->nscount);
267  uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr);
268  stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
269  }
270  break;
271 #endif /* UIP_ND6_SEND_NA */
272  default:
273  break;
274  }
275  nbr = nbr_table_next(ds6_neighbors, nbr);
276  }
277 }
278 /*---------------------------------------------------------------------------*/
281 {
282  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
283  uip_ds6_nbr_t *nbr_expiring = NULL;
284  while(nbr != NULL) {
285  if(nbr_expiring != NULL) {
286  clock_time_t curr = stimer_remaining(&nbr->reachable);
287  if(curr < stimer_remaining(&nbr->reachable)) {
288  nbr_expiring = nbr;
289  }
290  } else {
291  nbr_expiring = nbr;
292  }
293  nbr = nbr_table_next(ds6_neighbors, nbr);
294  }
295  return nbr_expiring;
296 }
297 /*---------------------------------------------------------------------------*/