1*50849Ssklower/* NEW */ 249268Sbostic/*- 349268Sbostic * Copyright (c) 1991 The Regents of the University of California. 449268Sbostic * All rights reserved. 549268Sbostic * 649268Sbostic * %sccs.include.redist.c% 749268Sbostic * 8*50849Ssklower * @(#)tp.trans 7.10 (Berkeley) 08/14/91 949268Sbostic */ 1049268Sbostic 1136396Ssklower/*********************************************************** 1236396Ssklower Copyright IBM Corporation 1987 1336396Ssklower 1436396Ssklower All Rights Reserved 1536396Ssklower 1636396SsklowerPermission to use, copy, modify, and distribute this software and its 1736396Ssklowerdocumentation for any purpose and without fee is hereby granted, 1836396Ssklowerprovided that the above copyright notice appear in all copies and that 1936396Ssklowerboth that copyright notice and this permission notice appear in 2036396Ssklowersupporting documentation, and that the name of IBM not be 2136396Ssklowerused in advertising or publicity pertaining to distribution of the 2236396Ssklowersoftware without specific, written prior permission. 2336396Ssklower 2436396SsklowerIBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2536396SsklowerALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2636396SsklowerIBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2736396SsklowerANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2836396SsklowerWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2936396SsklowerARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 3036396SsklowerSOFTWARE. 3136396Ssklower 3236396Ssklower******************************************************************/ 3336396Ssklower 3436396Ssklower/* 3536396Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3636396Ssklower */ 3736396Ssklower/* $Header: tp.trans,v 5.1 88/10/12 12:22:07 root Exp $ 3836396Ssklower * 3936396Ssklower * Transition file for TP. 4036396Ssklower * 4136396Ssklower * DO NOT: 4236396Ssklower * - change the order of any of the events or states. to do so will 4336396Ssklower * make tppt, netstat, etc. cease working. 4436396Ssklower * 4536396Ssklower * NOTE: 4636396Ssklower * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED*** 4736396Ssklower * (read: may not work!) 4836396Ssklower * 4936396Ssklower * I tried to put everything that causes a change of state in here, hence 5036396Ssklower * there are some seemingly trivial events like T_DETACH and T_LISTEN_req. 5136396Ssklower * 5236396Ssklower * Almost everything having to do w/ setting & cancelling timers is here 5336396Ssklower * but once it was debugged, I moved the setting of the 5436396Ssklower * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent. 5536396Ssklower * This is so the code wouldn't be duplicated all over creation in here. 5636396Ssklower * 5736396Ssklower */ 5836396Ssklower*PROTOCOL tp 5936396Ssklower 6036396Ssklower*INCLUDE 6136396Ssklower{ 62*50849Ssklower/* @(#)tp.trans 7.10 (Berkeley) 08/14/91 */ 6336396Ssklower#include "param.h" 6436396Ssklower#include "socket.h" 6536396Ssklower#include "socketvar.h" 6636396Ssklower#include "protosw.h" 6736396Ssklower#include "mbuf.h" 6836396Ssklower#include "time.h" 6936396Ssklower#include "errno.h" 7036396Ssklower#include "../netiso/tp_param.h" 7136396Ssklower#include "../netiso/tp_stat.h" 7236396Ssklower#include "../netiso/tp_pcb.h" 7336396Ssklower#include "../netiso/tp_tpdu.h" 7436396Ssklower#include "../netiso/argo_debug.h" 7536396Ssklower#include "../netiso/tp_trace.h" 7636396Ssklower#include "../netiso/iso_errno.h" 7736396Ssklower#include "../netiso/tp_seq.h" 7836396Ssklower#include "../netiso/cons.h" 7936396Ssklower 8036396Ssklower#define DRIVERTRACE TPPTdriver 8137469Ssklower#define sbwakeup(sb) sowakeup(p->tp_sock, sb); 8237469Ssklower#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0) 8336396Ssklower 8436396Ssklowerstatic trick_hc = 1; 8536396Ssklower 8636396Ssklowerint tp_emit(), 8736396Ssklower tp_goodack(), tp_goodXack(), 8836396Ssklower tp_stash() 8936396Ssklower; 9036396Ssklowervoid tp_indicate(), tp_getoptions(), 9136396Ssklower tp_soisdisconnecting(), tp_soisdisconnected(), 9236396Ssklower tp_recycle_tsuffix(), 9336396Ssklower tp_etimeout(), tp_euntimeout(), 9436396Ssklower tp_euntimeout_lss(), tp_ctimeout(), 9536396Ssklower tp_cuntimeout(), tp_ctimeout_MIN(), 9636396Ssklower tp_freeref(), tp_detach(), 9736396Ssklower tp0_stash(), tp0_send(), 9836396Ssklower tp_netcmd(), tp_send() 9936396Ssklower; 10036396Ssklower 10136396Ssklowertypedef struct tp_pcb tpcb_struct; 10236396Ssklower 10336396Ssklower 10436396Ssklower} 10536396Ssklower 10636396Ssklower*PCB tpcb_struct SYNONYM P 10736396Ssklower 10836396Ssklower*STATES 10936396Ssklower 11036396SsklowerTP_CLOSED 11136396SsklowerTP_CRSENT 11236396SsklowerTP_AKWAIT 11336396SsklowerTP_OPEN 11436396SsklowerTP_CLOSING 11536396SsklowerTP_REFWAIT 11636396SsklowerTP_LISTENING /* Local to this implementation */ 11738841SsklowerTP_CONFIRMING /* Local to this implementation */ 11836396Ssklower 11936396Ssklower*EVENTS { struct timeval e_time; } SYNONYM E 12036396Ssklower 12136396Ssklower /* 12236396Ssklower * C (typically cancelled) timers - 12336396Ssklower * 12436396Ssklower * let these be the first ones so for the sake of convenience 12536396Ssklower * their values are 0--> n-1 12636396Ssklower * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!! 12736396Ssklower */ 12836396Ssklower TM_inact 12936396Ssklower TM_retrans 13036396Ssklower /* TM_retrans is used for all 13136396Ssklower * simple retransmissions - CR,CC,XPD,DR 13236396Ssklower */ 13336396Ssklower 13436396Ssklower TM_sendack 13536396Ssklower /* TM_sendack does dual duty - keepalive AND sendack. 13636396Ssklower * It's set w/ keepalive-ticks every time an ack is sent. 13736396Ssklower * (this is done in (void) tp_emit() ). 13836396Ssklower * It's cancelled and reset whenever a DT 13936396Ssklower * arrives and it doesn't require immediate acking. 14036396Ssklower * Note that in this case it's set w/ the minimum of 14136396Ssklower * its prev value and the sendack-ticks value so the 14236396Ssklower * purpose of the keepalive is preserved. 14336396Ssklower */ 14436396Ssklower TM_notused 14536396Ssklower 14636396Ssklower /* 14736396Ssklower * E (typically expired) timers - these may be in any order. 14836396Ssklower * These cause procedures to be executed directly; may not 14936396Ssklower * cause an 'event' as we know them here. 15036396Ssklower */ 15136396Ssklower TM_reference { SeqNum e_low; SeqNum e_high; int e_retrans; } 15236396Ssklower TM_data_retrans { SeqNum e_low; SeqNum e_high; int e_retrans; } 15336396Ssklower 15436396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that 15536396Ssklower * for all tpdu types that can take e_data and e_datalen, these 15636396Ssklower * fields fall in the same place in the event structure, that is, 15736396Ssklower * e_data is the first field and e_datalen is the 2nd field. 15836396Ssklower */ 15936396Ssklower 16036396Ssklower ER_TPDU { 16136396Ssklower u_char e_reason; 16236396Ssklower } 16336396Ssklower CR_TPDU { struct mbuf *e_data; /* first field */ 16436396Ssklower int e_datalen; /* 2nd field */ 16536396Ssklower u_int e_cdt; 16636396Ssklower } 16736396Ssklower DR_TPDU { struct mbuf *e_data; /* first field */ 16836396Ssklower int e_datalen; /* 2nd field */ 16936396Ssklower u_short e_sref; 17036396Ssklower u_char e_reason; 17136396Ssklower } 17236396Ssklower DC_TPDU 17336396Ssklower CC_TPDU { struct mbuf *e_data; /* first field */ 17436396Ssklower int e_datalen; /* 2nd field */ 17536396Ssklower u_short e_sref; 17636396Ssklower u_int e_cdt; 17736396Ssklower } 17836396Ssklower AK_TPDU { u_int e_cdt; 17936396Ssklower SeqNum e_seq; 18036396Ssklower SeqNum e_subseq; 18136396Ssklower u_char e_fcc_present; 18236396Ssklower } 18336396Ssklower DT_TPDU { struct mbuf *e_data; /* first field */ 18436396Ssklower int e_datalen; /* 2nd field */ 18536396Ssklower u_int e_eot; 18636396Ssklower SeqNum e_seq; 18736396Ssklower } 18836396Ssklower XPD_TPDU { struct mbuf *e_data; /* first field */ 18936396Ssklower int e_datalen; /* 2nd field */ 19036396Ssklower SeqNum e_seq; 19136396Ssklower } 19236396Ssklower XAK_TPDU { SeqNum e_seq; } 19336396Ssklower 19436396Ssklower T_CONN_req 19536396Ssklower T_DISC_req { u_char e_reason; } 19636396Ssklower T_LISTEN_req 19736396Ssklower T_DATA_req 19836396Ssklower T_XPD_req 19936396Ssklower T_USR_rcvd 20036396Ssklower T_USR_Xrcvd 20136396Ssklower T_DETACH 20236396Ssklower T_NETRESET 20338841Ssklower T_ACPT_req 20436396Ssklower 20536396Ssklower 20636396Ssklower*TRANSITIONS 20736396Ssklower 20836396Ssklower 20936396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */ 21036396SsklowerSAME <== TP_AKWAIT [ CC_TPDU, DC_TPDU, XAK_TPDU ] 21136396Ssklower DEFAULT 21236396Ssklower NULLACTION 21336396Ssklower; 21436396Ssklower 21536396Ssklower 21636396Ssklower/* applicable in TP4, TP0 */ 21736396SsklowerSAME <== TP_REFWAIT DR_TPDU 21836396Ssklower ( $$.e_sref != 0 ) 21936396Ssklower { 22036396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 22136396Ssklower } 22236396Ssklower; 22336396Ssklower 22436396Ssklower/* applicable in TP4, TP0 */ 22536396SsklowerSAME <== TP_REFWAIT [ CR_TPDU, CC_TPDU, DT_TPDU, 22636396Ssklower DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ] 22736396Ssklower DEFAULT 22836396Ssklower { 22936396Ssklower# ifdef TP_DEBUG 23036396Ssklower if( $E.ev_number != AK_TPDU ) 23136396Ssklower printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number); 23236396Ssklower# endif TP_DEBUG 23336396Ssklower } 23436396Ssklower; 23536396Ssklower 23636396Ssklower/* applicable in TP4, TP0 */ 23736396SsklowerSAME <== TP_REFWAIT [ T_DETACH, T_DISC_req ] 23836396Ssklower DEFAULT 23936396Ssklower NULLACTION 24036396Ssklower; 24136396Ssklower 24236396Ssklower/* applicable in TP4, TP0 */ 24336396SsklowerSAME <== TP_CRSENT AK_TPDU 24436396Ssklower ($P.tp_class == TP_CLASS_0) 24536396Ssklower { 24636396Ssklower /* oh, man is this grotesque or what? */ 24736396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 24836396Ssklower /* but it's necessary because this pseudo-ack may happen 24936396Ssklower * before the CC arrives, but we HAVE to adjust the 25036396Ssklower * snduna as a result of the ack, WHENEVER it arrives 25136396Ssklower */ 25236396Ssklower } 25336396Ssklower; 25436396Ssklower 25536396Ssklower/* applicable in TP4, TP0 */ 25636396SsklowerSAME <== TP_CRSENT 25736396Ssklower [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU, XAK_TPDU ] 25836396Ssklower DEFAULT 25936396Ssklower NULLACTION 26036396Ssklower; 26136396Ssklower 26236396Ssklower/* applicable in TP4, TP0 */ 26336396SsklowerSAME <== TP_CLOSED [ DT_TPDU, XPD_TPDU, 26436396Ssklower ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 26536396Ssklower DEFAULT 26636396Ssklower NULLACTION 26736396Ssklower; 26836396Ssklower 26936396Ssklower/* TP_CLOSING doesn't exist in TP 0 */ 27036396SsklowerSAME <== TP_CLOSING 27136396Ssklower [ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ] 27236396Ssklower DEFAULT 27336396Ssklower NULLACTION 27436396Ssklower; 27536396Ssklower 27636396Ssklower 27736396Ssklower/* DC_TPDU doesn't exist in TP 0 */ 27836396SsklowerSAME <== TP_OPEN DC_TPDU 27936396Ssklower DEFAULT 28036396Ssklower NULLACTION 28136396Ssklower; 28236396Ssklower 28336396Ssklower/* applicable in TP4, TP0 */ 28436396SsklowerSAME <== TP_LISTENING [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU, 28536396Ssklower ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 28636396Ssklower DEFAULT 28736396Ssklower NULLACTION 28836396Ssklower; 28936396Ssklower 29036396Ssklower/* applicable in TP4, TP0 */ 29136396SsklowerTP_LISTENING <== TP_CLOSED T_LISTEN_req 29236396Ssklower DEFAULT 29336396Ssklower NULLACTION 29436396Ssklower; 29536396Ssklower 29636396Ssklower/* applicable in TP4, TP0 */ 29736396SsklowerTP_CLOSED <== [ TP_LISTENING, TP_CLOSED ] T_DETACH 29836396Ssklower DEFAULT 29936396Ssklower { 30036396Ssklower tp_detach($P); 30136396Ssklower } 30236396Ssklower; 30336396Ssklower 30438841SsklowerTP_CONFIRMING <== TP_LISTENING CR_TPDU 30538841Ssklower ( $P.tp_class == TP_CLASS_0) 30636396Ssklower { 30736396Ssklower $P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */ 30836396Ssklower } 30936396Ssklower; 31036396Ssklower 31138841SsklowerTP_CONFIRMING <== TP_LISTENING CR_TPDU 31238841Ssklower DEFAULT 31336396Ssklower { 31436396Ssklower IFTRACE(D_CONN) 31536396Ssklower tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0); 31636396Ssklower ENDTRACE 31736396Ssklower IFDEBUG(D_CONN) 31836396Ssklower printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data); 31936396Ssklower ENDDEBUG 32036396Ssklower $P.tp_refp->tpr_state = REF_OPEN; /* has timers */ 32138841Ssklower $P.tp_fcredit = $$.e_cdt; 32236396Ssklower 32336396Ssklower if ($$.e_datalen > 0) { 32436396Ssklower /* n/a for class 0 */ 32536396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); 32636396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 32736396Ssklower $$.e_data = MNULL; 32836396Ssklower } 32938841Ssklower } 33038841Ssklower; 33138841Ssklower 33238841SsklowerTP_OPEN <== TP_CONFIRMING T_ACPT_req 33338841Ssklower ( $P.tp_class == TP_CLASS_0 ) 33438841Ssklower { 33538841Ssklower IncStat(ts_tp0_conn); 33638841Ssklower IFTRACE(D_CONN) 33738841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 33838841Ssklower ENDTRACE 33938841Ssklower IFDEBUG(D_CONN) 34038841Ssklower printf("Confirming connection: $P" ); 34138841Ssklower ENDDEBUG 34238841Ssklower soisconnected($P.tp_sock); 34338841Ssklower (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ; 34438841Ssklower $P.tp_fcredit = 1; 34538841Ssklower } 34638841Ssklower; 34738841Ssklower 34838841SsklowerTP_AKWAIT <== TP_CONFIRMING T_ACPT_req 34938841Ssklower (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0) 35038841Ssklower { 35138841Ssklower IncStat(ts_tp4_conn); /* even though not quite open */ 35238841Ssklower IFTRACE(D_CONN) 35338841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 35438841Ssklower ENDTRACE 35538841Ssklower IFDEBUG(D_CONN) 35638841Ssklower printf("Confirming connection: $P" ); 35738841Ssklower ENDDEBUG 35838841Ssklower soisconnecting($P.tp_sock); 35947281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0)) 36038841Ssklower $P.tp_cong_win = $P.tp_fcredit; 36136396Ssklower $P.tp_retrans = $P.tp_Nretrans; 36236396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); 36338841Ssklower } 36436396Ssklower; 36536396Ssklower 36636396Ssklower/* TP4 only */ 36738841SsklowerTP_CLOSED <== TP_CONFIRMING T_ACPT_req 36836396Ssklower DEFAULT /* emit failed */ 36936396Ssklower { 37036396Ssklower register struct tp_ref *r = $P.tp_refp; 37136396Ssklower 37236396Ssklower IFDEBUG(D_CONN) 37336396Ssklower printf("event: CR_TPDU emit CC failed done " ); 37436396Ssklower ENDDEBUG 37538841Ssklower soisdisconnected($P.tp_sock); 37636396Ssklower tp_recycle_tsuffix( $P ); 37736396Ssklower tp_freeref(r); 37836396Ssklower tp_detach($P); 37936396Ssklower } 38036396Ssklower; 38136396Ssklower 38236396Ssklower/* applicable in TP4, TP0 */ 38336396SsklowerTP_CRSENT <== TP_CLOSED T_CONN_req 38436396Ssklower DEFAULT 38536396Ssklower { 38636396Ssklower int error; 38736396Ssklower struct mbuf *data = MNULL; 38836396Ssklower 38936396Ssklower IFTRACE(D_CONN) 39037469Ssklower tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags, 39137469Ssklower $P.tp_ucddata, 0, 0); 39236396Ssklower ENDTRACE 39337469Ssklower data = MCPY($P.tp_ucddata, M_WAIT); 39437469Ssklower if (data) { 39536396Ssklower IFDEBUG(D_CONN) 39636396Ssklower printf("T_CONN_req.trans m_copy cc 0x%x\n", 39737469Ssklower $P.tp_ucddata); 39837469Ssklower dump_mbuf(data, "sosnd @ T_CONN_req"); 39936396Ssklower ENDDEBUG 40036396Ssklower } 40136396Ssklower 40236396Ssklower if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) 40336396Ssklower return error; /* driver WON'T change state; will return error */ 40436396Ssklower 40536396Ssklower $P.tp_refp->tpr_state = REF_OPEN; /* has timers */ 40636396Ssklower if($P.tp_class != TP_CLASS_0) { 40736396Ssklower $P.tp_retrans = $P.tp_Nretrans; 40836396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks); 40936396Ssklower } 41036396Ssklower } 41136396Ssklower; 41236396Ssklower 41336396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */ 41436396SsklowerTP_REFWAIT <== [ TP_CRSENT, TP_AKWAIT, TP_OPEN ] DR_TPDU 41536396Ssklower DEFAULT 41636396Ssklower { 41748739Ssklower sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */ 41848739Ssklower if ($$.e_datalen > 0) { 41936396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 42036396Ssklower $$.e_data = MNULL; 42136396Ssklower } 42248739Ssklower tp_indicate(T_DISCONNECT, $P, 0); 42336396Ssklower tp_soisdisconnected($P); 42436396Ssklower if ($P.tp_class != TP_CLASS_0) { 42536396Ssklower if ($P.tp_state == TP_OPEN ) { 42636396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 42736396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 42836396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 42936396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 43036396Ssklower } 43136396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 43236396Ssklower if( $$.e_sref != 0 ) 43336396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 43436396Ssklower } 43536396Ssklower } 43636396Ssklower; 43736396Ssklower 43836396SsklowerSAME <== TP_CLOSED DR_TPDU 43936396Ssklower DEFAULT 44036396Ssklower { 44136396Ssklower if( $$.e_sref != 0 ) 44236396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 44336396Ssklower /* reference timer already set - reset it to be safe (???) */ 44436396Ssklower tp_euntimeout($P.tp_refp, TM_reference); /* all */ 44536396Ssklower tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks); 44636396Ssklower } 44736396Ssklower; 44836396Ssklower 44936396Ssklower/* NBS(34) */ 45036396SsklowerTP_REFWAIT <== TP_CRSENT ER_TPDU 45136396Ssklower DEFAULT 45236396Ssklower { 45336396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 45448739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 45536396Ssklower tp_soisdisconnected($P); 45636396Ssklower } 45736396Ssklower; 45836396Ssklower 45936396Ssklower/* NBS(27) */ 46036396SsklowerTP_REFWAIT <== TP_CLOSING DR_TPDU 46136396Ssklower DEFAULT 46236396Ssklower { 46336396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 46436396Ssklower tp_soisdisconnected($P); 46536396Ssklower } 46636396Ssklower; 46736396Ssklower/* these two transitions are the same but can't be combined because xebec 46836396Ssklower * can't handle the use of $$.e_reason if they're combined 46936396Ssklower */ 47036396Ssklower/* NBS(27) */ 47136396SsklowerTP_REFWAIT <== TP_CLOSING ER_TPDU 47236396Ssklower DEFAULT 47336396Ssklower { 47448739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 47536396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 47636396Ssklower tp_soisdisconnected($P); 47736396Ssklower } 47836396Ssklower; 47936396Ssklower/* NBS(27) */ 48036396SsklowerTP_REFWAIT <== TP_CLOSING DC_TPDU 48136396Ssklower DEFAULT 48236396Ssklower { 48336396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 48436396Ssklower tp_soisdisconnected($P); 48536396Ssklower } 48636396Ssklower; 48736396Ssklower 48836396Ssklower/* NBS(21) */ 48936396SsklowerSAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ] 49036396Ssklower DEFAULT 49136396Ssklower { /* don't ask me why we have to do this - spec says so */ 49236396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL); 49336396Ssklower /* don't bother with retransmissions of the DR */ 49436396Ssklower } 49536396Ssklower; 49636396Ssklower 49736396Ssklower/* NBS(34) */ 49836396SsklowerTP_REFWAIT <== TP_OPEN ER_TPDU 49936396Ssklower ($P.tp_class == TP_CLASS_0) 50036396Ssklower { 50136396Ssklower tp_soisdisconnecting($P.tp_sock); 50248739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 50336396Ssklower tp_soisdisconnected($P); 50436396Ssklower tp_netcmd( $P, CONN_CLOSE ); 50536396Ssklower } 50636396Ssklower; 50736396Ssklower 50836396SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU 50936396Ssklower DEFAULT 51036396Ssklower { 51136396Ssklower if ($P.tp_state == TP_OPEN) { 51236396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 51336396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 51436396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 51536396Ssklower } 51636396Ssklower tp_soisdisconnecting($P.tp_sock); 51748739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 51836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 51936396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 52036396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL); 52136396Ssklower } 52236396Ssklower; 52336396Ssklower/* NBS(6) */ 52436396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 52536396Ssklower ($P.tp_class == TP_CLASS_0) 52636396Ssklower { 52736396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 52836396Ssklower IncStat(ts_tp0_conn); 52936396Ssklower $P.tp_fcredit = 1; 53036396Ssklower soisconnected($P.tp_sock); 53136396Ssklower } 53236396Ssklower; 53336396Ssklower 53436396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 53536396Ssklower DEFAULT 53636396Ssklower { 53736396Ssklower IFDEBUG(D_CONN) 53836396Ssklower printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", 53936396Ssklower (int)$P.tp_flags); 54036396Ssklower ENDDEBUG 54136396Ssklower IncStat(ts_tp4_conn); 54236396Ssklower $P.tp_fref = $$.e_sref; 54336396Ssklower $P.tp_fcredit = $$.e_cdt; 54439921Ssklower $P.tp_ackrcvd = 0; 54547281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0)) 54636396Ssklower $P.tp_cong_win = $$.e_cdt; 54736396Ssklower tp_getoptions($P); 54836396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 54937469Ssklower if ($P.tp_ucddata) { 55036396Ssklower IFDEBUG(D_CONN) 55137469Ssklower printf("dropping user connect data cc 0x%x\n", 55237469Ssklower $P.tp_ucddata->m_len); 55336396Ssklower ENDDEBUG 55437469Ssklower m_freem($P.tp_ucddata); 55537469Ssklower $P.tp_ucddata = 0; 55636396Ssklower } 55736396Ssklower soisconnected($P.tp_sock); 55836396Ssklower if ($$.e_datalen > 0) { 55936396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */ 56036396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 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 75947281Ssklower ($P.tp_Xrcvnxt == $$.e_seq) 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; 77847281Ssklower $$.e_data->m_flags |= M_EOR; 77937469Ssklower sbinsertoob(&$P.tp_Xrcv, $$.e_data); 78036396Ssklower IFDEBUG(D_XPD) 78136396Ssklower dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv"); 78236396Ssklower ENDDEBUG 78336396Ssklower tp_indicate(T_XDATA, $P, 0); 78436396Ssklower sbwakeup( &$P.tp_Xrcv ); 78536396Ssklower 78636396Ssklower (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 78736396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 78836396Ssklower } 78936396Ssklower; 79036396Ssklower 79136396Ssklower/* TP4 only */ 79236396SsklowerSAME <== TP_OPEN T_USR_Xrcvd 79336396Ssklower DEFAULT 79436396Ssklower { 79536396Ssklower if( $P.tp_Xrcv.sb_cc == 0 ) { 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 ) { 83336396Ssklower /* might as well kick 'em again */ 83436396Ssklower tp_indicate(T_XDATA, $P, 0); 83536396Ssklower IncStat(ts_xpd_dup); 83636396Ssklower } 83736396Ssklower m_freem($$.e_data); 83836396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 83936396Ssklower /* don't send an xack because the xak gives "last one received", not 84036396Ssklower * "next one i expect" (dumb) 84136396Ssklower */ 84236396Ssklower } 84336396Ssklower; 84436396Ssklower 84536396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries 84636396Ssklower * to detach all its "children" 84736396Ssklower * Also (CRSENT) when user kills a job that's doing a connect() 84836396Ssklower */ 84936396SsklowerTP_REFWAIT <== TP_CRSENT T_DETACH 85036396Ssklower ($P.tp_class == TP_CLASS_0) 85136396Ssklower { 85236396Ssklower struct socket *so = $P.tp_sock; 85336396Ssklower 85436396Ssklower /* detach from parent socket so it can finish closing */ 85536396Ssklower if (so->so_head) { 85636396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 85736396Ssklower panic("tp: T_DETACH"); 85836396Ssklower so->so_head = 0; 85936396Ssklower } 86036396Ssklower tp_soisdisconnecting($P.tp_sock); 86136396Ssklower tp_netcmd( $P, CONN_CLOSE); 86236396Ssklower tp_soisdisconnected($P); 86336396Ssklower } 86436396Ssklower; 86536396Ssklower 86636396Ssklower/* TP4 only */ 86738841SsklowerTP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH 86836396Ssklower DEFAULT 86936396Ssklower { 87036396Ssklower struct socket *so = $P.tp_sock; 87137469Ssklower struct mbuf *data = MNULL; 87236396Ssklower 87336396Ssklower /* detach from parent socket so it can finish closing */ 87436396Ssklower if (so->so_head) { 87536396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 87636396Ssklower panic("tp: T_DETACH"); 87736396Ssklower so->so_head = 0; 87836396Ssklower } 87936396Ssklower if ($P.tp_state != TP_CLOSING) { 88036396Ssklower tp_soisdisconnecting($P.tp_sock); 88137469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 88237469Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data); 88336396Ssklower $P.tp_retrans = $P.tp_Nretrans; 88436396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 88536396Ssklower } 88636396Ssklower } 88736396Ssklower; 88836396Ssklower 88936396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req 89036396Ssklower ( $P.tp_class == TP_CLASS_0 ) 89136396Ssklower { 89236396Ssklower tp_soisdisconnecting($P.tp_sock); 89336396Ssklower tp_netcmd( $P, CONN_CLOSE); 89436396Ssklower tp_soisdisconnected($P); 89536396Ssklower } 89636396Ssklower; 89736396Ssklower 89836396Ssklower/* TP4 only */ 89938841SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req 90036396Ssklower DEFAULT 90136396Ssklower { 90237469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 90336396Ssklower 90436396Ssklower if($P.tp_state == TP_OPEN) { 90536396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 90636396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 90736396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 90836396Ssklower } 90937469Ssklower if (data) { 91036396Ssklower IFDEBUG(D_CONN) 91137469Ssklower printf("T_DISC_req.trans tp_ucddata 0x%x\n", 91237469Ssklower $P.tp_ucddata); 91337469Ssklower dump_mbuf(data, "ucddata @ T_DISC_req"); 91436396Ssklower ENDDEBUG 91536396Ssklower } 91636396Ssklower tp_soisdisconnecting($P.tp_sock); 91736396Ssklower $P.tp_retrans = $P.tp_Nretrans; 91836396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 91936396Ssklower 92036396Ssklower if( trick_hc ) 92136396Ssklower return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data); 92236396Ssklower } 92336396Ssklower; 92436396Ssklower 92536396Ssklower/* TP4 only */ 92636396SsklowerSAME <== TP_AKWAIT TM_retrans 92736396Ssklower ( $P.tp_retrans > 0 ) 92836396Ssklower { 92936396Ssklower int error; 93037469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 93136396Ssklower 93236396Ssklower IncStat(ts_retrans_cc); 93336396Ssklower $P.tp_retrans --; 93439921Ssklower $P.tp_cong_win = 1; 93539921Ssklower $P.tp_ackrcvd = 0; 93639921Ssklower 93737469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) 93836396Ssklower $P.tp_sock->so_error = error; 93936396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); 94036396Ssklower } 94136396Ssklower; 94236396Ssklower 94336396Ssklower/* TP4 only */ 94436396SsklowerTP_CLOSING <== TP_AKWAIT TM_retrans 94536396Ssklower DEFAULT /* out of time */ 94636396Ssklower { 94736396Ssklower IncStat(ts_conn_gaveup); 94836396Ssklower tp_soisdisconnecting($P.tp_sock); 94936396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 95036396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 95136396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL); 95236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 95336396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 95436396Ssklower } 95536396Ssklower; 95636396Ssklower 95736396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does, 95836396Ssklower * if transmissions are going on. 95936396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack 96036396Ssklower * turnaround) 96136396Ssklower */ 96236396Ssklower/* TP4 only */ 96336396SsklowerTP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ] 96436396Ssklower DEFAULT 96536396Ssklower { 96636396Ssklower tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ 96736396Ssklower tp_cuntimeout($P.tp_refp, TM_inact); 96836396Ssklower tp_cuntimeout($P.tp_refp, TM_sendack); 96936396Ssklower 97036396Ssklower IncStat(ts_conn_gaveup); 97136396Ssklower tp_soisdisconnecting($P.tp_sock); 97236396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 97336396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 97436396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL); 97536396Ssklower $P.tp_retrans = $P.tp_Nretrans; 97636396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 97736396Ssklower } 97836396Ssklower; 97936396Ssklower 98036396Ssklower/* TP4 only */ 98136396SsklowerSAME <== TP_OPEN TM_retrans 98236396Ssklower ( $P.tp_retrans > 0 ) 98336396Ssklower { 98439921Ssklower $P.tp_cong_win = 1; 98539921Ssklower $P.tp_ackrcvd = 0; 98636396Ssklower /* resume XPD */ 98736396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 98837469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 98936396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 99036396Ssklower * that doesn't matter 99136396Ssklower */ 99236396Ssklower 99336396Ssklower IFTRACE(D_XPD) 99436396Ssklower tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna", 99536396Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, 99636396Ssklower $P.tp_snduna); 99736396Ssklower ENDTRACE 99836396Ssklower IFDEBUG(D_XPD) 99936396Ssklower dump_mbuf(m, "XPD retrans emitting M"); 100036396Ssklower ENDDEBUG 100136396Ssklower IncStat(ts_retrans_xpd); 100236396Ssklower $P.tp_retrans --; 100336396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 100436396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 100536396Ssklower } 100636396Ssklower } 100736396Ssklower; 100836396Ssklower 100936396Ssklower/* TP4 only */ 101036396SsklowerSAME <== TP_OPEN TM_data_retrans 101136396Ssklower ( $$.e_retrans > 0 ) 101236396Ssklower { 101336396Ssklower register SeqNum low, lowsave = 0; 101436396Ssklower register struct tp_rtc *r = $P.tp_snduna_rtc; 101536396Ssklower register struct mbuf *m; 101636396Ssklower register SeqNum high = $$.e_high; 101736396Ssklower 101839921Ssklower low = $P.tp_snduna; 101939921Ssklower lowsave = high = low; 102039921Ssklower 102139921Ssklower tp_euntimeout_lss($P.tp_refp, TM_data_retrans, 102239921Ssklower SEQ_ADD($P, $P.tp_sndhiwat, 1)); 102339921Ssklower $P.tp_retrans_hiwat = $P.tp_sndhiwat; 102439921Ssklower 102536396Ssklower if (($P.tp_rx_strat & TPRX_EACH) == 0) 102636396Ssklower high = (high>low)?low:high; 102736396Ssklower 102836396Ssklower if( $P.tp_rx_strat & TPRX_USE_CW ) { 102936396Ssklower register int i; 103036396Ssklower 103136396Ssklower $P.tp_cong_win = 1; 103239921Ssklower $P.tp_ackrcvd = 0; 103339921Ssklower i = SEQ_ADD($P, low, $P.tp_cong_win); 103436396Ssklower 103539921Ssklower high = SEQ_MIN($P, high, $P.tp_sndhiwat); 103639921Ssklower 103736396Ssklower } 103836396Ssklower 103936396Ssklower while( SEQ_LEQ($P, low, high) ){ 104036396Ssklower if ( r == (struct tp_rtc *)0 ){ 104136396Ssklower IFDEBUG(D_RTC) 104236396Ssklower printf( "tp: retrans rtc list is GONE!\n"); 104336396Ssklower ENDDEBUG 104436396Ssklower break; 104536396Ssklower } 104636396Ssklower if ( r->tprt_seq == low ){ 104736396Ssklower if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL) 104836396Ssklower break; 104936396Ssklower (void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m); 105036396Ssklower IncStat(ts_retrans_dt); 105136396Ssklower SEQ_INC($P, low ); 105236396Ssklower } 105336396Ssklower r = r->tprt_next; 105436396Ssklower } 105539921Ssklower/* CE_BIT 105636396Ssklower if ( SEQ_LEQ($P, lowsave, high) ){ 105739921Ssklower*/ 105836396Ssklower $$.e_retrans --; 105936396Ssklower tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave, 106036396Ssklower (caddr_t)high, $$.e_retrans, 106136396Ssklower ($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks); 106239921Ssklower/* CE_BIT 106336396Ssklower } 106439921Ssklower*/ 106536396Ssklower } 106636396Ssklower; 106736396Ssklower 106836396Ssklower/* TP4 only */ 106936396SsklowerSAME <== TP_CLOSING TM_retrans 107036396Ssklower ( $P.tp_retrans > 0 ) 107136396Ssklower { 107236396Ssklower $P.tp_retrans --; 107336396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL); 107436396Ssklower IncStat(ts_retrans_dr); 107536396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); 107636396Ssklower } 107736396Ssklower; 107836396Ssklower 107936396Ssklower/* TP4 only */ 108036396SsklowerTP_REFWAIT <== TP_CLOSING TM_retrans 108136396Ssklower DEFAULT /* no more retrans - gave up */ 108236396Ssklower { 108336396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 108436396Ssklower $P.tp_refp->tpr_state = REF_FROZEN; 108536396Ssklower tp_recycle_tsuffix( $P ); 108636396Ssklower tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks); 108736396Ssklower } 108836396Ssklower; 108936396Ssklower 109036396Ssklower/* 109136396Ssklower * The resources are kept around until the ref timer goes off. 109236396Ssklower * The suffices are wiped out sooner so they can be reused right away. 109336396Ssklower */ 109436396Ssklower/* applicable in TP4, TP0 */ 109536396SsklowerTP_CLOSED <== TP_REFWAIT TM_reference 109636396Ssklower DEFAULT 109736396Ssklower { 109836396Ssklower tp_freeref($P.tp_refp); 109936396Ssklower tp_detach($P); 110036396Ssklower } 110136396Ssklower; 110236396Ssklower 110336396Ssklower/* applicable in TP4, TP0 */ 110436396Ssklower/* A duplicate CR from connectionless network layer can't happen */ 110536396SsklowerSAME <== TP_OPEN [ CR_TPDU, CC_TPDU ] 110636396Ssklower DEFAULT 110736396Ssklower { 110836396Ssklower if( $P.tp_class != TP_CLASS_0) { 110936396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 111036396Ssklower if ( $E.ev_number == CC_TPDU ) 111136396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 111236396Ssklower } 111336396Ssklower /* ignore it if class 0 - state tables are blank for this */ 111436396Ssklower } 111536396Ssklower; 111636396Ssklower 111736396Ssklower/* applicable in TP4, TP0 */ 111836396SsklowerSAME <== TP_OPEN T_DATA_req 111936396Ssklower DEFAULT 112036396Ssklower { 112136396Ssklower IFTRACE(D_DATA) 112236396Ssklower tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb", 112336396Ssklower $P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P); 112436396Ssklower ENDTRACE 112536396Ssklower 112636396Ssklower tp_send($P); 112736396Ssklower } 112836396Ssklower; 112936396Ssklower 113036396Ssklower/* TP4 only */ 113136396SsklowerSAME <== TP_OPEN T_XPD_req 113236396Ssklower DEFAULT 113336396Ssklower /* T_XPD_req was issued by sosend iff xpd socket buf was empty 113436396Ssklower * at time of sosend(), 113536396Ssklower * AND (which means) there were no unacknowledged XPD tpdus outstanding! 113636396Ssklower */ 113736396Ssklower { 113836396Ssklower int error = 0; 113936396Ssklower 114036396Ssklower /* resume XPD */ 114136396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 114237469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 114336396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 114436396Ssklower * that doesn't matter 114536396Ssklower */ 114636396Ssklower 114736396Ssklower IFTRACE(D_XPD) 114836396Ssklower tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna", 114936396Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, 115036396Ssklower $P.tp_snduna); 115136396Ssklower ENDTRACE 115236396Ssklower IFDEBUG(D_XPD) 115336396Ssklower printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc); 115436396Ssklower dump_mbuf(m, "XPD req emitting M"); 115536396Ssklower ENDDEBUG 115636396Ssklower error = 115736396Ssklower tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 115836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 115936396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 116036396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 116136396Ssklower } 116236396Ssklower if(trick_hc) 116336396Ssklower return error; 116436396Ssklower } 116536396Ssklower; 116636396Ssklower 116736396Ssklower/* TP4, faked ack in TP0 when cons send completes */ 116836396SsklowerSAME <== TP_OPEN AK_TPDU 116936396Ssklower ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) ) 117036396Ssklower 117136396Ssklower /* tp_goodack == true means 117236396Ssklower * EITHER it actually acked something heretofore unacknowledged 117336396Ssklower * OR no news but the credit should be processed. 117436396Ssklower */ 117536396Ssklower { 117636396Ssklower IFDEBUG(D_ACKRECV) 117736396Ssklower printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt); 117836396Ssklower ENDDEBUG 117936396Ssklower if( $P.tp_class != TP_CLASS_0) { 118036396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 118136396Ssklower tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq); 118236396Ssklower } 118336396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 118436396Ssklower 118539921Ssklower if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat && 118639921Ssklower $P.tp_snduna <= $P.tp_retrans_hiwat) { 118739921Ssklower 118839921Ssklower register struct mbuf *m; 118939921Ssklower /* extern struct mbuf *m_copy(); */ 119039921Ssklower register struct tp_rtc *r; 119139921Ssklower SeqNum high, retrans, low_save; 119239921Ssklower 119339921Ssklower high = SEQ_MIN($P, SEQ_ADD($P, $P.tp_snduna, 119439921Ssklower MIN($P.tp_cong_win, $P.tp_fcredit)) - 1, 119539921Ssklower $P.tp_sndhiwat); 119639921Ssklower low_save = retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1), 119739921Ssklower $P.tp_snduna); 119839921Ssklower for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) { 119939921Ssklower 120039921Ssklower for (r = $P.tp_snduna_rtc; r; r = r->tprt_next){ 120139921Ssklower if ( r->tprt_seq == retrans ){ 120239921Ssklower if(( m = m_copy(r->tprt_data, 0, r->tprt_octets )) 120339921Ssklower == MNULL) 120439921Ssklower break; 120539921Ssklower (void) tp_emit(DT_TPDU_type, $P, retrans, 120639921Ssklower r->tprt_eot, m); 120739921Ssklower $P.tp_last_retrans = retrans; 120839921Ssklower IncStat(ts_retrans_dt); 120939921Ssklower break; 121039921Ssklower } 121139921Ssklower } 121239921Ssklower if ( r == (struct tp_rtc *)0 ){ 121339921Ssklower IFDEBUG(D_RTC) 121439921Ssklower printf( "tp: retrans rtc list is GONE!\n"); 121539921Ssklower ENDDEBUG 121639921Ssklower break; 121739921Ssklower } 121839921Ssklower } 121939921Ssklower tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)low_save, 122039921Ssklower (caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks); 122139921Ssklower if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat) 122239921Ssklower tp_send($P); 122339921Ssklower } 122439921Ssklower else { 122539921Ssklower tp_send($P); 122639921Ssklower } 122736396Ssklower IFDEBUG(D_ACKRECV) 122836396Ssklower printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat); 122936396Ssklower ENDDEBUG 123036396Ssklower } 123136396Ssklower; 123236396Ssklower 123336396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 123436396SsklowerSAME <== TP_OPEN AK_TPDU 123536396Ssklower DEFAULT 123636396Ssklower { 123736396Ssklower IFTRACE(D_ACKRECV) 123836396Ssklower tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", 123936396Ssklower $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0); 124036396Ssklower ENDTRACE 124136396Ssklower if( $P.tp_class != TP_CLASS_0 ) { 124236396Ssklower 124336396Ssklower if ( !$$.e_fcc_present ) { 124436396Ssklower /* send ACK with FCC */ 124536396Ssklower IncStat( ts_ackreason[_ACK_FCC_] ); 124636396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL); 124736396Ssklower } 124836396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 124936396Ssklower } 125036396Ssklower } 125136396Ssklower; 125236396Ssklower 125336396Ssklower/* NBS(47) */ 125436396Ssklower /* goes in at *** */ 125536396Ssklower /* just so happens that this is never true now, because we allow 125636396Ssklower * only 1 packet in the queue at once (this could be changed) 125736396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 125836396Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??); 125936396Ssklower 126036396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 126136396Ssklower $P.tp_retrans = $P.tp_Nretrans; 126236396Ssklower tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); 126336396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 126436396Ssklower } 126536396Ssklower */ 126636396Ssklower /* end of the above hack */ 126736396Ssklower 126836396Ssklower/* TP4 only */ 126942944SsklowerSAME <== TP_OPEN XAK_TPDU 127036396Ssklower ( tp_goodXack($P, $$.e_seq) ) 127136396Ssklower /* tp_goodXack checks for good ack, removes the correct 127236396Ssklower * tpdu from the queue and returns 1 if ack was legit, 0 if not. 127336396Ssklower * also updates tp_Xuna 127436396Ssklower */ 127536396Ssklower { 127636396Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 127736396Ssklower tp_cuntimeout($P.tp_refp, TM_retrans); 127836396Ssklower 127936396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 128036396Ssklower 128136396Ssklower /* resume normal data */ 128236396Ssklower tp_send($P); 128336396Ssklower } 128436396Ssklower; 128536396Ssklower 128642944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 128742944SsklowerSAME <== TP_OPEN XAK_TPDU 128842944Ssklower DEFAULT 128942944Ssklower { 129042944Ssklower IFTRACE(D_ACKRECV) 129142944Ssklower tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0); 129242944Ssklower ENDTRACE 129342944Ssklower if( $P.tp_class != TP_CLASS_0 ) { 129442944Ssklower tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); 129542944Ssklower } 129642944Ssklower } 129742944Ssklower; 129842944Ssklower 129936396Ssklower/* TP4 only */ 130036396SsklowerSAME <== TP_OPEN TM_sendack 130136396Ssklower DEFAULT 130236396Ssklower { 130336396Ssklower IFTRACE(D_TIMER) 130436396Ssklower tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 130536396Ssklower $P.tp_sent_lcdt, 0); 130636396Ssklower ENDTRACE 130736396Ssklower IncPStat($P, tps_n_TMsendack); 130836396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 130936396Ssklower } 131036396Ssklower; 131136396Ssklower 131236396Ssklower/* TP0 only */ 131336396SsklowerSAME <== TP_OPEN T_USR_rcvd 131436396Ssklower ($P.tp_class == TP_CLASS_0) 131547281Ssklower { 131647281Ssklower if (sbspace(&$P.tp_sock->so_rcv) > 0) 131747281Ssklower tp0_openflow($P); 131847281Ssklower } 131936396Ssklower; 132036396Ssklower 132136396Ssklower/* TP4 only */ 132236396Ssklower /* If old credit was zero, 132336396Ssklower * we'd better inform other side that we now have space 132436396Ssklower * But this is not enough. Sender might not yet have 132536396Ssklower * seen an ack with cdt 0 but it might still think the 132636396Ssklower * window is closed, so it's going to wait. 132736396Ssklower * Best to send an ack each time. 132836396Ssklower * Strictly speaking, this ought to be a function of the 132936396Ssklower * general ack strategy. 133036396Ssklower */ 133136396SsklowerSAME <== TP_OPEN T_USR_rcvd 133236396Ssklower DEFAULT 133336396Ssklower { 133436396Ssklower if( trick_hc ) { 133539921Ssklower 1336*50849Ssklower LOCAL_CREDIT($P); 1337*50849Ssklower /* 1338*50849Ssklower * If the window has is now closed or has only 1339*50849Ssklower * one slot left and an ACK will increase this (local 1340*50849Ssklower * credit is greater than or equal to 1) send an AK 1341*50849Ssklower * here. Otherwise, we will wait for more data or 1342*50849Ssklower * the ack timer to fire. 1343*50849Ssklower */ 1344*50849Ssklower#define CREDIT_SMALL 1 1345*50849Ssklower if (SEQ_GEQ($P, $P.tp_rcvnxt, $P.tp_sent_uwe) && 1346*50849Ssklower $P.tp_lcredit > CREDIT_SMALL) { 1347*50849Ssklower IncStat(ts_ackreason[_ACK_USRRCV_]); 134839921Ssklower return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 1349*50849Ssklower } 135036396Ssklower } 135136396Ssklower } 135236396Ssklower; 135336396Ssklower 135436396Ssklower/* applicable in TP4, TP0 */ 135536396SsklowerSAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ] 135636396Ssklower DEFAULT 135736396Ssklower /* This happens if other end sent a DR when the user was waiting 135836396Ssklower * on a receive. 135936396Ssklower * Processing the DR includes putting us in REFWAIT state. 136036396Ssklower */ 136136396Ssklower { 136236396Ssklower if(trick_hc) 136336396Ssklower return ECONNABORTED; 136436396Ssklower } 136536396Ssklower; 136636396Ssklower 136736396Ssklower/* TP0 only */ 136836396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET 136936396Ssklower ( $P.tp_class != TP_CLASS_4 ) 137036396Ssklower /* 0 or (4 and 0) */ 137136396Ssklower /* in OPEN class will be 0 or 4 but not both */ 137236396Ssklower /* in CRSENT or LISTENING it could be in negotiation, hence both */ 137336396Ssklower /* Actually, this shouldn't ever happen in LISTENING */ 137436396Ssklower { 137536396Ssklower ASSERT( $P.tp_state != TP_LISTENING ); 137636396Ssklower tp_indicate(T_DISCONNECT, $P, ECONNRESET); 137736396Ssklower tp_soisdisconnected($P); 137836396Ssklower } 137936396Ssklower; 138036396Ssklower 138136396Ssklower/* TP4: ignore resets */ 138236396SsklowerSAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT, 138336396Ssklower TP_CLOSING, TP_LISTENING ] T_NETRESET 138436396Ssklower DEFAULT 138536396Ssklower NULLACTION 138636396Ssklower; 138736396Ssklower 138836396Ssklower/* applicable in TP4, TP0 */ 138936396SsklowerSAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET 139036396Ssklower DEFAULT 139136396Ssklower NULLACTION 139236396Ssklower; 139336396Ssklower 139436396Ssklower/* C'EST TOUT */ 1395