xref: /csrg-svn/sys/netiso/tp_pcb.c (revision 50501)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*50501Ssklower  *	@(#)tp_pcb.c	7.13 (Berkeley) 07/23/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 "types.h"
5636408Ssklower #include "param.h"
5736408Ssklower #include "mbuf.h"
5836408Ssklower #include "socket.h"
5936408Ssklower #include "socketvar.h"
6036408Ssklower #include "protosw.h"
6136408Ssklower #include "errno.h"
6236408Ssklower #include "time.h"
6337469Ssklower #include "argo_debug.h"
6437469Ssklower #include "tp_param.h"
6537469Ssklower #include "tp_timer.h"
6637469Ssklower #include "tp_ip.h"
6737469Ssklower #include "tp_stat.h"
6837469Ssklower #include "tp_pcb.h"
6937469Ssklower #include "tp_tpdu.h"
7037469Ssklower #include "tp_trace.h"
7137469Ssklower #include "tp_meas.h"
7237469Ssklower #include "tp_seq.h"
7337469Ssklower #include "tp_clnp.h"
7436408Ssklower 
7536408Ssklower struct tp_param tp_param = {
7636408Ssklower 	1,				/*  configured 		*/
7736408Ssklower };
7836408Ssklower 
7936408Ssklower /* ticks are in units of:
8036408Ssklower  * 500 nano-fortnights ;-) or
8136408Ssklower  * 500 ms or
8236408Ssklower  * 1/2 second
8336408Ssklower  */
8436408Ssklower 
8536408Ssklower struct tp_conn_param tp_conn_param[] = {
8636408Ssklower 	/* ISO_CLNS: TP4 CONNECTION LESS */
8736408Ssklower 	{
8836408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
8936408Ssklower 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
9036408Ssklower 
9136408Ssklower 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
9236408Ssklower 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
9336408Ssklower 
9436408Ssklower 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
9536408Ssklower 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
9636408Ssklower 
9736408Ssklower 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
9836408Ssklower 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
9936408Ssklower 
10036408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
10136408Ssklower 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
10236408Ssklower 
10336408Ssklower 		(short) 100, 			/* short p_lcdtfract */
10436408Ssklower 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
10536408Ssklower 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
10636408Ssklower 
10736408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
10836408Ssklower 		TPRX_USE_CW | TPRX_FASTSTART,
10936408Ssklower 								/* 4 bits p_rx_strat*/
11036408Ssklower 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
11136408Ssklower 		1,						/* 1 bit xtd format */
11236408Ssklower 		1,						/* 1 bit xpd service */
11336408Ssklower 		1,						/* 1 bit use_checksum */
11436408Ssklower 		0,						/* 1 bit use net xpd */
11536408Ssklower 		0,						/* 1 bit use rcc */
11636408Ssklower 		0,						/* 1 bit use efc */
11738841Ssklower 		1,						/* no disc indications */
11836408Ssklower 		0,						/* don't change params */
11936408Ssklower 		ISO_CLNS,				/* p_netservice */
12036408Ssklower 	},
12136408Ssklower 	/* IN_CLNS: TP4 CONNECTION LESS */
12236408Ssklower 	{
12336408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
12436408Ssklower 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
12536408Ssklower 
12636408Ssklower 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
12736408Ssklower 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
12836408Ssklower 
12936408Ssklower 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
13036408Ssklower 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
13136408Ssklower 
13236408Ssklower 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
13336408Ssklower 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
13436408Ssklower 
13536408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
13636408Ssklower 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
13736408Ssklower 
13836408Ssklower 		(short) 100, 			/* short p_lcdtfract */
13936408Ssklower 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
14036408Ssklower 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
14136408Ssklower 
14236408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
14336408Ssklower 		TPRX_USE_CW | TPRX_FASTSTART,
14436408Ssklower 								/* 4 bits p_rx_strat*/
14536408Ssklower 		TP_CLASS_4,				/* 5 bits p_class */
14636408Ssklower 		1,						/* 1 bit xtd format */
14736408Ssklower 		1,						/* 1 bit xpd service */
14836408Ssklower 		1,						/* 1 bit use_checksum */
14936408Ssklower 		0,						/* 1 bit use net xpd */
15036408Ssklower 		0,						/* 1 bit use rcc */
15136408Ssklower 		0,						/* 1 bit use efc */
15238841Ssklower 		1,						/* no disc indications */
15336408Ssklower 		0,						/* don't change params */
15436408Ssklower 		IN_CLNS,				/* p_netservice */
15536408Ssklower 	},
15636408Ssklower 	/* ISO_CONS: TP0 CONNECTION MODE */
15736408Ssklower 	{
15836408Ssklower 		TP_NRETRANS, 			/* short p_Nretrans;  */
15936408Ssklower 		0,		/* n/a */		/* short p_dr_ticks; */
16036408Ssklower 
16136408Ssklower 		40,		/* 20 sec */	/* short p_cc_ticks; */
16236408Ssklower 		0,		/* n/a */		/* short p_dt_ticks; */
16336408Ssklower 
16436408Ssklower 		0,		/* n/a */		/* short p_x_ticks;	*/
16536408Ssklower 		360,	/* 3  min */	/* short p_cr_ticks;*/
16636408Ssklower 
16736408Ssklower 		0,		/* n/a */		/* short p_keepalive_ticks;*/
16836408Ssklower 		0,		/* n/a */		/* short p_sendack_ticks; */
16936408Ssklower 
17036408Ssklower 		600,	/* for cr/cc to clear *//* short p_ref_ticks;	*/
17136408Ssklower 		0,		/* n/a */		/* short p_inact_ticks;	*/
17236408Ssklower 
17336408Ssklower 		/* Use tp4 defaults just in case the user changes ONLY
17436408Ssklower 		 * the class
17536408Ssklower 		 */
17636408Ssklower 		(short) 100, 			/* short p_lcdtfract */
17736408Ssklower 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
17836408Ssklower 		TP0_TPDUSIZE, 			/* 8 bits p_tpdusize */
17936408Ssklower 
18036408Ssklower 		0, 						/* 4 bits p_ack_strat */
18136408Ssklower 		0, 						/* 4 bits p_rx_strat*/
18236408Ssklower 		TP_CLASS_0,				/* 5 bits p_class */
18336408Ssklower 		0,						/* 1 bit xtd format */
18436408Ssklower 		0,						/* 1 bit xpd service */
18536408Ssklower 		0,						/* 1 bit use_checksum */
18636408Ssklower 		0,						/* 1 bit use net xpd */
18736408Ssklower 		0,						/* 1 bit use rcc */
18836408Ssklower 		0,						/* 1 bit use efc */
18936408Ssklower 		0,						/* no disc indications */
19036408Ssklower 		0,						/* don't change params */
19136408Ssklower 		ISO_CONS,				/* p_netservice */
19236408Ssklower 	},
19336408Ssklower 	/* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */
19436408Ssklower 	{
19536408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
19636408Ssklower 		40,		/* 20 sec */ 	/* short p_dr_ticks;  */
19736408Ssklower 
19836408Ssklower 		40,		/* 20 sec */ 	/* short p_cc_ticks; */
19936408Ssklower 		80,		/* 40 sec */ 	/* short p_dt_ticks; */
20036408Ssklower 
20136408Ssklower 		120,		/* 1 min */ 	/* short p_x_ticks;	 */
20236408Ssklower 		360,		/* 3 min */ 	/* short p_cr_ticks;*/
20336408Ssklower 
20436408Ssklower 		360,	/* 3 min */ 	/* short p_keepalive_ticks;*/
20536408Ssklower 		20,		/* 10 sec */ 	/* short p_sendack_ticks;  */
20636408Ssklower 
20736408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
20836408Ssklower 		480,	/* 4 min */ 	/* short p_inact_ticks;	*/
20936408Ssklower 
21036408Ssklower 		(short) 100, 			/* short p_lcdtfract */
21136408Ssklower 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
21236408Ssklower 		TP0_TPDUSIZE, 			/* u_char p_tpdusize */
21336408Ssklower 
21436408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
21536408Ssklower 		TPRX_USE_CW ,			/* No fast start */
21636408Ssklower 								/* 4 bits p_rx_strat*/
21736408Ssklower 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
21836408Ssklower 		0,						/* 1 bit xtd format */
21936408Ssklower 		1,						/* 1 bit xpd service */
22036408Ssklower 		1,						/* 1 bit use_checksum */
22136408Ssklower 		0,						/* 1 bit use net xpd */
22236408Ssklower 		0,						/* 1 bit use rcc */
22336408Ssklower 		0,						/* 1 bit use efc */
22436408Ssklower 		0,						/* no disc indications */
22536408Ssklower 		0,						/* don't change params */
22636408Ssklower 		ISO_COSNS,				/* p_netservice */
22736408Ssklower 	},
22836408Ssklower };
22936408Ssklower 
23036408Ssklower #ifdef INET
23136408Ssklower int		in_putnetaddr();
23236408Ssklower int		in_getnetaddr();
23344423Ssklower int		in_cmpnetaddr();
23436408Ssklower int 	in_putsufx();
23536408Ssklower int 	in_getsufx();
23636408Ssklower int 	in_recycle_tsuffix();
23736408Ssklower int 	tpip_mtu();
23836408Ssklower int 	in_pcbbind();
23936408Ssklower int 	in_pcbconnect();
24036408Ssklower int 	in_pcbdisconnect();
24136408Ssklower int 	in_pcbdetach();
24236408Ssklower int 	in_pcballoc();
24336408Ssklower int 	tpip_output();
24436408Ssklower int 	tpip_output_dg();
24536408Ssklower struct inpcb	tp_inpcb;
24636408Ssklower #endif INET
24736408Ssklower #ifdef ISO
24836408Ssklower int		iso_putnetaddr();
24936408Ssklower int		iso_getnetaddr();
25044423Ssklower int		iso_cmpnetaddr();
25136408Ssklower int 	iso_putsufx();
25236408Ssklower int 	iso_getsufx();
25336408Ssklower int 	iso_recycle_tsuffix();
25436408Ssklower int		tpclnp_mtu();
25536408Ssklower int		iso_pcbbind();
25636408Ssklower int		iso_pcbconnect();
25736408Ssklower int		iso_pcbdisconnect();
25836408Ssklower int 	iso_pcbdetach();
25936408Ssklower int 	iso_pcballoc();
26036408Ssklower int 	tpclnp_output();
26136408Ssklower int 	tpclnp_output_dg();
26236408Ssklower int		iso_nlctloutput();
26336408Ssklower struct isopcb	tp_isopcb;
26436408Ssklower #endif ISO
26545900Ssklower #ifdef TPCONS
26636408Ssklower int		iso_putnetaddr();
26736408Ssklower int		iso_getnetaddr();
26844423Ssklower int		iso_cmpnetaddr();
26936408Ssklower int 	iso_putsufx();
27036408Ssklower int 	iso_getsufx();
27136408Ssklower int 	iso_recycle_tsuffix();
27236408Ssklower int		iso_pcbbind();
27345900Ssklower int		tpcons_pcbconnect();
27449258Ssklower int		tpclnp_mtu();
27536408Ssklower int		iso_pcbdisconnect();
27636408Ssklower int 	iso_pcbdetach();
27736408Ssklower int 	iso_pcballoc();
27836408Ssklower int 	tpcons_output();
27936408Ssklower struct isopcb	tp_isopcb;
28045900Ssklower #endif TPCONS
28136408Ssklower 
28237469Ssklower 
28336408Ssklower struct nl_protosw nl_protosw[] = {
28436408Ssklower 	/* ISO_CLNS */
28536408Ssklower #ifdef ISO
28644423Ssklower 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
28736408Ssklower 		iso_putsufx, iso_getsufx,
28836408Ssklower 		iso_recycle_tsuffix,
28936408Ssklower 		tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
29036408Ssklower 		iso_pcbdisconnect,	iso_pcbdetach,
29136408Ssklower 		iso_pcballoc,
29236408Ssklower 		tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
29336408Ssklower 		(caddr_t) &tp_isopcb,
29436408Ssklower 		},
29537469Ssklower #else
29637469Ssklower 	{ 0 },
29736408Ssklower #endif ISO
29836408Ssklower 	/* IN_CLNS */
29936408Ssklower #ifdef INET
30044423Ssklower 	{ AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr,
30136408Ssklower 		in_putsufx, in_getsufx,
30236408Ssklower 		in_recycle_tsuffix,
30336408Ssklower 		tpip_mtu, in_pcbbind, in_pcbconnect,
30436408Ssklower 		in_pcbdisconnect,	in_pcbdetach,
30536408Ssklower 		in_pcballoc,
30636408Ssklower 		tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
30736408Ssklower 		(caddr_t) &tp_inpcb,
30836408Ssklower 		},
30937469Ssklower #else
31037469Ssklower 	{ 0 },
31136408Ssklower #endif INET
31236408Ssklower 	/* ISO_CONS */
31345900Ssklower #if defined(ISO) && defined(TPCONS)
31444423Ssklower 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
31536408Ssklower 		iso_putsufx, iso_getsufx,
31636408Ssklower 		iso_recycle_tsuffix,
31749258Ssklower 		tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect,
31836408Ssklower 		iso_pcbdisconnect,	iso_pcbdetach,
31936408Ssklower 		iso_pcballoc,
32045900Ssklower 		tpcons_output, tpcons_output, iso_nlctloutput,
32136408Ssklower 		(caddr_t) &tp_isopcb,
32236408Ssklower 		},
32337469Ssklower #else
32437469Ssklower 	{ 0 },
32537469Ssklower #endif ISO_CONS
32637469Ssklower 	/* End of protosw marker */
32737469Ssklower 	{ 0 }
32836408Ssklower };
32936408Ssklower 
33036408Ssklower /*
33136408Ssklower  * NAME:  tp_init()
33236408Ssklower  *
33336408Ssklower  * CALLED FROM:
33436408Ssklower  *  autoconf through the protosw structure
33536408Ssklower  *
33636408Ssklower  * FUNCTION:
33736408Ssklower  *  initialize tp machine
33836408Ssklower  *
33936408Ssklower  * RETURNS:  Nada
34036408Ssklower  *
34136408Ssklower  * SIDE EFFECTS:
34236408Ssklower  *
34336408Ssklower  * NOTES:
34436408Ssklower  */
34537469Ssklower int
34636408Ssklower tp_init()
34736408Ssklower {
34836408Ssklower 	static int 	init_done=0;
34936408Ssklower 	void	 	tp_timerinit();
35036408Ssklower 
35136408Ssklower 	if (init_done++)
35237469Ssklower 		return 0;
35336408Ssklower 
35436408Ssklower 
35536408Ssklower 	/* FOR INET */
35636408Ssklower 	tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb;
35736408Ssklower 	/* FOR ISO */
35836408Ssklower 	tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
35936408Ssklower 
36039923Ssklower     tp_start_win = 2;
36139923Ssklower 
36236408Ssklower 	tp_timerinit();
36336408Ssklower 	bzero((caddr_t)&tp_stat, sizeof(struct tp_stat));
36437469Ssklower 	return 0;
36536408Ssklower }
36636408Ssklower 
36736408Ssklower /*
36836408Ssklower  * NAME: 	tp_soisdisconnecting()
36936408Ssklower  *
37036408Ssklower  * CALLED FROM:
37136408Ssklower  *  tp.trans
37236408Ssklower  *
37336408Ssklower  * FUNCTION and ARGUMENTS:
37436408Ssklower  *  Set state of the socket (so) to reflect that fact that we're disconnectING
37536408Ssklower  *
37636408Ssklower  * RETURNS: 	Nada
37736408Ssklower  *
37836408Ssklower  * SIDE EFFECTS:
37936408Ssklower  *
38036408Ssklower  * NOTES:
38136408Ssklower  *  This differs from the regular soisdisconnecting() in that the latter
38236408Ssklower  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
38336408Ssklower  *  We don't want to set those flags because those flags will cause
38436408Ssklower  *  a SIGPIPE to be delivered in sosend() and we don't like that.
38536408Ssklower  *  If anyone else is sleeping on this socket, wake 'em up.
38636408Ssklower  */
38736408Ssklower void
38836408Ssklower tp_soisdisconnecting(so)
38936408Ssklower 	register struct socket *so;
39036408Ssklower {
39138841Ssklower 	soisdisconnecting(so);
39238841Ssklower 	so->so_state &= ~SS_CANTSENDMORE;
39336408Ssklower 	IFPERF(sototpcb(so))
39436408Ssklower 		register struct tp_pcb *tpcb = sototpcb(so);
39536408Ssklower 		u_int 	fsufx, lsufx;
39636408Ssklower 
39737469Ssklower 		bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
39837469Ssklower 		bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
39936408Ssklower 
40037469Ssklower 		tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref);
40136408Ssklower 		tpcb->tp_perf_on = 0; /* turn perf off */
40236408Ssklower 	ENDPERF
40336408Ssklower }
40436408Ssklower 
40536408Ssklower 
40636408Ssklower /*
40736408Ssklower  * NAME: tp_soisdisconnected()
40836408Ssklower  *
40936408Ssklower  * CALLED FROM:
41036408Ssklower  *	tp.trans
41136408Ssklower  *
41236408Ssklower  * FUNCTION and ARGUMENTS:
41336408Ssklower  *  Set state of the socket (so) to reflect that fact that we're disconnectED
41436408Ssklower  *  Set the state of the reference structure to closed, and
41536408Ssklower  *  recycle the suffix.
41636408Ssklower  *  Start a reference timer.
41736408Ssklower  *
41836408Ssklower  * RETURNS:	Nada
41936408Ssklower  *
42036408Ssklower  * SIDE EFFECTS:
42136408Ssklower  *
42236408Ssklower  * NOTES:
42336408Ssklower  *  This differs from the regular soisdisconnected() in that the latter
42436408Ssklower  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
42536408Ssklower  *  We don't want to set those flags because those flags will cause
42636408Ssklower  *  a SIGPIPE to be delivered in sosend() and we don't like that.
42736408Ssklower  *  If anyone else is sleeping on this socket, wake 'em up.
42836408Ssklower  */
42936408Ssklower void
43036408Ssklower tp_soisdisconnected(tpcb)
43136408Ssklower 	register struct tp_pcb	*tpcb;
43236408Ssklower {
43336408Ssklower 	register struct socket	*so = tpcb->tp_sock;
43436408Ssklower 
43538841Ssklower 	soisdisconnecting(so);
43638841Ssklower 	so->so_state &= ~SS_CANTSENDMORE;
43736408Ssklower 	IFPERF(sototpcb(so))
43837469Ssklower 		register struct tp_pcb *ttpcb = sototpcb(so);
43936408Ssklower 		u_int 	fsufx, lsufx;
44036408Ssklower 
44136408Ssklower 		/* CHOKE */
44237469Ssklower 		bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
44337469Ssklower 		bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
44436408Ssklower 
44537469Ssklower 		tpmeas(ttpcb->tp_lref, TPtime_close,
44637469Ssklower 		   &time, &lsufx, &fsufx, ttpcb->tp_fref);
44736408Ssklower 		tpcb->tp_perf_on = 0; /* turn perf off */
44836408Ssklower 	ENDPERF
44936408Ssklower 
45036408Ssklower 	tpcb->tp_refp->tpr_state = REF_FROZEN;
45136408Ssklower 	tp_recycle_tsuffix( tpcb );
45236408Ssklower 	tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks);
45336408Ssklower }
45436408Ssklower 
45536408Ssklower int tp_maxrefopen;  /* highest reference # of the set of open tp connections */
45636408Ssklower 
45736408Ssklower /*
45836408Ssklower  * NAME:	tp_freeref()
45936408Ssklower  *
46036408Ssklower  * CALLED FROM:
46136408Ssklower  *  tp.trans when the reference timer goes off, and
46236408Ssklower  *  from tp_attach() and tp_detach() when a tpcb is partially set up but not
46336408Ssklower  *  set up enough to have a ref timer set for it, and it's discarded
46436408Ssklower  *  due to some sort of error or an early close()
46536408Ssklower  *
46636408Ssklower  * FUNCTION and ARGUMENTS:
46736408Ssklower  *  Frees the reference represented by (r) for re-use.
46836408Ssklower  *
46936408Ssklower  * RETURNS: Nothing
47036408Ssklower  *
47136408Ssklower  * SIDE EFFECTS:
47236408Ssklower  *
47336408Ssklower  * NOTES:	better be called at clock priority !!!!!
47436408Ssklower  */
47536408Ssklower void
47636408Ssklower tp_freeref(r)
47736408Ssklower 	register struct tp_ref *r;
47836408Ssklower {
47936408Ssklower 	IFDEBUG(D_TIMER)
48036408Ssklower 		printf("tp_freeref called for ref %d maxrefopen %d\n",
48136408Ssklower 		r - tp_ref, tp_maxrefopen);
48236408Ssklower 	ENDDEBUG
48336408Ssklower 	IFTRACE(D_TIMER)
48436408Ssklower 		tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen",
48536408Ssklower 		r - tp_ref, tp_maxrefopen, 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;
49236408Ssklower 
49336408Ssklower 	r = &tp_ref[tp_maxrefopen];
49436408Ssklower 
49536408Ssklower 	while( tp_maxrefopen > 0 ) {
49636408Ssklower 		if(r->tpr_state )
49736408Ssklower 			break;
49836408Ssklower 		tp_maxrefopen--;
49936408Ssklower 		r--;
50036408Ssklower 	}
50136408Ssklower 	IFDEBUG(D_TIMER)
50236408Ssklower 		printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen);
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  */
52436408Ssklower static RefNum
52536408Ssklower tp_getref(tpcb)
52636408Ssklower 	register struct tp_pcb *tpcb;
52736408Ssklower {
52848733Ssklower 	register struct tp_ref	*r = tp_ref; /* tp_ref[0] is never used */
52936408Ssklower 	register int 			i=1;
53036408Ssklower 
53136408Ssklower 
53248733Ssklower 	while ((++r)->tpr_state != REF_FREE) {
53348733Ssklower 		if (++i == N_TPREF)
53436408Ssklower 			return TP_ENOREF;
53536408Ssklower 	}
53636408Ssklower 	r->tpr_state = REF_OPENING;
53736408Ssklower 	if (tp_maxrefopen < i)
53836408Ssklower 		tp_maxrefopen = i;
53936408Ssklower 	r->tpr_pcb = tpcb;
54036408Ssklower 	tpcb->tp_refp = r;
54136408Ssklower 
54236408Ssklower 	return i;
54336408Ssklower }
54436408Ssklower 
54536408Ssklower /*
54636408Ssklower  * NAME: tp_attach()
54736408Ssklower  *
54836408Ssklower  * CALLED FROM:
54936408Ssklower  *	tp_usrreq, PRU_ATTACH
55036408Ssklower  *
55136408Ssklower  * FUNCTION and ARGUMENTS:
55236408Ssklower  *  given a socket (so) and a protocol family (dom), allocate a tpcb
55336408Ssklower  *  and ref structure, initialize everything in the structures that
55436408Ssklower  *  needs to be initialized.
55536408Ssklower  *
55636408Ssklower  * RETURN VALUE:
55736408Ssklower  *  0 ok
55836408Ssklower  *  EINVAL if DEBUG(X) in is on and a disaster has occurred
55936408Ssklower  *  ENOPROTOOPT if TP hasn't been configured or if the
56036408Ssklower  *   socket wasn't created with tp as its protocol
56136408Ssklower  *  EISCONN if this socket is already part of a connection
56236408Ssklower  *  ETOOMANYREFS if ran out of tp reference numbers.
56336408Ssklower  *  E* whatever error is returned from soreserve()
56436408Ssklower  *    for from the network-layer pcb allocation routine
56536408Ssklower  *
56636408Ssklower  * SIDE EFFECTS:
56736408Ssklower  *
56836408Ssklower  * NOTES:
56936408Ssklower  */
57037469Ssklower tp_attach(so, dom)
57136408Ssklower 	struct socket 	*so;
57236408Ssklower 	int 			dom;
57336408Ssklower {
57436408Ssklower 	register struct tp_pcb	*tpcb;
57536408Ssklower 	int 					error;
57636408Ssklower 	int 					protocol = so->so_proto->pr_protocol;
57736408Ssklower 	extern struct tp_conn_param tp_conn_param[];
57836408Ssklower 
57936408Ssklower 	IFDEBUG(D_CONN)
58036408Ssklower 		printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
58136408Ssklower 	ENDDEBUG
58236408Ssklower 	IFTRACE(D_CONN)
58336408Ssklower 		tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
58436408Ssklower 	ENDTRACE
58536408Ssklower 	if ( ! tp_param.tpp_configed ) {
58636408Ssklower 		error = ENOPROTOOPT; /* protocol not available */
58736408Ssklower 		goto bad2;
58836408Ssklower 	}
58936408Ssklower 
59036408Ssklower 	if (so->so_pcb != NULL) {
59136408Ssklower 		return EISCONN;	/* socket already part of a connection*/
59236408Ssklower 	}
59336408Ssklower 
59436408Ssklower 	error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE);
59536408Ssklower 		/* later an ioctl will allow reallocation IF still in closed state */
59636408Ssklower 
59736408Ssklower 	if (error)
59836408Ssklower 		goto bad2;
59936408Ssklower 
60037469Ssklower 	MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
60137469Ssklower 	if (tpcb == NULL) {
60236408Ssklower 		error = ENOBUFS;
60336408Ssklower 		goto bad2;
60436408Ssklower 	}
60536408Ssklower 	bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
60636408Ssklower 
60736408Ssklower 	if ( ((tpcb->tp_lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) {
60836408Ssklower 		error = ETOOMANYREFS;
60936408Ssklower 		goto bad3;
61036408Ssklower 	}
61136408Ssklower 	tpcb->tp_sock =  so;
61236408Ssklower 	tpcb->tp_domain = dom;
61336408Ssklower 	if (protocol<ISOPROTO_TP4) {
61436408Ssklower 		tpcb->tp_netservice = ISO_CONS;
61536408Ssklower 		tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
61636408Ssklower 								 * will generate correct fake-ack values
61736408Ssklower 								 */
61836408Ssklower 	} else {
61936408Ssklower 		tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
62036408Ssklower 		/* the default */
62136408Ssklower 	}
62236408Ssklower 	tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
62336408Ssklower 
62436408Ssklower 	tpcb->tp_cong_win = 1;
62536408Ssklower 	tpcb->tp_state = TP_CLOSED;
62636408Ssklower 	tpcb->tp_vers  = TP_VERSION;
62736408Ssklower 
62836408Ssklower 		   /* Spec says default is 128 octets,
62936408Ssklower 			* that is, if the tpdusize argument never appears, use 128.
63036408Ssklower 			* As the initiator, we will always "propose" the 2048
63136408Ssklower 			* size, that is, we will put this argument in the CR
63236408Ssklower 			* always, but accept what the other side sends on the CC.
63336408Ssklower 			* If the initiator sends us something larger on a CR,
63436408Ssklower 			* we'll respond w/ this.
63536408Ssklower 			* Our maximum is 4096.  See tp_chksum.c comments.
63636408Ssklower 			*/
63736408Ssklower 	tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
63836408Ssklower 
63936408Ssklower 	tpcb->tp_seqmask  = TP_NML_FMT_MASK;
64036408Ssklower 	tpcb->tp_seqbit  =  TP_NML_FMT_BIT;
64136408Ssklower 	tpcb->tp_seqhalf  =  tpcb->tp_seqbit >> 1;
64236408Ssklower 	tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */
64336408Ssklower 	tpcb->tp_s_subseq = 0;
64436408Ssklower 
64536408Ssklower 	/* attach to a network-layer protoswitch */
64636408Ssklower 	/* new way */
64736408Ssklower 	tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice];
64836408Ssklower 	ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
64936408Ssklower #ifdef notdef
65036408Ssklower 	/* OLD WAY */
65136408Ssklower 	/* TODO: properly, this search would be on the basis of
65236408Ssklower 	* domain,netservice or just netservice only (if you have
65336408Ssklower 	* IN_CLNS, ISO_CLNS, and ISO_CONS)
65436408Ssklower 	*/
65536408Ssklower 	tpcb->tp_nlproto = nl_protosw;
65636408Ssklower 	while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain )  {
65736408Ssklower 		if( tpcb->tp_nlproto->nlp_afamily == 0 ) {
65836408Ssklower 			error = EAFNOSUPPORT;
65936408Ssklower 			goto bad4;
66036408Ssklower 		}
66136408Ssklower 		tpcb->tp_nlproto ++;
66236408Ssklower 	}
66336408Ssklower #endif notdef
66436408Ssklower 
66536408Ssklower 	/* xx_pcballoc sets so_pcb */
66636408Ssklower 	if ( error =  (tpcb->tp_nlproto->nlp_pcballoc) (
66736408Ssklower 							so, tpcb->tp_nlproto->nlp_pcblist ) ) {
66836408Ssklower 		goto bad4;
66936408Ssklower 	}
67036408Ssklower 
67136408Ssklower 	if( dom == AF_INET )
67236408Ssklower 		sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
67336408Ssklower 		/* nothing to do for iso case */
67436408Ssklower 
67550435Ssklower 	tpcb->tp_npcb = so->so_pcb;
67650435Ssklower 	so->so_pcb = (caddr_t) tpcb;
67736408Ssklower 
67836408Ssklower 	return 0;
67936408Ssklower 
68036408Ssklower bad4:
68136408Ssklower 	IFDEBUG(D_CONN)
68236408Ssklower 		printf("BAD4 in tp_attach, so 0x%x\n", so);
68336408Ssklower 	ENDDEBUG
68436408Ssklower 	tp_freeref(tpcb->tp_refp);
68536408Ssklower 
68636408Ssklower bad3:
68736408Ssklower 	IFDEBUG(D_CONN)
68836408Ssklower 		printf("BAD3 in tp_attach, so 0x%x\n", so);
68936408Ssklower 	ENDDEBUG
69036408Ssklower 
69137469Ssklower 	free((caddr_t)tpcb, M_PCB); /* never a cluster  */
69236408Ssklower 
69336408Ssklower bad2:
69436408Ssklower 	IFDEBUG(D_CONN)
69536408Ssklower 		printf("BAD2 in tp_attach, so 0x%x\n", so);
69636408Ssklower 	ENDDEBUG
69736408Ssklower 	so->so_pcb = 0;
69836408Ssklower 
69937469Ssklower /*bad:*/
70036408Ssklower 	IFDEBUG(D_CONN)
70136408Ssklower 		printf("BAD in tp_attach, so 0x%x\n", so);
70236408Ssklower 	ENDDEBUG
70336408Ssklower 	return error;
70436408Ssklower }
70536408Ssklower 
70636408Ssklower /*
70736408Ssklower  * NAME:  tp_detach()
70836408Ssklower  *
70936408Ssklower  * CALLED FROM:
71036408Ssklower  *	tp.trans, on behalf of a user close request
71136408Ssklower  *  and when the reference timer goes off
71236408Ssklower  * (if the disconnect  was initiated by the protocol entity
71336408Ssklower  * rather than by the user)
71436408Ssklower  *
71536408Ssklower  * FUNCTION and ARGUMENTS:
71636408Ssklower  *  remove the tpcb structure from the list of active or
71736408Ssklower  *  partially active connections, recycle all the mbufs
71836408Ssklower  *  associated with the pcb, ref structure, sockbufs, etc.
71936408Ssklower  *  Only free the ref structure if you know that a ref timer
72036408Ssklower  *  wasn't set for this tpcb.
72136408Ssklower  *
72236408Ssklower  * RETURNS:  Nada
72336408Ssklower  *
72436408Ssklower  * SIDE EFFECTS:
72536408Ssklower  *
72636408Ssklower  * NOTES:
72736408Ssklower  *  tp_soisdisconnected() was already when this is called
72836408Ssklower  */
72936408Ssklower void
73036408Ssklower tp_detach(tpcb)
73136408Ssklower 	register struct tp_pcb 	*tpcb;
73236408Ssklower {
73336408Ssklower 	void					tp_freeref();
73436408Ssklower 	register struct socket	 *so = tpcb->tp_sock;
73536408Ssklower 
73636408Ssklower 	IFDEBUG(D_CONN)
73737469Ssklower 		printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
73837469Ssklower 			tpcb,so);
73936408Ssklower 	ENDDEBUG
74036408Ssklower 	IFTRACE(D_CONN)
74136408Ssklower 		tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
74239196Ssklower 			tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0);
74336408Ssklower 	ENDTRACE
74436408Ssklower 
74536408Ssklower 	if (so->so_head) {
74636408Ssklower 		if (!soqremque(so, 0) && !soqremque(so, 1))
74736408Ssklower 			panic("sofree dq");
74836408Ssklower 		so->so_head = 0;
74936408Ssklower 	}
75036408Ssklower 
75136408Ssklower 	IFDEBUG(D_CONN)
75236408Ssklower 		printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n",
75336408Ssklower 		tpcb->tp_snduna_rtc,
75436408Ssklower 		tpcb->tp_rcvnxt_rtc);
75536408Ssklower 	ENDDEBUG
75636408Ssklower 
75736408Ssklower #define FREE_RTC_LIST(XXX)\
75836408Ssklower 	{ register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\
75936408Ssklower 		xxs = xxr->tprt_next;\
76036408Ssklower 		m_freem( xxr->tprt_data );\
76136408Ssklower 		m_free( dtom(xxr) ); xxr = xxs; }\
76236408Ssklower 		XXX = (struct tp_rtc *)0;\
76336408Ssklower 	}
76436408Ssklower 
76536408Ssklower 	FREE_RTC_LIST( tpcb->tp_snduna_rtc );
76636408Ssklower 	tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0;
76736408Ssklower 
76836408Ssklower 	FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc );
76936408Ssklower 
77036408Ssklower #undef FREE_RTC_LIST
77136408Ssklower 
77236408Ssklower 	IFDEBUG(D_CONN)
77347278Ssklower 		printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv);
77447278Ssklower 		dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
77547278Ssklower 		printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n",
77647278Ssklower 				tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
77747278Ssklower 	ENDDEBUG
77847278Ssklower 
77947278Ssklower 	if (so->so_snd.sb_cc != 0)
78047278Ssklower 		sbflush(&so->so_snd);
78147278Ssklower 	if (tpcb->tp_Xrcv.sb_cc != 0)
78247278Ssklower 		sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc);
78347278Ssklower 	if (tpcb->tp_ucddata)
78447278Ssklower 		m_freem(tpcb->tp_ucddata);
78547278Ssklower 
78647278Ssklower 	IFDEBUG(D_CONN)
78736408Ssklower 		printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
78850435Ssklower 			tpcb->tp_npcb, so);
78936408Ssklower 		printf("so 0x%x so_head 0x%x,  qlen %d q0len %d qlimit %d\n",
79036408Ssklower 		so,  so->so_head,
79136408Ssklower 		so->so_q0len, so->so_qlen, so->so_qlimit);
79236408Ssklower 	ENDDEBUG
79336408Ssklower 
79436408Ssklower 
79550435Ssklower 	(tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
79637469Ssklower 				/* does an sofree(so) */
79737469Ssklower 
79836408Ssklower 	IFDEBUG(D_CONN)
79936408Ssklower 		printf("after xxx_pcbdetach\n");
80036408Ssklower 	ENDDEBUG
80136408Ssklower 
80236408Ssklower 	if( tpcb->tp_refp->tpr_state == REF_OPENING ) {
80336408Ssklower 		/* no connection existed here so no reference timer will be called */
80436408Ssklower 		IFDEBUG(D_CONN)
80536408Ssklower 			printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref,
80636408Ssklower 			tpcb->tp_refp - &tp_ref[0]);
80736408Ssklower 		ENDDEBUG
80836408Ssklower 
80936408Ssklower 		tp_freeref(tpcb->tp_refp);
81036408Ssklower 	}
81136408Ssklower 
81237469Ssklower 	if (tpcb->tp_Xsnd.sb_mb) {
81337469Ssklower 		printf("Unsent Xdata on detach; would panic");
81437469Ssklower 		sbflush(&tpcb->tp_Xsnd);
81537469Ssklower 	}
81650435Ssklower 	so->so_pcb = 0;
81736408Ssklower 
81836408Ssklower 	/*
81936408Ssklower 	 * Get rid of the cluster mbuf allocated for performance measurements, if
82036408Ssklower 	 * there is one.  Note that tpcb->tp_perf_on says nothing about whether or
82136408Ssklower 	 * not a cluster mbuf was allocated, so you have to check for a pointer
82236408Ssklower 	 * to one (that is, we need the TP_PERF_MEASs around the following section
82336408Ssklower 	 * of code, not the IFPERFs)
82436408Ssklower 	 */
82536408Ssklower #ifdef TP_PERF_MEAS
82647278Ssklower 	if (tpcb->tp_p_mbuf) {
82737469Ssklower 		register struct mbuf *m = tpcb->tp_p_mbuf;
82837469Ssklower 		struct mbuf *n;
82936408Ssklower 		IFDEBUG(D_PERF_MEAS)
83036408Ssklower 			printf("freeing tp_p_meas 0x%x  ", tpcb->tp_p_meas);
83136408Ssklower 		ENDDEBUG
83237469Ssklower 		do {
83337469Ssklower 		    MFREE(m, n);
83437469Ssklower 		    m = n;
83537469Ssklower 		} while (n);
83637469Ssklower 		tpcb->tp_p_meas = 0;
83737469Ssklower 		tpcb->tp_p_mbuf = 0;
83836408Ssklower 	}
83936408Ssklower #endif TP_PERF_MEAS
84036408Ssklower 
84136408Ssklower 	IFDEBUG(D_CONN)
84237469Ssklower 		printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
84336408Ssklower 	ENDDEBUG
84437469Ssklower 	/* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
84536408Ssklower }
846*50501Ssklower 
847*50501Ssklower struct que {
848*50501Ssklower 	struct tp_pcb *next;
849*50501Ssklower 	struct tp_pcb *prev;
850*50501Ssklower } tp_bound_pcbs =
851*50501Ssklower {(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs};
852*50501Ssklower 
853*50501Ssklower u_short tp_unique;
854*50501Ssklower 
855*50501Ssklower tp_tselinuse(tlen, tsel, siso, reuseaddr)
856*50501Ssklower caddr_t tsel;
857*50501Ssklower register struct sockaddr_iso *siso;
858*50501Ssklower {
859*50501Ssklower 	struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
860*50501Ssklower 	register struct tp_pcb *t;
861*50501Ssklower 
862*50501Ssklower 	for (;;) {
863*50501Ssklower 		if (b != (struct tp_pcb *)&tp_bound_pcbs) {
864*50501Ssklower 			t = b; b = t->tp_next;
865*50501Ssklower 		} else if (l) {
866*50501Ssklower 			t = l; l = t->tp_nextlisten;
867*50501Ssklower 		} else
868*50501Ssklower 			break;
869*50501Ssklower 		if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
870*50501Ssklower 			if (t->tp_flags & TPF_GENERAL_ADDR) {
871*50501Ssklower 				if (siso == 0 || reuseaddr == 0)
872*50501Ssklower 					return 1;
873*50501Ssklower 			} else if (siso) {
874*50501Ssklower 				if (siso->siso_family == t->tp_domain &&
875*50501Ssklower 					t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL))
876*50501Ssklower 						return 1;
877*50501Ssklower 			} else if (reuseaddr == 0)
878*50501Ssklower 						return 1;
879*50501Ssklower 		}
880*50501Ssklower 	}
881*50501Ssklower 	return 0;
882*50501Ssklower 
883*50501Ssklower }
884*50501Ssklower 
885*50501Ssklower 
886*50501Ssklower tp_pcbbind(tpcb, nam)
887*50501Ssklower register struct tp_pcb *tpcb;
888*50501Ssklower register struct mbuf *nam;
889*50501Ssklower {
890*50501Ssklower 	register struct sockaddr_iso *siso = 0;
891*50501Ssklower 	int tlen = 0, wrapped = 0;
892*50501Ssklower 	caddr_t tsel;
893*50501Ssklower 	u_short tutil;
894*50501Ssklower 
895*50501Ssklower 	if (tpcb->tp_state != TP_CLOSED)
896*50501Ssklower 		return (EINVAL);
897*50501Ssklower 	if (nam) {
898*50501Ssklower 		siso = mtod(nam, struct sockaddr_iso *);
899*50501Ssklower 		switch (siso->siso_family) {
900*50501Ssklower 		default:
901*50501Ssklower 			return (EAFNOSUPPORT);
902*50501Ssklower #ifdef ISO
903*50501Ssklower 		case AF_ISO:
904*50501Ssklower 			tlen = siso->siso_tlen;
905*50501Ssklower 			tsel = TSEL(siso);
906*50501Ssklower 			if (siso->siso_nlen == 0)
907*50501Ssklower 				siso = 0;
908*50501Ssklower 			break;
909*50501Ssklower #endif
910*50501Ssklower #ifdef INET
911*50501Ssklower 		case AF_INET:
912*50501Ssklower 			tsel = (caddr_t)&tutil;
913*50501Ssklower 			if (tutil =  ((struct sockaddr_in *)siso)->sin_port) {
914*50501Ssklower 				tlen = 2;
915*50501Ssklower 			}
916*50501Ssklower 			if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0)
917*50501Ssklower 				siso = 0;
918*50501Ssklower 		}
919*50501Ssklower #endif
920*50501Ssklower 	}
921*50501Ssklower 	if (tpcb->tp_lsuffixlen == 0) {
922*50501Ssklower 		if (tlen) {
923*50501Ssklower 			if (tp_tselinuse(tsel, tlen, siso,
924*50501Ssklower 								tpcb->tp_sock->so_options & SO_REUSEADDR))
925*50501Ssklower 				return (EINVAL);
926*50501Ssklower 		} else for (tsel = (caddr_t)&tp_unique, tlen = 2;;){
927*50501Ssklower 			if (tp_unique++ < ISO_PORT_RESERVED ||
928*50501Ssklower 				tp_unique > ISO_PORT_USERRESERVED) {
929*50501Ssklower 					if (wrapped++)
930*50501Ssklower 						return ESRCH;
931*50501Ssklower 					tp_unique = ISO_PORT_RESERVED;
932*50501Ssklower 			}
933*50501Ssklower 			if (tp_tselinuse(tsel, tlen, siso, 0) == 0)
934*50501Ssklower 				break;
935*50501Ssklower 		}
936*50501Ssklower 		bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
937*50501Ssklower 		insque(tpcb, &tp_bound_pcbs);
938*50501Ssklower 	} else {
939*50501Ssklower 		if (tlen || siso == 0)
940*50501Ssklower 			return (EINVAL);
941*50501Ssklower 	}
942*50501Ssklower 	if (siso == 0) {
943*50501Ssklower 		tpcb->tp_flags |= TPF_GENERAL_ADDR;
944*50501Ssklower 		return (0);
945*50501Ssklower 	}
946*50501Ssklower 	return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam);
947*50501Ssklower }
948