136396Ssklower/*********************************************************** 236396Ssklower Copyright IBM Corporation 1987 336396Ssklower 436396Ssklower All Rights Reserved 536396Ssklower 636396SsklowerPermission to use, copy, modify, and distribute this software and its 736396Ssklowerdocumentation for any purpose and without fee is hereby granted, 836396Ssklowerprovided that the above copyright notice appear in all copies and that 936396Ssklowerboth that copyright notice and this permission notice appear in 1036396Ssklowersupporting documentation, and that the name of IBM not be 1136396Ssklowerused in advertising or publicity pertaining to distribution of the 1236396Ssklowersoftware without specific, written prior permission. 1336396Ssklower 1436396SsklowerIBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536396SsklowerALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636396SsklowerIBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736396SsklowerANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836396SsklowerWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936396SsklowerARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036396SsklowerSOFTWARE. 2136396Ssklower 2236396Ssklower******************************************************************/ 2336396Ssklower 2436396Ssklower/* 2536396Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636396Ssklower */ 2736396Ssklower/* $Header: tp.trans,v 5.1 88/10/12 12:22:07 root Exp $ 2836396Ssklower * 2936396Ssklower * Transition file for TP. 3036396Ssklower * 3136396Ssklower * DO NOT: 3236396Ssklower * - change the order of any of the events or states. to do so will 3336396Ssklower * make tppt, netstat, etc. cease working. 3436396Ssklower * 3536396Ssklower * NOTE: 3636396Ssklower * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED*** 3736396Ssklower * (read: may not work!) 3836396Ssklower * 3936396Ssklower * I tried to put everything that causes a change of state in here, hence 4036396Ssklower * there are some seemingly trivial events like T_DETACH and T_LISTEN_req. 4136396Ssklower * 4236396Ssklower * Almost everything having to do w/ setting & cancelling timers is here 4336396Ssklower * but once it was debugged, I moved the setting of the 4436396Ssklower * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent. 4536396Ssklower * This is so the code wouldn't be duplicated all over creation in here. 4636396Ssklower * 4736396Ssklower */ 4836396Ssklower*PROTOCOL tp 4936396Ssklower 5036396Ssklower*INCLUDE 5136396Ssklower 5236396Ssklower{ 53*48739Ssklower/* @(#)tp.trans 7.7 (Berkeley) 04/26/91 */ 5436396Ssklower#include "param.h" 5536396Ssklower#include "socket.h" 5636396Ssklower#include "socketvar.h" 5736396Ssklower#include "protosw.h" 5836396Ssklower#include "mbuf.h" 5936396Ssklower#include "time.h" 6036396Ssklower#include "errno.h" 6136396Ssklower#include "../netiso/tp_param.h" 6236396Ssklower#include "../netiso/tp_stat.h" 6336396Ssklower#include "../netiso/tp_pcb.h" 6436396Ssklower#include "../netiso/tp_tpdu.h" 6536396Ssklower#include "../netiso/argo_debug.h" 6636396Ssklower#include "../netiso/tp_trace.h" 6736396Ssklower#include "../netiso/iso_errno.h" 6836396Ssklower#include "../netiso/tp_seq.h" 6936396Ssklower#include "../netiso/cons.h" 7036396Ssklower 7136396Ssklower#define DRIVERTRACE TPPTdriver 7237469Ssklower#define sbwakeup(sb) sowakeup(p->tp_sock, sb); 7337469Ssklower#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0) 7436396Ssklower 7536396Ssklowerstatic trick_hc = 1; 7636396Ssklower 7736396Ssklowerint tp_emit(), 7836396Ssklower tp_goodack(), tp_goodXack(), 7936396Ssklower tp_stash() 8036396Ssklower; 8136396Ssklowervoid tp_indicate(), tp_getoptions(), 8236396Ssklower tp_soisdisconnecting(), tp_soisdisconnected(), 8336396Ssklower tp_recycle_tsuffix(), 8436396Ssklower tp_etimeout(), tp_euntimeout(), 8536396Ssklower tp_euntimeout_lss(), tp_ctimeout(), 8636396Ssklower tp_cuntimeout(), tp_ctimeout_MIN(), 8736396Ssklower tp_freeref(), tp_detach(), 8836396Ssklower tp0_stash(), tp0_send(), 8936396Ssklower tp_netcmd(), tp_send() 9036396Ssklower; 9136396Ssklower 9236396Ssklowertypedef struct tp_pcb tpcb_struct; 9336396Ssklower 9436396Ssklower 9536396Ssklower} 9636396Ssklower 9736396Ssklower*PCB tpcb_struct SYNONYM P 9836396Ssklower 9936396Ssklower*STATES 10036396Ssklower 10136396SsklowerTP_CLOSED 10236396SsklowerTP_CRSENT 10336396SsklowerTP_AKWAIT 10436396SsklowerTP_OPEN 10536396SsklowerTP_CLOSING 10636396SsklowerTP_REFWAIT 10736396SsklowerTP_LISTENING /* Local to this implementation */ 10838841SsklowerTP_CONFIRMING /* Local to this implementation */ 10936396Ssklower 11036396Ssklower*EVENTS { struct timeval e_time; } SYNONYM E 11136396Ssklower 11236396Ssklower /* 11336396Ssklower * C (typically cancelled) timers - 11436396Ssklower * 11536396Ssklower * let these be the first ones so for the sake of convenience 11636396Ssklower * their values are 0--> n-1 11736396Ssklower * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!! 11836396Ssklower */ 11936396Ssklower TM_inact 12036396Ssklower TM_retrans 12136396Ssklower /* TM_retrans is used for all 12236396Ssklower * simple retransmissions - CR,CC,XPD,DR 12336396Ssklower */ 12436396Ssklower 12536396Ssklower TM_sendack 12636396Ssklower /* TM_sendack does dual duty - keepalive AND sendack. 12736396Ssklower * It's set w/ keepalive-ticks every time an ack is sent. 12836396Ssklower * (this is done in (void) tp_emit() ). 12936396Ssklower * It's cancelled and reset whenever a DT 13036396Ssklower * arrives and it doesn't require immediate acking. 13136396Ssklower * Note that in this case it's set w/ the minimum of 13236396Ssklower * its prev value and the sendack-ticks value so the 13336396Ssklower * purpose of the keepalive is preserved. 13436396Ssklower */ 13536396Ssklower TM_notused 13636396Ssklower 13736396Ssklower /* 13836396Ssklower * E (typically expired) timers - these may be in any order. 13936396Ssklower * These cause procedures to be executed directly; may not 14036396Ssklower * cause an 'event' as we know them here. 14136396Ssklower */ 14236396Ssklower TM_reference { SeqNum e_low; SeqNum e_high; int e_retrans; } 14336396Ssklower TM_data_retrans { SeqNum e_low; SeqNum e_high; int e_retrans; } 14436396Ssklower 14536396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that 14636396Ssklower * for all tpdu types that can take e_data and e_datalen, these 14736396Ssklower * fields fall in the same place in the event structure, that is, 14836396Ssklower * e_data is the first field and e_datalen is the 2nd field. 14936396Ssklower */ 15036396Ssklower 15136396Ssklower ER_TPDU { 15236396Ssklower u_char e_reason; 15336396Ssklower } 15436396Ssklower CR_TPDU { struct mbuf *e_data; /* first field */ 15536396Ssklower int e_datalen; /* 2nd field */ 15636396Ssklower u_int e_cdt; 15736396Ssklower } 15836396Ssklower DR_TPDU { struct mbuf *e_data; /* first field */ 15936396Ssklower int e_datalen; /* 2nd field */ 16036396Ssklower u_short e_sref; 16136396Ssklower u_char e_reason; 16236396Ssklower } 16336396Ssklower DC_TPDU 16436396Ssklower CC_TPDU { struct mbuf *e_data; /* first field */ 16536396Ssklower int e_datalen; /* 2nd field */ 16636396Ssklower u_short e_sref; 16736396Ssklower u_int e_cdt; 16836396Ssklower } 16936396Ssklower AK_TPDU { u_int e_cdt; 17036396Ssklower SeqNum e_seq; 17136396Ssklower SeqNum e_subseq; 17236396Ssklower u_char e_fcc_present; 17336396Ssklower } 17436396Ssklower DT_TPDU { struct mbuf *e_data; /* first field */ 17536396Ssklower int e_datalen; /* 2nd field */ 17636396Ssklower u_int e_eot; 17736396Ssklower SeqNum e_seq; 17836396Ssklower } 17936396Ssklower XPD_TPDU { struct mbuf *e_data; /* first field */ 18036396Ssklower int e_datalen; /* 2nd field */ 18136396Ssklower SeqNum e_seq; 18236396Ssklower } 18336396Ssklower XAK_TPDU { SeqNum e_seq; } 18436396Ssklower 18536396Ssklower T_CONN_req 18636396Ssklower T_DISC_req { u_char e_reason; } 18736396Ssklower T_LISTEN_req 18836396Ssklower T_DATA_req 18936396Ssklower T_XPD_req 19036396Ssklower T_USR_rcvd 19136396Ssklower T_USR_Xrcvd 19236396Ssklower T_DETACH 19336396Ssklower T_NETRESET 19438841Ssklower T_ACPT_req 19536396Ssklower 19636396Ssklower 19736396Ssklower*TRANSITIONS 19836396Ssklower 19936396Ssklower 20036396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */ 20136396SsklowerSAME <== TP_AKWAIT [ CC_TPDU, DC_TPDU, XAK_TPDU ] 20236396Ssklower DEFAULT 20336396Ssklower NULLACTION 20436396Ssklower; 20536396Ssklower 20636396Ssklower 20736396Ssklower/* applicable in TP4, TP0 */ 20836396SsklowerSAME <== TP_REFWAIT DR_TPDU 20936396Ssklower ( $$.e_sref != 0 ) 21036396Ssklower { 21136396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 21236396Ssklower } 21336396Ssklower; 21436396Ssklower 21536396Ssklower/* applicable in TP4, TP0 */ 21636396SsklowerSAME <== TP_REFWAIT [ CR_TPDU, CC_TPDU, DT_TPDU, 21736396Ssklower DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ] 21836396Ssklower DEFAULT 21936396Ssklower { 22036396Ssklower# ifdef TP_DEBUG 22136396Ssklower if( $E.ev_number != AK_TPDU ) 22236396Ssklower printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number); 22336396Ssklower# endif TP_DEBUG 22436396Ssklower } 22536396Ssklower; 22636396Ssklower 22736396Ssklower/* applicable in TP4, TP0 */ 22836396SsklowerSAME <== TP_REFWAIT [ T_DETACH, T_DISC_req ] 22936396Ssklower DEFAULT 23036396Ssklower NULLACTION 23136396Ssklower; 23236396Ssklower 23336396Ssklower/* applicable in TP4, TP0 */ 23436396SsklowerSAME <== TP_CRSENT AK_TPDU 23536396Ssklower ($P.tp_class == TP_CLASS_0) 23636396Ssklower { 23736396Ssklower /* oh, man is this grotesque or what? */ 23836396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 23936396Ssklower /* but it's necessary because this pseudo-ack may happen 24036396Ssklower * before the CC arrives, but we HAVE to adjust the 24136396Ssklower * snduna as a result of the ack, WHENEVER it arrives 24236396Ssklower */ 24336396Ssklower } 24436396Ssklower; 24536396Ssklower 24636396Ssklower/* applicable in TP4, TP0 */ 24736396SsklowerSAME <== TP_CRSENT 24836396Ssklower [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU, XAK_TPDU ] 24936396Ssklower DEFAULT 25036396Ssklower NULLACTION 25136396Ssklower; 25236396Ssklower 25336396Ssklower/* applicable in TP4, TP0 */ 25436396SsklowerSAME <== TP_CLOSED [ DT_TPDU, XPD_TPDU, 25536396Ssklower ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 25636396Ssklower DEFAULT 25736396Ssklower NULLACTION 25836396Ssklower; 25936396Ssklower 26036396Ssklower/* TP_CLOSING doesn't exist in TP 0 */ 26136396SsklowerSAME <== TP_CLOSING 26236396Ssklower [ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ] 26336396Ssklower DEFAULT 26436396Ssklower NULLACTION 26536396Ssklower; 26636396Ssklower 26736396Ssklower 26836396Ssklower/* DC_TPDU doesn't exist in TP 0 */ 26936396SsklowerSAME <== TP_OPEN DC_TPDU 27036396Ssklower DEFAULT 27136396Ssklower NULLACTION 27236396Ssklower; 27336396Ssklower 27436396Ssklower/* applicable in TP4, TP0 */ 27536396SsklowerSAME <== TP_LISTENING [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU, 27636396Ssklower ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 27736396Ssklower DEFAULT 27836396Ssklower NULLACTION 27936396Ssklower; 28036396Ssklower 28136396Ssklower/* applicable in TP4, TP0 */ 28236396SsklowerTP_LISTENING <== TP_CLOSED T_LISTEN_req 28336396Ssklower DEFAULT 28436396Ssklower NULLACTION 28536396Ssklower; 28636396Ssklower 28736396Ssklower/* applicable in TP4, TP0 */ 28836396SsklowerTP_CLOSED <== [ TP_LISTENING, TP_CLOSED ] T_DETACH 28936396Ssklower DEFAULT 29036396Ssklower { 29136396Ssklower tp_detach($P); 29236396Ssklower } 29336396Ssklower; 29436396Ssklower 29538841SsklowerTP_CONFIRMING <== TP_LISTENING CR_TPDU 29638841Ssklower ( $P.tp_class == TP_CLASS_0) 29736396Ssklower { 29836396Ssklower $P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */ 29936396Ssklower } 30036396Ssklower; 30136396Ssklower 30238841SsklowerTP_CONFIRMING <== TP_LISTENING CR_TPDU 30338841Ssklower DEFAULT 30436396Ssklower { 30536396Ssklower IFTRACE(D_CONN) 30636396Ssklower tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0); 30736396Ssklower ENDTRACE 30836396Ssklower IFDEBUG(D_CONN) 30936396Ssklower printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data); 31036396Ssklower ENDDEBUG 31136396Ssklower $P.tp_refp->tpr_state = REF_OPEN; /* has timers */ 31238841Ssklower $P.tp_fcredit = $$.e_cdt; 31336396Ssklower 31436396Ssklower if ($$.e_datalen > 0) { 31536396Ssklower /* n/a for class 0 */ 31636396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); 31736396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 31836396Ssklower $$.e_data = MNULL; 31936396Ssklower } 32038841Ssklower } 32138841Ssklower; 32238841Ssklower 32338841SsklowerTP_OPEN <== TP_CONFIRMING T_ACPT_req 32438841Ssklower ( $P.tp_class == TP_CLASS_0 ) 32538841Ssklower { 32638841Ssklower IncStat(ts_tp0_conn); 32738841Ssklower IFTRACE(D_CONN) 32838841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 32938841Ssklower ENDTRACE 33038841Ssklower IFDEBUG(D_CONN) 33138841Ssklower printf("Confirming connection: $P" ); 33238841Ssklower ENDDEBUG 33338841Ssklower soisconnected($P.tp_sock); 33438841Ssklower (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ; 33538841Ssklower $P.tp_fcredit = 1; 33638841Ssklower } 33738841Ssklower; 33838841Ssklower 33938841SsklowerTP_AKWAIT <== TP_CONFIRMING T_ACPT_req 34038841Ssklower (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0) 34138841Ssklower { 34238841Ssklower IncStat(ts_tp4_conn); /* even though not quite open */ 34338841Ssklower IFTRACE(D_CONN) 34438841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 34538841Ssklower ENDTRACE 34638841Ssklower IFDEBUG(D_CONN) 34738841Ssklower printf("Confirming connection: $P" ); 34838841Ssklower ENDDEBUG 34938841Ssklower soisconnecting($P.tp_sock); 35047281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0)) 35138841Ssklower $P.tp_cong_win = $P.tp_fcredit; 35236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 35336396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); 35438841Ssklower } 35536396Ssklower; 35636396Ssklower 35736396Ssklower/* TP4 only */ 35838841SsklowerTP_CLOSED <== TP_CONFIRMING T_ACPT_req 35936396Ssklower DEFAULT /* emit failed */ 36036396Ssklower { 36136396Ssklower register struct tp_ref *r = $P.tp_refp; 36236396Ssklower 36336396Ssklower IFDEBUG(D_CONN) 36436396Ssklower printf("event: CR_TPDU emit CC failed done " ); 36536396Ssklower ENDDEBUG 36638841Ssklower soisdisconnected($P.tp_sock); 36736396Ssklower tp_recycle_tsuffix( $P ); 36836396Ssklower tp_freeref(r); 36936396Ssklower tp_detach($P); 37036396Ssklower } 37136396Ssklower; 37236396Ssklower 37336396Ssklower/* applicable in TP4, TP0 */ 37436396SsklowerTP_CRSENT <== TP_CLOSED T_CONN_req 37536396Ssklower DEFAULT 37636396Ssklower { 37736396Ssklower int error; 37836396Ssklower struct mbuf *data = MNULL; 37936396Ssklower 38036396Ssklower IFTRACE(D_CONN) 38137469Ssklower tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags, 38237469Ssklower $P.tp_ucddata, 0, 0); 38336396Ssklower ENDTRACE 38437469Ssklower data = MCPY($P.tp_ucddata, M_WAIT); 38537469Ssklower if (data) { 38636396Ssklower IFDEBUG(D_CONN) 38736396Ssklower printf("T_CONN_req.trans m_copy cc 0x%x\n", 38837469Ssklower $P.tp_ucddata); 38937469Ssklower dump_mbuf(data, "sosnd @ T_CONN_req"); 39036396Ssklower ENDDEBUG 39136396Ssklower } 39236396Ssklower 39336396Ssklower if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) 39436396Ssklower return error; /* driver WON'T change state; will return error */ 39536396Ssklower 39636396Ssklower $P.tp_refp->tpr_state = REF_OPEN; /* has timers */ 39736396Ssklower if($P.tp_class != TP_CLASS_0) { 39836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 39936396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks); 40036396Ssklower } 40136396Ssklower } 40236396Ssklower; 40336396Ssklower 40436396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */ 40536396SsklowerTP_REFWAIT <== [ TP_CRSENT, TP_AKWAIT, TP_OPEN ] DR_TPDU 40636396Ssklower DEFAULT 40736396Ssklower { 408*48739Ssklower sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */ 409*48739Ssklower if ($$.e_datalen > 0) { 41036396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 41136396Ssklower $$.e_data = MNULL; 41236396Ssklower } 413*48739Ssklower tp_indicate(T_DISCONNECT, $P, 0); 41436396Ssklower tp_soisdisconnected($P); 41536396Ssklower if ($P.tp_class != TP_CLASS_0) { 41636396Ssklower if ($P.tp_state == TP_OPEN ) { 41736396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 41836396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 41936396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 42036396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 42136396Ssklower } 42236396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 42336396Ssklower if( $$.e_sref != 0 ) 42436396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 42536396Ssklower } 42636396Ssklower } 42736396Ssklower; 42836396Ssklower 42936396SsklowerSAME <== TP_CLOSED DR_TPDU 43036396Ssklower DEFAULT 43136396Ssklower { 43236396Ssklower if( $$.e_sref != 0 ) 43336396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 43436396Ssklower /* reference timer already set - reset it to be safe (???) */ 43536396Ssklower tp_euntimeout($P.tp_refp, TM_reference); /* all */ 43636396Ssklower tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks); 43736396Ssklower } 43836396Ssklower; 43936396Ssklower 44036396Ssklower/* NBS(34) */ 44136396SsklowerTP_REFWAIT <== TP_CRSENT ER_TPDU 44236396Ssklower DEFAULT 44336396Ssklower { 44436396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 445*48739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 44636396Ssklower tp_soisdisconnected($P); 44736396Ssklower } 44836396Ssklower; 44936396Ssklower 45036396Ssklower/* NBS(27) */ 45136396SsklowerTP_REFWAIT <== TP_CLOSING DR_TPDU 45236396Ssklower DEFAULT 45336396Ssklower { 45436396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 45536396Ssklower tp_soisdisconnected($P); 45636396Ssklower } 45736396Ssklower; 45836396Ssklower/* these two transitions are the same but can't be combined because xebec 45936396Ssklower * can't handle the use of $$.e_reason if they're combined 46036396Ssklower */ 46136396Ssklower/* NBS(27) */ 46236396SsklowerTP_REFWAIT <== TP_CLOSING ER_TPDU 46336396Ssklower DEFAULT 46436396Ssklower { 465*48739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 46636396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 46736396Ssklower tp_soisdisconnected($P); 46836396Ssklower } 46936396Ssklower; 47036396Ssklower/* NBS(27) */ 47136396SsklowerTP_REFWAIT <== TP_CLOSING DC_TPDU 47236396Ssklower DEFAULT 47336396Ssklower { 47436396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 47536396Ssklower tp_soisdisconnected($P); 47636396Ssklower } 47736396Ssklower; 47836396Ssklower 47936396Ssklower/* NBS(21) */ 48036396SsklowerSAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ] 48136396Ssklower DEFAULT 48236396Ssklower { /* don't ask me why we have to do this - spec says so */ 48336396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL); 48436396Ssklower /* don't bother with retransmissions of the DR */ 48536396Ssklower } 48636396Ssklower; 48736396Ssklower 48836396Ssklower/* NBS(34) */ 48936396SsklowerTP_REFWAIT <== TP_OPEN ER_TPDU 49036396Ssklower ($P.tp_class == TP_CLASS_0) 49136396Ssklower { 49236396Ssklower tp_soisdisconnecting($P.tp_sock); 493*48739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 49436396Ssklower tp_soisdisconnected($P); 49536396Ssklower tp_netcmd( $P, CONN_CLOSE ); 49636396Ssklower } 49736396Ssklower; 49836396Ssklower 49936396SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU 50036396Ssklower DEFAULT 50136396Ssklower { 50236396Ssklower if ($P.tp_state == TP_OPEN) { 50336396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 50436396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 50536396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 50636396Ssklower } 50736396Ssklower tp_soisdisconnecting($P.tp_sock); 508*48739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 50936396Ssklower $P.tp_retrans = $P.tp_Nretrans; 51036396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 51136396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL); 51236396Ssklower } 51336396Ssklower; 51436396Ssklower/* NBS(6) */ 51536396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 51636396Ssklower ($P.tp_class == TP_CLASS_0) 51736396Ssklower { 51836396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 51936396Ssklower IncStat(ts_tp0_conn); 52036396Ssklower $P.tp_fcredit = 1; 52136396Ssklower soisconnected($P.tp_sock); 52236396Ssklower } 52336396Ssklower; 52436396Ssklower 52536396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 52636396Ssklower DEFAULT 52736396Ssklower { 52836396Ssklower IFDEBUG(D_CONN) 52936396Ssklower printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", 53036396Ssklower (int)$P.tp_flags); 53136396Ssklower ENDDEBUG 53236396Ssklower IncStat(ts_tp4_conn); 53336396Ssklower $P.tp_fref = $$.e_sref; 53436396Ssklower $P.tp_fcredit = $$.e_cdt; 53539921Ssklower $P.tp_ackrcvd = 0; 53647281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0)) 53736396Ssklower $P.tp_cong_win = $$.e_cdt; 53836396Ssklower tp_getoptions($P); 53936396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 54037469Ssklower if ($P.tp_ucddata) { 54136396Ssklower IFDEBUG(D_CONN) 54237469Ssklower printf("dropping user connect data cc 0x%x\n", 54337469Ssklower $P.tp_ucddata->m_len); 54436396Ssklower ENDDEBUG 54537469Ssklower m_freem($P.tp_ucddata); 54637469Ssklower $P.tp_ucddata = 0; 54736396Ssklower } 54836396Ssklower soisconnected($P.tp_sock); 54936396Ssklower if ($$.e_datalen > 0) { 55036396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */ 55136396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 55236396Ssklower $$.e_data = MNULL; 55336396Ssklower } 55436396Ssklower 55536396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 55636396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 55736396Ssklower } 55836396Ssklower; 55936396Ssklower 56036396Ssklower/* TP4 only */ 56136396SsklowerSAME <== TP_CRSENT TM_retrans 56236396Ssklower ( $P.tp_retrans > 0 ) 56336396Ssklower { 56436396Ssklower struct mbuf *data = MNULL; 56536396Ssklower int error; 56636396Ssklower 56736396Ssklower IncStat(ts_retrans_cr); 56839921Ssklower $P.tp_cong_win = 1; 56939921Ssklower $P.tp_ackrcvd = 0; 57037469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 57137469Ssklower if($P.tp_ucddata) { 57236396Ssklower IFDEBUG(D_CONN) 57337469Ssklower printf("TM_retrans.trans m_copy cc 0x%x\n", data); 57437469Ssklower dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans"); 57536396Ssklower ENDDEBUG 57636396Ssklower if( data == MNULL ) 57736396Ssklower return ENOBUFS; 57836396Ssklower } 57936396Ssklower 58036396Ssklower $P.tp_retrans --; 58136396Ssklower if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) { 58236396Ssklower $P.tp_sock->so_error = error; 58336396Ssklower } 58436396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks); 58536396Ssklower } 58636396Ssklower; 58736396Ssklower 58836396Ssklower/* TP4 only */ 58936396SsklowerTP_REFWAIT <== TP_CRSENT TM_retrans 59036396Ssklower DEFAULT /* no more CR retransmissions */ 59136396Ssklower { 59236396Ssklower IncStat(ts_conn_gaveup); 59336396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 59436396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 59536396Ssklower tp_soisdisconnected($P); 59636396Ssklower } 59736396Ssklower; 59836396Ssklower 59936396Ssklower/* TP4 only */ 60036396SsklowerSAME <== TP_AKWAIT CR_TPDU 60136396Ssklower DEFAULT 60236396Ssklower /* duplicate CR (which doesn't really exist in the context of 60336396Ssklower * a connectionless network layer) 60436396Ssklower * Doesn't occur in class 0. 60536396Ssklower */ 60636396Ssklower { 60736396Ssklower int error; 60837469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 60936396Ssklower 61037469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) { 61136396Ssklower $P.tp_sock->so_error = error; 61236396Ssklower } 61336396Ssklower $P.tp_retrans = $P.tp_Nretrans; 61436396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); 61536396Ssklower } 61636396Ssklower; 61736396Ssklower 61836396Ssklower/* TP4 only */ 61936396SsklowerTP_OPEN <== TP_AKWAIT DT_TPDU 62036396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 62136396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 62236396Ssklower { 62336396Ssklower int doack; 62436396Ssklower 62537469Ssklower /* 62637469Ssklower * Get rid of any confirm or connect data, so that if we 62737469Ssklower * crash or close, it isn't thought of as disconnect data. 62837469Ssklower */ 62937469Ssklower if ($P.tp_ucddata) { 63037469Ssklower m_freem($P.tp_ucddata); 63137469Ssklower $P.tp_ucddata = 0; 63236396Ssklower } 63336396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 63436396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 63536396Ssklower soisconnected($P.tp_sock); 63636396Ssklower tp_getoptions($P); 63736396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 63836396Ssklower 63936396Ssklower /* see also next 2 transitions, if you make any changes */ 64036396Ssklower 64136396Ssklower doack = tp_stash($P, $E); 64236396Ssklower IFDEBUG(D_DATA) 64336396Ssklower printf("tp_stash returns %d\n",doack); 64436396Ssklower ENDDEBUG 64536396Ssklower 64636396Ssklower if(doack) { 64736396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 64836396Ssklower tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); 64936396Ssklower } else 65036396Ssklower tp_ctimeout( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks); 65136396Ssklower 65236396Ssklower IFDEBUG(D_DATA) 65336396Ssklower printf("after stash calling sbwakeup\n"); 65436396Ssklower ENDDEBUG 65536396Ssklower } 65636396Ssklower; 65736396Ssklower 65836396SsklowerSAME <== TP_OPEN DT_TPDU 65936396Ssklower ( $P.tp_class == TP_CLASS_0 ) 66036396Ssklower { 66136396Ssklower tp0_stash($P, $E); 66236396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 66336396Ssklower 66436396Ssklower IFDEBUG(D_DATA) 66536396Ssklower printf("after stash calling sbwakeup\n"); 66636396Ssklower ENDDEBUG 66736396Ssklower } 66836396Ssklower; 66936396Ssklower 67036396Ssklower/* TP4 only */ 67136396SsklowerSAME <== TP_OPEN DT_TPDU 67236396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 67336396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 67436396Ssklower { 67536396Ssklower int doack; /* tells if we must ack immediately */ 67636396Ssklower 67736396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 67836396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 67936396Ssklower 68036396Ssklower doack = tp_stash($P, $E); 68136396Ssklower IFDEBUG(D_DATA) 68236396Ssklower printf("tp_stash returns %d\n",doack); 68336396Ssklower ENDDEBUG 68436396Ssklower 68536396Ssklower if(doack) 68636396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 68736396Ssklower else 68836396Ssklower tp_ctimeout_MIN( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks); 68936396Ssklower 69036396Ssklower IFDEBUG(D_DATA) 69136396Ssklower printf("after stash calling sbwakeup\n"); 69236396Ssklower ENDDEBUG 69336396Ssklower } 69436396Ssklower; 69536396Ssklower 69636396Ssklower/* Not in window - we must ack under certain circumstances, namely 69736396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given) 69836396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^. 69936396Ssklower * and 70036396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit 70136396Ssklower * 70236396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73) 70336396Ssklower * We just always ack. 70436396Ssklower */ 70536396Ssklower/* TP4 only */ 70636396SsklowerSAME <== [ TP_OPEN, TP_AKWAIT ] DT_TPDU 70736396Ssklower DEFAULT /* Not in window */ 70836396Ssklower { 70936396Ssklower IFTRACE(D_DATA) 71036396Ssklower tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", 71136396Ssklower $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0); 71236396Ssklower ENDTRACE 71336396Ssklower IncStat(ts_dt_niw); 71436396Ssklower m_freem($$.e_data); 71536396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 71636396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 71736396Ssklower } 71836396Ssklower; 71936396Ssklower 72036396Ssklower/* TP4 only */ 72136396SsklowerTP_OPEN <== TP_AKWAIT AK_TPDU 72236396Ssklower DEFAULT 72336396Ssklower { 72437469Ssklower if ($P.tp_ucddata) { 72537469Ssklower m_freem($P.tp_ucddata); 72637469Ssklower $P.tp_ucddata = 0; 72736396Ssklower } 72836396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 72936396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 73036396Ssklower 73136396Ssklower tp_getoptions($P); 73236396Ssklower soisconnected($P.tp_sock); 73336396Ssklower IFTRACE(D_CONN) 73436396Ssklower struct socket *so = $P.tp_sock; 73536396Ssklower tptrace(TPPTmisc, 73636396Ssklower "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", 73736396Ssklower so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); 73836396Ssklower tptrace(TPPTmisc, 73936396Ssklower "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", 74036396Ssklower so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); 74136396Ssklower ENDTRACE 74236396Ssklower 74336396Ssklower tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); 74436396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 74536396Ssklower } 74636396Ssklower; 74736396Ssklower 74836396Ssklower/* TP4 only */ 74936396SsklowerTP_OPEN <== [ TP_OPEN, TP_AKWAIT ] XPD_TPDU 75047281Ssklower ($P.tp_Xrcvnxt == $$.e_seq) 75136396Ssklower { 75236396Ssklower if( $P.tp_state == TP_AKWAIT ) { 75337469Ssklower if ($P.tp_ucddata) { 75437469Ssklower m_freem($P.tp_ucddata); 75537469Ssklower $P.tp_ucddata = 0; 75636396Ssklower } 75736396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 75836396Ssklower tp_getoptions($P); 75936396Ssklower soisconnected($P.tp_sock); 76036396Ssklower tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); 76136396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 76236396Ssklower } 76336396Ssklower IFTRACE(D_XPD) 76436396Ssklower tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", 76536396Ssklower $P.tp_Xrcvnxt,$$.e_seq, $$.e_datalen, $$.e_data->m_len); 76636396Ssklower ENDTRACE 76736396Ssklower 76837469Ssklower $P.tp_sock->so_state |= SS_RCVATMARK; 76947281Ssklower $$.e_data->m_flags |= M_EOR; 77037469Ssklower sbinsertoob(&$P.tp_Xrcv, $$.e_data); 77136396Ssklower IFDEBUG(D_XPD) 77236396Ssklower dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv"); 77336396Ssklower ENDDEBUG 77436396Ssklower tp_indicate(T_XDATA, $P, 0); 77536396Ssklower sbwakeup( &$P.tp_Xrcv ); 77636396Ssklower 77736396Ssklower (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 77836396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 77936396Ssklower } 78036396Ssklower; 78136396Ssklower 78236396Ssklower/* TP4 only */ 78336396SsklowerSAME <== TP_OPEN T_USR_Xrcvd 78436396Ssklower DEFAULT 78536396Ssklower { 78636396Ssklower if( $P.tp_Xrcv.sb_cc == 0 ) { 78736396Ssklower /* kludge for select(): */ 78837469Ssklower /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */ 78936396Ssklower } 79036396Ssklower } 79136396Ssklower /* OLD WAY: 79236396Ssklower * Ack only after the user receives the XPD. This is better for 79336396Ssklower * users that use one XPD right after another. 79436396Ssklower * Acking right away (the NEW WAY, see the prev. transition) is 79536396Ssklower * better for occasional * XPD, when the receiving user doesn't 79636396Ssklower * want to read the XPD immediately (which is session's behavior). 79736396Ssklower * 79836396Ssklower int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 79936396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 80036396Ssklower return error; 80136396Ssklower */ 80236396Ssklower; 80336396Ssklower 80436396Ssklower/* NOTE: presently if the user doesn't read the connection data 80536396Ssklower * before and expedited data PDU comes in, the connection data will 80636396Ssklower * be dropped. This is a bug. To avoid it, we need somewhere else 80736396Ssklower * to put the connection data. 80836396Ssklower * On the other hand, we need not to have it sitting around forever. 80936396Ssklower * This is a problem with the idea of trying to accommodate 81036396Ssklower * data on connect w/ a passive-open user interface. 81136396Ssklower */ 81236396Ssklower/* TP4 only */ 81336396Ssklower 81436396SsklowerSAME <== [ TP_AKWAIT, TP_OPEN ] XPD_TPDU 81536396Ssklower DEFAULT /* not in window or cdt==0 */ 81636396Ssklower { 81736396Ssklower IFTRACE(D_XPD) 81836396Ssklower tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", 81936396Ssklower $P.tp_Xrcvnxt, $$.e_seq, $P.tp_Xrcv.sb_cc , 0); 82036396Ssklower ENDTRACE 82136396Ssklower if( $P.tp_Xrcvnxt != $$.e_seq ) 82236396Ssklower IncStat(ts_xpd_niw); 82336396Ssklower if( $P.tp_Xrcv.sb_cc ) { 82436396Ssklower /* might as well kick 'em again */ 82536396Ssklower tp_indicate(T_XDATA, $P, 0); 82636396Ssklower IncStat(ts_xpd_dup); 82736396Ssklower } 82836396Ssklower m_freem($$.e_data); 82936396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 83036396Ssklower /* don't send an xack because the xak gives "last one received", not 83136396Ssklower * "next one i expect" (dumb) 83236396Ssklower */ 83336396Ssklower } 83436396Ssklower; 83536396Ssklower 83636396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries 83736396Ssklower * to detach all its "children" 83836396Ssklower * Also (CRSENT) when user kills a job that's doing a connect() 83936396Ssklower */ 84036396SsklowerTP_REFWAIT <== TP_CRSENT T_DETACH 84136396Ssklower ($P.tp_class == TP_CLASS_0) 84236396Ssklower { 84336396Ssklower struct socket *so = $P.tp_sock; 84436396Ssklower 84536396Ssklower /* detach from parent socket so it can finish closing */ 84636396Ssklower if (so->so_head) { 84736396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 84836396Ssklower panic("tp: T_DETACH"); 84936396Ssklower so->so_head = 0; 85036396Ssklower } 85136396Ssklower tp_soisdisconnecting($P.tp_sock); 85236396Ssklower tp_netcmd( $P, CONN_CLOSE); 85336396Ssklower tp_soisdisconnected($P); 85436396Ssklower } 85536396Ssklower; 85636396Ssklower 85736396Ssklower/* TP4 only */ 85838841SsklowerTP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH 85936396Ssklower DEFAULT 86036396Ssklower { 86136396Ssklower struct socket *so = $P.tp_sock; 86237469Ssklower struct mbuf *data = MNULL; 86336396Ssklower 86436396Ssklower /* detach from parent socket so it can finish closing */ 86536396Ssklower if (so->so_head) { 86636396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 86736396Ssklower panic("tp: T_DETACH"); 86836396Ssklower so->so_head = 0; 86936396Ssklower } 87036396Ssklower if ($P.tp_state != TP_CLOSING) { 87136396Ssklower tp_soisdisconnecting($P.tp_sock); 87237469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 87337469Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data); 87436396Ssklower $P.tp_retrans = $P.tp_Nretrans; 87536396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 87636396Ssklower } 87736396Ssklower } 87836396Ssklower; 87936396Ssklower 88036396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req 88136396Ssklower ( $P.tp_class == TP_CLASS_0 ) 88236396Ssklower { 88336396Ssklower tp_soisdisconnecting($P.tp_sock); 88436396Ssklower tp_netcmd( $P, CONN_CLOSE); 88536396Ssklower tp_soisdisconnected($P); 88636396Ssklower } 88736396Ssklower; 88836396Ssklower 88936396Ssklower/* TP4 only */ 89038841SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req 89136396Ssklower DEFAULT 89236396Ssklower { 89337469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 89436396Ssklower 89536396Ssklower if($P.tp_state == TP_OPEN) { 89636396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 89736396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 89836396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 89936396Ssklower } 90037469Ssklower if (data) { 90136396Ssklower IFDEBUG(D_CONN) 90237469Ssklower printf("T_DISC_req.trans tp_ucddata 0x%x\n", 90337469Ssklower $P.tp_ucddata); 90437469Ssklower dump_mbuf(data, "ucddata @ T_DISC_req"); 90536396Ssklower ENDDEBUG 90636396Ssklower } 90736396Ssklower tp_soisdisconnecting($P.tp_sock); 90836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 90936396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 91036396Ssklower 91136396Ssklower if( trick_hc ) 91236396Ssklower return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data); 91336396Ssklower } 91436396Ssklower; 91536396Ssklower 91636396Ssklower/* TP4 only */ 91736396SsklowerSAME <== TP_AKWAIT TM_retrans 91836396Ssklower ( $P.tp_retrans > 0 ) 91936396Ssklower { 92036396Ssklower int error; 92137469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 92236396Ssklower 92336396Ssklower IncStat(ts_retrans_cc); 92436396Ssklower $P.tp_retrans --; 92539921Ssklower $P.tp_cong_win = 1; 92639921Ssklower $P.tp_ackrcvd = 0; 92739921Ssklower 92837469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) 92936396Ssklower $P.tp_sock->so_error = error; 93036396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); 93136396Ssklower } 93236396Ssklower; 93336396Ssklower 93436396Ssklower/* TP4 only */ 93536396SsklowerTP_CLOSING <== TP_AKWAIT TM_retrans 93636396Ssklower DEFAULT /* out of time */ 93736396Ssklower { 93836396Ssklower IncStat(ts_conn_gaveup); 93936396Ssklower tp_soisdisconnecting($P.tp_sock); 94036396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 94136396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 94236396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL); 94336396Ssklower $P.tp_retrans = $P.tp_Nretrans; 94436396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 94536396Ssklower } 94636396Ssklower; 94736396Ssklower 94836396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does, 94936396Ssklower * if transmissions are going on. 95036396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack 95136396Ssklower * turnaround) 95236396Ssklower */ 95336396Ssklower/* TP4 only */ 95436396SsklowerTP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ] 95536396Ssklower DEFAULT 95636396Ssklower { 95736396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 95836396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 95936396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 96036396Ssklower 96136396Ssklower IncStat(ts_conn_gaveup); 96236396Ssklower tp_soisdisconnecting($P.tp_sock); 96336396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 96436396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 96536396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL); 96636396Ssklower $P.tp_retrans = $P.tp_Nretrans; 96736396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 96836396Ssklower } 96936396Ssklower; 97036396Ssklower 97136396Ssklower/* TP4 only */ 97236396SsklowerSAME <== TP_OPEN TM_retrans 97336396Ssklower ( $P.tp_retrans > 0 ) 97436396Ssklower { 97539921Ssklower $P.tp_cong_win = 1; 97639921Ssklower $P.tp_ackrcvd = 0; 97736396Ssklower /* resume XPD */ 97836396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 97937469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 98036396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 98136396Ssklower * that doesn't matter 98236396Ssklower */ 98336396Ssklower 98436396Ssklower IFTRACE(D_XPD) 98536396Ssklower tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna", 98636396Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, 98736396Ssklower $P.tp_snduna); 98836396Ssklower ENDTRACE 98936396Ssklower IFDEBUG(D_XPD) 99036396Ssklower dump_mbuf(m, "XPD retrans emitting M"); 99136396Ssklower ENDDEBUG 99236396Ssklower IncStat(ts_retrans_xpd); 99336396Ssklower $P.tp_retrans --; 99436396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 99536396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 99636396Ssklower } 99736396Ssklower } 99836396Ssklower; 99936396Ssklower 100036396Ssklower/* TP4 only */ 100136396SsklowerSAME <== TP_OPEN TM_data_retrans 100236396Ssklower ( $$.e_retrans > 0 ) 100336396Ssklower { 100436396Ssklower register SeqNum low, lowsave = 0; 100536396Ssklower register struct tp_rtc *r = $P.tp_snduna_rtc; 100636396Ssklower register struct mbuf *m; 100736396Ssklower register SeqNum high = $$.e_high; 100836396Ssklower 100939921Ssklower low = $P.tp_snduna; 101039921Ssklower lowsave = high = low; 101139921Ssklower 101239921Ssklower tp_euntimeout_lss($P.tp_refp, TM_data_retrans, 101339921Ssklower SEQ_ADD($P, $P.tp_sndhiwat, 1)); 101439921Ssklower $P.tp_retrans_hiwat = $P.tp_sndhiwat; 101539921Ssklower 101636396Ssklower if (($P.tp_rx_strat & TPRX_EACH) == 0) 101736396Ssklower high = (high>low)?low:high; 101836396Ssklower 101936396Ssklower if( $P.tp_rx_strat & TPRX_USE_CW ) { 102036396Ssklower register int i; 102136396Ssklower 102236396Ssklower $P.tp_cong_win = 1; 102339921Ssklower $P.tp_ackrcvd = 0; 102439921Ssklower i = SEQ_ADD($P, low, $P.tp_cong_win); 102536396Ssklower 102639921Ssklower high = SEQ_MIN($P, high, $P.tp_sndhiwat); 102739921Ssklower 102836396Ssklower } 102936396Ssklower 103036396Ssklower while( SEQ_LEQ($P, low, high) ){ 103136396Ssklower if ( r == (struct tp_rtc *)0 ){ 103236396Ssklower IFDEBUG(D_RTC) 103336396Ssklower printf( "tp: retrans rtc list is GONE!\n"); 103436396Ssklower ENDDEBUG 103536396Ssklower break; 103636396Ssklower } 103736396Ssklower if ( r->tprt_seq == low ){ 103836396Ssklower if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL) 103936396Ssklower break; 104036396Ssklower (void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m); 104136396Ssklower IncStat(ts_retrans_dt); 104236396Ssklower SEQ_INC($P, low ); 104336396Ssklower } 104436396Ssklower r = r->tprt_next; 104536396Ssklower } 104639921Ssklower/* CE_BIT 104736396Ssklower if ( SEQ_LEQ($P, lowsave, high) ){ 104839921Ssklower*/ 104936396Ssklower $$.e_retrans --; 105036396Ssklower tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave, 105136396Ssklower (caddr_t)high, $$.e_retrans, 105236396Ssklower ($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks); 105339921Ssklower/* CE_BIT 105436396Ssklower } 105539921Ssklower*/ 105636396Ssklower } 105736396Ssklower; 105836396Ssklower 105936396Ssklower/* TP4 only */ 106036396SsklowerSAME <== TP_CLOSING TM_retrans 106136396Ssklower ( $P.tp_retrans > 0 ) 106236396Ssklower { 106336396Ssklower $P.tp_retrans --; 106436396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL); 106536396Ssklower IncStat(ts_retrans_dr); 106636396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 106736396Ssklower } 106836396Ssklower; 106936396Ssklower 107036396Ssklower/* TP4 only */ 107136396SsklowerTP_REFWAIT <== TP_CLOSING TM_retrans 107236396Ssklower DEFAULT /* no more retrans - gave up */ 107336396Ssklower { 107436396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 107536396Ssklower $P.tp_refp->tpr_state = REF_FROZEN; 107636396Ssklower tp_recycle_tsuffix( $P ); 107736396Ssklower tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks); 107836396Ssklower } 107936396Ssklower; 108036396Ssklower 108136396Ssklower/* 108236396Ssklower * The resources are kept around until the ref timer goes off. 108336396Ssklower * The suffices are wiped out sooner so they can be reused right away. 108436396Ssklower */ 108536396Ssklower/* applicable in TP4, TP0 */ 108636396SsklowerTP_CLOSED <== TP_REFWAIT TM_reference 108736396Ssklower DEFAULT 108836396Ssklower { 108936396Ssklower tp_freeref($P.tp_refp); 109036396Ssklower tp_detach($P); 109136396Ssklower } 109236396Ssklower; 109336396Ssklower 109436396Ssklower/* applicable in TP4, TP0 */ 109536396Ssklower/* A duplicate CR from connectionless network layer can't happen */ 109636396SsklowerSAME <== TP_OPEN [ CR_TPDU, CC_TPDU ] 109736396Ssklower DEFAULT 109836396Ssklower { 109936396Ssklower if( $P.tp_class != TP_CLASS_0) { 110036396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 110136396Ssklower if ( $E.ev_number == CC_TPDU ) 110236396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 110336396Ssklower } 110436396Ssklower /* ignore it if class 0 - state tables are blank for this */ 110536396Ssklower } 110636396Ssklower; 110736396Ssklower 110836396Ssklower/* applicable in TP4, TP0 */ 110936396SsklowerSAME <== TP_OPEN T_DATA_req 111036396Ssklower DEFAULT 111136396Ssklower { 111236396Ssklower IFTRACE(D_DATA) 111336396Ssklower tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb", 111436396Ssklower $P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P); 111536396Ssklower ENDTRACE 111636396Ssklower 111736396Ssklower tp_send($P); 111836396Ssklower } 111936396Ssklower; 112036396Ssklower 112136396Ssklower/* TP4 only */ 112236396SsklowerSAME <== TP_OPEN T_XPD_req 112336396Ssklower DEFAULT 112436396Ssklower /* T_XPD_req was issued by sosend iff xpd socket buf was empty 112536396Ssklower * at time of sosend(), 112636396Ssklower * AND (which means) there were no unacknowledged XPD tpdus outstanding! 112736396Ssklower */ 112836396Ssklower { 112936396Ssklower int error = 0; 113036396Ssklower 113136396Ssklower /* resume XPD */ 113236396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 113337469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 113436396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 113536396Ssklower * that doesn't matter 113636396Ssklower */ 113736396Ssklower 113836396Ssklower IFTRACE(D_XPD) 113936396Ssklower tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna", 114036396Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, 114136396Ssklower $P.tp_snduna); 114236396Ssklower ENDTRACE 114336396Ssklower IFDEBUG(D_XPD) 114436396Ssklower printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc); 114536396Ssklower dump_mbuf(m, "XPD req emitting M"); 114636396Ssklower ENDDEBUG 114736396Ssklower error = 114836396Ssklower tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 114936396Ssklower $P.tp_retrans = $P.tp_Nretrans; 115036396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 115136396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 115236396Ssklower } 115336396Ssklower if(trick_hc) 115436396Ssklower return error; 115536396Ssklower } 115636396Ssklower; 115736396Ssklower 115836396Ssklower/* TP4, faked ack in TP0 when cons send completes */ 115936396SsklowerSAME <== TP_OPEN AK_TPDU 116036396Ssklower ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) ) 116136396Ssklower 116236396Ssklower /* tp_goodack == true means 116336396Ssklower * EITHER it actually acked something heretofore unacknowledged 116436396Ssklower * OR no news but the credit should be processed. 116536396Ssklower */ 116636396Ssklower { 116736396Ssklower IFDEBUG(D_ACKRECV) 116836396Ssklower printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt); 116936396Ssklower ENDDEBUG 117036396Ssklower if( $P.tp_class != TP_CLASS_0) { 117136396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 117236396Ssklower tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq); 117336396Ssklower } 117436396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 117536396Ssklower 117639921Ssklower if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat && 117739921Ssklower $P.tp_snduna <= $P.tp_retrans_hiwat) { 117839921Ssklower 117939921Ssklower register struct mbuf *m; 118039921Ssklower /* extern struct mbuf *m_copy(); */ 118139921Ssklower register struct tp_rtc *r; 118239921Ssklower SeqNum high, retrans, low_save; 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); 118739921Ssklower low_save = retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1), 118839921Ssklower $P.tp_snduna); 118939921Ssklower for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) { 119039921Ssklower 119139921Ssklower for (r = $P.tp_snduna_rtc; r; r = r->tprt_next){ 119239921Ssklower if ( r->tprt_seq == retrans ){ 119339921Ssklower if(( m = m_copy(r->tprt_data, 0, r->tprt_octets )) 119439921Ssklower == MNULL) 119539921Ssklower break; 119639921Ssklower (void) tp_emit(DT_TPDU_type, $P, retrans, 119739921Ssklower r->tprt_eot, m); 119839921Ssklower $P.tp_last_retrans = retrans; 119939921Ssklower IncStat(ts_retrans_dt); 120039921Ssklower break; 120139921Ssklower } 120239921Ssklower } 120339921Ssklower if ( r == (struct tp_rtc *)0 ){ 120439921Ssklower IFDEBUG(D_RTC) 120539921Ssklower printf( "tp: retrans rtc list is GONE!\n"); 120639921Ssklower ENDDEBUG 120739921Ssklower break; 120839921Ssklower } 120939921Ssklower } 121039921Ssklower tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)low_save, 121139921Ssklower (caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks); 121239921Ssklower if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat) 121339921Ssklower tp_send($P); 121439921Ssklower } 121539921Ssklower else { 121639921Ssklower tp_send($P); 121739921Ssklower } 121836396Ssklower IFDEBUG(D_ACKRECV) 121936396Ssklower printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat); 122036396Ssklower ENDDEBUG 122136396Ssklower } 122236396Ssklower; 122336396Ssklower 122436396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 122536396SsklowerSAME <== TP_OPEN AK_TPDU 122636396Ssklower DEFAULT 122736396Ssklower { 122836396Ssklower IFTRACE(D_ACKRECV) 122936396Ssklower tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", 123036396Ssklower $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0); 123136396Ssklower ENDTRACE 123236396Ssklower if( $P.tp_class != TP_CLASS_0 ) { 123336396Ssklower 123436396Ssklower if ( !$$.e_fcc_present ) { 123536396Ssklower /* send ACK with FCC */ 123636396Ssklower IncStat( ts_ackreason[_ACK_FCC_] ); 123736396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL); 123836396Ssklower } 123936396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 124036396Ssklower } 124136396Ssklower } 124236396Ssklower; 124336396Ssklower 124436396Ssklower/* NBS(47) */ 124536396Ssklower /* goes in at *** */ 124636396Ssklower /* just so happens that this is never true now, because we allow 124736396Ssklower * only 1 packet in the queue at once (this could be changed) 124836396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 124936396Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??); 125036396Ssklower 125136396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 125236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 125336396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 125436396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 125536396Ssklower } 125636396Ssklower */ 125736396Ssklower /* end of the above hack */ 125836396Ssklower 125936396Ssklower/* TP4 only */ 126042944SsklowerSAME <== TP_OPEN XAK_TPDU 126136396Ssklower ( tp_goodXack($P, $$.e_seq) ) 126236396Ssklower /* tp_goodXack checks for good ack, removes the correct 126336396Ssklower * tpdu from the queue and returns 1 if ack was legit, 0 if not. 126436396Ssklower * also updates tp_Xuna 126536396Ssklower */ 126636396Ssklower { 126736396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 126836396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 126936396Ssklower 127036396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 127136396Ssklower 127236396Ssklower /* resume normal data */ 127336396Ssklower tp_send($P); 127436396Ssklower } 127536396Ssklower; 127636396Ssklower 127742944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 127842944SsklowerSAME <== TP_OPEN XAK_TPDU 127942944Ssklower DEFAULT 128042944Ssklower { 128142944Ssklower IFTRACE(D_ACKRECV) 128242944Ssklower tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0); 128342944Ssklower ENDTRACE 128442944Ssklower if( $P.tp_class != TP_CLASS_0 ) { 128542944Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 128642944Ssklower } 128742944Ssklower } 128842944Ssklower; 128942944Ssklower 129036396Ssklower/* TP4 only */ 129136396SsklowerSAME <== TP_OPEN TM_sendack 129236396Ssklower DEFAULT 129336396Ssklower { 129436396Ssklower IFTRACE(D_TIMER) 129536396Ssklower tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 129636396Ssklower $P.tp_sent_lcdt, 0); 129736396Ssklower ENDTRACE 129836396Ssklower IncPStat($P, tps_n_TMsendack); 129936396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 130036396Ssklower } 130136396Ssklower; 130236396Ssklower 130336396Ssklower/* TP0 only */ 130436396SsklowerSAME <== TP_OPEN T_USR_rcvd 130536396Ssklower ($P.tp_class == TP_CLASS_0) 130647281Ssklower { 130747281Ssklower if (sbspace(&$P.tp_sock->so_rcv) > 0) 130847281Ssklower tp0_openflow($P); 130947281Ssklower } 131036396Ssklower; 131136396Ssklower 131236396Ssklower/* TP4 only */ 131336396Ssklower /* If old credit was zero, 131436396Ssklower * we'd better inform other side that we now have space 131536396Ssklower * But this is not enough. Sender might not yet have 131636396Ssklower * seen an ack with cdt 0 but it might still think the 131736396Ssklower * window is closed, so it's going to wait. 131836396Ssklower * Best to send an ack each time. 131936396Ssklower * Strictly speaking, this ought to be a function of the 132036396Ssklower * general ack strategy. 132136396Ssklower */ 132236396SsklowerSAME <== TP_OPEN T_USR_rcvd 132336396Ssklower DEFAULT 132436396Ssklower { 132536396Ssklower if( trick_hc ) { 132636396Ssklower IncStat(ts_ackreason[_ACK_USRRCV_]); 132739921Ssklower 132839921Ssklower /* send an ACK only if there's new information */ 132939921Ssklower LOCAL_CREDIT( $P ); 133039921Ssklower if (($P.tp_rcvnxt != $P.tp_sent_rcvnxt) || 133139921Ssklower ($P.tp_lcredit != $P.tp_sent_lcdt)) 133239921Ssklower 133339921Ssklower return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 133436396Ssklower } 133536396Ssklower } 133636396Ssklower; 133736396Ssklower 133836396Ssklower/* applicable in TP4, TP0 */ 133936396SsklowerSAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ] 134036396Ssklower DEFAULT 134136396Ssklower /* This happens if other end sent a DR when the user was waiting 134236396Ssklower * on a receive. 134336396Ssklower * Processing the DR includes putting us in REFWAIT state. 134436396Ssklower */ 134536396Ssklower { 134636396Ssklower if(trick_hc) 134736396Ssklower return ECONNABORTED; 134836396Ssklower } 134936396Ssklower; 135036396Ssklower 135136396Ssklower/* TP0 only */ 135236396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET 135336396Ssklower ( $P.tp_class != TP_CLASS_4 ) 135436396Ssklower /* 0 or (4 and 0) */ 135536396Ssklower /* in OPEN class will be 0 or 4 but not both */ 135636396Ssklower /* in CRSENT or LISTENING it could be in negotiation, hence both */ 135736396Ssklower /* Actually, this shouldn't ever happen in LISTENING */ 135836396Ssklower { 135936396Ssklower ASSERT( $P.tp_state != TP_LISTENING ); 136036396Ssklower tp_indicate(T_DISCONNECT, $P, ECONNRESET); 136136396Ssklower tp_soisdisconnected($P); 136236396Ssklower } 136336396Ssklower; 136436396Ssklower 136536396Ssklower/* TP4: ignore resets */ 136636396SsklowerSAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT, 136736396Ssklower TP_CLOSING, TP_LISTENING ] T_NETRESET 136836396Ssklower DEFAULT 136936396Ssklower NULLACTION 137036396Ssklower; 137136396Ssklower 137236396Ssklower/* applicable in TP4, TP0 */ 137336396SsklowerSAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET 137436396Ssklower DEFAULT 137536396Ssklower NULLACTION 137636396Ssklower; 137736396Ssklower 137836396Ssklower/* C'EST TOUT */ 1379