Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a47ed4cd authored by Noriaki TAKAMIYA's avatar Noriaki TAKAMIYA Committed by David S. Miller
Browse files

[IPV6] XFRM: Fix connected socket to use transformation.



When XFRM policy and state are ready after TCP connection is started,
the traffic should be transformed immediately, however it does not
on IPv6 TCP.

It depends on a dst cache replacement policy with connected socket.
It seems that the replacement is always done for IPv4, however, on
IPv6 case it is done only when routing cookie is changed.

This patch fix that non-transformation dst can be changed to
transformation one.
This behavior is required by MIPv6 and improves IPv6 IPsec.

Fixes by Masahide NAKAMURA.

Signed-off-by: default avatarNoriaki TAKAMIYA <takamiya@po.ntts.co.jp>
Signed-off-by: default avatarMasahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e773e4fa
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -105,6 +105,10 @@ struct rt6_info
	struct rt6key			rt6i_src;

	u8				rt6i_protocol;

#ifdef CONFIG_XFRM
	u32				rt6i_flow_cache_genid;
#endif
};

static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
+37 −2
Original line number Diff line number Diff line
@@ -139,6 +139,41 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)

EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);

static inline
void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
			   struct in6_addr *daddr, struct in6_addr *saddr)
{
	__ip6_dst_store(sk, dst, daddr, saddr);

#ifdef CONFIG_XFRM
	if (dst) {
		struct rt6_info *rt = (struct rt6_info  *)dst;
		rt->rt6i_flow_cache_genid = atomic_read(&flow_cache_genid);
	}
#endif
}

static inline
struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
{
	struct dst_entry *dst;

	dst = __sk_dst_check(sk, cookie);

#ifdef CONFIG_XFRM
	if (dst) {
		struct rt6_info *rt = (struct rt6_info *)dst;
		if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) {
			sk->sk_dst_cache = NULL;
			dst_release(dst);
			dst = NULL;
		}
	}
#endif

	return dst;
}

int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
{
	struct sock *sk = skb->sk;
@@ -166,7 +201,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
		final_p = &final;
	}

	dst = __sk_dst_check(sk, np->dst_cookie);
	dst = __inet6_csk_dst_check(sk, np->dst_cookie);

	if (dst == NULL) {
		int err = ip6_dst_lookup(sk, &dst, &fl);
@@ -186,7 +221,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
			return err;
		}

		__ip6_dst_store(sk, dst, NULL, NULL);
		__inet6_csk_dst_store(sk, dst, NULL, NULL);
	}

	skb->dst = dst_clone(dst);