xref: /csrg-svn/sys/netiso/tp_pcb.c (revision 37469)
136408Ssklower /***********************************************************
236408Ssklower 		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 $
3236408Ssklower  *
3336408Ssklower  *
3436408Ssklower  * This is the initialization and cleanup stuff -
3536408Ssklower  * for the tp machine in general as well as  for the individual pcbs.
3636408Ssklower  * tp_init() is called at system startup.  tp_attach() and tp_getref() are
3736408Ssklower  * called when a socket is created.  tp_detach() and tp_freeref()
3836408Ssklower  * are called during the closing stage and/or when the reference timer
3936408Ssklower  * goes off.
4036408Ssklower  * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific
4136408Ssklower  * versions of soisconnect*
4236408Ssklower  * and are called (obviously) during the closing phase.
4336408Ssklower  *
4436408Ssklower  */
4536408Ssklower 
4636408Ssklower #ifndef lint
4736408Ssklower static char *rcsid = "$Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $";
4836408Ssklower #endif lint
4936408Ssklower 
5036408Ssklower #include "argoxtwentyfive.h"
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"
59*37469Ssklower #include "argo_debug.h"
60*37469Ssklower #include "tp_param.h"
61*37469Ssklower #include "tp_timer.h"
62*37469Ssklower #include "tp_ip.h"
63*37469Ssklower #include "tp_stat.h"
64*37469Ssklower #include "tp_pcb.h"
65*37469Ssklower #include "tp_tpdu.h"
66*37469Ssklower #include "tp_trace.h"
67*37469Ssklower #include "tp_meas.h"
68*37469Ssklower #include "tp_seq.h"
69*37469Ssklower #include "tp_clnp.h"
7036408Ssklower 
7136408Ssklower /* list of reference structures */
7236408Ssklower struct tp_ref tp_ref[N_TPREF];
7336408Ssklower 
7436408Ssklower struct tp_param tp_param = {
7536408Ssklower 	1,				/*  configured 		*/
7636408Ssklower };
7736408Ssklower 
7836408Ssklower /* ticks are in units of:
7936408Ssklower  * 500 nano-fortnights ;-) or
8036408Ssklower  * 500 ms or
8136408Ssklower  * 1/2 second
8236408Ssklower  */
8336408Ssklower 
8436408Ssklower struct tp_conn_param tp_conn_param[] = {
8536408Ssklower 	/* ISO_CLNS: TP4 CONNECTION LESS */
8636408Ssklower 	{
8736408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
8836408Ssklower 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
8936408Ssklower 
9036408Ssklower 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
9136408Ssklower 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
9236408Ssklower 
9336408Ssklower 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
9436408Ssklower 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
9536408Ssklower 
9636408Ssklower 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
9736408Ssklower 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
9836408Ssklower 
9936408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
10036408Ssklower 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
10136408Ssklower 
10236408Ssklower 		(short) 100, 			/* short p_lcdtfract */
10336408Ssklower 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
10436408Ssklower 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
10536408Ssklower 
10636408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
10736408Ssklower 		TPRX_USE_CW | TPRX_FASTSTART,
10836408Ssklower 								/* 4 bits p_rx_strat*/
10936408Ssklower 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
11036408Ssklower 		1,						/* 1 bit xtd format */
11136408Ssklower 		1,						/* 1 bit xpd service */
11236408Ssklower 		1,						/* 1 bit use_checksum */
11336408Ssklower 		0,						/* 1 bit use net xpd */
11436408Ssklower 		0,						/* 1 bit use rcc */
11536408Ssklower 		0,						/* 1 bit use efc */
11636408Ssklower 		0,						/* no disc indications */
11736408Ssklower 		0,						/* don't change params */
11836408Ssklower 		ISO_CLNS,				/* p_netservice */
11936408Ssklower 	},
12036408Ssklower 	/* IN_CLNS: TP4 CONNECTION LESS */
12136408Ssklower 	{
12236408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
12336408Ssklower 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
12436408Ssklower 
12536408Ssklower 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
12636408Ssklower 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
12736408Ssklower 
12836408Ssklower 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
12936408Ssklower 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
13036408Ssklower 
13136408Ssklower 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
13236408Ssklower 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
13336408Ssklower 
13436408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
13536408Ssklower 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
13636408Ssklower 
13736408Ssklower 		(short) 100, 			/* short p_lcdtfract */
13836408Ssklower 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
13936408Ssklower 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
14036408Ssklower 
14136408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
14236408Ssklower 		TPRX_USE_CW | TPRX_FASTSTART,
14336408Ssklower 								/* 4 bits p_rx_strat*/
14436408Ssklower 		TP_CLASS_4,				/* 5 bits p_class */
14536408Ssklower 		1,						/* 1 bit xtd format */
14636408Ssklower 		1,						/* 1 bit xpd service */
14736408Ssklower 		1,						/* 1 bit use_checksum */
14836408Ssklower 		0,						/* 1 bit use net xpd */
14936408Ssklower 		0,						/* 1 bit use rcc */
15036408Ssklower 		0,						/* 1 bit use efc */
15136408Ssklower 		0,						/* no disc indications */
15236408Ssklower 		0,						/* don't change params */
15336408Ssklower 		IN_CLNS,				/* p_netservice */
15436408Ssklower 	},
15536408Ssklower 	/* ISO_CONS: TP0 CONNECTION MODE */
15636408Ssklower 	{
15736408Ssklower 		TP_NRETRANS, 			/* short p_Nretrans;  */
15836408Ssklower 		0,		/* n/a */		/* short p_dr_ticks; */
15936408Ssklower 
16036408Ssklower 		40,		/* 20 sec */	/* short p_cc_ticks; */
16136408Ssklower 		0,		/* n/a */		/* short p_dt_ticks; */
16236408Ssklower 
16336408Ssklower 		0,		/* n/a */		/* short p_x_ticks;	*/
16436408Ssklower 		360,	/* 3  min */	/* short p_cr_ticks;*/
16536408Ssklower 
16636408Ssklower 		0,		/* n/a */		/* short p_keepalive_ticks;*/
16736408Ssklower 		0,		/* n/a */		/* short p_sendack_ticks; */
16836408Ssklower 
16936408Ssklower 		600,	/* for cr/cc to clear *//* short p_ref_ticks;	*/
17036408Ssklower 		0,		/* n/a */		/* short p_inact_ticks;	*/
17136408Ssklower 
17236408Ssklower 		/* Use tp4 defaults just in case the user changes ONLY
17336408Ssklower 		 * the class
17436408Ssklower 		 */
17536408Ssklower 		(short) 100, 			/* short p_lcdtfract */
17636408Ssklower 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
17736408Ssklower 		TP0_TPDUSIZE, 			/* 8 bits p_tpdusize */
17836408Ssklower 
17936408Ssklower 		0, 						/* 4 bits p_ack_strat */
18036408Ssklower 		0, 						/* 4 bits p_rx_strat*/
18136408Ssklower 		TP_CLASS_0,				/* 5 bits p_class */
18236408Ssklower 		0,						/* 1 bit xtd format */
18336408Ssklower 		0,						/* 1 bit xpd service */
18436408Ssklower 		0,						/* 1 bit use_checksum */
18536408Ssklower 		0,						/* 1 bit use net xpd */
18636408Ssklower 		0,						/* 1 bit use rcc */
18736408Ssklower 		0,						/* 1 bit use efc */
18836408Ssklower 		0,						/* no disc indications */
18936408Ssklower 		0,						/* don't change params */
19036408Ssklower 		ISO_CONS,				/* p_netservice */
19136408Ssklower 	},
19236408Ssklower 	/* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */
19336408Ssklower 	{
19436408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
19536408Ssklower 		40,		/* 20 sec */ 	/* short p_dr_ticks;  */
19636408Ssklower 
19736408Ssklower 		40,		/* 20 sec */ 	/* short p_cc_ticks; */
19836408Ssklower 		80,		/* 40 sec */ 	/* short p_dt_ticks; */
19936408Ssklower 
20036408Ssklower 		120,		/* 1 min */ 	/* short p_x_ticks;	 */
20136408Ssklower 		360,		/* 3 min */ 	/* short p_cr_ticks;*/
20236408Ssklower 
20336408Ssklower 		360,	/* 3 min */ 	/* short p_keepalive_ticks;*/
20436408Ssklower 		20,		/* 10 sec */ 	/* short p_sendack_ticks;  */
20536408Ssklower 
20636408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
20736408Ssklower 		480,	/* 4 min */ 	/* short p_inact_ticks;	*/
20836408Ssklower 
20936408Ssklower 		(short) 100, 			/* short p_lcdtfract */
21036408Ssklower 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
21136408Ssklower 		TP0_TPDUSIZE, 			/* u_char p_tpdusize */
21236408Ssklower 
21336408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
21436408Ssklower 		TPRX_USE_CW ,			/* No fast start */
21536408Ssklower 								/* 4 bits p_rx_strat*/
21636408Ssklower 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
21736408Ssklower 		0,						/* 1 bit xtd format */
21836408Ssklower 		1,						/* 1 bit xpd service */
21936408Ssklower 		1,						/* 1 bit use_checksum */
22036408Ssklower 		0,						/* 1 bit use net xpd */
22136408Ssklower 		0,						/* 1 bit use rcc */
22236408Ssklower 		0,						/* 1 bit use efc */
22336408Ssklower 		0,						/* no disc indications */
22436408Ssklower 		0,						/* don't change params */
22536408Ssklower 		ISO_COSNS,				/* p_netservice */
22636408Ssklower 	},
22736408Ssklower };
22836408Ssklower 
22936408Ssklower #ifdef INET
23036408Ssklower int		in_putnetaddr();
23136408Ssklower int		in_getnetaddr();
23236408Ssklower int 	in_putsufx();
23336408Ssklower int 	in_getsufx();
23436408Ssklower int 	in_recycle_tsuffix();
23536408Ssklower int 	tpip_mtu();
23636408Ssklower int 	in_pcbbind();
23736408Ssklower int 	in_pcbconnect();
23836408Ssklower int 	in_pcbdisconnect();
23936408Ssklower int 	in_pcbdetach();
24036408Ssklower int 	in_pcballoc();
24136408Ssklower int 	tpip_output();
24236408Ssklower int 	tpip_output_dg();
24336408Ssklower struct inpcb	tp_inpcb;
24436408Ssklower #endif INET
24536408Ssklower #ifdef ISO
24636408Ssklower int		iso_putnetaddr();
24736408Ssklower int		iso_getnetaddr();
24836408Ssklower int 	iso_putsufx();
24936408Ssklower int 	iso_getsufx();
25036408Ssklower int 	iso_recycle_tsuffix();
25136408Ssklower int		tpclnp_mtu();
25236408Ssklower int		iso_pcbbind();
25336408Ssklower int		iso_pcbconnect();
25436408Ssklower int		iso_pcbdisconnect();
25536408Ssklower int 	iso_pcbdetach();
25636408Ssklower int 	iso_pcballoc();
25736408Ssklower int 	tpclnp_output();
25836408Ssklower int 	tpclnp_output_dg();
25936408Ssklower int		iso_nlctloutput();
26036408Ssklower struct isopcb	tp_isopcb;
26136408Ssklower #endif ISO
26236408Ssklower #if NARGOXTWENTYFIVE > 0
26336408Ssklower int		iso_putnetaddr();
26436408Ssklower int		iso_getnetaddr();
26536408Ssklower int 	iso_putsufx();
26636408Ssklower int 	iso_getsufx();
26736408Ssklower int 	iso_recycle_tsuffix();
26836408Ssklower int		tpcons_mtu();
26936408Ssklower int		iso_pcbbind();
27036408Ssklower int		iso_pcbconnect();
27136408Ssklower int		iso_pcbdisconnect();
27236408Ssklower int 	iso_pcbdetach();
27336408Ssklower int 	iso_pcballoc();
27436408Ssklower int 	tpcons_output();
27536408Ssklower int 	tpcons_output_dg();
27636408Ssklower struct isopcb	tp_isopcb;
27736408Ssklower #endif NARGOXTWENTYFIVE
27836408Ssklower 
279*37469Ssklower 
28036408Ssklower struct nl_protosw nl_protosw[] = {
28136408Ssklower 	/* ISO_CLNS */
28236408Ssklower #ifdef ISO
28336408Ssklower 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr,
28436408Ssklower 		iso_putsufx, iso_getsufx,
28536408Ssklower 		iso_recycle_tsuffix,
28636408Ssklower 		tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
28736408Ssklower 		iso_pcbdisconnect,	iso_pcbdetach,
28836408Ssklower 		iso_pcballoc,
28936408Ssklower 		tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
29036408Ssklower 		(caddr_t) &tp_isopcb,
29136408Ssklower 		},
292*37469Ssklower #else
293*37469Ssklower 	{ 0 },
29436408Ssklower #endif ISO
29536408Ssklower 	/* IN_CLNS */
29636408Ssklower #ifdef INET
29736408Ssklower 	{ AF_INET, in_putnetaddr, in_getnetaddr,
29836408Ssklower 		in_putsufx, in_getsufx,
29936408Ssklower 		in_recycle_tsuffix,
30036408Ssklower 		tpip_mtu, in_pcbbind, in_pcbconnect,
30136408Ssklower 		in_pcbdisconnect,	in_pcbdetach,
30236408Ssklower 		in_pcballoc,
30336408Ssklower 		tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
30436408Ssklower 		(caddr_t) &tp_inpcb,
30536408Ssklower 		},
306*37469Ssklower #else
307*37469Ssklower 	{ 0 },
30836408Ssklower #endif INET
30936408Ssklower 	/* ISO_CONS */
310*37469Ssklower #if defined(ISO) && (NARGOXTWENTYFIVE > 0)
31136408Ssklower 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr,
31236408Ssklower 		iso_putsufx, iso_getsufx,
31336408Ssklower 		iso_recycle_tsuffix,
31436408Ssklower 		tpcons_mtu, iso_pcbbind, iso_pcbconnect,
31536408Ssklower 		iso_pcbdisconnect,	iso_pcbdetach,
31636408Ssklower 		iso_pcballoc,
31736408Ssklower 		tpcons_output, tpcons_output_dg, iso_nlctloutput,
31836408Ssklower 		(caddr_t) &tp_isopcb,
31936408Ssklower 		},
320*37469Ssklower #else
321*37469Ssklower 	{ 0 },
322*37469Ssklower #endif ISO_CONS
323*37469Ssklower 	/* End of protosw marker */
324*37469Ssklower 	{ 0 }
32536408Ssklower };
32636408Ssklower 
32736408Ssklower /*
32836408Ssklower  * NAME:  tp_init()
32936408Ssklower  *
33036408Ssklower  * CALLED FROM:
33136408Ssklower  *  autoconf through the protosw structure
33236408Ssklower  *
33336408Ssklower  * FUNCTION:
33436408Ssklower  *  initialize tp machine
33536408Ssklower  *
33636408Ssklower  * RETURNS:  Nada
33736408Ssklower  *
33836408Ssklower  * SIDE EFFECTS:
33936408Ssklower  *
34036408Ssklower  * NOTES:
34136408Ssklower  */
342*37469Ssklower int
34336408Ssklower tp_init()
34436408Ssklower {
34536408Ssklower 	static int 	init_done=0;
34636408Ssklower 	void	 	tp_timerinit();
34736408Ssklower 
34836408Ssklower 	if (init_done++)
349*37469Ssklower 		return 0;
35036408Ssklower 
35136408Ssklower 
35236408Ssklower 	/* FOR INET */
35336408Ssklower 	tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb;
35436408Ssklower 	/* FOR ISO */
35536408Ssklower 	tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
35636408Ssklower 
35736408Ssklower 	tp_timerinit();
35836408Ssklower 	bzero((caddr_t)&tp_stat, sizeof(struct tp_stat));
359*37469Ssklower 	return 0;
36036408Ssklower }
36136408Ssklower 
36236408Ssklower /*
36336408Ssklower  * NAME: 	tp_soisdisconnecting()
36436408Ssklower  *
36536408Ssklower  * CALLED FROM:
36636408Ssklower  *  tp.trans
36736408Ssklower  *
36836408Ssklower  * FUNCTION and ARGUMENTS:
36936408Ssklower  *  Set state of the socket (so) to reflect that fact that we're disconnectING
37036408Ssklower  *
37136408Ssklower  * RETURNS: 	Nada
37236408Ssklower  *
37336408Ssklower  * SIDE EFFECTS:
37436408Ssklower  *
37536408Ssklower  * NOTES:
37636408Ssklower  *  This differs from the regular soisdisconnecting() in that the latter
37736408Ssklower  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
37836408Ssklower  *  We don't want to set those flags because those flags will cause
37936408Ssklower  *  a SIGPIPE to be delivered in sosend() and we don't like that.
38036408Ssklower  *  If anyone else is sleeping on this socket, wake 'em up.
38136408Ssklower  */
38236408Ssklower void
38336408Ssklower tp_soisdisconnecting(so)
38436408Ssklower 	register struct socket *so;
38536408Ssklower {
38636408Ssklower 	so->so_state &= ~SS_ISCONNECTING;
38736408Ssklower 	so->so_state |= SS_ISDISCONNECTING;
38836408Ssklower 	if (so->so_head) {
38936408Ssklower 		if (!soqremque(so, 0) && !soqremque(so, 1))
39036408Ssklower 			panic("tp_soisdisconnecting");
39136408Ssklower 		so->so_head = 0;
39236408Ssklower 	}
39336408Ssklower 	wakeup((caddr_t)&so->so_timeo);
39436408Ssklower 	sowwakeup(so);
39536408Ssklower 	sorwakeup(so);
39636408Ssklower 	IFPERF(sototpcb(so))
39736408Ssklower 		register struct tp_pcb *tpcb = sototpcb(so);
39836408Ssklower 		u_int 	fsufx, lsufx;
39936408Ssklower 
400*37469Ssklower 		bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
401*37469Ssklower 		bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
40236408Ssklower 
403*37469Ssklower 		tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref);
40436408Ssklower 		tpcb->tp_perf_on = 0; /* turn perf off */
40536408Ssklower 	ENDPERF
40636408Ssklower }
40736408Ssklower 
40836408Ssklower 
40936408Ssklower /*
41036408Ssklower  * NAME: tp_soisdisconnected()
41136408Ssklower  *
41236408Ssklower  * CALLED FROM:
41336408Ssklower  *	tp.trans
41436408Ssklower  *
41536408Ssklower  * FUNCTION and ARGUMENTS:
41636408Ssklower  *  Set state of the socket (so) to reflect that fact that we're disconnectED
41736408Ssklower  *  Set the state of the reference structure to closed, and
41836408Ssklower  *  recycle the suffix.
41936408Ssklower  *  Start a reference timer.
42036408Ssklower  *
42136408Ssklower  * RETURNS:	Nada
42236408Ssklower  *
42336408Ssklower  * SIDE EFFECTS:
42436408Ssklower  *
42536408Ssklower  * NOTES:
42636408Ssklower  *  This differs from the regular soisdisconnected() in that the latter
42736408Ssklower  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
42836408Ssklower  *  We don't want to set those flags because those flags will cause
42936408Ssklower  *  a SIGPIPE to be delivered in sosend() and we don't like that.
43036408Ssklower  *  If anyone else is sleeping on this socket, wake 'em up.
43136408Ssklower  */
43236408Ssklower void
43336408Ssklower tp_soisdisconnected(tpcb)
43436408Ssklower 	register struct tp_pcb	*tpcb;
43536408Ssklower {
43636408Ssklower 	register struct socket	*so = tpcb->tp_sock;
43736408Ssklower 
43836408Ssklower 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
43936408Ssklower 	if (so->so_head) {
44036408Ssklower 		if (!soqremque(so, 0) && !soqremque(so, 1))
44136408Ssklower 			panic("tp_soisdisconnected");
44236408Ssklower 		so->so_head = 0;
44336408Ssklower 	}
44436408Ssklower 	wakeup((caddr_t)&so->so_timeo);
44536408Ssklower 	sowwakeup(so);
44636408Ssklower 	sorwakeup(so);
44736408Ssklower 	IFPERF(sototpcb(so))
448*37469Ssklower 		register struct tp_pcb *ttpcb = sototpcb(so);
44936408Ssklower 		u_int 	fsufx, lsufx;
45036408Ssklower 
45136408Ssklower 		/* CHOKE */
452*37469Ssklower 		bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
453*37469Ssklower 		bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
45436408Ssklower 
455*37469Ssklower 		tpmeas(ttpcb->tp_lref, TPtime_close,
456*37469Ssklower 		   &time, &lsufx, &fsufx, ttpcb->tp_fref);
45736408Ssklower 		tpcb->tp_perf_on = 0; /* turn perf off */
45836408Ssklower 	ENDPERF
45936408Ssklower 
46036408Ssklower 	tpcb->tp_refp->tpr_state = REF_FROZEN;
46136408Ssklower 	tp_recycle_tsuffix( tpcb );
46236408Ssklower 	tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks);
46336408Ssklower }
46436408Ssklower 
46536408Ssklower int tp_maxrefopen;  /* highest reference # of the set of open tp connections */
46636408Ssklower 
46736408Ssklower /*
46836408Ssklower  * NAME:	tp_freeref()
46936408Ssklower  *
47036408Ssklower  * CALLED FROM:
47136408Ssklower  *  tp.trans when the reference timer goes off, and
47236408Ssklower  *  from tp_attach() and tp_detach() when a tpcb is partially set up but not
47336408Ssklower  *  set up enough to have a ref timer set for it, and it's discarded
47436408Ssklower  *  due to some sort of error or an early close()
47536408Ssklower  *
47636408Ssklower  * FUNCTION and ARGUMENTS:
47736408Ssklower  *  Frees the reference represented by (r) for re-use.
47836408Ssklower  *
47936408Ssklower  * RETURNS: Nothing
48036408Ssklower  *
48136408Ssklower  * SIDE EFFECTS:
48236408Ssklower  *
48336408Ssklower  * NOTES:	better be called at clock priority !!!!!
48436408Ssklower  */
48536408Ssklower void
48636408Ssklower tp_freeref(r)
48736408Ssklower 	register struct tp_ref *r;
48836408Ssklower {
48936408Ssklower 	IFDEBUG(D_TIMER)
49036408Ssklower 		printf("tp_freeref called for ref %d maxrefopen %d\n",
49136408Ssklower 		r - tp_ref, tp_maxrefopen);
49236408Ssklower 	ENDDEBUG
49336408Ssklower 	IFTRACE(D_TIMER)
49436408Ssklower 		tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen",
49536408Ssklower 		r - tp_ref, tp_maxrefopen, 0, 0);
49636408Ssklower 	ENDTRACE
49736408Ssklower 	r->tpr_state = REF_FREE;
49836408Ssklower 	IFDEBUG(D_CONN)
49936408Ssklower 		printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb);
50036408Ssklower 	ENDDEBUG
50136408Ssklower 	r->tpr_pcb = (struct tp_pcb *)0;
50236408Ssklower 
50336408Ssklower 	r = &tp_ref[tp_maxrefopen];
50436408Ssklower 
50536408Ssklower 	while( tp_maxrefopen > 0 ) {
50636408Ssklower 		if(r->tpr_state )
50736408Ssklower 			break;
50836408Ssklower 		tp_maxrefopen--;
50936408Ssklower 		r--;
51036408Ssklower 	}
51136408Ssklower 	IFDEBUG(D_TIMER)
51236408Ssklower 		printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen);
51336408Ssklower 	ENDDEBUG
51436408Ssklower }
51536408Ssklower 
51636408Ssklower /*
51736408Ssklower  * NAME:  tp_getref()
51836408Ssklower  *
51936408Ssklower  * CALLED FROM:
52036408Ssklower  *  tp_attach()
52136408Ssklower  *
52236408Ssklower  * FUNCTION and ARGUMENTS:
52336408Ssklower  *  obtains the next free reference and allocates the appropriate
52436408Ssklower  *  ref structure, links that structure to (tpcb)
52536408Ssklower  *
52636408Ssklower  * RETURN VALUE:
52736408Ssklower  *	a reference number
52836408Ssklower  *  or TP_ENOREF
52936408Ssklower  *
53036408Ssklower  * SIDE EFFECTS:
53136408Ssklower  *
53236408Ssklower  * NOTES:
53336408Ssklower  */
53436408Ssklower static RefNum
53536408Ssklower tp_getref(tpcb)
53636408Ssklower 	register struct tp_pcb *tpcb;
53736408Ssklower {
53836408Ssklower 	register struct tp_ref	*r = tp_ref;
53936408Ssklower 	register int 			i=1;
54036408Ssklower 
54136408Ssklower 	r++; /* tp_ref[0] is never used */
54236408Ssklower 
54336408Ssklower 	/* REF_FREE is zero */
54436408Ssklower 	while( r->tpr_state ) {
54536408Ssklower 		r++;
54636408Ssklower 		if ( i == N_TPREF ) {
54736408Ssklower 			return TP_ENOREF;
54836408Ssklower 		}
54936408Ssklower 		i++;
55036408Ssklower 	}
55136408Ssklower 	r->tpr_state = REF_OPENING;
55236408Ssklower 	if (tp_maxrefopen < i)
55336408Ssklower 		tp_maxrefopen = i;
55436408Ssklower 	r->tpr_pcb = tpcb;
55536408Ssklower 	tpcb->tp_refp = r;
55636408Ssklower 
55736408Ssklower 	return i;
55836408Ssklower }
55936408Ssklower 
56036408Ssklower /*
56136408Ssklower  * NAME: tp_attach()
56236408Ssklower  *
56336408Ssklower  * CALLED FROM:
56436408Ssklower  *	tp_usrreq, PRU_ATTACH
56536408Ssklower  *
56636408Ssklower  * FUNCTION and ARGUMENTS:
56736408Ssklower  *  given a socket (so) and a protocol family (dom), allocate a tpcb
56836408Ssklower  *  and ref structure, initialize everything in the structures that
56936408Ssklower  *  needs to be initialized.
57036408Ssklower  *
57136408Ssklower  * RETURN VALUE:
57236408Ssklower  *  0 ok
57336408Ssklower  *  EINVAL if DEBUG(X) in is on and a disaster has occurred
57436408Ssklower  *  ENOPROTOOPT if TP hasn't been configured or if the
57536408Ssklower  *   socket wasn't created with tp as its protocol
57636408Ssklower  *  EISCONN if this socket is already part of a connection
57736408Ssklower  *  ETOOMANYREFS if ran out of tp reference numbers.
57836408Ssklower  *  E* whatever error is returned from soreserve()
57936408Ssklower  *    for from the network-layer pcb allocation routine
58036408Ssklower  *
58136408Ssklower  * SIDE EFFECTS:
58236408Ssklower  *
58336408Ssklower  * NOTES:
58436408Ssklower  */
585*37469Ssklower tp_attach(so, dom)
58636408Ssklower 	struct socket 	*so;
58736408Ssklower 	int 			dom;
58836408Ssklower {
58936408Ssklower 	register struct tp_pcb	*tpcb;
59036408Ssklower 	int 					error;
59136408Ssklower 	int 					protocol = so->so_proto->pr_protocol;
59236408Ssklower 	extern struct tp_conn_param tp_conn_param[];
59336408Ssklower 
59436408Ssklower 	IFDEBUG(D_CONN)
59536408Ssklower 		printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
59636408Ssklower 	ENDDEBUG
59736408Ssklower 	IFTRACE(D_CONN)
59836408Ssklower 		tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
59936408Ssklower 	ENDTRACE
60036408Ssklower 	if ( ! tp_param.tpp_configed ) {
60136408Ssklower 		error = ENOPROTOOPT; /* protocol not available */
60236408Ssklower 		goto bad2;
60336408Ssklower 	}
60436408Ssklower 
60536408Ssklower 	if (so->so_pcb != NULL) {
60636408Ssklower 		return EISCONN;	/* socket already part of a connection*/
60736408Ssklower 	}
60836408Ssklower 
60936408Ssklower 	error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE);
61036408Ssklower 		/* later an ioctl will allow reallocation IF still in closed state */
61136408Ssklower 
61236408Ssklower 	if (error)
61336408Ssklower 		goto bad2;
61436408Ssklower 
615*37469Ssklower 	MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
616*37469Ssklower 	if (tpcb == NULL) {
61736408Ssklower 		error = ENOBUFS;
61836408Ssklower 		goto bad2;
61936408Ssklower 	}
62036408Ssklower 	bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
62136408Ssklower 
62236408Ssklower 	if ( ((tpcb->tp_lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) {
62336408Ssklower 		error = ETOOMANYREFS;
62436408Ssklower 		goto bad3;
62536408Ssklower 	}
62636408Ssklower 	tpcb->tp_sock =  so;
62736408Ssklower 	tpcb->tp_domain = dom;
62836408Ssklower 	if (protocol<ISOPROTO_TP4) {
62936408Ssklower 		tpcb->tp_netservice = ISO_CONS;
63036408Ssklower 		tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
63136408Ssklower 								 * will generate correct fake-ack values
63236408Ssklower 								 */
63336408Ssklower 	} else {
63436408Ssklower 		tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
63536408Ssklower 		/* the default */
63636408Ssklower 	}
63736408Ssklower 	tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
63836408Ssklower 
63936408Ssklower 	tpcb->tp_cong_win = 1;
64036408Ssklower 	tpcb->tp_state = TP_CLOSED;
64136408Ssklower 	tpcb->tp_vers  = TP_VERSION;
64236408Ssklower 
64336408Ssklower 		   /* Spec says default is 128 octets,
64436408Ssklower 			* that is, if the tpdusize argument never appears, use 128.
64536408Ssklower 			* As the initiator, we will always "propose" the 2048
64636408Ssklower 			* size, that is, we will put this argument in the CR
64736408Ssklower 			* always, but accept what the other side sends on the CC.
64836408Ssklower 			* If the initiator sends us something larger on a CR,
64936408Ssklower 			* we'll respond w/ this.
65036408Ssklower 			* Our maximum is 4096.  See tp_chksum.c comments.
65136408Ssklower 			*/
65236408Ssklower 	tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
65336408Ssklower 
65436408Ssklower 	tpcb->tp_seqmask  = TP_NML_FMT_MASK;
65536408Ssklower 	tpcb->tp_seqbit  =  TP_NML_FMT_BIT;
65636408Ssklower 	tpcb->tp_seqhalf  =  tpcb->tp_seqbit >> 1;
65736408Ssklower 	tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */
65836408Ssklower 	tpcb->tp_s_subseq = 0;
65936408Ssklower 
66036408Ssklower 	/* attach to a network-layer protoswitch */
66136408Ssklower 	/* new way */
66236408Ssklower 	tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice];
66336408Ssklower 	ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
66436408Ssklower #ifdef notdef
66536408Ssklower 	/* OLD WAY */
66636408Ssklower 	/* TODO: properly, this search would be on the basis of
66736408Ssklower 	* domain,netservice or just netservice only (if you have
66836408Ssklower 	* IN_CLNS, ISO_CLNS, and ISO_CONS)
66936408Ssklower 	*/
67036408Ssklower 	tpcb->tp_nlproto = nl_protosw;
67136408Ssklower 	while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain )  {
67236408Ssklower 		if( tpcb->tp_nlproto->nlp_afamily == 0 ) {
67336408Ssklower 			error = EAFNOSUPPORT;
67436408Ssklower 			goto bad4;
67536408Ssklower 		}
67636408Ssklower 		tpcb->tp_nlproto ++;
67736408Ssklower 	}
67836408Ssklower #endif notdef
67936408Ssklower 
68036408Ssklower 	/* xx_pcballoc sets so_pcb */
68136408Ssklower 	if ( error =  (tpcb->tp_nlproto->nlp_pcballoc) (
68236408Ssklower 							so, tpcb->tp_nlproto->nlp_pcblist ) ) {
68336408Ssklower 		goto bad4;
68436408Ssklower 	}
68536408Ssklower 
68636408Ssklower 	if( dom == AF_INET )
68736408Ssklower 		sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
68836408Ssklower 		/* nothing to do for iso case */
68936408Ssklower 
69036408Ssklower 	tpcb->tp_npcb = (caddr_t) so->so_pcb;
69136408Ssklower 	so->so_tpcb = (caddr_t) tpcb;
69236408Ssklower 
69336408Ssklower 	return 0;
69436408Ssklower 
69536408Ssklower bad4:
69636408Ssklower 	IFDEBUG(D_CONN)
69736408Ssklower 		printf("BAD4 in tp_attach, so 0x%x\n", so);
69836408Ssklower 	ENDDEBUG
69936408Ssklower 	tp_freeref(tpcb->tp_refp);
70036408Ssklower 
70136408Ssklower bad3:
70236408Ssklower 	IFDEBUG(D_CONN)
70336408Ssklower 		printf("BAD3 in tp_attach, so 0x%x\n", so);
70436408Ssklower 	ENDDEBUG
70536408Ssklower 
706*37469Ssklower 	free((caddr_t)tpcb, M_PCB); /* never a cluster  */
70736408Ssklower 
70836408Ssklower bad2:
70936408Ssklower 	IFDEBUG(D_CONN)
71036408Ssklower 		printf("BAD2 in tp_attach, so 0x%x\n", so);
71136408Ssklower 	ENDDEBUG
71236408Ssklower 	so->so_pcb = 0;
71336408Ssklower 	so->so_tpcb = 0;
71436408Ssklower 	sofree(so);
71536408Ssklower 
716*37469Ssklower /*bad:*/
71736408Ssklower 	IFDEBUG(D_CONN)
71836408Ssklower 		printf("BAD in tp_attach, so 0x%x\n", so);
71936408Ssklower 	ENDDEBUG
72036408Ssklower 	return error;
72136408Ssklower }
72236408Ssklower 
72336408Ssklower /*
72436408Ssklower  * NAME:  tp_detach()
72536408Ssklower  *
72636408Ssklower  * CALLED FROM:
72736408Ssklower  *	tp.trans, on behalf of a user close request
72836408Ssklower  *  and when the reference timer goes off
72936408Ssklower  * (if the disconnect  was initiated by the protocol entity
73036408Ssklower  * rather than by the user)
73136408Ssklower  *
73236408Ssklower  * FUNCTION and ARGUMENTS:
73336408Ssklower  *  remove the tpcb structure from the list of active or
73436408Ssklower  *  partially active connections, recycle all the mbufs
73536408Ssklower  *  associated with the pcb, ref structure, sockbufs, etc.
73636408Ssklower  *  Only free the ref structure if you know that a ref timer
73736408Ssklower  *  wasn't set for this tpcb.
73836408Ssklower  *
73936408Ssklower  * RETURNS:  Nada
74036408Ssklower  *
74136408Ssklower  * SIDE EFFECTS:
74236408Ssklower  *
74336408Ssklower  * NOTES:
74436408Ssklower  *  tp_soisdisconnected() was already when this is called
74536408Ssklower  */
74636408Ssklower void
74736408Ssklower tp_detach(tpcb)
74836408Ssklower 	register struct tp_pcb 	*tpcb;
74936408Ssklower {
75036408Ssklower 	void					tp_freeref();
75136408Ssklower 	register struct socket	 *so = tpcb->tp_sock;
75236408Ssklower 
75336408Ssklower 	IFDEBUG(D_CONN)
754*37469Ssklower 		printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
755*37469Ssklower 			tpcb,so);
75636408Ssklower 	ENDDEBUG
75736408Ssklower 	IFTRACE(D_CONN)
75836408Ssklower 		tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
75936408Ssklower 			tpcb, so, *(int *)(tpcb->tp_lsuffix), 0);
76036408Ssklower 	ENDTRACE
76136408Ssklower 
76236408Ssklower 	if (so->so_head) {
76336408Ssklower 		if (!soqremque(so, 0) && !soqremque(so, 1))
76436408Ssklower 			panic("sofree dq");
76536408Ssklower 		so->so_head = 0;
76636408Ssklower 	}
76736408Ssklower 
76836408Ssklower 	IFDEBUG(D_CONN)
76936408Ssklower 		printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n",
77036408Ssklower 		tpcb->tp_snduna_rtc,
77136408Ssklower 		tpcb->tp_rcvnxt_rtc);
77236408Ssklower 	ENDDEBUG
77336408Ssklower 
77436408Ssklower #define FREE_RTC_LIST(XXX)\
77536408Ssklower 	{ register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\
77636408Ssklower 		xxs = xxr->tprt_next;\
77736408Ssklower 		m_freem( xxr->tprt_data );\
77836408Ssklower 		m_free( dtom(xxr) ); xxr = xxs; }\
77936408Ssklower 		XXX = (struct tp_rtc *)0;\
78036408Ssklower 	}
78136408Ssklower 
78236408Ssklower 	FREE_RTC_LIST( tpcb->tp_snduna_rtc );
78336408Ssklower 	tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0;
78436408Ssklower 
78536408Ssklower 	FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc );
78636408Ssklower 
78736408Ssklower #undef FREE_RTC_LIST
78836408Ssklower 
78936408Ssklower 	IFDEBUG(D_CONN)
79036408Ssklower 		printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
79136408Ssklower 			so->so_pcb, so);
79236408Ssklower 		printf("so 0x%x so_head 0x%x,  qlen %d q0len %d qlimit %d\n",
79336408Ssklower 		so,  so->so_head,
79436408Ssklower 		so->so_q0len, so->so_qlen, so->so_qlimit);
79536408Ssklower 	ENDDEBUG
79636408Ssklower 
797*37469Ssklower 	if ( tpcb->tp_flags & (TPF_DISC_DATA_OUT | TPF_CONN_DATA_OUT ) )  {
79836408Ssklower 		ASSERT( so->so_snd.sb_cc != 0 );
79936408Ssklower 		IFDEBUG(D_CONN)
80036408Ssklower 			printf(
80136408Ssklower 			"detach, flags 0x%x doing sbdrop on so_snd, mb 0x%x cc 0x%x\n",
80236408Ssklower 				tpcb->tp_flags, so->so_snd.sb_mb, so->so_snd.sb_cc);
80336408Ssklower 			dump_mbuf( so->so_snd.sb_mb, "detach so snd: \n");
80436408Ssklower 		ENDDEBUG
80536408Ssklower 		if ( so->so_snd.sb_cc != 0 )
806*37469Ssklower 			sbflush(&so->so_snd);
80736408Ssklower 		tpcb->tp_flags &= ~(TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT);
80836408Ssklower 	}
80936408Ssklower 	if ( tpcb->tp_flags & (TPF_DISC_DATA_IN | TPF_CONN_DATA_IN ) ) {
81036408Ssklower 		ASSERT( tpcb->tp_Xrcv.sb_cc != 0 );
81136408Ssklower 		IFDEBUG(D_CONN)
81236408Ssklower 			printf(
81336408Ssklower 			"detach, flags 0x%x doing sbdrop on tp_Xrcv, mb 0x%x cc 0x%x\n",
81436408Ssklower 				tpcb->tp_flags, tpcb->tp_Xrcv.sb_mb, tpcb->tp_Xrcv.sb_cc);
81536408Ssklower 			dump_mbuf( tpcb->tp_Xrcv.sb_mb, "detach Xrcv: \n");
81636408Ssklower 		ENDDEBUG
81736408Ssklower 		if( tpcb->tp_Xrcv.sb_cc != 0 )
818*37469Ssklower 			sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc);
81936408Ssklower 		tpcb->tp_flags &= ~(TPF_CONN_DATA_IN | TPF_DISC_DATA_IN);
82036408Ssklower 	}
82136408Ssklower 
82236408Ssklower 	IFDEBUG(D_CONN)
82336408Ssklower 		printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv);
82436408Ssklower 		dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
82536408Ssklower 		printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n",
82636408Ssklower 				tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
82736408Ssklower 	ENDDEBUG
82836408Ssklower 
82936408Ssklower 
830*37469Ssklower 
831*37469Ssklower 	(tpcb->tp_nlproto->nlp_pcbdetach)((struct inpcb *)so->so_pcb);
832*37469Ssklower 				/* does an sofree(so) */
833*37469Ssklower 
83436408Ssklower 	IFDEBUG(D_CONN)
83536408Ssklower 		printf("after xxx_pcbdetach\n");
83636408Ssklower 	ENDDEBUG
83736408Ssklower 
83836408Ssklower 	if( tpcb->tp_refp->tpr_state == REF_OPENING ) {
83936408Ssklower 		/* no connection existed here so no reference timer will be called */
84036408Ssklower 		IFDEBUG(D_CONN)
84136408Ssklower 			printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref,
84236408Ssklower 			tpcb->tp_refp - &tp_ref[0]);
84336408Ssklower 		ENDDEBUG
84436408Ssklower 
84536408Ssklower 		tp_freeref(tpcb->tp_refp);
84636408Ssklower 	}
84736408Ssklower 
848*37469Ssklower 	if (tpcb->tp_Xsnd.sb_mb) {
849*37469Ssklower 		printf("Unsent Xdata on detach; would panic");
850*37469Ssklower 		sbflush(&tpcb->tp_Xsnd);
851*37469Ssklower 	}
85236408Ssklower 	so->so_tpcb = (caddr_t)0;
85336408Ssklower 
85436408Ssklower 	/*
85536408Ssklower 	 * Get rid of the cluster mbuf allocated for performance measurements, if
85636408Ssklower 	 * there is one.  Note that tpcb->tp_perf_on says nothing about whether or
85736408Ssklower 	 * not a cluster mbuf was allocated, so you have to check for a pointer
85836408Ssklower 	 * to one (that is, we need the TP_PERF_MEASs around the following section
85936408Ssklower 	 * of code, not the IFPERFs)
86036408Ssklower 	 */
86136408Ssklower #ifdef TP_PERF_MEAS
862*37469Ssklower 	if(tpcb->tp_p_mbuf) {
863*37469Ssklower 		register struct mbuf *m = tpcb->tp_p_mbuf;
864*37469Ssklower 		struct mbuf *n;
86536408Ssklower 		IFDEBUG(D_PERF_MEAS)
86636408Ssklower 			printf("freeing tp_p_meas 0x%x  ", tpcb->tp_p_meas);
86736408Ssklower 		ENDDEBUG
868*37469Ssklower 		do {
869*37469Ssklower 		    MFREE(m, n);
870*37469Ssklower 		    m = n;
871*37469Ssklower 		} while (n);
872*37469Ssklower 		tpcb->tp_p_meas = 0;
873*37469Ssklower 		tpcb->tp_p_mbuf = 0;
87436408Ssklower 	}
87536408Ssklower #endif TP_PERF_MEAS
87636408Ssklower 
87736408Ssklower 	IFDEBUG(D_CONN)
878*37469Ssklower 		printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
87936408Ssklower 	ENDDEBUG
880*37469Ssklower 	/* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
88136408Ssklower }
882