diff options
author | John Dykstra <john.dykstra1@gmail.com> | 2009-03-23 00:49:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-23 00:49:57 -0400 |
commit | 96e0bf4b5193d0d97d139f99e2dd128763d55521 (patch) | |
tree | 5e5a69c68072e605759a9cf9152caf0d0c6d1b7e /net/ipv4 | |
parent | 763dccdc8e9775b247c3ea86ae8f5f592c12024e (diff) |
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: Oliver Zheng <mailinglists+netdev@oliverzheng.com>
Signed-off-by: John Dykstra <john.dykstra1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp_input.c | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 8ac82b3703ab..2bc8e27a163d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -3585,15 +3585,18 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) | |||
3585 | int prior_packets; | 3585 | int prior_packets; |
3586 | int frto_cwnd = 0; | 3586 | int frto_cwnd = 0; |
3587 | 3587 | ||
3588 | /* If the ack is newer than sent or older than previous acks | 3588 | /* If the ack is older than previous acks |
3589 | * then we can probably ignore it. | 3589 | * then we can probably ignore it. |
3590 | */ | 3590 | */ |
3591 | if (after(ack, tp->snd_nxt)) | ||
3592 | goto uninteresting_ack; | ||
3593 | |||
3594 | if (before(ack, prior_snd_una)) | 3591 | if (before(ack, prior_snd_una)) |
3595 | goto old_ack; | 3592 | goto old_ack; |
3596 | 3593 | ||
3594 | /* If the ack includes data we haven't sent yet, discard | ||
3595 | * this segment (RFC793 Section 3.9). | ||
3596 | */ | ||
3597 | if (after(ack, tp->snd_nxt)) | ||
3598 | goto invalid_ack; | ||
3599 | |||
3597 | if (after(ack, prior_snd_una)) | 3600 | if (after(ack, prior_snd_una)) |
3598 | flag |= FLAG_SND_UNA_ADVANCED; | 3601 | flag |= FLAG_SND_UNA_ADVANCED; |
3599 | 3602 | ||
@@ -3683,6 +3686,10 @@ no_queue: | |||
3683 | tcp_ack_probe(sk); | 3686 | tcp_ack_probe(sk); |
3684 | return 1; | 3687 | return 1; |
3685 | 3688 | ||
3689 | invalid_ack: | ||
3690 | SOCK_DEBUG(sk, "Ack %u after %u:%u\n", ack, tp->snd_una, tp->snd_nxt); | ||
3691 | return -1; | ||
3692 | |||
3686 | old_ack: | 3693 | old_ack: |
3687 | if (TCP_SKB_CB(skb)->sacked) { | 3694 | if (TCP_SKB_CB(skb)->sacked) { |
3688 | tcp_sacktag_write_queue(sk, skb, prior_snd_una); | 3695 | tcp_sacktag_write_queue(sk, skb, prior_snd_una); |
@@ -3690,8 +3697,7 @@ old_ack: | |||
3690 | tcp_try_keep_open(sk); | 3697 | tcp_try_keep_open(sk); |
3691 | } | 3698 | } |
3692 | 3699 | ||
3693 | uninteresting_ack: | 3700 | SOCK_DEBUG(sk, "Ack %u before %u:%u\n", ack, tp->snd_una, tp->snd_nxt); |
3694 | SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt); | ||
3695 | return 0; | 3701 | return 0; |
3696 | } | 3702 | } |
3697 | 3703 | ||
@@ -5141,7 +5147,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
5141 | */ | 5147 | */ |
5142 | 5148 | ||
5143 | if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags && | 5149 | if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags && |
5144 | TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { | 5150 | TCP_SKB_CB(skb)->seq == tp->rcv_nxt && |
5151 | !after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) { | ||
5145 | int tcp_header_len = tp->tcp_header_len; | 5152 | int tcp_header_len = tp->tcp_header_len; |
5146 | 5153 | ||
5147 | /* Timestamp header prediction: tcp_header_len | 5154 | /* Timestamp header prediction: tcp_header_len |
@@ -5294,8 +5301,8 @@ slow_path: | |||
5294 | return -res; | 5301 | return -res; |
5295 | 5302 | ||
5296 | step5: | 5303 | step5: |
5297 | if (th->ack) | 5304 | if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) |
5298 | tcp_ack(sk, skb, FLAG_SLOWPATH); | 5305 | goto discard; |
5299 | 5306 | ||
5300 | tcp_rcv_rtt_measure_ts(sk, skb); | 5307 | tcp_rcv_rtt_measure_ts(sk, skb); |
5301 | 5308 | ||
@@ -5632,7 +5639,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
5632 | 5639 | ||
5633 | /* step 5: check the ACK field */ | 5640 | /* step 5: check the ACK field */ |
5634 | if (th->ack) { | 5641 | if (th->ack) { |
5635 | int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH); | 5642 | int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0; |
5636 | 5643 | ||
5637 | switch (sk->sk_state) { | 5644 | switch (sk->sk_state) { |
5638 | case TCP_SYN_RECV: | 5645 | case TCP_SYN_RECV: |