[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>
This commit is contained in:
committed by
David S. Miller
parent
1619cca292
commit
3c05d92ed4
@ -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_
|
|||||||
|
|
||||||
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
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user