[TCP]: sysctl to allow TCP window > 32767 sans wscale
Rick Jones [Tue, 21 Mar 2006 06:40:29 +0000 (22:40 -0800)]
Back in the dark ages, we had to be conservative and only allow 15-bit
window fields if the window scale option was not negotiated.  Some
ancient stacks used a signed 16-bit quantity for the window field of
the TCP header and would get confused.

Those days are long gone, so we can use the full 16-bits by default
now.

There is a sysctl added so that we can still interact with such old
stacks

Signed-off-by: Rick Jones <rick.jones2@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Documentation/networking/ip-sysctl.txt
include/linux/sysctl.h
include/net/tcp.h
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_output.c

index 651298b..f12007b 100644 (file)
@@ -355,6 +355,13 @@ somaxconn - INTEGER
        Defaults to 128.  See also tcp_max_syn_backlog for additional tuning
        for TCP sockets.
 
+tcp_workaround_signed_windows - BOOLEAN
+       If set, assume no receipt of a window scaling option means the
+       remote TCP is broken and treats the window as a signed quantity.
+       If unset, assume the remote TCP is not broken even if we do
+       not receive a window scaling option from them.
+       Default: 0
+
 IP Variables:
 
 ip_local_port_range - 2 INTEGERS
index 8754568..76eaeff 100644 (file)
@@ -402,6 +402,7 @@ enum
        NET_IPV4_IPFRAG_MAX_DIST=112,
        NET_TCP_MTU_PROBING=113,
        NET_TCP_BASE_MSS=114,
+       NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115,
 };
 
 enum {
index 16879fa..457e224 100644 (file)
@@ -224,6 +224,7 @@ extern int sysctl_tcp_tso_win_divisor;
 extern int sysctl_tcp_abc;
 extern int sysctl_tcp_mtu_probing;
 extern int sysctl_tcp_base_mss;
+extern int sysctl_tcp_workaround_signed_windows;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
index ebf2e0b..6b6c3ad 100644 (file)
@@ -680,7 +680,14 @@ ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
-
+        {
+               .ctl_name       = NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS,
+               .procname       = "tcp_workaround_signed_windows",
+               .data           = &sysctl_tcp_workaround_signed_windows,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
        { .ctl_name = 0 }
 };
 
index 518e568..9d79546 100644 (file)
 /* People can turn this off for buggy TCP's found in printers etc. */
 int sysctl_tcp_retrans_collapse = 1;
 
+/* People can turn this on to  work with those rare, broken TCPs that
+ * interpret the window field as a signed quantity.
+ */
+int sysctl_tcp_workaround_signed_windows = 0;
+
 /* This limits the percentage of the congestion window which we
  * will allow a single TSO frame to consume.  Building TSO frames
  * which are too large can cause TCP streams to be bursty.
@@ -177,12 +182,18 @@ void tcp_select_initial_window(int __space, __u32 mss,
                space = (space / mss) * mss;
 
        /* NOTE: offering an initial window larger than 32767
-        * will break some buggy TCP stacks. We try to be nice.
-        * If we are not window scaling, then this truncates
-        * our initial window offering to 32k. There should also
-        * be a sysctl option to stop being nice.
+        * will break some buggy TCP stacks. If the admin tells us
+        * it is likely we could be speaking with such a buggy stack
+        * we will truncate our initial window offering to 32K-1
+        * unless the remote has sent us a window scaling option,
+        * which we interpret as a sign the remote TCP is not
+        * misinterpreting the window field as a signed quantity.
         */
-       (*rcv_wnd) = min(space, MAX_TCP_WINDOW);
+       if (sysctl_tcp_workaround_signed_windows)
+               (*rcv_wnd) = min(space, MAX_TCP_WINDOW);
+       else
+               (*rcv_wnd) = space;
+
        (*rcv_wscale) = 0;
        if (wscale_ok) {
                /* Set window scaling on max possible window
@@ -241,7 +252,7 @@ static u16 tcp_select_window(struct sock *sk)
        /* Make sure we do not exceed the maximum possible
         * scaled window.
         */
-       if (!tp->rx_opt.rcv_wscale)
+       if (!tp->rx_opt.rcv_wscale && sysctl_tcp_workaround_signed_windows)
                new_win = min(new_win, MAX_TCP_WINDOW);
        else
                new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale));