xref: /csrg-svn/sys/netiso/tp_subr.c (revision 51204)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51204Ssklower  *	@(#)tp_subr.c	7.15 (Berkeley) 09/26/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 
73*51204Ssklower int		tp_emit(), tp_sbdrop();
74*51204Ssklower int		tprexmtthresh = 3;
75*51204Ssklower 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,
95*51204Ssklower 			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
120*51204Ssklower 			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
139*51204Ssklower tp_rtt_rtv(tpcb)
140*51204Ssklower register struct tp_pcb *tpcb;
14136413Ssklower {
142*51204Ssklower 	int new, old = tpcb->tp_dt_ticks;
143*51204Ssklower 	int delta, elapsed = tick - tpcb->tp_rttemit;
14436413Ssklower 
145*51204Ssklower 	if (tpcb->tp_rtt != 0) {
146*51204Ssklower 		/*
147*51204Ssklower 		 * rtt is the smoothed round trip time in machine clock ticks (hz).
148*51204Ssklower 		 * it is stored as a fixed point number, unscaled (unlike the tcp
149*51204Ssklower 		 * srtt.  The rationale here is that it is only significant to the
150*51204Ssklower 		 * nearest unit of slowtimo, which is at least 8 machine clock ticks
151*51204Ssklower 		 * so there is no need to scale.  The smoothing is done according
152*51204Ssklower 		 * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8).
153*51204Ssklower 		 */
154*51204Ssklower 		delta = elapsed - tpcb->tp_rtt;
155*51204Ssklower 		if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0)
156*51204Ssklower 			tpcb->tp_rtt = 1;
157*51204Ssklower 		/*
158*51204Ssklower 		 * rtv is a smoothed accumulated mean difference, unscaled
159*51204Ssklower 		 * for reasons expressed above.
160*51204Ssklower 		 * It is smoothed with an alpha of .75, and the round trip timer
161*51204Ssklower 		 * will be set to rtt + 4*rtv, also as TCP does.
162*51204Ssklower 		 */
163*51204Ssklower 		if (delta < 0)
164*51204Ssklower 			delta = -delta;
165*51204Ssklower 		if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0)
166*51204Ssklower 			tpcb->tp_rtv = 1;
167*51204Ssklower 	} else {
168*51204Ssklower 		/*
169*51204Ssklower 		 * No rtt measurement yet - use the unsmoothed rtt.
170*51204Ssklower 		 * Set the variance to half the rtt (so our first
171*51204Ssklower 		 * retransmit happens at 3*rtt)
172*51204Ssklower 		 */
173*51204Ssklower 		tpcb->tp_rtt = elapsed;
174*51204Ssklower 		tpcb->tp_rtv = elapsed >> 1;
175*51204Ssklower 	}
176*51204Ssklower 	tpcb->tp_rttemit = 0;
177*51204Ssklower 	tpcb->tp_rxtshift = 0;
178*51204Ssklower 	/*
179*51204Ssklower 	 * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar.
180*51204Ssklower 	 * Because of the way we do the smoothing, srtt and rttvar
181*51204Ssklower 	 * will each average +1/2 tick of bias.  When we compute
182*51204Ssklower 	 * the retransmit timer, we want 1/2 tick of rounding and
183*51204Ssklower 	 * 1 extra tick because of +-1/2 tick uncertainty in the
184*51204Ssklower 	 * firing of the timer.  The bias will give us exactly the
185*51204Ssklower 	 * 1.5 tick we need.  But, because the bias is
186*51204Ssklower 	 * statistical, we have to test that we don't drop below
187*51204Ssklower 	 * the minimum feasible timer (which is 2 ticks)."
188*51204Ssklower 	 */
189*51204Ssklower 	new = (((tpcb->tp_rtt + (tpcb->tp_rtv << 2)) * PR_SLOWHZ) + hz) / hz;
190*51204Ssklower 	new = MAX(new + 1, tpcb->tp_peer_acktime);
191*51204Ssklower 	new = MAX(new, 2);
192*51204Ssklower 	IFTRACE(D_RTT)
193*51204Ssklower 		tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks",
194*51204Ssklower 			old, rtv, rtt, new);
195*51204Ssklower 	ENDTRACE
196*51204Ssklower 	tpcb->tp_rxtcur = tpcb->tp_dt_ticks = new;
19736413Ssklower }
19836413Ssklower 
19936413Ssklower /*
20036413Ssklower  * CALLED FROM:
20136413Ssklower  *  tp.trans when an AK arrives
20236413Ssklower  * FUNCTION and ARGUMENTS:
20336413Ssklower  * 	Given (cdt), the credit from the AK tpdu, and
20436413Ssklower  *	(seq), the sequence number from the AK tpdu,
20536413Ssklower  *  tp_goodack() determines if the AK acknowledges something in the send
20636413Ssklower  * 	window, and if so, drops the appropriate packets from the retransmission
20736413Ssklower  *  list, computes the round trip time, and updates the retransmission timer
20836413Ssklower  *  based on the new smoothed round trip time.
20936413Ssklower  * RETURN VALUE:
21036413Ssklower  * 	Returns 1 if
21136413Ssklower  * 	EITHER it actually acked something heretofore unacknowledged
21236413Ssklower  * 	OR no news but the credit should be processed.
21336413Ssklower  * 	If something heretofore unacked was acked with this sequence number,
21436413Ssklower  * 	the appropriate tpdus are dropped from the retransmission control list,
21536413Ssklower  * 	by calling tp_sbdrop().
21636413Ssklower  * 	No need to see the tpdu itself.
21736413Ssklower  */
21836413Ssklower int
21936413Ssklower tp_goodack(tpcb, cdt, seq, subseq)
22036413Ssklower 	register struct tp_pcb	*tpcb;
22136413Ssklower 	u_int					cdt;
222*51204Ssklower 	register SeqNum			seq;
223*51204Ssklower 	u_int					subseq;
22436413Ssklower {
225*51204Ssklower 	int 	old_fcredit;
22636413Ssklower 	int 	bang = 0; 	/* bang --> ack for something heretofore unacked */
227*51204Ssklower 	u_int	bytes_acked;
22836413Ssklower 
22936413Ssklower 	IFDEBUG(D_ACKRECV)
230*51204Ssklower 		printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n",
231*51204Ssklower 			tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt);
23236413Ssklower 	ENDDEBUG
23336413Ssklower 	IFTRACE(D_ACKRECV)
23436413Ssklower 		tptraceTPCB(TPPTgotack,
235*51204Ssklower 			seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq);
23636413Ssklower 	ENDTRACE
23736413Ssklower 
23836413Ssklower 	IFPERF(tpcb)
23937469Ssklower 		tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0);
24036413Ssklower 	ENDPERF
24136413Ssklower 
242*51204Ssklower 	if (seq == tpcb->tp_snduna) {
243*51204Ssklower 		if (subseq < tpcb->tp_r_subseq ||
244*51204Ssklower 			(subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) {
245*51204Ssklower 		discard_the_ack:
246*51204Ssklower 			IFDEBUG(D_ACKRECV)
247*51204Ssklower 				printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n",
248*51204Ssklower 					tpcb, subseq, tpcb->tp_r_subseq);
249*51204Ssklower 			ENDDEBUG
250*51204Ssklower 			goto done;
25136413Ssklower 		}
252*51204Ssklower 		if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) {
253*51204Ssklower 			tpcb->tp_r_subseq = subseq;
254*51204Ssklower 			if (tpcb->tp_timer[TM_data_retrans] == 0)
255*51204Ssklower 				tpcb->tp_dupacks = 0;
256*51204Ssklower 			else if (++tpcb->tp_dupacks == tprexmtthresh) {
257*51204Ssklower 				/* partner went out of his way to signal with different
258*51204Ssklower 				   subsequences that he has the same lack of an expected
259*51204Ssklower 				   packet.  This may be an early indiciation of a loss */
26036413Ssklower 
261*51204Ssklower 				SeqNum onxt = tpcb->tp_sndnxt;
262*51204Ssklower 				struct mbuf *onxt_m = tpcb->tp_sndnxt_m;
263*51204Ssklower 				u_int win = min(tpcb->tp_fcredit,
264*51204Ssklower 							tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2;
265*51204Ssklower 				if (win < 2)
266*51204Ssklower 					win = 2;
267*51204Ssklower 				tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
268*51204Ssklower 				tpcb->tp_timer[TM_data_retrans] = 0;
269*51204Ssklower 				tpcb->tp_rttemit = 0;
270*51204Ssklower 				tpcb->tp_sndnxt = tpcb->tp_snduna;
271*51204Ssklower 				tpcb->tp_sndnxt_m = 0;
272*51204Ssklower 				tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
273*51204Ssklower 				tp_send(tpcb);
274*51204Ssklower 				tpcb->tp_cong_win = tpcb->tp_ssthresh +
275*51204Ssklower 					tpcb->tp_dupacks * tpcb->tp_l_tpdusize;
276*51204Ssklower 				if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) {
277*51204Ssklower 					tpcb->tp_sndnxt = onxt;
278*51204Ssklower 					tpcb->tp_sndnxt_m = onxt_m;
279*51204Ssklower 				}
28036413Ssklower 
281*51204Ssklower 			} else if (tpcb->tp_dupacks > tprexmtthresh) {
282*51204Ssklower 				tpcb->tp_cong_win += tpcb->tp_l_tpdusize;
28351138Ssklower 			}
284*51204Ssklower 			goto done;
285*51204Ssklower 		}
286*51204Ssklower 	} else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna))
287*51204Ssklower 		goto discard_the_ack;
288*51204Ssklower 	/*
289*51204Ssklower 	 * If the congestion window was inflated to account
290*51204Ssklower 	 * for the other side's cached packets, retract it.
291*51204Ssklower 	 */
292*51204Ssklower 	if (tpcb->tp_dupacks > tprexmtthresh &&
293*51204Ssklower 		tpcb->tp_cong_win > tpcb->tp_ssthresh)
294*51204Ssklower 			tpcb->tp_cong_win = tpcb->tp_ssthresh;
295*51204Ssklower 	tpcb->tp_r_subseq = subseq;
296*51204Ssklower 	old_fcredit = tpcb->tp_fcredit;
297*51204Ssklower 	tpcb->tp_fcredit = cdt;
298*51204Ssklower 	if (cdt > tpcb->tp_maxfcredit)
299*51204Ssklower 		tpcb->tp_maxfcredit = cdt;
300*51204Ssklower 	tpcb->tp_dupacks = 0;
30136413Ssklower 
302*51204Ssklower 	if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) {
30336413Ssklower 
304*51204Ssklower 		tpsbcheck(tpcb, 0);
305*51204Ssklower 		bytes_acked = tp_sbdrop(tpcb, seq);
306*51204Ssklower 		tpsbcheck(tpcb, 1);
307*51204Ssklower 		/*
308*51204Ssklower 		 * If transmit timer is running and timed sequence
309*51204Ssklower 		 * number was acked, update smoothed round trip time.
310*51204Ssklower 		 * Since we now have an rtt measurement, cancel the
311*51204Ssklower 		 * timer backoff (cf., Phil Karn's retransmit alg.).
312*51204Ssklower 		 * Recompute the initial retransmit timer.
313*51204Ssklower 		 */
314*51204Ssklower 		if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq))
315*51204Ssklower 			tp_rtt_rtv(tpcb);
316*51204Ssklower 		/*
317*51204Ssklower 		 * If all outstanding data is acked, stop retransmit timer.
318*51204Ssklower 		 * If there is more data to be acked, restart retransmit
319*51204Ssklower 		 * timer, using current (possibly backed-off) value.
320*51204Ssklower 		 * OSI combines the keepalive and persistance functions.
321*51204Ssklower 		 * So, there is no persistance timer per se, to restart.
322*51204Ssklower 		 */
323*51204Ssklower 		tpcb->tp_timer[TM_data_retrans] =
324*51204Ssklower 			(seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur;
325*51204Ssklower 		/*
326*51204Ssklower 		 * When new data is acked, open the congestion window.
327*51204Ssklower 		 * If the window gives us less than ssthresh packets
328*51204Ssklower 		 * in flight, open exponentially (maxseg per packet).
329*51204Ssklower 		 * Otherwise open linearly: maxseg per window
330*51204Ssklower 		 * (maxseg^2 / cwnd per packet), plus a constant
331*51204Ssklower 		 * fraction of a packet (maxseg/8) to help larger windows
332*51204Ssklower 		 * open quickly enough.
333*51204Ssklower 		 */
334*51204Ssklower 		{
335*51204Ssklower 			u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize;
33636413Ssklower 
337*51204Ssklower 			incr = min(incr, bytes_acked);
338*51204Ssklower 			if (cw > tpcb->tp_ssthresh)
339*51204Ssklower 				incr = incr * incr / cw + incr / 8;
340*51204Ssklower 			tpcb->tp_cong_win =
341*51204Ssklower 				min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat);
34236413Ssklower 		}
34336413Ssklower 		tpcb->tp_snduna = seq;
344*51204Ssklower 		if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) {
345*51204Ssklower 				tpcb->tp_sndnxt = seq;
346*51204Ssklower 				tpcb->tp_sndnxt_m = 0;
347*51204Ssklower 		}
34836413Ssklower 		bang++;
34936413Ssklower 	}
35036413Ssklower 
35136413Ssklower 	if( cdt != 0 && old_fcredit == 0 ) {
35236413Ssklower 		tpcb->tp_sendfcc = 1;
35336413Ssklower 	}
35436413Ssklower 	if( cdt == 0 && old_fcredit != 0 ) {
35536413Ssklower 		IncStat(ts_zfcdt);
35636413Ssklower 	}
35736413Ssklower 	tpcb->tp_fcredit = cdt;
358*51204Ssklower 	bang |= (old_fcredit < cdt);
35936413Ssklower 
360*51204Ssklower done:
36136413Ssklower 	IFDEBUG(D_ACKRECV)
362*51204Ssklower 		printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n",
363*51204Ssklower 			bang, cdt, old_fcredit, tpcb->tp_cong_win);
36436413Ssklower 	ENDDEBUG
365*51204Ssklower 	/* if (bang) XXXXX Very bad to remove this test, but somethings broken */
366*51204Ssklower 		tp_send(tpcb);
367*51204Ssklower 	return (bang);
36836413Ssklower }
36936413Ssklower 
37036413Ssklower /*
37136413Ssklower  * CALLED FROM:
37236413Ssklower  *  tp_goodack()
37336413Ssklower  * FUNCTION and ARGUMENTS:
37450901Ssklower  *  drops everything up TO but not INCLUDING seq # (seq)
37536413Ssklower  *  from the retransmission queue.
37636413Ssklower  */
37736413Ssklower tp_sbdrop(tpcb, seq)
37850901Ssklower 	register struct 	tp_pcb 			*tpcb;
37936413Ssklower 	SeqNum					seq;
38036413Ssklower {
38150901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
382*51204Ssklower 	register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna);
383*51204Ssklower 	int	oldcc = sb->sb_cc, oldi = i;
38436413Ssklower 
385*51204Ssklower 	if (i >= tpcb->tp_seqhalf)
386*51204Ssklower 		printf("tp_spdropping too much -- should panic");
387*51204Ssklower 	while (i-- > 0)
388*51204Ssklower 		sbdroprecord(sb);
38936413Ssklower 	IFDEBUG(D_ACKRECV)
390*51204Ssklower 		printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n",
391*51204Ssklower 			oldi, oldcc - sb->sb_cc, tpcb, seq);
39236413Ssklower 	ENDDEBUG
393*51204Ssklower 	if (sb->sb_flags & SB_NOTIFY)
394*51204Ssklower 		sowwakeup(tpcb->tp_sock);
39551138Ssklower 	return (oldcc - sb->sb_cc);
39636413Ssklower }
39736413Ssklower 
39836413Ssklower /*
39936413Ssklower  * CALLED FROM:
40036413Ssklower  * 	tp.trans on user send request, arrival of AK and arrival of XAK
40136413Ssklower  * FUNCTION and ARGUMENTS:
402*51204Ssklower  * 	Emits tpdus starting at sequence number (tpcb->tp_sndnxt).
40336413Ssklower  * 	Emits until a) runs out of data, or  b) runs into an XPD mark, or
404*51204Ssklower  * 			c) it hits seq number (highseq) limited by cong or credit.
40536413Ssklower  *
40636413Ssklower  * 	If you want XPD to buffer > 1 du per socket buffer, you can
40736413Ssklower  * 	modifiy this to issue XPD tpdus also, but then it'll have
40836413Ssklower  * 	to take some argument(s) to distinguish between the type of DU to
40950901Ssklower  * 	hand tp_emit.
41036413Ssklower  *
41136413Ssklower  * 	When something is sent for the first time, its time-of-send
412*51204Ssklower  * 	is stashed (in system clock ticks rather than pf_slowtimo ticks).
413*51204Ssklower  *  When the ack arrives, the smoothed round-trip time is figured
414*51204Ssklower  *  using this value.
41536413Ssklower  */
416*51204Ssklower void
41736413Ssklower tp_send(tpcb)
41836413Ssklower 	register struct tp_pcb	*tpcb;
41936413Ssklower {
42036413Ssklower 	register int			len;
421*51204Ssklower 	register struct mbuf	*m;
422*51204Ssklower 	struct mbuf				*mb = 0;
42336413Ssklower 	struct 	sockbuf			*sb = &tpcb->tp_sock->so_snd;
424*51204Ssklower 	unsigned int			eotsdu = 0;
425*51204Ssklower 	SeqNum					highseq, checkseq;
426*51204Ssklower 	int						idle, idleticks, off, cong_win;
42736413Ssklower #ifdef TP_PERF_MEAS
42851138Ssklower 	int			 			send_start_time = tick;
429*51204Ssklower 	SeqNum					oldnxt = tpcb->tp_sndnxt;
43036413Ssklower #endif TP_PERF_MEAS
43136413Ssklower 
432*51204Ssklower 	idle = (tpcb->tp_snduna == tpcb->tp_sndnew);
433*51204Ssklower 	if (idle) {
434*51204Ssklower 		idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact];
435*51204Ssklower 		if (idleticks > tpcb->tp_dt_ticks)
436*51204Ssklower 			/*
437*51204Ssklower 			 * We have been idle for "a while" and no acks are
438*51204Ssklower 			 * expected to clock out any data we send --
439*51204Ssklower 			 * slow start to get ack "clock" running again.
440*51204Ssklower 			 */
441*51204Ssklower 			tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
442*51204Ssklower 	}
44336413Ssklower 
444*51204Ssklower 	cong_win = tpcb->tp_cong_win;
445*51204Ssklower 	highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna);
446*51204Ssklower 	if (tpcb->tp_Xsnd.sb_mb)
447*51204Ssklower 		highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew);
44836413Ssklower 
44936413Ssklower 	IFDEBUG(D_DATA)
450*51204Ssklower 		printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n",
451*51204Ssklower 				tpcb, tpcb->tp_sndnxt, cong_win, highseq);
45236413Ssklower 	ENDDEBUG
45336413Ssklower 	IFTRACE(D_DATA)
454*51204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send sndnew snduna",
455*51204Ssklower 			tpcb->tp_sndnew,  tpcb->tp_snduna, 0, 0);
456*51204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin",
457*51204Ssklower 			tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win);
45836413Ssklower 	ENDTRACE
45936413Ssklower 	IFTRACE(D_DATA)
460*51204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin",
461*51204Ssklower 			tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win);
46236413Ssklower 	ENDTRACE
46336413Ssklower 
464*51204Ssklower 	if (tpcb->tp_sndnxt_m)
465*51204Ssklower 		m = tpcb->tp_sndnxt_m;
466*51204Ssklower 	else {
467*51204Ssklower 		off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna);
468*51204Ssklower 		for (m = sb->sb_mb; m && off > 0; m = m->m_next)
469*51204Ssklower 			off--;
470*51204Ssklower 	}
471*51204Ssklower send:
472*51204Ssklower 	/*
473*51204Ssklower 	 * Avoid silly window syndrome here . . . figure out how!
474*51204Ssklower 	 */
475*51204Ssklower 	checkseq = tpcb->tp_sndnum;
476*51204Ssklower 	if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq))
477*51204Ssklower 		checkseq = highseq;
47836413Ssklower 
479*51204Ssklower 	while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) {
48036413Ssklower 
481*51204Ssklower 		eotsdu = (m->m_flags & M_EOR) != 0;
482*51204Ssklower 		len = m->m_pkthdr.len;
483*51204Ssklower 		if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 &&
484*51204Ssklower 			len < (tpcb->tp_l_tpdusize / 2))
485*51204Ssklower 				break;  /* Nagle . . . . . */
486*51204Ssklower 		cong_win -= len;
48736413Ssklower 		/* make a copy - mb goes into the retransmission list
48836413Ssklower 		 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
48936413Ssklower 		 */
490*51204Ssklower 		mb = m;
49150901Ssklower 		m = m_copy(mb, 0, M_COPYALL);
49250901Ssklower 		if (m == MNULL)
493*51204Ssklower 				break;
494*51204Ssklower 		IFTRACE(D_STASH)
49536413Ssklower 			tptraceTPCB( TPPTmisc,
496*51204Ssklower 				"tp_send mcopy nxt high eotsdu len",
497*51204Ssklower 				tpcb->tp_sndnxt, highseq, eotsdu, len);
49836413Ssklower 		ENDTRACE
499*51204Ssklower 
500*51204Ssklower 		IFDEBUG(D_DATA)
501*51204Ssklower 			printf("tp_sending tpcb 0x%x nxt 0x%x\n",
502*51204Ssklower 				tpcb, tpcb->tp_sndnxt);
503*51204Ssklower 		ENDDEBUG
504*51204Ssklower 		/* when headers are precomputed, may need to fill
50550901Ssklower 			   in checksum here */
50650901Ssklower 		if (tpcb->tp_sock->so_error =
507*51204Ssklower 			tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) {
50836413Ssklower 			/* error */
509*51204Ssklower 			break;
51036413Ssklower 		}
511*51204Ssklower 		m = mb->m_nextpkt;
512*51204Ssklower 		tpcb->tp_sndnxt_m = m;
513*51204Ssklower 		if (tpcb->tp_sndnxt == tpcb->tp_sndnew) {
514*51204Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnew);
515*51204Ssklower 			/*
516*51204Ssklower 			 * Time this transmission if not a retransmission and
517*51204Ssklower 			 * not currently timing anything.
518*51204Ssklower 			 */
519*51204Ssklower 			if (tpcb->tp_rttemit == 0) {
520*51204Ssklower 				tpcb->tp_rttemit = tick;
521*51204Ssklower 				tpcb->tp_rttseq = tpcb->tp_sndnxt;
522*51204Ssklower 			}
523*51204Ssklower 			tpcb->tp_sndnxt = tpcb->tp_sndnew;
524*51204Ssklower 		} else
525*51204Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnxt);
526*51204Ssklower 		/*
527*51204Ssklower 		 * Set retransmit timer if not currently set.
528*51204Ssklower 		 * Initial value for retransmit timer is smoothed
529*51204Ssklower 		 * round-trip time + 2 * round-trip time variance.
530*51204Ssklower 		 * Initialize shift counter which is used for backoff
531*51204Ssklower 		 * of retransmit time.
532*51204Ssklower 		 */
533*51204Ssklower 		if (tpcb->tp_timer[TM_data_retrans] == 0) {
534*51204Ssklower 			tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks;
535*51204Ssklower 			tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks;
536*51204Ssklower 			tpcb->tp_rxtshift = 0;
53751138Ssklower 		}
53836413Ssklower 	}
539*51204Ssklower 	if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum))
540*51204Ssklower 		tpcb->tp_oktonagle = 0;
54150236Ssklower #ifdef TP_PERF_MEAS
54236413Ssklower 	IFPERF(tpcb)
54336413Ssklower 		{
54436413Ssklower 			register int npkts;
54551138Ssklower 			int	 elapsed = tick - send_start_time, *t;
54651138Ssklower 			struct timeval now;
54736413Ssklower 
548*51204Ssklower 			npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt);
54936413Ssklower 
550*51204Ssklower 			if (npkts > 0)
55136413Ssklower 				tpcb->tp_Nwindow++;
55236413Ssklower 
55336413Ssklower 			if (npkts > TP_PM_MAX)
55436413Ssklower 				npkts = TP_PM_MAX;
55536413Ssklower 
55636413Ssklower 			t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
55751138Ssklower 			*t += (t - elapsed) >> TP_RTT_ALPHA;
55836413Ssklower 
559*51204Ssklower 			if (mb == 0) {
56036413Ssklower 				IncPStat(tpcb, tps_win_lim_by_data[npkts] );
56136413Ssklower 			} else {
56236413Ssklower 				IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
56336413Ssklower 				/* not true with congestion-window being used */
56436413Ssklower 			}
56551138Ssklower 			now.tv_sec = elapsed / hz;
56651138Ssklower 			now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz;
56736413Ssklower 			tpmeas( tpcb->tp_lref,
568*51204Ssklower 					TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts);
56936413Ssklower 		}
57036413Ssklower 	ENDPERF
57150236Ssklower #endif TP_PERF_MEAS
57236413Ssklower 
57336413Ssklower 
57436413Ssklower 	IFTRACE(D_DATA)
57536413Ssklower 		tptraceTPCB( TPPTmisc,
576*51204Ssklower 			"tp_send at end: new nxt eotsdu error",
577*51204Ssklower 			tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error);
57836413Ssklower 
57936413Ssklower 	ENDTRACE
58036413Ssklower }
58136413Ssklower 
58250901Ssklower int TPNagleok;
58350901Ssklower int TPNagled;
58450901Ssklower 
58550901Ssklower tp_packetize(tpcb, m, eotsdu)
58650901Ssklower register struct tp_pcb *tpcb;
58750901Ssklower register struct mbuf *m;
58850901Ssklower int eotsdu;
58950901Ssklower {
59050901Ssklower 	register struct mbuf *n;
59150901Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_snd;
59250901Ssklower 	int	maxsize = tpcb->tp_l_tpdusize
59350901Ssklower 			- tp_headersize(DT_TPDU_type, tpcb)
59450901Ssklower 			- (tpcb->tp_use_checksum?4:0) ;
59550901Ssklower 	int totlen = m->m_pkthdr.len;
59650901Ssklower 	struct mbuf *m_split();
59750901Ssklower 	/*
59850901Ssklower 	 * Pre-packetize the data in the sockbuf
59950901Ssklower 	 * according to negotiated mtu.  Do it here
60050901Ssklower 	 * where we can safely wait for mbufs.
60150901Ssklower 	 *
60250901Ssklower 	 * This presumes knowledge of sockbuf conventions.
60350901Ssklower 	 * TODO: allocate space for header and fill it in (once!).
60450901Ssklower 	 */
605*51204Ssklower 	IFDEBUG(D_DATA)
606*51204Ssklower 		printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n",
607*51204Ssklower 			maxsize, totlen, eotsdu, tpcb->tp_sndnum);
60850901Ssklower 	ENDTRACE
60950901Ssklower 	if (tpcb->tp_oktonagle) {
61050901Ssklower 		if ((n = sb->sb_mb) == 0)
61150901Ssklower 			panic("tp_packetize");
61250901Ssklower 		while (n->m_act)
61350901Ssklower 			n = n->m_act;
61450901Ssklower 		if (n->m_flags & M_EOR)
61550901Ssklower 			panic("tp_packetize 2");
61650901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
61750901Ssklower 		if (totlen + n->m_pkthdr.len < maxsize) {
61850901Ssklower 			/* There is an unsent packet with space, combine data */
61950901Ssklower 			struct mbuf *old_n = n;
62050901Ssklower 			tpsbcheck(tpcb,3);
62150901Ssklower 			n->m_pkthdr.len += totlen;
62250901Ssklower 			while (n->m_next)
62350901Ssklower 				n = n->m_next;
62450901Ssklower 			sbcompress(sb, m, n);
62550901Ssklower 			tpsbcheck(tpcb,4);
62650901Ssklower 			n = old_n;
62750901Ssklower 			TPNagled++;
62850901Ssklower 			goto out;
62950901Ssklower 		}
63050901Ssklower 	}
63150901Ssklower 	while (m) {
63250901Ssklower 		n = m;
63350901Ssklower 		if (totlen > maxsize) {
63450901Ssklower 			if ((m = m_split(n, maxsize, M_WAIT)) == 0)
63550901Ssklower 				panic("tp_packetize");
63650901Ssklower 		} else
63750901Ssklower 			m = 0;
63850901Ssklower 		totlen -= maxsize;
63950901Ssklower 		tpsbcheck(tpcb, 5);
64050901Ssklower 		sbappendrecord(sb, n);
64150901Ssklower 		tpsbcheck(tpcb, 6);
64250901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
64350901Ssklower 	}
64450901Ssklower out:
64550901Ssklower 	if (eotsdu) {
64650901Ssklower 		n->m_flags |= M_EOR;  /* XXX belongs at end */
64750901Ssklower 		tpcb->tp_oktonagle = 0;
64850901Ssklower 	} else {
64950901Ssklower 		SEQ_DEC(tpcb, tpcb->tp_sndnum);
65050901Ssklower 		tpcb->tp_oktonagle = 1;
65150901Ssklower 		TPNagleok++;
65250901Ssklower 	}
653*51204Ssklower 	IFDEBUG(D_DATA)
654*51204Ssklower 		printf("SEND out: oktonagle %d sndnum 0x%x\n",
655*51204Ssklower 			tpcb->tp_oktonagle, tpcb->tp_sndnum);
656*51204Ssklower 	ENDTRACE
65750901Ssklower 	return 0;
65850901Ssklower }
65950901Ssklower 
66050901Ssklower 
66136413Ssklower /*
66236413Ssklower  * NAME: tp_stash()
66336413Ssklower  * CALLED FROM:
66436413Ssklower  *	tp.trans on arrival of a DT tpdu
66536413Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
66636413Ssklower  * 	Returns 1 if
66736413Ssklower  *		a) something new arrived and it's got eotsdu_reached bit on,
66836413Ssklower  * 		b) this arrival was caused other out-of-sequence things to be
66936413Ssklower  *    	accepted, or
67036413Ssklower  * 		c) this arrival is the highest seq # for which we last gave credit
67136413Ssklower  *   	(sender just sent a whole window)
67236413Ssklower  *  In other words, returns 1 if tp should send an ack immediately, 0 if
67336413Ssklower  *  the ack can wait a while.
67436413Ssklower  *
67536413Ssklower  * Note: this implementation no longer renegs on credit, (except
67636413Ssklower  * when debugging option D_RENEG is on, for the purpose of testing
67736413Ssklower  * ack subsequencing), so we don't  need to check for incoming tpdus
67836413Ssklower  * being in a reneged portion of the window.
67936413Ssklower  */
68036413Ssklower 
681*51204Ssklower tp_stash(tpcb, e)
68236413Ssklower 	register struct tp_pcb		*tpcb;
68336413Ssklower 	register struct tp_event	*e;
68436413Ssklower {
68536413Ssklower 	register int		ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
68636413Ssklower 									/* 0--> delay acks until full window */
68736413Ssklower 									/* 1--> ack each tpdu */
68836413Ssklower #ifndef lint
68936413Ssklower #define E e->ATTR(DT_TPDU)
69036413Ssklower #else lint
69136413Ssklower #define E e->ev_union.EV_DT_TPDU
69236413Ssklower #endif lint
69336413Ssklower 
69436413Ssklower 	if ( E.e_eot ) {
69536413Ssklower 		register struct mbuf *n = E.e_data;
69637469Ssklower 		n->m_flags |= M_EOR;
69738841Ssklower 		n->m_act = 0;
69837469Ssklower 	}
69936413Ssklower 		IFDEBUG(D_STASH)
70036413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
70136413Ssklower 				"stash: so_rcv before appending");
70236413Ssklower 			dump_mbuf(E.e_data,
70336413Ssklower 				"stash: e_data before appending");
70436413Ssklower 		ENDDEBUG
70536413Ssklower 
70636413Ssklower 	IFPERF(tpcb)
70736413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
70836413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
70937469Ssklower 			E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
71036413Ssklower 	ENDPERF
71136413Ssklower 
71251024Ssklower 	if (E.e_seq == tpcb->tp_rcvnxt) {
71336413Ssklower 
71436413Ssklower 		IFDEBUG(D_STASH)
71536413Ssklower 			printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
71636413Ssklower 			E.e_seq, E.e_datalen, E.e_eot);
71736413Ssklower 		ENDDEBUG
71836413Ssklower 
71936413Ssklower 		IFTRACE(D_STASH)
72036413Ssklower 			tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
72136413Ssklower 			E.e_seq, E.e_datalen, E.e_eot, 0);
72236413Ssklower 		ENDTRACE
72336413Ssklower 
72451024Ssklower 		SET_DELACK(tpcb);
72551024Ssklower 
72637469Ssklower 		sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
72737469Ssklower 
72836413Ssklower 		SEQ_INC( tpcb, tpcb->tp_rcvnxt );
72936413Ssklower 		/*
73050901Ssklower 		 * move chains from the reassembly queue to the socket buffer
73136413Ssklower 		 */
73250901Ssklower 		if (tpcb->tp_rsycnt) {
73350901Ssklower 			register struct mbuf **mp;
73450901Ssklower 			struct mbuf **mplim;
73536413Ssklower 
73650901Ssklower 			mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit);
73750901Ssklower 			mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit;
73836413Ssklower 
73950901Ssklower 			while (tpcb->tp_rsycnt && *mp) {
74050901Ssklower 				sbappend(&tpcb->tp_sock->so_rcv, *mp);
74150901Ssklower 				tpcb->tp_rsycnt--;
74250901Ssklower 				*mp = 0;
74350901Ssklower 				SEQ_INC(tpcb, tpcb->tp_rcvnxt);
74436413Ssklower 				ack_reason |= ACK_REORDER;
74550901Ssklower 				if (++mp == mplim)
74650901Ssklower 					mp = tpcb->tp_rsyq;
74736413Ssklower 			}
74836413Ssklower 		}
74936413Ssklower 		IFDEBUG(D_STASH)
75036413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
75136413Ssklower 				"stash: so_rcv after appending");
75236413Ssklower 		ENDDEBUG
75336413Ssklower 
75436413Ssklower 	} else {
75550901Ssklower 		register struct mbuf **mp;
75650901Ssklower 		SeqNum uwe;
75736413Ssklower 
75836413Ssklower 		IFTRACE(D_STASH)
75936413Ssklower 			tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
76036413Ssklower 			E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
76136413Ssklower 		ENDTRACE
76236413Ssklower 
76350975Ssklower 		if (tpcb->tp_rsyq == 0)
76450975Ssklower 			tp_rsyset(tpcb);
76550901Ssklower 		uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit);
76650901Ssklower 		if (tpcb->tp_rsyq == 0 ||
76750901Ssklower 						!IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) {
76836413Ssklower 			ack_reason = ACK_DONT;
76950901Ssklower 			m_freem(E.e_data);
77050901Ssklower 		} else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) {
77136413Ssklower 			IFDEBUG(D_STASH)
77236413Ssklower 				printf("tp_stash - drop & ack\n");
77336413Ssklower 			ENDDEBUG
77436413Ssklower 
77536413Ssklower 			/* retransmission - drop it and force an ack */
77636413Ssklower 			IncStat(ts_dt_dup);
77736413Ssklower 			IFPERF(tpcb)
77836413Ssklower 				IncPStat(tpcb, tps_n_ack_cuz_dup);
77936413Ssklower 			ENDPERF
78036413Ssklower 
78150901Ssklower 			m_freem(E.e_data);
78236413Ssklower 			ack_reason |= ACK_DUP;
78350901Ssklower 		} else {
78450901Ssklower 			*mp = E.e_data;
78550901Ssklower 			tpcb->tp_rsycnt++;
78650901Ssklower 			ack_reason = ACK_DONT;
78736413Ssklower 		}
78836413Ssklower 	}
78951024Ssklower 	/* there were some comments of historical interest here. */
79036413Ssklower 	{
79136413Ssklower 		LOCAL_CREDIT(tpcb);
79236413Ssklower 
79336413Ssklower 		if ( E.e_seq ==  tpcb->tp_sent_uwe )
79436413Ssklower 			ack_reason |= ACK_STRAT_FULLWIN;
79536413Ssklower 
79636413Ssklower 		IFTRACE(D_STASH)
79736413Ssklower 			tptraceTPCB(TPPTmisc,
79836413Ssklower 				"end of stash, eot, ack_reason, sent_uwe ",
79936413Ssklower 				E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
80036413Ssklower 		ENDTRACE
80136413Ssklower 
80236413Ssklower 		if ( ack_reason == ACK_DONT ) {
80336413Ssklower 			IncStat( ts_ackreason[ACK_DONT] );
80436413Ssklower 			return 0;
80536413Ssklower 		} else {
80636413Ssklower 			IFPERF(tpcb)
80736413Ssklower 				if(ack_reason & ACK_STRAT_EACH) {
80836413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_strat);
80936413Ssklower 				} else if(ack_reason & ACK_STRAT_FULLWIN) {
81036413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_fullwin);
81136413Ssklower 				} else if(ack_reason & ACK_REORDER) {
81236413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_reorder);
81336413Ssklower 				}
81436413Ssklower 				tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
81536413Ssklower 							SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
81636413Ssklower 			ENDPERF
81736413Ssklower 			{
81836413Ssklower 				register int i;
81936413Ssklower 
82036413Ssklower 				/* keep track of all reasons that apply */
82136413Ssklower 				for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
82236413Ssklower 					if( ack_reason & (1<<i) )
82336413Ssklower 						IncStat( ts_ackreason[i] );
82436413Ssklower 				}
82536413Ssklower 			}
82636413Ssklower 			return 1;
82736413Ssklower 		}
82836413Ssklower 	}
82936413Ssklower }
83050901Ssklower 
83150901Ssklower /*
83250901Ssklower  * tp_rsyflush - drop all the packets on the reassembly queue.
83350901Ssklower  * Do this when closing the socket, or when somebody has changed
83450901Ssklower  * the space avaible in the receive socket (XXX).
83550901Ssklower  */
83650901Ssklower tp_rsyflush(tpcb)
83750901Ssklower register struct tp_pcb *tpcb;
83850901Ssklower {
83950901Ssklower 	register struct mbuf *m, **mp;
84050901Ssklower 	if (tpcb->tp_rsycnt) {
84150901Ssklower 		for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit;
84250901Ssklower 									 --mp >= tpcb->tp_rsyq; )
84350901Ssklower 			if (*mp) {
84450901Ssklower 				tpcb->tp_rsycnt--;
84550901Ssklower 				m_freem(*mp);
84650901Ssklower 			}
84750901Ssklower 		if (tpcb->tp_rsycnt)
84850901Ssklower 			panic("tp_rsyflush");
84950901Ssklower 	}
85050901Ssklower 	free((caddr_t)tpcb->tp_rsyq, M_PCB);
85150901Ssklower 	tpcb->tp_rsyq = 0;
85250901Ssklower }
85350901Ssklower 
85450901Ssklower tp_rsyset(tpcb)
85550901Ssklower register struct tp_pcb *tpcb;
85650901Ssklower {
85750901Ssklower 	register struct socket *so = tpcb->tp_sock;
85850901Ssklower 	int maxcredit  = tpcb->tp_xtd_format ? 0xffff : 0xf;
85950975Ssklower 	int old_credit = tpcb->tp_maxlcredit;
86050975Ssklower 	caddr_t	rsyq;
86150901Ssklower 
86250901Ssklower 	tpcb->tp_maxlcredit = maxcredit = min(maxcredit,
86350901Ssklower 		  (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize);
86450901Ssklower 
86550975Ssklower 	if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0)
86650975Ssklower 		return;
86750901Ssklower 	maxcredit *= sizeof(struct mbuf *);
86850901Ssklower 	if (tpcb->tp_rsyq)
86950901Ssklower 		tp_rsyflush(tpcb);
87050901Ssklower 	if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT))
87150901Ssklower 		bzero(rsyq, maxcredit);
87250901Ssklower 	tpcb->tp_rsyq = (struct mbuf **)rsyq;
87350901Ssklower }
87450901Ssklower 
87550901Ssklower tpsbcheck(tpcb, i)
87650901Ssklower struct tp_pcb *tpcb;
87750901Ssklower {
87850901Ssklower 	register struct mbuf *n, *m;
87950901Ssklower 	register int len = 0, mbcnt = 0, pktlen;
88050901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
88150901Ssklower 
88250901Ssklower 	for (n = sb->sb_mb; n; n = n->m_nextpkt) {
88350901Ssklower 		if ((n->m_flags & M_PKTHDR) == 0)
88450901Ssklower 			panic("tpsbcheck nohdr");
88550901Ssklower 		pktlen = len + n->m_pkthdr.len;
88650901Ssklower 	    for (m = n; m; m = m->m_next) {
88750901Ssklower 			len += m->m_len;
88850901Ssklower 			mbcnt += MSIZE;
88950901Ssklower 			if (m->m_flags & M_EXT)
89050901Ssklower 				mbcnt += m->m_ext.ext_size;
89150901Ssklower 		}
89250901Ssklower 		if (len != pktlen) {
89350901Ssklower 			printf("test %d; len %d != pktlen %d on mbuf 0x%x\n",
89450901Ssklower 				i, len, pktlen, n);
89550901Ssklower 			panic("tpsbcheck short");
89650901Ssklower 		}
89750901Ssklower 	}
89850901Ssklower 	if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
89950901Ssklower 		printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc,
90050901Ssklower 		    mbcnt, sb->sb_mbcnt);
90150901Ssklower 		panic("tpsbcheck");
90250901Ssklower 	}
90350901Ssklower }
904