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*53683Ssklower * @(#)tp.trans 7.19 (Berkeley) 05/27/92 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*53683Ssklower/* @(#)tp.trans 7.19 (Berkeley) 05/27/92 */ 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(), 9351252Ssklower#ifdef TP_DEBUG_TIMERS 9436396Ssklower tp_etimeout(), tp_euntimeout(), 9551252Ssklower tp_ctimeout(), tp_cuntimeout(), 9651252Ssklower tp_ctimeout_MIN(), 9751252Ssklower#endif 9836396Ssklower tp_freeref(), tp_detach(), 9936396Ssklower tp0_stash(), tp0_send(), 10036396Ssklower tp_netcmd(), tp_send() 10136396Ssklower; 10236396Ssklower 10336396Ssklowertypedef struct tp_pcb tpcb_struct; 10436396Ssklower 10536396Ssklower 10636396Ssklower} 10736396Ssklower 10836396Ssklower*PCB tpcb_struct SYNONYM P 10936396Ssklower 11036396Ssklower*STATES 11136396Ssklower 11236396SsklowerTP_CLOSED 11336396SsklowerTP_CRSENT 11436396SsklowerTP_AKWAIT 11536396SsklowerTP_OPEN 11636396SsklowerTP_CLOSING 11736396SsklowerTP_REFWAIT 11836396SsklowerTP_LISTENING /* Local to this implementation */ 11938841SsklowerTP_CONFIRMING /* Local to this implementation */ 12036396Ssklower 12136396Ssklower*EVENTS { struct timeval e_time; } SYNONYM E 12236396Ssklower 12336396Ssklower /* 12436396Ssklower * C (typically cancelled) timers - 12536396Ssklower * 12636396Ssklower * let these be the first ones so for the sake of convenience 12736396Ssklower * their values are 0--> n-1 12836396Ssklower * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!! 12936396Ssklower */ 13036396Ssklower TM_inact 13136396Ssklower TM_retrans 13236396Ssklower /* TM_retrans is used for all 13336396Ssklower * simple retransmissions - CR,CC,XPD,DR 13436396Ssklower */ 13536396Ssklower 13636396Ssklower TM_sendack 13751204Ssklower /* TM_sendack does dual duty - keepalive AND closed-window 13851204Ssklower * Probes. 13936396Ssklower * It's set w/ keepalive-ticks every time an ack is sent. 14036396Ssklower * (this is done in (void) tp_emit() ). 14151204Ssklower * Whenever a DT arrives which doesn't require immediate acking, 14251204Ssklower * a separate fast-timeout flag is set ensuring 200ms response. 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 { 30751204Ssklower $P.tp_refstate = 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 32051204Ssklower $P.tp_refstate = 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 35850973Ssklower tp_getoptions($P); 35938841Ssklower soisconnecting($P.tp_sock); 36047281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0)) 36151204Ssklower $P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize; 36236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 36351204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 36438841Ssklower } 36536396Ssklower; 36636396Ssklower 36736396Ssklower/* TP4 only */ 36838841SsklowerTP_CLOSED <== TP_CONFIRMING T_ACPT_req 36936396Ssklower DEFAULT /* emit failed */ 37036396Ssklower { 37136396Ssklower IFDEBUG(D_CONN) 37236396Ssklower printf("event: CR_TPDU emit CC failed done " ); 37336396Ssklower ENDDEBUG 37438841Ssklower soisdisconnected($P.tp_sock); 37551214Ssklower tp_recycle_tsuffix($P); 37651214Ssklower tp_freeref($P.tp_lref); 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 } 42151208Ssklower if ($P.tp_state == TP_OPEN) 42251208Ssklower tp_indicate(T_DISCONNECT, $P, 0); 42351208Ssklower else { 42451208Ssklower int so_error = ECONNREFUSED; 42551208Ssklower if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) && 42651208Ssklower $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) && 42751208Ssklower $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK)) 42851208Ssklower so_error = ECONNABORTED; 42951208Ssklower tp_indicate(T_DISCONNECT, $P, so_error); 43051208Ssklower } 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); 438*53683Ssklower $P.tp_flags &= ~TPF_DELACK; 43936396Ssklower } 44051204Ssklower tp_cuntimeout($P, TM_retrans); 44136396Ssklower if( $$.e_sref != 0 ) 44236396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 44336396Ssklower } 44436396Ssklower } 44536396Ssklower; 44636396Ssklower 44736396SsklowerSAME <== TP_CLOSED DR_TPDU 44836396Ssklower DEFAULT 44936396Ssklower { 45036396Ssklower if( $$.e_sref != 0 ) 45136396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 45236396Ssklower /* reference timer already set - reset it to be safe (???) */ 45351204Ssklower tp_euntimeout($P, TM_reference); /* all */ 45451204Ssklower tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks); 45536396Ssklower } 45636396Ssklower; 45736396Ssklower 45836396Ssklower/* NBS(34) */ 45936396SsklowerTP_REFWAIT <== TP_CRSENT ER_TPDU 46036396Ssklower DEFAULT 46136396Ssklower { 46251204Ssklower tp_cuntimeout($P, TM_retrans); 46348739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 46436396Ssklower tp_soisdisconnected($P); 46536396Ssklower } 46636396Ssklower; 46736396Ssklower 46836396Ssklower/* NBS(27) */ 46936396SsklowerTP_REFWAIT <== TP_CLOSING DR_TPDU 47036396Ssklower DEFAULT 47136396Ssklower { 47251204Ssklower tp_cuntimeout($P, TM_retrans); 47336396Ssklower tp_soisdisconnected($P); 47436396Ssklower } 47536396Ssklower; 47636396Ssklower/* these two transitions are the same but can't be combined because xebec 47736396Ssklower * can't handle the use of $$.e_reason if they're combined 47836396Ssklower */ 47936396Ssklower/* NBS(27) */ 48036396SsklowerTP_REFWAIT <== TP_CLOSING ER_TPDU 48136396Ssklower DEFAULT 48236396Ssklower { 48348739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 48451204Ssklower tp_cuntimeout($P, TM_retrans); 48536396Ssklower tp_soisdisconnected($P); 48636396Ssklower } 48736396Ssklower; 48836396Ssklower/* NBS(27) */ 48936396SsklowerTP_REFWAIT <== TP_CLOSING DC_TPDU 49036396Ssklower DEFAULT 49136396Ssklower { 49251204Ssklower tp_cuntimeout($P, TM_retrans); 49336396Ssklower tp_soisdisconnected($P); 49436396Ssklower } 49536396Ssklower; 49636396Ssklower 49736396Ssklower/* NBS(21) */ 49836396SsklowerSAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ] 49936396Ssklower DEFAULT 50036396Ssklower { /* don't ask me why we have to do this - spec says so */ 50136396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL); 50236396Ssklower /* don't bother with retransmissions of the DR */ 50336396Ssklower } 50436396Ssklower; 50536396Ssklower 50636396Ssklower/* NBS(34) */ 50736396SsklowerTP_REFWAIT <== TP_OPEN ER_TPDU 50836396Ssklower ($P.tp_class == TP_CLASS_0) 50936396Ssklower { 51036396Ssklower tp_soisdisconnecting($P.tp_sock); 51148739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 51236396Ssklower tp_soisdisconnected($P); 51336396Ssklower tp_netcmd( $P, CONN_CLOSE ); 51436396Ssklower } 51536396Ssklower; 51636396Ssklower 51736396SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU 51836396Ssklower DEFAULT 51936396Ssklower { 52036396Ssklower if ($P.tp_state == TP_OPEN) { 52151204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 52251204Ssklower tp_cuntimeout($P, TM_inact); 52351204Ssklower tp_cuntimeout($P, TM_sendack); 52436396Ssklower } 52536396Ssklower tp_soisdisconnecting($P.tp_sock); 52648739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 52736396Ssklower $P.tp_retrans = $P.tp_Nretrans; 52851204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 52936396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL); 53036396Ssklower } 53136396Ssklower; 53236396Ssklower/* NBS(6) */ 53336396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 53436396Ssklower ($P.tp_class == TP_CLASS_0) 53536396Ssklower { 53651204Ssklower tp_cuntimeout($P, TM_retrans); 53736396Ssklower IncStat(ts_tp0_conn); 53836396Ssklower $P.tp_fcredit = 1; 53936396Ssklower soisconnected($P.tp_sock); 54036396Ssklower } 54136396Ssklower; 54236396Ssklower 54336396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 54436396Ssklower DEFAULT 54536396Ssklower { 54636396Ssklower IFDEBUG(D_CONN) 54736396Ssklower printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", 54836396Ssklower (int)$P.tp_flags); 54936396Ssklower ENDDEBUG 55036396Ssklower IncStat(ts_tp4_conn); 55136396Ssklower $P.tp_fref = $$.e_sref; 55236396Ssklower $P.tp_fcredit = $$.e_cdt; 55347281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0)) 55451204Ssklower $P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize; 55536396Ssklower tp_getoptions($P); 55651204Ssklower tp_cuntimeout($P, TM_retrans); 55737469Ssklower if ($P.tp_ucddata) { 55836396Ssklower IFDEBUG(D_CONN) 55937469Ssklower printf("dropping user connect data cc 0x%x\n", 56037469Ssklower $P.tp_ucddata->m_len); 56136396Ssklower ENDDEBUG 56237469Ssklower m_freem($P.tp_ucddata); 56337469Ssklower $P.tp_ucddata = 0; 56436396Ssklower } 56536396Ssklower soisconnected($P.tp_sock); 56636396Ssklower if ($$.e_datalen > 0) { 56736396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */ 56836396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 56936396Ssklower $$.e_data = MNULL; 57036396Ssklower } 57136396Ssklower 57236396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 57351204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 57436396Ssklower } 57536396Ssklower; 57636396Ssklower 57736396Ssklower/* TP4 only */ 57836396SsklowerSAME <== TP_CRSENT TM_retrans 57936396Ssklower ( $P.tp_retrans > 0 ) 58036396Ssklower { 58136396Ssklower struct mbuf *data = MNULL; 58236396Ssklower int error; 58336396Ssklower 58436396Ssklower IncStat(ts_retrans_cr); 58551204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 58637469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 58737469Ssklower if($P.tp_ucddata) { 58836396Ssklower IFDEBUG(D_CONN) 58937469Ssklower printf("TM_retrans.trans m_copy cc 0x%x\n", data); 59037469Ssklower dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans"); 59136396Ssklower ENDDEBUG 59236396Ssklower if( data == MNULL ) 59336396Ssklower return ENOBUFS; 59436396Ssklower } 59536396Ssklower 59636396Ssklower $P.tp_retrans --; 59736396Ssklower if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) { 59836396Ssklower $P.tp_sock->so_error = error; 59936396Ssklower } 60051204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks); 60136396Ssklower } 60236396Ssklower; 60336396Ssklower 60436396Ssklower/* TP4 only */ 60536396SsklowerTP_REFWAIT <== TP_CRSENT TM_retrans 60636396Ssklower DEFAULT /* no more CR retransmissions */ 60736396Ssklower { 60836396Ssklower IncStat(ts_conn_gaveup); 60936396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 61036396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 61136396Ssklower tp_soisdisconnected($P); 61236396Ssklower } 61336396Ssklower; 61436396Ssklower 61536396Ssklower/* TP4 only */ 61636396SsklowerSAME <== TP_AKWAIT CR_TPDU 61736396Ssklower DEFAULT 61836396Ssklower /* duplicate CR (which doesn't really exist in the context of 61936396Ssklower * a connectionless network layer) 62036396Ssklower * Doesn't occur in class 0. 62136396Ssklower */ 62236396Ssklower { 62336396Ssklower int error; 62437469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 62536396Ssklower 62637469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) { 62736396Ssklower $P.tp_sock->so_error = error; 62836396Ssklower } 62936396Ssklower $P.tp_retrans = $P.tp_Nretrans; 63051204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 63136396Ssklower } 63236396Ssklower; 63336396Ssklower 63436396Ssklower/* TP4 only */ 63536396SsklowerTP_OPEN <== TP_AKWAIT DT_TPDU 63636396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 63736396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 63836396Ssklower { 63936396Ssklower int doack; 64036396Ssklower 64137469Ssklower /* 64237469Ssklower * Get rid of any confirm or connect data, so that if we 64337469Ssklower * crash or close, it isn't thought of as disconnect data. 64437469Ssklower */ 64537469Ssklower if ($P.tp_ucddata) { 64637469Ssklower m_freem($P.tp_ucddata); 64737469Ssklower $P.tp_ucddata = 0; 64836396Ssklower } 64951204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 65051204Ssklower tp_cuntimeout($P, TM_retrans); 65136396Ssklower soisconnected($P.tp_sock); 65251204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 65336396Ssklower 65436396Ssklower /* see also next 2 transitions, if you make any changes */ 65536396Ssklower 65636396Ssklower doack = tp_stash($P, $E); 65736396Ssklower IFDEBUG(D_DATA) 65836396Ssklower printf("tp_stash returns %d\n",doack); 65936396Ssklower ENDDEBUG 66036396Ssklower 66151204Ssklower if (doack) { 66236396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 66351204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 66436396Ssklower } else 66551204Ssklower tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks); 66636396Ssklower 66736396Ssklower IFDEBUG(D_DATA) 66836396Ssklower printf("after stash calling sbwakeup\n"); 66936396Ssklower ENDDEBUG 67036396Ssklower } 67136396Ssklower; 67236396Ssklower 67336396SsklowerSAME <== TP_OPEN DT_TPDU 67436396Ssklower ( $P.tp_class == TP_CLASS_0 ) 67536396Ssklower { 67636396Ssklower tp0_stash($P, $E); 67736396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 67836396Ssklower 67936396Ssklower IFDEBUG(D_DATA) 68036396Ssklower printf("after stash calling sbwakeup\n"); 68136396Ssklower ENDDEBUG 68236396Ssklower } 68336396Ssklower; 68436396Ssklower 68536396Ssklower/* TP4 only */ 68636396SsklowerSAME <== TP_OPEN DT_TPDU 68736396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 68836396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 68936396Ssklower { 69036396Ssklower int doack; /* tells if we must ack immediately */ 69136396Ssklower 69251204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 69336396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 69436396Ssklower 69536396Ssklower doack = tp_stash($P, $E); 69636396Ssklower IFDEBUG(D_DATA) 69736396Ssklower printf("tp_stash returns %d\n",doack); 69836396Ssklower ENDDEBUG 69936396Ssklower 70036396Ssklower if(doack) 70136396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 70236396Ssklower else 70351204Ssklower tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks); 70436396Ssklower 70536396Ssklower IFDEBUG(D_DATA) 70636396Ssklower printf("after stash calling sbwakeup\n"); 70736396Ssklower ENDDEBUG 70836396Ssklower } 70936396Ssklower; 71036396Ssklower 71136396Ssklower/* Not in window - we must ack under certain circumstances, namely 71236396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given) 71336396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^. 71436396Ssklower * and 71536396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit 71636396Ssklower * 71736396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73) 71836396Ssklower * We just always ack. 71936396Ssklower */ 72036396Ssklower/* TP4 only */ 72136396SsklowerSAME <== [ TP_OPEN, TP_AKWAIT ] DT_TPDU 72236396Ssklower DEFAULT /* Not in window */ 72336396Ssklower { 72436396Ssklower IFTRACE(D_DATA) 72536396Ssklower tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", 72636396Ssklower $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0); 72736396Ssklower ENDTRACE 72836396Ssklower IncStat(ts_dt_niw); 72936396Ssklower m_freem($$.e_data); 73051204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 73136396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 73236396Ssklower } 73336396Ssklower; 73436396Ssklower 73536396Ssklower/* TP4 only */ 73636396SsklowerTP_OPEN <== TP_AKWAIT AK_TPDU 73736396Ssklower DEFAULT 73836396Ssklower { 73937469Ssklower if ($P.tp_ucddata) { 74037469Ssklower m_freem($P.tp_ucddata); 74137469Ssklower $P.tp_ucddata = 0; 74236396Ssklower } 74336396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 74451204Ssklower tp_cuntimeout($P, TM_retrans); 74536396Ssklower 74636396Ssklower soisconnected($P.tp_sock); 74736396Ssklower IFTRACE(D_CONN) 74836396Ssklower struct socket *so = $P.tp_sock; 74936396Ssklower tptrace(TPPTmisc, 75036396Ssklower "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", 75136396Ssklower so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); 75236396Ssklower tptrace(TPPTmisc, 75336396Ssklower "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", 75436396Ssklower so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); 75536396Ssklower ENDTRACE 75636396Ssklower 75751204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 75851204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 75936396Ssklower } 76036396Ssklower; 76136396Ssklower 76236396Ssklower/* TP4 only */ 76336396SsklowerTP_OPEN <== [ TP_OPEN, TP_AKWAIT ] XPD_TPDU 76447281Ssklower ($P.tp_Xrcvnxt == $$.e_seq) 76536396Ssklower { 76636396Ssklower if( $P.tp_state == TP_AKWAIT ) { 76737469Ssklower if ($P.tp_ucddata) { 76837469Ssklower m_freem($P.tp_ucddata); 76937469Ssklower $P.tp_ucddata = 0; 77036396Ssklower } 77151204Ssklower tp_cuntimeout($P, TM_retrans); 77236396Ssklower soisconnected($P.tp_sock); 77351204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 77451204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 77536396Ssklower } 77636396Ssklower IFTRACE(D_XPD) 77736396Ssklower tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", 77836396Ssklower $P.tp_Xrcvnxt,$$.e_seq, $$.e_datalen, $$.e_data->m_len); 77936396Ssklower ENDTRACE 78036396Ssklower 78137469Ssklower $P.tp_sock->so_state |= SS_RCVATMARK; 78247281Ssklower $$.e_data->m_flags |= M_EOR; 78337469Ssklower sbinsertoob(&$P.tp_Xrcv, $$.e_data); 78436396Ssklower IFDEBUG(D_XPD) 78536396Ssklower dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv"); 78636396Ssklower ENDDEBUG 78736396Ssklower tp_indicate(T_XDATA, $P, 0); 78836396Ssklower sbwakeup( &$P.tp_Xrcv ); 78936396Ssklower 79036396Ssklower (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 79136396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 79236396Ssklower } 79336396Ssklower; 79436396Ssklower 79536396Ssklower/* TP4 only */ 79636396SsklowerSAME <== TP_OPEN T_USR_Xrcvd 79736396Ssklower DEFAULT 79836396Ssklower { 79936396Ssklower if( $P.tp_Xrcv.sb_cc == 0 ) { 80036396Ssklower /* kludge for select(): */ 80137469Ssklower /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */ 80236396Ssklower } 80336396Ssklower } 80436396Ssklower /* OLD WAY: 80536396Ssklower * Ack only after the user receives the XPD. This is better for 80636396Ssklower * users that use one XPD right after another. 80736396Ssklower * Acking right away (the NEW WAY, see the prev. transition) is 80836396Ssklower * better for occasional * XPD, when the receiving user doesn't 80936396Ssklower * want to read the XPD immediately (which is session's behavior). 81036396Ssklower * 81136396Ssklower int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 81236396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 81336396Ssklower return error; 81436396Ssklower */ 81536396Ssklower; 81636396Ssklower 81736396Ssklower/* NOTE: presently if the user doesn't read the connection data 81836396Ssklower * before and expedited data PDU comes in, the connection data will 81936396Ssklower * be dropped. This is a bug. To avoid it, we need somewhere else 82036396Ssklower * to put the connection data. 82136396Ssklower * On the other hand, we need not to have it sitting around forever. 82236396Ssklower * This is a problem with the idea of trying to accommodate 82336396Ssklower * data on connect w/ a passive-open user interface. 82436396Ssklower */ 82536396Ssklower/* TP4 only */ 82636396Ssklower 82736396SsklowerSAME <== [ TP_AKWAIT, TP_OPEN ] XPD_TPDU 82836396Ssklower DEFAULT /* not in window or cdt==0 */ 82936396Ssklower { 83036396Ssklower IFTRACE(D_XPD) 83136396Ssklower tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", 83236396Ssklower $P.tp_Xrcvnxt, $$.e_seq, $P.tp_Xrcv.sb_cc , 0); 83336396Ssklower ENDTRACE 83436396Ssklower if( $P.tp_Xrcvnxt != $$.e_seq ) 83536396Ssklower IncStat(ts_xpd_niw); 83636396Ssklower if( $P.tp_Xrcv.sb_cc ) { 83736396Ssklower /* might as well kick 'em again */ 83836396Ssklower tp_indicate(T_XDATA, $P, 0); 83936396Ssklower IncStat(ts_xpd_dup); 84036396Ssklower } 84136396Ssklower m_freem($$.e_data); 84251204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 84336396Ssklower /* don't send an xack because the xak gives "last one received", not 84436396Ssklower * "next one i expect" (dumb) 84536396Ssklower */ 84636396Ssklower } 84736396Ssklower; 84836396Ssklower 84936396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries 85036396Ssklower * to detach all its "children" 85136396Ssklower * Also (CRSENT) when user kills a job that's doing a connect() 85236396Ssklower */ 85336396SsklowerTP_REFWAIT <== TP_CRSENT T_DETACH 85436396Ssklower ($P.tp_class == TP_CLASS_0) 85536396Ssklower { 85636396Ssklower struct socket *so = $P.tp_sock; 85736396Ssklower 85836396Ssklower /* detach from parent socket so it can finish closing */ 85936396Ssklower if (so->so_head) { 86036396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 86136396Ssklower panic("tp: T_DETACH"); 86236396Ssklower so->so_head = 0; 86336396Ssklower } 86436396Ssklower tp_soisdisconnecting($P.tp_sock); 86536396Ssklower tp_netcmd( $P, CONN_CLOSE); 86636396Ssklower tp_soisdisconnected($P); 86736396Ssklower } 86836396Ssklower; 86936396Ssklower 87036396Ssklower/* TP4 only */ 87138841SsklowerTP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH 87236396Ssklower DEFAULT 87336396Ssklower { 87436396Ssklower struct socket *so = $P.tp_sock; 87537469Ssklower struct mbuf *data = MNULL; 87636396Ssklower 87736396Ssklower /* detach from parent socket so it can finish closing */ 87836396Ssklower if (so->so_head) { 87936396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 88036396Ssklower panic("tp: T_DETACH"); 88136396Ssklower so->so_head = 0; 88236396Ssklower } 88336396Ssklower if ($P.tp_state != TP_CLOSING) { 88436396Ssklower tp_soisdisconnecting($P.tp_sock); 88537469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 88637469Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data); 88736396Ssklower $P.tp_retrans = $P.tp_Nretrans; 88851204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 88936396Ssklower } 89036396Ssklower } 89136396Ssklower; 89236396Ssklower 89336396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req 89436396Ssklower ( $P.tp_class == TP_CLASS_0 ) 89536396Ssklower { 89636396Ssklower tp_soisdisconnecting($P.tp_sock); 89736396Ssklower tp_netcmd( $P, CONN_CLOSE); 89836396Ssklower tp_soisdisconnected($P); 89936396Ssklower } 90036396Ssklower; 90136396Ssklower 90236396Ssklower/* TP4 only */ 90338841SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req 90436396Ssklower DEFAULT 90536396Ssklower { 90637469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 90736396Ssklower 90836396Ssklower if($P.tp_state == TP_OPEN) { 90951204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 91051204Ssklower tp_cuntimeout($P, TM_inact); 91151204Ssklower tp_cuntimeout($P, TM_sendack); 912*53683Ssklower $P.tp_flags &= ~TPF_DELACK; 91336396Ssklower } 91437469Ssklower if (data) { 91536396Ssklower IFDEBUG(D_CONN) 91637469Ssklower printf("T_DISC_req.trans tp_ucddata 0x%x\n", 91737469Ssklower $P.tp_ucddata); 91837469Ssklower dump_mbuf(data, "ucddata @ T_DISC_req"); 91936396Ssklower ENDDEBUG 92036396Ssklower } 92136396Ssklower tp_soisdisconnecting($P.tp_sock); 92236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 92351204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 92436396Ssklower 92536396Ssklower if( trick_hc ) 92636396Ssklower return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data); 92736396Ssklower } 92836396Ssklower; 92936396Ssklower 93036396Ssklower/* TP4 only */ 93136396SsklowerSAME <== TP_AKWAIT TM_retrans 93236396Ssklower ( $P.tp_retrans > 0 ) 93336396Ssklower { 93436396Ssklower int error; 93537469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 93636396Ssklower 93736396Ssklower IncStat(ts_retrans_cc); 93836396Ssklower $P.tp_retrans --; 93951204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 94039921Ssklower 94137469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) 94236396Ssklower $P.tp_sock->so_error = error; 94351204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 94436396Ssklower } 94536396Ssklower; 94636396Ssklower 94736396Ssklower/* TP4 only */ 94836396SsklowerTP_CLOSING <== TP_AKWAIT TM_retrans 94936396Ssklower DEFAULT /* out of time */ 95036396Ssklower { 95136396Ssklower IncStat(ts_conn_gaveup); 95236396Ssklower tp_soisdisconnecting($P.tp_sock); 95336396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 95436396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 95536396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL); 95636396Ssklower $P.tp_retrans = $P.tp_Nretrans; 95751204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 95836396Ssklower } 95936396Ssklower; 96036396Ssklower 96136396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does, 96236396Ssklower * if transmissions are going on. 96336396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack 96436396Ssklower * turnaround) 96536396Ssklower */ 96636396Ssklower/* TP4 only */ 96736396SsklowerTP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ] 96836396Ssklower DEFAULT 96936396Ssklower { 97051204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 97151204Ssklower tp_cuntimeout($P, TM_inact); 97251204Ssklower tp_cuntimeout($P, TM_sendack); 97336396Ssklower 97436396Ssklower IncStat(ts_conn_gaveup); 97536396Ssklower tp_soisdisconnecting($P.tp_sock); 97636396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 97736396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 97836396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL); 97936396Ssklower $P.tp_retrans = $P.tp_Nretrans; 98051204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 98136396Ssklower } 98236396Ssklower; 98336396Ssklower 98436396Ssklower/* TP4 only */ 98536396SsklowerSAME <== TP_OPEN TM_retrans 98636396Ssklower ( $P.tp_retrans > 0 ) 98736396Ssklower { 98851204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 98936396Ssklower /* resume XPD */ 99036396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 99137469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 99251204Ssklower int shift; 99336396Ssklower 99436396Ssklower IFTRACE(D_XPD) 99551204Ssklower tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna", 99651204Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 99736396Ssklower $P.tp_snduna); 99836396Ssklower ENDTRACE 99936396Ssklower IFDEBUG(D_XPD) 100036396Ssklower dump_mbuf(m, "XPD retrans emitting M"); 100136396Ssklower ENDDEBUG 100236396Ssklower IncStat(ts_retrans_xpd); 100336396Ssklower $P.tp_retrans --; 100451204Ssklower shift = max($P.tp_Nretrans - $P.tp_retrans, 6); 100536396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 100651204Ssklower tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift); 100736396Ssklower } 100836396Ssklower } 100936396Ssklower; 101036396Ssklower 101136396Ssklower/* TP4 only */ 101236396SsklowerSAME <== TP_OPEN TM_data_retrans 101351204Ssklower ($P.tp_rxtshift < TP_NRETRANS) 101436396Ssklower { 101551204Ssklower $P.tp_rxtshift++; 101651204Ssklower (void) tp_data_retrans($P); 101736396Ssklower } 101836396Ssklower; 101936396Ssklower 102036396Ssklower/* TP4 only */ 102136396SsklowerSAME <== TP_CLOSING TM_retrans 102236396Ssklower ( $P.tp_retrans > 0 ) 102336396Ssklower { 102436396Ssklower $P.tp_retrans --; 102536396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL); 102636396Ssklower IncStat(ts_retrans_dr); 102751204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 102836396Ssklower } 102936396Ssklower; 103036396Ssklower 103136396Ssklower/* TP4 only */ 103236396SsklowerTP_REFWAIT <== TP_CLOSING TM_retrans 103336396Ssklower DEFAULT /* no more retrans - gave up */ 103436396Ssklower { 103536396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 103651204Ssklower $P.tp_refstate = REF_FROZEN; 103736396Ssklower tp_recycle_tsuffix( $P ); 103851204Ssklower tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks); 103936396Ssklower } 104036396Ssklower; 104136396Ssklower 104236396Ssklower/* 104336396Ssklower * The resources are kept around until the ref timer goes off. 104436396Ssklower * The suffices are wiped out sooner so they can be reused right away. 104536396Ssklower */ 104636396Ssklower/* applicable in TP4, TP0 */ 104736396SsklowerTP_CLOSED <== TP_REFWAIT TM_reference 104836396Ssklower DEFAULT 104936396Ssklower { 105051214Ssklower tp_freeref($P.tp_lref); 105136396Ssklower tp_detach($P); 105236396Ssklower } 105336396Ssklower; 105436396Ssklower 105536396Ssklower/* applicable in TP4, TP0 */ 105636396Ssklower/* A duplicate CR from connectionless network layer can't happen */ 105736396SsklowerSAME <== TP_OPEN [ CR_TPDU, CC_TPDU ] 105836396Ssklower DEFAULT 105936396Ssklower { 106036396Ssklower if( $P.tp_class != TP_CLASS_0) { 106151204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 106236396Ssklower if ( $E.ev_number == CC_TPDU ) 106336396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 106436396Ssklower } 106536396Ssklower /* ignore it if class 0 - state tables are blank for this */ 106636396Ssklower } 106736396Ssklower; 106836396Ssklower 106936396Ssklower/* applicable in TP4, TP0 */ 107036396SsklowerSAME <== TP_OPEN T_DATA_req 107136396Ssklower DEFAULT 107236396Ssklower { 107336396Ssklower IFTRACE(D_DATA) 107451204Ssklower tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb", 107551204Ssklower $P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P); 107636396Ssklower ENDTRACE 107736396Ssklower 107836396Ssklower tp_send($P); 107936396Ssklower } 108036396Ssklower; 108136396Ssklower 108236396Ssklower/* TP4 only */ 108336396SsklowerSAME <== TP_OPEN T_XPD_req 108436396Ssklower DEFAULT 108536396Ssklower /* T_XPD_req was issued by sosend iff xpd socket buf was empty 108636396Ssklower * at time of sosend(), 108736396Ssklower * AND (which means) there were no unacknowledged XPD tpdus outstanding! 108836396Ssklower */ 108936396Ssklower { 109036396Ssklower int error = 0; 109136396Ssklower 109236396Ssklower /* resume XPD */ 109336396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 109437469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 109536396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 109636396Ssklower * that doesn't matter 109736396Ssklower */ 109836396Ssklower 109936396Ssklower IFTRACE(D_XPD) 110051204Ssklower tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna", 110151204Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 110236396Ssklower $P.tp_snduna); 110336396Ssklower ENDTRACE 110436396Ssklower IFDEBUG(D_XPD) 110536396Ssklower printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc); 110636396Ssklower dump_mbuf(m, "XPD req emitting M"); 110736396Ssklower ENDDEBUG 110836396Ssklower error = 110936396Ssklower tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 111036396Ssklower $P.tp_retrans = $P.tp_Nretrans; 111151204Ssklower 111251204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur); 111336396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 111436396Ssklower } 111536396Ssklower if(trick_hc) 111636396Ssklower return error; 111736396Ssklower } 111836396Ssklower; 111936396Ssklower 112036396Ssklower/* TP4, faked ack in TP0 when cons send completes */ 112136396SsklowerSAME <== TP_OPEN AK_TPDU 112236396Ssklower ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) ) 112336396Ssklower 112436396Ssklower /* tp_goodack == true means 112536396Ssklower * EITHER it actually acked something heretofore unacknowledged 112636396Ssklower * OR no news but the credit should be processed. 112736396Ssklower */ 112836396Ssklower { 112950904Ssklower struct sockbuf *sb = &$P.tp_sock->so_snd; 113050904Ssklower 113136396Ssklower IFDEBUG(D_ACKRECV) 113236396Ssklower printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt); 113336396Ssklower ENDDEBUG 113436396Ssklower if( $P.tp_class != TP_CLASS_0) { 113551204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 113636396Ssklower } 113750904Ssklower sbwakeup(sb); 113836396Ssklower IFDEBUG(D_ACKRECV) 113951204Ssklower printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt); 114036396Ssklower ENDDEBUG 114136396Ssklower } 114236396Ssklower; 114336396Ssklower 114436396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 114536396SsklowerSAME <== TP_OPEN AK_TPDU 114636396Ssklower DEFAULT 114736396Ssklower { 114836396Ssklower IFTRACE(D_ACKRECV) 114936396Ssklower tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", 115036396Ssklower $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0); 115136396Ssklower ENDTRACE 115236396Ssklower if( $P.tp_class != TP_CLASS_0 ) { 115336396Ssklower 115436396Ssklower if ( !$$.e_fcc_present ) { 115536396Ssklower /* send ACK with FCC */ 115636396Ssklower IncStat( ts_ackreason[_ACK_FCC_] ); 115736396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL); 115836396Ssklower } 115951204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 116036396Ssklower } 116136396Ssklower } 116236396Ssklower; 116336396Ssklower 116436396Ssklower/* NBS(47) */ 116536396Ssklower /* goes in at *** */ 116636396Ssklower /* just so happens that this is never true now, because we allow 116736396Ssklower * only 1 packet in the queue at once (this could be changed) 116836396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 116936396Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??); 117036396Ssklower 117136396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 117236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 117351204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks); 117436396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 117536396Ssklower } 117636396Ssklower */ 117736396Ssklower /* end of the above hack */ 117836396Ssklower 117936396Ssklower/* TP4 only */ 118042944SsklowerSAME <== TP_OPEN XAK_TPDU 118136396Ssklower ( tp_goodXack($P, $$.e_seq) ) 118236396Ssklower /* tp_goodXack checks for good ack, removes the correct 118336396Ssklower * tpdu from the queue and returns 1 if ack was legit, 0 if not. 118436396Ssklower * also updates tp_Xuna 118536396Ssklower */ 118636396Ssklower { 118751204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 118851204Ssklower tp_cuntimeout($P, TM_retrans); 118936396Ssklower 119036396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 119136396Ssklower 119236396Ssklower /* resume normal data */ 119336396Ssklower tp_send($P); 119436396Ssklower } 119536396Ssklower; 119636396Ssklower 119742944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 119842944SsklowerSAME <== TP_OPEN XAK_TPDU 119942944Ssklower DEFAULT 120042944Ssklower { 120142944Ssklower IFTRACE(D_ACKRECV) 120242944Ssklower tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0); 120342944Ssklower ENDTRACE 120442944Ssklower if( $P.tp_class != TP_CLASS_0 ) { 120551204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 120642944Ssklower } 120742944Ssklower } 120842944Ssklower; 120942944Ssklower 121036396Ssklower/* TP4 only */ 121136396SsklowerSAME <== TP_OPEN TM_sendack 121236396Ssklower DEFAULT 121336396Ssklower { 121451204Ssklower int timo; 121536396Ssklower IFTRACE(D_TIMER) 121636396Ssklower tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 121736396Ssklower $P.tp_sent_lcdt, 0); 121836396Ssklower ENDTRACE 121936396Ssklower IncPStat($P, tps_n_TMsendack); 122036396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 122151248Ssklower if ($P.tp_fcredit == 0) { 122251248Ssklower if ($P.tp_rxtshift < TP_MAXRXTSHIFT) 122351248Ssklower $P.tp_rxtshift++; 122451248Ssklower timo = ($P.tp_dt_ticks) << $P.tp_rxtshift; 122551248Ssklower } else 122651248Ssklower timo = $P.tp_sendack_ticks; 122751248Ssklower tp_ctimeout($P, TM_sendack, timo); 122836396Ssklower } 122936396Ssklower; 123036396Ssklower 123136396Ssklower/* TP0 only */ 123236396SsklowerSAME <== TP_OPEN T_USR_rcvd 123336396Ssklower ($P.tp_class == TP_CLASS_0) 123447281Ssklower { 123547281Ssklower if (sbspace(&$P.tp_sock->so_rcv) > 0) 123647281Ssklower tp0_openflow($P); 123747281Ssklower } 123836396Ssklower; 123936396Ssklower 124036396Ssklower/* TP4 only */ 124136396Ssklower /* If old credit was zero, 124236396Ssklower * we'd better inform other side that we now have space 124336396Ssklower * But this is not enough. Sender might not yet have 124436396Ssklower * seen an ack with cdt 0 but it might still think the 124536396Ssklower * window is closed, so it's going to wait. 124636396Ssklower * Best to send an ack each time. 124736396Ssklower * Strictly speaking, this ought to be a function of the 124836396Ssklower * general ack strategy. 124936396Ssklower */ 125036396SsklowerSAME <== TP_OPEN T_USR_rcvd 125136396Ssklower DEFAULT 125236396Ssklower { 125336396Ssklower if( trick_hc ) { 125451024Ssklower SeqNum ack_thresh; 125550849Ssklower /* 125651024Ssklower * If the upper window edge has advanced a reasonable 125751024Ssklower * amount beyond what was known, send an ACK. 125851024Ssklower * A reasonable amount is 2 packets, unless the max window 125951024Ssklower * is only 1 or 2 packets, in which case we 126051024Ssklower * should send an ack for any advance in the upper window edge. 126150849Ssklower */ 126251024Ssklower LOCAL_CREDIT($P); 126351024Ssklower ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt, 126451024Ssklower ($P.tp_maxlcredit > 2 ? 2 : 1)); 126551024Ssklower if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) { 126650849Ssklower IncStat(ts_ackreason[_ACK_USRRCV_]); 126751024Ssklower $P.tp_flags &= ~TPF_DELACK; 126839921Ssklower return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 126950849Ssklower } 127036396Ssklower } 127136396Ssklower } 127236396Ssklower; 127336396Ssklower 127436396Ssklower/* applicable in TP4, TP0 */ 127536396SsklowerSAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ] 127636396Ssklower DEFAULT 127736396Ssklower /* This happens if other end sent a DR when the user was waiting 127836396Ssklower * on a receive. 127936396Ssklower * Processing the DR includes putting us in REFWAIT state. 128036396Ssklower */ 128136396Ssklower { 128236396Ssklower if(trick_hc) 128336396Ssklower return ECONNABORTED; 128436396Ssklower } 128536396Ssklower; 128636396Ssklower 128736396Ssklower/* TP0 only */ 128836396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET 128936396Ssklower ( $P.tp_class != TP_CLASS_4 ) 129036396Ssklower /* 0 or (4 and 0) */ 129136396Ssklower /* in OPEN class will be 0 or 4 but not both */ 129236396Ssklower /* in CRSENT or LISTENING it could be in negotiation, hence both */ 129336396Ssklower /* Actually, this shouldn't ever happen in LISTENING */ 129436396Ssklower { 129536396Ssklower ASSERT( $P.tp_state != TP_LISTENING ); 129636396Ssklower tp_indicate(T_DISCONNECT, $P, ECONNRESET); 129736396Ssklower tp_soisdisconnected($P); 129836396Ssklower } 129936396Ssklower; 130036396Ssklower 130136396Ssklower/* TP4: ignore resets */ 130236396SsklowerSAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT, 130336396Ssklower TP_CLOSING, TP_LISTENING ] T_NETRESET 130436396Ssklower DEFAULT 130536396Ssklower NULLACTION 130636396Ssklower; 130736396Ssklower 130836396Ssklower/* applicable in TP4, TP0 */ 130936396SsklowerSAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET 131036396Ssklower DEFAULT 131136396Ssklower NULLACTION 131236396Ssklower; 131336396Ssklower 131436396Ssklower/* C'EST TOUT */ 1315