xref: /csrg-svn/sys/netiso/tp.trans (revision 51024)
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*51024Ssklower *	@(#)tp.trans	7.13 (Berkeley) 09/06/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*51024Ssklower/* @(#)tp.trans	7.13 (Berkeley) 09/06/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
35850973Ssklower		tp_getoptions($P);
35938841Ssklower		soisconnecting($P.tp_sock);
36047281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
36138841Ssklower			$P.tp_cong_win = $P.tp_fcredit;
36236396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
36336396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
36438841Ssklower	}
36536396Ssklower;
36636396Ssklower
36736396Ssklower/* TP4 only */
36838841SsklowerTP_CLOSED		<==		 TP_CONFIRMING								T_ACPT_req
36936396Ssklower	DEFAULT /* emit failed */
37036396Ssklower	{
37136396Ssklower		register struct tp_ref *r = $P.tp_refp;
37236396Ssklower
37336396Ssklower		IFDEBUG(D_CONN)
37436396Ssklower			printf("event: CR_TPDU emit CC failed done " );
37536396Ssklower		ENDDEBUG
37638841Ssklower		soisdisconnected($P.tp_sock);
37736396Ssklower		tp_recycle_tsuffix( $P );
37836396Ssklower		tp_freeref(r);
37936396Ssklower		tp_detach($P);
38036396Ssklower	}
38136396Ssklower;
38236396Ssklower
38336396Ssklower/* applicable in TP4, TP0 */
38436396SsklowerTP_CRSENT		<==		TP_CLOSED								T_CONN_req
38536396Ssklower	DEFAULT
38636396Ssklower	{
38736396Ssklower		int error;
38836396Ssklower		struct mbuf *data = MNULL;
38936396Ssklower
39036396Ssklower		IFTRACE(D_CONN)
39137469Ssklower			tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
39237469Ssklower			$P.tp_ucddata, 0, 0);
39336396Ssklower		ENDTRACE
39437469Ssklower		data =  MCPY($P.tp_ucddata, M_WAIT);
39537469Ssklower		if (data) {
39636396Ssklower			IFDEBUG(D_CONN)
39736396Ssklower				printf("T_CONN_req.trans m_copy cc 0x%x\n",
39837469Ssklower					$P.tp_ucddata);
39937469Ssklower				dump_mbuf(data, "sosnd @ T_CONN_req");
40036396Ssklower			ENDDEBUG
40136396Ssklower		}
40236396Ssklower
40336396Ssklower		if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
40436396Ssklower			return error; /* driver WON'T change state; will return error */
40536396Ssklower
40636396Ssklower		$P.tp_refp->tpr_state = REF_OPEN; /* has timers */
40736396Ssklower		if($P.tp_class != TP_CLASS_0) {
40836396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
40936396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
41036396Ssklower		}
41136396Ssklower	}
41236396Ssklower;
41336396Ssklower
41436396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
41536396SsklowerTP_REFWAIT 		<==		[ TP_CRSENT, TP_AKWAIT, TP_OPEN ] 			DR_TPDU
41636396Ssklower	DEFAULT
41736396Ssklower	{
41848739Ssklower		sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
41948739Ssklower		if ($$.e_datalen > 0) {
42036396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
42136396Ssklower			$$.e_data = MNULL;
42236396Ssklower		}
42348739Ssklower		tp_indicate(T_DISCONNECT, $P, 0);
42436396Ssklower		tp_soisdisconnected($P);
42536396Ssklower		if ($P.tp_class != TP_CLASS_0) {
42636396Ssklower			if ($P.tp_state == TP_OPEN ) {
42736396Ssklower				tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
42836396Ssklower				tp_cuntimeout($P.tp_refp, TM_retrans);
42936396Ssklower				tp_cuntimeout($P.tp_refp, TM_inact);
43036396Ssklower				tp_cuntimeout($P.tp_refp, TM_sendack);
43136396Ssklower			}
43236396Ssklower			tp_cuntimeout($P.tp_refp, TM_retrans);
43336396Ssklower			if( $$.e_sref !=  0 )
43436396Ssklower				(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
43536396Ssklower		}
43636396Ssklower	}
43736396Ssklower;
43836396Ssklower
43936396SsklowerSAME 			<==		TP_CLOSED 									DR_TPDU
44036396Ssklower	DEFAULT
44136396Ssklower	{
44236396Ssklower		if( $$.e_sref != 0 )
44336396Ssklower			(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
44436396Ssklower		/* reference timer already set - reset it to be safe (???) */
44536396Ssklower		tp_euntimeout($P.tp_refp, TM_reference); /* all */
44636396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks);
44736396Ssklower	}
44836396Ssklower;
44936396Ssklower
45036396Ssklower/* NBS(34) */
45136396SsklowerTP_REFWAIT 		<==  	TP_CRSENT  									ER_TPDU
45236396Ssklower	DEFAULT
45336396Ssklower	{
45436396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
45548739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
45636396Ssklower		tp_soisdisconnected($P);
45736396Ssklower	}
45836396Ssklower;
45936396Ssklower
46036396Ssklower/* NBS(27) */
46136396SsklowerTP_REFWAIT		<==		TP_CLOSING									DR_TPDU
46236396Ssklower	DEFAULT
46336396Ssklower	{
46436396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
46536396Ssklower		tp_soisdisconnected($P);
46636396Ssklower	}
46736396Ssklower;
46836396Ssklower/* these two transitions are the same but can't be combined because xebec
46936396Ssklower * can't handle the use of $$.e_reason if they're combined
47036396Ssklower */
47136396Ssklower/* NBS(27) */
47236396SsklowerTP_REFWAIT		<==		TP_CLOSING									ER_TPDU
47336396Ssklower	DEFAULT
47436396Ssklower	{
47548739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
47636396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
47736396Ssklower		tp_soisdisconnected($P);
47836396Ssklower	}
47936396Ssklower;
48036396Ssklower/* NBS(27) */
48136396SsklowerTP_REFWAIT		<==		TP_CLOSING									DC_TPDU
48236396Ssklower	DEFAULT
48336396Ssklower	{
48436396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
48536396Ssklower		tp_soisdisconnected($P);
48636396Ssklower	}
48736396Ssklower;
48836396Ssklower
48936396Ssklower/* NBS(21) */
49036396SsklowerSAME 			<== 	TP_CLOSED 						[ CC_TPDU, CR_TPDU ]
49136396Ssklower	DEFAULT
49236396Ssklower	{	/* don't ask me why we have to do this - spec says so */
49336396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
49436396Ssklower		/* don't bother with retransmissions of the DR */
49536396Ssklower	}
49636396Ssklower;
49736396Ssklower
49836396Ssklower/* NBS(34) */
49936396SsklowerTP_REFWAIT 		<== 	TP_OPEN  				 					ER_TPDU
50036396Ssklower	($P.tp_class == TP_CLASS_0)
50136396Ssklower	{
50236396Ssklower		tp_soisdisconnecting($P.tp_sock);
50348739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
50436396Ssklower		tp_soisdisconnected($P);
50536396Ssklower		tp_netcmd( $P, CONN_CLOSE );
50636396Ssklower	}
50736396Ssklower;
50836396Ssklower
50936396SsklowerTP_CLOSING 		<== 	[ TP_AKWAIT, TP_OPEN ]  					ER_TPDU
51036396Ssklower	DEFAULT
51136396Ssklower	{
51236396Ssklower		if ($P.tp_state == TP_OPEN) {
51336396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
51436396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
51536396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
51636396Ssklower		}
51736396Ssklower		tp_soisdisconnecting($P.tp_sock);
51848739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
51936396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
52036396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
52136396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
52236396Ssklower	}
52336396Ssklower;
52436396Ssklower/* NBS(6) */
52536396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
52636396Ssklower	($P.tp_class == TP_CLASS_0)
52736396Ssklower	{
52836396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
52936396Ssklower		IncStat(ts_tp0_conn);
53036396Ssklower		$P.tp_fcredit = 1;
53136396Ssklower		soisconnected($P.tp_sock);
53236396Ssklower	}
53336396Ssklower;
53436396Ssklower
53536396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
53636396Ssklower	DEFAULT
53736396Ssklower	{
53836396Ssklower		IFDEBUG(D_CONN)
53936396Ssklower			printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
54036396Ssklower				(int)$P.tp_flags);
54136396Ssklower		ENDDEBUG
54236396Ssklower		IncStat(ts_tp4_conn);
54336396Ssklower		$P.tp_fref = $$.e_sref;
54436396Ssklower		$P.tp_fcredit = $$.e_cdt;
54539921Ssklower		$P.tp_ackrcvd = 0;
54647281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
54736396Ssklower			$P.tp_cong_win = $$.e_cdt;
54836396Ssklower		tp_getoptions($P);
54936396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
55037469Ssklower		if ($P.tp_ucddata) {
55136396Ssklower			IFDEBUG(D_CONN)
55237469Ssklower				printf("dropping user connect data cc 0x%x\n",
55337469Ssklower					$P.tp_ucddata->m_len);
55436396Ssklower			ENDDEBUG
55537469Ssklower			m_freem($P.tp_ucddata);
55637469Ssklower			$P.tp_ucddata = 0;
55736396Ssklower		}
55836396Ssklower		soisconnected($P.tp_sock);
55936396Ssklower		if ($$.e_datalen > 0) {
56036396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
56136396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
56236396Ssklower			$$.e_data = MNULL;
56336396Ssklower		}
56436396Ssklower
56536396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
56636396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
56736396Ssklower	}
56836396Ssklower;
56936396Ssklower
57036396Ssklower/* TP4 only */
57136396SsklowerSAME			<==		TP_CRSENT									TM_retrans
57236396Ssklower	(	$P.tp_retrans > 0 )
57336396Ssklower	{
57436396Ssklower		struct mbuf *data = MNULL;
57536396Ssklower		int error;
57636396Ssklower
57736396Ssklower		IncStat(ts_retrans_cr);
57839921Ssklower		$P.tp_cong_win = 1;
57939921Ssklower		$P.tp_ackrcvd = 0;
58037469Ssklower		data = MCPY($P.tp_ucddata, M_NOWAIT);
58137469Ssklower		if($P.tp_ucddata) {
58236396Ssklower			IFDEBUG(D_CONN)
58337469Ssklower				printf("TM_retrans.trans m_copy cc 0x%x\n", data);
58437469Ssklower				dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
58536396Ssklower			ENDDEBUG
58636396Ssklower			if( data == MNULL )
58736396Ssklower				return ENOBUFS;
58836396Ssklower		}
58936396Ssklower
59036396Ssklower		$P.tp_retrans --;
59136396Ssklower		if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
59236396Ssklower			$P.tp_sock->so_error = error;
59336396Ssklower		}
59436396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
59536396Ssklower	}
59636396Ssklower;
59736396Ssklower
59836396Ssklower/* TP4 only  */
59936396SsklowerTP_REFWAIT		<==		TP_CRSENT									TM_retrans
60036396Ssklower	DEFAULT /* no more CR retransmissions */
60136396Ssklower	{
60236396Ssklower		IncStat(ts_conn_gaveup);
60336396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
60436396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
60536396Ssklower		tp_soisdisconnected($P);
60636396Ssklower	}
60736396Ssklower;
60836396Ssklower
60936396Ssklower/* TP4 only */
61036396SsklowerSAME 			<==	 TP_AKWAIT											CR_TPDU
61136396Ssklower	DEFAULT
61236396Ssklower	/* duplicate CR (which doesn't really exist in the context of
61336396Ssklower	 * a connectionless network layer)
61436396Ssklower	 * Doesn't occur in class 0.
61536396Ssklower	 */
61636396Ssklower	{
61736396Ssklower		int error;
61837469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
61936396Ssklower
62037469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
62136396Ssklower			$P.tp_sock->so_error = error;
62236396Ssklower		}
62336396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
62436396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
62536396Ssklower	}
62636396Ssklower;
62736396Ssklower
62836396Ssklower/* TP4 only */
62936396SsklowerTP_OPEN			<==		TP_AKWAIT 										DT_TPDU
63036396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
63136396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
63236396Ssklower	{
63336396Ssklower		int doack;
63436396Ssklower
63537469Ssklower		/*
63637469Ssklower		 * Get rid of any confirm or connect data, so that if we
63737469Ssklower		 * crash or close, it isn't thought of as disconnect data.
63837469Ssklower		 */
63937469Ssklower		if ($P.tp_ucddata) {
64037469Ssklower			m_freem($P.tp_ucddata);
64137469Ssklower			$P.tp_ucddata = 0;
64236396Ssklower		}
64336396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
64436396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
64536396Ssklower		soisconnected($P.tp_sock);
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		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			soisconnected($P.tp_sock);
76736396Ssklower			tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
76836396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
76936396Ssklower		}
77036396Ssklower		IFTRACE(D_XPD)
77136396Ssklower		tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
77236396Ssklower				$P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
77336396Ssklower		ENDTRACE
77436396Ssklower
77537469Ssklower		$P.tp_sock->so_state |= SS_RCVATMARK;
77647281Ssklower		$$.e_data->m_flags |= M_EOR;
77737469Ssklower		sbinsertoob(&$P.tp_Xrcv, $$.e_data);
77836396Ssklower		IFDEBUG(D_XPD)
77936396Ssklower			dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
78036396Ssklower		ENDDEBUG
78136396Ssklower		tp_indicate(T_XDATA, $P, 0);
78236396Ssklower		sbwakeup( &$P.tp_Xrcv );
78336396Ssklower
78436396Ssklower		(void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
78536396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
78636396Ssklower	}
78736396Ssklower;
78836396Ssklower
78936396Ssklower/* TP4 only */
79036396SsklowerSAME			<==		TP_OPEN 									T_USR_Xrcvd
79136396Ssklower	DEFAULT
79236396Ssklower	{
79336396Ssklower		if( $P.tp_Xrcv.sb_cc == 0 ) {
79436396Ssklower			/* kludge for select(): */
79537469Ssklower			/* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
79636396Ssklower		}
79736396Ssklower	}
79836396Ssklower	/* OLD WAY:
79936396Ssklower	 * Ack only after the user receives the XPD.  This is better for
80036396Ssklower	 * users that use one XPD right after another.
80136396Ssklower	 * Acking right away (the NEW WAY, see the prev. transition) is
80236396Ssklower	 * better for occasional * XPD, when the receiving user doesn't
80336396Ssklower	 * want to read the XPD immediately (which is session's behavior).
80436396Ssklower	 *
80536396Ssklower		int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
80636396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
80736396Ssklower		return error;
80836396Ssklower	*/
80936396Ssklower;
81036396Ssklower
81136396Ssklower/* NOTE: presently if the user doesn't read the connection data
81236396Ssklower * before and expedited data PDU comes in, the connection data will
81336396Ssklower * be dropped. This is a bug.  To avoid it, we need somewhere else
81436396Ssklower * to put the connection data.
81536396Ssklower * On the other hand, we need not to have it sitting around forever.
81636396Ssklower * This is a problem with the idea of trying to accommodate
81736396Ssklower * data on connect w/ a passive-open user interface.
81836396Ssklower */
81936396Ssklower/* TP4 only */
82036396Ssklower
82136396SsklowerSAME	 		<== 	[ TP_AKWAIT, TP_OPEN ] 							XPD_TPDU
82236396Ssklower	DEFAULT /* not in window or cdt==0 */
82336396Ssklower	{
82436396Ssklower		IFTRACE(D_XPD)
82536396Ssklower			tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
82636396Ssklower				$P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
82736396Ssklower		ENDTRACE
82836396Ssklower		if( $P.tp_Xrcvnxt != $$.e_seq )
82936396Ssklower			IncStat(ts_xpd_niw);
83036396Ssklower		if( $P.tp_Xrcv.sb_cc ) {
83136396Ssklower			/* might as well kick 'em again */
83236396Ssklower			tp_indicate(T_XDATA, $P, 0);
83336396Ssklower			IncStat(ts_xpd_dup);
83436396Ssklower		}
83536396Ssklower		m_freem($$.e_data);
83636396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
83736396Ssklower		/* don't send an xack because the xak gives "last one received", not
83836396Ssklower		 * "next one i expect" (dumb)
83936396Ssklower		 */
84036396Ssklower	}
84136396Ssklower;
84236396Ssklower
84336396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
84436396Ssklower * to detach all its "children"
84536396Ssklower * Also (CRSENT) when user kills a job that's doing a connect()
84636396Ssklower */
84736396SsklowerTP_REFWAIT		<== 	TP_CRSENT 										T_DETACH
84836396Ssklower	($P.tp_class == TP_CLASS_0)
84936396Ssklower	{
85036396Ssklower		struct socket *so = $P.tp_sock;
85136396Ssklower
85236396Ssklower		/* detach from parent socket so it can finish closing */
85336396Ssklower		if (so->so_head) {
85436396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
85536396Ssklower				panic("tp: T_DETACH");
85636396Ssklower			so->so_head = 0;
85736396Ssklower		}
85836396Ssklower		tp_soisdisconnecting($P.tp_sock);
85936396Ssklower		tp_netcmd( $P, CONN_CLOSE);
86036396Ssklower		tp_soisdisconnected($P);
86136396Ssklower	}
86236396Ssklower;
86336396Ssklower
86436396Ssklower/* TP4 only */
86538841SsklowerTP_CLOSING		<== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ]	T_DETACH
86636396Ssklower	DEFAULT
86736396Ssklower	{
86836396Ssklower		struct socket *so = $P.tp_sock;
86937469Ssklower		struct mbuf *data = MNULL;
87036396Ssklower
87136396Ssklower		/* detach from parent socket so it can finish closing */
87236396Ssklower		if (so->so_head) {
87336396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
87436396Ssklower				panic("tp: T_DETACH");
87536396Ssklower			so->so_head = 0;
87636396Ssklower		}
87736396Ssklower		if ($P.tp_state != TP_CLOSING) {
87836396Ssklower			tp_soisdisconnecting($P.tp_sock);
87937469Ssklower			data = MCPY($P.tp_ucddata, M_NOWAIT);
88037469Ssklower			(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
88136396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
88236396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
88336396Ssklower		}
88436396Ssklower	}
88536396Ssklower;
88636396Ssklower
88736396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT ]		 	  			T_DISC_req
88836396Ssklower	( $P.tp_class == TP_CLASS_0 )
88936396Ssklower	{
89036396Ssklower		tp_soisdisconnecting($P.tp_sock);
89136396Ssklower		tp_netcmd( $P, CONN_CLOSE);
89236396Ssklower		tp_soisdisconnected($P);
89336396Ssklower	}
89436396Ssklower;
89536396Ssklower
89636396Ssklower/* TP4 only */
89738841SsklowerTP_CLOSING		<==	[ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
89836396Ssklower	DEFAULT
89936396Ssklower	{
90037469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
90136396Ssklower
90236396Ssklower		if($P.tp_state == TP_OPEN) {
90336396Ssklower			tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
90436396Ssklower			tp_cuntimeout($P.tp_refp, TM_inact);
90536396Ssklower			tp_cuntimeout($P.tp_refp, TM_sendack);
90636396Ssklower		}
90737469Ssklower		if (data) {
90836396Ssklower			IFDEBUG(D_CONN)
90937469Ssklower				printf("T_DISC_req.trans tp_ucddata 0x%x\n",
91037469Ssklower					$P.tp_ucddata);
91137469Ssklower				dump_mbuf(data, "ucddata @ T_DISC_req");
91236396Ssklower			ENDDEBUG
91336396Ssklower		}
91436396Ssklower		tp_soisdisconnecting($P.tp_sock);
91536396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
91636396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
91736396Ssklower
91836396Ssklower		if( trick_hc )
91936396Ssklower			return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
92036396Ssklower	}
92136396Ssklower;
92236396Ssklower
92336396Ssklower/* TP4 only */
92436396SsklowerSAME			<==		TP_AKWAIT									TM_retrans
92536396Ssklower	( $P.tp_retrans > 0 )
92636396Ssklower	{
92736396Ssklower		int error;
92837469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
92936396Ssklower
93036396Ssklower		IncStat(ts_retrans_cc);
93136396Ssklower		$P.tp_retrans --;
93239921Ssklower		$P.tp_cong_win = 1;
93339921Ssklower		$P.tp_ackrcvd = 0;
93439921Ssklower
93537469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
93636396Ssklower			$P.tp_sock->so_error = error;
93736396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
93836396Ssklower	}
93936396Ssklower;
94036396Ssklower
94136396Ssklower/* TP4 only */
94236396SsklowerTP_CLOSING		<==		TP_AKWAIT									TM_retrans
94336396Ssklower	DEFAULT  /* out of time */
94436396Ssklower	{
94536396Ssklower		IncStat(ts_conn_gaveup);
94636396Ssklower		tp_soisdisconnecting($P.tp_sock);
94736396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
94836396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
94936396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
95036396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
95136396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
95236396Ssklower	}
95336396Ssklower;
95436396Ssklower
95536396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does,
95636396Ssklower * if transmissions are going on.
95736396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack
95836396Ssklower * turnaround)
95936396Ssklower */
96036396Ssklower/* TP4 only */
96136396SsklowerTP_CLOSING 		<==		TP_OPEN		   [ TM_inact, TM_retrans, TM_data_retrans ]
96236396Ssklower	DEFAULT
96336396Ssklower	{
96436396Ssklower		tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
96536396Ssklower		tp_cuntimeout($P.tp_refp, TM_inact);
96636396Ssklower		tp_cuntimeout($P.tp_refp, TM_sendack);
96736396Ssklower
96836396Ssklower		IncStat(ts_conn_gaveup);
96936396Ssklower		tp_soisdisconnecting($P.tp_sock);
97036396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
97136396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
97236396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
97336396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
97436396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
97536396Ssklower	}
97636396Ssklower;
97736396Ssklower
97836396Ssklower/* TP4 only */
97936396SsklowerSAME			<==		TP_OPEN										TM_retrans
98036396Ssklower	( $P.tp_retrans > 0 )
98136396Ssklower	{
98239921Ssklower		$P.tp_cong_win = 1;
98339921Ssklower		$P.tp_ackrcvd = 0;
98436396Ssklower		/* resume XPD */
98536396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
98637469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
98736396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
98836396Ssklower			 * that doesn't matter
98936396Ssklower			 */
99036396Ssklower
99136396Ssklower			IFTRACE(D_XPD)
99236396Ssklower				tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna",
99336396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
99436396Ssklower					$P.tp_snduna);
99536396Ssklower			ENDTRACE
99636396Ssklower			IFDEBUG(D_XPD)
99736396Ssklower				dump_mbuf(m, "XPD retrans emitting M");
99836396Ssklower			ENDDEBUG
99936396Ssklower			IncStat(ts_retrans_xpd);
100036396Ssklower			$P.tp_retrans --;
100136396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
100236396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
100336396Ssklower		}
100436396Ssklower	}
100536396Ssklower;
100636396Ssklower
100736396Ssklower/* TP4 only */
100836396SsklowerSAME 			<==		TP_OPEN									TM_data_retrans
100936396Ssklower	( $$.e_retrans > 0 )
101036396Ssklower	{
101136396Ssklower		register 	SeqNum			low, lowsave = 0;
101250904Ssklower		register	struct mbuf 	*m, *n = $P.tp_sock->so_snd.sb_mb;
101336396Ssklower		register	SeqNum			high = $$.e_high;
101436396Ssklower
101539921Ssklower		low = $P.tp_snduna;
101639921Ssklower		lowsave = high = low;
101739921Ssklower
101839921Ssklower		tp_euntimeout_lss($P.tp_refp, TM_data_retrans,
101939921Ssklower			SEQ_ADD($P, $P.tp_sndhiwat, 1));
102039921Ssklower		$P.tp_retrans_hiwat = $P.tp_sndhiwat;
102139921Ssklower
102236396Ssklower		if (($P.tp_rx_strat & TPRX_EACH) == 0)
102336396Ssklower			high = (high>low)?low:high;
102436396Ssklower
102536396Ssklower		if( $P.tp_rx_strat & TPRX_USE_CW ) {
102636396Ssklower			register int i;
102736396Ssklower
102836396Ssklower			$P.tp_cong_win = 1;
102939921Ssklower			$P.tp_ackrcvd = 0;
103039921Ssklower			i = SEQ_ADD($P, low, $P.tp_cong_win);
103136396Ssklower
103239921Ssklower			high = SEQ_MIN($P, high, $P.tp_sndhiwat);
103339921Ssklower
103436396Ssklower		}
103536396Ssklower
103650904Ssklower		while (SEQ_LEQ($P, low, high)) {
103750904Ssklower			if (n) {
103850904Ssklower				if ((m = m_copy(n, 0, M_COPYALL))== MNULL)
103936396Ssklower					break;
104050904Ssklower				(void) tp_emit(DT_TPDU_type, $P,
104150904Ssklower					low, (m->m_flags & M_EOR) != 0, m);
104236396Ssklower				IncStat(ts_retrans_dt);
104336396Ssklower				SEQ_INC($P, low );
104436396Ssklower			}
104550904Ssklower			n = n->m_nextpkt;
104636396Ssklower		}
104739921Ssklower/* CE_BIT
104836396Ssklower		if ( SEQ_LEQ($P, lowsave, high) ){
104939921Ssklower*/
105036396Ssklower			$$.e_retrans --;
105136396Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
105236396Ssklower					(caddr_t)high, $$.e_retrans,
105336396Ssklower					($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks);
105439921Ssklower/* CE_BIT
105536396Ssklower		}
105639921Ssklower*/
105736396Ssklower	}
105836396Ssklower;
105936396Ssklower
106036396Ssklower/* TP4 only */
106136396SsklowerSAME	 		<==		TP_CLOSING									TM_retrans
106236396Ssklower	(	$P.tp_retrans > 0 )
106336396Ssklower	{
106436396Ssklower		$P.tp_retrans --;
106536396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
106636396Ssklower		IncStat(ts_retrans_dr);
106736396Ssklower		tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
106836396Ssklower	}
106936396Ssklower;
107036396Ssklower
107136396Ssklower/* TP4 only */
107236396SsklowerTP_REFWAIT 		<==		TP_CLOSING									TM_retrans
107336396Ssklower	DEFAULT	/* no more retrans - gave up */
107436396Ssklower	{
107536396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
107636396Ssklower		$P.tp_refp->tpr_state = REF_FROZEN;
107736396Ssklower		tp_recycle_tsuffix( $P );
107836396Ssklower		tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks);
107936396Ssklower	}
108036396Ssklower;
108136396Ssklower
108236396Ssklower/*
108336396Ssklower * The resources are kept around until the ref timer goes off.
108436396Ssklower * The suffices are wiped out sooner so they can be reused right away.
108536396Ssklower */
108636396Ssklower/* applicable in TP4, TP0 */
108736396SsklowerTP_CLOSED 		<==		TP_REFWAIT 									TM_reference
108836396Ssklower	DEFAULT
108936396Ssklower	{
109036396Ssklower		tp_freeref($P.tp_refp);
109136396Ssklower		tp_detach($P);
109236396Ssklower	}
109336396Ssklower;
109436396Ssklower
109536396Ssklower/* applicable in TP4, TP0 */
109636396Ssklower/* A duplicate CR from connectionless network layer can't happen */
109736396SsklowerSAME 			<== 	TP_OPEN 							[ CR_TPDU, CC_TPDU ]
109836396Ssklower	DEFAULT
109936396Ssklower	{
110036396Ssklower		if( $P.tp_class != TP_CLASS_0) {
110136396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
110236396Ssklower			if ( $E.ev_number == CC_TPDU )
110336396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
110436396Ssklower		}
110536396Ssklower		/* ignore it if class 0 - state tables are blank for this */
110636396Ssklower	}
110736396Ssklower;
110836396Ssklower
110936396Ssklower/* applicable in TP4, TP0 */
111036396SsklowerSAME			<== 	TP_OPEN									T_DATA_req
111136396Ssklower	DEFAULT
111236396Ssklower	{
111336396Ssklower		IFTRACE(D_DATA)
111436396Ssklower			tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb",
111536396Ssklower				$P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P);
111636396Ssklower		ENDTRACE
111736396Ssklower
111836396Ssklower		tp_send($P);
111936396Ssklower	}
112036396Ssklower;
112136396Ssklower
112236396Ssklower/* TP4 only */
112336396SsklowerSAME			<==		TP_OPEN										T_XPD_req
112436396Ssklower	DEFAULT
112536396Ssklower		/* T_XPD_req was issued by sosend iff xpd socket buf was empty
112636396Ssklower		 * at time of sosend(),
112736396Ssklower		 * AND (which means) there were no unacknowledged XPD tpdus outstanding!
112836396Ssklower		 */
112936396Ssklower	{
113036396Ssklower		int error = 0;
113136396Ssklower
113236396Ssklower		/* resume XPD */
113336396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
113437469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
113536396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
113636396Ssklower			 * that doesn't matter
113736396Ssklower			 */
113836396Ssklower
113936396Ssklower			IFTRACE(D_XPD)
114036396Ssklower				tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna",
114136396Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
114236396Ssklower					$P.tp_snduna);
114336396Ssklower			ENDTRACE
114436396Ssklower			IFDEBUG(D_XPD)
114536396Ssklower				printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
114636396Ssklower				dump_mbuf(m, "XPD req emitting M");
114736396Ssklower			ENDDEBUG
114836396Ssklower			error =
114936396Ssklower				tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
115036396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
115136396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
115236396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
115336396Ssklower		}
115436396Ssklower		if(trick_hc)
115536396Ssklower			return error;
115636396Ssklower	}
115736396Ssklower;
115836396Ssklower
115936396Ssklower/* TP4, faked ack in TP0 when cons send completes */
116036396SsklowerSAME 			<==		TP_OPEN 									AK_TPDU
116136396Ssklower	( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
116236396Ssklower
116336396Ssklower	/* tp_goodack == true means
116436396Ssklower	 * EITHER it actually acked something heretofore unacknowledged
116536396Ssklower	 * OR no news but the credit should be processed.
116636396Ssklower	 */
116736396Ssklower	{
116850904Ssklower		struct sockbuf *sb = &$P.tp_sock->so_snd;
116950904Ssklower
117036396Ssklower		IFDEBUG(D_ACKRECV)
117136396Ssklower			printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
117236396Ssklower		ENDDEBUG
117336396Ssklower		if( $P.tp_class != TP_CLASS_0) {
117436396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
117536396Ssklower			tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq);
117636396Ssklower		}
117750904Ssklower		sbwakeup(sb);
117839921Ssklower		if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat &&
117939921Ssklower			$P.tp_snduna <= $P.tp_retrans_hiwat) {
118039921Ssklower
118150904Ssklower			register struct mbuf     *m, *n = sb->sb_mb;
118250904Ssklower			SeqNum		high, retrans, lowsave;
118339921Ssklower
118439921Ssklower			high = SEQ_MIN($P, SEQ_ADD($P, $P.tp_snduna,
118539921Ssklower					MIN($P.tp_cong_win, $P.tp_fcredit)) - 1,
118639921Ssklower					$P.tp_sndhiwat);
118750904Ssklower			retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1),
118839921Ssklower					$P.tp_snduna);
118950904Ssklower			for (lowsave = $P.tp_snduna;
119050904Ssklower					SEQ_LT($P, lowsave, retrans); SEQ_INC($P, lowsave))
119150904Ssklower				n = n->m_nextpkt;
119239921Ssklower			for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) {
119350904Ssklower				if (n == 0) {
119439921Ssklower					IFDEBUG(D_RTC)
119550904Ssklower						printf("tp: retrans list is GONE!\n");
119639921Ssklower					ENDDEBUG
119739921Ssklower					break;
119850904Ssklower				} else if (m = m_copy(n, 0, M_COPYALL)) {
119950904Ssklower					(void) tp_emit(DT_TPDU_type, $P, retrans,
120050904Ssklower						(m->m_flags & M_EOR) != 0, m);
120150904Ssklower					$P.tp_last_retrans = retrans;
120250904Ssklower					IncStat(ts_retrans_dt);
120339921Ssklower				}
120450904Ssklower				n = n->m_nextpkt;
120539921Ssklower			}
120650904Ssklower			tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
120739921Ssklower					(caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks);
120839921Ssklower			if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat)
120939921Ssklower				tp_send($P);
121039921Ssklower		}
121139921Ssklower		else {
121239921Ssklower			tp_send($P);
121339921Ssklower		}
121436396Ssklower		IFDEBUG(D_ACKRECV)
121536396Ssklower			printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat);
121636396Ssklower		ENDDEBUG
121736396Ssklower	}
121836396Ssklower;
121936396Ssklower
122036396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
122136396SsklowerSAME			<==		TP_OPEN 			 						 AK_TPDU
122236396Ssklower	DEFAULT
122336396Ssklower	{
122436396Ssklower		IFTRACE(D_ACKRECV)
122536396Ssklower			tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
122636396Ssklower				$$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
122736396Ssklower		ENDTRACE
122836396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
122936396Ssklower
123036396Ssklower			if ( !$$.e_fcc_present ) {
123136396Ssklower				/* send ACK with FCC */
123236396Ssklower				IncStat( ts_ackreason[_ACK_FCC_] );
123336396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
123436396Ssklower			}
123536396Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
123636396Ssklower		}
123736396Ssklower	}
123836396Ssklower;
123936396Ssklower
124036396Ssklower/* NBS(47) */
124136396Ssklower	/* goes in at *** */
124236396Ssklower		/* just so happens that this is never true now, because we allow
124336396Ssklower		 * only 1 packet in the queue at once (this could be changed)
124436396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
124536396Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
124636396Ssklower
124736396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
124836396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
124936396Ssklower			tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
125036396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
125136396Ssklower		}
125236396Ssklower		 */
125336396Ssklower	/* end of the above hack */
125436396Ssklower
125536396Ssklower/* TP4 only */
125642944SsklowerSAME			<== 	TP_OPEN										XAK_TPDU
125736396Ssklower	( tp_goodXack($P, $$.e_seq) )
125836396Ssklower	/* tp_goodXack checks for good ack, removes the correct
125936396Ssklower	 * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
126036396Ssklower	 * also updates tp_Xuna
126136396Ssklower	 */
126236396Ssklower	{
126336396Ssklower		tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
126436396Ssklower		tp_cuntimeout($P.tp_refp, TM_retrans);
126536396Ssklower
126636396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
126736396Ssklower
126836396Ssklower		/* resume normal data */
126936396Ssklower		tp_send($P);
127036396Ssklower	}
127136396Ssklower;
127236396Ssklower
127342944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
127442944SsklowerSAME			<==		TP_OPEN 			 						XAK_TPDU
127542944Ssklower	DEFAULT
127642944Ssklower	{
127742944Ssklower		IFTRACE(D_ACKRECV)
127842944Ssklower			tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
127942944Ssklower		ENDTRACE
128042944Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
128142944Ssklower			tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
128242944Ssklower		}
128342944Ssklower	}
128442944Ssklower;
128542944Ssklower
128636396Ssklower/* TP4 only */
128736396SsklowerSAME			<==		TP_OPEN 								TM_sendack
128836396Ssklower	DEFAULT
128936396Ssklower	{
129036396Ssklower		IFTRACE(D_TIMER)
129136396Ssklower			tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
129236396Ssklower			$P.tp_sent_lcdt, 0);
129336396Ssklower		ENDTRACE
129436396Ssklower		IncPStat($P, tps_n_TMsendack);
129536396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
129636396Ssklower	}
129736396Ssklower;
129836396Ssklower
129936396Ssklower/* TP0 only */
130036396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
130136396Ssklower	($P.tp_class == TP_CLASS_0)
130247281Ssklower	{
130347281Ssklower		if (sbspace(&$P.tp_sock->so_rcv) > 0)
130447281Ssklower			tp0_openflow($P);
130547281Ssklower	}
130636396Ssklower;
130736396Ssklower
130836396Ssklower/* TP4 only */
130936396Ssklower		/* If old credit was zero,
131036396Ssklower		 * we'd better inform other side that we now have space
131136396Ssklower		 * But this is not enough.  Sender might not yet have
131236396Ssklower		 * seen an ack with cdt 0 but it might still think the
131336396Ssklower		 * window is closed, so it's going to wait.
131436396Ssklower		 * Best to send an ack each time.
131536396Ssklower		 * Strictly speaking, this ought to be a function of the
131636396Ssklower		 * general ack strategy.
131736396Ssklower		 */
131836396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
131936396Ssklower	DEFAULT
132036396Ssklower	{
132136396Ssklower		if( trick_hc ) {
1322*51024Ssklower			SeqNum ack_thresh;
132350849Ssklower			/*
1324*51024Ssklower			 * If the upper window edge has advanced a reasonable
1325*51024Ssklower			 * amount beyond what was known, send an ACK.
1326*51024Ssklower			 * A reasonable amount is 2 packets, unless the max window
1327*51024Ssklower			 * is only 1 or 2 packets, in which case we
1328*51024Ssklower			 * should send an ack for any advance in the upper window edge.
132950849Ssklower			 */
1330*51024Ssklower			LOCAL_CREDIT($P);
1331*51024Ssklower			ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt,
1332*51024Ssklower									 ($P.tp_maxlcredit > 2 ? 2 : 1));
1333*51024Ssklower			if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) {
133450849Ssklower				IncStat(ts_ackreason[_ACK_USRRCV_]);
1335*51024Ssklower				$P.tp_flags &= ~TPF_DELACK;
133639921Ssklower				return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
133750849Ssklower			}
133836396Ssklower		}
133936396Ssklower	}
134036396Ssklower;
134136396Ssklower
134236396Ssklower/* applicable in TP4, TP0 */
134336396SsklowerSAME			<==		TP_REFWAIT 				[ T_USR_rcvd, T_USR_Xrcvd ]
134436396Ssklower	DEFAULT
134536396Ssklower	/* This happens if other end sent a DR when  the user was waiting
134636396Ssklower	 * on a receive.
134736396Ssklower	 * Processing the DR includes putting us in REFWAIT state.
134836396Ssklower	 */
134936396Ssklower	{
135036396Ssklower		if(trick_hc)
135136396Ssklower		return ECONNABORTED;
135236396Ssklower	}
135336396Ssklower;
135436396Ssklower
135536396Ssklower/* TP0 only */
135636396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT, TP_LISTENING ] 	T_NETRESET
135736396Ssklower	( $P.tp_class != TP_CLASS_4 )
135836396Ssklower		/* 0 or (4 and 0) */
135936396Ssklower		/* in OPEN class will be 0 or 4 but not both */
136036396Ssklower		/* in CRSENT or LISTENING it could be in negotiation, hence both */
136136396Ssklower		/* Actually, this shouldn't ever happen in LISTENING */
136236396Ssklower	{
136336396Ssklower		ASSERT( $P.tp_state != TP_LISTENING );
136436396Ssklower		tp_indicate(T_DISCONNECT, $P, ECONNRESET);
136536396Ssklower		tp_soisdisconnected($P);
136636396Ssklower	}
136736396Ssklower;
136836396Ssklower
136936396Ssklower/* TP4: ignore resets */
137036396SsklowerSAME		<==		[ TP_OPEN, TP_CRSENT, TP_AKWAIT,
137136396Ssklower						TP_CLOSING, TP_LISTENING ] 				T_NETRESET
137236396Ssklower	DEFAULT
137336396Ssklower	NULLACTION
137436396Ssklower;
137536396Ssklower
137636396Ssklower/* applicable in TP4, TP0 */
137736396SsklowerSAME			<==		[ TP_CLOSED, TP_REFWAIT ]				T_NETRESET
137836396Ssklower	DEFAULT
137936396Ssklower	NULLACTION
138036396Ssklower;
138136396Ssklower
138236396Ssklower/* C'EST TOUT */
1383