Added support for the FTP standalone client to the c64 target.
[contiki-2.x.git] / core / net / uip-nd6.c
blob8bd60fe5d2dd69b05eaa44a9a9e914bddbb74bec
1 /**
2 * \addtogroup uip6
3 * @{
4 */
6 /**
7 * \file
8 * Neighbor discovery (RFC 4861)
9 * \author Mathilde Durvy <mdurvy@cisco.com>
10 * \author Julien Abeille <jabeille@cisco.com>
14 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of the project nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
42 * Copyright (c) 2006, Swedish Institute of Computer Science.
43 * All rights reserved.
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 * 3. Neither the name of the Institute nor the names of its contributors
54 * may be used to endorse or promote products derived from this software
55 * without specific prior written permission.
57 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * SUCH DAMAGE.
71 #include <string.h>
72 #include "net/uip-icmp6.h"
73 #include "net/uip-nd6.h"
74 #include "net/uip-ds6.h"
75 #include "lib/random.h"
77 /*------------------------------------------------------------------*/
78 #define DEBUG 0
79 #if DEBUG
80 #include <stdio.h>
81 #define PRINTF(...) printf(__VA_ARGS__)
82 #define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_t *)addr)[15])
83 #define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",lladdr->addr[0], lladdr->addr[1], lladdr->addr[2], lladdr->addr[3],lladdr->addr[4], lladdr->addr[5])
84 #else
85 #define PRINTF(...)
86 #define PRINT6ADDR(addr)
87 #define PRINTLLADDR(addr)
88 #endif
90 #if UIP_LOGGING
91 #include <stdio.h>
92 void uip_log(char *msg);
94 #define UIP_LOG(m) uip_log(m)
95 #else
96 #define UIP_LOG(m)
97 #endif /* UIP_LOGGING == 1 */
99 /*------------------------------------------------------------------*/
100 /** @{ */
101 /** \name Pointers to the header structures.
102 * All pointers except UIP_IP_BUF depend on uip_ext_len, which at
103 * packet reception, is the total length of the extension headers.
105 * The pointer to ND6 options header also depends on nd6_opt_offset,
106 * which we set in each function.
108 * Care should be taken when manipulating these buffers about the
109 * value of these length variables
112 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) /**< Pointer to IP header */
113 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) /**< Pointer to ICMP header*/
114 /**@{ Pointers to messages just after icmp header */
115 #define UIP_ND6_RS_BUF ((uip_nd6_rs *)&uip_buf[uip_l2_l3_icmp_hdr_len])
116 #define UIP_ND6_RA_BUF ((uip_nd6_ra *)&uip_buf[uip_l2_l3_icmp_hdr_len])
117 #define UIP_ND6_NS_BUF ((uip_nd6_ns *)&uip_buf[uip_l2_l3_icmp_hdr_len])
118 #define UIP_ND6_NA_BUF ((uip_nd6_na *)&uip_buf[uip_l2_l3_icmp_hdr_len])
119 /** @} */
120 /** Pointer to ND option */
121 #define UIP_ND6_OPT_HDR_BUF ((uip_nd6_opt_hdr *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
122 #define UIP_ND6_OPT_PREFIX_BUF ((uip_nd6_opt_prefix_info *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
123 #define UIP_ND6_OPT_MTU_BUF ((uip_nd6_opt_mtu *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
124 /** @} */
126 static uint8_t nd6_opt_offset; /** Offset from the end of the icmpv6 header to the option in uip_buf*/
127 static uint8_t *nd6_opt_llao; /** Pointer to llao option in uip_buf */
129 #if !UIP_CONF_ROUTER // TBD see if we move it to ra_input
130 static uip_nd6_opt_prefix_info *nd6_opt_prefix_info; /** Pointer to prefix information option in uip_buf */
131 static uip_ipaddr_t ipaddr;
132 static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */
133 #endif
134 static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
135 static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
136 static uip_ds6_addr_t *addr; /** Pointer to an interface address */
138 /*------------------------------------------------------------------*/
139 /* create a llao */
140 static void
141 create_llao(uint8_t *llao, uint8_t type) {
142 llao[UIP_ND6_OPT_TYPE_OFFSET] = type;
143 llao[UIP_ND6_OPT_LEN_OFFSET] = UIP_ND6_OPT_LLAO_LEN >> 3;
144 memcpy(&llao[UIP_ND6_OPT_DATA_OFFSET], &uip_lladdr, UIP_LLADDR_LEN);
145 /* padding on some */
146 memset(&llao[UIP_ND6_OPT_DATA_OFFSET + UIP_LLADDR_LEN], 0,
147 UIP_ND6_OPT_LLAO_LEN - 2 - UIP_LLADDR_LEN);
150 /*------------------------------------------------------------------*/
153 void
154 uip_nd6_ns_input(void)
156 PRINTF("Received NS from");
157 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
158 PRINTF("to");
159 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
160 PRINTF("with target address");
161 PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NS_BUF->tgtipaddr));
162 PRINTF("\n");
163 UIP_STAT(++uip_stat.nd6.recv);
165 u8_t flags;
167 #if UIP_CONF_IPV6_CHECKS
168 if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) ||
169 (uip_is_addr_mcast(&UIP_ND6_NS_BUF->tgtipaddr)) ||
170 (UIP_ICMP_BUF->icode != 0)) {
171 PRINTF("NS received is bad\n");
172 goto discard;
174 #endif /* UIP_CONF_IPV6_CHECKS */
176 /* Options processing */
177 nd6_opt_llao = NULL;
178 nd6_opt_offset = UIP_ND6_NS_LEN;
179 while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) {
180 #if UIP_CONF_IPV6_CHECKS
181 if(UIP_ND6_OPT_HDR_BUF->len == 0) {
182 PRINTF("NS received is bad\n");
183 goto discard;
185 #endif /* UIP_CONF_IPV6_CHECKS */
186 switch (UIP_ND6_OPT_HDR_BUF->type) {
187 case UIP_ND6_OPT_SLLAO:
188 nd6_opt_llao = &uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset];
189 #if UIP_CONF_IPV6_CHECKS
190 /* There must be NO option in a DAD NS */
191 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
192 PRINTF("NS received is bad\n");
193 goto discard;
194 } else {
195 #endif /*UIP_CONF_IPV6_CHECKS */
196 nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr);
197 if(nbr == NULL) {
198 uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr,
199 (uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
200 0, NBR_STALE);
201 } else {
202 if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
203 &nbr->lladdr, UIP_LLADDR_LEN) != 0) {
204 memcpy(&nbr->lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
205 UIP_LLADDR_LEN);
206 nbr->state = NBR_STALE;
207 } else {
208 if(nbr->state == NBR_INCOMPLETE) {
209 nbr->state = NBR_STALE;
213 #if UIP_CONF_IPV6_CHECKS
215 #endif /*UIP_CONF_IPV6_CHECKS */
216 break;
217 default:
218 PRINTF("ND option not supported in NS");
219 break;
221 nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3);
224 addr = uip_ds6_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr);
225 if(addr != NULL) {
226 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
227 /* DAD CASE */
228 #if UIP_CONF_IPV6_CHECKS
229 if(!uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) {
230 PRINTF("NS received is bad\n");
231 goto discard;
233 #endif /* UIP_CONF_IPV6_CHECKS */
234 if(addr->state != ADDR_TENTATIVE) {
235 uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr);
236 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
237 flags = UIP_ND6_NA_FLAG_OVERRIDE;
238 goto create_na;
239 } else {
240 /** \todo if I sent a NS before him, I win */
241 uip_ds6_dad_failed(addr);
242 goto discard;
245 #if UIP_CONF_IPV6_CHECKS
246 if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)) {
248 * \NOTE do we do something here? we both are using the same address.
249 * If we are doing dad, we could cancel it, though we should receive a
250 * NA in response of DAD NS we sent, hence DAD will fail anyway. If we
251 * were not doing DAD, it means there is a duplicate in the network!
253 PRINTF("NS received is bad\n");
254 goto discard;
256 #endif /*UIP_CONF_IPV6_CHECKS */
258 /* Address resolution case */
259 if(uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) {
260 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
261 uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_ND6_NS_BUF->tgtipaddr);
262 flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE;
263 goto create_na;
266 /* NUD CASE */
267 if(uip_ds6_addr_lookup(&UIP_IP_BUF->destipaddr) == addr) {
268 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
269 uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_ND6_NS_BUF->tgtipaddr);
270 flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE;
271 goto create_na;
272 } else {
273 #if UIP_CONF_IPV6_CHECKS
274 PRINTF("NS received is bad\n");
275 goto discard;
276 #endif /* UIP_CONF_IPV6_CHECKS */
278 } else {
279 goto discard;
283 create_na:
284 uip_ext_len = 0;
285 UIP_IP_BUF->vtc = 0x60;
286 UIP_IP_BUF->tcflow = 0;
287 UIP_IP_BUF->flow = 0;
288 UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */
289 UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN;
290 UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
291 UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT;
293 UIP_ICMP_BUF->type = ICMP6_NA;
294 UIP_ICMP_BUF->icode = 0;
296 UIP_ND6_NA_BUF->flagsreserved = flags;
297 memcpy(&UIP_ND6_NA_BUF->tgtipaddr, &addr->ipaddr, sizeof(uip_ipaddr_t));
299 create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN],
300 UIP_ND6_OPT_TLLAO);
302 UIP_ICMP_BUF->icmpchksum = 0;
303 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
305 uip_len =
306 UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN;
308 UIP_STAT(++uip_stat.nd6.sent);
309 PRINTF("Sending NA to");
310 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
311 PRINTF("from");
312 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
313 PRINTF("with target address");
314 PRINT6ADDR(&UIP_ND6_NA_BUF->tgtipaddr);
315 PRINTF("\n");
316 return;
318 discard:
319 uip_len = 0;
320 return;
325 /*------------------------------------------------------------------*/
326 void
327 uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
329 uip_ext_len = 0;
330 UIP_IP_BUF->vtc = 0x60;
331 UIP_IP_BUF->tcflow = 0;
332 UIP_IP_BUF->flow = 0;
333 UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
334 UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT;
336 if(dest == NULL) {
337 uip_create_solicited_node(tgt, &UIP_IP_BUF->destipaddr);
338 } else {
339 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest);
341 UIP_ICMP_BUF->type = ICMP6_NS;
342 UIP_ICMP_BUF->icode = 0;
343 UIP_ND6_NS_BUF->reserved = 0;
344 uip_ipaddr_copy((uip_ipaddr_t *) &UIP_ND6_NS_BUF->tgtipaddr, tgt);
345 UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */
347 * check if we add a SLLAO option: for DAD, MUST NOT, for NUD, MAY
348 * (here yes), for Address resolution , MUST
350 if(!(uip_ds6_is_my_addr(tgt))) {
351 if(src != NULL) {
352 uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, src);
353 } else {
354 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
356 UIP_IP_BUF->len[1] =
357 UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN;
359 create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NS_LEN],
360 UIP_ND6_OPT_SLLAO);
362 uip_len =
363 UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN;
364 } else {
365 uip_create_unspecified(&UIP_IP_BUF->srcipaddr);
366 UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NS_LEN;
367 uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN;
370 UIP_ICMP_BUF->icmpchksum = 0;
371 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
373 UIP_STAT(++uip_stat.nd6.sent);
374 PRINTF("Sending NS to");
375 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
376 PRINTF("from");
377 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
378 PRINTF("with target address");
379 PRINT6ADDR(tgt);
380 PRINTF("\n");
381 return;
386 /*------------------------------------------------------------------*/
387 void
388 uip_nd6_na_input(void)
390 PRINTF("Received NA from");
391 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
392 PRINTF("to");
393 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
394 PRINTF("with target address");
395 PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NA_BUF->tgtipaddr));
396 PRINTF("\n");
397 UIP_STAT(++uip_stat.nd6.recv);
400 * booleans. the three last one are not 0 or 1 but 0 or 0x80, 0x40, 0x20
401 * but it works. Be careful though, do not use tests such as is_router == 1
403 u8_t is_llchange = 0;
404 u8_t is_router = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_ROUTER));
405 u8_t is_solicited =
406 ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_SOLICITED));
407 u8_t is_override =
408 ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_OVERRIDE));
410 #if UIP_CONF_IPV6_CHECKS
411 if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) ||
412 (UIP_ICMP_BUF->icode != 0) ||
413 (uip_is_addr_mcast(&UIP_ND6_NA_BUF->tgtipaddr)) ||
414 (is_solicited && uip_is_addr_mcast(&UIP_IP_BUF->destipaddr))) {
415 PRINTF("NA received is bad\n");
416 goto discard;
418 #endif /*UIP_CONF_IPV6_CHECKS */
420 /* Options processing: we handle TLLAO, and must ignore others */
421 nd6_opt_offset = UIP_ND6_NA_LEN;
422 nd6_opt_llao = NULL;
423 while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) {
424 #if UIP_CONF_IPV6_CHECKS
425 if(UIP_ND6_OPT_HDR_BUF->len == 0) {
426 PRINTF("NA received is bad\n");
427 goto discard;
429 #endif /*UIP_CONF_IPV6_CHECKS */
430 switch (UIP_ND6_OPT_HDR_BUF->type) {
431 case UIP_ND6_OPT_TLLAO:
432 nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF;
433 break;
434 default:
435 PRINTF("ND option not supported in NA\n");
436 break;
438 nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3);
440 addr = uip_ds6_addr_lookup(&UIP_ND6_NA_BUF->tgtipaddr);
441 /* Message processing, including TLLAO if any */
442 if(addr != NULL) {
443 if(addr->state == ADDR_TENTATIVE) {
444 uip_ds6_dad_failed(addr);
446 PRINTF("NA received is bad\n");
447 goto discard;
448 } else {
449 nbr = uip_ds6_nbr_lookup(&UIP_ND6_NA_BUF->tgtipaddr);
450 if(nbr == NULL) {
451 goto discard;
453 if(nd6_opt_llao != 0) {
454 is_llchange =
455 memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], (void *)(&nbr->lladdr),
456 UIP_LLADDR_LEN);
458 if(nbr->state == NBR_INCOMPLETE) {
459 if(nd6_opt_llao == NULL) {
460 goto discard;
462 memcpy(&nbr->lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
463 UIP_LLADDR_LEN);
464 if(is_solicited) {
465 nbr->state = NBR_REACHABLE;
466 nbr->nscount = 0;
468 /* reachable time is stored in ms */
469 stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);
471 } else {
472 nbr->state = NBR_STALE;
474 nbr->isrouter = is_router;
475 } else {
476 if(!is_override && is_llchange) {
477 if(nbr->state == NBR_REACHABLE) {
478 nbr->state = NBR_STALE;
480 goto discard;
481 } else {
482 if(is_override || (!is_override && nd6_opt_llao != 0 && !is_llchange)
483 || nd6_opt_llao == 0) {
484 if(nd6_opt_llao != 0) {
485 memcpy(&nbr->lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
486 UIP_LLADDR_LEN);
488 if(is_solicited) {
489 nbr->state = NBR_REACHABLE;
490 /* reachable time is stored in ms */
491 stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);
492 } else {
493 if(nd6_opt_llao != 0 && is_llchange) {
494 nbr->state = NBR_STALE;
499 if(nbr->isrouter && !is_router) {
500 defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr);
501 if(defrt != NULL) {
502 uip_ds6_defrt_rm(defrt);
505 nbr->isrouter = is_router;
508 #if UIP_CONF_IPV6_QUEUE_PKT
509 /* The nbr is now reachable, check if we had buffered a pkt for it */
510 if(nbr->queue_buf_len != 0) {
511 uip_len = nbr->queue_buf_len;
512 memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len);
513 nbr->queue_buf_len = 0;
514 return;
516 #endif /*UIP_CONF_IPV6_QUEUE_PKT */
518 discard:
519 uip_len = 0;
520 return;
524 #if UIP_CONF_ROUTER
525 #if UIP_ND6_SEND_RA
526 /*---------------------------------------------------------------------------*/
527 void
528 uip_nd6_rs_input(void)
531 PRINTF("Received RS from");
532 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
533 PRINTF("to");
534 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
535 PRINTF("\n");
536 UIP_STAT(++uip_stat.nd6.recv);
539 #if UIP_CONF_IPV6_CHECKS
541 * Check hop limit / icmp code
542 * target address must not be multicast
543 * if the NA is solicited, dest must not be multicast
545 if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (UIP_ICMP_BUF->icode != 0)) {
546 PRINTF("RS received is bad\n");
547 goto discard;
549 #endif /*UIP_CONF_IPV6_CHECKS */
551 /* Only valid option is Source Link-Layer Address option any thing
552 else is discarded */
553 nd6_opt_offset = UIP_ND6_RS_LEN;
554 nd6_opt_llao = NULL;
556 while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) {
557 #if UIP_CONF_IPV6_CHECKS
558 if(UIP_ND6_OPT_HDR_BUF->len == 0) {
559 PRINTF("RS received is bad\n");
560 goto discard;
562 #endif /*UIP_CONF_IPV6_CHECKS */
563 switch (UIP_ND6_OPT_HDR_BUF->type) {
564 case UIP_ND6_OPT_SLLAO:
565 nd6_opt_llao = UIP_ND6_OPT_HDR_BUF;
566 break;
567 default:
568 PRINTF("ND option not supported in RS\n");
569 break;
571 nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3);
573 /* Options processing: only SLLAO */
574 if(nd6_opt_llao != NULL) {
575 #if UIP_CONF_IPV6_CHECKS
576 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
577 PRINTF("RS received is bad\n");
578 goto discard;
579 } else {
580 #endif /*UIP_CONF_IPV6_CHECKS */
581 if((nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr)) == NULL) {
582 /* we need to add the neighbor */
583 uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr,
584 &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], 0, NBR_STALE);
585 } else {
586 /* If LL address changed, set neighbor state to stale */
587 if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
588 &nbr->lladdr, UIP_LLADDR_LEN) != 0) {
589 memcpy(&nbr->lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
590 UIP_LLADDR_LEN);
591 nbr->state = NBR_STALE;
593 nbr->isrouter = 0;
595 #if UIP_CONF_IPV6_CHECKS
597 #endif /*UIP_CONF_IPV6_CHECKS */
600 /* Schedule a sollicited RA */
601 uip_ds6_send_ra_sollicited();
603 discard:
604 uip_len = 0;
605 return;
608 /*---------------------------------------------------------------------------*/
609 void
610 uip_nd6_ra_output(uip_ipaddr_t * dest)
613 UIP_IP_BUF->vtc = 0x60;
614 UIP_IP_BUF->tcflow = 0;
615 UIP_IP_BUF->flow = 0;
616 UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
617 UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT;
619 if(dest == NULL) {
620 uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr);
621 } else {
622 /* For sollicited RA */
623 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest);
625 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
627 UIP_ICMP_BUF->type = ICMP6_RA;
628 UIP_ICMP_BUF->icode = 0;
630 UIP_ND6_RA_BUF->cur_ttl = uip_ds6_if.cur_hop_limit;
632 UIP_ND6_RA_BUF->flags_reserved =
633 (UIP_ND6_M_FLAG << 7) | (UIP_ND6_O_FLAG << 6);
635 UIP_ND6_RA_BUF->router_lifetime = uip_htons(UIP_ND6_ROUTER_LIFETIME);
636 //UIP_ND6_RA_BUF->reachable_time = uip_htonl(uip_ds6_if.reachable_time);
637 //UIP_ND6_RA_BUF->retrans_timer = uip_htonl(uip_ds6_if.retrans_timer);
638 UIP_ND6_RA_BUF->reachable_time = 0;
639 UIP_ND6_RA_BUF->retrans_timer = 0;
641 uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_RA_LEN;
642 nd6_opt_offset = UIP_ND6_RA_LEN;
645 /* Prefix list */
646 for(prefix = uip_ds6_prefix_list;
647 prefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; prefix++) {
648 if((prefix->isused) && (prefix->advertise)) {
649 UIP_ND6_OPT_PREFIX_BUF->type = UIP_ND6_OPT_PREFIX_INFO;
650 UIP_ND6_OPT_PREFIX_BUF->len = UIP_ND6_OPT_PREFIX_INFO_LEN / 8;
651 UIP_ND6_OPT_PREFIX_BUF->preflen = prefix->length;
652 UIP_ND6_OPT_PREFIX_BUF->flagsreserved1 = prefix->l_a_reserved;
653 UIP_ND6_OPT_PREFIX_BUF->validlt = uip_htonl(prefix->vlifetime);
654 UIP_ND6_OPT_PREFIX_BUF->preferredlt = uip_htonl(prefix->plifetime);
655 UIP_ND6_OPT_PREFIX_BUF->reserved2 = 0;
656 uip_ipaddr_copy(&(UIP_ND6_OPT_PREFIX_BUF->prefix), &(prefix->ipaddr));
657 nd6_opt_offset += UIP_ND6_OPT_PREFIX_INFO_LEN;
658 uip_len += UIP_ND6_OPT_PREFIX_INFO_LEN;
662 /* Source link-layer option */
663 create_llao((uint8_t *)UIP_ND6_OPT_HDR_BUF, UIP_ND6_OPT_SLLAO);
665 uip_len += UIP_ND6_OPT_LLAO_LEN;
666 nd6_opt_offset += UIP_ND6_OPT_LLAO_LEN;
668 /* MTU */
669 UIP_ND6_OPT_MTU_BUF->type = UIP_ND6_OPT_MTU;
670 UIP_ND6_OPT_MTU_BUF->len = UIP_ND6_OPT_MTU_LEN >> 3;
671 UIP_ND6_OPT_MTU_BUF->reserved = 0;
672 //UIP_ND6_OPT_MTU_BUF->mtu = uip_htonl(uip_ds6_if.link_mtu);
673 UIP_ND6_OPT_MTU_BUF->mtu = uip_htonl(1500);
675 uip_len += UIP_ND6_OPT_MTU_LEN;
676 nd6_opt_offset += UIP_ND6_OPT_MTU_LEN;
677 UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
678 UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
680 /*ICMP checksum */
681 UIP_ICMP_BUF->icmpchksum = 0;
682 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
684 UIP_STAT(++uip_stat.nd6.sent);
685 PRINTF("Sending RA to");
686 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
687 PRINTF("from");
688 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
689 PRINTF("\n");
690 return;
692 #endif /* UIP_ND6_SEND_RA */
693 #endif /* UIP_CONF_ROUTER */
695 #if !UIP_CONF_ROUTER
696 /*---------------------------------------------------------------------------*/
697 void
698 uip_nd6_rs_output(void)
700 UIP_IP_BUF->vtc = 0x60;
701 UIP_IP_BUF->tcflow = 0;
702 UIP_IP_BUF->flow = 0;
703 UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
704 UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT;
705 uip_create_linklocal_allrouters_mcast(&UIP_IP_BUF->destipaddr);
706 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
707 UIP_ICMP_BUF->type = ICMP6_RS;
708 UIP_ICMP_BUF->icode = 0;
709 UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */
711 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
712 UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_RS_LEN;
713 uip_len = uip_l3_icmp_hdr_len + UIP_ND6_RS_LEN;
714 } else {
715 uip_len = uip_l3_icmp_hdr_len + UIP_ND6_RS_LEN + UIP_ND6_OPT_LLAO_LEN;
716 UIP_IP_BUF->len[1] =
717 UIP_ICMPH_LEN + UIP_ND6_RS_LEN + UIP_ND6_OPT_LLAO_LEN;
719 create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_RS_LEN],
720 UIP_ND6_OPT_SLLAO);
723 UIP_ICMP_BUF->icmpchksum = 0;
724 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
726 UIP_STAT(++uip_stat.nd6.sent);
727 PRINTF("Sendin RS to");
728 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
729 PRINTF("from");
730 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
731 PRINTF("\n");
732 return;
736 /*---------------------------------------------------------------------------*/
737 void
738 uip_nd6_ra_input(void)
740 PRINTF("Received RA from");
741 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
742 PRINTF("to");
743 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
744 PRINTF("\n");
745 UIP_STAT(++uip_stat.nd6.recv);
747 #if UIP_CONF_IPV6_CHECKS
748 if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) ||
749 (!uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr)) ||
750 (UIP_ICMP_BUF->icode != 0)) {
751 PRINTF("RA received is bad");
752 goto discard;
754 #endif /*UIP_CONF_IPV6_CHECKS */
756 if(UIP_ND6_RA_BUF->cur_ttl != 0) {
757 uip_ds6_if.cur_hop_limit = UIP_ND6_RA_BUF->cur_ttl;
758 PRINTF("uip_ds6_if.cur_hop_limit %u\n", uip_ds6_if.cur_hop_limit);
761 if(UIP_ND6_RA_BUF->reachable_time != 0) {
762 if(uip_ds6_if.base_reachable_time !=
763 uip_ntohl(UIP_ND6_RA_BUF->reachable_time)) {
764 uip_ds6_if.base_reachable_time = uip_ntohl(UIP_ND6_RA_BUF->reachable_time);
765 uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time();
768 if(UIP_ND6_RA_BUF->retrans_timer != 0) {
769 uip_ds6_if.retrans_timer = uip_ntohl(UIP_ND6_RA_BUF->retrans_timer);
772 /* Options processing */
773 nd6_opt_offset = UIP_ND6_RA_LEN;
774 while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) {
775 if(UIP_ND6_OPT_HDR_BUF->len == 0) {
776 PRINTF("RA received is bad");
777 goto discard;
779 switch (UIP_ND6_OPT_HDR_BUF->type) {
780 case UIP_ND6_OPT_SLLAO:
781 PRINTF("Processing SLLAO option in RA\n");
782 nd6_opt_llao = (uint8_t *) UIP_ND6_OPT_HDR_BUF;
783 nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr);
784 if(nbr == NULL) {
785 nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr,
786 (uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
787 1, NBR_STALE);
788 } else {
789 if(nbr->state == NBR_INCOMPLETE) {
790 nbr->state = NBR_STALE;
792 if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
793 &nbr->lladdr, UIP_LLADDR_LEN) != 0) {
794 memcpy(&nbr->lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
795 UIP_LLADDR_LEN);
796 nbr->state = NBR_STALE;
798 nbr->isrouter = 1;
800 break;
801 case UIP_ND6_OPT_MTU:
802 PRINTF("Processing MTU option in RA\n");
803 uip_ds6_if.link_mtu =
804 uip_ntohl(((uip_nd6_opt_mtu *) UIP_ND6_OPT_HDR_BUF)->mtu);
805 break;
806 case UIP_ND6_OPT_PREFIX_INFO:
807 PRINTF("Processing PREFIX option in RA\n");
808 nd6_opt_prefix_info = (uip_nd6_opt_prefix_info *) UIP_ND6_OPT_HDR_BUF;
809 if((uip_ntohl(nd6_opt_prefix_info->validlt) >=
810 uip_ntohl(nd6_opt_prefix_info->preferredlt))
811 && (!uip_is_addr_link_local(&nd6_opt_prefix_info->prefix))) {
812 /* on-link flag related processing */
813 if(nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_ONLINK) {
814 prefix =
815 uip_ds6_prefix_lookup(&nd6_opt_prefix_info->prefix,
816 nd6_opt_prefix_info->preflen);
817 if(prefix == NULL) {
818 if(nd6_opt_prefix_info->validlt != 0) {
819 if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) {
820 prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix,
821 nd6_opt_prefix_info->preflen,
822 uip_ntohl(nd6_opt_prefix_info->
823 validlt));
824 } else {
825 prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix,
826 nd6_opt_prefix_info->preflen, 0);
829 } else {
830 switch (nd6_opt_prefix_info->validlt) {
831 case 0:
832 uip_ds6_prefix_rm(prefix);
833 break;
834 case UIP_ND6_INFINITE_LIFETIME:
835 prefix->isinfinite = 1;
836 break;
837 default:
838 PRINTF("Updating timer of prefix");
839 PRINT6ADDR(&prefix->ipaddr);
840 PRINTF("new value %lu\n", uip_ntohl(nd6_opt_prefix_info->validlt));
841 stimer_set(&prefix->vlifetime,
842 uip_ntohl(nd6_opt_prefix_info->validlt));
843 prefix->isinfinite = 0;
844 break;
848 /* End of on-link flag related processing */
849 /* autonomous flag related processing */
850 if((nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_AUTONOMOUS)
851 && (nd6_opt_prefix_info->validlt != 0)
852 && (nd6_opt_prefix_info->preflen == UIP_DEFAULT_PREFIX_LEN)) {
854 uip_ipaddr_copy(&ipaddr, &nd6_opt_prefix_info->prefix);
855 uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
856 addr = uip_ds6_addr_lookup(&ipaddr);
857 if((addr != NULL) && (addr->type == ADDR_AUTOCONF)) {
858 if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) {
859 /* The processing below is defined in RFC4862 section 5.5.3 e */
860 if((uip_ntohl(nd6_opt_prefix_info->validlt) > 2 * 60 * 60) ||
861 (uip_ntohl(nd6_opt_prefix_info->validlt) >
862 stimer_remaining(&addr->vlifetime))) {
863 PRINTF("Updating timer of address");
864 PRINT6ADDR(&addr->ipaddr);
865 PRINTF("new value %lu\n",
866 uip_ntohl(nd6_opt_prefix_info->validlt));
867 stimer_set(&addr->vlifetime,
868 uip_ntohl(nd6_opt_prefix_info->validlt));
869 } else {
870 stimer_set(&addr->vlifetime, 2 * 60 * 60);
871 PRINTF("Updating timer of address ");
872 PRINT6ADDR(&addr->ipaddr);
873 PRINTF("new value %lu\n", (unsigned long)(2 * 60 * 60));
875 addr->isinfinite = 0;
876 } else {
877 addr->isinfinite = 1;
879 } else {
880 if(uip_ntohl(nd6_opt_prefix_info->validlt) ==
881 UIP_ND6_INFINITE_LIFETIME) {
882 uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
883 } else {
884 uip_ds6_addr_add(&ipaddr, uip_ntohl(nd6_opt_prefix_info->validlt),
885 ADDR_AUTOCONF);
889 /* End of autonomous flag related processing */
891 break;
892 default:
893 PRINTF("ND option not supported in RA");
894 break;
896 nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3);
899 defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr);
900 if(UIP_ND6_RA_BUF->router_lifetime != 0) {
901 if(nbr != NULL) {
902 nbr->isrouter = 1;
904 if(defrt == NULL) {
905 uip_ds6_defrt_add(&UIP_IP_BUF->srcipaddr,
906 (unsigned
907 long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime)));
908 } else {
909 stimer_set(&(defrt->lifetime),
910 (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime)));
912 } else {
913 if(defrt != NULL) {
914 uip_ds6_defrt_rm(defrt);
918 #if UIP_CONF_IPV6_QUEUE_PKT
919 /* If the nbr just became reachable (e.g. it was in NBR_INCOMPLETE state
920 * and we got a SLLAO), check if we had buffered a pkt for it */
921 if((nbr != NULL) && (nbr->queue_buf_len != 0)) {
922 uip_len = nbr->queue_buf_len;
923 memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len);
924 nbr->queue_buf_len = 0;
925 return;
927 #endif /*UIP_CONF_IPV6_QUEUE_PKT */
929 discard:
930 uip_len = 0;
931 return;
933 #endif /* !UIP_CONF_ROUTER */
935 /** @} */