/** * Forwards an IPv6 packet. It finds an appropriate route for the * packet, decrements the HL value of the packet, and outputs * the packet on the appropriate interface. * * @param p the packet to forward (p->payload points to IP header) * @param iphdr the IPv6 header of the input packet * @param inp the netif on which this packet was received */ static void ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) { struct netif *netif; /* do not forward link-local addresses */ if (ip6_addr_islinklocal(ip6_current_dest_addr())) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* Find network interface where to forward this IP packet to. */ netif = ip6_route(IP6_ADDR_ANY6, ip6_current_dest_addr()); if (netif == NULL) { 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", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* decrement HL */ IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1); /* send ICMP6 if HL == 0 */ if (IP6H_HOPLIM(iphdr) == 0) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_time_exceeded(p, ICMP6_TE_HL); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return; } if (netif->mtu && (p->tot_len > netif->mtu)) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_packet_too_big(p, netif->mtu); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return; } 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", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); /* transmit pbuf on chosen interface */ netif->output_ip6(netif, p, ip6_current_dest_addr()); IP6_STATS_INC(ip6.fw); IP6_STATS_INC(ip6.xmit); return; }
/** * Forwards an IPv6 packet. It finds an appropriate route for the * packet, decrements the HL value of the packet, and outputs * the packet on the appropriate interface. * * @param p the packet to forward (p->payload points to IP header) * @param iphdr the IPv6 header of the input packet * @param inp the netif on which this packet was received * @return -1 if packet is to be dropped, 0 if there's no route, 1 if forwarded */ static int ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) { enum { FWD_DROP = -1, FWD_PROXY = 0, FWD_FORWARDED = 1 }; struct netif *netif; /* do not forward link-local addresses */ if (ip6_addr_islinklocal(ip6_current_dest_addr())) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return FWD_DROP; } /* Find network interface where to forward this IP packet to. */ netif = ip6_route_fwd(ip6_current_dest_addr()); if (netif == NULL) { 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", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); #if LWIP_CONNECTION_PROXY return FWD_PROXY; #else /* !LWIP_CONNECTION_PROXY */ #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return FWD_DROP; #endif /* !LWIP_CONNECTION_PROXY */ } #if LWIP_CONNECTION_PROXY /* The packet is for a destination on a directly connected network. * Check for addresses in that address space that proxy wants to * remap (e.g. to host loopback address/es) and hand it off to * proxy */ if (netif != netif_default && proxy_ip6_divert_hook != NULL && (*proxy_ip6_divert_hook)(netif, ip6_current_dest_addr())) { return FWD_PROXY; } #endif /* LWIP_CONNECTION_PROXY */ /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return FWD_DROP; } /* decrement HL */ IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1); /* send ICMP6 if HL == 0 */ if (IP6H_HOPLIM(iphdr) == 0) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_time_exceeded(p, ICMP6_TE_HL); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return FWD_DROP; } if (netif->mtu && (p->tot_len > netif->mtu)) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_packet_too_big(p, netif->mtu); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return FWD_DROP; } 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", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); /* transmit pbuf on chosen interface */ netif->output_ip6(netif, p, ip6_current_dest_addr()); IP6_STATS_INC(ip6.fw); IP6_STATS_INC(ip6.xmit); return FWD_FORWARDED; }