summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/ip6_forward.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-06 16:20:21 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-11 10:08:08 +0100
commit66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch)
tree48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/netinet6/ip6_forward.c
parentDefine __GLOBL1() and __GLOBL() (diff)
downloadrtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/netinet6/ip6_forward.c')
-rw-r--r--freebsd/sys/netinet6/ip6_forward.c103
1 files changed, 80 insertions, 23 deletions
diff --git a/freebsd/sys/netinet6/ip6_forward.c b/freebsd/sys/netinet6/ip6_forward.c
index fa5d373f..2b45804f 100644
--- a/freebsd/sys/netinet6/ip6_forward.c
+++ b/freebsd/sys/netinet6/ip6_forward.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
+#include <rtems/bsd/local/opt_ipfw.h>
#include <rtems/bsd/local/opt_ipsec.h>
#include <rtems/bsd/local/opt_ipstealth.h>
@@ -52,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syslog.h>
#include <net/if.h>
+#include <net/netisr.h>
#include <net/route.h>
#include <net/pfil.h>
@@ -100,11 +102,15 @@ ip6_forward(struct mbuf *m, int srcrt)
struct mbuf *mcopy = NULL;
struct ifnet *origifp; /* maybe unnecessary */
u_int32_t inzone, outzone;
- struct in6_addr src_in6, dst_in6;
+ struct in6_addr src_in6, dst_in6, odst;
#ifdef IPSEC
struct secpolicy *sp = NULL;
int ipsecrt = 0;
#endif
+#ifdef SCTP
+ int sw_csum;
+#endif
+ struct m_tag *fwd_tag;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
#ifdef IPSEC
@@ -116,7 +122,7 @@ ip6_forward(struct mbuf *m, int srcrt)
* before forwarding packet actually.
*/
if (ipsec6_in_reject(m, NULL)) {
- V_ipsec6stat.in_polvio++;
+ IPSEC6STAT_INC(in_polvio);
m_freem(m);
return;
}
@@ -131,7 +137,7 @@ ip6_forward(struct mbuf *m, int srcrt)
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
if (V_ip6_log_time + V_ip6_log_interval < time_second) {
V_ip6_log_time = time_second;
@@ -178,8 +184,8 @@ ip6_forward(struct mbuf *m, int srcrt)
sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND,
IP_FORWARDING, &error);
if (sp == NULL) {
- V_ipsec6stat.out_inval++;
- V_ip6stat.ip6s_cantforward++;
+ IPSEC6STAT_INC(out_inval);
+ IP6STAT_INC(ip6s_cantforward);
if (mcopy) {
#if 0
/* XXX: what icmp ? */
@@ -199,8 +205,8 @@ ip6_forward(struct mbuf *m, int srcrt)
/*
* This packet is just discarded.
*/
- V_ipsec6stat.out_polvio++;
- V_ip6stat.ip6s_cantforward++;
+ IPSEC6STAT_INC(out_polvio);
+ IP6STAT_INC(ip6s_cantforward);
KEY_FREESP(&sp);
if (mcopy) {
#if 0
@@ -222,7 +228,7 @@ ip6_forward(struct mbuf *m, int srcrt)
if (sp->req == NULL) {
/* XXX should be panic ? */
printf("ip6_forward: No IPsec request specified.\n");
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
KEY_FREESP(&sp);
if (mcopy) {
#if 0
@@ -306,7 +312,7 @@ ip6_forward(struct mbuf *m, int srcrt)
/* don't show these error codes to the user */
break;
}
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
if (mcopy) {
#if 0
/* XXX: what icmp ? */
@@ -347,18 +353,18 @@ ip6_forward(struct mbuf *m, int srcrt)
goto skip_routing;
skip_ipsec:
#endif
-
+again:
bzero(&rin6, sizeof(struct route_in6));
dst = (struct sockaddr_in6 *)&rin6.ro_dst;
dst->sin6_len = sizeof(struct sockaddr_in6);
dst->sin6_family = AF_INET6;
dst->sin6_addr = ip6->ip6_dst;
-
+again2:
rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
if (rin6.ro_rt != NULL)
RT_UNLOCK(rin6.ro_rt);
else {
- V_ip6stat.ip6s_noroute++;
+ IP6STAT_INC(ip6s_noroute);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
if (mcopy) {
icmp6_error(mcopy, ICMP6_DST_UNREACH,
@@ -383,13 +389,13 @@ skip_routing:
src_in6 = ip6->ip6_src;
if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) {
/* XXX: this should not happen */
- V_ip6stat.ip6s_cantforward++;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_cantforward);
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
- V_ip6stat.ip6s_cantforward++;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_cantforward);
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
if (inzone != outzone
@@ -397,8 +403,8 @@ skip_routing:
&& !ipsecrt
#endif
) {
- V_ip6stat.ip6s_cantforward++;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_cantforward);
+ IP6STAT_INC(ip6s_badscope);
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
if (V_ip6_log_time + V_ip6_log_interval < time_second) {
@@ -428,8 +434,8 @@ skip_routing:
if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
inzone != outzone) {
- V_ip6stat.ip6s_cantforward++;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_cantforward);
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
@@ -556,6 +562,7 @@ skip_routing:
if (!PFIL_HOOKED(&V_inet6_pfil_hook))
goto pass;
+ odst = ip6->ip6_dst;
/* Run through list of hooks for output packets. */
error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL);
if (error != 0)
@@ -564,16 +571,66 @@ skip_routing:
goto freecopy;
ip6 = mtod(m, struct ip6_hdr *);
+ /* See if destination IP address was changed by packet filter. */
+ if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) {
+ m->m_flags |= M_SKIP_FIREWALL;
+ /* If destination is now ourself drop to ip6_input(). */
+ if (in6_localip(&ip6->ip6_dst)) {
+ m->m_flags |= M_FASTFWD_OURS;
+ if (m->m_pkthdr.rcvif == NULL)
+ m->m_pkthdr.rcvif = V_loif;
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
+ m->m_pkthdr.csum_flags |=
+ CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+#ifdef SCTP
+ if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
+ m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
+#endif
+ error = netisr_queue(NETISR_IPV6, m);
+ goto out;
+ } else
+ goto again; /* Redo the routing table lookup. */
+ }
+
+ /* See if local, if yes, send it to netisr. */
+ if (m->m_flags & M_FASTFWD_OURS) {
+ if (m->m_pkthdr.rcvif == NULL)
+ m->m_pkthdr.rcvif = V_loif;
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
+ m->m_pkthdr.csum_flags |=
+ CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+#ifdef SCTP
+ if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
+ m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
+#endif
+ error = netisr_queue(NETISR_IPV6, m);
+ goto out;
+ }
+ /* Or forward to some other address? */
+ if ((m->m_flags & M_IP6_NEXTHOP) &&
+ (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
+ dst = (struct sockaddr_in6 *)&rin6.ro_dst;
+ bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in6));
+ m->m_flags |= M_SKIP_FIREWALL;
+ m->m_flags &= ~M_IP6_NEXTHOP;
+ m_tag_delete(m, fwd_tag);
+ goto again2;
+ }
+
pass:
error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
if (error) {
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
} else {
- V_ip6stat.ip6s_forward++;
+ IP6STAT_INC(ip6s_forward);
in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
if (type)
- V_ip6stat.ip6s_redirectsent++;
+ IP6STAT_INC(ip6s_redirectsent);
else {
if (mcopy)
goto freecopy;