xref: /csrg-svn/sys/netiso/tp_subr.c (revision 37469)
136413Ssklower /***********************************************************
236413Ssklower 		Copyright IBM Corporation 1987
336413Ssklower 
436413Ssklower                       All Rights Reserved
536413Ssklower 
636413Ssklower Permission to use, copy, modify, and distribute this software and its
736413Ssklower documentation for any purpose and without fee is hereby granted,
836413Ssklower provided that the above copyright notice appear in all copies and that
936413Ssklower both that copyright notice and this permission notice appear in
1036413Ssklower supporting documentation, and that the name of IBM not be
1136413Ssklower used in advertising or publicity pertaining to distribution of the
1236413Ssklower software without specific, written prior permission.
1336413Ssklower 
1436413Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536413Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636413Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736413Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836413Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936413Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036413Ssklower SOFTWARE.
2136413Ssklower 
2236413Ssklower ******************************************************************/
2336413Ssklower 
2436413Ssklower /*
2536413Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636413Ssklower  */
2736413Ssklower /*
2836413Ssklower  * ARGO TP
2936413Ssklower  *
3036413Ssklower  * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $
3136413Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $
3236413Ssklower  *
3336413Ssklower  * The main work of data transfer is done here.
3436413Ssklower  * These routines are called from tp.trans.
3536413Ssklower  * They include the routines that check the validity of acks and Xacks,
3636413Ssklower  * (tp_goodack() and tp_goodXack() )
3736413Ssklower  * take packets from socket buffers and send them (tp_send()),
3836413Ssklower  * drop the data from the socket buffers (tp_sbdrop()),
3936413Ssklower  * and put incoming packet data into socket buffers (tp_stash()).
4036413Ssklower  */
4136413Ssklower 
4236413Ssklower #ifndef lint
4336413Ssklower static char *rcsid = "$Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $";
4436413Ssklower #endif lint
4536413Ssklower 
4636413Ssklower #include "param.h"
4736413Ssklower #include "mbuf.h"
4836413Ssklower #include "socket.h"
4936413Ssklower #include "socketvar.h"
5036413Ssklower #include "protosw.h"
5136413Ssklower #include "errno.h"
5236413Ssklower #include "types.h"
5336413Ssklower #include "time.h"
5436413Ssklower 
55*37469Ssklower #include "tp_ip.h"
56*37469Ssklower #include "iso.h"
57*37469Ssklower #include "argo_debug.h"
58*37469Ssklower #include "tp_timer.h"
59*37469Ssklower #include "tp_param.h"
60*37469Ssklower #include "tp_stat.h"
61*37469Ssklower #include "tp_pcb.h"
62*37469Ssklower #include "tp_tpdu.h"
63*37469Ssklower #include "tp_trace.h"
64*37469Ssklower #include "tp_meas.h"
65*37469Ssklower #include "tp_seq.h"
6636413Ssklower 
6736413Ssklower int 		tp_emit();
6836413Ssklower static void tp_sbdrop();
6936413Ssklower 
7036413Ssklower #define SMOOTH(newtype, alpha, old, new) \
7136413Ssklower 	(newtype) (((new - old)>>alpha) + (old))
7236413Ssklower 
7336413Ssklower #define ABS(type, val) \
7436413Ssklower 	(type) (((int)(val)<0)?-(val):(val))
7536413Ssklower 
7636413Ssklower #define TP_MAKE_RTC( Xreg, Xseq, Xeot, Xdata, Xlen, Xretval, Xtype) \
7736413Ssklower { 	struct mbuf *xxn;\
7836413Ssklower 	MGET(xxn, M_DONTWAIT, Xtype);\
7936413Ssklower 	if( xxn == (struct mbuf *)0 ) {\
8036413Ssklower 		printf("MAKE RTC FAILED: ENOBUFS\n");\
8136413Ssklower 		return (int)Xretval;\
8236413Ssklower 	}\
8336413Ssklower 	xxn->m_act=MNULL;\
8436413Ssklower 	Xreg = mtod(xxn, struct tp_rtc *);\
8536413Ssklower 	if( Xreg == (struct tp_rtc *)0 ) {\
8636413Ssklower 		return (int)Xretval;\
8736413Ssklower 	}\
8836413Ssklower 	Xreg->tprt_eot = Xeot;\
8936413Ssklower 	Xreg->tprt_seq = Xseq;\
9036413Ssklower 	Xreg->tprt_data = Xdata;\
9136413Ssklower 	Xreg->tprt_octets = Xlen;\
9236413Ssklower }
9336413Ssklower 
9436413Ssklower 
9536413Ssklower /*
9636413Ssklower  * CALLED FROM:
9736413Ssklower  *	tp.trans, when an XAK arrives
9836413Ssklower  * FUNCTION and ARGUMENTS:
9936413Ssklower  * 	Determines if the sequence number (seq) from the XAK
10036413Ssklower  * 	acks anything new.  If so, drop the appropriate tpdu
10136413Ssklower  * 	from the XPD send queue.
10236413Ssklower  * RETURN VALUE:
10336413Ssklower  * 	Returns 1 if it did this, 0 if the ack caused no action.
10436413Ssklower  */
10536413Ssklower int
10636413Ssklower tp_goodXack(tpcb, seq)
10736413Ssklower 	struct tp_pcb	*tpcb;
10836413Ssklower 	SeqNum 			seq;
10936413Ssklower {
11036413Ssklower 
11136413Ssklower 	IFTRACE(D_XPD)
11236413Ssklower 		tptraceTPCB(TPPTgotXack,
11336413Ssklower 			seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat,
11436413Ssklower 			tpcb->tp_snduna);
11536413Ssklower 	ENDTRACE
11636413Ssklower 
11736413Ssklower 	if ( seq == tpcb->tp_Xuna ) {
11836413Ssklower 			tpcb->tp_Xuna = tpcb->tp_Xsndnxt;
11936413Ssklower 
12036413Ssklower 			/* DROP 1 packet from the Xsnd socket buf - just so happens
12136413Ssklower 			 * that only one packet can be there at any time
12236413Ssklower 			 * so drop the whole thing.  If you allow > 1 packet
12336413Ssklower 			 * the socket buffer, then you'll have to keep
12436413Ssklower 			 * track of how many characters went w/ each XPD tpdu, so this
12536413Ssklower 			 * will get messier
12636413Ssklower 			 */
12736413Ssklower 			IFDEBUG(D_XPD)
12836413Ssklower 				dump_mbuf(tpcb->tp_Xsnd.sb_mb,
12936413Ssklower 					"tp_goodXack Xsnd before sbdrop");
13036413Ssklower 			ENDDEBUG
13136413Ssklower 
13236413Ssklower 			IFTRACE(D_XPD)
13336413Ssklower 				tptraceTPCB(TPPTmisc,
13436413Ssklower 					"goodXack: dropping cc ",
13536413Ssklower 					(int)(tpcb->tp_Xsnd.sb_cc),
13636413Ssklower 					0,0,0);
13736413Ssklower 			ENDTRACE
13836413Ssklower 			sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc));
13936413Ssklower 			return 1;
14036413Ssklower 	}
14136413Ssklower 	return 0;
14236413Ssklower }
14336413Ssklower 
14436413Ssklower /*
14536413Ssklower  * CALLED FROM:
14636413Ssklower  *  tp_good_ack()
14736413Ssklower  * FUNCTION and ARGUMENTS:
14836413Ssklower  *  updates
14936413Ssklower  *  smoothed average round trip time (base_rtt)
15036413Ssklower  *  roundtrip time variance (base_rtv) - actually deviation, not variance
15136413Ssklower  *  given the new value (diff)
15236413Ssklower  * RETURN VALUE:
15336413Ssklower  * void
15436413Ssklower  */
15536413Ssklower 
15636413Ssklower void
15736413Ssklower tp_rtt_rtv( base_rtt, base_rtv, newmeas )
15836413Ssklower 	struct 	timeval *base_rtt, *base_rtv, *newmeas;
15936413Ssklower {
16036413Ssklower 	/* update  rt variance (really just the deviation):
16136413Ssklower 	 * 	rtv.smooth_ave =  SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | )
16236413Ssklower 	 */
16336413Ssklower 	base_rtv->tv_sec =
16436413Ssklower 		SMOOTH( long,  TP_RTV_ALPHA, base_rtv->tv_sec,
16536413Ssklower 			ABS( long, base_rtv->tv_sec - newmeas->tv_sec ));
16636413Ssklower 	base_rtv->tv_usec =
16736413Ssklower 		SMOOTH( long,  TP_RTV_ALPHA, base_rtv->tv_usec,
16836413Ssklower 			ABS(long, base_rtv->tv_usec - newmeas->tv_usec ));
16936413Ssklower 
17036413Ssklower 	/* update smoothed average rtt */
17136413Ssklower 	base_rtt->tv_sec =
17236413Ssklower 		SMOOTH( long,  TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec);
17336413Ssklower 	base_rtt->tv_usec =
17436413Ssklower 		SMOOTH( long,  TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec);
17536413Ssklower 
17636413Ssklower }
17736413Ssklower 
17836413Ssklower /*
17936413Ssklower  * CALLED FROM:
18036413Ssklower  *  tp.trans when an AK arrives
18136413Ssklower  * FUNCTION and ARGUMENTS:
18236413Ssklower  * 	Given (cdt), the credit from the AK tpdu, and
18336413Ssklower  *	(seq), the sequence number from the AK tpdu,
18436413Ssklower  *  tp_goodack() determines if the AK acknowledges something in the send
18536413Ssklower  * 	window, and if so, drops the appropriate packets from the retransmission
18636413Ssklower  *  list, computes the round trip time, and updates the retransmission timer
18736413Ssklower  *  based on the new smoothed round trip time.
18836413Ssklower  * RETURN VALUE:
18936413Ssklower  * 	Returns 1 if
19036413Ssklower  * 	EITHER it actually acked something heretofore unacknowledged
19136413Ssklower  * 	OR no news but the credit should be processed.
19236413Ssklower  * 	If something heretofore unacked was acked with this sequence number,
19336413Ssklower  * 	the appropriate tpdus are dropped from the retransmission control list,
19436413Ssklower  * 	by calling tp_sbdrop().
19536413Ssklower  * 	No need to see the tpdu itself.
19636413Ssklower  */
19736413Ssklower int
19836413Ssklower tp_goodack(tpcb, cdt, seq, subseq)
19936413Ssklower 	register struct tp_pcb	*tpcb;
20036413Ssklower 	u_int					cdt;
20136413Ssklower 	register SeqNum			seq, subseq;
20236413Ssklower {
20336413Ssklower 	int 	old_fcredit = tpcb->tp_fcredit;
20436413Ssklower 	int 	bang = 0; 	/* bang --> ack for something heretofore unacked */
20536413Ssklower 
20636413Ssklower 	IFDEBUG(D_ACKRECV)
20736413Ssklower 		printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n",
20836413Ssklower 			seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat);
20936413Ssklower 	ENDDEBUG
21036413Ssklower 	IFTRACE(D_ACKRECV)
21136413Ssklower 		tptraceTPCB(TPPTgotack,
21236413Ssklower 			seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq);
21336413Ssklower 	ENDTRACE
21436413Ssklower 
21536413Ssklower 	IFPERF(tpcb)
216*37469Ssklower 		tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0);
21736413Ssklower 	ENDPERF
21836413Ssklower 
21936413Ssklower 	if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) {
22036413Ssklower 		/* discard the ack */
22136413Ssklower 		IFTRACE(D_ACKRECV)
22236413Ssklower 			tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq",
22336413Ssklower 				subseq, tpcb->tp_r_subseq, 0, 0);
22436413Ssklower 		ENDTRACE
22536413Ssklower 		return 0;
22636413Ssklower 	} else {
22736413Ssklower 		tpcb->tp_r_subseq = subseq;
22836413Ssklower 	}
22936413Ssklower 
23036413Ssklower 	if ( IN_SWINDOW(tpcb, seq,
23136413Ssklower 			tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) {
23236413Ssklower 
23336413Ssklower 		IFDEBUG(D_XPD)
23436413Ssklower 			dump_mbuf(tpcb->tp_sock->so_snd.sb_mb,
23536413Ssklower 				"tp_goodack snd before sbdrop");
23636413Ssklower 		ENDDEBUG
23736413Ssklower 		tp_sbdrop(tpcb, SEQ_SUB(tpcb, seq, 1) );
23836413Ssklower 
23936413Ssklower 		/* increase congestion window but don't let it get too big */
24036413Ssklower 		{
24136413Ssklower 			register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf;
24236413Ssklower 
24336413Ssklower 			if( ++tpcb->tp_cong_win > maxcdt )
24436413Ssklower 				tpcb->tp_cong_win = maxcdt;
24536413Ssklower 		}
24636413Ssklower 
24736413Ssklower 		/* Compute smoothed round trip time.
24836413Ssklower 		 * Only measure rtt for tp_snduna if tp_snduna was among
24936413Ssklower 		 * the last TP_RTT_NUM seq numbers sent.
25036413Ssklower 		 */
25136413Ssklower 		if (SEQ_GEQ(tpcb, tpcb->tp_snduna,
25236413Ssklower 			SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM))) {
25336413Ssklower 
25436413Ssklower 			struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM];
25536413Ssklower 			struct timeval x;
25636413Ssklower 
25736413Ssklower 			GET_TIME_SINCE(t, &x);
25836413Ssklower 
25936413Ssklower 			tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x );
26036413Ssklower 
26136413Ssklower 			{	/* update the global rtt, rtv stats */
26236413Ssklower 				register int i =
26336413Ssklower 				   (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
26436413Ssklower 				tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x );
26536413Ssklower 
26636413Ssklower 				IFTRACE(D_RTT)
26736413Ssklower 					tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0);
26836413Ssklower 				ENDTRACE
26936413Ssklower 			}
27036413Ssklower 
27136413Ssklower 			IFTRACE(D_RTT)
27236413Ssklower 				tptraceTPCB(TPPTmisc,
27336413Ssklower 				"Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime",
27436413Ssklower 				tpcb->tp_snduna, time.tv_sec, time.tv_usec,
27536413Ssklower 					tpcb->tp_peer_acktime);
27636413Ssklower 
27736413Ssklower 				tptraceTPCB(TPPTmisc,
27836413Ssklower 				"(secs): emittime diff(x) rtt, rtv",
27936413Ssklower 					t->tv_sec,
28036413Ssklower 					x.tv_sec,
28136413Ssklower 					tpcb->tp_rtt.tv_sec,
28236413Ssklower 					tpcb->tp_rtv.tv_sec);
28336413Ssklower 				tptraceTPCB(TPPTmisc,
28436413Ssklower 				"(usecs): emittime diff(x) rtt rtv",
28536413Ssklower 					t->tv_usec,
28636413Ssklower 					x.tv_usec,
28736413Ssklower 					tpcb->tp_rtt.tv_usec,
28836413Ssklower 					tpcb->tp_rtv.tv_usec);
28936413Ssklower 			ENDTRACE
29036413Ssklower 
29136413Ssklower 			{
29236413Ssklower 				/* Update data retransmission timer based on the smoothed
29336413Ssklower 				 * round trip time, peer ack time, and the pseudo-arbitrary
29436413Ssklower 				 * number 4.
29536413Ssklower 				 * new ticks: avg rtt + 2*dev
29636413Ssklower 				 * rtt, rtv are in microsecs, and ticks are 500 ms
29736413Ssklower 				 * so 1 tick = 500*1000 us = 500000 us
29836413Ssklower 				 * so ticks = (rtt + 2 rtv)/500000
29936413Ssklower 				 * with ticks no les than peer ack time and no less than 4
30036413Ssklower 				 */
30136413Ssklower 
30236413Ssklower 				int rtt = tpcb->tp_rtt.tv_usec +
30336413Ssklower 					tpcb->tp_rtt.tv_sec*1000000;
30436413Ssklower 				int rtv = tpcb->tp_rtv.tv_usec +
30536413Ssklower 					tpcb->tp_rtv.tv_sec*1000000;
30636413Ssklower 
30736413Ssklower 				IFTRACE(D_RTT)
30836413Ssklower 					tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks",
30936413Ssklower 						tpcb->tp_dt_ticks,
31036413Ssklower 						rtv, rtt,
31136413Ssklower 						(rtt/500000 + (2 * rtv)/500000));
31236413Ssklower 				ENDTRACE
31336413Ssklower 				tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000;
31436413Ssklower 				tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks,
31536413Ssklower 					tpcb->tp_peer_acktime);
31636413Ssklower 				tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks,  4);
31736413Ssklower 			}
31836413Ssklower 		}
31936413Ssklower 		tpcb->tp_snduna = seq;
32036413Ssklower 
32136413Ssklower 		bang++;
32236413Ssklower 	}
32336413Ssklower 
32436413Ssklower 	if( cdt != 0 && old_fcredit == 0 ) {
32536413Ssklower 		tpcb->tp_sendfcc = 1;
32636413Ssklower 	}
32736413Ssklower 	if( cdt == 0 && old_fcredit != 0 ) {
32836413Ssklower 		IncStat(ts_zfcdt);
32936413Ssklower 	}
33036413Ssklower 	tpcb->tp_fcredit = cdt;
33136413Ssklower 
33236413Ssklower 	IFDEBUG(D_ACKRECV)
33336413Ssklower 		printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n",
33436413Ssklower 			(bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit );
33536413Ssklower 	ENDDEBUG
33636413Ssklower 
33736413Ssklower 	return (bang || (old_fcredit < cdt)) ;
33836413Ssklower }
33936413Ssklower 
34036413Ssklower /*
34136413Ssklower  * CALLED FROM:
34236413Ssklower  *  tp_goodack()
34336413Ssklower  * FUNCTION and ARGUMENTS:
34436413Ssklower  *  drops everything up TO and INCLUDING seq # (seq)
34536413Ssklower  *  from the retransmission queue.
34636413Ssklower  */
34736413Ssklower static void
34836413Ssklower tp_sbdrop(tpcb, seq)
34936413Ssklower 	struct 	tp_pcb 			*tpcb;
35036413Ssklower 	SeqNum					seq;
35136413Ssklower {
35236413Ssklower 	register struct tp_rtc	*s = tpcb->tp_snduna_rtc;
35336413Ssklower 
35436413Ssklower 	IFDEBUG(D_ACKRECV)
35536413Ssklower 		printf("tp_sbdrop up through seq 0x%x\n", seq);
35636413Ssklower 	ENDDEBUG
35736413Ssklower 	while (s != (struct tp_rtc *)0 && (SEQ_LEQ(tpcb, s->tprt_seq, seq))) {
35836413Ssklower 		m_freem( s->tprt_data );
35936413Ssklower 		tpcb->tp_snduna_rtc = s->tprt_next;
36036413Ssklower 		(void) m_free( dtom( s ) );
36136413Ssklower 		s = tpcb->tp_snduna_rtc;
36236413Ssklower 	}
36336413Ssklower 	if(tpcb->tp_snduna_rtc == (struct tp_rtc *)0)
36436413Ssklower 		tpcb->tp_sndhiwat_rtc = (struct tp_rtc *) 0;
36536413Ssklower 
36636413Ssklower }
36736413Ssklower 
36836413Ssklower /*
36936413Ssklower  * CALLED FROM:
37036413Ssklower  * 	tp.trans on user send request, arrival of AK and arrival of XAK
37136413Ssklower  * FUNCTION and ARGUMENTS:
37236413Ssklower  * 	Emits tpdus starting at sequence number (lowseq).
37336413Ssklower  * 	Emits until a) runs out of data, or  b) runs into an XPD mark, or
37436413Ssklower  * 			c) it hits seq number (highseq)
37536413Ssklower  * 	Removes the octets from the front of the socket buffer
37636413Ssklower  * 	and repackages them in one mbuf chain per tpdu.
37736413Ssklower  * 	Moves the mbuf chain to the doubly linked list that runs from
37836413Ssklower  * 	tpcb->tp_sndhiwat_rtc to tpcb->tp_snduna_rtc.
37936413Ssklower  *
38036413Ssklower  * 	Creates tpdus that are no larger than <tpcb->tp_l_tpdusize - headersize>,
38136413Ssklower  *
38236413Ssklower  * 	If you want XPD to buffer > 1 du per socket buffer, you can
38336413Ssklower  * 	modifiy this to issue XPD tpdus also, but then it'll have
38436413Ssklower  * 	to take some argument(s) to distinguish between the type of DU to
38536413Ssklower  * 	hand tp_emit, the socket buffer from which to get the data, and
38636413Ssklower  * 	the chain of tp_rtc structures on which to put the data sent.
38736413Ssklower  *
38836413Ssklower  * 	When something is sent for the first time, its time-of-send
38936413Ssklower  * 	is stashed (the last RTT_NUM of them are stashed).  When the
39036413Ssklower  * 	ack arrives, the smoothed round-trip time is figured using this value.
39136413Ssklower  * RETURN VALUE:
39236413Ssklower  * 	the highest seq # sent successfully.
39336413Ssklower  */
39436413Ssklower tp_send(tpcb)
39536413Ssklower 	register struct tp_pcb	*tpcb;
39636413Ssklower {
39736413Ssklower 	register int			len;
39836413Ssklower 	register struct mbuf	*m; /* the one we're inspecting now */
39936413Ssklower 	struct mbuf				*mb;/* beginning of this tpdu */
40036413Ssklower 	struct mbuf 			*nextrecord; /* NOT next tpdu but next sb record */
40136413Ssklower 	struct 	sockbuf			*sb = &tpcb->tp_sock->so_snd;
40236413Ssklower 	int						maxsize = tpcb->tp_l_tpdusize
40336413Ssklower 										- tp_headersize(DT_TPDU_type, tpcb)
40436413Ssklower 										- (tpcb->tp_use_checksum?4:0) ;
40536413Ssklower 	unsigned int			eotsdu_reached=0;
40636413Ssklower 	SeqNum					lowseq, highseq ;
40736413Ssklower 	SeqNum					lowsave;
40836413Ssklower #ifdef TP_PERF_MEAS
40936413Ssklower 	struct timeval 			send_start_time;
41036413Ssklower #endif TP_PERF_MEAS
41136413Ssklower 
41236413Ssklower 	lowsave =  lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1);
41336413Ssklower 
41436413Ssklower 	ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff);
41536413Ssklower 
41636413Ssklower 	if( tpcb->tp_rx_strat & TPRX_USE_CW ) {
41736413Ssklower 			/*first hiseq is temp vbl*/
41836413Ssklower 		highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win);
41936413Ssklower 	} else {
42036413Ssklower 		highseq = tpcb->tp_fcredit;
42136413Ssklower 	}
42236413Ssklower 	highseq = SEQ(tpcb, tpcb->tp_snduna + highseq);
42336413Ssklower 
42436413Ssklower 	SEQ_DEC(tpcb, highseq);
42536413Ssklower 
42636413Ssklower 	IFDEBUG(D_DATA)
42736413Ssklower 		printf(
42836413Ssklower 			"tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n",
42936413Ssklower 			tpcb, lowseq, highseq);
43036413Ssklower 		dump_mbuf(sb->sb_mb, "sb_mb:");
43136413Ssklower 	ENDDEBUG
43236413Ssklower 	IFTRACE(D_DATA)
43336413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna",
43436413Ssklower 			lowsave, tpcb->tp_sndhiwat,  tpcb->tp_snduna, 0);
43536413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin",
43636413Ssklower 			lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
43736413Ssklower 	ENDTRACE
43836413Ssklower 
43936413Ssklower 
44036413Ssklower 	if	( SEQ_GT(tpcb, lowseq, highseq) )
44136413Ssklower 			return ; /* don't send, don't change hiwat, don't set timers */
44236413Ssklower 
44336413Ssklower 	IFPERF(tpcb)
44436413Ssklower 		GET_CUR_TIME(&send_start_time);
44536413Ssklower 	ENDPERF
44636413Ssklower 
44736413Ssklower 	ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) );
44836413Ssklower 	SEQ_DEC(tpcb, lowseq);
44936413Ssklower 
45036413Ssklower 	IFTRACE(D_DATA)
45136413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin",
45236413Ssklower 			lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
45336413Ssklower 	ENDTRACE
45436413Ssklower 
45536413Ssklower 	while( SEQ_LT( tpcb, lowseq, highseq ) ) {
45636413Ssklower 		mb = m = sb->sb_mb;
45736413Ssklower 		if (m == (struct mbuf *)0) {
45836413Ssklower 			break; /* empty socket buffer */
45936413Ssklower 		}
460*37469Ssklower 		if (tpcb->tp_Xsnd.sb_mb) {
46136413Ssklower 			register SeqNum Xuna = * (mtod(m, SeqNum *));
46236413Ssklower 			IFTRACE(D_XPD)
46336413Ssklower 				tptraceTPCB( TPPTmisc,
46436413Ssklower 					"tp_send XPD mark low high tpcb.Xuna",
46536413Ssklower 					Xuna, lowseq, highseq, tpcb->tp_Xuna);
46636413Ssklower 			ENDTRACE
467*37469Ssklower 			/* stop sending here because there are unacked XPD which were
468*37469Ssklower 			 * given to us before the next data were.
469*37469Ssklower 			 */
470*37469Ssklower 			IncStat(ts_xpd_intheway);
471*37469Ssklower 			break;
47236413Ssklower 		}
47336413Ssklower 		eotsdu_reached = 0;
47436413Ssklower 		nextrecord = m->m_act;
475*37469Ssklower 		for (len = 0; m; m = m->m_next) {
47636413Ssklower 			len += m->m_len;
477*37469Ssklower 			if (m->m_flags & M_EOR)
47836413Ssklower 				eotsdu_reached = 1;
47936413Ssklower 			sbfree(sb, m); /* reduce counts in socket buffer */
48036413Ssklower 		}
481*37469Ssklower 		m = sb->sb_mb = nextrecord;
482*37469Ssklower 		IFTRACE(D_STASH)
483*37469Ssklower 			tptraceTPCB(TPPTmisc, "tp_send whole mbuf: m_len len maxsize",
484*37469Ssklower 				 0, mb->m_len, len, maxsize);
485*37469Ssklower 		ENDTRACE
48636413Ssklower 
48736413Ssklower 		if ( len == 0 && !eotsdu_reached) {
48836413Ssklower 			/* THIS SHOULD NEVER HAPPEN! */
48936413Ssklower 			ASSERT( 0 );
49036413Ssklower 			goto done;
49136413Ssklower 		}
49236413Ssklower 
49336413Ssklower 		/* If we arrive here one of the following holds:
49436413Ssklower 		 * 1. We have exactly <maxsize> octets of whole mbufs,
49536413Ssklower 		 * 2. We accumulated <maxsize> octets using partial mbufs,
49636413Ssklower 		 * 3. We found an TPMT_EOT or an XPD mark
49736413Ssklower 		 * 4. We hit the end of a chain through m_next.
49836413Ssklower 		 *    In this case, we'd LIKE to continue with the next record,
49936413Ssklower 		 *    but for the time being, for simplicity, we'll stop here.
50036413Ssklower 		 * In all cases, m points to mbuf containing first octet to be
50136413Ssklower 		 * sent in the tpdu AFTER the one we're going to send now,
50236413Ssklower 		 * or else m is null.
50336413Ssklower 		 *
50436413Ssklower 		 * The chain we're working on now begins at mb and has length <len>.
50536413Ssklower 		 */
50636413Ssklower 
50736413Ssklower 		IFTRACE(D_STASH)
50836413Ssklower 			tptraceTPCB( TPPTmisc,
50936413Ssklower 				"tp_send mcopy low high eotsdu_reached len",
51036413Ssklower 				lowseq, highseq, eotsdu_reached, len);
51136413Ssklower 		ENDTRACE
51236413Ssklower 
51336413Ssklower 		/* make a copy - mb goes into the retransmission list
51436413Ssklower 		 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
51536413Ssklower 		 */
51636413Ssklower 		if(len) {
51736413Ssklower 			if( (m = m_copy(mb, 0, len )) == MNULL ) {
51836413Ssklower 				goto done;
51936413Ssklower 			}
52036413Ssklower 		} else {
52136413Ssklower 			/* eotsdu reached */
52236413Ssklower 			MGET(m, M_WAIT, TPMT_DATA);
52336413Ssklower 			if (m == NULL)
52436413Ssklower 				goto done;
52536413Ssklower 			m->m_len = 0;
52636413Ssklower 			m->m_act = MNULL;
52736413Ssklower 		}
52836413Ssklower 
52936413Ssklower 		SEQ_INC(tpcb,lowseq);	/* it was decremented at the beginning */
53036413Ssklower 		{
53136413Ssklower 			struct tp_rtc *t;
53236413Ssklower 			/* make an rtc and put it at the end of the chain */
53336413Ssklower 
53436413Ssklower 			TP_MAKE_RTC( t, lowseq, eotsdu_reached, mb, len, lowseq,
53536413Ssklower 				TPMT_SNDRTC);
53636413Ssklower 			t->tprt_next = (struct tp_rtc *)0;
53736413Ssklower 
53836413Ssklower 			if ( tpcb->tp_sndhiwat_rtc != (struct tp_rtc *)0 )
53936413Ssklower 				tpcb->tp_sndhiwat_rtc->tprt_next = t;
54036413Ssklower 			else {
54136413Ssklower 				ASSERT( tpcb->tp_snduna_rtc == (struct tp_rtc *)0 );
54236413Ssklower 				tpcb->tp_snduna_rtc = t;
54336413Ssklower 			}
54436413Ssklower 
54536413Ssklower 			tpcb->tp_sndhiwat_rtc = t;
54636413Ssklower 		}
54736413Ssklower 
54836413Ssklower 		IFTRACE(D_DATA)
54936413Ssklower 			tptraceTPCB( TPPTmisc,
55036413Ssklower 				"tp_send emitting DT lowseq eotsdu_reached",
55136413Ssklower 				lowseq, eotsdu_reached, 0, 0);
55236413Ssklower 		ENDTRACE
55336413Ssklower 		if( tpcb->tp_sock->so_error =
55436413Ssklower 			tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m) )  {
55536413Ssklower 			/* error */
55636413Ssklower 			SEQ_DEC(tpcb, lowseq);
55736413Ssklower 			goto done;
55836413Ssklower 		}
55936413Ssklower 		/* set the transmit-time for computation of round-trip times */
56036413Ssklower 		bcopy( (caddr_t)&time,
56136413Ssklower 				(caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ),
56236413Ssklower 				sizeof(struct timeval));
56336413Ssklower 
56436413Ssklower 	}
56536413Ssklower 
56636413Ssklower done:
56736413Ssklower 	IFPERF(tpcb)
56836413Ssklower 		{
56936413Ssklower 			register int npkts;
57036413Ssklower 			struct timeval send_end_time;
57136413Ssklower 			register struct timeval *t;
57236413Ssklower 
57336413Ssklower 			npkts = lowseq;
57436413Ssklower 			SEQ_INC(tpcb, npkts);
57536413Ssklower 			npkts = SEQ_SUB(tpcb, npkts, lowsave);
57636413Ssklower 
57736413Ssklower 			if(npkts > 0)
57836413Ssklower 				tpcb->tp_Nwindow++;
57936413Ssklower 
58036413Ssklower 			if (npkts > TP_PM_MAX)
58136413Ssklower 				npkts = TP_PM_MAX;
58236413Ssklower 
58336413Ssklower 			GET_TIME_SINCE(&send_start_time, &send_end_time);
58436413Ssklower 			t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
58536413Ssklower 			t->tv_sec =
58636413Ssklower 				SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec);
58736413Ssklower 			t->tv_usec =
58836413Ssklower 				SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec);
58936413Ssklower 
59036413Ssklower 			if ( SEQ_LT(tpcb, lowseq, highseq) ) {
59136413Ssklower 				IncPStat(tpcb, tps_win_lim_by_data[npkts] );
59236413Ssklower 			} else {
59336413Ssklower 				IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
59436413Ssklower 				/* not true with congestion-window being used */
59536413Ssklower 			}
59636413Ssklower 			tpmeas( tpcb->tp_lref,
59736413Ssklower 					TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts);
59836413Ssklower 		}
59936413Ssklower 	ENDPERF
60036413Ssklower 
60136413Ssklower 	tpcb->tp_sndhiwat = lowseq;
60236413Ssklower 
60336413Ssklower 	if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat)  &&
60436413Ssklower 			(tpcb->tp_class != TP_CLASS_0) )
60536413Ssklower 			tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave,
60636413Ssklower 				tpcb->tp_sndhiwat,
60736413Ssklower 				(u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks);
60836413Ssklower 	IFTRACE(D_DATA)
60936413Ssklower 		tptraceTPCB( TPPTmisc,
61036413Ssklower 			"tp_send at end: sndhiwat lowseq eotsdu_reached error",
61136413Ssklower 			tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error);
61236413Ssklower 
61336413Ssklower 	ENDTRACE
61436413Ssklower }
61536413Ssklower 
61636413Ssklower /*
61736413Ssklower  * NAME: tp_stash()
61836413Ssklower  * CALLED FROM:
61936413Ssklower  *	tp.trans on arrival of a DT tpdu
62036413Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
62136413Ssklower  * 	Returns 1 if
62236413Ssklower  *		a) something new arrived and it's got eotsdu_reached bit on,
62336413Ssklower  * 		b) this arrival was caused other out-of-sequence things to be
62436413Ssklower  *    	accepted, or
62536413Ssklower  * 		c) this arrival is the highest seq # for which we last gave credit
62636413Ssklower  *   	(sender just sent a whole window)
62736413Ssklower  *  In other words, returns 1 if tp should send an ack immediately, 0 if
62836413Ssklower  *  the ack can wait a while.
62936413Ssklower  *
63036413Ssklower  * Note: this implementation no longer renegs on credit, (except
63136413Ssklower  * when debugging option D_RENEG is on, for the purpose of testing
63236413Ssklower  * ack subsequencing), so we don't  need to check for incoming tpdus
63336413Ssklower  * being in a reneged portion of the window.
63436413Ssklower  */
63536413Ssklower 
63636413Ssklower int
63736413Ssklower tp_stash( tpcb, e )
63836413Ssklower 	register struct tp_pcb		*tpcb;
63936413Ssklower 	register struct tp_event	*e;
64036413Ssklower {
64136413Ssklower 	register int		ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
64236413Ssklower 									/* 0--> delay acks until full window */
64336413Ssklower 									/* 1--> ack each tpdu */
64436413Ssklower 	int		newrec = 0;
64536413Ssklower 
64636413Ssklower #ifndef lint
64736413Ssklower #define E e->ATTR(DT_TPDU)
64836413Ssklower #else lint
64936413Ssklower #define E e->ev_union.EV_DT_TPDU
65036413Ssklower #endif lint
65136413Ssklower 
65236413Ssklower 	if ( E.e_eot ) {
65336413Ssklower 		register struct mbuf *n = E.e_data;
654*37469Ssklower 		n->m_flags |= M_EOR;
655*37469Ssklower 	}
65636413Ssklower 		IFDEBUG(D_STASH)
65736413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
65836413Ssklower 				"stash: so_rcv before appending");
65936413Ssklower 			dump_mbuf(E.e_data,
66036413Ssklower 				"stash: e_data before appending");
66136413Ssklower 		ENDDEBUG
66236413Ssklower 
66336413Ssklower 	IFPERF(tpcb)
66436413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
66536413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
666*37469Ssklower 			E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
66736413Ssklower 	ENDPERF
66836413Ssklower 
66936413Ssklower 	if( E.e_seq == tpcb->tp_rcvnxt ) {
67036413Ssklower 
67136413Ssklower 		IFDEBUG(D_STASH)
67236413Ssklower 			printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
67336413Ssklower 			E.e_seq, E.e_datalen, E.e_eot);
67436413Ssklower 		ENDDEBUG
67536413Ssklower 
67636413Ssklower 		IFTRACE(D_STASH)
67736413Ssklower 			tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
67836413Ssklower 			E.e_seq, E.e_datalen, E.e_eot, 0);
67936413Ssklower 		ENDTRACE
68036413Ssklower 
681*37469Ssklower 		sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
682*37469Ssklower 
68336413Ssklower 		if (newrec = E.e_eot ) /* ASSIGNMENT */
68436413Ssklower 			ack_reason |= ACK_EOT;
68536413Ssklower 
68636413Ssklower 		SEQ_INC( tpcb, tpcb->tp_rcvnxt );
68736413Ssklower 		/*
68836413Ssklower 		 * move chains from the rtc list to the socket buffer
68936413Ssklower 		 * and free the rtc header
69036413Ssklower 		 */
69136413Ssklower 		{
69236413Ssklower 			register struct tp_rtc	**r =  &tpcb->tp_rcvnxt_rtc;
69336413Ssklower 			register struct tp_rtc	*s = tpcb->tp_rcvnxt_rtc;
69436413Ssklower 
69536413Ssklower 			while (s != (struct tp_rtc *)0 && s->tprt_seq == tpcb->tp_rcvnxt) {
69636413Ssklower 				*r = s->tprt_next;
69736413Ssklower 
698*37469Ssklower 				sbappend(&tpcb->tp_sock->so_rcv, s->tprt_data);
69936413Ssklower 
70036413Ssklower 				SEQ_INC( tpcb, tpcb->tp_rcvnxt );
70136413Ssklower 
70236413Ssklower 				(void) m_free( dtom( s ) );
70336413Ssklower 				s = *r;
70436413Ssklower 				ack_reason |= ACK_REORDER;
70536413Ssklower 			}
70636413Ssklower 		}
70736413Ssklower 		IFDEBUG(D_STASH)
70836413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
70936413Ssklower 				"stash: so_rcv after appending");
71036413Ssklower 		ENDDEBUG
71136413Ssklower 
71236413Ssklower 	} else {
71336413Ssklower 		register struct tp_rtc **s = &tpcb->tp_rcvnxt_rtc;
71436413Ssklower 		register struct tp_rtc *r = tpcb->tp_rcvnxt_rtc;
71536413Ssklower 		register struct tp_rtc *t;
71636413Ssklower 
71736413Ssklower 		IFTRACE(D_STASH)
71836413Ssklower 			tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
71936413Ssklower 			E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
72036413Ssklower 		ENDTRACE
72136413Ssklower 
72236413Ssklower 		r = tpcb->tp_rcvnxt_rtc;
72336413Ssklower 		while (r != (struct tp_rtc *)0  && SEQ_LT(tpcb, r->tprt_seq, E.e_seq)) {
72436413Ssklower 			s = &r->tprt_next;
72536413Ssklower 			r = r->tprt_next;
72636413Ssklower 		}
72736413Ssklower 
72836413Ssklower 		if (r == (struct tp_rtc *)0 || SEQ_GT(tpcb, r->tprt_seq, E.e_seq) ) {
72936413Ssklower 			IncStat(ts_dt_ooo);
73036413Ssklower 
73136413Ssklower 			IFTRACE(D_STASH)
73236413Ssklower 				tptrace(TPPTmisc,
73336413Ssklower 				"tp_stash OUT OF ORDER- MAKE RTC: seq, 1st seq in list\n",
73436413Ssklower 					E.e_seq, r->tprt_seq,0,0);
73536413Ssklower 			ENDTRACE
73636413Ssklower 			IFDEBUG(D_STASH)
73736413Ssklower 				printf("tp_stash OUT OF ORDER- MAKE RTC\n");
73836413Ssklower 			ENDDEBUG
73936413Ssklower 			TP_MAKE_RTC(t, E.e_seq, E.e_eot, E.e_data, E.e_datalen, 0,
74036413Ssklower 				TPMT_RCVRTC);
74136413Ssklower 
74236413Ssklower 			*s = t;
74336413Ssklower 			t->tprt_next = (struct tp_rtc *)r;
74436413Ssklower 			ack_reason = ACK_DONT;
74536413Ssklower 			goto done;
74636413Ssklower 		} else {
74736413Ssklower 			IFDEBUG(D_STASH)
74836413Ssklower 				printf("tp_stash - drop & ack\n");
74936413Ssklower 			ENDDEBUG
75036413Ssklower 
75136413Ssklower 			/* retransmission - drop it and force an ack */
75236413Ssklower 			IncStat(ts_dt_dup);
75336413Ssklower 			IFPERF(tpcb)
75436413Ssklower 				IncPStat(tpcb, tps_n_ack_cuz_dup);
75536413Ssklower 			ENDPERF
75636413Ssklower 
75736413Ssklower 			m_freem( E.e_data );
75836413Ssklower 			ack_reason |= ACK_DUP;
75936413Ssklower 			goto done;
76036413Ssklower 		}
76136413Ssklower 	}
76236413Ssklower 
76336413Ssklower 
76436413Ssklower 	/*
76536413Ssklower 	 * an ack should be sent when at least one of the
76636413Ssklower 	 * following holds:
76736413Ssklower 	 * a) we've received a TPDU with EOTSDU set
76836413Ssklower 	 * b) the TPDU that just arrived represents the
76936413Ssklower 	 *    full window last advertised, or
77036413Ssklower 	 * c) when seq X arrives [ where
77136413Ssklower 	 * 		X = last_sent_uwe - 1/2 last_lcredit_sent
77236413Ssklower 	 * 		(the packet representing 1/2 the last advertised window) ]
77336413Ssklower 	 * 		and lcredit at the time of X arrival >  last_lcredit_sent/2
77436413Ssklower 	 * 		In other words, if the last ack sent advertised cdt=8 and uwe = 8
77536413Ssklower 	 * 		then when seq 4 arrives I'd like to send a new ack
77636413Ssklower 	 * 		iff the credit at the time of 4's arrival is > 4.
77736413Ssklower 	 * 		The other end thinks it has cdt of 4 so if local cdt
77836413Ssklower 	 * 		is still 4 there's no point in sending an ack, but if
77936413Ssklower 	 * 		my credit has increased because the receiver has taken
78036413Ssklower 	 * 		some data out of the buffer (soreceive doesn't notify
78136413Ssklower 	 * 		me until the SYSTEM CALL finishes), I'd like to tell
78236413Ssklower 	 * 		the other end.
78336413Ssklower 	 */
78436413Ssklower 
78536413Ssklower done:
78636413Ssklower 	{
78736413Ssklower 		LOCAL_CREDIT(tpcb);
78836413Ssklower 
78936413Ssklower 		if ( E.e_seq ==  tpcb->tp_sent_uwe )
79036413Ssklower 			ack_reason |= ACK_STRAT_FULLWIN;
79136413Ssklower 
79236413Ssklower 		IFTRACE(D_STASH)
79336413Ssklower 			tptraceTPCB(TPPTmisc,
79436413Ssklower 				"end of stash, eot, ack_reason, sent_uwe ",
79536413Ssklower 				E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
79636413Ssklower 		ENDTRACE
79736413Ssklower 
79836413Ssklower 		if ( ack_reason == ACK_DONT ) {
79936413Ssklower 			IncStat( ts_ackreason[ACK_DONT] );
80036413Ssklower 			return 0;
80136413Ssklower 		} else {
80236413Ssklower 			IFPERF(tpcb)
80336413Ssklower 				if(ack_reason & ACK_EOT) {
80436413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_eot);
80536413Ssklower 				}
80636413Ssklower 				if(ack_reason & ACK_STRAT_EACH) {
80736413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_strat);
80836413Ssklower 				} else if(ack_reason & ACK_STRAT_FULLWIN) {
80936413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_fullwin);
81036413Ssklower 				} else if(ack_reason & ACK_REORDER) {
81136413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_reorder);
81236413Ssklower 				}
81336413Ssklower 				tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
81436413Ssklower 							SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
81536413Ssklower 			ENDPERF
81636413Ssklower 			{
81736413Ssklower 				register int i;
81836413Ssklower 
81936413Ssklower 				/* keep track of all reasons that apply */
82036413Ssklower 				for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
82136413Ssklower 					if( ack_reason & (1<<i) )
82236413Ssklower 						IncStat( ts_ackreason[i] );
82336413Ssklower 				}
82436413Ssklower 			}
82536413Ssklower 			return 1;
82636413Ssklower 		}
82736413Ssklower 	}
82836413Ssklower }
82936413Ssklower 
83036413Ssklower /* class zero version */
83136413Ssklower void
83236413Ssklower tp0_stash( tpcb, e )
83336413Ssklower 	register struct tp_pcb		*tpcb;
83436413Ssklower 	register struct tp_event	*e;
83536413Ssklower {
83636413Ssklower #ifndef lint
83736413Ssklower #define E e->ATTR(DT_TPDU)
83836413Ssklower #else lint
83936413Ssklower #define E e->ev_union.EV_DT_TPDU
84036413Ssklower #endif lint
84136413Ssklower 
84236413Ssklower 	IFPERF(tpcb)
84336413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
84436413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
84536413Ssklower 				E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
84636413Ssklower 	ENDPERF
84736413Ssklower 
84836413Ssklower 	IFDEBUG(D_STASH)
84936413Ssklower 		printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
85036413Ssklower 		E.e_seq, E.e_datalen, E.e_eot);
85136413Ssklower 	ENDDEBUG
85236413Ssklower 
85336413Ssklower 	IFTRACE(D_STASH)
85436413Ssklower 		tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
85536413Ssklower 		E.e_seq, E.e_datalen, E.e_eot, 0);
85636413Ssklower 	ENDTRACE
85736413Ssklower 
85836413Ssklower 	if ( E.e_eot ) {
85936413Ssklower 		register struct mbuf *n = E.e_data;
86036413Ssklower 
86136413Ssklower 		/* sigh. have to go through this again! */
86236413Ssklower 		/* a kludgy optimization would be to take care of this in
86336413Ssklower 		 * tp_input (oh, horrors!)
86436413Ssklower 		 */
86536413Ssklower 		while (n->m_next )
86636413Ssklower 			n = n->m_next;
86736413Ssklower 
86836413Ssklower 		n->m_act = MNULL; /* set on tp_input */
86936413Ssklower 
870*37469Ssklower 		n->m_flags |= M_EOR;
87136413Ssklower 	}
872*37469Ssklower 	sbappendrecord (&tpcb->tp_sock->so_rcv, E.e_data);
87336413Ssklower 	IFDEBUG(D_STASH)
87436413Ssklower 		dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
87536413Ssklower 			"stash 0: so_rcv after appending");
87636413Ssklower 	ENDDEBUG
87736413Ssklower }
878