xref: /csrg-svn/sys/netiso/tp_subr.c (revision 51024)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51024Ssklower  *	@(#)tp_subr.c	7.13 (Berkeley) 09/06/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"
5936413Ssklower 
6037469Ssklower #include "tp_ip.h"
6137469Ssklower #include "iso.h"
6237469Ssklower #include "argo_debug.h"
6337469Ssklower #include "tp_timer.h"
6437469Ssklower #include "tp_param.h"
6537469Ssklower #include "tp_stat.h"
6637469Ssklower #include "tp_pcb.h"
6737469Ssklower #include "tp_tpdu.h"
6837469Ssklower #include "tp_trace.h"
6937469Ssklower #include "tp_meas.h"
7037469Ssklower #include "tp_seq.h"
7136413Ssklower 
7236413Ssklower int 		tp_emit();
7336413Ssklower static void tp_sbdrop();
7436413Ssklower 
7536413Ssklower #define SMOOTH(newtype, alpha, old, new) \
7636413Ssklower 	(newtype) (((new - old)>>alpha) + (old))
7736413Ssklower 
7836413Ssklower #define ABS(type, val) \
7936413Ssklower 	(type) (((int)(val)<0)?-(val):(val))
8036413Ssklower 
8136413Ssklower 
8236413Ssklower /*
8336413Ssklower  * CALLED FROM:
8436413Ssklower  *	tp.trans, when an XAK arrives
8536413Ssklower  * FUNCTION and ARGUMENTS:
8636413Ssklower  * 	Determines if the sequence number (seq) from the XAK
8736413Ssklower  * 	acks anything new.  If so, drop the appropriate tpdu
8836413Ssklower  * 	from the XPD send queue.
8936413Ssklower  * RETURN VALUE:
9036413Ssklower  * 	Returns 1 if it did this, 0 if the ack caused no action.
9136413Ssklower  */
9236413Ssklower int
9336413Ssklower tp_goodXack(tpcb, seq)
9436413Ssklower 	struct tp_pcb	*tpcb;
9536413Ssklower 	SeqNum 			seq;
9636413Ssklower {
9736413Ssklower 
9836413Ssklower 	IFTRACE(D_XPD)
9936413Ssklower 		tptraceTPCB(TPPTgotXack,
10036413Ssklower 			seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat,
10136413Ssklower 			tpcb->tp_snduna);
10236413Ssklower 	ENDTRACE
10336413Ssklower 
10436413Ssklower 	if ( seq == tpcb->tp_Xuna ) {
10536413Ssklower 			tpcb->tp_Xuna = tpcb->tp_Xsndnxt;
10636413Ssklower 
10736413Ssklower 			/* DROP 1 packet from the Xsnd socket buf - just so happens
10836413Ssklower 			 * that only one packet can be there at any time
10936413Ssklower 			 * so drop the whole thing.  If you allow > 1 packet
11036413Ssklower 			 * the socket buffer, then you'll have to keep
11136413Ssklower 			 * track of how many characters went w/ each XPD tpdu, so this
11236413Ssklower 			 * will get messier
11336413Ssklower 			 */
11436413Ssklower 			IFDEBUG(D_XPD)
11536413Ssklower 				dump_mbuf(tpcb->tp_Xsnd.sb_mb,
11636413Ssklower 					"tp_goodXack Xsnd before sbdrop");
11736413Ssklower 			ENDDEBUG
11836413Ssklower 
11936413Ssklower 			IFTRACE(D_XPD)
12036413Ssklower 				tptraceTPCB(TPPTmisc,
12136413Ssklower 					"goodXack: dropping cc ",
12236413Ssklower 					(int)(tpcb->tp_Xsnd.sb_cc),
12336413Ssklower 					0,0,0);
12436413Ssklower 			ENDTRACE
12536413Ssklower 			sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc));
12639922Ssklower 			CONG_ACK(tpcb, seq);
12736413Ssklower 			return 1;
12836413Ssklower 	}
12936413Ssklower 	return 0;
13036413Ssklower }
13136413Ssklower 
13236413Ssklower /*
13336413Ssklower  * CALLED FROM:
13436413Ssklower  *  tp_good_ack()
13536413Ssklower  * FUNCTION and ARGUMENTS:
13636413Ssklower  *  updates
13736413Ssklower  *  smoothed average round trip time (base_rtt)
13836413Ssklower  *  roundtrip time variance (base_rtv) - actually deviation, not variance
13936413Ssklower  *  given the new value (diff)
14036413Ssklower  * RETURN VALUE:
14136413Ssklower  * void
14236413Ssklower  */
14336413Ssklower 
14436413Ssklower void
14536413Ssklower tp_rtt_rtv( base_rtt, base_rtv, newmeas )
14636413Ssklower 	struct 	timeval *base_rtt, *base_rtv, *newmeas;
14736413Ssklower {
14836413Ssklower 	/* update  rt variance (really just the deviation):
14936413Ssklower 	 * 	rtv.smooth_ave =  SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | )
15036413Ssklower 	 */
15136413Ssklower 	base_rtv->tv_sec =
15236413Ssklower 		SMOOTH( long,  TP_RTV_ALPHA, base_rtv->tv_sec,
15344948Ssklower 			ABS( long, base_rtt->tv_sec - newmeas->tv_sec ));
15436413Ssklower 	base_rtv->tv_usec =
15536413Ssklower 		SMOOTH( long,  TP_RTV_ALPHA, base_rtv->tv_usec,
15644948Ssklower 			ABS(long, base_rtt->tv_usec - newmeas->tv_usec ));
15736413Ssklower 
15836413Ssklower 	/* update smoothed average rtt */
15936413Ssklower 	base_rtt->tv_sec =
16036413Ssklower 		SMOOTH( long,  TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec);
16136413Ssklower 	base_rtt->tv_usec =
16236413Ssklower 		SMOOTH( long,  TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec);
16336413Ssklower 
16436413Ssklower }
16536413Ssklower 
16636413Ssklower /*
16736413Ssklower  * CALLED FROM:
16836413Ssklower  *  tp.trans when an AK arrives
16936413Ssklower  * FUNCTION and ARGUMENTS:
17036413Ssklower  * 	Given (cdt), the credit from the AK tpdu, and
17136413Ssklower  *	(seq), the sequence number from the AK tpdu,
17236413Ssklower  *  tp_goodack() determines if the AK acknowledges something in the send
17336413Ssklower  * 	window, and if so, drops the appropriate packets from the retransmission
17436413Ssklower  *  list, computes the round trip time, and updates the retransmission timer
17536413Ssklower  *  based on the new smoothed round trip time.
17636413Ssklower  * RETURN VALUE:
17736413Ssklower  * 	Returns 1 if
17836413Ssklower  * 	EITHER it actually acked something heretofore unacknowledged
17936413Ssklower  * 	OR no news but the credit should be processed.
18036413Ssklower  * 	If something heretofore unacked was acked with this sequence number,
18136413Ssklower  * 	the appropriate tpdus are dropped from the retransmission control list,
18236413Ssklower  * 	by calling tp_sbdrop().
18336413Ssklower  * 	No need to see the tpdu itself.
18436413Ssklower  */
18536413Ssklower int
18636413Ssklower tp_goodack(tpcb, cdt, seq, subseq)
18736413Ssklower 	register struct tp_pcb	*tpcb;
18836413Ssklower 	u_int					cdt;
18936413Ssklower 	register SeqNum			seq, subseq;
19036413Ssklower {
19136413Ssklower 	int 	old_fcredit = tpcb->tp_fcredit;
19236413Ssklower 	int 	bang = 0; 	/* bang --> ack for something heretofore unacked */
19336413Ssklower 
19436413Ssklower 	IFDEBUG(D_ACKRECV)
19536413Ssklower 		printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n",
19636413Ssklower 			seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat);
19736413Ssklower 	ENDDEBUG
19836413Ssklower 	IFTRACE(D_ACKRECV)
19936413Ssklower 		tptraceTPCB(TPPTgotack,
20036413Ssklower 			seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq);
20136413Ssklower 	ENDTRACE
20236413Ssklower 
20336413Ssklower 	IFPERF(tpcb)
20437469Ssklower 		tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0);
20536413Ssklower 	ENDPERF
20636413Ssklower 
20736413Ssklower 	if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) {
20836413Ssklower 		/* discard the ack */
20936413Ssklower 		IFTRACE(D_ACKRECV)
21036413Ssklower 			tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq",
21136413Ssklower 				subseq, tpcb->tp_r_subseq, 0, 0);
21236413Ssklower 		ENDTRACE
21336413Ssklower 		return 0;
21436413Ssklower 	} else {
21536413Ssklower 		tpcb->tp_r_subseq = subseq;
21636413Ssklower 	}
21736413Ssklower 
21836413Ssklower 	if ( IN_SWINDOW(tpcb, seq,
21936413Ssklower 			tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) {
22036413Ssklower 
22136413Ssklower 		IFDEBUG(D_XPD)
22236413Ssklower 			dump_mbuf(tpcb->tp_sock->so_snd.sb_mb,
22336413Ssklower 				"tp_goodack snd before sbdrop");
22436413Ssklower 		ENDDEBUG
22550901Ssklower 		tpsbcheck(tpcb, 0);
22650901Ssklower 		tp_sbdrop(tpcb, seq);
22750901Ssklower 		tpsbcheck(tpcb, 1);
22836413Ssklower 
22936413Ssklower 		/* increase congestion window but don't let it get too big */
23036413Ssklower 		{
23136413Ssklower 			register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf;
23239922Ssklower 			CONG_ACK(tpcb, seq);
23336413Ssklower 		}
23436413Ssklower 
23536413Ssklower 		/* Compute smoothed round trip time.
23636413Ssklower 		 * Only measure rtt for tp_snduna if tp_snduna was among
23739922Ssklower 		 * the last TP_RTT_NUM seq numbers sent, and if the data
23839922Ssklower 		 * were not retransmitted.
23936413Ssklower 		 */
24036413Ssklower 		if (SEQ_GEQ(tpcb, tpcb->tp_snduna,
24139922Ssklower 			SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM))
24239922Ssklower 			&& SEQ_GT(tpcb, seq, SEQ_ADD(tpcb, tpcb->tp_retrans_hiwat, 1))) {
24336413Ssklower 
24436413Ssklower 			struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM];
24536413Ssklower 			struct timeval x;
24636413Ssklower 
24736413Ssklower 			GET_TIME_SINCE(t, &x);
24836413Ssklower 
24936413Ssklower 			tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x );
25036413Ssklower 
25136413Ssklower 			{	/* update the global rtt, rtv stats */
25236413Ssklower 				register int i =
25336413Ssklower 				   (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
25436413Ssklower 				tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x );
25536413Ssklower 
25636413Ssklower 				IFTRACE(D_RTT)
25736413Ssklower 					tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0);
25836413Ssklower 				ENDTRACE
25936413Ssklower 			}
26036413Ssklower 
26136413Ssklower 			IFTRACE(D_RTT)
26236413Ssklower 				tptraceTPCB(TPPTmisc,
26336413Ssklower 				"Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime",
26436413Ssklower 				tpcb->tp_snduna, time.tv_sec, time.tv_usec,
26536413Ssklower 					tpcb->tp_peer_acktime);
26636413Ssklower 
26736413Ssklower 				tptraceTPCB(TPPTmisc,
26836413Ssklower 				"(secs): emittime diff(x) rtt, rtv",
26936413Ssklower 					t->tv_sec,
27036413Ssklower 					x.tv_sec,
27136413Ssklower 					tpcb->tp_rtt.tv_sec,
27236413Ssklower 					tpcb->tp_rtv.tv_sec);
27336413Ssklower 				tptraceTPCB(TPPTmisc,
27436413Ssklower 				"(usecs): emittime diff(x) rtt rtv",
27536413Ssklower 					t->tv_usec,
27636413Ssklower 					x.tv_usec,
27736413Ssklower 					tpcb->tp_rtt.tv_usec,
27836413Ssklower 					tpcb->tp_rtv.tv_usec);
27936413Ssklower 			ENDTRACE
28036413Ssklower 
28136413Ssklower 			{
28236413Ssklower 				/* Update data retransmission timer based on the smoothed
28336413Ssklower 				 * round trip time, peer ack time, and the pseudo-arbitrary
28436413Ssklower 				 * number 4.
28536413Ssklower 				 * new ticks: avg rtt + 2*dev
28636413Ssklower 				 * rtt, rtv are in microsecs, and ticks are 500 ms
28736413Ssklower 				 * so 1 tick = 500*1000 us = 500000 us
28836413Ssklower 				 * so ticks = (rtt + 2 rtv)/500000
28936413Ssklower 				 * with ticks no les than peer ack time and no less than 4
29036413Ssklower 				 */
29136413Ssklower 
29236413Ssklower 				int rtt = tpcb->tp_rtt.tv_usec +
29336413Ssklower 					tpcb->tp_rtt.tv_sec*1000000;
29436413Ssklower 				int rtv = tpcb->tp_rtv.tv_usec +
29536413Ssklower 					tpcb->tp_rtv.tv_sec*1000000;
29636413Ssklower 
29736413Ssklower 				IFTRACE(D_RTT)
29836413Ssklower 					tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks",
29936413Ssklower 						tpcb->tp_dt_ticks,
30036413Ssklower 						rtv, rtt,
30136413Ssklower 						(rtt/500000 + (2 * rtv)/500000));
30236413Ssklower 				ENDTRACE
30336413Ssklower 				tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000;
30436413Ssklower 				tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks,
30536413Ssklower 					tpcb->tp_peer_acktime);
30636413Ssklower 				tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks,  4);
30736413Ssklower 			}
30836413Ssklower 		}
30936413Ssklower 		tpcb->tp_snduna = seq;
31039922Ssklower 		tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */
31136413Ssklower 
31236413Ssklower 		bang++;
31336413Ssklower 	}
31436413Ssklower 
31536413Ssklower 	if( cdt != 0 && old_fcredit == 0 ) {
31636413Ssklower 		tpcb->tp_sendfcc = 1;
31736413Ssklower 	}
31836413Ssklower 	if( cdt == 0 && old_fcredit != 0 ) {
31936413Ssklower 		IncStat(ts_zfcdt);
32036413Ssklower 	}
32136413Ssklower 	tpcb->tp_fcredit = cdt;
32236413Ssklower 
32336413Ssklower 	IFDEBUG(D_ACKRECV)
32436413Ssklower 		printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n",
32536413Ssklower 			(bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit );
32636413Ssklower 	ENDDEBUG
32736413Ssklower 
32836413Ssklower 	return (bang || (old_fcredit < cdt)) ;
32936413Ssklower }
33036413Ssklower 
33136413Ssklower /*
33236413Ssklower  * CALLED FROM:
33336413Ssklower  *  tp_goodack()
33436413Ssklower  * FUNCTION and ARGUMENTS:
33550901Ssklower  *  drops everything up TO but not INCLUDING seq # (seq)
33636413Ssklower  *  from the retransmission queue.
33736413Ssklower  */
33836413Ssklower static void
33936413Ssklower tp_sbdrop(tpcb, seq)
34050901Ssklower 	register struct 	tp_pcb 			*tpcb;
34136413Ssklower 	SeqNum					seq;
34236413Ssklower {
34350901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
34450901Ssklower 	register int i = ((int)seq)-((int)tpcb->tp_snduna);
34536413Ssklower 
34650901Ssklower 	if (i < 0) i += tpcb->tp_seqhalf;
34736413Ssklower 	IFDEBUG(D_ACKRECV)
34850901Ssklower 		printf("tp_sbdroping %d up through seq 0x%x\n", i, seq);
34936413Ssklower 	ENDDEBUG
35050901Ssklower 	while (i-- > 0)
35150901Ssklower 		sbdroprecord(sb);
35250901Ssklower 	if (SEQ_LT(tpcb, tpcb->tp_sndhiwat, seq))
35350901Ssklower 		tpcb->tp_sndhiwat_m = 0;
35436413Ssklower 
35536413Ssklower }
35636413Ssklower 
35736413Ssklower /*
35836413Ssklower  * CALLED FROM:
35936413Ssklower  * 	tp.trans on user send request, arrival of AK and arrival of XAK
36036413Ssklower  * FUNCTION and ARGUMENTS:
36136413Ssklower  * 	Emits tpdus starting at sequence number (lowseq).
36236413Ssklower  * 	Emits until a) runs out of data, or  b) runs into an XPD mark, or
36336413Ssklower  * 			c) it hits seq number (highseq)
36436413Ssklower  *
36536413Ssklower  * 	If you want XPD to buffer > 1 du per socket buffer, you can
36636413Ssklower  * 	modifiy this to issue XPD tpdus also, but then it'll have
36736413Ssklower  * 	to take some argument(s) to distinguish between the type of DU to
36850901Ssklower  * 	hand tp_emit.
36936413Ssklower  *
37036413Ssklower  * 	When something is sent for the first time, its time-of-send
37136413Ssklower  * 	is stashed (the last RTT_NUM of them are stashed).  When the
37236413Ssklower  * 	ack arrives, the smoothed round-trip time is figured using this value.
37336413Ssklower  * RETURN VALUE:
37436413Ssklower  * 	the highest seq # sent successfully.
37536413Ssklower  */
37636413Ssklower tp_send(tpcb)
37736413Ssklower 	register struct tp_pcb	*tpcb;
37836413Ssklower {
37936413Ssklower 	register int			len;
38036413Ssklower 	register struct mbuf	*m; /* the one we're inspecting now */
38136413Ssklower 	struct mbuf				*mb;/* beginning of this tpdu */
38236413Ssklower 	struct mbuf 			*nextrecord; /* NOT next tpdu but next sb record */
38336413Ssklower 	struct 	sockbuf			*sb = &tpcb->tp_sock->so_snd;
38436413Ssklower 	unsigned int			eotsdu_reached=0;
38536413Ssklower 	SeqNum					lowseq, highseq ;
38636413Ssklower 	SeqNum					lowsave;
38736413Ssklower #ifdef TP_PERF_MEAS
38850236Ssklower 
38936413Ssklower 	struct timeval 			send_start_time;
39050236Ssklower 	IFPERF(tpcb)
39150236Ssklower 		GET_CUR_TIME(&send_start_time);
39250236Ssklower 	ENDPERF
39336413Ssklower #endif TP_PERF_MEAS
39436413Ssklower 
39536413Ssklower 	lowsave =  lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1);
39636413Ssklower 
39736413Ssklower 	ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff);
39836413Ssklower 
39936413Ssklower 	if( tpcb->tp_rx_strat & TPRX_USE_CW ) {
40036413Ssklower 			/*first hiseq is temp vbl*/
40136413Ssklower 		highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win);
40236413Ssklower 	} else {
40336413Ssklower 		highseq = tpcb->tp_fcredit;
40436413Ssklower 	}
40536413Ssklower 	highseq = SEQ(tpcb, tpcb->tp_snduna + highseq);
40636413Ssklower 
40736413Ssklower 	SEQ_DEC(tpcb, highseq);
40836413Ssklower 
40936413Ssklower 	IFDEBUG(D_DATA)
41036413Ssklower 		printf(
41136413Ssklower 			"tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n",
41236413Ssklower 			tpcb, lowseq, highseq);
41336413Ssklower 		dump_mbuf(sb->sb_mb, "sb_mb:");
41436413Ssklower 	ENDDEBUG
41536413Ssklower 	IFTRACE(D_DATA)
41636413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna",
41736413Ssklower 			lowsave, tpcb->tp_sndhiwat,  tpcb->tp_snduna, 0);
41836413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin",
41936413Ssklower 			lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
42036413Ssklower 	ENDTRACE
42136413Ssklower 
42236413Ssklower 
42336413Ssklower 	if	( SEQ_GT(tpcb, lowseq, highseq) )
42436413Ssklower 			return ; /* don't send, don't change hiwat, don't set timers */
42536413Ssklower 
42636413Ssklower 	ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) );
42736413Ssklower 	SEQ_DEC(tpcb, lowseq);
42836413Ssklower 
42950901Ssklower 	if (tpcb->tp_Xsnd.sb_mb) {
43050901Ssklower 		IFTRACE(D_XPD)
43150901Ssklower 			tptraceTPCB( TPPTmisc,
43250901Ssklower 				"tp_send XPD mark low high tpcb.Xuna",
43350901Ssklower 				lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0);
43450901Ssklower 		ENDTRACE
43550901Ssklower 		/* stop sending here because there are unacked XPD present
43650901Ssklower 		 */
43750901Ssklower 		IncStat(ts_xpd_intheway);
43850901Ssklower 		goto done;
43950901Ssklower 	}
44036413Ssklower 	IFTRACE(D_DATA)
44136413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin",
44236413Ssklower 			lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
44336413Ssklower 	ENDTRACE
44436413Ssklower 
44550901Ssklower 	if (m = tpcb->tp_sndhiwat_m)
44650901Ssklower 		mb  = m->m_nextpkt;
44750901Ssklower 	else
44850901Ssklower 		mb = sb->sb_mb;
44950901Ssklower 	while ((SEQ_LT(tpcb, lowseq, highseq)) && mb ) {
45036413Ssklower 
45150901Ssklower 		/*
45236413Ssklower 		 * In all cases, m points to mbuf containing first octet to be
45336413Ssklower 		 * sent in the tpdu AFTER the one we're going to send now,
45436413Ssklower 		 * or else m is null.
45536413Ssklower 		 *
45636413Ssklower 		 * The chain we're working on now begins at mb and has length <len>.
45736413Ssklower 		 */
45836413Ssklower 
45950901Ssklower 		eotsdu_reached = (mb->m_flags & M_EOR) != 0;
46050901Ssklower 		len = mb->m_pkthdr.len;
46136413Ssklower 		IFTRACE(D_STASH)
46236413Ssklower 			tptraceTPCB( TPPTmisc,
46336413Ssklower 				"tp_send mcopy low high eotsdu_reached len",
46436413Ssklower 				lowseq, highseq, eotsdu_reached, len);
46536413Ssklower 		ENDTRACE
46636413Ssklower 
46736413Ssklower 		/* make a copy - mb goes into the retransmission list
46836413Ssklower 		 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
46936413Ssklower 		 */
47050901Ssklower 		m = m_copy(mb, 0, M_COPYALL);
47150901Ssklower 		if (m == MNULL)
47236413Ssklower 				goto done;
47336413Ssklower 		SEQ_INC(tpcb,lowseq);	/* it was decremented at the beginning */
47436413Ssklower 		IFTRACE(D_DATA)
47536413Ssklower 			tptraceTPCB( TPPTmisc,
47639196Ssklower 				"tp_send emitting DT lowseq eotsdu_reached len",
47739196Ssklower 				lowseq, eotsdu_reached, len, 0);
47836413Ssklower 		ENDTRACE
47950901Ssklower 		if (mb->m_nextpkt == 0 && tpcb->tp_oktonagle) {
48050901Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnum);
48150901Ssklower 			tpcb->tp_oktonagle = 0;
48250901Ssklower 			/* when headers are precomputed, may need to fill
48350901Ssklower 			   in checksum here */
48450901Ssklower 		}
48550901Ssklower 		if (tpcb->tp_sock->so_error =
48650901Ssklower 			tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m)) {
48736413Ssklower 			/* error */
48836413Ssklower 			SEQ_DEC(tpcb, lowseq);
48936413Ssklower 			goto done;
49036413Ssklower 		}
49150901Ssklower 		tpcb->tp_sndhiwat_m = mb;
49250901Ssklower 		mb = mb->m_nextpkt;
49336413Ssklower 		/* set the transmit-time for computation of round-trip times */
49436413Ssklower 		bcopy( (caddr_t)&time,
49536413Ssklower 				(caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ),
49636413Ssklower 				sizeof(struct timeval));
49736413Ssklower 
49836413Ssklower 	}
49936413Ssklower 
50036413Ssklower done:
50150236Ssklower #ifdef TP_PERF_MEAS
50236413Ssklower 	IFPERF(tpcb)
50336413Ssklower 		{
50436413Ssklower 			register int npkts;
50536413Ssklower 			struct timeval send_end_time;
50636413Ssklower 			register struct timeval *t;
50736413Ssklower 
50836413Ssklower 			npkts = lowseq;
50936413Ssklower 			SEQ_INC(tpcb, npkts);
51036413Ssklower 			npkts = SEQ_SUB(tpcb, npkts, lowsave);
51136413Ssklower 
51236413Ssklower 			if(npkts > 0)
51336413Ssklower 				tpcb->tp_Nwindow++;
51436413Ssklower 
51536413Ssklower 			if (npkts > TP_PM_MAX)
51636413Ssklower 				npkts = TP_PM_MAX;
51736413Ssklower 
51836413Ssklower 			GET_TIME_SINCE(&send_start_time, &send_end_time);
51936413Ssklower 			t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
52036413Ssklower 			t->tv_sec =
52136413Ssklower 				SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec);
52236413Ssklower 			t->tv_usec =
52336413Ssklower 				SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec);
52436413Ssklower 
52536413Ssklower 			if ( SEQ_LT(tpcb, lowseq, highseq) ) {
52636413Ssklower 				IncPStat(tpcb, tps_win_lim_by_data[npkts] );
52736413Ssklower 			} else {
52836413Ssklower 				IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
52936413Ssklower 				/* not true with congestion-window being used */
53036413Ssklower 			}
53136413Ssklower 			tpmeas( tpcb->tp_lref,
53236413Ssklower 					TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts);
53336413Ssklower 		}
53436413Ssklower 	ENDPERF
53550236Ssklower #endif TP_PERF_MEAS
53636413Ssklower 
53736413Ssklower 	tpcb->tp_sndhiwat = lowseq;
53836413Ssklower 
53936413Ssklower 	if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat)  &&
54036413Ssklower 			(tpcb->tp_class != TP_CLASS_0) )
54136413Ssklower 			tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave,
54236413Ssklower 				tpcb->tp_sndhiwat,
54336413Ssklower 				(u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks);
54436413Ssklower 	IFTRACE(D_DATA)
54536413Ssklower 		tptraceTPCB( TPPTmisc,
54636413Ssklower 			"tp_send at end: sndhiwat lowseq eotsdu_reached error",
54736413Ssklower 			tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error);
54836413Ssklower 
54936413Ssklower 	ENDTRACE
55036413Ssklower }
55136413Ssklower 
55250901Ssklower int TPNagleok;
55350901Ssklower int TPNagled;
55450901Ssklower 
55550901Ssklower tp_packetize(tpcb, m, eotsdu)
55650901Ssklower register struct tp_pcb *tpcb;
55750901Ssklower register struct mbuf *m;
55850901Ssklower int eotsdu;
55950901Ssklower {
56050901Ssklower 	register struct mbuf *n;
56150901Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_snd;
56250901Ssklower 	int	maxsize = tpcb->tp_l_tpdusize
56350901Ssklower 			- tp_headersize(DT_TPDU_type, tpcb)
56450901Ssklower 			- (tpcb->tp_use_checksum?4:0) ;
56550901Ssklower 	int totlen = m->m_pkthdr.len;
56650901Ssklower 	struct mbuf *m_split();
56750901Ssklower 	/*
56850901Ssklower 	 * Pre-packetize the data in the sockbuf
56950901Ssklower 	 * according to negotiated mtu.  Do it here
57050901Ssklower 	 * where we can safely wait for mbufs.
57150901Ssklower 	 *
57250901Ssklower 	 * This presumes knowledge of sockbuf conventions.
57350901Ssklower 	 * TODO: allocate space for header and fill it in (once!).
57450901Ssklower 	 */
57550901Ssklower 	IFTRACE(D_DATA)
57650901Ssklower 		tptraceTPCB(TPPTmisc,
57750901Ssklower 		"SEND BF: maxsize totlen eotsdu",
57850901Ssklower 			maxsize, totlen, eotsdu, 0);
57950901Ssklower 	ENDTRACE
58050901Ssklower 	if (tpcb->tp_oktonagle) {
58150901Ssklower 		if ((n = sb->sb_mb) == 0)
58250901Ssklower 			panic("tp_packetize");
58350901Ssklower 		while (n->m_act)
58450901Ssklower 			n = n->m_act;
58550901Ssklower 		if (n->m_flags & M_EOR)
58650901Ssklower 			panic("tp_packetize 2");
58750901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
58850901Ssklower 		if (totlen + n->m_pkthdr.len < maxsize) {
58950901Ssklower 			/* There is an unsent packet with space, combine data */
59050901Ssklower 			struct mbuf *old_n = n;
59150901Ssklower 			tpsbcheck(tpcb,3);
59250901Ssklower 			n->m_pkthdr.len += totlen;
59350901Ssklower 			while (n->m_next)
59450901Ssklower 				n = n->m_next;
59550901Ssklower 			sbcompress(sb, m, n);
59650901Ssklower 			tpsbcheck(tpcb,4);
59750901Ssklower 			n = old_n;
59850901Ssklower 			TPNagled++;
59950901Ssklower 			goto out;
60050901Ssklower 		}
60150901Ssklower 	}
60250901Ssklower 	while (m) {
60350901Ssklower 		n = m;
60450901Ssklower 		if (totlen > maxsize) {
60550901Ssklower 			if ((m = m_split(n, maxsize, M_WAIT)) == 0)
60650901Ssklower 				panic("tp_packetize");
60750901Ssklower 		} else
60850901Ssklower 			m = 0;
60950901Ssklower 		totlen -= maxsize;
61050901Ssklower 		tpsbcheck(tpcb, 5);
61150901Ssklower 		sbappendrecord(sb, n);
61250901Ssklower 		tpsbcheck(tpcb, 6);
61350901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
61450901Ssklower 	}
61550901Ssklower out:
61650901Ssklower 	if (eotsdu) {
61750901Ssklower 		n->m_flags |= M_EOR;  /* XXX belongs at end */
61850901Ssklower 		tpcb->tp_oktonagle = 0;
61950901Ssklower 	} else {
62050901Ssklower 		SEQ_DEC(tpcb, tpcb->tp_sndnum);
62150901Ssklower 		tpcb->tp_oktonagle = 1;
62250901Ssklower 		TPNagleok++;
62350901Ssklower 	}
62450901Ssklower 	return 0;
62550901Ssklower }
62650901Ssklower 
62750901Ssklower 
62836413Ssklower /*
62936413Ssklower  * NAME: tp_stash()
63036413Ssklower  * CALLED FROM:
63136413Ssklower  *	tp.trans on arrival of a DT tpdu
63236413Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
63336413Ssklower  * 	Returns 1 if
63436413Ssklower  *		a) something new arrived and it's got eotsdu_reached bit on,
63536413Ssklower  * 		b) this arrival was caused other out-of-sequence things to be
63636413Ssklower  *    	accepted, or
63736413Ssklower  * 		c) this arrival is the highest seq # for which we last gave credit
63836413Ssklower  *   	(sender just sent a whole window)
63936413Ssklower  *  In other words, returns 1 if tp should send an ack immediately, 0 if
64036413Ssklower  *  the ack can wait a while.
64136413Ssklower  *
64236413Ssklower  * Note: this implementation no longer renegs on credit, (except
64336413Ssklower  * when debugging option D_RENEG is on, for the purpose of testing
64436413Ssklower  * ack subsequencing), so we don't  need to check for incoming tpdus
64536413Ssklower  * being in a reneged portion of the window.
64636413Ssklower  */
64736413Ssklower 
64836413Ssklower tp_stash( tpcb, e )
64936413Ssklower 	register struct tp_pcb		*tpcb;
65036413Ssklower 	register struct tp_event	*e;
65136413Ssklower {
65236413Ssklower 	register int		ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
65336413Ssklower 									/* 0--> delay acks until full window */
65436413Ssklower 									/* 1--> ack each tpdu */
65536413Ssklower #ifndef lint
65636413Ssklower #define E e->ATTR(DT_TPDU)
65736413Ssklower #else lint
65836413Ssklower #define E e->ev_union.EV_DT_TPDU
65936413Ssklower #endif lint
66036413Ssklower 
66136413Ssklower 	if ( E.e_eot ) {
66236413Ssklower 		register struct mbuf *n = E.e_data;
66337469Ssklower 		n->m_flags |= M_EOR;
66438841Ssklower 		n->m_act = 0;
66537469Ssklower 	}
66636413Ssklower 		IFDEBUG(D_STASH)
66736413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
66836413Ssklower 				"stash: so_rcv before appending");
66936413Ssklower 			dump_mbuf(E.e_data,
67036413Ssklower 				"stash: e_data before appending");
67136413Ssklower 		ENDDEBUG
67236413Ssklower 
67336413Ssklower 	IFPERF(tpcb)
67436413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
67536413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
67637469Ssklower 			E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
67736413Ssklower 	ENDPERF
67836413Ssklower 
679*51024Ssklower 	if (E.e_seq == tpcb->tp_rcvnxt) {
68036413Ssklower 
68136413Ssklower 		IFDEBUG(D_STASH)
68236413Ssklower 			printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
68336413Ssklower 			E.e_seq, E.e_datalen, E.e_eot);
68436413Ssklower 		ENDDEBUG
68536413Ssklower 
68636413Ssklower 		IFTRACE(D_STASH)
68736413Ssklower 			tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
68836413Ssklower 			E.e_seq, E.e_datalen, E.e_eot, 0);
68936413Ssklower 		ENDTRACE
69036413Ssklower 
691*51024Ssklower 		SET_DELACK(tpcb);
692*51024Ssklower 
69337469Ssklower 		sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
69437469Ssklower 
69536413Ssklower 		SEQ_INC( tpcb, tpcb->tp_rcvnxt );
69636413Ssklower 		/*
69750901Ssklower 		 * move chains from the reassembly queue to the socket buffer
69836413Ssklower 		 */
69950901Ssklower 		if (tpcb->tp_rsycnt) {
70050901Ssklower 			register struct mbuf **mp;
70150901Ssklower 			struct mbuf **mplim;
70236413Ssklower 
70350901Ssklower 			mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit);
70450901Ssklower 			mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit;
70536413Ssklower 
70650901Ssklower 			while (tpcb->tp_rsycnt && *mp) {
70750901Ssklower 				sbappend(&tpcb->tp_sock->so_rcv, *mp);
70850901Ssklower 				tpcb->tp_rsycnt--;
70950901Ssklower 				*mp = 0;
71050901Ssklower 				SEQ_INC(tpcb, tpcb->tp_rcvnxt);
71136413Ssklower 				ack_reason |= ACK_REORDER;
71250901Ssklower 				if (++mp == mplim)
71350901Ssklower 					mp = tpcb->tp_rsyq;
71436413Ssklower 			}
71536413Ssklower 		}
71636413Ssklower 		IFDEBUG(D_STASH)
71736413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
71836413Ssklower 				"stash: so_rcv after appending");
71936413Ssklower 		ENDDEBUG
72036413Ssklower 
72136413Ssklower 	} else {
72250901Ssklower 		register struct mbuf **mp;
72350901Ssklower 		SeqNum uwe;
72436413Ssklower 
72536413Ssklower 		IFTRACE(D_STASH)
72636413Ssklower 			tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
72736413Ssklower 			E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
72836413Ssklower 		ENDTRACE
72936413Ssklower 
73050975Ssklower 		if (tpcb->tp_rsyq == 0)
73150975Ssklower 			tp_rsyset(tpcb);
73250901Ssklower 		uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit);
73350901Ssklower 		if (tpcb->tp_rsyq == 0 ||
73450901Ssklower 						!IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) {
73536413Ssklower 			ack_reason = ACK_DONT;
73650901Ssklower 			m_freem(E.e_data);
73750901Ssklower 		} else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) {
73836413Ssklower 			IFDEBUG(D_STASH)
73936413Ssklower 				printf("tp_stash - drop & ack\n");
74036413Ssklower 			ENDDEBUG
74136413Ssklower 
74236413Ssklower 			/* retransmission - drop it and force an ack */
74336413Ssklower 			IncStat(ts_dt_dup);
74436413Ssklower 			IFPERF(tpcb)
74536413Ssklower 				IncPStat(tpcb, tps_n_ack_cuz_dup);
74636413Ssklower 			ENDPERF
74736413Ssklower 
74850901Ssklower 			m_freem(E.e_data);
74936413Ssklower 			ack_reason |= ACK_DUP;
75050901Ssklower 		} else {
75150901Ssklower 			*mp = E.e_data;
75250901Ssklower 			tpcb->tp_rsycnt++;
75350901Ssklower 			ack_reason = ACK_DONT;
75436413Ssklower 		}
75536413Ssklower 	}
756*51024Ssklower 	/* there were some comments of historical interest here. */
75736413Ssklower 	{
75836413Ssklower 		LOCAL_CREDIT(tpcb);
75936413Ssklower 
76036413Ssklower 		if ( E.e_seq ==  tpcb->tp_sent_uwe )
76136413Ssklower 			ack_reason |= ACK_STRAT_FULLWIN;
76236413Ssklower 
76336413Ssklower 		IFTRACE(D_STASH)
76436413Ssklower 			tptraceTPCB(TPPTmisc,
76536413Ssklower 				"end of stash, eot, ack_reason, sent_uwe ",
76636413Ssklower 				E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
76736413Ssklower 		ENDTRACE
76836413Ssklower 
76936413Ssklower 		if ( ack_reason == ACK_DONT ) {
77036413Ssklower 			IncStat( ts_ackreason[ACK_DONT] );
77136413Ssklower 			return 0;
77236413Ssklower 		} else {
77336413Ssklower 			IFPERF(tpcb)
77436413Ssklower 				if(ack_reason & ACK_STRAT_EACH) {
77536413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_strat);
77636413Ssklower 				} else if(ack_reason & ACK_STRAT_FULLWIN) {
77736413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_fullwin);
77836413Ssklower 				} else if(ack_reason & ACK_REORDER) {
77936413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_reorder);
78036413Ssklower 				}
78136413Ssklower 				tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
78236413Ssklower 							SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
78336413Ssklower 			ENDPERF
78436413Ssklower 			{
78536413Ssklower 				register int i;
78636413Ssklower 
78736413Ssklower 				/* keep track of all reasons that apply */
78836413Ssklower 				for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
78936413Ssklower 					if( ack_reason & (1<<i) )
79036413Ssklower 						IncStat( ts_ackreason[i] );
79136413Ssklower 				}
79236413Ssklower 			}
79336413Ssklower 			return 1;
79436413Ssklower 		}
79536413Ssklower 	}
79636413Ssklower }
79750901Ssklower 
79850901Ssklower /*
79950901Ssklower  * tp_rsyflush - drop all the packets on the reassembly queue.
80050901Ssklower  * Do this when closing the socket, or when somebody has changed
80150901Ssklower  * the space avaible in the receive socket (XXX).
80250901Ssklower  */
80350901Ssklower tp_rsyflush(tpcb)
80450901Ssklower register struct tp_pcb *tpcb;
80550901Ssklower {
80650901Ssklower 	register struct mbuf *m, **mp;
80750901Ssklower 	if (tpcb->tp_rsycnt) {
80850901Ssklower 		for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit;
80950901Ssklower 									 --mp >= tpcb->tp_rsyq; )
81050901Ssklower 			if (*mp) {
81150901Ssklower 				tpcb->tp_rsycnt--;
81250901Ssklower 				m_freem(*mp);
81350901Ssklower 			}
81450901Ssklower 		if (tpcb->tp_rsycnt)
81550901Ssklower 			panic("tp_rsyflush");
81650901Ssklower 	}
81750901Ssklower 	free((caddr_t)tpcb->tp_rsyq, M_PCB);
81850901Ssklower 	tpcb->tp_rsyq = 0;
81950901Ssklower }
82050901Ssklower 
82150901Ssklower tp_rsyset(tpcb)
82250901Ssklower register struct tp_pcb *tpcb;
82350901Ssklower {
82450901Ssklower 	register struct socket *so = tpcb->tp_sock;
82550901Ssklower 	int maxcredit  = tpcb->tp_xtd_format ? 0xffff : 0xf;
82650975Ssklower 	int old_credit = tpcb->tp_maxlcredit;
82750975Ssklower 	caddr_t	rsyq;
82850901Ssklower 
82950901Ssklower 	tpcb->tp_maxlcredit = maxcredit = min(maxcredit,
83050901Ssklower 		  (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize);
83150901Ssklower 
83250975Ssklower 	if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0)
83350975Ssklower 		return;
83450901Ssklower 	maxcredit *= sizeof(struct mbuf *);
83550901Ssklower 	if (tpcb->tp_rsyq)
83650901Ssklower 		tp_rsyflush(tpcb);
83750901Ssklower 	if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT))
83850901Ssklower 		bzero(rsyq, maxcredit);
83950901Ssklower 	tpcb->tp_rsyq = (struct mbuf **)rsyq;
84050901Ssklower }
84150901Ssklower 
84250901Ssklower tpsbcheck(tpcb, i)
84350901Ssklower struct tp_pcb *tpcb;
84450901Ssklower {
84550901Ssklower 	register struct mbuf *n, *m;
84650901Ssklower 	register int len = 0, mbcnt = 0, pktlen;
84750901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
84850901Ssklower 
84950901Ssklower 	for (n = sb->sb_mb; n; n = n->m_nextpkt) {
85050901Ssklower 		if ((n->m_flags & M_PKTHDR) == 0)
85150901Ssklower 			panic("tpsbcheck nohdr");
85250901Ssklower 		pktlen = len + n->m_pkthdr.len;
85350901Ssklower 	    for (m = n; m; m = m->m_next) {
85450901Ssklower 			len += m->m_len;
85550901Ssklower 			mbcnt += MSIZE;
85650901Ssklower 			if (m->m_flags & M_EXT)
85750901Ssklower 				mbcnt += m->m_ext.ext_size;
85850901Ssklower 		}
85950901Ssklower 		if (len != pktlen) {
86050901Ssklower 			printf("test %d; len %d != pktlen %d on mbuf 0x%x\n",
86150901Ssklower 				i, len, pktlen, n);
86250901Ssklower 			panic("tpsbcheck short");
86350901Ssklower 		}
86450901Ssklower 	}
86550901Ssklower 	if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
86650901Ssklower 		printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc,
86750901Ssklower 		    mbcnt, sb->sb_mbcnt);
86850901Ssklower 		panic("tpsbcheck");
86950901Ssklower 	}
87050901Ssklower }
871