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

Commit 96e0bf4b authored by John Dykstra's avatar John Dykstra Committed by David S. Miller
Browse files

tcp: Discard segments that ack data not yet sent



Discard incoming packets whose ack field iincludes data not yet sent.
This is consistent with RFC 793 Section 3.9.

Change tcp_ack() to distinguish between too-small and too-large ack
field values.  Keep segments with too-large ack fields out of the fast
path, and change slow path to discard them.

Reported-by: default avatarOliver Zheng <mailinglists+netdev@oliverzheng.com>
Signed-off-by: default avatarJohn Dykstra <john.dykstra1@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 763dccdc
Loading
Loading
Loading
Loading
+17 −10
Original line number Diff line number Diff line
@@ -3585,15 +3585,18 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
	int prior_packets;
	int frto_cwnd = 0;

	/* If the ack is newer than sent or older than previous acks
	/* If the ack is older than previous acks
	 * then we can probably ignore it.
	 */
	if (after(ack, tp->snd_nxt))
		goto uninteresting_ack;

	if (before(ack, prior_snd_una))
		goto old_ack;

	/* If the ack includes data we haven't sent yet, discard
	 * this segment (RFC793 Section 3.9).
	 */
	if (after(ack, tp->snd_nxt))
		goto invalid_ack;

	if (after(ack, prior_snd_una))
		flag |= FLAG_SND_UNA_ADVANCED;

@@ -3683,6 +3686,10 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
		tcp_ack_probe(sk);
	return 1;

invalid_ack:
	SOCK_DEBUG(sk, "Ack %u after %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
	return -1;

old_ack:
	if (TCP_SKB_CB(skb)->sacked) {
		tcp_sacktag_write_queue(sk, skb, prior_snd_una);
@@ -3690,8 +3697,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
			tcp_try_keep_open(sk);
	}

uninteresting_ack:
	SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
	SOCK_DEBUG(sk, "Ack %u before %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
	return 0;
}

@@ -5141,7 +5147,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
	 */

	if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
	    TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
	    TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
	    !after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
		int tcp_header_len = tp->tcp_header_len;

		/* Timestamp header prediction: tcp_header_len
@@ -5294,8 +5301,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
		return -res;

step5:
	if (th->ack)
		tcp_ack(sk, skb, FLAG_SLOWPATH);
	if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
		goto discard;

	tcp_rcv_rtt_measure_ts(sk, skb);

@@ -5632,7 +5639,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,

	/* step 5: check the ACK field */
	if (th->ack) {
		int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH);
		int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;

		switch (sk->sk_state) {
		case TCP_SYN_RECV: