xref: /csrg-svn/sys/netiso/tp.trans (revision 51204)
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*51204Ssklower *	@(#)tp.trans	7.14 (Berkeley) 09/26/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*51204Ssklower/* @(#)tp.trans	7.14 (Berkeley) 09/26/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(),
94*51204Ssklower		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
135*51204Ssklower				/* TM_sendack does dual duty - keepalive AND closed-window
136*51204Ssklower				 * Probes.
13736396Ssklower				 * It's set w/ keepalive-ticks every time an ack is sent.
13836396Ssklower				 * (this is done in (void) tp_emit() ).
139*51204Ssklower				 * Whenever a DT arrives which doesn't require immediate acking,
140*51204Ssklower				 * a separate fast-timeout flag is set ensuring 200ms response.
14136396Ssklower				 */
14236396Ssklower TM_notused
14336396Ssklower
14436396Ssklower /*
14536396Ssklower  * E (typically expired) timers - these may be in any order.
14636396Ssklower  * These cause procedures to be executed directly; may not
14736396Ssklower  * cause an 'event' as we know them here.
14836396Ssklower  */
14936396Ssklower TM_reference		{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15036396Ssklower TM_data_retrans	{ SeqNum e_low; SeqNum e_high; int e_retrans; }
15136396Ssklower
15236396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that
15336396Ssklower * for all tpdu types that can take e_data and e_datalen, these
15436396Ssklower * fields fall in the same place in the event structure, that is,
15536396Ssklower * e_data is the first field and e_datalen is the 2nd field.
15636396Ssklower */
15736396Ssklower
15836396Ssklower ER_TPDU  	 	{
15936396Ssklower				  u_char		e_reason;
16036396Ssklower				}
16136396Ssklower CR_TPDU  	 	{ struct mbuf 	*e_data;	/* first field */
16236396Ssklower				  int 			e_datalen; /* 2nd field */
16336396Ssklower				  u_int			e_cdt;
16436396Ssklower				}
16536396Ssklower DR_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
16636396Ssklower				  int 			e_datalen; /* 2nd field */
16736396Ssklower				  u_short		e_sref;
16836396Ssklower				  u_char		e_reason;
16936396Ssklower				}
17036396Ssklower DC_TPDU
17136396Ssklower CC_TPDU   	 	{ struct mbuf 	*e_data;	/* first field */
17236396Ssklower				  int 			e_datalen; /* 2nd field */
17336396Ssklower				  u_short		e_sref;
17436396Ssklower				  u_int			e_cdt;
17536396Ssklower				}
17636396Ssklower AK_TPDU		{ u_int			e_cdt;
17736396Ssklower				  SeqNum 	 	e_seq;
17836396Ssklower				  SeqNum 	 	e_subseq;
17936396Ssklower				  u_char 	 	e_fcc_present;
18036396Ssklower				}
18136396Ssklower DT_TPDU		{ struct mbuf	*e_data; 	/* first field */
18236396Ssklower				  int 			e_datalen; /* 2nd field */
18336396Ssklower				  u_int 		e_eot;
18436396Ssklower				  SeqNum		e_seq;
18536396Ssklower				}
18636396Ssklower XPD_TPDU		{ struct mbuf 	*e_data;	/* first field */
18736396Ssklower				  int 			e_datalen; 	/* 2nd field */
18836396Ssklower				  SeqNum 		e_seq;
18936396Ssklower				}
19036396Ssklower XAK_TPDU		{ SeqNum 		e_seq;		}
19136396Ssklower
19236396Ssklower T_CONN_req
19336396Ssklower T_DISC_req		{ u_char		e_reason; 	}
19436396Ssklower T_LISTEN_req
19536396Ssklower T_DATA_req
19636396Ssklower T_XPD_req
19736396Ssklower T_USR_rcvd
19836396Ssklower T_USR_Xrcvd
19936396Ssklower T_DETACH
20036396Ssklower T_NETRESET
20138841Ssklower T_ACPT_req
20236396Ssklower
20336396Ssklower
20436396Ssklower*TRANSITIONS
20536396Ssklower
20636396Ssklower
20736396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */
20836396SsklowerSAME			<==			TP_AKWAIT			[ CC_TPDU, DC_TPDU, XAK_TPDU ]
20936396Ssklower	DEFAULT
21036396Ssklower	NULLACTION
21136396Ssklower;
21236396Ssklower
21336396Ssklower
21436396Ssklower/* applicable in TP4, TP0 */
21536396SsklowerSAME			<==			TP_REFWAIT								DR_TPDU
21636396Ssklower	( $$.e_sref !=  0 )
21736396Ssklower	{
21836396Ssklower		(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
21936396Ssklower	}
22036396Ssklower;
22136396Ssklower
22236396Ssklower/* applicable in TP4, TP0 */
22336396SsklowerSAME			<==			TP_REFWAIT			[ CR_TPDU, CC_TPDU, DT_TPDU,
22436396Ssklower					DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ]
22536396Ssklower	DEFAULT
22636396Ssklower	{
22736396Ssklower#		ifdef TP_DEBUG
22836396Ssklower		if( $E.ev_number != AK_TPDU )
22936396Ssklower			printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number);
23036396Ssklower#		endif TP_DEBUG
23136396Ssklower	}
23236396Ssklower;
23336396Ssklower
23436396Ssklower/* applicable in TP4, TP0 */
23536396SsklowerSAME			<==			TP_REFWAIT				[ T_DETACH, T_DISC_req ]
23636396Ssklower	DEFAULT
23736396Ssklower	NULLACTION
23836396Ssklower;
23936396Ssklower
24036396Ssklower/* applicable in TP4, TP0 */
24136396SsklowerSAME			<==			TP_CRSENT								 AK_TPDU
24236396Ssklower	($P.tp_class == TP_CLASS_0)
24336396Ssklower	{
24436396Ssklower		/* oh, man is this grotesque or what? */
24536396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq,  $$.e_subseq);
24636396Ssklower		/* but it's necessary because this pseudo-ack may happen
24736396Ssklower		 * before the CC arrives, but we HAVE to adjust the
24836396Ssklower		 * snduna as a result of the ack, WHENEVER it arrives
24936396Ssklower		 */
25036396Ssklower	}
25136396Ssklower;
25236396Ssklower
25336396Ssklower/* applicable in TP4, TP0 */
25436396SsklowerSAME			<==			TP_CRSENT
25536396Ssklower					[ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU,  XAK_TPDU ]
25636396Ssklower	DEFAULT
25736396Ssklower	NULLACTION
25836396Ssklower;
25936396Ssklower
26036396Ssklower/* applicable in TP4, TP0 */
26136396SsklowerSAME			<==			TP_CLOSED					[ DT_TPDU, XPD_TPDU,
26236396Ssklower										ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
26336396Ssklower	DEFAULT
26436396Ssklower	NULLACTION
26536396Ssklower;
26636396Ssklower
26736396Ssklower/* TP_CLOSING doesn't exist in TP 0 */
26836396SsklowerSAME 			<== 		TP_CLOSING
26936396Ssklower					[ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ]
27036396Ssklower	DEFAULT
27136396Ssklower	NULLACTION
27236396Ssklower;
27336396Ssklower
27436396Ssklower
27536396Ssklower/* DC_TPDU doesn't exist in TP 0 */
27636396SsklowerSAME			<==			TP_OPEN						  DC_TPDU
27736396Ssklower	DEFAULT
27836396Ssklower	NULLACTION
27936396Ssklower;
28036396Ssklower
28136396Ssklower/* applicable in TP4, TP0 */
28236396SsklowerSAME			<==		 	TP_LISTENING  [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU,
28336396Ssklower										 ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
28436396Ssklower	DEFAULT
28536396Ssklower	NULLACTION
28636396Ssklower;
28736396Ssklower
28836396Ssklower/* applicable in TP4, TP0 */
28936396SsklowerTP_LISTENING	<==			TP_CLOSED  							T_LISTEN_req
29036396Ssklower	DEFAULT
29136396Ssklower	NULLACTION
29236396Ssklower;
29336396Ssklower
29436396Ssklower/* applicable in TP4, TP0 */
29536396SsklowerTP_CLOSED  		<== 		[ TP_LISTENING, TP_CLOSED ] 			T_DETACH
29636396Ssklower	DEFAULT
29736396Ssklower	{
29836396Ssklower		tp_detach($P);
29936396Ssklower	}
30036396Ssklower;
30136396Ssklower
30238841SsklowerTP_CONFIRMING	<==		 TP_LISTENING  								CR_TPDU
30338841Ssklower	( $P.tp_class == TP_CLASS_0)
30436396Ssklower	{
305*51204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers ??? */
30636396Ssklower	}
30736396Ssklower;
30836396Ssklower
30938841SsklowerTP_CONFIRMING		<==		 TP_LISTENING  							CR_TPDU
31038841Ssklower	DEFAULT
31136396Ssklower	{
31236396Ssklower		IFTRACE(D_CONN)
31336396Ssklower			tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
31436396Ssklower		ENDTRACE
31536396Ssklower		IFDEBUG(D_CONN)
31636396Ssklower			printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
31736396Ssklower		ENDDEBUG
318*51204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers */
31938841Ssklower		$P.tp_fcredit = $$.e_cdt;
32036396Ssklower
32136396Ssklower		if ($$.e_datalen > 0) {
32236396Ssklower			/* n/a for class 0 */
32336396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0);
32436396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
32536396Ssklower			$$.e_data = MNULL;
32636396Ssklower		}
32738841Ssklower	}
32838841Ssklower;
32938841Ssklower
33038841SsklowerTP_OPEN		<==		 TP_CONFIRMING  								T_ACPT_req
33138841Ssklower	( $P.tp_class == TP_CLASS_0 )
33238841Ssklower	{
33338841Ssklower		IncStat(ts_tp0_conn);
33438841Ssklower		IFTRACE(D_CONN)
33538841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
33638841Ssklower		ENDTRACE
33738841Ssklower		IFDEBUG(D_CONN)
33838841Ssklower			printf("Confirming connection: $P" );
33938841Ssklower		ENDDEBUG
34038841Ssklower		soisconnected($P.tp_sock);
34138841Ssklower		(void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
34238841Ssklower		$P.tp_fcredit = 1;
34338841Ssklower	}
34438841Ssklower;
34538841Ssklower
34638841SsklowerTP_AKWAIT		<==		 TP_CONFIRMING  							T_ACPT_req
34738841Ssklower	(tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
34838841Ssklower	{
34938841Ssklower		IncStat(ts_tp4_conn); /* even though not quite open */
35038841Ssklower		IFTRACE(D_CONN)
35138841Ssklower			tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
35238841Ssklower		ENDTRACE
35338841Ssklower		IFDEBUG(D_CONN)
35438841Ssklower			printf("Confirming connection: $P" );
35538841Ssklower		ENDDEBUG
35650973Ssklower		tp_getoptions($P);
35738841Ssklower		soisconnecting($P.tp_sock);
35847281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
359*51204Ssklower			$P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize;
36036396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
361*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
36238841Ssklower	}
36336396Ssklower;
36436396Ssklower
36536396Ssklower/* TP4 only */
36638841SsklowerTP_CLOSED		<==		 TP_CONFIRMING								T_ACPT_req
36736396Ssklower	DEFAULT /* emit failed */
36836396Ssklower	{
36936396Ssklower		register struct tp_ref *r = $P.tp_refp;
37036396Ssklower
37136396Ssklower		IFDEBUG(D_CONN)
37236396Ssklower			printf("event: CR_TPDU emit CC failed done " );
37336396Ssklower		ENDDEBUG
37438841Ssklower		soisdisconnected($P.tp_sock);
37536396Ssklower		tp_recycle_tsuffix( $P );
37636396Ssklower		tp_freeref(r);
37736396Ssklower		tp_detach($P);
37836396Ssklower	}
37936396Ssklower;
38036396Ssklower
38136396Ssklower/* applicable in TP4, TP0 */
38236396SsklowerTP_CRSENT		<==		TP_CLOSED								T_CONN_req
38336396Ssklower	DEFAULT
38436396Ssklower	{
38536396Ssklower		int error;
38636396Ssklower		struct mbuf *data = MNULL;
38736396Ssklower
38836396Ssklower		IFTRACE(D_CONN)
38937469Ssklower			tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
39037469Ssklower			$P.tp_ucddata, 0, 0);
39136396Ssklower		ENDTRACE
39237469Ssklower		data =  MCPY($P.tp_ucddata, M_WAIT);
39337469Ssklower		if (data) {
39436396Ssklower			IFDEBUG(D_CONN)
39536396Ssklower				printf("T_CONN_req.trans m_copy cc 0x%x\n",
39637469Ssklower					$P.tp_ucddata);
39737469Ssklower				dump_mbuf(data, "sosnd @ T_CONN_req");
39836396Ssklower			ENDDEBUG
39936396Ssklower		}
40036396Ssklower
40136396Ssklower		if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
40236396Ssklower			return error; /* driver WON'T change state; will return error */
40336396Ssklower
404*51204Ssklower		$P.tp_refstate = REF_OPEN; /* has timers */
40536396Ssklower		if($P.tp_class != TP_CLASS_0) {
40636396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
407*51204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
40836396Ssklower		}
40936396Ssklower	}
41036396Ssklower;
41136396Ssklower
41236396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
41336396SsklowerTP_REFWAIT 		<==		[ TP_CRSENT, TP_AKWAIT, TP_OPEN ] 			DR_TPDU
41436396Ssklower	DEFAULT
41536396Ssklower	{
41648739Ssklower		sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
41748739Ssklower		if ($$.e_datalen > 0) {
41836396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
41936396Ssklower			$$.e_data = MNULL;
42036396Ssklower		}
42148739Ssklower		tp_indicate(T_DISCONNECT, $P, 0);
42236396Ssklower		tp_soisdisconnected($P);
42336396Ssklower		if ($P.tp_class != TP_CLASS_0) {
42436396Ssklower			if ($P.tp_state == TP_OPEN ) {
425*51204Ssklower				tp_euntimeout($P, TM_data_retrans); /* all */
426*51204Ssklower				tp_cuntimeout($P, TM_retrans);
427*51204Ssklower				tp_cuntimeout($P, TM_inact);
428*51204Ssklower				tp_cuntimeout($P, TM_sendack);
42936396Ssklower			}
430*51204Ssklower			tp_cuntimeout($P, TM_retrans);
43136396Ssklower			if( $$.e_sref !=  0 )
43236396Ssklower				(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
43336396Ssklower		}
43436396Ssklower	}
43536396Ssklower;
43636396Ssklower
43736396SsklowerSAME 			<==		TP_CLOSED 									DR_TPDU
43836396Ssklower	DEFAULT
43936396Ssklower	{
44036396Ssklower		if( $$.e_sref != 0 )
44136396Ssklower			(void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
44236396Ssklower		/* reference timer already set - reset it to be safe (???) */
443*51204Ssklower		tp_euntimeout($P, TM_reference); /* all */
444*51204Ssklower		tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
44536396Ssklower	}
44636396Ssklower;
44736396Ssklower
44836396Ssklower/* NBS(34) */
44936396SsklowerTP_REFWAIT 		<==  	TP_CRSENT  									ER_TPDU
45036396Ssklower	DEFAULT
45136396Ssklower	{
452*51204Ssklower		tp_cuntimeout($P, TM_retrans);
45348739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
45436396Ssklower		tp_soisdisconnected($P);
45536396Ssklower	}
45636396Ssklower;
45736396Ssklower
45836396Ssklower/* NBS(27) */
45936396SsklowerTP_REFWAIT		<==		TP_CLOSING									DR_TPDU
46036396Ssklower	DEFAULT
46136396Ssklower	{
462*51204Ssklower		tp_cuntimeout($P, TM_retrans);
46336396Ssklower		tp_soisdisconnected($P);
46436396Ssklower	}
46536396Ssklower;
46636396Ssklower/* these two transitions are the same but can't be combined because xebec
46736396Ssklower * can't handle the use of $$.e_reason if they're combined
46836396Ssklower */
46936396Ssklower/* NBS(27) */
47036396SsklowerTP_REFWAIT		<==		TP_CLOSING									ER_TPDU
47136396Ssklower	DEFAULT
47236396Ssklower	{
47348739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
474*51204Ssklower		tp_cuntimeout($P, TM_retrans);
47536396Ssklower		tp_soisdisconnected($P);
47636396Ssklower	}
47736396Ssklower;
47836396Ssklower/* NBS(27) */
47936396SsklowerTP_REFWAIT		<==		TP_CLOSING									DC_TPDU
48036396Ssklower	DEFAULT
48136396Ssklower	{
482*51204Ssklower		tp_cuntimeout($P, TM_retrans);
48336396Ssklower		tp_soisdisconnected($P);
48436396Ssklower	}
48536396Ssklower;
48636396Ssklower
48736396Ssklower/* NBS(21) */
48836396SsklowerSAME 			<== 	TP_CLOSED 						[ CC_TPDU, CR_TPDU ]
48936396Ssklower	DEFAULT
49036396Ssklower	{	/* don't ask me why we have to do this - spec says so */
49136396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
49236396Ssklower		/* don't bother with retransmissions of the DR */
49336396Ssklower	}
49436396Ssklower;
49536396Ssklower
49636396Ssklower/* NBS(34) */
49736396SsklowerTP_REFWAIT 		<== 	TP_OPEN  				 					ER_TPDU
49836396Ssklower	($P.tp_class == TP_CLASS_0)
49936396Ssklower	{
50036396Ssklower		tp_soisdisconnecting($P.tp_sock);
50148739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
50236396Ssklower		tp_soisdisconnected($P);
50336396Ssklower		tp_netcmd( $P, CONN_CLOSE );
50436396Ssklower	}
50536396Ssklower;
50636396Ssklower
50736396SsklowerTP_CLOSING 		<== 	[ TP_AKWAIT, TP_OPEN ]  					ER_TPDU
50836396Ssklower	DEFAULT
50936396Ssklower	{
51036396Ssklower		if ($P.tp_state == TP_OPEN) {
511*51204Ssklower			tp_euntimeout($P, TM_data_retrans); /* all */
512*51204Ssklower			tp_cuntimeout($P, TM_inact);
513*51204Ssklower			tp_cuntimeout($P, TM_sendack);
51436396Ssklower		}
51536396Ssklower		tp_soisdisconnecting($P.tp_sock);
51648739Ssklower		tp_indicate(ER_TPDU, $P, $$.e_reason);
51736396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
518*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
51936396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
52036396Ssklower	}
52136396Ssklower;
52236396Ssklower/* NBS(6) */
52336396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
52436396Ssklower	($P.tp_class == TP_CLASS_0)
52536396Ssklower	{
526*51204Ssklower		tp_cuntimeout($P, TM_retrans);
52736396Ssklower		IncStat(ts_tp0_conn);
52836396Ssklower		$P.tp_fcredit = 1;
52936396Ssklower		soisconnected($P.tp_sock);
53036396Ssklower	}
53136396Ssklower;
53236396Ssklower
53336396SsklowerTP_OPEN			<==		TP_CRSENT									CC_TPDU
53436396Ssklower	DEFAULT
53536396Ssklower	{
53636396Ssklower		IFDEBUG(D_CONN)
53736396Ssklower			printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
53836396Ssklower				(int)$P.tp_flags);
53936396Ssklower		ENDDEBUG
54036396Ssklower		IncStat(ts_tp4_conn);
54136396Ssklower		$P.tp_fref = $$.e_sref;
54236396Ssklower		$P.tp_fcredit = $$.e_cdt;
54347281Ssklower		if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
544*51204Ssklower			$P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize;
54536396Ssklower		tp_getoptions($P);
546*51204Ssklower		tp_cuntimeout($P, TM_retrans);
54737469Ssklower		if ($P.tp_ucddata) {
54836396Ssklower			IFDEBUG(D_CONN)
54937469Ssklower				printf("dropping user connect data cc 0x%x\n",
55037469Ssklower					$P.tp_ucddata->m_len);
55136396Ssklower			ENDDEBUG
55237469Ssklower			m_freem($P.tp_ucddata);
55337469Ssklower			$P.tp_ucddata = 0;
55436396Ssklower		}
55536396Ssklower		soisconnected($P.tp_sock);
55636396Ssklower		if ($$.e_datalen > 0) {
55736396Ssklower			ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
55836396Ssklower			sbappendrecord(&$P.tp_Xrcv, $$.e_data);
55936396Ssklower			$$.e_data = MNULL;
56036396Ssklower		}
56136396Ssklower
56236396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
563*51204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
56436396Ssklower	}
56536396Ssklower;
56636396Ssklower
56736396Ssklower/* TP4 only */
56836396SsklowerSAME			<==		TP_CRSENT									TM_retrans
56936396Ssklower	(	$P.tp_retrans > 0 )
57036396Ssklower	{
57136396Ssklower		struct mbuf *data = MNULL;
57236396Ssklower		int error;
57336396Ssklower
57436396Ssklower		IncStat(ts_retrans_cr);
575*51204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
57637469Ssklower		data = MCPY($P.tp_ucddata, M_NOWAIT);
57737469Ssklower		if($P.tp_ucddata) {
57836396Ssklower			IFDEBUG(D_CONN)
57937469Ssklower				printf("TM_retrans.trans m_copy cc 0x%x\n", data);
58037469Ssklower				dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
58136396Ssklower			ENDDEBUG
58236396Ssklower			if( data == MNULL )
58336396Ssklower				return ENOBUFS;
58436396Ssklower		}
58536396Ssklower
58636396Ssklower		$P.tp_retrans --;
58736396Ssklower		if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
58836396Ssklower			$P.tp_sock->so_error = error;
58936396Ssklower		}
590*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
59136396Ssklower	}
59236396Ssklower;
59336396Ssklower
59436396Ssklower/* TP4 only  */
59536396SsklowerTP_REFWAIT		<==		TP_CRSENT									TM_retrans
59636396Ssklower	DEFAULT /* no more CR retransmissions */
59736396Ssklower	{
59836396Ssklower		IncStat(ts_conn_gaveup);
59936396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
60036396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
60136396Ssklower		tp_soisdisconnected($P);
60236396Ssklower	}
60336396Ssklower;
60436396Ssklower
60536396Ssklower/* TP4 only */
60636396SsklowerSAME 			<==	 TP_AKWAIT											CR_TPDU
60736396Ssklower	DEFAULT
60836396Ssklower	/* duplicate CR (which doesn't really exist in the context of
60936396Ssklower	 * a connectionless network layer)
61036396Ssklower	 * Doesn't occur in class 0.
61136396Ssklower	 */
61236396Ssklower	{
61336396Ssklower		int error;
61437469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
61536396Ssklower
61637469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
61736396Ssklower			$P.tp_sock->so_error = error;
61836396Ssklower		}
61936396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
620*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
62136396Ssklower	}
62236396Ssklower;
62336396Ssklower
62436396Ssklower/* TP4 only */
62536396SsklowerTP_OPEN			<==		TP_AKWAIT 										DT_TPDU
62636396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
62736396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
62836396Ssklower	{
62936396Ssklower		int doack;
63036396Ssklower
63137469Ssklower		/*
63237469Ssklower		 * Get rid of any confirm or connect data, so that if we
63337469Ssklower		 * crash or close, it isn't thought of as disconnect data.
63437469Ssklower		 */
63537469Ssklower		if ($P.tp_ucddata) {
63637469Ssklower			m_freem($P.tp_ucddata);
63737469Ssklower			$P.tp_ucddata = 0;
63836396Ssklower		}
639*51204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
640*51204Ssklower		tp_cuntimeout($P, TM_retrans);
64136396Ssklower		soisconnected($P.tp_sock);
642*51204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
64336396Ssklower
64436396Ssklower		/* see also next 2 transitions, if you make any changes */
64536396Ssklower
64636396Ssklower		doack = tp_stash($P, $E);
64736396Ssklower		IFDEBUG(D_DATA)
64836396Ssklower			printf("tp_stash returns %d\n",doack);
64936396Ssklower		ENDDEBUG
65036396Ssklower
651*51204Ssklower		if (doack) {
65236396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
653*51204Ssklower			tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
65436396Ssklower		} else
655*51204Ssklower			tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks);
65636396Ssklower
65736396Ssklower		IFDEBUG(D_DATA)
65836396Ssklower			printf("after stash calling sbwakeup\n");
65936396Ssklower		ENDDEBUG
66036396Ssklower	}
66136396Ssklower;
66236396Ssklower
66336396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
66436396Ssklower	( $P.tp_class == TP_CLASS_0 )
66536396Ssklower	{
66636396Ssklower		tp0_stash($P, $E);
66736396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
66836396Ssklower
66936396Ssklower		IFDEBUG(D_DATA)
67036396Ssklower			printf("after stash calling sbwakeup\n");
67136396Ssklower		ENDDEBUG
67236396Ssklower	}
67336396Ssklower;
67436396Ssklower
67536396Ssklower/* TP4 only */
67636396SsklowerSAME			<==		TP_OPEN 									DT_TPDU
67736396Ssklower	( IN_RWINDOW( $P, $$.e_seq,
67836396Ssklower					$P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
67936396Ssklower	{
68036396Ssklower		int doack; /* tells if we must ack immediately */
68136396Ssklower
682*51204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
68336396Ssklower		sbwakeup( &$P.tp_sock->so_rcv );
68436396Ssklower
68536396Ssklower		doack = tp_stash($P, $E);
68636396Ssklower		IFDEBUG(D_DATA)
68736396Ssklower			printf("tp_stash returns %d\n",doack);
68836396Ssklower		ENDDEBUG
68936396Ssklower
69036396Ssklower		if(doack)
69136396Ssklower			(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
69236396Ssklower		else
693*51204Ssklower			tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks);
69436396Ssklower
69536396Ssklower		IFDEBUG(D_DATA)
69636396Ssklower			printf("after stash calling sbwakeup\n");
69736396Ssklower		ENDDEBUG
69836396Ssklower	}
69936396Ssklower;
70036396Ssklower
70136396Ssklower/* Not in window  - we must ack under certain circumstances, namely
70236396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given)
70336396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^.
70436396Ssklower * and
70536396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
70636396Ssklower *
70736396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73)
70836396Ssklower * We just always ack.
70936396Ssklower */
71036396Ssklower/* TP4 only */
71136396SsklowerSAME 			<== 	[ TP_OPEN, TP_AKWAIT ]							DT_TPDU
71236396Ssklower	DEFAULT /* Not in window */
71336396Ssklower	{
71436396Ssklower		IFTRACE(D_DATA)
71536396Ssklower			tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
71636396Ssklower				$$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
71736396Ssklower		ENDTRACE
71836396Ssklower		IncStat(ts_dt_niw);
71936396Ssklower		m_freem($$.e_data);
720*51204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
72136396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
72236396Ssklower	}
72336396Ssklower;
72436396Ssklower
72536396Ssklower/* TP4 only */
72636396SsklowerTP_OPEN			<==		TP_AKWAIT										AK_TPDU
72736396Ssklower	DEFAULT
72836396Ssklower	{
72937469Ssklower		if ($P.tp_ucddata) {
73037469Ssklower			m_freem($P.tp_ucddata);
73137469Ssklower			$P.tp_ucddata = 0;
73236396Ssklower		}
73336396Ssklower		(void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
734*51204Ssklower		tp_cuntimeout($P, TM_retrans);
73536396Ssklower
73636396Ssklower		soisconnected($P.tp_sock);
73736396Ssklower		IFTRACE(D_CONN)
73836396Ssklower			struct socket *so = $P.tp_sock;
73936396Ssklower			tptrace(TPPTmisc,
74036396Ssklower			"called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
74136396Ssklower				so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
74236396Ssklower			tptrace(TPPTmisc,
74336396Ssklower			"called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
74436396Ssklower				so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
74536396Ssklower		ENDTRACE
74636396Ssklower
747*51204Ssklower		tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
748*51204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
74936396Ssklower	}
75036396Ssklower;
75136396Ssklower
75236396Ssklower/* TP4 only */
75336396SsklowerTP_OPEN 		<== 	[ TP_OPEN, TP_AKWAIT ]						XPD_TPDU
75447281Ssklower	($P.tp_Xrcvnxt == $$.e_seq)
75536396Ssklower	{
75636396Ssklower		if( $P.tp_state == TP_AKWAIT ) {
75737469Ssklower			if ($P.tp_ucddata) {
75837469Ssklower				m_freem($P.tp_ucddata);
75937469Ssklower				$P.tp_ucddata = 0;
76036396Ssklower			}
761*51204Ssklower			tp_cuntimeout($P, TM_retrans);
76236396Ssklower			soisconnected($P.tp_sock);
763*51204Ssklower			tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
764*51204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
76536396Ssklower		}
76636396Ssklower		IFTRACE(D_XPD)
76736396Ssklower		tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
76836396Ssklower				$P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
76936396Ssklower		ENDTRACE
77036396Ssklower
77137469Ssklower		$P.tp_sock->so_state |= SS_RCVATMARK;
77247281Ssklower		$$.e_data->m_flags |= M_EOR;
77337469Ssklower		sbinsertoob(&$P.tp_Xrcv, $$.e_data);
77436396Ssklower		IFDEBUG(D_XPD)
77536396Ssklower			dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
77636396Ssklower		ENDDEBUG
77736396Ssklower		tp_indicate(T_XDATA, $P, 0);
77836396Ssklower		sbwakeup( &$P.tp_Xrcv );
77936396Ssklower
78036396Ssklower		(void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
78136396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
78236396Ssklower	}
78336396Ssklower;
78436396Ssklower
78536396Ssklower/* TP4 only */
78636396SsklowerSAME			<==		TP_OPEN 									T_USR_Xrcvd
78736396Ssklower	DEFAULT
78836396Ssklower	{
78936396Ssklower		if( $P.tp_Xrcv.sb_cc == 0 ) {
79036396Ssklower			/* kludge for select(): */
79137469Ssklower			/* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
79236396Ssklower		}
79336396Ssklower	}
79436396Ssklower	/* OLD WAY:
79536396Ssklower	 * Ack only after the user receives the XPD.  This is better for
79636396Ssklower	 * users that use one XPD right after another.
79736396Ssklower	 * Acking right away (the NEW WAY, see the prev. transition) is
79836396Ssklower	 * better for occasional * XPD, when the receiving user doesn't
79936396Ssklower	 * want to read the XPD immediately (which is session's behavior).
80036396Ssklower	 *
80136396Ssklower		int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
80236396Ssklower		SEQ_INC($P, $P.tp_Xrcvnxt);
80336396Ssklower		return error;
80436396Ssklower	*/
80536396Ssklower;
80636396Ssklower
80736396Ssklower/* NOTE: presently if the user doesn't read the connection data
80836396Ssklower * before and expedited data PDU comes in, the connection data will
80936396Ssklower * be dropped. This is a bug.  To avoid it, we need somewhere else
81036396Ssklower * to put the connection data.
81136396Ssklower * On the other hand, we need not to have it sitting around forever.
81236396Ssklower * This is a problem with the idea of trying to accommodate
81336396Ssklower * data on connect w/ a passive-open user interface.
81436396Ssklower */
81536396Ssklower/* TP4 only */
81636396Ssklower
81736396SsklowerSAME	 		<== 	[ TP_AKWAIT, TP_OPEN ] 							XPD_TPDU
81836396Ssklower	DEFAULT /* not in window or cdt==0 */
81936396Ssklower	{
82036396Ssklower		IFTRACE(D_XPD)
82136396Ssklower			tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
82236396Ssklower				$P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
82336396Ssklower		ENDTRACE
82436396Ssklower		if( $P.tp_Xrcvnxt != $$.e_seq )
82536396Ssklower			IncStat(ts_xpd_niw);
82636396Ssklower		if( $P.tp_Xrcv.sb_cc ) {
82736396Ssklower			/* might as well kick 'em again */
82836396Ssklower			tp_indicate(T_XDATA, $P, 0);
82936396Ssklower			IncStat(ts_xpd_dup);
83036396Ssklower		}
83136396Ssklower		m_freem($$.e_data);
832*51204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
83336396Ssklower		/* don't send an xack because the xak gives "last one received", not
83436396Ssklower		 * "next one i expect" (dumb)
83536396Ssklower		 */
83636396Ssklower	}
83736396Ssklower;
83836396Ssklower
83936396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
84036396Ssklower * to detach all its "children"
84136396Ssklower * Also (CRSENT) when user kills a job that's doing a connect()
84236396Ssklower */
84336396SsklowerTP_REFWAIT		<== 	TP_CRSENT 										T_DETACH
84436396Ssklower	($P.tp_class == TP_CLASS_0)
84536396Ssklower	{
84636396Ssklower		struct socket *so = $P.tp_sock;
84736396Ssklower
84836396Ssklower		/* detach from parent socket so it can finish closing */
84936396Ssklower		if (so->so_head) {
85036396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
85136396Ssklower				panic("tp: T_DETACH");
85236396Ssklower			so->so_head = 0;
85336396Ssklower		}
85436396Ssklower		tp_soisdisconnecting($P.tp_sock);
85536396Ssklower		tp_netcmd( $P, CONN_CLOSE);
85636396Ssklower		tp_soisdisconnected($P);
85736396Ssklower	}
85836396Ssklower;
85936396Ssklower
86036396Ssklower/* TP4 only */
86138841SsklowerTP_CLOSING		<== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ]	T_DETACH
86236396Ssklower	DEFAULT
86336396Ssklower	{
86436396Ssklower		struct socket *so = $P.tp_sock;
86537469Ssklower		struct mbuf *data = MNULL;
86636396Ssklower
86736396Ssklower		/* detach from parent socket so it can finish closing */
86836396Ssklower		if (so->so_head) {
86936396Ssklower			if (!soqremque(so, 0) && !soqremque(so, 1))
87036396Ssklower				panic("tp: T_DETACH");
87136396Ssklower			so->so_head = 0;
87236396Ssklower		}
87336396Ssklower		if ($P.tp_state != TP_CLOSING) {
87436396Ssklower			tp_soisdisconnecting($P.tp_sock);
87537469Ssklower			data = MCPY($P.tp_ucddata, M_NOWAIT);
87637469Ssklower			(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
87736396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
878*51204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
87936396Ssklower		}
88036396Ssklower	}
88136396Ssklower;
88236396Ssklower
88336396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT ]		 	  			T_DISC_req
88436396Ssklower	( $P.tp_class == TP_CLASS_0 )
88536396Ssklower	{
88636396Ssklower		tp_soisdisconnecting($P.tp_sock);
88736396Ssklower		tp_netcmd( $P, CONN_CLOSE);
88836396Ssklower		tp_soisdisconnected($P);
88936396Ssklower	}
89036396Ssklower;
89136396Ssklower
89236396Ssklower/* TP4 only */
89338841SsklowerTP_CLOSING		<==	[ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
89436396Ssklower	DEFAULT
89536396Ssklower	{
89637469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
89736396Ssklower
89836396Ssklower		if($P.tp_state == TP_OPEN) {
899*51204Ssklower			tp_euntimeout($P, TM_data_retrans); /* all */
900*51204Ssklower			tp_cuntimeout($P, TM_inact);
901*51204Ssklower			tp_cuntimeout($P, TM_sendack);
90236396Ssklower		}
90337469Ssklower		if (data) {
90436396Ssklower			IFDEBUG(D_CONN)
90537469Ssklower				printf("T_DISC_req.trans tp_ucddata 0x%x\n",
90637469Ssklower					$P.tp_ucddata);
90737469Ssklower				dump_mbuf(data, "ucddata @ T_DISC_req");
90836396Ssklower			ENDDEBUG
90936396Ssklower		}
91036396Ssklower		tp_soisdisconnecting($P.tp_sock);
91136396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
912*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
91336396Ssklower
91436396Ssklower		if( trick_hc )
91536396Ssklower			return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
91636396Ssklower	}
91736396Ssklower;
91836396Ssklower
91936396Ssklower/* TP4 only */
92036396SsklowerSAME			<==		TP_AKWAIT									TM_retrans
92136396Ssklower	( $P.tp_retrans > 0 )
92236396Ssklower	{
92336396Ssklower		int error;
92437469Ssklower		struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
92536396Ssklower
92636396Ssklower		IncStat(ts_retrans_cc);
92736396Ssklower		$P.tp_retrans --;
928*51204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
92939921Ssklower
93037469Ssklower		if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
93136396Ssklower			$P.tp_sock->so_error = error;
932*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
93336396Ssklower	}
93436396Ssklower;
93536396Ssklower
93636396Ssklower/* TP4 only */
93736396SsklowerTP_CLOSING		<==		TP_AKWAIT									TM_retrans
93836396Ssklower	DEFAULT  /* out of time */
93936396Ssklower	{
94036396Ssklower		IncStat(ts_conn_gaveup);
94136396Ssklower		tp_soisdisconnecting($P.tp_sock);
94236396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
94336396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
94436396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
94536396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
946*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
94736396Ssklower	}
94836396Ssklower;
94936396Ssklower
95036396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does,
95136396Ssklower * if transmissions are going on.
95236396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack
95336396Ssklower * turnaround)
95436396Ssklower */
95536396Ssklower/* TP4 only */
95636396SsklowerTP_CLOSING 		<==		TP_OPEN		   [ TM_inact, TM_retrans, TM_data_retrans ]
95736396Ssklower	DEFAULT
95836396Ssklower	{
959*51204Ssklower		tp_euntimeout($P, TM_data_retrans); /* all */
960*51204Ssklower		tp_cuntimeout($P, TM_inact);
961*51204Ssklower		tp_cuntimeout($P, TM_sendack);
96236396Ssklower
96336396Ssklower		IncStat(ts_conn_gaveup);
96436396Ssklower		tp_soisdisconnecting($P.tp_sock);
96536396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
96636396Ssklower		tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
96736396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
96836396Ssklower		$P.tp_retrans = $P.tp_Nretrans;
969*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
97036396Ssklower	}
97136396Ssklower;
97236396Ssklower
97336396Ssklower/* TP4 only */
97436396SsklowerSAME			<==		TP_OPEN										TM_retrans
97536396Ssklower	( $P.tp_retrans > 0 )
97636396Ssklower	{
977*51204Ssklower		$P.tp_cong_win = 1 * $P.tp_l_tpdusize;
97836396Ssklower		/* resume XPD */
97936396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
98037469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
981*51204Ssklower			int shift;
98236396Ssklower
98336396Ssklower			IFTRACE(D_XPD)
984*51204Ssklower				tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna",
985*51204Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt,
98636396Ssklower					$P.tp_snduna);
98736396Ssklower			ENDTRACE
98836396Ssklower			IFDEBUG(D_XPD)
98936396Ssklower				dump_mbuf(m, "XPD retrans emitting M");
99036396Ssklower			ENDDEBUG
99136396Ssklower			IncStat(ts_retrans_xpd);
99236396Ssklower			$P.tp_retrans --;
993*51204Ssklower			shift = max($P.tp_Nretrans - $P.tp_retrans, 6);
99436396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
995*51204Ssklower			tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift);
99636396Ssklower		}
99736396Ssklower	}
99836396Ssklower;
99936396Ssklower
100036396Ssklower/* TP4 only */
100136396SsklowerSAME 			<==		TP_OPEN									TM_data_retrans
1002*51204Ssklower	($P.tp_rxtshift < TP_NRETRANS)
100336396Ssklower	{
1004*51204Ssklower		$P.tp_rxtshift++;
1005*51204Ssklower		(void) tp_data_retrans($P);
100636396Ssklower	}
100736396Ssklower;
100836396Ssklower
100936396Ssklower/* TP4 only */
101036396SsklowerSAME	 		<==		TP_CLOSING									TM_retrans
101136396Ssklower	(	$P.tp_retrans > 0 )
101236396Ssklower	{
101336396Ssklower		$P.tp_retrans --;
101436396Ssklower		(void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
101536396Ssklower		IncStat(ts_retrans_dr);
1016*51204Ssklower		tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
101736396Ssklower	}
101836396Ssklower;
101936396Ssklower
102036396Ssklower/* TP4 only */
102136396SsklowerTP_REFWAIT 		<==		TP_CLOSING									TM_retrans
102236396Ssklower	DEFAULT	/* no more retrans - gave up */
102336396Ssklower	{
102436396Ssklower		$P.tp_sock->so_error = ETIMEDOUT;
1025*51204Ssklower		$P.tp_refstate = REF_FROZEN;
102636396Ssklower		tp_recycle_tsuffix( $P );
1027*51204Ssklower		tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
102836396Ssklower	}
102936396Ssklower;
103036396Ssklower
103136396Ssklower/*
103236396Ssklower * The resources are kept around until the ref timer goes off.
103336396Ssklower * The suffices are wiped out sooner so they can be reused right away.
103436396Ssklower */
103536396Ssklower/* applicable in TP4, TP0 */
103636396SsklowerTP_CLOSED 		<==		TP_REFWAIT 									TM_reference
103736396Ssklower	DEFAULT
103836396Ssklower	{
103936396Ssklower		tp_freeref($P.tp_refp);
104036396Ssklower		tp_detach($P);
104136396Ssklower	}
104236396Ssklower;
104336396Ssklower
104436396Ssklower/* applicable in TP4, TP0 */
104536396Ssklower/* A duplicate CR from connectionless network layer can't happen */
104636396SsklowerSAME 			<== 	TP_OPEN 							[ CR_TPDU, CC_TPDU ]
104736396Ssklower	DEFAULT
104836396Ssklower	{
104936396Ssklower		if( $P.tp_class != TP_CLASS_0) {
1050*51204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
105136396Ssklower			if ( $E.ev_number == CC_TPDU )
105236396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
105336396Ssklower		}
105436396Ssklower		/* ignore it if class 0 - state tables are blank for this */
105536396Ssklower	}
105636396Ssklower;
105736396Ssklower
105836396Ssklower/* applicable in TP4, TP0 */
105936396SsklowerSAME			<== 	TP_OPEN									T_DATA_req
106036396Ssklower	DEFAULT
106136396Ssklower	{
106236396Ssklower		IFTRACE(D_DATA)
1063*51204Ssklower			tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb",
1064*51204Ssklower				$P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P);
106536396Ssklower		ENDTRACE
106636396Ssklower
106736396Ssklower		tp_send($P);
106836396Ssklower	}
106936396Ssklower;
107036396Ssklower
107136396Ssklower/* TP4 only */
107236396SsklowerSAME			<==		TP_OPEN										T_XPD_req
107336396Ssklower	DEFAULT
107436396Ssklower		/* T_XPD_req was issued by sosend iff xpd socket buf was empty
107536396Ssklower		 * at time of sosend(),
107636396Ssklower		 * AND (which means) there were no unacknowledged XPD tpdus outstanding!
107736396Ssklower		 */
107836396Ssklower	{
107936396Ssklower		int error = 0;
108036396Ssklower
108136396Ssklower		/* resume XPD */
108236396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
108337469Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
108436396Ssklower			/* m_copy doesn't preserve the m_xlink field, but at this pt.
108536396Ssklower			 * that doesn't matter
108636396Ssklower			 */
108736396Ssklower
108836396Ssklower			IFTRACE(D_XPD)
1089*51204Ssklower				tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna",
1090*51204Ssklower					$P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt,
109136396Ssklower					$P.tp_snduna);
109236396Ssklower			ENDTRACE
109336396Ssklower			IFDEBUG(D_XPD)
109436396Ssklower				printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
109536396Ssklower				dump_mbuf(m, "XPD req emitting M");
109636396Ssklower			ENDDEBUG
109736396Ssklower			error =
109836396Ssklower				tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
109936396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
1100*51204Ssklower
1101*51204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur);
110236396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
110336396Ssklower		}
110436396Ssklower		if(trick_hc)
110536396Ssklower			return error;
110636396Ssklower	}
110736396Ssklower;
110836396Ssklower
110936396Ssklower/* TP4, faked ack in TP0 when cons send completes */
111036396SsklowerSAME 			<==		TP_OPEN 									AK_TPDU
111136396Ssklower	( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
111236396Ssklower
111336396Ssklower	/* tp_goodack == true means
111436396Ssklower	 * EITHER it actually acked something heretofore unacknowledged
111536396Ssklower	 * OR no news but the credit should be processed.
111636396Ssklower	 */
111736396Ssklower	{
111850904Ssklower		struct sockbuf *sb = &$P.tp_sock->so_snd;
111950904Ssklower
112036396Ssklower		IFDEBUG(D_ACKRECV)
112136396Ssklower			printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
112236396Ssklower		ENDDEBUG
112336396Ssklower		if( $P.tp_class != TP_CLASS_0) {
1124*51204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
112536396Ssklower		}
112650904Ssklower		sbwakeup(sb);
112736396Ssklower		IFDEBUG(D_ACKRECV)
1128*51204Ssklower			printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt);
112936396Ssklower		ENDDEBUG
113036396Ssklower	}
113136396Ssklower;
113236396Ssklower
113336396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
113436396SsklowerSAME			<==		TP_OPEN 			 						 AK_TPDU
113536396Ssklower	DEFAULT
113636396Ssklower	{
113736396Ssklower		IFTRACE(D_ACKRECV)
113836396Ssklower			tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
113936396Ssklower				$$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
114036396Ssklower		ENDTRACE
114136396Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
114236396Ssklower
114336396Ssklower			if ( !$$.e_fcc_present ) {
114436396Ssklower				/* send ACK with FCC */
114536396Ssklower				IncStat( ts_ackreason[_ACK_FCC_] );
114636396Ssklower				(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
114736396Ssklower			}
1148*51204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
114936396Ssklower		}
115036396Ssklower	}
115136396Ssklower;
115236396Ssklower
115336396Ssklower/* NBS(47) */
115436396Ssklower	/* goes in at *** */
115536396Ssklower		/* just so happens that this is never true now, because we allow
115636396Ssklower		 * only 1 packet in the queue at once (this could be changed)
115736396Ssklower		if	( $P.tp_Xsnd.sb_mb )  {
115836396Ssklower			struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
115936396Ssklower
116036396Ssklower			(void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
116136396Ssklower			$P.tp_retrans = $P.tp_Nretrans;
1162*51204Ssklower			tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks);
116336396Ssklower			SEQ_INC($P, $P.tp_Xsndnxt);
116436396Ssklower		}
116536396Ssklower		 */
116636396Ssklower	/* end of the above hack */
116736396Ssklower
116836396Ssklower/* TP4 only */
116942944SsklowerSAME			<== 	TP_OPEN										XAK_TPDU
117036396Ssklower	( tp_goodXack($P, $$.e_seq) )
117136396Ssklower	/* tp_goodXack checks for good ack, removes the correct
117236396Ssklower	 * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
117336396Ssklower	 * also updates tp_Xuna
117436396Ssklower	 */
117536396Ssklower	{
1176*51204Ssklower		tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
1177*51204Ssklower		tp_cuntimeout($P, TM_retrans);
117836396Ssklower
117936396Ssklower		sbwakeup( &$P.tp_sock->so_snd );
118036396Ssklower
118136396Ssklower		/* resume normal data */
118236396Ssklower		tp_send($P);
118336396Ssklower	}
118436396Ssklower;
118536396Ssklower
118642944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */
118742944SsklowerSAME			<==		TP_OPEN 			 						XAK_TPDU
118842944Ssklower	DEFAULT
118942944Ssklower	{
119042944Ssklower		IFTRACE(D_ACKRECV)
119142944Ssklower			tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
119242944Ssklower		ENDTRACE
119342944Ssklower		if( $P.tp_class != TP_CLASS_0 ) {
1194*51204Ssklower			tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
119542944Ssklower		}
119642944Ssklower	}
119742944Ssklower;
119842944Ssklower
119936396Ssklower/* TP4 only */
120036396SsklowerSAME			<==		TP_OPEN 								TM_sendack
120136396Ssklower	DEFAULT
120236396Ssklower	{
1203*51204Ssklower		int timo;
120436396Ssklower		IFTRACE(D_TIMER)
120536396Ssklower			tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
120636396Ssklower			$P.tp_sent_lcdt, 0);
120736396Ssklower		ENDTRACE
120836396Ssklower		IncPStat($P, tps_n_TMsendack);
120936396Ssklower		(void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
121036396Ssklower	}
121136396Ssklower;
121236396Ssklower
121336396Ssklower/* TP0 only */
121436396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
121536396Ssklower	($P.tp_class == TP_CLASS_0)
121647281Ssklower	{
121747281Ssklower		if (sbspace(&$P.tp_sock->so_rcv) > 0)
121847281Ssklower			tp0_openflow($P);
121947281Ssklower	}
122036396Ssklower;
122136396Ssklower
122236396Ssklower/* TP4 only */
122336396Ssklower		/* If old credit was zero,
122436396Ssklower		 * we'd better inform other side that we now have space
122536396Ssklower		 * But this is not enough.  Sender might not yet have
122636396Ssklower		 * seen an ack with cdt 0 but it might still think the
122736396Ssklower		 * window is closed, so it's going to wait.
122836396Ssklower		 * Best to send an ack each time.
122936396Ssklower		 * Strictly speaking, this ought to be a function of the
123036396Ssklower		 * general ack strategy.
123136396Ssklower		 */
123236396SsklowerSAME			<==		TP_OPEN 									T_USR_rcvd
123336396Ssklower	DEFAULT
123436396Ssklower	{
123536396Ssklower		if( trick_hc ) {
123651024Ssklower			SeqNum ack_thresh;
123750849Ssklower			/*
123851024Ssklower			 * If the upper window edge has advanced a reasonable
123951024Ssklower			 * amount beyond what was known, send an ACK.
124051024Ssklower			 * A reasonable amount is 2 packets, unless the max window
124151024Ssklower			 * is only 1 or 2 packets, in which case we
124251024Ssklower			 * should send an ack for any advance in the upper window edge.
124350849Ssklower			 */
124451024Ssklower			LOCAL_CREDIT($P);
124551024Ssklower			ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt,
124651024Ssklower									 ($P.tp_maxlcredit > 2 ? 2 : 1));
124751024Ssklower			if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) {
124850849Ssklower				IncStat(ts_ackreason[_ACK_USRRCV_]);
124951024Ssklower				$P.tp_flags &= ~TPF_DELACK;
125039921Ssklower				return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
125150849Ssklower			}
125236396Ssklower		}
125336396Ssklower	}
125436396Ssklower;
125536396Ssklower
125636396Ssklower/* applicable in TP4, TP0 */
125736396SsklowerSAME			<==		TP_REFWAIT 				[ T_USR_rcvd, T_USR_Xrcvd ]
125836396Ssklower	DEFAULT
125936396Ssklower	/* This happens if other end sent a DR when  the user was waiting
126036396Ssklower	 * on a receive.
126136396Ssklower	 * Processing the DR includes putting us in REFWAIT state.
126236396Ssklower	 */
126336396Ssklower	{
126436396Ssklower		if(trick_hc)
126536396Ssklower		return ECONNABORTED;
126636396Ssklower	}
126736396Ssklower;
126836396Ssklower
126936396Ssklower/* TP0 only */
127036396SsklowerTP_REFWAIT		<==		[ TP_OPEN, TP_CRSENT, TP_LISTENING ] 	T_NETRESET
127136396Ssklower	( $P.tp_class != TP_CLASS_4 )
127236396Ssklower		/* 0 or (4 and 0) */
127336396Ssklower		/* in OPEN class will be 0 or 4 but not both */
127436396Ssklower		/* in CRSENT or LISTENING it could be in negotiation, hence both */
127536396Ssklower		/* Actually, this shouldn't ever happen in LISTENING */
127636396Ssklower	{
127736396Ssklower		ASSERT( $P.tp_state != TP_LISTENING );
127836396Ssklower		tp_indicate(T_DISCONNECT, $P, ECONNRESET);
127936396Ssklower		tp_soisdisconnected($P);
128036396Ssklower	}
128136396Ssklower;
128236396Ssklower
128336396Ssklower/* TP4: ignore resets */
128436396SsklowerSAME		<==		[ TP_OPEN, TP_CRSENT, TP_AKWAIT,
128536396Ssklower						TP_CLOSING, TP_LISTENING ] 				T_NETRESET
128636396Ssklower	DEFAULT
128736396Ssklower	NULLACTION
128836396Ssklower;
128936396Ssklower
129036396Ssklower/* applicable in TP4, TP0 */
129136396SsklowerSAME			<==		[ TP_CLOSED, TP_REFWAIT ]				T_NETRESET
129236396Ssklower	DEFAULT
129336396Ssklower	NULLACTION
129436396Ssklower;
129536396Ssklower
129636396Ssklower/* C'EST TOUT */
1297