150849Ssklower/* NEW */ 249268Sbostic/*- 363221Sbostic * Copyright (c) 1991, 1993 463221Sbostic * The Regents of the University of California. All rights reserved. 549268Sbostic * 649268Sbostic * %sccs.include.redist.c% 749268Sbostic * 8*63223Sbostic * @(#)tp.trans 8.1 (Berkeley) 06/10/93 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*63223Sbostic/* @(#)tp.trans 8.1 (Berkeley) 06/10/93 */ 6356532Sbostic#include <sys/param.h> 6456532Sbostic#include <sys/systm.h> 6556532Sbostic#include <sys/socket.h> 6656532Sbostic#include <sys/socketvar.h> 6756532Sbostic#include <sys/protosw.h> 6856532Sbostic#include <sys/mbuf.h> 6956532Sbostic#include <sys/time.h> 7056532Sbostic#include <sys/errno.h> 7136396Ssklower 7256532Sbostic#include <netiso/tp_param.h> 7356532Sbostic#include <netiso/tp_stat.h> 7456532Sbostic#include <netiso/tp_pcb.h> 7556532Sbostic#include <netiso/tp_tpdu.h> 7656532Sbostic#include <netiso/argo_debug.h> 7756532Sbostic#include <netiso/tp_trace.h> 7856532Sbostic#include <netiso/iso_errno.h> 7956532Sbostic#include <netiso/tp_seq.h> 8056532Sbostic#include <netiso/cons.h> 8156532Sbostic 8236396Ssklower#define DRIVERTRACE TPPTdriver 8337469Ssklower#define sbwakeup(sb) sowakeup(p->tp_sock, sb); 8437469Ssklower#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0) 8536396Ssklower 8636396Ssklowerstatic trick_hc = 1; 8736396Ssklower 8836396Ssklowerint tp_emit(), 8936396Ssklower tp_goodack(), tp_goodXack(), 9036396Ssklower tp_stash() 9136396Ssklower; 9236396Ssklowervoid tp_indicate(), tp_getoptions(), 9336396Ssklower tp_soisdisconnecting(), tp_soisdisconnected(), 9436396Ssklower tp_recycle_tsuffix(), 9551252Ssklower#ifdef TP_DEBUG_TIMERS 9636396Ssklower tp_etimeout(), tp_euntimeout(), 9751252Ssklower tp_ctimeout(), tp_cuntimeout(), 9851252Ssklower tp_ctimeout_MIN(), 9951252Ssklower#endif 10036396Ssklower tp_freeref(), tp_detach(), 10136396Ssklower tp0_stash(), tp0_send(), 10236396Ssklower tp_netcmd(), tp_send() 10336396Ssklower; 10436396Ssklower 10536396Ssklowertypedef struct tp_pcb tpcb_struct; 10636396Ssklower 10736396Ssklower 10836396Ssklower} 10936396Ssklower 11036396Ssklower*PCB tpcb_struct SYNONYM P 11136396Ssklower 11236396Ssklower*STATES 11336396Ssklower 11436396SsklowerTP_CLOSED 11536396SsklowerTP_CRSENT 11636396SsklowerTP_AKWAIT 11736396SsklowerTP_OPEN 11836396SsklowerTP_CLOSING 11936396SsklowerTP_REFWAIT 12036396SsklowerTP_LISTENING /* Local to this implementation */ 12138841SsklowerTP_CONFIRMING /* Local to this implementation */ 12236396Ssklower 12336396Ssklower*EVENTS { struct timeval e_time; } SYNONYM E 12436396Ssklower 12536396Ssklower /* 12636396Ssklower * C (typically cancelled) timers - 12736396Ssklower * 12836396Ssklower * let these be the first ones so for the sake of convenience 12936396Ssklower * their values are 0--> n-1 13036396Ssklower * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!! 13136396Ssklower */ 13236396Ssklower TM_inact 13336396Ssklower TM_retrans 13436396Ssklower /* TM_retrans is used for all 13536396Ssklower * simple retransmissions - CR,CC,XPD,DR 13636396Ssklower */ 13736396Ssklower 13836396Ssklower TM_sendack 13951204Ssklower /* TM_sendack does dual duty - keepalive AND closed-window 14051204Ssklower * Probes. 14136396Ssklower * It's set w/ keepalive-ticks every time an ack is sent. 14236396Ssklower * (this is done in (void) tp_emit() ). 14351204Ssklower * Whenever a DT arrives which doesn't require immediate acking, 14451204Ssklower * a separate fast-timeout flag is set ensuring 200ms response. 14536396Ssklower */ 14636396Ssklower TM_notused 14736396Ssklower 14836396Ssklower /* 14936396Ssklower * E (typically expired) timers - these may be in any order. 15036396Ssklower * These cause procedures to be executed directly; may not 15136396Ssklower * cause an 'event' as we know them here. 15236396Ssklower */ 15336396Ssklower TM_reference { SeqNum e_low; SeqNum e_high; int e_retrans; } 15436396Ssklower TM_data_retrans { SeqNum e_low; SeqNum e_high; int e_retrans; } 15536396Ssklower 15636396Ssklower/* NOTE: in tp_input is a minor optimization that assumes that 15736396Ssklower * for all tpdu types that can take e_data and e_datalen, these 15836396Ssklower * fields fall in the same place in the event structure, that is, 15936396Ssklower * e_data is the first field and e_datalen is the 2nd field. 16036396Ssklower */ 16136396Ssklower 16236396Ssklower ER_TPDU { 16336396Ssklower u_char e_reason; 16436396Ssklower } 16536396Ssklower CR_TPDU { struct mbuf *e_data; /* first field */ 16636396Ssklower int e_datalen; /* 2nd field */ 16736396Ssklower u_int e_cdt; 16836396Ssklower } 16936396Ssklower DR_TPDU { struct mbuf *e_data; /* first field */ 17036396Ssklower int e_datalen; /* 2nd field */ 17136396Ssklower u_short e_sref; 17236396Ssklower u_char e_reason; 17336396Ssklower } 17436396Ssklower DC_TPDU 17536396Ssklower CC_TPDU { struct mbuf *e_data; /* first field */ 17636396Ssklower int e_datalen; /* 2nd field */ 17736396Ssklower u_short e_sref; 17836396Ssklower u_int e_cdt; 17936396Ssklower } 18036396Ssklower AK_TPDU { u_int e_cdt; 18136396Ssklower SeqNum e_seq; 18236396Ssklower SeqNum e_subseq; 18336396Ssklower u_char e_fcc_present; 18436396Ssklower } 18536396Ssklower DT_TPDU { struct mbuf *e_data; /* first field */ 18636396Ssklower int e_datalen; /* 2nd field */ 18736396Ssklower u_int e_eot; 18836396Ssklower SeqNum e_seq; 18936396Ssklower } 19036396Ssklower XPD_TPDU { struct mbuf *e_data; /* first field */ 19136396Ssklower int e_datalen; /* 2nd field */ 19236396Ssklower SeqNum e_seq; 19336396Ssklower } 19436396Ssklower XAK_TPDU { SeqNum e_seq; } 19536396Ssklower 19636396Ssklower T_CONN_req 19736396Ssklower T_DISC_req { u_char e_reason; } 19836396Ssklower T_LISTEN_req 19936396Ssklower T_DATA_req 20036396Ssklower T_XPD_req 20136396Ssklower T_USR_rcvd 20236396Ssklower T_USR_Xrcvd 20336396Ssklower T_DETACH 20436396Ssklower T_NETRESET 20538841Ssklower T_ACPT_req 20636396Ssklower 20736396Ssklower 20836396Ssklower*TRANSITIONS 20936396Ssklower 21036396Ssklower 21136396Ssklower/* TP_AKWAIT doesn't exist in TP 0 */ 21236396SsklowerSAME <== TP_AKWAIT [ CC_TPDU, DC_TPDU, XAK_TPDU ] 21336396Ssklower DEFAULT 21436396Ssklower NULLACTION 21536396Ssklower; 21636396Ssklower 21736396Ssklower 21836396Ssklower/* applicable in TP4, TP0 */ 21936396SsklowerSAME <== TP_REFWAIT DR_TPDU 22036396Ssklower ( $$.e_sref != 0 ) 22136396Ssklower { 22236396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 22336396Ssklower } 22436396Ssklower; 22536396Ssklower 22636396Ssklower/* applicable in TP4, TP0 */ 22736396SsklowerSAME <== TP_REFWAIT [ CR_TPDU, CC_TPDU, DT_TPDU, 22836396Ssklower DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ] 22936396Ssklower DEFAULT 23036396Ssklower { 23136396Ssklower# ifdef TP_DEBUG 23236396Ssklower if( $E.ev_number != AK_TPDU ) 23336396Ssklower printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number); 23436396Ssklower# endif TP_DEBUG 23536396Ssklower } 23636396Ssklower; 23736396Ssklower 23836396Ssklower/* applicable in TP4, TP0 */ 23936396SsklowerSAME <== TP_REFWAIT [ T_DETACH, T_DISC_req ] 24036396Ssklower DEFAULT 24136396Ssklower NULLACTION 24236396Ssklower; 24336396Ssklower 24436396Ssklower/* applicable in TP4, TP0 */ 24536396SsklowerSAME <== TP_CRSENT AK_TPDU 24636396Ssklower ($P.tp_class == TP_CLASS_0) 24736396Ssklower { 24836396Ssklower /* oh, man is this grotesque or what? */ 24936396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 25036396Ssklower /* but it's necessary because this pseudo-ack may happen 25136396Ssklower * before the CC arrives, but we HAVE to adjust the 25236396Ssklower * snduna as a result of the ack, WHENEVER it arrives 25336396Ssklower */ 25436396Ssklower } 25536396Ssklower; 25636396Ssklower 25736396Ssklower/* applicable in TP4, TP0 */ 25836396SsklowerSAME <== TP_CRSENT 25936396Ssklower [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU, XAK_TPDU ] 26036396Ssklower DEFAULT 26136396Ssklower NULLACTION 26236396Ssklower; 26336396Ssklower 26436396Ssklower/* applicable in TP4, TP0 */ 26536396SsklowerSAME <== TP_CLOSED [ DT_TPDU, XPD_TPDU, 26636396Ssklower ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 26736396Ssklower DEFAULT 26836396Ssklower NULLACTION 26936396Ssklower; 27036396Ssklower 27136396Ssklower/* TP_CLOSING doesn't exist in TP 0 */ 27236396SsklowerSAME <== TP_CLOSING 27336396Ssklower [ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ] 27436396Ssklower DEFAULT 27536396Ssklower NULLACTION 27636396Ssklower; 27736396Ssklower 27836396Ssklower 27936396Ssklower/* DC_TPDU doesn't exist in TP 0 */ 28036396SsklowerSAME <== TP_OPEN DC_TPDU 28136396Ssklower DEFAULT 28236396Ssklower NULLACTION 28336396Ssklower; 28436396Ssklower 28536396Ssklower/* applicable in TP4, TP0 */ 28636396SsklowerSAME <== TP_LISTENING [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU, 28736396Ssklower ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 28836396Ssklower DEFAULT 28936396Ssklower NULLACTION 29036396Ssklower; 29136396Ssklower 29236396Ssklower/* applicable in TP4, TP0 */ 29336396SsklowerTP_LISTENING <== TP_CLOSED T_LISTEN_req 29436396Ssklower DEFAULT 29536396Ssklower NULLACTION 29636396Ssklower; 29736396Ssklower 29836396Ssklower/* applicable in TP4, TP0 */ 29936396SsklowerTP_CLOSED <== [ TP_LISTENING, TP_CLOSED ] T_DETACH 30036396Ssklower DEFAULT 30136396Ssklower { 30236396Ssklower tp_detach($P); 30336396Ssklower } 30436396Ssklower; 30536396Ssklower 30638841SsklowerTP_CONFIRMING <== TP_LISTENING CR_TPDU 30738841Ssklower ( $P.tp_class == TP_CLASS_0) 30836396Ssklower { 30951204Ssklower $P.tp_refstate = REF_OPEN; /* has timers ??? */ 31036396Ssklower } 31136396Ssklower; 31236396Ssklower 31338841SsklowerTP_CONFIRMING <== TP_LISTENING CR_TPDU 31438841Ssklower DEFAULT 31536396Ssklower { 31636396Ssklower IFTRACE(D_CONN) 31736396Ssklower tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0); 31836396Ssklower ENDTRACE 31936396Ssklower IFDEBUG(D_CONN) 32036396Ssklower printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data); 32136396Ssklower ENDDEBUG 32251204Ssklower $P.tp_refstate = REF_OPEN; /* has timers */ 32338841Ssklower $P.tp_fcredit = $$.e_cdt; 32436396Ssklower 32536396Ssklower if ($$.e_datalen > 0) { 32636396Ssklower /* n/a for class 0 */ 32736396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); 32836396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 32936396Ssklower $$.e_data = MNULL; 33036396Ssklower } 33138841Ssklower } 33238841Ssklower; 33338841Ssklower 33438841SsklowerTP_OPEN <== TP_CONFIRMING T_ACPT_req 33538841Ssklower ( $P.tp_class == TP_CLASS_0 ) 33638841Ssklower { 33738841Ssklower IncStat(ts_tp0_conn); 33838841Ssklower IFTRACE(D_CONN) 33938841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 34038841Ssklower ENDTRACE 34138841Ssklower IFDEBUG(D_CONN) 34238841Ssklower printf("Confirming connection: $P" ); 34338841Ssklower ENDDEBUG 34438841Ssklower soisconnected($P.tp_sock); 34538841Ssklower (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ; 34638841Ssklower $P.tp_fcredit = 1; 34738841Ssklower } 34838841Ssklower; 34938841Ssklower 35038841SsklowerTP_AKWAIT <== TP_CONFIRMING T_ACPT_req 35138841Ssklower (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0) 35238841Ssklower { 35338841Ssklower IncStat(ts_tp4_conn); /* even though not quite open */ 35438841Ssklower IFTRACE(D_CONN) 35538841Ssklower tptrace(TPPTmisc, "Confiming", $P, 0,0,0); 35638841Ssklower ENDTRACE 35738841Ssklower IFDEBUG(D_CONN) 35838841Ssklower printf("Confirming connection: $P" ); 35938841Ssklower ENDDEBUG 36050973Ssklower tp_getoptions($P); 36138841Ssklower soisconnecting($P.tp_sock); 36247281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0)) 36351204Ssklower $P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize; 36436396Ssklower $P.tp_retrans = $P.tp_Nretrans; 36551204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 36638841Ssklower } 36736396Ssklower; 36836396Ssklower 36936396Ssklower/* TP4 only */ 37038841SsklowerTP_CLOSED <== TP_CONFIRMING T_ACPT_req 37136396Ssklower DEFAULT /* emit failed */ 37236396Ssklower { 37336396Ssklower IFDEBUG(D_CONN) 37436396Ssklower printf("event: CR_TPDU emit CC failed done " ); 37536396Ssklower ENDDEBUG 37638841Ssklower soisdisconnected($P.tp_sock); 37751214Ssklower tp_recycle_tsuffix($P); 37851214Ssklower tp_freeref($P.tp_lref); 37936396Ssklower tp_detach($P); 38036396Ssklower } 38136396Ssklower; 38236396Ssklower 38336396Ssklower/* applicable in TP4, TP0 */ 38436396SsklowerTP_CRSENT <== TP_CLOSED T_CONN_req 38536396Ssklower DEFAULT 38636396Ssklower { 38736396Ssklower int error; 38836396Ssklower struct mbuf *data = MNULL; 38936396Ssklower 39036396Ssklower IFTRACE(D_CONN) 39137469Ssklower tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags, 39237469Ssklower $P.tp_ucddata, 0, 0); 39336396Ssklower ENDTRACE 39437469Ssklower data = MCPY($P.tp_ucddata, M_WAIT); 39537469Ssklower if (data) { 39636396Ssklower IFDEBUG(D_CONN) 39736396Ssklower printf("T_CONN_req.trans m_copy cc 0x%x\n", 39837469Ssklower $P.tp_ucddata); 39937469Ssklower dump_mbuf(data, "sosnd @ T_CONN_req"); 40036396Ssklower ENDDEBUG 40136396Ssklower } 40236396Ssklower 40336396Ssklower if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) 40436396Ssklower return error; /* driver WON'T change state; will return error */ 40536396Ssklower 40651204Ssklower $P.tp_refstate = REF_OPEN; /* has timers */ 40736396Ssklower if($P.tp_class != TP_CLASS_0) { 40836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 40951204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks); 41036396Ssklower } 41136396Ssklower } 41236396Ssklower; 41336396Ssklower 41436396Ssklower/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */ 41536396SsklowerTP_REFWAIT <== [ TP_CRSENT, TP_AKWAIT, TP_OPEN ] DR_TPDU 41636396Ssklower DEFAULT 41736396Ssklower { 41848739Ssklower sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */ 41948739Ssklower if ($$.e_datalen > 0) { 42036396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 42136396Ssklower $$.e_data = MNULL; 42236396Ssklower } 42351208Ssklower if ($P.tp_state == TP_OPEN) 42451208Ssklower tp_indicate(T_DISCONNECT, $P, 0); 42551208Ssklower else { 42651208Ssklower int so_error = ECONNREFUSED; 42751208Ssklower if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) && 42851208Ssklower $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) && 42951208Ssklower $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK)) 43051208Ssklower so_error = ECONNABORTED; 43151208Ssklower tp_indicate(T_DISCONNECT, $P, so_error); 43251208Ssklower } 43336396Ssklower tp_soisdisconnected($P); 43436396Ssklower if ($P.tp_class != TP_CLASS_0) { 43536396Ssklower if ($P.tp_state == TP_OPEN ) { 43651204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 43751204Ssklower tp_cuntimeout($P, TM_retrans); 43851204Ssklower tp_cuntimeout($P, TM_inact); 43951204Ssklower tp_cuntimeout($P, TM_sendack); 44053683Ssklower $P.tp_flags &= ~TPF_DELACK; 44136396Ssklower } 44251204Ssklower tp_cuntimeout($P, TM_retrans); 44336396Ssklower if( $$.e_sref != 0 ) 44436396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 44536396Ssklower } 44636396Ssklower } 44736396Ssklower; 44836396Ssklower 44936396SsklowerSAME <== TP_CLOSED DR_TPDU 45036396Ssklower DEFAULT 45136396Ssklower { 45236396Ssklower if( $$.e_sref != 0 ) 45336396Ssklower (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 45436396Ssklower /* reference timer already set - reset it to be safe (???) */ 45551204Ssklower tp_euntimeout($P, TM_reference); /* all */ 45651204Ssklower tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks); 45736396Ssklower } 45836396Ssklower; 45936396Ssklower 46036396Ssklower/* NBS(34) */ 46136396SsklowerTP_REFWAIT <== TP_CRSENT ER_TPDU 46236396Ssklower DEFAULT 46336396Ssklower { 46451204Ssklower tp_cuntimeout($P, TM_retrans); 46548739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 46636396Ssklower tp_soisdisconnected($P); 46736396Ssklower } 46836396Ssklower; 46936396Ssklower 47036396Ssklower/* NBS(27) */ 47136396SsklowerTP_REFWAIT <== TP_CLOSING DR_TPDU 47236396Ssklower DEFAULT 47336396Ssklower { 47451204Ssklower tp_cuntimeout($P, TM_retrans); 47536396Ssklower tp_soisdisconnected($P); 47636396Ssklower } 47736396Ssklower; 47836396Ssklower/* these two transitions are the same but can't be combined because xebec 47936396Ssklower * can't handle the use of $$.e_reason if they're combined 48036396Ssklower */ 48136396Ssklower/* NBS(27) */ 48236396SsklowerTP_REFWAIT <== TP_CLOSING ER_TPDU 48336396Ssklower DEFAULT 48436396Ssklower { 48548739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 48651204Ssklower tp_cuntimeout($P, TM_retrans); 48736396Ssklower tp_soisdisconnected($P); 48836396Ssklower } 48936396Ssklower; 49036396Ssklower/* NBS(27) */ 49136396SsklowerTP_REFWAIT <== TP_CLOSING DC_TPDU 49236396Ssklower DEFAULT 49336396Ssklower { 49451204Ssklower tp_cuntimeout($P, TM_retrans); 49536396Ssklower tp_soisdisconnected($P); 49636396Ssklower } 49736396Ssklower; 49836396Ssklower 49936396Ssklower/* NBS(21) */ 50036396SsklowerSAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ] 50136396Ssklower DEFAULT 50236396Ssklower { /* don't ask me why we have to do this - spec says so */ 50336396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL); 50436396Ssklower /* don't bother with retransmissions of the DR */ 50536396Ssklower } 50636396Ssklower; 50736396Ssklower 50836396Ssklower/* NBS(34) */ 50936396SsklowerTP_REFWAIT <== TP_OPEN ER_TPDU 51036396Ssklower ($P.tp_class == TP_CLASS_0) 51136396Ssklower { 51236396Ssklower tp_soisdisconnecting($P.tp_sock); 51348739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 51436396Ssklower tp_soisdisconnected($P); 51536396Ssklower tp_netcmd( $P, CONN_CLOSE ); 51636396Ssklower } 51736396Ssklower; 51836396Ssklower 51936396SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU 52036396Ssklower DEFAULT 52136396Ssklower { 52236396Ssklower if ($P.tp_state == TP_OPEN) { 52351204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 52451204Ssklower tp_cuntimeout($P, TM_inact); 52551204Ssklower tp_cuntimeout($P, TM_sendack); 52636396Ssklower } 52736396Ssklower tp_soisdisconnecting($P.tp_sock); 52848739Ssklower tp_indicate(ER_TPDU, $P, $$.e_reason); 52936396Ssklower $P.tp_retrans = $P.tp_Nretrans; 53051204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 53136396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL); 53236396Ssklower } 53336396Ssklower; 53436396Ssklower/* NBS(6) */ 53536396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 53636396Ssklower ($P.tp_class == TP_CLASS_0) 53736396Ssklower { 53851204Ssklower tp_cuntimeout($P, TM_retrans); 53936396Ssklower IncStat(ts_tp0_conn); 54036396Ssklower $P.tp_fcredit = 1; 54136396Ssklower soisconnected($P.tp_sock); 54236396Ssklower } 54336396Ssklower; 54436396Ssklower 54536396SsklowerTP_OPEN <== TP_CRSENT CC_TPDU 54636396Ssklower DEFAULT 54736396Ssklower { 54836396Ssklower IFDEBUG(D_CONN) 54936396Ssklower printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", 55036396Ssklower (int)$P.tp_flags); 55136396Ssklower ENDDEBUG 55236396Ssklower IncStat(ts_tp4_conn); 55336396Ssklower $P.tp_fref = $$.e_sref; 55436396Ssklower $P.tp_fcredit = $$.e_cdt; 55547281Ssklower if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0)) 55651204Ssklower $P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize; 55736396Ssklower tp_getoptions($P); 55851204Ssklower tp_cuntimeout($P, TM_retrans); 55937469Ssklower if ($P.tp_ucddata) { 56036396Ssklower IFDEBUG(D_CONN) 56137469Ssklower printf("dropping user connect data cc 0x%x\n", 56237469Ssklower $P.tp_ucddata->m_len); 56336396Ssklower ENDDEBUG 56437469Ssklower m_freem($P.tp_ucddata); 56537469Ssklower $P.tp_ucddata = 0; 56636396Ssklower } 56736396Ssklower soisconnected($P.tp_sock); 56836396Ssklower if ($$.e_datalen > 0) { 56936396Ssklower ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */ 57036396Ssklower sbappendrecord(&$P.tp_Xrcv, $$.e_data); 57136396Ssklower $$.e_data = MNULL; 57236396Ssklower } 57336396Ssklower 57436396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 57551204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 57636396Ssklower } 57736396Ssklower; 57836396Ssklower 57936396Ssklower/* TP4 only */ 58036396SsklowerSAME <== TP_CRSENT TM_retrans 58136396Ssklower ( $P.tp_retrans > 0 ) 58236396Ssklower { 58336396Ssklower struct mbuf *data = MNULL; 58436396Ssklower int error; 58536396Ssklower 58636396Ssklower IncStat(ts_retrans_cr); 58751204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 58837469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 58937469Ssklower if($P.tp_ucddata) { 59036396Ssklower IFDEBUG(D_CONN) 59137469Ssklower printf("TM_retrans.trans m_copy cc 0x%x\n", data); 59237469Ssklower dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans"); 59336396Ssklower ENDDEBUG 59436396Ssklower if( data == MNULL ) 59536396Ssklower return ENOBUFS; 59636396Ssklower } 59736396Ssklower 59836396Ssklower $P.tp_retrans --; 59936396Ssklower if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) { 60036396Ssklower $P.tp_sock->so_error = error; 60136396Ssklower } 60251204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks); 60336396Ssklower } 60436396Ssklower; 60536396Ssklower 60636396Ssklower/* TP4 only */ 60736396SsklowerTP_REFWAIT <== TP_CRSENT TM_retrans 60836396Ssklower DEFAULT /* no more CR retransmissions */ 60936396Ssklower { 61036396Ssklower IncStat(ts_conn_gaveup); 61136396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 61236396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 61336396Ssklower tp_soisdisconnected($P); 61436396Ssklower } 61536396Ssklower; 61636396Ssklower 61736396Ssklower/* TP4 only */ 61836396SsklowerSAME <== TP_AKWAIT CR_TPDU 61936396Ssklower DEFAULT 62036396Ssklower /* duplicate CR (which doesn't really exist in the context of 62136396Ssklower * a connectionless network layer) 62236396Ssklower * Doesn't occur in class 0. 62336396Ssklower */ 62436396Ssklower { 62536396Ssklower int error; 62637469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 62736396Ssklower 62837469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) { 62936396Ssklower $P.tp_sock->so_error = error; 63036396Ssklower } 63136396Ssklower $P.tp_retrans = $P.tp_Nretrans; 63251204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 63336396Ssklower } 63436396Ssklower; 63536396Ssklower 63636396Ssklower/* TP4 only */ 63736396SsklowerTP_OPEN <== TP_AKWAIT DT_TPDU 63836396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 63936396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 64036396Ssklower { 64136396Ssklower int doack; 64236396Ssklower 64337469Ssklower /* 64437469Ssklower * Get rid of any confirm or connect data, so that if we 64537469Ssklower * crash or close, it isn't thought of as disconnect data. 64637469Ssklower */ 64737469Ssklower if ($P.tp_ucddata) { 64837469Ssklower m_freem($P.tp_ucddata); 64937469Ssklower $P.tp_ucddata = 0; 65036396Ssklower } 65151204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 65251204Ssklower tp_cuntimeout($P, TM_retrans); 65336396Ssklower soisconnected($P.tp_sock); 65451204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 65536396Ssklower 65636396Ssklower /* see also next 2 transitions, if you make any changes */ 65736396Ssklower 65836396Ssklower doack = tp_stash($P, $E); 65936396Ssklower IFDEBUG(D_DATA) 66036396Ssklower printf("tp_stash returns %d\n",doack); 66136396Ssklower ENDDEBUG 66236396Ssklower 66351204Ssklower if (doack) { 66436396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 66551204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 66636396Ssklower } else 66751204Ssklower tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks); 66836396Ssklower 66936396Ssklower IFDEBUG(D_DATA) 67036396Ssklower printf("after stash calling sbwakeup\n"); 67136396Ssklower ENDDEBUG 67236396Ssklower } 67336396Ssklower; 67436396Ssklower 67536396SsklowerSAME <== TP_OPEN DT_TPDU 67636396Ssklower ( $P.tp_class == TP_CLASS_0 ) 67736396Ssklower { 67836396Ssklower tp0_stash($P, $E); 67936396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 68036396Ssklower 68136396Ssklower IFDEBUG(D_DATA) 68236396Ssklower printf("after stash calling sbwakeup\n"); 68336396Ssklower ENDDEBUG 68436396Ssklower } 68536396Ssklower; 68636396Ssklower 68736396Ssklower/* TP4 only */ 68836396SsklowerSAME <== TP_OPEN DT_TPDU 68936396Ssklower ( IN_RWINDOW( $P, $$.e_seq, 69036396Ssklower $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) 69136396Ssklower { 69236396Ssklower int doack; /* tells if we must ack immediately */ 69336396Ssklower 69451204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 69536396Ssklower sbwakeup( &$P.tp_sock->so_rcv ); 69636396Ssklower 69736396Ssklower doack = tp_stash($P, $E); 69836396Ssklower IFDEBUG(D_DATA) 69936396Ssklower printf("tp_stash returns %d\n",doack); 70036396Ssklower ENDDEBUG 70136396Ssklower 70236396Ssklower if(doack) 70336396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 70436396Ssklower else 70551204Ssklower tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks); 70636396Ssklower 70736396Ssklower IFDEBUG(D_DATA) 70836396Ssklower printf("after stash calling sbwakeup\n"); 70936396Ssklower ENDDEBUG 71036396Ssklower } 71136396Ssklower; 71236396Ssklower 71336396Ssklower/* Not in window - we must ack under certain circumstances, namely 71436396Ssklower * a) if the seq number is below lwe but > lwe - (max credit ever given) 71536396Ssklower * (to handle lost acks) Can use max-possible-credit for this ^^^. 71636396Ssklower * and 71736396Ssklower * b) seq number is > uwe but < uwe + previously sent & withdrawn credit 71836396Ssklower * 71936396Ssklower * (see 12.2.3.8.1 of ISO spec, p. 73) 72036396Ssklower * We just always ack. 72136396Ssklower */ 72236396Ssklower/* TP4 only */ 72336396SsklowerSAME <== [ TP_OPEN, TP_AKWAIT ] DT_TPDU 72436396Ssklower DEFAULT /* Not in window */ 72536396Ssklower { 72636396Ssklower IFTRACE(D_DATA) 72736396Ssklower tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", 72836396Ssklower $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0); 72936396Ssklower ENDTRACE 73036396Ssklower IncStat(ts_dt_niw); 73136396Ssklower m_freem($$.e_data); 73251204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 73336396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 73436396Ssklower } 73536396Ssklower; 73636396Ssklower 73736396Ssklower/* TP4 only */ 73836396SsklowerTP_OPEN <== TP_AKWAIT AK_TPDU 73936396Ssklower DEFAULT 74036396Ssklower { 74137469Ssklower if ($P.tp_ucddata) { 74237469Ssklower m_freem($P.tp_ucddata); 74337469Ssklower $P.tp_ucddata = 0; 74436396Ssklower } 74536396Ssklower (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); 74651204Ssklower tp_cuntimeout($P, TM_retrans); 74736396Ssklower 74836396Ssklower soisconnected($P.tp_sock); 74936396Ssklower IFTRACE(D_CONN) 75036396Ssklower struct socket *so = $P.tp_sock; 75136396Ssklower tptrace(TPPTmisc, 75236396Ssklower "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", 75336396Ssklower so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); 75436396Ssklower tptrace(TPPTmisc, 75536396Ssklower "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", 75636396Ssklower so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); 75736396Ssklower ENDTRACE 75836396Ssklower 75951204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 76051204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 76136396Ssklower } 76236396Ssklower; 76336396Ssklower 76436396Ssklower/* TP4 only */ 76536396SsklowerTP_OPEN <== [ TP_OPEN, TP_AKWAIT ] XPD_TPDU 76647281Ssklower ($P.tp_Xrcvnxt == $$.e_seq) 76736396Ssklower { 76836396Ssklower if( $P.tp_state == TP_AKWAIT ) { 76937469Ssklower if ($P.tp_ucddata) { 77037469Ssklower m_freem($P.tp_ucddata); 77137469Ssklower $P.tp_ucddata = 0; 77236396Ssklower } 77351204Ssklower tp_cuntimeout($P, TM_retrans); 77436396Ssklower soisconnected($P.tp_sock); 77551204Ssklower tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); 77651204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 77736396Ssklower } 77836396Ssklower IFTRACE(D_XPD) 77936396Ssklower tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", 78036396Ssklower $P.tp_Xrcvnxt,$$.e_seq, $$.e_datalen, $$.e_data->m_len); 78136396Ssklower ENDTRACE 78236396Ssklower 78337469Ssklower $P.tp_sock->so_state |= SS_RCVATMARK; 78447281Ssklower $$.e_data->m_flags |= M_EOR; 78537469Ssklower sbinsertoob(&$P.tp_Xrcv, $$.e_data); 78636396Ssklower IFDEBUG(D_XPD) 78736396Ssklower dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv"); 78836396Ssklower ENDDEBUG 78936396Ssklower tp_indicate(T_XDATA, $P, 0); 79036396Ssklower sbwakeup( &$P.tp_Xrcv ); 79136396Ssklower 79236396Ssklower (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 79336396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 79436396Ssklower } 79536396Ssklower; 79636396Ssklower 79736396Ssklower/* TP4 only */ 79836396SsklowerSAME <== TP_OPEN T_USR_Xrcvd 79936396Ssklower DEFAULT 80036396Ssklower { 80136396Ssklower if( $P.tp_Xrcv.sb_cc == 0 ) { 80236396Ssklower /* kludge for select(): */ 80337469Ssklower /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */ 80436396Ssklower } 80536396Ssklower } 80636396Ssklower /* OLD WAY: 80736396Ssklower * Ack only after the user receives the XPD. This is better for 80836396Ssklower * users that use one XPD right after another. 80936396Ssklower * Acking right away (the NEW WAY, see the prev. transition) is 81036396Ssklower * better for occasional * XPD, when the receiving user doesn't 81136396Ssklower * want to read the XPD immediately (which is session's behavior). 81236396Ssklower * 81336396Ssklower int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); 81436396Ssklower SEQ_INC($P, $P.tp_Xrcvnxt); 81536396Ssklower return error; 81636396Ssklower */ 81736396Ssklower; 81836396Ssklower 81936396Ssklower/* NOTE: presently if the user doesn't read the connection data 82036396Ssklower * before and expedited data PDU comes in, the connection data will 82136396Ssklower * be dropped. This is a bug. To avoid it, we need somewhere else 82236396Ssklower * to put the connection data. 82336396Ssklower * On the other hand, we need not to have it sitting around forever. 82436396Ssklower * This is a problem with the idea of trying to accommodate 82536396Ssklower * data on connect w/ a passive-open user interface. 82636396Ssklower */ 82736396Ssklower/* TP4 only */ 82836396Ssklower 82936396SsklowerSAME <== [ TP_AKWAIT, TP_OPEN ] XPD_TPDU 83036396Ssklower DEFAULT /* not in window or cdt==0 */ 83136396Ssklower { 83236396Ssklower IFTRACE(D_XPD) 83336396Ssklower tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", 83436396Ssklower $P.tp_Xrcvnxt, $$.e_seq, $P.tp_Xrcv.sb_cc , 0); 83536396Ssklower ENDTRACE 83636396Ssklower if( $P.tp_Xrcvnxt != $$.e_seq ) 83736396Ssklower IncStat(ts_xpd_niw); 83836396Ssklower if( $P.tp_Xrcv.sb_cc ) { 83936396Ssklower /* might as well kick 'em again */ 84036396Ssklower tp_indicate(T_XDATA, $P, 0); 84136396Ssklower IncStat(ts_xpd_dup); 84236396Ssklower } 84336396Ssklower m_freem($$.e_data); 84451204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 84536396Ssklower /* don't send an xack because the xak gives "last one received", not 84636396Ssklower * "next one i expect" (dumb) 84736396Ssklower */ 84836396Ssklower } 84936396Ssklower; 85036396Ssklower 85136396Ssklower/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries 85236396Ssklower * to detach all its "children" 85336396Ssklower * Also (CRSENT) when user kills a job that's doing a connect() 85436396Ssklower */ 85536396SsklowerTP_REFWAIT <== TP_CRSENT T_DETACH 85636396Ssklower ($P.tp_class == TP_CLASS_0) 85736396Ssklower { 85836396Ssklower struct socket *so = $P.tp_sock; 85936396Ssklower 86036396Ssklower /* detach from parent socket so it can finish closing */ 86136396Ssklower if (so->so_head) { 86236396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 86336396Ssklower panic("tp: T_DETACH"); 86436396Ssklower so->so_head = 0; 86536396Ssklower } 86636396Ssklower tp_soisdisconnecting($P.tp_sock); 86736396Ssklower tp_netcmd( $P, CONN_CLOSE); 86836396Ssklower tp_soisdisconnected($P); 86936396Ssklower } 87036396Ssklower; 87136396Ssklower 87236396Ssklower/* TP4 only */ 87338841SsklowerTP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH 87436396Ssklower DEFAULT 87536396Ssklower { 87636396Ssklower struct socket *so = $P.tp_sock; 87737469Ssklower struct mbuf *data = MNULL; 87836396Ssklower 87936396Ssklower /* detach from parent socket so it can finish closing */ 88036396Ssklower if (so->so_head) { 88136396Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 88236396Ssklower panic("tp: T_DETACH"); 88336396Ssklower so->so_head = 0; 88436396Ssklower } 88536396Ssklower if ($P.tp_state != TP_CLOSING) { 88636396Ssklower tp_soisdisconnecting($P.tp_sock); 88737469Ssklower data = MCPY($P.tp_ucddata, M_NOWAIT); 88837469Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data); 88936396Ssklower $P.tp_retrans = $P.tp_Nretrans; 89051204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 89136396Ssklower } 89236396Ssklower } 89336396Ssklower; 89436396Ssklower 89536396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req 89636396Ssklower ( $P.tp_class == TP_CLASS_0 ) 89736396Ssklower { 89836396Ssklower tp_soisdisconnecting($P.tp_sock); 89936396Ssklower tp_netcmd( $P, CONN_CLOSE); 90036396Ssklower tp_soisdisconnected($P); 90136396Ssklower } 90236396Ssklower; 90336396Ssklower 90436396Ssklower/* TP4 only */ 90538841SsklowerTP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req 90636396Ssklower DEFAULT 90736396Ssklower { 90837469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 90936396Ssklower 91036396Ssklower if($P.tp_state == TP_OPEN) { 91151204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 91251204Ssklower tp_cuntimeout($P, TM_inact); 91351204Ssklower tp_cuntimeout($P, TM_sendack); 91453683Ssklower $P.tp_flags &= ~TPF_DELACK; 91536396Ssklower } 91637469Ssklower if (data) { 91736396Ssklower IFDEBUG(D_CONN) 91837469Ssklower printf("T_DISC_req.trans tp_ucddata 0x%x\n", 91937469Ssklower $P.tp_ucddata); 92037469Ssklower dump_mbuf(data, "ucddata @ T_DISC_req"); 92136396Ssklower ENDDEBUG 92236396Ssklower } 92336396Ssklower tp_soisdisconnecting($P.tp_sock); 92436396Ssklower $P.tp_retrans = $P.tp_Nretrans; 92551204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 92636396Ssklower 92736396Ssklower if( trick_hc ) 92836396Ssklower return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data); 92936396Ssklower } 93036396Ssklower; 93136396Ssklower 93236396Ssklower/* TP4 only */ 93336396SsklowerSAME <== TP_AKWAIT TM_retrans 93436396Ssklower ( $P.tp_retrans > 0 ) 93536396Ssklower { 93636396Ssklower int error; 93737469Ssklower struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); 93836396Ssklower 93936396Ssklower IncStat(ts_retrans_cc); 94036396Ssklower $P.tp_retrans --; 94151204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 94239921Ssklower 94337469Ssklower if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) 94436396Ssklower $P.tp_sock->so_error = error; 94551204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); 94636396Ssklower } 94736396Ssklower; 94836396Ssklower 94936396Ssklower/* TP4 only */ 95036396SsklowerTP_CLOSING <== TP_AKWAIT TM_retrans 95136396Ssklower DEFAULT /* out of time */ 95236396Ssklower { 95336396Ssklower IncStat(ts_conn_gaveup); 95436396Ssklower tp_soisdisconnecting($P.tp_sock); 95536396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 95636396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 95736396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL); 95836396Ssklower $P.tp_retrans = $P.tp_Nretrans; 95951204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 96036396Ssklower } 96136396Ssklower; 96236396Ssklower 96336396Ssklower/* the retrans timers had better go off BEFORE the inactivity timer does, 96436396Ssklower * if transmissions are going on. 96536396Ssklower * (i.e., TM_inact should be greater than timer for all retrans plus ack 96636396Ssklower * turnaround) 96736396Ssklower */ 96836396Ssklower/* TP4 only */ 96936396SsklowerTP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ] 97036396Ssklower DEFAULT 97136396Ssklower { 97251204Ssklower tp_euntimeout($P, TM_data_retrans); /* all */ 97351204Ssklower tp_cuntimeout($P, TM_inact); 97451204Ssklower tp_cuntimeout($P, TM_sendack); 97536396Ssklower 97636396Ssklower IncStat(ts_conn_gaveup); 97736396Ssklower tp_soisdisconnecting($P.tp_sock); 97836396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 97936396Ssklower tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); 98036396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL); 98136396Ssklower $P.tp_retrans = $P.tp_Nretrans; 98251204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 98336396Ssklower } 98436396Ssklower; 98536396Ssklower 98636396Ssklower/* TP4 only */ 98736396SsklowerSAME <== TP_OPEN TM_retrans 98836396Ssklower ( $P.tp_retrans > 0 ) 98936396Ssklower { 99051204Ssklower $P.tp_cong_win = 1 * $P.tp_l_tpdusize; 99136396Ssklower /* resume XPD */ 99236396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 99337469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 99451204Ssklower int shift; 99536396Ssklower 99636396Ssklower IFTRACE(D_XPD) 99751204Ssklower tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna", 99851204Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 99936396Ssklower $P.tp_snduna); 100036396Ssklower ENDTRACE 100136396Ssklower IFDEBUG(D_XPD) 100236396Ssklower dump_mbuf(m, "XPD retrans emitting M"); 100336396Ssklower ENDDEBUG 100436396Ssklower IncStat(ts_retrans_xpd); 100536396Ssklower $P.tp_retrans --; 100651204Ssklower shift = max($P.tp_Nretrans - $P.tp_retrans, 6); 100736396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 100851204Ssklower tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift); 100936396Ssklower } 101036396Ssklower } 101136396Ssklower; 101236396Ssklower 101336396Ssklower/* TP4 only */ 101436396SsklowerSAME <== TP_OPEN TM_data_retrans 101551204Ssklower ($P.tp_rxtshift < TP_NRETRANS) 101636396Ssklower { 101751204Ssklower $P.tp_rxtshift++; 101851204Ssklower (void) tp_data_retrans($P); 101936396Ssklower } 102036396Ssklower; 102136396Ssklower 102236396Ssklower/* TP4 only */ 102336396SsklowerSAME <== TP_CLOSING TM_retrans 102436396Ssklower ( $P.tp_retrans > 0 ) 102536396Ssklower { 102636396Ssklower $P.tp_retrans --; 102736396Ssklower (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL); 102836396Ssklower IncStat(ts_retrans_dr); 102951204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); 103036396Ssklower } 103136396Ssklower; 103236396Ssklower 103336396Ssklower/* TP4 only */ 103436396SsklowerTP_REFWAIT <== TP_CLOSING TM_retrans 103536396Ssklower DEFAULT /* no more retrans - gave up */ 103636396Ssklower { 103736396Ssklower $P.tp_sock->so_error = ETIMEDOUT; 103851204Ssklower $P.tp_refstate = REF_FROZEN; 103936396Ssklower tp_recycle_tsuffix( $P ); 104051204Ssklower tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks); 104136396Ssklower } 104236396Ssklower; 104336396Ssklower 104436396Ssklower/* 104536396Ssklower * The resources are kept around until the ref timer goes off. 104636396Ssklower * The suffices are wiped out sooner so they can be reused right away. 104736396Ssklower */ 104836396Ssklower/* applicable in TP4, TP0 */ 104936396SsklowerTP_CLOSED <== TP_REFWAIT TM_reference 105036396Ssklower DEFAULT 105136396Ssklower { 105251214Ssklower tp_freeref($P.tp_lref); 105336396Ssklower tp_detach($P); 105436396Ssklower } 105536396Ssklower; 105636396Ssklower 105736396Ssklower/* applicable in TP4, TP0 */ 105836396Ssklower/* A duplicate CR from connectionless network layer can't happen */ 105936396SsklowerSAME <== TP_OPEN [ CR_TPDU, CC_TPDU ] 106036396Ssklower DEFAULT 106136396Ssklower { 106236396Ssklower if( $P.tp_class != TP_CLASS_0) { 106351204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 106436396Ssklower if ( $E.ev_number == CC_TPDU ) 106536396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 106636396Ssklower } 106736396Ssklower /* ignore it if class 0 - state tables are blank for this */ 106836396Ssklower } 106936396Ssklower; 107036396Ssklower 107136396Ssklower/* applicable in TP4, TP0 */ 107236396SsklowerSAME <== TP_OPEN T_DATA_req 107336396Ssklower DEFAULT 107436396Ssklower { 107536396Ssklower IFTRACE(D_DATA) 107651204Ssklower tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb", 107751204Ssklower $P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P); 107836396Ssklower ENDTRACE 107936396Ssklower 108036396Ssklower tp_send($P); 108136396Ssklower } 108236396Ssklower; 108336396Ssklower 108436396Ssklower/* TP4 only */ 108536396SsklowerSAME <== TP_OPEN T_XPD_req 108636396Ssklower DEFAULT 108736396Ssklower /* T_XPD_req was issued by sosend iff xpd socket buf was empty 108836396Ssklower * at time of sosend(), 108936396Ssklower * AND (which means) there were no unacknowledged XPD tpdus outstanding! 109036396Ssklower */ 109136396Ssklower { 109236396Ssklower int error = 0; 109336396Ssklower 109436396Ssklower /* resume XPD */ 109536396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 109637469Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); 109736396Ssklower /* m_copy doesn't preserve the m_xlink field, but at this pt. 109836396Ssklower * that doesn't matter 109936396Ssklower */ 110036396Ssklower 110136396Ssklower IFTRACE(D_XPD) 110251204Ssklower tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna", 110351204Ssklower $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 110436396Ssklower $P.tp_snduna); 110536396Ssklower ENDTRACE 110636396Ssklower IFDEBUG(D_XPD) 110736396Ssklower printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc); 110836396Ssklower dump_mbuf(m, "XPD req emitting M"); 110936396Ssklower ENDDEBUG 111036396Ssklower error = 111136396Ssklower tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 111236396Ssklower $P.tp_retrans = $P.tp_Nretrans; 111351204Ssklower 111451204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur); 111536396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 111636396Ssklower } 111736396Ssklower if(trick_hc) 111836396Ssklower return error; 111936396Ssklower } 112036396Ssklower; 112136396Ssklower 112236396Ssklower/* TP4, faked ack in TP0 when cons send completes */ 112336396SsklowerSAME <== TP_OPEN AK_TPDU 112436396Ssklower ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) ) 112536396Ssklower 112636396Ssklower /* tp_goodack == true means 112736396Ssklower * EITHER it actually acked something heretofore unacknowledged 112836396Ssklower * OR no news but the credit should be processed. 112936396Ssklower */ 113036396Ssklower { 113150904Ssklower struct sockbuf *sb = &$P.tp_sock->so_snd; 113250904Ssklower 113336396Ssklower IFDEBUG(D_ACKRECV) 113436396Ssklower printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt); 113536396Ssklower ENDDEBUG 113636396Ssklower if( $P.tp_class != TP_CLASS_0) { 113751204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 113836396Ssklower } 113950904Ssklower sbwakeup(sb); 114036396Ssklower IFDEBUG(D_ACKRECV) 114151204Ssklower printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt); 114236396Ssklower ENDDEBUG 114336396Ssklower } 114436396Ssklower; 114536396Ssklower 114636396Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 114736396SsklowerSAME <== TP_OPEN AK_TPDU 114836396Ssklower DEFAULT 114936396Ssklower { 115036396Ssklower IFTRACE(D_ACKRECV) 115136396Ssklower tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", 115236396Ssklower $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0); 115336396Ssklower ENDTRACE 115436396Ssklower if( $P.tp_class != TP_CLASS_0 ) { 115536396Ssklower 115636396Ssklower if ( !$$.e_fcc_present ) { 115736396Ssklower /* send ACK with FCC */ 115836396Ssklower IncStat( ts_ackreason[_ACK_FCC_] ); 115936396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL); 116036396Ssklower } 116151204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 116236396Ssklower } 116336396Ssklower } 116436396Ssklower; 116536396Ssklower 116636396Ssklower/* NBS(47) */ 116736396Ssklower /* goes in at *** */ 116836396Ssklower /* just so happens that this is never true now, because we allow 116936396Ssklower * only 1 packet in the queue at once (this could be changed) 117036396Ssklower if ( $P.tp_Xsnd.sb_mb ) { 117136396Ssklower struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??); 117236396Ssklower 117336396Ssklower (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); 117436396Ssklower $P.tp_retrans = $P.tp_Nretrans; 117551204Ssklower tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks); 117636396Ssklower SEQ_INC($P, $P.tp_Xsndnxt); 117736396Ssklower } 117836396Ssklower */ 117936396Ssklower /* end of the above hack */ 118036396Ssklower 118136396Ssklower/* TP4 only */ 118242944SsklowerSAME <== TP_OPEN XAK_TPDU 118336396Ssklower ( tp_goodXack($P, $$.e_seq) ) 118436396Ssklower /* tp_goodXack checks for good ack, removes the correct 118536396Ssklower * tpdu from the queue and returns 1 if ack was legit, 0 if not. 118636396Ssklower * also updates tp_Xuna 118736396Ssklower */ 118836396Ssklower { 118951204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 119051204Ssklower tp_cuntimeout($P, TM_retrans); 119136396Ssklower 119236396Ssklower sbwakeup( &$P.tp_sock->so_snd ); 119336396Ssklower 119436396Ssklower /* resume normal data */ 119536396Ssklower tp_send($P); 119636396Ssklower } 119736396Ssklower; 119836396Ssklower 119942944Ssklower/* TP4, and TP0 after sending a CC or possibly a CR */ 120042944SsklowerSAME <== TP_OPEN XAK_TPDU 120142944Ssklower DEFAULT 120242944Ssklower { 120342944Ssklower IFTRACE(D_ACKRECV) 120442944Ssklower tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0); 120542944Ssklower ENDTRACE 120642944Ssklower if( $P.tp_class != TP_CLASS_0 ) { 120751204Ssklower tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); 120842944Ssklower } 120942944Ssklower } 121042944Ssklower; 121142944Ssklower 121236396Ssklower/* TP4 only */ 121336396SsklowerSAME <== TP_OPEN TM_sendack 121436396Ssklower DEFAULT 121536396Ssklower { 121651204Ssklower int timo; 121736396Ssklower IFTRACE(D_TIMER) 121836396Ssklower tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 121936396Ssklower $P.tp_sent_lcdt, 0); 122036396Ssklower ENDTRACE 122136396Ssklower IncPStat($P, tps_n_TMsendack); 122236396Ssklower (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 122351248Ssklower if ($P.tp_fcredit == 0) { 122451248Ssklower if ($P.tp_rxtshift < TP_MAXRXTSHIFT) 122551248Ssklower $P.tp_rxtshift++; 122651248Ssklower timo = ($P.tp_dt_ticks) << $P.tp_rxtshift; 122751248Ssklower } else 122851248Ssklower timo = $P.tp_sendack_ticks; 122951248Ssklower tp_ctimeout($P, TM_sendack, timo); 123036396Ssklower } 123136396Ssklower; 123236396Ssklower 123336396Ssklower/* TP0 only */ 123436396SsklowerSAME <== TP_OPEN T_USR_rcvd 123536396Ssklower ($P.tp_class == TP_CLASS_0) 123647281Ssklower { 123747281Ssklower if (sbspace(&$P.tp_sock->so_rcv) > 0) 123847281Ssklower tp0_openflow($P); 123947281Ssklower } 124036396Ssklower; 124136396Ssklower 124236396Ssklower/* TP4 only */ 124336396Ssklower /* If old credit was zero, 124436396Ssklower * we'd better inform other side that we now have space 124536396Ssklower * But this is not enough. Sender might not yet have 124636396Ssklower * seen an ack with cdt 0 but it might still think the 124736396Ssklower * window is closed, so it's going to wait. 124836396Ssklower * Best to send an ack each time. 124936396Ssklower * Strictly speaking, this ought to be a function of the 125036396Ssklower * general ack strategy. 125136396Ssklower */ 125236396SsklowerSAME <== TP_OPEN T_USR_rcvd 125336396Ssklower DEFAULT 125436396Ssklower { 125536396Ssklower if( trick_hc ) { 125651024Ssklower SeqNum ack_thresh; 125750849Ssklower /* 125851024Ssklower * If the upper window edge has advanced a reasonable 125951024Ssklower * amount beyond what was known, send an ACK. 126051024Ssklower * A reasonable amount is 2 packets, unless the max window 126151024Ssklower * is only 1 or 2 packets, in which case we 126251024Ssklower * should send an ack for any advance in the upper window edge. 126350849Ssklower */ 126451024Ssklower LOCAL_CREDIT($P); 126551024Ssklower ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt, 126651024Ssklower ($P.tp_maxlcredit > 2 ? 2 : 1)); 126751024Ssklower if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) { 126850849Ssklower IncStat(ts_ackreason[_ACK_USRRCV_]); 126951024Ssklower $P.tp_flags &= ~TPF_DELACK; 127039921Ssklower return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 127150849Ssklower } 127236396Ssklower } 127336396Ssklower } 127436396Ssklower; 127536396Ssklower 127636396Ssklower/* applicable in TP4, TP0 */ 127736396SsklowerSAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ] 127836396Ssklower DEFAULT 127936396Ssklower /* This happens if other end sent a DR when the user was waiting 128036396Ssklower * on a receive. 128136396Ssklower * Processing the DR includes putting us in REFWAIT state. 128236396Ssklower */ 128336396Ssklower { 128436396Ssklower if(trick_hc) 128536396Ssklower return ECONNABORTED; 128636396Ssklower } 128736396Ssklower; 128836396Ssklower 128936396Ssklower/* TP0 only */ 129036396SsklowerTP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET 129136396Ssklower ( $P.tp_class != TP_CLASS_4 ) 129236396Ssklower /* 0 or (4 and 0) */ 129336396Ssklower /* in OPEN class will be 0 or 4 but not both */ 129436396Ssklower /* in CRSENT or LISTENING it could be in negotiation, hence both */ 129536396Ssklower /* Actually, this shouldn't ever happen in LISTENING */ 129636396Ssklower { 129736396Ssklower ASSERT( $P.tp_state != TP_LISTENING ); 129836396Ssklower tp_indicate(T_DISCONNECT, $P, ECONNRESET); 129936396Ssklower tp_soisdisconnected($P); 130036396Ssklower } 130136396Ssklower; 130236396Ssklower 130336396Ssklower/* TP4: ignore resets */ 130436396SsklowerSAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT, 130536396Ssklower TP_CLOSING, TP_LISTENING ] T_NETRESET 130636396Ssklower DEFAULT 130736396Ssklower NULLACTION 130836396Ssklower; 130936396Ssklower 131036396Ssklower/* applicable in TP4, TP0 */ 131136396SsklowerSAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET 131236396Ssklower DEFAULT 131336396Ssklower NULLACTION 131436396Ssklower; 131536396Ssklower 131636396Ssklower/* C'EST TOUT */ 1317