diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2005-09-14 23:50:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-09-14 23:50:35 -0400 |
commit | 3c05d92ed49f644d1f5a960fa48637d63b946016 (patch) | |
tree | 4882f2b114f7bb497e9844e21fe8bff4f8160def /net | |
parent | 1619cca2921f6927f4240e03f413d4165c7002fc (diff) |
[TCP]: Compute in_sacked properly when we split up a TSO frame.
The problem is that the SACK fragmenting code may incorrectly call
tcp_fragment() with a length larger than the skb->len. This happens
when the skb on the transmit queue completely falls to the LHS of the
SACK.
And add a BUG() check to tcp_fragment() so we can spot this kind of
error more quickly in the future.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp_input.c | 16 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 2 |
2 files changed, 11 insertions, 7 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 29222b964951..a7537c7bbd06 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -979,14 +979,19 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
979 | if (!before(TCP_SKB_CB(skb)->seq, end_seq)) | 979 | if (!before(TCP_SKB_CB(skb)->seq, end_seq)) |
980 | break; | 980 | break; |
981 | 981 | ||
982 | in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && | ||
983 | !before(end_seq, TCP_SKB_CB(skb)->end_seq); | ||
984 | |||
982 | pcount = tcp_skb_pcount(skb); | 985 | pcount = tcp_skb_pcount(skb); |
983 | 986 | ||
984 | if (pcount > 1 && | 987 | if (pcount > 1 && !in_sack && |
985 | (after(start_seq, TCP_SKB_CB(skb)->seq) || | 988 | after(TCP_SKB_CB(skb)->end_seq, start_seq)) { |
986 | before(end_seq, TCP_SKB_CB(skb)->end_seq))) { | ||
987 | unsigned int pkt_len; | 989 | unsigned int pkt_len; |
988 | 990 | ||
989 | if (after(start_seq, TCP_SKB_CB(skb)->seq)) | 991 | in_sack = !after(start_seq, |
992 | TCP_SKB_CB(skb)->seq); | ||
993 | |||
994 | if (!in_sack) | ||
990 | pkt_len = (start_seq - | 995 | pkt_len = (start_seq - |
991 | TCP_SKB_CB(skb)->seq); | 996 | TCP_SKB_CB(skb)->seq); |
992 | else | 997 | else |
@@ -999,9 +1004,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
999 | 1004 | ||
1000 | fack_count += pcount; | 1005 | fack_count += pcount; |
1001 | 1006 | ||
1002 | in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && | ||
1003 | !before(end_seq, TCP_SKB_CB(skb)->end_seq); | ||
1004 | |||
1005 | sacked = TCP_SKB_CB(skb)->sacked; | 1007 | sacked = TCP_SKB_CB(skb)->sacked; |
1006 | 1008 | ||
1007 | /* Account D-SACK for retransmitted packet. */ | 1009 | /* Account D-SACK for retransmitted packet. */ |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index c10e4435e3b1..b018e31b6530 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -435,6 +435,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss | |||
435 | int nsize, old_factor; | 435 | int nsize, old_factor; |
436 | u16 flags; | 436 | u16 flags; |
437 | 437 | ||
438 | BUG_ON(len >= skb->len); | ||
439 | |||
438 | nsize = skb_headlen(skb) - len; | 440 | nsize = skb_headlen(skb) - len; |
439 | if (nsize < 0) | 441 | if (nsize < 0) |
440 | nsize = 0; | 442 | nsize = 0; |