diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 13 | 
1 files changed, 12 insertions, 1 deletions
| diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5d46832c6f72..1f5e62229aaa 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1411,6 +1411,15 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,  	TCP_SKB_CB(skb)->sacked = 0;  } +static void tcp_v6_restore_cb(struct sk_buff *skb) +{ +	/* We need to move header back to the beginning if xfrm6_policy_check() +	 * and tcp_v6_fill_cb() are going to be called again. +	 */ +	memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, +		sizeof(struct inet6_skb_parm)); +} +  static int tcp_v6_rcv(struct sk_buff *skb)  {  	const struct tcphdr *th; @@ -1543,6 +1552,7 @@ do_time_wait:  			inet_twsk_deschedule(tw, &tcp_death_row);  			inet_twsk_put(tw);  			sk = sk2; +			tcp_v6_restore_cb(skb);  			goto process;  		}  		/* Fall through to ACK */ @@ -1551,6 +1561,7 @@ do_time_wait:  		tcp_v6_timewait_ack(sk, skb);  		break;  	case TCP_TW_RST: +		tcp_v6_restore_cb(skb);  		goto no_tcp_socket;  	case TCP_TW_SUCCESS:  		; @@ -1585,7 +1596,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb)  		skb->sk = sk;  		skb->destructor = sock_edemux;  		if (sk->sk_state != TCP_TIME_WAIT) { -			struct dst_entry *dst = sk->sk_rx_dst; +			struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);  			if (dst)  				dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); |