136408Ssklower /*********************************************************** 239196Ssklower Copyright IBM Corporation 1987 336408Ssklower 436408Ssklower All Rights Reserved 536408Ssklower 636408Ssklower Permission to use, copy, modify, and distribute this software and its 736408Ssklower documentation for any purpose and without fee is hereby granted, 836408Ssklower provided that the above copyright notice appear in all copies and that 936408Ssklower both that copyright notice and this permission notice appear in 1036408Ssklower supporting documentation, and that the name of IBM not be 1136408Ssklower used in advertising or publicity pertaining to distribution of the 1236408Ssklower software without specific, written prior permission. 1336408Ssklower 1436408Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536408Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636408Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736408Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836408Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936408Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036408Ssklower SOFTWARE. 2136408Ssklower 2236408Ssklower ******************************************************************/ 2336408Ssklower 2436408Ssklower /* 2536408Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636408Ssklower */ 2736408Ssklower /* 2836408Ssklower * ARGO TP 2936408Ssklower * 3036408Ssklower * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $ 3136408Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $ 32*49258Ssklower * @(#)tp_pcb.c 7.10 (Berkeley) 05/06/91 * 3336408Ssklower * 3436408Ssklower * 3536408Ssklower * This is the initialization and cleanup stuff - 3636408Ssklower * for the tp machine in general as well as for the individual pcbs. 3736408Ssklower * tp_init() is called at system startup. tp_attach() and tp_getref() are 3836408Ssklower * called when a socket is created. tp_detach() and tp_freeref() 3936408Ssklower * are called during the closing stage and/or when the reference timer 4036408Ssklower * goes off. 4136408Ssklower * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific 4236408Ssklower * versions of soisconnect* 4336408Ssklower * and are called (obviously) during the closing phase. 4436408Ssklower * 4536408Ssklower */ 4636408Ssklower 4736408Ssklower #ifndef lint 4836408Ssklower static char *rcsid = "$Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $"; 4936408Ssklower #endif lint 5036408Ssklower 5136408Ssklower #include "types.h" 5236408Ssklower #include "param.h" 5336408Ssklower #include "mbuf.h" 5436408Ssklower #include "socket.h" 5536408Ssklower #include "socketvar.h" 5636408Ssklower #include "protosw.h" 5736408Ssklower #include "errno.h" 5836408Ssklower #include "time.h" 5937469Ssklower #include "argo_debug.h" 6037469Ssklower #include "tp_param.h" 6137469Ssklower #include "tp_timer.h" 6237469Ssklower #include "tp_ip.h" 6337469Ssklower #include "tp_stat.h" 6437469Ssklower #include "tp_pcb.h" 6537469Ssklower #include "tp_tpdu.h" 6637469Ssklower #include "tp_trace.h" 6737469Ssklower #include "tp_meas.h" 6837469Ssklower #include "tp_seq.h" 6937469Ssklower #include "tp_clnp.h" 7036408Ssklower 7136408Ssklower struct tp_param tp_param = { 7236408Ssklower 1, /* configured */ 7336408Ssklower }; 7436408Ssklower 7536408Ssklower /* ticks are in units of: 7636408Ssklower * 500 nano-fortnights ;-) or 7736408Ssklower * 500 ms or 7836408Ssklower * 1/2 second 7936408Ssklower */ 8036408Ssklower 8136408Ssklower struct tp_conn_param tp_conn_param[] = { 8236408Ssklower /* ISO_CLNS: TP4 CONNECTION LESS */ 8336408Ssklower { 8436408Ssklower TP_NRETRANS, /* short p_Nretrans; */ 8536408Ssklower 20, /* 10 sec */ /* short p_dr_ticks; */ 8636408Ssklower 8736408Ssklower 20, /* 10 sec */ /* short p_cc_ticks; */ 8836408Ssklower 20, /* 10 sec */ /* short p_dt_ticks; */ 8936408Ssklower 9036408Ssklower 40, /* 20 sec */ /* short p_x_ticks; */ 9136408Ssklower 80, /* 40 sec */ /* short p_cr_ticks;*/ 9236408Ssklower 9336408Ssklower 240, /* 2 min */ /* short p_keepalive_ticks;*/ 9436408Ssklower 10, /* 5 sec */ /* short p_sendack_ticks; */ 9536408Ssklower 9636408Ssklower 600, /* 5 min */ /* short p_ref_ticks; */ 9736408Ssklower 360, /* 3 min */ /* short p_inact_ticks; */ 9836408Ssklower 9936408Ssklower (short) 100, /* short p_lcdtfract */ 10036408Ssklower (short) TP_SOCKBUFSIZE, /* short p_winsize */ 10136408Ssklower TP_TPDUSIZE, /* u_char p_tpdusize */ 10236408Ssklower 10336408Ssklower TPACK_WINDOW, /* 4 bits p_ack_strat */ 10436408Ssklower TPRX_USE_CW | TPRX_FASTSTART, 10536408Ssklower /* 4 bits p_rx_strat*/ 10636408Ssklower TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ 10736408Ssklower 1, /* 1 bit xtd format */ 10836408Ssklower 1, /* 1 bit xpd service */ 10936408Ssklower 1, /* 1 bit use_checksum */ 11036408Ssklower 0, /* 1 bit use net xpd */ 11136408Ssklower 0, /* 1 bit use rcc */ 11236408Ssklower 0, /* 1 bit use efc */ 11338841Ssklower 1, /* no disc indications */ 11436408Ssklower 0, /* don't change params */ 11536408Ssklower ISO_CLNS, /* p_netservice */ 11636408Ssklower }, 11736408Ssklower /* IN_CLNS: TP4 CONNECTION LESS */ 11836408Ssklower { 11936408Ssklower TP_NRETRANS, /* short p_Nretrans; */ 12036408Ssklower 20, /* 10 sec */ /* short p_dr_ticks; */ 12136408Ssklower 12236408Ssklower 20, /* 10 sec */ /* short p_cc_ticks; */ 12336408Ssklower 20, /* 10 sec */ /* short p_dt_ticks; */ 12436408Ssklower 12536408Ssklower 40, /* 20 sec */ /* short p_x_ticks; */ 12636408Ssklower 80, /* 40 sec */ /* short p_cr_ticks;*/ 12736408Ssklower 12836408Ssklower 240, /* 2 min */ /* short p_keepalive_ticks;*/ 12936408Ssklower 10, /* 5 sec */ /* short p_sendack_ticks; */ 13036408Ssklower 13136408Ssklower 600, /* 5 min */ /* short p_ref_ticks; */ 13236408Ssklower 360, /* 3 min */ /* short p_inact_ticks; */ 13336408Ssklower 13436408Ssklower (short) 100, /* short p_lcdtfract */ 13536408Ssklower (short) TP_SOCKBUFSIZE, /* short p_winsize */ 13636408Ssklower TP_TPDUSIZE, /* u_char p_tpdusize */ 13736408Ssklower 13836408Ssklower TPACK_WINDOW, /* 4 bits p_ack_strat */ 13936408Ssklower TPRX_USE_CW | TPRX_FASTSTART, 14036408Ssklower /* 4 bits p_rx_strat*/ 14136408Ssklower TP_CLASS_4, /* 5 bits p_class */ 14236408Ssklower 1, /* 1 bit xtd format */ 14336408Ssklower 1, /* 1 bit xpd service */ 14436408Ssklower 1, /* 1 bit use_checksum */ 14536408Ssklower 0, /* 1 bit use net xpd */ 14636408Ssklower 0, /* 1 bit use rcc */ 14736408Ssklower 0, /* 1 bit use efc */ 14838841Ssklower 1, /* no disc indications */ 14936408Ssklower 0, /* don't change params */ 15036408Ssklower IN_CLNS, /* p_netservice */ 15136408Ssklower }, 15236408Ssklower /* ISO_CONS: TP0 CONNECTION MODE */ 15336408Ssklower { 15436408Ssklower TP_NRETRANS, /* short p_Nretrans; */ 15536408Ssklower 0, /* n/a */ /* short p_dr_ticks; */ 15636408Ssklower 15736408Ssklower 40, /* 20 sec */ /* short p_cc_ticks; */ 15836408Ssklower 0, /* n/a */ /* short p_dt_ticks; */ 15936408Ssklower 16036408Ssklower 0, /* n/a */ /* short p_x_ticks; */ 16136408Ssklower 360, /* 3 min */ /* short p_cr_ticks;*/ 16236408Ssklower 16336408Ssklower 0, /* n/a */ /* short p_keepalive_ticks;*/ 16436408Ssklower 0, /* n/a */ /* short p_sendack_ticks; */ 16536408Ssklower 16636408Ssklower 600, /* for cr/cc to clear *//* short p_ref_ticks; */ 16736408Ssklower 0, /* n/a */ /* short p_inact_ticks; */ 16836408Ssklower 16936408Ssklower /* Use tp4 defaults just in case the user changes ONLY 17036408Ssklower * the class 17136408Ssklower */ 17236408Ssklower (short) 100, /* short p_lcdtfract */ 17336408Ssklower (short) TP0_SOCKBUFSIZE, /* short p_winsize */ 17436408Ssklower TP0_TPDUSIZE, /* 8 bits p_tpdusize */ 17536408Ssklower 17636408Ssklower 0, /* 4 bits p_ack_strat */ 17736408Ssklower 0, /* 4 bits p_rx_strat*/ 17836408Ssklower TP_CLASS_0, /* 5 bits p_class */ 17936408Ssklower 0, /* 1 bit xtd format */ 18036408Ssklower 0, /* 1 bit xpd service */ 18136408Ssklower 0, /* 1 bit use_checksum */ 18236408Ssklower 0, /* 1 bit use net xpd */ 18336408Ssklower 0, /* 1 bit use rcc */ 18436408Ssklower 0, /* 1 bit use efc */ 18536408Ssklower 0, /* no disc indications */ 18636408Ssklower 0, /* don't change params */ 18736408Ssklower ISO_CONS, /* p_netservice */ 18836408Ssklower }, 18936408Ssklower /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */ 19036408Ssklower { 19136408Ssklower TP_NRETRANS, /* short p_Nretrans; */ 19236408Ssklower 40, /* 20 sec */ /* short p_dr_ticks; */ 19336408Ssklower 19436408Ssklower 40, /* 20 sec */ /* short p_cc_ticks; */ 19536408Ssklower 80, /* 40 sec */ /* short p_dt_ticks; */ 19636408Ssklower 19736408Ssklower 120, /* 1 min */ /* short p_x_ticks; */ 19836408Ssklower 360, /* 3 min */ /* short p_cr_ticks;*/ 19936408Ssklower 20036408Ssklower 360, /* 3 min */ /* short p_keepalive_ticks;*/ 20136408Ssklower 20, /* 10 sec */ /* short p_sendack_ticks; */ 20236408Ssklower 20336408Ssklower 600, /* 5 min */ /* short p_ref_ticks; */ 20436408Ssklower 480, /* 4 min */ /* short p_inact_ticks; */ 20536408Ssklower 20636408Ssklower (short) 100, /* short p_lcdtfract */ 20736408Ssklower (short) TP0_SOCKBUFSIZE, /* short p_winsize */ 20836408Ssklower TP0_TPDUSIZE, /* u_char p_tpdusize */ 20936408Ssklower 21036408Ssklower TPACK_WINDOW, /* 4 bits p_ack_strat */ 21136408Ssklower TPRX_USE_CW , /* No fast start */ 21236408Ssklower /* 4 bits p_rx_strat*/ 21336408Ssklower TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ 21436408Ssklower 0, /* 1 bit xtd format */ 21536408Ssklower 1, /* 1 bit xpd service */ 21636408Ssklower 1, /* 1 bit use_checksum */ 21736408Ssklower 0, /* 1 bit use net xpd */ 21836408Ssklower 0, /* 1 bit use rcc */ 21936408Ssklower 0, /* 1 bit use efc */ 22036408Ssklower 0, /* no disc indications */ 22136408Ssklower 0, /* don't change params */ 22236408Ssklower ISO_COSNS, /* p_netservice */ 22336408Ssklower }, 22436408Ssklower }; 22536408Ssklower 22636408Ssklower #ifdef INET 22736408Ssklower int in_putnetaddr(); 22836408Ssklower int in_getnetaddr(); 22944423Ssklower int in_cmpnetaddr(); 23036408Ssklower int in_putsufx(); 23136408Ssklower int in_getsufx(); 23236408Ssklower int in_recycle_tsuffix(); 23336408Ssklower int tpip_mtu(); 23436408Ssklower int in_pcbbind(); 23536408Ssklower int in_pcbconnect(); 23636408Ssklower int in_pcbdisconnect(); 23736408Ssklower int in_pcbdetach(); 23836408Ssklower int in_pcballoc(); 23936408Ssklower int tpip_output(); 24036408Ssklower int tpip_output_dg(); 24136408Ssklower struct inpcb tp_inpcb; 24236408Ssklower #endif INET 24336408Ssklower #ifdef ISO 24436408Ssklower int iso_putnetaddr(); 24536408Ssklower int iso_getnetaddr(); 24644423Ssklower int iso_cmpnetaddr(); 24736408Ssklower int iso_putsufx(); 24836408Ssklower int iso_getsufx(); 24936408Ssklower int iso_recycle_tsuffix(); 25036408Ssklower int tpclnp_mtu(); 25136408Ssklower int iso_pcbbind(); 25236408Ssklower int iso_pcbconnect(); 25336408Ssklower int iso_pcbdisconnect(); 25436408Ssklower int iso_pcbdetach(); 25536408Ssklower int iso_pcballoc(); 25636408Ssklower int tpclnp_output(); 25736408Ssklower int tpclnp_output_dg(); 25836408Ssklower int iso_nlctloutput(); 25936408Ssklower struct isopcb tp_isopcb; 26036408Ssklower #endif ISO 26145900Ssklower #ifdef TPCONS 26236408Ssklower int iso_putnetaddr(); 26336408Ssklower int iso_getnetaddr(); 26444423Ssklower int iso_cmpnetaddr(); 26536408Ssklower int iso_putsufx(); 26636408Ssklower int iso_getsufx(); 26736408Ssklower int iso_recycle_tsuffix(); 26836408Ssklower int iso_pcbbind(); 26945900Ssklower int tpcons_pcbconnect(); 270*49258Ssklower int tpclnp_mtu(); 27136408Ssklower int iso_pcbdisconnect(); 27236408Ssklower int iso_pcbdetach(); 27336408Ssklower int iso_pcballoc(); 27436408Ssklower int tpcons_output(); 27536408Ssklower struct isopcb tp_isopcb; 27645900Ssklower #endif TPCONS 27736408Ssklower 27837469Ssklower 27936408Ssklower struct nl_protosw nl_protosw[] = { 28036408Ssklower /* ISO_CLNS */ 28136408Ssklower #ifdef ISO 28244423Ssklower { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, 28336408Ssklower iso_putsufx, iso_getsufx, 28436408Ssklower iso_recycle_tsuffix, 28536408Ssklower tpclnp_mtu, iso_pcbbind, iso_pcbconnect, 28636408Ssklower iso_pcbdisconnect, iso_pcbdetach, 28736408Ssklower iso_pcballoc, 28836408Ssklower tpclnp_output, tpclnp_output_dg, iso_nlctloutput, 28936408Ssklower (caddr_t) &tp_isopcb, 29036408Ssklower }, 29137469Ssklower #else 29237469Ssklower { 0 }, 29336408Ssklower #endif ISO 29436408Ssklower /* IN_CLNS */ 29536408Ssklower #ifdef INET 29644423Ssklower { AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr, 29736408Ssklower in_putsufx, in_getsufx, 29836408Ssklower in_recycle_tsuffix, 29936408Ssklower tpip_mtu, in_pcbbind, in_pcbconnect, 30036408Ssklower in_pcbdisconnect, in_pcbdetach, 30136408Ssklower in_pcballoc, 30236408Ssklower tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL, 30336408Ssklower (caddr_t) &tp_inpcb, 30436408Ssklower }, 30537469Ssklower #else 30637469Ssklower { 0 }, 30736408Ssklower #endif INET 30836408Ssklower /* ISO_CONS */ 30945900Ssklower #if defined(ISO) && defined(TPCONS) 31044423Ssklower { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, 31136408Ssklower iso_putsufx, iso_getsufx, 31236408Ssklower iso_recycle_tsuffix, 313*49258Ssklower tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect, 31436408Ssklower iso_pcbdisconnect, iso_pcbdetach, 31536408Ssklower iso_pcballoc, 31645900Ssklower tpcons_output, tpcons_output, iso_nlctloutput, 31736408Ssklower (caddr_t) &tp_isopcb, 31836408Ssklower }, 31937469Ssklower #else 32037469Ssklower { 0 }, 32137469Ssklower #endif ISO_CONS 32237469Ssklower /* End of protosw marker */ 32337469Ssklower { 0 } 32436408Ssklower }; 32536408Ssklower 32636408Ssklower /* 32736408Ssklower * NAME: tp_init() 32836408Ssklower * 32936408Ssklower * CALLED FROM: 33036408Ssklower * autoconf through the protosw structure 33136408Ssklower * 33236408Ssklower * FUNCTION: 33336408Ssklower * initialize tp machine 33436408Ssklower * 33536408Ssklower * RETURNS: Nada 33636408Ssklower * 33736408Ssklower * SIDE EFFECTS: 33836408Ssklower * 33936408Ssklower * NOTES: 34036408Ssklower */ 34137469Ssklower int 34236408Ssklower tp_init() 34336408Ssklower { 34436408Ssklower static int init_done=0; 34536408Ssklower void tp_timerinit(); 34636408Ssklower 34736408Ssklower if (init_done++) 34837469Ssklower return 0; 34936408Ssklower 35036408Ssklower 35136408Ssklower /* FOR INET */ 35236408Ssklower tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb; 35336408Ssklower /* FOR ISO */ 35436408Ssklower tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb; 35536408Ssklower 35639923Ssklower tp_start_win = 2; 35739923Ssklower 35836408Ssklower tp_timerinit(); 35936408Ssklower bzero((caddr_t)&tp_stat, sizeof(struct tp_stat)); 36037469Ssklower return 0; 36136408Ssklower } 36236408Ssklower 36336408Ssklower /* 36436408Ssklower * NAME: tp_soisdisconnecting() 36536408Ssklower * 36636408Ssklower * CALLED FROM: 36736408Ssklower * tp.trans 36836408Ssklower * 36936408Ssklower * FUNCTION and ARGUMENTS: 37036408Ssklower * Set state of the socket (so) to reflect that fact that we're disconnectING 37136408Ssklower * 37236408Ssklower * RETURNS: Nada 37336408Ssklower * 37436408Ssklower * SIDE EFFECTS: 37536408Ssklower * 37636408Ssklower * NOTES: 37736408Ssklower * This differs from the regular soisdisconnecting() in that the latter 37836408Ssklower * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. 37936408Ssklower * We don't want to set those flags because those flags will cause 38036408Ssklower * a SIGPIPE to be delivered in sosend() and we don't like that. 38136408Ssklower * If anyone else is sleeping on this socket, wake 'em up. 38236408Ssklower */ 38336408Ssklower void 38436408Ssklower tp_soisdisconnecting(so) 38536408Ssklower register struct socket *so; 38636408Ssklower { 38738841Ssklower soisdisconnecting(so); 38838841Ssklower so->so_state &= ~SS_CANTSENDMORE; 38936408Ssklower IFPERF(sototpcb(so)) 39036408Ssklower register struct tp_pcb *tpcb = sototpcb(so); 39136408Ssklower u_int fsufx, lsufx; 39236408Ssklower 39337469Ssklower bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); 39437469Ssklower bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); 39536408Ssklower 39637469Ssklower tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref); 39736408Ssklower tpcb->tp_perf_on = 0; /* turn perf off */ 39836408Ssklower ENDPERF 39936408Ssklower } 40036408Ssklower 40136408Ssklower 40236408Ssklower /* 40336408Ssklower * NAME: tp_soisdisconnected() 40436408Ssklower * 40536408Ssklower * CALLED FROM: 40636408Ssklower * tp.trans 40736408Ssklower * 40836408Ssklower * FUNCTION and ARGUMENTS: 40936408Ssklower * Set state of the socket (so) to reflect that fact that we're disconnectED 41036408Ssklower * Set the state of the reference structure to closed, and 41136408Ssklower * recycle the suffix. 41236408Ssklower * Start a reference timer. 41336408Ssklower * 41436408Ssklower * RETURNS: Nada 41536408Ssklower * 41636408Ssklower * SIDE EFFECTS: 41736408Ssklower * 41836408Ssklower * NOTES: 41936408Ssklower * This differs from the regular soisdisconnected() in that the latter 42036408Ssklower * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. 42136408Ssklower * We don't want to set those flags because those flags will cause 42236408Ssklower * a SIGPIPE to be delivered in sosend() and we don't like that. 42336408Ssklower * If anyone else is sleeping on this socket, wake 'em up. 42436408Ssklower */ 42536408Ssklower void 42636408Ssklower tp_soisdisconnected(tpcb) 42736408Ssklower register struct tp_pcb *tpcb; 42836408Ssklower { 42936408Ssklower register struct socket *so = tpcb->tp_sock; 43036408Ssklower 43138841Ssklower soisdisconnecting(so); 43238841Ssklower so->so_state &= ~SS_CANTSENDMORE; 43336408Ssklower IFPERF(sototpcb(so)) 43437469Ssklower register struct tp_pcb *ttpcb = sototpcb(so); 43536408Ssklower u_int fsufx, lsufx; 43636408Ssklower 43736408Ssklower /* CHOKE */ 43837469Ssklower bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); 43937469Ssklower bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); 44036408Ssklower 44137469Ssklower tpmeas(ttpcb->tp_lref, TPtime_close, 44237469Ssklower &time, &lsufx, &fsufx, ttpcb->tp_fref); 44336408Ssklower tpcb->tp_perf_on = 0; /* turn perf off */ 44436408Ssklower ENDPERF 44536408Ssklower 44636408Ssklower tpcb->tp_refp->tpr_state = REF_FROZEN; 44736408Ssklower tp_recycle_tsuffix( tpcb ); 44836408Ssklower tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks); 44936408Ssklower } 45036408Ssklower 45136408Ssklower int tp_maxrefopen; /* highest reference # of the set of open tp connections */ 45236408Ssklower 45336408Ssklower /* 45436408Ssklower * NAME: tp_freeref() 45536408Ssklower * 45636408Ssklower * CALLED FROM: 45736408Ssklower * tp.trans when the reference timer goes off, and 45836408Ssklower * from tp_attach() and tp_detach() when a tpcb is partially set up but not 45936408Ssklower * set up enough to have a ref timer set for it, and it's discarded 46036408Ssklower * due to some sort of error or an early close() 46136408Ssklower * 46236408Ssklower * FUNCTION and ARGUMENTS: 46336408Ssklower * Frees the reference represented by (r) for re-use. 46436408Ssklower * 46536408Ssklower * RETURNS: Nothing 46636408Ssklower * 46736408Ssklower * SIDE EFFECTS: 46836408Ssklower * 46936408Ssklower * NOTES: better be called at clock priority !!!!! 47036408Ssklower */ 47136408Ssklower void 47236408Ssklower tp_freeref(r) 47336408Ssklower register struct tp_ref *r; 47436408Ssklower { 47536408Ssklower IFDEBUG(D_TIMER) 47636408Ssklower printf("tp_freeref called for ref %d maxrefopen %d\n", 47736408Ssklower r - tp_ref, tp_maxrefopen); 47836408Ssklower ENDDEBUG 47936408Ssklower IFTRACE(D_TIMER) 48036408Ssklower tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen", 48136408Ssklower r - tp_ref, tp_maxrefopen, 0, 0); 48236408Ssklower ENDTRACE 48336408Ssklower r->tpr_state = REF_FREE; 48436408Ssklower IFDEBUG(D_CONN) 48536408Ssklower printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb); 48636408Ssklower ENDDEBUG 48736408Ssklower r->tpr_pcb = (struct tp_pcb *)0; 48836408Ssklower 48936408Ssklower r = &tp_ref[tp_maxrefopen]; 49036408Ssklower 49136408Ssklower while( tp_maxrefopen > 0 ) { 49236408Ssklower if(r->tpr_state ) 49336408Ssklower break; 49436408Ssklower tp_maxrefopen--; 49536408Ssklower r--; 49636408Ssklower } 49736408Ssklower IFDEBUG(D_TIMER) 49836408Ssklower printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen); 49936408Ssklower ENDDEBUG 50036408Ssklower } 50136408Ssklower 50236408Ssklower /* 50336408Ssklower * NAME: tp_getref() 50436408Ssklower * 50536408Ssklower * CALLED FROM: 50636408Ssklower * tp_attach() 50736408Ssklower * 50836408Ssklower * FUNCTION and ARGUMENTS: 50936408Ssklower * obtains the next free reference and allocates the appropriate 51036408Ssklower * ref structure, links that structure to (tpcb) 51136408Ssklower * 51236408Ssklower * RETURN VALUE: 51336408Ssklower * a reference number 51436408Ssklower * or TP_ENOREF 51536408Ssklower * 51636408Ssklower * SIDE EFFECTS: 51736408Ssklower * 51836408Ssklower * NOTES: 51936408Ssklower */ 52036408Ssklower static RefNum 52136408Ssklower tp_getref(tpcb) 52236408Ssklower register struct tp_pcb *tpcb; 52336408Ssklower { 52448733Ssklower register struct tp_ref *r = tp_ref; /* tp_ref[0] is never used */ 52536408Ssklower register int i=1; 52636408Ssklower 52736408Ssklower 52848733Ssklower while ((++r)->tpr_state != REF_FREE) { 52948733Ssklower if (++i == N_TPREF) 53036408Ssklower return TP_ENOREF; 53136408Ssklower } 53236408Ssklower r->tpr_state = REF_OPENING; 53336408Ssklower if (tp_maxrefopen < i) 53436408Ssklower tp_maxrefopen = i; 53536408Ssklower r->tpr_pcb = tpcb; 53636408Ssklower tpcb->tp_refp = r; 53736408Ssklower 53836408Ssklower return i; 53936408Ssklower } 54036408Ssklower 54136408Ssklower /* 54236408Ssklower * NAME: tp_attach() 54336408Ssklower * 54436408Ssklower * CALLED FROM: 54536408Ssklower * tp_usrreq, PRU_ATTACH 54636408Ssklower * 54736408Ssklower * FUNCTION and ARGUMENTS: 54836408Ssklower * given a socket (so) and a protocol family (dom), allocate a tpcb 54936408Ssklower * and ref structure, initialize everything in the structures that 55036408Ssklower * needs to be initialized. 55136408Ssklower * 55236408Ssklower * RETURN VALUE: 55336408Ssklower * 0 ok 55436408Ssklower * EINVAL if DEBUG(X) in is on and a disaster has occurred 55536408Ssklower * ENOPROTOOPT if TP hasn't been configured or if the 55636408Ssklower * socket wasn't created with tp as its protocol 55736408Ssklower * EISCONN if this socket is already part of a connection 55836408Ssklower * ETOOMANYREFS if ran out of tp reference numbers. 55936408Ssklower * E* whatever error is returned from soreserve() 56036408Ssklower * for from the network-layer pcb allocation routine 56136408Ssklower * 56236408Ssklower * SIDE EFFECTS: 56336408Ssklower * 56436408Ssklower * NOTES: 56536408Ssklower */ 56637469Ssklower tp_attach(so, dom) 56736408Ssklower struct socket *so; 56836408Ssklower int dom; 56936408Ssklower { 57036408Ssklower register struct tp_pcb *tpcb; 57136408Ssklower int error; 57236408Ssklower int protocol = so->so_proto->pr_protocol; 57336408Ssklower extern struct tp_conn_param tp_conn_param[]; 57436408Ssklower 57536408Ssklower IFDEBUG(D_CONN) 57636408Ssklower printf("tp_attach:dom 0x%x so 0x%x ", dom, so); 57736408Ssklower ENDDEBUG 57836408Ssklower IFTRACE(D_CONN) 57936408Ssklower tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); 58036408Ssklower ENDTRACE 58136408Ssklower if ( ! tp_param.tpp_configed ) { 58236408Ssklower error = ENOPROTOOPT; /* protocol not available */ 58336408Ssklower goto bad2; 58436408Ssklower } 58536408Ssklower 58636408Ssklower if (so->so_pcb != NULL) { 58736408Ssklower return EISCONN; /* socket already part of a connection*/ 58836408Ssklower } 58936408Ssklower 59036408Ssklower error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE); 59136408Ssklower /* later an ioctl will allow reallocation IF still in closed state */ 59236408Ssklower 59336408Ssklower if (error) 59436408Ssklower goto bad2; 59536408Ssklower 59637469Ssklower MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); 59737469Ssklower if (tpcb == NULL) { 59836408Ssklower error = ENOBUFS; 59936408Ssklower goto bad2; 60036408Ssklower } 60136408Ssklower bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); 60236408Ssklower 60336408Ssklower if ( ((tpcb->tp_lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { 60436408Ssklower error = ETOOMANYREFS; 60536408Ssklower goto bad3; 60636408Ssklower } 60736408Ssklower tpcb->tp_sock = so; 60836408Ssklower tpcb->tp_domain = dom; 60936408Ssklower if (protocol<ISOPROTO_TP4) { 61036408Ssklower tpcb->tp_netservice = ISO_CONS; 61136408Ssklower tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC 61236408Ssklower * will generate correct fake-ack values 61336408Ssklower */ 61436408Ssklower } else { 61536408Ssklower tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; 61636408Ssklower /* the default */ 61736408Ssklower } 61836408Ssklower tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; 61936408Ssklower 62036408Ssklower tpcb->tp_cong_win = 1; 62136408Ssklower tpcb->tp_state = TP_CLOSED; 62236408Ssklower tpcb->tp_vers = TP_VERSION; 62336408Ssklower 62436408Ssklower /* Spec says default is 128 octets, 62536408Ssklower * that is, if the tpdusize argument never appears, use 128. 62636408Ssklower * As the initiator, we will always "propose" the 2048 62736408Ssklower * size, that is, we will put this argument in the CR 62836408Ssklower * always, but accept what the other side sends on the CC. 62936408Ssklower * If the initiator sends us something larger on a CR, 63036408Ssklower * we'll respond w/ this. 63136408Ssklower * Our maximum is 4096. See tp_chksum.c comments. 63236408Ssklower */ 63336408Ssklower tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; 63436408Ssklower 63536408Ssklower tpcb->tp_seqmask = TP_NML_FMT_MASK; 63636408Ssklower tpcb->tp_seqbit = TP_NML_FMT_BIT; 63736408Ssklower tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 63836408Ssklower tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */ 63936408Ssklower tpcb->tp_s_subseq = 0; 64036408Ssklower 64136408Ssklower /* attach to a network-layer protoswitch */ 64236408Ssklower /* new way */ 64336408Ssklower tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice]; 64436408Ssklower ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); 64536408Ssklower #ifdef notdef 64636408Ssklower /* OLD WAY */ 64736408Ssklower /* TODO: properly, this search would be on the basis of 64836408Ssklower * domain,netservice or just netservice only (if you have 64936408Ssklower * IN_CLNS, ISO_CLNS, and ISO_CONS) 65036408Ssklower */ 65136408Ssklower tpcb->tp_nlproto = nl_protosw; 65236408Ssklower while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain ) { 65336408Ssklower if( tpcb->tp_nlproto->nlp_afamily == 0 ) { 65436408Ssklower error = EAFNOSUPPORT; 65536408Ssklower goto bad4; 65636408Ssklower } 65736408Ssklower tpcb->tp_nlproto ++; 65836408Ssklower } 65936408Ssklower #endif notdef 66036408Ssklower 66136408Ssklower /* xx_pcballoc sets so_pcb */ 66236408Ssklower if ( error = (tpcb->tp_nlproto->nlp_pcballoc) ( 66336408Ssklower so, tpcb->tp_nlproto->nlp_pcblist ) ) { 66436408Ssklower goto bad4; 66536408Ssklower } 66636408Ssklower 66736408Ssklower if( dom == AF_INET ) 66836408Ssklower sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; 66936408Ssklower /* nothing to do for iso case */ 67036408Ssklower 67136408Ssklower tpcb->tp_npcb = (caddr_t) so->so_pcb; 67236408Ssklower so->so_tpcb = (caddr_t) tpcb; 67336408Ssklower 67436408Ssklower return 0; 67536408Ssklower 67636408Ssklower bad4: 67736408Ssklower IFDEBUG(D_CONN) 67836408Ssklower printf("BAD4 in tp_attach, so 0x%x\n", so); 67936408Ssklower ENDDEBUG 68036408Ssklower tp_freeref(tpcb->tp_refp); 68136408Ssklower 68236408Ssklower bad3: 68336408Ssklower IFDEBUG(D_CONN) 68436408Ssklower printf("BAD3 in tp_attach, so 0x%x\n", so); 68536408Ssklower ENDDEBUG 68636408Ssklower 68737469Ssklower free((caddr_t)tpcb, M_PCB); /* never a cluster */ 68836408Ssklower 68936408Ssklower bad2: 69036408Ssklower IFDEBUG(D_CONN) 69136408Ssklower printf("BAD2 in tp_attach, so 0x%x\n", so); 69236408Ssklower ENDDEBUG 69336408Ssklower so->so_pcb = 0; 69436408Ssklower so->so_tpcb = 0; 69536408Ssklower 69637469Ssklower /*bad:*/ 69736408Ssklower IFDEBUG(D_CONN) 69836408Ssklower printf("BAD in tp_attach, so 0x%x\n", so); 69936408Ssklower ENDDEBUG 70036408Ssklower return error; 70136408Ssklower } 70236408Ssklower 70336408Ssklower /* 70436408Ssklower * NAME: tp_detach() 70536408Ssklower * 70636408Ssklower * CALLED FROM: 70736408Ssklower * tp.trans, on behalf of a user close request 70836408Ssklower * and when the reference timer goes off 70936408Ssklower * (if the disconnect was initiated by the protocol entity 71036408Ssklower * rather than by the user) 71136408Ssklower * 71236408Ssklower * FUNCTION and ARGUMENTS: 71336408Ssklower * remove the tpcb structure from the list of active or 71436408Ssklower * partially active connections, recycle all the mbufs 71536408Ssklower * associated with the pcb, ref structure, sockbufs, etc. 71636408Ssklower * Only free the ref structure if you know that a ref timer 71736408Ssklower * wasn't set for this tpcb. 71836408Ssklower * 71936408Ssklower * RETURNS: Nada 72036408Ssklower * 72136408Ssklower * SIDE EFFECTS: 72236408Ssklower * 72336408Ssklower * NOTES: 72436408Ssklower * tp_soisdisconnected() was already when this is called 72536408Ssklower */ 72636408Ssklower void 72736408Ssklower tp_detach(tpcb) 72836408Ssklower register struct tp_pcb *tpcb; 72936408Ssklower { 73036408Ssklower void tp_freeref(); 73136408Ssklower register struct socket *so = tpcb->tp_sock; 73236408Ssklower 73336408Ssklower IFDEBUG(D_CONN) 73437469Ssklower printf("tp_detach(tpcb 0x%x, so 0x%x)\n", 73537469Ssklower tpcb,so); 73636408Ssklower ENDDEBUG 73736408Ssklower IFTRACE(D_CONN) 73836408Ssklower tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", 73939196Ssklower tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); 74036408Ssklower ENDTRACE 74136408Ssklower 74236408Ssklower if (so->so_head) { 74336408Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 74436408Ssklower panic("sofree dq"); 74536408Ssklower so->so_head = 0; 74636408Ssklower } 74736408Ssklower 74836408Ssklower IFDEBUG(D_CONN) 74936408Ssklower printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n", 75036408Ssklower tpcb->tp_snduna_rtc, 75136408Ssklower tpcb->tp_rcvnxt_rtc); 75236408Ssklower ENDDEBUG 75336408Ssklower 75436408Ssklower #define FREE_RTC_LIST(XXX)\ 75536408Ssklower { register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\ 75636408Ssklower xxs = xxr->tprt_next;\ 75736408Ssklower m_freem( xxr->tprt_data );\ 75836408Ssklower m_free( dtom(xxr) ); xxr = xxs; }\ 75936408Ssklower XXX = (struct tp_rtc *)0;\ 76036408Ssklower } 76136408Ssklower 76236408Ssklower FREE_RTC_LIST( tpcb->tp_snduna_rtc ); 76336408Ssklower tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0; 76436408Ssklower 76536408Ssklower FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc ); 76636408Ssklower 76736408Ssklower #undef FREE_RTC_LIST 76836408Ssklower 76936408Ssklower IFDEBUG(D_CONN) 77047278Ssklower printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); 77147278Ssklower dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); 77247278Ssklower printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", 77347278Ssklower tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); 77447278Ssklower ENDDEBUG 77547278Ssklower 77647278Ssklower if (so->so_snd.sb_cc != 0) 77747278Ssklower sbflush(&so->so_snd); 77847278Ssklower if (tpcb->tp_Xrcv.sb_cc != 0) 77947278Ssklower sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc); 78047278Ssklower if (tpcb->tp_ucddata) 78147278Ssklower m_freem(tpcb->tp_ucddata); 78247278Ssklower 78347278Ssklower IFDEBUG(D_CONN) 78436408Ssklower printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", 78536408Ssklower so->so_pcb, so); 78636408Ssklower printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", 78736408Ssklower so, so->so_head, 78836408Ssklower so->so_q0len, so->so_qlen, so->so_qlimit); 78936408Ssklower ENDDEBUG 79036408Ssklower 79136408Ssklower 79247278Ssklower (tpcb->tp_nlproto->nlp_pcbdetach)(so->so_pcb); 79337469Ssklower /* does an sofree(so) */ 79437469Ssklower 79536408Ssklower IFDEBUG(D_CONN) 79636408Ssklower printf("after xxx_pcbdetach\n"); 79736408Ssklower ENDDEBUG 79836408Ssklower 79936408Ssklower if( tpcb->tp_refp->tpr_state == REF_OPENING ) { 80036408Ssklower /* no connection existed here so no reference timer will be called */ 80136408Ssklower IFDEBUG(D_CONN) 80236408Ssklower printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref, 80336408Ssklower tpcb->tp_refp - &tp_ref[0]); 80436408Ssklower ENDDEBUG 80536408Ssklower 80636408Ssklower tp_freeref(tpcb->tp_refp); 80736408Ssklower } 80836408Ssklower 80937469Ssklower if (tpcb->tp_Xsnd.sb_mb) { 81037469Ssklower printf("Unsent Xdata on detach; would panic"); 81137469Ssklower sbflush(&tpcb->tp_Xsnd); 81237469Ssklower } 81336408Ssklower so->so_tpcb = (caddr_t)0; 81436408Ssklower 81536408Ssklower /* 81636408Ssklower * Get rid of the cluster mbuf allocated for performance measurements, if 81736408Ssklower * there is one. Note that tpcb->tp_perf_on says nothing about whether or 81836408Ssklower * not a cluster mbuf was allocated, so you have to check for a pointer 81936408Ssklower * to one (that is, we need the TP_PERF_MEASs around the following section 82036408Ssklower * of code, not the IFPERFs) 82136408Ssklower */ 82236408Ssklower #ifdef TP_PERF_MEAS 82347278Ssklower if (tpcb->tp_p_mbuf) { 82437469Ssklower register struct mbuf *m = tpcb->tp_p_mbuf; 82537469Ssklower struct mbuf *n; 82636408Ssklower IFDEBUG(D_PERF_MEAS) 82736408Ssklower printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); 82836408Ssklower ENDDEBUG 82937469Ssklower do { 83037469Ssklower MFREE(m, n); 83137469Ssklower m = n; 83237469Ssklower } while (n); 83337469Ssklower tpcb->tp_p_meas = 0; 83437469Ssklower tpcb->tp_p_mbuf = 0; 83536408Ssklower } 83636408Ssklower #endif TP_PERF_MEAS 83736408Ssklower 83836408Ssklower IFDEBUG(D_CONN) 83937469Ssklower printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); 84036408Ssklower ENDDEBUG 84137469Ssklower /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */ 84236408Ssklower } 843