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