xref: /csrg-svn/sys/netiso/tp_subr.c (revision 63222)
149268Sbostic /*-
2*63222Sbostic  * Copyright (c) 1991, 1993
3*63222Sbostic  *	The Regents of the University of California.  All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*63222Sbostic  *	@(#)tp_subr.c	8.1 (Berkeley) 06/10/93
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 
5156533Sbostic #include <sys/param.h>
5256533Sbostic #include <sys/systm.h>
5356533Sbostic #include <sys/mbuf.h>
5456533Sbostic #include <sys/socket.h>
5556533Sbostic #include <sys/socketvar.h>
5656533Sbostic #include <sys/protosw.h>
5756533Sbostic #include <sys/errno.h>
5856533Sbostic #include <sys/time.h>
5956533Sbostic #include <sys/kernel.h>
6036413Ssklower 
6156533Sbostic #include <netiso/tp_ip.h>
6256533Sbostic #include <netiso/iso.h>
6356533Sbostic #include <netiso/argo_debug.h>
6456533Sbostic #include <netiso/tp_timer.h>
6556533Sbostic #include <netiso/tp_param.h>
6656533Sbostic #include <netiso/tp_stat.h>
6756533Sbostic #include <netiso/tp_pcb.h>
6856533Sbostic #include <netiso/tp_tpdu.h>
6956533Sbostic #include <netiso/tp_trace.h>
7056533Sbostic #include <netiso/tp_meas.h>
7156533Sbostic #include <netiso/tp_seq.h>
7236413Ssklower 
7351204Ssklower int		tp_emit(), tp_sbdrop();
7451204Ssklower int		tprexmtthresh = 3;
7551341Ssklower 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
tp_goodXack(tpcb,seq)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
tp_rtt_rtv(tpcb)14051204Ssklower tp_rtt_rtv(tpcb)
14151204Ssklower register struct tp_pcb *tpcb;
14236413Ssklower {
14351341Ssklower 	int old = tpcb->tp_rtt;
14451341Ssklower 	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 */);
19251341Ssklower 	IFDEBUG(D_RTT)
19351341Ssklower 		printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n",
19451341Ssklower 			"tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old);
19551341Ssklower 	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
tp_goodack(tpcb,cdt,seq,subseq)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;
26551341Ssklower 				IFDEBUG(D_ACKRECV)
26651341Ssklower 					printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n",
26751341Ssklower 						"goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt);
26851341Ssklower 				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 		 */
32753689Ssklower 		if (tpcb->tp_class != TP_CLASS_0)
32853689Ssklower 			tpcb->tp_timer[TM_data_retrans] =
32953689Ssklower 				(seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur;
33051204Ssklower 		/*
33151204Ssklower 		 * When new data is acked, open the congestion window.
33251204Ssklower 		 * If the window gives us less than ssthresh packets
33351204Ssklower 		 * in flight, open exponentially (maxseg per packet).
33451204Ssklower 		 * Otherwise open linearly: maxseg per window
33551204Ssklower 		 * (maxseg^2 / cwnd per packet), plus a constant
33651204Ssklower 		 * fraction of a packet (maxseg/8) to help larger windows
33751204Ssklower 		 * open quickly enough.
33851204Ssklower 		 */
33951204Ssklower 		{
34051204Ssklower 			u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize;
34136413Ssklower 
34251204Ssklower 			incr = min(incr, bytes_acked);
34351204Ssklower 			if (cw > tpcb->tp_ssthresh)
34451204Ssklower 				incr = incr * incr / cw + incr / 8;
34551204Ssklower 			tpcb->tp_cong_win =
34651204Ssklower 				min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat);
34736413Ssklower 		}
34836413Ssklower 		tpcb->tp_snduna = seq;
34951204Ssklower 		if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) {
35051204Ssklower 				tpcb->tp_sndnxt = seq;
35151204Ssklower 				tpcb->tp_sndnxt_m = 0;
35251204Ssklower 		}
35336413Ssklower 		bang++;
35436413Ssklower 	}
35536413Ssklower 
35636413Ssklower 	if( cdt != 0 && old_fcredit == 0 ) {
35736413Ssklower 		tpcb->tp_sendfcc = 1;
35836413Ssklower 	}
35951249Ssklower 	if (cdt == 0) {
36051249Ssklower 		if (old_fcredit != 0)
36151249Ssklower 			IncStat(ts_zfcdt);
36251249Ssklower 		/* The following might mean that the window shrunk */
36351249Ssklower 		if (tpcb->tp_timer[TM_data_retrans]) {
36451249Ssklower 			tpcb->tp_timer[TM_data_retrans] = 0;
36551249Ssklower 			tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
36651249Ssklower 			if (tpcb->tp_sndnxt != tpcb->tp_snduna) {
36751249Ssklower 				tpcb->tp_sndnxt = tpcb->tp_snduna;
36851249Ssklower 				tpcb->tp_sndnxt_m = 0;
36951249Ssklower 			}
37051249Ssklower 		}
37136413Ssklower 	}
37236413Ssklower 	tpcb->tp_fcredit = cdt;
37351204Ssklower 	bang |= (old_fcredit < cdt);
37436413Ssklower 
37551204Ssklower done:
37636413Ssklower 	IFDEBUG(D_ACKRECV)
37751204Ssklower 		printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n",
37851204Ssklower 			bang, cdt, old_fcredit, tpcb->tp_cong_win);
37936413Ssklower 	ENDDEBUG
38051204Ssklower 	/* if (bang) XXXXX Very bad to remove this test, but somethings broken */
38151204Ssklower 		tp_send(tpcb);
38251204Ssklower 	return (bang);
38336413Ssklower }
38436413Ssklower 
38536413Ssklower /*
38636413Ssklower  * CALLED FROM:
38736413Ssklower  *  tp_goodack()
38836413Ssklower  * FUNCTION and ARGUMENTS:
38950901Ssklower  *  drops everything up TO but not INCLUDING seq # (seq)
39036413Ssklower  *  from the retransmission queue.
39136413Ssklower  */
tp_sbdrop(tpcb,seq)39236413Ssklower tp_sbdrop(tpcb, seq)
39350901Ssklower 	register struct 	tp_pcb 			*tpcb;
39436413Ssklower 	SeqNum					seq;
39536413Ssklower {
39650901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
39751204Ssklower 	register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna);
39851204Ssklower 	int	oldcc = sb->sb_cc, oldi = i;
39936413Ssklower 
40051204Ssklower 	if (i >= tpcb->tp_seqhalf)
40151204Ssklower 		printf("tp_spdropping too much -- should panic");
40251204Ssklower 	while (i-- > 0)
40351204Ssklower 		sbdroprecord(sb);
40436413Ssklower 	IFDEBUG(D_ACKRECV)
40551204Ssklower 		printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n",
40651204Ssklower 			oldi, oldcc - sb->sb_cc, tpcb, seq);
40736413Ssklower 	ENDDEBUG
40851204Ssklower 	if (sb->sb_flags & SB_NOTIFY)
40951204Ssklower 		sowwakeup(tpcb->tp_sock);
41051138Ssklower 	return (oldcc - sb->sb_cc);
41136413Ssklower }
41236413Ssklower 
41336413Ssklower /*
41436413Ssklower  * CALLED FROM:
41536413Ssklower  * 	tp.trans on user send request, arrival of AK and arrival of XAK
41636413Ssklower  * FUNCTION and ARGUMENTS:
41751204Ssklower  * 	Emits tpdus starting at sequence number (tpcb->tp_sndnxt).
41836413Ssklower  * 	Emits until a) runs out of data, or  b) runs into an XPD mark, or
41951204Ssklower  * 			c) it hits seq number (highseq) limited by cong or credit.
42036413Ssklower  *
42136413Ssklower  * 	If you want XPD to buffer > 1 du per socket buffer, you can
42236413Ssklower  * 	modifiy this to issue XPD tpdus also, but then it'll have
42336413Ssklower  * 	to take some argument(s) to distinguish between the type of DU to
42450901Ssklower  * 	hand tp_emit.
42536413Ssklower  *
42636413Ssklower  * 	When something is sent for the first time, its time-of-send
42751204Ssklower  * 	is stashed (in system clock ticks rather than pf_slowtimo ticks).
42851204Ssklower  *  When the ack arrives, the smoothed round-trip time is figured
42951204Ssklower  *  using this value.
43036413Ssklower  */
43151204Ssklower void
tp_send(tpcb)43236413Ssklower tp_send(tpcb)
43336413Ssklower 	register struct tp_pcb	*tpcb;
43436413Ssklower {
43536413Ssklower 	register int			len;
43651204Ssklower 	register struct mbuf	*m;
43751204Ssklower 	struct mbuf				*mb = 0;
43836413Ssklower 	struct 	sockbuf			*sb = &tpcb->tp_sock->so_snd;
43951204Ssklower 	unsigned int			eotsdu = 0;
44051204Ssklower 	SeqNum					highseq, checkseq;
44151204Ssklower 	int						idle, idleticks, off, cong_win;
44236413Ssklower #ifdef TP_PERF_MEAS
44351341Ssklower 	int			 			send_start_time = ticks;
44451204Ssklower 	SeqNum					oldnxt = tpcb->tp_sndnxt;
44560359Sbostic #endif /* TP_PERF_MEAS */
44636413Ssklower 
44751204Ssklower 	idle = (tpcb->tp_snduna == tpcb->tp_sndnew);
44851204Ssklower 	if (idle) {
44951204Ssklower 		idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact];
45051204Ssklower 		if (idleticks > tpcb->tp_dt_ticks)
45151204Ssklower 			/*
45251204Ssklower 			 * We have been idle for "a while" and no acks are
45351204Ssklower 			 * expected to clock out any data we send --
45451204Ssklower 			 * slow start to get ack "clock" running again.
45551204Ssklower 			 */
45651204Ssklower 			tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
45751204Ssklower 	}
45836413Ssklower 
45951204Ssklower 	cong_win = tpcb->tp_cong_win;
46051204Ssklower 	highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna);
46151204Ssklower 	if (tpcb->tp_Xsnd.sb_mb)
46251204Ssklower 		highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew);
46336413Ssklower 
46436413Ssklower 	IFDEBUG(D_DATA)
46551204Ssklower 		printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n",
46651204Ssklower 				tpcb, tpcb->tp_sndnxt, cong_win, highseq);
46736413Ssklower 	ENDDEBUG
46836413Ssklower 	IFTRACE(D_DATA)
46951204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send sndnew snduna",
47051204Ssklower 			tpcb->tp_sndnew,  tpcb->tp_snduna, 0, 0);
47151204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin",
47251204Ssklower 			tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win);
47336413Ssklower 	ENDTRACE
47436413Ssklower 	IFTRACE(D_DATA)
47551204Ssklower 		tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin",
47651204Ssklower 			tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win);
47736413Ssklower 	ENDTRACE
47836413Ssklower 
47951204Ssklower 	if (tpcb->tp_sndnxt_m)
48051204Ssklower 		m = tpcb->tp_sndnxt_m;
48151204Ssklower 	else {
48251204Ssklower 		off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna);
48351204Ssklower 		for (m = sb->sb_mb; m && off > 0; m = m->m_next)
48451204Ssklower 			off--;
48551204Ssklower 	}
48651204Ssklower send:
48751204Ssklower 	/*
48851204Ssklower 	 * Avoid silly window syndrome here . . . figure out how!
48951204Ssklower 	 */
49051204Ssklower 	checkseq = tpcb->tp_sndnum;
49151204Ssklower 	if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq))
49251249Ssklower 		checkseq = highseq; /* i.e. DON'T retain highest assigned packet */
49336413Ssklower 
49451204Ssklower 	while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) {
49536413Ssklower 
49651204Ssklower 		eotsdu = (m->m_flags & M_EOR) != 0;
49751204Ssklower 		len = m->m_pkthdr.len;
49851204Ssklower 		if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 &&
49951204Ssklower 			len < (tpcb->tp_l_tpdusize / 2))
50051204Ssklower 				break;  /* Nagle . . . . . */
50151204Ssklower 		cong_win -= len;
50236413Ssklower 		/* make a copy - mb goes into the retransmission list
50336413Ssklower 		 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
50436413Ssklower 		 */
50551204Ssklower 		mb = m;
50650901Ssklower 		m = m_copy(mb, 0, M_COPYALL);
50750901Ssklower 		if (m == MNULL)
50851204Ssklower 				break;
50951204Ssklower 		IFTRACE(D_STASH)
51036413Ssklower 			tptraceTPCB( TPPTmisc,
51151204Ssklower 				"tp_send mcopy nxt high eotsdu len",
51251204Ssklower 				tpcb->tp_sndnxt, highseq, eotsdu, len);
51336413Ssklower 		ENDTRACE
51451204Ssklower 
51551204Ssklower 		IFDEBUG(D_DATA)
51651204Ssklower 			printf("tp_sending tpcb 0x%x nxt 0x%x\n",
51751204Ssklower 				tpcb, tpcb->tp_sndnxt);
51851204Ssklower 		ENDDEBUG
51951204Ssklower 		/* when headers are precomputed, may need to fill
52050901Ssklower 			   in checksum here */
52150901Ssklower 		if (tpcb->tp_sock->so_error =
52251204Ssklower 			tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) {
52336413Ssklower 			/* error */
52451204Ssklower 			break;
52536413Ssklower 		}
52651204Ssklower 		m = mb->m_nextpkt;
52751204Ssklower 		tpcb->tp_sndnxt_m = m;
52851204Ssklower 		if (tpcb->tp_sndnxt == tpcb->tp_sndnew) {
52951204Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnew);
53051204Ssklower 			/*
53151204Ssklower 			 * Time this transmission if not a retransmission and
53251204Ssklower 			 * not currently timing anything.
53351204Ssklower 			 */
53451204Ssklower 			if (tpcb->tp_rttemit == 0) {
53551341Ssklower 				tpcb->tp_rttemit = ticks;
53651204Ssklower 				tpcb->tp_rttseq = tpcb->tp_sndnxt;
53751204Ssklower 			}
53851204Ssklower 			tpcb->tp_sndnxt = tpcb->tp_sndnew;
53951204Ssklower 		} else
54051204Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnxt);
54151204Ssklower 		/*
54251204Ssklower 		 * Set retransmit timer if not currently set.
54351204Ssklower 		 * Initial value for retransmit timer is smoothed
54451204Ssklower 		 * round-trip time + 2 * round-trip time variance.
54551204Ssklower 		 * Initialize shift counter which is used for backoff
54651204Ssklower 		 * of retransmit time.
54751204Ssklower 		 */
54853689Ssklower 		if (tpcb->tp_timer[TM_data_retrans] == 0 &&
54953689Ssklower 			tpcb->tp_class != TP_CLASS_0) {
55051204Ssklower 			tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks;
55151204Ssklower 			tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks;
55251204Ssklower 			tpcb->tp_rxtshift = 0;
55351138Ssklower 		}
55436413Ssklower 	}
55551204Ssklower 	if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum))
55651204Ssklower 		tpcb->tp_oktonagle = 0;
55750236Ssklower #ifdef TP_PERF_MEAS
55836413Ssklower 	IFPERF(tpcb)
55936413Ssklower 		{
56036413Ssklower 			register int npkts;
56151341Ssklower 			int	 elapsed = ticks - send_start_time, *t;
56251138Ssklower 			struct timeval now;
56336413Ssklower 
56451204Ssklower 			npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt);
56536413Ssklower 
56651204Ssklower 			if (npkts > 0)
56736413Ssklower 				tpcb->tp_Nwindow++;
56836413Ssklower 
56936413Ssklower 			if (npkts > TP_PM_MAX)
57036413Ssklower 				npkts = TP_PM_MAX;
57136413Ssklower 
57236413Ssklower 			t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
57351138Ssklower 			*t += (t - elapsed) >> TP_RTT_ALPHA;
57436413Ssklower 
57551204Ssklower 			if (mb == 0) {
57636413Ssklower 				IncPStat(tpcb, tps_win_lim_by_data[npkts] );
57736413Ssklower 			} else {
57836413Ssklower 				IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
57936413Ssklower 				/* not true with congestion-window being used */
58036413Ssklower 			}
58151138Ssklower 			now.tv_sec = elapsed / hz;
58251138Ssklower 			now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz;
58336413Ssklower 			tpmeas( tpcb->tp_lref,
58451204Ssklower 					TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts);
58536413Ssklower 		}
58636413Ssklower 	ENDPERF
58760359Sbostic #endif /* TP_PERF_MEAS */
58836413Ssklower 
58936413Ssklower 
59036413Ssklower 	IFTRACE(D_DATA)
59136413Ssklower 		tptraceTPCB( TPPTmisc,
59251204Ssklower 			"tp_send at end: new nxt eotsdu error",
59351204Ssklower 			tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error);
59436413Ssklower 
59536413Ssklower 	ENDTRACE
59636413Ssklower }
59736413Ssklower 
59850901Ssklower int TPNagleok;
59950901Ssklower int TPNagled;
60050901Ssklower 
tp_packetize(tpcb,m,eotsdu)60150901Ssklower tp_packetize(tpcb, m, eotsdu)
60250901Ssklower register struct tp_pcb *tpcb;
60350901Ssklower register struct mbuf *m;
60450901Ssklower int eotsdu;
60550901Ssklower {
60650901Ssklower 	register struct mbuf *n;
60750901Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_snd;
60850901Ssklower 	int	maxsize = tpcb->tp_l_tpdusize
60950901Ssklower 			- tp_headersize(DT_TPDU_type, tpcb)
61050901Ssklower 			- (tpcb->tp_use_checksum?4:0) ;
61150901Ssklower 	int totlen = m->m_pkthdr.len;
61250901Ssklower 	struct mbuf *m_split();
61350901Ssklower 	/*
61450901Ssklower 	 * Pre-packetize the data in the sockbuf
61550901Ssklower 	 * according to negotiated mtu.  Do it here
61650901Ssklower 	 * where we can safely wait for mbufs.
61750901Ssklower 	 *
61850901Ssklower 	 * This presumes knowledge of sockbuf conventions.
61950901Ssklower 	 * TODO: allocate space for header and fill it in (once!).
62050901Ssklower 	 */
62151204Ssklower 	IFDEBUG(D_DATA)
62251204Ssklower 		printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n",
62351204Ssklower 			maxsize, totlen, eotsdu, tpcb->tp_sndnum);
62450901Ssklower 	ENDTRACE
62550901Ssklower 	if (tpcb->tp_oktonagle) {
62650901Ssklower 		if ((n = sb->sb_mb) == 0)
62750901Ssklower 			panic("tp_packetize");
62850901Ssklower 		while (n->m_act)
62950901Ssklower 			n = n->m_act;
63050901Ssklower 		if (n->m_flags & M_EOR)
63150901Ssklower 			panic("tp_packetize 2");
63250901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
63350901Ssklower 		if (totlen + n->m_pkthdr.len < maxsize) {
63450901Ssklower 			/* There is an unsent packet with space, combine data */
63550901Ssklower 			struct mbuf *old_n = n;
63650901Ssklower 			tpsbcheck(tpcb,3);
63750901Ssklower 			n->m_pkthdr.len += totlen;
63850901Ssklower 			while (n->m_next)
63950901Ssklower 				n = n->m_next;
64050901Ssklower 			sbcompress(sb, m, n);
64150901Ssklower 			tpsbcheck(tpcb,4);
64250901Ssklower 			n = old_n;
64350901Ssklower 			TPNagled++;
64450901Ssklower 			goto out;
64550901Ssklower 		}
64650901Ssklower 	}
64750901Ssklower 	while (m) {
64850901Ssklower 		n = m;
64950901Ssklower 		if (totlen > maxsize) {
65050901Ssklower 			if ((m = m_split(n, maxsize, M_WAIT)) == 0)
65150901Ssklower 				panic("tp_packetize");
65250901Ssklower 		} else
65350901Ssklower 			m = 0;
65450901Ssklower 		totlen -= maxsize;
65550901Ssklower 		tpsbcheck(tpcb, 5);
65650901Ssklower 		sbappendrecord(sb, n);
65750901Ssklower 		tpsbcheck(tpcb, 6);
65850901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
65950901Ssklower 	}
66050901Ssklower out:
66150901Ssklower 	if (eotsdu) {
66250901Ssklower 		n->m_flags |= M_EOR;  /* XXX belongs at end */
66350901Ssklower 		tpcb->tp_oktonagle = 0;
66450901Ssklower 	} else {
66550901Ssklower 		SEQ_DEC(tpcb, tpcb->tp_sndnum);
66650901Ssklower 		tpcb->tp_oktonagle = 1;
66750901Ssklower 		TPNagleok++;
66850901Ssklower 	}
66951204Ssklower 	IFDEBUG(D_DATA)
67051204Ssklower 		printf("SEND out: oktonagle %d sndnum 0x%x\n",
67151204Ssklower 			tpcb->tp_oktonagle, tpcb->tp_sndnum);
67251204Ssklower 	ENDTRACE
67350901Ssklower 	return 0;
67450901Ssklower }
67550901Ssklower 
67650901Ssklower 
67736413Ssklower /*
67836413Ssklower  * NAME: tp_stash()
67936413Ssklower  * CALLED FROM:
68036413Ssklower  *	tp.trans on arrival of a DT tpdu
68136413Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
68236413Ssklower  * 	Returns 1 if
68336413Ssklower  *		a) something new arrived and it's got eotsdu_reached bit on,
68436413Ssklower  * 		b) this arrival was caused other out-of-sequence things to be
68536413Ssklower  *    	accepted, or
68636413Ssklower  * 		c) this arrival is the highest seq # for which we last gave credit
68736413Ssklower  *   	(sender just sent a whole window)
68836413Ssklower  *  In other words, returns 1 if tp should send an ack immediately, 0 if
68936413Ssklower  *  the ack can wait a while.
69036413Ssklower  *
69136413Ssklower  * Note: this implementation no longer renegs on credit, (except
69236413Ssklower  * when debugging option D_RENEG is on, for the purpose of testing
69336413Ssklower  * ack subsequencing), so we don't  need to check for incoming tpdus
69436413Ssklower  * being in a reneged portion of the window.
69536413Ssklower  */
69636413Ssklower 
tp_stash(tpcb,e)69751204Ssklower tp_stash(tpcb, e)
69836413Ssklower 	register struct tp_pcb		*tpcb;
69936413Ssklower 	register struct tp_event	*e;
70036413Ssklower {
70136413Ssklower 	register int		ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
70236413Ssklower 									/* 0--> delay acks until full window */
70336413Ssklower 									/* 1--> ack each tpdu */
70436413Ssklower #ifndef lint
70536413Ssklower #define E e->ATTR(DT_TPDU)
70660359Sbostic #else /* lint */
70736413Ssklower #define E e->ev_union.EV_DT_TPDU
70860359Sbostic #endif /* lint */
70936413Ssklower 
71036413Ssklower 	if ( E.e_eot ) {
71136413Ssklower 		register struct mbuf *n = E.e_data;
71237469Ssklower 		n->m_flags |= M_EOR;
71338841Ssklower 		n->m_act = 0;
71437469Ssklower 	}
71536413Ssklower 		IFDEBUG(D_STASH)
71636413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
71736413Ssklower 				"stash: so_rcv before appending");
71836413Ssklower 			dump_mbuf(E.e_data,
71936413Ssklower 				"stash: e_data before appending");
72036413Ssklower 		ENDDEBUG
72136413Ssklower 
72236413Ssklower 	IFPERF(tpcb)
72336413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
72436413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
72537469Ssklower 			E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
72636413Ssklower 	ENDPERF
72736413Ssklower 
72851024Ssklower 	if (E.e_seq == tpcb->tp_rcvnxt) {
72936413Ssklower 
73036413Ssklower 		IFDEBUG(D_STASH)
73136413Ssklower 			printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
73236413Ssklower 			E.e_seq, E.e_datalen, E.e_eot);
73336413Ssklower 		ENDDEBUG
73436413Ssklower 
73536413Ssklower 		IFTRACE(D_STASH)
73636413Ssklower 			tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
73736413Ssklower 			E.e_seq, E.e_datalen, E.e_eot, 0);
73836413Ssklower 		ENDTRACE
73936413Ssklower 
74051024Ssklower 		SET_DELACK(tpcb);
74151024Ssklower 
74237469Ssklower 		sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
74337469Ssklower 
74436413Ssklower 		SEQ_INC( tpcb, tpcb->tp_rcvnxt );
74536413Ssklower 		/*
74650901Ssklower 		 * move chains from the reassembly queue to the socket buffer
74736413Ssklower 		 */
74850901Ssklower 		if (tpcb->tp_rsycnt) {
74950901Ssklower 			register struct mbuf **mp;
75050901Ssklower 			struct mbuf **mplim;
75136413Ssklower 
75250901Ssklower 			mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit);
75350901Ssklower 			mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit;
75436413Ssklower 
75550901Ssklower 			while (tpcb->tp_rsycnt && *mp) {
75650901Ssklower 				sbappend(&tpcb->tp_sock->so_rcv, *mp);
75750901Ssklower 				tpcb->tp_rsycnt--;
75850901Ssklower 				*mp = 0;
75950901Ssklower 				SEQ_INC(tpcb, tpcb->tp_rcvnxt);
76036413Ssklower 				ack_reason |= ACK_REORDER;
76150901Ssklower 				if (++mp == mplim)
76250901Ssklower 					mp = tpcb->tp_rsyq;
76336413Ssklower 			}
76436413Ssklower 		}
76536413Ssklower 		IFDEBUG(D_STASH)
76636413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
76736413Ssklower 				"stash: so_rcv after appending");
76836413Ssklower 		ENDDEBUG
76936413Ssklower 
77036413Ssklower 	} else {
77150901Ssklower 		register struct mbuf **mp;
77250901Ssklower 		SeqNum uwe;
77336413Ssklower 
77436413Ssklower 		IFTRACE(D_STASH)
77536413Ssklower 			tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
77636413Ssklower 			E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
77736413Ssklower 		ENDTRACE
77836413Ssklower 
77950975Ssklower 		if (tpcb->tp_rsyq == 0)
78050975Ssklower 			tp_rsyset(tpcb);
78150901Ssklower 		uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit);
78250901Ssklower 		if (tpcb->tp_rsyq == 0 ||
78350901Ssklower 						!IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) {
78436413Ssklower 			ack_reason = ACK_DONT;
78550901Ssklower 			m_freem(E.e_data);
78650901Ssklower 		} else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) {
78736413Ssklower 			IFDEBUG(D_STASH)
78836413Ssklower 				printf("tp_stash - drop & ack\n");
78936413Ssklower 			ENDDEBUG
79036413Ssklower 
79136413Ssklower 			/* retransmission - drop it and force an ack */
79236413Ssklower 			IncStat(ts_dt_dup);
79336413Ssklower 			IFPERF(tpcb)
79436413Ssklower 				IncPStat(tpcb, tps_n_ack_cuz_dup);
79536413Ssklower 			ENDPERF
79636413Ssklower 
79750901Ssklower 			m_freem(E.e_data);
79836413Ssklower 			ack_reason |= ACK_DUP;
79950901Ssklower 		} else {
80050901Ssklower 			*mp = E.e_data;
80150901Ssklower 			tpcb->tp_rsycnt++;
80250901Ssklower 			ack_reason = ACK_DONT;
80336413Ssklower 		}
80436413Ssklower 	}
80551024Ssklower 	/* there were some comments of historical interest here. */
80636413Ssklower 	{
80736413Ssklower 		LOCAL_CREDIT(tpcb);
80836413Ssklower 
80936413Ssklower 		if ( E.e_seq ==  tpcb->tp_sent_uwe )
81036413Ssklower 			ack_reason |= ACK_STRAT_FULLWIN;
81136413Ssklower 
81236413Ssklower 		IFTRACE(D_STASH)
81336413Ssklower 			tptraceTPCB(TPPTmisc,
81436413Ssklower 				"end of stash, eot, ack_reason, sent_uwe ",
81536413Ssklower 				E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
81636413Ssklower 		ENDTRACE
81736413Ssklower 
81836413Ssklower 		if ( ack_reason == ACK_DONT ) {
81936413Ssklower 			IncStat( ts_ackreason[ACK_DONT] );
82036413Ssklower 			return 0;
82136413Ssklower 		} else {
82236413Ssklower 			IFPERF(tpcb)
82336413Ssklower 				if(ack_reason & ACK_STRAT_EACH) {
82436413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_strat);
82536413Ssklower 				} else if(ack_reason & ACK_STRAT_FULLWIN) {
82636413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_fullwin);
82736413Ssklower 				} else if(ack_reason & ACK_REORDER) {
82836413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_reorder);
82936413Ssklower 				}
83036413Ssklower 				tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
83136413Ssklower 							SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
83236413Ssklower 			ENDPERF
83336413Ssklower 			{
83436413Ssklower 				register int i;
83536413Ssklower 
83636413Ssklower 				/* keep track of all reasons that apply */
83736413Ssklower 				for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
83836413Ssklower 					if( ack_reason & (1<<i) )
83936413Ssklower 						IncStat( ts_ackreason[i] );
84036413Ssklower 				}
84136413Ssklower 			}
84236413Ssklower 			return 1;
84336413Ssklower 		}
84436413Ssklower 	}
84536413Ssklower }
84650901Ssklower 
84750901Ssklower /*
84850901Ssklower  * tp_rsyflush - drop all the packets on the reassembly queue.
84950901Ssklower  * Do this when closing the socket, or when somebody has changed
85050901Ssklower  * the space avaible in the receive socket (XXX).
85150901Ssklower  */
tp_rsyflush(tpcb)85250901Ssklower tp_rsyflush(tpcb)
85350901Ssklower register struct tp_pcb *tpcb;
85450901Ssklower {
85550901Ssklower 	register struct mbuf *m, **mp;
85650901Ssklower 	if (tpcb->tp_rsycnt) {
85750901Ssklower 		for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit;
85850901Ssklower 									 --mp >= tpcb->tp_rsyq; )
85950901Ssklower 			if (*mp) {
86050901Ssklower 				tpcb->tp_rsycnt--;
86150901Ssklower 				m_freem(*mp);
86250901Ssklower 			}
86353689Ssklower 		if (tpcb->tp_rsycnt) {
86453689Ssklower 			printf("tp_rsyflush %x\n", tpcb);
86553689Ssklower 			tpcb->tp_rsycnt = 0;
86653689Ssklower 		}
86750901Ssklower 	}
86850901Ssklower 	free((caddr_t)tpcb->tp_rsyq, M_PCB);
86950901Ssklower 	tpcb->tp_rsyq = 0;
87050901Ssklower }
87150901Ssklower 
tp_rsyset(tpcb)87250901Ssklower tp_rsyset(tpcb)
87350901Ssklower register struct tp_pcb *tpcb;
87450901Ssklower {
87550901Ssklower 	register struct socket *so = tpcb->tp_sock;
87650901Ssklower 	int maxcredit  = tpcb->tp_xtd_format ? 0xffff : 0xf;
87750975Ssklower 	int old_credit = tpcb->tp_maxlcredit;
87850975Ssklower 	caddr_t	rsyq;
87950901Ssklower 
88050901Ssklower 	tpcb->tp_maxlcredit = maxcredit = min(maxcredit,
88150901Ssklower 		  (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize);
88250901Ssklower 
88350975Ssklower 	if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0)
88450975Ssklower 		return;
88550901Ssklower 	maxcredit *= sizeof(struct mbuf *);
88650901Ssklower 	if (tpcb->tp_rsyq)
88750901Ssklower 		tp_rsyflush(tpcb);
88850901Ssklower 	if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT))
88950901Ssklower 		bzero(rsyq, maxcredit);
89050901Ssklower 	tpcb->tp_rsyq = (struct mbuf **)rsyq;
89150901Ssklower }
89250901Ssklower 
89350901Ssklower tpsbcheck(tpcb, i)
89450901Ssklower struct tp_pcb *tpcb;
89550901Ssklower {
89650901Ssklower 	register struct mbuf *n, *m;
89750901Ssklower 	register int len = 0, mbcnt = 0, pktlen;
89850901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
89950901Ssklower 
90050901Ssklower 	for (n = sb->sb_mb; n; n = n->m_nextpkt) {
90150901Ssklower 		if ((n->m_flags & M_PKTHDR) == 0)
90250901Ssklower 			panic("tpsbcheck nohdr");
90350901Ssklower 		pktlen = len + n->m_pkthdr.len;
90450901Ssklower 	    for (m = n; m; m = m->m_next) {
90550901Ssklower 			len += m->m_len;
90650901Ssklower 			mbcnt += MSIZE;
90750901Ssklower 			if (m->m_flags & M_EXT)
90850901Ssklower 				mbcnt += m->m_ext.ext_size;
90950901Ssklower 		}
91050901Ssklower 		if (len != pktlen) {
91150901Ssklower 			printf("test %d; len %d != pktlen %d on mbuf 0x%x\n",
91250901Ssklower 				i, len, pktlen, n);
91350901Ssklower 			panic("tpsbcheck short");
91450901Ssklower 		}
91550901Ssklower 	}
91650901Ssklower 	if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
91750901Ssklower 		printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc,
91850901Ssklower 		    mbcnt, sb->sb_mbcnt);
91950901Ssklower 		panic("tpsbcheck");
92050901Ssklower 	}
92150901Ssklower }
922