xref: /csrg-svn/sys/netiso/tp_subr.c (revision 51341)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51341Ssklower  *	@(#)tp_subr.c	7.17 (Berkeley) 10/08/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;
75*51341Ssklower extern int	ticks;
7651204Ssklower void	tp_send();
7736413Ssklower 
7836413Ssklower /*
7936413Ssklower  * CALLED FROM:
8036413Ssklower  *	tp.trans, when an XAK arrives
8136413Ssklower  * FUNCTION and ARGUMENTS:
8236413Ssklower  * 	Determines if the sequence number (seq) from the XAK
8336413Ssklower  * 	acks anything new.  If so, drop the appropriate tpdu
8436413Ssklower  * 	from the XPD send queue.
8536413Ssklower  * RETURN VALUE:
8636413Ssklower  * 	Returns 1 if it did this, 0 if the ack caused no action.
8736413Ssklower  */
8836413Ssklower int
8936413Ssklower tp_goodXack(tpcb, seq)
9036413Ssklower 	struct tp_pcb	*tpcb;
9136413Ssklower 	SeqNum 			seq;
9236413Ssklower {
9336413Ssklower 
9436413Ssklower 	IFTRACE(D_XPD)
9536413Ssklower 		tptraceTPCB(TPPTgotXack,
9651204Ssklower 			seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew,
9736413Ssklower 			tpcb->tp_snduna);
9836413Ssklower 	ENDTRACE
9936413Ssklower 
10036413Ssklower 	if ( seq == tpcb->tp_Xuna ) {
10136413Ssklower 			tpcb->tp_Xuna = tpcb->tp_Xsndnxt;
10236413Ssklower 
10336413Ssklower 			/* DROP 1 packet from the Xsnd socket buf - just so happens
10436413Ssklower 			 * that only one packet can be there at any time
10536413Ssklower 			 * so drop the whole thing.  If you allow > 1 packet
10636413Ssklower 			 * the socket buffer, then you'll have to keep
10736413Ssklower 			 * track of how many characters went w/ each XPD tpdu, so this
10836413Ssklower 			 * will get messier
10936413Ssklower 			 */
11036413Ssklower 			IFDEBUG(D_XPD)
11136413Ssklower 				dump_mbuf(tpcb->tp_Xsnd.sb_mb,
11236413Ssklower 					"tp_goodXack Xsnd before sbdrop");
11336413Ssklower 			ENDDEBUG
11436413Ssklower 
11536413Ssklower 			IFTRACE(D_XPD)
11636413Ssklower 				tptraceTPCB(TPPTmisc,
11736413Ssklower 					"goodXack: dropping cc ",
11836413Ssklower 					(int)(tpcb->tp_Xsnd.sb_cc),
11936413Ssklower 					0,0,0);
12036413Ssklower 			ENDTRACE
12151204Ssklower 			sbdroprecord(&tpcb->tp_Xsnd);
12236413Ssklower 			return 1;
12336413Ssklower 	}
12436413Ssklower 	return 0;
12536413Ssklower }
12636413Ssklower 
12736413Ssklower /*
12836413Ssklower  * CALLED FROM:
12936413Ssklower  *  tp_good_ack()
13036413Ssklower  * FUNCTION and ARGUMENTS:
13136413Ssklower  *  updates
13251138Ssklower  *  smoothed average round trip time (*rtt)
13351138Ssklower  *  roundtrip time variance (*rtv) - actually deviation, not variance
13436413Ssklower  *  given the new value (diff)
13536413Ssklower  * RETURN VALUE:
13636413Ssklower  * void
13736413Ssklower  */
13836413Ssklower 
13936413Ssklower void
14051204Ssklower tp_rtt_rtv(tpcb)
14151204Ssklower register struct tp_pcb *tpcb;
14236413Ssklower {
143*51341Ssklower 	int old = tpcb->tp_rtt;
144*51341Ssklower 	int delta, elapsed = ticks - tpcb->tp_rttemit;
14536413Ssklower 
14651204Ssklower 	if (tpcb->tp_rtt != 0) {
14751204Ssklower 		/*
14851204Ssklower 		 * rtt is the smoothed round trip time in machine clock ticks (hz).
14951249Ssklower 		 * It is stored as a fixed point number, unscaled (unlike the tcp
15051249Ssklower 		 * srtt).  The rationale here is that it is only significant to the
15151204Ssklower 		 * nearest unit of slowtimo, which is at least 8 machine clock ticks
15251204Ssklower 		 * so there is no need to scale.  The smoothing is done according
15351204Ssklower 		 * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8).
15451204Ssklower 		 */
15551204Ssklower 		delta = elapsed - tpcb->tp_rtt;
15651204Ssklower 		if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0)
15751204Ssklower 			tpcb->tp_rtt = 1;
15851204Ssklower 		/*
15951204Ssklower 		 * rtv is a smoothed accumulated mean difference, unscaled
16051204Ssklower 		 * for reasons expressed above.
16151204Ssklower 		 * It is smoothed with an alpha of .75, and the round trip timer
16251204Ssklower 		 * will be set to rtt + 4*rtv, also as TCP does.
16351204Ssklower 		 */
16451204Ssklower 		if (delta < 0)
16551204Ssklower 			delta = -delta;
16651204Ssklower 		if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0)
16751204Ssklower 			tpcb->tp_rtv = 1;
16851204Ssklower 	} else {
16951204Ssklower 		/*
17051204Ssklower 		 * No rtt measurement yet - use the unsmoothed rtt.
17151204Ssklower 		 * Set the variance to half the rtt (so our first
17251204Ssklower 		 * retransmit happens at 3*rtt)
17351204Ssklower 		 */
17451204Ssklower 		tpcb->tp_rtt = elapsed;
17551204Ssklower 		tpcb->tp_rtv = elapsed >> 1;
17651204Ssklower 	}
17751204Ssklower 	tpcb->tp_rttemit = 0;
17851204Ssklower 	tpcb->tp_rxtshift = 0;
17951204Ssklower 	/*
18051204Ssklower 	 * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar.
18151204Ssklower 	 * Because of the way we do the smoothing, srtt and rttvar
18251204Ssklower 	 * will each average +1/2 tick of bias.  When we compute
18351204Ssklower 	 * the retransmit timer, we want 1/2 tick of rounding and
18451204Ssklower 	 * 1 extra tick because of +-1/2 tick uncertainty in the
18551204Ssklower 	 * firing of the timer.  The bias will give us exactly the
18651204Ssklower 	 * 1.5 tick we need.  But, because the bias is
18751204Ssklower 	 * statistical, we have to test that we don't drop below
18851204Ssklower 	 * the minimum feasible timer (which is 2 ticks)."
18951204Ssklower 	 */
19051249Ssklower 	TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb),
19151249Ssklower 		tpcb->tp_peer_acktime, 128 /* XXX */);
192*51341Ssklower 	IFDEBUG(D_RTT)
193*51341Ssklower 		printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n",
194*51341Ssklower 			"tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old);
195*51341Ssklower 	ENDDEBUG
19651249Ssklower 	tpcb->tp_rxtcur = tpcb->tp_dt_ticks;
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;
22251204Ssklower 	register SeqNum			seq;
22351204Ssklower 	u_int					subseq;
22436413Ssklower {
22551204Ssklower 	int 	old_fcredit;
22636413Ssklower 	int 	bang = 0; 	/* bang --> ack for something heretofore unacked */
22751204Ssklower 	u_int	bytes_acked;
22836413Ssklower 
22936413Ssklower 	IFDEBUG(D_ACKRECV)
23051204Ssklower 		printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n",
23151204Ssklower 			tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt);
23236413Ssklower 	ENDDEBUG
23336413Ssklower 	IFTRACE(D_ACKRECV)
23436413Ssklower 		tptraceTPCB(TPPTgotack,
23551204Ssklower 			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 
24251204Ssklower 	if (seq == tpcb->tp_snduna) {
24351204Ssklower 		if (subseq < tpcb->tp_r_subseq ||
24451204Ssklower 			(subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) {
24551204Ssklower 		discard_the_ack:
24651204Ssklower 			IFDEBUG(D_ACKRECV)
24751204Ssklower 				printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n",
24851204Ssklower 					tpcb, subseq, tpcb->tp_r_subseq);
24951204Ssklower 			ENDDEBUG
25051204Ssklower 			goto done;
25136413Ssklower 		}
25251204Ssklower 		if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) {
25351204Ssklower 			tpcb->tp_r_subseq = subseq;
25451204Ssklower 			if (tpcb->tp_timer[TM_data_retrans] == 0)
25551204Ssklower 				tpcb->tp_dupacks = 0;
25651204Ssklower 			else if (++tpcb->tp_dupacks == tprexmtthresh) {
25751204Ssklower 				/* partner went out of his way to signal with different
25851204Ssklower 				   subsequences that he has the same lack of an expected
25951204Ssklower 				   packet.  This may be an early indiciation of a loss */
26036413Ssklower 
26151204Ssklower 				SeqNum onxt = tpcb->tp_sndnxt;
26251204Ssklower 				struct mbuf *onxt_m = tpcb->tp_sndnxt_m;
26351204Ssklower 				u_int win = min(tpcb->tp_fcredit,
26451204Ssklower 							tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2;
265*51341Ssklower 				IFDEBUG(D_ACKRECV)
266*51341Ssklower 					printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n",
267*51341Ssklower 						"goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt);
268*51341Ssklower 				ENDDEBUG
26951204Ssklower 				if (win < 2)
27051204Ssklower 					win = 2;
27151204Ssklower 				tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
27251204Ssklower 				tpcb->tp_timer[TM_data_retrans] = 0;
27351204Ssklower 				tpcb->tp_rttemit = 0;
27451204Ssklower 				tpcb->tp_sndnxt = tpcb->tp_snduna;
27551204Ssklower 				tpcb->tp_sndnxt_m = 0;
27651204Ssklower 				tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
27751204Ssklower 				tp_send(tpcb);
27851204Ssklower 				tpcb->tp_cong_win = tpcb->tp_ssthresh +
27951204Ssklower 					tpcb->tp_dupacks * tpcb->tp_l_tpdusize;
28051204Ssklower 				if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) {
28151204Ssklower 					tpcb->tp_sndnxt = onxt;
28251204Ssklower 					tpcb->tp_sndnxt_m = onxt_m;
28351204Ssklower 				}
28436413Ssklower 
28551204Ssklower 			} else if (tpcb->tp_dupacks > tprexmtthresh) {
28651204Ssklower 				tpcb->tp_cong_win += tpcb->tp_l_tpdusize;
28751138Ssklower 			}
28851204Ssklower 			goto done;
28951204Ssklower 		}
29051204Ssklower 	} else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna))
29151204Ssklower 		goto discard_the_ack;
29251204Ssklower 	/*
29351204Ssklower 	 * If the congestion window was inflated to account
29451204Ssklower 	 * for the other side's cached packets, retract it.
29551204Ssklower 	 */
29651204Ssklower 	if (tpcb->tp_dupacks > tprexmtthresh &&
29751204Ssklower 		tpcb->tp_cong_win > tpcb->tp_ssthresh)
29851204Ssklower 			tpcb->tp_cong_win = tpcb->tp_ssthresh;
29951204Ssklower 	tpcb->tp_r_subseq = subseq;
30051204Ssklower 	old_fcredit = tpcb->tp_fcredit;
30151204Ssklower 	tpcb->tp_fcredit = cdt;
30251204Ssklower 	if (cdt > tpcb->tp_maxfcredit)
30351204Ssklower 		tpcb->tp_maxfcredit = cdt;
30451204Ssklower 	tpcb->tp_dupacks = 0;
30536413Ssklower 
30651204Ssklower 	if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) {
30736413Ssklower 
30851204Ssklower 		tpsbcheck(tpcb, 0);
30951204Ssklower 		bytes_acked = tp_sbdrop(tpcb, seq);
31051204Ssklower 		tpsbcheck(tpcb, 1);
31151204Ssklower 		/*
31251204Ssklower 		 * If transmit timer is running and timed sequence
31351204Ssklower 		 * number was acked, update smoothed round trip time.
31451204Ssklower 		 * Since we now have an rtt measurement, cancel the
31551204Ssklower 		 * timer backoff (cf., Phil Karn's retransmit alg.).
31651204Ssklower 		 * Recompute the initial retransmit timer.
31751204Ssklower 		 */
31851204Ssklower 		if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq))
31951204Ssklower 			tp_rtt_rtv(tpcb);
32051204Ssklower 		/*
32151204Ssklower 		 * If all outstanding data is acked, stop retransmit timer.
32251204Ssklower 		 * If there is more data to be acked, restart retransmit
32351204Ssklower 		 * timer, using current (possibly backed-off) value.
32451204Ssklower 		 * OSI combines the keepalive and persistance functions.
32551204Ssklower 		 * So, there is no persistance timer per se, to restart.
32651204Ssklower 		 */
32751204Ssklower 		tpcb->tp_timer[TM_data_retrans] =
32851204Ssklower 			(seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur;
32951204Ssklower 		/*
33051204Ssklower 		 * When new data is acked, open the congestion window.
33151204Ssklower 		 * If the window gives us less than ssthresh packets
33251204Ssklower 		 * in flight, open exponentially (maxseg per packet).
33351204Ssklower 		 * Otherwise open linearly: maxseg per window
33451204Ssklower 		 * (maxseg^2 / cwnd per packet), plus a constant
33551204Ssklower 		 * fraction of a packet (maxseg/8) to help larger windows
33651204Ssklower 		 * open quickly enough.
33751204Ssklower 		 */
33851204Ssklower 		{
33951204Ssklower 			u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize;
34036413Ssklower 
34151204Ssklower 			incr = min(incr, bytes_acked);
34251204Ssklower 			if (cw > tpcb->tp_ssthresh)
34351204Ssklower 				incr = incr * incr / cw + incr / 8;
34451204Ssklower 			tpcb->tp_cong_win =
34551204Ssklower 				min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat);
34636413Ssklower 		}
34736413Ssklower 		tpcb->tp_snduna = seq;
34851204Ssklower 		if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) {
34951204Ssklower 				tpcb->tp_sndnxt = seq;
35051204Ssklower 				tpcb->tp_sndnxt_m = 0;
35151204Ssklower 		}
35236413Ssklower 		bang++;
35336413Ssklower 	}
35436413Ssklower 
35536413Ssklower 	if( cdt != 0 && old_fcredit == 0 ) {
35636413Ssklower 		tpcb->tp_sendfcc = 1;
35736413Ssklower 	}
35851249Ssklower 	if (cdt == 0) {
35951249Ssklower 		if (old_fcredit != 0)
36051249Ssklower 			IncStat(ts_zfcdt);
36151249Ssklower 		/* The following might mean that the window shrunk */
36251249Ssklower 		if (tpcb->tp_timer[TM_data_retrans]) {
36351249Ssklower 			tpcb->tp_timer[TM_data_retrans] = 0;
36451249Ssklower 			tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
36551249Ssklower 			if (tpcb->tp_sndnxt != tpcb->tp_snduna) {
36651249Ssklower 				tpcb->tp_sndnxt = tpcb->tp_snduna;
36751249Ssklower 				tpcb->tp_sndnxt_m = 0;
36851249Ssklower 			}
36951249Ssklower 		}
37036413Ssklower 	}
37136413Ssklower 	tpcb->tp_fcredit = cdt;
37251204Ssklower 	bang |= (old_fcredit < cdt);
37336413Ssklower 
37451204Ssklower done:
37536413Ssklower 	IFDEBUG(D_ACKRECV)
37651204Ssklower 		printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n",
37751204Ssklower 			bang, cdt, old_fcredit, tpcb->tp_cong_win);
37836413Ssklower 	ENDDEBUG
37951204Ssklower 	/* if (bang) XXXXX Very bad to remove this test, but somethings broken */
38051204Ssklower 		tp_send(tpcb);
38151204Ssklower 	return (bang);
38236413Ssklower }
38336413Ssklower 
38436413Ssklower /*
38536413Ssklower  * CALLED FROM:
38636413Ssklower  *  tp_goodack()
38736413Ssklower  * FUNCTION and ARGUMENTS:
38850901Ssklower  *  drops everything up TO but not INCLUDING seq # (seq)
38936413Ssklower  *  from the retransmission queue.
39036413Ssklower  */
39136413Ssklower tp_sbdrop(tpcb, seq)
39250901Ssklower 	register struct 	tp_pcb 			*tpcb;
39336413Ssklower 	SeqNum					seq;
39436413Ssklower {
39550901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
39651204Ssklower 	register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna);
39751204Ssklower 	int	oldcc = sb->sb_cc, oldi = i;
39836413Ssklower 
39951204Ssklower 	if (i >= tpcb->tp_seqhalf)
40051204Ssklower 		printf("tp_spdropping too much -- should panic");
40151204Ssklower 	while (i-- > 0)
40251204Ssklower 		sbdroprecord(sb);
40336413Ssklower 	IFDEBUG(D_ACKRECV)
40451204Ssklower 		printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n",
40551204Ssklower 			oldi, oldcc - sb->sb_cc, tpcb, seq);
40636413Ssklower 	ENDDEBUG
40751204Ssklower 	if (sb->sb_flags & SB_NOTIFY)
40851204Ssklower 		sowwakeup(tpcb->tp_sock);
40951138Ssklower 	return (oldcc - sb->sb_cc);
41036413Ssklower }
41136413Ssklower 
41236413Ssklower /*
41336413Ssklower  * CALLED FROM:
41436413Ssklower  * 	tp.trans on user send request, arrival of AK and arrival of XAK
41536413Ssklower  * FUNCTION and ARGUMENTS:
41651204Ssklower  * 	Emits tpdus starting at sequence number (tpcb->tp_sndnxt).
41736413Ssklower  * 	Emits until a) runs out of data, or  b) runs into an XPD mark, or
41851204Ssklower  * 			c) it hits seq number (highseq) limited by cong or credit.
41936413Ssklower  *
42036413Ssklower  * 	If you want XPD to buffer > 1 du per socket buffer, you can
42136413Ssklower  * 	modifiy this to issue XPD tpdus also, but then it'll have
42236413Ssklower  * 	to take some argument(s) to distinguish between the type of DU to
42350901Ssklower  * 	hand tp_emit.
42436413Ssklower  *
42536413Ssklower  * 	When something is sent for the first time, its time-of-send
42651204Ssklower  * 	is stashed (in system clock ticks rather than pf_slowtimo ticks).
42751204Ssklower  *  When the ack arrives, the smoothed round-trip time is figured
42851204Ssklower  *  using this value.
42936413Ssklower  */
43051204Ssklower void
43136413Ssklower tp_send(tpcb)
43236413Ssklower 	register struct tp_pcb	*tpcb;
43336413Ssklower {
43436413Ssklower 	register int			len;
43551204Ssklower 	register struct mbuf	*m;
43651204Ssklower 	struct mbuf				*mb = 0;
43736413Ssklower 	struct 	sockbuf			*sb = &tpcb->tp_sock->so_snd;
43851204Ssklower 	unsigned int			eotsdu = 0;
43951204Ssklower 	SeqNum					highseq, checkseq;
44051204Ssklower 	int						idle, idleticks, off, cong_win;
44136413Ssklower #ifdef TP_PERF_MEAS
442*51341Ssklower 	int			 			send_start_time = ticks;
44351204Ssklower 	SeqNum					oldnxt = tpcb->tp_sndnxt;
44436413Ssklower #endif TP_PERF_MEAS
44536413Ssklower 
44651204Ssklower 	idle = (tpcb->tp_snduna == tpcb->tp_sndnew);
44751204Ssklower 	if (idle) {
44851204Ssklower 		idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact];
44951204Ssklower 		if (idleticks > tpcb->tp_dt_ticks)
45051204Ssklower 			/*
45151204Ssklower 			 * We have been idle for "a while" and no acks are
45251204Ssklower 			 * expected to clock out any data we send --
45351204Ssklower 			 * slow start to get ack "clock" running again.
45451204Ssklower 			 */
45551204Ssklower 			tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
45651204Ssklower 	}
45736413Ssklower 
45851204Ssklower 	cong_win = tpcb->tp_cong_win;
45951204Ssklower 	highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna);
46051204Ssklower 	if (tpcb->tp_Xsnd.sb_mb)
46151204Ssklower 		highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew);
46236413Ssklower 
46336413Ssklower 	IFDEBUG(D_DATA)
46451204Ssklower 		printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n",
46551204Ssklower 				tpcb, tpcb->tp_sndnxt, cong_win, highseq);
46636413Ssklower 	ENDDEBUG
46736413Ssklower 	IFTRACE(D_DATA)
46851204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send sndnew snduna",
46951204Ssklower 			tpcb->tp_sndnew,  tpcb->tp_snduna, 0, 0);
47051204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin",
47151204Ssklower 			tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win);
47236413Ssklower 	ENDTRACE
47336413Ssklower 	IFTRACE(D_DATA)
47451204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin",
47551204Ssklower 			tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win);
47636413Ssklower 	ENDTRACE
47736413Ssklower 
47851204Ssklower 	if (tpcb->tp_sndnxt_m)
47951204Ssklower 		m = tpcb->tp_sndnxt_m;
48051204Ssklower 	else {
48151204Ssklower 		off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna);
48251204Ssklower 		for (m = sb->sb_mb; m && off > 0; m = m->m_next)
48351204Ssklower 			off--;
48451204Ssklower 	}
48551204Ssklower send:
48651204Ssklower 	/*
48751204Ssklower 	 * Avoid silly window syndrome here . . . figure out how!
48851204Ssklower 	 */
48951204Ssklower 	checkseq = tpcb->tp_sndnum;
49051204Ssklower 	if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq))
49151249Ssklower 		checkseq = highseq; /* i.e. DON'T retain highest assigned packet */
49236413Ssklower 
49351204Ssklower 	while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) {
49436413Ssklower 
49551204Ssklower 		eotsdu = (m->m_flags & M_EOR) != 0;
49651204Ssklower 		len = m->m_pkthdr.len;
49751204Ssklower 		if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 &&
49851204Ssklower 			len < (tpcb->tp_l_tpdusize / 2))
49951204Ssklower 				break;  /* Nagle . . . . . */
50051204Ssklower 		cong_win -= len;
50136413Ssklower 		/* make a copy - mb goes into the retransmission list
50236413Ssklower 		 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
50336413Ssklower 		 */
50451204Ssklower 		mb = m;
50550901Ssklower 		m = m_copy(mb, 0, M_COPYALL);
50650901Ssklower 		if (m == MNULL)
50751204Ssklower 				break;
50851204Ssklower 		IFTRACE(D_STASH)
50936413Ssklower 			tptraceTPCB( TPPTmisc,
51051204Ssklower 				"tp_send mcopy nxt high eotsdu len",
51151204Ssklower 				tpcb->tp_sndnxt, highseq, eotsdu, len);
51236413Ssklower 		ENDTRACE
51351204Ssklower 
51451204Ssklower 		IFDEBUG(D_DATA)
51551204Ssklower 			printf("tp_sending tpcb 0x%x nxt 0x%x\n",
51651204Ssklower 				tpcb, tpcb->tp_sndnxt);
51751204Ssklower 		ENDDEBUG
51851204Ssklower 		/* when headers are precomputed, may need to fill
51950901Ssklower 			   in checksum here */
52050901Ssklower 		if (tpcb->tp_sock->so_error =
52151204Ssklower 			tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) {
52236413Ssklower 			/* error */
52351204Ssklower 			break;
52436413Ssklower 		}
52551204Ssklower 		m = mb->m_nextpkt;
52651204Ssklower 		tpcb->tp_sndnxt_m = m;
52751204Ssklower 		if (tpcb->tp_sndnxt == tpcb->tp_sndnew) {
52851204Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnew);
52951204Ssklower 			/*
53051204Ssklower 			 * Time this transmission if not a retransmission and
53151204Ssklower 			 * not currently timing anything.
53251204Ssklower 			 */
53351204Ssklower 			if (tpcb->tp_rttemit == 0) {
534*51341Ssklower 				tpcb->tp_rttemit = ticks;
53551204Ssklower 				tpcb->tp_rttseq = tpcb->tp_sndnxt;
53651204Ssklower 			}
53751204Ssklower 			tpcb->tp_sndnxt = tpcb->tp_sndnew;
53851204Ssklower 		} else
53951204Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnxt);
54051204Ssklower 		/*
54151204Ssklower 		 * Set retransmit timer if not currently set.
54251204Ssklower 		 * Initial value for retransmit timer is smoothed
54351204Ssklower 		 * round-trip time + 2 * round-trip time variance.
54451204Ssklower 		 * Initialize shift counter which is used for backoff
54551204Ssklower 		 * of retransmit time.
54651204Ssklower 		 */
54751204Ssklower 		if (tpcb->tp_timer[TM_data_retrans] == 0) {
54851204Ssklower 			tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks;
54951204Ssklower 			tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks;
55051204Ssklower 			tpcb->tp_rxtshift = 0;
55151138Ssklower 		}
55236413Ssklower 	}
55351204Ssklower 	if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum))
55451204Ssklower 		tpcb->tp_oktonagle = 0;
55550236Ssklower #ifdef TP_PERF_MEAS
55636413Ssklower 	IFPERF(tpcb)
55736413Ssklower 		{
55836413Ssklower 			register int npkts;
559*51341Ssklower 			int	 elapsed = ticks - send_start_time, *t;
56051138Ssklower 			struct timeval now;
56136413Ssklower 
56251204Ssklower 			npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt);
56336413Ssklower 
56451204Ssklower 			if (npkts > 0)
56536413Ssklower 				tpcb->tp_Nwindow++;
56636413Ssklower 
56736413Ssklower 			if (npkts > TP_PM_MAX)
56836413Ssklower 				npkts = TP_PM_MAX;
56936413Ssklower 
57036413Ssklower 			t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
57151138Ssklower 			*t += (t - elapsed) >> TP_RTT_ALPHA;
57236413Ssklower 
57351204Ssklower 			if (mb == 0) {
57436413Ssklower 				IncPStat(tpcb, tps_win_lim_by_data[npkts] );
57536413Ssklower 			} else {
57636413Ssklower 				IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
57736413Ssklower 				/* not true with congestion-window being used */
57836413Ssklower 			}
57951138Ssklower 			now.tv_sec = elapsed / hz;
58051138Ssklower 			now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz;
58136413Ssklower 			tpmeas( tpcb->tp_lref,
58251204Ssklower 					TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts);
58336413Ssklower 		}
58436413Ssklower 	ENDPERF
58550236Ssklower #endif TP_PERF_MEAS
58636413Ssklower 
58736413Ssklower 
58836413Ssklower 	IFTRACE(D_DATA)
58936413Ssklower 		tptraceTPCB( TPPTmisc,
59051204Ssklower 			"tp_send at end: new nxt eotsdu error",
59151204Ssklower 			tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error);
59236413Ssklower 
59336413Ssklower 	ENDTRACE
59436413Ssklower }
59536413Ssklower 
59650901Ssklower int TPNagleok;
59750901Ssklower int TPNagled;
59850901Ssklower 
59950901Ssklower tp_packetize(tpcb, m, eotsdu)
60050901Ssklower register struct tp_pcb *tpcb;
60150901Ssklower register struct mbuf *m;
60250901Ssklower int eotsdu;
60350901Ssklower {
60450901Ssklower 	register struct mbuf *n;
60550901Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_snd;
60650901Ssklower 	int	maxsize = tpcb->tp_l_tpdusize
60750901Ssklower 			- tp_headersize(DT_TPDU_type, tpcb)
60850901Ssklower 			- (tpcb->tp_use_checksum?4:0) ;
60950901Ssklower 	int totlen = m->m_pkthdr.len;
61050901Ssklower 	struct mbuf *m_split();
61150901Ssklower 	/*
61250901Ssklower 	 * Pre-packetize the data in the sockbuf
61350901Ssklower 	 * according to negotiated mtu.  Do it here
61450901Ssklower 	 * where we can safely wait for mbufs.
61550901Ssklower 	 *
61650901Ssklower 	 * This presumes knowledge of sockbuf conventions.
61750901Ssklower 	 * TODO: allocate space for header and fill it in (once!).
61850901Ssklower 	 */
61951204Ssklower 	IFDEBUG(D_DATA)
62051204Ssklower 		printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n",
62151204Ssklower 			maxsize, totlen, eotsdu, tpcb->tp_sndnum);
62250901Ssklower 	ENDTRACE
62350901Ssklower 	if (tpcb->tp_oktonagle) {
62450901Ssklower 		if ((n = sb->sb_mb) == 0)
62550901Ssklower 			panic("tp_packetize");
62650901Ssklower 		while (n->m_act)
62750901Ssklower 			n = n->m_act;
62850901Ssklower 		if (n->m_flags & M_EOR)
62950901Ssklower 			panic("tp_packetize 2");
63050901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
63150901Ssklower 		if (totlen + n->m_pkthdr.len < maxsize) {
63250901Ssklower 			/* There is an unsent packet with space, combine data */
63350901Ssklower 			struct mbuf *old_n = n;
63450901Ssklower 			tpsbcheck(tpcb,3);
63550901Ssklower 			n->m_pkthdr.len += totlen;
63650901Ssklower 			while (n->m_next)
63750901Ssklower 				n = n->m_next;
63850901Ssklower 			sbcompress(sb, m, n);
63950901Ssklower 			tpsbcheck(tpcb,4);
64050901Ssklower 			n = old_n;
64150901Ssklower 			TPNagled++;
64250901Ssklower 			goto out;
64350901Ssklower 		}
64450901Ssklower 	}
64550901Ssklower 	while (m) {
64650901Ssklower 		n = m;
64750901Ssklower 		if (totlen > maxsize) {
64850901Ssklower 			if ((m = m_split(n, maxsize, M_WAIT)) == 0)
64950901Ssklower 				panic("tp_packetize");
65050901Ssklower 		} else
65150901Ssklower 			m = 0;
65250901Ssklower 		totlen -= maxsize;
65350901Ssklower 		tpsbcheck(tpcb, 5);
65450901Ssklower 		sbappendrecord(sb, n);
65550901Ssklower 		tpsbcheck(tpcb, 6);
65650901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
65750901Ssklower 	}
65850901Ssklower out:
65950901Ssklower 	if (eotsdu) {
66050901Ssklower 		n->m_flags |= M_EOR;  /* XXX belongs at end */
66150901Ssklower 		tpcb->tp_oktonagle = 0;
66250901Ssklower 	} else {
66350901Ssklower 		SEQ_DEC(tpcb, tpcb->tp_sndnum);
66450901Ssklower 		tpcb->tp_oktonagle = 1;
66550901Ssklower 		TPNagleok++;
66650901Ssklower 	}
66751204Ssklower 	IFDEBUG(D_DATA)
66851204Ssklower 		printf("SEND out: oktonagle %d sndnum 0x%x\n",
66951204Ssklower 			tpcb->tp_oktonagle, tpcb->tp_sndnum);
67051204Ssklower 	ENDTRACE
67150901Ssklower 	return 0;
67250901Ssklower }
67350901Ssklower 
67450901Ssklower 
67536413Ssklower /*
67636413Ssklower  * NAME: tp_stash()
67736413Ssklower  * CALLED FROM:
67836413Ssklower  *	tp.trans on arrival of a DT tpdu
67936413Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
68036413Ssklower  * 	Returns 1 if
68136413Ssklower  *		a) something new arrived and it's got eotsdu_reached bit on,
68236413Ssklower  * 		b) this arrival was caused other out-of-sequence things to be
68336413Ssklower  *    	accepted, or
68436413Ssklower  * 		c) this arrival is the highest seq # for which we last gave credit
68536413Ssklower  *   	(sender just sent a whole window)
68636413Ssklower  *  In other words, returns 1 if tp should send an ack immediately, 0 if
68736413Ssklower  *  the ack can wait a while.
68836413Ssklower  *
68936413Ssklower  * Note: this implementation no longer renegs on credit, (except
69036413Ssklower  * when debugging option D_RENEG is on, for the purpose of testing
69136413Ssklower  * ack subsequencing), so we don't  need to check for incoming tpdus
69236413Ssklower  * being in a reneged portion of the window.
69336413Ssklower  */
69436413Ssklower 
69551204Ssklower tp_stash(tpcb, e)
69636413Ssklower 	register struct tp_pcb		*tpcb;
69736413Ssklower 	register struct tp_event	*e;
69836413Ssklower {
69936413Ssklower 	register int		ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
70036413Ssklower 									/* 0--> delay acks until full window */
70136413Ssklower 									/* 1--> ack each tpdu */
70236413Ssklower #ifndef lint
70336413Ssklower #define E e->ATTR(DT_TPDU)
70436413Ssklower #else lint
70536413Ssklower #define E e->ev_union.EV_DT_TPDU
70636413Ssklower #endif lint
70736413Ssklower 
70836413Ssklower 	if ( E.e_eot ) {
70936413Ssklower 		register struct mbuf *n = E.e_data;
71037469Ssklower 		n->m_flags |= M_EOR;
71138841Ssklower 		n->m_act = 0;
71237469Ssklower 	}
71336413Ssklower 		IFDEBUG(D_STASH)
71436413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
71536413Ssklower 				"stash: so_rcv before appending");
71636413Ssklower 			dump_mbuf(E.e_data,
71736413Ssklower 				"stash: e_data before appending");
71836413Ssklower 		ENDDEBUG
71936413Ssklower 
72036413Ssklower 	IFPERF(tpcb)
72136413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
72236413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
72337469Ssklower 			E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
72436413Ssklower 	ENDPERF
72536413Ssklower 
72651024Ssklower 	if (E.e_seq == tpcb->tp_rcvnxt) {
72736413Ssklower 
72836413Ssklower 		IFDEBUG(D_STASH)
72936413Ssklower 			printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
73036413Ssklower 			E.e_seq, E.e_datalen, E.e_eot);
73136413Ssklower 		ENDDEBUG
73236413Ssklower 
73336413Ssklower 		IFTRACE(D_STASH)
73436413Ssklower 			tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
73536413Ssklower 			E.e_seq, E.e_datalen, E.e_eot, 0);
73636413Ssklower 		ENDTRACE
73736413Ssklower 
73851024Ssklower 		SET_DELACK(tpcb);
73951024Ssklower 
74037469Ssklower 		sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
74137469Ssklower 
74236413Ssklower 		SEQ_INC( tpcb, tpcb->tp_rcvnxt );
74336413Ssklower 		/*
74450901Ssklower 		 * move chains from the reassembly queue to the socket buffer
74536413Ssklower 		 */
74650901Ssklower 		if (tpcb->tp_rsycnt) {
74750901Ssklower 			register struct mbuf **mp;
74850901Ssklower 			struct mbuf **mplim;
74936413Ssklower 
75050901Ssklower 			mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit);
75150901Ssklower 			mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit;
75236413Ssklower 
75350901Ssklower 			while (tpcb->tp_rsycnt && *mp) {
75450901Ssklower 				sbappend(&tpcb->tp_sock->so_rcv, *mp);
75550901Ssklower 				tpcb->tp_rsycnt--;
75650901Ssklower 				*mp = 0;
75750901Ssklower 				SEQ_INC(tpcb, tpcb->tp_rcvnxt);
75836413Ssklower 				ack_reason |= ACK_REORDER;
75950901Ssklower 				if (++mp == mplim)
76050901Ssklower 					mp = tpcb->tp_rsyq;
76136413Ssklower 			}
76236413Ssklower 		}
76336413Ssklower 		IFDEBUG(D_STASH)
76436413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
76536413Ssklower 				"stash: so_rcv after appending");
76636413Ssklower 		ENDDEBUG
76736413Ssklower 
76836413Ssklower 	} else {
76950901Ssklower 		register struct mbuf **mp;
77050901Ssklower 		SeqNum uwe;
77136413Ssklower 
77236413Ssklower 		IFTRACE(D_STASH)
77336413Ssklower 			tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
77436413Ssklower 			E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
77536413Ssklower 		ENDTRACE
77636413Ssklower 
77750975Ssklower 		if (tpcb->tp_rsyq == 0)
77850975Ssklower 			tp_rsyset(tpcb);
77950901Ssklower 		uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit);
78050901Ssklower 		if (tpcb->tp_rsyq == 0 ||
78150901Ssklower 						!IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) {
78236413Ssklower 			ack_reason = ACK_DONT;
78350901Ssklower 			m_freem(E.e_data);
78450901Ssklower 		} else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) {
78536413Ssklower 			IFDEBUG(D_STASH)
78636413Ssklower 				printf("tp_stash - drop & ack\n");
78736413Ssklower 			ENDDEBUG
78836413Ssklower 
78936413Ssklower 			/* retransmission - drop it and force an ack */
79036413Ssklower 			IncStat(ts_dt_dup);
79136413Ssklower 			IFPERF(tpcb)
79236413Ssklower 				IncPStat(tpcb, tps_n_ack_cuz_dup);
79336413Ssklower 			ENDPERF
79436413Ssklower 
79550901Ssklower 			m_freem(E.e_data);
79636413Ssklower 			ack_reason |= ACK_DUP;
79750901Ssklower 		} else {
79850901Ssklower 			*mp = E.e_data;
79950901Ssklower 			tpcb->tp_rsycnt++;
80050901Ssklower 			ack_reason = ACK_DONT;
80136413Ssklower 		}
80236413Ssklower 	}
80351024Ssklower 	/* there were some comments of historical interest here. */
80436413Ssklower 	{
80536413Ssklower 		LOCAL_CREDIT(tpcb);
80636413Ssklower 
80736413Ssklower 		if ( E.e_seq ==  tpcb->tp_sent_uwe )
80836413Ssklower 			ack_reason |= ACK_STRAT_FULLWIN;
80936413Ssklower 
81036413Ssklower 		IFTRACE(D_STASH)
81136413Ssklower 			tptraceTPCB(TPPTmisc,
81236413Ssklower 				"end of stash, eot, ack_reason, sent_uwe ",
81336413Ssklower 				E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
81436413Ssklower 		ENDTRACE
81536413Ssklower 
81636413Ssklower 		if ( ack_reason == ACK_DONT ) {
81736413Ssklower 			IncStat( ts_ackreason[ACK_DONT] );
81836413Ssklower 			return 0;
81936413Ssklower 		} else {
82036413Ssklower 			IFPERF(tpcb)
82136413Ssklower 				if(ack_reason & ACK_STRAT_EACH) {
82236413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_strat);
82336413Ssklower 				} else if(ack_reason & ACK_STRAT_FULLWIN) {
82436413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_fullwin);
82536413Ssklower 				} else if(ack_reason & ACK_REORDER) {
82636413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_reorder);
82736413Ssklower 				}
82836413Ssklower 				tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
82936413Ssklower 							SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
83036413Ssklower 			ENDPERF
83136413Ssklower 			{
83236413Ssklower 				register int i;
83336413Ssklower 
83436413Ssklower 				/* keep track of all reasons that apply */
83536413Ssklower 				for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
83636413Ssklower 					if( ack_reason & (1<<i) )
83736413Ssklower 						IncStat( ts_ackreason[i] );
83836413Ssklower 				}
83936413Ssklower 			}
84036413Ssklower 			return 1;
84136413Ssklower 		}
84236413Ssklower 	}
84336413Ssklower }
84450901Ssklower 
84550901Ssklower /*
84650901Ssklower  * tp_rsyflush - drop all the packets on the reassembly queue.
84750901Ssklower  * Do this when closing the socket, or when somebody has changed
84850901Ssklower  * the space avaible in the receive socket (XXX).
84950901Ssklower  */
85050901Ssklower tp_rsyflush(tpcb)
85150901Ssklower register struct tp_pcb *tpcb;
85250901Ssklower {
85350901Ssklower 	register struct mbuf *m, **mp;
85450901Ssklower 	if (tpcb->tp_rsycnt) {
85550901Ssklower 		for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit;
85650901Ssklower 									 --mp >= tpcb->tp_rsyq; )
85750901Ssklower 			if (*mp) {
85850901Ssklower 				tpcb->tp_rsycnt--;
85950901Ssklower 				m_freem(*mp);
86050901Ssklower 			}
86150901Ssklower 		if (tpcb->tp_rsycnt)
86250901Ssklower 			panic("tp_rsyflush");
86350901Ssklower 	}
86450901Ssklower 	free((caddr_t)tpcb->tp_rsyq, M_PCB);
86550901Ssklower 	tpcb->tp_rsyq = 0;
86650901Ssklower }
86750901Ssklower 
86850901Ssklower tp_rsyset(tpcb)
86950901Ssklower register struct tp_pcb *tpcb;
87050901Ssklower {
87150901Ssklower 	register struct socket *so = tpcb->tp_sock;
87250901Ssklower 	int maxcredit  = tpcb->tp_xtd_format ? 0xffff : 0xf;
87350975Ssklower 	int old_credit = tpcb->tp_maxlcredit;
87450975Ssklower 	caddr_t	rsyq;
87550901Ssklower 
87650901Ssklower 	tpcb->tp_maxlcredit = maxcredit = min(maxcredit,
87750901Ssklower 		  (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize);
87850901Ssklower 
87950975Ssklower 	if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0)
88050975Ssklower 		return;
88150901Ssklower 	maxcredit *= sizeof(struct mbuf *);
88250901Ssklower 	if (tpcb->tp_rsyq)
88350901Ssklower 		tp_rsyflush(tpcb);
88450901Ssklower 	if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT))
88550901Ssklower 		bzero(rsyq, maxcredit);
88650901Ssklower 	tpcb->tp_rsyq = (struct mbuf **)rsyq;
88750901Ssklower }
88850901Ssklower 
88950901Ssklower tpsbcheck(tpcb, i)
89050901Ssklower struct tp_pcb *tpcb;
89150901Ssklower {
89250901Ssklower 	register struct mbuf *n, *m;
89350901Ssklower 	register int len = 0, mbcnt = 0, pktlen;
89450901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
89550901Ssklower 
89650901Ssklower 	for (n = sb->sb_mb; n; n = n->m_nextpkt) {
89750901Ssklower 		if ((n->m_flags & M_PKTHDR) == 0)
89850901Ssklower 			panic("tpsbcheck nohdr");
89950901Ssklower 		pktlen = len + n->m_pkthdr.len;
90050901Ssklower 	    for (m = n; m; m = m->m_next) {
90150901Ssklower 			len += m->m_len;
90250901Ssklower 			mbcnt += MSIZE;
90350901Ssklower 			if (m->m_flags & M_EXT)
90450901Ssklower 				mbcnt += m->m_ext.ext_size;
90550901Ssklower 		}
90650901Ssklower 		if (len != pktlen) {
90750901Ssklower 			printf("test %d; len %d != pktlen %d on mbuf 0x%x\n",
90850901Ssklower 				i, len, pktlen, n);
90950901Ssklower 			panic("tpsbcheck short");
91050901Ssklower 		}
91150901Ssklower 	}
91250901Ssklower 	if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
91350901Ssklower 		printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc,
91450901Ssklower 		    mbcnt, sb->sb_mbcnt);
91550901Ssklower 		panic("tpsbcheck");
91650901Ssklower 	}
91750901Ssklower }
918