xref: /csrg-svn/sys/netiso/tp.trans (revision 50904)
150849Ssklower/* NEW */
249268Sbostic/*-
349268Sbostic * Copyright (c) 1991 The Regents of the University of California.
449268Sbostic * All rights reserved.
549268Sbostic *
649268Sbostic * %sccs.include.redist.c%
749268Sbostic *
8*50904Ssklower *	@(#)tp.trans	7.11 (Berkeley) 08/28/91
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*50904Ssklower/* @(#)tp.trans	7.11 (Berkeley) 08/28/91 */
6336396Ssklower#include "param.h"
6436396Ssklower#include "socket.h"
6536396Ssklower#include "socketvar.h"
6636396Ssklower#include "protosw.h"
6736396Ssklower#include "mbuf.h"
6836396Ssklower#include "time.h"
6936396Ssklower#include "errno.h"
7036396Ssklower#include "../netiso/tp_param.h"
7136396Ssklower#include "../netiso/tp_stat.h"
7236396Ssklower#include "../netiso/tp_pcb.h"
7336396Ssklower#include "../netiso/tp_tpdu.h"
7436396Ssklower#include "../netiso/argo_debug.h"
7536396Ssklower#include "../netiso/tp_trace.h"
7636396Ssklower#include "../netiso/iso_errno.h"
7736396Ssklower#include "../netiso/tp_seq.h"
7836396Ssklower#include "../netiso/cons.h"
7936396Ssklower
8036396Ssklower#define DRIVERTRACE TPPTdriver
8137469Ssklower#define sbwakeup(sb)	sowakeup(p->tp_sock, sb);
8237469Ssklower#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
8336396Ssklower
8436396Ssklowerstatic 	trick_hc = 1;
8536396Ssklower
8636396Ssklowerint 	tp_emit(),
8736396Ssklower		tp_goodack(),				tp_goodXack(),
8836396Ssklower		tp_stash()
8936396Ssklower;
9036396Ssklowervoid	tp_indicate(),				tp_getoptions(),
9136396Ssklower		tp_soisdisconnecting(), 	tp_soisdisconnected(),
9236396Ssklower		tp_recycle_tsuffix(),
9336396Ssklower		tp_etimeout(),				tp_euntimeout(),
9436396Ssklower		tp_euntimeout_lss(),		tp_ctimeout(),
9536396Ssklower		tp_cuntimeout(),			tp_ctimeout_MIN(),
9636396Ssklower		tp_freeref(),				tp_detach(),
9736396Ssklower		tp0_stash(), 				tp0_send(),
9836396Ssklower		tp_netcmd(),				tp_send()
9936396Ssklower;
10036396Ssklower
10136396Ssklowertypedef  struct tp_pcb tpcb_struct;
10236396Ssklower
10336396Ssklower
10436396Ssklower}
10536396Ssklower
10636396Ssklower*PCB    tpcb_struct 	SYNONYM  P
10736396Ssklower
10836396Ssklower*STATES
10936396Ssklower
11036396SsklowerTP_CLOSED
11136396SsklowerTP_CRSENT
11236396SsklowerTP_AKWAIT
11336396SsklowerTP_OPEN
11436396SsklowerTP_CLOSING
11536396SsklowerTP_REFWAIT
11636396SsklowerTP_LISTENING	/* Local to this implementation */
11738841SsklowerTP_CONFIRMING	/* Local to this implementation */
11836396Ssklower
11936396Ssklower*EVENTS		{ struct timeval e_time; } 		SYNONYM  E
12036396Ssklower
12136396Ssklower /*
12236396Ssklower  * C (typically cancelled) timers  -
12336396Ssklower  *
12436396Ssklower  * let these be the first ones so for the sake of convenience
12536396Ssklower  * their values are 0--> n-1
12636396Ssklower  * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!!
12736396Ssklower  */
12836396Ssklower TM_inact
12936396Ssklower TM_retrans
13036396Ssklower				/* TM_retrans is used for all
13136396Ssklower				 * simple retransmissions - CR,CC,XPD,DR
13236396Ssklower				 */
13336396Ssklower
13436396Ssklower TM_sendack
13536396Ssklower				/* TM_sendack does dual duty - keepalive AND sendack.
13636396Ssklower				 * It's set w/ keepalive-ticks every time an ack is sent.
13736396Ssklower				 * (this is done in (void) tp_emit() ).
13836396Ssklower				 * It's cancelled and reset whenever a DT
13936396Ssklower				 * arrives and it doesn't require immediate acking.
14036396Ssklower				 * Note that in this case it's set w/ the minimum of
14136396Ssklower				 * its prev value and the sendack-ticks value so the
14236396Ssklower				 * purpose of the keepalive is preserved.
14336396Ssklower				 */
14436396Ssklower TM_notused
14536396Ssklower
14636396Ssklower /*
14736396Ssklower  * E (typically expired) timers - these may be in any order.
14836396Ssklower  * These cause procedures to be executed directly; may not
14936396Ssklower  * cause an 'event' as we know them here.
15036396Ssklower  */
15136396Ssklower TM_reference		{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15236396Ssklower TM_data_retrans	{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15336396Ssklower
15436396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that
15536396Ssklower * for all tpdu types that can take e_data and e_datalen, these
15636396Ssklower * fields fall in the same place in the event structure, that is,
15736396Ssklower * e_data is the first field and e_datalen is the 2nd field.
15836396Ssklower */
15936396Ssklower
16036396Ssklower ER_TPDU  	 	{
16136396Ssklower				  u_char		e_reason;
16236396Ssklower				}
16336396Ssklower CR_TPDU  	 	{ struct mbuf 	*e_data;	/* first field */
16436396Ssklower				  int 			e_datalen; /* 2nd field */
16536396Ssklower				  u_int			e_cdt;
16636396Ssklower				}
16736396Ssklower DR_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
16836396Ssklower				  int 			e_datalen; /* 2nd field */
16936396Ssklower				  u_short		e_sref;
17036396Ssklower				  u_char		e_reason;
17136396Ssklower				}
17236396Ssklower DC_TPDU
17336396Ssklower CC_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
17436396Ssklower				  int 			e_datalen; /* 2nd field */
17536396Ssklower				  u_short		e_sref;
17636396Ssklower				  u_int			e_cdt;
17736396Ssklower				}
17836396Ssklower AK_TPDU		{ u_int			e_cdt;
17936396Ssklower				  SeqNum 	 	e_seq;
18036396Ssklower				  SeqNum 	 	e_subseq;
18136396Ssklower				  u_char 	 	e_fcc_present;
18236396Ssklower				}
18336396Ssklower DT_TPDU		{ struct mbuf	*e_data; 	/* first field */
18436396Ssklower				  int 			e_datalen; /* 2nd field */
18536396Ssklower				  u_int 		e_eot;
18636396Ssklower				  SeqNum		e_seq;
18736396Ssklower				}
18836396Ssklower XPD_TPDU		{ struct mbuf 	*e_data;	/* first field */
18936396Ssklower				  int 			e_datalen; 	/* 2nd field */
19036396Ssklower				  SeqNum 		e_seq;
19136396Ssklower				}
19236396Ssklower XAK_TPDU		{ SeqNum 		e_seq;		}
19336396Ssklower
19436396Ssklower T_CONN_req
19536396Ssklower T_DISC_req		{ u_char		e_reason; 	}
19636396Ssklower T_LISTEN_req
19736396Ssklower T_DATA_req
19836396Ssklower T_XPD_req
19936396Ssklower T_USR_rcvd
20036396Ssklower T_USR_Xrcvd
20136396Ssklower T_DETACH
20236396Ssklower T_NETRESET
20338841Ssklower T_ACPT_req
20436396Ssklower
20536396Ssklower
20636396Ssklower*TRANSITIONS
20736396Ssklower
20836396Ssklower
20936396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */
21036396SsklowerSAME			<==			TP_AKWAIT			[ CC_TPDU, DC_TPDU, XAK_TPDU ]
21136396Ssklower	DEFAULT
21236396Ssklower	NULLACTION
21336396Ssklower;
21436396Ssklower
21536396Ssklower
21636396Ssklower/* applicable in TP4, TP0 */
21736396SsklowerSAME			<==			TP_REFWAIT								DR_TPDU
21836396Ssklower	( $$.e_sref !=  0 )
21936396Ssklower	{
22036396Ssklower		(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
22136396Ssklower	}
22236396Ssklower;
22336396Ssklower
22436396Ssklower/* applicable in TP4, TP0 */
22536396SsklowerSAME			<==			TP_REFWAIT			[ CR_TPDU, CC_TPDU, DT_TPDU,
22636396Ssklower					DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ]
22736396Ssklower	DEFAULT
22836396Ssklower	{
22936396Ssklower#		ifdef TP_DEBUG
23036396Ssklower		if( $E.ev_number != AK_TPDU )
23136396Ssklower			printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number);
23236396Ssklower#		endif TP_DEBUG
23336396Ssklower	}
23436396Ssklower;
23536396Ssklower
23636396Ssklower/* applicable in TP4, TP0 */
23736396SsklowerSAME			<==			TP_REFWAIT				[ T_DETACH, T_DISC_req ]
23836396Ssklower	DEFAULT
23936396Ssklower	NULLACTION
24036396Ssklower;
24136396Ssklower
24236396Ssklower/* applicable in TP4, TP0 */
24336396SsklowerSAME			<==			TP_CRSENT								 AK_TPDU
24436396Ssklower	($P.tp_class == TP_CLASS_0)
24536396Ssklower	{
24636396Ssklower		/* oh, man is this grotesque or what? */
24736396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq,  $$.e_subseq);
24836396Ssklower		/* but it's necessary because this pseudo-ack may happen
24936396Ssklower		 * before the CC arrives, but we HAVE to adjust the
25036396Ssklower		 * snduna as a result of the ack, WHENEVER it arrives
25136396Ssklower		 */
25236396Ssklower	}
25336396Ssklower;
25436396Ssklower
25536396Ssklower/* applicable in TP4, TP0 */
25636396SsklowerSAME			<==			TP_CRSENT
25736396Ssklower					[ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU,  XAK_TPDU ]
25836396Ssklower	DEFAULT
25936396Ssklower	NULLACTION
26036396Ssklower;
26136396Ssklower
26236396Ssklower/* applicable in TP4, TP0 */
26336396SsklowerSAME			<==			TP_CLOSED					[ DT_TPDU, XPD_TPDU,
26436396Ssklower										ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
26536396Ssklower	DEFAULT
26636396Ssklower	NULLACTION
26736396Ssklower;
26836396Ssklower
26936396Ssklower/* TP_CLOSING doesn't exist in TP 0 */
27036396SsklowerSAME 			<== 		TP_CLOSING
27136396Ssklower					[ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ]
27236396Ssklower	DEFAULT
27336396Ssklower	NULLACTION
27436396Ssklower;
27536396Ssklower
27636396Ssklower
27736396Ssklower/* DC_TPDU doesn't exist in TP 0 */
27836396SsklowerSAME			<==			TP_OPEN						  DC_TPDU
27936396Ssklower	DEFAULT
28036396Ssklower	NULLACTION
28136396Ssklower;
28236396Ssklower
28336396Ssklower/* applicable in TP4, TP0 */
28436396SsklowerSAME			<==		 	TP_LISTENING  [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU,
28536396Ssklower										 ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
28636396Ssklower	DEFAULT
28736396Ssklower	NULLACTION
28836396Ssklower;
28936396Ssklower
29036396Ssklower/* applicable in TP4, TP0 */
29136396SsklowerTP_LISTENING	<==			TP_CLOSED  							T_LISTEN_req
29236396Ssklower	DEFAULT
29336396Ssklower	NULLACTION
29436396Ssklower;
29536396Ssklower
29636396Ssklower/* applicable in TP4, TP0 */
29736396SsklowerTP_CLOSED  		<== 		[ TP_LISTENING, TP_CLOSED ] 			T_DETACH
29836396Ssklower	DEFAULT
29936396Ssklower	{
30036396Ssklower		tp_detach($P);
30136396Ssklower	}
30236396Ssklower;
30336396Ssklower
30438841SsklowerTP_CONFIRMING	<==		 TP_LISTENING  								CR_TPDU
30538841Ssklower	( $P.tp_class == TP_CLASS_0)
30636396Ssklower	{
30736396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */
30836396Ssklower	}
30936396Ssklower;
31036396Ssklower
31138841SsklowerTP_CONFIRMING		<==		 TP_LISTENING  							CR_TPDU
31238841Ssklower	DEFAULT
31336396Ssklower	{
31436396Ssklower		IFTRACE(D_CONN)
31536396Ssklower			tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
31636396Ssklower		ENDTRACE
31736396Ssklower		IFDEBUG(D_CONN)
31836396Ssklower			printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
31936396Ssklower		ENDDEBUG
32036396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers */
32138841Ssklower		$P.tp_fcredit = $$.e_cdt;
32236396Ssklower
32336396Ssklower		if ($$.e_datalen > 0) {
32436396Ssklower			/* n/a for class 0 */
32536396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0);
32636396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
32736396Ssklower			$$.e_data = MNULL;
32836396Ssklower		}
32938841Ssklower	}
33038841Ssklower;
33138841Ssklower
33238841SsklowerTP_OPEN		<==		 TP_CONFIRMING  								T_ACPT_req
33338841Ssklower	( $P.tp_class == TP_CLASS_0 )
33438841Ssklower	{
33538841Ssklower		IncStat(ts_tp0_conn);
33638841Ssklower		IFTRACE(D_CONN)
33738841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
33838841Ssklower		ENDTRACE
33938841Ssklower		IFDEBUG(D_CONN)
34038841Ssklower			printf("Confirming connection: $P" );
34138841Ssklower		ENDDEBUG
34238841Ssklower		soisconnected($P.tp_sock);
34338841Ssklower		(void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
34438841Ssklower		$P.tp_fcredit = 1;
34538841Ssklower	}
34638841Ssklower;
34738841Ssklower
34838841SsklowerTP_AKWAIT		<==		 TP_CONFIRMING  							T_ACPT_req
34938841Ssklower	(tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
35038841Ssklower	{
35138841Ssklower		IncStat(ts_tp4_conn); /* even though not quite open */
35238841Ssklower		IFTRACE(D_CONN)
35338841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
35438841Ssklower		ENDTRACE
35538841Ssklower		IFDEBUG(D_CONN)
35638841Ssklower			printf("Confirming connection: $P" );
35738841Ssklower		ENDDEBUG
35838841Ssklower		soisconnecting($P.tp_sock);
35947281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
36038841Ssklower			$P.tp_cong_win = $P.tp_fcredit;
36136396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
36236396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
36338841Ssklower	}
36436396Ssklower;
36536396Ssklower
36636396Ssklower/* TP4 only */
36738841SsklowerTP_CLOSED		<==		 TP_CONFIRMING								T_ACPT_req
36836396Ssklower	DEFAULT /* emit failed */
36936396Ssklower	{
37036396Ssklower		register struct tp_ref *r = $P.tp_refp;
37136396Ssklower
37236396Ssklower		IFDEBUG(D_CONN)
37336396Ssklower			printf("event: CR_TPDU emit CC failed done " );
37436396Ssklower		ENDDEBUG
37538841Ssklower		soisdisconnected($P.tp_sock);
37636396Ssklower		tp_recycle_tsuffix( $P );
37736396Ssklower		tp_freeref(r);
37836396Ssklower		tp_detach($P);
37936396Ssklower	}
38036396Ssklower;
38136396Ssklower
38236396Ssklower/* applicable in TP4, TP0 */
38336396SsklowerTP_CRSENT		<==		TP_CLOSED								T_CONN_req
38436396Ssklower	DEFAULT
38536396Ssklower	{
38636396Ssklower		int error;
38736396Ssklower		struct mbuf *data = MNULL;
38836396Ssklower
38936396Ssklower		IFTRACE(D_CONN)
39037469Ssklower			tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
39137469Ssklower			$P.tp_ucddata, 0, 0);
39236396Ssklower		ENDTRACE
39337469Ssklower		data =  MCPY($P.tp_ucddata, M_WAIT);
39437469Ssklower		if (data) {
39536396Ssklower			IFDEBUG(D_CONN)
39636396Ssklower				printf("T_CONN_req.trans m_copy cc 0x%x\n",
39737469Ssklower					$P.tp_ucddata);
39837469Ssklower				dump_mbuf(data, "sosnd @ T_CONN_req");
39936396Ssklower			ENDDEBUG
40036396Ssklower		}
40136396Ssklower
40236396Ssklower		if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
40336396Ssklower			return error; /* driver WON'T change state; will return error */
40436396Ssklower
40536396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers */
40636396Ssklower		if($P.tp_class != TP_CLASS_0) {
40736396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
40836396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
40936396Ssklower		}
41036396Ssklower	}
41136396Ssklower;
41236396Ssklower
41336396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
41436396SsklowerTP_REFWAIT 		<==		[ TP_CRSENT, TP_AKWAIT, TP_OPEN ] 			DR_TPDU
41536396Ssklower	DEFAULT
41636396Ssklower	{
41748739Ssklower		sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
41848739Ssklower		if ($$.e_datalen > 0) {
41936396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
42036396Ssklower			$$.e_data = MNULL;
42136396Ssklower		}
42248739Ssklower		tp_indicate(T_DISCONNECT, $P, 0);
42336396Ssklower		tp_soisdisconnected($P);
42436396Ssklower		if ($P.tp_class != TP_CLASS_0) {
42536396Ssklower			if ($P.tp_state == TP_OPEN ) {
42636396Ssklower				tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
42736396Ssklower				tp_cuntimeout($P.tp_refp, TM_retrans);
42836396Ssklower				tp_cuntimeout($P.tp_refp, TM_inact);
42936396Ssklower				tp_cuntimeout($P.tp_refp, TM_sendack);
43036396Ssklower			}
43136396Ssklower			tp_cuntimeout($P.tp_refp, TM_retrans);
43236396Ssklower			if( $$.e_sref !=  0 )
43336396Ssklower				(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
43436396Ssklower		}
43536396Ssklower	}
43636396Ssklower;
43736396Ssklower
43836396SsklowerSAME 			<==		TP_CLOSED 									DR_TPDU
43936396Ssklower	DEFAULT
44036396Ssklower	{
44136396Ssklower		if( $$.e_sref != 0 )
44236396Ssklower			(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
44336396Ssklower		/* reference timer already set - reset it to be safe (???) */
44436396Ssklower		tp_euntimeout($P.tp_refp, TM_reference); /* all */
44536396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks);
44636396Ssklower	}
44736396Ssklower;
44836396Ssklower
44936396Ssklower/* NBS(34) */
45036396SsklowerTP_REFWAIT 		<==  	TP_CRSENT  									ER_TPDU
45136396Ssklower	DEFAULT
45236396Ssklower	{
45336396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
45448739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
45536396Ssklower		tp_soisdisconnected($P);
45636396Ssklower	}
45736396Ssklower;
45836396Ssklower
45936396Ssklower/* NBS(27) */
46036396SsklowerTP_REFWAIT		<==		TP_CLOSING									DR_TPDU
46136396Ssklower	DEFAULT
46236396Ssklower	{
46336396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
46436396Ssklower		tp_soisdisconnected($P);
46536396Ssklower	}
46636396Ssklower;
46736396Ssklower/* these two transitions are the same but can't be combined because xebec
46836396Ssklower * can't handle the use of $$.e_reason if they're combined
46936396Ssklower */
47036396Ssklower/* NBS(27) */
47136396SsklowerTP_REFWAIT		<==		TP_CLOSING									ER_TPDU
47236396Ssklower	DEFAULT
47336396Ssklower	{
47448739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
47536396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
47636396Ssklower		tp_soisdisconnected($P);
47736396Ssklower	}
47836396Ssklower;
47936396Ssklower/* NBS(27) */
48036396SsklowerTP_REFWAIT		<==		TP_CLOSING									DC_TPDU
48136396Ssklower	DEFAULT
48236396Ssklower	{
48336396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
48436396Ssklower		tp_soisdisconnected($P);
48536396Ssklower	}
48636396Ssklower;
48736396Ssklower
48836396Ssklower/* NBS(21) */
48936396SsklowerSAME 			<== 	TP_CLOSED 						[ CC_TPDU, CR_TPDU ]
49036396Ssklower	DEFAULT
49136396Ssklower	{	/* don't ask me why we have to do this - spec says so */
49236396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
49336396Ssklower		/* don't bother with retransmissions of the DR */
49436396Ssklower	}
49536396Ssklower;
49636396Ssklower
49736396Ssklower/* NBS(34) */
49836396SsklowerTP_REFWAIT 		<== 	TP_OPEN  				 					ER_TPDU
49936396Ssklower	($P.tp_class == TP_CLASS_0)
50036396Ssklower	{
50136396Ssklower		tp_soisdisconnecting($P.tp_sock);
50248739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
50336396Ssklower		tp_soisdisconnected($P);
50436396Ssklower		tp_netcmd( $P, CONN_CLOSE );
50536396Ssklower	}
50636396Ssklower;
50736396Ssklower
50836396SsklowerTP_CLOSING 		<== 	[ TP_AKWAIT, TP_OPEN ]  					ER_TPDU
50936396Ssklower	DEFAULT
51036396Ssklower	{
51136396Ssklower		if ($P.tp_state == TP_OPEN) {
51236396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
51336396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
51436396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
51536396Ssklower		}
51636396Ssklower		tp_soisdisconnecting($P.tp_sock);
51748739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
51836396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
51936396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
52036396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
52136396Ssklower	}
52236396Ssklower;
52336396Ssklower/* NBS(6) */
52436396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
52536396Ssklower	($P.tp_class == TP_CLASS_0)
52636396Ssklower	{
52736396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
52836396Ssklower		IncStat(ts_tp0_conn);
52936396Ssklower		$P.tp_fcredit = 1;
53036396Ssklower		soisconnected($P.tp_sock);
53136396Ssklower	}
53236396Ssklower;
53336396Ssklower
53436396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
53536396Ssklower	DEFAULT
53636396Ssklower	{
53736396Ssklower		IFDEBUG(D_CONN)
53836396Ssklower			printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
53936396Ssklower				(int)$P.tp_flags);
54036396Ssklower		ENDDEBUG
54136396Ssklower		IncStat(ts_tp4_conn);
54236396Ssklower		$P.tp_fref = $$.e_sref;
54336396Ssklower		$P.tp_fcredit = $$.e_cdt;
54439921Ssklower		$P.tp_ackrcvd = 0;
54547281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
54636396Ssklower			$P.tp_cong_win = $$.e_cdt;
54736396Ssklower		tp_getoptions($P);
54836396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
54937469Ssklower		if ($P.tp_ucddata) {
55036396Ssklower			IFDEBUG(D_CONN)
55137469Ssklower				printf("dropping user connect data cc 0x%x\n",
55237469Ssklower					$P.tp_ucddata->m_len);
55336396Ssklower			ENDDEBUG
55437469Ssklower			m_freem($P.tp_ucddata);
55537469Ssklower			$P.tp_ucddata = 0;
55636396Ssklower		}
55736396Ssklower		soisconnected($P.tp_sock);
55836396Ssklower		if ($$.e_datalen > 0) {
55936396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
56036396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
56136396Ssklower			$$.e_data = MNULL;
56236396Ssklower		}
56336396Ssklower
56436396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
56536396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
56636396Ssklower	}
56736396Ssklower;
56836396Ssklower
56936396Ssklower/* TP4 only */
57036396SsklowerSAME			<==		TP_CRSENT									TM_retrans
57136396Ssklower	(	$P.tp_retrans > 0 )
57236396Ssklower	{
57336396Ssklower		struct mbuf *data = MNULL;
57436396Ssklower		int error;
57536396Ssklower
57636396Ssklower		IncStat(ts_retrans_cr);
57739921Ssklower		$P.tp_cong_win = 1;
57839921Ssklower		$P.tp_ackrcvd = 0;
57937469Ssklower		data = MCPY($P.tp_ucddata, M_NOWAIT);
58037469Ssklower		if($P.tp_ucddata) {
58136396Ssklower			IFDEBUG(D_CONN)
58237469Ssklower				printf("TM_retrans.trans m_copy cc 0x%x\n", data);
58337469Ssklower				dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
58436396Ssklower			ENDDEBUG
58536396Ssklower			if( data == MNULL )
58636396Ssklower				return ENOBUFS;
58736396Ssklower		}
58836396Ssklower
58936396Ssklower		$P.tp_retrans --;
59036396Ssklower		if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
59136396Ssklower			$P.tp_sock->so_error = error;
59236396Ssklower		}
59336396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
59436396Ssklower	}
59536396Ssklower;
59636396Ssklower
59736396Ssklower/* TP4 only  */
59836396SsklowerTP_REFWAIT		<==		TP_CRSENT									TM_retrans
59936396Ssklower	DEFAULT /* no more CR retransmissions */
60036396Ssklower	{
60136396Ssklower		IncStat(ts_conn_gaveup);
60236396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
60336396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
60436396Ssklower		tp_soisdisconnected($P);
60536396Ssklower	}
60636396Ssklower;
60736396Ssklower
60836396Ssklower/* TP4 only */
60936396SsklowerSAME 			<==	 TP_AKWAIT											CR_TPDU
61036396Ssklower	DEFAULT
61136396Ssklower	/* duplicate CR (which doesn't really exist in the context of
61236396Ssklower	 * a connectionless network layer)
61336396Ssklower	 * Doesn't occur in class 0.
61436396Ssklower	 */
61536396Ssklower	{
61636396Ssklower		int error;
61737469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
61836396Ssklower
61937469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
62036396Ssklower			$P.tp_sock->so_error = error;
62136396Ssklower		}
62236396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
62336396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
62436396Ssklower	}
62536396Ssklower;
62636396Ssklower
62736396Ssklower/* TP4 only */
62836396SsklowerTP_OPEN			<==		TP_AKWAIT 										DT_TPDU
62936396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
63036396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
63136396Ssklower	{
63236396Ssklower		int doack;
63336396Ssklower
63437469Ssklower		/*
63537469Ssklower		 * Get rid of any confirm or connect data, so that if we
63637469Ssklower		 * crash or close, it isn't thought of as disconnect data.
63737469Ssklower		 */
63837469Ssklower		if ($P.tp_ucddata) {
63937469Ssklower			m_freem($P.tp_ucddata);
64037469Ssklower			$P.tp_ucddata = 0;
64136396Ssklower		}
64236396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
64336396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
64436396Ssklower		soisconnected($P.tp_sock);
64536396Ssklower		tp_getoptions($P);
64636396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
64736396Ssklower
64836396Ssklower		/* see also next 2 transitions, if you make any changes */
64936396Ssklower
65036396Ssklower		doack = tp_stash($P, $E);
65136396Ssklower		IFDEBUG(D_DATA)
65236396Ssklower			printf("tp_stash returns %d\n",doack);
65336396Ssklower		ENDDEBUG
65436396Ssklower
65536396Ssklower		if(doack) {
65636396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
65736396Ssklower			tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
65836396Ssklower		} else
65936396Ssklower			tp_ctimeout( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
66036396Ssklower
66136396Ssklower		IFDEBUG(D_DATA)
66236396Ssklower			printf("after stash calling sbwakeup\n");
66336396Ssklower		ENDDEBUG
66436396Ssklower	}
66536396Ssklower;
66636396Ssklower
66736396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
66836396Ssklower	( $P.tp_class == TP_CLASS_0 )
66936396Ssklower	{
67036396Ssklower		tp0_stash($P, $E);
67136396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
67236396Ssklower
67336396Ssklower		IFDEBUG(D_DATA)
67436396Ssklower			printf("after stash calling sbwakeup\n");
67536396Ssklower		ENDDEBUG
67636396Ssklower	}
67736396Ssklower;
67836396Ssklower
67936396Ssklower/* TP4 only */
68036396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
68136396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
68236396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
68336396Ssklower	{
68436396Ssklower		int doack; /* tells if we must ack immediately */
68536396Ssklower
68636396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
68736396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
68836396Ssklower
68936396Ssklower		doack = tp_stash($P, $E);
69036396Ssklower		IFDEBUG(D_DATA)
69136396Ssklower			printf("tp_stash returns %d\n",doack);
69236396Ssklower		ENDDEBUG
69336396Ssklower
69436396Ssklower		if(doack)
69536396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
69636396Ssklower		else
69736396Ssklower			tp_ctimeout_MIN( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
69836396Ssklower
69936396Ssklower		IFDEBUG(D_DATA)
70036396Ssklower			printf("after stash calling sbwakeup\n");
70136396Ssklower		ENDDEBUG
70236396Ssklower	}
70336396Ssklower;
70436396Ssklower
70536396Ssklower/* Not in window  - we must ack under certain circumstances, namely
70636396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given)
70736396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^.
70836396Ssklower * and
70936396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
71036396Ssklower *
71136396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73)
71236396Ssklower * We just always ack.
71336396Ssklower */
71436396Ssklower/* TP4 only */
71536396SsklowerSAME 			<== 	[ TP_OPEN, TP_AKWAIT ]							DT_TPDU
71636396Ssklower	DEFAULT /* Not in window */
71736396Ssklower	{
71836396Ssklower		IFTRACE(D_DATA)
71936396Ssklower			tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
72036396Ssklower				$$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
72136396Ssklower		ENDTRACE
72236396Ssklower		IncStat(ts_dt_niw);
72336396Ssklower		m_freem($$.e_data);
72436396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
72536396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
72636396Ssklower	}
72736396Ssklower;
72836396Ssklower
72936396Ssklower/* TP4 only */
73036396SsklowerTP_OPEN			<==		TP_AKWAIT										AK_TPDU
73136396Ssklower	DEFAULT
73236396Ssklower	{
73337469Ssklower		if ($P.tp_ucddata) {
73437469Ssklower			m_freem($P.tp_ucddata);
73537469Ssklower			$P.tp_ucddata = 0;
73636396Ssklower		}
73736396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
73836396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
73936396Ssklower
74036396Ssklower		tp_getoptions($P);
74136396Ssklower		soisconnected($P.tp_sock);
74236396Ssklower		IFTRACE(D_CONN)
74336396Ssklower			struct socket *so = $P.tp_sock;
74436396Ssklower			tptrace(TPPTmisc,
74536396Ssklower			"called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
74636396Ssklower				so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
74736396Ssklower			tptrace(TPPTmisc,
74836396Ssklower			"called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
74936396Ssklower				so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
75036396Ssklower		ENDTRACE
75136396Ssklower
75236396Ssklower		tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
75336396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
75436396Ssklower	}
75536396Ssklower;
75636396Ssklower
75736396Ssklower/* TP4 only */
75836396SsklowerTP_OPEN 		<== 	[ TP_OPEN, TP_AKWAIT ]						XPD_TPDU
75947281Ssklower	($P.tp_Xrcvnxt == $$.e_seq)
76036396Ssklower	{
76136396Ssklower		if( $P.tp_state == TP_AKWAIT ) {
76237469Ssklower			if ($P.tp_ucddata) {
76337469Ssklower				m_freem($P.tp_ucddata);
76437469Ssklower				$P.tp_ucddata = 0;
76536396Ssklower			}
76636396Ssklower			tp_cuntimeout($P.tp_refp, TM_retrans);
76736396Ssklower			tp_getoptions($P);
76836396Ssklower			soisconnected($P.tp_sock);
76936396Ssklower			tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
77036396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
77136396Ssklower		}
77236396Ssklower		IFTRACE(D_XPD)
77336396Ssklower		tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
77436396Ssklower				$P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
77536396Ssklower		ENDTRACE
77636396Ssklower
77737469Ssklower		$P.tp_sock->so_state |= SS_RCVATMARK;
77847281Ssklower		$$.e_data->m_flags |= M_EOR;
77937469Ssklower		sbinsertoob(&$P.tp_Xrcv, $$.e_data);
78036396Ssklower		IFDEBUG(D_XPD)
78136396Ssklower			dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
78236396Ssklower		ENDDEBUG
78336396Ssklower		tp_indicate(T_XDATA, $P, 0);
78436396Ssklower		sbwakeup( &$P.tp_Xrcv );
78536396Ssklower
78636396Ssklower		(void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
78736396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
78836396Ssklower	}
78936396Ssklower;
79036396Ssklower
79136396Ssklower/* TP4 only */
79236396SsklowerSAME			<==		TP_OPEN 									T_USR_Xrcvd
79336396Ssklower	DEFAULT
79436396Ssklower	{
79536396Ssklower		if( $P.tp_Xrcv.sb_cc == 0 ) {
79636396Ssklower			/* kludge for select(): */
79737469Ssklower			/* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
79836396Ssklower		}
79936396Ssklower	}
80036396Ssklower	/* OLD WAY:
80136396Ssklower	 * Ack only after the user receives the XPD.  This is better for
80236396Ssklower	 * users that use one XPD right after another.
80336396Ssklower	 * Acking right away (the NEW WAY, see the prev. transition) is
80436396Ssklower	 * better for occasional * XPD, when the receiving user doesn't
80536396Ssklower	 * want to read the XPD immediately (which is session's behavior).
80636396Ssklower	 *
80736396Ssklower		int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
80836396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
80936396Ssklower		return error;
81036396Ssklower	*/
81136396Ssklower;
81236396Ssklower
81336396Ssklower/* NOTE: presently if the user doesn't read the connection data
81436396Ssklower * before and expedited data PDU comes in, the connection data will
81536396Ssklower * be dropped. This is a bug.  To avoid it, we need somewhere else
81636396Ssklower * to put the connection data.
81736396Ssklower * On the other hand, we need not to have it sitting around forever.
81836396Ssklower * This is a problem with the idea of trying to accommodate
81936396Ssklower * data on connect w/ a passive-open user interface.
82036396Ssklower */
82136396Ssklower/* TP4 only */
82236396Ssklower
82336396SsklowerSAME	 		<== 	[ TP_AKWAIT, TP_OPEN ] 							XPD_TPDU
82436396Ssklower	DEFAULT /* not in window or cdt==0 */
82536396Ssklower	{
82636396Ssklower		IFTRACE(D_XPD)
82736396Ssklower			tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
82836396Ssklower				$P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
82936396Ssklower		ENDTRACE
83036396Ssklower		if( $P.tp_Xrcvnxt != $$.e_seq )
83136396Ssklower			IncStat(ts_xpd_niw);
83236396Ssklower		if( $P.tp_Xrcv.sb_cc ) {
83336396Ssklower			/* might as well kick 'em again */
83436396Ssklower			tp_indicate(T_XDATA, $P, 0);
83536396Ssklower			IncStat(ts_xpd_dup);
83636396Ssklower		}
83736396Ssklower		m_freem($$.e_data);
83836396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
83936396Ssklower		/* don't send an xack because the xak gives "last one received", not
84036396Ssklower		 * "next one i expect" (dumb)
84136396Ssklower		 */
84236396Ssklower	}
84336396Ssklower;
84436396Ssklower
84536396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
84636396Ssklower * to detach all its "children"
84736396Ssklower * Also (CRSENT) when user kills a job that's doing a connect()
84836396Ssklower */
84936396SsklowerTP_REFWAIT		<== 	TP_CRSENT 										T_DETACH
85036396Ssklower	($P.tp_class == TP_CLASS_0)
85136396Ssklower	{
85236396Ssklower		struct socket *so = $P.tp_sock;
85336396Ssklower
85436396Ssklower		/* detach from parent socket so it can finish closing */
85536396Ssklower		if (so->so_head) {
85636396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
85736396Ssklower				panic("tp: T_DETACH");
85836396Ssklower			so->so_head = 0;
85936396Ssklower		}
86036396Ssklower		tp_soisdisconnecting($P.tp_sock);
86136396Ssklower		tp_netcmd( $P, CONN_CLOSE);
86236396Ssklower		tp_soisdisconnected($P);
86336396Ssklower	}
86436396Ssklower;
86536396Ssklower
86636396Ssklower/* TP4 only */
86738841SsklowerTP_CLOSING		<== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ]	T_DETACH
86836396Ssklower	DEFAULT
86936396Ssklower	{
87036396Ssklower		struct socket *so = $P.tp_sock;
87137469Ssklower		struct mbuf *data = MNULL;
87236396Ssklower
87336396Ssklower		/* detach from parent socket so it can finish closing */
87436396Ssklower		if (so->so_head) {
87536396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
87636396Ssklower				panic("tp: T_DETACH");
87736396Ssklower			so->so_head = 0;
87836396Ssklower		}
87936396Ssklower		if ($P.tp_state != TP_CLOSING) {
88036396Ssklower			tp_soisdisconnecting($P.tp_sock);
88137469Ssklower			data = MCPY($P.tp_ucddata, M_NOWAIT);
88237469Ssklower			(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
88336396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
88436396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
88536396Ssklower		}
88636396Ssklower	}
88736396Ssklower;
88836396Ssklower
88936396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT ]		 	  			T_DISC_req
89036396Ssklower	( $P.tp_class == TP_CLASS_0 )
89136396Ssklower	{
89236396Ssklower		tp_soisdisconnecting($P.tp_sock);
89336396Ssklower		tp_netcmd( $P, CONN_CLOSE);
89436396Ssklower		tp_soisdisconnected($P);
89536396Ssklower	}
89636396Ssklower;
89736396Ssklower
89836396Ssklower/* TP4 only */
89938841SsklowerTP_CLOSING		<==	[ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
90036396Ssklower	DEFAULT
90136396Ssklower	{
90237469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
90336396Ssklower
90436396Ssklower		if($P.tp_state == TP_OPEN) {
90536396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
90636396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
90736396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
90836396Ssklower		}
90937469Ssklower		if (data) {
91036396Ssklower			IFDEBUG(D_CONN)
91137469Ssklower				printf("T_DISC_req.trans tp_ucddata 0x%x\n",
91237469Ssklower					$P.tp_ucddata);
91337469Ssklower				dump_mbuf(data, "ucddata @ T_DISC_req");
91436396Ssklower			ENDDEBUG
91536396Ssklower		}
91636396Ssklower		tp_soisdisconnecting($P.tp_sock);
91736396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
91836396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
91936396Ssklower
92036396Ssklower		if( trick_hc )
92136396Ssklower			return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
92236396Ssklower	}
92336396Ssklower;
92436396Ssklower
92536396Ssklower/* TP4 only */
92636396SsklowerSAME			<==		TP_AKWAIT									TM_retrans
92736396Ssklower	( $P.tp_retrans > 0 )
92836396Ssklower	{
92936396Ssklower		int error;
93037469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
93136396Ssklower
93236396Ssklower		IncStat(ts_retrans_cc);
93336396Ssklower		$P.tp_retrans --;
93439921Ssklower		$P.tp_cong_win = 1;
93539921Ssklower		$P.tp_ackrcvd = 0;
93639921Ssklower
93737469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
93836396Ssklower			$P.tp_sock->so_error = error;
93936396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
94036396Ssklower	}
94136396Ssklower;
94236396Ssklower
94336396Ssklower/* TP4 only */
94436396SsklowerTP_CLOSING		<==		TP_AKWAIT									TM_retrans
94536396Ssklower	DEFAULT  /* out of time */
94636396Ssklower	{
94736396Ssklower		IncStat(ts_conn_gaveup);
94836396Ssklower		tp_soisdisconnecting($P.tp_sock);
94936396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
95036396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
95136396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
95236396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
95336396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
95436396Ssklower	}
95536396Ssklower;
95636396Ssklower
95736396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does,
95836396Ssklower * if transmissions are going on.
95936396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack
96036396Ssklower * turnaround)
96136396Ssklower */
96236396Ssklower/* TP4 only */
96336396SsklowerTP_CLOSING 		<==		TP_OPEN		   [ TM_inact, TM_retrans, TM_data_retrans ]
96436396Ssklower	DEFAULT
96536396Ssklower	{
96636396Ssklower		tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
96736396Ssklower		tp_cuntimeout($P.tp_refp, TM_inact);
96836396Ssklower		tp_cuntimeout($P.tp_refp, TM_sendack);
96936396Ssklower
97036396Ssklower		IncStat(ts_conn_gaveup);
97136396Ssklower		tp_soisdisconnecting($P.tp_sock);
97236396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
97336396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
97436396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
97536396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
97636396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
97736396Ssklower	}
97836396Ssklower;
97936396Ssklower
98036396Ssklower/* TP4 only */
98136396SsklowerSAME			<==		TP_OPEN										TM_retrans
98236396Ssklower	( $P.tp_retrans > 0 )
98336396Ssklower	{
98439921Ssklower		$P.tp_cong_win = 1;
98539921Ssklower		$P.tp_ackrcvd = 0;
98636396Ssklower		/* resume XPD */
98736396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
98837469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
98936396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
99036396Ssklower			 * that doesn't matter
99136396Ssklower			 */
99236396Ssklower
99336396Ssklower			IFTRACE(D_XPD)
99436396Ssklower				tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna",
99536396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
99636396Ssklower					$P.tp_snduna);
99736396Ssklower			ENDTRACE
99836396Ssklower			IFDEBUG(D_XPD)
99936396Ssklower				dump_mbuf(m, "XPD retrans emitting M");
100036396Ssklower			ENDDEBUG
100136396Ssklower			IncStat(ts_retrans_xpd);
100236396Ssklower			$P.tp_retrans --;
100336396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
100436396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
100536396Ssklower		}
100636396Ssklower	}
100736396Ssklower;
100836396Ssklower
100936396Ssklower/* TP4 only */
101036396SsklowerSAME 			<==		TP_OPEN									TM_data_retrans
101136396Ssklower	( $$.e_retrans > 0 )
101236396Ssklower	{
101336396Ssklower		register 	SeqNum			low, lowsave = 0;
1014*50904Ssklower		register	struct mbuf 	*m, *n = $P.tp_sock->so_snd.sb_mb;
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
1038*50904Ssklower		while (SEQ_LEQ($P, low, high)) {
1039*50904Ssklower			if (n) {
1040*50904Ssklower				if ((m = m_copy(n, 0, M_COPYALL))== MNULL)
104136396Ssklower					break;
1042*50904Ssklower				(void) tp_emit(DT_TPDU_type, $P,
1043*50904Ssklower					low, (m->m_flags & M_EOR) != 0, m);
104436396Ssklower				IncStat(ts_retrans_dt);
104536396Ssklower				SEQ_INC($P, low );
104636396Ssklower			}
1047*50904Ssklower			n = n->m_nextpkt;
104836396Ssklower		}
104939921Ssklower/* CE_BIT
105036396Ssklower		if ( SEQ_LEQ($P, lowsave, high) ){
105139921Ssklower*/
105236396Ssklower			$$.e_retrans --;
105336396Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
105436396Ssklower					(caddr_t)high, $$.e_retrans,
105536396Ssklower					($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks);
105639921Ssklower/* CE_BIT
105736396Ssklower		}
105839921Ssklower*/
105936396Ssklower	}
106036396Ssklower;
106136396Ssklower
106236396Ssklower/* TP4 only */
106336396SsklowerSAME	 		<==		TP_CLOSING									TM_retrans
106436396Ssklower	(	$P.tp_retrans > 0 )
106536396Ssklower	{
106636396Ssklower		$P.tp_retrans --;
106736396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
106836396Ssklower		IncStat(ts_retrans_dr);
106936396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
107036396Ssklower	}
107136396Ssklower;
107236396Ssklower
107336396Ssklower/* TP4 only */
107436396SsklowerTP_REFWAIT 		<==		TP_CLOSING									TM_retrans
107536396Ssklower	DEFAULT	/* no more retrans - gave up */
107636396Ssklower	{
107736396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
107836396Ssklower		$P.tp_refp->tpr_state = REF_FROZEN;
107936396Ssklower		tp_recycle_tsuffix( $P );
108036396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks);
108136396Ssklower	}
108236396Ssklower;
108336396Ssklower
108436396Ssklower/*
108536396Ssklower * The resources are kept around until the ref timer goes off.
108636396Ssklower * The suffices are wiped out sooner so they can be reused right away.
108736396Ssklower */
108836396Ssklower/* applicable in TP4, TP0 */
108936396SsklowerTP_CLOSED 		<==		TP_REFWAIT 									TM_reference
109036396Ssklower	DEFAULT
109136396Ssklower	{
109236396Ssklower		tp_freeref($P.tp_refp);
109336396Ssklower		tp_detach($P);
109436396Ssklower	}
109536396Ssklower;
109636396Ssklower
109736396Ssklower/* applicable in TP4, TP0 */
109836396Ssklower/* A duplicate CR from connectionless network layer can't happen */
109936396SsklowerSAME 			<== 	TP_OPEN 							[ CR_TPDU, CC_TPDU ]
110036396Ssklower	DEFAULT
110136396Ssklower	{
110236396Ssklower		if( $P.tp_class != TP_CLASS_0) {
110336396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
110436396Ssklower			if ( $E.ev_number == CC_TPDU )
110536396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
110636396Ssklower		}
110736396Ssklower		/* ignore it if class 0 - state tables are blank for this */
110836396Ssklower	}
110936396Ssklower;
111036396Ssklower
111136396Ssklower/* applicable in TP4, TP0 */
111236396SsklowerSAME			<== 	TP_OPEN									T_DATA_req
111336396Ssklower	DEFAULT
111436396Ssklower	{
111536396Ssklower		IFTRACE(D_DATA)
111636396Ssklower			tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb",
111736396Ssklower				$P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P);
111836396Ssklower		ENDTRACE
111936396Ssklower
112036396Ssklower		tp_send($P);
112136396Ssklower	}
112236396Ssklower;
112336396Ssklower
112436396Ssklower/* TP4 only */
112536396SsklowerSAME			<==		TP_OPEN										T_XPD_req
112636396Ssklower	DEFAULT
112736396Ssklower		/* T_XPD_req was issued by sosend iff xpd socket buf was empty
112836396Ssklower		 * at time of sosend(),
112936396Ssklower		 * AND (which means) there were no unacknowledged XPD tpdus outstanding!
113036396Ssklower		 */
113136396Ssklower	{
113236396Ssklower		int error = 0;
113336396Ssklower
113436396Ssklower		/* resume XPD */
113536396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
113637469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
113736396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
113836396Ssklower			 * that doesn't matter
113936396Ssklower			 */
114036396Ssklower
114136396Ssklower			IFTRACE(D_XPD)
114236396Ssklower				tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna",
114336396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
114436396Ssklower					$P.tp_snduna);
114536396Ssklower			ENDTRACE
114636396Ssklower			IFDEBUG(D_XPD)
114736396Ssklower				printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
114836396Ssklower				dump_mbuf(m, "XPD req emitting M");
114936396Ssklower			ENDDEBUG
115036396Ssklower			error =
115136396Ssklower				tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
115236396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
115336396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
115436396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
115536396Ssklower		}
115636396Ssklower		if(trick_hc)
115736396Ssklower			return error;
115836396Ssklower	}
115936396Ssklower;
116036396Ssklower
116136396Ssklower/* TP4, faked ack in TP0 when cons send completes */
116236396SsklowerSAME 			<==		TP_OPEN 									AK_TPDU
116336396Ssklower	( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
116436396Ssklower
116536396Ssklower	/* tp_goodack == true means
116636396Ssklower	 * EITHER it actually acked something heretofore unacknowledged
116736396Ssklower	 * OR no news but the credit should be processed.
116836396Ssklower	 */
116936396Ssklower	{
1170*50904Ssklower		struct sockbuf *sb = &$P.tp_sock->so_snd;
1171*50904Ssklower
117236396Ssklower		IFDEBUG(D_ACKRECV)
117336396Ssklower			printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
117436396Ssklower		ENDDEBUG
117536396Ssklower		if( $P.tp_class != TP_CLASS_0) {
117636396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
117736396Ssklower			tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq);
117836396Ssklower		}
1179*50904Ssklower		sbwakeup(sb);
118039921Ssklower		if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat &&
118139921Ssklower			$P.tp_snduna <= $P.tp_retrans_hiwat) {
118239921Ssklower
1183*50904Ssklower			register struct mbuf     *m, *n = sb->sb_mb;
1184*50904Ssklower			SeqNum		high, retrans, lowsave;
118539921Ssklower
118639921Ssklower			high = SEQ_MIN($P, SEQ_ADD($P, $P.tp_snduna,
118739921Ssklower					MIN($P.tp_cong_win, $P.tp_fcredit)) - 1,
118839921Ssklower					$P.tp_sndhiwat);
1189*50904Ssklower			retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1),
119039921Ssklower					$P.tp_snduna);
1191*50904Ssklower			for (lowsave = $P.tp_snduna;
1192*50904Ssklower					SEQ_LT($P, lowsave, retrans); SEQ_INC($P, lowsave))
1193*50904Ssklower				n = n->m_nextpkt;
119439921Ssklower			for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) {
1195*50904Ssklower				if (n == 0) {
119639921Ssklower					IFDEBUG(D_RTC)
1197*50904Ssklower						printf("tp: retrans list is GONE!\n");
119839921Ssklower					ENDDEBUG
119939921Ssklower					break;
1200*50904Ssklower				} else if (m = m_copy(n, 0, M_COPYALL)) {
1201*50904Ssklower					(void) tp_emit(DT_TPDU_type, $P, retrans,
1202*50904Ssklower						(m->m_flags & M_EOR) != 0, m);
1203*50904Ssklower					$P.tp_last_retrans = retrans;
1204*50904Ssklower					IncStat(ts_retrans_dt);
120539921Ssklower				}
1206*50904Ssklower				n = n->m_nextpkt;
120739921Ssklower			}
1208*50904Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
120939921Ssklower					(caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks);
121039921Ssklower			if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat)
121139921Ssklower				tp_send($P);
121239921Ssklower		}
121339921Ssklower		else {
121439921Ssklower			tp_send($P);
121539921Ssklower		}
121636396Ssklower		IFDEBUG(D_ACKRECV)
121736396Ssklower			printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat);
121836396Ssklower		ENDDEBUG
121936396Ssklower	}
122036396Ssklower;
122136396Ssklower
122236396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
122336396SsklowerSAME			<==		TP_OPEN 			 						 AK_TPDU
122436396Ssklower	DEFAULT
122536396Ssklower	{
122636396Ssklower		IFTRACE(D_ACKRECV)
122736396Ssklower			tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
122836396Ssklower				$$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
122936396Ssklower		ENDTRACE
123036396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
123136396Ssklower
123236396Ssklower			if ( !$$.e_fcc_present ) {
123336396Ssklower				/* send ACK with FCC */
123436396Ssklower				IncStat( ts_ackreason[_ACK_FCC_] );
123536396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
123636396Ssklower			}
123736396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
123836396Ssklower		}
123936396Ssklower	}
124036396Ssklower;
124136396Ssklower
124236396Ssklower/* NBS(47) */
124336396Ssklower	/* goes in at *** */
124436396Ssklower		/* just so happens that this is never true now, because we allow
124536396Ssklower		 * only 1 packet in the queue at once (this could be changed)
124636396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
124736396Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
124836396Ssklower
124936396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
125036396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
125136396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
125236396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
125336396Ssklower		}
125436396Ssklower		 */
125536396Ssklower	/* end of the above hack */
125636396Ssklower
125736396Ssklower/* TP4 only */
125842944SsklowerSAME			<== 	TP_OPEN										XAK_TPDU
125936396Ssklower	( tp_goodXack($P, $$.e_seq) )
126036396Ssklower	/* tp_goodXack checks for good ack, removes the correct
126136396Ssklower	 * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
126236396Ssklower	 * also updates tp_Xuna
126336396Ssklower	 */
126436396Ssklower	{
126536396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
126636396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
126736396Ssklower
126836396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
126936396Ssklower
127036396Ssklower		/* resume normal data */
127136396Ssklower		tp_send($P);
127236396Ssklower	}
127336396Ssklower;
127436396Ssklower
127542944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
127642944SsklowerSAME			<==		TP_OPEN 			 						XAK_TPDU
127742944Ssklower	DEFAULT
127842944Ssklower	{
127942944Ssklower		IFTRACE(D_ACKRECV)
128042944Ssklower			tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
128142944Ssklower		ENDTRACE
128242944Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
128342944Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
128442944Ssklower		}
128542944Ssklower	}
128642944Ssklower;
128742944Ssklower
128836396Ssklower/* TP4 only */
128936396SsklowerSAME			<==		TP_OPEN 								TM_sendack
129036396Ssklower	DEFAULT
129136396Ssklower	{
129236396Ssklower		IFTRACE(D_TIMER)
129336396Ssklower			tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
129436396Ssklower			$P.tp_sent_lcdt, 0);
129536396Ssklower		ENDTRACE
129636396Ssklower		IncPStat($P, tps_n_TMsendack);
129736396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
129836396Ssklower	}
129936396Ssklower;
130036396Ssklower
130136396Ssklower/* TP0 only */
130236396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
130336396Ssklower	($P.tp_class == TP_CLASS_0)
130447281Ssklower	{
130547281Ssklower		if (sbspace(&$P.tp_sock->so_rcv) > 0)
130647281Ssklower			tp0_openflow($P);
130747281Ssklower	}
130836396Ssklower;
130936396Ssklower
131036396Ssklower/* TP4 only */
131136396Ssklower		/* If old credit was zero,
131236396Ssklower		 * we'd better inform other side that we now have space
131336396Ssklower		 * But this is not enough.  Sender might not yet have
131436396Ssklower		 * seen an ack with cdt 0 but it might still think the
131536396Ssklower		 * window is closed, so it's going to wait.
131636396Ssklower		 * Best to send an ack each time.
131736396Ssklower		 * Strictly speaking, this ought to be a function of the
131836396Ssklower		 * general ack strategy.
131936396Ssklower		 */
132036396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
132136396Ssklower	DEFAULT
132236396Ssklower	{
132336396Ssklower		if( trick_hc ) {
132439921Ssklower
132550849Ssklower			LOCAL_CREDIT($P);
132650849Ssklower			/*
132750849Ssklower			 * If the window has is now closed or has only
132850849Ssklower			 * one slot left and an ACK will increase this (local
132950849Ssklower			 * credit is greater than or equal to 1) send an AK
133050849Ssklower			 * here. Otherwise, we will wait for more data or
133150849Ssklower			 * the ack timer to fire.
133250849Ssklower			 */
133350849Ssklower#define CREDIT_SMALL 1
133450849Ssklower			if (SEQ_GEQ($P, $P.tp_rcvnxt, $P.tp_sent_uwe) &&
133550849Ssklower				$P.tp_lcredit > CREDIT_SMALL) {
133650849Ssklower				IncStat(ts_ackreason[_ACK_USRRCV_]);
133739921Ssklower				return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
133850849Ssklower			}
133936396Ssklower		}
134036396Ssklower	}
134136396Ssklower;
134236396Ssklower
134336396Ssklower/* applicable in TP4, TP0 */
134436396SsklowerSAME			<==		TP_REFWAIT 				[ T_USR_rcvd, T_USR_Xrcvd ]
134536396Ssklower	DEFAULT
134636396Ssklower	/* This happens if other end sent a DR when  the user was waiting
134736396Ssklower	 * on a receive.
134836396Ssklower	 * Processing the DR includes putting us in REFWAIT state.
134936396Ssklower	 */
135036396Ssklower	{
135136396Ssklower		if(trick_hc)
135236396Ssklower		return ECONNABORTED;
135336396Ssklower	}
135436396Ssklower;
135536396Ssklower
135636396Ssklower/* TP0 only */
135736396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT, TP_LISTENING ] 	T_NETRESET
135836396Ssklower	( $P.tp_class != TP_CLASS_4 )
135936396Ssklower		/* 0 or (4 and 0) */
136036396Ssklower		/* in OPEN class will be 0 or 4 but not both */
136136396Ssklower		/* in CRSENT or LISTENING it could be in negotiation, hence both */
136236396Ssklower		/* Actually, this shouldn't ever happen in LISTENING */
136336396Ssklower	{
136436396Ssklower		ASSERT( $P.tp_state != TP_LISTENING );
136536396Ssklower		tp_indicate(T_DISCONNECT, $P, ECONNRESET);
136636396Ssklower		tp_soisdisconnected($P);
136736396Ssklower	}
136836396Ssklower;
136936396Ssklower
137036396Ssklower/* TP4: ignore resets */
137136396SsklowerSAME		<==		[ TP_OPEN, TP_CRSENT, TP_AKWAIT,
137236396Ssklower						TP_CLOSING, TP_LISTENING ] 				T_NETRESET
137336396Ssklower	DEFAULT
137436396Ssklower	NULLACTION
137536396Ssklower;
137636396Ssklower
137736396Ssklower/* applicable in TP4, TP0 */
137836396SsklowerSAME			<==		[ TP_CLOSED, TP_REFWAIT ]				T_NETRESET
137936396Ssklower	DEFAULT
138036396Ssklower	NULLACTION
138136396Ssklower;
138236396Ssklower
138336396Ssklower/* C'EST TOUT */
1384