PATCH (was Possible Linux/Solaris 7 TCP bug)

David S. Miller (davem@redhat.com)
Fri, 13 Aug 1999 04:59:38 -0700


This is hindering my work quite badly so I'd be very grateful
if some TCP guru could take a look at the trace and tell me
which OS is the one in fault (for which one I'll need to wait
for a patch, that is).

Please try this patch, it should fix the stuck connections.

--- ./include/net/tcp.h.~1~ Wed Aug 11 04:48:56 1999
+++ ./include/net/tcp.h Fri Aug 13 04:29:02 1999
@@ -142,7 +139,8 @@
nonagle;

/* And these are ours. */
- __u32 rcv_nxt,snd_nxt;
+ __u32 rcv_nxt, snd_nxt;
+ __u16 window;
struct tcp_func *af_specific;
struct tcp_bind_bucket *tb;
struct tcp_tw_bucket *next_death;
--- ./net/ipv4/tcp_input.c.~1~ Sun Aug 8 01:44:24 1999
+++ ./net/ipv4/tcp_input.c Fri Aug 13 04:40:55 1999
@@ -1006,7 +1006,8 @@
tcp_tw_reschedule(tw);
}
/* Ack old packets if necessary */
- if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt))
+ if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt) &&
+ (th->doff * 4) > len)
return TCP_TW_ACK;
return 0;
}
@@ -1067,7 +1068,8 @@
tw->family = sk->family;
tw->reuse = sk->reuse;
tw->rcv_nxt = sk->tp_pinfo.af_tcp.rcv_nxt;
- tw->snd_nxt = sk->tp_pinfo.af_tcp.snd_nxt;
+ tw->snd_nxt = sk->tp_pinfo.af_tcp.snd_nxt;
+ tw->window = tcp_select_window(sk);
tw->af_specific = sk->tp_pinfo.af_tcp.af_specific;

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
--- ./net/ipv4/tcp_ipv4.c.~1~ Thu Aug 12 08:35:18 1999
+++ ./net/ipv4/tcp_ipv4.c Fri Aug 13 04:31:33 1999
@@ -1026,7 +1028,7 @@
*
* Assumes that the caller did basic address and flag checks.
*/
-static void tcp_v4_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack)
+static void tcp_v4_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack, __u16 window)
{
struct tcphdr *th = skb->h.th;
struct tcphdr rth;
@@ -1042,6 +1044,8 @@
rth.ack_seq = ack;
rth.ack = 1;

+ rth.window = htons(window);
+
memset(&arg, 0, sizeof arg);
arg.iov[0].iov_base = (unsigned char *)&rth;
arg.iov[0].iov_len = sizeof rth;
@@ -1774,10 +1778,12 @@
do_time_wait:
/* Sorry for the ugly switch. 2.3 will have a better solution. */
switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
- skb, th, skb->len)) {
+ skb, th, skb->len)) {
case TCP_TW_ACK:
- tcp_v4_send_ack(skb, ((struct tcp_tw_bucket *)sk)->snd_nxt,
- ((struct tcp_tw_bucket *)sk)->rcv_nxt);
+ tcp_v4_send_ack(skb,
+ ((struct tcp_tw_bucket *)sk)->snd_nxt,
+ ((struct tcp_tw_bucket *)sk)->rcv_nxt,
+ ((struct tcp_tw_bucket *)sk)->window);
goto discard_it;
case TCP_TW_RST:
goto no_tcp_socket;
--- ./net/ipv6/tcp_ipv6.c.~1~ Thu Aug 12 08:35:24 1999
+++ ./net/ipv6/tcp_ipv6.c Fri Aug 13 04:31:29 1999
@@ -1121,7 +1121,7 @@
kfree_skb(buff);
}

-static void tcp_v6_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack)
+static void tcp_v6_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack, __u16 window)
{
struct tcphdr *th = skb->h.th, *t1;
struct sk_buff *buff;
@@ -1144,6 +1144,8 @@
t1->seq = seq;
t1->ack_seq = ack;

+ t1->window = htons(window);
+
buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);

fl.nl_u.ip6_u.daddr = &skb->nh.ipv6h->saddr;
@@ -1461,10 +1463,12 @@

do_time_wait:
switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
- skb, th, skb->len)) {
+ skb, th, skb->len)) {
case TCP_TW_ACK:
- tcp_v6_send_ack(skb, ((struct tcp_tw_bucket *)sk)->snd_nxt,
- ((struct tcp_tw_bucket *)sk)->rcv_nxt);
+ tcp_v6_send_ack(skb,
+ ((struct tcp_tw_bucket *)sk)->snd_nxt,
+ ((struct tcp_tw_bucket *)sk)->rcv_nxt,
+ ((struct tcp_tw_bucket *)sk)->window);
goto discard_it;
case TCP_TW_RST:
goto no_tcp_socket;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/