150849Ssklower/* NEW */ 249268Sbostic/*- 349268Sbostic * Copyright (c) 1991 The Regents of the University of California. 449268Sbostic * All rights reserved. 549268Sbostic * 649268Sbostic * %sccs.include.redist.c% 749268Sbostic * 8*51208Ssklower * @(#)tp.trans 7.15 (Berkeley) 09/30/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*51208Ssklower/* @(#)tp.trans 7.15 (Berkeley) 09/30/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(), 9451204Ssklower 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 13551204Ssklower /* TM_sendack does dual duty - keepalive AND closed-window 13651204Ssklower * Probes. 13736396Ssklower * It's set w/ keepalive-ticks every time an ack is sent. 13836396Ssklower * (this is done in (void) tp_emit() ). 13951204Ssklower * Whenever a DT arrives which doesn't require immediate acking, 14051204Ssklower * a separate fast-timeout flag is set ensuring 200ms response. 14136396Ssklower */ 14236396Ssklower TM_notused 14336396Ssklower 14436396Ssklower /* 14536396Ssklower * E (typically expired) timers - these may be in any order. 14636396Ssklower * These cause procedures to be executed directly; may not 14736396Ssklower * cause an 'event' as we know them here. 14836396Ssklower */ 14936396Ssklower TM_reference { SeqNum e_low; SeqNum e_high; int e_retrans; } 15036396Ssklower TM_data_retrans { SeqNum e_low; SeqNum e_high; int e_retrans; } 15136396Ssklower 15236396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that 15336396Ssklower * for all tpdu types that can take e_data and e_datalen, these 15436396Ssklower * fields fall in the same place in the event structure, that is, 15536396Ssklower * e_data is the first field and e_datalen is the 2nd field. 15636396Ssklower */ 15736396Ssklower 15836396Ssklower ER_TPDU { 15936396Ssklower u_char e_reason; 16036396Ssklower } 16136396Ssklower CR_TPDU { struct mbuf *e_data; /* first field */ 16236396Ssklower int e_datalen; /* 2nd field */ 16336396Ssklower u_int e_cdt; 16436396Ssklower } 16536396Ssklower DR_TPDU { struct mbuf *e_data; /* first field */ 16636396Ssklower int e_datalen; /* 2nd field */ 16736396Ssklower u_short e_sref; 16836396Ssklower u_char e_reason; 16936396Ssklower } 17036396Ssklower DC_TPDU 17136396Ssklower CC_TPDU { struct mbuf *e_data; /* first field */ 17236396Ssklower int e_datalen; /* 2nd field */ 17336396Ssklower u_short e_sref; 17436396Ssklower u_int e_cdt; 17536396Ssklower } 17636396Ssklower AK_TPDU { u_int e_cdt; 17736396Ssklower SeqNum e_seq; 17836396Ssklower SeqNum e_subseq; 17936396Ssklower u_char e_fcc_present; 18036396Ssklower } 18136396Ssklower DT_TPDU { struct mbuf *e_data; /* first field */ 18236396Ssklower int e_datalen; /* 2nd field */ 18336396Ssklower u_int e_eot; 18436396Ssklower SeqNum e_seq; 18536396Ssklower } 18636396Ssklower XPD_TPDU { struct mbuf *e_data; /* first field */ 18736396Ssklower int e_datalen; /* 2nd field */ 18836396Ssklower SeqNum e_seq; 18936396Ssklower } 19036396Ssklower XAK_TPDU { SeqNum e_seq; } 19136396Ssklower 19236396Ssklower T_CONN_req 19336396Ssklower T_DISC_req { u_char e_reason; } 19436396Ssklower T_LISTEN_req 19536396Ssklower T_DATA_req 19636396Ssklower T_XPD_req 19736396Ssklower T_USR_rcvd 19836396Ssklower T_USR_Xrcvd 19936396Ssklower T_DETACH 20036396Ssklower T_NETRESET 20138841Ssklower T_ACPT_req 20236396Ssklower 20336396Ssklower 20436396Ssklower*TRANSITIONS 20536396Ssklower 20636396Ssklower 20736396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */ 20836396SsklowerSAME <== TP_AKWAIT [ CC_TPDU, DC_TPDU, XAK_TPDU ] 20936396Ssklower DEFAULT 21036396Ssklower NULLACTION 21136396Ssklower; 21236396Ssklower 21336396Ssklower 21436396Ssklower/* applicable in TP4, TP0 */ 21536396SsklowerSAME <== TP_REFWAIT DR_TPDU 21636396Ssklower ( $$.e_sref != 0 ) 21736396Ssklower { 21836396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 21936396Ssklower } 22036396Ssklower; 22136396Ssklower 22236396Ssklower/* applicable in TP4, TP0 */ 22336396SsklowerSAME <== TP_REFWAIT [ CR_TPDU, CC_TPDU, DT_TPDU, 22436396Ssklower DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ] 22536396Ssklower DEFAULT 22636396Ssklower { 22736396Ssklower# ifdef TP_DEBUG 22836396Ssklower if( $E.ev_number != AK_TPDU ) 22936396Ssklower printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number); 23036396Ssklower# endif TP_DEBUG 23136396Ssklower } 23236396Ssklower; 23336396Ssklower 23436396Ssklower/* applicable in TP4, TP0 */ 23536396SsklowerSAME <== TP_REFWAIT [ T_DETACH, T_DISC_req ] 23636396Ssklower DEFAULT 23736396Ssklower NULLACTION 23836396Ssklower; 23936396Ssklower 24036396Ssklower/* applicable in TP4, TP0 */ 24136396SsklowerSAME <== TP_CRSENT AK_TPDU 24236396Ssklower ($P.tp_class == TP_CLASS_0) 24336396Ssklower { 24436396Ssklower /* oh, man is this grotesque or what? */ 24536396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 24636396Ssklower /* but it's necessary because this pseudo-ack may happen 24736396Ssklower * before the CC arrives, but we HAVE to adjust the 24836396Ssklower * snduna as a result of the ack, WHENEVER it arrives 24936396Ssklower */ 25036396Ssklower } 25136396Ssklower; 25236396Ssklower 25336396Ssklower/* applicable in TP4, TP0 */ 25436396SsklowerSAME <== TP_CRSENT 25536396Ssklower [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU, XAK_TPDU ] 25636396Ssklower DEFAULT 25736396Ssklower NULLACTION 25836396Ssklower; 25936396Ssklower 26036396Ssklower/* applicable in TP4, TP0 */ 26136396SsklowerSAME <== TP_CLOSED [ DT_TPDU, XPD_TPDU, 26236396Ssklower ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 26336396Ssklower DEFAULT 26436396Ssklower NULLACTION 26536396Ssklower; 26636396Ssklower 26736396Ssklower/* TP_CLOSING doesn't exist in TP 0 */ 26836396SsklowerSAME <== TP_CLOSING 26936396Ssklower [ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ] 27036396Ssklower DEFAULT 27136396Ssklower NULLACTION 27236396Ssklower; 27336396Ssklower 27436396Ssklower 27536396Ssklower/* DC_TPDU doesn't exist in TP 0 */ 27636396SsklowerSAME <== TP_OPEN DC_TPDU 27736396Ssklower DEFAULT 27836396Ssklower NULLACTION 27936396Ssklower; 28036396Ssklower 28136396Ssklower/* applicable in TP4, TP0 */ 28236396SsklowerSAME <== TP_LISTENING [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU, 28336396Ssklower ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 28436396Ssklower DEFAULT 28536396Ssklower NULLACTION 28636396Ssklower; 28736396Ssklower 28836396Ssklower/* applicable in TP4, TP0 */ 28936396SsklowerTP_LISTENING <== TP_CLOSED T_LISTEN_req 29036396Ssklower DEFAULT 29136396Ssklower NULLACTION 29236396Ssklower; 29336396Ssklower 29436396Ssklower/* applicable in TP4, TP0 */ 29536396SsklowerTP_CLOSED <== [ TP_LISTENING, TP_CLOSED ] T_DETACH 29636396Ssklower DEFAULT 29736396Ssklower { 29836396Ssklower tp_detach($P); 29936396Ssklower } 30036396Ssklower; 30136396Ssklower 30238841SsklowerTP_CONFIRMING <== TP_LISTENING CR_TPDU 30338841Ssklower ( $P.tp_class == TP_CLASS_0) 30436396Ssklower { 30551204Ssklower $P.tp_refstate = REF_OPEN; /* has timers ??? */ 30636396Ssklower } 30736396Ssklower; 30836396Ssklower 30938841SsklowerTP_CONFIRMING <== TP_LISTENING CR_TPDU 31038841Ssklower DEFAULT 31136396Ssklower { 31236396Ssklower IFTRACE(D_CONN) 31336396Ssklower tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0); 31436396Ssklower ENDTRACE 31536396Ssklower IFDEBUG(D_CONN) 31636396Ssklower printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data); 31736396Ssklower ENDDEBUG 31851204Ssklower $P.tp_refstate = REF_OPEN; /* has timers */ 31938841Ssklower $P.tp_fcredit = $$.e_cdt; 32036396Ssklower 32136396Ssklower if ($$.e_datalen > 0) { 32236396Ssklower /* n/a for class 0 */ 32336396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); 32436396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 32536396Ssklower $$.e_data = MNULL; 32636396Ssklower } 32738841Ssklower } 32838841Ssklower; 32938841Ssklower 33038841SsklowerTP_OPEN <== TP_CONFIRMING T_ACPT_req 33138841Ssklower ( $P.tp_class == TP_CLASS_0 ) 33238841Ssklower { 33338841Ssklower IncStat(ts_tp0_conn); 33438841Ssklower IFTRACE(D_CONN) 33538841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 33638841Ssklower ENDTRACE 33738841Ssklower IFDEBUG(D_CONN) 33838841Ssklower printf("Confirming connection: $P" ); 33938841Ssklower ENDDEBUG 34038841Ssklower soisconnected($P.tp_sock); 34138841Ssklower (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ; 34238841Ssklower $P.tp_fcredit = 1; 34338841Ssklower } 34438841Ssklower; 34538841Ssklower 34638841SsklowerTP_AKWAIT <== TP_CONFIRMING T_ACPT_req 34738841Ssklower (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0) 34838841Ssklower { 34938841Ssklower IncStat(ts_tp4_conn); /* even though not quite open */ 35038841Ssklower IFTRACE(D_CONN) 35138841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 35238841Ssklower ENDTRACE 35338841Ssklower IFDEBUG(D_CONN) 35438841Ssklower printf("Confirming connection: $P" ); 35538841Ssklower ENDDEBUG 35650973Ssklower tp_getoptions($P); 35738841Ssklower soisconnecting($P.tp_sock); 35847281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0)) 35951204Ssklower $P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize; 36036396Ssklower $P.tp_retrans = $P.tp_Nretrans; 36151204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 36238841Ssklower } 36336396Ssklower; 36436396Ssklower 36536396Ssklower/* TP4 only */ 36638841SsklowerTP_CLOSED <== TP_CONFIRMING T_ACPT_req 36736396Ssklower DEFAULT /* emit failed */ 36836396Ssklower { 36936396Ssklower register struct tp_ref *r = $P.tp_refp; 37036396Ssklower 37136396Ssklower IFDEBUG(D_CONN) 37236396Ssklower printf("event: CR_TPDU emit CC failed done " ); 37336396Ssklower ENDDEBUG 37438841Ssklower soisdisconnected($P.tp_sock); 37536396Ssklower tp_recycle_tsuffix( $P ); 37636396Ssklower tp_freeref(r); 37736396Ssklower tp_detach($P); 37836396Ssklower } 37936396Ssklower; 38036396Ssklower 38136396Ssklower/* applicable in TP4, TP0 */ 38236396SsklowerTP_CRSENT <== TP_CLOSED T_CONN_req 38336396Ssklower DEFAULT 38436396Ssklower { 38536396Ssklower int error; 38636396Ssklower struct mbuf *data = MNULL; 38736396Ssklower 38836396Ssklower IFTRACE(D_CONN) 38937469Ssklower tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags, 39037469Ssklower $P.tp_ucddata, 0, 0); 39136396Ssklower ENDTRACE 39237469Ssklower data = MCPY($P.tp_ucddata, M_WAIT); 39337469Ssklower if (data) { 39436396Ssklower IFDEBUG(D_CONN) 39536396Ssklower printf("T_CONN_req.trans m_copy cc 0x%x\n", 39637469Ssklower $P.tp_ucddata); 39737469Ssklower dump_mbuf(data, "sosnd @ T_CONN_req"); 39836396Ssklower ENDDEBUG 39936396Ssklower } 40036396Ssklower 40136396Ssklower if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) 40236396Ssklower return error; /* driver WON'T change state; will return error */ 40336396Ssklower 40451204Ssklower $P.tp_refstate = REF_OPEN; /* has timers */ 40536396Ssklower if($P.tp_class != TP_CLASS_0) { 40636396Ssklower $P.tp_retrans = $P.tp_Nretrans; 40751204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks); 40836396Ssklower } 40936396Ssklower } 41036396Ssklower; 41136396Ssklower 41236396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */ 41336396SsklowerTP_REFWAIT <== [ TP_CRSENT, TP_AKWAIT, TP_OPEN ] DR_TPDU 41436396Ssklower DEFAULT 41536396Ssklower { 41648739Ssklower sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */ 41748739Ssklower if ($$.e_datalen > 0) { 41836396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 41936396Ssklower $$.e_data = MNULL; 42036396Ssklower } 421*51208Ssklower if ($P.tp_state == TP_OPEN) 422*51208Ssklower tp_indicate(T_DISCONNECT, $P, 0); 423*51208Ssklower else { 424*51208Ssklower int so_error = ECONNREFUSED; 425*51208Ssklower if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) && 426*51208Ssklower $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) && 427*51208Ssklower $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK)) 428*51208Ssklower so_error = ECONNABORTED; 429*51208Ssklower tp_indicate(T_DISCONNECT, $P, so_error); 430*51208Ssklower } 43136396Ssklower tp_soisdisconnected($P); 43236396Ssklower if ($P.tp_class != TP_CLASS_0) { 43336396Ssklower if ($P.tp_state == TP_OPEN ) { 43451204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 43551204Ssklower tp_cuntimeout($P, TM_retrans); 43651204Ssklower tp_cuntimeout($P, TM_inact); 43751204Ssklower tp_cuntimeout($P, TM_sendack); 43836396Ssklower } 43951204Ssklower tp_cuntimeout($P, TM_retrans); 44036396Ssklower if( $$.e_sref != 0 ) 44136396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 44236396Ssklower } 44336396Ssklower } 44436396Ssklower; 44536396Ssklower 44636396SsklowerSAME <== TP_CLOSED DR_TPDU 44736396Ssklower DEFAULT 44836396Ssklower { 44936396Ssklower if( $$.e_sref != 0 ) 45036396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 45136396Ssklower /* reference timer already set - reset it to be safe (???) */ 45251204Ssklower tp_euntimeout($P, TM_reference); /* all */ 45351204Ssklower tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks); 45436396Ssklower } 45536396Ssklower; 45636396Ssklower 45736396Ssklower/* NBS(34) */ 45836396SsklowerTP_REFWAIT <== TP_CRSENT ER_TPDU 45936396Ssklower DEFAULT 46036396Ssklower { 46151204Ssklower tp_cuntimeout($P, TM_retrans); 46248739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 46336396Ssklower tp_soisdisconnected($P); 46436396Ssklower } 46536396Ssklower; 46636396Ssklower 46736396Ssklower/* NBS(27) */ 46836396SsklowerTP_REFWAIT <== TP_CLOSING DR_TPDU 46936396Ssklower DEFAULT 47036396Ssklower { 47151204Ssklower tp_cuntimeout($P, TM_retrans); 47236396Ssklower tp_soisdisconnected($P); 47336396Ssklower } 47436396Ssklower; 47536396Ssklower/* these two transitions are the same but can't be combined because xebec 47636396Ssklower * can't handle the use of $$.e_reason if they're combined 47736396Ssklower */ 47836396Ssklower/* NBS(27) */ 47936396SsklowerTP_REFWAIT <== TP_CLOSING ER_TPDU 48036396Ssklower DEFAULT 48136396Ssklower { 48248739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 48351204Ssklower tp_cuntimeout($P, TM_retrans); 48436396Ssklower tp_soisdisconnected($P); 48536396Ssklower } 48636396Ssklower; 48736396Ssklower/* NBS(27) */ 48836396SsklowerTP_REFWAIT <== TP_CLOSING DC_TPDU 48936396Ssklower DEFAULT 49036396Ssklower { 49151204Ssklower tp_cuntimeout($P, TM_retrans); 49236396Ssklower tp_soisdisconnected($P); 49336396Ssklower } 49436396Ssklower; 49536396Ssklower 49636396Ssklower/* NBS(21) */ 49736396SsklowerSAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ] 49836396Ssklower DEFAULT 49936396Ssklower { /* don't ask me why we have to do this - spec says so */ 50036396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL); 50136396Ssklower /* don't bother with retransmissions of the DR */ 50236396Ssklower } 50336396Ssklower; 50436396Ssklower 50536396Ssklower/* NBS(34) */ 50636396SsklowerTP_REFWAIT <== TP_OPEN ER_TPDU 50736396Ssklower ($P.tp_class == TP_CLASS_0) 50836396Ssklower { 50936396Ssklower tp_soisdisconnecting($P.tp_sock); 51048739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 51136396Ssklower tp_soisdisconnected($P); 51236396Ssklower tp_netcmd( $P, CONN_CLOSE ); 51336396Ssklower } 51436396Ssklower; 51536396Ssklower 51636396SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU 51736396Ssklower DEFAULT 51836396Ssklower { 51936396Ssklower if ($P.tp_state == TP_OPEN) { 52051204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 52151204Ssklower tp_cuntimeout($P, TM_inact); 52251204Ssklower tp_cuntimeout($P, TM_sendack); 52336396Ssklower } 52436396Ssklower tp_soisdisconnecting($P.tp_sock); 52548739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 52636396Ssklower $P.tp_retrans = $P.tp_Nretrans; 52751204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 52836396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL); 52936396Ssklower } 53036396Ssklower; 53136396Ssklower/* NBS(6) */ 53236396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 53336396Ssklower ($P.tp_class == TP_CLASS_0) 53436396Ssklower { 53551204Ssklower tp_cuntimeout($P, TM_retrans); 53636396Ssklower IncStat(ts_tp0_conn); 53736396Ssklower $P.tp_fcredit = 1; 53836396Ssklower soisconnected($P.tp_sock); 53936396Ssklower } 54036396Ssklower; 54136396Ssklower 54236396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 54336396Ssklower DEFAULT 54436396Ssklower { 54536396Ssklower IFDEBUG(D_CONN) 54636396Ssklower printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", 54736396Ssklower (int)$P.tp_flags); 54836396Ssklower ENDDEBUG 54936396Ssklower IncStat(ts_tp4_conn); 55036396Ssklower $P.tp_fref = $$.e_sref; 55136396Ssklower $P.tp_fcredit = $$.e_cdt; 55247281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0)) 55351204Ssklower $P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize; 55436396Ssklower tp_getoptions($P); 55551204Ssklower tp_cuntimeout($P, TM_retrans); 55637469Ssklower if ($P.tp_ucddata) { 55736396Ssklower IFDEBUG(D_CONN) 55837469Ssklower printf("dropping user connect data cc 0x%x\n", 55937469Ssklower $P.tp_ucddata->m_len); 56036396Ssklower ENDDEBUG 56137469Ssklower m_freem($P.tp_ucddata); 56237469Ssklower $P.tp_ucddata = 0; 56336396Ssklower } 56436396Ssklower soisconnected($P.tp_sock); 56536396Ssklower if ($$.e_datalen > 0) { 56636396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */ 56736396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 56836396Ssklower $$.e_data = MNULL; 56936396Ssklower } 57036396Ssklower 57136396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 57251204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 57336396Ssklower } 57436396Ssklower; 57536396Ssklower 57636396Ssklower/* TP4 only */ 57736396SsklowerSAME <== TP_CRSENT TM_retrans 57836396Ssklower ( $P.tp_retrans > 0 ) 57936396Ssklower { 58036396Ssklower struct mbuf *data = MNULL; 58136396Ssklower int error; 58236396Ssklower 58336396Ssklower IncStat(ts_retrans_cr); 58451204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 58537469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 58637469Ssklower if($P.tp_ucddata) { 58736396Ssklower IFDEBUG(D_CONN) 58837469Ssklower printf("TM_retrans.trans m_copy cc 0x%x\n", data); 58937469Ssklower dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans"); 59036396Ssklower ENDDEBUG 59136396Ssklower if( data == MNULL ) 59236396Ssklower return ENOBUFS; 59336396Ssklower } 59436396Ssklower 59536396Ssklower $P.tp_retrans --; 59636396Ssklower if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) { 59736396Ssklower $P.tp_sock->so_error = error; 59836396Ssklower } 59951204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks); 60036396Ssklower } 60136396Ssklower; 60236396Ssklower 60336396Ssklower/* TP4 only */ 60436396SsklowerTP_REFWAIT <== TP_CRSENT TM_retrans 60536396Ssklower DEFAULT /* no more CR retransmissions */ 60636396Ssklower { 60736396Ssklower IncStat(ts_conn_gaveup); 60836396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 60936396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 61036396Ssklower tp_soisdisconnected($P); 61136396Ssklower } 61236396Ssklower; 61336396Ssklower 61436396Ssklower/* TP4 only */ 61536396SsklowerSAME <== TP_AKWAIT CR_TPDU 61636396Ssklower DEFAULT 61736396Ssklower /* duplicate CR (which doesn't really exist in the context of 61836396Ssklower * a connectionless network layer) 61936396Ssklower * Doesn't occur in class 0. 62036396Ssklower */ 62136396Ssklower { 62236396Ssklower int error; 62337469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 62436396Ssklower 62537469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) { 62636396Ssklower $P.tp_sock->so_error = error; 62736396Ssklower } 62836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 62951204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 63036396Ssklower } 63136396Ssklower; 63236396Ssklower 63336396Ssklower/* TP4 only */ 63436396SsklowerTP_OPEN <== TP_AKWAIT DT_TPDU 63536396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 63636396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 63736396Ssklower { 63836396Ssklower int doack; 63936396Ssklower 64037469Ssklower /* 64137469Ssklower * Get rid of any confirm or connect data, so that if we 64237469Ssklower * crash or close, it isn't thought of as disconnect data. 64337469Ssklower */ 64437469Ssklower if ($P.tp_ucddata) { 64537469Ssklower m_freem($P.tp_ucddata); 64637469Ssklower $P.tp_ucddata = 0; 64736396Ssklower } 64851204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 64951204Ssklower tp_cuntimeout($P, TM_retrans); 65036396Ssklower soisconnected($P.tp_sock); 65151204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 65236396Ssklower 65336396Ssklower /* see also next 2 transitions, if you make any changes */ 65436396Ssklower 65536396Ssklower doack = tp_stash($P, $E); 65636396Ssklower IFDEBUG(D_DATA) 65736396Ssklower printf("tp_stash returns %d\n",doack); 65836396Ssklower ENDDEBUG 65936396Ssklower 66051204Ssklower if (doack) { 66136396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 66251204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 66336396Ssklower } else 66451204Ssklower tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks); 66536396Ssklower 66636396Ssklower IFDEBUG(D_DATA) 66736396Ssklower printf("after stash calling sbwakeup\n"); 66836396Ssklower ENDDEBUG 66936396Ssklower } 67036396Ssklower; 67136396Ssklower 67236396SsklowerSAME <== TP_OPEN DT_TPDU 67336396Ssklower ( $P.tp_class == TP_CLASS_0 ) 67436396Ssklower { 67536396Ssklower tp0_stash($P, $E); 67636396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 67736396Ssklower 67836396Ssklower IFDEBUG(D_DATA) 67936396Ssklower printf("after stash calling sbwakeup\n"); 68036396Ssklower ENDDEBUG 68136396Ssklower } 68236396Ssklower; 68336396Ssklower 68436396Ssklower/* TP4 only */ 68536396SsklowerSAME <== TP_OPEN DT_TPDU 68636396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 68736396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 68836396Ssklower { 68936396Ssklower int doack; /* tells if we must ack immediately */ 69036396Ssklower 69151204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 69236396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 69336396Ssklower 69436396Ssklower doack = tp_stash($P, $E); 69536396Ssklower IFDEBUG(D_DATA) 69636396Ssklower printf("tp_stash returns %d\n",doack); 69736396Ssklower ENDDEBUG 69836396Ssklower 69936396Ssklower if(doack) 70036396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 70136396Ssklower else 70251204Ssklower tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks); 70336396Ssklower 70436396Ssklower IFDEBUG(D_DATA) 70536396Ssklower printf("after stash calling sbwakeup\n"); 70636396Ssklower ENDDEBUG 70736396Ssklower } 70836396Ssklower; 70936396Ssklower 71036396Ssklower/* Not in window - we must ack under certain circumstances, namely 71136396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given) 71236396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^. 71336396Ssklower * and 71436396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit 71536396Ssklower * 71636396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73) 71736396Ssklower * We just always ack. 71836396Ssklower */ 71936396Ssklower/* TP4 only */ 72036396SsklowerSAME <== [ TP_OPEN, TP_AKWAIT ] DT_TPDU 72136396Ssklower DEFAULT /* Not in window */ 72236396Ssklower { 72336396Ssklower IFTRACE(D_DATA) 72436396Ssklower tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", 72536396Ssklower $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0); 72636396Ssklower ENDTRACE 72736396Ssklower IncStat(ts_dt_niw); 72836396Ssklower m_freem($$.e_data); 72951204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 73036396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 73136396Ssklower } 73236396Ssklower; 73336396Ssklower 73436396Ssklower/* TP4 only */ 73536396SsklowerTP_OPEN <== TP_AKWAIT AK_TPDU 73636396Ssklower DEFAULT 73736396Ssklower { 73837469Ssklower if ($P.tp_ucddata) { 73937469Ssklower m_freem($P.tp_ucddata); 74037469Ssklower $P.tp_ucddata = 0; 74136396Ssklower } 74236396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 74351204Ssklower tp_cuntimeout($P, TM_retrans); 74436396Ssklower 74536396Ssklower soisconnected($P.tp_sock); 74636396Ssklower IFTRACE(D_CONN) 74736396Ssklower struct socket *so = $P.tp_sock; 74836396Ssklower tptrace(TPPTmisc, 74936396Ssklower "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", 75036396Ssklower so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); 75136396Ssklower tptrace(TPPTmisc, 75236396Ssklower "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", 75336396Ssklower so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); 75436396Ssklower ENDTRACE 75536396Ssklower 75651204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 75751204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 75836396Ssklower } 75936396Ssklower; 76036396Ssklower 76136396Ssklower/* TP4 only */ 76236396SsklowerTP_OPEN <== [ TP_OPEN, TP_AKWAIT ] XPD_TPDU 76347281Ssklower ($P.tp_Xrcvnxt == $$.e_seq) 76436396Ssklower { 76536396Ssklower if( $P.tp_state == TP_AKWAIT ) { 76637469Ssklower if ($P.tp_ucddata) { 76737469Ssklower m_freem($P.tp_ucddata); 76837469Ssklower $P.tp_ucddata = 0; 76936396Ssklower } 77051204Ssklower tp_cuntimeout($P, TM_retrans); 77136396Ssklower soisconnected($P.tp_sock); 77251204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 77351204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 77436396Ssklower } 77536396Ssklower IFTRACE(D_XPD) 77636396Ssklower tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", 77736396Ssklower $P.tp_Xrcvnxt,$$.e_seq, $$.e_datalen, $$.e_data->m_len); 77836396Ssklower ENDTRACE 77936396Ssklower 78037469Ssklower $P.tp_sock->so_state |= SS_RCVATMARK; 78147281Ssklower $$.e_data->m_flags |= M_EOR; 78237469Ssklower sbinsertoob(&$P.tp_Xrcv, $$.e_data); 78336396Ssklower IFDEBUG(D_XPD) 78436396Ssklower dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv"); 78536396Ssklower ENDDEBUG 78636396Ssklower tp_indicate(T_XDATA, $P, 0); 78736396Ssklower sbwakeup( &$P.tp_Xrcv ); 78836396Ssklower 78936396Ssklower (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 79036396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 79136396Ssklower } 79236396Ssklower; 79336396Ssklower 79436396Ssklower/* TP4 only */ 79536396SsklowerSAME <== TP_OPEN T_USR_Xrcvd 79636396Ssklower DEFAULT 79736396Ssklower { 79836396Ssklower if( $P.tp_Xrcv.sb_cc == 0 ) { 79936396Ssklower /* kludge for select(): */ 80037469Ssklower /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */ 80136396Ssklower } 80236396Ssklower } 80336396Ssklower /* OLD WAY: 80436396Ssklower * Ack only after the user receives the XPD. This is better for 80536396Ssklower * users that use one XPD right after another. 80636396Ssklower * Acking right away (the NEW WAY, see the prev. transition) is 80736396Ssklower * better for occasional * XPD, when the receiving user doesn't 80836396Ssklower * want to read the XPD immediately (which is session's behavior). 80936396Ssklower * 81036396Ssklower int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 81136396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 81236396Ssklower return error; 81336396Ssklower */ 81436396Ssklower; 81536396Ssklower 81636396Ssklower/* NOTE: presently if the user doesn't read the connection data 81736396Ssklower * before and expedited data PDU comes in, the connection data will 81836396Ssklower * be dropped. This is a bug. To avoid it, we need somewhere else 81936396Ssklower * to put the connection data. 82036396Ssklower * On the other hand, we need not to have it sitting around forever. 82136396Ssklower * This is a problem with the idea of trying to accommodate 82236396Ssklower * data on connect w/ a passive-open user interface. 82336396Ssklower */ 82436396Ssklower/* TP4 only */ 82536396Ssklower 82636396SsklowerSAME <== [ TP_AKWAIT, TP_OPEN ] XPD_TPDU 82736396Ssklower DEFAULT /* not in window or cdt==0 */ 82836396Ssklower { 82936396Ssklower IFTRACE(D_XPD) 83036396Ssklower tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", 83136396Ssklower $P.tp_Xrcvnxt, $$.e_seq, $P.tp_Xrcv.sb_cc , 0); 83236396Ssklower ENDTRACE 83336396Ssklower if( $P.tp_Xrcvnxt != $$.e_seq ) 83436396Ssklower IncStat(ts_xpd_niw); 83536396Ssklower if( $P.tp_Xrcv.sb_cc ) { 83636396Ssklower /* might as well kick 'em again */ 83736396Ssklower tp_indicate(T_XDATA, $P, 0); 83836396Ssklower IncStat(ts_xpd_dup); 83936396Ssklower } 84036396Ssklower m_freem($$.e_data); 84151204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 84236396Ssklower /* don't send an xack because the xak gives "last one received", not 84336396Ssklower * "next one i expect" (dumb) 84436396Ssklower */ 84536396Ssklower } 84636396Ssklower; 84736396Ssklower 84836396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries 84936396Ssklower * to detach all its "children" 85036396Ssklower * Also (CRSENT) when user kills a job that's doing a connect() 85136396Ssklower */ 85236396SsklowerTP_REFWAIT <== TP_CRSENT T_DETACH 85336396Ssklower ($P.tp_class == TP_CLASS_0) 85436396Ssklower { 85536396Ssklower struct socket *so = $P.tp_sock; 85636396Ssklower 85736396Ssklower /* detach from parent socket so it can finish closing */ 85836396Ssklower if (so->so_head) { 85936396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 86036396Ssklower panic("tp: T_DETACH"); 86136396Ssklower so->so_head = 0; 86236396Ssklower } 86336396Ssklower tp_soisdisconnecting($P.tp_sock); 86436396Ssklower tp_netcmd( $P, CONN_CLOSE); 86536396Ssklower tp_soisdisconnected($P); 86636396Ssklower } 86736396Ssklower; 86836396Ssklower 86936396Ssklower/* TP4 only */ 87038841SsklowerTP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH 87136396Ssklower DEFAULT 87236396Ssklower { 87336396Ssklower struct socket *so = $P.tp_sock; 87437469Ssklower struct mbuf *data = MNULL; 87536396Ssklower 87636396Ssklower /* detach from parent socket so it can finish closing */ 87736396Ssklower if (so->so_head) { 87836396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 87936396Ssklower panic("tp: T_DETACH"); 88036396Ssklower so->so_head = 0; 88136396Ssklower } 88236396Ssklower if ($P.tp_state != TP_CLOSING) { 88336396Ssklower tp_soisdisconnecting($P.tp_sock); 88437469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 88537469Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data); 88636396Ssklower $P.tp_retrans = $P.tp_Nretrans; 88751204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 88836396Ssklower } 88936396Ssklower } 89036396Ssklower; 89136396Ssklower 89236396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req 89336396Ssklower ( $P.tp_class == TP_CLASS_0 ) 89436396Ssklower { 89536396Ssklower tp_soisdisconnecting($P.tp_sock); 89636396Ssklower tp_netcmd( $P, CONN_CLOSE); 89736396Ssklower tp_soisdisconnected($P); 89836396Ssklower } 89936396Ssklower; 90036396Ssklower 90136396Ssklower/* TP4 only */ 90238841SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req 90336396Ssklower DEFAULT 90436396Ssklower { 90537469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 90636396Ssklower 90736396Ssklower if($P.tp_state == TP_OPEN) { 90851204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 90951204Ssklower tp_cuntimeout($P, TM_inact); 91051204Ssklower tp_cuntimeout($P, TM_sendack); 91136396Ssklower } 91237469Ssklower if (data) { 91336396Ssklower IFDEBUG(D_CONN) 91437469Ssklower printf("T_DISC_req.trans tp_ucddata 0x%x\n", 91537469Ssklower $P.tp_ucddata); 91637469Ssklower dump_mbuf(data, "ucddata @ T_DISC_req"); 91736396Ssklower ENDDEBUG 91836396Ssklower } 91936396Ssklower tp_soisdisconnecting($P.tp_sock); 92036396Ssklower $P.tp_retrans = $P.tp_Nretrans; 92151204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 92236396Ssklower 92336396Ssklower if( trick_hc ) 92436396Ssklower return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data); 92536396Ssklower } 92636396Ssklower; 92736396Ssklower 92836396Ssklower/* TP4 only */ 92936396SsklowerSAME <== TP_AKWAIT TM_retrans 93036396Ssklower ( $P.tp_retrans > 0 ) 93136396Ssklower { 93236396Ssklower int error; 93337469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 93436396Ssklower 93536396Ssklower IncStat(ts_retrans_cc); 93636396Ssklower $P.tp_retrans --; 93751204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 93839921Ssklower 93937469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) 94036396Ssklower $P.tp_sock->so_error = error; 94151204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 94236396Ssklower } 94336396Ssklower; 94436396Ssklower 94536396Ssklower/* TP4 only */ 94636396SsklowerTP_CLOSING <== TP_AKWAIT TM_retrans 94736396Ssklower DEFAULT /* out of time */ 94836396Ssklower { 94936396Ssklower IncStat(ts_conn_gaveup); 95036396Ssklower tp_soisdisconnecting($P.tp_sock); 95136396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 95236396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 95336396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL); 95436396Ssklower $P.tp_retrans = $P.tp_Nretrans; 95551204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 95636396Ssklower } 95736396Ssklower; 95836396Ssklower 95936396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does, 96036396Ssklower * if transmissions are going on. 96136396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack 96236396Ssklower * turnaround) 96336396Ssklower */ 96436396Ssklower/* TP4 only */ 96536396SsklowerTP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ] 96636396Ssklower DEFAULT 96736396Ssklower { 96851204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 96951204Ssklower tp_cuntimeout($P, TM_inact); 97051204Ssklower tp_cuntimeout($P, TM_sendack); 97136396Ssklower 97236396Ssklower IncStat(ts_conn_gaveup); 97336396Ssklower tp_soisdisconnecting($P.tp_sock); 97436396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 97536396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 97636396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL); 97736396Ssklower $P.tp_retrans = $P.tp_Nretrans; 97851204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 97936396Ssklower } 98036396Ssklower; 98136396Ssklower 98236396Ssklower/* TP4 only */ 98336396SsklowerSAME <== TP_OPEN TM_retrans 98436396Ssklower ( $P.tp_retrans > 0 ) 98536396Ssklower { 98651204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 98736396Ssklower /* resume XPD */ 98836396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 98937469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 99051204Ssklower int shift; 99136396Ssklower 99236396Ssklower IFTRACE(D_XPD) 99351204Ssklower tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna", 99451204Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 99536396Ssklower $P.tp_snduna); 99636396Ssklower ENDTRACE 99736396Ssklower IFDEBUG(D_XPD) 99836396Ssklower dump_mbuf(m, "XPD retrans emitting M"); 99936396Ssklower ENDDEBUG 100036396Ssklower IncStat(ts_retrans_xpd); 100136396Ssklower $P.tp_retrans --; 100251204Ssklower shift = max($P.tp_Nretrans - $P.tp_retrans, 6); 100336396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 100451204Ssklower tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift); 100536396Ssklower } 100636396Ssklower } 100736396Ssklower; 100836396Ssklower 100936396Ssklower/* TP4 only */ 101036396SsklowerSAME <== TP_OPEN TM_data_retrans 101151204Ssklower ($P.tp_rxtshift < TP_NRETRANS) 101236396Ssklower { 101351204Ssklower $P.tp_rxtshift++; 101451204Ssklower (void) tp_data_retrans($P); 101536396Ssklower } 101636396Ssklower; 101736396Ssklower 101836396Ssklower/* TP4 only */ 101936396SsklowerSAME <== TP_CLOSING TM_retrans 102036396Ssklower ( $P.tp_retrans > 0 ) 102136396Ssklower { 102236396Ssklower $P.tp_retrans --; 102336396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL); 102436396Ssklower IncStat(ts_retrans_dr); 102551204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 102636396Ssklower } 102736396Ssklower; 102836396Ssklower 102936396Ssklower/* TP4 only */ 103036396SsklowerTP_REFWAIT <== TP_CLOSING TM_retrans 103136396Ssklower DEFAULT /* no more retrans - gave up */ 103236396Ssklower { 103336396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 103451204Ssklower $P.tp_refstate = REF_FROZEN; 103536396Ssklower tp_recycle_tsuffix( $P ); 103651204Ssklower tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks); 103736396Ssklower } 103836396Ssklower; 103936396Ssklower 104036396Ssklower/* 104136396Ssklower * The resources are kept around until the ref timer goes off. 104236396Ssklower * The suffices are wiped out sooner so they can be reused right away. 104336396Ssklower */ 104436396Ssklower/* applicable in TP4, TP0 */ 104536396SsklowerTP_CLOSED <== TP_REFWAIT TM_reference 104636396Ssklower DEFAULT 104736396Ssklower { 104836396Ssklower tp_freeref($P.tp_refp); 104936396Ssklower tp_detach($P); 105036396Ssklower } 105136396Ssklower; 105236396Ssklower 105336396Ssklower/* applicable in TP4, TP0 */ 105436396Ssklower/* A duplicate CR from connectionless network layer can't happen */ 105536396SsklowerSAME <== TP_OPEN [ CR_TPDU, CC_TPDU ] 105636396Ssklower DEFAULT 105736396Ssklower { 105836396Ssklower if( $P.tp_class != TP_CLASS_0) { 105951204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 106036396Ssklower if ( $E.ev_number == CC_TPDU ) 106136396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 106236396Ssklower } 106336396Ssklower /* ignore it if class 0 - state tables are blank for this */ 106436396Ssklower } 106536396Ssklower; 106636396Ssklower 106736396Ssklower/* applicable in TP4, TP0 */ 106836396SsklowerSAME <== TP_OPEN T_DATA_req 106936396Ssklower DEFAULT 107036396Ssklower { 107136396Ssklower IFTRACE(D_DATA) 107251204Ssklower tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb", 107351204Ssklower $P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P); 107436396Ssklower ENDTRACE 107536396Ssklower 107636396Ssklower tp_send($P); 107736396Ssklower } 107836396Ssklower; 107936396Ssklower 108036396Ssklower/* TP4 only */ 108136396SsklowerSAME <== TP_OPEN T_XPD_req 108236396Ssklower DEFAULT 108336396Ssklower /* T_XPD_req was issued by sosend iff xpd socket buf was empty 108436396Ssklower * at time of sosend(), 108536396Ssklower * AND (which means) there were no unacknowledged XPD tpdus outstanding! 108636396Ssklower */ 108736396Ssklower { 108836396Ssklower int error = 0; 108936396Ssklower 109036396Ssklower /* resume XPD */ 109136396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 109237469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 109336396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 109436396Ssklower * that doesn't matter 109536396Ssklower */ 109636396Ssklower 109736396Ssklower IFTRACE(D_XPD) 109851204Ssklower tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna", 109951204Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 110036396Ssklower $P.tp_snduna); 110136396Ssklower ENDTRACE 110236396Ssklower IFDEBUG(D_XPD) 110336396Ssklower printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc); 110436396Ssklower dump_mbuf(m, "XPD req emitting M"); 110536396Ssklower ENDDEBUG 110636396Ssklower error = 110736396Ssklower tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 110836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 110951204Ssklower 111051204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur); 111136396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 111236396Ssklower } 111336396Ssklower if(trick_hc) 111436396Ssklower return error; 111536396Ssklower } 111636396Ssklower; 111736396Ssklower 111836396Ssklower/* TP4, faked ack in TP0 when cons send completes */ 111936396SsklowerSAME <== TP_OPEN AK_TPDU 112036396Ssklower ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) ) 112136396Ssklower 112236396Ssklower /* tp_goodack == true means 112336396Ssklower * EITHER it actually acked something heretofore unacknowledged 112436396Ssklower * OR no news but the credit should be processed. 112536396Ssklower */ 112636396Ssklower { 112750904Ssklower struct sockbuf *sb = &$P.tp_sock->so_snd; 112850904Ssklower 112936396Ssklower IFDEBUG(D_ACKRECV) 113036396Ssklower printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt); 113136396Ssklower ENDDEBUG 113236396Ssklower if( $P.tp_class != TP_CLASS_0) { 113351204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 113436396Ssklower } 113550904Ssklower sbwakeup(sb); 113636396Ssklower IFDEBUG(D_ACKRECV) 113751204Ssklower printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt); 113836396Ssklower ENDDEBUG 113936396Ssklower } 114036396Ssklower; 114136396Ssklower 114236396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 114336396SsklowerSAME <== TP_OPEN AK_TPDU 114436396Ssklower DEFAULT 114536396Ssklower { 114636396Ssklower IFTRACE(D_ACKRECV) 114736396Ssklower tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", 114836396Ssklower $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0); 114936396Ssklower ENDTRACE 115036396Ssklower if( $P.tp_class != TP_CLASS_0 ) { 115136396Ssklower 115236396Ssklower if ( !$$.e_fcc_present ) { 115336396Ssklower /* send ACK with FCC */ 115436396Ssklower IncStat( ts_ackreason[_ACK_FCC_] ); 115536396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL); 115636396Ssklower } 115751204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 115836396Ssklower } 115936396Ssklower } 116036396Ssklower; 116136396Ssklower 116236396Ssklower/* NBS(47) */ 116336396Ssklower /* goes in at *** */ 116436396Ssklower /* just so happens that this is never true now, because we allow 116536396Ssklower * only 1 packet in the queue at once (this could be changed) 116636396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 116736396Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??); 116836396Ssklower 116936396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 117036396Ssklower $P.tp_retrans = $P.tp_Nretrans; 117151204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks); 117236396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 117336396Ssklower } 117436396Ssklower */ 117536396Ssklower /* end of the above hack */ 117636396Ssklower 117736396Ssklower/* TP4 only */ 117842944SsklowerSAME <== TP_OPEN XAK_TPDU 117936396Ssklower ( tp_goodXack($P, $$.e_seq) ) 118036396Ssklower /* tp_goodXack checks for good ack, removes the correct 118136396Ssklower * tpdu from the queue and returns 1 if ack was legit, 0 if not. 118236396Ssklower * also updates tp_Xuna 118336396Ssklower */ 118436396Ssklower { 118551204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 118651204Ssklower tp_cuntimeout($P, TM_retrans); 118736396Ssklower 118836396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 118936396Ssklower 119036396Ssklower /* resume normal data */ 119136396Ssklower tp_send($P); 119236396Ssklower } 119336396Ssklower; 119436396Ssklower 119542944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 119642944SsklowerSAME <== TP_OPEN XAK_TPDU 119742944Ssklower DEFAULT 119842944Ssklower { 119942944Ssklower IFTRACE(D_ACKRECV) 120042944Ssklower tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0); 120142944Ssklower ENDTRACE 120242944Ssklower if( $P.tp_class != TP_CLASS_0 ) { 120351204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 120442944Ssklower } 120542944Ssklower } 120642944Ssklower; 120742944Ssklower 120836396Ssklower/* TP4 only */ 120936396SsklowerSAME <== TP_OPEN TM_sendack 121036396Ssklower DEFAULT 121136396Ssklower { 121251204Ssklower int timo; 121336396Ssklower IFTRACE(D_TIMER) 121436396Ssklower tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 121536396Ssklower $P.tp_sent_lcdt, 0); 121636396Ssklower ENDTRACE 121736396Ssklower IncPStat($P, tps_n_TMsendack); 121836396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 121936396Ssklower } 122036396Ssklower; 122136396Ssklower 122236396Ssklower/* TP0 only */ 122336396SsklowerSAME <== TP_OPEN T_USR_rcvd 122436396Ssklower ($P.tp_class == TP_CLASS_0) 122547281Ssklower { 122647281Ssklower if (sbspace(&$P.tp_sock->so_rcv) > 0) 122747281Ssklower tp0_openflow($P); 122847281Ssklower } 122936396Ssklower; 123036396Ssklower 123136396Ssklower/* TP4 only */ 123236396Ssklower /* If old credit was zero, 123336396Ssklower * we'd better inform other side that we now have space 123436396Ssklower * But this is not enough. Sender might not yet have 123536396Ssklower * seen an ack with cdt 0 but it might still think the 123636396Ssklower * window is closed, so it's going to wait. 123736396Ssklower * Best to send an ack each time. 123836396Ssklower * Strictly speaking, this ought to be a function of the 123936396Ssklower * general ack strategy. 124036396Ssklower */ 124136396SsklowerSAME <== TP_OPEN T_USR_rcvd 124236396Ssklower DEFAULT 124336396Ssklower { 124436396Ssklower if( trick_hc ) { 124551024Ssklower SeqNum ack_thresh; 124650849Ssklower /* 124751024Ssklower * If the upper window edge has advanced a reasonable 124851024Ssklower * amount beyond what was known, send an ACK. 124951024Ssklower * A reasonable amount is 2 packets, unless the max window 125051024Ssklower * is only 1 or 2 packets, in which case we 125151024Ssklower * should send an ack for any advance in the upper window edge. 125250849Ssklower */ 125351024Ssklower LOCAL_CREDIT($P); 125451024Ssklower ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt, 125551024Ssklower ($P.tp_maxlcredit > 2 ? 2 : 1)); 125651024Ssklower if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) { 125750849Ssklower IncStat(ts_ackreason[_ACK_USRRCV_]); 125851024Ssklower $P.tp_flags &= ~TPF_DELACK; 125939921Ssklower return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 126050849Ssklower } 126136396Ssklower } 126236396Ssklower } 126336396Ssklower; 126436396Ssklower 126536396Ssklower/* applicable in TP4, TP0 */ 126636396SsklowerSAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ] 126736396Ssklower DEFAULT 126836396Ssklower /* This happens if other end sent a DR when the user was waiting 126936396Ssklower * on a receive. 127036396Ssklower * Processing the DR includes putting us in REFWAIT state. 127136396Ssklower */ 127236396Ssklower { 127336396Ssklower if(trick_hc) 127436396Ssklower return ECONNABORTED; 127536396Ssklower } 127636396Ssklower; 127736396Ssklower 127836396Ssklower/* TP0 only */ 127936396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET 128036396Ssklower ( $P.tp_class != TP_CLASS_4 ) 128136396Ssklower /* 0 or (4 and 0) */ 128236396Ssklower /* in OPEN class will be 0 or 4 but not both */ 128336396Ssklower /* in CRSENT or LISTENING it could be in negotiation, hence both */ 128436396Ssklower /* Actually, this shouldn't ever happen in LISTENING */ 128536396Ssklower { 128636396Ssklower ASSERT( $P.tp_state != TP_LISTENING ); 128736396Ssklower tp_indicate(T_DISCONNECT, $P, ECONNRESET); 128836396Ssklower tp_soisdisconnected($P); 128936396Ssklower } 129036396Ssklower; 129136396Ssklower 129236396Ssklower/* TP4: ignore resets */ 129336396SsklowerSAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT, 129436396Ssklower TP_CLOSING, TP_LISTENING ] T_NETRESET 129536396Ssklower DEFAULT 129636396Ssklower NULLACTION 129736396Ssklower; 129836396Ssklower 129936396Ssklower/* applicable in TP4, TP0 */ 130036396SsklowerSAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET 130136396Ssklower DEFAULT 130236396Ssklower NULLACTION 130336396Ssklower; 130436396Ssklower 130536396Ssklower/* C'EST TOUT */ 1306