xref: /csrg-svn/sys/netiso/tp_subr.c (revision 51249)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51249Ssklower  *	@(#)tp_subr.c	7.16 (Berkeley) 10/02/91
849268Sbostic  */
949268Sbostic 
1036413Ssklower /***********************************************************
1136413Ssklower 		Copyright IBM Corporation 1987
1236413Ssklower 
1336413Ssklower                       All Rights Reserved
1436413Ssklower 
1536413Ssklower Permission to use, copy, modify, and distribute this software and its
1636413Ssklower documentation for any purpose and without fee is hereby granted,
1736413Ssklower provided that the above copyright notice appear in all copies and that
1836413Ssklower both that copyright notice and this permission notice appear in
1936413Ssklower supporting documentation, and that the name of IBM not be
2036413Ssklower used in advertising or publicity pertaining to distribution of the
2136413Ssklower software without specific, written prior permission.
2236413Ssklower 
2336413Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436413Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536413Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636413Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736413Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836413Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936413Ssklower SOFTWARE.
3036413Ssklower 
3136413Ssklower ******************************************************************/
3236413Ssklower 
3336413Ssklower /*
3436413Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536413Ssklower  */
3636413Ssklower /*
3736413Ssklower  * ARGO TP
3836413Ssklower  *
3936413Ssklower  * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $
4036413Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $
4136413Ssklower  *
4236413Ssklower  * The main work of data transfer is done here.
4336413Ssklower  * These routines are called from tp.trans.
4436413Ssklower  * They include the routines that check the validity of acks and Xacks,
4536413Ssklower  * (tp_goodack() and tp_goodXack() )
4636413Ssklower  * take packets from socket buffers and send them (tp_send()),
4736413Ssklower  * drop the data from the socket buffers (tp_sbdrop()),
4836413Ssklower  * and put incoming packet data into socket buffers (tp_stash()).
4936413Ssklower  */
5036413Ssklower 
5136413Ssklower #include "param.h"
5236413Ssklower #include "mbuf.h"
5336413Ssklower #include "socket.h"
5436413Ssklower #include "socketvar.h"
5536413Ssklower #include "protosw.h"
5636413Ssklower #include "errno.h"
5736413Ssklower #include "types.h"
5836413Ssklower #include "time.h"
5951138Ssklower #include "kernel.h"
6036413Ssklower 
6137469Ssklower #include "tp_ip.h"
6237469Ssklower #include "iso.h"
6337469Ssklower #include "argo_debug.h"
6437469Ssklower #include "tp_timer.h"
6537469Ssklower #include "tp_param.h"
6637469Ssklower #include "tp_stat.h"
6737469Ssklower #include "tp_pcb.h"
6837469Ssklower #include "tp_tpdu.h"
6937469Ssklower #include "tp_trace.h"
7037469Ssklower #include "tp_meas.h"
7137469Ssklower #include "tp_seq.h"
7236413Ssklower 
7351204Ssklower int		tp_emit(), tp_sbdrop();
7451204Ssklower int		tprexmtthresh = 3;
7551204Ssklower void	tp_send();
7636413Ssklower 
7736413Ssklower /*
7836413Ssklower  * CALLED FROM:
7936413Ssklower  *	tp.trans, when an XAK arrives
8036413Ssklower  * FUNCTION and ARGUMENTS:
8136413Ssklower  * 	Determines if the sequence number (seq) from the XAK
8236413Ssklower  * 	acks anything new.  If so, drop the appropriate tpdu
8336413Ssklower  * 	from the XPD send queue.
8436413Ssklower  * RETURN VALUE:
8536413Ssklower  * 	Returns 1 if it did this, 0 if the ack caused no action.
8636413Ssklower  */
8736413Ssklower int
8836413Ssklower tp_goodXack(tpcb, seq)
8936413Ssklower 	struct tp_pcb	*tpcb;
9036413Ssklower 	SeqNum 			seq;
9136413Ssklower {
9236413Ssklower 
9336413Ssklower 	IFTRACE(D_XPD)
9436413Ssklower 		tptraceTPCB(TPPTgotXack,
9551204Ssklower 			seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew,
9636413Ssklower 			tpcb->tp_snduna);
9736413Ssklower 	ENDTRACE
9836413Ssklower 
9936413Ssklower 	if ( seq == tpcb->tp_Xuna ) {
10036413Ssklower 			tpcb->tp_Xuna = tpcb->tp_Xsndnxt;
10136413Ssklower 
10236413Ssklower 			/* DROP 1 packet from the Xsnd socket buf - just so happens
10336413Ssklower 			 * that only one packet can be there at any time
10436413Ssklower 			 * so drop the whole thing.  If you allow > 1 packet
10536413Ssklower 			 * the socket buffer, then you'll have to keep
10636413Ssklower 			 * track of how many characters went w/ each XPD tpdu, so this
10736413Ssklower 			 * will get messier
10836413Ssklower 			 */
10936413Ssklower 			IFDEBUG(D_XPD)
11036413Ssklower 				dump_mbuf(tpcb->tp_Xsnd.sb_mb,
11136413Ssklower 					"tp_goodXack Xsnd before sbdrop");
11236413Ssklower 			ENDDEBUG
11336413Ssklower 
11436413Ssklower 			IFTRACE(D_XPD)
11536413Ssklower 				tptraceTPCB(TPPTmisc,
11636413Ssklower 					"goodXack: dropping cc ",
11736413Ssklower 					(int)(tpcb->tp_Xsnd.sb_cc),
11836413Ssklower 					0,0,0);
11936413Ssklower 			ENDTRACE
12051204Ssklower 			sbdroprecord(&tpcb->tp_Xsnd);
12136413Ssklower 			return 1;
12236413Ssklower 	}
12336413Ssklower 	return 0;
12436413Ssklower }
12536413Ssklower 
12636413Ssklower /*
12736413Ssklower  * CALLED FROM:
12836413Ssklower  *  tp_good_ack()
12936413Ssklower  * FUNCTION and ARGUMENTS:
13036413Ssklower  *  updates
13151138Ssklower  *  smoothed average round trip time (*rtt)
13251138Ssklower  *  roundtrip time variance (*rtv) - actually deviation, not variance
13336413Ssklower  *  given the new value (diff)
13436413Ssklower  * RETURN VALUE:
13536413Ssklower  * void
13636413Ssklower  */
13736413Ssklower 
13836413Ssklower void
13951204Ssklower tp_rtt_rtv(tpcb)
14051204Ssklower register struct tp_pcb *tpcb;
14136413Ssklower {
14251204Ssklower 	int new, old = tpcb->tp_dt_ticks;
14351204Ssklower 	int delta, elapsed = tick - tpcb->tp_rttemit;
14436413Ssklower 
14551204Ssklower 	if (tpcb->tp_rtt != 0) {
14651204Ssklower 		/*
14751204Ssklower 		 * rtt is the smoothed round trip time in machine clock ticks (hz).
148*51249Ssklower 		 * It is stored as a fixed point number, unscaled (unlike the tcp
149*51249Ssklower 		 * srtt).  The rationale here is that it is only significant to the
15051204Ssklower 		 * nearest unit of slowtimo, which is at least 8 machine clock ticks
15151204Ssklower 		 * so there is no need to scale.  The smoothing is done according
15251204Ssklower 		 * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8).
15351204Ssklower 		 */
15451204Ssklower 		delta = elapsed - tpcb->tp_rtt;
15551204Ssklower 		if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0)
15651204Ssklower 			tpcb->tp_rtt = 1;
15751204Ssklower 		/*
15851204Ssklower 		 * rtv is a smoothed accumulated mean difference, unscaled
15951204Ssklower 		 * for reasons expressed above.
16051204Ssklower 		 * It is smoothed with an alpha of .75, and the round trip timer
16151204Ssklower 		 * will be set to rtt + 4*rtv, also as TCP does.
16251204Ssklower 		 */
16351204Ssklower 		if (delta < 0)
16451204Ssklower 			delta = -delta;
16551204Ssklower 		if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0)
16651204Ssklower 			tpcb->tp_rtv = 1;
16751204Ssklower 	} else {
16851204Ssklower 		/*
16951204Ssklower 		 * No rtt measurement yet - use the unsmoothed rtt.
17051204Ssklower 		 * Set the variance to half the rtt (so our first
17151204Ssklower 		 * retransmit happens at 3*rtt)
17251204Ssklower 		 */
17351204Ssklower 		tpcb->tp_rtt = elapsed;
17451204Ssklower 		tpcb->tp_rtv = elapsed >> 1;
17551204Ssklower 	}
17651204Ssklower 	tpcb->tp_rttemit = 0;
17751204Ssklower 	tpcb->tp_rxtshift = 0;
17851204Ssklower 	/*
17951204Ssklower 	 * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar.
18051204Ssklower 	 * Because of the way we do the smoothing, srtt and rttvar
18151204Ssklower 	 * will each average +1/2 tick of bias.  When we compute
18251204Ssklower 	 * the retransmit timer, we want 1/2 tick of rounding and
18351204Ssklower 	 * 1 extra tick because of +-1/2 tick uncertainty in the
18451204Ssklower 	 * firing of the timer.  The bias will give us exactly the
18551204Ssklower 	 * 1.5 tick we need.  But, because the bias is
18651204Ssklower 	 * statistical, we have to test that we don't drop below
18751204Ssklower 	 * the minimum feasible timer (which is 2 ticks)."
18851204Ssklower 	 */
189*51249Ssklower 	TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb),
190*51249Ssklower 		tpcb->tp_peer_acktime, 128 /* XXX */);
19151204Ssklower 	IFTRACE(D_RTT)
19251204Ssklower 		tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks",
19351204Ssklower 			old, rtv, rtt, new);
19451204Ssklower 	ENDTRACE
195*51249Ssklower 	tpcb->tp_rxtcur = tpcb->tp_dt_ticks;
19636413Ssklower }
19736413Ssklower 
19836413Ssklower /*
19936413Ssklower  * CALLED FROM:
20036413Ssklower  *  tp.trans when an AK arrives
20136413Ssklower  * FUNCTION and ARGUMENTS:
20236413Ssklower  * 	Given (cdt), the credit from the AK tpdu, and
20336413Ssklower  *	(seq), the sequence number from the AK tpdu,
20436413Ssklower  *  tp_goodack() determines if the AK acknowledges something in the send
20536413Ssklower  * 	window, and if so, drops the appropriate packets from the retransmission
20636413Ssklower  *  list, computes the round trip time, and updates the retransmission timer
20736413Ssklower  *  based on the new smoothed round trip time.
20836413Ssklower  * RETURN VALUE:
20936413Ssklower  * 	Returns 1 if
21036413Ssklower  * 	EITHER it actually acked something heretofore unacknowledged
21136413Ssklower  * 	OR no news but the credit should be processed.
21236413Ssklower  * 	If something heretofore unacked was acked with this sequence number,
21336413Ssklower  * 	the appropriate tpdus are dropped from the retransmission control list,
21436413Ssklower  * 	by calling tp_sbdrop().
21536413Ssklower  * 	No need to see the tpdu itself.
21636413Ssklower  */
21736413Ssklower int
21836413Ssklower tp_goodack(tpcb, cdt, seq, subseq)
21936413Ssklower 	register struct tp_pcb	*tpcb;
22036413Ssklower 	u_int					cdt;
22151204Ssklower 	register SeqNum			seq;
22251204Ssklower 	u_int					subseq;
22336413Ssklower {
22451204Ssklower 	int 	old_fcredit;
22536413Ssklower 	int 	bang = 0; 	/* bang --> ack for something heretofore unacked */
22651204Ssklower 	u_int	bytes_acked;
22736413Ssklower 
22836413Ssklower 	IFDEBUG(D_ACKRECV)
22951204Ssklower 		printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n",
23051204Ssklower 			tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt);
23136413Ssklower 	ENDDEBUG
23236413Ssklower 	IFTRACE(D_ACKRECV)
23336413Ssklower 		tptraceTPCB(TPPTgotack,
23451204Ssklower 			seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq);
23536413Ssklower 	ENDTRACE
23636413Ssklower 
23736413Ssklower 	IFPERF(tpcb)
23837469Ssklower 		tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0);
23936413Ssklower 	ENDPERF
24036413Ssklower 
24151204Ssklower 	if (seq == tpcb->tp_snduna) {
24251204Ssklower 		if (subseq < tpcb->tp_r_subseq ||
24351204Ssklower 			(subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) {
24451204Ssklower 		discard_the_ack:
24551204Ssklower 			IFDEBUG(D_ACKRECV)
24651204Ssklower 				printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n",
24751204Ssklower 					tpcb, subseq, tpcb->tp_r_subseq);
24851204Ssklower 			ENDDEBUG
24951204Ssklower 			goto done;
25036413Ssklower 		}
25151204Ssklower 		if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) {
25251204Ssklower 			tpcb->tp_r_subseq = subseq;
25351204Ssklower 			if (tpcb->tp_timer[TM_data_retrans] == 0)
25451204Ssklower 				tpcb->tp_dupacks = 0;
25551204Ssklower 			else if (++tpcb->tp_dupacks == tprexmtthresh) {
25651204Ssklower 				/* partner went out of his way to signal with different
25751204Ssklower 				   subsequences that he has the same lack of an expected
25851204Ssklower 				   packet.  This may be an early indiciation of a loss */
25936413Ssklower 
26051204Ssklower 				SeqNum onxt = tpcb->tp_sndnxt;
26151204Ssklower 				struct mbuf *onxt_m = tpcb->tp_sndnxt_m;
26251204Ssklower 				u_int win = min(tpcb->tp_fcredit,
26351204Ssklower 							tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2;
26451204Ssklower 				if (win < 2)
26551204Ssklower 					win = 2;
26651204Ssklower 				tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
26751204Ssklower 				tpcb->tp_timer[TM_data_retrans] = 0;
26851204Ssklower 				tpcb->tp_rttemit = 0;
26951204Ssklower 				tpcb->tp_sndnxt = tpcb->tp_snduna;
27051204Ssklower 				tpcb->tp_sndnxt_m = 0;
27151204Ssklower 				tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
27251204Ssklower 				tp_send(tpcb);
27351204Ssklower 				tpcb->tp_cong_win = tpcb->tp_ssthresh +
27451204Ssklower 					tpcb->tp_dupacks * tpcb->tp_l_tpdusize;
27551204Ssklower 				if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) {
27651204Ssklower 					tpcb->tp_sndnxt = onxt;
27751204Ssklower 					tpcb->tp_sndnxt_m = onxt_m;
27851204Ssklower 				}
27936413Ssklower 
28051204Ssklower 			} else if (tpcb->tp_dupacks > tprexmtthresh) {
28151204Ssklower 				tpcb->tp_cong_win += tpcb->tp_l_tpdusize;
28251138Ssklower 			}
28351204Ssklower 			goto done;
28451204Ssklower 		}
28551204Ssklower 	} else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna))
28651204Ssklower 		goto discard_the_ack;
28751204Ssklower 	/*
28851204Ssklower 	 * If the congestion window was inflated to account
28951204Ssklower 	 * for the other side's cached packets, retract it.
29051204Ssklower 	 */
29151204Ssklower 	if (tpcb->tp_dupacks > tprexmtthresh &&
29251204Ssklower 		tpcb->tp_cong_win > tpcb->tp_ssthresh)
29351204Ssklower 			tpcb->tp_cong_win = tpcb->tp_ssthresh;
29451204Ssklower 	tpcb->tp_r_subseq = subseq;
29551204Ssklower 	old_fcredit = tpcb->tp_fcredit;
29651204Ssklower 	tpcb->tp_fcredit = cdt;
29751204Ssklower 	if (cdt > tpcb->tp_maxfcredit)
29851204Ssklower 		tpcb->tp_maxfcredit = cdt;
29951204Ssklower 	tpcb->tp_dupacks = 0;
30036413Ssklower 
30151204Ssklower 	if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) {
30236413Ssklower 
30351204Ssklower 		tpsbcheck(tpcb, 0);
30451204Ssklower 		bytes_acked = tp_sbdrop(tpcb, seq);
30551204Ssklower 		tpsbcheck(tpcb, 1);
30651204Ssklower 		/*
30751204Ssklower 		 * If transmit timer is running and timed sequence
30851204Ssklower 		 * number was acked, update smoothed round trip time.
30951204Ssklower 		 * Since we now have an rtt measurement, cancel the
31051204Ssklower 		 * timer backoff (cf., Phil Karn's retransmit alg.).
31151204Ssklower 		 * Recompute the initial retransmit timer.
31251204Ssklower 		 */
31351204Ssklower 		if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq))
31451204Ssklower 			tp_rtt_rtv(tpcb);
31551204Ssklower 		/*
31651204Ssklower 		 * If all outstanding data is acked, stop retransmit timer.
31751204Ssklower 		 * If there is more data to be acked, restart retransmit
31851204Ssklower 		 * timer, using current (possibly backed-off) value.
31951204Ssklower 		 * OSI combines the keepalive and persistance functions.
32051204Ssklower 		 * So, there is no persistance timer per se, to restart.
32151204Ssklower 		 */
32251204Ssklower 		tpcb->tp_timer[TM_data_retrans] =
32351204Ssklower 			(seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur;
32451204Ssklower 		/*
32551204Ssklower 		 * When new data is acked, open the congestion window.
32651204Ssklower 		 * If the window gives us less than ssthresh packets
32751204Ssklower 		 * in flight, open exponentially (maxseg per packet).
32851204Ssklower 		 * Otherwise open linearly: maxseg per window
32951204Ssklower 		 * (maxseg^2 / cwnd per packet), plus a constant
33051204Ssklower 		 * fraction of a packet (maxseg/8) to help larger windows
33151204Ssklower 		 * open quickly enough.
33251204Ssklower 		 */
33351204Ssklower 		{
33451204Ssklower 			u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize;
33536413Ssklower 
33651204Ssklower 			incr = min(incr, bytes_acked);
33751204Ssklower 			if (cw > tpcb->tp_ssthresh)
33851204Ssklower 				incr = incr * incr / cw + incr / 8;
33951204Ssklower 			tpcb->tp_cong_win =
34051204Ssklower 				min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat);
34136413Ssklower 		}
34236413Ssklower 		tpcb->tp_snduna = seq;
34351204Ssklower 		if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) {
34451204Ssklower 				tpcb->tp_sndnxt = seq;
34551204Ssklower 				tpcb->tp_sndnxt_m = 0;
34651204Ssklower 		}
34736413Ssklower 		bang++;
34836413Ssklower 	}
34936413Ssklower 
35036413Ssklower 	if( cdt != 0 && old_fcredit == 0 ) {
35136413Ssklower 		tpcb->tp_sendfcc = 1;
35236413Ssklower 	}
353*51249Ssklower 	if (cdt == 0) {
354*51249Ssklower 		if (old_fcredit != 0)
355*51249Ssklower 			IncStat(ts_zfcdt);
356*51249Ssklower 		/* The following might mean that the window shrunk */
357*51249Ssklower 		if (tpcb->tp_timer[TM_data_retrans]) {
358*51249Ssklower 			tpcb->tp_timer[TM_data_retrans] = 0;
359*51249Ssklower 			tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
360*51249Ssklower 			if (tpcb->tp_sndnxt != tpcb->tp_snduna) {
361*51249Ssklower 				tpcb->tp_sndnxt = tpcb->tp_snduna;
362*51249Ssklower 				tpcb->tp_sndnxt_m = 0;
363*51249Ssklower 			}
364*51249Ssklower 		}
36536413Ssklower 	}
36636413Ssklower 	tpcb->tp_fcredit = cdt;
36751204Ssklower 	bang |= (old_fcredit < cdt);
36836413Ssklower 
36951204Ssklower done:
37036413Ssklower 	IFDEBUG(D_ACKRECV)
37151204Ssklower 		printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n",
37251204Ssklower 			bang, cdt, old_fcredit, tpcb->tp_cong_win);
37336413Ssklower 	ENDDEBUG
37451204Ssklower 	/* if (bang) XXXXX Very bad to remove this test, but somethings broken */
37551204Ssklower 		tp_send(tpcb);
37651204Ssklower 	return (bang);
37736413Ssklower }
37836413Ssklower 
37936413Ssklower /*
38036413Ssklower  * CALLED FROM:
38136413Ssklower  *  tp_goodack()
38236413Ssklower  * FUNCTION and ARGUMENTS:
38350901Ssklower  *  drops everything up TO but not INCLUDING seq # (seq)
38436413Ssklower  *  from the retransmission queue.
38536413Ssklower  */
38636413Ssklower tp_sbdrop(tpcb, seq)
38750901Ssklower 	register struct 	tp_pcb 			*tpcb;
38836413Ssklower 	SeqNum					seq;
38936413Ssklower {
39050901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
39151204Ssklower 	register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna);
39251204Ssklower 	int	oldcc = sb->sb_cc, oldi = i;
39336413Ssklower 
39451204Ssklower 	if (i >= tpcb->tp_seqhalf)
39551204Ssklower 		printf("tp_spdropping too much -- should panic");
39651204Ssklower 	while (i-- > 0)
39751204Ssklower 		sbdroprecord(sb);
39836413Ssklower 	IFDEBUG(D_ACKRECV)
39951204Ssklower 		printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n",
40051204Ssklower 			oldi, oldcc - sb->sb_cc, tpcb, seq);
40136413Ssklower 	ENDDEBUG
40251204Ssklower 	if (sb->sb_flags & SB_NOTIFY)
40351204Ssklower 		sowwakeup(tpcb->tp_sock);
40451138Ssklower 	return (oldcc - sb->sb_cc);
40536413Ssklower }
40636413Ssklower 
40736413Ssklower /*
40836413Ssklower  * CALLED FROM:
40936413Ssklower  * 	tp.trans on user send request, arrival of AK and arrival of XAK
41036413Ssklower  * FUNCTION and ARGUMENTS:
41151204Ssklower  * 	Emits tpdus starting at sequence number (tpcb->tp_sndnxt).
41236413Ssklower  * 	Emits until a) runs out of data, or  b) runs into an XPD mark, or
41351204Ssklower  * 			c) it hits seq number (highseq) limited by cong or credit.
41436413Ssklower  *
41536413Ssklower  * 	If you want XPD to buffer > 1 du per socket buffer, you can
41636413Ssklower  * 	modifiy this to issue XPD tpdus also, but then it'll have
41736413Ssklower  * 	to take some argument(s) to distinguish between the type of DU to
41850901Ssklower  * 	hand tp_emit.
41936413Ssklower  *
42036413Ssklower  * 	When something is sent for the first time, its time-of-send
42151204Ssklower  * 	is stashed (in system clock ticks rather than pf_slowtimo ticks).
42251204Ssklower  *  When the ack arrives, the smoothed round-trip time is figured
42351204Ssklower  *  using this value.
42436413Ssklower  */
42551204Ssklower void
42636413Ssklower tp_send(tpcb)
42736413Ssklower 	register struct tp_pcb	*tpcb;
42836413Ssklower {
42936413Ssklower 	register int			len;
43051204Ssklower 	register struct mbuf	*m;
43151204Ssklower 	struct mbuf				*mb = 0;
43236413Ssklower 	struct 	sockbuf			*sb = &tpcb->tp_sock->so_snd;
43351204Ssklower 	unsigned int			eotsdu = 0;
43451204Ssklower 	SeqNum					highseq, checkseq;
43551204Ssklower 	int						idle, idleticks, off, cong_win;
43636413Ssklower #ifdef TP_PERF_MEAS
43751138Ssklower 	int			 			send_start_time = tick;
43851204Ssklower 	SeqNum					oldnxt = tpcb->tp_sndnxt;
43936413Ssklower #endif TP_PERF_MEAS
44036413Ssklower 
44151204Ssklower 	idle = (tpcb->tp_snduna == tpcb->tp_sndnew);
44251204Ssklower 	if (idle) {
44351204Ssklower 		idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact];
44451204Ssklower 		if (idleticks > tpcb->tp_dt_ticks)
44551204Ssklower 			/*
44651204Ssklower 			 * We have been idle for "a while" and no acks are
44751204Ssklower 			 * expected to clock out any data we send --
44851204Ssklower 			 * slow start to get ack "clock" running again.
44951204Ssklower 			 */
45051204Ssklower 			tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
45151204Ssklower 	}
45236413Ssklower 
45351204Ssklower 	cong_win = tpcb->tp_cong_win;
45451204Ssklower 	highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna);
45551204Ssklower 	if (tpcb->tp_Xsnd.sb_mb)
45651204Ssklower 		highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew);
45736413Ssklower 
45836413Ssklower 	IFDEBUG(D_DATA)
45951204Ssklower 		printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n",
46051204Ssklower 				tpcb, tpcb->tp_sndnxt, cong_win, highseq);
46136413Ssklower 	ENDDEBUG
46236413Ssklower 	IFTRACE(D_DATA)
46351204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send sndnew snduna",
46451204Ssklower 			tpcb->tp_sndnew,  tpcb->tp_snduna, 0, 0);
46551204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin",
46651204Ssklower 			tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win);
46736413Ssklower 	ENDTRACE
46836413Ssklower 	IFTRACE(D_DATA)
46951204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin",
47051204Ssklower 			tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win);
47136413Ssklower 	ENDTRACE
47236413Ssklower 
47351204Ssklower 	if (tpcb->tp_sndnxt_m)
47451204Ssklower 		m = tpcb->tp_sndnxt_m;
47551204Ssklower 	else {
47651204Ssklower 		off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna);
47751204Ssklower 		for (m = sb->sb_mb; m && off > 0; m = m->m_next)
47851204Ssklower 			off--;
47951204Ssklower 	}
48051204Ssklower send:
48151204Ssklower 	/*
48251204Ssklower 	 * Avoid silly window syndrome here . . . figure out how!
48351204Ssklower 	 */
48451204Ssklower 	checkseq = tpcb->tp_sndnum;
48551204Ssklower 	if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq))
486*51249Ssklower 		checkseq = highseq; /* i.e. DON'T retain highest assigned packet */
48736413Ssklower 
48851204Ssklower 	while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) {
48936413Ssklower 
49051204Ssklower 		eotsdu = (m->m_flags & M_EOR) != 0;
49151204Ssklower 		len = m->m_pkthdr.len;
49251204Ssklower 		if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 &&
49351204Ssklower 			len < (tpcb->tp_l_tpdusize / 2))
49451204Ssklower 				break;  /* Nagle . . . . . */
49551204Ssklower 		cong_win -= len;
49636413Ssklower 		/* make a copy - mb goes into the retransmission list
49736413Ssklower 		 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
49836413Ssklower 		 */
49951204Ssklower 		mb = m;
50050901Ssklower 		m = m_copy(mb, 0, M_COPYALL);
50150901Ssklower 		if (m == MNULL)
50251204Ssklower 				break;
50351204Ssklower 		IFTRACE(D_STASH)
50436413Ssklower 			tptraceTPCB( TPPTmisc,
50551204Ssklower 				"tp_send mcopy nxt high eotsdu len",
50651204Ssklower 				tpcb->tp_sndnxt, highseq, eotsdu, len);
50736413Ssklower 		ENDTRACE
50851204Ssklower 
50951204Ssklower 		IFDEBUG(D_DATA)
51051204Ssklower 			printf("tp_sending tpcb 0x%x nxt 0x%x\n",
51151204Ssklower 				tpcb, tpcb->tp_sndnxt);
51251204Ssklower 		ENDDEBUG
51351204Ssklower 		/* when headers are precomputed, may need to fill
51450901Ssklower 			   in checksum here */
51550901Ssklower 		if (tpcb->tp_sock->so_error =
51651204Ssklower 			tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) {
51736413Ssklower 			/* error */
51851204Ssklower 			break;
51936413Ssklower 		}
52051204Ssklower 		m = mb->m_nextpkt;
52151204Ssklower 		tpcb->tp_sndnxt_m = m;
52251204Ssklower 		if (tpcb->tp_sndnxt == tpcb->tp_sndnew) {
52351204Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnew);
52451204Ssklower 			/*
52551204Ssklower 			 * Time this transmission if not a retransmission and
52651204Ssklower 			 * not currently timing anything.
52751204Ssklower 			 */
52851204Ssklower 			if (tpcb->tp_rttemit == 0) {
52951204Ssklower 				tpcb->tp_rttemit = tick;
53051204Ssklower 				tpcb->tp_rttseq = tpcb->tp_sndnxt;
53151204Ssklower 			}
53251204Ssklower 			tpcb->tp_sndnxt = tpcb->tp_sndnew;
53351204Ssklower 		} else
53451204Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnxt);
53551204Ssklower 		/*
53651204Ssklower 		 * Set retransmit timer if not currently set.
53751204Ssklower 		 * Initial value for retransmit timer is smoothed
53851204Ssklower 		 * round-trip time + 2 * round-trip time variance.
53951204Ssklower 		 * Initialize shift counter which is used for backoff
54051204Ssklower 		 * of retransmit time.
54151204Ssklower 		 */
54251204Ssklower 		if (tpcb->tp_timer[TM_data_retrans] == 0) {
54351204Ssklower 			tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks;
54451204Ssklower 			tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks;
54551204Ssklower 			tpcb->tp_rxtshift = 0;
54651138Ssklower 		}
54736413Ssklower 	}
54851204Ssklower 	if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum))
54951204Ssklower 		tpcb->tp_oktonagle = 0;
55050236Ssklower #ifdef TP_PERF_MEAS
55136413Ssklower 	IFPERF(tpcb)
55236413Ssklower 		{
55336413Ssklower 			register int npkts;
55451138Ssklower 			int	 elapsed = tick - send_start_time, *t;
55551138Ssklower 			struct timeval now;
55636413Ssklower 
55751204Ssklower 			npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt);
55836413Ssklower 
55951204Ssklower 			if (npkts > 0)
56036413Ssklower 				tpcb->tp_Nwindow++;
56136413Ssklower 
56236413Ssklower 			if (npkts > TP_PM_MAX)
56336413Ssklower 				npkts = TP_PM_MAX;
56436413Ssklower 
56536413Ssklower 			t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
56651138Ssklower 			*t += (t - elapsed) >> TP_RTT_ALPHA;
56736413Ssklower 
56851204Ssklower 			if (mb == 0) {
56936413Ssklower 				IncPStat(tpcb, tps_win_lim_by_data[npkts] );
57036413Ssklower 			} else {
57136413Ssklower 				IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
57236413Ssklower 				/* not true with congestion-window being used */
57336413Ssklower 			}
57451138Ssklower 			now.tv_sec = elapsed / hz;
57551138Ssklower 			now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz;
57636413Ssklower 			tpmeas( tpcb->tp_lref,
57751204Ssklower 					TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts);
57836413Ssklower 		}
57936413Ssklower 	ENDPERF
58050236Ssklower #endif TP_PERF_MEAS
58136413Ssklower 
58236413Ssklower 
58336413Ssklower 	IFTRACE(D_DATA)
58436413Ssklower 		tptraceTPCB( TPPTmisc,
58551204Ssklower 			"tp_send at end: new nxt eotsdu error",
58651204Ssklower 			tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error);
58736413Ssklower 
58836413Ssklower 	ENDTRACE
58936413Ssklower }
59036413Ssklower 
59150901Ssklower int TPNagleok;
59250901Ssklower int TPNagled;
59350901Ssklower 
59450901Ssklower tp_packetize(tpcb, m, eotsdu)
59550901Ssklower register struct tp_pcb *tpcb;
59650901Ssklower register struct mbuf *m;
59750901Ssklower int eotsdu;
59850901Ssklower {
59950901Ssklower 	register struct mbuf *n;
60050901Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_snd;
60150901Ssklower 	int	maxsize = tpcb->tp_l_tpdusize
60250901Ssklower 			- tp_headersize(DT_TPDU_type, tpcb)
60350901Ssklower 			- (tpcb->tp_use_checksum?4:0) ;
60450901Ssklower 	int totlen = m->m_pkthdr.len;
60550901Ssklower 	struct mbuf *m_split();
60650901Ssklower 	/*
60750901Ssklower 	 * Pre-packetize the data in the sockbuf
60850901Ssklower 	 * according to negotiated mtu.  Do it here
60950901Ssklower 	 * where we can safely wait for mbufs.
61050901Ssklower 	 *
61150901Ssklower 	 * This presumes knowledge of sockbuf conventions.
61250901Ssklower 	 * TODO: allocate space for header and fill it in (once!).
61350901Ssklower 	 */
61451204Ssklower 	IFDEBUG(D_DATA)
61551204Ssklower 		printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n",
61651204Ssklower 			maxsize, totlen, eotsdu, tpcb->tp_sndnum);
61750901Ssklower 	ENDTRACE
61850901Ssklower 	if (tpcb->tp_oktonagle) {
61950901Ssklower 		if ((n = sb->sb_mb) == 0)
62050901Ssklower 			panic("tp_packetize");
62150901Ssklower 		while (n->m_act)
62250901Ssklower 			n = n->m_act;
62350901Ssklower 		if (n->m_flags & M_EOR)
62450901Ssklower 			panic("tp_packetize 2");
62550901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
62650901Ssklower 		if (totlen + n->m_pkthdr.len < maxsize) {
62750901Ssklower 			/* There is an unsent packet with space, combine data */
62850901Ssklower 			struct mbuf *old_n = n;
62950901Ssklower 			tpsbcheck(tpcb,3);
63050901Ssklower 			n->m_pkthdr.len += totlen;
63150901Ssklower 			while (n->m_next)
63250901Ssklower 				n = n->m_next;
63350901Ssklower 			sbcompress(sb, m, n);
63450901Ssklower 			tpsbcheck(tpcb,4);
63550901Ssklower 			n = old_n;
63650901Ssklower 			TPNagled++;
63750901Ssklower 			goto out;
63850901Ssklower 		}
63950901Ssklower 	}
64050901Ssklower 	while (m) {
64150901Ssklower 		n = m;
64250901Ssklower 		if (totlen > maxsize) {
64350901Ssklower 			if ((m = m_split(n, maxsize, M_WAIT)) == 0)
64450901Ssklower 				panic("tp_packetize");
64550901Ssklower 		} else
64650901Ssklower 			m = 0;
64750901Ssklower 		totlen -= maxsize;
64850901Ssklower 		tpsbcheck(tpcb, 5);
64950901Ssklower 		sbappendrecord(sb, n);
65050901Ssklower 		tpsbcheck(tpcb, 6);
65150901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
65250901Ssklower 	}
65350901Ssklower out:
65450901Ssklower 	if (eotsdu) {
65550901Ssklower 		n->m_flags |= M_EOR;  /* XXX belongs at end */
65650901Ssklower 		tpcb->tp_oktonagle = 0;
65750901Ssklower 	} else {
65850901Ssklower 		SEQ_DEC(tpcb, tpcb->tp_sndnum);
65950901Ssklower 		tpcb->tp_oktonagle = 1;
66050901Ssklower 		TPNagleok++;
66150901Ssklower 	}
66251204Ssklower 	IFDEBUG(D_DATA)
66351204Ssklower 		printf("SEND out: oktonagle %d sndnum 0x%x\n",
66451204Ssklower 			tpcb->tp_oktonagle, tpcb->tp_sndnum);
66551204Ssklower 	ENDTRACE
66650901Ssklower 	return 0;
66750901Ssklower }
66850901Ssklower 
66950901Ssklower 
67036413Ssklower /*
67136413Ssklower  * NAME: tp_stash()
67236413Ssklower  * CALLED FROM:
67336413Ssklower  *	tp.trans on arrival of a DT tpdu
67436413Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
67536413Ssklower  * 	Returns 1 if
67636413Ssklower  *		a) something new arrived and it's got eotsdu_reached bit on,
67736413Ssklower  * 		b) this arrival was caused other out-of-sequence things to be
67836413Ssklower  *    	accepted, or
67936413Ssklower  * 		c) this arrival is the highest seq # for which we last gave credit
68036413Ssklower  *   	(sender just sent a whole window)
68136413Ssklower  *  In other words, returns 1 if tp should send an ack immediately, 0 if
68236413Ssklower  *  the ack can wait a while.
68336413Ssklower  *
68436413Ssklower  * Note: this implementation no longer renegs on credit, (except
68536413Ssklower  * when debugging option D_RENEG is on, for the purpose of testing
68636413Ssklower  * ack subsequencing), so we don't  need to check for incoming tpdus
68736413Ssklower  * being in a reneged portion of the window.
68836413Ssklower  */
68936413Ssklower 
69051204Ssklower tp_stash(tpcb, e)
69136413Ssklower 	register struct tp_pcb		*tpcb;
69236413Ssklower 	register struct tp_event	*e;
69336413Ssklower {
69436413Ssklower 	register int		ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
69536413Ssklower 									/* 0--> delay acks until full window */
69636413Ssklower 									/* 1--> ack each tpdu */
69736413Ssklower #ifndef lint
69836413Ssklower #define E e->ATTR(DT_TPDU)
69936413Ssklower #else lint
70036413Ssklower #define E e->ev_union.EV_DT_TPDU
70136413Ssklower #endif lint
70236413Ssklower 
70336413Ssklower 	if ( E.e_eot ) {
70436413Ssklower 		register struct mbuf *n = E.e_data;
70537469Ssklower 		n->m_flags |= M_EOR;
70638841Ssklower 		n->m_act = 0;
70737469Ssklower 	}
70836413Ssklower 		IFDEBUG(D_STASH)
70936413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
71036413Ssklower 				"stash: so_rcv before appending");
71136413Ssklower 			dump_mbuf(E.e_data,
71236413Ssklower 				"stash: e_data before appending");
71336413Ssklower 		ENDDEBUG
71436413Ssklower 
71536413Ssklower 	IFPERF(tpcb)
71636413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
71736413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
71837469Ssklower 			E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
71936413Ssklower 	ENDPERF
72036413Ssklower 
72151024Ssklower 	if (E.e_seq == tpcb->tp_rcvnxt) {
72236413Ssklower 
72336413Ssklower 		IFDEBUG(D_STASH)
72436413Ssklower 			printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
72536413Ssklower 			E.e_seq, E.e_datalen, E.e_eot);
72636413Ssklower 		ENDDEBUG
72736413Ssklower 
72836413Ssklower 		IFTRACE(D_STASH)
72936413Ssklower 			tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
73036413Ssklower 			E.e_seq, E.e_datalen, E.e_eot, 0);
73136413Ssklower 		ENDTRACE
73236413Ssklower 
73351024Ssklower 		SET_DELACK(tpcb);
73451024Ssklower 
73537469Ssklower 		sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
73637469Ssklower 
73736413Ssklower 		SEQ_INC( tpcb, tpcb->tp_rcvnxt );
73836413Ssklower 		/*
73950901Ssklower 		 * move chains from the reassembly queue to the socket buffer
74036413Ssklower 		 */
74150901Ssklower 		if (tpcb->tp_rsycnt) {
74250901Ssklower 			register struct mbuf **mp;
74350901Ssklower 			struct mbuf **mplim;
74436413Ssklower 
74550901Ssklower 			mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit);
74650901Ssklower 			mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit;
74736413Ssklower 
74850901Ssklower 			while (tpcb->tp_rsycnt && *mp) {
74950901Ssklower 				sbappend(&tpcb->tp_sock->so_rcv, *mp);
75050901Ssklower 				tpcb->tp_rsycnt--;
75150901Ssklower 				*mp = 0;
75250901Ssklower 				SEQ_INC(tpcb, tpcb->tp_rcvnxt);
75336413Ssklower 				ack_reason |= ACK_REORDER;
75450901Ssklower 				if (++mp == mplim)
75550901Ssklower 					mp = tpcb->tp_rsyq;
75636413Ssklower 			}
75736413Ssklower 		}
75836413Ssklower 		IFDEBUG(D_STASH)
75936413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
76036413Ssklower 				"stash: so_rcv after appending");
76136413Ssklower 		ENDDEBUG
76236413Ssklower 
76336413Ssklower 	} else {
76450901Ssklower 		register struct mbuf **mp;
76550901Ssklower 		SeqNum uwe;
76636413Ssklower 
76736413Ssklower 		IFTRACE(D_STASH)
76836413Ssklower 			tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
76936413Ssklower 			E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
77036413Ssklower 		ENDTRACE
77136413Ssklower 
77250975Ssklower 		if (tpcb->tp_rsyq == 0)
77350975Ssklower 			tp_rsyset(tpcb);
77450901Ssklower 		uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit);
77550901Ssklower 		if (tpcb->tp_rsyq == 0 ||
77650901Ssklower 						!IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) {
77736413Ssklower 			ack_reason = ACK_DONT;
77850901Ssklower 			m_freem(E.e_data);
77950901Ssklower 		} else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) {
78036413Ssklower 			IFDEBUG(D_STASH)
78136413Ssklower 				printf("tp_stash - drop & ack\n");
78236413Ssklower 			ENDDEBUG
78336413Ssklower 
78436413Ssklower 			/* retransmission - drop it and force an ack */
78536413Ssklower 			IncStat(ts_dt_dup);
78636413Ssklower 			IFPERF(tpcb)
78736413Ssklower 				IncPStat(tpcb, tps_n_ack_cuz_dup);
78836413Ssklower 			ENDPERF
78936413Ssklower 
79050901Ssklower 			m_freem(E.e_data);
79136413Ssklower 			ack_reason |= ACK_DUP;
79250901Ssklower 		} else {
79350901Ssklower 			*mp = E.e_data;
79450901Ssklower 			tpcb->tp_rsycnt++;
79550901Ssklower 			ack_reason = ACK_DONT;
79636413Ssklower 		}
79736413Ssklower 	}
79851024Ssklower 	/* there were some comments of historical interest here. */
79936413Ssklower 	{
80036413Ssklower 		LOCAL_CREDIT(tpcb);
80136413Ssklower 
80236413Ssklower 		if ( E.e_seq ==  tpcb->tp_sent_uwe )
80336413Ssklower 			ack_reason |= ACK_STRAT_FULLWIN;
80436413Ssklower 
80536413Ssklower 		IFTRACE(D_STASH)
80636413Ssklower 			tptraceTPCB(TPPTmisc,
80736413Ssklower 				"end of stash, eot, ack_reason, sent_uwe ",
80836413Ssklower 				E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
80936413Ssklower 		ENDTRACE
81036413Ssklower 
81136413Ssklower 		if ( ack_reason == ACK_DONT ) {
81236413Ssklower 			IncStat( ts_ackreason[ACK_DONT] );
81336413Ssklower 			return 0;
81436413Ssklower 		} else {
81536413Ssklower 			IFPERF(tpcb)
81636413Ssklower 				if(ack_reason & ACK_STRAT_EACH) {
81736413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_strat);
81836413Ssklower 				} else if(ack_reason & ACK_STRAT_FULLWIN) {
81936413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_fullwin);
82036413Ssklower 				} else if(ack_reason & ACK_REORDER) {
82136413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_reorder);
82236413Ssklower 				}
82336413Ssklower 				tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
82436413Ssklower 							SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
82536413Ssklower 			ENDPERF
82636413Ssklower 			{
82736413Ssklower 				register int i;
82836413Ssklower 
82936413Ssklower 				/* keep track of all reasons that apply */
83036413Ssklower 				for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
83136413Ssklower 					if( ack_reason & (1<<i) )
83236413Ssklower 						IncStat( ts_ackreason[i] );
83336413Ssklower 				}
83436413Ssklower 			}
83536413Ssklower 			return 1;
83636413Ssklower 		}
83736413Ssklower 	}
83836413Ssklower }
83950901Ssklower 
84050901Ssklower /*
84150901Ssklower  * tp_rsyflush - drop all the packets on the reassembly queue.
84250901Ssklower  * Do this when closing the socket, or when somebody has changed
84350901Ssklower  * the space avaible in the receive socket (XXX).
84450901Ssklower  */
84550901Ssklower tp_rsyflush(tpcb)
84650901Ssklower register struct tp_pcb *tpcb;
84750901Ssklower {
84850901Ssklower 	register struct mbuf *m, **mp;
84950901Ssklower 	if (tpcb->tp_rsycnt) {
85050901Ssklower 		for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit;
85150901Ssklower 									 --mp >= tpcb->tp_rsyq; )
85250901Ssklower 			if (*mp) {
85350901Ssklower 				tpcb->tp_rsycnt--;
85450901Ssklower 				m_freem(*mp);
85550901Ssklower 			}
85650901Ssklower 		if (tpcb->tp_rsycnt)
85750901Ssklower 			panic("tp_rsyflush");
85850901Ssklower 	}
85950901Ssklower 	free((caddr_t)tpcb->tp_rsyq, M_PCB);
86050901Ssklower 	tpcb->tp_rsyq = 0;
86150901Ssklower }
86250901Ssklower 
86350901Ssklower tp_rsyset(tpcb)
86450901Ssklower register struct tp_pcb *tpcb;
86550901Ssklower {
86650901Ssklower 	register struct socket *so = tpcb->tp_sock;
86750901Ssklower 	int maxcredit  = tpcb->tp_xtd_format ? 0xffff : 0xf;
86850975Ssklower 	int old_credit = tpcb->tp_maxlcredit;
86950975Ssklower 	caddr_t	rsyq;
87050901Ssklower 
87150901Ssklower 	tpcb->tp_maxlcredit = maxcredit = min(maxcredit,
87250901Ssklower 		  (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize);
87350901Ssklower 
87450975Ssklower 	if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0)
87550975Ssklower 		return;
87650901Ssklower 	maxcredit *= sizeof(struct mbuf *);
87750901Ssklower 	if (tpcb->tp_rsyq)
87850901Ssklower 		tp_rsyflush(tpcb);
87950901Ssklower 	if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT))
88050901Ssklower 		bzero(rsyq, maxcredit);
88150901Ssklower 	tpcb->tp_rsyq = (struct mbuf **)rsyq;
88250901Ssklower }
88350901Ssklower 
88450901Ssklower tpsbcheck(tpcb, i)
88550901Ssklower struct tp_pcb *tpcb;
88650901Ssklower {
88750901Ssklower 	register struct mbuf *n, *m;
88850901Ssklower 	register int len = 0, mbcnt = 0, pktlen;
88950901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
89050901Ssklower 
89150901Ssklower 	for (n = sb->sb_mb; n; n = n->m_nextpkt) {
89250901Ssklower 		if ((n->m_flags & M_PKTHDR) == 0)
89350901Ssklower 			panic("tpsbcheck nohdr");
89450901Ssklower 		pktlen = len + n->m_pkthdr.len;
89550901Ssklower 	    for (m = n; m; m = m->m_next) {
89650901Ssklower 			len += m->m_len;
89750901Ssklower 			mbcnt += MSIZE;
89850901Ssklower 			if (m->m_flags & M_EXT)
89950901Ssklower 				mbcnt += m->m_ext.ext_size;
90050901Ssklower 		}
90150901Ssklower 		if (len != pktlen) {
90250901Ssklower 			printf("test %d; len %d != pktlen %d on mbuf 0x%x\n",
90350901Ssklower 				i, len, pktlen, n);
90450901Ssklower 			panic("tpsbcheck short");
90550901Ssklower 		}
90650901Ssklower 	}
90750901Ssklower 	if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
90850901Ssklower 		printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc,
90950901Ssklower 		    mbcnt, sb->sb_mbcnt);
91050901Ssklower 		panic("tpsbcheck");
91150901Ssklower 	}
91250901Ssklower }
913