err_t ip6_output_if(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest, u8_t ttl, u8_t proto, struct netif *netif) { struct ip6_hdr *iphdr; PERF_START; LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len)); if (pbuf_header(p, IP6_HLEN)) { LWIP_DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));IP_STATS_INC(ip.err); return ERR_BUF; } LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len)); iphdr = p->payload; if (dest != IP_HDRINCL) { LWIP_DEBUGF(IP_DEBUG, ("!IP_HDRLINCL\n")); iphdr->hoplim = ttl; iphdr->nexthdr = proto; iphdr->len = htons(p->tot_len - IP6_HLEN); ip6_addr_set(&(iphdr->dest), dest); iphdr->v = 6; if (ip6_addr_isany(src)) { ip6_addr_set(&(iphdr->src), &(netif->ip6_addr)); } else { ip6_addr_set(&(iphdr->src), src); } } else { dest = &(iphdr->dest); } IP_STATS_INC(ip.xmit); LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %"U16_F")\n", netif->name[0], netif->name[1], p->tot_len)); #if IP_DEBUG ip6_debug_print(p); #endif /* IP_DEBUG */ PERF_STOP("ip_output_if"); if (netif->ip6_output != 0) { return (netif->ip6_output(netif, p, dest)); } else { return (ERR_RTE); } }
/** * Same as ip6_output_if() but 'src' address is not replaced by netif address * when it is 'any'. */ err_t ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth, struct netif *netif) { struct ip6_hdr *ip6hdr; ip6_addr_t dest_addr; LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); /* Should the IPv6 header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { /* generate IPv6 header */ if (pbuf_header(p, IP6_HLEN)) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); IP6_STATS_INC(ip6.err); return ERR_BUF; } ip6hdr = (struct ip6_hdr *)p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", (p->len >= sizeof(struct ip6_hdr))); IP6H_HOPLIM_SET(ip6hdr, hl); IP6H_NEXTH_SET(ip6hdr, nexth); /* dest cannot be NULL here */ ip6_addr_copy(ip6hdr->dest, *dest); IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); if (src == NULL) { src = IP6_ADDR_ANY6; } /* src cannot be NULL here */ ip6_addr_copy(ip6hdr->src, *src); } else { /* IP header already included in p */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy(dest_addr, ip6hdr->dest); dest = &dest_addr; } IP6_STATS_INC(ip6.xmit); LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip6_debug_print(p); #if ENABLE_LOOPBACK { int i; #if !LWIP_HAVE_LOOPIF if (ip6_addr_isloopback(dest)) { return netif_loop_output(netif, p); } #endif /* !LWIP_HAVE_LOOPIF */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(dest, netif_ip6_addr(netif, i))) { /* Packet to self, enqueue it for loopback */ LWIP_DEBUGF(IP6_DEBUG, ("netif_loop_output()\n")); return netif_loop_output(netif, p); } } } #endif /* ENABLE_LOOPBACK */ #if LWIP_IPV6_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { return ip6_frag(p, netif, dest); } #endif /* LWIP_IPV6_FRAG */ LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()\n")); return netif->output_ip6(netif, p, dest); }
/** * This function is called by the network interface device driver when * an IPv6 packet is received. The function does the basic checks of the * IP header such as packet size being at least larger than the header * size etc. If the packet was not destined for us, the packet is * forwarded (using ip6_forward). * * Finally, the packet is sent to the upper layer protocol input function. * * @param p the received IPv6 packet (p->payload points to IPv6 header) * @param inp the netif on which this packet was received * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't * processed, but currently always returns ERR_OK) */ err_t ip6_input(struct pbuf *p, struct netif *inp) { struct ip6_hdr *ip6hdr; struct netif *netif; u8_t nexth; u16_t hlen; /* the current header length */ u8_t i; #if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/ @todo int check_ip_src=1; #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ IP6_STATS_INC(ip6.recv); /* identify the IP header */ ip6hdr = (struct ip6_hdr *)p->payload; if (IP6H_V(ip6hdr) != 6) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U32_F"\n", IP6H_V(ip6hdr))); pbuf_free(p); IP6_STATS_INC(ip6.err); IP6_STATS_INC(ip6.drop); return ERR_OK; } #ifdef LWIP_HOOK_IP6_INPUT if (LWIP_HOOK_IP6_INPUT(p, inp)) { /* the packet has been eaten */ return ERR_OK; } #endif /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ if ((IP6_HLEN > p->len) || ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len)) { if (IP6_HLEN > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", IP6_HLEN, p->len)); } if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", IP6H_PLEN(ip6hdr) + IP6_HLEN, p->tot_len)); } /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); return ERR_OK; } /* Trim pbuf. This should have been done at the netif layer, * but we'll do it anyway just to be sure that its done. */ pbuf_realloc(p, IP6_HLEN + IP6H_PLEN(ip6hdr)); /* copy IP addresses to aligned ip6_addr_t */ ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest); ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src); /* current header pointer. */ ip_data.current_ip6_header = ip6hdr; /* In netif, used in case we need to send ICMPv6 packets back. */ ip_data.current_netif = inp; ip_data.current_input_netif = inp; /* match packet against an interface, i.e. is this packet for us? */ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { /* Always joined to multicast if-local and link-local all-nodes group. */ if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) || ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) { netif = inp; } #if LWIP_IPV6_MLD else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) { netif = inp; } #else /* LWIP_IPV6_MLD */ else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) { /* Filter solicited node packets when MLD is not enabled * (for Neighbor discovery). */ netif = NULL; for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) && ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { netif = inp; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); break; } } } #endif /* LWIP_IPV6_MLD */ else { netif = NULL; } } else { /* start trying with inp. if that's not acceptable, start walking the list of configured netifs. 'first' is used as a boolean to mark whether we started walking the list */ int first = 1; netif = inp; do { /* interface is up? */ if (netif_is_up(netif)) { /* unicast to this interface address? address configured? */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i))) { /* exit outer loop */ goto netif_found; } } } if (ip6_addr_islinklocal(ip6_current_dest_addr())) { /* Do not match link-local addresses to other netifs. */ netif = NULL; break; } if (first) { first = 0; netif = netif_list; } else { netif = netif->next; } if (netif == inp) { netif = netif->next; } } while (netif != NULL); netif_found: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n", netif ? netif->name[0] : 'X', netif? netif->name[1] : 'X')); } /* "::" packet source address? (used in duplicate address detection) */ if (ip6_addr_isany(ip6_current_src_addr()) && (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) { /* packet source is not valid */ /* free (drop) packet pbufs */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n")); pbuf_free(p); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } /* packet not for us? */ if (netif == NULL) { /* packet not for us, route or discard */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n")); #if LWIP_IPV6_FORWARD /* non-multicast packet? */ if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { /* try to forward IP packet on (other) interfaces */ ip6_forward(p, ip6hdr, inp); } #endif /* LWIP_IPV6_FORWARD */ pbuf_free(p); goto ip6_input_cleanup; } /* current netif pointer. */ ip_data.current_netif = netif; /* Save next header type. */ nexth = IP6H_NEXTH(ip6hdr); /* Init header length. */ hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; /* Move to payload. */ pbuf_header(p, -IP6_HLEN); /* Process known option extension headers, if present. */ while (nexth != IP6_NEXTH_NONE) { switch (nexth) { case IP6_NEXTH_HOPBYHOP: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -(s16_t)hlen); break; case IP6_NEXTH_DESTOPTS: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -(s16_t)hlen); break; case IP6_NEXTH_ROUTING: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -(s16_t)hlen); break; case IP6_NEXTH_FRAGMENT: { struct ip6_frag_hdr * frag_hdr; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n")); frag_hdr = (struct ip6_frag_hdr *)p->payload; /* Get next header type. */ nexth = frag_hdr->_nexth; /* Fragment Header length. */ hlen = 8; ip_data.current_ip_header_tot_len += hlen; /* Make sure this header fits in current pbuf. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_FRAG_STATS_INC(ip6_frag.lenerr); IP6_FRAG_STATS_INC(ip6_frag.drop); goto ip6_input_cleanup; } /* Offset == 0 and more_fragments == 0? */ if ((frag_hdr->_fragment_offset & PP_HTONS(IP6_FRAG_OFFSET_MASK | IP6_FRAG_MORE_FLAG)) == 0) { /* This is a 1-fragment packet, usually a packet that we have * already reassembled. Skip this header anc continue. */ pbuf_header(p, -(s16_t)hlen); } else { #if LWIP_IPV6_REASS /* reassemble the packet */ p = ip6_reass(p); /* packet not fully reassembled yet? */ if (p == NULL) { goto ip6_input_cleanup; } /* Returned p point to IPv6 header. * Update all our variables and pointers and continue. */ ip6hdr = (struct ip6_hdr *)p->payload; nexth = IP6H_NEXTH(ip6hdr); hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; pbuf_header(p, -IP6_HLEN); #else /* LWIP_IPV6_REASS */ /* free (drop) packet pbufs */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n")); pbuf_free(p); IP6_STATS_INC(ip6.opterr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; #endif /* LWIP_IPV6_REASS */ } break; } default: goto options_done; break; } } options_done: /* p points to IPv6 header again. */ pbuf_header_force(p, ip_data.current_ip_header_tot_len); /* send to upper layers */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); ip6_debug_print(p); LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); #if LWIP_RAW /* raw input did not eat the packet? */ if (raw_input(p, inp) == 0) #endif /* LWIP_RAW */ { switch (nexth) { case IP6_NEXTH_NONE: pbuf_free(p); break; #if LWIP_UDP case IP6_NEXTH_UDP: #if LWIP_UDPLITE case IP6_NEXTH_UDPLITE: #endif /* LWIP_UDPLITE */ /* Point to payload. */ pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); udp_input(p, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case IP6_NEXTH_TCP: /* Point to payload. */ pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); tcp_input(p, inp); break; #endif /* LWIP_TCP */ #if LWIP_ICMP6 case IP6_NEXTH_ICMP6: /* Point to payload. */ pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); icmp6_input(p, inp); break; #endif /* LWIP_ICMP */ default: #if LWIP_ICMP6 /* send ICMP parameter problem unless it was a multicast or ICMPv6 */ if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) && (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) { icmp6_param_problem(p, ICMP6_PP_HEADER, ip_data.current_ip_header_tot_len - hlen); } #endif /* LWIP_ICMP */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", IP6H_NEXTH(ip6hdr))); pbuf_free(p); IP6_STATS_INC(ip6.proterr); IP6_STATS_INC(ip6.drop); break; } } ip6_input_cleanup: ip_data.current_netif = NULL; ip_data.current_input_netif = NULL; ip_data.current_ip6_header = NULL; ip_data.current_ip_header_tot_len = 0; ip6_addr_set_zero(ip6_current_src_addr()); ip6_addr_set_zero(ip6_current_dest_addr()); return ERR_OK; }
/** * Sends an IPv6 packet on a network interface. This function constructs * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is * used as source (usually during network startup). If the source IPv6 address it * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network * interface is filled in as source address. If the destination IPv6 address is * IP_HDRINCL, p is assumed to already include an IPv6 header and p->payload points * to it instead of the data. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IPv6 header and p->payload points to that IPv6 header) * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an * IP address of the netif is selected and used as source address. * if src == NULL, IP6_ADDR_ANY is used as source) * @param dest the destination IPv6 address to send the packet to * @param hl the Hop Limit value to be set in the IPv6 header * @param tc the Traffic Class value to be set in the IPv6 header * @param nexth the Next Header to be set in the IPv6 header * @param netif the netif on which to send this packet * @return ERR_OK if the packet was sent OK * ERR_BUF if p doesn't have enough space for IPv6/LINK headers * returns errors returned by netif->output */ err_t ip6_output_if(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth, struct netif *netif) { struct ip6_hdr *ip6hdr; ip6_addr_t dest_addr; /* pbufs passed to IP must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ LWIP_ASSERT("p->ref == 1", p->ref == 1); /* Should the IPv6 header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { /* generate IPv6 header */ if (pbuf_header(p, IP6_HLEN)) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); IP6_STATS_INC(ip6.err); return ERR_BUF; } ip6hdr = (struct ip6_hdr *)p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", (p->len >= sizeof(struct ip6_hdr))); IP6H_HOPLIM_SET(ip6hdr, hl); IP6H_NEXTH_SET(ip6hdr, nexth); /* dest cannot be NULL here */ ip6_addr_copy(ip6hdr->dest, *dest); IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); if (src == NULL) { src = IP6_ADDR_ANY; } else if (ip6_addr_isany(src)) { src = ip6_select_source_address(netif, dest); if ((src == NULL) || ip6_addr_isany(src)) { /* No appropriate source address was found for this packet. */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); IP6_STATS_INC(ip6.rterr); return ERR_RTE; } } /* src cannot be NULL here */ ip6_addr_copy(ip6hdr->src, *src); } else { /* IP header already included in p */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy(dest_addr, ip6hdr->dest); dest = &dest_addr; } IP6_STATS_INC(ip6.xmit); LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip6_debug_print(p); #if ENABLE_LOOPBACK /* TODO implement loopback for v6 if (ip6_addr_cmp(dest, netif_ip6_addr(0))) { return netif_loop_output(netif, p, dest); }*/ #endif /* ENABLE_LOOPBACK */ #if LWIP_IPV6_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { return ip6_frag(p, netif, dest); } #endif /* LWIP_IPV6_FRAG */ LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()")); return netif->output_ip6(netif, p, dest); }
void ip6_input(struct pbuf *p, struct netif *inp) { struct ip6_hdr *iphdr; struct netif *netif; PERF_START; #if IP_DEBUG ip6_debug_print(p); #endif /* IP_DEBUG */ IP_STATS_INC(ip.recv); /* identify the IP header */ iphdr = p->payload; if (iphdr->v != 6) { LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n")); #if IP_DEBUG ip6_debug_print(p); #endif /* IP_DEBUG */ pbuf_free(p); IP_STATS_INC(ip.err);IP_STATS_INC(ip.drop); return; } char forus = 0; /* is this packet for us? */ for (netif = netif_list; netif != NULL; netif = netif->next) { #if IP_DEBUG LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest ")); ip6_addr_debug_print(IP_DEBUG, ((struct ip6_addr *)&(iphdr->dest))); LWIP_DEBUGF(IP_DEBUG, ("netif->ip6_addr ")); ip6_addr_debug_print(IP_DEBUG, ((struct ip6_addr *)&(netif->ip6_addr))); LWIP_DEBUGF(IP_DEBUG, ("\n\r")); #endif /* IP_DEBUG */ if (ip6_addr_cmp(&(iphdr->dest), &(netif->ip6_addr))) { forus = 1; LWIP_DEBUGF(IP_DEBUG, ("ip6_input: packet for us: perfect match")); break; } if (ip6_addr_issolicitedmulticast(&(iphdr->dest), &(netif->ip6_addr))) { forus = 1; LWIP_DEBUGF(IP_DEBUG, ("ip6_input: packet for us on solicited multicast address\n")); break; } } // check if it is a multicast address and we are listening on that address if (ip6_addr_isallnodes(&(iphdr->dest))) forus = 1; if (forus == 0) { /* packet not for us, route or discard */ LWIP_DEBUGF(IP_DEBUG, ("ip6_input: packet not for us.\n")); #if IP_FORWARD ip6_forward(p, iphdr); #endif pbuf_free(p); return; } pbuf_realloc(p, IP6_HLEN + ntohs(iphdr->len)); /* send to upper layers */ #if IP_DEBUG /* LWIP_DEBUGF("ip_input: \n"); ip_debug_print(p); LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/ #endif /* IP_DEBUG */ /*if(pbuf_header(p, -IP6_HLEN)) { LWIP_ASSERT("Can't move over header in packet", 0); return; }*/ switch (iphdr->nexthdr) { #if LWIP_UDP case IP6_PROTO_UDP: udp_input(p, inp); break; #endif #if LWIP_TCP case IP6_PROTO_TCP: tcp_input(p, inp); break; #endif #if LWIP_ICMP case IP6_PROTO_ICMP: icmp6_input(p, inp); break; #endif /* LWIP_ICMP */ default: #if LWIP_ICMP /* send ICMP destination protocol unreachable */ icmp6_dest_unreach(p, ICMP_DUR_PROTO); #endif /* LWIP_ICMP */ pbuf_free(p); LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n", iphdr->nexthdr)); IP_STATS_INC(ip.proterr); IP_STATS_INC(ip.drop); }PERF_STOP("ip_input"); }