Hello!

The patch is appended. It is bug for all the archs,
which results in superfast restransmissions on 32bit machines and
turns off retransmissions on 64bit ones.

The patch consists of three chunks:

1. Very suspicious place. I catched the bug here, so that
   I did not delete debugging chunk. I strongly suspect
   that the problems with sockets dying in SYN_SENT (and, as recently
   reported, in SYN_RECV with weird timeout value) have similar nature.
2. Another bug: dup acks do not mean forward progress.
3. tcp_fragment() does not initialize skb->when and another
   parts of code (chunk 1) use it to calculate retr. timeout.
   Actually, it is bug in tcp_ack_packets_out(), it should not
   use skb->when blindly, but I do not know its correct variant.

Alexey




diff -ur ../orig/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- ../orig/linux/net/ipv4/tcp_input.c  Sat May  1 16:30:37 1999
+++ linux/net/ipv4/tcp_input.c  Tue May 11 22:37:54 1999
@@ -749,7 +749,6 @@
 static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
 {
        struct sk_buff *skb = skb_peek(&sk->write_queue);
-       __u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
 
        /* Some data was ACK'd, if still retransmitting (due to a
         * timeout), resend more of the retransmit queue.  The
@@ -759,6 +758,15 @@
                tcp_xmit_retransmit_queue(sk);
                tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
        } else {
+               __u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
+               if ((__s32)when < 0) {
+                       /* Before deleting this, please prove
+                          that it is impossible 8) --ANK
+                        */
+                       printk("Pizdets: %u %u %u %u\n", when, tp->rto, tcp_time_stamp,
+                              TCP_SKB_CB(skb)->when);
+                       when = 1;
+               }
                tcp_reset_xmit_timer(sk, TIME_RETRANS, when);
        }
 }
@@ -786,8 +794,6 @@
        if (after(ack, tp->snd_nxt) || before(ack, tp->snd_una))
                goto uninteresting_ack;
 
-       dst_confirm(sk->dst_cache);
-
        /* If there is data set flag 1 */
        if (len != th->doff*4) {
                flag |= FLAG_DATA;
@@ -819,7 +825,10 @@
        /* We passed data and got it acked, remove any soft error
         * log. Something worked...
         */
-       sk->err_soft = 0;
+       if (ack != tp->snd_una) {
+               sk->err_soft = 0;
+               dst_confirm(sk->dst_cache);
+       }
 
        /* If this ack opens up a zero window, clear backoff.  It was
         * being used to time the probes, and is probably far higher than
diff -ur ../orig/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- ../orig/linux/net/ipv4/tcp_output.c Sat May  1 16:30:44 1999
+++ linux/net/ipv4/tcp_output.c Tue May 11 22:37:54 1999
@@ -240,6 +240,11 @@
        /* Rechecksum original buffer. */
        skb->csum = csum_partial(skb->data, skb->len, 0);
 
+       /* Looks stupid, but our code really uses when of
+          skbs, which it never sent before. --ANK
+        */
+       TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
+
        /* Link BUFF into the send queue. */
        __skb_append(skb, buff);
 
-
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to [EMAIL PROTECTED]

Reply via email to