Commit 3c05d92e authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[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: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1619cca2
...@@ -979,14 +979,19 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ ...@@ -979,14 +979,19 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
if (!before(TCP_SKB_CB(skb)->seq, end_seq)) if (!before(TCP_SKB_CB(skb)->seq, end_seq))
break; break;
in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
!before(end_seq, TCP_SKB_CB(skb)->end_seq);
pcount = tcp_skb_pcount(skb); pcount = tcp_skb_pcount(skb);
if (pcount > 1 && if (pcount > 1 && !in_sack &&
(after(start_seq, TCP_SKB_CB(skb)->seq) || after(TCP_SKB_CB(skb)->end_seq, start_seq)) {
before(end_seq, TCP_SKB_CB(skb)->end_seq))) {
unsigned int pkt_len; unsigned int pkt_len;
if (after(start_seq, TCP_SKB_CB(skb)->seq)) in_sack = !after(start_seq,
TCP_SKB_CB(skb)->seq);
if (!in_sack)
pkt_len = (start_seq - pkt_len = (start_seq -
TCP_SKB_CB(skb)->seq); TCP_SKB_CB(skb)->seq);
else else
...@@ -999,9 +1004,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ ...@@ -999,9 +1004,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
fack_count += pcount; fack_count += pcount;
in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
!before(end_seq, TCP_SKB_CB(skb)->end_seq);
sacked = TCP_SKB_CB(skb)->sacked; sacked = TCP_SKB_CB(skb)->sacked;
/* Account D-SACK for retransmitted packet. */ /* Account D-SACK for retransmitted packet. */
......
...@@ -435,6 +435,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss ...@@ -435,6 +435,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss
int nsize, old_factor; int nsize, old_factor;
u16 flags; u16 flags;
BUG_ON(len >= skb->len);
nsize = skb_headlen(skb) - len; nsize = skb_headlen(skb) - len;
if (nsize < 0) if (nsize < 0)
nsize = 0; nsize = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment