8 * Copyright (c) 2010 Inico Technologies Ltd.
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * This file is part of the lwIP TCP/IP stack.
35 * Author: Ivan Delamer <delamer@inicotech.com>
38 * Please coordinate changes and requests with Ivan Delamer
39 * <delamer@inicotech.com>
44 #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
48 #include "lwip/netif.h"
51 #include "lwip/ip6_addr.h"
52 #include "lwip/ip6_frag.h"
53 #include "lwip/icmp6.h"
56 #include "lwip/priv/tcp_priv.h"
57 #include "lwip/dhcp6.h"
59 #include "lwip/mld6.h"
60 #include "lwip/debug.h"
61 #include "lwip/stats.h"
63 #if LWIP_IPV6_ROUTE_TABLE_SUPPORT
64 #include "lwip/ip6_route_table.h"
67 #ifdef LWIP_HOOK_FILENAME
68 #include LWIP_HOOK_FILENAME
71 #if LWIP_IP_DEBUG_TARGET
72 extern int debug_target_match(int is_ipv6, ipX_addr_t *src, ipX_addr_t *dest);
76 * Finds the appropriate network interface for a given IPv6 address. It tries to select
77 * a netif following a sequence of heuristics:
78 * 1) if there is only 1 netif, return it
79 * 2) if the destination is a link-local address, try to match the src address to a netif.
80 * this is a tricky case because with multiple netifs, link-local addresses only have
81 * meaning within a particular subnet/link.
82 * #if LWIP_IPV6_ROUTE_TABLE_SUPPORT
83 * 3) tries to find a netif with a configured address matching the destination or look up
84 * a route table for potential matching routes.
86 * 3) tries to match the destination subnet to a configured address
88 * 4) tries to find a router-announced route
89 * #if !LWIP_IPV6_ROUTE_TABLE_SUPPORT
90 * 5) tries to match the source address to the netif
92 * 6) returns the default netif, if configured
94 * @param src the source IPv6 address, if known
95 * @param dest the destination IPv6 address for which to find the route
96 * @return the netif on which to send to reach dest
99 ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
101 struct netif *netif = NULL;
104 /* If single netif configuration, fast return. */
105 if ((netif_list != NULL) && (netif_list->next == NULL)) {
106 if (!netif_is_up(netif_list) || !netif_is_link_up(netif_list)) {
112 /* Special processing for link-local addresses. */
113 if (ip6_addr_islinklocal(dest)) {
114 if (ip6_addr_isany(src)) {
115 /* Use default netif, if Up. */
116 if (netif_default == NULL || !netif_is_up(netif_default) ||
117 !netif_is_link_up(netif_default)) {
120 return netif_default;
123 /* Try to find the netif for the source address. */
124 for (netif = netif_list; netif != NULL; netif = netif->next) {
125 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
126 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
127 ip6_addr_cmp(src, netif_ip6_addr(netif, i))) {
133 /* netif not found, use default netif, if up */
134 if (netif_default == NULL || !netif_is_up(netif_default) ||
135 !netif_is_link_up(netif_default)) {
138 return netif_default;
141 /* we come here for non-link-local addresses */
142 #ifdef LWIP_HOOK_IP6_ROUTE
143 netif = LWIP_HOOK_IP6_ROUTE(src, dest);
149 #if LWIP_IPV6_ROUTE_TABLE_SUPPORT
150 /* See if the destination subnet matches a configured address. In accordance
151 * with RFC 5942, dynamically configured addresses do not have an implied
152 * local subnet, and thus should be considered /128 assignments. However, as
153 * such, the destination address may still match a local address, and so we
154 * still need to check for exact matches here. By (lwIP) policy, statically
155 * configured addresses do always have an implied local /64 subnet. */
156 for (netif = netif_list; netif != NULL; netif = netif->next) {
157 if (!netif_is_up(netif) || !netif_is_link_up(netif)) {
160 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
161 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
162 ip6_addr_netcmp(dest, netif_ip6_addr(netif, i)) &&
163 (netif_ip6_addr_isstatic(netif, i) ||
164 ip6_addr_nethostcmp(dest, netif_ip6_addr(netif, i)))) {
170 /* Lookup route table */
171 if ((netif = ip6_static_route(src, dest)) != NULL)
175 #endif /* LWIP_IPV6_ROUTE_TABLE_SUPPORT */
177 #if LWIP_IPV6_ROUTER_SUPPORT
178 /* Get the netif for a suitable router-announced route. */
179 netif = nd6_find_route(dest);
183 #endif /* LWIP_IPV6_ROUTER_SUPPORT */
185 #if !LWIP_IPV6_ROUTE_TABLE_SUPPORT
186 /* try with the netif that matches the source address. */
187 if (!ip6_addr_isany(src)) {
188 for (netif = netif_list; netif != NULL; netif = netif->next) {
189 if (!netif_is_up(netif) || !netif_is_link_up(netif)) {
192 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
193 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
194 ip6_addr_cmp(src, netif_ip6_addr(netif, i))) {
200 #endif /* !LWIP_IPV6_ROUTE_TABLE_SUPPORT */
202 #if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF
203 /* loopif is disabled, loopback traffic is passed through any netif */
204 if (ip6_addr_isloopback(dest)) {
205 /* don't check for link on loopback traffic */
206 if (netif_default != NULL && netif_is_up(netif_default)) {
207 return netif_default;
209 /* default netif is not up, just use any netif for loopback traffic */
210 for (netif = netif_list; netif != NULL; netif = netif->next) {
211 if (netif_is_up(netif)) {
217 #endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */
219 /* no matching netif found, use default netif, if up */
220 if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default)) {
223 return netif_default;
228 * Select the best IPv6 source address for a given destination IPv6 address.
230 * This implementation follows RFC 6724 Sec. 5 to the following extent:
231 * - Rules 1, 2, 3: fully implemented
232 * - Rules 4, 5, 5.5: not applicable
233 * - Rule 6: not implemented
234 * - Rule 7: not applicable
235 * - Rule 8: limited to "prefer /64 subnet match over non-match"
237 * For Rule 2, we deliberately deviate from RFC 6724 Sec. 3.1 by considering
238 * ULAs to be of smaller scope than global addresses, to avoid that a preferred
239 * ULA is picked over a deprecated global address when given a global address
240 * as destination, as that would likely result in broken two-way communication.
242 * As long as temporary addresses are not supported (as used in Rule 7), a
243 * proper implementation of Rule 8 would obviate the need to implement Rule 6.
245 * @param netif the netif on which to send a packet
246 * @param dest the destination we are trying to reach
247 * @return the most suitable source address to use, or NULL if no suitable
248 * source address is found
251 ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest)
253 const ip_addr_t *best_addr;
254 const ip6_addr_t *cand_addr;
255 s8_t dest_scope, cand_scope, best_scope;
256 u8_t i, cand_pref, best_pref, cand_bits, best_bits;
258 /* Start by determining the scope of the given destination address. These
259 * tests are hopefully (roughly) in order of likeliness to match. */
260 if (ip6_addr_isglobal(dest)) {
261 dest_scope = IP6_MULTICAST_SCOPE_GLOBAL;
262 } else if (ip6_addr_islinklocal(dest) || ip6_addr_isloopback(dest)) {
263 dest_scope = IP6_MULTICAST_SCOPE_LINK_LOCAL;
264 } else if (ip6_addr_isuniquelocal(dest)) {
265 dest_scope = IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL;
266 } else if (ip6_addr_ismulticast(dest)) {
267 dest_scope = ip6_addr_multicast_scope(dest);
268 } else if (ip6_addr_issitelocal(dest)) {
269 dest_scope = IP6_MULTICAST_SCOPE_SITE_LOCAL;
271 /* no match, consider scope global */
272 dest_scope = IP6_MULTICAST_SCOPE_GLOBAL;
277 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
278 /* Consider only valid (= preferred and deprecated) addresses. */
279 if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
282 /* Determine the scope of this candidate address. Same ordering idea. */
283 cand_addr = netif_ip6_addr(netif, i);
285 if (ip6_addr_isany(cand_addr) || ip6_addr_ismulticast(cand_addr)) {
286 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("unspecified / multicast address assigned as unicast address on %c%c%u\n", netif->name[0], netif->name[1], netif->num));
290 if (ip6_addr_isglobal(cand_addr)) {
291 cand_scope = IP6_MULTICAST_SCOPE_GLOBAL;
292 } else if (ip6_addr_islinklocal(cand_addr)) {
293 cand_scope = IP6_MULTICAST_SCOPE_LINK_LOCAL;
294 } else if (ip6_addr_isuniquelocal(cand_addr)) {
295 cand_scope = IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL;
296 } else if (ip6_addr_issitelocal(cand_addr)) {
297 cand_scope = IP6_MULTICAST_SCOPE_SITE_LOCAL;
299 /* no match, treat as low-priority global scope */
300 cand_scope = IP6_MULTICAST_SCOPE_RESERVEDF;
302 cand_pref = ip6_addr_ispreferred(netif_ip6_addr_state(netif, i));
303 /* @todo compute the actual common bits, for longest matching prefix. */
304 if (ip6_addr_netcmp(cand_addr, dest)) {
307 else if (ip6_addr_net48cmp(cand_addr, dest)) {
313 if (cand_bits == 64 && ip6_addr_nethostcmp(cand_addr, dest)) {
314 return netif_ip_addr6(netif, i); /* Rule 1 */
316 if ((best_addr == NULL) || /* no alternative yet */
317 ((cand_scope < best_scope) && (cand_scope >= dest_scope)) ||
318 ((cand_scope > best_scope) && (best_scope < dest_scope)) || /* Rule 2 */
319 ((cand_scope == best_scope) && ((cand_pref > best_pref) || /* Rule 3 */
320 ((cand_pref == best_pref) && (cand_bits > best_bits))))) { /* Rule 8 */
321 /* We found a new "winning" candidate. */
322 best_addr = netif_ip_addr6(netif, i);
323 best_scope = cand_scope;
324 best_pref = cand_pref;
325 best_bits = cand_bits;
329 return best_addr; /* may be NULL */
332 #if LWIP_IPV6_FORWARD
334 * Forwards an IPv6 packet. It finds an appropriate route for the
335 * packet, decrements the HL value of the packet, and outputs
336 * the packet on the appropriate interface.
338 * @param p the packet to forward (p->payload points to IP header)
339 * @param iphdr the IPv6 header of the input packet
340 * @param inp the netif on which this packet was received
343 ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
347 /* do not forward link-local or loopback addresses */
348 if (ip6_addr_islinklocal(ip6_current_dest_addr()) ||
349 ip6_addr_isloopback(ip6_current_dest_addr())) {
350 LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n"));
351 IP6_STATS_INC(ip6.rterr);
352 IP6_STATS_INC(ip6.drop);
356 /* Find network interface where to forward this IP packet to. */
357 netif = ip6_route(IP6_ADDR_ANY6, ip6_current_dest_addr());
359 LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
360 IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
361 IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
362 IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
363 IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
364 IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
365 IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
366 IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
367 IP6_ADDR_BLOCK8(ip6_current_dest_addr())));
369 /* Don't send ICMP messages in response to ICMP messages */
370 if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
371 icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE);
373 #endif /* LWIP_ICMP6 */
374 IP6_STATS_INC(ip6.rterr);
375 IP6_STATS_INC(ip6.drop);
378 /* Do not forward packets onto the same network interface on which
381 LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n"));
382 IP6_STATS_INC(ip6.rterr);
383 IP6_STATS_INC(ip6.drop);
388 IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1);
389 /* send ICMP6 if HL == 0 */
390 if (IP6H_HOPLIM(iphdr) == 0) {
392 /* Don't send ICMP messages in response to ICMP messages */
393 if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
394 icmp6_time_exceeded(p, ICMP6_TE_HL);
396 #endif /* LWIP_ICMP6 */
397 IP6_STATS_INC(ip6.drop);
401 if (netif->mtu && (p->tot_len > netif->mtu)) {
403 /* Don't send ICMP messages in response to ICMP messages */
404 if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
405 icmp6_packet_too_big(p, netif->mtu);
407 #endif /* LWIP_ICMP6 */
408 IP6_STATS_INC(ip6.drop);
412 LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
413 IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
414 IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
415 IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
416 IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
417 IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
418 IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
419 IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
420 IP6_ADDR_BLOCK8(ip6_current_dest_addr())));
422 /* transmit pbuf on chosen interface */
423 netif->output_ip6(netif, p, ip6_current_dest_addr());
424 IP6_STATS_INC(ip6.fw);
425 IP6_STATS_INC(ip6.xmit);
428 #endif /* LWIP_IPV6_FORWARD */
431 * This function is called by the network interface device driver when
432 * an IPv6 packet is received. The function does the basic checks of the
433 * IP header such as packet size being at least larger than the header
434 * size etc. If the packet was not destined for us, the packet is
435 * forwarded (using ip6_forward).
437 * Finally, the packet is sent to the upper layer protocol input function.
439 * @param p the received IPv6 packet (p->payload points to IPv6 header)
440 * @param inp the netif on which this packet was received
441 * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
442 * processed, but currently always returns ERR_OK)
445 ip6_input(struct pbuf *p, struct netif *inp)
447 struct ip6_hdr *ip6hdr;
450 u16_t hlen; /* the current header length */
452 #if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/
455 #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
457 LWIP_ASSERT_CORE_LOCKED();
459 IP6_STATS_INC(ip6.recv);
461 /* identify the IP header */
462 ip6hdr = (struct ip6_hdr *)p->payload;
463 if (IP6H_V(ip6hdr) != 6) {
464 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U32_F"\n",
467 IP6_STATS_INC(ip6.err);
468 IP6_STATS_INC(ip6.drop);
472 #ifdef LWIP_HOOK_IP6_INPUT
473 if (LWIP_HOOK_IP6_INPUT(p, inp)) {
474 /* the packet has been eaten */
479 /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
480 if ((IP6_HLEN > p->len) || ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len)) {
481 if (IP6_HLEN > p->len) {
482 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
483 ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
484 (u16_t)IP6_HLEN, p->len));
486 if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) {
487 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
488 ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
489 (u16_t)(IP6H_PLEN(ip6hdr) + IP6_HLEN), p->tot_len));
491 /* free (drop) packet pbufs */
493 IP6_STATS_INC(ip6.lenerr);
494 IP6_STATS_INC(ip6.drop);
498 /* Trim pbuf. This should have been done at the netif layer,
499 * but we'll do it anyway just to be sure that its done. */
500 pbuf_realloc(p, IP6_HLEN + IP6H_PLEN(ip6hdr));
502 /* copy IP addresses to aligned ip6_addr_t */
503 ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest);
504 ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src);
506 /* Don't accept virtual IPv4 mapped IPv6 addresses.
507 * Don't accept multicast source addresses. */
508 if (ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_dest)) ||
509 ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_src)) ||
510 ip6_addr_ismulticast(ip_2_ip6(&ip_data.current_iphdr_src))) {
511 IP6_STATS_INC(ip6.err);
512 IP6_STATS_INC(ip6.drop);
516 /* current header pointer. */
517 ip_data.current_ip6_header = ip6hdr;
519 /* In netif, used in case we need to send ICMPv6 packets back. */
520 ip_data.current_netif = inp;
521 ip_data.current_input_netif = inp;
523 /* match packet against an interface, i.e. is this packet for us? */
524 if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
525 /* Always joined to multicast if-local and link-local all-nodes group. */
526 if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) ||
527 ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) ||
528 ip6_addr_isallnodes_networklocal(ip6_current_dest_addr()) ||
529 ip6_addr_isallrouters_linklocal(ip6_current_dest_addr())) {
533 else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) {
536 #else /* LWIP_IPV6_MLD */
537 else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) {
538 /* Filter solicited node packets when MLD is not enabled
539 * (for Neighbor discovery). */
541 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
542 if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) &&
543 ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) {
545 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c%"U16_F"\n",
546 netif->name[0], netif->name[1], netif->num));
551 #endif /* LWIP_IPV6_MLD */
556 /* start trying with inp. if that's not acceptable, start walking the
557 list of configured netifs.
558 'first' is used as a boolean to mark whether we started walking the list */
562 /* interface is up? */
563 if (netif_is_up(netif)) {
564 /* unicast to this interface address? address configured? */
565 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
566 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
567 ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i))) {
568 /* exit outer loop */
574 if (ip6_addr_islinklocal(ip6_current_dest_addr())
575 #if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF
576 || ip6_addr_isloopback(ip6_current_dest_addr())
577 #endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */
579 /* Do not match link-local addresses to other netifs. The loopback
580 * address is to be considered link-local and packets to it should be
581 * dropped on other interfaces, as per RFC 4291 Sec. 2.5.3. This
582 * requirement cannot be implemented in the case that loopback
583 * traffic is sent across a non-loopback interface, however.
596 } while (netif != NULL);
598 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c%"U16_F"\n",
599 netif ? netif->name[0] : 'X', netif? netif->name[1] : 'X', netif ? netif->num : 0));
602 /* "::" packet source address? (used in duplicate address detection) */
603 if (ip6_addr_isany(ip6_current_src_addr()) &&
604 (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) {
605 /* packet source is not valid */
606 /* free (drop) packet pbufs */
607 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n"));
609 IP6_STATS_INC(ip6.drop);
610 goto ip6_input_cleanup;
613 /* packet not for us? */
615 /* packet not for us, route or discard */
616 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n"));
617 #if LWIP_IPV6_FORWARD
618 /* non-multicast packet? */
619 if (!ip6_addr_ismulticast(ip6_current_dest_addr())) {
620 /* try to forward IP packet on (other) interfaces */
621 ip6_forward(p, ip6hdr, inp);
623 #endif /* LWIP_IPV6_FORWARD */
625 goto ip6_input_cleanup;
628 /* current netif pointer. */
629 ip_data.current_netif = netif;
631 /* Save next header type. */
632 nexth = IP6H_NEXTH(ip6hdr);
634 /* Init header length. */
635 hlen = ip_data.current_ip_header_tot_len = IP6_HLEN;
637 /* Move to payload. */
638 pbuf_header(p, -IP6_HLEN);
640 /* Process known option extension headers, if present. */
641 while (nexth != IP6_NEXTH_NONE)
644 case IP6_NEXTH_HOPBYHOP:
645 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n"));
646 /* Get next header type. */
647 nexth = *((u8_t *)p->payload);
649 /* Get the header length. */
650 hlen = 8 * (1 + *((u8_t *)p->payload + 1));
651 ip_data.current_ip_header_tot_len += hlen;
653 /* Skip over this header. */
655 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
656 ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
658 /* free (drop) packet pbufs */
660 IP6_STATS_INC(ip6.lenerr);
661 IP6_STATS_INC(ip6.drop);
662 goto ip6_input_cleanup;
665 pbuf_header(p, -(s16_t)hlen);
667 case IP6_NEXTH_DESTOPTS:
668 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n"));
669 /* Get next header type. */
670 nexth = *((u8_t *)p->payload);
672 /* Get the header length. */
673 hlen = 8 * (1 + *((u8_t *)p->payload + 1));
674 ip_data.current_ip_header_tot_len += hlen;
676 /* Skip over this header. */
678 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
679 ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
681 /* free (drop) packet pbufs */
683 IP6_STATS_INC(ip6.lenerr);
684 IP6_STATS_INC(ip6.drop);
685 goto ip6_input_cleanup;
688 pbuf_header(p, -(s16_t)hlen);
690 case IP6_NEXTH_ROUTING:
691 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n"));
692 /* Get next header type. */
693 nexth = *((u8_t *)p->payload);
695 /* Get the header length. */
696 hlen = 8 * (1 + *((u8_t *)p->payload + 1));
697 ip_data.current_ip_header_tot_len += hlen;
699 /* Skip over this header. */
701 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
702 ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
704 /* free (drop) packet pbufs */
706 IP6_STATS_INC(ip6.lenerr);
707 IP6_STATS_INC(ip6.drop);
708 goto ip6_input_cleanup;
711 pbuf_header(p, -(s16_t)hlen);
714 case IP6_NEXTH_FRAGMENT:
716 struct ip6_frag_hdr *frag_hdr;
717 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n"));
719 frag_hdr = (struct ip6_frag_hdr *)p->payload;
721 /* Get next header type. */
722 nexth = frag_hdr->_nexth;
724 /* Fragment Header length. */
726 ip_data.current_ip_header_tot_len += hlen;
728 /* Make sure this header fits in current pbuf. */
730 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
731 ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
733 /* free (drop) packet pbufs */
735 IP6_FRAG_STATS_INC(ip6_frag.lenerr);
736 IP6_FRAG_STATS_INC(ip6_frag.drop);
737 goto ip6_input_cleanup;
740 /* Offset == 0 and more_fragments == 0? */
741 if ((frag_hdr->_fragment_offset &
742 PP_HTONS(IP6_FRAG_OFFSET_MASK | IP6_FRAG_MORE_FLAG)) == 0) {
743 /* This is a 1-fragment packet, usually a packet that we have
744 * already reassembled. Skip this header anc continue. */
745 pbuf_header(p, -(s16_t)hlen);
749 /* reassemble the packet */
751 /* packet not fully reassembled yet? */
753 goto ip6_input_cleanup;
756 /* Returned p point to IPv6 header.
757 * Update all our variables and pointers and continue. */
758 ip6hdr = (struct ip6_hdr *)p->payload;
759 nexth = IP6H_NEXTH(ip6hdr);
760 hlen = ip_data.current_ip_header_tot_len = IP6_HLEN;
761 pbuf_header(p, -IP6_HLEN);
763 #else /* LWIP_IPV6_REASS */
764 /* free (drop) packet pbufs */
765 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n"));
767 IP6_STATS_INC(ip6.opterr);
768 IP6_STATS_INC(ip6.drop);
769 goto ip6_input_cleanup;
770 #endif /* LWIP_IPV6_REASS */
781 /* p points to IPv6 header again. */
782 pbuf_header_force(p, (s16_t)ip_data.current_ip_header_tot_len);
784 /* send to upper layers */
785 #if IP_DEBUG && LWIP_IP_DEBUG_TARGET
786 if (debug_target_match(1, ip6_2_ipX(&ip_data.current_iphdr_src.ip6), ip6_2_ipX(&ip_data.current_iphdr_dest.ip6)))
789 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n"));
791 LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
792 #if IP_DEBUG && LWIP_IP_DEBUG_TARGET
797 /* raw input did not eat the packet? */
798 if (raw_input(p, inp) == 0)
799 #endif /* LWIP_RAW */
808 case IP6_NEXTH_UDPLITE:
809 #endif /* LWIP_UDPLITE */
810 /* Point to payload. */
811 pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len);
814 #endif /* LWIP_UDP */
817 /* Point to payload. */
818 pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len);
821 #endif /* LWIP_TCP */
823 case IP6_NEXTH_ICMP6:
824 /* Point to payload. */
825 pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len);
828 #endif /* LWIP_ICMP */
831 /* send ICMP parameter problem unless it was a multicast or ICMPv6 */
832 if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) &&
833 (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) {
834 icmp6_param_problem(p, ICMP6_PP_HEADER, ip_data.current_ip_header_tot_len - hlen);
836 #endif /* LWIP_ICMP */
837 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", (u16_t)IP6H_NEXTH(ip6hdr)));
839 IP6_STATS_INC(ip6.proterr);
840 IP6_STATS_INC(ip6.drop);
846 ip_data.current_netif = NULL;
847 ip_data.current_input_netif = NULL;
848 ip_data.current_ip6_header = NULL;
849 ip_data.current_ip_header_tot_len = 0;
850 ip6_addr_set_zero(ip6_current_src_addr());
851 ip6_addr_set_zero(ip6_current_dest_addr());
858 * Sends an IPv6 packet on a network interface. This function constructs
859 * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is
860 * used as source (usually during network startup). If the source IPv6 address it
861 * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network
862 * interface is filled in as source address. If the destination IPv6 address is
863 * LWIP_IP_HDRINCL, p is assumed to already include an IPv6 header and
864 * p->payload points to it instead of the data.
866 * @param p the packet to send (p->payload points to the data, e.g. next
867 protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
868 IPv6 header and p->payload points to that IPv6 header)
869 * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
870 * IP address of the netif is selected and used as source address.
871 * if src == NULL, IP6_ADDR_ANY is used as source)
872 * @param dest the destination IPv6 address to send the packet to
873 * @param hl the Hop Limit value to be set in the IPv6 header
874 * @param tc the Traffic Class value to be set in the IPv6 header
875 * @param nexth the Next Header to be set in the IPv6 header
876 * @param netif the netif on which to send this packet
877 * @return ERR_OK if the packet was sent OK
878 * ERR_BUF if p doesn't have enough space for IPv6/LINK headers
879 * returns errors returned by netif->output
882 ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
884 u8_t nexth, struct netif *netif)
886 const ip6_addr_t *src_used = src;
887 if (dest != LWIP_IP_HDRINCL) {
888 if (src != NULL && ip6_addr_isany(src)) {
889 src_used = ip_2_ip6(ip6_select_source_address(netif, dest));
890 if ((src_used == NULL) || ip6_addr_isany(src_used)) {
891 /* No appropriate source address was found for this packet. */
892 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n"));
893 IP6_STATS_INC(ip6.rterr);
898 return ip6_output_if_src(p, src_used, dest, hl, tc, nexth, netif);
902 * Same as ip6_output_if() but 'src' address is not replaced by netif address
906 ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
908 u8_t nexth, struct netif *netif)
910 struct ip6_hdr *ip6hdr;
911 ip6_addr_t dest_addr;
913 LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
915 /* Should the IPv6 header be generated or is it already included in p? */
916 if (dest != LWIP_IP_HDRINCL) {
917 /* generate IPv6 header */
918 if (pbuf_header(p, IP6_HLEN)) {
919 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n"));
920 IP6_STATS_INC(ip6.err);
924 ip6hdr = (struct ip6_hdr *)p->payload;
925 LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr",
926 (p->len >= sizeof(struct ip6_hdr)));
928 IP6H_HOPLIM_SET(ip6hdr, hl);
929 IP6H_NEXTH_SET(ip6hdr, nexth);
931 /* dest cannot be NULL here */
932 ip6_addr_copy(ip6hdr->dest, *dest);
934 IP6H_VTCFL_SET(ip6hdr, 6, tc, 0);
935 IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN);
940 /* src cannot be NULL here */
941 ip6_addr_copy(ip6hdr->src, *src);
944 /* IP header already included in p */
945 ip6hdr = (struct ip6_hdr *)p->payload;
946 ip6_addr_copy(dest_addr, ip6hdr->dest);
950 IP6_STATS_INC(ip6.xmit);
952 #if IP_DEBUG && LWIP_IP_DEBUG_TARGET
953 if (debug_target_match(1, ip6_2_ipX(src), ip6_2_ipX(dest)))
956 LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num));
958 #if IP_DEBUG && LWIP_IP_DEBUG_TARGET
965 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
966 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
967 ip6_addr_cmp(dest, netif_ip6_addr(netif, i))) {
968 /* Packet to self, enqueue it for loopback */
969 LWIP_DEBUGF(IP6_DEBUG, ("netif_loop_output()\n"));
970 return netif_loop_output(netif, p);
974 #if LWIP_MULTICAST_TX_OPTIONS
975 if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
976 netif_loop_output(netif, p);
978 #endif /* LWIP_MULTICAST_TX_OPTIONS */
979 #endif /* ENABLE_LOOPBACK */
981 /* don't fragment if interface has mtu set to 0 [loopif] */
982 if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) {
983 return ip6_frag(p, netif, dest);
985 #endif /* LWIP_IPV6_FRAG */
987 LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()\n"));
988 return netif->output_ip6(netif, p, dest);
992 * Simple interface to ip6_output_if. It finds the outgoing network
993 * interface and calls upon ip6_output_if to do the actual work.
995 * @param p the packet to send (p->payload points to the data, e.g. next
996 protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
997 IPv6 header and p->payload points to that IPv6 header)
998 * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
999 * IP address of the netif is selected and used as source address.
1000 * if src == NULL, IP6_ADDR_ANY is used as source)
1001 * @param dest the destination IPv6 address to send the packet to
1002 * @param hl the Hop Limit value to be set in the IPv6 header
1003 * @param tc the Traffic Class value to be set in the IPv6 header
1004 * @param nexth the Next Header to be set in the IPv6 header
1005 * @param pcb the management channel
1007 * @return ERR_RTE if no route is found
1008 * see ip_output_if() for more return values
1011 ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
1012 u8_t hl, u8_t tc, u8_t nexth, struct ip_pcb *pcb)
1016 struct netif *netif;
1017 struct ip6_hdr *ip6hdr;
1018 ip6_addr_t src_addr, dest_addr;
1020 LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
1022 if (dest != LWIP_IP_HDRINCL) {
1023 netif = ip6_route(src, dest);
1025 /* IP header included in p, read addresses. */
1026 ip6hdr = (struct ip6_hdr *)p->payload;
1027 ip6_addr_copy(src_addr, ip6hdr->src);
1028 ip6_addr_copy(dest_addr, ip6hdr->dest);
1029 netif = ip6_route(&src_addr, &dest_addr);
1032 if (netif == NULL) {
1033 LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
1034 IP6_ADDR_BLOCK1(dest),
1035 IP6_ADDR_BLOCK2(dest),
1036 IP6_ADDR_BLOCK3(dest),
1037 IP6_ADDR_BLOCK4(dest),
1038 IP6_ADDR_BLOCK5(dest),
1039 IP6_ADDR_BLOCK6(dest),
1040 IP6_ADDR_BLOCK7(dest),
1041 IP6_ADDR_BLOCK8(dest)));
1042 IP6_STATS_INC(ip6.rterr);
1046 if (pcb) netif_apply_pcb(netif, pcb);
1047 ret = ip6_output_if(p, src, dest, hl, tc, nexth, netif);
1048 if (pcb) netif_apply_pcb(netif, NULL);
1054 #if LWIP_NETIF_HWADDRHINT
1055 /** Like ip6_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
1056 * before calling ip6_output_if.
1058 * @param p the packet to send (p->payload points to the data, e.g. next
1059 protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
1060 IPv6 header and p->payload points to that IPv6 header)
1061 * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
1062 * IP address of the netif is selected and used as source address.
1063 * if src == NULL, IP6_ADDR_ANY is used as source)
1064 * @param dest the destination IPv6 address to send the packet to
1065 * @param hl the Hop Limit value to be set in the IPv6 header
1066 * @param tc the Traffic Class value to be set in the IPv6 header
1067 * @param nexth the Next Header to be set in the IPv6 header
1068 * @param addr_hint address hint pointer set to netif->addr_hint before
1069 * calling ip_output_if()
1071 * @return ERR_RTE if no route is found
1072 * see ip_output_if() for more return values
1075 ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
1076 u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint)
1078 struct netif *netif;
1079 struct ip6_hdr *ip6hdr;
1080 ip6_addr_t src_addr, dest_addr;
1083 LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
1085 if (dest != LWIP_IP_HDRINCL) {
1086 netif = ip6_route(src, dest);
1088 /* IP header included in p, read addresses. */
1089 ip6hdr = (struct ip6_hdr *)p->payload;
1090 ip6_addr_copy(src_addr, ip6hdr->src);
1091 ip6_addr_copy(dest_addr, ip6hdr->dest);
1092 netif = ip6_route(&src_addr, &dest_addr);
1095 if (netif == NULL) {
1096 LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
1097 IP6_ADDR_BLOCK1(dest),
1098 IP6_ADDR_BLOCK2(dest),
1099 IP6_ADDR_BLOCK3(dest),
1100 IP6_ADDR_BLOCK4(dest),
1101 IP6_ADDR_BLOCK5(dest),
1102 IP6_ADDR_BLOCK6(dest),
1103 IP6_ADDR_BLOCK7(dest),
1104 IP6_ADDR_BLOCK8(dest)));
1105 IP6_STATS_INC(ip6.rterr);
1109 NETIF_SET_HWADDRHINT(netif, addr_hint);
1110 err = ip6_output_if(p, src, dest, hl, tc, nexth, netif);
1111 NETIF_SET_HWADDRHINT(netif, NULL);
1115 #endif /* LWIP_NETIF_HWADDRHINT*/
1119 * Add a hop-by-hop options header with a router alert option and padding.
1121 * Used by MLD when sending a Multicast listener report/done message.
1123 * @param p the packet to which we will prepend the options header
1124 * @param nexth the next header protocol number (e.g. IP6_NEXTH_ICMP6)
1125 * @param value the value of the router alert option data (e.g. IP6_ROUTER_ALERT_VALUE_MLD)
1126 * @return ERR_OK if hop-by-hop header was added, ERR_* otherwise
1129 ip6_options_add_hbh_ra(struct pbuf *p, u8_t nexth, u8_t value)
1131 struct ip6_hbh_hdr *hbh_hdr;
1133 /* Move pointer to make room for hop-by-hop options header. */
1134 if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) {
1135 LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n"));
1136 IP6_STATS_INC(ip6.err);
1140 hbh_hdr = (struct ip6_hbh_hdr *)p->payload;
1143 hbh_hdr->_nexth = nexth;
1145 hbh_hdr->_ra_opt_type = IP6_ROUTER_ALERT_OPTION;
1146 hbh_hdr->_ra_opt_dlen = 2;
1147 hbh_hdr->_ra_opt_data = value;
1148 hbh_hdr->_padn_opt_type = IP6_PADN_ALERT_OPTION;
1149 hbh_hdr->_padn_opt_dlen = 0;
1153 #endif /* LWIP_IPV6_MLD */
1156 /* Print an IPv6 header by using LWIP_DEBUGF
1157 * @param p an IPv6 packet, p->payload pointing to the IPv6 header
1160 ip6_debug_print(struct pbuf *p)
1162 struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
1164 LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n"));
1165 LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
1166 LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" | %3"U16_F" | %7"U32_F" | (ver, class, flow)\n",
1170 LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
1171 LWIP_DEBUGF(IP6_DEBUG, ("| %5"U16_F" | %3"U16_F" | %3"U16_F" | (plen, nexth, hopl)\n",
1174 IP6H_HOPLIM(ip6hdr)));
1175 LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
1176 LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (src)\n",
1177 IP6_ADDR_BLOCK1(&(ip6hdr->src)),
1178 IP6_ADDR_BLOCK2(&(ip6hdr->src)),
1179 IP6_ADDR_BLOCK3(&(ip6hdr->src)),
1180 IP6_ADDR_BLOCK4(&(ip6hdr->src))));
1181 LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n",
1182 IP6_ADDR_BLOCK5(&(ip6hdr->src)),
1183 IP6_ADDR_BLOCK6(&(ip6hdr->src)),
1184 IP6_ADDR_BLOCK7(&(ip6hdr->src)),
1185 IP6_ADDR_BLOCK8(&(ip6hdr->src))));
1186 LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
1187 LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (dest)\n",
1188 IP6_ADDR_BLOCK1(&(ip6hdr->dest)),
1189 IP6_ADDR_BLOCK2(&(ip6hdr->dest)),
1190 IP6_ADDR_BLOCK3(&(ip6hdr->dest)),
1191 IP6_ADDR_BLOCK4(&(ip6hdr->dest))));
1192 LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n",
1193 IP6_ADDR_BLOCK5(&(ip6hdr->dest)),
1194 IP6_ADDR_BLOCK6(&(ip6hdr->dest)),
1195 IP6_ADDR_BLOCK7(&(ip6hdr->dest)),
1196 IP6_ADDR_BLOCK8(&(ip6hdr->dest))));
1197 LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
1199 #endif /* IP6_DEBUG */
1201 #endif /* LWIP_IPV6 */