diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 15 | 
1 files changed, 14 insertions, 1 deletions
| diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9c0b54e87b47..1f5e62229aaa 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1199,6 +1199,8 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +  						     newnp->opt->opt_flen); +	tcp_ca_openreq_child(newsk, dst); +  	tcp_sync_mss(newsk, dst_mtu(dst));  	newtp->advmss = dst_metric_advmss(dst);  	if (tcp_sk(sk)->rx_opt.user_mss && @@ -1409,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; @@ -1541,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 */ @@ -1549,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:  		; @@ -1583,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); |