ReactOS 0.4.16-dev-1165-g40721f4
nd6.c
Go to the documentation of this file.
1
9/*
10 * Copyright (c) 2010 Inico Technologies Ltd.
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without modification,
14 * are permitted provided that the following conditions are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * 3. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * OF SUCH DAMAGE.
34 *
35 * This file is part of the lwIP TCP/IP stack.
36 *
37 * Author: Ivan Delamer <delamer@inicotech.com>
38 *
39 *
40 * Please coordinate changes and requests with Ivan Delamer
41 * <delamer@inicotech.com>
42 */
43
44#include "lwip/opt.h"
45
46#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
47
48#include "lwip/nd6.h"
49#include "lwip/priv/nd6_priv.h"
50#include "lwip/prot/nd6.h"
51#include "lwip/prot/icmp6.h"
52#include "lwip/pbuf.h"
53#include "lwip/mem.h"
54#include "lwip/memp.h"
55#include "lwip/ip6.h"
56#include "lwip/ip6_addr.h"
57#include "lwip/inet_chksum.h"
58#include "lwip/netif.h"
59#include "lwip/icmp6.h"
60#include "lwip/mld6.h"
61#include "lwip/dhcp6.h"
62#include "lwip/ip.h"
63#include "lwip/stats.h"
64#include "lwip/dns.h"
65
66#include <string.h>
67
68#ifdef LWIP_HOOK_FILENAME
69#include LWIP_HOOK_FILENAME
70#endif
71
72#if LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK
73#error LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK
74#endif
75#if LWIP_ND6_NUM_NEIGHBORS > 127
76#error LWIP_ND6_NUM_NEIGHBORS must fit into an s8_t (max value: 127)
77#endif
78#if LWIP_ND6_NUM_DESTINATIONS > 32767
79#error LWIP_ND6_NUM_DESTINATIONS must fit into an s16_t (max value: 32767)
80#endif
81#if LWIP_ND6_NUM_PREFIXES > 127
82#error LWIP_ND6_NUM_PREFIXES must fit into an s8_t (max value: 127)
83#endif
84#if LWIP_ND6_NUM_ROUTERS > 127
85#error LWIP_ND6_NUM_ROUTERS must fit into an s8_t (max value: 127)
86#endif
87
88/* Router tables. */
89struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS];
90struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS];
91struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES];
92struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS];
93
94/* Default values, can be updated by a RA message. */
95u32_t reachable_time = LWIP_ND6_REACHABLE_TIME;
96u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* @todo implement this value in timer */
97
98#if LWIP_ND6_QUEUEING
99static u8_t nd6_queue_size = 0;
100#endif
101
102/* Index for cache entries. */
103static netif_addr_idx_t nd6_cached_destination_index;
104
105/* Multicast address holder. */
106static ip6_addr_t multicast_address;
107
108static u8_t nd6_tmr_rs_reduction;
109
110/* Static buffer to parse RA packet options */
111union ra_options {
112 struct lladdr_option lladdr;
113 struct mtu_option mtu;
114 struct prefix_option prefix;
115#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS
116 struct rdnss_option rdnss;
117#endif
118};
119static union ra_options nd6_ra_buffer;
120
121/* Forward declarations. */
122static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr);
123static s8_t nd6_new_neighbor_cache_entry(void);
124static void nd6_free_neighbor_cache_entry(s8_t i);
125static s16_t nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr);
126static s16_t nd6_new_destination_cache_entry(void);
127static int nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif);
128static s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif);
129static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif);
130static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif);
131static s8_t nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif);
132static s8_t nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif);
133static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif);
134static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q);
135
136#define ND6_SEND_FLAG_MULTICAST_DEST 0x01
137#define ND6_SEND_FLAG_ALLNODES_DEST 0x02
138#define ND6_SEND_FLAG_ANY_SRC 0x04
139static void nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags);
140static void nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags);
141static void nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags);
142#if LWIP_IPV6_SEND_ROUTER_SOLICIT
143static err_t nd6_send_rs(struct netif *netif);
144#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
145
146#if LWIP_ND6_QUEUEING
147static void nd6_free_q(struct nd6_q_entry *q);
148#else /* LWIP_ND6_QUEUEING */
149#define nd6_free_q(q) pbuf_free(q)
150#endif /* LWIP_ND6_QUEUEING */
151static void nd6_send_q(s8_t i);
152
153
161static void
162nd6_duplicate_addr_detected(struct netif *netif, s8_t addr_idx)
163{
164
165 /* Mark the address as duplicate, but leave its lifetimes alone. If this was
166 * a manually assigned address, it will remain in existence as duplicate, and
167 * as such be unusable for any practical purposes until manual intervention.
168 * If this was an autogenerated address, the address will follow normal
169 * expiration rules, and thus disappear once its valid lifetime expires. */
170 netif_ip6_addr_set_state(netif, addr_idx, IP6_ADDR_DUPLICATED);
171
172#if LWIP_IPV6_AUTOCONFIG
173 /* If the affected address was the link-local address that we use to generate
174 * all other addresses, then we should not continue to use those derived
175 * addresses either, so mark them as duplicate as well. For autoconfig-only
176 * setups, this will make the interface effectively unusable, approaching the
177 * intention of RFC 4862 Sec. 5.4.5. @todo implement the full requirements */
178 if (addr_idx == 0) {
179 s8_t i;
180 for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
181 if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) &&
182 !netif_ip6_addr_isstatic(netif, i)) {
183 netif_ip6_addr_set_state(netif, i, IP6_ADDR_DUPLICATED);
184 }
185 }
186 }
187#endif /* LWIP_IPV6_AUTOCONFIG */
188}
189
190#if LWIP_IPV6_AUTOCONFIG
200static void
201nd6_process_autoconfig_prefix(struct netif *netif,
202 struct prefix_option *prefix_opt, const ip6_addr_t *prefix_addr)
203{
204 ip6_addr_t ip6addr;
205 u32_t valid_life, pref_life;
206 u8_t addr_state;
207 s8_t i, free_idx;
208
209 /* The caller already checks RFC 4862 Sec. 5.5.3 points (a) and (b). We do
210 * the rest, starting with checks for (c) and (d) here. */
211 valid_life = lwip_htonl(prefix_opt->valid_lifetime);
212 pref_life = lwip_htonl(prefix_opt->preferred_lifetime);
213 if (pref_life > valid_life || prefix_opt->prefix_length != 64) {
214 return; /* silently ignore this prefix for autoconfiguration purposes */
215 }
216
217 /* If an autogenerated address already exists for this prefix, update its
218 * lifetimes. An address is considered autogenerated if 1) it is not static
219 * (i.e., manually assigned), and 2) there is an advertised autoconfiguration
220 * prefix for it (the one we are processing here). This does not necessarily
221 * exclude the possibility that the address was actually assigned by, say,
222 * DHCPv6. If that distinction becomes important in the future, more state
223 * must be kept. As explained elsewhere we also update lifetimes of tentative
224 * and duplicate addresses. Skip address slot 0 (the link-local address). */
225 for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
226 addr_state = netif_ip6_addr_state(netif, i);
227 if (!ip6_addr_isinvalid(addr_state) && !netif_ip6_addr_isstatic(netif, i) &&
228 ip6_addr_net_eq(prefix_addr, netif_ip6_addr(netif, i))) {
229 /* Update the valid lifetime, as per RFC 4862 Sec. 5.5.3 point (e).
230 * The valid lifetime will never drop to zero as a result of this. */
231 u32_t remaining_life = netif_ip6_addr_valid_life(netif, i);
232 if (valid_life > ND6_2HRS || valid_life > remaining_life) {
233 netif_ip6_addr_set_valid_life(netif, i, valid_life);
234 } else if (remaining_life > ND6_2HRS) {
235 netif_ip6_addr_set_valid_life(netif, i, ND6_2HRS);
236 }
237 LWIP_ASSERT("bad valid lifetime", !netif_ip6_addr_isstatic(netif, i));
238 /* Update the preferred lifetime. No bounds checks are needed here. In
239 * rare cases the advertisement may un-deprecate the address, though.
240 * Deprecation is left to the timer code where it is handled anyway. */
241 if (pref_life > 0 && addr_state == IP6_ADDR_DEPRECATED) {
242 netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED);
243 }
244 netif_ip6_addr_set_pref_life(netif, i, pref_life);
245 return; /* there should be at most one matching address */
246 }
247 }
248
249 /* No autogenerated address exists for this prefix yet. See if we can add a
250 * new one. However, if IPv6 autoconfiguration is administratively disabled,
251 * do not generate new addresses, but do keep updating lifetimes for existing
252 * addresses. Also, when adding new addresses, we must protect explicitly
253 * against a valid lifetime of zero, because again, we use that as a special
254 * value. The generated address would otherwise expire immediately anyway.
255 * Finally, the original link-local address must be usable at all. We start
256 * creating addresses even if the link-local address is still in tentative
257 * state though, and deal with the fallout of that upon DAD collision. */
258 addr_state = netif_ip6_addr_state(netif, 0);
259 if (!netif->ip6_autoconfig_enabled || valid_life == IP6_ADDR_LIFE_STATIC ||
260 ip6_addr_isinvalid(addr_state) || ip6_addr_isduplicated(addr_state)) {
261 return;
262 }
263
264 /* Construct the new address that we intend to use, and then see if that
265 * address really does not exist. It might have been added manually, after
266 * all. As a side effect, find a free slot. Note that we cannot use
267 * netif_add_ip6_address() here, as it would return ERR_OK if the address
268 * already did exist, resulting in that address being given lifetimes. */
269 IP6_ADDR(&ip6addr, prefix_addr->addr[0], prefix_addr->addr[1],
270 netif_ip6_addr(netif, 0)->addr[2], netif_ip6_addr(netif, 0)->addr[3]);
271 ip6_addr_assign_zone(&ip6addr, IP6_UNICAST, netif);
272
273 free_idx = 0;
274 for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
275 if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) {
276 if (ip6_addr_eq(&ip6addr, netif_ip6_addr(netif, i))) {
277 return; /* formed address already exists */
278 }
279 } else if (free_idx == 0) {
280 free_idx = i;
281 }
282 }
283 if (free_idx == 0) {
284 return; /* no address slots available, try again on next advertisement */
285 }
286
287 /* Assign the new address to the interface. */
288 ip_addr_copy_from_ip6(netif->ip6_addr[free_idx], ip6addr);
289 netif_ip6_addr_set_valid_life(netif, free_idx, valid_life);
290 netif_ip6_addr_set_pref_life(netif, free_idx, pref_life);
291 netif_ip6_addr_set_state(netif, free_idx, IP6_ADDR_TENTATIVE);
292}
293#endif /* LWIP_IPV6_AUTOCONFIG */
294
301void
302nd6_input(struct pbuf *p, struct netif *inp)
303{
305 s8_t i;
306 s16_t dest_idx;
307
308 ND6_STATS_INC(nd6.recv);
309
310 msg_type = *((u8_t *)p->payload);
311 switch (msg_type) {
312 case ICMP6_TYPE_NA: /* Neighbor Advertisement. */
313 {
314 struct na_header *na_hdr;
315 struct lladdr_option *lladdr_opt;
316 ip6_addr_t target_address;
317
318 /* Check that na header fits in packet. */
319 if (p->len < (sizeof(struct na_header))) {
320 /* @todo debug message */
321 pbuf_free(p);
322 ND6_STATS_INC(nd6.lenerr);
323 ND6_STATS_INC(nd6.drop);
324 return;
325 }
326
327 na_hdr = (struct na_header *)p->payload;
328
329 /* Create an aligned, zoned copy of the target address. */
330 ip6_addr_copy_from_packed(target_address, na_hdr->target_address);
331 ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp);
332
333 /* Check a subset of the other RFC 4861 Sec. 7.1.2 requirements. */
334 if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || na_hdr->code != 0 ||
335 ip6_addr_ismulticast(&target_address)) {
336 pbuf_free(p);
337 ND6_STATS_INC(nd6.proterr);
338 ND6_STATS_INC(nd6.drop);
339 return;
340 }
341
342 /* @todo RFC MUST: if IP destination is multicast, Solicited flag is zero */
343 /* @todo RFC MUST: all included options have a length greater than zero */
344
345 /* Unsolicited NA?*/
346 if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
347 /* This is an unsolicited NA.
348 * link-layer changed?
349 * part of DAD mechanism? */
350
351#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
352 /* If the target address matches this netif, it is a DAD response. */
353 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
354 if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) &&
355 !ip6_addr_isduplicated(netif_ip6_addr_state(inp, i)) &&
356 ip6_addr_eq(&target_address, netif_ip6_addr(inp, i))) {
357 /* We are using a duplicate address. */
358 nd6_duplicate_addr_detected(inp, i);
359
360 pbuf_free(p);
361 return;
362 }
363 }
364#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */
365
366 /* Check that link-layer address option also fits in packet. */
367 if (p->len < (sizeof(struct na_header) + 2)) {
368 /* @todo debug message */
369 pbuf_free(p);
370 ND6_STATS_INC(nd6.lenerr);
371 ND6_STATS_INC(nd6.drop);
372 return;
373 }
374
375 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header));
376
377 if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) {
378 /* @todo debug message */
379 pbuf_free(p);
380 ND6_STATS_INC(nd6.lenerr);
381 ND6_STATS_INC(nd6.drop);
382 return;
383 }
384
385 /* This is an unsolicited NA, most likely there was a LLADDR change. */
386 i = nd6_find_neighbor_cache_entry(&target_address);
387 if (i >= 0) {
388 if (na_hdr->flags & ND6_FLAG_OVERRIDE) {
389 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
390 }
391 }
392 } else {
393 /* This is a solicited NA.
394 * neighbor address resolution response?
395 * neighbor unreachability detection response? */
396
397 /* Find the cache entry corresponding to this na. */
398 i = nd6_find_neighbor_cache_entry(&target_address);
399 if (i < 0) {
400 /* We no longer care about this target address. drop it. */
401 pbuf_free(p);
402 return;
403 }
404
405 /* Update cache entry. */
406 if ((na_hdr->flags & ND6_FLAG_OVERRIDE) ||
407 (neighbor_cache[i].state == ND6_INCOMPLETE)) {
408 /* Check that link-layer address option also fits in packet. */
409 if (p->len < (sizeof(struct na_header) + 2)) {
410 /* @todo debug message */
411 pbuf_free(p);
412 ND6_STATS_INC(nd6.lenerr);
413 ND6_STATS_INC(nd6.drop);
414 return;
415 }
416
417 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header));
418
419 if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) {
420 /* @todo debug message */
421 pbuf_free(p);
422 ND6_STATS_INC(nd6.lenerr);
423 ND6_STATS_INC(nd6.drop);
424 return;
425 }
426
427 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
428 }
429
430 neighbor_cache[i].netif = inp;
431 neighbor_cache[i].state = ND6_REACHABLE;
432 neighbor_cache[i].counter.reachable_time = reachable_time;
433
434 /* Send queued packets, if any. */
435 if (neighbor_cache[i].q != NULL) {
436 nd6_send_q(i);
437 }
438 }
439
440 break; /* ICMP6_TYPE_NA */
441 }
442 case ICMP6_TYPE_NS: /* Neighbor solicitation. */
443 {
444 struct ns_header *ns_hdr;
445 struct lladdr_option *lladdr_opt;
446 ip6_addr_t target_address;
448
449 /* Check that ns header fits in packet. */
450 if (p->len < sizeof(struct ns_header)) {
451 /* @todo debug message */
452 pbuf_free(p);
453 ND6_STATS_INC(nd6.lenerr);
454 ND6_STATS_INC(nd6.drop);
455 return;
456 }
457
458 ns_hdr = (struct ns_header *)p->payload;
459
460 /* Create an aligned, zoned copy of the target address. */
461 ip6_addr_copy_from_packed(target_address, ns_hdr->target_address);
462 ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp);
463
464 /* Check a subset of the other RFC 4861 Sec. 7.1.1 requirements. */
465 if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ns_hdr->code != 0 ||
466 ip6_addr_ismulticast(&target_address)) {
467 pbuf_free(p);
468 ND6_STATS_INC(nd6.proterr);
469 ND6_STATS_INC(nd6.drop);
470 return;
471 }
472
473 /* @todo RFC MUST: all included options have a length greater than zero */
474 /* @todo RFC MUST: if IP source is 'any', destination is solicited-node multicast address */
475 /* @todo RFC MUST: if IP source is 'any', there is no source LL address option */
476
477 /* Check if there is a link-layer address provided. Only point to it if in this buffer. */
478 if (p->len >= (sizeof(struct ns_header) + 2)) {
479 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header));
480 if (p->len < (sizeof(struct ns_header) + (lladdr_opt->length << 3))) {
481 lladdr_opt = NULL;
482 }
483 } else {
484 lladdr_opt = NULL;
485 }
486
487 /* Check if the target address is configured on the receiving netif. */
488 accepted = 0;
489 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
490 if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) ||
491 (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) &&
492 ip6_addr_isany(ip6_current_src_addr()))) &&
493 ip6_addr_eq(&target_address, netif_ip6_addr(inp, i))) {
494 accepted = 1;
495 break;
496 }
497 }
498
499 /* NS not for us? */
500 if (!accepted) {
501 pbuf_free(p);
502 return;
503 }
504
505 /* Check for ANY address in src (DAD algorithm). */
506 if (ip6_addr_isany(ip6_current_src_addr())) {
507 /* Sender is validating this address. */
508 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
509 if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) &&
510 ip6_addr_eq(&target_address, netif_ip6_addr(inp, i))) {
511 /* Send a NA back so that the sender does not use this address. */
512 nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST);
513 if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) {
514 /* We shouldn't use this address either. */
515 nd6_duplicate_addr_detected(inp, i);
516 }
517 }
518 }
519 } else {
520 /* Sender is trying to resolve our address. */
521 /* Verify that they included their own link-layer address. */
522 if (lladdr_opt == NULL) {
523 /* Not a valid message. */
524 pbuf_free(p);
525 ND6_STATS_INC(nd6.proterr);
526 ND6_STATS_INC(nd6.drop);
527 return;
528 }
529
530 i = nd6_find_neighbor_cache_entry(ip6_current_src_addr());
531 if (i>= 0) {
532 /* We already have a record for the solicitor. */
533 if (neighbor_cache[i].state == ND6_INCOMPLETE) {
534 neighbor_cache[i].netif = inp;
535 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
536
537 /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */
538 neighbor_cache[i].state = ND6_DELAY;
539 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
540 }
541 } else {
542 /* Add their IPv6 address and link-layer address to neighbor cache.
543 * We will need it at least to send a unicast NA message, but most
544 * likely we will also be communicating with this node soon. */
545 i = nd6_new_neighbor_cache_entry();
546 if (i < 0) {
547 /* We couldn't assign a cache entry for this neighbor.
548 * we won't be able to reply. drop it. */
549 pbuf_free(p);
550 ND6_STATS_INC(nd6.memerr);
551 return;
552 }
553 neighbor_cache[i].netif = inp;
554 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
555 ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr());
556
557 /* Receiving a message does not prove reachability: only in one direction.
558 * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
559 neighbor_cache[i].state = ND6_DELAY;
560 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
561 }
562
563 /* Send back a NA for us. Allocate the reply pbuf. */
564 nd6_send_na(inp, &target_address, ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE);
565 }
566
567 break; /* ICMP6_TYPE_NS */
568 }
569 case ICMP6_TYPE_RA: /* Router Advertisement. */
570 {
571 struct ra_header *ra_hdr;
572 u8_t *buffer; /* Used to copy options. */
574#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS
575 /* There can be multiple RDNSS options per RA */
576 u8_t rdnss_server_idx = 0;
577#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */
578
579 /* Check that RA header fits in packet. */
580 if (p->len < sizeof(struct ra_header)) {
581 /* @todo debug message */
582 pbuf_free(p);
583 ND6_STATS_INC(nd6.lenerr);
584 ND6_STATS_INC(nd6.drop);
585 return;
586 }
587
588 ra_hdr = (struct ra_header *)p->payload;
589
590 /* Check a subset of the other RFC 4861 Sec. 6.1.2 requirements. */
591 if (!ip6_addr_islinklocal(ip6_current_src_addr()) ||
592 IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ra_hdr->code != 0) {
593 pbuf_free(p);
594 ND6_STATS_INC(nd6.proterr);
595 ND6_STATS_INC(nd6.drop);
596 return;
597 }
598
599 /* @todo RFC MUST: all included options have a length greater than zero */
600
601 /* If we are sending RS messages, stop. */
602#if LWIP_IPV6_SEND_ROUTER_SOLICIT
603 /* ensure at least one solicitation is sent (see RFC 4861, ch. 6.3.7) */
604 if ((inp->rs_count < LWIP_ND6_MAX_MULTICAST_SOLICIT) ||
605 (nd6_send_rs(inp) == ERR_OK)) {
606 inp->rs_count = 0;
607 } else {
608 inp->rs_count = 1;
609 }
610#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
611
612 /* Get the matching default router entry. */
613 i = nd6_get_router(ip6_current_src_addr(), inp);
614 if (i < 0) {
615 /* Create a new router entry. */
616 i = nd6_new_router(ip6_current_src_addr(), inp);
617 }
618
619 if (i < 0) {
620 /* Could not create a new router entry. */
621 pbuf_free(p);
622 ND6_STATS_INC(nd6.memerr);
623 return;
624 }
625
626 /* Re-set invalidation timer. */
627 default_router_list[i].invalidation_timer = lwip_htons(ra_hdr->router_lifetime);
628
629 /* Re-set default timer values. */
630#if LWIP_ND6_ALLOW_RA_UPDATES
631 if (ra_hdr->retrans_timer > 0) {
632 retrans_timer = lwip_htonl(ra_hdr->retrans_timer);
633 }
634 if (ra_hdr->reachable_time > 0) {
635 reachable_time = lwip_htonl(ra_hdr->reachable_time);
636 }
637#endif /* LWIP_ND6_ALLOW_RA_UPDATES */
638
639 /* @todo set default hop limit... */
640 /* ra_hdr->current_hop_limit;*/
641
642 /* Update flags in local entry (incl. preference). */
643 default_router_list[i].flags = ra_hdr->flags;
644
645#if LWIP_IPV6_DHCP6
646 /* Trigger DHCPv6 if enabled */
647 dhcp6_nd6_ra_trigger(inp, ra_hdr->flags & ND6_RA_FLAG_MANAGED_ADDR_CONFIG,
648 ra_hdr->flags & ND6_RA_FLAG_OTHER_CONFIG);
649#endif
650
651 /* Offset to options. */
652 offset = sizeof(struct ra_header);
653
654 /* Process each option. */
655 while ((p->tot_len - offset) >= 2) {
656 u8_t option_type;
657 u16_t option_len;
658 int option_len8 = pbuf_try_get_at(p, offset + 1);
659 if (option_len8 <= 0) {
660 /* read beyond end or zero length */
661 goto lenerr_drop_free_return;
662 }
663 option_len = ((u8_t)option_len8) << 3;
664 if (option_len > p->tot_len - offset) {
665 /* short packet (option does not fit in) */
666 goto lenerr_drop_free_return;
667 }
668 if (p->len == p->tot_len) {
669 /* no need to copy from contiguous pbuf */
670 buffer = &((u8_t*)p->payload)[offset];
671 } else {
672 /* check if this option fits into our buffer */
673 if (option_len > sizeof(nd6_ra_buffer)) {
674 option_type = pbuf_get_at(p, offset);
675 /* invalid option length */
676 if (option_type != ND6_OPTION_TYPE_RDNSS) {
677 goto lenerr_drop_free_return;
678 }
679 /* we allow RDNSS option to be longer - we'll just drop some servers */
680 option_len = sizeof(nd6_ra_buffer);
681 }
682 buffer = (u8_t*)&nd6_ra_buffer;
683 option_len = pbuf_copy_partial(p, &nd6_ra_buffer, option_len, offset);
684 }
685 option_type = buffer[0];
686 switch (option_type) {
688 {
689 struct lladdr_option *lladdr_opt;
690 if (option_len < sizeof(struct lladdr_option)) {
691 goto lenerr_drop_free_return;
692 }
693 lladdr_opt = (struct lladdr_option *)buffer;
694 if ((default_router_list[i].neighbor_entry != NULL) &&
695 (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) {
696 SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len);
697 default_router_list[i].neighbor_entry->state = ND6_REACHABLE;
698 default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time;
699 }
700 break;
701 }
703 {
704 struct mtu_option *mtu_opt;
705 u32_t mtu32;
706 if (option_len < sizeof(struct mtu_option)) {
707 goto lenerr_drop_free_return;
708 }
709 mtu_opt = (struct mtu_option *)buffer;
710 mtu32 = lwip_htonl(mtu_opt->mtu);
711 if ((mtu32 >= IP6_MIN_MTU_LENGTH) && (mtu32 <= 0xffff)) {
712#if LWIP_ND6_ALLOW_RA_UPDATES
713 if (inp->mtu) {
714 /* don't set the mtu for IPv6 higher than the netif driver supports */
715 inp->mtu6 = LWIP_MIN(LWIP_MIN(inp->mtu, inp->mtu6), (u16_t)mtu32);
716 } else {
717 inp->mtu6 = (u16_t)mtu32;
718 }
719#endif /* LWIP_ND6_ALLOW_RA_UPDATES */
720 }
721 break;
722 }
724 {
725 struct prefix_option *prefix_opt;
726 ip6_addr_t prefix_addr;
727 if (option_len < sizeof(struct prefix_option)) {
728 goto lenerr_drop_free_return;
729 }
730
731 prefix_opt = (struct prefix_option *)buffer;
732
733 /* Get a memory-aligned copy of the prefix. */
734 ip6_addr_copy_from_packed(prefix_addr, prefix_opt->prefix);
735 ip6_addr_assign_zone(&prefix_addr, IP6_UNICAST, inp);
736
737 if (!ip6_addr_islinklocal(&prefix_addr)) {
738 if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) &&
739 (prefix_opt->prefix_length == 64)) {
740 /* Add to on-link prefix list. */
741 u32_t valid_life;
742 s8_t prefix;
743
744 valid_life = lwip_htonl(prefix_opt->valid_lifetime);
745
746 /* find cache entry for this prefix. */
747 prefix = nd6_get_onlink_prefix(&prefix_addr, inp);
748 if (prefix < 0 && valid_life > 0) {
749 /* Create a new cache entry. */
750 prefix = nd6_new_onlink_prefix(&prefix_addr, inp);
751 }
752 if (prefix >= 0) {
753 prefix_list[prefix].invalidation_timer = valid_life;
754 }
755 }
756#if LWIP_IPV6_AUTOCONFIG
757 if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) {
758 /* Perform processing for autoconfiguration. */
759 nd6_process_autoconfig_prefix(inp, prefix_opt, &prefix_addr);
760 }
761#endif /* LWIP_IPV6_AUTOCONFIG */
762 }
763
764 break;
765 }
767 /* @todo implement preferred routes.
768 struct route_option * route_opt;
769 route_opt = (struct route_option *)buffer;*/
770
771 break;
772#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS
774 {
775 u8_t num, n;
776 u16_t copy_offset = offset + SIZEOF_RDNSS_OPTION_BASE;
777 struct rdnss_option * rdnss_opt;
778 if (option_len < SIZEOF_RDNSS_OPTION_BASE) {
779 goto lenerr_drop_free_return;
780 }
781
782 rdnss_opt = (struct rdnss_option *)buffer;
783 num = (rdnss_opt->length - 1) / 2;
784 for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++, copy_offset += sizeof(ip6_addr_p_t)) {
785 ip_addr_t rdnss_address;
786
787 /* Copy directly from pbuf to get an aligned, zoned copy of the prefix. */
788 if (pbuf_copy_partial(p, &rdnss_address, sizeof(ip6_addr_p_t), copy_offset) == sizeof(ip6_addr_p_t)) {
789 IP_SET_TYPE_VAL(rdnss_address, IPADDR_TYPE_V6);
790 ip6_addr_assign_zone(ip_2_ip6(&rdnss_address), IP6_UNKNOWN, inp);
791
792 if (htonl(rdnss_opt->lifetime) > 0) {
793 /* TODO implement Lifetime > 0 */
794 dns_setserver(rdnss_server_idx++, &rdnss_address);
795 } else {
796 /* TODO implement DNS removal in dns.c */
797 u8_t s;
798 for (s = 0; s < DNS_MAX_SERVERS; s++) {
799 const ip_addr_t *addr = dns_getserver(s);
800 if(ip_addr_eq(addr, &rdnss_address)) {
801 dns_setserver(s, NULL);
802 }
803 }
804 }
805 }
806 }
807 break;
808 }
809#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */
810 default:
811 /* Unrecognized option, abort. */
812 ND6_STATS_INC(nd6.proterr);
813 break;
814 }
815 /* option length is checked earlier to be non-zero to make sure loop ends */
816 offset += 8 * (u8_t)option_len8;
817 }
818
819 break; /* ICMP6_TYPE_RA */
820 }
821 case ICMP6_TYPE_RD: /* Redirect */
822 {
823 struct redirect_header *redir_hdr;
824 struct lladdr_option *lladdr_opt;
825 ip6_addr_t destination_address, target_address;
826
827 /* Check that Redir header fits in packet. */
828 if (p->len < sizeof(struct redirect_header)) {
829 /* @todo debug message */
830 pbuf_free(p);
831 ND6_STATS_INC(nd6.lenerr);
832 ND6_STATS_INC(nd6.drop);
833 return;
834 }
835
836 redir_hdr = (struct redirect_header *)p->payload;
837
838 /* Create an aligned, zoned copy of the destination address. */
839 ip6_addr_copy_from_packed(destination_address, redir_hdr->destination_address);
840 ip6_addr_assign_zone(&destination_address, IP6_UNICAST, inp);
841
842 /* Check a subset of the other RFC 4861 Sec. 8.1 requirements. */
843 if (!ip6_addr_islinklocal(ip6_current_src_addr()) ||
844 IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM ||
845 redir_hdr->code != 0 || ip6_addr_ismulticast(&destination_address)) {
846 pbuf_free(p);
847 ND6_STATS_INC(nd6.proterr);
848 ND6_STATS_INC(nd6.drop);
849 return;
850 }
851
852 /* @todo RFC MUST: IP source address equals first-hop router for destination_address */
853 /* @todo RFC MUST: ICMP target address is either link-local address or same as destination_address */
854 /* @todo RFC MUST: all included options have a length greater than zero */
855
856 if (p->len >= (sizeof(struct redirect_header) + 2)) {
857 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header));
858 if (p->len < (sizeof(struct redirect_header) + (lladdr_opt->length << 3))) {
859 lladdr_opt = NULL;
860 }
861 } else {
862 lladdr_opt = NULL;
863 }
864
865 /* Find dest address in cache */
866 dest_idx = nd6_find_destination_cache_entry(&destination_address);
867 if (dest_idx < 0) {
868 /* Destination not in cache, drop packet. */
869 pbuf_free(p);
870 return;
871 }
872
873 /* Create an aligned, zoned copy of the target address. */
874 ip6_addr_copy_from_packed(target_address, redir_hdr->target_address);
875 ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp);
876
877 /* Set the new target address. */
878 ip6_addr_copy(destination_cache[dest_idx].next_hop_addr, target_address);
879
880 /* If Link-layer address of other router is given, try to add to neighbor cache. */
881 if (lladdr_opt != NULL) {
882 if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) {
883 i = nd6_find_neighbor_cache_entry(&target_address);
884 if (i < 0) {
885 i = nd6_new_neighbor_cache_entry();
886 if (i >= 0) {
887 neighbor_cache[i].netif = inp;
888 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
889 ip6_addr_copy(neighbor_cache[i].next_hop_address, target_address);
890
891 /* Receiving a message does not prove reachability: only in one direction.
892 * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
893 neighbor_cache[i].state = ND6_DELAY;
894 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
895 }
896 }
897 if (i >= 0) {
898 if (neighbor_cache[i].state == ND6_INCOMPLETE) {
899 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
900 /* Receiving a message does not prove reachability: only in one direction.
901 * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
902 neighbor_cache[i].state = ND6_DELAY;
903 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
904 }
905 }
906 }
907 }
908 break; /* ICMP6_TYPE_RD */
909 }
910 case ICMP6_TYPE_PTB: /* Packet too big */
911 {
912 struct icmp6_hdr *icmp6hdr; /* Packet too big message */
913 struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */
914 u32_t pmtu;
915 ip6_addr_t destination_address;
916
917 /* Check that ICMPv6 header + IPv6 header fit in payload */
918 if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) {
919 /* drop short packets */
920 pbuf_free(p);
921 ND6_STATS_INC(nd6.lenerr);
922 ND6_STATS_INC(nd6.drop);
923 return;
924 }
925
926 icmp6hdr = (struct icmp6_hdr *)p->payload;
927 ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr));
928
929 /* Create an aligned, zoned copy of the destination address. */
930 ip6_addr_copy_from_packed(destination_address, ip6hdr->dest);
931 ip6_addr_assign_zone(&destination_address, IP6_UNKNOWN, inp);
932
933 /* Look for entry in destination cache. */
934 dest_idx = nd6_find_destination_cache_entry(&destination_address);
935 if (dest_idx < 0) {
936 /* Destination not in cache, drop packet. */
937 pbuf_free(p);
938 return;
939 }
940
941 /* Change the Path MTU. */
942 pmtu = lwip_htonl(icmp6hdr->data);
943 destination_cache[dest_idx].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF);
944
945 break; /* ICMP6_TYPE_PTB */
946 }
947
948 default:
949 ND6_STATS_INC(nd6.proterr);
950 ND6_STATS_INC(nd6.drop);
951 break; /* default */
952 }
953
954 pbuf_free(p);
955 return;
956lenerr_drop_free_return:
957 ND6_STATS_INC(nd6.lenerr);
958 ND6_STATS_INC(nd6.drop);
959 pbuf_free(p);
960}
961
962
973void
974nd6_tmr(void)
975{
976 s8_t i;
977 struct netif *netif;
978
979 /* Process neighbor entries. */
980 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
981 switch (neighbor_cache[i].state) {
982 case ND6_INCOMPLETE:
983 if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) &&
984 (!neighbor_cache[i].isrouter)) {
985 /* Retries exceeded. */
986 nd6_free_neighbor_cache_entry(i);
987 } else {
988 /* Send a NS for this entry. */
989 neighbor_cache[i].counter.probes_sent++;
990 nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST);
991 }
992 break;
993 case ND6_REACHABLE:
994 /* Send queued packets, if any are left. Should have been sent already. */
995 if (neighbor_cache[i].q != NULL) {
996 nd6_send_q(i);
997 }
998 if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) {
999 /* Change to stale state. */
1000 neighbor_cache[i].state = ND6_STALE;
1001 neighbor_cache[i].counter.stale_time = 0;
1002 } else {
1003 neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL;
1004 }
1005 break;
1006 case ND6_STALE:
1007 neighbor_cache[i].counter.stale_time++;
1008 break;
1009 case ND6_DELAY:
1010 if (neighbor_cache[i].counter.delay_time <= 1) {
1011 /* Change to PROBE state. */
1012 neighbor_cache[i].state = ND6_PROBE;
1013 neighbor_cache[i].counter.probes_sent = 0;
1014 } else {
1015 neighbor_cache[i].counter.delay_time--;
1016 }
1017 break;
1018 case ND6_PROBE:
1019 if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) &&
1020 (!neighbor_cache[i].isrouter)) {
1021 /* Retries exceeded. */
1022 nd6_free_neighbor_cache_entry(i);
1023 } else {
1024 /* Send a NS for this entry. */
1025 neighbor_cache[i].counter.probes_sent++;
1026 nd6_send_neighbor_cache_probe(&neighbor_cache[i], 0);
1027 }
1028 break;
1029 case ND6_NO_ENTRY:
1030 default:
1031 /* Do nothing. */
1032 break;
1033 }
1034 }
1035
1036 /* Process destination entries. */
1037 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
1038 destination_cache[i].age++;
1039 }
1040
1041 /* Process router entries. */
1042 for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
1043 if (default_router_list[i].neighbor_entry != NULL) {
1044 /* Active entry. */
1045 if (default_router_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) {
1046 /* No more than 1 second remaining. Clear this entry. Also clear any of
1047 * its destination cache entries, as per RFC 4861 Sec. 5.3 and 6.3.5. */
1048 s8_t j;
1049 for (j = 0; j < LWIP_ND6_NUM_DESTINATIONS; j++) {
1050 if (ip6_addr_eq(&destination_cache[j].next_hop_addr,
1051 &default_router_list[i].neighbor_entry->next_hop_address)) {
1052 ip6_addr_set_any(&destination_cache[j].destination_addr);
1053 }
1054 }
1055 default_router_list[i].neighbor_entry->isrouter = 0;
1056 default_router_list[i].neighbor_entry = NULL;
1057 default_router_list[i].invalidation_timer = 0;
1058 default_router_list[i].flags = 0;
1059 } else {
1060 default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000;
1061 }
1062 }
1063 }
1064
1065 /* Process prefix entries. */
1066 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
1067 if (prefix_list[i].netif != NULL) {
1068 if (prefix_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) {
1069 /* Entry timed out, remove it */
1070 prefix_list[i].invalidation_timer = 0;
1071 prefix_list[i].netif = NULL;
1072 } else {
1073 prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000;
1074 }
1075 }
1076 }
1077
1078 /* Process our own addresses, updating address lifetimes and/or DAD state. */
1080 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
1081 u8_t addr_state;
1082#if LWIP_IPV6_ADDRESS_LIFETIMES
1083 /* Step 1: update address lifetimes (valid and preferred). */
1084 addr_state = netif_ip6_addr_state(netif, i);
1085 /* RFC 4862 is not entirely clear as to whether address lifetimes affect
1086 * tentative addresses, and is even less clear as to what should happen
1087 * with duplicate addresses. We choose to track and update lifetimes for
1088 * both those types, although for different reasons:
1089 * - for tentative addresses, the line of thought of Sec. 5.7 combined
1090 * with the potentially long period that an address may be in tentative
1091 * state (due to the interface being down) suggests that lifetimes
1092 * should be independent of external factors which would include DAD;
1093 * - for duplicate addresses, retiring them early could result in a new
1094 * but unwanted attempt at marking them as valid, while retiring them
1095 * late/never could clog up address slots on the netif.
1096 * As a result, we may end up expiring addresses of either type here.
1097 */
1098 if (!ip6_addr_isinvalid(addr_state) &&
1099 !netif_ip6_addr_isstatic(netif, i)) {
1100 u32_t life = netif_ip6_addr_valid_life(netif, i);
1101 if (life <= ND6_TMR_INTERVAL / 1000) {
1102 /* The address has expired. */
1103 netif_ip6_addr_set_valid_life(netif, i, 0);
1104 netif_ip6_addr_set_pref_life(netif, i, 0);
1105 netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
1106 } else {
1107 if (!ip6_addr_life_isinfinite(life)) {
1108 life -= ND6_TMR_INTERVAL / 1000;
1109 LWIP_ASSERT("bad valid lifetime", life != IP6_ADDR_LIFE_STATIC);
1110 netif_ip6_addr_set_valid_life(netif, i, life);
1111 }
1112 /* The address is still here. Update the preferred lifetime too. */
1113 life = netif_ip6_addr_pref_life(netif, i);
1114 if (life <= ND6_TMR_INTERVAL / 1000) {
1115 /* This case must also trigger if 'life' was already zero, so as to
1116 * deal correctly with advertised preferred-lifetime reductions. */
1117 netif_ip6_addr_set_pref_life(netif, i, 0);
1118 if (addr_state == IP6_ADDR_PREFERRED)
1119 netif_ip6_addr_set_state(netif, i, IP6_ADDR_DEPRECATED);
1120 } else if (!ip6_addr_life_isinfinite(life)) {
1121 life -= ND6_TMR_INTERVAL / 1000;
1122 netif_ip6_addr_set_pref_life(netif, i, life);
1123 }
1124 }
1125 }
1126 /* The address state may now have changed, so reobtain it next. */
1127#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
1128 /* Step 2: update DAD state. */
1129 addr_state = netif_ip6_addr_state(netif, i);
1130 if (ip6_addr_istentative(addr_state)) {
1131 if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) {
1132 /* No NA received in response. Mark address as valid. For dynamic
1133 * addresses with an expired preferred lifetime, the state is set to
1134 * deprecated right away. That should almost never happen, though. */
1135 addr_state = IP6_ADDR_PREFERRED;
1136#if LWIP_IPV6_ADDRESS_LIFETIMES
1137 if (!netif_ip6_addr_isstatic(netif, i) &&
1138 netif_ip6_addr_pref_life(netif, i) == 0) {
1139 addr_state = IP6_ADDR_DEPRECATED;
1140 }
1141#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
1142 netif_ip6_addr_set_state(netif, i, addr_state);
1143 } else if (netif_is_up(netif) && netif_is_link_up(netif)) {
1144 /* tentative: set next state by increasing by one */
1145 netif_ip6_addr_set_state(netif, i, addr_state + 1);
1146 /* Send a NS for this address. Use the unspecified address as source
1147 * address in all cases (RFC 4862 Sec. 5.4.2), not in the least
1148 * because as it is, we only consider multicast replies for DAD. */
1149 nd6_send_ns(netif, netif_ip6_addr(netif, i),
1150 ND6_SEND_FLAG_MULTICAST_DEST | ND6_SEND_FLAG_ANY_SRC);
1151 }
1152 }
1153 }
1154 }
1155
1156#if LWIP_IPV6_SEND_ROUTER_SOLICIT
1157 /* Send router solicitation messages, if necessary. */
1158 if (!nd6_tmr_rs_reduction) {
1159 nd6_tmr_rs_reduction = (ND6_RTR_SOLICITATION_INTERVAL / ND6_TMR_INTERVAL) - 1;
1161 if ((netif->rs_count > 0) && netif_is_up(netif) &&
1163 !ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)) &&
1164 !ip6_addr_isduplicated(netif_ip6_addr_state(netif, 0))) {
1165 if (nd6_send_rs(netif) == ERR_OK) {
1166 netif->rs_count--;
1167 }
1168 }
1169 }
1170 } else {
1171 nd6_tmr_rs_reduction--;
1172 }
1173#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
1174
1175}
1176
1182static void
1183nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags)
1184{
1185 nd6_send_ns(entry->netif, &entry->next_hop_address, flags);
1186}
1187
1195static void
1196nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags)
1197{
1198 struct ns_header *ns_hdr;
1199 struct pbuf *p;
1200 const ip6_addr_t *src_addr = NULL;
1201 u16_t lladdr_opt_len;
1202
1203 LWIP_ASSERT("target address is required", target_addr != NULL);
1204
1205 if (!(flags & ND6_SEND_FLAG_ANY_SRC)) {
1206 int i;
1207 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
1208 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
1209 ip6_addr_net_eq(target_addr, netif_ip6_addr(netif, i))) {
1210 src_addr = netif_ip6_addr(netif, i);
1211 break;
1212 }
1213 }
1214
1215 if (i == LWIP_IPV6_NUM_ADDRESSES) {
1216 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("ICMPv6 NS: no available src address\n"));
1217 ND6_STATS_INC(nd6.err);
1218 return;
1219 }
1220
1221 /* calculate option length (in 8-byte-blocks) */
1222 lladdr_opt_len = ((netif->hwaddr_len + 2) + 7) >> 3;
1223 } else {
1224 src_addr = IP6_ADDR_ANY6;
1225 /* Option "MUST NOT be included when the source IP address is the unspecified address." */
1226 lladdr_opt_len = 0;
1227 }
1228
1229 /* Allocate a packet. */
1230 p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + (lladdr_opt_len << 3), PBUF_RAM);
1231 if (p == NULL) {
1232 ND6_STATS_INC(nd6.memerr);
1233 return;
1234 }
1235
1236 /* Set fields. */
1237 ns_hdr = (struct ns_header *)p->payload;
1238
1239 ns_hdr->type = ICMP6_TYPE_NS;
1240 ns_hdr->code = 0;
1241 ns_hdr->chksum = 0;
1242 ns_hdr->reserved = 0;
1243 ip6_addr_copy_to_packed(ns_hdr->target_address, *target_addr);
1244
1245 if (lladdr_opt_len != 0) {
1246 struct lladdr_option *lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header));
1247 lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR;
1248 lladdr_opt->length = (u8_t)lladdr_opt_len;
1249 SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len);
1250 }
1251
1252 /* Generate the solicited node address for the target address. */
1253 if (flags & ND6_SEND_FLAG_MULTICAST_DEST) {
1254 ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]);
1255 ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif);
1256 target_addr = &multicast_address;
1257 }
1258
1259#if CHECKSUM_GEN_ICMP6
1260 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
1261 ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr,
1262 target_addr);
1263 }
1264#endif /* CHECKSUM_GEN_ICMP6 */
1265
1266 /* Send the packet out. */
1267 ND6_STATS_INC(nd6.xmit);
1268 ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, target_addr,
1269 ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif);
1270 pbuf_free(p);
1271}
1272
1280static void
1281nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags)
1282{
1283 struct na_header *na_hdr;
1284 struct lladdr_option *lladdr_opt;
1285 struct pbuf *p;
1286 const ip6_addr_t *src_addr;
1287 const ip6_addr_t *dest_addr;
1288 u16_t lladdr_opt_len;
1289
1290 LWIP_ASSERT("target address is required", target_addr != NULL);
1291
1292 /* Use link-local address as source address. */
1293 /* src_addr = netif_ip6_addr(netif, 0); */
1294 /* Use target address as source address. */
1295 src_addr = target_addr;
1296
1297 /* Allocate a packet. */
1298 lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0);
1299 p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + (lladdr_opt_len << 3), PBUF_RAM);
1300 if (p == NULL) {
1301 ND6_STATS_INC(nd6.memerr);
1302 return;
1303 }
1304
1305 /* Set fields. */
1306 na_hdr = (struct na_header *)p->payload;
1307 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header));
1308
1309 na_hdr->type = ICMP6_TYPE_NA;
1310 na_hdr->code = 0;
1311 na_hdr->chksum = 0;
1312 na_hdr->flags = flags & 0xf0;
1313 na_hdr->reserved[0] = 0;
1314 na_hdr->reserved[1] = 0;
1315 na_hdr->reserved[2] = 0;
1316 ip6_addr_copy_to_packed(na_hdr->target_address, *target_addr);
1317
1318 lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR;
1319 lladdr_opt->length = (u8_t)lladdr_opt_len;
1320 SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len);
1321
1322 /* Generate the solicited node address for the target address. */
1323 if (flags & ND6_SEND_FLAG_MULTICAST_DEST) {
1324 ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]);
1325 ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif);
1326 dest_addr = &multicast_address;
1327 } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) {
1328 ip6_addr_set_allnodes_linklocal(&multicast_address);
1329 ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif);
1330 dest_addr = &multicast_address;
1331 } else {
1332 dest_addr = ip6_current_src_addr();
1333 }
1334
1335#if CHECKSUM_GEN_ICMP6
1336 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
1337 na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr,
1338 dest_addr);
1339 }
1340#endif /* CHECKSUM_GEN_ICMP6 */
1341
1342 /* Send the packet out. */
1343 ND6_STATS_INC(nd6.xmit);
1344 ip6_output_if(p, src_addr, dest_addr,
1345 ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif);
1346 pbuf_free(p);
1347}
1348
1349#if LWIP_IPV6_SEND_ROUTER_SOLICIT
1355static err_t
1356nd6_send_rs(struct netif *netif)
1357{
1358 struct rs_header *rs_hdr;
1359 struct lladdr_option *lladdr_opt;
1360 struct pbuf *p;
1361 const ip6_addr_t *src_addr;
1362 err_t err;
1363 u16_t lladdr_opt_len = 0;
1364
1365 /* Link-local source address, or unspecified address? */
1366 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) {
1367 src_addr = netif_ip6_addr(netif, 0);
1368 } else {
1369 src_addr = IP6_ADDR_ANY6;
1370 }
1371
1372 /* Generate the all routers target address. */
1373 ip6_addr_set_allrouters_linklocal(&multicast_address);
1374 ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif);
1375
1376 /* Allocate a packet. */
1377 if (src_addr != IP6_ADDR_ANY6) {
1378 lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0);
1379 }
1380 p = pbuf_alloc(PBUF_IP, sizeof(struct rs_header) + (lladdr_opt_len << 3), PBUF_RAM);
1381 if (p == NULL) {
1382 ND6_STATS_INC(nd6.memerr);
1383 return ERR_BUF;
1384 }
1385
1386 /* Set fields. */
1387 rs_hdr = (struct rs_header *)p->payload;
1388
1389 rs_hdr->type = ICMP6_TYPE_RS;
1390 rs_hdr->code = 0;
1391 rs_hdr->chksum = 0;
1392 rs_hdr->reserved = 0;
1393
1394 if (src_addr != IP6_ADDR_ANY6) {
1395 /* Include our hw address. */
1396 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header));
1397 lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR;
1398 lladdr_opt->length = (u8_t)lladdr_opt_len;
1399 SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len);
1400 }
1401
1402#if CHECKSUM_GEN_ICMP6
1403 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
1404 rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr,
1405 &multicast_address);
1406 }
1407#endif /* CHECKSUM_GEN_ICMP6 */
1408
1409 /* Send the packet out. */
1410 ND6_STATS_INC(nd6.xmit);
1411
1412 err = ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, &multicast_address,
1413 ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif);
1414 pbuf_free(p);
1415
1416 return err;
1417}
1418#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
1419
1427static s8_t
1428nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr)
1429{
1430 s8_t i;
1431 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
1432 if (ip6_addr_eq(ip6addr, &(neighbor_cache[i].next_hop_address))) {
1433 return i;
1434 }
1435 }
1436 return -1;
1437}
1438
1448static s8_t
1449nd6_new_neighbor_cache_entry(void)
1450{
1451 s8_t i;
1452 s8_t j;
1453 u32_t time;
1454
1455
1456 /* First, try to find an empty entry. */
1457 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
1458 if (neighbor_cache[i].state == ND6_NO_ENTRY) {
1459 return i;
1460 }
1461 }
1462
1463 /* We need to recycle an entry. in general, do not recycle if it is a router. */
1464
1465 /* Next, try to find a Stale entry. */
1466 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
1467 if ((neighbor_cache[i].state == ND6_STALE) &&
1468 (!neighbor_cache[i].isrouter)) {
1469 nd6_free_neighbor_cache_entry(i);
1470 return i;
1471 }
1472 }
1473
1474 /* Next, try to find a Probe entry. */
1475 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
1476 if ((neighbor_cache[i].state == ND6_PROBE) &&
1477 (!neighbor_cache[i].isrouter)) {
1478 nd6_free_neighbor_cache_entry(i);
1479 return i;
1480 }
1481 }
1482
1483 /* Next, try to find a Delayed entry. */
1484 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
1485 if ((neighbor_cache[i].state == ND6_DELAY) &&
1486 (!neighbor_cache[i].isrouter)) {
1487 nd6_free_neighbor_cache_entry(i);
1488 return i;
1489 }
1490 }
1491
1492 /* Next, try to find the oldest reachable entry. */
1493 time = 0xfffffffful;
1494 j = -1;
1495 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
1496 if ((neighbor_cache[i].state == ND6_REACHABLE) &&
1497 (!neighbor_cache[i].isrouter)) {
1498 if (neighbor_cache[i].counter.reachable_time < time) {
1499 j = i;
1500 time = neighbor_cache[i].counter.reachable_time;
1501 }
1502 }
1503 }
1504 if (j >= 0) {
1505 nd6_free_neighbor_cache_entry(j);
1506 return j;
1507 }
1508
1509 /* Next, find oldest incomplete entry without queued packets. */
1510 time = 0;
1511 j = -1;
1512 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
1513 if (
1514 (neighbor_cache[i].q == NULL) &&
1515 (neighbor_cache[i].state == ND6_INCOMPLETE) &&
1516 (!neighbor_cache[i].isrouter)) {
1517 if (neighbor_cache[i].counter.probes_sent >= time) {
1518 j = i;
1519 time = neighbor_cache[i].counter.probes_sent;
1520 }
1521 }
1522 }
1523 if (j >= 0) {
1524 nd6_free_neighbor_cache_entry(j);
1525 return j;
1526 }
1527
1528 /* Next, find oldest incomplete entry with queued packets. */
1529 time = 0;
1530 j = -1;
1531 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
1532 if ((neighbor_cache[i].state == ND6_INCOMPLETE) &&
1533 (!neighbor_cache[i].isrouter)) {
1534 if (neighbor_cache[i].counter.probes_sent >= time) {
1535 j = i;
1536 time = neighbor_cache[i].counter.probes_sent;
1537 }
1538 }
1539 }
1540 if (j >= 0) {
1541 nd6_free_neighbor_cache_entry(j);
1542 return j;
1543 }
1544
1545 /* No more entries to try. */
1546 return -1;
1547}
1548
1555static void
1556nd6_free_neighbor_cache_entry(s8_t i)
1557{
1558 if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) {
1559 return;
1560 }
1561 if (neighbor_cache[i].isrouter) {
1562 /* isrouter needs to be cleared before deleting a neighbor cache entry */
1563 return;
1564 }
1565
1566 /* Free any queued packets. */
1567 if (neighbor_cache[i].q != NULL) {
1568 nd6_free_q(neighbor_cache[i].q);
1569 neighbor_cache[i].q = NULL;
1570 }
1571
1572 neighbor_cache[i].state = ND6_NO_ENTRY;
1573 neighbor_cache[i].isrouter = 0;
1574 neighbor_cache[i].netif = NULL;
1575 neighbor_cache[i].counter.reachable_time = 0;
1576 ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address));
1577}
1578
1586static s16_t
1587nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr)
1588{
1589 s16_t i;
1590
1591 IP6_ADDR_ZONECHECK(ip6addr);
1592
1593 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
1594 if (ip6_addr_eq(ip6addr, &(destination_cache[i].destination_addr))) {
1595 return i;
1596 }
1597 }
1598 return -1;
1599}
1600
1608static s16_t
1609nd6_new_destination_cache_entry(void)
1610{
1611 s16_t i, j;
1612 u32_t age;
1613
1614 /* Find an empty entry. */
1615 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
1616 if (ip6_addr_isany(&(destination_cache[i].destination_addr))) {
1617 return i;
1618 }
1619 }
1620
1621 /* Find oldest entry. */
1622 age = 0;
1624 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
1625 if (destination_cache[i].age > age) {
1626 j = i;
1627 }
1628 }
1629
1630 return j;
1631}
1632
1639void
1640nd6_clear_destination_cache(void)
1641{
1642 int i;
1643
1644 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
1645 ip6_addr_set_any(&destination_cache[i].destination_addr);
1646 }
1647}
1648
1656static int
1657nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif)
1658{
1659 s8_t i;
1660
1661 /* Check to see if the address matches an on-link prefix. */
1662 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
1663 if ((prefix_list[i].netif == netif) &&
1664 (prefix_list[i].invalidation_timer > 0) &&
1665 ip6_addr_net_eq(ip6addr, &(prefix_list[i].prefix))) {
1666 return 1;
1667 }
1668 }
1669 /* Check to see if address prefix matches a manually configured (= static)
1670 * address. Static addresses have an implied /64 subnet assignment. Dynamic
1671 * addresses (from autoconfiguration) have no implied subnet assignment, and
1672 * are thus effectively /128 assignments. See RFC 5942 for more on this. */
1673 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
1674 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
1675 netif_ip6_addr_isstatic(netif, i) &&
1676 ip6_addr_net_eq(ip6addr, netif_ip6_addr(netif, i))) {
1677 return 1;
1678 }
1679 }
1680 return 0;
1681}
1682
1696static s8_t
1697nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif)
1698{
1699 struct netif *router_netif;
1700 s8_t i, j, valid_router;
1701 static s8_t last_router;
1702
1703 LWIP_UNUSED_ARG(ip6addr); /* @todo match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */
1704
1705 /* @todo: implement default router preference */
1706
1707 /* Look for valid routers. A reachable router is preferred. */
1708 valid_router = -1;
1709 for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
1710 /* Is the router netif both set and apppropriate? */
1711 if (default_router_list[i].neighbor_entry != NULL) {
1712 router_netif = default_router_list[i].neighbor_entry->netif;
1713 if ((router_netif != NULL) && (netif != NULL ? netif == router_netif :
1714 (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) {
1715 /* Is the router valid, i.e., reachable or probably reachable as per
1716 * RFC 4861 Sec. 6.3.6? Note that we will never return a router that
1717 * has no neighbor cache entry, due to the netif association tests. */
1718 if (default_router_list[i].neighbor_entry->state != ND6_INCOMPLETE) {
1719 /* Is the router known to be reachable? */
1720 if (default_router_list[i].neighbor_entry->state == ND6_REACHABLE) {
1721 return i; /* valid and reachable - done! */
1722 } else if (valid_router < 0) {
1723 valid_router = i; /* valid but not known to be reachable */
1724 }
1725 }
1726 }
1727 }
1728 }
1729 if (valid_router >= 0) {
1730 return valid_router;
1731 }
1732
1733 /* Look for any router for which we have any information at all. */
1734 /* last_router is used for round-robin selection of incomplete routers, as
1735 * recommended in RFC 4861 Sec. 6.3.6 point (2). Advance only when picking a
1736 * route, to select the same router as next-hop target in the common case. */
1737 if ((netif == NULL) && (++last_router >= LWIP_ND6_NUM_ROUTERS)) {
1738 last_router = 0;
1739 }
1740 i = last_router;
1741 for (j = 0; j < LWIP_ND6_NUM_ROUTERS; j++) {
1742 if (default_router_list[i].neighbor_entry != NULL) {
1743 router_netif = default_router_list[i].neighbor_entry->netif;
1744 if ((router_netif != NULL) && (netif != NULL ? netif == router_netif :
1745 (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) {
1746 return i;
1747 }
1748 }
1749 if (++i >= LWIP_ND6_NUM_ROUTERS) {
1750 i = 0;
1751 }
1752 }
1753
1754 /* no suitable router found. */
1755 return -1;
1756}
1757
1768struct netif *
1769nd6_find_route(const ip6_addr_t *ip6addr)
1770{
1771 struct netif *netif;
1772 s8_t i;
1773
1774 /* @todo decide if it makes sense to check the destination cache first */
1775
1776 /* Check if there is a matching on-link prefix. There may be multiple
1777 * matches. Pick the first one that is associated with a suitable netif. */
1778 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) {
1779 netif = prefix_list[i].netif;
1780 if ((netif != NULL) && ip6_addr_net_eq(&prefix_list[i].prefix, ip6addr) &&
1782 return netif;
1783 }
1784 }
1785
1786 /* No on-link prefix match. Find a router that can forward the packet. */
1787 i = nd6_select_router(ip6addr, NULL);
1788 if (i >= 0) {
1789 LWIP_ASSERT("selected router must have a neighbor entry",
1790 default_router_list[i].neighbor_entry != NULL);
1791 return default_router_list[i].neighbor_entry->netif;
1792 }
1793
1794 return NULL;
1795}
1796
1804static s8_t
1805nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif)
1806{
1807 s8_t i;
1808
1809 IP6_ADDR_ZONECHECK_NETIF(router_addr, netif);
1810
1811 /* Look for router. */
1812 for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
1813 if ((default_router_list[i].neighbor_entry != NULL) &&
1814 ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) &&
1815 ip6_addr_eq(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) {
1816 return i;
1817 }
1818 }
1819
1820 /* router not found. */
1821 return -1;
1822}
1823
1831static s8_t
1832nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif)
1833{
1834 s8_t router_index;
1835 s8_t free_router_index;
1836 s8_t neighbor_index;
1837
1838 IP6_ADDR_ZONECHECK_NETIF(router_addr, netif);
1839
1840 /* Do we have a neighbor entry for this router? */
1841 neighbor_index = nd6_find_neighbor_cache_entry(router_addr);
1842 if (neighbor_index < 0) {
1843 /* Create a neighbor entry for this router. */
1844 neighbor_index = nd6_new_neighbor_cache_entry();
1845 if (neighbor_index < 0) {
1846 /* Could not create neighbor entry for this router. */
1847 return -1;
1848 }
1849 ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr);
1850 neighbor_cache[neighbor_index].netif = netif;
1851 neighbor_cache[neighbor_index].q = NULL;
1852 neighbor_cache[neighbor_index].state = ND6_INCOMPLETE;
1853 neighbor_cache[neighbor_index].counter.probes_sent = 1;
1854 nd6_send_neighbor_cache_probe(&neighbor_cache[neighbor_index], ND6_SEND_FLAG_MULTICAST_DEST);
1855 }
1856
1857 /* Mark neighbor as router. */
1858 neighbor_cache[neighbor_index].isrouter = 1;
1859
1860 /* Look for empty entry. */
1861 free_router_index = LWIP_ND6_NUM_ROUTERS;
1862 for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) {
1863 /* check if router already exists (this is a special case for 2 netifs on the same subnet
1864 - e.g. wifi and cable) */
1865 if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){
1866 return router_index;
1867 }
1868 if (default_router_list[router_index].neighbor_entry == NULL) {
1869 /* remember lowest free index to create a new entry */
1870 free_router_index = router_index;
1871 }
1872 }
1873 if (free_router_index < LWIP_ND6_NUM_ROUTERS) {
1874 default_router_list[free_router_index].neighbor_entry = &(neighbor_cache[neighbor_index]);
1875 return free_router_index;
1876 }
1877
1878 /* Could not create a router entry. */
1879
1880 /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */
1881 neighbor_cache[neighbor_index].isrouter = 0;
1882
1883 /* router not found. */
1884 return -1;
1885}
1886
1894static s8_t
1895nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif)
1896{
1897 s8_t i;
1898
1899 /* Look for prefix in list. */
1900 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) {
1901 if ((ip6_addr_net_eq(&(prefix_list[i].prefix), prefix)) &&
1902 (prefix_list[i].netif == netif)) {
1903 return i;
1904 }
1905 }
1906
1907 /* Entry not available. */
1908 return -1;
1909}
1910
1918static s8_t
1919nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif)
1920{
1921 s8_t i;
1922
1923 /* Create new entry. */
1924 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) {
1925 if ((prefix_list[i].netif == NULL) ||
1926 (prefix_list[i].invalidation_timer == 0)) {
1927 /* Found empty prefix entry. */
1928 prefix_list[i].netif = netif;
1929 ip6_addr_set(&(prefix_list[i].prefix), prefix);
1930 return i;
1931 }
1932 }
1933
1934 /* Entry not available. */
1935 return -1;
1936}
1937
1950static s8_t
1951nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif)
1952{
1953#ifdef LWIP_HOOK_ND6_GET_GW
1954 const ip6_addr_t *next_hop_addr;
1955#endif /* LWIP_HOOK_ND6_GET_GW */
1956 s8_t i;
1957 s16_t dst_idx;
1958 struct nd6_destination_cache_entry *dest;
1959
1960 IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif);
1961
1962#if LWIP_NETIF_HWADDRHINT
1963 if (netif->hints != NULL) {
1964 /* per-pcb cached entry was given */
1965 netif_addr_idx_t addr_hint = netif->hints->addr_hint;
1966 if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) {
1967 nd6_cached_destination_index = addr_hint;
1968 }
1969 }
1970#endif /* LWIP_NETIF_HWADDRHINT */
1971
1972 LWIP_ASSERT("sane cache index", nd6_cached_destination_index < LWIP_ND6_NUM_DESTINATIONS);
1973
1974 /* Look for ip6addr in destination cache. */
1975 dest = &destination_cache[nd6_cached_destination_index];
1976 if (ip6_addr_eq(ip6addr, &dest->destination_addr)) {
1977 /* the cached entry index is the right one! */
1978 /* do nothing. */
1979 ND6_STATS_INC(nd6.cachehit);
1980 } else {
1981 /* Search destination cache. */
1982 dst_idx = nd6_find_destination_cache_entry(ip6addr);
1983 if (dst_idx >= 0) {
1984 /* found destination entry. make it our new cached index. */
1985 LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX);
1986 nd6_cached_destination_index = (netif_addr_idx_t)dst_idx;
1987 dest = &destination_cache[dst_idx];
1988 } else {
1989 /* Not found. Create a new destination entry. */
1990 dst_idx = nd6_new_destination_cache_entry();
1991 if (dst_idx >= 0) {
1992 /* got new destination entry. make it our new cached index. */
1993 LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX);
1994 nd6_cached_destination_index = (netif_addr_idx_t)dst_idx;
1995 dest = &destination_cache[dst_idx];
1996 } else {
1997 /* Could not create a destination cache entry. */
1998 return ERR_MEM;
1999 }
2000
2001 /* Copy dest address to destination cache. */
2002 ip6_addr_set(&dest->destination_addr, ip6addr);
2003
2004 /* Now find the next hop. is it a neighbor? */
2005 if (ip6_addr_islinklocal(ip6addr) ||
2006 nd6_is_prefix_in_netif(ip6addr, netif)) {
2007 /* Destination in local link. */
2008 dest->pmtu = netif_mtu6(netif);
2009 ip6_addr_copy(dest->next_hop_addr, dest->destination_addr);
2010#ifdef LWIP_HOOK_ND6_GET_GW
2011 } else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) {
2012 /* Next hop for destination provided by hook function. */
2013 dest->pmtu = netif->mtu;
2014 ip6_addr_set(&dest->next_hop_addr, next_hop_addr);
2015#endif /* LWIP_HOOK_ND6_GET_GW */
2016 } else {
2017 /* We need to select a router. */
2018 i = nd6_select_router(ip6addr, netif);
2019 if (i < 0) {
2020 /* No router found. */
2021 ip6_addr_set_any(&dest->destination_addr);
2022 return ERR_RTE;
2023 }
2024 dest->pmtu = netif_mtu6(netif); /* Start with netif mtu, correct through ICMPv6 if necessary */
2025 ip6_addr_copy(dest->next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address);
2026 }
2027 }
2028#if LWIP_NETIF_HWADDRHINT
2029 if (netif->hints != NULL) {
2030 /* per-pcb cached entry was given */
2031 netif->hints->addr_hint = nd6_cached_destination_index;
2032 }
2033#endif /* LWIP_NETIF_HWADDRHINT */
2034 }
2035
2036 /* Look in neighbor cache for the next-hop address. */
2037 if (ip6_addr_eq(&dest->next_hop_addr,
2038 &(neighbor_cache[dest->cached_neighbor_idx].next_hop_address))) {
2039 /* Cache hit. */
2040 /* Do nothing. */
2041 ND6_STATS_INC(nd6.cachehit);
2042 } else {
2043 i = nd6_find_neighbor_cache_entry(&dest->next_hop_addr);
2044 if (i >= 0) {
2045 /* Found a matching record, make it new cached entry. */
2046 dest->cached_neighbor_idx = i;
2047 } else {
2048 /* Neighbor not in cache. Make a new entry. */
2049 i = nd6_new_neighbor_cache_entry();
2050 if (i >= 0) {
2051 /* got new neighbor entry. make it our new cached index. */
2052 dest->cached_neighbor_idx = i;
2053 } else {
2054 /* Could not create a neighbor cache entry. */
2055 return ERR_MEM;
2056 }
2057
2058 /* Initialize fields. */
2059 ip6_addr_copy(neighbor_cache[i].next_hop_address, dest->next_hop_addr);
2060 neighbor_cache[i].isrouter = 0;
2061 neighbor_cache[i].netif = netif;
2062 neighbor_cache[i].state = ND6_INCOMPLETE;
2063 neighbor_cache[i].counter.probes_sent = 1;
2064 nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST);
2065 }
2066 }
2067
2068 /* Reset this destination's age. */
2069 dest->age = 0;
2070
2071 return dest->cached_neighbor_idx;
2072}
2073
2081static err_t
2082nd6_queue_packet(s8_t neighbor_index, struct pbuf *q)
2083{
2085 struct pbuf *p;
2086 int copy_needed = 0;
2087#if LWIP_ND6_QUEUEING
2088 struct nd6_q_entry *new_entry, *r;
2089#endif /* LWIP_ND6_QUEUEING */
2090
2091 if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) {
2092 return ERR_ARG;
2093 }
2094
2095 /* IF q includes a pbuf that must be copied, we have to copy the whole chain
2096 * into a new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */
2097 p = q;
2098 while (p) {
2099 if (PBUF_NEEDS_COPY(p)) {
2100 copy_needed = 1;
2101 break;
2102 }
2103 p = p->next;
2104 }
2105 if (copy_needed) {
2106 /* copy the whole packet into new pbufs */
2108 while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) {
2109 /* Free oldest packet (as per RFC recommendation) */
2110#if LWIP_ND6_QUEUEING
2111 r = neighbor_cache[neighbor_index].q;
2112 neighbor_cache[neighbor_index].q = r->next;
2113 r->next = NULL;
2114 nd6_free_q(r);
2115#else /* LWIP_ND6_QUEUEING */
2116 pbuf_free(neighbor_cache[neighbor_index].q);
2117 neighbor_cache[neighbor_index].q = NULL;
2118#endif /* LWIP_ND6_QUEUEING */
2120 }
2121 } else {
2122 /* referencing the old pbuf is enough */
2123 p = q;
2124 pbuf_ref(p);
2125 }
2126 /* packet was copied/ref'd? */
2127 if (p != NULL) {
2128 /* queue packet ... */
2129#if LWIP_ND6_QUEUEING
2130 /* allocate a new nd6 queue entry */
2131 new_entry = NULL;
2132 if (nd6_queue_size < MEMP_NUM_ND6_QUEUE) {
2133 new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE);
2134 nd6_queue_size++;
2135 }
2136 if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) {
2137 /* Free oldest packet (as per RFC recommendation) */
2138 r = neighbor_cache[neighbor_index].q;
2139 neighbor_cache[neighbor_index].q = r->next;
2140 r->next = NULL;
2141 nd6_free_q(r);
2142 new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE);
2143 nd6_queue_size++;
2144 }
2145 if (new_entry != NULL) {
2146 new_entry->next = NULL;
2147 new_entry->p = p;
2148 if (neighbor_cache[neighbor_index].q != NULL) {
2149 /* queue was already existent, append the new entry to the end */
2150 r = neighbor_cache[neighbor_index].q;
2151 while (r->next != NULL) {
2152 r = r->next;
2153 }
2154 r->next = new_entry;
2155 } else {
2156 /* queue did not exist, first item in queue */
2157 neighbor_cache[neighbor_index].q = new_entry;
2158 }
2159 LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index));
2160 result = ERR_OK;
2161 } else {
2162 /* the pool MEMP_ND6_QUEUE is empty */
2163 pbuf_free(p);
2164 LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p));
2165 /* { result == ERR_MEM } through initialization */
2166 }
2167#else /* LWIP_ND6_QUEUEING */
2168 /* Queue a single packet. If an older packet is already queued, free it as per RFC. */
2169 if (neighbor_cache[neighbor_index].q != NULL) {
2170 pbuf_free(neighbor_cache[neighbor_index].q);
2171 }
2172 neighbor_cache[neighbor_index].q = p;
2173 LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index));
2174 result = ERR_OK;
2175#endif /* LWIP_ND6_QUEUEING */
2176 } else {
2177 LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q));
2178 /* { result == ERR_MEM } through initialization */
2179 }
2180
2181 return result;
2182}
2183
2184#if LWIP_ND6_QUEUEING
2190static void
2191nd6_free_q(struct nd6_q_entry *q)
2192{
2193 struct nd6_q_entry *r;
2194 LWIP_ASSERT("q != NULL", q != NULL);
2195 LWIP_ASSERT("q->p != NULL", q->p != NULL);
2196 while (q) {
2197 r = q;
2198 q = q->next;
2199 LWIP_ASSERT("r->p != NULL", (r->p != NULL));
2200 pbuf_free(r->p);
2201 memp_free(MEMP_ND6_QUEUE, r);
2202 nd6_queue_size--;
2203 }
2204}
2205#endif /* LWIP_ND6_QUEUEING */
2206
2212static void
2213nd6_send_q(s8_t i)
2214{
2215 struct ip6_hdr *ip6hdr;
2216 ip6_addr_t dest;
2217#if LWIP_ND6_QUEUEING
2218 struct nd6_q_entry *q;
2219#endif /* LWIP_ND6_QUEUEING */
2220
2221 if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) {
2222 return;
2223 }
2224
2225#if LWIP_ND6_QUEUEING
2226 while (neighbor_cache[i].q != NULL) {
2227 /* remember first in queue */
2228 q = neighbor_cache[i].q;
2229 /* pop first item off the queue */
2230 neighbor_cache[i].q = q->next;
2231 /* Get ipv6 header. */
2232 ip6hdr = (struct ip6_hdr *)(q->p->payload);
2233 /* Create an aligned copy. */
2234 ip6_addr_copy_from_packed(dest, ip6hdr->dest);
2235 /* Restore the zone, if applicable. */
2236 ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif);
2237 /* send the queued IPv6 packet */
2238 (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, &dest);
2239 /* free the queued IP packet */
2240 pbuf_free(q->p);
2241 /* now queue entry can be freed */
2242 memp_free(MEMP_ND6_QUEUE, q);
2243 nd6_queue_size--;
2244 }
2245#else /* LWIP_ND6_QUEUEING */
2246 if (neighbor_cache[i].q != NULL) {
2247 /* Get ipv6 header. */
2248 ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload);
2249 /* Create an aligned copy. */
2250 ip6_addr_copy_from_packed(dest, ip6hdr->dest);
2251 /* Restore the zone, if applicable. */
2252 ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif);
2253 /* send the queued IPv6 packet */
2254 (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, &dest);
2255 /* free the queued IP packet */
2256 pbuf_free(neighbor_cache[i].q);
2257 neighbor_cache[i].q = NULL;
2258 }
2259#endif /* LWIP_ND6_QUEUEING */
2260}
2261
2284err_t
2285nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp)
2286{
2287 s8_t i;
2288
2289 /* Get next hop record. */
2290 i = nd6_get_next_hop_entry(ip6addr, netif);
2291 if (i < 0) {
2292 /* failed to get a next hop neighbor record. */
2293 return i;
2294 }
2295
2296 /* Now that we have a destination record, send or queue the packet. */
2297 if (neighbor_cache[i].state == ND6_STALE) {
2298 /* Switch to delay state. */
2299 neighbor_cache[i].state = ND6_DELAY;
2300 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
2301 }
2302 /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */
2303 if ((neighbor_cache[i].state == ND6_REACHABLE) ||
2304 (neighbor_cache[i].state == ND6_DELAY) ||
2305 (neighbor_cache[i].state == ND6_PROBE)) {
2306
2307 /* Tell the caller to send out the packet now. */
2308 *hwaddrp = neighbor_cache[i].lladdr;
2309 return ERR_OK;
2310 }
2311
2312 /* We should queue packet on this interface. */
2313 *hwaddrp = NULL;
2314 return nd6_queue_packet(i, q);
2315}
2316
2317
2325u16_t
2326nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif)
2327{
2328 s16_t i;
2329
2330 i = nd6_find_destination_cache_entry(ip6addr);
2331 if (i >= 0) {
2332 if (destination_cache[i].pmtu > 0) {
2333 return destination_cache[i].pmtu;
2334 }
2335 }
2336
2337 if (netif != NULL) {
2338 return netif_mtu6(netif);
2339 }
2340
2341 return IP6_MIN_MTU_LENGTH; /* Minimum MTU */
2342}
2343
2344
2345#if LWIP_ND6_TCP_REACHABILITY_HINTS
2355void
2356nd6_reachability_hint(const ip6_addr_t *ip6addr)
2357{
2358 s8_t i;
2359 s16_t dst_idx;
2360 struct nd6_destination_cache_entry *dest;
2361
2362 /* Find destination in cache. */
2363 if (ip6_addr_eq(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) {
2364 dst_idx = nd6_cached_destination_index;
2365 ND6_STATS_INC(nd6.cachehit);
2366 } else {
2367 dst_idx = nd6_find_destination_cache_entry(ip6addr);
2368 }
2369 if (dst_idx < 0) {
2370 return;
2371 }
2372
2373 /* Find next hop neighbor in cache. */
2374 dest = &destination_cache[dst_idx];
2375 if (ip6_addr_eq(&dest->next_hop_addr, &(neighbor_cache[dest->cached_neighbor_idx].next_hop_address))) {
2376 i = dest->cached_neighbor_idx;
2377 ND6_STATS_INC(nd6.cachehit);
2378 } else {
2379 i = nd6_find_neighbor_cache_entry(&dest->next_hop_addr);
2380 }
2381 if (i < 0) {
2382 return;
2383 }
2384
2385 /* For safety: don't set as reachable if we don't have a LL address yet. Misuse protection. */
2386 if (neighbor_cache[i].state == ND6_INCOMPLETE || neighbor_cache[i].state == ND6_NO_ENTRY) {
2387 return;
2388 }
2389
2390 /* Set reachability state. */
2391 neighbor_cache[i].state = ND6_REACHABLE;
2392 neighbor_cache[i].counter.reachable_time = reachable_time;
2393}
2394#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
2395
2401void
2402nd6_cleanup_netif(struct netif *netif)
2403{
2404 u8_t i;
2405 s8_t router_index;
2406 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
2407 if (prefix_list[i].netif == netif) {
2408 prefix_list[i].netif = NULL;
2409 }
2410 }
2411 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
2412 if (neighbor_cache[i].netif == netif) {
2413 for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) {
2414 if (default_router_list[router_index].neighbor_entry == &neighbor_cache[i]) {
2415 default_router_list[router_index].neighbor_entry = NULL;
2416 default_router_list[router_index].flags = 0;
2417 }
2418 }
2419 neighbor_cache[i].isrouter = 0;
2420 nd6_free_neighbor_cache_entry(i);
2421 }
2422 }
2423 /* Clear the destination cache, since many entries may now have become
2424 * invalid for one of several reasons. As destination cache entries have no
2425 * netif association, use a sledgehammer approach (this can be improved). */
2426 nd6_clear_destination_cache();
2427}
2428
2429#if LWIP_IPV6_MLD
2438void
2439nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state)
2440{
2441 u8_t old_state, old_member, new_member;
2442
2443 old_state = netif_ip6_addr_state(netif, addr_idx);
2444
2445 /* Determine whether we were, and should be, a member of the solicited-node
2446 * multicast group for this address. For tentative addresses, the group is
2447 * not joined until the address enters the TENTATIVE_1 (or VALID) state. */
2448 old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_DUPLICATED && old_state != IP6_ADDR_TENTATIVE);
2449 new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_DUPLICATED && new_state != IP6_ADDR_TENTATIVE);
2450
2451 if (old_member != new_member) {
2452 ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]);
2453 ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif);
2454
2455 if (new_member) {
2456 mld6_joingroup_netif(netif, &multicast_address);
2457 } else {
2458 mld6_leavegroup_netif(netif, &multicast_address);
2459 }
2460 }
2461}
2462#endif /* LWIP_IPV6_MLD */
2463
2465void
2466nd6_restart_netif(struct netif *netif)
2467{
2468#if LWIP_IPV6_SEND_ROUTER_SOLICIT
2469 /* Send Router Solicitation messages (see RFC 4861, ch. 6.3.7). */
2471#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
2472}
2473
2474#endif /* LWIP_IPV6 */
static int state
Definition: maze.c:121
#define lwip_htons(x)
Definition: def.h:86
#define LWIP_MIN(x, y)
Definition: def.h:66
#define lwip_htonl(x)
Definition: def.h:88
#define NULL
Definition: types.h:112
#define S16_F
Definition: cc.h:20
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
#define ERR_MEM
Definition: fontsub.h:52
GLdouble s
Definition: gl.h:2039
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLdouble n
Definition: glext.h:7729
GLuint buffer
Definition: glext.h:5915
GLintptr offset
Definition: glext.h:5920
GLbitfield flags
Definition: glext.h:7161
GLenum const GLvoid * addr
Definition: glext.h:9621
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLuint num
Definition: glext.h:9618
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
uint32_t u32_t
Definition: arch.h:129
uint8_t u8_t
Definition: arch.h:125
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:373
uint16_t u16_t
Definition: arch.h:127
int8_t s8_t
Definition: arch.h:126
int16_t s16_t
Definition: arch.h:128
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:55
#define LWIP_DBG_TRACE
Definition: debug.h:83
s8_t err_t
Definition: err.h:96
@ ERR_BUF
Definition: err.h:59
@ ERR_RTE
Definition: err.h:63
@ ERR_OK
Definition: err.h:55
@ ERR_ARG
Definition: err.h:88
@ IPADDR_TYPE_V6
Definition: ip_addr.h:58
#define IP6_DEBUG
Definition: opt.h:3554
#define DNS_MAX_SERVERS
Definition: opt.h:1153
#define LWIP_IPV6_NUM_ADDRESSES
Definition: opt.h:2487
#define LWIP_IPV6_DUP_DETECT_ATTEMPTS
Definition: opt.h:2541
#define SMEMCPY(dst, src, len)
Definition: opt.h:145
#define LWIP_ND6_REACHABLE_TIME
Definition: opt.h:2689
#define LWIP_ND6_DELAY_FIRST_PROBE_TIME
Definition: opt.h:2704
#define LWIP_ND6_RETRANS_TIMER
Definition: opt.h:2696
#define LWIP_ND6_NUM_ROUTERS
Definition: opt.h:2651
#define LWIP_ND6_MAX_MULTICAST_SOLICIT
Definition: opt.h:2659
#define LWIP_ND6_NUM_NEIGHBORS
Definition: opt.h:2630
#define MEMP_NUM_ND6_QUEUE
Definition: opt.h:2623
#define LWIP_ND6_NUM_DESTINATIONS
Definition: opt.h:2637
#define LWIP_ND6_NUM_PREFIXES
Definition: opt.h:2644
#define netif_is_up(netif)
Definition: netif.h:479
u8_t pbuf_get_at(const struct pbuf *p, u16_t offset)
Definition: pbuf.c:1402
void pbuf_ref(struct pbuf *p)
Definition: pbuf.c:831
int pbuf_try_get_at(const struct pbuf *p, u16_t offset)
Definition: pbuf.c:1420
#define PBUF_NEEDS_COPY(p)
Definition: pbuf.h:72
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:224
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1058
struct pbuf * pbuf_clone(pbuf_layer layer, pbuf_type type, struct pbuf *p)
Definition: pbuf.c:1337
@ PBUF_RAM
Definition: pbuf.h:152
@ PBUF_LINK
Definition: pbuf.h:102
@ PBUF_IP
Definition: pbuf.h:97
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:356
#define ip_addr_eq(addr1, addr2)
Definition: ip_addr.h:374
ip6_addr_t ip_addr_t
Definition: ip_addr.h:344
#define IP_SET_TYPE_VAL(ipaddr, iptype)
Definition: ip_addr.h:352
#define ip_addr_copy_from_ip6(dest, src)
Definition: ip_addr.h:361
uint32_t entry
Definition: isohybrid.c:63
if(dx< 0)
Definition: linetemp.h:194
#define MEMCPY(DST, SRC, BYTES)
Definition: macros.h:231
void * memp_malloc(memp_t type)
Definition: memp.c:337
void memp_free(memp_t type, void *mem)
Definition: memp.c:420
__u16 time
Definition: mkdosfs.c:8
#define htonl(x)
Definition: module.h:214
static char * dest
Definition: rtl.c:135
#define NETIF_ADDR_IDX_MAX
Definition: netif.h:248
#define netif_is_link_up(netif)
Definition: netif.h:491
#define NETIF_FOREACH(netif)
Definition: netif.h:424
u8_t netif_addr_idx_t
Definition: netif.h:247
#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag)
Definition: netif.h:416
@ ICMP6_TYPE_NS
Definition: icmp6.h:78
@ ICMP6_TYPE_RD
Definition: icmp6.h:82
@ ICMP6_TYPE_PTB
Definition: icmp6.h:51
@ ICMP6_TYPE_NA
Definition: icmp6.h:80
@ ICMP6_TYPE_RS
Definition: icmp6.h:74
@ ICMP6_TYPE_RA
Definition: icmp6.h:76
#define IP6_MIN_MTU_LENGTH
Definition: ip6.h:47
#define IP6H_HOPLIM(hdr)
Definition: ip6.h:105
typedefPACK_STRUCT_END struct ip6_addr_packed ip6_addr_p_t
Definition: ip6.h:62
#define IP6_NEXTH_ICMP6
Definition: ip6.h:72
#define IP6_HLEN
Definition: ip6.h:64
#define ND6_OPTION_TYPE_PREFIX_INFO
Definition: nd6.h:171
#define ND6_RA_FLAG_OTHER_CONFIG
Definition: nd6.h:107
#define ND6_OPTION_TYPE_RDNSS
Definition: nd6.h:251
#define ND6_FLAG_OVERRIDE
Definition: nd6.h:86
#define ND6_PREFIX_FLAG_ON_LINK
Definition: nd6.h:172
#define ND6_OPTION_TYPE_SOURCE_LLADDR
Definition: nd6.h:154
#define ND6_OPTION_TYPE_TARGET_LLADDR
Definition: nd6.h:155
#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG
Definition: nd6.h:106
#define ND6_OPTION_TYPE_MTU
Definition: nd6.h:215
#define ND6_PREFIX_FLAG_AUTONOMOUS
Definition: nd6.h:173
#define ND6_FLAG_SOLICITED
Definition: nd6.h:85
#define SIZEOF_RDNSS_OPTION_BASE
Definition: nd6.h:268
#define ND6_OPTION_TYPE_ROUTE_INFO
Definition: nd6.h:232
#define err(...)
msg_type
Definition: rpc_msg.h:77
static void accepted(enum accept_stat, struct rpc_err *)
Definition: rpc_prot.c:280
#define ND6_STATS_INC(x)
Definition: stats.h:460
Definition: ip6.h:82
Definition: nd6.h:71
Definition: netif.h:269
void * state
Definition: netif.h:332
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]
Definition: netif.h:350
u16_t mtu
Definition: netif.h:344
u8_t hwaddr_len
Definition: netif.h:352
Definition: nd6.h:53
Definition: pbuf.h:186
Definition: nd6.h:118
Definition: nd6.h:93
Character const *const prefix
Definition: tempnam.cpp:195