Skip to content

Commit 15d99e0

Browse files
Rick Jonesdavem330
authored andcommitted
[TCP]: sysctl to allow TCP window > 32767 sans wscale
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c1b1bce commit 15d99e0

File tree

5 files changed

+34
-7
lines changed

5 files changed

+34
-7
lines changed

Documentation/networking/ip-sysctl.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,13 @@ somaxconn - INTEGER
355355
Defaults to 128. See also tcp_max_syn_backlog for additional tuning
356356
for TCP sockets.
357357

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+
358365
IP Variables:
359366

360367
ip_local_port_range - 2 INTEGERS

include/linux/sysctl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ enum
402402
NET_IPV4_IPFRAG_MAX_DIST=112,
403403
NET_TCP_MTU_PROBING=113,
404404
NET_TCP_BASE_MSS=114,
405+
NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115,
405406
};
406407

407408
enum {

include/net/tcp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ extern int sysctl_tcp_tso_win_divisor;
224224
extern int sysctl_tcp_abc;
225225
extern int sysctl_tcp_mtu_probing;
226226
extern int sysctl_tcp_base_mss;
227+
extern int sysctl_tcp_workaround_signed_windows;
227228

228229
extern atomic_t tcp_memory_allocated;
229230
extern atomic_t tcp_sockets_allocated;

net/ipv4/sysctl_net_ipv4.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,14 @@ ctl_table ipv4_table[] = {
680680
.mode = 0644,
681681
.proc_handler = &proc_dointvec,
682682
},
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+
},
684691
{ .ctl_name = 0 }
685692
};
686693

net/ipv4/tcp_output.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
/* People can turn this off for buggy TCP's found in printers etc. */
4646
int sysctl_tcp_retrans_collapse = 1;
4747

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+
4853
/* This limits the percentage of the congestion window which we
4954
* will allow a single TSO frame to consume. Building TSO frames
5055
* which are too large can cause TCP streams to be bursty.
@@ -177,12 +182,18 @@ void tcp_select_initial_window(int __space, __u32 mss,
177182
space = (space / mss) * mss;
178183

179184
/* NOTE: offering an initial window larger than 32767
180-
* will break some buggy TCP stacks. We try to be nice.
181-
* If we are not window scaling, then this truncates
182-
* our initial window offering to 32k. There should also
183-
* be a sysctl option to stop being nice.
185+
* will break some buggy TCP stacks. If the admin tells us
186+
* it is likely we could be speaking with such a buggy stack
187+
* we will truncate our initial window offering to 32K-1
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.
184191
*/
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+
186197
(*rcv_wscale) = 0;
187198
if (wscale_ok) {
188199
/* Set window scaling on max possible window
@@ -241,7 +252,7 @@ static u16 tcp_select_window(struct sock *sk)
241252
/* Make sure we do not exceed the maximum possible
242253
* scaled window.
243254
*/
244-
if (!tp->rx_opt.rcv_wscale)
255+
if (!tp->rx_opt.rcv_wscale && sysctl_tcp_workaround_signed_windows)
245256
new_win = min(new_win, MAX_TCP_WINDOW);
246257
else
247258
new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale));

0 commit comments

Comments
 (0)