summaryrefslogtreecommitdiffstats
path: root/src/vnet/tcp/tcp_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/tcp/tcp_output.c')
-rw-r--r--src/vnet/tcp/tcp_output.c22
1 files changed, 9 insertions, 13 deletions
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c
index 3b1bbacbbe6..46c5661f7c1 100644
--- a/src/vnet/tcp/tcp_output.c
+++ b/src/vnet/tcp/tcp_output.c
@@ -121,33 +121,29 @@ tcp_update_rcv_wnd (tcp_connection_t * tc)
*/
available_space = transport_max_rx_enqueue (&tc->connection);
- /* Make sure we have a multiple of 1 << rcv_wscale. We round down to
- * avoid advertising a window larger than what can be buffered */
- available_space = round_down_pow2 (available_space, 1 << tc->rcv_wscale);
-
- if (PREDICT_FALSE (available_space < tc->rcv_opts.mss))
- {
- tc->rcv_wnd = 0;
- return;
- }
-
/*
* Use the above and what we know about what we've previously advertised
* to compute the new window
*/
observed_wnd = (i32) tc->rcv_wnd - (tc->rcv_nxt - tc->rcv_las);
- /* Bad. Thou shalt not shrink */
+ /* Check if we are about to retract the window. Do the comparison before
+ * rounding to avoid errors. Per RFC7323 sec. 2.4 we could remove this */
if (PREDICT_FALSE ((i32) available_space < observed_wnd))
{
- wnd = round_pow2 (clib_max (observed_wnd, 0), 1 << tc->rcv_wscale);
+ wnd = round_down_pow2 (clib_max (observed_wnd, 0), 1 << tc->rcv_wscale);
TCP_EVT (TCP_EVT_RCV_WND_SHRUNK, tc, observed_wnd, available_space);
}
else
{
- wnd = available_space;
+ /* Make sure we have a multiple of 1 << rcv_wscale. We round down to
+ * avoid advertising a window larger than what can be buffered */
+ wnd = round_down_pow2 (available_space, 1 << tc->rcv_wscale);
}
+ if (PREDICT_FALSE (wnd < tc->rcv_opts.mss))
+ wnd = 0;
+
tc->rcv_wnd = clib_min (wnd, TCP_WND_MAX << tc->rcv_wscale);
}