xref: /csrg-svn/sys/netiso/tp.trans (revision 38841)
136396Ssklower/***********************************************************
236396Ssklower		Copyright IBM Corporation 1987
336396Ssklower
436396Ssklower                      All Rights Reserved
536396Ssklower
636396SsklowerPermission to use, copy, modify, and distribute this software and its
736396Ssklowerdocumentation for any purpose and without fee is hereby granted,
836396Ssklowerprovided that the above copyright notice appear in all copies and that
936396Ssklowerboth that copyright notice and this permission notice appear in
1036396Ssklowersupporting documentation, and that the name of IBM not be
1136396Ssklowerused in advertising or publicity pertaining to distribution of the
1236396Ssklowersoftware without specific, written prior permission.
1336396Ssklower
1436396SsklowerIBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536396SsklowerALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636396SsklowerIBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736396SsklowerANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836396SsklowerWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936396SsklowerARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036396SsklowerSOFTWARE.
2136396Ssklower
2236396Ssklower******************************************************************/
2336396Ssklower
2436396Ssklower/*
2536396Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636396Ssklower */
2736396Ssklower/* $Header: tp.trans,v 5.1 88/10/12 12:22:07 root Exp $
2836396Ssklower *
2936396Ssklower * Transition file for TP.
3036396Ssklower *
3136396Ssklower * DO NOT:
3236396Ssklower * - change the order of any of the events or states.  to do so will
3336396Ssklower *   make tppt, netstat, etc. cease working.
3436396Ssklower *
3536396Ssklower * NOTE:
3636396Ssklower * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED***
3736396Ssklower * (read: may not work!)
3836396Ssklower *
3936396Ssklower * I tried to put everything that causes a change of state in here, hence
4036396Ssklower * there are some seemingly trivial events  like T_DETACH and T_LISTEN_req.
4136396Ssklower *
4236396Ssklower * Almost everything having to do w/ setting & cancelling timers is here
4336396Ssklower * but once it was debugged, I moved the setting of the
4436396Ssklower * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent.
4536396Ssklower * This is so the code wouldn't be duplicated all over creation in here.
4636396Ssklower *
4736396Ssklower */
4836396Ssklower*PROTOCOL tp
4936396Ssklower
5036396Ssklower*INCLUDE
5136396Ssklower
5236396Ssklower{
53*38841Ssklower/*	@(#)tp.trans	7.3 (Berkeley) 08/29/89 */
5436396Ssklower#include "param.h"
5536396Ssklower#include "socket.h"
5636396Ssklower#include "socketvar.h"
5736396Ssklower#include "protosw.h"
5836396Ssklower#include "mbuf.h"
5936396Ssklower#include "time.h"
6036396Ssklower#include "errno.h"
6136396Ssklower#include "../netiso/tp_param.h"
6236396Ssklower#include "../netiso/tp_stat.h"
6336396Ssklower#include "../netiso/tp_pcb.h"
6436396Ssklower#include "../netiso/tp_tpdu.h"
6536396Ssklower#include "../netiso/argo_debug.h"
6636396Ssklower#include "../netiso/tp_trace.h"
6736396Ssklower#include "../netiso/iso_errno.h"
6836396Ssklower#include "../netiso/tp_seq.h"
6936396Ssklower#include "../netiso/cons.h"
7036396Ssklower
7136396Ssklower#define DRIVERTRACE TPPTdriver
7237469Ssklower#define sbwakeup(sb)	sowakeup(p->tp_sock, sb);
7337469Ssklower#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
7436396Ssklower
7536396Ssklowerstatic 	trick_hc = 1;
7636396Ssklower
7736396Ssklowerint 	tp_emit(),
7836396Ssklower		tp_goodack(),				tp_goodXack(),
7936396Ssklower		tp_stash()
8036396Ssklower;
8136396Ssklowervoid	tp_indicate(),				tp_getoptions(),
8236396Ssklower		tp_soisdisconnecting(), 	tp_soisdisconnected(),
8336396Ssklower		tp_recycle_tsuffix(),
8436396Ssklower		tp_etimeout(),				tp_euntimeout(),
8536396Ssklower		tp_euntimeout_lss(),		tp_ctimeout(),
8636396Ssklower		tp_cuntimeout(),			tp_ctimeout_MIN(),
8736396Ssklower		tp_freeref(),				tp_detach(),
8836396Ssklower		tp0_stash(), 				tp0_send(),
8936396Ssklower		tp_netcmd(),				tp_send()
9036396Ssklower;
9136396Ssklower
9236396Ssklowertypedef  struct tp_pcb tpcb_struct;
9336396Ssklower
9436396Ssklower
9536396Ssklower}
9636396Ssklower
9736396Ssklower*PCB    tpcb_struct 	SYNONYM  P
9836396Ssklower
9936396Ssklower*STATES
10036396Ssklower
10136396SsklowerTP_CLOSED
10236396SsklowerTP_CRSENT
10336396SsklowerTP_AKWAIT
10436396SsklowerTP_OPEN
10536396SsklowerTP_CLOSING
10636396SsklowerTP_REFWAIT
10736396SsklowerTP_LISTENING	/* Local to this implementation */
108*38841SsklowerTP_CONFIRMING	/* Local to this implementation */
10936396Ssklower
11036396Ssklower*EVENTS		{ struct timeval e_time; } 		SYNONYM  E
11136396Ssklower
11236396Ssklower /*
11336396Ssklower  * C (typically cancelled) timers  -
11436396Ssklower  *
11536396Ssklower  * let these be the first ones so for the sake of convenience
11636396Ssklower  * their values are 0--> n-1
11736396Ssklower  * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!!
11836396Ssklower  */
11936396Ssklower TM_inact
12036396Ssklower TM_retrans
12136396Ssklower				/* TM_retrans is used for all
12236396Ssklower				 * simple retransmissions - CR,CC,XPD,DR
12336396Ssklower				 */
12436396Ssklower
12536396Ssklower TM_sendack
12636396Ssklower				/* TM_sendack does dual duty - keepalive AND sendack.
12736396Ssklower				 * It's set w/ keepalive-ticks every time an ack is sent.
12836396Ssklower				 * (this is done in (void) tp_emit() ).
12936396Ssklower				 * It's cancelled and reset whenever a DT
13036396Ssklower				 * arrives and it doesn't require immediate acking.
13136396Ssklower				 * Note that in this case it's set w/ the minimum of
13236396Ssklower				 * its prev value and the sendack-ticks value so the
13336396Ssklower				 * purpose of the keepalive is preserved.
13436396Ssklower				 */
13536396Ssklower TM_notused
13636396Ssklower
13736396Ssklower /*
13836396Ssklower  * E (typically expired) timers - these may be in any order.
13936396Ssklower  * These cause procedures to be executed directly; may not
14036396Ssklower  * cause an 'event' as we know them here.
14136396Ssklower  */
14236396Ssklower TM_reference		{ SeqNum e_low; SeqNum e_high; int e_retrans; }
14336396Ssklower TM_data_retrans	{ SeqNum e_low; SeqNum e_high; int e_retrans; }
14436396Ssklower
14536396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that
14636396Ssklower * for all tpdu types that can take e_data and e_datalen, these
14736396Ssklower * fields fall in the same place in the event structure, that is,
14836396Ssklower * e_data is the first field and e_datalen is the 2nd field.
14936396Ssklower */
15036396Ssklower
15136396Ssklower ER_TPDU  	 	{
15236396Ssklower				  u_char		e_reason;
15336396Ssklower				}
15436396Ssklower CR_TPDU  	 	{ struct mbuf 	*e_data;	/* first field */
15536396Ssklower				  int 			e_datalen; /* 2nd field */
15636396Ssklower				  u_int			e_cdt;
15736396Ssklower				}
15836396Ssklower DR_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
15936396Ssklower				  int 			e_datalen; /* 2nd field */
16036396Ssklower				  u_short		e_sref;
16136396Ssklower				  u_char		e_reason;
16236396Ssklower				}
16336396Ssklower DC_TPDU
16436396Ssklower CC_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
16536396Ssklower				  int 			e_datalen; /* 2nd field */
16636396Ssklower				  u_short		e_sref;
16736396Ssklower				  u_int			e_cdt;
16836396Ssklower				}
16936396Ssklower AK_TPDU		{ u_int			e_cdt;
17036396Ssklower				  SeqNum 	 	e_seq;
17136396Ssklower				  SeqNum 	 	e_subseq;
17236396Ssklower				  u_char 	 	e_fcc_present;
17336396Ssklower				}
17436396Ssklower DT_TPDU		{ struct mbuf	*e_data; 	/* first field */
17536396Ssklower				  int 			e_datalen; /* 2nd field */
17636396Ssklower				  u_int 		e_eot;
17736396Ssklower				  SeqNum		e_seq;
17836396Ssklower				}
17936396Ssklower XPD_TPDU		{ struct mbuf 	*e_data;	/* first field */
18036396Ssklower				  int 			e_datalen; 	/* 2nd field */
18136396Ssklower				  SeqNum 		e_seq;
18236396Ssklower				}
18336396Ssklower XAK_TPDU		{ SeqNum 		e_seq;		}
18436396Ssklower
18536396Ssklower T_CONN_req
18636396Ssklower T_DISC_req		{ u_char		e_reason; 	}
18736396Ssklower T_LISTEN_req
18836396Ssklower T_DATA_req
18936396Ssklower T_XPD_req
19036396Ssklower T_USR_rcvd
19136396Ssklower T_USR_Xrcvd
19236396Ssklower T_DETACH
19336396Ssklower T_NETRESET
194*38841Ssklower T_ACPT_req
19536396Ssklower
19636396Ssklower
19736396Ssklower*TRANSITIONS
19836396Ssklower
19936396Ssklower
20036396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */
20136396SsklowerSAME			<==			TP_AKWAIT			[ CC_TPDU, DC_TPDU, XAK_TPDU ]
20236396Ssklower	DEFAULT
20336396Ssklower	NULLACTION
20436396Ssklower;
20536396Ssklower
20636396Ssklower
20736396Ssklower/* applicable in TP4, TP0 */
20836396SsklowerSAME			<==			TP_REFWAIT								DR_TPDU
20936396Ssklower	( $$.e_sref !=  0 )
21036396Ssklower	{
21136396Ssklower		(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
21236396Ssklower	}
21336396Ssklower;
21436396Ssklower
21536396Ssklower/* applicable in TP4, TP0 */
21636396SsklowerSAME			<==			TP_REFWAIT			[ CR_TPDU, CC_TPDU, DT_TPDU,
21736396Ssklower					DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ]
21836396Ssklower	DEFAULT
21936396Ssklower	{
22036396Ssklower#		ifdef TP_DEBUG
22136396Ssklower		if( $E.ev_number != AK_TPDU )
22236396Ssklower			printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number);
22336396Ssklower#		endif TP_DEBUG
22436396Ssklower	}
22536396Ssklower;
22636396Ssklower
22736396Ssklower/* applicable in TP4, TP0 */
22836396SsklowerSAME			<==			TP_REFWAIT				[ T_DETACH, T_DISC_req ]
22936396Ssklower	DEFAULT
23036396Ssklower	NULLACTION
23136396Ssklower;
23236396Ssklower
23336396Ssklower/* applicable in TP4, TP0 */
23436396SsklowerSAME			<==			TP_CRSENT								 AK_TPDU
23536396Ssklower	($P.tp_class == TP_CLASS_0)
23636396Ssklower	{
23736396Ssklower		/* oh, man is this grotesque or what? */
23836396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq,  $$.e_subseq);
23936396Ssklower		/* but it's necessary because this pseudo-ack may happen
24036396Ssklower		 * before the CC arrives, but we HAVE to adjust the
24136396Ssklower		 * snduna as a result of the ack, WHENEVER it arrives
24236396Ssklower		 */
24336396Ssklower	}
24436396Ssklower;
24536396Ssklower
24636396Ssklower/* applicable in TP4, TP0 */
24736396SsklowerSAME			<==			TP_CRSENT
24836396Ssklower					[ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU,  XAK_TPDU ]
24936396Ssklower	DEFAULT
25036396Ssklower	NULLACTION
25136396Ssklower;
25236396Ssklower
25336396Ssklower/* applicable in TP4, TP0 */
25436396SsklowerSAME			<==			TP_CLOSED					[ DT_TPDU, XPD_TPDU,
25536396Ssklower										ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
25636396Ssklower	DEFAULT
25736396Ssklower	NULLACTION
25836396Ssklower;
25936396Ssklower
26036396Ssklower/* TP_CLOSING doesn't exist in TP 0 */
26136396SsklowerSAME 			<== 		TP_CLOSING
26236396Ssklower					[ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ]
26336396Ssklower	DEFAULT
26436396Ssklower	NULLACTION
26536396Ssklower;
26636396Ssklower
26736396Ssklower
26836396Ssklower/* DC_TPDU doesn't exist in TP 0 */
26936396SsklowerSAME			<==			TP_OPEN						  DC_TPDU
27036396Ssklower	DEFAULT
27136396Ssklower	NULLACTION
27236396Ssklower;
27336396Ssklower
27436396Ssklower/* applicable in TP4, TP0 */
27536396SsklowerSAME			<==		 	TP_LISTENING  [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU,
27636396Ssklower										 ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
27736396Ssklower	DEFAULT
27836396Ssklower	NULLACTION
27936396Ssklower;
28036396Ssklower
28136396Ssklower/* applicable in TP4, TP0 */
28236396SsklowerTP_LISTENING	<==			TP_CLOSED  							T_LISTEN_req
28336396Ssklower	DEFAULT
28436396Ssklower	NULLACTION
28536396Ssklower;
28636396Ssklower
28736396Ssklower/* applicable in TP4, TP0 */
28836396SsklowerTP_CLOSED  		<== 		[ TP_LISTENING, TP_CLOSED ] 			T_DETACH
28936396Ssklower	DEFAULT
29036396Ssklower	{
29136396Ssklower		tp_detach($P);
29236396Ssklower	}
29336396Ssklower;
29436396Ssklower
295*38841SsklowerTP_CONFIRMING	<==		 TP_LISTENING  								CR_TPDU
296*38841Ssklower	( $P.tp_class == TP_CLASS_0)
29736396Ssklower	{
29836396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */
29936396Ssklower	}
30036396Ssklower;
30136396Ssklower
302*38841SsklowerTP_CONFIRMING		<==		 TP_LISTENING  							CR_TPDU
303*38841Ssklower	DEFAULT
30436396Ssklower	{
30536396Ssklower		IFTRACE(D_CONN)
30636396Ssklower			tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
30736396Ssklower		ENDTRACE
30836396Ssklower		IFDEBUG(D_CONN)
30936396Ssklower			printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
31036396Ssklower		ENDDEBUG
31136396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers */
312*38841Ssklower		$P.tp_fcredit = $$.e_cdt;
31336396Ssklower
31436396Ssklower		if ($$.e_datalen > 0) {
31536396Ssklower			/* n/a for class 0 */
31636396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0);
31736396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
31837469Ssklower			/*$P.tp_flags |= TPF_CONN_DATA_IN;*/
31936396Ssklower			$$.e_data = MNULL;
32036396Ssklower		}
321*38841Ssklower	}
322*38841Ssklower;
323*38841Ssklower
324*38841SsklowerTP_OPEN		<==		 TP_CONFIRMING  								T_ACPT_req
325*38841Ssklower	( $P.tp_class == TP_CLASS_0 )
326*38841Ssklower	{
327*38841Ssklower		IncStat(ts_tp0_conn);
328*38841Ssklower		IFTRACE(D_CONN)
329*38841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
330*38841Ssklower		ENDTRACE
331*38841Ssklower		IFDEBUG(D_CONN)
332*38841Ssklower			printf("Confirming connection: $P" );
333*38841Ssklower		ENDDEBUG
334*38841Ssklower		soisconnected($P.tp_sock);
335*38841Ssklower		(void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
336*38841Ssklower		$P.tp_fcredit = 1;
337*38841Ssklower	}
338*38841Ssklower;
339*38841Ssklower
340*38841SsklowerTP_AKWAIT		<==		 TP_CONFIRMING  							T_ACPT_req
341*38841Ssklower	(tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
342*38841Ssklower	{
343*38841Ssklower		IncStat(ts_tp4_conn); /* even though not quite open */
344*38841Ssklower		IFTRACE(D_CONN)
345*38841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
346*38841Ssklower		ENDTRACE
347*38841Ssklower		IFDEBUG(D_CONN)
348*38841Ssklower			printf("Confirming connection: $P" );
349*38841Ssklower		ENDDEBUG
350*38841Ssklower		soisconnecting($P.tp_sock);
35136396Ssklower		if($P.tp_rx_strat & TPRX_FASTSTART)
352*38841Ssklower			$P.tp_cong_win = $P.tp_fcredit;
35336396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
35436396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
355*38841Ssklower	}
35636396Ssklower;
35736396Ssklower
35836396Ssklower/* TP4 only */
359*38841SsklowerTP_CLOSED		<==		 TP_CONFIRMING								T_ACPT_req
36036396Ssklower	DEFAULT /* emit failed */
36136396Ssklower	{
36236396Ssklower		register struct tp_ref *r = $P.tp_refp;
36336396Ssklower
36436396Ssklower		IFDEBUG(D_CONN)
36536396Ssklower			printf("event: CR_TPDU emit CC failed done " );
36636396Ssklower		ENDDEBUG
367*38841Ssklower		soisdisconnected($P.tp_sock);
36836396Ssklower		tp_recycle_tsuffix( $P );
36936396Ssklower		tp_freeref(r);
37036396Ssklower		tp_detach($P);
37136396Ssklower	}
37236396Ssklower;
37336396Ssklower
37436396Ssklower/* applicable in TP4, TP0 */
37536396SsklowerTP_CRSENT		<==		TP_CLOSED								T_CONN_req
37636396Ssklower	DEFAULT
37736396Ssklower	{
37836396Ssklower		int error;
37936396Ssklower		struct mbuf *data = MNULL;
38036396Ssklower
38136396Ssklower		IFTRACE(D_CONN)
38237469Ssklower			tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
38337469Ssklower			$P.tp_ucddata, 0, 0);
38436396Ssklower		ENDTRACE
38537469Ssklower		data =  MCPY($P.tp_ucddata, M_WAIT);
38637469Ssklower		if (data) {
38736396Ssklower			IFDEBUG(D_CONN)
38836396Ssklower				printf("T_CONN_req.trans m_copy cc 0x%x\n",
38937469Ssklower					$P.tp_ucddata);
39037469Ssklower				dump_mbuf(data, "sosnd @ T_CONN_req");
39136396Ssklower			ENDDEBUG
39236396Ssklower		}
39336396Ssklower
39436396Ssklower		if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
39536396Ssklower			return error; /* driver WON'T change state; will return error */
39636396Ssklower
39736396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers */
39836396Ssklower		if($P.tp_class != TP_CLASS_0) {
39936396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
40036396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
40136396Ssklower		}
40236396Ssklower	}
40336396Ssklower;
40436396Ssklower
40536396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
40636396SsklowerTP_REFWAIT 		<==		[ TP_CRSENT, TP_AKWAIT, TP_OPEN ] 			DR_TPDU
40736396Ssklower	DEFAULT
40836396Ssklower	{
40936396Ssklower		if ($$.e_datalen > 0 && $P.tp_class != TP_CLASS_0) {
41037469Ssklower			/*sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc); /* purge expedited data */
41137469Ssklower			sbflush(&$P.tp_Xrcv);
41236396Ssklower			$P.tp_flags |= TPF_DISC_DATA_IN;
41336396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
41436396Ssklower			$$.e_data = MNULL;
41536396Ssklower		}
41636396Ssklower		tp_indicate(T_DISCONNECT, $P, TP_ERROR_MASK | (u_short)$$.e_reason);
41736396Ssklower		tp_soisdisconnected($P);
41836396Ssklower		if ($P.tp_class != TP_CLASS_0) {
41936396Ssklower			if ($P.tp_state == TP_OPEN ) {
42036396Ssklower				tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
42136396Ssklower				tp_cuntimeout($P.tp_refp, TM_retrans);
42236396Ssklower				tp_cuntimeout($P.tp_refp, TM_inact);
42336396Ssklower				tp_cuntimeout($P.tp_refp, TM_sendack);
42436396Ssklower			}
42536396Ssklower			tp_cuntimeout($P.tp_refp, TM_retrans);
42636396Ssklower			if( $$.e_sref !=  0 )
42736396Ssklower				(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
42836396Ssklower		}
42936396Ssklower	}
43036396Ssklower;
43136396Ssklower
43236396SsklowerSAME 			<==		TP_CLOSED 									DR_TPDU
43336396Ssklower	DEFAULT
43436396Ssklower	{
43536396Ssklower		if( $$.e_sref != 0 )
43636396Ssklower			(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
43736396Ssklower		/* reference timer already set - reset it to be safe (???) */
43836396Ssklower		tp_euntimeout($P.tp_refp, TM_reference); /* all */
43936396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks);
44036396Ssklower	}
44136396Ssklower;
44236396Ssklower
44336396Ssklower/* NBS(34) */
44436396SsklowerTP_REFWAIT 		<==  	TP_CRSENT  									ER_TPDU
44536396Ssklower	DEFAULT
44636396Ssklower	{
44736396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
44836396Ssklower		tp_indicate(T_DISCONNECT, $P,
44936396Ssklower			TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
45036396Ssklower		tp_soisdisconnected($P);
45136396Ssklower	}
45236396Ssklower;
45336396Ssklower
45436396Ssklower/* NBS(27) */
45536396SsklowerTP_REFWAIT		<==		TP_CLOSING									DR_TPDU
45636396Ssklower	DEFAULT
45736396Ssklower	{
45836396Ssklower		$P.tp_sock->so_error = (u_short)$$.e_reason;
45936396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
46036396Ssklower		tp_soisdisconnected($P);
46136396Ssklower	}
46236396Ssklower;
46336396Ssklower/* these two transitions are the same but can't be combined because xebec
46436396Ssklower * can't handle the use of $$.e_reason if they're combined
46536396Ssklower */
46636396Ssklower/* NBS(27) */
46736396SsklowerTP_REFWAIT		<==		TP_CLOSING									ER_TPDU
46836396Ssklower	DEFAULT
46936396Ssklower	{
47036396Ssklower		$P.tp_sock->so_error = (u_short)$$.e_reason;
47136396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
47236396Ssklower		tp_soisdisconnected($P);
47336396Ssklower	}
47436396Ssklower;
47536396Ssklower/* NBS(27) */
47636396SsklowerTP_REFWAIT		<==		TP_CLOSING									DC_TPDU
47736396Ssklower	DEFAULT
47836396Ssklower	{
47936396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
48036396Ssklower		tp_soisdisconnected($P);
48136396Ssklower	}
48236396Ssklower;
48336396Ssklower
48436396Ssklower/* NBS(21) */
48536396SsklowerSAME 			<== 	TP_CLOSED 						[ CC_TPDU, CR_TPDU ]
48636396Ssklower	DEFAULT
48736396Ssklower	{	/* don't ask me why we have to do this - spec says so */
48836396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
48936396Ssklower		/* don't bother with retransmissions of the DR */
49036396Ssklower	}
49136396Ssklower;
49236396Ssklower
49336396Ssklower/* NBS(34) */
49436396SsklowerTP_REFWAIT 		<== 	TP_OPEN  				 					ER_TPDU
49536396Ssklower	($P.tp_class == TP_CLASS_0)
49636396Ssklower	{
49736396Ssklower		tp_soisdisconnecting($P.tp_sock);
49836396Ssklower		tp_indicate(T_DISCONNECT, $P,
49936396Ssklower			TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
50036396Ssklower
50136396Ssklower		tp_soisdisconnected($P);
50236396Ssklower		tp_netcmd( $P, CONN_CLOSE );
50336396Ssklower	}
50436396Ssklower;
50536396Ssklower
50636396SsklowerTP_CLOSING 		<== 	[ TP_AKWAIT, TP_OPEN ]  					ER_TPDU
50736396Ssklower	DEFAULT
50836396Ssklower	{
50936396Ssklower		if ($P.tp_state == TP_OPEN) {
51036396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
51136396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
51236396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
51336396Ssklower		}
51436396Ssklower		tp_soisdisconnecting($P.tp_sock);
51536396Ssklower		tp_indicate(T_DISCONNECT, $P,
51636396Ssklower			TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
51736396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
51836396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
51936396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
52036396Ssklower	}
52136396Ssklower;
52236396Ssklower/* NBS(6) */
52336396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
52436396Ssklower	($P.tp_class == TP_CLASS_0)
52536396Ssklower	{
52636396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
52736396Ssklower		IncStat(ts_tp0_conn);
52836396Ssklower		$P.tp_fcredit = 1;
52936396Ssklower		soisconnected($P.tp_sock);
53036396Ssklower	}
53136396Ssklower;
53236396Ssklower
53336396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
53436396Ssklower	DEFAULT
53536396Ssklower	{
53636396Ssklower		IFDEBUG(D_CONN)
53736396Ssklower			printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
53836396Ssklower				(int)$P.tp_flags);
53936396Ssklower		ENDDEBUG
54036396Ssklower		IncStat(ts_tp4_conn);
54136396Ssklower		$P.tp_fref = $$.e_sref;
54236396Ssklower		$P.tp_fcredit = $$.e_cdt;
54336396Ssklower		if($P.tp_rx_strat & TPRX_FASTSTART)
54436396Ssklower			$P.tp_cong_win = $$.e_cdt;
54536396Ssklower		tp_getoptions($P);
54636396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
54737469Ssklower		if ($P.tp_ucddata) {
54836396Ssklower			IFDEBUG(D_CONN)
54937469Ssklower				printf("dropping user connect data cc 0x%x\n",
55037469Ssklower					$P.tp_ucddata->m_len);
55136396Ssklower			ENDDEBUG
55237469Ssklower			m_freem($P.tp_ucddata);
55337469Ssklower			$P.tp_ucddata = 0;
55436396Ssklower		}
55536396Ssklower		soisconnected($P.tp_sock);
55636396Ssklower		if ($$.e_datalen > 0) {
55736396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
55836396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
55936396Ssklower			$P.tp_flags |= TPF_CONN_DATA_IN;
56036396Ssklower			$$.e_data = MNULL;
56136396Ssklower		}
56236396Ssklower
56336396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
56436396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
56536396Ssklower	}
56636396Ssklower;
56736396Ssklower
56836396Ssklower/* TP4 only */
56936396SsklowerSAME			<==		TP_CRSENT									TM_retrans
57036396Ssklower	(	$P.tp_retrans > 0 )
57136396Ssklower	{
57236396Ssklower		struct mbuf *data = MNULL;
57336396Ssklower		int error;
57436396Ssklower
57536396Ssklower		IncStat(ts_retrans_cr);
57637469Ssklower		data = MCPY($P.tp_ucddata, M_NOWAIT);
57737469Ssklower		if($P.tp_ucddata) {
57836396Ssklower			IFDEBUG(D_CONN)
57937469Ssklower				printf("TM_retrans.trans m_copy cc 0x%x\n", data);
58037469Ssklower				dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
58136396Ssklower			ENDDEBUG
58236396Ssklower			if( data == MNULL )
58336396Ssklower				return ENOBUFS;
58436396Ssklower		}
58536396Ssklower
58636396Ssklower		$P.tp_retrans --;
58736396Ssklower		if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
58836396Ssklower			$P.tp_sock->so_error = error;
58936396Ssklower		}
59036396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
59136396Ssklower	}
59236396Ssklower;
59336396Ssklower
59436396Ssklower/* TP4 only  */
59536396SsklowerTP_REFWAIT		<==		TP_CRSENT									TM_retrans
59636396Ssklower	DEFAULT /* no more CR retransmissions */
59736396Ssklower	{
59836396Ssklower		IncStat(ts_conn_gaveup);
59936396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
60036396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
60136396Ssklower		tp_soisdisconnected($P);
60236396Ssklower	}
60336396Ssklower;
60436396Ssklower
60536396Ssklower/* TP4 only */
60636396SsklowerSAME 			<==	 TP_AKWAIT											CR_TPDU
60736396Ssklower	DEFAULT
60836396Ssklower	/* duplicate CR (which doesn't really exist in the context of
60936396Ssklower	 * a connectionless network layer)
61036396Ssklower	 * Doesn't occur in class 0.
61136396Ssklower	 */
61236396Ssklower	{
61336396Ssklower		int error;
61437469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
61536396Ssklower
61637469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
61736396Ssklower			$P.tp_sock->so_error = error;
61836396Ssklower		}
61936396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
62036396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
62136396Ssklower	}
62236396Ssklower;
62336396Ssklower
62436396Ssklower/* TP4 only */
62536396SsklowerTP_OPEN			<==		TP_AKWAIT 										DT_TPDU
62636396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
62736396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
62836396Ssklower	{
62936396Ssklower		int doack;
63036396Ssklower
63137469Ssklower		/*
63237469Ssklower		 * Get rid of any confirm or connect data, so that if we
63337469Ssklower		 * crash or close, it isn't thought of as disconnect data.
63437469Ssklower		 */
63537469Ssklower		if ($P.tp_ucddata) {
63637469Ssklower			m_freem($P.tp_ucddata);
63737469Ssklower			$P.tp_ucddata = 0;
63836396Ssklower		}
63936396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
64036396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
64136396Ssklower		soisconnected($P.tp_sock);
64236396Ssklower		tp_getoptions($P);
64336396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
64436396Ssklower
64536396Ssklower		/* see also next 2 transitions, if you make any changes */
64636396Ssklower
64736396Ssklower		doack = tp_stash($P, $E);
64836396Ssklower		IFDEBUG(D_DATA)
64936396Ssklower			printf("tp_stash returns %d\n",doack);
65036396Ssklower		ENDDEBUG
65136396Ssklower
65236396Ssklower		if(doack) {
65336396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
65436396Ssklower			tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
65536396Ssklower		} else
65636396Ssklower			tp_ctimeout( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
65736396Ssklower
65836396Ssklower		IFDEBUG(D_DATA)
65936396Ssklower			printf("after stash calling sbwakeup\n");
66036396Ssklower		ENDDEBUG
66136396Ssklower	}
66236396Ssklower;
66336396Ssklower
66436396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
66536396Ssklower	( $P.tp_class == TP_CLASS_0 )
66636396Ssklower	{
66736396Ssklower		tp0_stash($P, $E);
66836396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
66936396Ssklower
67036396Ssklower		IFDEBUG(D_DATA)
67136396Ssklower			printf("after stash calling sbwakeup\n");
67236396Ssklower		ENDDEBUG
67336396Ssklower	}
67436396Ssklower;
67536396Ssklower
67636396Ssklower/* TP4 only */
67736396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
67836396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
67936396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
68036396Ssklower	{
68136396Ssklower		int doack; /* tells if we must ack immediately */
68236396Ssklower
68336396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
68436396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
68536396Ssklower
68636396Ssklower		doack = tp_stash($P, $E);
68736396Ssklower		IFDEBUG(D_DATA)
68836396Ssklower			printf("tp_stash returns %d\n",doack);
68936396Ssklower		ENDDEBUG
69036396Ssklower
69136396Ssklower		if(doack)
69236396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
69336396Ssklower		else
69436396Ssklower			tp_ctimeout_MIN( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
69536396Ssklower
69636396Ssklower		IFDEBUG(D_DATA)
69736396Ssklower			printf("after stash calling sbwakeup\n");
69836396Ssklower		ENDDEBUG
69936396Ssklower	}
70036396Ssklower;
70136396Ssklower
70236396Ssklower/* Not in window  - we must ack under certain circumstances, namely
70336396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given)
70436396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^.
70536396Ssklower * and
70636396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
70736396Ssklower *
70836396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73)
70936396Ssklower * We just always ack.
71036396Ssklower */
71136396Ssklower/* TP4 only */
71236396SsklowerSAME 			<== 	[ TP_OPEN, TP_AKWAIT ]							DT_TPDU
71336396Ssklower	DEFAULT /* Not in window */
71436396Ssklower	{
71536396Ssklower		IFTRACE(D_DATA)
71636396Ssklower			tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
71736396Ssklower				$$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
71836396Ssklower		ENDTRACE
71936396Ssklower		IncStat(ts_dt_niw);
72036396Ssklower		m_freem($$.e_data);
72136396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
72236396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
72336396Ssklower	}
72436396Ssklower;
72536396Ssklower
72636396Ssklower/* TP4 only */
72736396SsklowerTP_OPEN			<==		TP_AKWAIT										AK_TPDU
72836396Ssklower	DEFAULT
72936396Ssklower	{
73037469Ssklower		if ($P.tp_ucddata) {
73137469Ssklower			m_freem($P.tp_ucddata);
73237469Ssklower			$P.tp_ucddata = 0;
73336396Ssklower		}
73436396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
73536396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
73636396Ssklower
73736396Ssklower		tp_getoptions($P);
73836396Ssklower		soisconnected($P.tp_sock);
73936396Ssklower		IFTRACE(D_CONN)
74036396Ssklower			struct socket *so = $P.tp_sock;
74136396Ssklower			tptrace(TPPTmisc,
74236396Ssklower			"called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
74336396Ssklower				so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
74436396Ssklower			tptrace(TPPTmisc,
74536396Ssklower			"called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
74636396Ssklower				so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
74736396Ssklower		ENDTRACE
74836396Ssklower
74936396Ssklower		tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
75036396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
75136396Ssklower	}
75236396Ssklower;
75336396Ssklower
75436396Ssklower/* TP4 only */
75536396SsklowerTP_OPEN 		<== 	[ TP_OPEN, TP_AKWAIT ]						XPD_TPDU
75637469Ssklower	( $P.tp_Xrcvnxt == $$.e_seq  /* && $P.tp_Xrcv.sb_cc == 0*/)
75736396Ssklower	{
75836396Ssklower		if( $P.tp_state == TP_AKWAIT ) {
75937469Ssklower			if ($P.tp_ucddata) {
76037469Ssklower				m_freem($P.tp_ucddata);
76137469Ssklower				$P.tp_ucddata = 0;
76236396Ssklower			}
76336396Ssklower			tp_cuntimeout($P.tp_refp, TM_retrans);
76436396Ssklower			tp_getoptions($P);
76536396Ssklower			soisconnected($P.tp_sock);
76636396Ssklower			tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
76736396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
76836396Ssklower		}
76936396Ssklower		IFTRACE(D_XPD)
77036396Ssklower		tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
77136396Ssklower				$P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
77236396Ssklower		ENDTRACE
77336396Ssklower
77437469Ssklower		$P.tp_sock->so_state |= SS_RCVATMARK;
77537469Ssklower		sbinsertoob(&$P.tp_Xrcv, $$.e_data);
77636396Ssklower		IFDEBUG(D_XPD)
77736396Ssklower			dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
77836396Ssklower		ENDDEBUG
77936396Ssklower		tp_indicate(T_XDATA, $P, 0);
78036396Ssklower		sbwakeup( &$P.tp_Xrcv );
78136396Ssklower
78236396Ssklower		(void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
78336396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
78436396Ssklower	}
78536396Ssklower;
78636396Ssklower
78736396Ssklower/* TP4 only */
78836396SsklowerSAME			<==		TP_OPEN 									T_USR_Xrcvd
78936396Ssklower	DEFAULT
79036396Ssklower	{
79136396Ssklower		if( $P.tp_Xrcv.sb_cc == 0 ) {
79237469Ssklower			/*$P.tp_flags &= ~TPF_XPD_PRESENT;*/
79336396Ssklower			/* kludge for select(): */
79437469Ssklower			/* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
79536396Ssklower		}
79636396Ssklower	}
79736396Ssklower	/* OLD WAY:
79836396Ssklower	 * Ack only after the user receives the XPD.  This is better for
79936396Ssklower	 * users that use one XPD right after another.
80036396Ssklower	 * Acking right away (the NEW WAY, see the prev. transition) is
80136396Ssklower	 * better for occasional * XPD, when the receiving user doesn't
80236396Ssklower	 * want to read the XPD immediately (which is session's behavior).
80336396Ssklower	 *
80436396Ssklower		int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
80536396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
80636396Ssklower		return error;
80736396Ssklower	*/
80836396Ssklower;
80936396Ssklower
81036396Ssklower/* NOTE: presently if the user doesn't read the connection data
81136396Ssklower * before and expedited data PDU comes in, the connection data will
81236396Ssklower * be dropped. This is a bug.  To avoid it, we need somewhere else
81336396Ssklower * to put the connection data.
81436396Ssklower * On the other hand, we need not to have it sitting around forever.
81536396Ssklower * This is a problem with the idea of trying to accommodate
81636396Ssklower * data on connect w/ a passive-open user interface.
81736396Ssklower */
81836396Ssklower/* TP4 only */
81936396Ssklower
82036396SsklowerSAME	 		<== 	[ TP_AKWAIT, TP_OPEN ] 							XPD_TPDU
82136396Ssklower	DEFAULT /* not in window or cdt==0 */
82236396Ssklower	{
82336396Ssklower		IFTRACE(D_XPD)
82436396Ssklower			tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
82536396Ssklower				$P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
82636396Ssklower		ENDTRACE
82736396Ssklower		if( $P.tp_Xrcvnxt != $$.e_seq )
82836396Ssklower			IncStat(ts_xpd_niw);
82936396Ssklower		if( $P.tp_Xrcv.sb_cc ) {
83037469Ssklower#ifdef notdef
83136396Ssklower			if( $P.tp_flags & TPF_CONN_DATA_IN ) {
83236396Ssklower				/* user isn't reading the connection data; see note above */
83336396Ssklower				sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc);
83436396Ssklower				$P.tp_flags &= ~TPF_CONN_DATA_IN;
83536396Ssklower			}
83637469Ssklower#endif notdef
83736396Ssklower			/* might as well kick 'em again */
83836396Ssklower			tp_indicate(T_XDATA, $P, 0);
83936396Ssklower			IncStat(ts_xpd_dup);
84036396Ssklower		}
84136396Ssklower		m_freem($$.e_data);
84236396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
84336396Ssklower		/* don't send an xack because the xak gives "last one received", not
84436396Ssklower		 * "next one i expect" (dumb)
84536396Ssklower		 */
84636396Ssklower	}
84736396Ssklower;
84836396Ssklower
84936396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
85036396Ssklower * to detach all its "children"
85136396Ssklower * Also (CRSENT) when user kills a job that's doing a connect()
85236396Ssklower */
85336396SsklowerTP_REFWAIT		<== 	TP_CRSENT 										T_DETACH
85436396Ssklower	($P.tp_class == TP_CLASS_0)
85536396Ssklower	{
85636396Ssklower		struct socket *so = $P.tp_sock;
85736396Ssklower
85836396Ssklower		/* detach from parent socket so it can finish closing */
85936396Ssklower		if (so->so_head) {
86036396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
86136396Ssklower				panic("tp: T_DETACH");
86236396Ssklower			so->so_head = 0;
86336396Ssklower		}
86436396Ssklower		tp_soisdisconnecting($P.tp_sock);
86536396Ssklower		tp_netcmd( $P, CONN_CLOSE);
86636396Ssklower		tp_soisdisconnected($P);
86736396Ssklower	}
86836396Ssklower;
86936396Ssklower
87036396Ssklower/* TP4 only */
871*38841SsklowerTP_CLOSING		<== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ]	T_DETACH
87236396Ssklower	DEFAULT
87336396Ssklower	{
87436396Ssklower		struct socket *so = $P.tp_sock;
87537469Ssklower		struct mbuf *data = MNULL;
87636396Ssklower
87736396Ssklower		/* detach from parent socket so it can finish closing */
87836396Ssklower		if (so->so_head) {
87936396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
88036396Ssklower				panic("tp: T_DETACH");
88136396Ssklower			so->so_head = 0;
88236396Ssklower		}
88336396Ssklower		if ($P.tp_state != TP_CLOSING) {
88436396Ssklower			tp_soisdisconnecting($P.tp_sock);
88537469Ssklower			data = MCPY($P.tp_ucddata, M_NOWAIT);
88637469Ssklower			(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
88736396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
88836396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
88936396Ssklower		}
89036396Ssklower	}
89136396Ssklower;
89236396Ssklower
89336396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT ]		 	  			T_DISC_req
89436396Ssklower	( $P.tp_class == TP_CLASS_0 )
89536396Ssklower	{
89636396Ssklower		tp_soisdisconnecting($P.tp_sock);
89736396Ssklower		tp_netcmd( $P, CONN_CLOSE);
89836396Ssklower		tp_soisdisconnected($P);
89936396Ssklower	}
90036396Ssklower;
90136396Ssklower
90236396Ssklower/* TP4 only */
903*38841SsklowerTP_CLOSING		<==	[ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
90436396Ssklower	DEFAULT
90536396Ssklower	{
90637469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
90736396Ssklower
90836396Ssklower		if($P.tp_state == TP_OPEN) {
90936396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
91036396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
91136396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
91236396Ssklower		}
91337469Ssklower		if (data) {
91436396Ssklower			IFDEBUG(D_CONN)
91537469Ssklower				printf("T_DISC_req.trans tp_ucddata 0x%x\n",
91637469Ssklower					$P.tp_ucddata);
91737469Ssklower				dump_mbuf(data, "ucddata @ T_DISC_req");
91836396Ssklower			ENDDEBUG
91936396Ssklower		}
92036396Ssklower		tp_soisdisconnecting($P.tp_sock);
92136396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
92236396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
92336396Ssklower
92436396Ssklower		if( trick_hc )
92536396Ssklower			return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
92636396Ssklower	}
92736396Ssklower;
92836396Ssklower
92936396Ssklower/* TP4 only */
93036396SsklowerSAME			<==		TP_AKWAIT									TM_retrans
93136396Ssklower	( $P.tp_retrans > 0 )
93236396Ssklower	{
93336396Ssklower		int error;
93437469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
93536396Ssklower
93636396Ssklower		IncStat(ts_retrans_cc);
93736396Ssklower		$P.tp_retrans --;
93837469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
93936396Ssklower			$P.tp_sock->so_error = error;
94036396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
94136396Ssklower	}
94236396Ssklower;
94336396Ssklower
94436396Ssklower/* TP4 only */
94536396SsklowerTP_CLOSING		<==		TP_AKWAIT									TM_retrans
94636396Ssklower	DEFAULT  /* out of time */
94736396Ssklower	{
94836396Ssklower		IncStat(ts_conn_gaveup);
94936396Ssklower		tp_soisdisconnecting($P.tp_sock);
95036396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
95136396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
95236396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
95336396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
95436396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
95536396Ssklower	}
95636396Ssklower;
95736396Ssklower
95836396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does,
95936396Ssklower * if transmissions are going on.
96036396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack
96136396Ssklower * turnaround)
96236396Ssklower */
96336396Ssklower/* TP4 only */
96436396SsklowerTP_CLOSING 		<==		TP_OPEN		   [ TM_inact, TM_retrans, TM_data_retrans ]
96536396Ssklower	DEFAULT
96636396Ssklower	{
96736396Ssklower		tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
96836396Ssklower		tp_cuntimeout($P.tp_refp, TM_inact);
96936396Ssklower		tp_cuntimeout($P.tp_refp, TM_sendack);
97036396Ssklower
97136396Ssklower		IncStat(ts_conn_gaveup);
97236396Ssklower		tp_soisdisconnecting($P.tp_sock);
97336396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
97436396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
97536396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
97636396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
97736396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
97836396Ssklower	}
97936396Ssklower;
98036396Ssklower
98136396Ssklower/* TP4 only */
98236396SsklowerSAME			<==		TP_OPEN										TM_retrans
98336396Ssklower	( $P.tp_retrans > 0 )
98436396Ssklower	{
98536396Ssklower		/* resume XPD */
98636396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
98737469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
98836396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
98936396Ssklower			 * that doesn't matter
99036396Ssklower			 */
99136396Ssklower
99236396Ssklower			IFTRACE(D_XPD)
99336396Ssklower				tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna",
99436396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
99536396Ssklower					$P.tp_snduna);
99636396Ssklower			ENDTRACE
99736396Ssklower			IFDEBUG(D_XPD)
99836396Ssklower				dump_mbuf(m, "XPD retrans emitting M");
99936396Ssklower			ENDDEBUG
100036396Ssklower			IncStat(ts_retrans_xpd);
100136396Ssklower			$P.tp_retrans --;
100236396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
100336396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
100436396Ssklower		}
100536396Ssklower	}
100636396Ssklower;
100736396Ssklower
100836396Ssklower/* TP4 only */
100936396SsklowerSAME 			<==		TP_OPEN									TM_data_retrans
101036396Ssklower	( $$.e_retrans > 0 )
101136396Ssklower	{
101236396Ssklower		register 	SeqNum			low, lowsave = 0;
101336396Ssklower		register	struct tp_rtc 	*r = $P.tp_snduna_rtc;
101436396Ssklower		register	struct mbuf 	*m;
101536396Ssklower		register	SeqNum			high = $$.e_high;
101636396Ssklower
101736396Ssklower		low =
101836396Ssklower			SEQ_GT($P, $P.tp_snduna, $$.e_low )? $P.tp_snduna: $$.e_low;
101936396Ssklower		lowsave = low;
102036396Ssklower		if (($P.tp_rx_strat & TPRX_EACH) == 0)
102136396Ssklower			high = (high>low)?low:high;
102236396Ssklower
102336396Ssklower		if( $P.tp_rx_strat & TPRX_USE_CW ) {
102436396Ssklower			register int i;
102536396Ssklower
102636396Ssklower			$P.tp_cong_win = 1;
102736396Ssklower
102836396Ssklower			i = SEQ_ADD($P, low, $P.tp_cong_win);
102936396Ssklower			if(SEQ_LT($P, i, high ))
103036396Ssklower				high = i;
103136396Ssklower		}
103236396Ssklower
103336396Ssklower		while( SEQ_LEQ($P, low, high) ){
103436396Ssklower			if ( r == (struct tp_rtc *)0 ){
103536396Ssklower				IFDEBUG(D_RTC)
103636396Ssklower					printf( "tp: retrans rtc list is GONE!\n");
103736396Ssklower				ENDDEBUG
103836396Ssklower				break;
103936396Ssklower			}
104036396Ssklower			if ( r->tprt_seq == low ){
104136396Ssklower				if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL)
104236396Ssklower					break;
104336396Ssklower				(void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m);
104436396Ssklower				IncStat(ts_retrans_dt);
104536396Ssklower				SEQ_INC($P, low );
104636396Ssklower			}
104736396Ssklower			r = r->tprt_next;
104836396Ssklower		}
104936396Ssklower		if ( SEQ_LEQ($P, lowsave, high) ){
105036396Ssklower			$$.e_retrans --;
105136396Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
105236396Ssklower					(caddr_t)high, $$.e_retrans,
105336396Ssklower					($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks);
105436396Ssklower		}
105536396Ssklower	}
105636396Ssklower;
105736396Ssklower
105836396Ssklower/* TP4 only */
105936396SsklowerSAME	 		<==		TP_CLOSING									TM_retrans
106036396Ssklower	(	$P.tp_retrans > 0 )
106136396Ssklower	{
106236396Ssklower		$P.tp_retrans --;
106336396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
106436396Ssklower		IncStat(ts_retrans_dr);
106536396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
106636396Ssklower	}
106736396Ssklower;
106836396Ssklower
106936396Ssklower/* TP4 only */
107036396SsklowerTP_REFWAIT 		<==		TP_CLOSING									TM_retrans
107136396Ssklower	DEFAULT	/* no more retrans - gave up */
107236396Ssklower	{
107336396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
107436396Ssklower		$P.tp_refp->tpr_state = REF_FROZEN;
107536396Ssklower		tp_recycle_tsuffix( $P );
107636396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks);
107736396Ssklower	}
107836396Ssklower;
107936396Ssklower
108036396Ssklower/*
108136396Ssklower * The resources are kept around until the ref timer goes off.
108236396Ssklower * The suffices are wiped out sooner so they can be reused right away.
108336396Ssklower */
108436396Ssklower/* applicable in TP4, TP0 */
108536396SsklowerTP_CLOSED 		<==		TP_REFWAIT 									TM_reference
108636396Ssklower	DEFAULT
108736396Ssklower	{
108836396Ssklower		tp_freeref($P.tp_refp);
108936396Ssklower		tp_detach($P);
109036396Ssklower	}
109136396Ssklower;
109236396Ssklower
109336396Ssklower/* applicable in TP4, TP0 */
109436396Ssklower/* A duplicate CR from connectionless network layer can't happen */
109536396SsklowerSAME 			<== 	TP_OPEN 							[ CR_TPDU, CC_TPDU ]
109636396Ssklower	DEFAULT
109736396Ssklower	{
109836396Ssklower		if( $P.tp_class != TP_CLASS_0) {
109936396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
110036396Ssklower			if ( $E.ev_number == CC_TPDU )
110136396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
110236396Ssklower		}
110336396Ssklower		/* ignore it if class 0 - state tables are blank for this */
110436396Ssklower	}
110536396Ssklower;
110636396Ssklower
110736396Ssklower/* applicable in TP4, TP0 */
110836396SsklowerSAME			<== 	TP_OPEN									T_DATA_req
110936396Ssklower	DEFAULT
111036396Ssklower	{
111136396Ssklower		IFTRACE(D_DATA)
111236396Ssklower			tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb",
111336396Ssklower				$P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P);
111436396Ssklower		ENDTRACE
111536396Ssklower
111636396Ssklower		tp_send($P);
111736396Ssklower	}
111836396Ssklower;
111936396Ssklower
112036396Ssklower/* TP4 only */
112136396SsklowerSAME			<==		TP_OPEN										T_XPD_req
112236396Ssklower	DEFAULT
112336396Ssklower		/* T_XPD_req was issued by sosend iff xpd socket buf was empty
112436396Ssklower		 * at time of sosend(),
112536396Ssklower		 * AND (which means) there were no unacknowledged XPD tpdus outstanding!
112636396Ssklower		 */
112736396Ssklower	{
112836396Ssklower		int error = 0;
112936396Ssklower
113036396Ssklower		/* resume XPD */
113136396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
113237469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
113336396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
113436396Ssklower			 * that doesn't matter
113536396Ssklower			 */
113636396Ssklower
113736396Ssklower			IFTRACE(D_XPD)
113836396Ssklower				tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna",
113936396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
114036396Ssklower					$P.tp_snduna);
114136396Ssklower			ENDTRACE
114236396Ssklower			IFDEBUG(D_XPD)
114336396Ssklower				printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
114436396Ssklower				dump_mbuf(m, "XPD req emitting M");
114536396Ssklower			ENDDEBUG
114636396Ssklower			error =
114736396Ssklower				tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
114836396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
114936396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
115036396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
115136396Ssklower		}
115236396Ssklower		if(trick_hc)
115336396Ssklower			return error;
115436396Ssklower	}
115536396Ssklower;
115636396Ssklower
115736396Ssklower/* TP4, faked ack in TP0 when cons send completes */
115836396SsklowerSAME 			<==		TP_OPEN 									AK_TPDU
115936396Ssklower	( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
116036396Ssklower
116136396Ssklower	/* tp_goodack == true means
116236396Ssklower	 * EITHER it actually acked something heretofore unacknowledged
116336396Ssklower	 * OR no news but the credit should be processed.
116436396Ssklower	 */
116536396Ssklower	{
116636396Ssklower		IFDEBUG(D_ACKRECV)
116736396Ssklower			printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
116836396Ssklower		ENDDEBUG
116936396Ssklower		if( $P.tp_class != TP_CLASS_0) {
117036396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
117136396Ssklower			tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq);
117236396Ssklower		}
117336396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
117436396Ssklower
117536396Ssklower		tp_send($P);
117636396Ssklower		IFDEBUG(D_ACKRECV)
117736396Ssklower			printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat);
117836396Ssklower		ENDDEBUG
117936396Ssklower	}
118036396Ssklower;
118136396Ssklower
118236396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
118336396SsklowerSAME			<==		TP_OPEN 			 						XAK_TPDU
118436396Ssklower	DEFAULT
118536396Ssklower	{
118636396Ssklower		IFTRACE(D_ACKRECV)
118736396Ssklower			tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
118836396Ssklower		ENDTRACE
118936396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
119036396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
119136396Ssklower		}
119236396Ssklower	}
119336396Ssklower;
119436396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
119536396SsklowerSAME			<==		TP_OPEN 			 						 AK_TPDU
119636396Ssklower	DEFAULT
119736396Ssklower	{
119836396Ssklower		IFTRACE(D_ACKRECV)
119936396Ssklower			tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
120036396Ssklower				$$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
120136396Ssklower		ENDTRACE
120236396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
120336396Ssklower
120436396Ssklower			if ( !$$.e_fcc_present ) {
120536396Ssklower				/* send ACK with FCC */
120636396Ssklower				IncStat( ts_ackreason[_ACK_FCC_] );
120736396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
120836396Ssklower			}
120936396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
121036396Ssklower		}
121136396Ssklower	}
121236396Ssklower;
121336396Ssklower
121436396Ssklower/* NBS(47) */
121536396Ssklower	/* goes in at *** */
121636396Ssklower		/* just so happens that this is never true now, because we allow
121736396Ssklower		 * only 1 packet in the queue at once (this could be changed)
121836396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
121936396Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
122036396Ssklower
122136396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
122236396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
122336396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
122436396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
122536396Ssklower		}
122636396Ssklower		 */
122736396Ssklower	/* end of the above hack */
122836396Ssklower
122936396Ssklower/* TP4 only */
123036396SsklowerSAME			<== 	TP_OPEN 										XAK_TPDU
123136396Ssklower	( tp_goodXack($P, $$.e_seq) )
123236396Ssklower	/* tp_goodXack checks for good ack, removes the correct
123336396Ssklower	 * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
123436396Ssklower	 * also updates tp_Xuna
123536396Ssklower	 */
123636396Ssklower	{
123736396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
123836396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
123936396Ssklower
124036396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
124136396Ssklower
124236396Ssklower		/* resume normal data */
124336396Ssklower		tp_send($P);
124436396Ssklower	}
124536396Ssklower;
124636396Ssklower
124736396Ssklower/* TP4 only */
124836396SsklowerSAME			<==		TP_OPEN 								TM_sendack
124936396Ssklower	DEFAULT
125036396Ssklower	{
125136396Ssklower		IFTRACE(D_TIMER)
125236396Ssklower			tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
125336396Ssklower			$P.tp_sent_lcdt, 0);
125436396Ssklower		ENDTRACE
125536396Ssklower		IncPStat($P, tps_n_TMsendack);
125636396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
125736396Ssklower	}
125836396Ssklower;
125936396Ssklower
126036396Ssklower/* TP0 only */
126136396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
126236396Ssklower	($P.tp_class == TP_CLASS_0)
126336396Ssklower	NULLACTION
126436396Ssklower;
126536396Ssklower
126636396Ssklower/* TP4 only */
126736396Ssklower		/* If old credit was zero,
126836396Ssklower		 * we'd better inform other side that we now have space
126936396Ssklower		 * But this is not enough.  Sender might not yet have
127036396Ssklower		 * seen an ack with cdt 0 but it might still think the
127136396Ssklower		 * window is closed, so it's going to wait.
127236396Ssklower		 * Best to send an ack each time.
127336396Ssklower		 * Strictly speaking, this ought to be a function of the
127436396Ssklower		 * general ack strategy.
127536396Ssklower		 */
127636396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
127736396Ssklower	DEFAULT
127836396Ssklower	{
127936396Ssklower		if( trick_hc ) {
128036396Ssklower			IncStat(ts_ackreason[_ACK_USRRCV_]);
128136396Ssklower			return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
128236396Ssklower		}
128336396Ssklower	}
128436396Ssklower;
128536396Ssklower
128636396Ssklower/* applicable in TP4, TP0 */
128736396SsklowerSAME			<==		TP_REFWAIT 				[ T_USR_rcvd, T_USR_Xrcvd ]
128836396Ssklower	DEFAULT
128936396Ssklower	/* This happens if other end sent a DR when  the user was waiting
129036396Ssklower	 * on a receive.
129136396Ssklower	 * Processing the DR includes putting us in REFWAIT state.
129236396Ssklower	 */
129336396Ssklower	{
129436396Ssklower		if(trick_hc)
129536396Ssklower		return ECONNABORTED;
129636396Ssklower	}
129736396Ssklower;
129836396Ssklower
129936396Ssklower/* TP0 only */
130036396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT, TP_LISTENING ] 	T_NETRESET
130136396Ssklower	( $P.tp_class != TP_CLASS_4 )
130236396Ssklower		/* 0 or (4 and 0) */
130336396Ssklower		/* in OPEN class will be 0 or 4 but not both */
130436396Ssklower		/* in CRSENT or LISTENING it could be in negotiation, hence both */
130536396Ssklower		/* Actually, this shouldn't ever happen in LISTENING */
130636396Ssklower	{
130736396Ssklower		ASSERT( $P.tp_state != TP_LISTENING );
130836396Ssklower		tp_indicate(T_DISCONNECT, $P, ECONNRESET);
130936396Ssklower		tp_soisdisconnected($P);
131036396Ssklower	}
131136396Ssklower;
131236396Ssklower
131336396Ssklower/* TP4: ignore resets */
131436396SsklowerSAME		<==		[ TP_OPEN, TP_CRSENT, TP_AKWAIT,
131536396Ssklower						TP_CLOSING, TP_LISTENING ] 				T_NETRESET
131636396Ssklower	DEFAULT
131736396Ssklower	NULLACTION
131836396Ssklower;
131936396Ssklower
132036396Ssklower/* applicable in TP4, TP0 */
132136396SsklowerSAME			<==		[ TP_CLOSED, TP_REFWAIT ]				T_NETRESET
132236396Ssklower	DEFAULT
132336396Ssklower	NULLACTION
132436396Ssklower;
132536396Ssklower
132636396Ssklower/* C'EST TOUT */
1327