aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorJohn Dykstra <john.dykstra1@gmail.com>2009-03-23 00:49:57 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-23 00:49:57 -0400
commit96e0bf4b5193d0d97d139f99e2dd128763d55521 (patch)
tree5e5a69c68072e605759a9cf9152caf0d0c6d1b7e /net/ipv4/tcp_input.c
parent763dccdc8e9775b247c3ea86ae8f5f592c12024e (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/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c27
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
3689invalid_ack:
3690 SOCK_DEBUG(sk, "Ack %u after %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
3691 return -1;
3692
3686old_ack: 3693old_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
3693uninteresting_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
5296step5: 5303step5:
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: