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*42944Ssklower/* @(#)tp.trans 7.5 (Berkeley) 06/06/90 */ 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); 31837469Ssklower /*$P.tp_flags |= TPF_CONN_DATA_IN;*/ 31936396Ssklower $$.e_data = MNULL; 32036396Ssklower } 32138841Ssklower } 32238841Ssklower; 32338841Ssklower 32438841SsklowerTP_OPEN <== TP_CONFIRMING T_ACPT_req 32538841Ssklower ( $P.tp_class == TP_CLASS_0 ) 32638841Ssklower { 32738841Ssklower IncStat(ts_tp0_conn); 32838841Ssklower IFTRACE(D_CONN) 32938841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 33038841Ssklower ENDTRACE 33138841Ssklower IFDEBUG(D_CONN) 33238841Ssklower printf("Confirming connection: $P" ); 33338841Ssklower ENDDEBUG 33438841Ssklower soisconnected($P.tp_sock); 33538841Ssklower (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ; 33638841Ssklower $P.tp_fcredit = 1; 33738841Ssklower } 33838841Ssklower; 33938841Ssklower 34038841SsklowerTP_AKWAIT <== TP_CONFIRMING T_ACPT_req 34138841Ssklower (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0) 34238841Ssklower { 34338841Ssklower IncStat(ts_tp4_conn); /* even though not quite open */ 34438841Ssklower IFTRACE(D_CONN) 34538841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 34638841Ssklower ENDTRACE 34738841Ssklower IFDEBUG(D_CONN) 34838841Ssklower printf("Confirming connection: $P" ); 34938841Ssklower ENDDEBUG 35038841Ssklower soisconnecting($P.tp_sock); 35136396Ssklower if($P.tp_rx_strat & TPRX_FASTSTART) 35238841Ssklower $P.tp_cong_win = $P.tp_fcredit; 35336396Ssklower $P.tp_retrans = $P.tp_Nretrans; 35436396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); 35538841Ssklower } 35636396Ssklower; 35736396Ssklower 35836396Ssklower/* TP4 only */ 35938841SsklowerTP_CLOSED <== TP_CONFIRMING T_ACPT_req 36036396Ssklower DEFAULT /* emit failed */ 36136396Ssklower { 36236396Ssklower register struct tp_ref *r = $P.tp_refp; 36336396Ssklower 36436396Ssklower IFDEBUG(D_CONN) 36536396Ssklower printf("event: CR_TPDU emit CC failed done " ); 36636396Ssklower ENDDEBUG 36738841Ssklower soisdisconnected($P.tp_sock); 36836396Ssklower tp_recycle_tsuffix( $P ); 36936396Ssklower tp_freeref(r); 37036396Ssklower tp_detach($P); 37136396Ssklower } 37236396Ssklower; 37336396Ssklower 37436396Ssklower/* applicable in TP4, TP0 */ 37536396SsklowerTP_CRSENT <== TP_CLOSED T_CONN_req 37636396Ssklower DEFAULT 37736396Ssklower { 37836396Ssklower int error; 37936396Ssklower struct mbuf *data = MNULL; 38036396Ssklower 38136396Ssklower IFTRACE(D_CONN) 38237469Ssklower tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags, 38337469Ssklower $P.tp_ucddata, 0, 0); 38436396Ssklower ENDTRACE 38537469Ssklower data = MCPY($P.tp_ucddata, M_WAIT); 38637469Ssklower if (data) { 38736396Ssklower IFDEBUG(D_CONN) 38836396Ssklower printf("T_CONN_req.trans m_copy cc 0x%x\n", 38937469Ssklower $P.tp_ucddata); 39037469Ssklower dump_mbuf(data, "sosnd @ T_CONN_req"); 39136396Ssklower ENDDEBUG 39236396Ssklower } 39336396Ssklower 39436396Ssklower if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) 39536396Ssklower return error; /* driver WON'T change state; will return error */ 39636396Ssklower 39736396Ssklower $P.tp_refp->tpr_state = REF_OPEN; /* has timers */ 39836396Ssklower if($P.tp_class != TP_CLASS_0) { 39936396Ssklower $P.tp_retrans = $P.tp_Nretrans; 40036396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks); 40136396Ssklower } 40236396Ssklower } 40336396Ssklower; 40436396Ssklower 40536396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */ 40636396SsklowerTP_REFWAIT <== [ TP_CRSENT, TP_AKWAIT, TP_OPEN ] DR_TPDU 40736396Ssklower DEFAULT 40836396Ssklower { 40936396Ssklower if ($$.e_datalen > 0 && $P.tp_class != TP_CLASS_0) { 41037469Ssklower /*sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc); /* purge expedited data */ 41137469Ssklower sbflush(&$P.tp_Xrcv); 41236396Ssklower $P.tp_flags |= TPF_DISC_DATA_IN; 41336396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 41436396Ssklower $$.e_data = MNULL; 41536396Ssklower } 41636396Ssklower tp_indicate(T_DISCONNECT, $P, TP_ERROR_MASK | (u_short)$$.e_reason); 41736396Ssklower tp_soisdisconnected($P); 41836396Ssklower if ($P.tp_class != TP_CLASS_0) { 41936396Ssklower if ($P.tp_state == TP_OPEN ) { 42036396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 42136396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 42236396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 42336396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 42436396Ssklower } 42536396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 42636396Ssklower if( $$.e_sref != 0 ) 42736396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 42836396Ssklower } 42936396Ssklower } 43036396Ssklower; 43136396Ssklower 43236396SsklowerSAME <== TP_CLOSED DR_TPDU 43336396Ssklower DEFAULT 43436396Ssklower { 43536396Ssklower if( $$.e_sref != 0 ) 43636396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 43736396Ssklower /* reference timer already set - reset it to be safe (???) */ 43836396Ssklower tp_euntimeout($P.tp_refp, TM_reference); /* all */ 43936396Ssklower tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks); 44036396Ssklower } 44136396Ssklower; 44236396Ssklower 44336396Ssklower/* NBS(34) */ 44436396SsklowerTP_REFWAIT <== TP_CRSENT ER_TPDU 44536396Ssklower DEFAULT 44636396Ssklower { 44736396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 44836396Ssklower tp_indicate(T_DISCONNECT, $P, 44936396Ssklower TP_ERROR_MASK |(u_short)($$.e_reason | 0x40)); 45036396Ssklower tp_soisdisconnected($P); 45136396Ssklower } 45236396Ssklower; 45336396Ssklower 45436396Ssklower/* NBS(27) */ 45536396SsklowerTP_REFWAIT <== TP_CLOSING DR_TPDU 45636396Ssklower DEFAULT 45736396Ssklower { 45836396Ssklower $P.tp_sock->so_error = (u_short)$$.e_reason; 45936396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 46036396Ssklower tp_soisdisconnected($P); 46136396Ssklower } 46236396Ssklower; 46336396Ssklower/* these two transitions are the same but can't be combined because xebec 46436396Ssklower * can't handle the use of $$.e_reason if they're combined 46536396Ssklower */ 46636396Ssklower/* NBS(27) */ 46736396SsklowerTP_REFWAIT <== TP_CLOSING ER_TPDU 46836396Ssklower DEFAULT 46936396Ssklower { 47036396Ssklower $P.tp_sock->so_error = (u_short)$$.e_reason; 47136396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 47236396Ssklower tp_soisdisconnected($P); 47336396Ssklower } 47436396Ssklower; 47536396Ssklower/* NBS(27) */ 47636396SsklowerTP_REFWAIT <== TP_CLOSING DC_TPDU 47736396Ssklower DEFAULT 47836396Ssklower { 47936396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 48036396Ssklower tp_soisdisconnected($P); 48136396Ssklower } 48236396Ssklower; 48336396Ssklower 48436396Ssklower/* NBS(21) */ 48536396SsklowerSAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ] 48636396Ssklower DEFAULT 48736396Ssklower { /* don't ask me why we have to do this - spec says so */ 48836396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL); 48936396Ssklower /* don't bother with retransmissions of the DR */ 49036396Ssklower } 49136396Ssklower; 49236396Ssklower 49336396Ssklower/* NBS(34) */ 49436396SsklowerTP_REFWAIT <== TP_OPEN ER_TPDU 49536396Ssklower ($P.tp_class == TP_CLASS_0) 49636396Ssklower { 49736396Ssklower tp_soisdisconnecting($P.tp_sock); 49836396Ssklower tp_indicate(T_DISCONNECT, $P, 49936396Ssklower TP_ERROR_MASK |(u_short)($$.e_reason | 0x40)); 50036396Ssklower 50136396Ssklower tp_soisdisconnected($P); 50236396Ssklower tp_netcmd( $P, CONN_CLOSE ); 50336396Ssklower } 50436396Ssklower; 50536396Ssklower 50636396SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU 50736396Ssklower DEFAULT 50836396Ssklower { 50936396Ssklower if ($P.tp_state == TP_OPEN) { 51036396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 51136396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 51236396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 51336396Ssklower } 51436396Ssklower tp_soisdisconnecting($P.tp_sock); 51536396Ssklower tp_indicate(T_DISCONNECT, $P, 51636396Ssklower TP_ERROR_MASK |(u_short)($$.e_reason | 0x40)); 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; 54436396Ssklower if($P.tp_rx_strat & TPRX_FASTSTART) 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 $P.tp_flags |= TPF_CONN_DATA_IN; 56136396Ssklower $$.e_data = MNULL; 56236396Ssklower } 56336396Ssklower 56436396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 56536396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 56636396Ssklower } 56736396Ssklower; 56836396Ssklower 56936396Ssklower/* TP4 only */ 57036396SsklowerSAME <== TP_CRSENT TM_retrans 57136396Ssklower ( $P.tp_retrans > 0 ) 57236396Ssklower { 57336396Ssklower struct mbuf *data = MNULL; 57436396Ssklower int error; 57536396Ssklower 57636396Ssklower IncStat(ts_retrans_cr); 57739921Ssklower $P.tp_cong_win = 1; 57839921Ssklower $P.tp_ackrcvd = 0; 57937469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 58037469Ssklower if($P.tp_ucddata) { 58136396Ssklower IFDEBUG(D_CONN) 58237469Ssklower printf("TM_retrans.trans m_copy cc 0x%x\n", data); 58337469Ssklower dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans"); 58436396Ssklower ENDDEBUG 58536396Ssklower if( data == MNULL ) 58636396Ssklower return ENOBUFS; 58736396Ssklower } 58836396Ssklower 58936396Ssklower $P.tp_retrans --; 59036396Ssklower if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) { 59136396Ssklower $P.tp_sock->so_error = error; 59236396Ssklower } 59336396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks); 59436396Ssklower } 59536396Ssklower; 59636396Ssklower 59736396Ssklower/* TP4 only */ 59836396SsklowerTP_REFWAIT <== TP_CRSENT TM_retrans 59936396Ssklower DEFAULT /* no more CR retransmissions */ 60036396Ssklower { 60136396Ssklower IncStat(ts_conn_gaveup); 60236396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 60336396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 60436396Ssklower tp_soisdisconnected($P); 60536396Ssklower } 60636396Ssklower; 60736396Ssklower 60836396Ssklower/* TP4 only */ 60936396SsklowerSAME <== TP_AKWAIT CR_TPDU 61036396Ssklower DEFAULT 61136396Ssklower /* duplicate CR (which doesn't really exist in the context of 61236396Ssklower * a connectionless network layer) 61336396Ssklower * Doesn't occur in class 0. 61436396Ssklower */ 61536396Ssklower { 61636396Ssklower int error; 61737469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 61836396Ssklower 61937469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) { 62036396Ssklower $P.tp_sock->so_error = error; 62136396Ssklower } 62236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 62336396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); 62436396Ssklower } 62536396Ssklower; 62636396Ssklower 62736396Ssklower/* TP4 only */ 62836396SsklowerTP_OPEN <== TP_AKWAIT DT_TPDU 62936396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 63036396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 63136396Ssklower { 63236396Ssklower int doack; 63336396Ssklower 63437469Ssklower /* 63537469Ssklower * Get rid of any confirm or connect data, so that if we 63637469Ssklower * crash or close, it isn't thought of as disconnect data. 63737469Ssklower */ 63837469Ssklower if ($P.tp_ucddata) { 63937469Ssklower m_freem($P.tp_ucddata); 64037469Ssklower $P.tp_ucddata = 0; 64136396Ssklower } 64236396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 64336396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 64436396Ssklower soisconnected($P.tp_sock); 64536396Ssklower tp_getoptions($P); 64636396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 64736396Ssklower 64836396Ssklower /* see also next 2 transitions, if you make any changes */ 64936396Ssklower 65036396Ssklower doack = tp_stash($P, $E); 65136396Ssklower IFDEBUG(D_DATA) 65236396Ssklower printf("tp_stash returns %d\n",doack); 65336396Ssklower ENDDEBUG 65436396Ssklower 65536396Ssklower if(doack) { 65636396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 65736396Ssklower tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); 65836396Ssklower } else 65936396Ssklower tp_ctimeout( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks); 66036396Ssklower 66136396Ssklower IFDEBUG(D_DATA) 66236396Ssklower printf("after stash calling sbwakeup\n"); 66336396Ssklower ENDDEBUG 66436396Ssklower } 66536396Ssklower; 66636396Ssklower 66736396SsklowerSAME <== TP_OPEN DT_TPDU 66836396Ssklower ( $P.tp_class == TP_CLASS_0 ) 66936396Ssklower { 67036396Ssklower tp0_stash($P, $E); 67136396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 67236396Ssklower 67336396Ssklower IFDEBUG(D_DATA) 67436396Ssklower printf("after stash calling sbwakeup\n"); 67536396Ssklower ENDDEBUG 67636396Ssklower } 67736396Ssklower; 67836396Ssklower 67936396Ssklower/* TP4 only */ 68036396SsklowerSAME <== TP_OPEN DT_TPDU 68136396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 68236396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 68336396Ssklower { 68436396Ssklower int doack; /* tells if we must ack immediately */ 68536396Ssklower 68636396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 68736396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 68836396Ssklower 68936396Ssklower doack = tp_stash($P, $E); 69036396Ssklower IFDEBUG(D_DATA) 69136396Ssklower printf("tp_stash returns %d\n",doack); 69236396Ssklower ENDDEBUG 69336396Ssklower 69436396Ssklower if(doack) 69536396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 69636396Ssklower else 69736396Ssklower tp_ctimeout_MIN( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks); 69836396Ssklower 69936396Ssklower IFDEBUG(D_DATA) 70036396Ssklower printf("after stash calling sbwakeup\n"); 70136396Ssklower ENDDEBUG 70236396Ssklower } 70336396Ssklower; 70436396Ssklower 70536396Ssklower/* Not in window - we must ack under certain circumstances, namely 70636396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given) 70736396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^. 70836396Ssklower * and 70936396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit 71036396Ssklower * 71136396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73) 71236396Ssklower * We just always ack. 71336396Ssklower */ 71436396Ssklower/* TP4 only */ 71536396SsklowerSAME <== [ TP_OPEN, TP_AKWAIT ] DT_TPDU 71636396Ssklower DEFAULT /* Not in window */ 71736396Ssklower { 71836396Ssklower IFTRACE(D_DATA) 71936396Ssklower tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", 72036396Ssklower $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0); 72136396Ssklower ENDTRACE 72236396Ssklower IncStat(ts_dt_niw); 72336396Ssklower m_freem($$.e_data); 72436396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 72536396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 72636396Ssklower } 72736396Ssklower; 72836396Ssklower 72936396Ssklower/* TP4 only */ 73036396SsklowerTP_OPEN <== TP_AKWAIT AK_TPDU 73136396Ssklower DEFAULT 73236396Ssklower { 73337469Ssklower if ($P.tp_ucddata) { 73437469Ssklower m_freem($P.tp_ucddata); 73537469Ssklower $P.tp_ucddata = 0; 73636396Ssklower } 73736396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 73836396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 73936396Ssklower 74036396Ssklower tp_getoptions($P); 74136396Ssklower soisconnected($P.tp_sock); 74236396Ssklower IFTRACE(D_CONN) 74336396Ssklower struct socket *so = $P.tp_sock; 74436396Ssklower tptrace(TPPTmisc, 74536396Ssklower "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", 74636396Ssklower so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); 74736396Ssklower tptrace(TPPTmisc, 74836396Ssklower "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", 74936396Ssklower so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); 75036396Ssklower ENDTRACE 75136396Ssklower 75236396Ssklower tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); 75336396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 75436396Ssklower } 75536396Ssklower; 75636396Ssklower 75736396Ssklower/* TP4 only */ 75836396SsklowerTP_OPEN <== [ TP_OPEN, TP_AKWAIT ] XPD_TPDU 75937469Ssklower ( $P.tp_Xrcvnxt == $$.e_seq /* && $P.tp_Xrcv.sb_cc == 0*/) 76036396Ssklower { 76136396Ssklower if( $P.tp_state == TP_AKWAIT ) { 76237469Ssklower if ($P.tp_ucddata) { 76337469Ssklower m_freem($P.tp_ucddata); 76437469Ssklower $P.tp_ucddata = 0; 76536396Ssklower } 76636396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 76736396Ssklower tp_getoptions($P); 76836396Ssklower soisconnected($P.tp_sock); 76936396Ssklower tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); 77036396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 77136396Ssklower } 77236396Ssklower IFTRACE(D_XPD) 77336396Ssklower tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", 77436396Ssklower $P.tp_Xrcvnxt,$$.e_seq, $$.e_datalen, $$.e_data->m_len); 77536396Ssklower ENDTRACE 77636396Ssklower 77737469Ssklower $P.tp_sock->so_state |= SS_RCVATMARK; 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 ) { 79537469Ssklower /*$P.tp_flags &= ~TPF_XPD_PRESENT;*/ 79636396Ssklower /* kludge for select(): */ 79737469Ssklower /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */ 79836396Ssklower } 79936396Ssklower } 80036396Ssklower /* OLD WAY: 80136396Ssklower * Ack only after the user receives the XPD. This is better for 80236396Ssklower * users that use one XPD right after another. 80336396Ssklower * Acking right away (the NEW WAY, see the prev. transition) is 80436396Ssklower * better for occasional * XPD, when the receiving user doesn't 80536396Ssklower * want to read the XPD immediately (which is session's behavior). 80636396Ssklower * 80736396Ssklower int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 80836396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 80936396Ssklower return error; 81036396Ssklower */ 81136396Ssklower; 81236396Ssklower 81336396Ssklower/* NOTE: presently if the user doesn't read the connection data 81436396Ssklower * before and expedited data PDU comes in, the connection data will 81536396Ssklower * be dropped. This is a bug. To avoid it, we need somewhere else 81636396Ssklower * to put the connection data. 81736396Ssklower * On the other hand, we need not to have it sitting around forever. 81836396Ssklower * This is a problem with the idea of trying to accommodate 81936396Ssklower * data on connect w/ a passive-open user interface. 82036396Ssklower */ 82136396Ssklower/* TP4 only */ 82236396Ssklower 82336396SsklowerSAME <== [ TP_AKWAIT, TP_OPEN ] XPD_TPDU 82436396Ssklower DEFAULT /* not in window or cdt==0 */ 82536396Ssklower { 82636396Ssklower IFTRACE(D_XPD) 82736396Ssklower tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", 82836396Ssklower $P.tp_Xrcvnxt, $$.e_seq, $P.tp_Xrcv.sb_cc , 0); 82936396Ssklower ENDTRACE 83036396Ssklower if( $P.tp_Xrcvnxt != $$.e_seq ) 83136396Ssklower IncStat(ts_xpd_niw); 83236396Ssklower if( $P.tp_Xrcv.sb_cc ) { 83337469Ssklower#ifdef notdef 83436396Ssklower if( $P.tp_flags & TPF_CONN_DATA_IN ) { 83536396Ssklower /* user isn't reading the connection data; see note above */ 83636396Ssklower sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc); 83736396Ssklower $P.tp_flags &= ~TPF_CONN_DATA_IN; 83836396Ssklower } 83937469Ssklower#endif notdef 84036396Ssklower /* might as well kick 'em again */ 84136396Ssklower tp_indicate(T_XDATA, $P, 0); 84236396Ssklower IncStat(ts_xpd_dup); 84336396Ssklower } 84436396Ssklower m_freem($$.e_data); 84536396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 84636396Ssklower /* don't send an xack because the xak gives "last one received", not 84736396Ssklower * "next one i expect" (dumb) 84836396Ssklower */ 84936396Ssklower } 85036396Ssklower; 85136396Ssklower 85236396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries 85336396Ssklower * to detach all its "children" 85436396Ssklower * Also (CRSENT) when user kills a job that's doing a connect() 85536396Ssklower */ 85636396SsklowerTP_REFWAIT <== TP_CRSENT T_DETACH 85736396Ssklower ($P.tp_class == TP_CLASS_0) 85836396Ssklower { 85936396Ssklower struct socket *so = $P.tp_sock; 86036396Ssklower 86136396Ssklower /* detach from parent socket so it can finish closing */ 86236396Ssklower if (so->so_head) { 86336396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 86436396Ssklower panic("tp: T_DETACH"); 86536396Ssklower so->so_head = 0; 86636396Ssklower } 86736396Ssklower tp_soisdisconnecting($P.tp_sock); 86836396Ssklower tp_netcmd( $P, CONN_CLOSE); 86936396Ssklower tp_soisdisconnected($P); 87036396Ssklower } 87136396Ssklower; 87236396Ssklower 87336396Ssklower/* TP4 only */ 87438841SsklowerTP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH 87536396Ssklower DEFAULT 87636396Ssklower { 87736396Ssklower struct socket *so = $P.tp_sock; 87837469Ssklower struct mbuf *data = MNULL; 87936396Ssklower 88036396Ssklower /* detach from parent socket so it can finish closing */ 88136396Ssklower if (so->so_head) { 88236396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 88336396Ssklower panic("tp: T_DETACH"); 88436396Ssklower so->so_head = 0; 88536396Ssklower } 88636396Ssklower if ($P.tp_state != TP_CLOSING) { 88736396Ssklower tp_soisdisconnecting($P.tp_sock); 88837469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 88937469Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data); 89036396Ssklower $P.tp_retrans = $P.tp_Nretrans; 89136396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 89236396Ssklower } 89336396Ssklower } 89436396Ssklower; 89536396Ssklower 89636396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req 89736396Ssklower ( $P.tp_class == TP_CLASS_0 ) 89836396Ssklower { 89936396Ssklower tp_soisdisconnecting($P.tp_sock); 90036396Ssklower tp_netcmd( $P, CONN_CLOSE); 90136396Ssklower tp_soisdisconnected($P); 90236396Ssklower } 90336396Ssklower; 90436396Ssklower 90536396Ssklower/* TP4 only */ 90638841SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req 90736396Ssklower DEFAULT 90836396Ssklower { 90937469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 91036396Ssklower 91136396Ssklower if($P.tp_state == TP_OPEN) { 91236396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 91336396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 91436396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 91536396Ssklower } 91637469Ssklower if (data) { 91736396Ssklower IFDEBUG(D_CONN) 91837469Ssklower printf("T_DISC_req.trans tp_ucddata 0x%x\n", 91937469Ssklower $P.tp_ucddata); 92037469Ssklower dump_mbuf(data, "ucddata @ T_DISC_req"); 92136396Ssklower ENDDEBUG 92236396Ssklower } 92336396Ssklower tp_soisdisconnecting($P.tp_sock); 92436396Ssklower $P.tp_retrans = $P.tp_Nretrans; 92536396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 92636396Ssklower 92736396Ssklower if( trick_hc ) 92836396Ssklower return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data); 92936396Ssklower } 93036396Ssklower; 93136396Ssklower 93236396Ssklower/* TP4 only */ 93336396SsklowerSAME <== TP_AKWAIT TM_retrans 93436396Ssklower ( $P.tp_retrans > 0 ) 93536396Ssklower { 93636396Ssklower int error; 93737469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 93836396Ssklower 93936396Ssklower IncStat(ts_retrans_cc); 94036396Ssklower $P.tp_retrans --; 94139921Ssklower $P.tp_cong_win = 1; 94239921Ssklower $P.tp_ackrcvd = 0; 94339921Ssklower 94437469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) 94536396Ssklower $P.tp_sock->so_error = error; 94636396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); 94736396Ssklower } 94836396Ssklower; 94936396Ssklower 95036396Ssklower/* TP4 only */ 95136396SsklowerTP_CLOSING <== TP_AKWAIT TM_retrans 95236396Ssklower DEFAULT /* out of time */ 95336396Ssklower { 95436396Ssklower IncStat(ts_conn_gaveup); 95536396Ssklower tp_soisdisconnecting($P.tp_sock); 95636396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 95736396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 95836396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL); 95936396Ssklower $P.tp_retrans = $P.tp_Nretrans; 96036396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 96136396Ssklower } 96236396Ssklower; 96336396Ssklower 96436396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does, 96536396Ssklower * if transmissions are going on. 96636396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack 96736396Ssklower * turnaround) 96836396Ssklower */ 96936396Ssklower/* TP4 only */ 97036396SsklowerTP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ] 97136396Ssklower DEFAULT 97236396Ssklower { 97336396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 97436396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 97536396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 97636396Ssklower 97736396Ssklower IncStat(ts_conn_gaveup); 97836396Ssklower tp_soisdisconnecting($P.tp_sock); 97936396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 98036396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 98136396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL); 98236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 98336396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 98436396Ssklower } 98536396Ssklower; 98636396Ssklower 98736396Ssklower/* TP4 only */ 98836396SsklowerSAME <== TP_OPEN TM_retrans 98936396Ssklower ( $P.tp_retrans > 0 ) 99036396Ssklower { 99139921Ssklower $P.tp_cong_win = 1; 99239921Ssklower $P.tp_ackrcvd = 0; 99336396Ssklower /* resume XPD */ 99436396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 99537469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 99636396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 99736396Ssklower * that doesn't matter 99836396Ssklower */ 99936396Ssklower 100036396Ssklower IFTRACE(D_XPD) 100136396Ssklower tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna", 100236396Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, 100336396Ssklower $P.tp_snduna); 100436396Ssklower ENDTRACE 100536396Ssklower IFDEBUG(D_XPD) 100636396Ssklower dump_mbuf(m, "XPD retrans emitting M"); 100736396Ssklower ENDDEBUG 100836396Ssklower IncStat(ts_retrans_xpd); 100936396Ssklower $P.tp_retrans --; 101036396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 101136396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 101236396Ssklower } 101336396Ssklower } 101436396Ssklower; 101536396Ssklower 101636396Ssklower/* TP4 only */ 101736396SsklowerSAME <== TP_OPEN TM_data_retrans 101836396Ssklower ( $$.e_retrans > 0 ) 101936396Ssklower { 102036396Ssklower register SeqNum low, lowsave = 0; 102136396Ssklower register struct tp_rtc *r = $P.tp_snduna_rtc; 102236396Ssklower register struct mbuf *m; 102336396Ssklower register SeqNum high = $$.e_high; 102436396Ssklower 102539921Ssklower low = $P.tp_snduna; 102639921Ssklower lowsave = high = low; 102739921Ssklower 102839921Ssklower tp_euntimeout_lss($P.tp_refp, TM_data_retrans, 102939921Ssklower SEQ_ADD($P, $P.tp_sndhiwat, 1)); 103039921Ssklower $P.tp_retrans_hiwat = $P.tp_sndhiwat; 103139921Ssklower 103236396Ssklower if (($P.tp_rx_strat & TPRX_EACH) == 0) 103336396Ssklower high = (high>low)?low:high; 103436396Ssklower 103536396Ssklower if( $P.tp_rx_strat & TPRX_USE_CW ) { 103636396Ssklower register int i; 103736396Ssklower 103836396Ssklower $P.tp_cong_win = 1; 103939921Ssklower $P.tp_ackrcvd = 0; 104039921Ssklower i = SEQ_ADD($P, low, $P.tp_cong_win); 104136396Ssklower 104239921Ssklower high = SEQ_MIN($P, high, $P.tp_sndhiwat); 104339921Ssklower 104436396Ssklower } 104536396Ssklower 104636396Ssklower while( SEQ_LEQ($P, low, high) ){ 104736396Ssklower if ( r == (struct tp_rtc *)0 ){ 104836396Ssklower IFDEBUG(D_RTC) 104936396Ssklower printf( "tp: retrans rtc list is GONE!\n"); 105036396Ssklower ENDDEBUG 105136396Ssklower break; 105236396Ssklower } 105336396Ssklower if ( r->tprt_seq == low ){ 105436396Ssklower if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL) 105536396Ssklower break; 105636396Ssklower (void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m); 105736396Ssklower IncStat(ts_retrans_dt); 105836396Ssklower SEQ_INC($P, low ); 105936396Ssklower } 106036396Ssklower r = r->tprt_next; 106136396Ssklower } 106239921Ssklower/* CE_BIT 106336396Ssklower if ( SEQ_LEQ($P, lowsave, high) ){ 106439921Ssklower*/ 106536396Ssklower $$.e_retrans --; 106636396Ssklower tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave, 106736396Ssklower (caddr_t)high, $$.e_retrans, 106836396Ssklower ($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks); 106939921Ssklower/* CE_BIT 107036396Ssklower } 107139921Ssklower*/ 107236396Ssklower } 107336396Ssklower; 107436396Ssklower 107536396Ssklower/* TP4 only */ 107636396SsklowerSAME <== TP_CLOSING TM_retrans 107736396Ssklower ( $P.tp_retrans > 0 ) 107836396Ssklower { 107936396Ssklower $P.tp_retrans --; 108036396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL); 108136396Ssklower IncStat(ts_retrans_dr); 108236396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 108336396Ssklower } 108436396Ssklower; 108536396Ssklower 108636396Ssklower/* TP4 only */ 108736396SsklowerTP_REFWAIT <== TP_CLOSING TM_retrans 108836396Ssklower DEFAULT /* no more retrans - gave up */ 108936396Ssklower { 109036396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 109136396Ssklower $P.tp_refp->tpr_state = REF_FROZEN; 109236396Ssklower tp_recycle_tsuffix( $P ); 109336396Ssklower tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks); 109436396Ssklower } 109536396Ssklower; 109636396Ssklower 109736396Ssklower/* 109836396Ssklower * The resources are kept around until the ref timer goes off. 109936396Ssklower * The suffices are wiped out sooner so they can be reused right away. 110036396Ssklower */ 110136396Ssklower/* applicable in TP4, TP0 */ 110236396SsklowerTP_CLOSED <== TP_REFWAIT TM_reference 110336396Ssklower DEFAULT 110436396Ssklower { 110536396Ssklower tp_freeref($P.tp_refp); 110636396Ssklower tp_detach($P); 110736396Ssklower } 110836396Ssklower; 110936396Ssklower 111036396Ssklower/* applicable in TP4, TP0 */ 111136396Ssklower/* A duplicate CR from connectionless network layer can't happen */ 111236396SsklowerSAME <== TP_OPEN [ CR_TPDU, CC_TPDU ] 111336396Ssklower DEFAULT 111436396Ssklower { 111536396Ssklower if( $P.tp_class != TP_CLASS_0) { 111636396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 111736396Ssklower if ( $E.ev_number == CC_TPDU ) 111836396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 111936396Ssklower } 112036396Ssklower /* ignore it if class 0 - state tables are blank for this */ 112136396Ssklower } 112236396Ssklower; 112336396Ssklower 112436396Ssklower/* applicable in TP4, TP0 */ 112536396SsklowerSAME <== TP_OPEN T_DATA_req 112636396Ssklower DEFAULT 112736396Ssklower { 112836396Ssklower IFTRACE(D_DATA) 112936396Ssklower tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb", 113036396Ssklower $P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P); 113136396Ssklower ENDTRACE 113236396Ssklower 113336396Ssklower tp_send($P); 113436396Ssklower } 113536396Ssklower; 113636396Ssklower 113736396Ssklower/* TP4 only */ 113836396SsklowerSAME <== TP_OPEN T_XPD_req 113936396Ssklower DEFAULT 114036396Ssklower /* T_XPD_req was issued by sosend iff xpd socket buf was empty 114136396Ssklower * at time of sosend(), 114236396Ssklower * AND (which means) there were no unacknowledged XPD tpdus outstanding! 114336396Ssklower */ 114436396Ssklower { 114536396Ssklower int error = 0; 114636396Ssklower 114736396Ssklower /* resume XPD */ 114836396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 114937469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 115036396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 115136396Ssklower * that doesn't matter 115236396Ssklower */ 115336396Ssklower 115436396Ssklower IFTRACE(D_XPD) 115536396Ssklower tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna", 115636396Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, 115736396Ssklower $P.tp_snduna); 115836396Ssklower ENDTRACE 115936396Ssklower IFDEBUG(D_XPD) 116036396Ssklower printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc); 116136396Ssklower dump_mbuf(m, "XPD req emitting M"); 116236396Ssklower ENDDEBUG 116336396Ssklower error = 116436396Ssklower tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 116536396Ssklower $P.tp_retrans = $P.tp_Nretrans; 116636396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 116736396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 116836396Ssklower } 116936396Ssklower if(trick_hc) 117036396Ssklower return error; 117136396Ssklower } 117236396Ssklower; 117336396Ssklower 117436396Ssklower/* TP4, faked ack in TP0 when cons send completes */ 117536396SsklowerSAME <== TP_OPEN AK_TPDU 117636396Ssklower ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) ) 117736396Ssklower 117836396Ssklower /* tp_goodack == true means 117936396Ssklower * EITHER it actually acked something heretofore unacknowledged 118036396Ssklower * OR no news but the credit should be processed. 118136396Ssklower */ 118236396Ssklower { 118336396Ssklower IFDEBUG(D_ACKRECV) 118436396Ssklower printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt); 118536396Ssklower ENDDEBUG 118636396Ssklower if( $P.tp_class != TP_CLASS_0) { 118736396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 118836396Ssklower tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq); 118936396Ssklower } 119036396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 119136396Ssklower 119239921Ssklower if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat && 119339921Ssklower $P.tp_snduna <= $P.tp_retrans_hiwat) { 119439921Ssklower 119539921Ssklower register struct mbuf *m; 119639921Ssklower /* extern struct mbuf *m_copy(); */ 119739921Ssklower register struct tp_rtc *r; 119839921Ssklower SeqNum high, retrans, low_save; 119939921Ssklower 120039921Ssklower high = SEQ_MIN($P, SEQ_ADD($P, $P.tp_snduna, 120139921Ssklower MIN($P.tp_cong_win, $P.tp_fcredit)) - 1, 120239921Ssklower $P.tp_sndhiwat); 120339921Ssklower low_save = retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1), 120439921Ssklower $P.tp_snduna); 120539921Ssklower for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) { 120639921Ssklower 120739921Ssklower for (r = $P.tp_snduna_rtc; r; r = r->tprt_next){ 120839921Ssklower if ( r->tprt_seq == retrans ){ 120939921Ssklower if(( m = m_copy(r->tprt_data, 0, r->tprt_octets )) 121039921Ssklower == MNULL) 121139921Ssklower break; 121239921Ssklower (void) tp_emit(DT_TPDU_type, $P, retrans, 121339921Ssklower r->tprt_eot, m); 121439921Ssklower $P.tp_last_retrans = retrans; 121539921Ssklower IncStat(ts_retrans_dt); 121639921Ssklower break; 121739921Ssklower } 121839921Ssklower } 121939921Ssklower if ( r == (struct tp_rtc *)0 ){ 122039921Ssklower IFDEBUG(D_RTC) 122139921Ssklower printf( "tp: retrans rtc list is GONE!\n"); 122239921Ssklower ENDDEBUG 122339921Ssklower break; 122439921Ssklower } 122539921Ssklower } 122639921Ssklower tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)low_save, 122739921Ssklower (caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks); 122839921Ssklower if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat) 122939921Ssklower tp_send($P); 123039921Ssklower } 123139921Ssklower else { 123239921Ssklower tp_send($P); 123339921Ssklower } 123436396Ssklower IFDEBUG(D_ACKRECV) 123536396Ssklower printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat); 123636396Ssklower ENDDEBUG 123736396Ssklower } 123836396Ssklower; 123936396Ssklower 124036396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 124136396SsklowerSAME <== TP_OPEN AK_TPDU 124236396Ssklower DEFAULT 124336396Ssklower { 124436396Ssklower IFTRACE(D_ACKRECV) 124536396Ssklower tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", 124636396Ssklower $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0); 124736396Ssklower ENDTRACE 124836396Ssklower if( $P.tp_class != TP_CLASS_0 ) { 124936396Ssklower 125036396Ssklower if ( !$$.e_fcc_present ) { 125136396Ssklower /* send ACK with FCC */ 125236396Ssklower IncStat( ts_ackreason[_ACK_FCC_] ); 125336396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL); 125436396Ssklower } 125536396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 125636396Ssklower } 125736396Ssklower } 125836396Ssklower; 125936396Ssklower 126036396Ssklower/* NBS(47) */ 126136396Ssklower /* goes in at *** */ 126236396Ssklower /* just so happens that this is never true now, because we allow 126336396Ssklower * only 1 packet in the queue at once (this could be changed) 126436396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 126536396Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??); 126636396Ssklower 126736396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 126836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 126936396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 127036396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 127136396Ssklower } 127236396Ssklower */ 127336396Ssklower /* end of the above hack */ 127436396Ssklower 127536396Ssklower/* TP4 only */ 1276*42944SsklowerSAME <== TP_OPEN XAK_TPDU 127736396Ssklower ( tp_goodXack($P, $$.e_seq) ) 127836396Ssklower /* tp_goodXack checks for good ack, removes the correct 127936396Ssklower * tpdu from the queue and returns 1 if ack was legit, 0 if not. 128036396Ssklower * also updates tp_Xuna 128136396Ssklower */ 128236396Ssklower { 128336396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 128436396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 128536396Ssklower 128636396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 128736396Ssklower 128836396Ssklower /* resume normal data */ 128936396Ssklower tp_send($P); 129036396Ssklower } 129136396Ssklower; 129236396Ssklower 1293*42944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 1294*42944SsklowerSAME <== TP_OPEN XAK_TPDU 1295*42944Ssklower DEFAULT 1296*42944Ssklower { 1297*42944Ssklower IFTRACE(D_ACKRECV) 1298*42944Ssklower tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0); 1299*42944Ssklower ENDTRACE 1300*42944Ssklower if( $P.tp_class != TP_CLASS_0 ) { 1301*42944Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 1302*42944Ssklower } 1303*42944Ssklower } 1304*42944Ssklower; 1305*42944Ssklower 130636396Ssklower/* TP4 only */ 130736396SsklowerSAME <== TP_OPEN TM_sendack 130836396Ssklower DEFAULT 130936396Ssklower { 131036396Ssklower IFTRACE(D_TIMER) 131136396Ssklower tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 131236396Ssklower $P.tp_sent_lcdt, 0); 131336396Ssklower ENDTRACE 131436396Ssklower IncPStat($P, tps_n_TMsendack); 131536396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 131636396Ssklower } 131736396Ssklower; 131836396Ssklower 131936396Ssklower/* TP0 only */ 132036396SsklowerSAME <== TP_OPEN T_USR_rcvd 132136396Ssklower ($P.tp_class == TP_CLASS_0) 132236396Ssklower NULLACTION 132336396Ssklower; 132436396Ssklower 132536396Ssklower/* TP4 only */ 132636396Ssklower /* If old credit was zero, 132736396Ssklower * we'd better inform other side that we now have space 132836396Ssklower * But this is not enough. Sender might not yet have 132936396Ssklower * seen an ack with cdt 0 but it might still think the 133036396Ssklower * window is closed, so it's going to wait. 133136396Ssklower * Best to send an ack each time. 133236396Ssklower * Strictly speaking, this ought to be a function of the 133336396Ssklower * general ack strategy. 133436396Ssklower */ 133536396SsklowerSAME <== TP_OPEN T_USR_rcvd 133636396Ssklower DEFAULT 133736396Ssklower { 133836396Ssklower if( trick_hc ) { 133936396Ssklower IncStat(ts_ackreason[_ACK_USRRCV_]); 134039921Ssklower 134139921Ssklower /* send an ACK only if there's new information */ 134239921Ssklower LOCAL_CREDIT( $P ); 134339921Ssklower if (($P.tp_rcvnxt != $P.tp_sent_rcvnxt) || 134439921Ssklower ($P.tp_lcredit != $P.tp_sent_lcdt)) 134539921Ssklower 134639921Ssklower return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 134736396Ssklower } 134836396Ssklower } 134936396Ssklower; 135036396Ssklower 135136396Ssklower/* applicable in TP4, TP0 */ 135236396SsklowerSAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ] 135336396Ssklower DEFAULT 135436396Ssklower /* This happens if other end sent a DR when the user was waiting 135536396Ssklower * on a receive. 135636396Ssklower * Processing the DR includes putting us in REFWAIT state. 135736396Ssklower */ 135836396Ssklower { 135936396Ssklower if(trick_hc) 136036396Ssklower return ECONNABORTED; 136136396Ssklower } 136236396Ssklower; 136336396Ssklower 136436396Ssklower/* TP0 only */ 136536396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET 136636396Ssklower ( $P.tp_class != TP_CLASS_4 ) 136736396Ssklower /* 0 or (4 and 0) */ 136836396Ssklower /* in OPEN class will be 0 or 4 but not both */ 136936396Ssklower /* in CRSENT or LISTENING it could be in negotiation, hence both */ 137036396Ssklower /* Actually, this shouldn't ever happen in LISTENING */ 137136396Ssklower { 137236396Ssklower ASSERT( $P.tp_state != TP_LISTENING ); 137336396Ssklower tp_indicate(T_DISCONNECT, $P, ECONNRESET); 137436396Ssklower tp_soisdisconnected($P); 137536396Ssklower } 137636396Ssklower; 137736396Ssklower 137836396Ssklower/* TP4: ignore resets */ 137936396SsklowerSAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT, 138036396Ssklower TP_CLOSING, TP_LISTENING ] T_NETRESET 138136396Ssklower DEFAULT 138236396Ssklower NULLACTION 138336396Ssklower; 138436396Ssklower 138536396Ssklower/* applicable in TP4, TP0 */ 138636396SsklowerSAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET 138736396Ssklower DEFAULT 138836396Ssklower NULLACTION 138936396Ssklower; 139036396Ssklower 139136396Ssklower/* C'EST TOUT */ 1392