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
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
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
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
72 #include "net/uip-icmp6.h"
73 #include "net/uip-nd6.h"
74 #include "net/uip-ds6.h"
75 #include "lib/random.h"
77 /*------------------------------------------------------------------*/
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])
86 #define PRINT6ADDR(addr)
87 #define PRINTLLADDR(addr)
92 void uip_log(char *msg
);
94 #define UIP_LOG(m) uip_log(m)
97 #endif /* UIP_LOGGING == 1 */
99 /*------------------------------------------------------------------*/
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])
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])
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 */
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 /*------------------------------------------------------------------*/
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 /*------------------------------------------------------------------*/
154 uip_nd6_ns_input(void)
156 PRINTF("Received NS from");
157 PRINT6ADDR(&UIP_IP_BUF
->srcipaddr
);
159 PRINT6ADDR(&UIP_IP_BUF
->destipaddr
);
160 PRINTF("with target address");
161 PRINT6ADDR((uip_ipaddr_t
*) (&UIP_ND6_NS_BUF
->tgtipaddr
));
163 UIP_STAT(++uip_stat
.nd6
.recv
);
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");
174 #endif /* UIP_CONF_IPV6_CHECKS */
176 /* Options processing */
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");
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");
195 #endif /*UIP_CONF_IPV6_CHECKS */
196 nbr
= uip_ds6_nbr_lookup(&UIP_IP_BUF
->srcipaddr
);
198 uip_ds6_nbr_add(&UIP_IP_BUF
->srcipaddr
,
199 (uip_lladdr_t
*)&nd6_opt_llao
[UIP_ND6_OPT_DATA_OFFSET
],
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
],
206 nbr
->state
= NBR_STALE
;
208 if(nbr
->state
== NBR_INCOMPLETE
) {
209 nbr
->state
= NBR_STALE
;
213 #if UIP_CONF_IPV6_CHECKS
215 #endif /*UIP_CONF_IPV6_CHECKS */
218 PRINTF("ND option not supported in NS");
221 nd6_opt_offset
+= (UIP_ND6_OPT_HDR_BUF
->len
<< 3);
224 addr
= uip_ds6_addr_lookup(&UIP_ND6_NS_BUF
->tgtipaddr
);
226 if(uip_is_addr_unspecified(&UIP_IP_BUF
->srcipaddr
)) {
228 #if UIP_CONF_IPV6_CHECKS
229 if(!uip_is_addr_solicited_node(&UIP_IP_BUF
->destipaddr
)) {
230 PRINTF("NS received is bad\n");
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
;
240 /** \todo if I sent a NS before him, I win */
241 uip_ds6_dad_failed(addr
);
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");
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
;
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
;
273 #if UIP_CONF_IPV6_CHECKS
274 PRINTF("NS received is bad\n");
276 #endif /* UIP_CONF_IPV6_CHECKS */
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
],
302 UIP_ICMP_BUF
->icmpchksum
= 0;
303 UIP_ICMP_BUF
->icmpchksum
= ~uip_icmp6chksum();
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
);
312 PRINT6ADDR(&UIP_IP_BUF
->srcipaddr
);
313 PRINTF("with target address");
314 PRINT6ADDR(&UIP_ND6_NA_BUF
->tgtipaddr
);
325 /*------------------------------------------------------------------*/
327 uip_nd6_ns_output(uip_ipaddr_t
* src
, uip_ipaddr_t
* dest
, uip_ipaddr_t
* tgt
)
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
;
337 uip_create_solicited_node(tgt
, &UIP_IP_BUF
->destipaddr
);
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
))) {
352 uip_ipaddr_copy(&UIP_IP_BUF
->srcipaddr
, src
);
354 uip_ds6_select_src(&UIP_IP_BUF
->srcipaddr
, &UIP_IP_BUF
->destipaddr
);
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
],
363 UIP_IPH_LEN
+ UIP_ICMPH_LEN
+ UIP_ND6_NS_LEN
+ UIP_ND6_OPT_LLAO_LEN
;
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
);
377 PRINT6ADDR(&UIP_IP_BUF
->srcipaddr
);
378 PRINTF("with target address");
386 /*------------------------------------------------------------------*/
388 uip_nd6_na_input(void)
390 PRINTF("Received NA from");
391 PRINT6ADDR(&UIP_IP_BUF
->srcipaddr
);
393 PRINT6ADDR(&UIP_IP_BUF
->destipaddr
);
394 PRINTF("with target address");
395 PRINT6ADDR((uip_ipaddr_t
*) (&UIP_ND6_NA_BUF
->tgtipaddr
));
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
));
406 ((UIP_ND6_NA_BUF
->flagsreserved
& UIP_ND6_NA_FLAG_SOLICITED
));
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");
418 #endif /*UIP_CONF_IPV6_CHECKS */
420 /* Options processing: we handle TLLAO, and must ignore others */
421 nd6_opt_offset
= UIP_ND6_NA_LEN
;
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");
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
;
435 PRINTF("ND option not supported in NA\n");
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 */
443 if(addr
->state
== ADDR_TENTATIVE
) {
444 uip_ds6_dad_failed(addr
);
446 PRINTF("NA received is bad\n");
449 nbr
= uip_ds6_nbr_lookup(&UIP_ND6_NA_BUF
->tgtipaddr
);
453 if(nd6_opt_llao
!= 0) {
455 memcmp(&nd6_opt_llao
[UIP_ND6_OPT_DATA_OFFSET
], (void *)(&nbr
->lladdr
),
458 if(nbr
->state
== NBR_INCOMPLETE
) {
459 if(nd6_opt_llao
== NULL
) {
462 memcpy(&nbr
->lladdr
, &nd6_opt_llao
[UIP_ND6_OPT_DATA_OFFSET
],
465 nbr
->state
= NBR_REACHABLE
;
468 /* reachable time is stored in ms */
469 stimer_set(&(nbr
->reachable
), uip_ds6_if
.reachable_time
/ 1000);
472 nbr
->state
= NBR_STALE
;
474 nbr
->isrouter
= is_router
;
476 if(!is_override
&& is_llchange
) {
477 if(nbr
->state
== NBR_REACHABLE
) {
478 nbr
->state
= NBR_STALE
;
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
],
489 nbr
->state
= NBR_REACHABLE
;
490 /* reachable time is stored in ms */
491 stimer_set(&(nbr
->reachable
), uip_ds6_if
.reachable_time
/ 1000);
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
);
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;
516 #endif /*UIP_CONF_IPV6_QUEUE_PKT */
526 /*---------------------------------------------------------------------------*/
528 uip_nd6_rs_input(void)
531 PRINTF("Received RS from");
532 PRINT6ADDR(&UIP_IP_BUF
->srcipaddr
);
534 PRINT6ADDR(&UIP_IP_BUF
->destipaddr
);
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");
549 #endif /*UIP_CONF_IPV6_CHECKS */
551 /* Only valid option is Source Link-Layer Address option any thing
553 nd6_opt_offset
= UIP_ND6_RS_LEN
;
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");
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
;
568 PRINTF("ND option not supported in RS\n");
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");
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
);
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
],
591 nbr
->state
= NBR_STALE
;
595 #if UIP_CONF_IPV6_CHECKS
597 #endif /*UIP_CONF_IPV6_CHECKS */
600 /* Schedule a sollicited RA */
601 uip_ds6_send_ra_sollicited();
608 /*---------------------------------------------------------------------------*/
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
;
620 uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF
->destipaddr
);
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
;
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
;
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);
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
);
688 PRINT6ADDR(&UIP_IP_BUF
->srcipaddr
);
692 #endif /* UIP_ND6_SEND_RA */
693 #endif /* UIP_CONF_ROUTER */
696 /*---------------------------------------------------------------------------*/
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
;
715 uip_len
= uip_l3_icmp_hdr_len
+ UIP_ND6_RS_LEN
+ UIP_ND6_OPT_LLAO_LEN
;
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
],
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
);
730 PRINT6ADDR(&UIP_IP_BUF
->srcipaddr
);
736 /*---------------------------------------------------------------------------*/
738 uip_nd6_ra_input(void)
740 PRINTF("Received RA from");
741 PRINT6ADDR(&UIP_IP_BUF
->srcipaddr
);
743 PRINT6ADDR(&UIP_IP_BUF
->destipaddr
);
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");
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");
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
);
785 nbr
= uip_ds6_nbr_add(&UIP_IP_BUF
->srcipaddr
,
786 (uip_lladdr_t
*)&nd6_opt_llao
[UIP_ND6_OPT_DATA_OFFSET
],
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
],
796 nbr
->state
= NBR_STALE
;
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
);
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
) {
815 uip_ds6_prefix_lookup(&nd6_opt_prefix_info
->prefix
,
816 nd6_opt_prefix_info
->preflen
);
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
->
825 prefix
= uip_ds6_prefix_add(&nd6_opt_prefix_info
->prefix
,
826 nd6_opt_prefix_info
->preflen
, 0);
830 switch (nd6_opt_prefix_info
->validlt
) {
832 uip_ds6_prefix_rm(prefix
);
834 case UIP_ND6_INFINITE_LIFETIME
:
835 prefix
->isinfinite
= 1;
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;
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
));
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;
877 addr
->isinfinite
= 1;
880 if(uip_ntohl(nd6_opt_prefix_info
->validlt
) ==
881 UIP_ND6_INFINITE_LIFETIME
) {
882 uip_ds6_addr_add(&ipaddr
, 0, ADDR_AUTOCONF
);
884 uip_ds6_addr_add(&ipaddr
, uip_ntohl(nd6_opt_prefix_info
->validlt
),
889 /* End of autonomous flag related processing */
893 PRINTF("ND option not supported in RA");
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) {
905 uip_ds6_defrt_add(&UIP_IP_BUF
->srcipaddr
,
907 long)(uip_ntohs(UIP_ND6_RA_BUF
->router_lifetime
)));
909 stimer_set(&(defrt
->lifetime
),
910 (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF
->router_lifetime
)));
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;
927 #endif /*UIP_CONF_IPV6_QUEUE_PKT */
933 #endif /* !UIP_CONF_ROUTER */