summaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_vti.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_vti.c')
-rw-r--r--net/ipv6/ip6_vti.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index bcda14de7f8..ace10d0b3aa 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -95,6 +95,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote,
unsigned int hash = HASH(remote, local);
struct ip6_tnl *t;
struct vti6_net *ip6n = net_generic(net, vti6_net_id);
+ struct in6_addr any;
for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (ipv6_addr_equal(local, &t->parms.laddr) &&
@@ -102,6 +103,22 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote,
(t->dev->flags & IFF_UP))
return t;
}
+
+ memset(&any, 0, sizeof(any));
+ hash = HASH(&any, local);
+ for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ if (ipv6_addr_equal(local, &t->parms.laddr) &&
+ (t->dev->flags & IFF_UP))
+ return t;
+ }
+
+ hash = HASH(remote, &any);
+ for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ if (ipv6_addr_equal(remote, &t->parms.raddr) &&
+ (t->dev->flags & IFF_UP))
+ return t;
+ }
+
t = rcu_dereference(ip6n->tnls_wc[0]);
if (t && (t->dev->flags & IFF_UP))
return t;
@@ -287,8 +304,8 @@ static int vti6_rcv(struct sk_buff *skb)
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
rcu_read_lock();
- if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
- &ipv6h->daddr)) != NULL) {
+ t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
+ if (t != NULL) {
if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) {
rcu_read_unlock();
goto discard;
@@ -412,6 +429,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
struct net_device_stats *stats = &t->dev->stats;
struct dst_entry *dst = skb_dst(skb);
struct net_device *tdev;
+ struct xfrm_state *x;
int err = -1;
if (!dst)
@@ -425,7 +443,12 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
goto tx_err_link_failure;
}
- if (!vti6_state_check(dst->xfrm, &t->parms.raddr, &t->parms.laddr))
+ x = dst->xfrm;
+ if (!vti6_state_check(x, &t->parms.raddr, &t->parms.laddr))
+ goto tx_err_link_failure;
+
+ if (!ip6_tnl_xmit_ctl(t, (const struct in6_addr *)&x->props.saddr,
+ (const struct in6_addr *)&x->id.daddr))
goto tx_err_link_failure;
tdev = dst->dev;
@@ -480,7 +503,7 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
ipv6h = ipv6_hdr(skb);
if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
- !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
+ vti6_addr_conflict(t, ipv6h))
goto tx_err;
xfrm_decode_session(skb, &fl, AF_INET6);