diff options
-rw-r--r-- | Documentation/networking/ip-sysctl.txt | 7 | ||||
-rw-r--r-- | include/linux/sysctl.h | 1 | ||||
-rw-r--r-- | include/net/tcp.h | 1 | ||||
-rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 9 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 23 |
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 | ||
358 | tcp_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 | |||
358 | IP Variables: | 365 | IP Variables: |
359 | 366 | ||
360 | ip_local_port_range - 2 INTEGERS | 367 | ip_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 | ||
407 | enum { | 408 | enum { |
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; | |||
224 | extern int sysctl_tcp_abc; | 224 | extern int sysctl_tcp_abc; |
225 | extern int sysctl_tcp_mtu_probing; | 225 | extern int sysctl_tcp_mtu_probing; |
226 | extern int sysctl_tcp_base_mss; | 226 | extern int sysctl_tcp_base_mss; |
227 | extern int sysctl_tcp_workaround_signed_windows; | ||
227 | 228 | ||
228 | extern atomic_t tcp_memory_allocated; | 229 | extern atomic_t tcp_memory_allocated; |
229 | extern atomic_t tcp_sockets_allocated; | 230 | extern 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. */ |
46 | int sysctl_tcp_retrans_collapse = 1; | 46 | int 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 | */ | ||
51 | int 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)); |