Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Mar 2012 18:06:05 +0200
From:      Andre Oppermann <andre@freebsd.org>
To:        darrenr@freebsd.org
Cc:        freebsd-net@freebsd.org
Subject:   Re: FreeBSD TCP ignores zero window size
Message-ID:  <4F75D9ED.7080707@freebsd.org>
In-Reply-To: <4F75C1A3.4030401@freebsd.org>
References:  <4F75C1A3.4030401@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On 30.03.2012 16:22, Darren Reed wrote:
> I've been tracking down some problems with FreeBSD's sending
> of TCP packets and seem to have come to the conclusion that
> in FreeBSD 8.2-RELEASE, when the system is working with a
> TCP connection that has a moderate delay in it, FreeBSD's
> TCP ignores the other end telling it that the window size
> is now 0 and continues to send data. I suspect that this is
> meant to make sense because it is expecting that the ACK
> that will open up the window is already in transit. But that
> only accounts for the condition where the TCP on FreeBSD can
> compute and decide that the remote TCP will have its buffer
> full. What I find harder to accept is that when FreeBSD's
> TCP receives a TCP packet from the remote end advertising
> a window of 0, FreeBSD's response is to send more data and
> not a window probe or is that now the expected behaviour?
> And whilst you might say "ok" for a packet of data, I'm
> somewhat hard pressed to explain why FreeBSD's TCP sends
> multiple packets with data in them after receiving a TCP
> packet from the other end advertising a zero window size.
>
> However this causes a problem with firewalls (;_) that are
> close to the FreeBSD end because for them, it appears that
> FreeBSD is sending data outside of its window.
>
> Is this a known problem?
> If so, has it been fixed in a later version of FreeBSD?
> (No, I haven't tested anything other than 8.2)

The window update acceptance test is too restrictive.  In your case
the last updated seq# tracking gets it wrong and prevents the update.

The code hasn't changed for a long time and newer versions behave the
same.

The concept patch below simplifies the logic, better tracks the seq#
and is a bit more permissive.

-- 
Andre

$ svn diff netinet/tcp_input.c
Index: netinet/tcp_input.c
===================================================================
--- netinet/tcp_input.c (revision 233227)
+++ netinet/tcp_input.c (working copy)
@@ -1717,7 +1730,7 @@
                          * Pull snd_wl1 up to prevent seq wrap relative to
                          * th_seq.
                          */
-                       tp->snd_wl1 = th->th_seq;
+                       tp->snd_wl1 = th->th_seq + tlen;
                         /*
                          * Pull rcv_up up to prevent seq wrap relative to
                          * rcv_nxt.
@@ -2710,15 +2723,16 @@
          * Don't look at window if no ACK: TAC's send garbage on first SYN.
          */
         if ((thflags & TH_ACK) &&
-           (SEQ_LT(tp->snd_wl1, th->th_seq) ||
-           (tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) ||
-            (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) {
+           (BYTES_THIS_ACK(tp, th) > 0 ||               /* new data acked */
+            SEQ_GT(th->th_seq, tp->snd_wl1) ||          /* new data received */
+            (th->th_seq == tp->snd_wl1 && tiwin > tp->snd_wnd))) { /* pure win update */
+
                 /* keep track of pure window updates */
                 if (tlen == 0 &&
                     tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
                         TCPSTAT_INC(tcps_rcvwinupd);
                 tp->snd_wnd = tiwin;
-               tp->snd_wl1 = th->th_seq;
+               tp->snd_wl1 = th->th_seq + tlen;
                 tp->snd_wl2 = th->th_ack;
                 if (tp->snd_wnd > tp->max_sndwnd)
                         tp->max_sndwnd = tp->snd_wnd;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4F75D9ED.7080707>