summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2004-10-25 06:57:45 -0700
committerDavid S. Miller <davem@nuts.davemloft.net>2004-10-25 06:57:45 -0700
commitf335c143218df5b29b9d55211e6a6141ce1b67fd (patch)
tree5da2bff36931adb6e2f8ea83d76cb47bdc7804ac
parent7515caf10ea7ef7d433d50a213769225f44d8180 (diff)
[TCP]: Handle real partial-ACKs of TSO frames correctly.
Actually, I think we've caught your crash now. If that code path is triggering at all, then it'll trigger with TSO packets too. If we get a truly partial ack on a TSO packet, then tcp_tso_acked will not trim it off. So we will fall through to this last-ditch trim call, which doesn't update packets_out. There are two solutions to this problem. I've taken the simpler approach for now. We simply trim off the partial bits in tcp_tso_acked and live with the fact that the packet counters may differ from what's on the netwrok by one. Later on we can 'fix' this by remembering where the original TSO packet started from, perhaps in skb->h or somewhere. Dave, is this worth it? Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/tcp_input.c18
-rw-r--r--net/ipv4/tcp_output.c2
2 files changed, 7 insertions, 13 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 559ba0c55da5..e8769f30f0c6 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2369,25 +2369,19 @@ static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb,
{
struct tcp_opt *tp = tcp_sk(sk);
struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
- __u32 mss = tcp_skb_mss(skb);
- __u32 snd_una = tp->snd_una;
- __u32 orig_seq, seq;
- __u32 packets_acked = 0;
+ __u32 seq = tp->snd_una;
+ __u32 packets_acked;
int acked = 0;
/* If we get here, the whole TSO packet has not been
* acked.
*/
- BUG_ON(!after(scb->end_seq, snd_una));
+ BUG_ON(!after(scb->end_seq, seq));
- seq = orig_seq = scb->seq;
- while (!after(seq + mss, snd_una)) {
- packets_acked++;
- seq += mss;
- }
-
- if (tcp_trim_head(sk, skb, (seq - orig_seq)))
+ packets_acked = tcp_skb_pcount(skb);
+ if (tcp_trim_head(sk, skb, seq - scb->seq))
return 0;
+ packets_acked -= tcp_skb_pcount(skb);
if (packets_acked) {
__u8 sacked = scb->sacked;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index b268b7d65976..0b08a3499b29 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -588,7 +588,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
/* Any change of skb->len requires recalculation of tso
* factor and mss.
*/
- if (tcp_skb_mss(skb))
+ if (tcp_skb_pcount(skb) > 1)
tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb));
return 0;