Skip to content

Commit

Permalink
tcp: Discard segments that ack data not yet sent
Browse files Browse the repository at this point in the history
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:  Oliver Zheng <mailinglists+netdev@oliverzheng.com>
Signed-off-by: John Dykstra <john.dykstra1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
John Dykstra authored and David S. Miller committed Mar 23, 2009
1 parent 763dccd commit 96e0bf4
Showing 1 changed file with 17 additions and 10 deletions.
27 changes: 17 additions & 10 deletions net/ipv4/tcp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -3683,15 +3686,18 @@ 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);
if (icsk->icsk_ca_state == TCP_CA_Open)
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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 96e0bf4

Please sign in to comment.