xref: /csrg-svn/sys/netiso/tp.trans (revision 63223)
150849Ssklower/* NEW */
249268Sbostic/*-
363221Sbostic * Copyright (c) 1991, 1993
463221Sbostic *	The Regents of the University of California.  All rights reserved.
549268Sbostic *
649268Sbostic * %sccs.include.redist.c%
749268Sbostic *
8*63223Sbostic *	@(#)tp.trans	8.1 (Berkeley) 06/10/93
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*63223Sbostic/* @(#)tp.trans	8.1 (Berkeley) 06/10/93 */
6356532Sbostic#include <sys/param.h>
6456532Sbostic#include <sys/systm.h>
6556532Sbostic#include <sys/socket.h>
6656532Sbostic#include <sys/socketvar.h>
6756532Sbostic#include <sys/protosw.h>
6856532Sbostic#include <sys/mbuf.h>
6956532Sbostic#include <sys/time.h>
7056532Sbostic#include <sys/errno.h>
7136396Ssklower
7256532Sbostic#include <netiso/tp_param.h>
7356532Sbostic#include <netiso/tp_stat.h>
7456532Sbostic#include <netiso/tp_pcb.h>
7556532Sbostic#include <netiso/tp_tpdu.h>
7656532Sbostic#include <netiso/argo_debug.h>
7756532Sbostic#include <netiso/tp_trace.h>
7856532Sbostic#include <netiso/iso_errno.h>
7956532Sbostic#include <netiso/tp_seq.h>
8056532Sbostic#include <netiso/cons.h>
8156532Sbostic
8236396Ssklower#define DRIVERTRACE TPPTdriver
8337469Ssklower#define sbwakeup(sb)	sowakeup(p->tp_sock, sb);
8437469Ssklower#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
8536396Ssklower
8636396Ssklowerstatic 	trick_hc = 1;
8736396Ssklower
8836396Ssklowerint 	tp_emit(),
8936396Ssklower		tp_goodack(),				tp_goodXack(),
9036396Ssklower		tp_stash()
9136396Ssklower;
9236396Ssklowervoid	tp_indicate(),				tp_getoptions(),
9336396Ssklower		tp_soisdisconnecting(), 	tp_soisdisconnected(),
9436396Ssklower		tp_recycle_tsuffix(),
9551252Ssklower#ifdef TP_DEBUG_TIMERS
9636396Ssklower		tp_etimeout(),				tp_euntimeout(),
9751252Ssklower		tp_ctimeout(),				tp_cuntimeout(),
9851252Ssklower		tp_ctimeout_MIN(),
9951252Ssklower#endif
10036396Ssklower		tp_freeref(),				tp_detach(),
10136396Ssklower		tp0_stash(), 				tp0_send(),
10236396Ssklower		tp_netcmd(),				tp_send()
10336396Ssklower;
10436396Ssklower
10536396Ssklowertypedef  struct tp_pcb tpcb_struct;
10636396Ssklower
10736396Ssklower
10836396Ssklower}
10936396Ssklower
11036396Ssklower*PCB    tpcb_struct 	SYNONYM  P
11136396Ssklower
11236396Ssklower*STATES
11336396Ssklower
11436396SsklowerTP_CLOSED
11536396SsklowerTP_CRSENT
11636396SsklowerTP_AKWAIT
11736396SsklowerTP_OPEN
11836396SsklowerTP_CLOSING
11936396SsklowerTP_REFWAIT
12036396SsklowerTP_LISTENING	/* Local to this implementation */
12138841SsklowerTP_CONFIRMING	/* Local to this implementation */
12236396Ssklower
12336396Ssklower*EVENTS		{ struct timeval e_time; } 		SYNONYM  E
12436396Ssklower
12536396Ssklower /*
12636396Ssklower  * C (typically cancelled) timers  -
12736396Ssklower  *
12836396Ssklower  * let these be the first ones so for the sake of convenience
12936396Ssklower  * their values are 0--> n-1
13036396Ssklower  * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!!
13136396Ssklower  */
13236396Ssklower TM_inact
13336396Ssklower TM_retrans
13436396Ssklower				/* TM_retrans is used for all
13536396Ssklower				 * simple retransmissions - CR,CC,XPD,DR
13636396Ssklower				 */
13736396Ssklower
13836396Ssklower TM_sendack
13951204Ssklower				/* TM_sendack does dual duty - keepalive AND closed-window
14051204Ssklower				 * Probes.
14136396Ssklower				 * It's set w/ keepalive-ticks every time an ack is sent.
14236396Ssklower				 * (this is done in (void) tp_emit() ).
14351204Ssklower				 * Whenever a DT arrives which doesn't require immediate acking,
14451204Ssklower				 * a separate fast-timeout flag is set ensuring 200ms response.
14536396Ssklower				 */
14636396Ssklower TM_notused
14736396Ssklower
14836396Ssklower /*
14936396Ssklower  * E (typically expired) timers - these may be in any order.
15036396Ssklower  * These cause procedures to be executed directly; may not
15136396Ssklower  * cause an 'event' as we know them here.
15236396Ssklower  */
15336396Ssklower TM_reference		{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15436396Ssklower TM_data_retrans	{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15536396Ssklower
15636396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that
15736396Ssklower * for all tpdu types that can take e_data and e_datalen, these
15836396Ssklower * fields fall in the same place in the event structure, that is,
15936396Ssklower * e_data is the first field and e_datalen is the 2nd field.
16036396Ssklower */
16136396Ssklower
16236396Ssklower ER_TPDU  	 	{
16336396Ssklower				  u_char		e_reason;
16436396Ssklower				}
16536396Ssklower CR_TPDU  	 	{ struct mbuf 	*e_data;	/* first field */
16636396Ssklower				  int 			e_datalen; /* 2nd field */
16736396Ssklower				  u_int			e_cdt;
16836396Ssklower				}
16936396Ssklower DR_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
17036396Ssklower				  int 			e_datalen; /* 2nd field */
17136396Ssklower				  u_short		e_sref;
17236396Ssklower				  u_char		e_reason;
17336396Ssklower				}
17436396Ssklower DC_TPDU
17536396Ssklower CC_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
17636396Ssklower				  int 			e_datalen; /* 2nd field */
17736396Ssklower				  u_short		e_sref;
17836396Ssklower				  u_int			e_cdt;
17936396Ssklower				}
18036396Ssklower AK_TPDU		{ u_int			e_cdt;
18136396Ssklower				  SeqNum 	 	e_seq;
18236396Ssklower				  SeqNum 	 	e_subseq;
18336396Ssklower				  u_char 	 	e_fcc_present;
18436396Ssklower				}
18536396Ssklower DT_TPDU		{ struct mbuf	*e_data; 	/* first field */
18636396Ssklower				  int 			e_datalen; /* 2nd field */
18736396Ssklower				  u_int 		e_eot;
18836396Ssklower				  SeqNum		e_seq;
18936396Ssklower				}
19036396Ssklower XPD_TPDU		{ struct mbuf 	*e_data;	/* first field */
19136396Ssklower				  int 			e_datalen; 	/* 2nd field */
19236396Ssklower				  SeqNum 		e_seq;
19336396Ssklower				}
19436396Ssklower XAK_TPDU		{ SeqNum 		e_seq;		}
19536396Ssklower
19636396Ssklower T_CONN_req
19736396Ssklower T_DISC_req		{ u_char		e_reason; 	}
19836396Ssklower T_LISTEN_req
19936396Ssklower T_DATA_req
20036396Ssklower T_XPD_req
20136396Ssklower T_USR_rcvd
20236396Ssklower T_USR_Xrcvd
20336396Ssklower T_DETACH
20436396Ssklower T_NETRESET
20538841Ssklower T_ACPT_req
20636396Ssklower
20736396Ssklower
20836396Ssklower*TRANSITIONS
20936396Ssklower
21036396Ssklower
21136396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */
21236396SsklowerSAME			<==			TP_AKWAIT			[ CC_TPDU, DC_TPDU, XAK_TPDU ]
21336396Ssklower	DEFAULT
21436396Ssklower	NULLACTION
21536396Ssklower;
21636396Ssklower
21736396Ssklower
21836396Ssklower/* applicable in TP4, TP0 */
21936396SsklowerSAME			<==			TP_REFWAIT								DR_TPDU
22036396Ssklower	( $$.e_sref !=  0 )
22136396Ssklower	{
22236396Ssklower		(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
22336396Ssklower	}
22436396Ssklower;
22536396Ssklower
22636396Ssklower/* applicable in TP4, TP0 */
22736396SsklowerSAME			<==			TP_REFWAIT			[ CR_TPDU, CC_TPDU, DT_TPDU,
22836396Ssklower					DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ]
22936396Ssklower	DEFAULT
23036396Ssklower	{
23136396Ssklower#		ifdef TP_DEBUG
23236396Ssklower		if( $E.ev_number != AK_TPDU )
23336396Ssklower			printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number);
23436396Ssklower#		endif TP_DEBUG
23536396Ssklower	}
23636396Ssklower;
23736396Ssklower
23836396Ssklower/* applicable in TP4, TP0 */
23936396SsklowerSAME			<==			TP_REFWAIT				[ T_DETACH, T_DISC_req ]
24036396Ssklower	DEFAULT
24136396Ssklower	NULLACTION
24236396Ssklower;
24336396Ssklower
24436396Ssklower/* applicable in TP4, TP0 */
24536396SsklowerSAME			<==			TP_CRSENT								 AK_TPDU
24636396Ssklower	($P.tp_class == TP_CLASS_0)
24736396Ssklower	{
24836396Ssklower		/* oh, man is this grotesque or what? */
24936396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq,  $$.e_subseq);
25036396Ssklower		/* but it's necessary because this pseudo-ack may happen
25136396Ssklower		 * before the CC arrives, but we HAVE to adjust the
25236396Ssklower		 * snduna as a result of the ack, WHENEVER it arrives
25336396Ssklower		 */
25436396Ssklower	}
25536396Ssklower;
25636396Ssklower
25736396Ssklower/* applicable in TP4, TP0 */
25836396SsklowerSAME			<==			TP_CRSENT
25936396Ssklower					[ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU,  XAK_TPDU ]
26036396Ssklower	DEFAULT
26136396Ssklower	NULLACTION
26236396Ssklower;
26336396Ssklower
26436396Ssklower/* applicable in TP4, TP0 */
26536396SsklowerSAME			<==			TP_CLOSED					[ DT_TPDU, XPD_TPDU,
26636396Ssklower										ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
26736396Ssklower	DEFAULT
26836396Ssklower	NULLACTION
26936396Ssklower;
27036396Ssklower
27136396Ssklower/* TP_CLOSING doesn't exist in TP 0 */
27236396SsklowerSAME 			<== 		TP_CLOSING
27336396Ssklower					[ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ]
27436396Ssklower	DEFAULT
27536396Ssklower	NULLACTION
27636396Ssklower;
27736396Ssklower
27836396Ssklower
27936396Ssklower/* DC_TPDU doesn't exist in TP 0 */
28036396SsklowerSAME			<==			TP_OPEN						  DC_TPDU
28136396Ssklower	DEFAULT
28236396Ssklower	NULLACTION
28336396Ssklower;
28436396Ssklower
28536396Ssklower/* applicable in TP4, TP0 */
28636396SsklowerSAME			<==		 	TP_LISTENING  [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU,
28736396Ssklower										 ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
28836396Ssklower	DEFAULT
28936396Ssklower	NULLACTION
29036396Ssklower;
29136396Ssklower
29236396Ssklower/* applicable in TP4, TP0 */
29336396SsklowerTP_LISTENING	<==			TP_CLOSED  							T_LISTEN_req
29436396Ssklower	DEFAULT
29536396Ssklower	NULLACTION
29636396Ssklower;
29736396Ssklower
29836396Ssklower/* applicable in TP4, TP0 */
29936396SsklowerTP_CLOSED  		<== 		[ TP_LISTENING, TP_CLOSED ] 			T_DETACH
30036396Ssklower	DEFAULT
30136396Ssklower	{
30236396Ssklower		tp_detach($P);
30336396Ssklower	}
30436396Ssklower;
30536396Ssklower
30638841SsklowerTP_CONFIRMING	<==		 TP_LISTENING  								CR_TPDU
30738841Ssklower	( $P.tp_class == TP_CLASS_0)
30836396Ssklower	{
30951204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers ??? */
31036396Ssklower	}
31136396Ssklower;
31236396Ssklower
31338841SsklowerTP_CONFIRMING		<==		 TP_LISTENING  							CR_TPDU
31438841Ssklower	DEFAULT
31536396Ssklower	{
31636396Ssklower		IFTRACE(D_CONN)
31736396Ssklower			tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
31836396Ssklower		ENDTRACE
31936396Ssklower		IFDEBUG(D_CONN)
32036396Ssklower			printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
32136396Ssklower		ENDDEBUG
32251204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers */
32338841Ssklower		$P.tp_fcredit = $$.e_cdt;
32436396Ssklower
32536396Ssklower		if ($$.e_datalen > 0) {
32636396Ssklower			/* n/a for class 0 */
32736396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0);
32836396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
32936396Ssklower			$$.e_data = MNULL;
33036396Ssklower		}
33138841Ssklower	}
33238841Ssklower;
33338841Ssklower
33438841SsklowerTP_OPEN		<==		 TP_CONFIRMING  								T_ACPT_req
33538841Ssklower	( $P.tp_class == TP_CLASS_0 )
33638841Ssklower	{
33738841Ssklower		IncStat(ts_tp0_conn);
33838841Ssklower		IFTRACE(D_CONN)
33938841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
34038841Ssklower		ENDTRACE
34138841Ssklower		IFDEBUG(D_CONN)
34238841Ssklower			printf("Confirming connection: $P" );
34338841Ssklower		ENDDEBUG
34438841Ssklower		soisconnected($P.tp_sock);
34538841Ssklower		(void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
34638841Ssklower		$P.tp_fcredit = 1;
34738841Ssklower	}
34838841Ssklower;
34938841Ssklower
35038841SsklowerTP_AKWAIT		<==		 TP_CONFIRMING  							T_ACPT_req
35138841Ssklower	(tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
35238841Ssklower	{
35338841Ssklower		IncStat(ts_tp4_conn); /* even though not quite open */
35438841Ssklower		IFTRACE(D_CONN)
35538841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
35638841Ssklower		ENDTRACE
35738841Ssklower		IFDEBUG(D_CONN)
35838841Ssklower			printf("Confirming connection: $P" );
35938841Ssklower		ENDDEBUG
36050973Ssklower		tp_getoptions($P);
36138841Ssklower		soisconnecting($P.tp_sock);
36247281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
36351204Ssklower			$P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize;
36436396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
36551204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
36638841Ssklower	}
36736396Ssklower;
36836396Ssklower
36936396Ssklower/* TP4 only */
37038841SsklowerTP_CLOSED		<==		 TP_CONFIRMING								T_ACPT_req
37136396Ssklower	DEFAULT /* emit failed */
37236396Ssklower	{
37336396Ssklower		IFDEBUG(D_CONN)
37436396Ssklower			printf("event: CR_TPDU emit CC failed done " );
37536396Ssklower		ENDDEBUG
37638841Ssklower		soisdisconnected($P.tp_sock);
37751214Ssklower		tp_recycle_tsuffix($P);
37851214Ssklower		tp_freeref($P.tp_lref);
37936396Ssklower		tp_detach($P);
38036396Ssklower	}
38136396Ssklower;
38236396Ssklower
38336396Ssklower/* applicable in TP4, TP0 */
38436396SsklowerTP_CRSENT		<==		TP_CLOSED								T_CONN_req
38536396Ssklower	DEFAULT
38636396Ssklower	{
38736396Ssklower		int error;
38836396Ssklower		struct mbuf *data = MNULL;
38936396Ssklower
39036396Ssklower		IFTRACE(D_CONN)
39137469Ssklower			tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
39237469Ssklower			$P.tp_ucddata, 0, 0);
39336396Ssklower		ENDTRACE
39437469Ssklower		data =  MCPY($P.tp_ucddata, M_WAIT);
39537469Ssklower		if (data) {
39636396Ssklower			IFDEBUG(D_CONN)
39736396Ssklower				printf("T_CONN_req.trans m_copy cc 0x%x\n",
39837469Ssklower					$P.tp_ucddata);
39937469Ssklower				dump_mbuf(data, "sosnd @ T_CONN_req");
40036396Ssklower			ENDDEBUG
40136396Ssklower		}
40236396Ssklower
40336396Ssklower		if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
40436396Ssklower			return error; /* driver WON'T change state; will return error */
40536396Ssklower
40651204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers */
40736396Ssklower		if($P.tp_class != TP_CLASS_0) {
40836396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
40951204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
41036396Ssklower		}
41136396Ssklower	}
41236396Ssklower;
41336396Ssklower
41436396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
41536396SsklowerTP_REFWAIT 		<==		[ TP_CRSENT, TP_AKWAIT, TP_OPEN ] 			DR_TPDU
41636396Ssklower	DEFAULT
41736396Ssklower	{
41848739Ssklower		sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
41948739Ssklower		if ($$.e_datalen > 0) {
42036396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
42136396Ssklower			$$.e_data = MNULL;
42236396Ssklower		}
42351208Ssklower		if ($P.tp_state == TP_OPEN)
42451208Ssklower			tp_indicate(T_DISCONNECT, $P, 0);
42551208Ssklower		else {
42651208Ssklower			int so_error = ECONNREFUSED;
42751208Ssklower			if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) &&
42851208Ssklower			    $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) &&
42951208Ssklower			    $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK))
43051208Ssklower				so_error = ECONNABORTED;
43151208Ssklower			tp_indicate(T_DISCONNECT, $P, so_error);
43251208Ssklower		}
43336396Ssklower		tp_soisdisconnected($P);
43436396Ssklower		if ($P.tp_class != TP_CLASS_0) {
43536396Ssklower			if ($P.tp_state == TP_OPEN ) {
43651204Ssklower				tp_euntimeout($P, TM_data_retrans); /* all */
43751204Ssklower				tp_cuntimeout($P, TM_retrans);
43851204Ssklower				tp_cuntimeout($P, TM_inact);
43951204Ssklower				tp_cuntimeout($P, TM_sendack);
44053683Ssklower				$P.tp_flags &= ~TPF_DELACK;
44136396Ssklower			}
44251204Ssklower			tp_cuntimeout($P, TM_retrans);
44336396Ssklower			if( $$.e_sref !=  0 )
44436396Ssklower				(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
44536396Ssklower		}
44636396Ssklower	}
44736396Ssklower;
44836396Ssklower
44936396SsklowerSAME 			<==		TP_CLOSED 									DR_TPDU
45036396Ssklower	DEFAULT
45136396Ssklower	{
45236396Ssklower		if( $$.e_sref != 0 )
45336396Ssklower			(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
45436396Ssklower		/* reference timer already set - reset it to be safe (???) */
45551204Ssklower		tp_euntimeout($P, TM_reference); /* all */
45651204Ssklower		tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
45736396Ssklower	}
45836396Ssklower;
45936396Ssklower
46036396Ssklower/* NBS(34) */
46136396SsklowerTP_REFWAIT 		<==  	TP_CRSENT  									ER_TPDU
46236396Ssklower	DEFAULT
46336396Ssklower	{
46451204Ssklower		tp_cuntimeout($P, TM_retrans);
46548739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
46636396Ssklower		tp_soisdisconnected($P);
46736396Ssklower	}
46836396Ssklower;
46936396Ssklower
47036396Ssklower/* NBS(27) */
47136396SsklowerTP_REFWAIT		<==		TP_CLOSING									DR_TPDU
47236396Ssklower	DEFAULT
47336396Ssklower	{
47451204Ssklower		tp_cuntimeout($P, TM_retrans);
47536396Ssklower		tp_soisdisconnected($P);
47636396Ssklower	}
47736396Ssklower;
47836396Ssklower/* these two transitions are the same but can't be combined because xebec
47936396Ssklower * can't handle the use of $$.e_reason if they're combined
48036396Ssklower */
48136396Ssklower/* NBS(27) */
48236396SsklowerTP_REFWAIT		<==		TP_CLOSING									ER_TPDU
48336396Ssklower	DEFAULT
48436396Ssklower	{
48548739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
48651204Ssklower		tp_cuntimeout($P, TM_retrans);
48736396Ssklower		tp_soisdisconnected($P);
48836396Ssklower	}
48936396Ssklower;
49036396Ssklower/* NBS(27) */
49136396SsklowerTP_REFWAIT		<==		TP_CLOSING									DC_TPDU
49236396Ssklower	DEFAULT
49336396Ssklower	{
49451204Ssklower		tp_cuntimeout($P, TM_retrans);
49536396Ssklower		tp_soisdisconnected($P);
49636396Ssklower	}
49736396Ssklower;
49836396Ssklower
49936396Ssklower/* NBS(21) */
50036396SsklowerSAME 			<== 	TP_CLOSED 						[ CC_TPDU, CR_TPDU ]
50136396Ssklower	DEFAULT
50236396Ssklower	{	/* don't ask me why we have to do this - spec says so */
50336396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
50436396Ssklower		/* don't bother with retransmissions of the DR */
50536396Ssklower	}
50636396Ssklower;
50736396Ssklower
50836396Ssklower/* NBS(34) */
50936396SsklowerTP_REFWAIT 		<== 	TP_OPEN  				 					ER_TPDU
51036396Ssklower	($P.tp_class == TP_CLASS_0)
51136396Ssklower	{
51236396Ssklower		tp_soisdisconnecting($P.tp_sock);
51348739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
51436396Ssklower		tp_soisdisconnected($P);
51536396Ssklower		tp_netcmd( $P, CONN_CLOSE );
51636396Ssklower	}
51736396Ssklower;
51836396Ssklower
51936396SsklowerTP_CLOSING 		<== 	[ TP_AKWAIT, TP_OPEN ]  					ER_TPDU
52036396Ssklower	DEFAULT
52136396Ssklower	{
52236396Ssklower		if ($P.tp_state == TP_OPEN) {
52351204Ssklower			tp_euntimeout($P, TM_data_retrans); /* all */
52451204Ssklower			tp_cuntimeout($P, TM_inact);
52551204Ssklower			tp_cuntimeout($P, TM_sendack);
52636396Ssklower		}
52736396Ssklower		tp_soisdisconnecting($P.tp_sock);
52848739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
52936396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
53051204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
53136396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
53236396Ssklower	}
53336396Ssklower;
53436396Ssklower/* NBS(6) */
53536396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
53636396Ssklower	($P.tp_class == TP_CLASS_0)
53736396Ssklower	{
53851204Ssklower		tp_cuntimeout($P, TM_retrans);
53936396Ssklower		IncStat(ts_tp0_conn);
54036396Ssklower		$P.tp_fcredit = 1;
54136396Ssklower		soisconnected($P.tp_sock);
54236396Ssklower	}
54336396Ssklower;
54436396Ssklower
54536396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
54636396Ssklower	DEFAULT
54736396Ssklower	{
54836396Ssklower		IFDEBUG(D_CONN)
54936396Ssklower			printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
55036396Ssklower				(int)$P.tp_flags);
55136396Ssklower		ENDDEBUG
55236396Ssklower		IncStat(ts_tp4_conn);
55336396Ssklower		$P.tp_fref = $$.e_sref;
55436396Ssklower		$P.tp_fcredit = $$.e_cdt;
55547281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
55651204Ssklower			$P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize;
55736396Ssklower		tp_getoptions($P);
55851204Ssklower		tp_cuntimeout($P, TM_retrans);
55937469Ssklower		if ($P.tp_ucddata) {
56036396Ssklower			IFDEBUG(D_CONN)
56137469Ssklower				printf("dropping user connect data cc 0x%x\n",
56237469Ssklower					$P.tp_ucddata->m_len);
56336396Ssklower			ENDDEBUG
56437469Ssklower			m_freem($P.tp_ucddata);
56537469Ssklower			$P.tp_ucddata = 0;
56636396Ssklower		}
56736396Ssklower		soisconnected($P.tp_sock);
56836396Ssklower		if ($$.e_datalen > 0) {
56936396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
57036396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
57136396Ssklower			$$.e_data = MNULL;
57236396Ssklower		}
57336396Ssklower
57436396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
57551204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
57636396Ssklower	}
57736396Ssklower;
57836396Ssklower
57936396Ssklower/* TP4 only */
58036396SsklowerSAME			<==		TP_CRSENT									TM_retrans
58136396Ssklower	(	$P.tp_retrans > 0 )
58236396Ssklower	{
58336396Ssklower		struct mbuf *data = MNULL;
58436396Ssklower		int error;
58536396Ssklower
58636396Ssklower		IncStat(ts_retrans_cr);
58751204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
58837469Ssklower		data = MCPY($P.tp_ucddata, M_NOWAIT);
58937469Ssklower		if($P.tp_ucddata) {
59036396Ssklower			IFDEBUG(D_CONN)
59137469Ssklower				printf("TM_retrans.trans m_copy cc 0x%x\n", data);
59237469Ssklower				dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
59336396Ssklower			ENDDEBUG
59436396Ssklower			if( data == MNULL )
59536396Ssklower				return ENOBUFS;
59636396Ssklower		}
59736396Ssklower
59836396Ssklower		$P.tp_retrans --;
59936396Ssklower		if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
60036396Ssklower			$P.tp_sock->so_error = error;
60136396Ssklower		}
60251204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
60336396Ssklower	}
60436396Ssklower;
60536396Ssklower
60636396Ssklower/* TP4 only  */
60736396SsklowerTP_REFWAIT		<==		TP_CRSENT									TM_retrans
60836396Ssklower	DEFAULT /* no more CR retransmissions */
60936396Ssklower	{
61036396Ssklower		IncStat(ts_conn_gaveup);
61136396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
61236396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
61336396Ssklower		tp_soisdisconnected($P);
61436396Ssklower	}
61536396Ssklower;
61636396Ssklower
61736396Ssklower/* TP4 only */
61836396SsklowerSAME 			<==	 TP_AKWAIT											CR_TPDU
61936396Ssklower	DEFAULT
62036396Ssklower	/* duplicate CR (which doesn't really exist in the context of
62136396Ssklower	 * a connectionless network layer)
62236396Ssklower	 * Doesn't occur in class 0.
62336396Ssklower	 */
62436396Ssklower	{
62536396Ssklower		int error;
62637469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
62736396Ssklower
62837469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
62936396Ssklower			$P.tp_sock->so_error = error;
63036396Ssklower		}
63136396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
63251204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
63336396Ssklower	}
63436396Ssklower;
63536396Ssklower
63636396Ssklower/* TP4 only */
63736396SsklowerTP_OPEN			<==		TP_AKWAIT 										DT_TPDU
63836396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
63936396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
64036396Ssklower	{
64136396Ssklower		int doack;
64236396Ssklower
64337469Ssklower		/*
64437469Ssklower		 * Get rid of any confirm or connect data, so that if we
64537469Ssklower		 * crash or close, it isn't thought of as disconnect data.
64637469Ssklower		 */
64737469Ssklower		if ($P.tp_ucddata) {
64837469Ssklower			m_freem($P.tp_ucddata);
64937469Ssklower			$P.tp_ucddata = 0;
65036396Ssklower		}
65151204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
65251204Ssklower		tp_cuntimeout($P, TM_retrans);
65336396Ssklower		soisconnected($P.tp_sock);
65451204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
65536396Ssklower
65636396Ssklower		/* see also next 2 transitions, if you make any changes */
65736396Ssklower
65836396Ssklower		doack = tp_stash($P, $E);
65936396Ssklower		IFDEBUG(D_DATA)
66036396Ssklower			printf("tp_stash returns %d\n",doack);
66136396Ssklower		ENDDEBUG
66236396Ssklower
66351204Ssklower		if (doack) {
66436396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
66551204Ssklower			tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
66636396Ssklower		} else
66751204Ssklower			tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks);
66836396Ssklower
66936396Ssklower		IFDEBUG(D_DATA)
67036396Ssklower			printf("after stash calling sbwakeup\n");
67136396Ssklower		ENDDEBUG
67236396Ssklower	}
67336396Ssklower;
67436396Ssklower
67536396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
67636396Ssklower	( $P.tp_class == TP_CLASS_0 )
67736396Ssklower	{
67836396Ssklower		tp0_stash($P, $E);
67936396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
68036396Ssklower
68136396Ssklower		IFDEBUG(D_DATA)
68236396Ssklower			printf("after stash calling sbwakeup\n");
68336396Ssklower		ENDDEBUG
68436396Ssklower	}
68536396Ssklower;
68636396Ssklower
68736396Ssklower/* TP4 only */
68836396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
68936396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
69036396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
69136396Ssklower	{
69236396Ssklower		int doack; /* tells if we must ack immediately */
69336396Ssklower
69451204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
69536396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
69636396Ssklower
69736396Ssklower		doack = tp_stash($P, $E);
69836396Ssklower		IFDEBUG(D_DATA)
69936396Ssklower			printf("tp_stash returns %d\n",doack);
70036396Ssklower		ENDDEBUG
70136396Ssklower
70236396Ssklower		if(doack)
70336396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
70436396Ssklower		else
70551204Ssklower			tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks);
70636396Ssklower
70736396Ssklower		IFDEBUG(D_DATA)
70836396Ssklower			printf("after stash calling sbwakeup\n");
70936396Ssklower		ENDDEBUG
71036396Ssklower	}
71136396Ssklower;
71236396Ssklower
71336396Ssklower/* Not in window  - we must ack under certain circumstances, namely
71436396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given)
71536396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^.
71636396Ssklower * and
71736396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
71836396Ssklower *
71936396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73)
72036396Ssklower * We just always ack.
72136396Ssklower */
72236396Ssklower/* TP4 only */
72336396SsklowerSAME 			<== 	[ TP_OPEN, TP_AKWAIT ]							DT_TPDU
72436396Ssklower	DEFAULT /* Not in window */
72536396Ssklower	{
72636396Ssklower		IFTRACE(D_DATA)
72736396Ssklower			tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
72836396Ssklower				$$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
72936396Ssklower		ENDTRACE
73036396Ssklower		IncStat(ts_dt_niw);
73136396Ssklower		m_freem($$.e_data);
73251204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
73336396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
73436396Ssklower	}
73536396Ssklower;
73636396Ssklower
73736396Ssklower/* TP4 only */
73836396SsklowerTP_OPEN			<==		TP_AKWAIT										AK_TPDU
73936396Ssklower	DEFAULT
74036396Ssklower	{
74137469Ssklower		if ($P.tp_ucddata) {
74237469Ssklower			m_freem($P.tp_ucddata);
74337469Ssklower			$P.tp_ucddata = 0;
74436396Ssklower		}
74536396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
74651204Ssklower		tp_cuntimeout($P, TM_retrans);
74736396Ssklower
74836396Ssklower		soisconnected($P.tp_sock);
74936396Ssklower		IFTRACE(D_CONN)
75036396Ssklower			struct socket *so = $P.tp_sock;
75136396Ssklower			tptrace(TPPTmisc,
75236396Ssklower			"called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
75336396Ssklower				so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
75436396Ssklower			tptrace(TPPTmisc,
75536396Ssklower			"called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
75636396Ssklower				so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
75736396Ssklower		ENDTRACE
75836396Ssklower
75951204Ssklower		tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
76051204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
76136396Ssklower	}
76236396Ssklower;
76336396Ssklower
76436396Ssklower/* TP4 only */
76536396SsklowerTP_OPEN 		<== 	[ TP_OPEN, TP_AKWAIT ]						XPD_TPDU
76647281Ssklower	($P.tp_Xrcvnxt == $$.e_seq)
76736396Ssklower	{
76836396Ssklower		if( $P.tp_state == TP_AKWAIT ) {
76937469Ssklower			if ($P.tp_ucddata) {
77037469Ssklower				m_freem($P.tp_ucddata);
77137469Ssklower				$P.tp_ucddata = 0;
77236396Ssklower			}
77351204Ssklower			tp_cuntimeout($P, TM_retrans);
77436396Ssklower			soisconnected($P.tp_sock);
77551204Ssklower			tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
77651204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
77736396Ssklower		}
77836396Ssklower		IFTRACE(D_XPD)
77936396Ssklower		tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
78036396Ssklower				$P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
78136396Ssklower		ENDTRACE
78236396Ssklower
78337469Ssklower		$P.tp_sock->so_state |= SS_RCVATMARK;
78447281Ssklower		$$.e_data->m_flags |= M_EOR;
78537469Ssklower		sbinsertoob(&$P.tp_Xrcv, $$.e_data);
78636396Ssklower		IFDEBUG(D_XPD)
78736396Ssklower			dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
78836396Ssklower		ENDDEBUG
78936396Ssklower		tp_indicate(T_XDATA, $P, 0);
79036396Ssklower		sbwakeup( &$P.tp_Xrcv );
79136396Ssklower
79236396Ssklower		(void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
79336396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
79436396Ssklower	}
79536396Ssklower;
79636396Ssklower
79736396Ssklower/* TP4 only */
79836396SsklowerSAME			<==		TP_OPEN 									T_USR_Xrcvd
79936396Ssklower	DEFAULT
80036396Ssklower	{
80136396Ssklower		if( $P.tp_Xrcv.sb_cc == 0 ) {
80236396Ssklower			/* kludge for select(): */
80337469Ssklower			/* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
80436396Ssklower		}
80536396Ssklower	}
80636396Ssklower	/* OLD WAY:
80736396Ssklower	 * Ack only after the user receives the XPD.  This is better for
80836396Ssklower	 * users that use one XPD right after another.
80936396Ssklower	 * Acking right away (the NEW WAY, see the prev. transition) is
81036396Ssklower	 * better for occasional * XPD, when the receiving user doesn't
81136396Ssklower	 * want to read the XPD immediately (which is session's behavior).
81236396Ssklower	 *
81336396Ssklower		int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
81436396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
81536396Ssklower		return error;
81636396Ssklower	*/
81736396Ssklower;
81836396Ssklower
81936396Ssklower/* NOTE: presently if the user doesn't read the connection data
82036396Ssklower * before and expedited data PDU comes in, the connection data will
82136396Ssklower * be dropped. This is a bug.  To avoid it, we need somewhere else
82236396Ssklower * to put the connection data.
82336396Ssklower * On the other hand, we need not to have it sitting around forever.
82436396Ssklower * This is a problem with the idea of trying to accommodate
82536396Ssklower * data on connect w/ a passive-open user interface.
82636396Ssklower */
82736396Ssklower/* TP4 only */
82836396Ssklower
82936396SsklowerSAME	 		<== 	[ TP_AKWAIT, TP_OPEN ] 							XPD_TPDU
83036396Ssklower	DEFAULT /* not in window or cdt==0 */
83136396Ssklower	{
83236396Ssklower		IFTRACE(D_XPD)
83336396Ssklower			tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
83436396Ssklower				$P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
83536396Ssklower		ENDTRACE
83636396Ssklower		if( $P.tp_Xrcvnxt != $$.e_seq )
83736396Ssklower			IncStat(ts_xpd_niw);
83836396Ssklower		if( $P.tp_Xrcv.sb_cc ) {
83936396Ssklower			/* might as well kick 'em again */
84036396Ssklower			tp_indicate(T_XDATA, $P, 0);
84136396Ssklower			IncStat(ts_xpd_dup);
84236396Ssklower		}
84336396Ssklower		m_freem($$.e_data);
84451204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
84536396Ssklower		/* don't send an xack because the xak gives "last one received", not
84636396Ssklower		 * "next one i expect" (dumb)
84736396Ssklower		 */
84836396Ssklower	}
84936396Ssklower;
85036396Ssklower
85136396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
85236396Ssklower * to detach all its "children"
85336396Ssklower * Also (CRSENT) when user kills a job that's doing a connect()
85436396Ssklower */
85536396SsklowerTP_REFWAIT		<== 	TP_CRSENT 										T_DETACH
85636396Ssklower	($P.tp_class == TP_CLASS_0)
85736396Ssklower	{
85836396Ssklower		struct socket *so = $P.tp_sock;
85936396Ssklower
86036396Ssklower		/* detach from parent socket so it can finish closing */
86136396Ssklower		if (so->so_head) {
86236396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
86336396Ssklower				panic("tp: T_DETACH");
86436396Ssklower			so->so_head = 0;
86536396Ssklower		}
86636396Ssklower		tp_soisdisconnecting($P.tp_sock);
86736396Ssklower		tp_netcmd( $P, CONN_CLOSE);
86836396Ssklower		tp_soisdisconnected($P);
86936396Ssklower	}
87036396Ssklower;
87136396Ssklower
87236396Ssklower/* TP4 only */
87338841SsklowerTP_CLOSING		<== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ]	T_DETACH
87436396Ssklower	DEFAULT
87536396Ssklower	{
87636396Ssklower		struct socket *so = $P.tp_sock;
87737469Ssklower		struct mbuf *data = MNULL;
87836396Ssklower
87936396Ssklower		/* detach from parent socket so it can finish closing */
88036396Ssklower		if (so->so_head) {
88136396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
88236396Ssklower				panic("tp: T_DETACH");
88336396Ssklower			so->so_head = 0;
88436396Ssklower		}
88536396Ssklower		if ($P.tp_state != TP_CLOSING) {
88636396Ssklower			tp_soisdisconnecting($P.tp_sock);
88737469Ssklower			data = MCPY($P.tp_ucddata, M_NOWAIT);
88837469Ssklower			(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
88936396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
89051204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
89136396Ssklower		}
89236396Ssklower	}
89336396Ssklower;
89436396Ssklower
89536396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT ]		 	  			T_DISC_req
89636396Ssklower	( $P.tp_class == TP_CLASS_0 )
89736396Ssklower	{
89836396Ssklower		tp_soisdisconnecting($P.tp_sock);
89936396Ssklower		tp_netcmd( $P, CONN_CLOSE);
90036396Ssklower		tp_soisdisconnected($P);
90136396Ssklower	}
90236396Ssklower;
90336396Ssklower
90436396Ssklower/* TP4 only */
90538841SsklowerTP_CLOSING		<==	[ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
90636396Ssklower	DEFAULT
90736396Ssklower	{
90837469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
90936396Ssklower
91036396Ssklower		if($P.tp_state == TP_OPEN) {
91151204Ssklower			tp_euntimeout($P, TM_data_retrans); /* all */
91251204Ssklower			tp_cuntimeout($P, TM_inact);
91351204Ssklower			tp_cuntimeout($P, TM_sendack);
91453683Ssklower			$P.tp_flags &= ~TPF_DELACK;
91536396Ssklower		}
91637469Ssklower		if (data) {
91736396Ssklower			IFDEBUG(D_CONN)
91837469Ssklower				printf("T_DISC_req.trans tp_ucddata 0x%x\n",
91937469Ssklower					$P.tp_ucddata);
92037469Ssklower				dump_mbuf(data, "ucddata @ T_DISC_req");
92136396Ssklower			ENDDEBUG
92236396Ssklower		}
92336396Ssklower		tp_soisdisconnecting($P.tp_sock);
92436396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
92551204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
92636396Ssklower
92736396Ssklower		if( trick_hc )
92836396Ssklower			return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
92936396Ssklower	}
93036396Ssklower;
93136396Ssklower
93236396Ssklower/* TP4 only */
93336396SsklowerSAME			<==		TP_AKWAIT									TM_retrans
93436396Ssklower	( $P.tp_retrans > 0 )
93536396Ssklower	{
93636396Ssklower		int error;
93737469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
93836396Ssklower
93936396Ssklower		IncStat(ts_retrans_cc);
94036396Ssklower		$P.tp_retrans --;
94151204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
94239921Ssklower
94337469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
94436396Ssklower			$P.tp_sock->so_error = error;
94551204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
94636396Ssklower	}
94736396Ssklower;
94836396Ssklower
94936396Ssklower/* TP4 only */
95036396SsklowerTP_CLOSING		<==		TP_AKWAIT									TM_retrans
95136396Ssklower	DEFAULT  /* out of time */
95236396Ssklower	{
95336396Ssklower		IncStat(ts_conn_gaveup);
95436396Ssklower		tp_soisdisconnecting($P.tp_sock);
95536396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
95636396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
95736396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
95836396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
95951204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
96036396Ssklower	}
96136396Ssklower;
96236396Ssklower
96336396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does,
96436396Ssklower * if transmissions are going on.
96536396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack
96636396Ssklower * turnaround)
96736396Ssklower */
96836396Ssklower/* TP4 only */
96936396SsklowerTP_CLOSING 		<==		TP_OPEN		   [ TM_inact, TM_retrans, TM_data_retrans ]
97036396Ssklower	DEFAULT
97136396Ssklower	{
97251204Ssklower		tp_euntimeout($P, TM_data_retrans); /* all */
97351204Ssklower		tp_cuntimeout($P, TM_inact);
97451204Ssklower		tp_cuntimeout($P, TM_sendack);
97536396Ssklower
97636396Ssklower		IncStat(ts_conn_gaveup);
97736396Ssklower		tp_soisdisconnecting($P.tp_sock);
97836396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
97936396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
98036396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
98136396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
98251204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
98336396Ssklower	}
98436396Ssklower;
98536396Ssklower
98636396Ssklower/* TP4 only */
98736396SsklowerSAME			<==		TP_OPEN										TM_retrans
98836396Ssklower	( $P.tp_retrans > 0 )
98936396Ssklower	{
99051204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
99136396Ssklower		/* resume XPD */
99236396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
99337469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
99451204Ssklower			int shift;
99536396Ssklower
99636396Ssklower			IFTRACE(D_XPD)
99751204Ssklower				tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna",
99851204Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt,
99936396Ssklower					$P.tp_snduna);
100036396Ssklower			ENDTRACE
100136396Ssklower			IFDEBUG(D_XPD)
100236396Ssklower				dump_mbuf(m, "XPD retrans emitting M");
100336396Ssklower			ENDDEBUG
100436396Ssklower			IncStat(ts_retrans_xpd);
100536396Ssklower			$P.tp_retrans --;
100651204Ssklower			shift = max($P.tp_Nretrans - $P.tp_retrans, 6);
100736396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
100851204Ssklower			tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift);
100936396Ssklower		}
101036396Ssklower	}
101136396Ssklower;
101236396Ssklower
101336396Ssklower/* TP4 only */
101436396SsklowerSAME 			<==		TP_OPEN									TM_data_retrans
101551204Ssklower	($P.tp_rxtshift < TP_NRETRANS)
101636396Ssklower	{
101751204Ssklower		$P.tp_rxtshift++;
101851204Ssklower		(void) tp_data_retrans($P);
101936396Ssklower	}
102036396Ssklower;
102136396Ssklower
102236396Ssklower/* TP4 only */
102336396SsklowerSAME	 		<==		TP_CLOSING									TM_retrans
102436396Ssklower	(	$P.tp_retrans > 0 )
102536396Ssklower	{
102636396Ssklower		$P.tp_retrans --;
102736396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
102836396Ssklower		IncStat(ts_retrans_dr);
102951204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
103036396Ssklower	}
103136396Ssklower;
103236396Ssklower
103336396Ssklower/* TP4 only */
103436396SsklowerTP_REFWAIT 		<==		TP_CLOSING									TM_retrans
103536396Ssklower	DEFAULT	/* no more retrans - gave up */
103636396Ssklower	{
103736396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
103851204Ssklower		$P.tp_refstate = REF_FROZEN;
103936396Ssklower		tp_recycle_tsuffix( $P );
104051204Ssklower		tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
104136396Ssklower	}
104236396Ssklower;
104336396Ssklower
104436396Ssklower/*
104536396Ssklower * The resources are kept around until the ref timer goes off.
104636396Ssklower * The suffices are wiped out sooner so they can be reused right away.
104736396Ssklower */
104836396Ssklower/* applicable in TP4, TP0 */
104936396SsklowerTP_CLOSED 		<==		TP_REFWAIT 									TM_reference
105036396Ssklower	DEFAULT
105136396Ssklower	{
105251214Ssklower		tp_freeref($P.tp_lref);
105336396Ssklower		tp_detach($P);
105436396Ssklower	}
105536396Ssklower;
105636396Ssklower
105736396Ssklower/* applicable in TP4, TP0 */
105836396Ssklower/* A duplicate CR from connectionless network layer can't happen */
105936396SsklowerSAME 			<== 	TP_OPEN 							[ CR_TPDU, CC_TPDU ]
106036396Ssklower	DEFAULT
106136396Ssklower	{
106236396Ssklower		if( $P.tp_class != TP_CLASS_0) {
106351204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
106436396Ssklower			if ( $E.ev_number == CC_TPDU )
106536396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
106636396Ssklower		}
106736396Ssklower		/* ignore it if class 0 - state tables are blank for this */
106836396Ssklower	}
106936396Ssklower;
107036396Ssklower
107136396Ssklower/* applicable in TP4, TP0 */
107236396SsklowerSAME			<== 	TP_OPEN									T_DATA_req
107336396Ssklower	DEFAULT
107436396Ssklower	{
107536396Ssklower		IFTRACE(D_DATA)
107651204Ssklower			tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb",
107751204Ssklower				$P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P);
107836396Ssklower		ENDTRACE
107936396Ssklower
108036396Ssklower		tp_send($P);
108136396Ssklower	}
108236396Ssklower;
108336396Ssklower
108436396Ssklower/* TP4 only */
108536396SsklowerSAME			<==		TP_OPEN										T_XPD_req
108636396Ssklower	DEFAULT
108736396Ssklower		/* T_XPD_req was issued by sosend iff xpd socket buf was empty
108836396Ssklower		 * at time of sosend(),
108936396Ssklower		 * AND (which means) there were no unacknowledged XPD tpdus outstanding!
109036396Ssklower		 */
109136396Ssklower	{
109236396Ssklower		int error = 0;
109336396Ssklower
109436396Ssklower		/* resume XPD */
109536396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
109637469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
109736396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
109836396Ssklower			 * that doesn't matter
109936396Ssklower			 */
110036396Ssklower
110136396Ssklower			IFTRACE(D_XPD)
110251204Ssklower				tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna",
110351204Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt,
110436396Ssklower					$P.tp_snduna);
110536396Ssklower			ENDTRACE
110636396Ssklower			IFDEBUG(D_XPD)
110736396Ssklower				printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
110836396Ssklower				dump_mbuf(m, "XPD req emitting M");
110936396Ssklower			ENDDEBUG
111036396Ssklower			error =
111136396Ssklower				tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
111236396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
111351204Ssklower
111451204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur);
111536396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
111636396Ssklower		}
111736396Ssklower		if(trick_hc)
111836396Ssklower			return error;
111936396Ssklower	}
112036396Ssklower;
112136396Ssklower
112236396Ssklower/* TP4, faked ack in TP0 when cons send completes */
112336396SsklowerSAME 			<==		TP_OPEN 									AK_TPDU
112436396Ssklower	( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
112536396Ssklower
112636396Ssklower	/* tp_goodack == true means
112736396Ssklower	 * EITHER it actually acked something heretofore unacknowledged
112836396Ssklower	 * OR no news but the credit should be processed.
112936396Ssklower	 */
113036396Ssklower	{
113150904Ssklower		struct sockbuf *sb = &$P.tp_sock->so_snd;
113250904Ssklower
113336396Ssklower		IFDEBUG(D_ACKRECV)
113436396Ssklower			printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
113536396Ssklower		ENDDEBUG
113636396Ssklower		if( $P.tp_class != TP_CLASS_0) {
113751204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
113836396Ssklower		}
113950904Ssklower		sbwakeup(sb);
114036396Ssklower		IFDEBUG(D_ACKRECV)
114151204Ssklower			printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt);
114236396Ssklower		ENDDEBUG
114336396Ssklower	}
114436396Ssklower;
114536396Ssklower
114636396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
114736396SsklowerSAME			<==		TP_OPEN 			 						 AK_TPDU
114836396Ssklower	DEFAULT
114936396Ssklower	{
115036396Ssklower		IFTRACE(D_ACKRECV)
115136396Ssklower			tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
115236396Ssklower				$$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
115336396Ssklower		ENDTRACE
115436396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
115536396Ssklower
115636396Ssklower			if ( !$$.e_fcc_present ) {
115736396Ssklower				/* send ACK with FCC */
115836396Ssklower				IncStat( ts_ackreason[_ACK_FCC_] );
115936396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
116036396Ssklower			}
116151204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
116236396Ssklower		}
116336396Ssklower	}
116436396Ssklower;
116536396Ssklower
116636396Ssklower/* NBS(47) */
116736396Ssklower	/* goes in at *** */
116836396Ssklower		/* just so happens that this is never true now, because we allow
116936396Ssklower		 * only 1 packet in the queue at once (this could be changed)
117036396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
117136396Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
117236396Ssklower
117336396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
117436396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
117551204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks);
117636396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
117736396Ssklower		}
117836396Ssklower		 */
117936396Ssklower	/* end of the above hack */
118036396Ssklower
118136396Ssklower/* TP4 only */
118242944SsklowerSAME			<== 	TP_OPEN										XAK_TPDU
118336396Ssklower	( tp_goodXack($P, $$.e_seq) )
118436396Ssklower	/* tp_goodXack checks for good ack, removes the correct
118536396Ssklower	 * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
118636396Ssklower	 * also updates tp_Xuna
118736396Ssklower	 */
118836396Ssklower	{
118951204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
119051204Ssklower		tp_cuntimeout($P, TM_retrans);
119136396Ssklower
119236396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
119336396Ssklower
119436396Ssklower		/* resume normal data */
119536396Ssklower		tp_send($P);
119636396Ssklower	}
119736396Ssklower;
119836396Ssklower
119942944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
120042944SsklowerSAME			<==		TP_OPEN 			 						XAK_TPDU
120142944Ssklower	DEFAULT
120242944Ssklower	{
120342944Ssklower		IFTRACE(D_ACKRECV)
120442944Ssklower			tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
120542944Ssklower		ENDTRACE
120642944Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
120751204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
120842944Ssklower		}
120942944Ssklower	}
121042944Ssklower;
121142944Ssklower
121236396Ssklower/* TP4 only */
121336396SsklowerSAME			<==		TP_OPEN 								TM_sendack
121436396Ssklower	DEFAULT
121536396Ssklower	{
121651204Ssklower		int timo;
121736396Ssklower		IFTRACE(D_TIMER)
121836396Ssklower			tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
121936396Ssklower			$P.tp_sent_lcdt, 0);
122036396Ssklower		ENDTRACE
122136396Ssklower		IncPStat($P, tps_n_TMsendack);
122236396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
122351248Ssklower		if ($P.tp_fcredit == 0) {
122451248Ssklower			if ($P.tp_rxtshift < TP_MAXRXTSHIFT)
122551248Ssklower				$P.tp_rxtshift++;
122651248Ssklower			timo = ($P.tp_dt_ticks) << $P.tp_rxtshift;
122751248Ssklower		} else
122851248Ssklower			timo = $P.tp_sendack_ticks;
122951248Ssklower		tp_ctimeout($P, TM_sendack, timo);
123036396Ssklower	}
123136396Ssklower;
123236396Ssklower
123336396Ssklower/* TP0 only */
123436396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
123536396Ssklower	($P.tp_class == TP_CLASS_0)
123647281Ssklower	{
123747281Ssklower		if (sbspace(&$P.tp_sock->so_rcv) > 0)
123847281Ssklower			tp0_openflow($P);
123947281Ssklower	}
124036396Ssklower;
124136396Ssklower
124236396Ssklower/* TP4 only */
124336396Ssklower		/* If old credit was zero,
124436396Ssklower		 * we'd better inform other side that we now have space
124536396Ssklower		 * But this is not enough.  Sender might not yet have
124636396Ssklower		 * seen an ack with cdt 0 but it might still think the
124736396Ssklower		 * window is closed, so it's going to wait.
124836396Ssklower		 * Best to send an ack each time.
124936396Ssklower		 * Strictly speaking, this ought to be a function of the
125036396Ssklower		 * general ack strategy.
125136396Ssklower		 */
125236396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
125336396Ssklower	DEFAULT
125436396Ssklower	{
125536396Ssklower		if( trick_hc ) {
125651024Ssklower			SeqNum ack_thresh;
125750849Ssklower			/*
125851024Ssklower			 * If the upper window edge has advanced a reasonable
125951024Ssklower			 * amount beyond what was known, send an ACK.
126051024Ssklower			 * A reasonable amount is 2 packets, unless the max window
126151024Ssklower			 * is only 1 or 2 packets, in which case we
126251024Ssklower			 * should send an ack for any advance in the upper window edge.
126350849Ssklower			 */
126451024Ssklower			LOCAL_CREDIT($P);
126551024Ssklower			ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt,
126651024Ssklower									 ($P.tp_maxlcredit > 2 ? 2 : 1));
126751024Ssklower			if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) {
126850849Ssklower				IncStat(ts_ackreason[_ACK_USRRCV_]);
126951024Ssklower				$P.tp_flags &= ~TPF_DELACK;
127039921Ssklower				return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
127150849Ssklower			}
127236396Ssklower		}
127336396Ssklower	}
127436396Ssklower;
127536396Ssklower
127636396Ssklower/* applicable in TP4, TP0 */
127736396SsklowerSAME			<==		TP_REFWAIT 				[ T_USR_rcvd, T_USR_Xrcvd ]
127836396Ssklower	DEFAULT
127936396Ssklower	/* This happens if other end sent a DR when  the user was waiting
128036396Ssklower	 * on a receive.
128136396Ssklower	 * Processing the DR includes putting us in REFWAIT state.
128236396Ssklower	 */
128336396Ssklower	{
128436396Ssklower		if(trick_hc)
128536396Ssklower		return ECONNABORTED;
128636396Ssklower	}
128736396Ssklower;
128836396Ssklower
128936396Ssklower/* TP0 only */
129036396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT, TP_LISTENING ] 	T_NETRESET
129136396Ssklower	( $P.tp_class != TP_CLASS_4 )
129236396Ssklower		/* 0 or (4 and 0) */
129336396Ssklower		/* in OPEN class will be 0 or 4 but not both */
129436396Ssklower		/* in CRSENT or LISTENING it could be in negotiation, hence both */
129536396Ssklower		/* Actually, this shouldn't ever happen in LISTENING */
129636396Ssklower	{
129736396Ssklower		ASSERT( $P.tp_state != TP_LISTENING );
129836396Ssklower		tp_indicate(T_DISCONNECT, $P, ECONNRESET);
129936396Ssklower		tp_soisdisconnected($P);
130036396Ssklower	}
130136396Ssklower;
130236396Ssklower
130336396Ssklower/* TP4: ignore resets */
130436396SsklowerSAME		<==		[ TP_OPEN, TP_CRSENT, TP_AKWAIT,
130536396Ssklower						TP_CLOSING, TP_LISTENING ] 				T_NETRESET
130636396Ssklower	DEFAULT
130736396Ssklower	NULLACTION
130836396Ssklower;
130936396Ssklower
131036396Ssklower/* applicable in TP4, TP0 */
131136396SsklowerSAME			<==		[ TP_CLOSED, TP_REFWAIT ]				T_NETRESET
131236396Ssklower	DEFAULT
131336396Ssklower	NULLACTION
131436396Ssklower;
131536396Ssklower
131636396Ssklower/* C'EST TOUT */
1317