From nobody@FreeBSD.org  Thu Mar 28 23:55:05 2013
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115])
	by hub.freebsd.org (Postfix) with ESMTP id 5A5C1540
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 28 Mar 2013 23:55:05 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 31BDEBDD
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 28 Mar 2013 23:55:05 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.5/8.14.5) with ESMTP id r2SNt4SW071111
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 28 Mar 2013 23:55:04 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.5/8.14.5/Submit) id r2SNt4KM071110;
	Thu, 28 Mar 2013 23:55:04 GMT
	(envelope-from nobody)
Message-Id: <201303282355.r2SNt4KM071110@red.freebsd.org>
Date: Thu, 28 Mar 2013 23:55:04 GMT
From: HouYeFei&XiBoLiu <lglion718@163.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: An error of calculating TCP sequence number will resault in the machine to restart
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         177456
>Category:       kern
>Synopsis:       [tcp] [patch] An error of calculating TCP sequence number will resault in the machine to restart
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    glebius
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Mar 29 00:00:00 UTC 2013
>Closed-Date:    Wed Jan 22 09:19:35 UTC 2014
>Last-Modified:  Wed Jan 22 09:19:35 UTC 2014
>Originator:     HouYeFei&XiBoLiu
>Release:        FreeBSD-9.0
>Organization:
H3C
>Environment:
FreeBSD www.unixnotes.net 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Sun May  4 12:36:15 HKT 2012     root@www.unixnotes.net:/usr/src/sys/i386/compile/unixnotes  i386
>Description:
There is  a large number of TCP links between  Client and Server, each link can transmit large amounts of data. When the Client is low on memory, at the same time it wants  to establish a new  TCP connection to the server. The Client sends SYN message and startups retransmission timer, but retransmission of the first time

sends failed because there is not enough mbuf.At this time, a sequence number is transmitted messages on the tcpcb (tp->snd_nxt) regression. Then

a syn+ack message is received and processing the tp->snd_una sequence number is increased by 1, resault in tp->snd_nxt < th->snd_una. It is likely that 

the sending buffer has data to send, but actually is empty, call

Tcp_output to send ack to the Server. But Tcp_output enter to the mbuf replication process, leading to access a null pointer.
>How-To-Repeat:
Make Client and Server to create a large number of TCP links. The system of the Client is FreeBSD9.0.
>Fix:
Please read the patch file

Patch attached with submission follows:


	case TCPS_SYN_SENT:
		        /* Do window scaling on this connection? */
			if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
				(TF_RCVD_SCALE|TF_REQ_SCALE)) {
				tp->rcv_scale = tp->request_r_scale;
			}
			tp->rcv_adv += imin(tp->rcv_wnd,
			    TCP_MAXWIN << tp->rcv_scale);
			tp->snd_una++;		/* SYN is acked */



the begin of modification:
			if (SEQ_LT(tp->snd_nxt, tp->snd_una))
			{
				tp->snd_nxt = tp->snd_una;
			}
the end of modification:




			/*
			 * If there's data, delay ACK; if there's also a FIN
			 * ACKNOW will be turned on later.
			 */
			if (DELAY_ACK(tp) && tlen != 0)
				tcp_timer_activate(tp, TT_DELACK,
				    tcp_delacktime);
			else
				tp->t_flags |= TF_ACKNOW;

			


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Fri Mar 29 04:25:17 UTC 2013 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=177456 

From: Gleb Smirnoff <glebius@FreeBSD.org>
To: HouYeFei&XiBoLiu <lglion718@163.com>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: misc/177456: An error of calculating TCP sequence number will
 resault in the machine to restart
Date: Fri, 29 Mar 2013 16:08:03 +0400

   HouYeFei & XiBoLiu,
 
 On Thu, Mar 28, 2013 at 11:55:04PM +0000, HouYeFei&XiBoLiu wrote:
 H> >Number:         177456
 H> >Category:       misc
 H> >Synopsis:       An error of calculating TCP sequence number will resault in the machine to restart
 H> >Confidential:   no
 H> >Severity:       non-critical
 H> >Priority:       low
 H> >Responsible:    freebsd-bugs
 H> >State:          open
 H> >Quarter:        
 H> >Keywords:       
 H> >Date-Required:
 H> >Class:          sw-bug
 H> >Submitter-Id:   current-users
 H> >Arrival-Date:   Fri Mar 29 00:00:00 UTC 2013
 H> >Closed-Date:
 H> >Last-Modified:
 H> >Originator:     HouYeFei&XiBoLiu
 H> >Release:        FreeBSD-9.0
 H> >Organization:
 H> H3C
 H> >Environment:
 H> FreeBSD www.unixnotes.net 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Sun May  4 12:36:15 HKT 2012     root@www.unixnotes.net:/usr/src/sys/i386/compile/unixnotes  i386
 H> >Description:
 H> There is  a large number of TCP links between  Client and Server, each link can transmit large amounts of data. When the Client is low on memory, at the same time it wants  to establish a new  TCP connection to the server. The Client sends SYN message and startups retransmission timer, but retransmission of the first time
 H> 
 H> sends failed because there is not enough mbuf.At this time, a sequence number is transmitted messages on the tcpcb (tp->snd_nxt) regression. Then
 H> 
 H> a syn+ack message is received and processing the tp->snd_una sequence number is increased by 1, resault in tp->snd_nxt < th->snd_una. It is likely that 
 H> 
 H> the sending buffer has data to send, but actually is empty, call
 H> 
 H> Tcp_output to send ack to the Server. But Tcp_output enter to the mbuf replication process, leading to access a null pointer.
 
 I am trying to reproduce the problem, with no success yet.
 
 Can you please clarify the sequence of failures that is required? I understand
 your submission in the following way:
 
 Client performs connect(2).
 Client TCP stack generates SYN packet, and this packet is lost in network.
 Client TCP stack tries to retransmit SYN packet, buf mbuf allocation fails.
 Client TCP stack retransmits SYN packet.
 Server replies with SYN+ACK.
 ... and according to you smth should go wrong ...
 
 But in my tests nothing goes wrong. Client successfully retransmits SYN and
 connection is established.
 
 This is how I instrument this. I have added special TCP option and set it
 before doing connect. The tcp_output() emulates failures that you
 described:
 
 Index: tcp_output.c
 ===================================================================
 --- tcp_output.c        (revision 248873)
 +++ tcp_output.c        (working copy)
 @@ -898,6 +898,13 @@ send:
                 else
                         TCPSTAT_INC(tcps_sndwinup);
  
 +               /* Fail allocating second packet. */
 +               if (tp->t_flags & TF_ZHOPA && tp->t_zhopa == 1) {
 +                       tp->t_zhopa = 2;
 +                       m = NULL;
 +                       error = ENOBUFS;
 +                       goto out;
 +               } else
                 m = m_gethdr(M_NOWAIT, MT_DATA);
                 if (m == NULL) {
                         error = ENOBUFS;
 @@ -1273,6 +1280,13 @@ timer:
         if (V_path_mtu_discovery && tp->t_maxopd > V_tcp_minmss)
                 ip->ip_off |= htons(IP_DF);
  
 +       /* Lose first packet. */
 +       if (tp->t_flags & TF_ZHOPA && tp->t_zhopa == 0) {
 +               tp->t_zhopa = 1;
 +               m_freem(m);
 +               error = 0;
 +       } else
 +
         error = ip_output(m, tp->t_inpcb->inp_options, &ro,
             ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), 0,
             tp->t_inpcb);
 
 Am I doing something wrong? Can you provide your way to reproduce this?
 
 Do you have backtrace of the panic?
 
 -- 
 Totus tuus, Glebius.

From: Gleb Smirnoff <glebius@FreeBSD.org>
To: ?????? <lglion718@163.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: misc/177456: An error of calculating TCP sequence number will
 resault in the machine to restart
Date: Wed, 3 Apr 2013 19:21:12 +0400

   Hi!
 
 On Wed, Apr 03, 2013 at 07:52:42AM +0800, ?????? wrote:
 ?> I mean there is a bug in FreeBSD's tcp code.  I'm trying to describe it by pictuer. Pelease see the attachments??
 
 I am trying to model what you are describing in the picture by
 special crafted code.
 
 I intentionally model memory allocation failure on first two
 packets for a connection that has special socket option.
 
 I'm modelling allocation failure at tcp_output.c near line 900:
 
 Index: tcp_output.c
 ===================================================================
 --- tcp_output.c        (revision 249051)
 +++ tcp_output.c        (working copy)
 @@ -898,6 +898,13 @@ send:
                 else
                         TCPSTAT_INC(tcps_sndwinup);
  
 +               /* Fail allocating first 2 packets. */
 +               if (tp->t_flags & TF_ZHOPA && tp->t_zhopa < 2) {
 +                       tp->t_zhopa++;
 +                       m = NULL;
 +                       error = ENOBUFS;
 +                       goto out;
 +               } else
                 m = m_gethdr(M_NOWAIT, MT_DATA);
                 if (m == NULL) {
                         error = ENOBUFS;
 
 
 I have no success in reproducing your problems. With above code,
 first 2 packets are failing to allocate, but third retransmission
 succeeds and connection is established with no problems.
 
 May be I incorrectly understand your description :( Please don't
 give up and try to explain again.
 
 A modelling code that demonstrates problem would be appreciated.
 
 -- 
 Totus tuus, Glebius.
State-Changed-From-To: open->analyzed 
State-Changed-By: glebius 
State-Changed-When: Mon Apr 8 11:01:18 UTC 2013 
State-Changed-Why:  
Grab the PR. I've reproduced it. 


Responsible-Changed-From-To: freebsd-net->glebius 
Responsible-Changed-By: glebius 
Responsible-Changed-When: Mon Apr 8 11:01:18 UTC 2013 
Responsible-Changed-Why:  
Grab the PR. I've reproduced it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=177456 

From: Gleb Smirnoff <glebius@FreeBSD.org>
To: HouYeFei&XiBoLiu <lglion718@163.com>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: kern/177456: An error of calculating TCP sequence number will
 resault in the machine to restart
Date: Mon, 8 Apr 2013 19:04:12 +0400

 --nktOf83SvqltY3iw
 Content-Type: text/plain; charset=koi8-r
 Content-Disposition: inline
 
   HouYeFei&XiBoLiu,
 
   can you please revert your patch to tcp_input.c, and instead
 test the attached patch to tcp_output.c?
 
   Patches are applied using the patch(1) command line utility.
 
 -- 
 Totus tuus, Glebius.
 
 --nktOf83SvqltY3iw
 Content-Type: text/x-diff; charset=koi8-r
 Content-Disposition: attachment; filename="kern177456.diff"
 
 Index: tcp_output.c
 ===================================================================
 --- tcp_output.c	(revision 249250)
 +++ tcp_output.c	(working copy)
 @@ -1123,75 +1123,6 @@ send:
  	    __func__, len, hdrlen, ipoptlen, m_length(m, NULL)));
  #endif
  
 -	/*
 -	 * In transmit state, time the transmission and arrange for
 -	 * the retransmit.  In persist state, just set snd_max.
 -	 */
 -	if ((tp->t_flags & TF_FORCEDATA) == 0 || 
 -	    !tcp_timer_active(tp, TT_PERSIST)) {
 -		tcp_seq startseq = tp->snd_nxt;
 -
 -		/*
 -		 * Advance snd_nxt over sequence space of this segment.
 -		 */
 -		if (flags & (TH_SYN|TH_FIN)) {
 -			if (flags & TH_SYN)
 -				tp->snd_nxt++;
 -			if (flags & TH_FIN) {
 -				tp->snd_nxt++;
 -				tp->t_flags |= TF_SENTFIN;
 -			}
 -		}
 -		if (sack_rxmit)
 -			goto timer;
 -		tp->snd_nxt += len;
 -		if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
 -			tp->snd_max = tp->snd_nxt;
 -			/*
 -			 * Time this transmission if not a retransmission and
 -			 * not currently timing anything.
 -			 */
 -			if (tp->t_rtttime == 0) {
 -				tp->t_rtttime = ticks;
 -				tp->t_rtseq = startseq;
 -				TCPSTAT_INC(tcps_segstimed);
 -			}
 -		}
 -
 -		/*
 -		 * Set retransmit timer if not currently set,
 -		 * and not doing a pure ack or a keep-alive probe.
 -		 * Initial value for retransmit timer is smoothed
 -		 * round-trip time + 2 * round-trip time variance.
 -		 * Initialize shift counter which is used for backoff
 -		 * of retransmit time.
 -		 */
 -timer:
 -		if (!tcp_timer_active(tp, TT_REXMT) &&
 -		    ((sack_rxmit && tp->snd_nxt != tp->snd_max) ||
 -		     (tp->snd_nxt != tp->snd_una))) {
 -			if (tcp_timer_active(tp, TT_PERSIST)) {
 -				tcp_timer_activate(tp, TT_PERSIST, 0);
 -				tp->t_rxtshift = 0;
 -			}
 -			tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur);
 -		}
 -	} else {
 -		/*
 -		 * Persist case, update snd_max but since we are in
 -		 * persist mode (no window) we do not update snd_nxt.
 -		 */
 -		int xlen = len;
 -		if (flags & TH_SYN)
 -			++xlen;
 -		if (flags & TH_FIN) {
 -			++xlen;
 -			tp->t_flags |= TF_SENTFIN;
 -		}
 -		if (SEQ_GT(tp->snd_nxt + xlen, tp->snd_max))
 -			tp->snd_max = tp->snd_nxt + len;
 -	}
 -
  	/* Run HHOOK_TCP_ESTABLISHED_OUT helper hooks. */
  	hhook_run_tcp_est_out(tp, th, &to, len, tso);
  
 @@ -1282,6 +1213,80 @@ send:
  	RO_RTFREE(&ro);
      }
  #endif /* INET */
 +
 +out:
 +	/*
 +	 * In transmit state, time the transmission and arrange for
 +	 * the retransmit.  In persist state, just set snd_max.
 +	 */
 +	if ((tp->t_flags & TF_FORCEDATA) == 0 || 
 +	    !tcp_timer_active(tp, TT_PERSIST)) {
 +		tcp_seq startseq = tp->snd_nxt;
 +
 +		/*
 +		 * Advance snd_nxt over sequence space of this segment.
 +		 */
 +		if (flags & (TH_SYN|TH_FIN)) {
 +			if (flags & TH_SYN)
 +				tp->snd_nxt++;
 +			if (flags & TH_FIN) {
 +				tp->snd_nxt++;
 +				tp->t_flags |= TF_SENTFIN;
 +			}
 +		}
 +		if (sack_rxmit)
 +			goto timer;
 +		tp->snd_nxt += len;
 +		if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
 +			tp->snd_max = tp->snd_nxt;
 +			/*
 +			 * Time this transmission if not a retransmission and
 +			 * not currently timing anything.
 +			 */
 +			if (tp->t_rtttime == 0) {
 +				tp->t_rtttime = ticks;
 +				tp->t_rtseq = startseq;
 +				TCPSTAT_INC(tcps_segstimed);
 +			}
 +		}
 +
 +		/*
 +		 * Set retransmit timer if not currently set,
 +		 * and not doing a pure ack or a keep-alive probe.
 +		 * Initial value for retransmit timer is smoothed
 +		 * round-trip time + 2 * round-trip time variance.
 +		 * Initialize shift counter which is used for backoff
 +		 * of retransmit time.
 +		 */
 +timer:
 +		if (!tcp_timer_active(tp, TT_REXMT) &&
 +		    ((sack_rxmit && tp->snd_nxt != tp->snd_max) ||
 +		     (tp->snd_nxt != tp->snd_una))) {
 +			if (tcp_timer_active(tp, TT_PERSIST)) {
 +				tcp_timer_activate(tp, TT_PERSIST, 0);
 +				tp->t_rxtshift = 0;
 +			}
 +			if (tp->t_flags & TF_ZHOPA && tp->t_zhopa == 1)
 +			tcp_timer_activate(tp, TT_REXMT, 10);
 +			else
 +			tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur);
 +		}
 +	} else {
 +		/*
 +		 * Persist case, update snd_max but since we are in
 +		 * persist mode (no window) we do not update snd_nxt.
 +		 */
 +		int xlen = len;
 +		if (flags & TH_SYN)
 +			++xlen;
 +		if (flags & TH_FIN) {
 +			++xlen;
 +			tp->t_flags |= TF_SENTFIN;
 +		}
 +		if (SEQ_GT(tp->snd_nxt + xlen, tp->snd_max))
 +			tp->snd_max = tp->snd_nxt + len;
 +	}
 +
  	if (error) {
  
  		/*
 @@ -1309,7 +1314,6 @@ send:
  			} else
  				tp->snd_nxt -= len;
  		}
 -out:
  		SOCKBUF_UNLOCK_ASSERT(&so->so_snd);	/* Check gotos. */
  		switch (error) {
  		case EPERM:
 
 --nktOf83SvqltY3iw--
State-Changed-From-To: analyzed->patched 
State-Changed-By: glebius 
State-Changed-When: Thu Apr 11 18:22:18 UTC 2013 
State-Changed-Why:  
Fixed in head/. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=177456 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/177456: commit references a PR
Date: Thu, 11 Apr 2013 18:24:09 +0000 (UTC)

 Author: glebius
 Date: Thu Apr 11 18:23:56 2013
 New Revision: 249372
 URL: http://svnweb.freebsd.org/changeset/base/249372
 
 Log:
   Fix tcp_output() so that tcpcb is updated in the same manner when an
   mbuf allocation fails, as in a case when ip_output() returns error.
   
   To achieve that, move large block of code that updates tcpcb below
   the out: label.
   
   This fixes a panic, that requires the following sequence to happen:
   
   1) The SYN was sent to the network, tp->snd_nxt = iss + 1, tp->snd_una = iss
   2) The retransmit timeout happened for the SYN we had sent,
      tcp_timer_rexmt() sets tp->snd_nxt = tp->snd_una, and calls tcp_output().
      In tcp_output m_get() fails.
   3) Later on the SYN|ACK for the SYN sent in step 1) came,
      tcp_input sets tp->snd_una += 1, which leads to
      tp->snd_una > tp->snd_nxt inconsistency, that later panics in
      socket buffer code.
   
   For reference, this bug fixed in DragonflyBSD repo:
   
   http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/1ff9b7d322dc5a26f7173aa8c38ecb79da80e419
   
   Reviewed by:	andre
   Tested by:	pho
   Sponsored by:	Nginx, Inc.
   PR:		kern/177456
   Submitted by:	HouYeFei&XiBoLiu <lglion718 163.com>
 
 Modified:
   head/sys/netinet/tcp_output.c
 
 Modified: head/sys/netinet/tcp_output.c
 ==============================================================================
 --- head/sys/netinet/tcp_output.c	Thu Apr 11 18:02:42 2013	(r249371)
 +++ head/sys/netinet/tcp_output.c	Thu Apr 11 18:23:56 2013	(r249372)
 @@ -852,6 +852,7 @@ send:
  		if (m == NULL) {
  			SOCKBUF_UNLOCK(&so->so_snd);
  			error = ENOBUFS;
 +			sack_rxmit = 0;
  			goto out;
  		}
  
 @@ -874,6 +875,7 @@ send:
  				SOCKBUF_UNLOCK(&so->so_snd);
  				(void) m_free(m);
  				error = ENOBUFS;
 +				sack_rxmit = 0;
  				goto out;
  			}
  		}
 @@ -901,6 +903,7 @@ send:
  		m = m_gethdr(M_NOWAIT, MT_DATA);
  		if (m == NULL) {
  			error = ENOBUFS;
 +			sack_rxmit = 0;
  			goto out;
  		}
  #ifdef INET6
 @@ -1123,75 +1126,6 @@ send:
  	    __func__, len, hdrlen, ipoptlen, m_length(m, NULL)));
  #endif
  
 -	/*
 -	 * In transmit state, time the transmission and arrange for
 -	 * the retransmit.  In persist state, just set snd_max.
 -	 */
 -	if ((tp->t_flags & TF_FORCEDATA) == 0 || 
 -	    !tcp_timer_active(tp, TT_PERSIST)) {
 -		tcp_seq startseq = tp->snd_nxt;
 -
 -		/*
 -		 * Advance snd_nxt over sequence space of this segment.
 -		 */
 -		if (flags & (TH_SYN|TH_FIN)) {
 -			if (flags & TH_SYN)
 -				tp->snd_nxt++;
 -			if (flags & TH_FIN) {
 -				tp->snd_nxt++;
 -				tp->t_flags |= TF_SENTFIN;
 -			}
 -		}
 -		if (sack_rxmit)
 -			goto timer;
 -		tp->snd_nxt += len;
 -		if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
 -			tp->snd_max = tp->snd_nxt;
 -			/*
 -			 * Time this transmission if not a retransmission and
 -			 * not currently timing anything.
 -			 */
 -			if (tp->t_rtttime == 0) {
 -				tp->t_rtttime = ticks;
 -				tp->t_rtseq = startseq;
 -				TCPSTAT_INC(tcps_segstimed);
 -			}
 -		}
 -
 -		/*
 -		 * Set retransmit timer if not currently set,
 -		 * and not doing a pure ack or a keep-alive probe.
 -		 * Initial value for retransmit timer is smoothed
 -		 * round-trip time + 2 * round-trip time variance.
 -		 * Initialize shift counter which is used for backoff
 -		 * of retransmit time.
 -		 */
 -timer:
 -		if (!tcp_timer_active(tp, TT_REXMT) &&
 -		    ((sack_rxmit && tp->snd_nxt != tp->snd_max) ||
 -		     (tp->snd_nxt != tp->snd_una))) {
 -			if (tcp_timer_active(tp, TT_PERSIST)) {
 -				tcp_timer_activate(tp, TT_PERSIST, 0);
 -				tp->t_rxtshift = 0;
 -			}
 -			tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur);
 -		}
 -	} else {
 -		/*
 -		 * Persist case, update snd_max but since we are in
 -		 * persist mode (no window) we do not update snd_nxt.
 -		 */
 -		int xlen = len;
 -		if (flags & TH_SYN)
 -			++xlen;
 -		if (flags & TH_FIN) {
 -			++xlen;
 -			tp->t_flags |= TF_SENTFIN;
 -		}
 -		if (SEQ_GT(tp->snd_nxt + xlen, tp->snd_max))
 -			tp->snd_max = tp->snd_nxt + len;
 -	}
 -
  	/* Run HHOOK_TCP_ESTABLISHED_OUT helper hooks. */
  	hhook_run_tcp_est_out(tp, th, &to, len, tso);
  
 @@ -1282,6 +1216,77 @@ timer:
  	RO_RTFREE(&ro);
      }
  #endif /* INET */
 +
 +out:
 +	/*
 +	 * In transmit state, time the transmission and arrange for
 +	 * the retransmit.  In persist state, just set snd_max.
 +	 */
 +	if ((tp->t_flags & TF_FORCEDATA) == 0 || 
 +	    !tcp_timer_active(tp, TT_PERSIST)) {
 +		tcp_seq startseq = tp->snd_nxt;
 +
 +		/*
 +		 * Advance snd_nxt over sequence space of this segment.
 +		 */
 +		if (flags & (TH_SYN|TH_FIN)) {
 +			if (flags & TH_SYN)
 +				tp->snd_nxt++;
 +			if (flags & TH_FIN) {
 +				tp->snd_nxt++;
 +				tp->t_flags |= TF_SENTFIN;
 +			}
 +		}
 +		if (sack_rxmit)
 +			goto timer;
 +		tp->snd_nxt += len;
 +		if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
 +			tp->snd_max = tp->snd_nxt;
 +			/*
 +			 * Time this transmission if not a retransmission and
 +			 * not currently timing anything.
 +			 */
 +			if (tp->t_rtttime == 0) {
 +				tp->t_rtttime = ticks;
 +				tp->t_rtseq = startseq;
 +				TCPSTAT_INC(tcps_segstimed);
 +			}
 +		}
 +
 +		/*
 +		 * Set retransmit timer if not currently set,
 +		 * and not doing a pure ack or a keep-alive probe.
 +		 * Initial value for retransmit timer is smoothed
 +		 * round-trip time + 2 * round-trip time variance.
 +		 * Initialize shift counter which is used for backoff
 +		 * of retransmit time.
 +		 */
 +timer:
 +		if (!tcp_timer_active(tp, TT_REXMT) &&
 +		    ((sack_rxmit && tp->snd_nxt != tp->snd_max) ||
 +		     (tp->snd_nxt != tp->snd_una))) {
 +			if (tcp_timer_active(tp, TT_PERSIST)) {
 +				tcp_timer_activate(tp, TT_PERSIST, 0);
 +				tp->t_rxtshift = 0;
 +			}
 +			tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur);
 +		}
 +	} else {
 +		/*
 +		 * Persist case, update snd_max but since we are in
 +		 * persist mode (no window) we do not update snd_nxt.
 +		 */
 +		int xlen = len;
 +		if (flags & TH_SYN)
 +			++xlen;
 +		if (flags & TH_FIN) {
 +			++xlen;
 +			tp->t_flags |= TF_SENTFIN;
 +		}
 +		if (SEQ_GT(tp->snd_nxt + xlen, tp->snd_max))
 +			tp->snd_max = tp->snd_nxt + len;
 +	}
 +
  	if (error) {
  
  		/*
 @@ -1309,7 +1314,6 @@ timer:
  			} else
  				tp->snd_nxt -= len;
  		}
 -out:
  		SOCKBUF_UNLOCK_ASSERT(&so->so_snd);	/* Check gotos. */
  		switch (error) {
  		case EPERM:
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: glebius 
State-Changed-When: Wed Jan 22 09:19:01 UTC 2014 
State-Changed-Why:  
Fixed in 10.0-RELEASE. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=177456 
>Unformatted:
