xref: /csrg-svn/sys/netiso/tp.trans (revision 47281)
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*47281Ssklower/*	@(#)tp.trans	7.6 (Berkeley) 03/12/91 */
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 */
10838841SsklowerTP_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
19438841Ssklower 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
29538841SsklowerTP_CONFIRMING	<==		 TP_LISTENING  								CR_TPDU
29638841Ssklower	( $P.tp_class == TP_CLASS_0)
29736396Ssklower	{
29836396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */
29936396Ssklower	}
30036396Ssklower;
30136396Ssklower
30238841SsklowerTP_CONFIRMING		<==		 TP_LISTENING  							CR_TPDU
30338841Ssklower	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 */
31238841Ssklower		$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);
31836396Ssklower			$$.e_data = MNULL;
31936396Ssklower		}
32038841Ssklower	}
32138841Ssklower;
32238841Ssklower
32338841SsklowerTP_OPEN		<==		 TP_CONFIRMING  								T_ACPT_req
32438841Ssklower	( $P.tp_class == TP_CLASS_0 )
32538841Ssklower	{
32638841Ssklower		IncStat(ts_tp0_conn);
32738841Ssklower		IFTRACE(D_CONN)
32838841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
32938841Ssklower		ENDTRACE
33038841Ssklower		IFDEBUG(D_CONN)
33138841Ssklower			printf("Confirming connection: $P" );
33238841Ssklower		ENDDEBUG
33338841Ssklower		soisconnected($P.tp_sock);
33438841Ssklower		(void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
33538841Ssklower		$P.tp_fcredit = 1;
33638841Ssklower	}
33738841Ssklower;
33838841Ssklower
33938841SsklowerTP_AKWAIT		<==		 TP_CONFIRMING  							T_ACPT_req
34038841Ssklower	(tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
34138841Ssklower	{
34238841Ssklower		IncStat(ts_tp4_conn); /* even though not quite open */
34338841Ssklower		IFTRACE(D_CONN)
34438841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
34538841Ssklower		ENDTRACE
34638841Ssklower		IFDEBUG(D_CONN)
34738841Ssklower			printf("Confirming connection: $P" );
34838841Ssklower		ENDDEBUG
34938841Ssklower		soisconnecting($P.tp_sock);
350*47281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
35138841Ssklower			$P.tp_cong_win = $P.tp_fcredit;
35236396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
35336396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
35438841Ssklower	}
35536396Ssklower;
35636396Ssklower
35736396Ssklower/* TP4 only */
35838841SsklowerTP_CLOSED		<==		 TP_CONFIRMING								T_ACPT_req
35936396Ssklower	DEFAULT /* emit failed */
36036396Ssklower	{
36136396Ssklower		register struct tp_ref *r = $P.tp_refp;
36236396Ssklower
36336396Ssklower		IFDEBUG(D_CONN)
36436396Ssklower			printf("event: CR_TPDU emit CC failed done " );
36536396Ssklower		ENDDEBUG
36638841Ssklower		soisdisconnected($P.tp_sock);
36736396Ssklower		tp_recycle_tsuffix( $P );
36836396Ssklower		tp_freeref(r);
36936396Ssklower		tp_detach($P);
37036396Ssklower	}
37136396Ssklower;
37236396Ssklower
37336396Ssklower/* applicable in TP4, TP0 */
37436396SsklowerTP_CRSENT		<==		TP_CLOSED								T_CONN_req
37536396Ssklower	DEFAULT
37636396Ssklower	{
37736396Ssklower		int error;
37836396Ssklower		struct mbuf *data = MNULL;
37936396Ssklower
38036396Ssklower		IFTRACE(D_CONN)
38137469Ssklower			tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
38237469Ssklower			$P.tp_ucddata, 0, 0);
38336396Ssklower		ENDTRACE
38437469Ssklower		data =  MCPY($P.tp_ucddata, M_WAIT);
38537469Ssklower		if (data) {
38636396Ssklower			IFDEBUG(D_CONN)
38736396Ssklower				printf("T_CONN_req.trans m_copy cc 0x%x\n",
38837469Ssklower					$P.tp_ucddata);
38937469Ssklower				dump_mbuf(data, "sosnd @ T_CONN_req");
39036396Ssklower			ENDDEBUG
39136396Ssklower		}
39236396Ssklower
39336396Ssklower		if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
39436396Ssklower			return error; /* driver WON'T change state; will return error */
39536396Ssklower
39636396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers */
39736396Ssklower		if($P.tp_class != TP_CLASS_0) {
39836396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
39936396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
40036396Ssklower		}
40136396Ssklower	}
40236396Ssklower;
40336396Ssklower
40436396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
40536396SsklowerTP_REFWAIT 		<==		[ TP_CRSENT, TP_AKWAIT, TP_OPEN ] 			DR_TPDU
40636396Ssklower	DEFAULT
40736396Ssklower	{
40836396Ssklower		if ($$.e_datalen > 0 && $P.tp_class != TP_CLASS_0) {
40937469Ssklower			/*sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc); /* purge expedited data */
41037469Ssklower			sbflush(&$P.tp_Xrcv);
41136396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
41236396Ssklower			$$.e_data = MNULL;
41336396Ssklower		}
41436396Ssklower		tp_indicate(T_DISCONNECT, $P, TP_ERROR_MASK | (u_short)$$.e_reason);
41536396Ssklower		tp_soisdisconnected($P);
41636396Ssklower		if ($P.tp_class != TP_CLASS_0) {
41736396Ssklower			if ($P.tp_state == TP_OPEN ) {
41836396Ssklower				tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
41936396Ssklower				tp_cuntimeout($P.tp_refp, TM_retrans);
42036396Ssklower				tp_cuntimeout($P.tp_refp, TM_inact);
42136396Ssklower				tp_cuntimeout($P.tp_refp, TM_sendack);
42236396Ssklower			}
42336396Ssklower			tp_cuntimeout($P.tp_refp, TM_retrans);
42436396Ssklower			if( $$.e_sref !=  0 )
42536396Ssklower				(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
42636396Ssklower		}
42736396Ssklower	}
42836396Ssklower;
42936396Ssklower
43036396SsklowerSAME 			<==		TP_CLOSED 									DR_TPDU
43136396Ssklower	DEFAULT
43236396Ssklower	{
43336396Ssklower		if( $$.e_sref != 0 )
43436396Ssklower			(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
43536396Ssklower		/* reference timer already set - reset it to be safe (???) */
43636396Ssklower		tp_euntimeout($P.tp_refp, TM_reference); /* all */
43736396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks);
43836396Ssklower	}
43936396Ssklower;
44036396Ssklower
44136396Ssklower/* NBS(34) */
44236396SsklowerTP_REFWAIT 		<==  	TP_CRSENT  									ER_TPDU
44336396Ssklower	DEFAULT
44436396Ssklower	{
44536396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
44636396Ssklower		tp_indicate(T_DISCONNECT, $P,
44736396Ssklower			TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
44836396Ssklower		tp_soisdisconnected($P);
44936396Ssklower	}
45036396Ssklower;
45136396Ssklower
45236396Ssklower/* NBS(27) */
45336396SsklowerTP_REFWAIT		<==		TP_CLOSING									DR_TPDU
45436396Ssklower	DEFAULT
45536396Ssklower	{
45636396Ssklower		$P.tp_sock->so_error = (u_short)$$.e_reason;
45736396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
45836396Ssklower		tp_soisdisconnected($P);
45936396Ssklower	}
46036396Ssklower;
46136396Ssklower/* these two transitions are the same but can't be combined because xebec
46236396Ssklower * can't handle the use of $$.e_reason if they're combined
46336396Ssklower */
46436396Ssklower/* NBS(27) */
46536396SsklowerTP_REFWAIT		<==		TP_CLOSING									ER_TPDU
46636396Ssklower	DEFAULT
46736396Ssklower	{
46836396Ssklower		$P.tp_sock->so_error = (u_short)$$.e_reason;
46936396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
47036396Ssklower		tp_soisdisconnected($P);
47136396Ssklower	}
47236396Ssklower;
47336396Ssklower/* NBS(27) */
47436396SsklowerTP_REFWAIT		<==		TP_CLOSING									DC_TPDU
47536396Ssklower	DEFAULT
47636396Ssklower	{
47736396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
47836396Ssklower		tp_soisdisconnected($P);
47936396Ssklower	}
48036396Ssklower;
48136396Ssklower
48236396Ssklower/* NBS(21) */
48336396SsklowerSAME 			<== 	TP_CLOSED 						[ CC_TPDU, CR_TPDU ]
48436396Ssklower	DEFAULT
48536396Ssklower	{	/* don't ask me why we have to do this - spec says so */
48636396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
48736396Ssklower		/* don't bother with retransmissions of the DR */
48836396Ssklower	}
48936396Ssklower;
49036396Ssklower
49136396Ssklower/* NBS(34) */
49236396SsklowerTP_REFWAIT 		<== 	TP_OPEN  				 					ER_TPDU
49336396Ssklower	($P.tp_class == TP_CLASS_0)
49436396Ssklower	{
49536396Ssklower		tp_soisdisconnecting($P.tp_sock);
49636396Ssklower		tp_indicate(T_DISCONNECT, $P,
49736396Ssklower			TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
49836396Ssklower
49936396Ssklower		tp_soisdisconnected($P);
50036396Ssklower		tp_netcmd( $P, CONN_CLOSE );
50136396Ssklower	}
50236396Ssklower;
50336396Ssklower
50436396SsklowerTP_CLOSING 		<== 	[ TP_AKWAIT, TP_OPEN ]  					ER_TPDU
50536396Ssklower	DEFAULT
50636396Ssklower	{
50736396Ssklower		if ($P.tp_state == TP_OPEN) {
50836396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
50936396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
51036396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
51136396Ssklower		}
51236396Ssklower		tp_soisdisconnecting($P.tp_sock);
51336396Ssklower		tp_indicate(T_DISCONNECT, $P,
51436396Ssklower			TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
51536396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
51636396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
51736396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
51836396Ssklower	}
51936396Ssklower;
52036396Ssklower/* NBS(6) */
52136396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
52236396Ssklower	($P.tp_class == TP_CLASS_0)
52336396Ssklower	{
52436396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
52536396Ssklower		IncStat(ts_tp0_conn);
52636396Ssklower		$P.tp_fcredit = 1;
52736396Ssklower		soisconnected($P.tp_sock);
52836396Ssklower	}
52936396Ssklower;
53036396Ssklower
53136396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
53236396Ssklower	DEFAULT
53336396Ssklower	{
53436396Ssklower		IFDEBUG(D_CONN)
53536396Ssklower			printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
53636396Ssklower				(int)$P.tp_flags);
53736396Ssklower		ENDDEBUG
53836396Ssklower		IncStat(ts_tp4_conn);
53936396Ssklower		$P.tp_fref = $$.e_sref;
54036396Ssklower		$P.tp_fcredit = $$.e_cdt;
54139921Ssklower		$P.tp_ackrcvd = 0;
542*47281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
54336396Ssklower			$P.tp_cong_win = $$.e_cdt;
54436396Ssklower		tp_getoptions($P);
54536396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
54637469Ssklower		if ($P.tp_ucddata) {
54736396Ssklower			IFDEBUG(D_CONN)
54837469Ssklower				printf("dropping user connect data cc 0x%x\n",
54937469Ssklower					$P.tp_ucddata->m_len);
55036396Ssklower			ENDDEBUG
55137469Ssklower			m_freem($P.tp_ucddata);
55237469Ssklower			$P.tp_ucddata = 0;
55336396Ssklower		}
55436396Ssklower		soisconnected($P.tp_sock);
55536396Ssklower		if ($$.e_datalen > 0) {
55636396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
55736396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
55836396Ssklower			$$.e_data = MNULL;
55936396Ssklower		}
56036396Ssklower
56136396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
56236396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
56336396Ssklower	}
56436396Ssklower;
56536396Ssklower
56636396Ssklower/* TP4 only */
56736396SsklowerSAME			<==		TP_CRSENT									TM_retrans
56836396Ssklower	(	$P.tp_retrans > 0 )
56936396Ssklower	{
57036396Ssklower		struct mbuf *data = MNULL;
57136396Ssklower		int error;
57236396Ssklower
57336396Ssklower		IncStat(ts_retrans_cr);
57439921Ssklower		$P.tp_cong_win = 1;
57539921Ssklower		$P.tp_ackrcvd = 0;
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
756*47281Ssklower	($P.tp_Xrcvnxt == $$.e_seq)
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;
775*47281Ssklower		$$.e_data->m_flags |= M_EOR;
77637469Ssklower		sbinsertoob(&$P.tp_Xrcv, $$.e_data);
77736396Ssklower		IFDEBUG(D_XPD)
77836396Ssklower			dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
77936396Ssklower		ENDDEBUG
78036396Ssklower		tp_indicate(T_XDATA, $P, 0);
78136396Ssklower		sbwakeup( &$P.tp_Xrcv );
78236396Ssklower
78336396Ssklower		(void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
78436396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
78536396Ssklower	}
78636396Ssklower;
78736396Ssklower
78836396Ssklower/* TP4 only */
78936396SsklowerSAME			<==		TP_OPEN 									T_USR_Xrcvd
79036396Ssklower	DEFAULT
79136396Ssklower	{
79236396Ssklower		if( $P.tp_Xrcv.sb_cc == 0 ) {
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 ) {
83036396Ssklower			/* might as well kick 'em again */
83136396Ssklower			tp_indicate(T_XDATA, $P, 0);
83236396Ssklower			IncStat(ts_xpd_dup);
83336396Ssklower		}
83436396Ssklower		m_freem($$.e_data);
83536396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
83636396Ssklower		/* don't send an xack because the xak gives "last one received", not
83736396Ssklower		 * "next one i expect" (dumb)
83836396Ssklower		 */
83936396Ssklower	}
84036396Ssklower;
84136396Ssklower
84236396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
84336396Ssklower * to detach all its "children"
84436396Ssklower * Also (CRSENT) when user kills a job that's doing a connect()
84536396Ssklower */
84636396SsklowerTP_REFWAIT		<== 	TP_CRSENT 										T_DETACH
84736396Ssklower	($P.tp_class == TP_CLASS_0)
84836396Ssklower	{
84936396Ssklower		struct socket *so = $P.tp_sock;
85036396Ssklower
85136396Ssklower		/* detach from parent socket so it can finish closing */
85236396Ssklower		if (so->so_head) {
85336396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
85436396Ssklower				panic("tp: T_DETACH");
85536396Ssklower			so->so_head = 0;
85636396Ssklower		}
85736396Ssklower		tp_soisdisconnecting($P.tp_sock);
85836396Ssklower		tp_netcmd( $P, CONN_CLOSE);
85936396Ssklower		tp_soisdisconnected($P);
86036396Ssklower	}
86136396Ssklower;
86236396Ssklower
86336396Ssklower/* TP4 only */
86438841SsklowerTP_CLOSING		<== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ]	T_DETACH
86536396Ssklower	DEFAULT
86636396Ssklower	{
86736396Ssklower		struct socket *so = $P.tp_sock;
86837469Ssklower		struct mbuf *data = MNULL;
86936396Ssklower
87036396Ssklower		/* detach from parent socket so it can finish closing */
87136396Ssklower		if (so->so_head) {
87236396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
87336396Ssklower				panic("tp: T_DETACH");
87436396Ssklower			so->so_head = 0;
87536396Ssklower		}
87636396Ssklower		if ($P.tp_state != TP_CLOSING) {
87736396Ssklower			tp_soisdisconnecting($P.tp_sock);
87837469Ssklower			data = MCPY($P.tp_ucddata, M_NOWAIT);
87937469Ssklower			(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
88036396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
88136396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
88236396Ssklower		}
88336396Ssklower	}
88436396Ssklower;
88536396Ssklower
88636396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT ]		 	  			T_DISC_req
88736396Ssklower	( $P.tp_class == TP_CLASS_0 )
88836396Ssklower	{
88936396Ssklower		tp_soisdisconnecting($P.tp_sock);
89036396Ssklower		tp_netcmd( $P, CONN_CLOSE);
89136396Ssklower		tp_soisdisconnected($P);
89236396Ssklower	}
89336396Ssklower;
89436396Ssklower
89536396Ssklower/* TP4 only */
89638841SsklowerTP_CLOSING		<==	[ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
89736396Ssklower	DEFAULT
89836396Ssklower	{
89937469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
90036396Ssklower
90136396Ssklower		if($P.tp_state == TP_OPEN) {
90236396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
90336396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
90436396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
90536396Ssklower		}
90637469Ssklower		if (data) {
90736396Ssklower			IFDEBUG(D_CONN)
90837469Ssklower				printf("T_DISC_req.trans tp_ucddata 0x%x\n",
90937469Ssklower					$P.tp_ucddata);
91037469Ssklower				dump_mbuf(data, "ucddata @ T_DISC_req");
91136396Ssklower			ENDDEBUG
91236396Ssklower		}
91336396Ssklower		tp_soisdisconnecting($P.tp_sock);
91436396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
91536396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
91636396Ssklower
91736396Ssklower		if( trick_hc )
91836396Ssklower			return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
91936396Ssklower	}
92036396Ssklower;
92136396Ssklower
92236396Ssklower/* TP4 only */
92336396SsklowerSAME			<==		TP_AKWAIT									TM_retrans
92436396Ssklower	( $P.tp_retrans > 0 )
92536396Ssklower	{
92636396Ssklower		int error;
92737469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
92836396Ssklower
92936396Ssklower		IncStat(ts_retrans_cc);
93036396Ssklower		$P.tp_retrans --;
93139921Ssklower		$P.tp_cong_win = 1;
93239921Ssklower		$P.tp_ackrcvd = 0;
93339921Ssklower
93437469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
93536396Ssklower			$P.tp_sock->so_error = error;
93636396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
93736396Ssklower	}
93836396Ssklower;
93936396Ssklower
94036396Ssklower/* TP4 only */
94136396SsklowerTP_CLOSING		<==		TP_AKWAIT									TM_retrans
94236396Ssklower	DEFAULT  /* out of time */
94336396Ssklower	{
94436396Ssklower		IncStat(ts_conn_gaveup);
94536396Ssklower		tp_soisdisconnecting($P.tp_sock);
94636396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
94736396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
94836396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
94936396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
95036396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
95136396Ssklower	}
95236396Ssklower;
95336396Ssklower
95436396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does,
95536396Ssklower * if transmissions are going on.
95636396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack
95736396Ssklower * turnaround)
95836396Ssklower */
95936396Ssklower/* TP4 only */
96036396SsklowerTP_CLOSING 		<==		TP_OPEN		   [ TM_inact, TM_retrans, TM_data_retrans ]
96136396Ssklower	DEFAULT
96236396Ssklower	{
96336396Ssklower		tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
96436396Ssklower		tp_cuntimeout($P.tp_refp, TM_inact);
96536396Ssklower		tp_cuntimeout($P.tp_refp, TM_sendack);
96636396Ssklower
96736396Ssklower		IncStat(ts_conn_gaveup);
96836396Ssklower		tp_soisdisconnecting($P.tp_sock);
96936396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
97036396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
97136396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
97236396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
97336396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
97436396Ssklower	}
97536396Ssklower;
97636396Ssklower
97736396Ssklower/* TP4 only */
97836396SsklowerSAME			<==		TP_OPEN										TM_retrans
97936396Ssklower	( $P.tp_retrans > 0 )
98036396Ssklower	{
98139921Ssklower		$P.tp_cong_win = 1;
98239921Ssklower		$P.tp_ackrcvd = 0;
98336396Ssklower		/* resume XPD */
98436396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
98537469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
98636396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
98736396Ssklower			 * that doesn't matter
98836396Ssklower			 */
98936396Ssklower
99036396Ssklower			IFTRACE(D_XPD)
99136396Ssklower				tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna",
99236396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
99336396Ssklower					$P.tp_snduna);
99436396Ssklower			ENDTRACE
99536396Ssklower			IFDEBUG(D_XPD)
99636396Ssklower				dump_mbuf(m, "XPD retrans emitting M");
99736396Ssklower			ENDDEBUG
99836396Ssklower			IncStat(ts_retrans_xpd);
99936396Ssklower			$P.tp_retrans --;
100036396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
100136396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
100236396Ssklower		}
100336396Ssklower	}
100436396Ssklower;
100536396Ssklower
100636396Ssklower/* TP4 only */
100736396SsklowerSAME 			<==		TP_OPEN									TM_data_retrans
100836396Ssklower	( $$.e_retrans > 0 )
100936396Ssklower	{
101036396Ssklower		register 	SeqNum			low, lowsave = 0;
101136396Ssklower		register	struct tp_rtc 	*r = $P.tp_snduna_rtc;
101236396Ssklower		register	struct mbuf 	*m;
101336396Ssklower		register	SeqNum			high = $$.e_high;
101436396Ssklower
101539921Ssklower		low = $P.tp_snduna;
101639921Ssklower		lowsave = high = low;
101739921Ssklower
101839921Ssklower		tp_euntimeout_lss($P.tp_refp, TM_data_retrans,
101939921Ssklower			SEQ_ADD($P, $P.tp_sndhiwat, 1));
102039921Ssklower		$P.tp_retrans_hiwat = $P.tp_sndhiwat;
102139921Ssklower
102236396Ssklower		if (($P.tp_rx_strat & TPRX_EACH) == 0)
102336396Ssklower			high = (high>low)?low:high;
102436396Ssklower
102536396Ssklower		if( $P.tp_rx_strat & TPRX_USE_CW ) {
102636396Ssklower			register int i;
102736396Ssklower
102836396Ssklower			$P.tp_cong_win = 1;
102939921Ssklower			$P.tp_ackrcvd = 0;
103039921Ssklower			i = SEQ_ADD($P, low, $P.tp_cong_win);
103136396Ssklower
103239921Ssklower			high = SEQ_MIN($P, high, $P.tp_sndhiwat);
103339921Ssklower
103436396Ssklower		}
103536396Ssklower
103636396Ssklower		while( SEQ_LEQ($P, low, high) ){
103736396Ssklower			if ( r == (struct tp_rtc *)0 ){
103836396Ssklower				IFDEBUG(D_RTC)
103936396Ssklower					printf( "tp: retrans rtc list is GONE!\n");
104036396Ssklower				ENDDEBUG
104136396Ssklower				break;
104236396Ssklower			}
104336396Ssklower			if ( r->tprt_seq == low ){
104436396Ssklower				if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL)
104536396Ssklower					break;
104636396Ssklower				(void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m);
104736396Ssklower				IncStat(ts_retrans_dt);
104836396Ssklower				SEQ_INC($P, low );
104936396Ssklower			}
105036396Ssklower			r = r->tprt_next;
105136396Ssklower		}
105239921Ssklower/* CE_BIT
105336396Ssklower		if ( SEQ_LEQ($P, lowsave, high) ){
105439921Ssklower*/
105536396Ssklower			$$.e_retrans --;
105636396Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
105736396Ssklower					(caddr_t)high, $$.e_retrans,
105836396Ssklower					($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks);
105939921Ssklower/* CE_BIT
106036396Ssklower		}
106139921Ssklower*/
106236396Ssklower	}
106336396Ssklower;
106436396Ssklower
106536396Ssklower/* TP4 only */
106636396SsklowerSAME	 		<==		TP_CLOSING									TM_retrans
106736396Ssklower	(	$P.tp_retrans > 0 )
106836396Ssklower	{
106936396Ssklower		$P.tp_retrans --;
107036396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
107136396Ssklower		IncStat(ts_retrans_dr);
107236396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
107336396Ssklower	}
107436396Ssklower;
107536396Ssklower
107636396Ssklower/* TP4 only */
107736396SsklowerTP_REFWAIT 		<==		TP_CLOSING									TM_retrans
107836396Ssklower	DEFAULT	/* no more retrans - gave up */
107936396Ssklower	{
108036396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
108136396Ssklower		$P.tp_refp->tpr_state = REF_FROZEN;
108236396Ssklower		tp_recycle_tsuffix( $P );
108336396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks);
108436396Ssklower	}
108536396Ssklower;
108636396Ssklower
108736396Ssklower/*
108836396Ssklower * The resources are kept around until the ref timer goes off.
108936396Ssklower * The suffices are wiped out sooner so they can be reused right away.
109036396Ssklower */
109136396Ssklower/* applicable in TP4, TP0 */
109236396SsklowerTP_CLOSED 		<==		TP_REFWAIT 									TM_reference
109336396Ssklower	DEFAULT
109436396Ssklower	{
109536396Ssklower		tp_freeref($P.tp_refp);
109636396Ssklower		tp_detach($P);
109736396Ssklower	}
109836396Ssklower;
109936396Ssklower
110036396Ssklower/* applicable in TP4, TP0 */
110136396Ssklower/* A duplicate CR from connectionless network layer can't happen */
110236396SsklowerSAME 			<== 	TP_OPEN 							[ CR_TPDU, CC_TPDU ]
110336396Ssklower	DEFAULT
110436396Ssklower	{
110536396Ssklower		if( $P.tp_class != TP_CLASS_0) {
110636396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
110736396Ssklower			if ( $E.ev_number == CC_TPDU )
110836396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
110936396Ssklower		}
111036396Ssklower		/* ignore it if class 0 - state tables are blank for this */
111136396Ssklower	}
111236396Ssklower;
111336396Ssklower
111436396Ssklower/* applicable in TP4, TP0 */
111536396SsklowerSAME			<== 	TP_OPEN									T_DATA_req
111636396Ssklower	DEFAULT
111736396Ssklower	{
111836396Ssklower		IFTRACE(D_DATA)
111936396Ssklower			tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb",
112036396Ssklower				$P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P);
112136396Ssklower		ENDTRACE
112236396Ssklower
112336396Ssklower		tp_send($P);
112436396Ssklower	}
112536396Ssklower;
112636396Ssklower
112736396Ssklower/* TP4 only */
112836396SsklowerSAME			<==		TP_OPEN										T_XPD_req
112936396Ssklower	DEFAULT
113036396Ssklower		/* T_XPD_req was issued by sosend iff xpd socket buf was empty
113136396Ssklower		 * at time of sosend(),
113236396Ssklower		 * AND (which means) there were no unacknowledged XPD tpdus outstanding!
113336396Ssklower		 */
113436396Ssklower	{
113536396Ssklower		int error = 0;
113636396Ssklower
113736396Ssklower		/* resume XPD */
113836396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
113937469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
114036396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
114136396Ssklower			 * that doesn't matter
114236396Ssklower			 */
114336396Ssklower
114436396Ssklower			IFTRACE(D_XPD)
114536396Ssklower				tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna",
114636396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
114736396Ssklower					$P.tp_snduna);
114836396Ssklower			ENDTRACE
114936396Ssklower			IFDEBUG(D_XPD)
115036396Ssklower				printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
115136396Ssklower				dump_mbuf(m, "XPD req emitting M");
115236396Ssklower			ENDDEBUG
115336396Ssklower			error =
115436396Ssklower				tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
115536396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
115636396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
115736396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
115836396Ssklower		}
115936396Ssklower		if(trick_hc)
116036396Ssklower			return error;
116136396Ssklower	}
116236396Ssklower;
116336396Ssklower
116436396Ssklower/* TP4, faked ack in TP0 when cons send completes */
116536396SsklowerSAME 			<==		TP_OPEN 									AK_TPDU
116636396Ssklower	( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
116736396Ssklower
116836396Ssklower	/* tp_goodack == true means
116936396Ssklower	 * EITHER it actually acked something heretofore unacknowledged
117036396Ssklower	 * OR no news but the credit should be processed.
117136396Ssklower	 */
117236396Ssklower	{
117336396Ssklower		IFDEBUG(D_ACKRECV)
117436396Ssklower			printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
117536396Ssklower		ENDDEBUG
117636396Ssklower		if( $P.tp_class != TP_CLASS_0) {
117736396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
117836396Ssklower			tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq);
117936396Ssklower		}
118036396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
118136396Ssklower
118239921Ssklower		if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat &&
118339921Ssklower			$P.tp_snduna <= $P.tp_retrans_hiwat) {
118439921Ssklower
118539921Ssklower			register    struct mbuf     *m;
118639921Ssklower			/* extern      struct mbuf     *m_copy(); */
118739921Ssklower			register    struct tp_rtc   *r;
118839921Ssklower			SeqNum      high, retrans, low_save;
118939921Ssklower
119039921Ssklower			high = SEQ_MIN($P, SEQ_ADD($P, $P.tp_snduna,
119139921Ssklower					MIN($P.tp_cong_win, $P.tp_fcredit)) - 1,
119239921Ssklower					$P.tp_sndhiwat);
119339921Ssklower			low_save = retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1),
119439921Ssklower					$P.tp_snduna);
119539921Ssklower			for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) {
119639921Ssklower
119739921Ssklower				for (r = $P.tp_snduna_rtc; r; r = r->tprt_next){
119839921Ssklower					if ( r->tprt_seq == retrans ){
119939921Ssklower						if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))
120039921Ssklower								== MNULL)
120139921Ssklower							break;
120239921Ssklower						(void) tp_emit(DT_TPDU_type, $P, retrans,
120339921Ssklower							r->tprt_eot, m);
120439921Ssklower						$P.tp_last_retrans = retrans;
120539921Ssklower						IncStat(ts_retrans_dt);
120639921Ssklower						break;
120739921Ssklower					}
120839921Ssklower				}
120939921Ssklower				if ( r == (struct tp_rtc *)0 ){
121039921Ssklower					IFDEBUG(D_RTC)
121139921Ssklower						printf( "tp: retrans rtc list is GONE!\n");
121239921Ssklower					ENDDEBUG
121339921Ssklower					break;
121439921Ssklower				}
121539921Ssklower			}
121639921Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)low_save,
121739921Ssklower					(caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks);
121839921Ssklower			if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat)
121939921Ssklower				tp_send($P);
122039921Ssklower		}
122139921Ssklower		else {
122239921Ssklower			tp_send($P);
122339921Ssklower		}
122436396Ssklower		IFDEBUG(D_ACKRECV)
122536396Ssklower			printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat);
122636396Ssklower		ENDDEBUG
122736396Ssklower	}
122836396Ssklower;
122936396Ssklower
123036396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
123136396SsklowerSAME			<==		TP_OPEN 			 						 AK_TPDU
123236396Ssklower	DEFAULT
123336396Ssklower	{
123436396Ssklower		IFTRACE(D_ACKRECV)
123536396Ssklower			tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
123636396Ssklower				$$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
123736396Ssklower		ENDTRACE
123836396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
123936396Ssklower
124036396Ssklower			if ( !$$.e_fcc_present ) {
124136396Ssklower				/* send ACK with FCC */
124236396Ssklower				IncStat( ts_ackreason[_ACK_FCC_] );
124336396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
124436396Ssklower			}
124536396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
124636396Ssklower		}
124736396Ssklower	}
124836396Ssklower;
124936396Ssklower
125036396Ssklower/* NBS(47) */
125136396Ssklower	/* goes in at *** */
125236396Ssklower		/* just so happens that this is never true now, because we allow
125336396Ssklower		 * only 1 packet in the queue at once (this could be changed)
125436396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
125536396Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
125636396Ssklower
125736396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
125836396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
125936396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
126036396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
126136396Ssklower		}
126236396Ssklower		 */
126336396Ssklower	/* end of the above hack */
126436396Ssklower
126536396Ssklower/* TP4 only */
126642944SsklowerSAME			<== 	TP_OPEN										XAK_TPDU
126736396Ssklower	( tp_goodXack($P, $$.e_seq) )
126836396Ssklower	/* tp_goodXack checks for good ack, removes the correct
126936396Ssklower	 * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
127036396Ssklower	 * also updates tp_Xuna
127136396Ssklower	 */
127236396Ssklower	{
127336396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
127436396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
127536396Ssklower
127636396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
127736396Ssklower
127836396Ssklower		/* resume normal data */
127936396Ssklower		tp_send($P);
128036396Ssklower	}
128136396Ssklower;
128236396Ssklower
128342944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
128442944SsklowerSAME			<==		TP_OPEN 			 						XAK_TPDU
128542944Ssklower	DEFAULT
128642944Ssklower	{
128742944Ssklower		IFTRACE(D_ACKRECV)
128842944Ssklower			tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
128942944Ssklower		ENDTRACE
129042944Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
129142944Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
129242944Ssklower		}
129342944Ssklower	}
129442944Ssklower;
129542944Ssklower
129636396Ssklower/* TP4 only */
129736396SsklowerSAME			<==		TP_OPEN 								TM_sendack
129836396Ssklower	DEFAULT
129936396Ssklower	{
130036396Ssklower		IFTRACE(D_TIMER)
130136396Ssklower			tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
130236396Ssklower			$P.tp_sent_lcdt, 0);
130336396Ssklower		ENDTRACE
130436396Ssklower		IncPStat($P, tps_n_TMsendack);
130536396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
130636396Ssklower	}
130736396Ssklower;
130836396Ssklower
130936396Ssklower/* TP0 only */
131036396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
131136396Ssklower	($P.tp_class == TP_CLASS_0)
1312*47281Ssklower	{
1313*47281Ssklower		if (sbspace(&$P.tp_sock->so_rcv) > 0)
1314*47281Ssklower			tp0_openflow($P);
1315*47281Ssklower	}
131636396Ssklower;
131736396Ssklower
131836396Ssklower/* TP4 only */
131936396Ssklower		/* If old credit was zero,
132036396Ssklower		 * we'd better inform other side that we now have space
132136396Ssklower		 * But this is not enough.  Sender might not yet have
132236396Ssklower		 * seen an ack with cdt 0 but it might still think the
132336396Ssklower		 * window is closed, so it's going to wait.
132436396Ssklower		 * Best to send an ack each time.
132536396Ssklower		 * Strictly speaking, this ought to be a function of the
132636396Ssklower		 * general ack strategy.
132736396Ssklower		 */
132836396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
132936396Ssklower	DEFAULT
133036396Ssklower	{
133136396Ssklower		if( trick_hc ) {
133236396Ssklower			IncStat(ts_ackreason[_ACK_USRRCV_]);
133339921Ssklower
133439921Ssklower			/* send an ACK only if there's new information */
133539921Ssklower			LOCAL_CREDIT( $P );
133639921Ssklower			if (($P.tp_rcvnxt != $P.tp_sent_rcvnxt) ||
133739921Ssklower				($P.tp_lcredit != $P.tp_sent_lcdt))
133839921Ssklower
133939921Ssklower				return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
134036396Ssklower		}
134136396Ssklower	}
134236396Ssklower;
134336396Ssklower
134436396Ssklower/* applicable in TP4, TP0 */
134536396SsklowerSAME			<==		TP_REFWAIT 				[ T_USR_rcvd, T_USR_Xrcvd ]
134636396Ssklower	DEFAULT
134736396Ssklower	/* This happens if other end sent a DR when  the user was waiting
134836396Ssklower	 * on a receive.
134936396Ssklower	 * Processing the DR includes putting us in REFWAIT state.
135036396Ssklower	 */
135136396Ssklower	{
135236396Ssklower		if(trick_hc)
135336396Ssklower		return ECONNABORTED;
135436396Ssklower	}
135536396Ssklower;
135636396Ssklower
135736396Ssklower/* TP0 only */
135836396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT, TP_LISTENING ] 	T_NETRESET
135936396Ssklower	( $P.tp_class != TP_CLASS_4 )
136036396Ssklower		/* 0 or (4 and 0) */
136136396Ssklower		/* in OPEN class will be 0 or 4 but not both */
136236396Ssklower		/* in CRSENT or LISTENING it could be in negotiation, hence both */
136336396Ssklower		/* Actually, this shouldn't ever happen in LISTENING */
136436396Ssklower	{
136536396Ssklower		ASSERT( $P.tp_state != TP_LISTENING );
136636396Ssklower		tp_indicate(T_DISCONNECT, $P, ECONNRESET);
136736396Ssklower		tp_soisdisconnected($P);
136836396Ssklower	}
136936396Ssklower;
137036396Ssklower
137136396Ssklower/* TP4: ignore resets */
137236396SsklowerSAME		<==		[ TP_OPEN, TP_CRSENT, TP_AKWAIT,
137336396Ssklower						TP_CLOSING, TP_LISTENING ] 				T_NETRESET
137436396Ssklower	DEFAULT
137536396Ssklower	NULLACTION
137636396Ssklower;
137736396Ssklower
137836396Ssklower/* applicable in TP4, TP0 */
137936396SsklowerSAME			<==		[ TP_CLOSED, TP_REFWAIT ]				T_NETRESET
138036396Ssklower	DEFAULT
138136396Ssklower	NULLACTION
138236396Ssklower;
138336396Ssklower
138436396Ssklower/* C'EST TOUT */
1385