diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 28 | 
1 files changed, 15 insertions, 13 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 020766292bb0..d978bb2f748b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -415,6 +415,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)  		    !icsk->icsk_backoff)  			break; +		if (sock_owned_by_user(sk)) +			break; +  		icsk->icsk_backoff--;  		inet_csk(sk)->icsk_rto = __tcp_set_rto(tp) <<  					 icsk->icsk_backoff; @@ -429,11 +432,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)  		if (remaining) {  			inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,  						  remaining, TCP_RTO_MAX); -		} else if (sock_owned_by_user(sk)) { -			/* RTO revert clocked out retransmission, -			 * but socket is locked. Will defer. */ -			inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, -						  HZ/20, TCP_RTO_MAX);  		} else {  			/* RTO revert clocked out retransmission.  			 * Will retransmit now */ @@ -1422,7 +1420,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  	newsk = tcp_create_openreq_child(sk, req, skb);  	if (!newsk) -		goto exit; +		goto exit_nonewsk;  	newsk->sk_gso_type = SKB_GSO_TCPV4;  	sk_setup_caps(newsk, dst); @@ -1469,16 +1467,20 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  	}  #endif +	if (__inet_inherit_port(sk, newsk) < 0) { +		sock_put(newsk); +		goto exit; +	}  	__inet_hash_nolisten(newsk, NULL); -	__inet_inherit_port(sk, newsk);  	return newsk;  exit_overflow:  	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); +exit_nonewsk: +	dst_release(dst);  exit:  	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); -	dst_release(dst);  	return NULL;  }  EXPORT_SYMBOL(tcp_v4_syn_recv_sock); @@ -2028,7 +2030,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)  get_req:  			req = icsk->icsk_accept_queue.listen_opt->syn_table[st->sbucket];  		} -		sk	  = sk_next(st->syn_wait_sk); +		sk	  = sk_nulls_next(st->syn_wait_sk);  		st->state = TCP_SEQ_STATE_LISTENING;  		read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);  	} else { @@ -2037,11 +2039,13 @@ get_req:  		if (reqsk_queue_len(&icsk->icsk_accept_queue))  			goto start_req;  		read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); -		sk = sk_next(sk); +		sk = sk_nulls_next(sk);  	}  get_sk:  	sk_nulls_for_each_from(sk, node) { -		if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { +		if (!net_eq(sock_net(sk), net)) +			continue; +		if (sk->sk_family == st->family) {  			cur = sk;  			goto out;  		} @@ -2571,7 +2575,6 @@ struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)  	return tcp_gro_receive(head, skb);  } -EXPORT_SYMBOL(tcp4_gro_receive);  int tcp4_gro_complete(struct sk_buff *skb)  { @@ -2584,7 +2587,6 @@ int tcp4_gro_complete(struct sk_buff *skb)  	return tcp_gro_complete(skb);  } -EXPORT_SYMBOL(tcp4_gro_complete);  struct proto tcp_prot = {  	.name			= "TCP",  | 
