xref: /csrg-svn/sys/netiso/tp.trans (revision 49268)
1*49268Sbostic/*-
2*49268Sbostic * Copyright (c) 1991 The Regents of the University of California.
3*49268Sbostic * All rights reserved.
4*49268Sbostic *
5*49268Sbostic * %sccs.include.redist.c%
6*49268Sbostic *
7*49268Sbostic *	@(#)tp.trans	7.8 (Berkeley) 05/06/91
8*49268Sbostic */
9*49268Sbostic
1036396Ssklower/***********************************************************
1136396Ssklower		Copyright IBM Corporation 1987
1236396Ssklower
1336396Ssklower                      All Rights Reserved
1436396Ssklower
1536396SsklowerPermission to use, copy, modify, and distribute this software and its
1636396Ssklowerdocumentation for any purpose and without fee is hereby granted,
1736396Ssklowerprovided that the above copyright notice appear in all copies and that
1836396Ssklowerboth that copyright notice and this permission notice appear in
1936396Ssklowersupporting documentation, and that the name of IBM not be
2036396Ssklowerused in advertising or publicity pertaining to distribution of the
2136396Ssklowersoftware without specific, written prior permission.
2236396Ssklower
2336396SsklowerIBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436396SsklowerALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536396SsklowerIBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636396SsklowerANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736396SsklowerWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836396SsklowerARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936396SsklowerSOFTWARE.
3036396Ssklower
3136396Ssklower******************************************************************/
3236396Ssklower
3336396Ssklower/*
3436396Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536396Ssklower */
3636396Ssklower/* $Header: tp.trans,v 5.1 88/10/12 12:22:07 root Exp $
3736396Ssklower *
3836396Ssklower * Transition file for TP.
3936396Ssklower *
4036396Ssklower * DO NOT:
4136396Ssklower * - change the order of any of the events or states.  to do so will
4236396Ssklower *   make tppt, netstat, etc. cease working.
4336396Ssklower *
4436396Ssklower * NOTE:
4536396Ssklower * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED***
4636396Ssklower * (read: may not work!)
4736396Ssklower *
4836396Ssklower * I tried to put everything that causes a change of state in here, hence
4936396Ssklower * there are some seemingly trivial events  like T_DETACH and T_LISTEN_req.
5036396Ssklower *
5136396Ssklower * Almost everything having to do w/ setting & cancelling timers is here
5236396Ssklower * but once it was debugged, I moved the setting of the
5336396Ssklower * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent.
5436396Ssklower * This is so the code wouldn't be duplicated all over creation in here.
5536396Ssklower *
5636396Ssklower */
5736396Ssklower*PROTOCOL tp
5836396Ssklower
5936396Ssklower*INCLUDE
6036396Ssklower
6136396Ssklower{
6236396Ssklower#include "param.h"
6336396Ssklower#include "socket.h"
6436396Ssklower#include "socketvar.h"
6536396Ssklower#include "protosw.h"
6636396Ssklower#include "mbuf.h"
6736396Ssklower#include "time.h"
6836396Ssklower#include "errno.h"
6936396Ssklower#include "../netiso/tp_param.h"
7036396Ssklower#include "../netiso/tp_stat.h"
7136396Ssklower#include "../netiso/tp_pcb.h"
7236396Ssklower#include "../netiso/tp_tpdu.h"
7336396Ssklower#include "../netiso/argo_debug.h"
7436396Ssklower#include "../netiso/tp_trace.h"
7536396Ssklower#include "../netiso/iso_errno.h"
7636396Ssklower#include "../netiso/tp_seq.h"
7736396Ssklower#include "../netiso/cons.h"
7836396Ssklower
7936396Ssklower#define DRIVERTRACE TPPTdriver
8037469Ssklower#define sbwakeup(sb)	sowakeup(p->tp_sock, sb);
8137469Ssklower#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
8236396Ssklower
8336396Ssklowerstatic 	trick_hc = 1;
8436396Ssklower
8536396Ssklowerint 	tp_emit(),
8636396Ssklower		tp_goodack(),				tp_goodXack(),
8736396Ssklower		tp_stash()
8836396Ssklower;
8936396Ssklowervoid	tp_indicate(),				tp_getoptions(),
9036396Ssklower		tp_soisdisconnecting(), 	tp_soisdisconnected(),
9136396Ssklower		tp_recycle_tsuffix(),
9236396Ssklower		tp_etimeout(),				tp_euntimeout(),
9336396Ssklower		tp_euntimeout_lss(),		tp_ctimeout(),
9436396Ssklower		tp_cuntimeout(),			tp_ctimeout_MIN(),
9536396Ssklower		tp_freeref(),				tp_detach(),
9636396Ssklower		tp0_stash(), 				tp0_send(),
9736396Ssklower		tp_netcmd(),				tp_send()
9836396Ssklower;
9936396Ssklower
10036396Ssklowertypedef  struct tp_pcb tpcb_struct;
10136396Ssklower
10236396Ssklower
10336396Ssklower}
10436396Ssklower
10536396Ssklower*PCB    tpcb_struct 	SYNONYM  P
10636396Ssklower
10736396Ssklower*STATES
10836396Ssklower
10936396SsklowerTP_CLOSED
11036396SsklowerTP_CRSENT
11136396SsklowerTP_AKWAIT
11236396SsklowerTP_OPEN
11336396SsklowerTP_CLOSING
11436396SsklowerTP_REFWAIT
11536396SsklowerTP_LISTENING	/* Local to this implementation */
11638841SsklowerTP_CONFIRMING	/* Local to this implementation */
11736396Ssklower
11836396Ssklower*EVENTS		{ struct timeval e_time; } 		SYNONYM  E
11936396Ssklower
12036396Ssklower /*
12136396Ssklower  * C (typically cancelled) timers  -
12236396Ssklower  *
12336396Ssklower  * let these be the first ones so for the sake of convenience
12436396Ssklower  * their values are 0--> n-1
12536396Ssklower  * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!!
12636396Ssklower  */
12736396Ssklower TM_inact
12836396Ssklower TM_retrans
12936396Ssklower				/* TM_retrans is used for all
13036396Ssklower				 * simple retransmissions - CR,CC,XPD,DR
13136396Ssklower				 */
13236396Ssklower
13336396Ssklower TM_sendack
13436396Ssklower				/* TM_sendack does dual duty - keepalive AND sendack.
13536396Ssklower				 * It's set w/ keepalive-ticks every time an ack is sent.
13636396Ssklower				 * (this is done in (void) tp_emit() ).
13736396Ssklower				 * It's cancelled and reset whenever a DT
13836396Ssklower				 * arrives and it doesn't require immediate acking.
13936396Ssklower				 * Note that in this case it's set w/ the minimum of
14036396Ssklower				 * its prev value and the sendack-ticks value so the
14136396Ssklower				 * purpose of the keepalive is preserved.
14236396Ssklower				 */
14336396Ssklower TM_notused
14436396Ssklower
14536396Ssklower /*
14636396Ssklower  * E (typically expired) timers - these may be in any order.
14736396Ssklower  * These cause procedures to be executed directly; may not
14836396Ssklower  * cause an 'event' as we know them here.
14936396Ssklower  */
15036396Ssklower TM_reference		{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15136396Ssklower TM_data_retrans	{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15236396Ssklower
15336396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that
15436396Ssklower * for all tpdu types that can take e_data and e_datalen, these
15536396Ssklower * fields fall in the same place in the event structure, that is,
15636396Ssklower * e_data is the first field and e_datalen is the 2nd field.
15736396Ssklower */
15836396Ssklower
15936396Ssklower ER_TPDU  	 	{
16036396Ssklower				  u_char		e_reason;
16136396Ssklower				}
16236396Ssklower CR_TPDU  	 	{ struct mbuf 	*e_data;	/* first field */
16336396Ssklower				  int 			e_datalen; /* 2nd field */
16436396Ssklower				  u_int			e_cdt;
16536396Ssklower				}
16636396Ssklower DR_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
16736396Ssklower				  int 			e_datalen; /* 2nd field */
16836396Ssklower				  u_short		e_sref;
16936396Ssklower				  u_char		e_reason;
17036396Ssklower				}
17136396Ssklower DC_TPDU
17236396Ssklower CC_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
17336396Ssklower				  int 			e_datalen; /* 2nd field */
17436396Ssklower				  u_short		e_sref;
17536396Ssklower				  u_int			e_cdt;
17636396Ssklower				}
17736396Ssklower AK_TPDU		{ u_int			e_cdt;
17836396Ssklower				  SeqNum 	 	e_seq;
17936396Ssklower				  SeqNum 	 	e_subseq;
18036396Ssklower				  u_char 	 	e_fcc_present;
18136396Ssklower				}
18236396Ssklower DT_TPDU		{ struct mbuf	*e_data; 	/* first field */
18336396Ssklower				  int 			e_datalen; /* 2nd field */
18436396Ssklower				  u_int 		e_eot;
18536396Ssklower				  SeqNum		e_seq;
18636396Ssklower				}
18736396Ssklower XPD_TPDU		{ struct mbuf 	*e_data;	/* first field */
18836396Ssklower				  int 			e_datalen; 	/* 2nd field */
18936396Ssklower				  SeqNum 		e_seq;
19036396Ssklower				}
19136396Ssklower XAK_TPDU		{ SeqNum 		e_seq;		}
19236396Ssklower
19336396Ssklower T_CONN_req
19436396Ssklower T_DISC_req		{ u_char		e_reason; 	}
19536396Ssklower T_LISTEN_req
19636396Ssklower T_DATA_req
19736396Ssklower T_XPD_req
19836396Ssklower T_USR_rcvd
19936396Ssklower T_USR_Xrcvd
20036396Ssklower T_DETACH
20136396Ssklower T_NETRESET
20238841Ssklower T_ACPT_req
20336396Ssklower
20436396Ssklower
20536396Ssklower*TRANSITIONS
20636396Ssklower
20736396Ssklower
20836396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */
20936396SsklowerSAME			<==			TP_AKWAIT			[ CC_TPDU, DC_TPDU, XAK_TPDU ]
21036396Ssklower	DEFAULT
21136396Ssklower	NULLACTION
21236396Ssklower;
21336396Ssklower
21436396Ssklower
21536396Ssklower/* applicable in TP4, TP0 */
21636396SsklowerSAME			<==			TP_REFWAIT								DR_TPDU
21736396Ssklower	( $$.e_sref !=  0 )
21836396Ssklower	{
21936396Ssklower		(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
22036396Ssklower	}
22136396Ssklower;
22236396Ssklower
22336396Ssklower/* applicable in TP4, TP0 */
22436396SsklowerSAME			<==			TP_REFWAIT			[ CR_TPDU, CC_TPDU, DT_TPDU,
22536396Ssklower					DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ]
22636396Ssklower	DEFAULT
22736396Ssklower	{
22836396Ssklower#		ifdef TP_DEBUG
22936396Ssklower		if( $E.ev_number != AK_TPDU )
23036396Ssklower			printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number);
23136396Ssklower#		endif TP_DEBUG
23236396Ssklower	}
23336396Ssklower;
23436396Ssklower
23536396Ssklower/* applicable in TP4, TP0 */
23636396SsklowerSAME			<==			TP_REFWAIT				[ T_DETACH, T_DISC_req ]
23736396Ssklower	DEFAULT
23836396Ssklower	NULLACTION
23936396Ssklower;
24036396Ssklower
24136396Ssklower/* applicable in TP4, TP0 */
24236396SsklowerSAME			<==			TP_CRSENT								 AK_TPDU
24336396Ssklower	($P.tp_class == TP_CLASS_0)
24436396Ssklower	{
24536396Ssklower		/* oh, man is this grotesque or what? */
24636396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq,  $$.e_subseq);
24736396Ssklower		/* but it's necessary because this pseudo-ack may happen
24836396Ssklower		 * before the CC arrives, but we HAVE to adjust the
24936396Ssklower		 * snduna as a result of the ack, WHENEVER it arrives
25036396Ssklower		 */
25136396Ssklower	}
25236396Ssklower;
25336396Ssklower
25436396Ssklower/* applicable in TP4, TP0 */
25536396SsklowerSAME			<==			TP_CRSENT
25636396Ssklower					[ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU,  XAK_TPDU ]
25736396Ssklower	DEFAULT
25836396Ssklower	NULLACTION
25936396Ssklower;
26036396Ssklower
26136396Ssklower/* applicable in TP4, TP0 */
26236396SsklowerSAME			<==			TP_CLOSED					[ DT_TPDU, XPD_TPDU,
26336396Ssklower										ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
26436396Ssklower	DEFAULT
26536396Ssklower	NULLACTION
26636396Ssklower;
26736396Ssklower
26836396Ssklower/* TP_CLOSING doesn't exist in TP 0 */
26936396SsklowerSAME 			<== 		TP_CLOSING
27036396Ssklower					[ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ]
27136396Ssklower	DEFAULT
27236396Ssklower	NULLACTION
27336396Ssklower;
27436396Ssklower
27536396Ssklower
27636396Ssklower/* DC_TPDU doesn't exist in TP 0 */
27736396SsklowerSAME			<==			TP_OPEN						  DC_TPDU
27836396Ssklower	DEFAULT
27936396Ssklower	NULLACTION
28036396Ssklower;
28136396Ssklower
28236396Ssklower/* applicable in TP4, TP0 */
28336396SsklowerSAME			<==		 	TP_LISTENING  [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU,
28436396Ssklower										 ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
28536396Ssklower	DEFAULT
28636396Ssklower	NULLACTION
28736396Ssklower;
28836396Ssklower
28936396Ssklower/* applicable in TP4, TP0 */
29036396SsklowerTP_LISTENING	<==			TP_CLOSED  							T_LISTEN_req
29136396Ssklower	DEFAULT
29236396Ssklower	NULLACTION
29336396Ssklower;
29436396Ssklower
29536396Ssklower/* applicable in TP4, TP0 */
29636396SsklowerTP_CLOSED  		<== 		[ TP_LISTENING, TP_CLOSED ] 			T_DETACH
29736396Ssklower	DEFAULT
29836396Ssklower	{
29936396Ssklower		tp_detach($P);
30036396Ssklower	}
30136396Ssklower;
30236396Ssklower
30338841SsklowerTP_CONFIRMING	<==		 TP_LISTENING  								CR_TPDU
30438841Ssklower	( $P.tp_class == TP_CLASS_0)
30536396Ssklower	{
30636396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */
30736396Ssklower	}
30836396Ssklower;
30936396Ssklower
31038841SsklowerTP_CONFIRMING		<==		 TP_LISTENING  							CR_TPDU
31138841Ssklower	DEFAULT
31236396Ssklower	{
31336396Ssklower		IFTRACE(D_CONN)
31436396Ssklower			tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
31536396Ssklower		ENDTRACE
31636396Ssklower		IFDEBUG(D_CONN)
31736396Ssklower			printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
31836396Ssklower		ENDDEBUG
31936396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers */
32038841Ssklower		$P.tp_fcredit = $$.e_cdt;
32136396Ssklower
32236396Ssklower		if ($$.e_datalen > 0) {
32336396Ssklower			/* n/a for class 0 */
32436396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0);
32536396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
32636396Ssklower			$$.e_data = MNULL;
32736396Ssklower		}
32838841Ssklower	}
32938841Ssklower;
33038841Ssklower
33138841SsklowerTP_OPEN		<==		 TP_CONFIRMING  								T_ACPT_req
33238841Ssklower	( $P.tp_class == TP_CLASS_0 )
33338841Ssklower	{
33438841Ssklower		IncStat(ts_tp0_conn);
33538841Ssklower		IFTRACE(D_CONN)
33638841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
33738841Ssklower		ENDTRACE
33838841Ssklower		IFDEBUG(D_CONN)
33938841Ssklower			printf("Confirming connection: $P" );
34038841Ssklower		ENDDEBUG
34138841Ssklower		soisconnected($P.tp_sock);
34238841Ssklower		(void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
34338841Ssklower		$P.tp_fcredit = 1;
34438841Ssklower	}
34538841Ssklower;
34638841Ssklower
34738841SsklowerTP_AKWAIT		<==		 TP_CONFIRMING  							T_ACPT_req
34838841Ssklower	(tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
34938841Ssklower	{
35038841Ssklower		IncStat(ts_tp4_conn); /* even though not quite open */
35138841Ssklower		IFTRACE(D_CONN)
35238841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
35338841Ssklower		ENDTRACE
35438841Ssklower		IFDEBUG(D_CONN)
35538841Ssklower			printf("Confirming connection: $P" );
35638841Ssklower		ENDDEBUG
35738841Ssklower		soisconnecting($P.tp_sock);
35847281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
35938841Ssklower			$P.tp_cong_win = $P.tp_fcredit;
36036396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
36136396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
36238841Ssklower	}
36336396Ssklower;
36436396Ssklower
36536396Ssklower/* TP4 only */
36638841SsklowerTP_CLOSED		<==		 TP_CONFIRMING								T_ACPT_req
36736396Ssklower	DEFAULT /* emit failed */
36836396Ssklower	{
36936396Ssklower		register struct tp_ref *r = $P.tp_refp;
37036396Ssklower
37136396Ssklower		IFDEBUG(D_CONN)
37236396Ssklower			printf("event: CR_TPDU emit CC failed done " );
37336396Ssklower		ENDDEBUG
37438841Ssklower		soisdisconnected($P.tp_sock);
37536396Ssklower		tp_recycle_tsuffix( $P );
37636396Ssklower		tp_freeref(r);
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
40436396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers */
40536396Ssklower		if($P.tp_class != TP_CLASS_0) {
40636396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
40736396Ssklower			tp_ctimeout($P.tp_refp, 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		}
42148739Ssklower		tp_indicate(T_DISCONNECT, $P, 0);
42236396Ssklower		tp_soisdisconnected($P);
42336396Ssklower		if ($P.tp_class != TP_CLASS_0) {
42436396Ssklower			if ($P.tp_state == TP_OPEN ) {
42536396Ssklower				tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
42636396Ssklower				tp_cuntimeout($P.tp_refp, TM_retrans);
42736396Ssklower				tp_cuntimeout($P.tp_refp, TM_inact);
42836396Ssklower				tp_cuntimeout($P.tp_refp, TM_sendack);
42936396Ssklower			}
43036396Ssklower			tp_cuntimeout($P.tp_refp, TM_retrans);
43136396Ssklower			if( $$.e_sref !=  0 )
43236396Ssklower				(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
43336396Ssklower		}
43436396Ssklower	}
43536396Ssklower;
43636396Ssklower
43736396SsklowerSAME 			<==		TP_CLOSED 									DR_TPDU
43836396Ssklower	DEFAULT
43936396Ssklower	{
44036396Ssklower		if( $$.e_sref != 0 )
44136396Ssklower			(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
44236396Ssklower		/* reference timer already set - reset it to be safe (???) */
44336396Ssklower		tp_euntimeout($P.tp_refp, TM_reference); /* all */
44436396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks);
44536396Ssklower	}
44636396Ssklower;
44736396Ssklower
44836396Ssklower/* NBS(34) */
44936396SsklowerTP_REFWAIT 		<==  	TP_CRSENT  									ER_TPDU
45036396Ssklower	DEFAULT
45136396Ssklower	{
45236396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
45348739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
45436396Ssklower		tp_soisdisconnected($P);
45536396Ssklower	}
45636396Ssklower;
45736396Ssklower
45836396Ssklower/* NBS(27) */
45936396SsklowerTP_REFWAIT		<==		TP_CLOSING									DR_TPDU
46036396Ssklower	DEFAULT
46136396Ssklower	{
46236396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
46336396Ssklower		tp_soisdisconnected($P);
46436396Ssklower	}
46536396Ssklower;
46636396Ssklower/* these two transitions are the same but can't be combined because xebec
46736396Ssklower * can't handle the use of $$.e_reason if they're combined
46836396Ssklower */
46936396Ssklower/* NBS(27) */
47036396SsklowerTP_REFWAIT		<==		TP_CLOSING									ER_TPDU
47136396Ssklower	DEFAULT
47236396Ssklower	{
47348739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
47436396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
47536396Ssklower		tp_soisdisconnected($P);
47636396Ssklower	}
47736396Ssklower;
47836396Ssklower/* NBS(27) */
47936396SsklowerTP_REFWAIT		<==		TP_CLOSING									DC_TPDU
48036396Ssklower	DEFAULT
48136396Ssklower	{
48236396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
48336396Ssklower		tp_soisdisconnected($P);
48436396Ssklower	}
48536396Ssklower;
48636396Ssklower
48736396Ssklower/* NBS(21) */
48836396SsklowerSAME 			<== 	TP_CLOSED 						[ CC_TPDU, CR_TPDU ]
48936396Ssklower	DEFAULT
49036396Ssklower	{	/* don't ask me why we have to do this - spec says so */
49136396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
49236396Ssklower		/* don't bother with retransmissions of the DR */
49336396Ssklower	}
49436396Ssklower;
49536396Ssklower
49636396Ssklower/* NBS(34) */
49736396SsklowerTP_REFWAIT 		<== 	TP_OPEN  				 					ER_TPDU
49836396Ssklower	($P.tp_class == TP_CLASS_0)
49936396Ssklower	{
50036396Ssklower		tp_soisdisconnecting($P.tp_sock);
50148739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
50236396Ssklower		tp_soisdisconnected($P);
50336396Ssklower		tp_netcmd( $P, CONN_CLOSE );
50436396Ssklower	}
50536396Ssklower;
50636396Ssklower
50736396SsklowerTP_CLOSING 		<== 	[ TP_AKWAIT, TP_OPEN ]  					ER_TPDU
50836396Ssklower	DEFAULT
50936396Ssklower	{
51036396Ssklower		if ($P.tp_state == TP_OPEN) {
51136396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
51236396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
51336396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
51436396Ssklower		}
51536396Ssklower		tp_soisdisconnecting($P.tp_sock);
51648739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
51736396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
51836396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
51936396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
52036396Ssklower	}
52136396Ssklower;
52236396Ssklower/* NBS(6) */
52336396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
52436396Ssklower	($P.tp_class == TP_CLASS_0)
52536396Ssklower	{
52636396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
52736396Ssklower		IncStat(ts_tp0_conn);
52836396Ssklower		$P.tp_fcredit = 1;
52936396Ssklower		soisconnected($P.tp_sock);
53036396Ssklower	}
53136396Ssklower;
53236396Ssklower
53336396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
53436396Ssklower	DEFAULT
53536396Ssklower	{
53636396Ssklower		IFDEBUG(D_CONN)
53736396Ssklower			printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
53836396Ssklower				(int)$P.tp_flags);
53936396Ssklower		ENDDEBUG
54036396Ssklower		IncStat(ts_tp4_conn);
54136396Ssklower		$P.tp_fref = $$.e_sref;
54236396Ssklower		$P.tp_fcredit = $$.e_cdt;
54339921Ssklower		$P.tp_ackrcvd = 0;
54447281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
54536396Ssklower			$P.tp_cong_win = $$.e_cdt;
54636396Ssklower		tp_getoptions($P);
54736396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
54837469Ssklower		if ($P.tp_ucddata) {
54936396Ssklower			IFDEBUG(D_CONN)
55037469Ssklower				printf("dropping user connect data cc 0x%x\n",
55137469Ssklower					$P.tp_ucddata->m_len);
55236396Ssklower			ENDDEBUG
55337469Ssklower			m_freem($P.tp_ucddata);
55437469Ssklower			$P.tp_ucddata = 0;
55536396Ssklower		}
55636396Ssklower		soisconnected($P.tp_sock);
55736396Ssklower		if ($$.e_datalen > 0) {
55836396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
55936396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
56036396Ssklower			$$.e_data = MNULL;
56136396Ssklower		}
56236396Ssklower
56336396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
56436396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
56536396Ssklower	}
56636396Ssklower;
56736396Ssklower
56836396Ssklower/* TP4 only */
56936396SsklowerSAME			<==		TP_CRSENT									TM_retrans
57036396Ssklower	(	$P.tp_retrans > 0 )
57136396Ssklower	{
57236396Ssklower		struct mbuf *data = MNULL;
57336396Ssklower		int error;
57436396Ssklower
57536396Ssklower		IncStat(ts_retrans_cr);
57639921Ssklower		$P.tp_cong_win = 1;
57739921Ssklower		$P.tp_ackrcvd = 0;
57837469Ssklower		data = MCPY($P.tp_ucddata, M_NOWAIT);
57937469Ssklower		if($P.tp_ucddata) {
58036396Ssklower			IFDEBUG(D_CONN)
58137469Ssklower				printf("TM_retrans.trans m_copy cc 0x%x\n", data);
58237469Ssklower				dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
58336396Ssklower			ENDDEBUG
58436396Ssklower			if( data == MNULL )
58536396Ssklower				return ENOBUFS;
58636396Ssklower		}
58736396Ssklower
58836396Ssklower		$P.tp_retrans --;
58936396Ssklower		if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
59036396Ssklower			$P.tp_sock->so_error = error;
59136396Ssklower		}
59236396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
59336396Ssklower	}
59436396Ssklower;
59536396Ssklower
59636396Ssklower/* TP4 only  */
59736396SsklowerTP_REFWAIT		<==		TP_CRSENT									TM_retrans
59836396Ssklower	DEFAULT /* no more CR retransmissions */
59936396Ssklower	{
60036396Ssklower		IncStat(ts_conn_gaveup);
60136396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
60236396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
60336396Ssklower		tp_soisdisconnected($P);
60436396Ssklower	}
60536396Ssklower;
60636396Ssklower
60736396Ssklower/* TP4 only */
60836396SsklowerSAME 			<==	 TP_AKWAIT											CR_TPDU
60936396Ssklower	DEFAULT
61036396Ssklower	/* duplicate CR (which doesn't really exist in the context of
61136396Ssklower	 * a connectionless network layer)
61236396Ssklower	 * Doesn't occur in class 0.
61336396Ssklower	 */
61436396Ssklower	{
61536396Ssklower		int error;
61637469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
61736396Ssklower
61837469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
61936396Ssklower			$P.tp_sock->so_error = error;
62036396Ssklower		}
62136396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
62236396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
62336396Ssklower	}
62436396Ssklower;
62536396Ssklower
62636396Ssklower/* TP4 only */
62736396SsklowerTP_OPEN			<==		TP_AKWAIT 										DT_TPDU
62836396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
62936396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
63036396Ssklower	{
63136396Ssklower		int doack;
63236396Ssklower
63337469Ssklower		/*
63437469Ssklower		 * Get rid of any confirm or connect data, so that if we
63537469Ssklower		 * crash or close, it isn't thought of as disconnect data.
63637469Ssklower		 */
63737469Ssklower		if ($P.tp_ucddata) {
63837469Ssklower			m_freem($P.tp_ucddata);
63937469Ssklower			$P.tp_ucddata = 0;
64036396Ssklower		}
64136396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
64236396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
64336396Ssklower		soisconnected($P.tp_sock);
64436396Ssklower		tp_getoptions($P);
64536396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
64636396Ssklower
64736396Ssklower		/* see also next 2 transitions, if you make any changes */
64836396Ssklower
64936396Ssklower		doack = tp_stash($P, $E);
65036396Ssklower		IFDEBUG(D_DATA)
65136396Ssklower			printf("tp_stash returns %d\n",doack);
65236396Ssklower		ENDDEBUG
65336396Ssklower
65436396Ssklower		if(doack) {
65536396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
65636396Ssklower			tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
65736396Ssklower		} else
65836396Ssklower			tp_ctimeout( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
65936396Ssklower
66036396Ssklower		IFDEBUG(D_DATA)
66136396Ssklower			printf("after stash calling sbwakeup\n");
66236396Ssklower		ENDDEBUG
66336396Ssklower	}
66436396Ssklower;
66536396Ssklower
66636396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
66736396Ssklower	( $P.tp_class == TP_CLASS_0 )
66836396Ssklower	{
66936396Ssklower		tp0_stash($P, $E);
67036396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
67136396Ssklower
67236396Ssklower		IFDEBUG(D_DATA)
67336396Ssklower			printf("after stash calling sbwakeup\n");
67436396Ssklower		ENDDEBUG
67536396Ssklower	}
67636396Ssklower;
67736396Ssklower
67836396Ssklower/* TP4 only */
67936396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
68036396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
68136396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
68236396Ssklower	{
68336396Ssklower		int doack; /* tells if we must ack immediately */
68436396Ssklower
68536396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
68636396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
68736396Ssklower
68836396Ssklower		doack = tp_stash($P, $E);
68936396Ssklower		IFDEBUG(D_DATA)
69036396Ssklower			printf("tp_stash returns %d\n",doack);
69136396Ssklower		ENDDEBUG
69236396Ssklower
69336396Ssklower		if(doack)
69436396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
69536396Ssklower		else
69636396Ssklower			tp_ctimeout_MIN( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
69736396Ssklower
69836396Ssklower		IFDEBUG(D_DATA)
69936396Ssklower			printf("after stash calling sbwakeup\n");
70036396Ssklower		ENDDEBUG
70136396Ssklower	}
70236396Ssklower;
70336396Ssklower
70436396Ssklower/* Not in window  - we must ack under certain circumstances, namely
70536396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given)
70636396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^.
70736396Ssklower * and
70836396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
70936396Ssklower *
71036396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73)
71136396Ssklower * We just always ack.
71236396Ssklower */
71336396Ssklower/* TP4 only */
71436396SsklowerSAME 			<== 	[ TP_OPEN, TP_AKWAIT ]							DT_TPDU
71536396Ssklower	DEFAULT /* Not in window */
71636396Ssklower	{
71736396Ssklower		IFTRACE(D_DATA)
71836396Ssklower			tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
71936396Ssklower				$$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
72036396Ssklower		ENDTRACE
72136396Ssklower		IncStat(ts_dt_niw);
72236396Ssklower		m_freem($$.e_data);
72336396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
72436396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
72536396Ssklower	}
72636396Ssklower;
72736396Ssklower
72836396Ssklower/* TP4 only */
72936396SsklowerTP_OPEN			<==		TP_AKWAIT										AK_TPDU
73036396Ssklower	DEFAULT
73136396Ssklower	{
73237469Ssklower		if ($P.tp_ucddata) {
73337469Ssklower			m_freem($P.tp_ucddata);
73437469Ssklower			$P.tp_ucddata = 0;
73536396Ssklower		}
73636396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
73736396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
73836396Ssklower
73936396Ssklower		tp_getoptions($P);
74036396Ssklower		soisconnected($P.tp_sock);
74136396Ssklower		IFTRACE(D_CONN)
74236396Ssklower			struct socket *so = $P.tp_sock;
74336396Ssklower			tptrace(TPPTmisc,
74436396Ssklower			"called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
74536396Ssklower				so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
74636396Ssklower			tptrace(TPPTmisc,
74736396Ssklower			"called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
74836396Ssklower				so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
74936396Ssklower		ENDTRACE
75036396Ssklower
75136396Ssklower		tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
75236396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
75336396Ssklower	}
75436396Ssklower;
75536396Ssklower
75636396Ssklower/* TP4 only */
75736396SsklowerTP_OPEN 		<== 	[ TP_OPEN, TP_AKWAIT ]						XPD_TPDU
75847281Ssklower	($P.tp_Xrcvnxt == $$.e_seq)
75936396Ssklower	{
76036396Ssklower		if( $P.tp_state == TP_AKWAIT ) {
76137469Ssklower			if ($P.tp_ucddata) {
76237469Ssklower				m_freem($P.tp_ucddata);
76337469Ssklower				$P.tp_ucddata = 0;
76436396Ssklower			}
76536396Ssklower			tp_cuntimeout($P.tp_refp, TM_retrans);
76636396Ssklower			tp_getoptions($P);
76736396Ssklower			soisconnected($P.tp_sock);
76836396Ssklower			tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
76936396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
77036396Ssklower		}
77136396Ssklower		IFTRACE(D_XPD)
77236396Ssklower		tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
77336396Ssklower				$P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
77436396Ssklower		ENDTRACE
77536396Ssklower
77637469Ssklower		$P.tp_sock->so_state |= SS_RCVATMARK;
77747281Ssklower		$$.e_data->m_flags |= M_EOR;
77837469Ssklower		sbinsertoob(&$P.tp_Xrcv, $$.e_data);
77936396Ssklower		IFDEBUG(D_XPD)
78036396Ssklower			dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
78136396Ssklower		ENDDEBUG
78236396Ssklower		tp_indicate(T_XDATA, $P, 0);
78336396Ssklower		sbwakeup( &$P.tp_Xrcv );
78436396Ssklower
78536396Ssklower		(void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
78636396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
78736396Ssklower	}
78836396Ssklower;
78936396Ssklower
79036396Ssklower/* TP4 only */
79136396SsklowerSAME			<==		TP_OPEN 									T_USR_Xrcvd
79236396Ssklower	DEFAULT
79336396Ssklower	{
79436396Ssklower		if( $P.tp_Xrcv.sb_cc == 0 ) {
79536396Ssklower			/* kludge for select(): */
79637469Ssklower			/* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
79736396Ssklower		}
79836396Ssklower	}
79936396Ssklower	/* OLD WAY:
80036396Ssklower	 * Ack only after the user receives the XPD.  This is better for
80136396Ssklower	 * users that use one XPD right after another.
80236396Ssklower	 * Acking right away (the NEW WAY, see the prev. transition) is
80336396Ssklower	 * better for occasional * XPD, when the receiving user doesn't
80436396Ssklower	 * want to read the XPD immediately (which is session's behavior).
80536396Ssklower	 *
80636396Ssklower		int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
80736396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
80836396Ssklower		return error;
80936396Ssklower	*/
81036396Ssklower;
81136396Ssklower
81236396Ssklower/* NOTE: presently if the user doesn't read the connection data
81336396Ssklower * before and expedited data PDU comes in, the connection data will
81436396Ssklower * be dropped. This is a bug.  To avoid it, we need somewhere else
81536396Ssklower * to put the connection data.
81636396Ssklower * On the other hand, we need not to have it sitting around forever.
81736396Ssklower * This is a problem with the idea of trying to accommodate
81836396Ssklower * data on connect w/ a passive-open user interface.
81936396Ssklower */
82036396Ssklower/* TP4 only */
82136396Ssklower
82236396SsklowerSAME	 		<== 	[ TP_AKWAIT, TP_OPEN ] 							XPD_TPDU
82336396Ssklower	DEFAULT /* not in window or cdt==0 */
82436396Ssklower	{
82536396Ssklower		IFTRACE(D_XPD)
82636396Ssklower			tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
82736396Ssklower				$P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
82836396Ssklower		ENDTRACE
82936396Ssklower		if( $P.tp_Xrcvnxt != $$.e_seq )
83036396Ssklower			IncStat(ts_xpd_niw);
83136396Ssklower		if( $P.tp_Xrcv.sb_cc ) {
83236396Ssklower			/* might as well kick 'em again */
83336396Ssklower			tp_indicate(T_XDATA, $P, 0);
83436396Ssklower			IncStat(ts_xpd_dup);
83536396Ssklower		}
83636396Ssklower		m_freem($$.e_data);
83736396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
83836396Ssklower		/* don't send an xack because the xak gives "last one received", not
83936396Ssklower		 * "next one i expect" (dumb)
84036396Ssklower		 */
84136396Ssklower	}
84236396Ssklower;
84336396Ssklower
84436396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
84536396Ssklower * to detach all its "children"
84636396Ssklower * Also (CRSENT) when user kills a job that's doing a connect()
84736396Ssklower */
84836396SsklowerTP_REFWAIT		<== 	TP_CRSENT 										T_DETACH
84936396Ssklower	($P.tp_class == TP_CLASS_0)
85036396Ssklower	{
85136396Ssklower		struct socket *so = $P.tp_sock;
85236396Ssklower
85336396Ssklower		/* detach from parent socket so it can finish closing */
85436396Ssklower		if (so->so_head) {
85536396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
85636396Ssklower				panic("tp: T_DETACH");
85736396Ssklower			so->so_head = 0;
85836396Ssklower		}
85936396Ssklower		tp_soisdisconnecting($P.tp_sock);
86036396Ssklower		tp_netcmd( $P, CONN_CLOSE);
86136396Ssklower		tp_soisdisconnected($P);
86236396Ssklower	}
86336396Ssklower;
86436396Ssklower
86536396Ssklower/* TP4 only */
86638841SsklowerTP_CLOSING		<== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ]	T_DETACH
86736396Ssklower	DEFAULT
86836396Ssklower	{
86936396Ssklower		struct socket *so = $P.tp_sock;
87037469Ssklower		struct mbuf *data = MNULL;
87136396Ssklower
87236396Ssklower		/* detach from parent socket so it can finish closing */
87336396Ssklower		if (so->so_head) {
87436396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
87536396Ssklower				panic("tp: T_DETACH");
87636396Ssklower			so->so_head = 0;
87736396Ssklower		}
87836396Ssklower		if ($P.tp_state != TP_CLOSING) {
87936396Ssklower			tp_soisdisconnecting($P.tp_sock);
88037469Ssklower			data = MCPY($P.tp_ucddata, M_NOWAIT);
88137469Ssklower			(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
88236396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
88336396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
88436396Ssklower		}
88536396Ssklower	}
88636396Ssklower;
88736396Ssklower
88836396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT ]		 	  			T_DISC_req
88936396Ssklower	( $P.tp_class == TP_CLASS_0 )
89036396Ssklower	{
89136396Ssklower		tp_soisdisconnecting($P.tp_sock);
89236396Ssklower		tp_netcmd( $P, CONN_CLOSE);
89336396Ssklower		tp_soisdisconnected($P);
89436396Ssklower	}
89536396Ssklower;
89636396Ssklower
89736396Ssklower/* TP4 only */
89838841SsklowerTP_CLOSING		<==	[ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
89936396Ssklower	DEFAULT
90036396Ssklower	{
90137469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
90236396Ssklower
90336396Ssklower		if($P.tp_state == TP_OPEN) {
90436396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
90536396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
90636396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
90736396Ssklower		}
90837469Ssklower		if (data) {
90936396Ssklower			IFDEBUG(D_CONN)
91037469Ssklower				printf("T_DISC_req.trans tp_ucddata 0x%x\n",
91137469Ssklower					$P.tp_ucddata);
91237469Ssklower				dump_mbuf(data, "ucddata @ T_DISC_req");
91336396Ssklower			ENDDEBUG
91436396Ssklower		}
91536396Ssklower		tp_soisdisconnecting($P.tp_sock);
91636396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
91736396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
91836396Ssklower
91936396Ssklower		if( trick_hc )
92036396Ssklower			return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
92136396Ssklower	}
92236396Ssklower;
92336396Ssklower
92436396Ssklower/* TP4 only */
92536396SsklowerSAME			<==		TP_AKWAIT									TM_retrans
92636396Ssklower	( $P.tp_retrans > 0 )
92736396Ssklower	{
92836396Ssklower		int error;
92937469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
93036396Ssklower
93136396Ssklower		IncStat(ts_retrans_cc);
93236396Ssklower		$P.tp_retrans --;
93339921Ssklower		$P.tp_cong_win = 1;
93439921Ssklower		$P.tp_ackrcvd = 0;
93539921Ssklower
93637469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
93736396Ssklower			$P.tp_sock->so_error = error;
93836396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
93936396Ssklower	}
94036396Ssklower;
94136396Ssklower
94236396Ssklower/* TP4 only */
94336396SsklowerTP_CLOSING		<==		TP_AKWAIT									TM_retrans
94436396Ssklower	DEFAULT  /* out of time */
94536396Ssklower	{
94636396Ssklower		IncStat(ts_conn_gaveup);
94736396Ssklower		tp_soisdisconnecting($P.tp_sock);
94836396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
94936396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
95036396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
95136396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
95236396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
95336396Ssklower	}
95436396Ssklower;
95536396Ssklower
95636396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does,
95736396Ssklower * if transmissions are going on.
95836396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack
95936396Ssklower * turnaround)
96036396Ssklower */
96136396Ssklower/* TP4 only */
96236396SsklowerTP_CLOSING 		<==		TP_OPEN		   [ TM_inact, TM_retrans, TM_data_retrans ]
96336396Ssklower	DEFAULT
96436396Ssklower	{
96536396Ssklower		tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
96636396Ssklower		tp_cuntimeout($P.tp_refp, TM_inact);
96736396Ssklower		tp_cuntimeout($P.tp_refp, TM_sendack);
96836396Ssklower
96936396Ssklower		IncStat(ts_conn_gaveup);
97036396Ssklower		tp_soisdisconnecting($P.tp_sock);
97136396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
97236396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
97336396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
97436396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
97536396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
97636396Ssklower	}
97736396Ssklower;
97836396Ssklower
97936396Ssklower/* TP4 only */
98036396SsklowerSAME			<==		TP_OPEN										TM_retrans
98136396Ssklower	( $P.tp_retrans > 0 )
98236396Ssklower	{
98339921Ssklower		$P.tp_cong_win = 1;
98439921Ssklower		$P.tp_ackrcvd = 0;
98536396Ssklower		/* resume XPD */
98636396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
98737469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
98836396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
98936396Ssklower			 * that doesn't matter
99036396Ssklower			 */
99136396Ssklower
99236396Ssklower			IFTRACE(D_XPD)
99336396Ssklower				tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna",
99436396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
99536396Ssklower					$P.tp_snduna);
99636396Ssklower			ENDTRACE
99736396Ssklower			IFDEBUG(D_XPD)
99836396Ssklower				dump_mbuf(m, "XPD retrans emitting M");
99936396Ssklower			ENDDEBUG
100036396Ssklower			IncStat(ts_retrans_xpd);
100136396Ssklower			$P.tp_retrans --;
100236396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
100336396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
100436396Ssklower		}
100536396Ssklower	}
100636396Ssklower;
100736396Ssklower
100836396Ssklower/* TP4 only */
100936396SsklowerSAME 			<==		TP_OPEN									TM_data_retrans
101036396Ssklower	( $$.e_retrans > 0 )
101136396Ssklower	{
101236396Ssklower		register 	SeqNum			low, lowsave = 0;
101336396Ssklower		register	struct tp_rtc 	*r = $P.tp_snduna_rtc;
101436396Ssklower		register	struct mbuf 	*m;
101536396Ssklower		register	SeqNum			high = $$.e_high;
101636396Ssklower
101739921Ssklower		low = $P.tp_snduna;
101839921Ssklower		lowsave = high = low;
101939921Ssklower
102039921Ssklower		tp_euntimeout_lss($P.tp_refp, TM_data_retrans,
102139921Ssklower			SEQ_ADD($P, $P.tp_sndhiwat, 1));
102239921Ssklower		$P.tp_retrans_hiwat = $P.tp_sndhiwat;
102339921Ssklower
102436396Ssklower		if (($P.tp_rx_strat & TPRX_EACH) == 0)
102536396Ssklower			high = (high>low)?low:high;
102636396Ssklower
102736396Ssklower		if( $P.tp_rx_strat & TPRX_USE_CW ) {
102836396Ssklower			register int i;
102936396Ssklower
103036396Ssklower			$P.tp_cong_win = 1;
103139921Ssklower			$P.tp_ackrcvd = 0;
103239921Ssklower			i = SEQ_ADD($P, low, $P.tp_cong_win);
103336396Ssklower
103439921Ssklower			high = SEQ_MIN($P, high, $P.tp_sndhiwat);
103539921Ssklower
103636396Ssklower		}
103736396Ssklower
103836396Ssklower		while( SEQ_LEQ($P, low, high) ){
103936396Ssklower			if ( r == (struct tp_rtc *)0 ){
104036396Ssklower				IFDEBUG(D_RTC)
104136396Ssklower					printf( "tp: retrans rtc list is GONE!\n");
104236396Ssklower				ENDDEBUG
104336396Ssklower				break;
104436396Ssklower			}
104536396Ssklower			if ( r->tprt_seq == low ){
104636396Ssklower				if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL)
104736396Ssklower					break;
104836396Ssklower				(void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m);
104936396Ssklower				IncStat(ts_retrans_dt);
105036396Ssklower				SEQ_INC($P, low );
105136396Ssklower			}
105236396Ssklower			r = r->tprt_next;
105336396Ssklower		}
105439921Ssklower/* CE_BIT
105536396Ssklower		if ( SEQ_LEQ($P, lowsave, high) ){
105639921Ssklower*/
105736396Ssklower			$$.e_retrans --;
105836396Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
105936396Ssklower					(caddr_t)high, $$.e_retrans,
106036396Ssklower					($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks);
106139921Ssklower/* CE_BIT
106236396Ssklower		}
106339921Ssklower*/
106436396Ssklower	}
106536396Ssklower;
106636396Ssklower
106736396Ssklower/* TP4 only */
106836396SsklowerSAME	 		<==		TP_CLOSING									TM_retrans
106936396Ssklower	(	$P.tp_retrans > 0 )
107036396Ssklower	{
107136396Ssklower		$P.tp_retrans --;
107236396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
107336396Ssklower		IncStat(ts_retrans_dr);
107436396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
107536396Ssklower	}
107636396Ssklower;
107736396Ssklower
107836396Ssklower/* TP4 only */
107936396SsklowerTP_REFWAIT 		<==		TP_CLOSING									TM_retrans
108036396Ssklower	DEFAULT	/* no more retrans - gave up */
108136396Ssklower	{
108236396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
108336396Ssklower		$P.tp_refp->tpr_state = REF_FROZEN;
108436396Ssklower		tp_recycle_tsuffix( $P );
108536396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks);
108636396Ssklower	}
108736396Ssklower;
108836396Ssklower
108936396Ssklower/*
109036396Ssklower * The resources are kept around until the ref timer goes off.
109136396Ssklower * The suffices are wiped out sooner so they can be reused right away.
109236396Ssklower */
109336396Ssklower/* applicable in TP4, TP0 */
109436396SsklowerTP_CLOSED 		<==		TP_REFWAIT 									TM_reference
109536396Ssklower	DEFAULT
109636396Ssklower	{
109736396Ssklower		tp_freeref($P.tp_refp);
109836396Ssklower		tp_detach($P);
109936396Ssklower	}
110036396Ssklower;
110136396Ssklower
110236396Ssklower/* applicable in TP4, TP0 */
110336396Ssklower/* A duplicate CR from connectionless network layer can't happen */
110436396SsklowerSAME 			<== 	TP_OPEN 							[ CR_TPDU, CC_TPDU ]
110536396Ssklower	DEFAULT
110636396Ssklower	{
110736396Ssklower		if( $P.tp_class != TP_CLASS_0) {
110836396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
110936396Ssklower			if ( $E.ev_number == CC_TPDU )
111036396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
111136396Ssklower		}
111236396Ssklower		/* ignore it if class 0 - state tables are blank for this */
111336396Ssklower	}
111436396Ssklower;
111536396Ssklower
111636396Ssklower/* applicable in TP4, TP0 */
111736396SsklowerSAME			<== 	TP_OPEN									T_DATA_req
111836396Ssklower	DEFAULT
111936396Ssklower	{
112036396Ssklower		IFTRACE(D_DATA)
112136396Ssklower			tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb",
112236396Ssklower				$P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P);
112336396Ssklower		ENDTRACE
112436396Ssklower
112536396Ssklower		tp_send($P);
112636396Ssklower	}
112736396Ssklower;
112836396Ssklower
112936396Ssklower/* TP4 only */
113036396SsklowerSAME			<==		TP_OPEN										T_XPD_req
113136396Ssklower	DEFAULT
113236396Ssklower		/* T_XPD_req was issued by sosend iff xpd socket buf was empty
113336396Ssklower		 * at time of sosend(),
113436396Ssklower		 * AND (which means) there were no unacknowledged XPD tpdus outstanding!
113536396Ssklower		 */
113636396Ssklower	{
113736396Ssklower		int error = 0;
113836396Ssklower
113936396Ssklower		/* resume XPD */
114036396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
114137469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
114236396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
114336396Ssklower			 * that doesn't matter
114436396Ssklower			 */
114536396Ssklower
114636396Ssklower			IFTRACE(D_XPD)
114736396Ssklower				tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna",
114836396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
114936396Ssklower					$P.tp_snduna);
115036396Ssklower			ENDTRACE
115136396Ssklower			IFDEBUG(D_XPD)
115236396Ssklower				printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
115336396Ssklower				dump_mbuf(m, "XPD req emitting M");
115436396Ssklower			ENDDEBUG
115536396Ssklower			error =
115636396Ssklower				tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
115736396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
115836396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
115936396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
116036396Ssklower		}
116136396Ssklower		if(trick_hc)
116236396Ssklower			return error;
116336396Ssklower	}
116436396Ssklower;
116536396Ssklower
116636396Ssklower/* TP4, faked ack in TP0 when cons send completes */
116736396SsklowerSAME 			<==		TP_OPEN 									AK_TPDU
116836396Ssklower	( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
116936396Ssklower
117036396Ssklower	/* tp_goodack == true means
117136396Ssklower	 * EITHER it actually acked something heretofore unacknowledged
117236396Ssklower	 * OR no news but the credit should be processed.
117336396Ssklower	 */
117436396Ssklower	{
117536396Ssklower		IFDEBUG(D_ACKRECV)
117636396Ssklower			printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
117736396Ssklower		ENDDEBUG
117836396Ssklower		if( $P.tp_class != TP_CLASS_0) {
117936396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
118036396Ssklower			tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq);
118136396Ssklower		}
118236396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
118336396Ssklower
118439921Ssklower		if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat &&
118539921Ssklower			$P.tp_snduna <= $P.tp_retrans_hiwat) {
118639921Ssklower
118739921Ssklower			register    struct mbuf     *m;
118839921Ssklower			/* extern      struct mbuf     *m_copy(); */
118939921Ssklower			register    struct tp_rtc   *r;
119039921Ssklower			SeqNum      high, retrans, low_save;
119139921Ssklower
119239921Ssklower			high = SEQ_MIN($P, SEQ_ADD($P, $P.tp_snduna,
119339921Ssklower					MIN($P.tp_cong_win, $P.tp_fcredit)) - 1,
119439921Ssklower					$P.tp_sndhiwat);
119539921Ssklower			low_save = retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1),
119639921Ssklower					$P.tp_snduna);
119739921Ssklower			for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) {
119839921Ssklower
119939921Ssklower				for (r = $P.tp_snduna_rtc; r; r = r->tprt_next){
120039921Ssklower					if ( r->tprt_seq == retrans ){
120139921Ssklower						if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))
120239921Ssklower								== MNULL)
120339921Ssklower							break;
120439921Ssklower						(void) tp_emit(DT_TPDU_type, $P, retrans,
120539921Ssklower							r->tprt_eot, m);
120639921Ssklower						$P.tp_last_retrans = retrans;
120739921Ssklower						IncStat(ts_retrans_dt);
120839921Ssklower						break;
120939921Ssklower					}
121039921Ssklower				}
121139921Ssklower				if ( r == (struct tp_rtc *)0 ){
121239921Ssklower					IFDEBUG(D_RTC)
121339921Ssklower						printf( "tp: retrans rtc list is GONE!\n");
121439921Ssklower					ENDDEBUG
121539921Ssklower					break;
121639921Ssklower				}
121739921Ssklower			}
121839921Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)low_save,
121939921Ssklower					(caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks);
122039921Ssklower			if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat)
122139921Ssklower				tp_send($P);
122239921Ssklower		}
122339921Ssklower		else {
122439921Ssklower			tp_send($P);
122539921Ssklower		}
122636396Ssklower		IFDEBUG(D_ACKRECV)
122736396Ssklower			printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat);
122836396Ssklower		ENDDEBUG
122936396Ssklower	}
123036396Ssklower;
123136396Ssklower
123236396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
123336396SsklowerSAME			<==		TP_OPEN 			 						 AK_TPDU
123436396Ssklower	DEFAULT
123536396Ssklower	{
123636396Ssklower		IFTRACE(D_ACKRECV)
123736396Ssklower			tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
123836396Ssklower				$$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
123936396Ssklower		ENDTRACE
124036396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
124136396Ssklower
124236396Ssklower			if ( !$$.e_fcc_present ) {
124336396Ssklower				/* send ACK with FCC */
124436396Ssklower				IncStat( ts_ackreason[_ACK_FCC_] );
124536396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
124636396Ssklower			}
124736396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
124836396Ssklower		}
124936396Ssklower	}
125036396Ssklower;
125136396Ssklower
125236396Ssklower/* NBS(47) */
125336396Ssklower	/* goes in at *** */
125436396Ssklower		/* just so happens that this is never true now, because we allow
125536396Ssklower		 * only 1 packet in the queue at once (this could be changed)
125636396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
125736396Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
125836396Ssklower
125936396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
126036396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
126136396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
126236396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
126336396Ssklower		}
126436396Ssklower		 */
126536396Ssklower	/* end of the above hack */
126636396Ssklower
126736396Ssklower/* TP4 only */
126842944SsklowerSAME			<== 	TP_OPEN										XAK_TPDU
126936396Ssklower	( tp_goodXack($P, $$.e_seq) )
127036396Ssklower	/* tp_goodXack checks for good ack, removes the correct
127136396Ssklower	 * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
127236396Ssklower	 * also updates tp_Xuna
127336396Ssklower	 */
127436396Ssklower	{
127536396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
127636396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
127736396Ssklower
127836396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
127936396Ssklower
128036396Ssklower		/* resume normal data */
128136396Ssklower		tp_send($P);
128236396Ssklower	}
128336396Ssklower;
128436396Ssklower
128542944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
128642944SsklowerSAME			<==		TP_OPEN 			 						XAK_TPDU
128742944Ssklower	DEFAULT
128842944Ssklower	{
128942944Ssklower		IFTRACE(D_ACKRECV)
129042944Ssklower			tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
129142944Ssklower		ENDTRACE
129242944Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
129342944Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
129442944Ssklower		}
129542944Ssklower	}
129642944Ssklower;
129742944Ssklower
129836396Ssklower/* TP4 only */
129936396SsklowerSAME			<==		TP_OPEN 								TM_sendack
130036396Ssklower	DEFAULT
130136396Ssklower	{
130236396Ssklower		IFTRACE(D_TIMER)
130336396Ssklower			tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
130436396Ssklower			$P.tp_sent_lcdt, 0);
130536396Ssklower		ENDTRACE
130636396Ssklower		IncPStat($P, tps_n_TMsendack);
130736396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
130836396Ssklower	}
130936396Ssklower;
131036396Ssklower
131136396Ssklower/* TP0 only */
131236396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
131336396Ssklower	($P.tp_class == TP_CLASS_0)
131447281Ssklower	{
131547281Ssklower		if (sbspace(&$P.tp_sock->so_rcv) > 0)
131647281Ssklower			tp0_openflow($P);
131747281Ssklower	}
131836396Ssklower;
131936396Ssklower
132036396Ssklower/* TP4 only */
132136396Ssklower		/* If old credit was zero,
132236396Ssklower		 * we'd better inform other side that we now have space
132336396Ssklower		 * But this is not enough.  Sender might not yet have
132436396Ssklower		 * seen an ack with cdt 0 but it might still think the
132536396Ssklower		 * window is closed, so it's going to wait.
132636396Ssklower		 * Best to send an ack each time.
132736396Ssklower		 * Strictly speaking, this ought to be a function of the
132836396Ssklower		 * general ack strategy.
132936396Ssklower		 */
133036396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
133136396Ssklower	DEFAULT
133236396Ssklower	{
133336396Ssklower		if( trick_hc ) {
133436396Ssklower			IncStat(ts_ackreason[_ACK_USRRCV_]);
133539921Ssklower
133639921Ssklower			/* send an ACK only if there's new information */
133739921Ssklower			LOCAL_CREDIT( $P );
133839921Ssklower			if (($P.tp_rcvnxt != $P.tp_sent_rcvnxt) ||
133939921Ssklower				($P.tp_lcredit != $P.tp_sent_lcdt))
134039921Ssklower
134139921Ssklower				return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
134236396Ssklower		}
134336396Ssklower	}
134436396Ssklower;
134536396Ssklower
134636396Ssklower/* applicable in TP4, TP0 */
134736396SsklowerSAME			<==		TP_REFWAIT 				[ T_USR_rcvd, T_USR_Xrcvd ]
134836396Ssklower	DEFAULT
134936396Ssklower	/* This happens if other end sent a DR when  the user was waiting
135036396Ssklower	 * on a receive.
135136396Ssklower	 * Processing the DR includes putting us in REFWAIT state.
135236396Ssklower	 */
135336396Ssklower	{
135436396Ssklower		if(trick_hc)
135536396Ssklower		return ECONNABORTED;
135636396Ssklower	}
135736396Ssklower;
135836396Ssklower
135936396Ssklower/* TP0 only */
136036396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT, TP_LISTENING ] 	T_NETRESET
136136396Ssklower	( $P.tp_class != TP_CLASS_4 )
136236396Ssklower		/* 0 or (4 and 0) */
136336396Ssklower		/* in OPEN class will be 0 or 4 but not both */
136436396Ssklower		/* in CRSENT or LISTENING it could be in negotiation, hence both */
136536396Ssklower		/* Actually, this shouldn't ever happen in LISTENING */
136636396Ssklower	{
136736396Ssklower		ASSERT( $P.tp_state != TP_LISTENING );
136836396Ssklower		tp_indicate(T_DISCONNECT, $P, ECONNRESET);
136936396Ssklower		tp_soisdisconnected($P);
137036396Ssklower	}
137136396Ssklower;
137236396Ssklower
137336396Ssklower/* TP4: ignore resets */
137436396SsklowerSAME		<==		[ TP_OPEN, TP_CRSENT, TP_AKWAIT,
137536396Ssklower						TP_CLOSING, TP_LISTENING ] 				T_NETRESET
137636396Ssklower	DEFAULT
137736396Ssklower	NULLACTION
137836396Ssklower;
137936396Ssklower
138036396Ssklower/* applicable in TP4, TP0 */
138136396SsklowerSAME			<==		[ TP_CLOSED, TP_REFWAIT ]				T_NETRESET
138236396Ssklower	DEFAULT
138336396Ssklower	NULLACTION
138436396Ssklower;
138536396Ssklower
138636396Ssklower/* C'EST TOUT */
1387