| Summary: | tcp advertises wrong window if tcpsendspace and tcprecvspace are set to 64K | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | jayanth <jayanth> | ||||
| Component: | kern | Assignee: | freebsd-bugs (Nobody) <bugs> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | 4.0-CURRENT | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
State Changed From-To: open->closed |
There seems to be a certain condition where tcp advertises the wrong window size when the tcpsendspace and tcprecvspace value are set to a value = 65536(>65000 ) Assume rfc1323 is off. Went through the code and found that in tcp_input.c in tcp_mss() the following code bumps the value from 65536 to 65700 tcp_mss() --------- #ifdef RTV_RPIPE if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0) #endif bufsize = so->so_rcv.sb_hiwat; if (bufsize > mss) { bufsize = roundup(bufsize, mss); ^^^^^^^^^^^^^^^^^^^^^^^^^^^ if (bufsize > sb_max) bufsize = sb_max; (void)sbreserve(&so->so_rcv, bufsize); If the keepalive timer expires the tcp_respond() uses the sbspace(so->so_rcv) to determine the window size. tcp_respond() ------------ ti->ti_win = htons((u_short) (win >> tp->rcv_scale)); else ti->ti_win = htons((u_short)win); ti->ti_win is cast to a unsigned short resulting in the wrap around 65700 - 65336 = 164 which is the advertised window size.. The problem occurs if the roundup result is greater than 65536. Fix: The fix is to limit the maximum permissible TCP window size to 65535 octets if window scaling is disabled. How-To-Repeat: set tcpsendspace and tcprecvspace to 65536. turn rfc1323 off. Turn keepalive on and open a connection. Send some data and let the connection be idle. let the keepalive timer expire at the server end. tcp now advertises a window size of 164 instead of the original window size.