aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/ip-sysctl.txt7
-rw-r--r--include/linux/sysctl.h1
-rw-r--r--include/net/tcp.h1
-rw-r--r--net/ipv4/sysctl_net_ipv4.c9
-rw-r--r--net/ipv4/tcp_output.c23
5 files changed, 34 insertions, 7 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 651298ba019a..f12007b80a46 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -355,6 +355,13 @@ somaxconn - INTEGER
355 Defaults to 128. See also tcp_max_syn_backlog for additional tuning 355 Defaults to 128. See also tcp_max_syn_backlog for additional tuning
356 for TCP sockets. 356 for TCP sockets.
357 357
358tcp_workaround_signed_windows - BOOLEAN
359 If set, assume no receipt of a window scaling option means the
360 remote TCP is broken and treats the window as a signed quantity.
361 If unset, assume the remote TCP is not broken even if we do
362 not receive a window scaling option from them.
363 Default: 0
364
358IP Variables: 365IP Variables:
359 366
360ip_local_port_range - 2 INTEGERS 367ip_local_port_range - 2 INTEGERS
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 8754568a75d7..76eaeff76f82 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -402,6 +402,7 @@ enum
402 NET_IPV4_IPFRAG_MAX_DIST=112, 402 NET_IPV4_IPFRAG_MAX_DIST=112,
403 NET_TCP_MTU_PROBING=113, 403 NET_TCP_MTU_PROBING=113,
404 NET_TCP_BASE_MSS=114, 404 NET_TCP_BASE_MSS=114,
405 NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115,
405}; 406};
406 407
407enum { 408enum {
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 16879fa560de..457e224de468 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -224,6 +224,7 @@ extern int sysctl_tcp_tso_win_divisor;
224extern int sysctl_tcp_abc; 224extern int sysctl_tcp_abc;
225extern int sysctl_tcp_mtu_probing; 225extern int sysctl_tcp_mtu_probing;
226extern int sysctl_tcp_base_mss; 226extern int sysctl_tcp_base_mss;
227extern int sysctl_tcp_workaround_signed_windows;
227 228
228extern atomic_t tcp_memory_allocated; 229extern atomic_t tcp_memory_allocated;
229extern atomic_t tcp_sockets_allocated; 230extern atomic_t tcp_sockets_allocated;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index ebf2e0b363c4..6b6c3adfcf00 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -680,7 +680,14 @@ ctl_table ipv4_table[] = {
680 .mode = 0644, 680 .mode = 0644,
681 .proc_handler = &proc_dointvec, 681 .proc_handler = &proc_dointvec,
682 }, 682 },
683 683 {
684 .ctl_name = NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS,
685 .procname = "tcp_workaround_signed_windows",
686 .data = &sysctl_tcp_workaround_signed_windows,
687 .maxlen = sizeof(int),
688 .mode = 0644,
689 .proc_handler = &proc_dointvec
690 },
684 { .ctl_name = 0 } 691 { .ctl_name = 0 }
685}; 692};
686 693
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 518e568b53f3..9d79546d384e 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -45,6 +45,11 @@
45/* People can turn this off for buggy TCP's found in printers etc. */ 45/* People can turn this off for buggy TCP's found in printers etc. */
46int sysctl_tcp_retrans_collapse = 1; 46int sysctl_tcp_retrans_collapse = 1;
47 47
48/* People can turn this on to work with those rare, broken TCPs that
49 * interpret the window field as a signed quantity.
50 */
51int sysctl_tcp_workaround_signed_windows = 0;
52
48/* This limits the percentage of the congestion window which we 53/* This limits the percentage of the congestion window which we
49 * will allow a single TSO frame to consume. Building TSO frames 54 * will allow a single TSO frame to consume. Building TSO frames
50 * which are too large can cause TCP streams to be bursty. 55 * which are too large can cause TCP streams to be bursty.
@@ -177,12 +182,18 @@ void tcp_select_initial_window(int __space, __u32 mss,
177 space = (space / mss) * mss; 182 space = (space / mss) * mss;
178 183
179 /* NOTE: offering an initial window larger than 32767 184 /* NOTE: offering an initial window larger than 32767
180 * will break some buggy TCP stacks. We try to be nice. 185 * will break some buggy TCP stacks. If the admin tells us
181 * If we are not window scaling, then this truncates 186 * it is likely we could be speaking with such a buggy stack
182 * our initial window offering to 32k. There should also 187 * we will truncate our initial window offering to 32K-1
183 * be a sysctl option to stop being nice. 188 * unless the remote has sent us a window scaling option,
189 * which we interpret as a sign the remote TCP is not
190 * misinterpreting the window field as a signed quantity.
184 */ 191 */
185 (*rcv_wnd) = min(space, MAX_TCP_WINDOW); 192 if (sysctl_tcp_workaround_signed_windows)
193 (*rcv_wnd) = min(space, MAX_TCP_WINDOW);
194 else
195 (*rcv_wnd) = space;
196
186 (*rcv_wscale) = 0; 197 (*rcv_wscale) = 0;
187 if (wscale_ok) { 198 if (wscale_ok) {
188 /* Set window scaling on max possible window 199 /* Set window scaling on max possible window
@@ -241,7 +252,7 @@ static u16 tcp_select_window(struct sock *sk)
241 /* Make sure we do not exceed the maximum possible 252 /* Make sure we do not exceed the maximum possible
242 * scaled window. 253 * scaled window.
243 */ 254 */
244 if (!tp->rx_opt.rcv_wscale) 255 if (!tp->rx_opt.rcv_wscale && sysctl_tcp_workaround_signed_windows)
245 new_win = min(new_win, MAX_TCP_WINDOW); 256 new_win = min(new_win, MAX_TCP_WINDOW);
246 else 257 else
247 new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale)); 258 new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale));