xref: /csrg-svn/sys/netiso/tp_pcb.c (revision 51204)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51204Ssklower  *	@(#)tp_pcb.c	7.18 (Berkeley) 09/26/91
849268Sbostic  */
949268Sbostic 
1036408Ssklower /***********************************************************
1139196Ssklower 				Copyright IBM Corporation 1987
1236408Ssklower 
1336408Ssklower                       All Rights Reserved
1436408Ssklower 
1536408Ssklower Permission to use, copy, modify, and distribute this software and its
1636408Ssklower documentation for any purpose and without fee is hereby granted,
1736408Ssklower provided that the above copyright notice appear in all copies and that
1836408Ssklower both that copyright notice and this permission notice appear in
1936408Ssklower supporting documentation, and that the name of IBM not be
2036408Ssklower used in advertising or publicity pertaining to distribution of the
2136408Ssklower software without specific, written prior permission.
2236408Ssklower 
2336408Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436408Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536408Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636408Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736408Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836408Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936408Ssklower SOFTWARE.
3036408Ssklower 
3136408Ssklower ******************************************************************/
3236408Ssklower 
3336408Ssklower /*
3436408Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536408Ssklower  */
3636408Ssklower /*
3736408Ssklower  * ARGO TP
3836408Ssklower  *
3936408Ssklower  * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $
4036408Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $
4136408Ssklower  *
4236408Ssklower  *
4336408Ssklower  * This is the initialization and cleanup stuff -
4436408Ssklower  * for the tp machine in general as well as  for the individual pcbs.
4536408Ssklower  * tp_init() is called at system startup.  tp_attach() and tp_getref() are
4636408Ssklower  * called when a socket is created.  tp_detach() and tp_freeref()
4736408Ssklower  * are called during the closing stage and/or when the reference timer
4836408Ssklower  * goes off.
4936408Ssklower  * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific
5036408Ssklower  * versions of soisconnect*
5136408Ssklower  * and are called (obviously) during the closing phase.
5236408Ssklower  *
5336408Ssklower  */
5436408Ssklower 
5536408Ssklower #include "param.h"
5650648Ssklower #include "systm.h"
5736408Ssklower #include "mbuf.h"
5836408Ssklower #include "socket.h"
5936408Ssklower #include "socketvar.h"
6050648Ssklower #include "domain.h"
6136408Ssklower #include "protosw.h"
6236408Ssklower #include "errno.h"
6336408Ssklower #include "time.h"
6437469Ssklower #include "argo_debug.h"
6537469Ssklower #include "tp_param.h"
6637469Ssklower #include "tp_timer.h"
6737469Ssklower #include "tp_ip.h"
6837469Ssklower #include "tp_stat.h"
6937469Ssklower #include "tp_pcb.h"
7037469Ssklower #include "tp_tpdu.h"
7137469Ssklower #include "tp_trace.h"
7237469Ssklower #include "tp_meas.h"
7337469Ssklower #include "tp_seq.h"
7437469Ssklower #include "tp_clnp.h"
7536408Ssklower 
7636408Ssklower struct tp_param tp_param = {
7736408Ssklower 	1,				/*  configured 		*/
7836408Ssklower };
7936408Ssklower 
8036408Ssklower /* ticks are in units of:
8136408Ssklower  * 500 nano-fortnights ;-) or
8236408Ssklower  * 500 ms or
8336408Ssklower  * 1/2 second
8436408Ssklower  */
8536408Ssklower 
8636408Ssklower struct tp_conn_param tp_conn_param[] = {
8736408Ssklower 	/* ISO_CLNS: TP4 CONNECTION LESS */
8836408Ssklower 	{
8936408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
9036408Ssklower 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
9136408Ssklower 
9236408Ssklower 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
9336408Ssklower 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
9436408Ssklower 
9536408Ssklower 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
9636408Ssklower 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
9736408Ssklower 
9836408Ssklower 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
9936408Ssklower 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
10036408Ssklower 
10136408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
10236408Ssklower 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
10336408Ssklower 
10436408Ssklower 		(short) 100, 			/* short p_lcdtfract */
10536408Ssklower 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
10636408Ssklower 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
10736408Ssklower 
10836408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
10936408Ssklower 		TPRX_USE_CW | TPRX_FASTSTART,
11036408Ssklower 								/* 4 bits p_rx_strat*/
11136408Ssklower 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
11236408Ssklower 		1,						/* 1 bit xtd format */
11336408Ssklower 		1,						/* 1 bit xpd service */
11436408Ssklower 		1,						/* 1 bit use_checksum */
11536408Ssklower 		0,						/* 1 bit use net xpd */
11636408Ssklower 		0,						/* 1 bit use rcc */
11736408Ssklower 		0,						/* 1 bit use efc */
11838841Ssklower 		1,						/* no disc indications */
11936408Ssklower 		0,						/* don't change params */
12036408Ssklower 		ISO_CLNS,				/* p_netservice */
12136408Ssklower 	},
12236408Ssklower 	/* IN_CLNS: TP4 CONNECTION LESS */
12336408Ssklower 	{
12436408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
12536408Ssklower 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
12636408Ssklower 
12736408Ssklower 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
12836408Ssklower 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
12936408Ssklower 
13036408Ssklower 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
13136408Ssklower 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
13236408Ssklower 
13336408Ssklower 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
13436408Ssklower 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
13536408Ssklower 
13636408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
13736408Ssklower 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
13836408Ssklower 
13936408Ssklower 		(short) 100, 			/* short p_lcdtfract */
14036408Ssklower 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
14136408Ssklower 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
14236408Ssklower 
14336408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
14436408Ssklower 		TPRX_USE_CW | TPRX_FASTSTART,
14536408Ssklower 								/* 4 bits p_rx_strat*/
14636408Ssklower 		TP_CLASS_4,				/* 5 bits p_class */
14736408Ssklower 		1,						/* 1 bit xtd format */
14836408Ssklower 		1,						/* 1 bit xpd service */
14936408Ssklower 		1,						/* 1 bit use_checksum */
15036408Ssklower 		0,						/* 1 bit use net xpd */
15136408Ssklower 		0,						/* 1 bit use rcc */
15236408Ssklower 		0,						/* 1 bit use efc */
15338841Ssklower 		1,						/* no disc indications */
15436408Ssklower 		0,						/* don't change params */
15536408Ssklower 		IN_CLNS,				/* p_netservice */
15636408Ssklower 	},
15736408Ssklower 	/* ISO_CONS: TP0 CONNECTION MODE */
15836408Ssklower 	{
15936408Ssklower 		TP_NRETRANS, 			/* short p_Nretrans;  */
16036408Ssklower 		0,		/* n/a */		/* short p_dr_ticks; */
16136408Ssklower 
16236408Ssklower 		40,		/* 20 sec */	/* short p_cc_ticks; */
16336408Ssklower 		0,		/* n/a */		/* short p_dt_ticks; */
16436408Ssklower 
16536408Ssklower 		0,		/* n/a */		/* short p_x_ticks;	*/
16636408Ssklower 		360,	/* 3  min */	/* short p_cr_ticks;*/
16736408Ssklower 
16836408Ssklower 		0,		/* n/a */		/* short p_keepalive_ticks;*/
16936408Ssklower 		0,		/* n/a */		/* short p_sendack_ticks; */
17036408Ssklower 
17136408Ssklower 		600,	/* for cr/cc to clear *//* short p_ref_ticks;	*/
17236408Ssklower 		0,		/* n/a */		/* short p_inact_ticks;	*/
17336408Ssklower 
17436408Ssklower 		/* Use tp4 defaults just in case the user changes ONLY
17536408Ssklower 		 * the class
17636408Ssklower 		 */
17736408Ssklower 		(short) 100, 			/* short p_lcdtfract */
17836408Ssklower 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
17936408Ssklower 		TP0_TPDUSIZE, 			/* 8 bits p_tpdusize */
18036408Ssklower 
18136408Ssklower 		0, 						/* 4 bits p_ack_strat */
18236408Ssklower 		0, 						/* 4 bits p_rx_strat*/
18336408Ssklower 		TP_CLASS_0,				/* 5 bits p_class */
18436408Ssklower 		0,						/* 1 bit xtd format */
18536408Ssklower 		0,						/* 1 bit xpd service */
18636408Ssklower 		0,						/* 1 bit use_checksum */
18736408Ssklower 		0,						/* 1 bit use net xpd */
18836408Ssklower 		0,						/* 1 bit use rcc */
18936408Ssklower 		0,						/* 1 bit use efc */
19036408Ssklower 		0,						/* no disc indications */
19136408Ssklower 		0,						/* don't change params */
19236408Ssklower 		ISO_CONS,				/* p_netservice */
19336408Ssklower 	},
19436408Ssklower 	/* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */
19536408Ssklower 	{
19636408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
19736408Ssklower 		40,		/* 20 sec */ 	/* short p_dr_ticks;  */
19836408Ssklower 
19936408Ssklower 		40,		/* 20 sec */ 	/* short p_cc_ticks; */
20036408Ssklower 		80,		/* 40 sec */ 	/* short p_dt_ticks; */
20136408Ssklower 
20236408Ssklower 		120,		/* 1 min */ 	/* short p_x_ticks;	 */
20336408Ssklower 		360,		/* 3 min */ 	/* short p_cr_ticks;*/
20436408Ssklower 
20536408Ssklower 		360,	/* 3 min */ 	/* short p_keepalive_ticks;*/
20636408Ssklower 		20,		/* 10 sec */ 	/* short p_sendack_ticks;  */
20736408Ssklower 
20836408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
20936408Ssklower 		480,	/* 4 min */ 	/* short p_inact_ticks;	*/
21036408Ssklower 
21136408Ssklower 		(short) 100, 			/* short p_lcdtfract */
21236408Ssklower 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
21336408Ssklower 		TP0_TPDUSIZE, 			/* u_char p_tpdusize */
21436408Ssklower 
21536408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
21636408Ssklower 		TPRX_USE_CW ,			/* No fast start */
21736408Ssklower 								/* 4 bits p_rx_strat*/
21836408Ssklower 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
21936408Ssklower 		0,						/* 1 bit xtd format */
22036408Ssklower 		1,						/* 1 bit xpd service */
22136408Ssklower 		1,						/* 1 bit use_checksum */
22236408Ssklower 		0,						/* 1 bit use net xpd */
22336408Ssklower 		0,						/* 1 bit use rcc */
22436408Ssklower 		0,						/* 1 bit use efc */
22536408Ssklower 		0,						/* no disc indications */
22636408Ssklower 		0,						/* don't change params */
22736408Ssklower 		ISO_COSNS,				/* p_netservice */
22836408Ssklower 	},
22936408Ssklower };
23036408Ssklower 
23136408Ssklower #ifdef INET
23236408Ssklower int		in_putnetaddr();
23336408Ssklower int		in_getnetaddr();
23444423Ssklower int		in_cmpnetaddr();
23536408Ssklower int 	in_putsufx();
23636408Ssklower int 	in_getsufx();
23736408Ssklower int 	in_recycle_tsuffix();
23836408Ssklower int 	tpip_mtu();
23936408Ssklower int 	in_pcbbind();
24036408Ssklower int 	in_pcbconnect();
24136408Ssklower int 	in_pcbdisconnect();
24236408Ssklower int 	in_pcbdetach();
24336408Ssklower int 	in_pcballoc();
24436408Ssklower int 	tpip_output();
24536408Ssklower int 	tpip_output_dg();
24636408Ssklower struct inpcb	tp_inpcb;
24736408Ssklower #endif INET
24836408Ssklower #ifdef ISO
24936408Ssklower int		iso_putnetaddr();
25036408Ssklower int		iso_getnetaddr();
25144423Ssklower int		iso_cmpnetaddr();
25236408Ssklower int 	iso_putsufx();
25336408Ssklower int 	iso_getsufx();
25436408Ssklower int 	iso_recycle_tsuffix();
25536408Ssklower int		tpclnp_mtu();
25636408Ssklower int		iso_pcbbind();
25736408Ssklower int		iso_pcbconnect();
25836408Ssklower int		iso_pcbdisconnect();
25936408Ssklower int 	iso_pcbdetach();
26036408Ssklower int 	iso_pcballoc();
26136408Ssklower int 	tpclnp_output();
26236408Ssklower int 	tpclnp_output_dg();
26336408Ssklower int		iso_nlctloutput();
26436408Ssklower struct isopcb	tp_isopcb;
26536408Ssklower #endif ISO
26645900Ssklower #ifdef TPCONS
26736408Ssklower int		iso_putnetaddr();
26836408Ssklower int		iso_getnetaddr();
26944423Ssklower int		iso_cmpnetaddr();
27036408Ssklower int 	iso_putsufx();
27136408Ssklower int 	iso_getsufx();
27236408Ssklower int 	iso_recycle_tsuffix();
27336408Ssklower int		iso_pcbbind();
27445900Ssklower int		tpcons_pcbconnect();
27549258Ssklower int		tpclnp_mtu();
27636408Ssklower int		iso_pcbdisconnect();
27736408Ssklower int 	iso_pcbdetach();
27836408Ssklower int 	iso_pcballoc();
27936408Ssklower int 	tpcons_output();
28036408Ssklower struct isopcb	tp_isopcb;
28145900Ssklower #endif TPCONS
28236408Ssklower 
28337469Ssklower 
28436408Ssklower struct nl_protosw nl_protosw[] = {
28536408Ssklower 	/* ISO_CLNS */
28636408Ssklower #ifdef ISO
28744423Ssklower 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
28836408Ssklower 		iso_putsufx, iso_getsufx,
28936408Ssklower 		iso_recycle_tsuffix,
29036408Ssklower 		tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
29136408Ssklower 		iso_pcbdisconnect,	iso_pcbdetach,
29236408Ssklower 		iso_pcballoc,
29336408Ssklower 		tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
29436408Ssklower 		(caddr_t) &tp_isopcb,
29536408Ssklower 		},
29637469Ssklower #else
29737469Ssklower 	{ 0 },
29836408Ssklower #endif ISO
29936408Ssklower 	/* IN_CLNS */
30036408Ssklower #ifdef INET
30144423Ssklower 	{ AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr,
30236408Ssklower 		in_putsufx, in_getsufx,
30336408Ssklower 		in_recycle_tsuffix,
30436408Ssklower 		tpip_mtu, in_pcbbind, in_pcbconnect,
30536408Ssklower 		in_pcbdisconnect,	in_pcbdetach,
30636408Ssklower 		in_pcballoc,
30736408Ssklower 		tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
30836408Ssklower 		(caddr_t) &tp_inpcb,
30936408Ssklower 		},
31037469Ssklower #else
31137469Ssklower 	{ 0 },
31236408Ssklower #endif INET
31336408Ssklower 	/* ISO_CONS */
31445900Ssklower #if defined(ISO) && defined(TPCONS)
31544423Ssklower 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
31636408Ssklower 		iso_putsufx, iso_getsufx,
31736408Ssklower 		iso_recycle_tsuffix,
31849258Ssklower 		tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect,
31936408Ssklower 		iso_pcbdisconnect,	iso_pcbdetach,
32036408Ssklower 		iso_pcballoc,
32145900Ssklower 		tpcons_output, tpcons_output, iso_nlctloutput,
32236408Ssklower 		(caddr_t) &tp_isopcb,
32336408Ssklower 		},
32437469Ssklower #else
32537469Ssklower 	{ 0 },
32637469Ssklower #endif ISO_CONS
32737469Ssklower 	/* End of protosw marker */
32837469Ssklower 	{ 0 }
32936408Ssklower };
33036408Ssklower 
33136408Ssklower /*
33236408Ssklower  * NAME:  tp_init()
33336408Ssklower  *
33436408Ssklower  * CALLED FROM:
33536408Ssklower  *  autoconf through the protosw structure
33636408Ssklower  *
33736408Ssklower  * FUNCTION:
33836408Ssklower  *  initialize tp machine
33936408Ssklower  *
34036408Ssklower  * RETURNS:  Nada
34136408Ssklower  *
34236408Ssklower  * SIDE EFFECTS:
34336408Ssklower  *
34436408Ssklower  * NOTES:
34536408Ssklower  */
34637469Ssklower int
34736408Ssklower tp_init()
34836408Ssklower {
34936408Ssklower 	static int 	init_done=0;
35036408Ssklower 	void	 	tp_timerinit();
35136408Ssklower 
35236408Ssklower 	if (init_done++)
35337469Ssklower 		return 0;
35436408Ssklower 
35536408Ssklower 
35636408Ssklower 	/* FOR INET */
35736408Ssklower 	tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb;
35836408Ssklower 	/* FOR ISO */
35936408Ssklower 	tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
36036408Ssklower 
36139923Ssklower     tp_start_win = 2;
36239923Ssklower 
36336408Ssklower 	tp_timerinit();
36436408Ssklower 	bzero((caddr_t)&tp_stat, sizeof(struct tp_stat));
36537469Ssklower 	return 0;
36636408Ssklower }
36736408Ssklower 
36836408Ssklower /*
36936408Ssklower  * NAME: 	tp_soisdisconnecting()
37036408Ssklower  *
37136408Ssklower  * CALLED FROM:
37236408Ssklower  *  tp.trans
37336408Ssklower  *
37436408Ssklower  * FUNCTION and ARGUMENTS:
37536408Ssklower  *  Set state of the socket (so) to reflect that fact that we're disconnectING
37636408Ssklower  *
37736408Ssklower  * RETURNS: 	Nada
37836408Ssklower  *
37936408Ssklower  * SIDE EFFECTS:
38036408Ssklower  *
38136408Ssklower  * NOTES:
38236408Ssklower  *  This differs from the regular soisdisconnecting() in that the latter
38336408Ssklower  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
38436408Ssklower  *  We don't want to set those flags because those flags will cause
38536408Ssklower  *  a SIGPIPE to be delivered in sosend() and we don't like that.
38636408Ssklower  *  If anyone else is sleeping on this socket, wake 'em up.
38736408Ssklower  */
38836408Ssklower void
38936408Ssklower tp_soisdisconnecting(so)
39036408Ssklower 	register struct socket *so;
39136408Ssklower {
39238841Ssklower 	soisdisconnecting(so);
39338841Ssklower 	so->so_state &= ~SS_CANTSENDMORE;
39436408Ssklower 	IFPERF(sototpcb(so))
39536408Ssklower 		register struct tp_pcb *tpcb = sototpcb(so);
39636408Ssklower 		u_int 	fsufx, lsufx;
39736408Ssklower 
39837469Ssklower 		bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
39937469Ssklower 		bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
40036408Ssklower 
40137469Ssklower 		tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref);
40236408Ssklower 		tpcb->tp_perf_on = 0; /* turn perf off */
40336408Ssklower 	ENDPERF
40436408Ssklower }
40536408Ssklower 
40636408Ssklower 
40736408Ssklower /*
40836408Ssklower  * NAME: tp_soisdisconnected()
40936408Ssklower  *
41036408Ssklower  * CALLED FROM:
41136408Ssklower  *	tp.trans
41236408Ssklower  *
41336408Ssklower  * FUNCTION and ARGUMENTS:
41436408Ssklower  *  Set state of the socket (so) to reflect that fact that we're disconnectED
41536408Ssklower  *  Set the state of the reference structure to closed, and
41636408Ssklower  *  recycle the suffix.
41736408Ssklower  *  Start a reference timer.
41836408Ssklower  *
41936408Ssklower  * RETURNS:	Nada
42036408Ssklower  *
42136408Ssklower  * SIDE EFFECTS:
42236408Ssklower  *
42336408Ssklower  * NOTES:
42436408Ssklower  *  This differs from the regular soisdisconnected() in that the latter
42536408Ssklower  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
42636408Ssklower  *  We don't want to set those flags because those flags will cause
42736408Ssklower  *  a SIGPIPE to be delivered in sosend() and we don't like that.
42836408Ssklower  *  If anyone else is sleeping on this socket, wake 'em up.
42936408Ssklower  */
43036408Ssklower void
43136408Ssklower tp_soisdisconnected(tpcb)
43236408Ssklower 	register struct tp_pcb	*tpcb;
43336408Ssklower {
43436408Ssklower 	register struct socket	*so = tpcb->tp_sock;
43536408Ssklower 
43638841Ssklower 	soisdisconnecting(so);
43738841Ssklower 	so->so_state &= ~SS_CANTSENDMORE;
43851007Ssklower 	IFPERF(tpcb)
43937469Ssklower 		register struct tp_pcb *ttpcb = sototpcb(so);
44036408Ssklower 		u_int 	fsufx, lsufx;
44136408Ssklower 
44236408Ssklower 		/* CHOKE */
44337469Ssklower 		bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
44437469Ssklower 		bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
44536408Ssklower 
44637469Ssklower 		tpmeas(ttpcb->tp_lref, TPtime_close,
44737469Ssklower 		   &time, &lsufx, &fsufx, ttpcb->tp_fref);
44836408Ssklower 		tpcb->tp_perf_on = 0; /* turn perf off */
44936408Ssklower 	ENDPERF
45036408Ssklower 
45151007Ssklower 	tpcb->tp_refstate = REF_FROZEN;
45251007Ssklower 	tp_recycle_tsuffix(tpcb);
453*51204Ssklower 	tp_etimeout(tpcb, TM_reference, (int)tpcb->tp_refer_ticks);
45436408Ssklower }
45536408Ssklower 
45636408Ssklower /*
45736408Ssklower  * NAME:	tp_freeref()
45836408Ssklower  *
45936408Ssklower  * CALLED FROM:
46036408Ssklower  *  tp.trans when the reference timer goes off, and
46136408Ssklower  *  from tp_attach() and tp_detach() when a tpcb is partially set up but not
46236408Ssklower  *  set up enough to have a ref timer set for it, and it's discarded
46336408Ssklower  *  due to some sort of error or an early close()
46436408Ssklower  *
46536408Ssklower  * FUNCTION and ARGUMENTS:
46636408Ssklower  *  Frees the reference represented by (r) for re-use.
46736408Ssklower  *
46836408Ssklower  * RETURNS: Nothing
46936408Ssklower  *
47036408Ssklower  * SIDE EFFECTS:
47136408Ssklower  *
47236408Ssklower  * NOTES:	better be called at clock priority !!!!!
47336408Ssklower  */
47436408Ssklower void
47536408Ssklower tp_freeref(r)
47636408Ssklower 	register struct tp_ref *r;
47736408Ssklower {
47851007Ssklower 	register struct tp_pcb *tpcb = r->tpr_pcb;
47936408Ssklower 	IFDEBUG(D_TIMER)
48036408Ssklower 		printf("tp_freeref called for ref %d maxrefopen %d\n",
48151007Ssklower 		r - tp_ref, tp_refinfo.tpr_maxopen);
48236408Ssklower 	ENDDEBUG
48336408Ssklower 	IFTRACE(D_TIMER)
48451007Ssklower 		tptrace(TPPTmisc, "tp_freeref ref maxrefopen",
48551007Ssklower 		r - tp_ref, tp_refinfo.tpr_maxopen, 0, 0);
48636408Ssklower 	ENDTRACE
48736408Ssklower 	r->tpr_state = REF_FREE;
48836408Ssklower 	IFDEBUG(D_CONN)
48936408Ssklower 		printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb);
49036408Ssklower 	ENDDEBUG
49136408Ssklower 	r->tpr_pcb = (struct tp_pcb *)0;
49251007Ssklower 	if (tpcb)
49351007Ssklower 		tpcb->tp_refp = 0;
49436408Ssklower 
49551007Ssklower 	for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--)
49651007Ssklower 		if (r->tpr_pcb)
49751007Ssklower 			break;
49851007Ssklower 	tp_refinfo.tpr_maxopen = r - tp_ref;
49951007Ssklower 	tp_refinfo.tpr_numopen--;
50036408Ssklower 
50136408Ssklower 	IFDEBUG(D_TIMER)
50251007Ssklower 		printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen);
50336408Ssklower 	ENDDEBUG
50436408Ssklower }
50536408Ssklower 
50636408Ssklower /*
50736408Ssklower  * NAME:  tp_getref()
50836408Ssklower  *
50936408Ssklower  * CALLED FROM:
51036408Ssklower  *  tp_attach()
51136408Ssklower  *
51236408Ssklower  * FUNCTION and ARGUMENTS:
51336408Ssklower  *  obtains the next free reference and allocates the appropriate
51436408Ssklower  *  ref structure, links that structure to (tpcb)
51536408Ssklower  *
51636408Ssklower  * RETURN VALUE:
51736408Ssklower  *	a reference number
51836408Ssklower  *  or TP_ENOREF
51936408Ssklower  *
52036408Ssklower  * SIDE EFFECTS:
52136408Ssklower  *
52236408Ssklower  * NOTES:
52336408Ssklower  */
524*51204Ssklower u_long
52536408Ssklower tp_getref(tpcb)
52636408Ssklower 	register struct tp_pcb *tpcb;
52736408Ssklower {
52851007Ssklower 	register struct tp_ref	*r, *rlim;
52951007Ssklower 	register int 			i;
53051007Ssklower 	caddr_t obase;
53151007Ssklower 	unsigned size;
53236408Ssklower 
53351007Ssklower 	if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size)
53451007Ssklower 		for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size;
53551007Ssklower 								++r < rlim; ) 	/* tp_ref[0] is never used */
53651007Ssklower 			if (r->tpr_pcb == 0)
53751007Ssklower 				goto got_one;
53851007Ssklower 	/* else have to allocate more space */
53936408Ssklower 
54051007Ssklower 	obase = (caddr_t)tp_refinfo.tpr_base;
54151007Ssklower 	size = tp_refinfo.tpr_size * sizeof(struct tp_ref);
54251007Ssklower 	r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT);
54351007Ssklower 	if (r == 0)
54451007Ssklower 		return (--tp_refinfo.tpr_numopen, TP_ENOREF);
54551007Ssklower 	tp_refinfo.tpr_base = tp_ref = r;
54651007Ssklower 	tp_refinfo.tpr_size *= 2;
54751007Ssklower 	bcopy(obase, (caddr_t)r, size);
54851007Ssklower 	free(obase, M_PCB);
54951007Ssklower 	r = (struct tp_ref *)(size + (caddr_t)r);
55051007Ssklower 	bzero((caddr_t)r, size);
55151007Ssklower 
55251007Ssklower got_one:
55351007Ssklower 	r->tpr_pcb = tpcb;
55436408Ssklower 	r->tpr_state = REF_OPENING;
55536408Ssklower 	tpcb->tp_refp = r;
55651007Ssklower 	i = r - tp_refinfo.tpr_base;
55751007Ssklower 	if (tp_refinfo.tpr_maxopen < i)
55851007Ssklower 		tp_refinfo.tpr_maxopen = i;
55936408Ssklower 	return i;
56036408Ssklower }
56136408Ssklower 
56236408Ssklower /*
56350648Ssklower  * NAME: tp_set_npcb()
56450648Ssklower  *
56550648Ssklower  * CALLED FROM:
56650648Ssklower  *	tp_attach(), tp_route_to()
56750648Ssklower  *
56850648Ssklower  * FUNCTION and ARGUMENTS:
56950648Ssklower  *  given a tpcb, allocate an appropriate lower-lever npcb, freeing
57050648Ssklower  *  any old ones that might need re-assigning.
57150648Ssklower  */
57250648Ssklower tp_set_npcb(tpcb)
57350648Ssklower register struct tp_pcb *tpcb;
57450648Ssklower {
57550648Ssklower 	register struct socket *so = tpcb->tp_sock;
57650648Ssklower 	int error;
57750648Ssklower 
57850648Ssklower 	if (tpcb->tp_nlproto && tpcb->tp_npcb) {
57950648Ssklower 		short so_state = so->so_state;
58050648Ssklower 		so->so_state &= ~SS_NOFDREF;
58150648Ssklower 		tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb);
58250648Ssklower 		so->so_state = so_state;
58350648Ssklower 	}
58450648Ssklower 	tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice];
58550648Ssklower 	/* xx_pcballoc sets so_pcb */
58650648Ssklower 	error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist);
58750648Ssklower 	tpcb->tp_npcb = so->so_pcb;
58850648Ssklower 	so->so_pcb = (caddr_t)tpcb;
58950648Ssklower 	return (error);
59050648Ssklower }
59150648Ssklower /*
59236408Ssklower  * NAME: tp_attach()
59336408Ssklower  *
59436408Ssklower  * CALLED FROM:
59536408Ssklower  *	tp_usrreq, PRU_ATTACH
59636408Ssklower  *
59736408Ssklower  * FUNCTION and ARGUMENTS:
59836408Ssklower  *  given a socket (so) and a protocol family (dom), allocate a tpcb
59936408Ssklower  *  and ref structure, initialize everything in the structures that
60036408Ssklower  *  needs to be initialized.
60136408Ssklower  *
60236408Ssklower  * RETURN VALUE:
60336408Ssklower  *  0 ok
60436408Ssklower  *  EINVAL if DEBUG(X) in is on and a disaster has occurred
60536408Ssklower  *  ENOPROTOOPT if TP hasn't been configured or if the
60636408Ssklower  *   socket wasn't created with tp as its protocol
60736408Ssklower  *  EISCONN if this socket is already part of a connection
60836408Ssklower  *  ETOOMANYREFS if ran out of tp reference numbers.
60936408Ssklower  *  E* whatever error is returned from soreserve()
61036408Ssklower  *    for from the network-layer pcb allocation routine
61136408Ssklower  *
61236408Ssklower  * SIDE EFFECTS:
61336408Ssklower  *
61436408Ssklower  * NOTES:
61536408Ssklower  */
61650648Ssklower tp_attach(so, protocol)
61750648Ssklower 	struct socket 			*so;
61850648Ssklower 	int 					protocol;
61936408Ssklower {
62036408Ssklower 	register struct tp_pcb	*tpcb;
62136408Ssklower 	int 					error;
62250648Ssklower 	int 					dom = so->so_proto->pr_domain->dom_family;
623*51204Ssklower 	u_long					lref;
62436408Ssklower 	extern struct tp_conn_param tp_conn_param[];
62536408Ssklower 
62636408Ssklower 	IFDEBUG(D_CONN)
62736408Ssklower 		printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
62836408Ssklower 	ENDDEBUG
62936408Ssklower 	IFTRACE(D_CONN)
63036408Ssklower 		tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
63136408Ssklower 	ENDTRACE
63236408Ssklower 	if ( ! tp_param.tpp_configed ) {
63336408Ssklower 		error = ENOPROTOOPT; /* protocol not available */
63436408Ssklower 		goto bad2;
63536408Ssklower 	}
63636408Ssklower 
63736408Ssklower 	if (so->so_pcb != NULL) {
63836408Ssklower 		return EISCONN;	/* socket already part of a connection*/
63936408Ssklower 	}
64036408Ssklower 
64151007Ssklower 	error = soreserve(so, 2 * TP_SOCKBUFSIZE, TP_SOCKBUFSIZE);
64236408Ssklower 		/* later an ioctl will allow reallocation IF still in closed state */
64336408Ssklower 
64436408Ssklower 	if (error)
64536408Ssklower 		goto bad2;
64636408Ssklower 
64737469Ssklower 	MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
64837469Ssklower 	if (tpcb == NULL) {
64936408Ssklower 		error = ENOBUFS;
65036408Ssklower 		goto bad2;
65136408Ssklower 	}
65236408Ssklower 	bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
65336408Ssklower 
654*51204Ssklower 	if ( ((lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) {
65536408Ssklower 		error = ETOOMANYREFS;
65636408Ssklower 		goto bad3;
65736408Ssklower 	}
658*51204Ssklower 	tpcb->tp_lref = lref;
65936408Ssklower 	tpcb->tp_sock =  so;
66036408Ssklower 	tpcb->tp_domain = dom;
66150648Ssklower 	/* tpcb->tp_proto = protocol; someday maybe? */
66250648Ssklower 	if (protocol && protocol<ISOPROTO_TP4) {
66336408Ssklower 		tpcb->tp_netservice = ISO_CONS;
66436408Ssklower 		tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
66536408Ssklower 								 * will generate correct fake-ack values
66636408Ssklower 								 */
66736408Ssklower 	} else {
66836408Ssklower 		tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
66936408Ssklower 		/* the default */
67036408Ssklower 	}
67136408Ssklower 	tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
67236408Ssklower 
67336408Ssklower 	tpcb->tp_state = TP_CLOSED;
67436408Ssklower 	tpcb->tp_vers  = TP_VERSION;
67550940Ssklower 	tpcb->tp_notdetached = 1;
67636408Ssklower 
67736408Ssklower 		   /* Spec says default is 128 octets,
67836408Ssklower 			* that is, if the tpdusize argument never appears, use 128.
67936408Ssklower 			* As the initiator, we will always "propose" the 2048
68036408Ssklower 			* size, that is, we will put this argument in the CR
68136408Ssklower 			* always, but accept what the other side sends on the CC.
68236408Ssklower 			* If the initiator sends us something larger on a CR,
68336408Ssklower 			* we'll respond w/ this.
68436408Ssklower 			* Our maximum is 4096.  See tp_chksum.c comments.
68536408Ssklower 			*/
686*51204Ssklower 	tpcb->tp_cong_win =
687*51204Ssklower 		tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
68836408Ssklower 
68936408Ssklower 	tpcb->tp_seqmask  = TP_NML_FMT_MASK;
69036408Ssklower 	tpcb->tp_seqbit  =  TP_NML_FMT_BIT;
69136408Ssklower 	tpcb->tp_seqhalf  =  tpcb->tp_seqbit >> 1;
69236408Ssklower 
69336408Ssklower 	/* attach to a network-layer protoswitch */
69450648Ssklower 	if ( error =  tp_set_npcb(tpcb))
69550648Ssklower 		goto bad4;
69636408Ssklower 	ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
69736408Ssklower 
69850648Ssklower 	/* nothing to do for iso case */
69936408Ssklower 	if( dom == AF_INET )
70036408Ssklower 		sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
70136408Ssklower 
70236408Ssklower 	return 0;
70336408Ssklower 
70436408Ssklower bad4:
70536408Ssklower 	IFDEBUG(D_CONN)
70636408Ssklower 		printf("BAD4 in tp_attach, so 0x%x\n", so);
70736408Ssklower 	ENDDEBUG
70836408Ssklower 	tp_freeref(tpcb->tp_refp);
70936408Ssklower 
71036408Ssklower bad3:
71136408Ssklower 	IFDEBUG(D_CONN)
71236408Ssklower 		printf("BAD3 in tp_attach, so 0x%x\n", so);
71336408Ssklower 	ENDDEBUG
71436408Ssklower 
71537469Ssklower 	free((caddr_t)tpcb, M_PCB); /* never a cluster  */
71636408Ssklower 
71736408Ssklower bad2:
71836408Ssklower 	IFDEBUG(D_CONN)
71936408Ssklower 		printf("BAD2 in tp_attach, so 0x%x\n", so);
72036408Ssklower 	ENDDEBUG
72136408Ssklower 	so->so_pcb = 0;
72236408Ssklower 
72337469Ssklower /*bad:*/
72436408Ssklower 	IFDEBUG(D_CONN)
72536408Ssklower 		printf("BAD in tp_attach, so 0x%x\n", so);
72636408Ssklower 	ENDDEBUG
72736408Ssklower 	return error;
72836408Ssklower }
72936408Ssklower 
73036408Ssklower /*
73136408Ssklower  * NAME:  tp_detach()
73236408Ssklower  *
73336408Ssklower  * CALLED FROM:
73436408Ssklower  *	tp.trans, on behalf of a user close request
73536408Ssklower  *  and when the reference timer goes off
73636408Ssklower  * (if the disconnect  was initiated by the protocol entity
73736408Ssklower  * rather than by the user)
73836408Ssklower  *
73936408Ssklower  * FUNCTION and ARGUMENTS:
74036408Ssklower  *  remove the tpcb structure from the list of active or
74136408Ssklower  *  partially active connections, recycle all the mbufs
74236408Ssklower  *  associated with the pcb, ref structure, sockbufs, etc.
74336408Ssklower  *  Only free the ref structure if you know that a ref timer
74436408Ssklower  *  wasn't set for this tpcb.
74536408Ssklower  *
74636408Ssklower  * RETURNS:  Nada
74736408Ssklower  *
74836408Ssklower  * SIDE EFFECTS:
74936408Ssklower  *
75036408Ssklower  * NOTES:
75136408Ssklower  *  tp_soisdisconnected() was already when this is called
75236408Ssklower  */
75336408Ssklower void
75436408Ssklower tp_detach(tpcb)
75536408Ssklower 	register struct tp_pcb 	*tpcb;
75636408Ssklower {
75750904Ssklower 	void					tp_freeref(), tp_rsyflush();
75836408Ssklower 	register struct socket	 *so = tpcb->tp_sock;
75936408Ssklower 
76036408Ssklower 	IFDEBUG(D_CONN)
76137469Ssklower 		printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
76237469Ssklower 			tpcb,so);
76336408Ssklower 	ENDDEBUG
76436408Ssklower 	IFTRACE(D_CONN)
76536408Ssklower 		tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
76639196Ssklower 			tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0);
76736408Ssklower 	ENDTRACE
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 
77650648Ssklower 	if (tpcb->tp_Xsnd.sb_mb) {
77750648Ssklower 		printf("Unsent Xdata on detach; would panic");
77850648Ssklower 		sbflush(&tpcb->tp_Xsnd);
77950648Ssklower 	}
78047278Ssklower 	if (tpcb->tp_ucddata)
78147278Ssklower 		m_freem(tpcb->tp_ucddata);
78247278Ssklower 
78347278Ssklower 	IFDEBUG(D_CONN)
78450904Ssklower 		printf("reassembly info cnt %d rsyq 0x%x\n",
78550904Ssklower 		    tpcb->tp_rsycnt, tpcb->tp_rsyq);
78650904Ssklower 	ENDDEBUG
78750904Ssklower 	if (tpcb->tp_rsyq)
78850904Ssklower 		tp_rsyflush(tpcb);
78950904Ssklower 
79050940Ssklower 	if (tpcb->tp_next) {
79150940Ssklower 		remque(tpcb);
79250940Ssklower 		tpcb->tp_next = tpcb->tp_prev = 0;
79350940Ssklower 	}
79450940Ssklower 	tpcb->tp_notdetached = 0;
79550940Ssklower 
79650904Ssklower 	IFDEBUG(D_CONN)
79736408Ssklower 		printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
79850435Ssklower 			tpcb->tp_npcb, so);
79936408Ssklower 		printf("so 0x%x so_head 0x%x,  qlen %d q0len %d qlimit %d\n",
80036408Ssklower 		so,  so->so_head,
80136408Ssklower 		so->so_q0len, so->so_qlen, so->so_qlimit);
80236408Ssklower 	ENDDEBUG
80336408Ssklower 
80450435Ssklower 	(tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
80550648Ssklower 				/* does an so->so_pcb = 0; sofree(so) */
80637469Ssklower 
80736408Ssklower 	IFDEBUG(D_CONN)
80836408Ssklower 		printf("after xxx_pcbdetach\n");
80936408Ssklower 	ENDDEBUG
81036408Ssklower 
81150940Ssklower 	if (tpcb->tp_state == TP_LISTENING) {
81250940Ssklower 		register struct tp_pcb **tt;
81350940Ssklower 		for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
81450940Ssklower 			if (*tt == tpcb)
81550940Ssklower 				break;
81650940Ssklower 		if (*tt)
81750940Ssklower 			*tt = tpcb->tp_nextlisten;
81850940Ssklower 		else
81950940Ssklower 			printf("tp_detach from listen: should panic\n");
82050940Ssklower 	}
82151007Ssklower 	if (tpcb->tp_refp && tpcb->tp_refp->tpr_state == REF_OPENING ) {
82236408Ssklower 		/* no connection existed here so no reference timer will be called */
82336408Ssklower 		IFDEBUG(D_CONN)
82436408Ssklower 			printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref,
82536408Ssklower 			tpcb->tp_refp - &tp_ref[0]);
82636408Ssklower 		ENDDEBUG
82736408Ssklower 
82836408Ssklower 		tp_freeref(tpcb->tp_refp);
82936408Ssklower 	}
83050648Ssklower #ifdef TP_PERF_MEAS
83136408Ssklower 	/*
83236408Ssklower 	 * Get rid of the cluster mbuf allocated for performance measurements, if
83336408Ssklower 	 * there is one.  Note that tpcb->tp_perf_on says nothing about whether or
83436408Ssklower 	 * not a cluster mbuf was allocated, so you have to check for a pointer
83536408Ssklower 	 * to one (that is, we need the TP_PERF_MEASs around the following section
83636408Ssklower 	 * of code, not the IFPERFs)
83736408Ssklower 	 */
83847278Ssklower 	if (tpcb->tp_p_mbuf) {
83937469Ssklower 		register struct mbuf *m = tpcb->tp_p_mbuf;
84037469Ssklower 		struct mbuf *n;
84136408Ssklower 		IFDEBUG(D_PERF_MEAS)
84236408Ssklower 			printf("freeing tp_p_meas 0x%x  ", tpcb->tp_p_meas);
84336408Ssklower 		ENDDEBUG
84437469Ssklower 		do {
84537469Ssklower 		    MFREE(m, n);
84637469Ssklower 		    m = n;
84737469Ssklower 		} while (n);
84837469Ssklower 		tpcb->tp_p_meas = 0;
84937469Ssklower 		tpcb->tp_p_mbuf = 0;
85036408Ssklower 	}
85136408Ssklower #endif TP_PERF_MEAS
85236408Ssklower 
85336408Ssklower 	IFDEBUG(D_CONN)
85437469Ssklower 		printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
85536408Ssklower 	ENDDEBUG
85637469Ssklower 	/* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
85736408Ssklower }
85850501Ssklower 
85950501Ssklower struct que {
86050501Ssklower 	struct tp_pcb *next;
86150501Ssklower 	struct tp_pcb *prev;
86250501Ssklower } tp_bound_pcbs =
86350501Ssklower {(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs};
86450501Ssklower 
86550501Ssklower u_short tp_unique;
86650501Ssklower 
86750501Ssklower tp_tselinuse(tlen, tsel, siso, reuseaddr)
86850501Ssklower caddr_t tsel;
86950501Ssklower register struct sockaddr_iso *siso;
87050501Ssklower {
87150501Ssklower 	struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
87250501Ssklower 	register struct tp_pcb *t;
87350501Ssklower 
87450501Ssklower 	for (;;) {
87550501Ssklower 		if (b != (struct tp_pcb *)&tp_bound_pcbs) {
87650501Ssklower 			t = b; b = t->tp_next;
87750501Ssklower 		} else if (l) {
87850501Ssklower 			t = l; l = t->tp_nextlisten;
87950501Ssklower 		} else
88050501Ssklower 			break;
88150501Ssklower 		if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
88250501Ssklower 			if (t->tp_flags & TPF_GENERAL_ADDR) {
88350501Ssklower 				if (siso == 0 || reuseaddr == 0)
88450501Ssklower 					return 1;
88550501Ssklower 			} else if (siso) {
88650501Ssklower 				if (siso->siso_family == t->tp_domain &&
88750501Ssklower 					t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL))
88850501Ssklower 						return 1;
88950501Ssklower 			} else if (reuseaddr == 0)
89050501Ssklower 						return 1;
89150501Ssklower 		}
89250501Ssklower 	}
89350501Ssklower 	return 0;
89450501Ssklower 
89550501Ssklower }
89650501Ssklower 
89750501Ssklower 
89850501Ssklower tp_pcbbind(tpcb, nam)
89950501Ssklower register struct tp_pcb *tpcb;
90050501Ssklower register struct mbuf *nam;
90150501Ssklower {
90250501Ssklower 	register struct sockaddr_iso *siso = 0;
90350501Ssklower 	int tlen = 0, wrapped = 0;
90450501Ssklower 	caddr_t tsel;
90550501Ssklower 	u_short tutil;
90650501Ssklower 
90750501Ssklower 	if (tpcb->tp_state != TP_CLOSED)
90850501Ssklower 		return (EINVAL);
90950501Ssklower 	if (nam) {
91050501Ssklower 		siso = mtod(nam, struct sockaddr_iso *);
91150501Ssklower 		switch (siso->siso_family) {
91250501Ssklower 		default:
91350501Ssklower 			return (EAFNOSUPPORT);
91450501Ssklower #ifdef ISO
91550501Ssklower 		case AF_ISO:
91650501Ssklower 			tlen = siso->siso_tlen;
91750501Ssklower 			tsel = TSEL(siso);
91850501Ssklower 			if (siso->siso_nlen == 0)
91950501Ssklower 				siso = 0;
92050501Ssklower 			break;
92150501Ssklower #endif
92250501Ssklower #ifdef INET
92350501Ssklower 		case AF_INET:
92450501Ssklower 			tsel = (caddr_t)&tutil;
92550501Ssklower 			if (tutil =  ((struct sockaddr_in *)siso)->sin_port) {
92650501Ssklower 				tlen = 2;
92750501Ssklower 			}
92850501Ssklower 			if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0)
92950501Ssklower 				siso = 0;
93050501Ssklower 		}
93150501Ssklower #endif
93250501Ssklower 	}
93350501Ssklower 	if (tpcb->tp_lsuffixlen == 0) {
93450501Ssklower 		if (tlen) {
93550648Ssklower 			if (tp_tselinuse(tlen, tsel, siso,
93650501Ssklower 								tpcb->tp_sock->so_options & SO_REUSEADDR))
93750501Ssklower 				return (EINVAL);
93850501Ssklower 		} else for (tsel = (caddr_t)&tp_unique, tlen = 2;;){
93950501Ssklower 			if (tp_unique++ < ISO_PORT_RESERVED ||
94050501Ssklower 				tp_unique > ISO_PORT_USERRESERVED) {
94150501Ssklower 					if (wrapped++)
94250501Ssklower 						return ESRCH;
94350501Ssklower 					tp_unique = ISO_PORT_RESERVED;
94450501Ssklower 			}
94550648Ssklower 			if (tp_tselinuse(tlen, tsel, siso, 0) == 0)
94650501Ssklower 				break;
94750501Ssklower 		}
94850501Ssklower 		bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
94950501Ssklower 		insque(tpcb, &tp_bound_pcbs);
95050501Ssklower 	} else {
95150501Ssklower 		if (tlen || siso == 0)
95250501Ssklower 			return (EINVAL);
95350501Ssklower 	}
95450501Ssklower 	if (siso == 0) {
95550501Ssklower 		tpcb->tp_flags |= TPF_GENERAL_ADDR;
95650501Ssklower 		return (0);
95750501Ssklower 	}
95850501Ssklower 	return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam);
95950501Ssklower }
960