xref: /csrg-svn/sys/netiso/tp_pcb.c (revision 48733)
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*48733Ssklower  *	@(#)tp_pcb.c	7.9 (Berkeley) 04/26/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		tpcons_mtu();
26936408Ssklower int		iso_pcbbind();
27045900Ssklower int		tpcons_pcbconnect();
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,
31345900Ssklower 		tpcons_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 {
524*48733Ssklower 	register struct tp_ref	*r = tp_ref; /* tp_ref[0] is never used */
52536408Ssklower 	register int 			i=1;
52636408Ssklower 
52736408Ssklower 
528*48733Ssklower 	while ((++r)->tpr_state != REF_FREE) {
529*48733Ssklower 		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