xref: /csrg-svn/sys/netiso/tp_subr.c (revision 36413)
1*36413Ssklower /***********************************************************
2*36413Ssklower 		Copyright IBM Corporation 1987
3*36413Ssklower 
4*36413Ssklower                       All Rights Reserved
5*36413Ssklower 
6*36413Ssklower Permission to use, copy, modify, and distribute this software and its
7*36413Ssklower documentation for any purpose and without fee is hereby granted,
8*36413Ssklower provided that the above copyright notice appear in all copies and that
9*36413Ssklower both that copyright notice and this permission notice appear in
10*36413Ssklower supporting documentation, and that the name of IBM not be
11*36413Ssklower used in advertising or publicity pertaining to distribution of the
12*36413Ssklower software without specific, written prior permission.
13*36413Ssklower 
14*36413Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36413Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36413Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36413Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36413Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36413Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36413Ssklower SOFTWARE.
21*36413Ssklower 
22*36413Ssklower ******************************************************************/
23*36413Ssklower 
24*36413Ssklower /*
25*36413Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36413Ssklower  */
27*36413Ssklower /*
28*36413Ssklower  * ARGO TP
29*36413Ssklower  *
30*36413Ssklower  * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $
31*36413Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $
32*36413Ssklower  *
33*36413Ssklower  * The main work of data transfer is done here.
34*36413Ssklower  * These routines are called from tp.trans.
35*36413Ssklower  * They include the routines that check the validity of acks and Xacks,
36*36413Ssklower  * (tp_goodack() and tp_goodXack() )
37*36413Ssklower  * take packets from socket buffers and send them (tp_send()),
38*36413Ssklower  * drop the data from the socket buffers (tp_sbdrop()),
39*36413Ssklower  * and put incoming packet data into socket buffers (tp_stash()).
40*36413Ssklower  */
41*36413Ssklower 
42*36413Ssklower #ifndef lint
43*36413Ssklower static char *rcsid = "$Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $";
44*36413Ssklower #endif lint
45*36413Ssklower 
46*36413Ssklower #include "param.h"
47*36413Ssklower #include "mbuf.h"
48*36413Ssklower #include "socket.h"
49*36413Ssklower #include "socketvar.h"
50*36413Ssklower #include "protosw.h"
51*36413Ssklower #include "errno.h"
52*36413Ssklower #include "types.h"
53*36413Ssklower #include "time.h"
54*36413Ssklower 
55*36413Ssklower #include "../netiso/tp_ip.h"
56*36413Ssklower #include "../netiso/iso.h"
57*36413Ssklower #include "../netiso/argo_debug.h"
58*36413Ssklower #include "../netiso/tp_timer.h"
59*36413Ssklower #include "../netiso/tp_param.h"
60*36413Ssklower #include "../netiso/tp_stat.h"
61*36413Ssklower #include "../netiso/tp_pcb.h"
62*36413Ssklower #include "../netiso/tp_tpdu.h"
63*36413Ssklower #include "../netiso/tp_trace.h"
64*36413Ssklower #include "../netiso/tp_meas.h"
65*36413Ssklower #include "../netiso/tp_seq.h"
66*36413Ssklower 
67*36413Ssklower int 		tp_emit();
68*36413Ssklower static void tp_sbdrop();
69*36413Ssklower 
70*36413Ssklower #define SMOOTH(newtype, alpha, old, new) \
71*36413Ssklower 	(newtype) (((new - old)>>alpha) + (old))
72*36413Ssklower 
73*36413Ssklower #define ABS(type, val) \
74*36413Ssklower 	(type) (((int)(val)<0)?-(val):(val))
75*36413Ssklower 
76*36413Ssklower #define TP_MAKE_RTC( Xreg, Xseq, Xeot, Xdata, Xlen, Xretval, Xtype) \
77*36413Ssklower { 	struct mbuf *xxn;\
78*36413Ssklower 	MGET(xxn, M_DONTWAIT, Xtype);\
79*36413Ssklower 	if( xxn == (struct mbuf *)0 ) {\
80*36413Ssklower 		printf("MAKE RTC FAILED: ENOBUFS\n");\
81*36413Ssklower 		return (int)Xretval;\
82*36413Ssklower 	}\
83*36413Ssklower 	xxn->m_act=MNULL;\
84*36413Ssklower 	Xreg = mtod(xxn, struct tp_rtc *);\
85*36413Ssklower 	if( Xreg == (struct tp_rtc *)0 ) {\
86*36413Ssklower 		return (int)Xretval;\
87*36413Ssklower 	}\
88*36413Ssklower 	Xreg->tprt_eot = Xeot;\
89*36413Ssklower 	Xreg->tprt_seq = Xseq;\
90*36413Ssklower 	Xreg->tprt_data = Xdata;\
91*36413Ssklower 	Xreg->tprt_octets = Xlen;\
92*36413Ssklower }
93*36413Ssklower 
94*36413Ssklower 
95*36413Ssklower /*
96*36413Ssklower  * CALLED FROM:
97*36413Ssklower  *	tp.trans, when an XAK arrives
98*36413Ssklower  * FUNCTION and ARGUMENTS:
99*36413Ssklower  * 	Determines if the sequence number (seq) from the XAK
100*36413Ssklower  * 	acks anything new.  If so, drop the appropriate tpdu
101*36413Ssklower  * 	from the XPD send queue.
102*36413Ssklower  * RETURN VALUE:
103*36413Ssklower  * 	Returns 1 if it did this, 0 if the ack caused no action.
104*36413Ssklower  */
105*36413Ssklower int
106*36413Ssklower tp_goodXack(tpcb, seq)
107*36413Ssklower 	struct tp_pcb	*tpcb;
108*36413Ssklower 	SeqNum 			seq;
109*36413Ssklower {
110*36413Ssklower 
111*36413Ssklower 	IFTRACE(D_XPD)
112*36413Ssklower 		tptraceTPCB(TPPTgotXack,
113*36413Ssklower 			seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat,
114*36413Ssklower 			tpcb->tp_snduna);
115*36413Ssklower 	ENDTRACE
116*36413Ssklower 
117*36413Ssklower 	if ( seq == tpcb->tp_Xuna ) {
118*36413Ssklower 			tpcb->tp_Xuna = tpcb->tp_Xsndnxt;
119*36413Ssklower 
120*36413Ssklower 			/* DROP 1 packet from the Xsnd socket buf - just so happens
121*36413Ssklower 			 * that only one packet can be there at any time
122*36413Ssklower 			 * so drop the whole thing.  If you allow > 1 packet
123*36413Ssklower 			 * the socket buffer, then you'll have to keep
124*36413Ssklower 			 * track of how many characters went w/ each XPD tpdu, so this
125*36413Ssklower 			 * will get messier
126*36413Ssklower 			 */
127*36413Ssklower 			IFDEBUG(D_XPD)
128*36413Ssklower 				dump_mbuf(tpcb->tp_Xsnd.sb_mb,
129*36413Ssklower 					"tp_goodXack Xsnd before sbdrop");
130*36413Ssklower 			ENDDEBUG
131*36413Ssklower 
132*36413Ssklower 			IFTRACE(D_XPD)
133*36413Ssklower 				tptraceTPCB(TPPTmisc,
134*36413Ssklower 					"goodXack: dropping cc ",
135*36413Ssklower 					(int)(tpcb->tp_Xsnd.sb_cc),
136*36413Ssklower 					0,0,0);
137*36413Ssklower 			ENDTRACE
138*36413Ssklower 			sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc));
139*36413Ssklower 			return 1;
140*36413Ssklower 	}
141*36413Ssklower 	return 0;
142*36413Ssklower }
143*36413Ssklower 
144*36413Ssklower /*
145*36413Ssklower  * CALLED FROM:
146*36413Ssklower  *  tp_good_ack()
147*36413Ssklower  * FUNCTION and ARGUMENTS:
148*36413Ssklower  *  updates
149*36413Ssklower  *  smoothed average round trip time (base_rtt)
150*36413Ssklower  *  roundtrip time variance (base_rtv) - actually deviation, not variance
151*36413Ssklower  *  given the new value (diff)
152*36413Ssklower  * RETURN VALUE:
153*36413Ssklower  * void
154*36413Ssklower  */
155*36413Ssklower 
156*36413Ssklower void
157*36413Ssklower tp_rtt_rtv( base_rtt, base_rtv, newmeas )
158*36413Ssklower 	struct 	timeval *base_rtt, *base_rtv, *newmeas;
159*36413Ssklower {
160*36413Ssklower 	/* update  rt variance (really just the deviation):
161*36413Ssklower 	 * 	rtv.smooth_ave =  SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | )
162*36413Ssklower 	 */
163*36413Ssklower 	base_rtv->tv_sec =
164*36413Ssklower 		SMOOTH( long,  TP_RTV_ALPHA, base_rtv->tv_sec,
165*36413Ssklower 			ABS( long, base_rtv->tv_sec - newmeas->tv_sec ));
166*36413Ssklower 	base_rtv->tv_usec =
167*36413Ssklower 		SMOOTH( long,  TP_RTV_ALPHA, base_rtv->tv_usec,
168*36413Ssklower 			ABS(long, base_rtv->tv_usec - newmeas->tv_usec ));
169*36413Ssklower 
170*36413Ssklower 	/* update smoothed average rtt */
171*36413Ssklower 	base_rtt->tv_sec =
172*36413Ssklower 		SMOOTH( long,  TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec);
173*36413Ssklower 	base_rtt->tv_usec =
174*36413Ssklower 		SMOOTH( long,  TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec);
175*36413Ssklower 
176*36413Ssklower }
177*36413Ssklower 
178*36413Ssklower /*
179*36413Ssklower  * CALLED FROM:
180*36413Ssklower  *  tp.trans when an AK arrives
181*36413Ssklower  * FUNCTION and ARGUMENTS:
182*36413Ssklower  * 	Given (cdt), the credit from the AK tpdu, and
183*36413Ssklower  *	(seq), the sequence number from the AK tpdu,
184*36413Ssklower  *  tp_goodack() determines if the AK acknowledges something in the send
185*36413Ssklower  * 	window, and if so, drops the appropriate packets from the retransmission
186*36413Ssklower  *  list, computes the round trip time, and updates the retransmission timer
187*36413Ssklower  *  based on the new smoothed round trip time.
188*36413Ssklower  * RETURN VALUE:
189*36413Ssklower  * 	Returns 1 if
190*36413Ssklower  * 	EITHER it actually acked something heretofore unacknowledged
191*36413Ssklower  * 	OR no news but the credit should be processed.
192*36413Ssklower  * 	If something heretofore unacked was acked with this sequence number,
193*36413Ssklower  * 	the appropriate tpdus are dropped from the retransmission control list,
194*36413Ssklower  * 	by calling tp_sbdrop().
195*36413Ssklower  * 	No need to see the tpdu itself.
196*36413Ssklower  */
197*36413Ssklower int
198*36413Ssklower tp_goodack(tpcb, cdt, seq, subseq)
199*36413Ssklower 	register struct tp_pcb	*tpcb;
200*36413Ssklower 	u_int					cdt;
201*36413Ssklower 	register SeqNum			seq, subseq;
202*36413Ssklower {
203*36413Ssklower 	int 	old_fcredit = tpcb->tp_fcredit;
204*36413Ssklower 	int 	bang = 0; 	/* bang --> ack for something heretofore unacked */
205*36413Ssklower 
206*36413Ssklower 	IFDEBUG(D_ACKRECV)
207*36413Ssklower 		printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n",
208*36413Ssklower 			seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat);
209*36413Ssklower 	ENDDEBUG
210*36413Ssklower 	IFTRACE(D_ACKRECV)
211*36413Ssklower 		tptraceTPCB(TPPTgotack,
212*36413Ssklower 			seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq);
213*36413Ssklower 	ENDTRACE
214*36413Ssklower 
215*36413Ssklower 	IFPERF(tpcb)
216*36413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, 0, seq, 0, 0);
217*36413Ssklower 	ENDPERF
218*36413Ssklower 
219*36413Ssklower 	if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) {
220*36413Ssklower 		/* discard the ack */
221*36413Ssklower 		IFTRACE(D_ACKRECV)
222*36413Ssklower 			tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq",
223*36413Ssklower 				subseq, tpcb->tp_r_subseq, 0, 0);
224*36413Ssklower 		ENDTRACE
225*36413Ssklower 		return 0;
226*36413Ssklower 	} else {
227*36413Ssklower 		tpcb->tp_r_subseq = subseq;
228*36413Ssklower 	}
229*36413Ssklower 
230*36413Ssklower 	if ( IN_SWINDOW(tpcb, seq,
231*36413Ssklower 			tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) {
232*36413Ssklower 
233*36413Ssklower 		IFDEBUG(D_XPD)
234*36413Ssklower 			dump_mbuf(tpcb->tp_sock->so_snd.sb_mb,
235*36413Ssklower 				"tp_goodack snd before sbdrop");
236*36413Ssklower 		ENDDEBUG
237*36413Ssklower 		tp_sbdrop(tpcb, SEQ_SUB(tpcb, seq, 1) );
238*36413Ssklower 
239*36413Ssklower 		/* increase congestion window but don't let it get too big */
240*36413Ssklower 		{
241*36413Ssklower 			register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf;
242*36413Ssklower 
243*36413Ssklower 			if( ++tpcb->tp_cong_win > maxcdt )
244*36413Ssklower 				tpcb->tp_cong_win = maxcdt;
245*36413Ssklower 		}
246*36413Ssklower 
247*36413Ssklower 		/* Compute smoothed round trip time.
248*36413Ssklower 		 * Only measure rtt for tp_snduna if tp_snduna was among
249*36413Ssklower 		 * the last TP_RTT_NUM seq numbers sent.
250*36413Ssklower 		 */
251*36413Ssklower 		if (SEQ_GEQ(tpcb, tpcb->tp_snduna,
252*36413Ssklower 			SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM))) {
253*36413Ssklower 
254*36413Ssklower 			struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM];
255*36413Ssklower 			struct timeval x;
256*36413Ssklower 
257*36413Ssklower 			GET_TIME_SINCE(t, &x);
258*36413Ssklower 
259*36413Ssklower 			tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x );
260*36413Ssklower 
261*36413Ssklower 			{	/* update the global rtt, rtv stats */
262*36413Ssklower 				register int i =
263*36413Ssklower 				   (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
264*36413Ssklower 				tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x );
265*36413Ssklower 
266*36413Ssklower 				IFTRACE(D_RTT)
267*36413Ssklower 					tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0);
268*36413Ssklower 				ENDTRACE
269*36413Ssklower 			}
270*36413Ssklower 
271*36413Ssklower 			IFTRACE(D_RTT)
272*36413Ssklower 				tptraceTPCB(TPPTmisc,
273*36413Ssklower 				"Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime",
274*36413Ssklower 				tpcb->tp_snduna, time.tv_sec, time.tv_usec,
275*36413Ssklower 					tpcb->tp_peer_acktime);
276*36413Ssklower 
277*36413Ssklower 				tptraceTPCB(TPPTmisc,
278*36413Ssklower 				"(secs): emittime diff(x) rtt, rtv",
279*36413Ssklower 					t->tv_sec,
280*36413Ssklower 					x.tv_sec,
281*36413Ssklower 					tpcb->tp_rtt.tv_sec,
282*36413Ssklower 					tpcb->tp_rtv.tv_sec);
283*36413Ssklower 				tptraceTPCB(TPPTmisc,
284*36413Ssklower 				"(usecs): emittime diff(x) rtt rtv",
285*36413Ssklower 					t->tv_usec,
286*36413Ssklower 					x.tv_usec,
287*36413Ssklower 					tpcb->tp_rtt.tv_usec,
288*36413Ssklower 					tpcb->tp_rtv.tv_usec);
289*36413Ssklower 			ENDTRACE
290*36413Ssklower 
291*36413Ssklower 			{
292*36413Ssklower 				/* Update data retransmission timer based on the smoothed
293*36413Ssklower 				 * round trip time, peer ack time, and the pseudo-arbitrary
294*36413Ssklower 				 * number 4.
295*36413Ssklower 				 * new ticks: avg rtt + 2*dev
296*36413Ssklower 				 * rtt, rtv are in microsecs, and ticks are 500 ms
297*36413Ssklower 				 * so 1 tick = 500*1000 us = 500000 us
298*36413Ssklower 				 * so ticks = (rtt + 2 rtv)/500000
299*36413Ssklower 				 * with ticks no les than peer ack time and no less than 4
300*36413Ssklower 				 */
301*36413Ssklower 
302*36413Ssklower 				int rtt = tpcb->tp_rtt.tv_usec +
303*36413Ssklower 					tpcb->tp_rtt.tv_sec*1000000;
304*36413Ssklower 				int rtv = tpcb->tp_rtv.tv_usec +
305*36413Ssklower 					tpcb->tp_rtv.tv_sec*1000000;
306*36413Ssklower 
307*36413Ssklower 				IFTRACE(D_RTT)
308*36413Ssklower 					tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks",
309*36413Ssklower 						tpcb->tp_dt_ticks,
310*36413Ssklower 						rtv, rtt,
311*36413Ssklower 						(rtt/500000 + (2 * rtv)/500000));
312*36413Ssklower 				ENDTRACE
313*36413Ssklower 				tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000;
314*36413Ssklower 				tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks,
315*36413Ssklower 					tpcb->tp_peer_acktime);
316*36413Ssklower 				tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks,  4);
317*36413Ssklower 			}
318*36413Ssklower 		}
319*36413Ssklower 		tpcb->tp_snduna = seq;
320*36413Ssklower 
321*36413Ssklower 		bang++;
322*36413Ssklower 	}
323*36413Ssklower 
324*36413Ssklower 	if( cdt != 0 && old_fcredit == 0 ) {
325*36413Ssklower 		tpcb->tp_sendfcc = 1;
326*36413Ssklower 	}
327*36413Ssklower 	if( cdt == 0 && old_fcredit != 0 ) {
328*36413Ssklower 		IncStat(ts_zfcdt);
329*36413Ssklower 	}
330*36413Ssklower 	tpcb->tp_fcredit = cdt;
331*36413Ssklower 
332*36413Ssklower 	IFDEBUG(D_ACKRECV)
333*36413Ssklower 		printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n",
334*36413Ssklower 			(bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit );
335*36413Ssklower 	ENDDEBUG
336*36413Ssklower 
337*36413Ssklower 	return (bang || (old_fcredit < cdt)) ;
338*36413Ssklower }
339*36413Ssklower 
340*36413Ssklower /*
341*36413Ssklower  * CALLED FROM:
342*36413Ssklower  *  tp_goodack()
343*36413Ssklower  * FUNCTION and ARGUMENTS:
344*36413Ssklower  *  drops everything up TO and INCLUDING seq # (seq)
345*36413Ssklower  *  from the retransmission queue.
346*36413Ssklower  */
347*36413Ssklower static void
348*36413Ssklower tp_sbdrop(tpcb, seq)
349*36413Ssklower 	struct 	tp_pcb 			*tpcb;
350*36413Ssklower 	SeqNum					seq;
351*36413Ssklower {
352*36413Ssklower 	register struct tp_rtc	*s = tpcb->tp_snduna_rtc;
353*36413Ssklower 
354*36413Ssklower 	IFDEBUG(D_ACKRECV)
355*36413Ssklower 		printf("tp_sbdrop up through seq 0x%x\n", seq);
356*36413Ssklower 	ENDDEBUG
357*36413Ssklower 	while (s != (struct tp_rtc *)0 && (SEQ_LEQ(tpcb, s->tprt_seq, seq))) {
358*36413Ssklower 		m_freem( s->tprt_data );
359*36413Ssklower 		tpcb->tp_snduna_rtc = s->tprt_next;
360*36413Ssklower 		(void) m_free( dtom( s ) );
361*36413Ssklower 		s = tpcb->tp_snduna_rtc;
362*36413Ssklower 	}
363*36413Ssklower 	if(tpcb->tp_snduna_rtc == (struct tp_rtc *)0)
364*36413Ssklower 		tpcb->tp_sndhiwat_rtc = (struct tp_rtc *) 0;
365*36413Ssklower 
366*36413Ssklower }
367*36413Ssklower 
368*36413Ssklower /*
369*36413Ssklower  * CALLED FROM:
370*36413Ssklower  * 	tp.trans on user send request, arrival of AK and arrival of XAK
371*36413Ssklower  * FUNCTION and ARGUMENTS:
372*36413Ssklower  * 	Emits tpdus starting at sequence number (lowseq).
373*36413Ssklower  * 	Emits until a) runs out of data, or  b) runs into an XPD mark, or
374*36413Ssklower  * 			c) it hits seq number (highseq)
375*36413Ssklower  * 	Removes the octets from the front of the socket buffer
376*36413Ssklower  * 	and repackages them in one mbuf chain per tpdu.
377*36413Ssklower  * 	Moves the mbuf chain to the doubly linked list that runs from
378*36413Ssklower  * 	tpcb->tp_sndhiwat_rtc to tpcb->tp_snduna_rtc.
379*36413Ssklower  *
380*36413Ssklower  * 	Creates tpdus that are no larger than <tpcb->tp_l_tpdusize - headersize>,
381*36413Ssklower  *
382*36413Ssklower  * 	If you want XPD to buffer > 1 du per socket buffer, you can
383*36413Ssklower  * 	modifiy this to issue XPD tpdus also, but then it'll have
384*36413Ssklower  * 	to take some argument(s) to distinguish between the type of DU to
385*36413Ssklower  * 	hand tp_emit, the socket buffer from which to get the data, and
386*36413Ssklower  * 	the chain of tp_rtc structures on which to put the data sent.
387*36413Ssklower  *
388*36413Ssklower  * 	When something is sent for the first time, its time-of-send
389*36413Ssklower  * 	is stashed (the last RTT_NUM of them are stashed).  When the
390*36413Ssklower  * 	ack arrives, the smoothed round-trip time is figured using this value.
391*36413Ssklower  * RETURN VALUE:
392*36413Ssklower  * 	the highest seq # sent successfully.
393*36413Ssklower  */
394*36413Ssklower 
395*36413Ssklower /* For xpd marks we use mbufs of a special type with length 0;
396*36413Ssklower  * the m_next field is really the seq number of the xpd tpdu that
397*36413Ssklower  * must be acked before more normal data may be sent
398*36413Ssklower  */
399*36413Ssklower 
400*36413Ssklower tp_send(tpcb)
401*36413Ssklower 	register struct tp_pcb	*tpcb;
402*36413Ssklower {
403*36413Ssklower 	register int			len;
404*36413Ssklower 	register struct mbuf	*m; /* the one we're inspecting now */
405*36413Ssklower 	struct mbuf				*mb;/* beginning of this tpdu */
406*36413Ssklower 	register struct mbuf	**n;/* link field we'll be modifying when we
407*36413Ssklower 								take mb-->m out of the socket buffer */
408*36413Ssklower 	struct mbuf 			*nextrecord; /* NOT next tpdu but next sb record */
409*36413Ssklower 	struct 	sockbuf			*sb = &tpcb->tp_sock->so_snd;
410*36413Ssklower 	int						maxsize = tpcb->tp_l_tpdusize
411*36413Ssklower 										- tp_headersize(DT_TPDU_type, tpcb)
412*36413Ssklower 										- (tpcb->tp_use_checksum?4:0) ;
413*36413Ssklower 	unsigned int			eotsdu_reached=0;
414*36413Ssklower 	SeqNum					lowseq, highseq ;
415*36413Ssklower 	SeqNum					lowsave;
416*36413Ssklower #ifdef TP_PERF_MEAS
417*36413Ssklower 	struct timeval 			send_start_time;
418*36413Ssklower #endif TP_PERF_MEAS
419*36413Ssklower 
420*36413Ssklower 	lowsave =  lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1);
421*36413Ssklower 
422*36413Ssklower 	ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff);
423*36413Ssklower 
424*36413Ssklower 	if( tpcb->tp_rx_strat & TPRX_USE_CW ) {
425*36413Ssklower 			/*first hiseq is temp vbl*/
426*36413Ssklower 		highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win);
427*36413Ssklower 	} else {
428*36413Ssklower 		highseq = tpcb->tp_fcredit;
429*36413Ssklower 	}
430*36413Ssklower 	highseq = SEQ(tpcb, tpcb->tp_snduna + highseq);
431*36413Ssklower 
432*36413Ssklower 	SEQ_DEC(tpcb, highseq);
433*36413Ssklower 
434*36413Ssklower 	IFDEBUG(D_DATA)
435*36413Ssklower 		printf(
436*36413Ssklower 			"tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n",
437*36413Ssklower 			tpcb, lowseq, highseq);
438*36413Ssklower 		dump_mbuf(sb->sb_mb, "sb_mb:");
439*36413Ssklower 	ENDDEBUG
440*36413Ssklower 	IFTRACE(D_DATA)
441*36413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna",
442*36413Ssklower 			lowsave, tpcb->tp_sndhiwat,  tpcb->tp_snduna, 0);
443*36413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin",
444*36413Ssklower 			lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
445*36413Ssklower 	ENDTRACE
446*36413Ssklower 
447*36413Ssklower 
448*36413Ssklower 	if	( SEQ_GT(tpcb, lowseq, highseq) )
449*36413Ssklower 			return ; /* don't send, don't change hiwat, don't set timers */
450*36413Ssklower 
451*36413Ssklower 	IFPERF(tpcb)
452*36413Ssklower 		GET_CUR_TIME(&send_start_time);
453*36413Ssklower 	ENDPERF
454*36413Ssklower 
455*36413Ssklower 	ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) );
456*36413Ssklower 	SEQ_DEC(tpcb, lowseq);
457*36413Ssklower 
458*36413Ssklower 	IFTRACE(D_DATA)
459*36413Ssklower 		tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin",
460*36413Ssklower 			lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
461*36413Ssklower 	ENDTRACE
462*36413Ssklower 
463*36413Ssklower 	while( SEQ_LT( tpcb, lowseq, highseq ) ) {
464*36413Ssklower 		mb = m = sb->sb_mb;
465*36413Ssklower 		if (m == (struct mbuf *)0) {
466*36413Ssklower 			break; /* empty socket buffer */
467*36413Ssklower 		}
468*36413Ssklower 		if ( m->m_type == TPMT_XPD ) {
469*36413Ssklower 			register SeqNum Xuna = * (mtod(m, SeqNum *));
470*36413Ssklower 			register struct mbuf *mnext = MNULL;
471*36413Ssklower 			IFTRACE(D_XPD)
472*36413Ssklower 				tptraceTPCB( TPPTmisc,
473*36413Ssklower 					"tp_send XPD mark low high tpcb.Xuna",
474*36413Ssklower 					Xuna, lowseq, highseq, tpcb->tp_Xuna);
475*36413Ssklower 			ENDTRACE
476*36413Ssklower 			if( SEQ_GEQ(tpcb, Xuna, tpcb->tp_Xuna))  {
477*36413Ssklower 				/* stop sending here because there are unacked XPD which were
478*36413Ssklower 				 * given to us before the next data were. Leave mark in place.
479*36413Ssklower 				 */
480*36413Ssklower 				IncStat(ts_xpd_intheway);
481*36413Ssklower 				break;
482*36413Ssklower 			}
483*36413Ssklower 			/* otherwise, mark is obsolete; delete it */
484*36413Ssklower 			sbfree(sb, m); /* have to do this to delete the sb_mbcnt */
485*36413Ssklower 			sb->sb_mb = m->m_act;
486*36413Ssklower 			IncStat(ts_xpdmark_del);
487*36413Ssklower 			if( mnext = m_free(m) ) {
488*36413Ssklower 				IFTRACE(D_XPD)
489*36413Ssklower 					tptraceTPCB( TPPTmisc,
490*36413Ssklower 						"tp_send XPD mark deleted mnext old_act new_act",
491*36413Ssklower 						mnext, sb->sb_mb, mnext->m_act, 0);
492*36413Ssklower 				ENDTRACE
493*36413Ssklower 				IFDEBUG(D_XPD)
494*36413Ssklower 					printf(
495*36413Ssklower 			"tp_send XPD mark deleted mnext 0x%x old act 0x%x new act 0x%x\n",
496*36413Ssklower 						mnext, sb->sb_mb, mnext->m_act, 0);
497*36413Ssklower 				ENDDEBUG
498*36413Ssklower 				mnext->m_act = sb->sb_mb;
499*36413Ssklower 				sb->sb_mb = mnext;
500*36413Ssklower 			}
501*36413Ssklower 			continue;
502*36413Ssklower 		}
503*36413Ssklower 		n  = &sb->sb_mb;
504*36413Ssklower 		eotsdu_reached = 0;
505*36413Ssklower 		len =  0;
506*36413Ssklower 		nextrecord = m->m_act;
507*36413Ssklower 		while ( eotsdu_reached == 0  &&  len < maxsize  && m != MNULL) {
508*36413Ssklower 			*n = m; /* meaningless first time through the loop */
509*36413Ssklower 			len += m->m_len;
510*36413Ssklower 			if ( len > maxsize ) {
511*36413Ssklower 				/*
512*36413Ssklower 				 * Won't use the whole mbuf - split into 2 mbufs.
513*36413Ssklower 				 */
514*36413Ssklower 				int amount = m->m_len + maxsize - len;
515*36413Ssklower 				struct mbuf *mx;
516*36413Ssklower 
517*36413Ssklower 				/* copy the part we are NOT using and put that back in the
518*36413Ssklower 				 * socket buf; leave m with this tpdu chain; adjust its fields
519*36413Ssklower 				 */
520*36413Ssklower 				IFTRACE(D_STASH)
521*36413Ssklower 					tptraceTPCB(TPPTmisc,
522*36413Ssklower 					"tp_send SPLIT len, amount, m->m_len, tpdusize",
523*36413Ssklower 						len, amount, m->m_len, maxsize);
524*36413Ssklower 				ENDTRACE
525*36413Ssklower 				mx = m_copy(m, amount, m->m_len - amount); /* preserves type */
526*36413Ssklower 				mx->m_next = m->m_next;
527*36413Ssklower 				mx->m_act = m->m_act; /* preserve */
528*36413Ssklower 
529*36413Ssklower 				CHANGE_MTYPE(m, TPMT_DATA);
530*36413Ssklower 				m->m_next = (struct mbuf *)0;
531*36413Ssklower 				m->m_act = (struct mbuf *)0; /* not strictly necessary */
532*36413Ssklower 				m->m_len = amount;
533*36413Ssklower 
534*36413Ssklower 				/* would do an sbfree but don't want the mbcnt to be
535*36413Ssklower 				 * decremented since it was never sballoced
536*36413Ssklower 				 */
537*36413Ssklower 				sb->sb_cc -= amount;
538*36413Ssklower 				len = maxsize;
539*36413Ssklower 				m = mx;
540*36413Ssklower 				break;
541*36413Ssklower 			}
542*36413Ssklower 
543*36413Ssklower 			/* going to use the whole mbuf */
544*36413Ssklower 			IFTRACE(D_STASH)
545*36413Ssklower 				tptraceTPCB(TPPTmisc, "tp_send whole mbuf: m_len len maxsize",
546*36413Ssklower 					 0, m->m_len, len, maxsize);
547*36413Ssklower 			ENDTRACE
548*36413Ssklower 
549*36413Ssklower 			if ( m->m_type == TPMT_EOT )
550*36413Ssklower 				eotsdu_reached = 1;
551*36413Ssklower 
552*36413Ssklower 			sbfree(sb, m); /* reduce counts in socket buffer */
553*36413Ssklower 			n = &m->m_next;
554*36413Ssklower 			m = m->m_next;
555*36413Ssklower 
556*36413Ssklower 			*n = (struct mbuf *)0;  /* unlink the to-be-sent stuff from
557*36413Ssklower 				the stuff still in the sb_mb so when we do the m_free
558*36413Ssklower 				it won't clobber part of the socket buffer */
559*36413Ssklower 		}
560*36413Ssklower 
561*36413Ssklower 		if ( len == 0 && !eotsdu_reached) {
562*36413Ssklower 			/* THIS SHOULD NEVER HAPPEN! */
563*36413Ssklower 			ASSERT( 0 );
564*36413Ssklower 			goto done;
565*36413Ssklower 		}
566*36413Ssklower 
567*36413Ssklower 		/* sb_mb is non-null */
568*36413Ssklower 		if(m) {
569*36413Ssklower 			sb->sb_mb = m;
570*36413Ssklower 			if(nextrecord != m)
571*36413Ssklower 				m->m_act = nextrecord;
572*36413Ssklower 		} else
573*36413Ssklower 			sb->sb_mb = nextrecord;
574*36413Ssklower 
575*36413Ssklower 		/* If we arrive here one of the following holds:
576*36413Ssklower 		 * 1. We have exactly <maxsize> octets of whole mbufs,
577*36413Ssklower 		 * 2. We accumulated <maxsize> octets using partial mbufs,
578*36413Ssklower 		 * 3. We found an TPMT_EOT or an XPD mark
579*36413Ssklower 		 * 4. We hit the end of a chain through m_next.
580*36413Ssklower 		 *    In this case, we'd LIKE to continue with the next record,
581*36413Ssklower 		 *    but for the time being, for simplicity, we'll stop here.
582*36413Ssklower 		 * In all cases, m points to mbuf containing first octet to be
583*36413Ssklower 		 * sent in the tpdu AFTER the one we're going to send now,
584*36413Ssklower 		 * or else m is null.
585*36413Ssklower 		 *
586*36413Ssklower 		 * The chain we're working on now begins at mb and has length <len>.
587*36413Ssklower 		 */
588*36413Ssklower 
589*36413Ssklower 		IFTRACE(D_STASH)
590*36413Ssklower 			tptraceTPCB( TPPTmisc,
591*36413Ssklower 				"tp_send mcopy low high eotsdu_reached len",
592*36413Ssklower 				lowseq, highseq, eotsdu_reached, len);
593*36413Ssklower 		ENDTRACE
594*36413Ssklower 
595*36413Ssklower 		/* make a copy - mb goes into the retransmission list
596*36413Ssklower 		 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
597*36413Ssklower 		 */
598*36413Ssklower 		if(len) {
599*36413Ssklower 			if( (m = m_copy(mb, 0, len )) == MNULL ) {
600*36413Ssklower 				goto done;
601*36413Ssklower 			}
602*36413Ssklower 		} else {
603*36413Ssklower 			/* eotsdu reached */
604*36413Ssklower 			MGET(m, M_WAIT, TPMT_DATA);
605*36413Ssklower 			if (m == NULL)
606*36413Ssklower 				goto done;
607*36413Ssklower 			m->m_len = 0;
608*36413Ssklower 			m->m_act = MNULL;
609*36413Ssklower 		}
610*36413Ssklower 
611*36413Ssklower 		SEQ_INC(tpcb,lowseq);	/* it was decremented at the beginning */
612*36413Ssklower 		{
613*36413Ssklower 			struct tp_rtc *t;
614*36413Ssklower 			/* make an rtc and put it at the end of the chain */
615*36413Ssklower 
616*36413Ssklower 			TP_MAKE_RTC( t, lowseq, eotsdu_reached, mb, len, lowseq,
617*36413Ssklower 				TPMT_SNDRTC);
618*36413Ssklower 			t->tprt_next = (struct tp_rtc *)0;
619*36413Ssklower 
620*36413Ssklower 			if ( tpcb->tp_sndhiwat_rtc != (struct tp_rtc *)0 )
621*36413Ssklower 				tpcb->tp_sndhiwat_rtc->tprt_next = t;
622*36413Ssklower 			else {
623*36413Ssklower 				ASSERT( tpcb->tp_snduna_rtc == (struct tp_rtc *)0 );
624*36413Ssklower 				tpcb->tp_snduna_rtc = t;
625*36413Ssklower 			}
626*36413Ssklower 
627*36413Ssklower 			tpcb->tp_sndhiwat_rtc = t;
628*36413Ssklower 		}
629*36413Ssklower 
630*36413Ssklower 		IFTRACE(D_DATA)
631*36413Ssklower 			tptraceTPCB( TPPTmisc,
632*36413Ssklower 				"tp_send emitting DT lowseq eotsdu_reached",
633*36413Ssklower 				lowseq, eotsdu_reached, 0, 0);
634*36413Ssklower 		ENDTRACE
635*36413Ssklower 		if( tpcb->tp_sock->so_error =
636*36413Ssklower 			tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m) )  {
637*36413Ssklower 			/* error */
638*36413Ssklower 			SEQ_DEC(tpcb, lowseq);
639*36413Ssklower 			goto done;
640*36413Ssklower 		}
641*36413Ssklower 		/* set the transmit-time for computation of round-trip times */
642*36413Ssklower 		bcopy( (caddr_t)&time,
643*36413Ssklower 				(caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ),
644*36413Ssklower 				sizeof(struct timeval));
645*36413Ssklower 
646*36413Ssklower 	}
647*36413Ssklower 
648*36413Ssklower done:
649*36413Ssklower 	IFPERF(tpcb)
650*36413Ssklower 		{
651*36413Ssklower 			register int npkts;
652*36413Ssklower 			struct timeval send_end_time;
653*36413Ssklower 			register struct timeval *t;
654*36413Ssklower 
655*36413Ssklower 			npkts = lowseq;
656*36413Ssklower 			SEQ_INC(tpcb, npkts);
657*36413Ssklower 			npkts = SEQ_SUB(tpcb, npkts, lowsave);
658*36413Ssklower 
659*36413Ssklower 			if(npkts > 0)
660*36413Ssklower 				tpcb->tp_Nwindow++;
661*36413Ssklower 
662*36413Ssklower 			if (npkts > TP_PM_MAX)
663*36413Ssklower 				npkts = TP_PM_MAX;
664*36413Ssklower 
665*36413Ssklower 			GET_TIME_SINCE(&send_start_time, &send_end_time);
666*36413Ssklower 			t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
667*36413Ssklower 			t->tv_sec =
668*36413Ssklower 				SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec);
669*36413Ssklower 			t->tv_usec =
670*36413Ssklower 				SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec);
671*36413Ssklower 
672*36413Ssklower 			if ( SEQ_LT(tpcb, lowseq, highseq) ) {
673*36413Ssklower 				IncPStat(tpcb, tps_win_lim_by_data[npkts] );
674*36413Ssklower 			} else {
675*36413Ssklower 				IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
676*36413Ssklower 				/* not true with congestion-window being used */
677*36413Ssklower 			}
678*36413Ssklower 			tpmeas( tpcb->tp_lref,
679*36413Ssklower 					TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts);
680*36413Ssklower 		}
681*36413Ssklower 	ENDPERF
682*36413Ssklower 
683*36413Ssklower 	tpcb->tp_sndhiwat = lowseq;
684*36413Ssklower 
685*36413Ssklower 	if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat)  &&
686*36413Ssklower 			(tpcb->tp_class != TP_CLASS_0) )
687*36413Ssklower 			tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave,
688*36413Ssklower 				tpcb->tp_sndhiwat,
689*36413Ssklower 				(u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks);
690*36413Ssklower 	IFTRACE(D_DATA)
691*36413Ssklower 		tptraceTPCB( TPPTmisc,
692*36413Ssklower 			"tp_send at end: sndhiwat lowseq eotsdu_reached error",
693*36413Ssklower 			tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error);
694*36413Ssklower 
695*36413Ssklower 	ENDTRACE
696*36413Ssklower }
697*36413Ssklower 
698*36413Ssklower /*
699*36413Ssklower  * NAME: tp_stash()
700*36413Ssklower  * CALLED FROM:
701*36413Ssklower  *	tp.trans on arrival of a DT tpdu
702*36413Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
703*36413Ssklower  * 	Returns 1 if
704*36413Ssklower  *		a) something new arrived and it's got eotsdu_reached bit on,
705*36413Ssklower  * 		b) this arrival was caused other out-of-sequence things to be
706*36413Ssklower  *    	accepted, or
707*36413Ssklower  * 		c) this arrival is the highest seq # for which we last gave credit
708*36413Ssklower  *   	(sender just sent a whole window)
709*36413Ssklower  *  In other words, returns 1 if tp should send an ack immediately, 0 if
710*36413Ssklower  *  the ack can wait a while.
711*36413Ssklower  *
712*36413Ssklower  * Note: this implementation no longer renegs on credit, (except
713*36413Ssklower  * when debugging option D_RENEG is on, for the purpose of testing
714*36413Ssklower  * ack subsequencing), so we don't  need to check for incoming tpdus
715*36413Ssklower  * being in a reneged portion of the window.
716*36413Ssklower  */
717*36413Ssklower 
718*36413Ssklower int
719*36413Ssklower tp_stash( tpcb, e )
720*36413Ssklower 	register struct tp_pcb		*tpcb;
721*36413Ssklower 	register struct tp_event	*e;
722*36413Ssklower {
723*36413Ssklower 	register int		ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
724*36413Ssklower 									/* 0--> delay acks until full window */
725*36413Ssklower 									/* 1--> ack each tpdu */
726*36413Ssklower 	int		newrec = 0;
727*36413Ssklower 
728*36413Ssklower #ifndef lint
729*36413Ssklower #define E e->ATTR(DT_TPDU)
730*36413Ssklower #else lint
731*36413Ssklower #define E e->ev_union.EV_DT_TPDU
732*36413Ssklower #endif lint
733*36413Ssklower 
734*36413Ssklower 	if ( E.e_eot ) {
735*36413Ssklower 		register struct mbuf *n = E.e_data;
736*36413Ssklower 
737*36413Ssklower 		/* sigh. have to go through this again! */
738*36413Ssklower 		/* a kludgy optimization would be to take care of this in
739*36413Ssklower 		 * tp_input (oh, horrors!)
740*36413Ssklower 		 * BTW, don't set ack_reason here because we don't know if the
741*36413Ssklower 		 * sequence number is right
742*36413Ssklower 		 */
743*36413Ssklower 		while (n->m_next )
744*36413Ssklower 			n = n->m_next;
745*36413Ssklower 
746*36413Ssklower 		n->m_act = MNULL; /* set on tp_input */
747*36413Ssklower 		CHANGE_MTYPE(n, TPMT_EOT);
748*36413Ssklower 
749*36413Ssklower 		IFDEBUG(D_STASH)
750*36413Ssklower 			printf("EOT! changing m_type of m 0x%x\n",  n);
751*36413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
752*36413Ssklower 				"stash: so_rcv before appending");
753*36413Ssklower 			dump_mbuf(E.e_data,
754*36413Ssklower 				"stash: e_data before appending");
755*36413Ssklower 		ENDDEBUG
756*36413Ssklower 	}
757*36413Ssklower 
758*36413Ssklower 	IFPERF(tpcb)
759*36413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
760*36413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
761*36413Ssklower 				E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
762*36413Ssklower 	ENDPERF
763*36413Ssklower 
764*36413Ssklower 	if( E.e_seq == tpcb->tp_rcvnxt ) {
765*36413Ssklower 
766*36413Ssklower 		IFDEBUG(D_STASH)
767*36413Ssklower 			printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
768*36413Ssklower 			E.e_seq, E.e_datalen, E.e_eot);
769*36413Ssklower 		ENDDEBUG
770*36413Ssklower 
771*36413Ssklower 		IFTRACE(D_STASH)
772*36413Ssklower 			tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
773*36413Ssklower 			E.e_seq, E.e_datalen, E.e_eot, 0);
774*36413Ssklower 		ENDTRACE
775*36413Ssklower 
776*36413Ssklower 		if( E.e_datalen == 0 && E.e_eot ) {
777*36413Ssklower 			IFDEBUG(D_STASH)
778*36413Ssklower 				printf("stash EQ: appendrec\n");
779*36413Ssklower 			ENDDEBUG
780*36413Ssklower 			sbappendrecord (&tpcb->tp_sock->so_rcv, E.e_data);
781*36413Ssklower 			/* 'cause sbappend won't append something of length zero */
782*36413Ssklower 		} else {
783*36413Ssklower 			IFDEBUG(D_STASH)
784*36413Ssklower 				printf("stash EQ: plain old append\n");
785*36413Ssklower 			ENDDEBUG
786*36413Ssklower 			sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
787*36413Ssklower 		}
788*36413Ssklower 		if (newrec = E.e_eot ) /* ASSIGNMENT */
789*36413Ssklower 			ack_reason |= ACK_EOT;
790*36413Ssklower 
791*36413Ssklower 		SEQ_INC( tpcb, tpcb->tp_rcvnxt );
792*36413Ssklower 		/*
793*36413Ssklower 		 * move chains from the rtc list to the socket buffer
794*36413Ssklower 		 * and free the rtc header
795*36413Ssklower 		 */
796*36413Ssklower 		{
797*36413Ssklower 			register struct tp_rtc	**r =  &tpcb->tp_rcvnxt_rtc;
798*36413Ssklower 			register struct tp_rtc	*s = tpcb->tp_rcvnxt_rtc;
799*36413Ssklower 
800*36413Ssklower 			while (s != (struct tp_rtc *)0 && s->tprt_seq == tpcb->tp_rcvnxt) {
801*36413Ssklower 				*r = s->tprt_next;
802*36413Ssklower 
803*36413Ssklower 				if ( newrec ) {
804*36413Ssklower 					sbappendrecord(&tpcb->tp_sock->so_rcv, s->tprt_data);
805*36413Ssklower 				} else
806*36413Ssklower 					sbappend(&tpcb->tp_sock->so_rcv, s->tprt_data);
807*36413Ssklower 				newrec = s->tprt_eot;
808*36413Ssklower 
809*36413Ssklower 				SEQ_INC( tpcb, tpcb->tp_rcvnxt );
810*36413Ssklower 
811*36413Ssklower 				(void) m_free( dtom( s ) );
812*36413Ssklower 				s = *r;
813*36413Ssklower 				ack_reason |= ACK_REORDER;
814*36413Ssklower 			}
815*36413Ssklower 		}
816*36413Ssklower 		IFDEBUG(D_STASH)
817*36413Ssklower 			dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
818*36413Ssklower 				"stash: so_rcv after appending");
819*36413Ssklower 		ENDDEBUG
820*36413Ssklower 
821*36413Ssklower 	} else {
822*36413Ssklower 		register struct tp_rtc **s = &tpcb->tp_rcvnxt_rtc;
823*36413Ssklower 		register struct tp_rtc *r = tpcb->tp_rcvnxt_rtc;
824*36413Ssklower 		register struct tp_rtc *t;
825*36413Ssklower 
826*36413Ssklower 		IFTRACE(D_STASH)
827*36413Ssklower 			tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
828*36413Ssklower 			E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
829*36413Ssklower 		ENDTRACE
830*36413Ssklower 
831*36413Ssklower 		r = tpcb->tp_rcvnxt_rtc;
832*36413Ssklower 		while (r != (struct tp_rtc *)0  && SEQ_LT(tpcb, r->tprt_seq, E.e_seq)) {
833*36413Ssklower 			s = &r->tprt_next;
834*36413Ssklower 			r = r->tprt_next;
835*36413Ssklower 		}
836*36413Ssklower 
837*36413Ssklower 		if (r == (struct tp_rtc *)0 || SEQ_GT(tpcb, r->tprt_seq, E.e_seq) ) {
838*36413Ssklower 			IncStat(ts_dt_ooo);
839*36413Ssklower 
840*36413Ssklower 			IFTRACE(D_STASH)
841*36413Ssklower 				tptrace(TPPTmisc,
842*36413Ssklower 				"tp_stash OUT OF ORDER- MAKE RTC: seq, 1st seq in list\n",
843*36413Ssklower 					E.e_seq, r->tprt_seq,0,0);
844*36413Ssklower 			ENDTRACE
845*36413Ssklower 			IFDEBUG(D_STASH)
846*36413Ssklower 				printf("tp_stash OUT OF ORDER- MAKE RTC\n");
847*36413Ssklower 			ENDDEBUG
848*36413Ssklower 			TP_MAKE_RTC(t, E.e_seq, E.e_eot, E.e_data, E.e_datalen, 0,
849*36413Ssklower 				TPMT_RCVRTC);
850*36413Ssklower 
851*36413Ssklower 			*s = t;
852*36413Ssklower 			t->tprt_next = (struct tp_rtc *)r;
853*36413Ssklower 			ack_reason = ACK_DONT;
854*36413Ssklower 			goto done;
855*36413Ssklower 		} else {
856*36413Ssklower 			IFDEBUG(D_STASH)
857*36413Ssklower 				printf("tp_stash - drop & ack\n");
858*36413Ssklower 			ENDDEBUG
859*36413Ssklower 
860*36413Ssklower 			/* retransmission - drop it and force an ack */
861*36413Ssklower 			IncStat(ts_dt_dup);
862*36413Ssklower 			IFPERF(tpcb)
863*36413Ssklower 				IncPStat(tpcb, tps_n_ack_cuz_dup);
864*36413Ssklower 			ENDPERF
865*36413Ssklower 
866*36413Ssklower 			m_freem( E.e_data );
867*36413Ssklower 			ack_reason |= ACK_DUP;
868*36413Ssklower 			goto done;
869*36413Ssklower 		}
870*36413Ssklower 	}
871*36413Ssklower 
872*36413Ssklower 
873*36413Ssklower 	/*
874*36413Ssklower 	 * an ack should be sent when at least one of the
875*36413Ssklower 	 * following holds:
876*36413Ssklower 	 * a) we've received a TPDU with EOTSDU set
877*36413Ssklower 	 * b) the TPDU that just arrived represents the
878*36413Ssklower 	 *    full window last advertised, or
879*36413Ssklower 	 * c) when seq X arrives [ where
880*36413Ssklower 	 * 		X = last_sent_uwe - 1/2 last_lcredit_sent
881*36413Ssklower 	 * 		(the packet representing 1/2 the last advertised window) ]
882*36413Ssklower 	 * 		and lcredit at the time of X arrival >  last_lcredit_sent/2
883*36413Ssklower 	 * 		In other words, if the last ack sent advertised cdt=8 and uwe = 8
884*36413Ssklower 	 * 		then when seq 4 arrives I'd like to send a new ack
885*36413Ssklower 	 * 		iff the credit at the time of 4's arrival is > 4.
886*36413Ssklower 	 * 		The other end thinks it has cdt of 4 so if local cdt
887*36413Ssklower 	 * 		is still 4 there's no point in sending an ack, but if
888*36413Ssklower 	 * 		my credit has increased because the receiver has taken
889*36413Ssklower 	 * 		some data out of the buffer (soreceive doesn't notify
890*36413Ssklower 	 * 		me until the SYSTEM CALL finishes), I'd like to tell
891*36413Ssklower 	 * 		the other end.
892*36413Ssklower 	 */
893*36413Ssklower 
894*36413Ssklower done:
895*36413Ssklower 	{
896*36413Ssklower 		LOCAL_CREDIT(tpcb);
897*36413Ssklower 
898*36413Ssklower 		if ( E.e_seq ==  tpcb->tp_sent_uwe )
899*36413Ssklower 			ack_reason |= ACK_STRAT_FULLWIN;
900*36413Ssklower 
901*36413Ssklower 		IFTRACE(D_STASH)
902*36413Ssklower 			tptraceTPCB(TPPTmisc,
903*36413Ssklower 				"end of stash, eot, ack_reason, sent_uwe ",
904*36413Ssklower 				E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
905*36413Ssklower 		ENDTRACE
906*36413Ssklower 
907*36413Ssklower 		if ( ack_reason == ACK_DONT ) {
908*36413Ssklower 			IncStat( ts_ackreason[ACK_DONT] );
909*36413Ssklower 			return 0;
910*36413Ssklower 		} else {
911*36413Ssklower 			IFPERF(tpcb)
912*36413Ssklower 				if(ack_reason & ACK_EOT) {
913*36413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_eot);
914*36413Ssklower 				}
915*36413Ssklower 				if(ack_reason & ACK_STRAT_EACH) {
916*36413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_strat);
917*36413Ssklower 				} else if(ack_reason & ACK_STRAT_FULLWIN) {
918*36413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_fullwin);
919*36413Ssklower 				} else if(ack_reason & ACK_REORDER) {
920*36413Ssklower 					IncPStat(tpcb, tps_n_ack_cuz_reorder);
921*36413Ssklower 				}
922*36413Ssklower 				tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
923*36413Ssklower 							SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
924*36413Ssklower 			ENDPERF
925*36413Ssklower 			{
926*36413Ssklower 				register int i;
927*36413Ssklower 
928*36413Ssklower 				/* keep track of all reasons that apply */
929*36413Ssklower 				for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
930*36413Ssklower 					if( ack_reason & (1<<i) )
931*36413Ssklower 						IncStat( ts_ackreason[i] );
932*36413Ssklower 				}
933*36413Ssklower 			}
934*36413Ssklower 			return 1;
935*36413Ssklower 		}
936*36413Ssklower 	}
937*36413Ssklower }
938*36413Ssklower 
939*36413Ssklower /* class zero version */
940*36413Ssklower void
941*36413Ssklower tp0_stash( tpcb, e )
942*36413Ssklower 	register struct tp_pcb		*tpcb;
943*36413Ssklower 	register struct tp_event	*e;
944*36413Ssklower {
945*36413Ssklower #ifndef lint
946*36413Ssklower #define E e->ATTR(DT_TPDU)
947*36413Ssklower #else lint
948*36413Ssklower #define E e->ev_union.EV_DT_TPDU
949*36413Ssklower #endif lint
950*36413Ssklower 
951*36413Ssklower 	IFPERF(tpcb)
952*36413Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
953*36413Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
954*36413Ssklower 				E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
955*36413Ssklower 	ENDPERF
956*36413Ssklower 
957*36413Ssklower 	IFDEBUG(D_STASH)
958*36413Ssklower 		printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
959*36413Ssklower 		E.e_seq, E.e_datalen, E.e_eot);
960*36413Ssklower 	ENDDEBUG
961*36413Ssklower 
962*36413Ssklower 	IFTRACE(D_STASH)
963*36413Ssklower 		tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
964*36413Ssklower 		E.e_seq, E.e_datalen, E.e_eot, 0);
965*36413Ssklower 	ENDTRACE
966*36413Ssklower 
967*36413Ssklower 	if ( E.e_eot ) {
968*36413Ssklower 		register struct mbuf *n = E.e_data;
969*36413Ssklower 
970*36413Ssklower 		/* sigh. have to go through this again! */
971*36413Ssklower 		/* a kludgy optimization would be to take care of this in
972*36413Ssklower 		 * tp_input (oh, horrors!)
973*36413Ssklower 		 */
974*36413Ssklower 		while (n->m_next )
975*36413Ssklower 			n = n->m_next;
976*36413Ssklower 
977*36413Ssklower 		n->m_act = MNULL; /* set on tp_input */
978*36413Ssklower 
979*36413Ssklower 		CHANGE_MTYPE(n, TPMT_EOT);
980*36413Ssklower 	}
981*36413Ssklower 	if( E.e_datalen == 0 && E.e_eot ) {
982*36413Ssklower 		sbappendrecord (&tpcb->tp_sock->so_rcv, E.e_data);
983*36413Ssklower 	} else {
984*36413Ssklower 		sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
985*36413Ssklower 	}
986*36413Ssklower 	IFDEBUG(D_STASH)
987*36413Ssklower 		dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
988*36413Ssklower 			"stash 0: so_rcv after appending");
989*36413Ssklower 	ENDDEBUG
990*36413Ssklower }
991*36413Ssklower 
992