diff options
| -rw-r--r-- | net/ipv4/tcp_input.c | 12 | 
1 files changed, 11 insertions, 1 deletions
| diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 5a45a0923a1f..384fa5e2f065 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5174,6 +5174,16 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)  	 */  	if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {  		if (tcp_receive_window(tp) == 0) { +			/* Some stacks are known to send bare FIN packets +			 * in a loop even if we send RWIN 0 in our ACK. +			 * Accepting this FIN does not hurt memory pressure +			 * because the FIN flag will simply be merged to the +			 * receive queue tail skb in most cases. +			 */ +			if (!skb->len && +			    (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) +				goto queue_and_out; +  			reason = SKB_DROP_REASON_TCP_ZEROWINDOW;  			NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPZEROWINDOWDROP);  			goto out_of_window; @@ -5188,7 +5198,7 @@ queue_and_out:  			inet_csk_schedule_ack(sk);  			sk->sk_data_ready(sk); -			if (skb_queue_len(&sk->sk_receive_queue)) { +			if (skb_queue_len(&sk->sk_receive_queue) && skb->len) {  				reason = SKB_DROP_REASON_PROTO_MEM;  				NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVQDROP);  				goto drop; |