summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/ip6_forward.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/ip6_forward.c')
-rw-r--r--sys/netinet6/ip6_forward.c107
1 files changed, 38 insertions, 69 deletions
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 0ce591f..ca5101f 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -77,10 +77,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6protosw.h>
-#ifdef VIMAGE_GLOBALS
-struct route_in6 ip6_forward_rt;
-#endif
-
/*
* Forward a packet. If some error occurs return the sender
* an icmp packet. Note we can't always generate a meaningful
@@ -100,6 +96,7 @@ ip6_forward(struct mbuf *m, int srcrt)
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
struct sockaddr_in6 *dst = NULL;
struct rtentry *rt = NULL;
+ struct route_in6 rin6;
int error, type = 0, code = 0;
struct mbuf *mcopy = NULL;
struct ifnet *origifp; /* maybe unnecessary */
@@ -112,8 +109,6 @@ ip6_forward(struct mbuf *m, int srcrt)
#endif
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
- /* GIANT_REQUIRED; */ /* XXX bz: ip6_forward_rt */
-
#ifdef IPSEC
/*
* Check AH/ESP integrity.
@@ -355,56 +350,27 @@ ip6_forward(struct mbuf *m, int srcrt)
skip_ipsec:
#endif
- dst = (struct sockaddr_in6 *)&V_ip6_forward_rt.ro_dst;
- if (!srcrt) {
- /* ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst */
- if (V_ip6_forward_rt.ro_rt == 0 ||
- (V_ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) {
- if (V_ip6_forward_rt.ro_rt) {
- RTFREE(V_ip6_forward_rt.ro_rt);
- V_ip6_forward_rt.ro_rt = 0;
- }
-
- /* this probably fails but give it a try again */
- rtalloc((struct route *)&V_ip6_forward_rt);
- }
-
- if (V_ip6_forward_rt.ro_rt == 0) {
- V_ip6stat.ip6s_noroute++;
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
- if (mcopy) {
- icmp6_error(mcopy, ICMP6_DST_UNREACH,
- ICMP6_DST_UNREACH_NOROUTE, 0);
- }
- m_freem(m);
- return;
- }
- } else if ((rt = V_ip6_forward_rt.ro_rt) == 0 ||
- !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
- if (V_ip6_forward_rt.ro_rt) {
- RTFREE(V_ip6_forward_rt.ro_rt);
- V_ip6_forward_rt.ro_rt = 0;
- }
- bzero(dst, sizeof(*dst));
- dst->sin6_len = sizeof(struct sockaddr_in6);
- dst->sin6_family = AF_INET6;
- dst->sin6_addr = ip6->ip6_dst;
-
- rtalloc((struct route *)&V_ip6_forward_rt);
- if (V_ip6_forward_rt.ro_rt == 0) {
- V_ip6stat.ip6s_noroute++;
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
- if (mcopy) {
- icmp6_error(mcopy, ICMP6_DST_UNREACH,
- ICMP6_DST_UNREACH_NOROUTE, 0);
- }
- m_freem(m);
- return;
+ 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;
+
+ rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0);
+ if (rin6.ro_rt != NULL)
+ RT_UNLOCK(rin6.ro_rt);
+ else {
+ V_ip6stat.ip6s_noroute++;
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
+ if (mcopy) {
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_NOROUTE, 0);
}
+ goto bad;
}
- rt = V_ip6_forward_rt.ro_rt;
+ rt = rin6.ro_rt;
#ifdef IPSEC
- skip_routing:;
+skip_routing:
#endif
/*
@@ -421,14 +387,12 @@ skip_ipsec:
/* XXX: this should not happen */
V_ip6stat.ip6s_cantforward++;
V_ip6stat.ip6s_badscope++;
- m_freem(m);
- return;
+ goto bad;
}
if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
V_ip6stat.ip6s_cantforward++;
V_ip6stat.ip6s_badscope++;
- m_freem(m);
- return;
+ goto bad;
}
if (inzone != outzone
#ifdef IPSEC
@@ -452,8 +416,7 @@ skip_ipsec:
if (mcopy)
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
- m_freem(m);
- return;
+ goto bad;
}
/*
@@ -469,8 +432,7 @@ skip_ipsec:
inzone != outzone) {
V_ip6stat.ip6s_cantforward++;
V_ip6stat.ip6s_badscope++;
- m_freem(m);
- return;
+ goto bad;
}
if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
@@ -510,8 +472,7 @@ skip_ipsec:
#endif /* IPSEC */
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
}
- m_freem(m);
- return;
+ goto bad;
}
if (rt->rt_flags & RTF_GATEWAY)
@@ -544,8 +505,7 @@ skip_ipsec:
*/
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_ADDR, 0);
- m_freem(m);
- return;
+ goto bad;
}
type = ND_REDIRECT;
}
@@ -624,12 +584,12 @@ pass:
senderr:
if (mcopy == NULL)
- return;
+ goto out;
switch (error) {
case 0:
if (type == ND_REDIRECT) {
icmp6_redirect_output(mcopy, rt);
- return;
+ goto out;
}
goto freecopy;
@@ -651,9 +611,18 @@ senderr:
break;
}
icmp6_error(mcopy, type, code, 0);
- return;
+ goto out;
freecopy:
m_freem(mcopy);
- return;
+ goto out;
+bad:
+ m_freem(m);
+out:
+ if (rt != NULL
+#ifdef IPSEC
+ && !ipsecrt
+#endif
+ )
+ RTFREE(rt);
}
OpenPOWER on IntegriCloud