which happen to have a TCB in TIME_WAIT, where an mbuf which had been
advanced past the IP+TCP headers and TCP options would be reused as if
it had not been advanced. Problem found by Juergen Hannken-Illjes, who
also suggested a work-around on which this fix is based.
fixed in FreeBSD by John Polstra:
Fix a bug (apparently very old) that can cause a TCP connection to
be dropped when it has an unusual traffic pattern. For full details
as well as a test case that demonstrates the failure, see the
referenced PR (FreeBSD's kern/3998).
Under certain circumstances involving the persist state, it is
possible for the receive side's tp->rcv_nxt to advance beyond its
tp->rcv_adv. This causes (tp->rcv_adv - tp->rcv_nxt) to become
negative. However, in the code affected by this fix, that difference
was interpreted as an unsigned number by max(). Since it was
negative, it was taken as a huge unsigned number. The effect was
to cause the receiver to believe that its receive window had negative
size, thereby rejecting all received segments including ACKs. As
the test case shows, this led to fruitless retransmissions and
eventually to a dropped connection. Even connections using the
loopback interface could be dropped. The fix substitutes the signed
imax() for the unsigned max() function.
Bill informs me that his research indicates this bug appeared in Reno.
(like the alpha). Biggest problem: IP headers were overlayed with
structure which included pointers, and which therefore didn't overlay
properly on 64-bit machines. Solution: instead of threading pointers
through IP header overlays, add a "queue element" structure to do
the threading, and point it at the ip headers.
* Convert several data structures to use queue.h.
* Split in_pcbnotify() into two parts; one for notifying a specific PCB, and
one for notifying all PCBs for a particular foreign address.
* Don't add the extra 1/8 of the mss when ramping up the congestion window.
* Scale the RTT values slightly to adjust for rounding errors.
* Set the lower bound of the RTO to RTT+2.
I've found a problem with the TCP delayed ack algorithm. If the writer's
buffer becomes full before sending an entire window, the writer will stop
and the ack will be delayed and the transmission will be stalled pending
a timeout on (and transmission of) the delayed ack.
As an experiment, I've applied the following patch to my (NetBSD) kernel,
and it alleviates the problem.
The worst case for this change is that the writer sets the PSH bit on
every outgoing packet, in which case delayed ack is effectively disabled.
This is not an issue of correctness, however, and since most vendors use
the PSH bit a bit more intelligently, it doesn't seem like a serious
problem.