xref: /csrg-svn/sys/netiso/tp.trans (revision 53683)
150849Ssklower/* NEW */
249268Sbostic/*-
349268Sbostic * Copyright (c) 1991 The Regents of the University of California.
449268Sbostic * All rights reserved.
549268Sbostic *
649268Sbostic * %sccs.include.redist.c%
749268Sbostic *
8*53683Ssklower *	@(#)tp.trans	7.19 (Berkeley) 05/27/92
949268Sbostic */
1049268Sbostic
1136396Ssklower/***********************************************************
1236396Ssklower		Copyright IBM Corporation 1987
1336396Ssklower
1436396Ssklower                      All Rights Reserved
1536396Ssklower
1636396SsklowerPermission to use, copy, modify, and distribute this software and its
1736396Ssklowerdocumentation for any purpose and without fee is hereby granted,
1836396Ssklowerprovided that the above copyright notice appear in all copies and that
1936396Ssklowerboth that copyright notice and this permission notice appear in
2036396Ssklowersupporting documentation, and that the name of IBM not be
2136396Ssklowerused in advertising or publicity pertaining to distribution of the
2236396Ssklowersoftware without specific, written prior permission.
2336396Ssklower
2436396SsklowerIBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2536396SsklowerALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2636396SsklowerIBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2736396SsklowerANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2836396SsklowerWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2936396SsklowerARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
3036396SsklowerSOFTWARE.
3136396Ssklower
3236396Ssklower******************************************************************/
3336396Ssklower
3436396Ssklower/*
3536396Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3636396Ssklower */
3736396Ssklower/* $Header: tp.trans,v 5.1 88/10/12 12:22:07 root Exp $
3836396Ssklower *
3936396Ssklower * Transition file for TP.
4036396Ssklower *
4136396Ssklower * DO NOT:
4236396Ssklower * - change the order of any of the events or states.  to do so will
4336396Ssklower *   make tppt, netstat, etc. cease working.
4436396Ssklower *
4536396Ssklower * NOTE:
4636396Ssklower * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED***
4736396Ssklower * (read: may not work!)
4836396Ssklower *
4936396Ssklower * I tried to put everything that causes a change of state in here, hence
5036396Ssklower * there are some seemingly trivial events  like T_DETACH and T_LISTEN_req.
5136396Ssklower *
5236396Ssklower * Almost everything having to do w/ setting & cancelling timers is here
5336396Ssklower * but once it was debugged, I moved the setting of the
5436396Ssklower * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent.
5536396Ssklower * This is so the code wouldn't be duplicated all over creation in here.
5636396Ssklower *
5736396Ssklower */
5836396Ssklower*PROTOCOL tp
5936396Ssklower
6036396Ssklower*INCLUDE
6136396Ssklower{
62*53683Ssklower/* @(#)tp.trans	7.19 (Berkeley) 05/27/92 */
6336396Ssklower#include "param.h"
6436396Ssklower#include "socket.h"
6536396Ssklower#include "socketvar.h"
6636396Ssklower#include "protosw.h"
6736396Ssklower#include "mbuf.h"
6836396Ssklower#include "time.h"
6936396Ssklower#include "errno.h"
7036396Ssklower#include "../netiso/tp_param.h"
7136396Ssklower#include "../netiso/tp_stat.h"
7236396Ssklower#include "../netiso/tp_pcb.h"
7336396Ssklower#include "../netiso/tp_tpdu.h"
7436396Ssklower#include "../netiso/argo_debug.h"
7536396Ssklower#include "../netiso/tp_trace.h"
7636396Ssklower#include "../netiso/iso_errno.h"
7736396Ssklower#include "../netiso/tp_seq.h"
7836396Ssklower#include "../netiso/cons.h"
7936396Ssklower
8036396Ssklower#define DRIVERTRACE TPPTdriver
8137469Ssklower#define sbwakeup(sb)	sowakeup(p->tp_sock, sb);
8237469Ssklower#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
8336396Ssklower
8436396Ssklowerstatic 	trick_hc = 1;
8536396Ssklower
8636396Ssklowerint 	tp_emit(),
8736396Ssklower		tp_goodack(),				tp_goodXack(),
8836396Ssklower		tp_stash()
8936396Ssklower;
9036396Ssklowervoid	tp_indicate(),				tp_getoptions(),
9136396Ssklower		tp_soisdisconnecting(), 	tp_soisdisconnected(),
9236396Ssklower		tp_recycle_tsuffix(),
9351252Ssklower#ifdef TP_DEBUG_TIMERS
9436396Ssklower		tp_etimeout(),				tp_euntimeout(),
9551252Ssklower		tp_ctimeout(),				tp_cuntimeout(),
9651252Ssklower		tp_ctimeout_MIN(),
9751252Ssklower#endif
9836396Ssklower		tp_freeref(),				tp_detach(),
9936396Ssklower		tp0_stash(), 				tp0_send(),
10036396Ssklower		tp_netcmd(),				tp_send()
10136396Ssklower;
10236396Ssklower
10336396Ssklowertypedef  struct tp_pcb tpcb_struct;
10436396Ssklower
10536396Ssklower
10636396Ssklower}
10736396Ssklower
10836396Ssklower*PCB    tpcb_struct 	SYNONYM  P
10936396Ssklower
11036396Ssklower*STATES
11136396Ssklower
11236396SsklowerTP_CLOSED
11336396SsklowerTP_CRSENT
11436396SsklowerTP_AKWAIT
11536396SsklowerTP_OPEN
11636396SsklowerTP_CLOSING
11736396SsklowerTP_REFWAIT
11836396SsklowerTP_LISTENING	/* Local to this implementation */
11938841SsklowerTP_CONFIRMING	/* Local to this implementation */
12036396Ssklower
12136396Ssklower*EVENTS		{ struct timeval e_time; } 		SYNONYM  E
12236396Ssklower
12336396Ssklower /*
12436396Ssklower  * C (typically cancelled) timers  -
12536396Ssklower  *
12636396Ssklower  * let these be the first ones so for the sake of convenience
12736396Ssklower  * their values are 0--> n-1
12836396Ssklower  * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!!
12936396Ssklower  */
13036396Ssklower TM_inact
13136396Ssklower TM_retrans
13236396Ssklower				/* TM_retrans is used for all
13336396Ssklower				 * simple retransmissions - CR,CC,XPD,DR
13436396Ssklower				 */
13536396Ssklower
13636396Ssklower TM_sendack
13751204Ssklower				/* TM_sendack does dual duty - keepalive AND closed-window
13851204Ssklower				 * Probes.
13936396Ssklower				 * It's set w/ keepalive-ticks every time an ack is sent.
14036396Ssklower				 * (this is done in (void) tp_emit() ).
14151204Ssklower				 * Whenever a DT arrives which doesn't require immediate acking,
14251204Ssklower				 * a separate fast-timeout flag is set ensuring 200ms response.
14336396Ssklower				 */
14436396Ssklower TM_notused
14536396Ssklower
14636396Ssklower /*
14736396Ssklower  * E (typically expired) timers - these may be in any order.
14836396Ssklower  * These cause procedures to be executed directly; may not
14936396Ssklower  * cause an 'event' as we know them here.
15036396Ssklower  */
15136396Ssklower TM_reference		{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15236396Ssklower TM_data_retrans	{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15336396Ssklower
15436396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that
15536396Ssklower * for all tpdu types that can take e_data and e_datalen, these
15636396Ssklower * fields fall in the same place in the event structure, that is,
15736396Ssklower * e_data is the first field and e_datalen is the 2nd field.
15836396Ssklower */
15936396Ssklower
16036396Ssklower ER_TPDU  	 	{
16136396Ssklower				  u_char		e_reason;
16236396Ssklower				}
16336396Ssklower CR_TPDU  	 	{ struct mbuf 	*e_data;	/* first field */
16436396Ssklower				  int 			e_datalen; /* 2nd field */
16536396Ssklower				  u_int			e_cdt;
16636396Ssklower				}
16736396Ssklower DR_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
16836396Ssklower				  int 			e_datalen; /* 2nd field */
16936396Ssklower				  u_short		e_sref;
17036396Ssklower				  u_char		e_reason;
17136396Ssklower				}
17236396Ssklower DC_TPDU
17336396Ssklower CC_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
17436396Ssklower				  int 			e_datalen; /* 2nd field */
17536396Ssklower				  u_short		e_sref;
17636396Ssklower				  u_int			e_cdt;
17736396Ssklower				}
17836396Ssklower AK_TPDU		{ u_int			e_cdt;
17936396Ssklower				  SeqNum 	 	e_seq;
18036396Ssklower				  SeqNum 	 	e_subseq;
18136396Ssklower				  u_char 	 	e_fcc_present;
18236396Ssklower				}
18336396Ssklower DT_TPDU		{ struct mbuf	*e_data; 	/* first field */
18436396Ssklower				  int 			e_datalen; /* 2nd field */
18536396Ssklower				  u_int 		e_eot;
18636396Ssklower				  SeqNum		e_seq;
18736396Ssklower				}
18836396Ssklower XPD_TPDU		{ struct mbuf 	*e_data;	/* first field */
18936396Ssklower				  int 			e_datalen; 	/* 2nd field */
19036396Ssklower				  SeqNum 		e_seq;
19136396Ssklower				}
19236396Ssklower XAK_TPDU		{ SeqNum 		e_seq;		}
19336396Ssklower
19436396Ssklower T_CONN_req
19536396Ssklower T_DISC_req		{ u_char		e_reason; 	}
19636396Ssklower T_LISTEN_req
19736396Ssklower T_DATA_req
19836396Ssklower T_XPD_req
19936396Ssklower T_USR_rcvd
20036396Ssklower T_USR_Xrcvd
20136396Ssklower T_DETACH
20236396Ssklower T_NETRESET
20338841Ssklower T_ACPT_req
20436396Ssklower
20536396Ssklower
20636396Ssklower*TRANSITIONS
20736396Ssklower
20836396Ssklower
20936396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */
21036396SsklowerSAME			<==			TP_AKWAIT			[ CC_TPDU, DC_TPDU, XAK_TPDU ]
21136396Ssklower	DEFAULT
21236396Ssklower	NULLACTION
21336396Ssklower;
21436396Ssklower
21536396Ssklower
21636396Ssklower/* applicable in TP4, TP0 */
21736396SsklowerSAME			<==			TP_REFWAIT								DR_TPDU
21836396Ssklower	( $$.e_sref !=  0 )
21936396Ssklower	{
22036396Ssklower		(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
22136396Ssklower	}
22236396Ssklower;
22336396Ssklower
22436396Ssklower/* applicable in TP4, TP0 */
22536396SsklowerSAME			<==			TP_REFWAIT			[ CR_TPDU, CC_TPDU, DT_TPDU,
22636396Ssklower					DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ]
22736396Ssklower	DEFAULT
22836396Ssklower	{
22936396Ssklower#		ifdef TP_DEBUG
23036396Ssklower		if( $E.ev_number != AK_TPDU )
23136396Ssklower			printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number);
23236396Ssklower#		endif TP_DEBUG
23336396Ssklower	}
23436396Ssklower;
23536396Ssklower
23636396Ssklower/* applicable in TP4, TP0 */
23736396SsklowerSAME			<==			TP_REFWAIT				[ T_DETACH, T_DISC_req ]
23836396Ssklower	DEFAULT
23936396Ssklower	NULLACTION
24036396Ssklower;
24136396Ssklower
24236396Ssklower/* applicable in TP4, TP0 */
24336396SsklowerSAME			<==			TP_CRSENT								 AK_TPDU
24436396Ssklower	($P.tp_class == TP_CLASS_0)
24536396Ssklower	{
24636396Ssklower		/* oh, man is this grotesque or what? */
24736396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq,  $$.e_subseq);
24836396Ssklower		/* but it's necessary because this pseudo-ack may happen
24936396Ssklower		 * before the CC arrives, but we HAVE to adjust the
25036396Ssklower		 * snduna as a result of the ack, WHENEVER it arrives
25136396Ssklower		 */
25236396Ssklower	}
25336396Ssklower;
25436396Ssklower
25536396Ssklower/* applicable in TP4, TP0 */
25636396SsklowerSAME			<==			TP_CRSENT
25736396Ssklower					[ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU,  XAK_TPDU ]
25836396Ssklower	DEFAULT
25936396Ssklower	NULLACTION
26036396Ssklower;
26136396Ssklower
26236396Ssklower/* applicable in TP4, TP0 */
26336396SsklowerSAME			<==			TP_CLOSED					[ DT_TPDU, XPD_TPDU,
26436396Ssklower										ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
26536396Ssklower	DEFAULT
26636396Ssklower	NULLACTION
26736396Ssklower;
26836396Ssklower
26936396Ssklower/* TP_CLOSING doesn't exist in TP 0 */
27036396SsklowerSAME 			<== 		TP_CLOSING
27136396Ssklower					[ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ]
27236396Ssklower	DEFAULT
27336396Ssklower	NULLACTION
27436396Ssklower;
27536396Ssklower
27636396Ssklower
27736396Ssklower/* DC_TPDU doesn't exist in TP 0 */
27836396SsklowerSAME			<==			TP_OPEN						  DC_TPDU
27936396Ssklower	DEFAULT
28036396Ssklower	NULLACTION
28136396Ssklower;
28236396Ssklower
28336396Ssklower/* applicable in TP4, TP0 */
28436396SsklowerSAME			<==		 	TP_LISTENING  [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU,
28536396Ssklower										 ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
28636396Ssklower	DEFAULT
28736396Ssklower	NULLACTION
28836396Ssklower;
28936396Ssklower
29036396Ssklower/* applicable in TP4, TP0 */
29136396SsklowerTP_LISTENING	<==			TP_CLOSED  							T_LISTEN_req
29236396Ssklower	DEFAULT
29336396Ssklower	NULLACTION
29436396Ssklower;
29536396Ssklower
29636396Ssklower/* applicable in TP4, TP0 */
29736396SsklowerTP_CLOSED  		<== 		[ TP_LISTENING, TP_CLOSED ] 			T_DETACH
29836396Ssklower	DEFAULT
29936396Ssklower	{
30036396Ssklower		tp_detach($P);
30136396Ssklower	}
30236396Ssklower;
30336396Ssklower
30438841SsklowerTP_CONFIRMING	<==		 TP_LISTENING  								CR_TPDU
30538841Ssklower	( $P.tp_class == TP_CLASS_0)
30636396Ssklower	{
30751204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers ??? */
30836396Ssklower	}
30936396Ssklower;
31036396Ssklower
31138841SsklowerTP_CONFIRMING		<==		 TP_LISTENING  							CR_TPDU
31238841Ssklower	DEFAULT
31336396Ssklower	{
31436396Ssklower		IFTRACE(D_CONN)
31536396Ssklower			tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
31636396Ssklower		ENDTRACE
31736396Ssklower		IFDEBUG(D_CONN)
31836396Ssklower			printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
31936396Ssklower		ENDDEBUG
32051204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers */
32138841Ssklower		$P.tp_fcredit = $$.e_cdt;
32236396Ssklower
32336396Ssklower		if ($$.e_datalen > 0) {
32436396Ssklower			/* n/a for class 0 */
32536396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0);
32636396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
32736396Ssklower			$$.e_data = MNULL;
32836396Ssklower		}
32938841Ssklower	}
33038841Ssklower;
33138841Ssklower
33238841SsklowerTP_OPEN		<==		 TP_CONFIRMING  								T_ACPT_req
33338841Ssklower	( $P.tp_class == TP_CLASS_0 )
33438841Ssklower	{
33538841Ssklower		IncStat(ts_tp0_conn);
33638841Ssklower		IFTRACE(D_CONN)
33738841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
33838841Ssklower		ENDTRACE
33938841Ssklower		IFDEBUG(D_CONN)
34038841Ssklower			printf("Confirming connection: $P" );
34138841Ssklower		ENDDEBUG
34238841Ssklower		soisconnected($P.tp_sock);
34338841Ssklower		(void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
34438841Ssklower		$P.tp_fcredit = 1;
34538841Ssklower	}
34638841Ssklower;
34738841Ssklower
34838841SsklowerTP_AKWAIT		<==		 TP_CONFIRMING  							T_ACPT_req
34938841Ssklower	(tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
35038841Ssklower	{
35138841Ssklower		IncStat(ts_tp4_conn); /* even though not quite open */
35238841Ssklower		IFTRACE(D_CONN)
35338841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
35438841Ssklower		ENDTRACE
35538841Ssklower		IFDEBUG(D_CONN)
35638841Ssklower			printf("Confirming connection: $P" );
35738841Ssklower		ENDDEBUG
35850973Ssklower		tp_getoptions($P);
35938841Ssklower		soisconnecting($P.tp_sock);
36047281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
36151204Ssklower			$P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize;
36236396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
36351204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
36438841Ssklower	}
36536396Ssklower;
36636396Ssklower
36736396Ssklower/* TP4 only */
36838841SsklowerTP_CLOSED		<==		 TP_CONFIRMING								T_ACPT_req
36936396Ssklower	DEFAULT /* emit failed */
37036396Ssklower	{
37136396Ssklower		IFDEBUG(D_CONN)
37236396Ssklower			printf("event: CR_TPDU emit CC failed done " );
37336396Ssklower		ENDDEBUG
37438841Ssklower		soisdisconnected($P.tp_sock);
37551214Ssklower		tp_recycle_tsuffix($P);
37651214Ssklower		tp_freeref($P.tp_lref);
37736396Ssklower		tp_detach($P);
37836396Ssklower	}
37936396Ssklower;
38036396Ssklower
38136396Ssklower/* applicable in TP4, TP0 */
38236396SsklowerTP_CRSENT		<==		TP_CLOSED								T_CONN_req
38336396Ssklower	DEFAULT
38436396Ssklower	{
38536396Ssklower		int error;
38636396Ssklower		struct mbuf *data = MNULL;
38736396Ssklower
38836396Ssklower		IFTRACE(D_CONN)
38937469Ssklower			tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
39037469Ssklower			$P.tp_ucddata, 0, 0);
39136396Ssklower		ENDTRACE
39237469Ssklower		data =  MCPY($P.tp_ucddata, M_WAIT);
39337469Ssklower		if (data) {
39436396Ssklower			IFDEBUG(D_CONN)
39536396Ssklower				printf("T_CONN_req.trans m_copy cc 0x%x\n",
39637469Ssklower					$P.tp_ucddata);
39737469Ssklower				dump_mbuf(data, "sosnd @ T_CONN_req");
39836396Ssklower			ENDDEBUG
39936396Ssklower		}
40036396Ssklower
40136396Ssklower		if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
40236396Ssklower			return error; /* driver WON'T change state; will return error */
40336396Ssklower
40451204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers */
40536396Ssklower		if($P.tp_class != TP_CLASS_0) {
40636396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
40751204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
40836396Ssklower		}
40936396Ssklower	}
41036396Ssklower;
41136396Ssklower
41236396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
41336396SsklowerTP_REFWAIT 		<==		[ TP_CRSENT, TP_AKWAIT, TP_OPEN ] 			DR_TPDU
41436396Ssklower	DEFAULT
41536396Ssklower	{
41648739Ssklower		sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
41748739Ssklower		if ($$.e_datalen > 0) {
41836396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
41936396Ssklower			$$.e_data = MNULL;
42036396Ssklower		}
42151208Ssklower		if ($P.tp_state == TP_OPEN)
42251208Ssklower			tp_indicate(T_DISCONNECT, $P, 0);
42351208Ssklower		else {
42451208Ssklower			int so_error = ECONNREFUSED;
42551208Ssklower			if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) &&
42651208Ssklower			    $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) &&
42751208Ssklower			    $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK))
42851208Ssklower				so_error = ECONNABORTED;
42951208Ssklower			tp_indicate(T_DISCONNECT, $P, so_error);
43051208Ssklower		}
43136396Ssklower		tp_soisdisconnected($P);
43236396Ssklower		if ($P.tp_class != TP_CLASS_0) {
43336396Ssklower			if ($P.tp_state == TP_OPEN ) {
43451204Ssklower				tp_euntimeout($P, TM_data_retrans); /* all */
43551204Ssklower				tp_cuntimeout($P, TM_retrans);
43651204Ssklower				tp_cuntimeout($P, TM_inact);
43751204Ssklower				tp_cuntimeout($P, TM_sendack);
438*53683Ssklower				$P.tp_flags &= ~TPF_DELACK;
43936396Ssklower			}
44051204Ssklower			tp_cuntimeout($P, TM_retrans);
44136396Ssklower			if( $$.e_sref !=  0 )
44236396Ssklower				(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
44336396Ssklower		}
44436396Ssklower	}
44536396Ssklower;
44636396Ssklower
44736396SsklowerSAME 			<==		TP_CLOSED 									DR_TPDU
44836396Ssklower	DEFAULT
44936396Ssklower	{
45036396Ssklower		if( $$.e_sref != 0 )
45136396Ssklower			(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
45236396Ssklower		/* reference timer already set - reset it to be safe (???) */
45351204Ssklower		tp_euntimeout($P, TM_reference); /* all */
45451204Ssklower		tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
45536396Ssklower	}
45636396Ssklower;
45736396Ssklower
45836396Ssklower/* NBS(34) */
45936396SsklowerTP_REFWAIT 		<==  	TP_CRSENT  									ER_TPDU
46036396Ssklower	DEFAULT
46136396Ssklower	{
46251204Ssklower		tp_cuntimeout($P, TM_retrans);
46348739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
46436396Ssklower		tp_soisdisconnected($P);
46536396Ssklower	}
46636396Ssklower;
46736396Ssklower
46836396Ssklower/* NBS(27) */
46936396SsklowerTP_REFWAIT		<==		TP_CLOSING									DR_TPDU
47036396Ssklower	DEFAULT
47136396Ssklower	{
47251204Ssklower		tp_cuntimeout($P, TM_retrans);
47336396Ssklower		tp_soisdisconnected($P);
47436396Ssklower	}
47536396Ssklower;
47636396Ssklower/* these two transitions are the same but can't be combined because xebec
47736396Ssklower * can't handle the use of $$.e_reason if they're combined
47836396Ssklower */
47936396Ssklower/* NBS(27) */
48036396SsklowerTP_REFWAIT		<==		TP_CLOSING									ER_TPDU
48136396Ssklower	DEFAULT
48236396Ssklower	{
48348739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
48451204Ssklower		tp_cuntimeout($P, TM_retrans);
48536396Ssklower		tp_soisdisconnected($P);
48636396Ssklower	}
48736396Ssklower;
48836396Ssklower/* NBS(27) */
48936396SsklowerTP_REFWAIT		<==		TP_CLOSING									DC_TPDU
49036396Ssklower	DEFAULT
49136396Ssklower	{
49251204Ssklower		tp_cuntimeout($P, TM_retrans);
49336396Ssklower		tp_soisdisconnected($P);
49436396Ssklower	}
49536396Ssklower;
49636396Ssklower
49736396Ssklower/* NBS(21) */
49836396SsklowerSAME 			<== 	TP_CLOSED 						[ CC_TPDU, CR_TPDU ]
49936396Ssklower	DEFAULT
50036396Ssklower	{	/* don't ask me why we have to do this - spec says so */
50136396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
50236396Ssklower		/* don't bother with retransmissions of the DR */
50336396Ssklower	}
50436396Ssklower;
50536396Ssklower
50636396Ssklower/* NBS(34) */
50736396SsklowerTP_REFWAIT 		<== 	TP_OPEN  				 					ER_TPDU
50836396Ssklower	($P.tp_class == TP_CLASS_0)
50936396Ssklower	{
51036396Ssklower		tp_soisdisconnecting($P.tp_sock);
51148739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
51236396Ssklower		tp_soisdisconnected($P);
51336396Ssklower		tp_netcmd( $P, CONN_CLOSE );
51436396Ssklower	}
51536396Ssklower;
51636396Ssklower
51736396SsklowerTP_CLOSING 		<== 	[ TP_AKWAIT, TP_OPEN ]  					ER_TPDU
51836396Ssklower	DEFAULT
51936396Ssklower	{
52036396Ssklower		if ($P.tp_state == TP_OPEN) {
52151204Ssklower			tp_euntimeout($P, TM_data_retrans); /* all */
52251204Ssklower			tp_cuntimeout($P, TM_inact);
52351204Ssklower			tp_cuntimeout($P, TM_sendack);
52436396Ssklower		}
52536396Ssklower		tp_soisdisconnecting($P.tp_sock);
52648739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
52736396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
52851204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
52936396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
53036396Ssklower	}
53136396Ssklower;
53236396Ssklower/* NBS(6) */
53336396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
53436396Ssklower	($P.tp_class == TP_CLASS_0)
53536396Ssklower	{
53651204Ssklower		tp_cuntimeout($P, TM_retrans);
53736396Ssklower		IncStat(ts_tp0_conn);
53836396Ssklower		$P.tp_fcredit = 1;
53936396Ssklower		soisconnected($P.tp_sock);
54036396Ssklower	}
54136396Ssklower;
54236396Ssklower
54336396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
54436396Ssklower	DEFAULT
54536396Ssklower	{
54636396Ssklower		IFDEBUG(D_CONN)
54736396Ssklower			printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
54836396Ssklower				(int)$P.tp_flags);
54936396Ssklower		ENDDEBUG
55036396Ssklower		IncStat(ts_tp4_conn);
55136396Ssklower		$P.tp_fref = $$.e_sref;
55236396Ssklower		$P.tp_fcredit = $$.e_cdt;
55347281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
55451204Ssklower			$P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize;
55536396Ssklower		tp_getoptions($P);
55651204Ssklower		tp_cuntimeout($P, TM_retrans);
55737469Ssklower		if ($P.tp_ucddata) {
55836396Ssklower			IFDEBUG(D_CONN)
55937469Ssklower				printf("dropping user connect data cc 0x%x\n",
56037469Ssklower					$P.tp_ucddata->m_len);
56136396Ssklower			ENDDEBUG
56237469Ssklower			m_freem($P.tp_ucddata);
56337469Ssklower			$P.tp_ucddata = 0;
56436396Ssklower		}
56536396Ssklower		soisconnected($P.tp_sock);
56636396Ssklower		if ($$.e_datalen > 0) {
56736396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
56836396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
56936396Ssklower			$$.e_data = MNULL;
57036396Ssklower		}
57136396Ssklower
57236396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
57351204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
57436396Ssklower	}
57536396Ssklower;
57636396Ssklower
57736396Ssklower/* TP4 only */
57836396SsklowerSAME			<==		TP_CRSENT									TM_retrans
57936396Ssklower	(	$P.tp_retrans > 0 )
58036396Ssklower	{
58136396Ssklower		struct mbuf *data = MNULL;
58236396Ssklower		int error;
58336396Ssklower
58436396Ssklower		IncStat(ts_retrans_cr);
58551204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
58637469Ssklower		data = MCPY($P.tp_ucddata, M_NOWAIT);
58737469Ssklower		if($P.tp_ucddata) {
58836396Ssklower			IFDEBUG(D_CONN)
58937469Ssklower				printf("TM_retrans.trans m_copy cc 0x%x\n", data);
59037469Ssklower				dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
59136396Ssklower			ENDDEBUG
59236396Ssklower			if( data == MNULL )
59336396Ssklower				return ENOBUFS;
59436396Ssklower		}
59536396Ssklower
59636396Ssklower		$P.tp_retrans --;
59736396Ssklower		if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
59836396Ssklower			$P.tp_sock->so_error = error;
59936396Ssklower		}
60051204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
60136396Ssklower	}
60236396Ssklower;
60336396Ssklower
60436396Ssklower/* TP4 only  */
60536396SsklowerTP_REFWAIT		<==		TP_CRSENT									TM_retrans
60636396Ssklower	DEFAULT /* no more CR retransmissions */
60736396Ssklower	{
60836396Ssklower		IncStat(ts_conn_gaveup);
60936396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
61036396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
61136396Ssklower		tp_soisdisconnected($P);
61236396Ssklower	}
61336396Ssklower;
61436396Ssklower
61536396Ssklower/* TP4 only */
61636396SsklowerSAME 			<==	 TP_AKWAIT											CR_TPDU
61736396Ssklower	DEFAULT
61836396Ssklower	/* duplicate CR (which doesn't really exist in the context of
61936396Ssklower	 * a connectionless network layer)
62036396Ssklower	 * Doesn't occur in class 0.
62136396Ssklower	 */
62236396Ssklower	{
62336396Ssklower		int error;
62437469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
62536396Ssklower
62637469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
62736396Ssklower			$P.tp_sock->so_error = error;
62836396Ssklower		}
62936396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
63051204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
63136396Ssklower	}
63236396Ssklower;
63336396Ssklower
63436396Ssklower/* TP4 only */
63536396SsklowerTP_OPEN			<==		TP_AKWAIT 										DT_TPDU
63636396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
63736396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
63836396Ssklower	{
63936396Ssklower		int doack;
64036396Ssklower
64137469Ssklower		/*
64237469Ssklower		 * Get rid of any confirm or connect data, so that if we
64337469Ssklower		 * crash or close, it isn't thought of as disconnect data.
64437469Ssklower		 */
64537469Ssklower		if ($P.tp_ucddata) {
64637469Ssklower			m_freem($P.tp_ucddata);
64737469Ssklower			$P.tp_ucddata = 0;
64836396Ssklower		}
64951204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
65051204Ssklower		tp_cuntimeout($P, TM_retrans);
65136396Ssklower		soisconnected($P.tp_sock);
65251204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
65336396Ssklower
65436396Ssklower		/* see also next 2 transitions, if you make any changes */
65536396Ssklower
65636396Ssklower		doack = tp_stash($P, $E);
65736396Ssklower		IFDEBUG(D_DATA)
65836396Ssklower			printf("tp_stash returns %d\n",doack);
65936396Ssklower		ENDDEBUG
66036396Ssklower
66151204Ssklower		if (doack) {
66236396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
66351204Ssklower			tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
66436396Ssklower		} else
66551204Ssklower			tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks);
66636396Ssklower
66736396Ssklower		IFDEBUG(D_DATA)
66836396Ssklower			printf("after stash calling sbwakeup\n");
66936396Ssklower		ENDDEBUG
67036396Ssklower	}
67136396Ssklower;
67236396Ssklower
67336396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
67436396Ssklower	( $P.tp_class == TP_CLASS_0 )
67536396Ssklower	{
67636396Ssklower		tp0_stash($P, $E);
67736396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
67836396Ssklower
67936396Ssklower		IFDEBUG(D_DATA)
68036396Ssklower			printf("after stash calling sbwakeup\n");
68136396Ssklower		ENDDEBUG
68236396Ssklower	}
68336396Ssklower;
68436396Ssklower
68536396Ssklower/* TP4 only */
68636396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
68736396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
68836396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
68936396Ssklower	{
69036396Ssklower		int doack; /* tells if we must ack immediately */
69136396Ssklower
69251204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
69336396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
69436396Ssklower
69536396Ssklower		doack = tp_stash($P, $E);
69636396Ssklower		IFDEBUG(D_DATA)
69736396Ssklower			printf("tp_stash returns %d\n",doack);
69836396Ssklower		ENDDEBUG
69936396Ssklower
70036396Ssklower		if(doack)
70136396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
70236396Ssklower		else
70351204Ssklower			tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks);
70436396Ssklower
70536396Ssklower		IFDEBUG(D_DATA)
70636396Ssklower			printf("after stash calling sbwakeup\n");
70736396Ssklower		ENDDEBUG
70836396Ssklower	}
70936396Ssklower;
71036396Ssklower
71136396Ssklower/* Not in window  - we must ack under certain circumstances, namely
71236396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given)
71336396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^.
71436396Ssklower * and
71536396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
71636396Ssklower *
71736396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73)
71836396Ssklower * We just always ack.
71936396Ssklower */
72036396Ssklower/* TP4 only */
72136396SsklowerSAME 			<== 	[ TP_OPEN, TP_AKWAIT ]							DT_TPDU
72236396Ssklower	DEFAULT /* Not in window */
72336396Ssklower	{
72436396Ssklower		IFTRACE(D_DATA)
72536396Ssklower			tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
72636396Ssklower				$$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
72736396Ssklower		ENDTRACE
72836396Ssklower		IncStat(ts_dt_niw);
72936396Ssklower		m_freem($$.e_data);
73051204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
73136396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
73236396Ssklower	}
73336396Ssklower;
73436396Ssklower
73536396Ssklower/* TP4 only */
73636396SsklowerTP_OPEN			<==		TP_AKWAIT										AK_TPDU
73736396Ssklower	DEFAULT
73836396Ssklower	{
73937469Ssklower		if ($P.tp_ucddata) {
74037469Ssklower			m_freem($P.tp_ucddata);
74137469Ssklower			$P.tp_ucddata = 0;
74236396Ssklower		}
74336396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
74451204Ssklower		tp_cuntimeout($P, TM_retrans);
74536396Ssklower
74636396Ssklower		soisconnected($P.tp_sock);
74736396Ssklower		IFTRACE(D_CONN)
74836396Ssklower			struct socket *so = $P.tp_sock;
74936396Ssklower			tptrace(TPPTmisc,
75036396Ssklower			"called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
75136396Ssklower				so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
75236396Ssklower			tptrace(TPPTmisc,
75336396Ssklower			"called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
75436396Ssklower				so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
75536396Ssklower		ENDTRACE
75636396Ssklower
75751204Ssklower		tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
75851204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
75936396Ssklower	}
76036396Ssklower;
76136396Ssklower
76236396Ssklower/* TP4 only */
76336396SsklowerTP_OPEN 		<== 	[ TP_OPEN, TP_AKWAIT ]						XPD_TPDU
76447281Ssklower	($P.tp_Xrcvnxt == $$.e_seq)
76536396Ssklower	{
76636396Ssklower		if( $P.tp_state == TP_AKWAIT ) {
76737469Ssklower			if ($P.tp_ucddata) {
76837469Ssklower				m_freem($P.tp_ucddata);
76937469Ssklower				$P.tp_ucddata = 0;
77036396Ssklower			}
77151204Ssklower			tp_cuntimeout($P, TM_retrans);
77236396Ssklower			soisconnected($P.tp_sock);
77351204Ssklower			tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
77451204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
77536396Ssklower		}
77636396Ssklower		IFTRACE(D_XPD)
77736396Ssklower		tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
77836396Ssklower				$P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
77936396Ssklower		ENDTRACE
78036396Ssklower
78137469Ssklower		$P.tp_sock->so_state |= SS_RCVATMARK;
78247281Ssklower		$$.e_data->m_flags |= M_EOR;
78337469Ssklower		sbinsertoob(&$P.tp_Xrcv, $$.e_data);
78436396Ssklower		IFDEBUG(D_XPD)
78536396Ssklower			dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
78636396Ssklower		ENDDEBUG
78736396Ssklower		tp_indicate(T_XDATA, $P, 0);
78836396Ssklower		sbwakeup( &$P.tp_Xrcv );
78936396Ssklower
79036396Ssklower		(void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
79136396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
79236396Ssklower	}
79336396Ssklower;
79436396Ssklower
79536396Ssklower/* TP4 only */
79636396SsklowerSAME			<==		TP_OPEN 									T_USR_Xrcvd
79736396Ssklower	DEFAULT
79836396Ssklower	{
79936396Ssklower		if( $P.tp_Xrcv.sb_cc == 0 ) {
80036396Ssklower			/* kludge for select(): */
80137469Ssklower			/* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
80236396Ssklower		}
80336396Ssklower	}
80436396Ssklower	/* OLD WAY:
80536396Ssklower	 * Ack only after the user receives the XPD.  This is better for
80636396Ssklower	 * users that use one XPD right after another.
80736396Ssklower	 * Acking right away (the NEW WAY, see the prev. transition) is
80836396Ssklower	 * better for occasional * XPD, when the receiving user doesn't
80936396Ssklower	 * want to read the XPD immediately (which is session's behavior).
81036396Ssklower	 *
81136396Ssklower		int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
81236396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
81336396Ssklower		return error;
81436396Ssklower	*/
81536396Ssklower;
81636396Ssklower
81736396Ssklower/* NOTE: presently if the user doesn't read the connection data
81836396Ssklower * before and expedited data PDU comes in, the connection data will
81936396Ssklower * be dropped. This is a bug.  To avoid it, we need somewhere else
82036396Ssklower * to put the connection data.
82136396Ssklower * On the other hand, we need not to have it sitting around forever.
82236396Ssklower * This is a problem with the idea of trying to accommodate
82336396Ssklower * data on connect w/ a passive-open user interface.
82436396Ssklower */
82536396Ssklower/* TP4 only */
82636396Ssklower
82736396SsklowerSAME	 		<== 	[ TP_AKWAIT, TP_OPEN ] 							XPD_TPDU
82836396Ssklower	DEFAULT /* not in window or cdt==0 */
82936396Ssklower	{
83036396Ssklower		IFTRACE(D_XPD)
83136396Ssklower			tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
83236396Ssklower				$P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
83336396Ssklower		ENDTRACE
83436396Ssklower		if( $P.tp_Xrcvnxt != $$.e_seq )
83536396Ssklower			IncStat(ts_xpd_niw);
83636396Ssklower		if( $P.tp_Xrcv.sb_cc ) {
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);
84251204Ssklower		tp_ctimeout($P, 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 */
87138841SsklowerTP_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;
88851204Ssklower			tp_ctimeout($P, 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 */
90338841SsklowerTP_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) {
90951204Ssklower			tp_euntimeout($P, TM_data_retrans); /* all */
91051204Ssklower			tp_cuntimeout($P, TM_inact);
91151204Ssklower			tp_cuntimeout($P, TM_sendack);
912*53683Ssklower			$P.tp_flags &= ~TPF_DELACK;
91336396Ssklower		}
91437469Ssklower		if (data) {
91536396Ssklower			IFDEBUG(D_CONN)
91637469Ssklower				printf("T_DISC_req.trans tp_ucddata 0x%x\n",
91737469Ssklower					$P.tp_ucddata);
91837469Ssklower				dump_mbuf(data, "ucddata @ T_DISC_req");
91936396Ssklower			ENDDEBUG
92036396Ssklower		}
92136396Ssklower		tp_soisdisconnecting($P.tp_sock);
92236396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
92351204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
92436396Ssklower
92536396Ssklower		if( trick_hc )
92636396Ssklower			return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
92736396Ssklower	}
92836396Ssklower;
92936396Ssklower
93036396Ssklower/* TP4 only */
93136396SsklowerSAME			<==		TP_AKWAIT									TM_retrans
93236396Ssklower	( $P.tp_retrans > 0 )
93336396Ssklower	{
93436396Ssklower		int error;
93537469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
93636396Ssklower
93736396Ssklower		IncStat(ts_retrans_cc);
93836396Ssklower		$P.tp_retrans --;
93951204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
94039921Ssklower
94137469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
94236396Ssklower			$P.tp_sock->so_error = error;
94351204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
94436396Ssklower	}
94536396Ssklower;
94636396Ssklower
94736396Ssklower/* TP4 only */
94836396SsklowerTP_CLOSING		<==		TP_AKWAIT									TM_retrans
94936396Ssklower	DEFAULT  /* out of time */
95036396Ssklower	{
95136396Ssklower		IncStat(ts_conn_gaveup);
95236396Ssklower		tp_soisdisconnecting($P.tp_sock);
95336396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
95436396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
95536396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
95636396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
95751204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
95836396Ssklower	}
95936396Ssklower;
96036396Ssklower
96136396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does,
96236396Ssklower * if transmissions are going on.
96336396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack
96436396Ssklower * turnaround)
96536396Ssklower */
96636396Ssklower/* TP4 only */
96736396SsklowerTP_CLOSING 		<==		TP_OPEN		   [ TM_inact, TM_retrans, TM_data_retrans ]
96836396Ssklower	DEFAULT
96936396Ssklower	{
97051204Ssklower		tp_euntimeout($P, TM_data_retrans); /* all */
97151204Ssklower		tp_cuntimeout($P, TM_inact);
97251204Ssklower		tp_cuntimeout($P, TM_sendack);
97336396Ssklower
97436396Ssklower		IncStat(ts_conn_gaveup);
97536396Ssklower		tp_soisdisconnecting($P.tp_sock);
97636396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
97736396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
97836396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
97936396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
98051204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
98136396Ssklower	}
98236396Ssklower;
98336396Ssklower
98436396Ssklower/* TP4 only */
98536396SsklowerSAME			<==		TP_OPEN										TM_retrans
98636396Ssklower	( $P.tp_retrans > 0 )
98736396Ssklower	{
98851204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
98936396Ssklower		/* resume XPD */
99036396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
99137469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
99251204Ssklower			int shift;
99336396Ssklower
99436396Ssklower			IFTRACE(D_XPD)
99551204Ssklower				tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna",
99651204Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt,
99736396Ssklower					$P.tp_snduna);
99836396Ssklower			ENDTRACE
99936396Ssklower			IFDEBUG(D_XPD)
100036396Ssklower				dump_mbuf(m, "XPD retrans emitting M");
100136396Ssklower			ENDDEBUG
100236396Ssklower			IncStat(ts_retrans_xpd);
100336396Ssklower			$P.tp_retrans --;
100451204Ssklower			shift = max($P.tp_Nretrans - $P.tp_retrans, 6);
100536396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
100651204Ssklower			tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift);
100736396Ssklower		}
100836396Ssklower	}
100936396Ssklower;
101036396Ssklower
101136396Ssklower/* TP4 only */
101236396SsklowerSAME 			<==		TP_OPEN									TM_data_retrans
101351204Ssklower	($P.tp_rxtshift < TP_NRETRANS)
101436396Ssklower	{
101551204Ssklower		$P.tp_rxtshift++;
101651204Ssklower		(void) tp_data_retrans($P);
101736396Ssklower	}
101836396Ssklower;
101936396Ssklower
102036396Ssklower/* TP4 only */
102136396SsklowerSAME	 		<==		TP_CLOSING									TM_retrans
102236396Ssklower	(	$P.tp_retrans > 0 )
102336396Ssklower	{
102436396Ssklower		$P.tp_retrans --;
102536396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
102636396Ssklower		IncStat(ts_retrans_dr);
102751204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
102836396Ssklower	}
102936396Ssklower;
103036396Ssklower
103136396Ssklower/* TP4 only */
103236396SsklowerTP_REFWAIT 		<==		TP_CLOSING									TM_retrans
103336396Ssklower	DEFAULT	/* no more retrans - gave up */
103436396Ssklower	{
103536396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
103651204Ssklower		$P.tp_refstate = REF_FROZEN;
103736396Ssklower		tp_recycle_tsuffix( $P );
103851204Ssklower		tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
103936396Ssklower	}
104036396Ssklower;
104136396Ssklower
104236396Ssklower/*
104336396Ssklower * The resources are kept around until the ref timer goes off.
104436396Ssklower * The suffices are wiped out sooner so they can be reused right away.
104536396Ssklower */
104636396Ssklower/* applicable in TP4, TP0 */
104736396SsklowerTP_CLOSED 		<==		TP_REFWAIT 									TM_reference
104836396Ssklower	DEFAULT
104936396Ssklower	{
105051214Ssklower		tp_freeref($P.tp_lref);
105136396Ssklower		tp_detach($P);
105236396Ssklower	}
105336396Ssklower;
105436396Ssklower
105536396Ssklower/* applicable in TP4, TP0 */
105636396Ssklower/* A duplicate CR from connectionless network layer can't happen */
105736396SsklowerSAME 			<== 	TP_OPEN 							[ CR_TPDU, CC_TPDU ]
105836396Ssklower	DEFAULT
105936396Ssklower	{
106036396Ssklower		if( $P.tp_class != TP_CLASS_0) {
106151204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
106236396Ssklower			if ( $E.ev_number == CC_TPDU )
106336396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
106436396Ssklower		}
106536396Ssklower		/* ignore it if class 0 - state tables are blank for this */
106636396Ssklower	}
106736396Ssklower;
106836396Ssklower
106936396Ssklower/* applicable in TP4, TP0 */
107036396SsklowerSAME			<== 	TP_OPEN									T_DATA_req
107136396Ssklower	DEFAULT
107236396Ssklower	{
107336396Ssklower		IFTRACE(D_DATA)
107451204Ssklower			tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb",
107551204Ssklower				$P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P);
107636396Ssklower		ENDTRACE
107736396Ssklower
107836396Ssklower		tp_send($P);
107936396Ssklower	}
108036396Ssklower;
108136396Ssklower
108236396Ssklower/* TP4 only */
108336396SsklowerSAME			<==		TP_OPEN										T_XPD_req
108436396Ssklower	DEFAULT
108536396Ssklower		/* T_XPD_req was issued by sosend iff xpd socket buf was empty
108636396Ssklower		 * at time of sosend(),
108736396Ssklower		 * AND (which means) there were no unacknowledged XPD tpdus outstanding!
108836396Ssklower		 */
108936396Ssklower	{
109036396Ssklower		int error = 0;
109136396Ssklower
109236396Ssklower		/* resume XPD */
109336396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
109437469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
109536396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
109636396Ssklower			 * that doesn't matter
109736396Ssklower			 */
109836396Ssklower
109936396Ssklower			IFTRACE(D_XPD)
110051204Ssklower				tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna",
110151204Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt,
110236396Ssklower					$P.tp_snduna);
110336396Ssklower			ENDTRACE
110436396Ssklower			IFDEBUG(D_XPD)
110536396Ssklower				printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
110636396Ssklower				dump_mbuf(m, "XPD req emitting M");
110736396Ssklower			ENDDEBUG
110836396Ssklower			error =
110936396Ssklower				tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
111036396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
111151204Ssklower
111251204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur);
111336396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
111436396Ssklower		}
111536396Ssklower		if(trick_hc)
111636396Ssklower			return error;
111736396Ssklower	}
111836396Ssklower;
111936396Ssklower
112036396Ssklower/* TP4, faked ack in TP0 when cons send completes */
112136396SsklowerSAME 			<==		TP_OPEN 									AK_TPDU
112236396Ssklower	( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
112336396Ssklower
112436396Ssklower	/* tp_goodack == true means
112536396Ssklower	 * EITHER it actually acked something heretofore unacknowledged
112636396Ssklower	 * OR no news but the credit should be processed.
112736396Ssklower	 */
112836396Ssklower	{
112950904Ssklower		struct sockbuf *sb = &$P.tp_sock->so_snd;
113050904Ssklower
113136396Ssklower		IFDEBUG(D_ACKRECV)
113236396Ssklower			printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
113336396Ssklower		ENDDEBUG
113436396Ssklower		if( $P.tp_class != TP_CLASS_0) {
113551204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
113636396Ssklower		}
113750904Ssklower		sbwakeup(sb);
113836396Ssklower		IFDEBUG(D_ACKRECV)
113951204Ssklower			printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt);
114036396Ssklower		ENDDEBUG
114136396Ssklower	}
114236396Ssklower;
114336396Ssklower
114436396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
114536396SsklowerSAME			<==		TP_OPEN 			 						 AK_TPDU
114636396Ssklower	DEFAULT
114736396Ssklower	{
114836396Ssklower		IFTRACE(D_ACKRECV)
114936396Ssklower			tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
115036396Ssklower				$$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
115136396Ssklower		ENDTRACE
115236396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
115336396Ssklower
115436396Ssklower			if ( !$$.e_fcc_present ) {
115536396Ssklower				/* send ACK with FCC */
115636396Ssklower				IncStat( ts_ackreason[_ACK_FCC_] );
115736396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
115836396Ssklower			}
115951204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
116036396Ssklower		}
116136396Ssklower	}
116236396Ssklower;
116336396Ssklower
116436396Ssklower/* NBS(47) */
116536396Ssklower	/* goes in at *** */
116636396Ssklower		/* just so happens that this is never true now, because we allow
116736396Ssklower		 * only 1 packet in the queue at once (this could be changed)
116836396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
116936396Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
117036396Ssklower
117136396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
117236396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
117351204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks);
117436396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
117536396Ssklower		}
117636396Ssklower		 */
117736396Ssklower	/* end of the above hack */
117836396Ssklower
117936396Ssklower/* TP4 only */
118042944SsklowerSAME			<== 	TP_OPEN										XAK_TPDU
118136396Ssklower	( tp_goodXack($P, $$.e_seq) )
118236396Ssklower	/* tp_goodXack checks for good ack, removes the correct
118336396Ssklower	 * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
118436396Ssklower	 * also updates tp_Xuna
118536396Ssklower	 */
118636396Ssklower	{
118751204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
118851204Ssklower		tp_cuntimeout($P, TM_retrans);
118936396Ssklower
119036396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
119136396Ssklower
119236396Ssklower		/* resume normal data */
119336396Ssklower		tp_send($P);
119436396Ssklower	}
119536396Ssklower;
119636396Ssklower
119742944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
119842944SsklowerSAME			<==		TP_OPEN 			 						XAK_TPDU
119942944Ssklower	DEFAULT
120042944Ssklower	{
120142944Ssklower		IFTRACE(D_ACKRECV)
120242944Ssklower			tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
120342944Ssklower		ENDTRACE
120442944Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
120551204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
120642944Ssklower		}
120742944Ssklower	}
120842944Ssklower;
120942944Ssklower
121036396Ssklower/* TP4 only */
121136396SsklowerSAME			<==		TP_OPEN 								TM_sendack
121236396Ssklower	DEFAULT
121336396Ssklower	{
121451204Ssklower		int timo;
121536396Ssklower		IFTRACE(D_TIMER)
121636396Ssklower			tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
121736396Ssklower			$P.tp_sent_lcdt, 0);
121836396Ssklower		ENDTRACE
121936396Ssklower		IncPStat($P, tps_n_TMsendack);
122036396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
122151248Ssklower		if ($P.tp_fcredit == 0) {
122251248Ssklower			if ($P.tp_rxtshift < TP_MAXRXTSHIFT)
122351248Ssklower				$P.tp_rxtshift++;
122451248Ssklower			timo = ($P.tp_dt_ticks) << $P.tp_rxtshift;
122551248Ssklower		} else
122651248Ssklower			timo = $P.tp_sendack_ticks;
122751248Ssklower		tp_ctimeout($P, TM_sendack, timo);
122836396Ssklower	}
122936396Ssklower;
123036396Ssklower
123136396Ssklower/* TP0 only */
123236396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
123336396Ssklower	($P.tp_class == TP_CLASS_0)
123447281Ssklower	{
123547281Ssklower		if (sbspace(&$P.tp_sock->so_rcv) > 0)
123647281Ssklower			tp0_openflow($P);
123747281Ssklower	}
123836396Ssklower;
123936396Ssklower
124036396Ssklower/* TP4 only */
124136396Ssklower		/* If old credit was zero,
124236396Ssklower		 * we'd better inform other side that we now have space
124336396Ssklower		 * But this is not enough.  Sender might not yet have
124436396Ssklower		 * seen an ack with cdt 0 but it might still think the
124536396Ssklower		 * window is closed, so it's going to wait.
124636396Ssklower		 * Best to send an ack each time.
124736396Ssklower		 * Strictly speaking, this ought to be a function of the
124836396Ssklower		 * general ack strategy.
124936396Ssklower		 */
125036396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
125136396Ssklower	DEFAULT
125236396Ssklower	{
125336396Ssklower		if( trick_hc ) {
125451024Ssklower			SeqNum ack_thresh;
125550849Ssklower			/*
125651024Ssklower			 * If the upper window edge has advanced a reasonable
125751024Ssklower			 * amount beyond what was known, send an ACK.
125851024Ssklower			 * A reasonable amount is 2 packets, unless the max window
125951024Ssklower			 * is only 1 or 2 packets, in which case we
126051024Ssklower			 * should send an ack for any advance in the upper window edge.
126150849Ssklower			 */
126251024Ssklower			LOCAL_CREDIT($P);
126351024Ssklower			ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt,
126451024Ssklower									 ($P.tp_maxlcredit > 2 ? 2 : 1));
126551024Ssklower			if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) {
126650849Ssklower				IncStat(ts_ackreason[_ACK_USRRCV_]);
126751024Ssklower				$P.tp_flags &= ~TPF_DELACK;
126839921Ssklower				return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
126950849Ssklower			}
127036396Ssklower		}
127136396Ssklower	}
127236396Ssklower;
127336396Ssklower
127436396Ssklower/* applicable in TP4, TP0 */
127536396SsklowerSAME			<==		TP_REFWAIT 				[ T_USR_rcvd, T_USR_Xrcvd ]
127636396Ssklower	DEFAULT
127736396Ssklower	/* This happens if other end sent a DR when  the user was waiting
127836396Ssklower	 * on a receive.
127936396Ssklower	 * Processing the DR includes putting us in REFWAIT state.
128036396Ssklower	 */
128136396Ssklower	{
128236396Ssklower		if(trick_hc)
128336396Ssklower		return ECONNABORTED;
128436396Ssklower	}
128536396Ssklower;
128636396Ssklower
128736396Ssklower/* TP0 only */
128836396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT, TP_LISTENING ] 	T_NETRESET
128936396Ssklower	( $P.tp_class != TP_CLASS_4 )
129036396Ssklower		/* 0 or (4 and 0) */
129136396Ssklower		/* in OPEN class will be 0 or 4 but not both */
129236396Ssklower		/* in CRSENT or LISTENING it could be in negotiation, hence both */
129336396Ssklower		/* Actually, this shouldn't ever happen in LISTENING */
129436396Ssklower	{
129536396Ssklower		ASSERT( $P.tp_state != TP_LISTENING );
129636396Ssklower		tp_indicate(T_DISCONNECT, $P, ECONNRESET);
129736396Ssklower		tp_soisdisconnected($P);
129836396Ssklower	}
129936396Ssklower;
130036396Ssklower
130136396Ssklower/* TP4: ignore resets */
130236396SsklowerSAME		<==		[ TP_OPEN, TP_CRSENT, TP_AKWAIT,
130336396Ssklower						TP_CLOSING, TP_LISTENING ] 				T_NETRESET
130436396Ssklower	DEFAULT
130536396Ssklower	NULLACTION
130636396Ssklower;
130736396Ssklower
130836396Ssklower/* applicable in TP4, TP0 */
130936396SsklowerSAME			<==		[ TP_CLOSED, TP_REFWAIT ]				T_NETRESET
131036396Ssklower	DEFAULT
131136396Ssklower	NULLACTION
131236396Ssklower;
131336396Ssklower
131436396Ssklower/* C'EST TOUT */
1315