xref: /csrg-svn/sys/netiso/tp_subr.c (revision 51138)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51138Ssklower  *	@(#)tp_subr.c	7.14 (Berkeley) 09/17/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"
59*51138Ssklower #include "kernel.h"
6036413Ssklower 
6137469Ssklower #include "tp_ip.h"
6237469Ssklower #include "iso.h"
6337469Ssklower #include "argo_debug.h"
6437469Ssklower #include "tp_timer.h"
6537469Ssklower #include "tp_param.h"
6637469Ssklower #include "tp_stat.h"
6737469Ssklower #include "tp_pcb.h"
6837469Ssklower #include "tp_tpdu.h"
6937469Ssklower #include "tp_trace.h"
7037469Ssklower #include "tp_meas.h"
7137469Ssklower #include "tp_seq.h"
7236413Ssklower 
73*51138Ssklower int 		tp_emit(), tp_sbdrop();
7436413Ssklower 
7536413Ssklower /*
7636413Ssklower  * CALLED FROM:
7736413Ssklower  *	tp.trans, when an XAK arrives
7836413Ssklower  * FUNCTION and ARGUMENTS:
7936413Ssklower  * 	Determines if the sequence number (seq) from the XAK
8036413Ssklower  * 	acks anything new.  If so, drop the appropriate tpdu
8136413Ssklower  * 	from the XPD send queue.
8236413Ssklower  * RETURN VALUE:
8336413Ssklower  * 	Returns 1 if it did this, 0 if the ack caused no action.
8436413Ssklower  */
8536413Ssklower int
8636413Ssklower tp_goodXack(tpcb, seq)
8736413Ssklower 	struct tp_pcb	*tpcb;
8836413Ssklower 	SeqNum 			seq;
8936413Ssklower {
9036413Ssklower 
9136413Ssklower 	IFTRACE(D_XPD)
9236413Ssklower 		tptraceTPCB(TPPTgotXack,
9336413Ssklower 			seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat,
9436413Ssklower 			tpcb->tp_snduna);
9536413Ssklower 	ENDTRACE
9636413Ssklower 
9736413Ssklower 	if ( seq == tpcb->tp_Xuna ) {
9836413Ssklower 			tpcb->tp_Xuna = tpcb->tp_Xsndnxt;
9936413Ssklower 
10036413Ssklower 			/* DROP 1 packet from the Xsnd socket buf - just so happens
10136413Ssklower 			 * that only one packet can be there at any time
10236413Ssklower 			 * so drop the whole thing.  If you allow > 1 packet
10336413Ssklower 			 * the socket buffer, then you'll have to keep
10436413Ssklower 			 * track of how many characters went w/ each XPD tpdu, so this
10536413Ssklower 			 * will get messier
10636413Ssklower 			 */
10736413Ssklower 			IFDEBUG(D_XPD)
10836413Ssklower 				dump_mbuf(tpcb->tp_Xsnd.sb_mb,
10936413Ssklower 					"tp_goodXack Xsnd before sbdrop");
11036413Ssklower 			ENDDEBUG
11136413Ssklower 
11236413Ssklower 			IFTRACE(D_XPD)
11336413Ssklower 				tptraceTPCB(TPPTmisc,
11436413Ssklower 					"goodXack: dropping cc ",
11536413Ssklower 					(int)(tpcb->tp_Xsnd.sb_cc),
11636413Ssklower 					0,0,0);
11736413Ssklower 			ENDTRACE
11836413Ssklower 			sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc));
11939922Ssklower 			CONG_ACK(tpcb, seq);
12036413Ssklower 			return 1;
12136413Ssklower 	}
12236413Ssklower 	return 0;
12336413Ssklower }
12436413Ssklower 
12536413Ssklower /*
12636413Ssklower  * CALLED FROM:
12736413Ssklower  *  tp_good_ack()
12836413Ssklower  * FUNCTION and ARGUMENTS:
12936413Ssklower  *  updates
130*51138Ssklower  *  smoothed average round trip time (*rtt)
131*51138Ssklower  *  roundtrip time variance (*rtv) - actually deviation, not variance
13236413Ssklower  *  given the new value (diff)
13336413Ssklower  * RETURN VALUE:
13436413Ssklower  * void
13536413Ssklower  */
13636413Ssklower 
13736413Ssklower void
138*51138Ssklower tp_rtt_rtv( rtt, rtv, newmeas )
139*51138Ssklower 	register int	 *rtt, *rtv;
140*51138Ssklower 	int newmeas;
14136413Ssklower {
142*51138Ssklower 	int delta = newmeas - *rtt;
14336413Ssklower 
144*51138Ssklower 	if ((*rtt += (delta >> TP_RTT_ALPHA)) <= 0)
145*51138Ssklower 		*rtt = 1;
146*51138Ssklower 	if (delta < 0)
147*51138Ssklower 		delta = -delta;
148*51138Ssklower 	if (*rtv = ((delta - *rtv) >> TP_RTV_ALPHA) <= 0)
149*51138Ssklower 		*rtv = 1;
15036413Ssklower }
15136413Ssklower 
15236413Ssklower /*
15336413Ssklower  * CALLED FROM:
15436413Ssklower  *  tp.trans when an AK arrives
15536413Ssklower  * FUNCTION and ARGUMENTS:
15636413Ssklower  * 	Given (cdt), the credit from the AK tpdu, and
15736413Ssklower  *	(seq), the sequence number from the AK tpdu,
15836413Ssklower  *  tp_goodack() determines if the AK acknowledges something in the send
15936413Ssklower  * 	window, and if so, drops the appropriate packets from the retransmission
16036413Ssklower  *  list, computes the round trip time, and updates the retransmission timer
16136413Ssklower  *  based on the new smoothed round trip time.
16236413Ssklower  * RETURN VALUE:
16336413Ssklower  * 	Returns 1 if
16436413Ssklower  * 	EITHER it actually acked something heretofore unacknowledged
16536413Ssklower  * 	OR no news but the credit should be processed.
16636413Ssklower  * 	If something heretofore unacked was acked with this sequence number,
16736413Ssklower  * 	the appropriate tpdus are dropped from the retransmission control list,
16836413Ssklower  * 	by calling tp_sbdrop().
16936413Ssklower  * 	No need to see the tpdu itself.
17036413Ssklower  */
17136413Ssklower int
17236413Ssklower tp_goodack(tpcb, cdt, seq, subseq)
17336413Ssklower 	register struct tp_pcb	*tpcb;
17436413Ssklower 	u_int					cdt;
17536413Ssklower 	register SeqNum			seq, subseq;
17636413Ssklower {
17736413Ssklower 	int 	old_fcredit = tpcb->tp_fcredit;
17836413Ssklower 	int 	bang = 0; 	/* bang --> ack for something heretofore unacked */
17936413Ssklower 
18036413Ssklower 	IFDEBUG(D_ACKRECV)
18136413Ssklower 		printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n",
18236413Ssklower 			seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat);
18336413Ssklower 	ENDDEBUG
18436413Ssklower 	IFTRACE(D_ACKRECV)
18536413Ssklower 		tptraceTPCB(TPPTgotack,
18636413Ssklower 			seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq);
18736413Ssklower 	ENDTRACE
18836413Ssklower 
18936413Ssklower 	IFPERF(tpcb)
19037469Ssklower 		tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0);
19136413Ssklower 	ENDPERF
19236413Ssklower 
19336413Ssklower 	if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) {
19436413Ssklower 		/* discard the ack */
19536413Ssklower 		IFTRACE(D_ACKRECV)
19636413Ssklower 			tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq",
19736413Ssklower 				subseq, tpcb->tp_r_subseq, 0, 0);
19836413Ssklower 		ENDTRACE
19936413Ssklower 		return 0;
20036413Ssklower 	} else {
20136413Ssklower 		tpcb->tp_r_subseq = subseq;
20236413Ssklower 	}
20336413Ssklower 
20436413Ssklower 	if ( IN_SWINDOW(tpcb, seq,
20536413Ssklower 			tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) {
20636413Ssklower 
20736413Ssklower 		IFDEBUG(D_XPD)
20836413Ssklower 			dump_mbuf(tpcb->tp_sock->so_snd.sb_mb,
20936413Ssklower 				"tp_goodack snd before sbdrop");
21036413Ssklower 		ENDDEBUG
21150901Ssklower 		tpsbcheck(tpcb, 0);
212*51138Ssklower 		(void)tp_sbdrop(tpcb, seq);
21350901Ssklower 		tpsbcheck(tpcb, 1);
21436413Ssklower 
21536413Ssklower 		/* increase congestion window but don't let it get too big */
21636413Ssklower 		{
21736413Ssklower 			register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf;
21839922Ssklower 			CONG_ACK(tpcb, seq);
21936413Ssklower 		}
22036413Ssklower 
22136413Ssklower 		/* Compute smoothed round trip time.
222*51138Ssklower 		 * Only measure rtt for tp_snduna if acked and the data
22339922Ssklower 		 * were not retransmitted.
22436413Ssklower 		 */
225*51138Ssklower 		if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) {
226*51138Ssklower 			int x = tick - tpcb->tp_rttemit;
22736413Ssklower 
228*51138Ssklower 			if (tpcb->tp_rtt)
229*51138Ssklower 				tp_rtt_rtv(&(tpcb->tp_rtt), &(tpcb->tp_rtv), x);
230*51138Ssklower 			else {
231*51138Ssklower 				tpcb->tp_rtt = x;
232*51138Ssklower 				tpcb->tp_rtv = x >> 1;
233*51138Ssklower 			}
23436413Ssklower 
23536413Ssklower 			{	/* update the global rtt, rtv stats */
236*51138Ssklower 				int i = tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
237*51138Ssklower 				tp_rtt_rtv(tp_stat.ts_rtt + i, tp_stat.ts_rtv + i, x);
23836413Ssklower 
23936413Ssklower 				IFTRACE(D_RTT)
24036413Ssklower 					tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0);
24136413Ssklower 				ENDTRACE
24236413Ssklower 			}
24336413Ssklower 
24436413Ssklower 			IFTRACE(D_RTT)
24536413Ssklower 				tptraceTPCB(TPPTmisc,
24636413Ssklower 				"Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime",
24736413Ssklower 				tpcb->tp_snduna, time.tv_sec, time.tv_usec,
24836413Ssklower 					tpcb->tp_peer_acktime);
24936413Ssklower 
25036413Ssklower 				tptraceTPCB(TPPTmisc,
251*51138Ssklower 					"(secs): emittime diff(x) rtt, rtv",
252*51138Ssklower 						tpcb->tp_rttemit, x, tpcb->tp_rtt, tpcb->tp_rtv);
25336413Ssklower 			ENDTRACE
25436413Ssklower 
25536413Ssklower 			{
25636413Ssklower 				/* Update data retransmission timer based on the smoothed
25736413Ssklower 				 * round trip time, peer ack time, and the pseudo-arbitrary
258*51138Ssklower 				 * number 2.
259*51138Ssklower 				 * new ticks: (avg rtt + 4*dev)
260*51138Ssklower 				 * rtt, rtv are in hz-ticks,
261*51138Ssklower 				 * and slowtimo-ticks are hz / 2;
262*51138Ssklower 				 * We want no less than peer ack time and no less than 2
26336413Ssklower 				 */
26436413Ssklower 
26536413Ssklower 
266*51138Ssklower 				int rtt = tpcb->tp_rtt, rtv = tpcb->tp_rtv,
267*51138Ssklower 					old = tpcb->tp_dt_ticks, new;
268*51138Ssklower 
269*51138Ssklower 				new = (((rtt + (rtv << 2)) << 1) + hz) / hz;
270*51138Ssklower 				new = MAX(new + 1, old);
271*51138Ssklower 				new = MAX(new, tpcb->tp_peer_acktime);
272*51138Ssklower 				new = MAX(new, 2);
27336413Ssklower 				IFTRACE(D_RTT)
27436413Ssklower 					tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks",
275*51138Ssklower 						old, rtv, rtt, new);
27636413Ssklower 				ENDTRACE
277*51138Ssklower 				tpcb->tp_dt_ticks = new;
27836413Ssklower 			}
279*51138Ssklower 			tpcb->tp_rxtcur = tpcb->tp_dt_ticks;
280*51138Ssklower 			tpcb->tp_rxtshift = 0;
281*51138Ssklower 
28236413Ssklower 		}
28336413Ssklower 		tpcb->tp_snduna = seq;
28439922Ssklower 		tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */
28536413Ssklower 
28636413Ssklower 		bang++;
28736413Ssklower 	}
28836413Ssklower 
28936413Ssklower 	if( cdt != 0 && old_fcredit == 0 ) {
29036413Ssklower 		tpcb->tp_sendfcc = 1;
29136413Ssklower 	}
29236413Ssklower 	if( cdt == 0 && old_fcredit != 0 ) {
29336413Ssklower 		IncStat(ts_zfcdt);
29436413Ssklower 	}
29536413Ssklower 	tpcb->tp_fcredit = cdt;
29636413Ssklower 
29736413Ssklower 	IFDEBUG(D_ACKRECV)
29836413Ssklower 		printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n",
29936413Ssklower 			(bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit );
30036413Ssklower 	ENDDEBUG
30136413Ssklower 
30236413Ssklower 	return (bang || (old_fcredit < cdt)) ;
30336413Ssklower }
30436413Ssklower 
30536413Ssklower /*
30636413Ssklower  * CALLED FROM:
30736413Ssklower  *  tp_goodack()
30836413Ssklower  * FUNCTION and ARGUMENTS:
30950901Ssklower  *  drops everything up TO but not INCLUDING seq # (seq)
31036413Ssklower  *  from the retransmission queue.
31136413Ssklower  */
31236413Ssklower tp_sbdrop(tpcb, seq)
31350901Ssklower 	register struct 	tp_pcb 			*tpcb;
31436413Ssklower 	SeqNum					seq;
31536413Ssklower {
31650901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
31750901Ssklower 	register int i = ((int)seq)-((int)tpcb->tp_snduna);
318*51138Ssklower 	int	oldcc = sb->sb_cc;
31936413Ssklower 
32050901Ssklower 	if (i < 0) i += tpcb->tp_seqhalf;
32136413Ssklower 	IFDEBUG(D_ACKRECV)
32250901Ssklower 		printf("tp_sbdroping %d up through seq 0x%x\n", i, seq);
32336413Ssklower 	ENDDEBUG
32450901Ssklower 	while (i-- > 0)
32550901Ssklower 		sbdroprecord(sb);
32650901Ssklower 	if (SEQ_LT(tpcb, tpcb->tp_sndhiwat, seq))
32750901Ssklower 		tpcb->tp_sndhiwat_m = 0;
328*51138Ssklower 	return (oldcc - sb->sb_cc);
32936413Ssklower }
33036413Ssklower 
33136413Ssklower /*
33236413Ssklower  * CALLED FROM:
33336413Ssklower  * 	tp.trans on user send request, arrival of AK and arrival of XAK
33436413Ssklower  * FUNCTION and ARGUMENTS:
33536413Ssklower  * 	Emits tpdus starting at sequence number (lowseq).
33636413Ssklower  * 	Emits until a) runs out of data, or  b) runs into an XPD mark, or
33736413Ssklower  * 			c) it hits seq number (highseq)
33836413Ssklower  *
33936413Ssklower  * 	If you want XPD to buffer > 1 du per socket buffer, you can
34036413Ssklower  * 	modifiy this to issue XPD tpdus also, but then it'll have
34136413Ssklower  * 	to take some argument(s) to distinguish between the type of DU to
34250901Ssklower  * 	hand tp_emit.
34336413Ssklower  *
34436413Ssklower  * 	When something is sent for the first time, its time-of-send
34536413Ssklower  * 	is stashed (the last RTT_NUM of them are stashed).  When the
34636413Ssklower  * 	ack arrives, the smoothed round-trip time is figured using this value.
34736413Ssklower  * RETURN VALUE:
34836413Ssklower  * 	the highest seq # sent successfully.
34936413Ssklower  */
35036413Ssklower tp_send(tpcb)
35136413Ssklower 	register struct tp_pcb	*tpcb;
35236413Ssklower {
35336413Ssklower 	register int			len;
35436413Ssklower 	register struct mbuf	*m; /* the one we're inspecting now */
35536413Ssklower 	struct mbuf				*mb;/* beginning of this tpdu */
35636413Ssklower 	struct mbuf 			*nextrecord; /* NOT next tpdu but next sb record */
35736413Ssklower 	struct 	sockbuf			*sb = &tpcb->tp_sock->so_snd;
35836413Ssklower 	unsigned int			eotsdu_reached=0;
35936413Ssklower 	SeqNum					lowseq, highseq ;
36036413Ssklower 	SeqNum					lowsave;
36136413Ssklower #ifdef TP_PERF_MEAS
36250236Ssklower 
363*51138Ssklower 	int			 			send_start_time = tick;
36436413Ssklower #endif TP_PERF_MEAS
36536413Ssklower 
36636413Ssklower 	lowsave =  lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1);
36736413Ssklower 
36836413Ssklower 	ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff);
36936413Ssklower 
37036413Ssklower 	if( tpcb->tp_rx_strat & TPRX_USE_CW ) {
37136413Ssklower 			/*first hiseq is temp vbl*/
37236413Ssklower 		highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win);
37336413Ssklower 	} else {
37436413Ssklower 		highseq = tpcb->tp_fcredit;
37536413Ssklower 	}
37636413Ssklower 	highseq = SEQ(tpcb, tpcb->tp_snduna + highseq);
37736413Ssklower 
37836413Ssklower 	SEQ_DEC(tpcb, highseq);
37936413Ssklower 
38036413Ssklower 	IFDEBUG(D_DATA)
38136413Ssklower 		printf(
38236413Ssklower 			"tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n",
38336413Ssklower 			tpcb, lowseq, highseq);
38436413Ssklower 		dump_mbuf(sb->sb_mb, "sb_mb:");
38536413Ssklower 	ENDDEBUG
38636413Ssklower 	IFTRACE(D_DATA)
38736413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna",
38836413Ssklower 			lowsave, tpcb->tp_sndhiwat,  tpcb->tp_snduna, 0);
38936413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin",
39036413Ssklower 			lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
39136413Ssklower 	ENDTRACE
39236413Ssklower 
39336413Ssklower 
39436413Ssklower 	if	( SEQ_GT(tpcb, lowseq, highseq) )
39536413Ssklower 			return ; /* don't send, don't change hiwat, don't set timers */
39636413Ssklower 
39736413Ssklower 	ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) );
39836413Ssklower 	SEQ_DEC(tpcb, lowseq);
39936413Ssklower 
40050901Ssklower 	if (tpcb->tp_Xsnd.sb_mb) {
40150901Ssklower 		IFTRACE(D_XPD)
40250901Ssklower 			tptraceTPCB( TPPTmisc,
40350901Ssklower 				"tp_send XPD mark low high tpcb.Xuna",
40450901Ssklower 				lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0);
40550901Ssklower 		ENDTRACE
40650901Ssklower 		/* stop sending here because there are unacked XPD present
40750901Ssklower 		 */
40850901Ssklower 		IncStat(ts_xpd_intheway);
40950901Ssklower 		goto done;
41050901Ssklower 	}
41136413Ssklower 	IFTRACE(D_DATA)
41236413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin",
41336413Ssklower 			lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
41436413Ssklower 	ENDTRACE
41536413Ssklower 
41650901Ssklower 	if (m = tpcb->tp_sndhiwat_m)
41750901Ssklower 		mb  = m->m_nextpkt;
41850901Ssklower 	else
41950901Ssklower 		mb = sb->sb_mb;
42050901Ssklower 	while ((SEQ_LT(tpcb, lowseq, highseq)) && mb ) {
42136413Ssklower 
42250901Ssklower 		/*
42336413Ssklower 		 * In all cases, m points to mbuf containing first octet to be
42436413Ssklower 		 * sent in the tpdu AFTER the one we're going to send now,
42536413Ssklower 		 * or else m is null.
42636413Ssklower 		 *
42736413Ssklower 		 * The chain we're working on now begins at mb and has length <len>.
42836413Ssklower 		 */
42936413Ssklower 
43050901Ssklower 		eotsdu_reached = (mb->m_flags & M_EOR) != 0;
43150901Ssklower 		len = mb->m_pkthdr.len;
43236413Ssklower 		IFTRACE(D_STASH)
43336413Ssklower 			tptraceTPCB( TPPTmisc,
43436413Ssklower 				"tp_send mcopy low high eotsdu_reached len",
43536413Ssklower 				lowseq, highseq, eotsdu_reached, len);
43636413Ssklower 		ENDTRACE
43736413Ssklower 
43836413Ssklower 		/* make a copy - mb goes into the retransmission list
43936413Ssklower 		 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
44036413Ssklower 		 */
44150901Ssklower 		m = m_copy(mb, 0, M_COPYALL);
44250901Ssklower 		if (m == MNULL)
44336413Ssklower 				goto done;
44436413Ssklower 		SEQ_INC(tpcb,lowseq);	/* it was decremented at the beginning */
44536413Ssklower 		IFTRACE(D_DATA)
44636413Ssklower 			tptraceTPCB( TPPTmisc,
44739196Ssklower 				"tp_send emitting DT lowseq eotsdu_reached len",
44839196Ssklower 				lowseq, eotsdu_reached, len, 0);
44936413Ssklower 		ENDTRACE
45050901Ssklower 		if (mb->m_nextpkt == 0 && tpcb->tp_oktonagle) {
45150901Ssklower 			SEQ_INC(tpcb, tpcb->tp_sndnum);
45250901Ssklower 			tpcb->tp_oktonagle = 0;
45350901Ssklower 			/* when headers are precomputed, may need to fill
45450901Ssklower 			   in checksum here */
45550901Ssklower 		}
45650901Ssklower 		if (tpcb->tp_sock->so_error =
45750901Ssklower 			tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m)) {
45836413Ssklower 			/* error */
45936413Ssklower 			SEQ_DEC(tpcb, lowseq);
46036413Ssklower 			goto done;
46136413Ssklower 		}
462*51138Ssklower 		/* set the transmit-time for computation of round-trip times */
463*51138Ssklower 		if (tpcb->tp_rttemit == 0) {
464*51138Ssklower 			tpcb->tp_rttemit = tick;
465*51138Ssklower 			tpcb->tp_rttseq = lowseq;
466*51138Ssklower 		}
46750901Ssklower 		tpcb->tp_sndhiwat_m = mb;
46850901Ssklower 		mb = mb->m_nextpkt;
46936413Ssklower 	}
47036413Ssklower 
47136413Ssklower done:
47250236Ssklower #ifdef TP_PERF_MEAS
47336413Ssklower 	IFPERF(tpcb)
47436413Ssklower 		{
47536413Ssklower 			register int npkts;
476*51138Ssklower 			int	 elapsed = tick - send_start_time, *t;
477*51138Ssklower 			struct timeval now;
47836413Ssklower 
47936413Ssklower 			npkts = lowseq;
48036413Ssklower 			SEQ_INC(tpcb, npkts);
48136413Ssklower 			npkts = SEQ_SUB(tpcb, npkts, lowsave);
48236413Ssklower 
48336413Ssklower 			if(npkts > 0)
48436413Ssklower 				tpcb->tp_Nwindow++;
48536413Ssklower 
48636413Ssklower 			if (npkts > TP_PM_MAX)
48736413Ssklower 				npkts = TP_PM_MAX;
48836413Ssklower 
48936413Ssklower 			t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
490*51138Ssklower 			*t += (t - elapsed) >> TP_RTT_ALPHA;
49136413Ssklower 
49236413Ssklower 			if ( SEQ_LT(tpcb, lowseq, highseq) ) {
49336413Ssklower 				IncPStat(tpcb, tps_win_lim_by_data[npkts] );
49436413Ssklower 			} else {
49536413Ssklower 				IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
49636413Ssklower 				/* not true with congestion-window being used */
49736413Ssklower 			}
498*51138Ssklower 			now.tv_sec = elapsed / hz;
499*51138Ssklower 			now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz;
50036413Ssklower 			tpmeas( tpcb->tp_lref,
501*51138Ssklower 					TPsbsend, &elapsed, lowsave, tpcb->tp_Nwindow, npkts);
50236413Ssklower 		}
50336413Ssklower 	ENDPERF
50450236Ssklower #endif TP_PERF_MEAS
50536413Ssklower 
50636413Ssklower 	tpcb->tp_sndhiwat = lowseq;
50736413Ssklower 
50836413Ssklower 	if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat)  &&
50936413Ssklower 			(tpcb->tp_class != TP_CLASS_0) )
51036413Ssklower 			tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave,
51136413Ssklower 				tpcb->tp_sndhiwat,
51236413Ssklower 				(u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks);
51336413Ssklower 	IFTRACE(D_DATA)
51436413Ssklower 		tptraceTPCB( TPPTmisc,
51536413Ssklower 			"tp_send at end: sndhiwat lowseq eotsdu_reached error",
51636413Ssklower 			tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error);
51736413Ssklower 
51836413Ssklower 	ENDTRACE
51936413Ssklower }
52036413Ssklower 
52150901Ssklower int TPNagleok;
52250901Ssklower int TPNagled;
52350901Ssklower 
52450901Ssklower tp_packetize(tpcb, m, eotsdu)
52550901Ssklower register struct tp_pcb *tpcb;
52650901Ssklower register struct mbuf *m;
52750901Ssklower int eotsdu;
52850901Ssklower {
52950901Ssklower 	register struct mbuf *n;
53050901Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_snd;
53150901Ssklower 	int	maxsize = tpcb->tp_l_tpdusize
53250901Ssklower 			- tp_headersize(DT_TPDU_type, tpcb)
53350901Ssklower 			- (tpcb->tp_use_checksum?4:0) ;
53450901Ssklower 	int totlen = m->m_pkthdr.len;
53550901Ssklower 	struct mbuf *m_split();
53650901Ssklower 	/*
53750901Ssklower 	 * Pre-packetize the data in the sockbuf
53850901Ssklower 	 * according to negotiated mtu.  Do it here
53950901Ssklower 	 * where we can safely wait for mbufs.
54050901Ssklower 	 *
54150901Ssklower 	 * This presumes knowledge of sockbuf conventions.
54250901Ssklower 	 * TODO: allocate space for header and fill it in (once!).
54350901Ssklower 	 */
54450901Ssklower 	IFTRACE(D_DATA)
54550901Ssklower 		tptraceTPCB(TPPTmisc,
54650901Ssklower 		"SEND BF: maxsize totlen eotsdu",
54750901Ssklower 			maxsize, totlen, eotsdu, 0);
54850901Ssklower 	ENDTRACE
54950901Ssklower 	if (tpcb->tp_oktonagle) {
55050901Ssklower 		if ((n = sb->sb_mb) == 0)
55150901Ssklower 			panic("tp_packetize");
55250901Ssklower 		while (n->m_act)
55350901Ssklower 			n = n->m_act;
55450901Ssklower 		if (n->m_flags & M_EOR)
55550901Ssklower 			panic("tp_packetize 2");
55650901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
55750901Ssklower 		if (totlen + n->m_pkthdr.len < maxsize) {
55850901Ssklower 			/* There is an unsent packet with space, combine data */
55950901Ssklower 			struct mbuf *old_n = n;
56050901Ssklower 			tpsbcheck(tpcb,3);
56150901Ssklower 			n->m_pkthdr.len += totlen;
56250901Ssklower 			while (n->m_next)
56350901Ssklower 				n = n->m_next;
56450901Ssklower 			sbcompress(sb, m, n);
56550901Ssklower 			tpsbcheck(tpcb,4);
56650901Ssklower 			n = old_n;
56750901Ssklower 			TPNagled++;
56850901Ssklower 			goto out;
56950901Ssklower 		}
57050901Ssklower 	}
57150901Ssklower 	while (m) {
57250901Ssklower 		n = m;
57350901Ssklower 		if (totlen > maxsize) {
57450901Ssklower 			if ((m = m_split(n, maxsize, M_WAIT)) == 0)
57550901Ssklower 				panic("tp_packetize");
57650901Ssklower 		} else
57750901Ssklower 			m = 0;
57850901Ssklower 		totlen -= maxsize;
57950901Ssklower 		tpsbcheck(tpcb, 5);
58050901Ssklower 		sbappendrecord(sb, n);
58150901Ssklower 		tpsbcheck(tpcb, 6);
58250901Ssklower 		SEQ_INC(tpcb, tpcb->tp_sndnum);
58350901Ssklower 	}
58450901Ssklower out:
58550901Ssklower 	if (eotsdu) {
58650901Ssklower 		n->m_flags |= M_EOR;  /* XXX belongs at end */
58750901Ssklower 		tpcb->tp_oktonagle = 0;
58850901Ssklower 	} else {
58950901Ssklower 		SEQ_DEC(tpcb, tpcb->tp_sndnum);
59050901Ssklower 		tpcb->tp_oktonagle = 1;
59150901Ssklower 		TPNagleok++;
59250901Ssklower 	}
59350901Ssklower 	return 0;
59450901Ssklower }
59550901Ssklower 
59650901Ssklower 
59736413Ssklower /*
59836413Ssklower  * NAME: tp_stash()
59936413Ssklower  * CALLED FROM:
60036413Ssklower  *	tp.trans on arrival of a DT tpdu
60136413Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
60236413Ssklower  * 	Returns 1 if
60336413Ssklower  *		a) something new arrived and it's got eotsdu_reached bit on,
60436413Ssklower  * 		b) this arrival was caused other out-of-sequence things to be
60536413Ssklower  *    	accepted, or
60636413Ssklower  * 		c) this arrival is the highest seq # for which we last gave credit
60736413Ssklower  *   	(sender just sent a whole window)
60836413Ssklower  *  In other words, returns 1 if tp should send an ack immediately, 0 if
60936413Ssklower  *  the ack can wait a while.
61036413Ssklower  *
61136413Ssklower  * Note: this implementation no longer renegs on credit, (except
61236413Ssklower  * when debugging option D_RENEG is on, for the purpose of testing
61336413Ssklower  * ack subsequencing), so we don't  need to check for incoming tpdus
61436413Ssklower  * being in a reneged portion of the window.
61536413Ssklower  */
61636413Ssklower 
61736413Ssklower tp_stash( tpcb, e )
61836413Ssklower 	register struct tp_pcb		*tpcb;
61936413Ssklower 	register struct tp_event	*e;
62036413Ssklower {
62136413Ssklower 	register int		ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
62236413Ssklower 									/* 0--> delay acks until full window */
62336413Ssklower 									/* 1--> ack each tpdu */
62436413Ssklower #ifndef lint
62536413Ssklower #define E e->ATTR(DT_TPDU)
62636413Ssklower #else lint
62736413Ssklower #define E e->ev_union.EV_DT_TPDU
62836413Ssklower #endif lint
62936413Ssklower 
63036413Ssklower 	if ( E.e_eot ) {
63136413Ssklower 		register struct mbuf *n = E.e_data;
63237469Ssklower 		n->m_flags |= M_EOR;
63338841Ssklower 		n->m_act = 0;
63437469Ssklower 	}
63536413Ssklower 		IFDEBUG(D_STASH)
63636413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
63736413Ssklower 				"stash: so_rcv before appending");
63836413Ssklower 			dump_mbuf(E.e_data,
63936413Ssklower 				"stash: e_data before appending");
64036413Ssklower 		ENDDEBUG
64136413Ssklower 
64236413Ssklower 	IFPERF(tpcb)
64336413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
64436413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
64537469Ssklower 			E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
64636413Ssklower 	ENDPERF
64736413Ssklower 
64851024Ssklower 	if (E.e_seq == tpcb->tp_rcvnxt) {
64936413Ssklower 
65036413Ssklower 		IFDEBUG(D_STASH)
65136413Ssklower 			printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
65236413Ssklower 			E.e_seq, E.e_datalen, E.e_eot);
65336413Ssklower 		ENDDEBUG
65436413Ssklower 
65536413Ssklower 		IFTRACE(D_STASH)
65636413Ssklower 			tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
65736413Ssklower 			E.e_seq, E.e_datalen, E.e_eot, 0);
65836413Ssklower 		ENDTRACE
65936413Ssklower 
66051024Ssklower 		SET_DELACK(tpcb);
66151024Ssklower 
66237469Ssklower 		sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
66337469Ssklower 
66436413Ssklower 		SEQ_INC( tpcb, tpcb->tp_rcvnxt );
66536413Ssklower 		/*
66650901Ssklower 		 * move chains from the reassembly queue to the socket buffer
66736413Ssklower 		 */
66850901Ssklower 		if (tpcb->tp_rsycnt) {
66950901Ssklower 			register struct mbuf **mp;
67050901Ssklower 			struct mbuf **mplim;
67136413Ssklower 
67250901Ssklower 			mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit);
67350901Ssklower 			mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit;
67436413Ssklower 
67550901Ssklower 			while (tpcb->tp_rsycnt && *mp) {
67650901Ssklower 				sbappend(&tpcb->tp_sock->so_rcv, *mp);
67750901Ssklower 				tpcb->tp_rsycnt--;
67850901Ssklower 				*mp = 0;
67950901Ssklower 				SEQ_INC(tpcb, tpcb->tp_rcvnxt);
68036413Ssklower 				ack_reason |= ACK_REORDER;
68150901Ssklower 				if (++mp == mplim)
68250901Ssklower 					mp = tpcb->tp_rsyq;
68336413Ssklower 			}
68436413Ssklower 		}
68536413Ssklower 		IFDEBUG(D_STASH)
68636413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
68736413Ssklower 				"stash: so_rcv after appending");
68836413Ssklower 		ENDDEBUG
68936413Ssklower 
69036413Ssklower 	} else {
69150901Ssklower 		register struct mbuf **mp;
69250901Ssklower 		SeqNum uwe;
69336413Ssklower 
69436413Ssklower 		IFTRACE(D_STASH)
69536413Ssklower 			tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
69636413Ssklower 			E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
69736413Ssklower 		ENDTRACE
69836413Ssklower 
69950975Ssklower 		if (tpcb->tp_rsyq == 0)
70050975Ssklower 			tp_rsyset(tpcb);
70150901Ssklower 		uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit);
70250901Ssklower 		if (tpcb->tp_rsyq == 0 ||
70350901Ssklower 						!IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) {
70436413Ssklower 			ack_reason = ACK_DONT;
70550901Ssklower 			m_freem(E.e_data);
70650901Ssklower 		} else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) {
70736413Ssklower 			IFDEBUG(D_STASH)
70836413Ssklower 				printf("tp_stash - drop & ack\n");
70936413Ssklower 			ENDDEBUG
71036413Ssklower 
71136413Ssklower 			/* retransmission - drop it and force an ack */
71236413Ssklower 			IncStat(ts_dt_dup);
71336413Ssklower 			IFPERF(tpcb)
71436413Ssklower 				IncPStat(tpcb, tps_n_ack_cuz_dup);
71536413Ssklower 			ENDPERF
71636413Ssklower 
71750901Ssklower 			m_freem(E.e_data);
71836413Ssklower 			ack_reason |= ACK_DUP;
71950901Ssklower 		} else {
72050901Ssklower 			*mp = E.e_data;
72150901Ssklower 			tpcb->tp_rsycnt++;
72250901Ssklower 			ack_reason = ACK_DONT;
72336413Ssklower 		}
72436413Ssklower 	}
72551024Ssklower 	/* there were some comments of historical interest here. */
72636413Ssklower 	{
72736413Ssklower 		LOCAL_CREDIT(tpcb);
72836413Ssklower 
72936413Ssklower 		if ( E.e_seq ==  tpcb->tp_sent_uwe )
73036413Ssklower 			ack_reason |= ACK_STRAT_FULLWIN;
73136413Ssklower 
73236413Ssklower 		IFTRACE(D_STASH)
73336413Ssklower 			tptraceTPCB(TPPTmisc,
73436413Ssklower 				"end of stash, eot, ack_reason, sent_uwe ",
73536413Ssklower 				E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
73636413Ssklower 		ENDTRACE
73736413Ssklower 
73836413Ssklower 		if ( ack_reason == ACK_DONT ) {
73936413Ssklower 			IncStat( ts_ackreason[ACK_DONT] );
74036413Ssklower 			return 0;
74136413Ssklower 		} else {
74236413Ssklower 			IFPERF(tpcb)
74336413Ssklower 				if(ack_reason & ACK_STRAT_EACH) {
74436413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_strat);
74536413Ssklower 				} else if(ack_reason & ACK_STRAT_FULLWIN) {
74636413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_fullwin);
74736413Ssklower 				} else if(ack_reason & ACK_REORDER) {
74836413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_reorder);
74936413Ssklower 				}
75036413Ssklower 				tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
75136413Ssklower 							SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
75236413Ssklower 			ENDPERF
75336413Ssklower 			{
75436413Ssklower 				register int i;
75536413Ssklower 
75636413Ssklower 				/* keep track of all reasons that apply */
75736413Ssklower 				for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
75836413Ssklower 					if( ack_reason & (1<<i) )
75936413Ssklower 						IncStat( ts_ackreason[i] );
76036413Ssklower 				}
76136413Ssklower 			}
76236413Ssklower 			return 1;
76336413Ssklower 		}
76436413Ssklower 	}
76536413Ssklower }
76650901Ssklower 
76750901Ssklower /*
76850901Ssklower  * tp_rsyflush - drop all the packets on the reassembly queue.
76950901Ssklower  * Do this when closing the socket, or when somebody has changed
77050901Ssklower  * the space avaible in the receive socket (XXX).
77150901Ssklower  */
77250901Ssklower tp_rsyflush(tpcb)
77350901Ssklower register struct tp_pcb *tpcb;
77450901Ssklower {
77550901Ssklower 	register struct mbuf *m, **mp;
77650901Ssklower 	if (tpcb->tp_rsycnt) {
77750901Ssklower 		for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit;
77850901Ssklower 									 --mp >= tpcb->tp_rsyq; )
77950901Ssklower 			if (*mp) {
78050901Ssklower 				tpcb->tp_rsycnt--;
78150901Ssklower 				m_freem(*mp);
78250901Ssklower 			}
78350901Ssklower 		if (tpcb->tp_rsycnt)
78450901Ssklower 			panic("tp_rsyflush");
78550901Ssklower 	}
78650901Ssklower 	free((caddr_t)tpcb->tp_rsyq, M_PCB);
78750901Ssklower 	tpcb->tp_rsyq = 0;
78850901Ssklower }
78950901Ssklower 
79050901Ssklower tp_rsyset(tpcb)
79150901Ssklower register struct tp_pcb *tpcb;
79250901Ssklower {
79350901Ssklower 	register struct socket *so = tpcb->tp_sock;
79450901Ssklower 	int maxcredit  = tpcb->tp_xtd_format ? 0xffff : 0xf;
79550975Ssklower 	int old_credit = tpcb->tp_maxlcredit;
79650975Ssklower 	caddr_t	rsyq;
79750901Ssklower 
79850901Ssklower 	tpcb->tp_maxlcredit = maxcredit = min(maxcredit,
79950901Ssklower 		  (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize);
80050901Ssklower 
80150975Ssklower 	if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0)
80250975Ssklower 		return;
80350901Ssklower 	maxcredit *= sizeof(struct mbuf *);
80450901Ssklower 	if (tpcb->tp_rsyq)
80550901Ssklower 		tp_rsyflush(tpcb);
80650901Ssklower 	if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT))
80750901Ssklower 		bzero(rsyq, maxcredit);
80850901Ssklower 	tpcb->tp_rsyq = (struct mbuf **)rsyq;
80950901Ssklower }
81050901Ssklower 
81150901Ssklower tpsbcheck(tpcb, i)
81250901Ssklower struct tp_pcb *tpcb;
81350901Ssklower {
81450901Ssklower 	register struct mbuf *n, *m;
81550901Ssklower 	register int len = 0, mbcnt = 0, pktlen;
81650901Ssklower 	struct sockbuf *sb = &tpcb->tp_sock->so_snd;
81750901Ssklower 
81850901Ssklower 	for (n = sb->sb_mb; n; n = n->m_nextpkt) {
81950901Ssklower 		if ((n->m_flags & M_PKTHDR) == 0)
82050901Ssklower 			panic("tpsbcheck nohdr");
82150901Ssklower 		pktlen = len + n->m_pkthdr.len;
82250901Ssklower 	    for (m = n; m; m = m->m_next) {
82350901Ssklower 			len += m->m_len;
82450901Ssklower 			mbcnt += MSIZE;
82550901Ssklower 			if (m->m_flags & M_EXT)
82650901Ssklower 				mbcnt += m->m_ext.ext_size;
82750901Ssklower 		}
82850901Ssklower 		if (len != pktlen) {
82950901Ssklower 			printf("test %d; len %d != pktlen %d on mbuf 0x%x\n",
83050901Ssklower 				i, len, pktlen, n);
83150901Ssklower 			panic("tpsbcheck short");
83250901Ssklower 		}
83350901Ssklower 	}
83450901Ssklower 	if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
83550901Ssklower 		printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc,
83650901Ssklower 		    mbcnt, sb->sb_mbcnt);
83750901Ssklower 		panic("tpsbcheck");
83850901Ssklower 	}
83950901Ssklower }
840