diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-01 12:09:33 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-01 12:09:33 -0700 |
commit | 54866f032307063776b4eff7eadb131d47f9f9b4 (patch) | |
tree | 5fb7b5f886b43fbe115e81c14570c40c44956b53 /net/ipv4/tcp_input.c | |
parent | b4d367fb20ed19be4a53fa88b407248aeb8bd461 (diff) | |
parent | 49259d34c52df6be482fefca946debe28ba9a2f6 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
[IRDA] IRNET: Fix build when TCGETS2 is defined.
[NET]: docbook fixes for netif_ functions
[NET]: Hide the net_ns kmem cache
[NET]: Mark the setup_net as __net_init
[NET]: Hide the dead code in the net_namespace.c
[NET]: Relax the reference counting of init_net_ns
[NETNS]: Make the init/exit hooks checks outside the loop
[NET]: Forget the zero_it argument of sk_alloc()
[NET]: Remove bogus zero_it argument from sk_alloc
[NET]: Make the sk_clone() lighter
[NET]: Move some core sock setup into sk_prot_alloc
[NET]: Auto-zero the allocated sock object
[NET]: Cleanup the allocation/freeing of the sock object
[NET]: Move the get_net() from sock_copy()
[NET]: Move the sock_copy() from the header
[TCP]: Another TAGBITS -> SACKED_ACKED|LOST conversion
[TCP]: Process DSACKs that reside within a SACK block
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 69d8c38ccd3..ca9590f4f52 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1330,12 +1330,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ cached_fack_count = 0; } - for (i=0; i<num_sacks; i++, sp++) { + for (i = 0; i < num_sacks; i++) { struct sk_buff *skb; __u32 start_seq = ntohl(sp->start_seq); __u32 end_seq = ntohl(sp->end_seq); int fack_count; int dup_sack = (found_dup_sack && (i == first_sack_index)); + int next_dup = (found_dup_sack && (i+1 == first_sack_index)); + + sp++; if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) { if (dup_sack) { @@ -1361,7 +1364,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ flag |= FLAG_DATA_LOST; tcp_for_write_queue_from(skb, sk) { - int in_sack; + int in_sack = 0; u8 sacked; if (skb == tcp_send_head(sk)) @@ -1380,7 +1383,23 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (!before(TCP_SKB_CB(skb)->seq, end_seq)) break; - in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq); + dup_sack = (found_dup_sack && (i == first_sack_index)); + + /* Due to sorting DSACK may reside within this SACK block! */ + if (next_dup) { + u32 dup_start = ntohl(sp->start_seq); + u32 dup_end = ntohl(sp->end_seq); + + if (before(TCP_SKB_CB(skb)->seq, dup_end)) { + in_sack = tcp_match_skb_to_sack(sk, skb, dup_start, dup_end); + if (in_sack > 0) + dup_sack = 1; + } + } + + /* DSACK info lost if out-of-mem, try SACK still */ + if (in_sack <= 0) + in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq); if (in_sack < 0) break; @@ -2059,7 +2078,7 @@ static void tcp_update_scoreboard(struct sock *sk) if (!tcp_skb_timedout(sk, skb)) break; - if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { + if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_SACKED_ACKED|TCPCB_LOST))) { TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; tp->lost_out += tcp_skb_pcount(skb); tcp_verify_retransmit_hint(tp, skb); |