xref: /csrg-svn/sys/netiso/tp_pcb.c (revision 53687)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*53687Ssklower  *	@(#)tp_pcb.c	7.24 (Berkeley) 05/27/92
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 /* ticks are in units of:
7736408Ssklower  * 500 nano-fortnights ;-) or
7836408Ssklower  * 500 ms or
7936408Ssklower  * 1/2 second
8036408Ssklower  */
8136408Ssklower 
8236408Ssklower struct tp_conn_param tp_conn_param[] = {
8336408Ssklower 	/* ISO_CLNS: TP4 CONNECTION LESS */
8436408Ssklower 	{
8536408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
8636408Ssklower 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
8736408Ssklower 
8836408Ssklower 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
8936408Ssklower 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
9036408Ssklower 
9136408Ssklower 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
9236408Ssklower 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
9336408Ssklower 
9436408Ssklower 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
9536408Ssklower 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
9636408Ssklower 
9736408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
9836408Ssklower 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
9936408Ssklower 
10036408Ssklower 		(short) 100, 			/* short p_lcdtfract */
10136408Ssklower 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
10236408Ssklower 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
10336408Ssklower 
10436408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
10536408Ssklower 		TPRX_USE_CW | TPRX_FASTSTART,
10636408Ssklower 								/* 4 bits p_rx_strat*/
10736408Ssklower 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
10836408Ssklower 		1,						/* 1 bit xtd format */
10936408Ssklower 		1,						/* 1 bit xpd service */
11036408Ssklower 		1,						/* 1 bit use_checksum */
11136408Ssklower 		0,						/* 1 bit use net xpd */
11236408Ssklower 		0,						/* 1 bit use rcc */
11336408Ssklower 		0,						/* 1 bit use efc */
11438841Ssklower 		1,						/* no disc indications */
11536408Ssklower 		0,						/* don't change params */
11636408Ssklower 		ISO_CLNS,				/* p_netservice */
11736408Ssklower 	},
11836408Ssklower 	/* IN_CLNS: TP4 CONNECTION LESS */
11936408Ssklower 	{
12036408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
12136408Ssklower 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
12236408Ssklower 
12336408Ssklower 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
12436408Ssklower 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
12536408Ssklower 
12636408Ssklower 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
12736408Ssklower 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
12836408Ssklower 
12936408Ssklower 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
13036408Ssklower 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
13136408Ssklower 
13236408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
13336408Ssklower 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
13436408Ssklower 
13536408Ssklower 		(short) 100, 			/* short p_lcdtfract */
13636408Ssklower 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
13736408Ssklower 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
13836408Ssklower 
13936408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
14036408Ssklower 		TPRX_USE_CW | TPRX_FASTSTART,
14136408Ssklower 								/* 4 bits p_rx_strat*/
14236408Ssklower 		TP_CLASS_4,				/* 5 bits p_class */
14336408Ssklower 		1,						/* 1 bit xtd format */
14436408Ssklower 		1,						/* 1 bit xpd service */
14536408Ssklower 		1,						/* 1 bit use_checksum */
14636408Ssklower 		0,						/* 1 bit use net xpd */
14736408Ssklower 		0,						/* 1 bit use rcc */
14836408Ssklower 		0,						/* 1 bit use efc */
14938841Ssklower 		1,						/* no disc indications */
15036408Ssklower 		0,						/* don't change params */
15136408Ssklower 		IN_CLNS,				/* p_netservice */
15236408Ssklower 	},
15336408Ssklower 	/* ISO_CONS: TP0 CONNECTION MODE */
15436408Ssklower 	{
15536408Ssklower 		TP_NRETRANS, 			/* short p_Nretrans;  */
15636408Ssklower 		0,		/* n/a */		/* short p_dr_ticks; */
15736408Ssklower 
15836408Ssklower 		40,		/* 20 sec */	/* short p_cc_ticks; */
15936408Ssklower 		0,		/* n/a */		/* short p_dt_ticks; */
16036408Ssklower 
16136408Ssklower 		0,		/* n/a */		/* short p_x_ticks;	*/
16236408Ssklower 		360,	/* 3  min */	/* short p_cr_ticks;*/
16336408Ssklower 
16436408Ssklower 		0,		/* n/a */		/* short p_keepalive_ticks;*/
16536408Ssklower 		0,		/* n/a */		/* short p_sendack_ticks; */
16636408Ssklower 
16736408Ssklower 		600,	/* for cr/cc to clear *//* short p_ref_ticks;	*/
16836408Ssklower 		0,		/* n/a */		/* short p_inact_ticks;	*/
16936408Ssklower 
17036408Ssklower 		/* Use tp4 defaults just in case the user changes ONLY
17136408Ssklower 		 * the class
17236408Ssklower 		 */
17336408Ssklower 		(short) 100, 			/* short p_lcdtfract */
17436408Ssklower 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
17536408Ssklower 		TP0_TPDUSIZE, 			/* 8 bits p_tpdusize */
17636408Ssklower 
17736408Ssklower 		0, 						/* 4 bits p_ack_strat */
17836408Ssklower 		0, 						/* 4 bits p_rx_strat*/
17936408Ssklower 		TP_CLASS_0,				/* 5 bits p_class */
18036408Ssklower 		0,						/* 1 bit xtd format */
18136408Ssklower 		0,						/* 1 bit xpd service */
18236408Ssklower 		0,						/* 1 bit use_checksum */
18336408Ssklower 		0,						/* 1 bit use net xpd */
18436408Ssklower 		0,						/* 1 bit use rcc */
18536408Ssklower 		0,						/* 1 bit use efc */
18636408Ssklower 		0,						/* no disc indications */
18736408Ssklower 		0,						/* don't change params */
18836408Ssklower 		ISO_CONS,				/* p_netservice */
18936408Ssklower 	},
19036408Ssklower 	/* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */
19136408Ssklower 	{
19236408Ssklower 		TP_NRETRANS, 	/* short p_Nretrans;  */
19336408Ssklower 		40,		/* 20 sec */ 	/* short p_dr_ticks;  */
19436408Ssklower 
19536408Ssklower 		40,		/* 20 sec */ 	/* short p_cc_ticks; */
19636408Ssklower 		80,		/* 40 sec */ 	/* short p_dt_ticks; */
19736408Ssklower 
19836408Ssklower 		120,		/* 1 min */ 	/* short p_x_ticks;	 */
19936408Ssklower 		360,		/* 3 min */ 	/* short p_cr_ticks;*/
20036408Ssklower 
20136408Ssklower 		360,	/* 3 min */ 	/* short p_keepalive_ticks;*/
20236408Ssklower 		20,		/* 10 sec */ 	/* short p_sendack_ticks;  */
20336408Ssklower 
20436408Ssklower 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
20536408Ssklower 		480,	/* 4 min */ 	/* short p_inact_ticks;	*/
20636408Ssklower 
20736408Ssklower 		(short) 100, 			/* short p_lcdtfract */
20836408Ssklower 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
20936408Ssklower 		TP0_TPDUSIZE, 			/* u_char p_tpdusize */
21036408Ssklower 
21136408Ssklower 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
21236408Ssklower 		TPRX_USE_CW ,			/* No fast start */
21336408Ssklower 								/* 4 bits p_rx_strat*/
21436408Ssklower 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
21536408Ssklower 		0,						/* 1 bit xtd format */
21636408Ssklower 		1,						/* 1 bit xpd service */
21736408Ssklower 		1,						/* 1 bit use_checksum */
21836408Ssklower 		0,						/* 1 bit use net xpd */
21936408Ssklower 		0,						/* 1 bit use rcc */
22036408Ssklower 		0,						/* 1 bit use efc */
22136408Ssklower 		0,						/* no disc indications */
22236408Ssklower 		0,						/* don't change params */
22336408Ssklower 		ISO_COSNS,				/* p_netservice */
22436408Ssklower 	},
22536408Ssklower };
22636408Ssklower 
22736408Ssklower #ifdef INET
22836408Ssklower int		in_putnetaddr();
22936408Ssklower int		in_getnetaddr();
23044423Ssklower int		in_cmpnetaddr();
23136408Ssklower int 	in_putsufx();
23236408Ssklower int 	in_getsufx();
23336408Ssklower int 	in_recycle_tsuffix();
23436408Ssklower int 	tpip_mtu();
23536408Ssklower int 	in_pcbbind();
23636408Ssklower int 	in_pcbconnect();
23736408Ssklower int 	in_pcbdisconnect();
23836408Ssklower int 	in_pcbdetach();
23936408Ssklower int 	in_pcballoc();
24036408Ssklower int 	tpip_output();
24136408Ssklower int 	tpip_output_dg();
24236408Ssklower struct inpcb	tp_inpcb;
24336408Ssklower #endif INET
24436408Ssklower #ifdef ISO
24536408Ssklower int		iso_putnetaddr();
24636408Ssklower int		iso_getnetaddr();
24744423Ssklower int		iso_cmpnetaddr();
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
26245900Ssklower #ifdef TPCONS
26336408Ssklower int		iso_putnetaddr();
26436408Ssklower int		iso_getnetaddr();
26544423Ssklower int		iso_cmpnetaddr();
26636408Ssklower int 	iso_putsufx();
26736408Ssklower int 	iso_getsufx();
26836408Ssklower int 	iso_recycle_tsuffix();
26936408Ssklower int		iso_pcbbind();
27045900Ssklower int		tpcons_pcbconnect();
27149258Ssklower int		tpclnp_mtu();
27236408Ssklower int		iso_pcbdisconnect();
27336408Ssklower int 	iso_pcbdetach();
27436408Ssklower int 	iso_pcballoc();
27536408Ssklower int 	tpcons_output();
27636408Ssklower struct isopcb	tp_isopcb;
27745900Ssklower #endif TPCONS
27836408Ssklower 
27937469Ssklower 
28036408Ssklower struct nl_protosw nl_protosw[] = {
28136408Ssklower 	/* ISO_CLNS */
28236408Ssklower #ifdef ISO
28344423Ssklower 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
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 		},
29237469Ssklower #else
29337469Ssklower 	{ 0 },
29436408Ssklower #endif ISO
29536408Ssklower 	/* IN_CLNS */
29636408Ssklower #ifdef INET
29744423Ssklower 	{ AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr,
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 		},
30637469Ssklower #else
30737469Ssklower 	{ 0 },
30836408Ssklower #endif INET
30936408Ssklower 	/* ISO_CONS */
31045900Ssklower #if defined(ISO) && defined(TPCONS)
31144423Ssklower 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
31236408Ssklower 		iso_putsufx, iso_getsufx,
31336408Ssklower 		iso_recycle_tsuffix,
31449258Ssklower 		tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect,
31536408Ssklower 		iso_pcbdisconnect,	iso_pcbdetach,
31636408Ssklower 		iso_pcballoc,
31745900Ssklower 		tpcons_output, tpcons_output, iso_nlctloutput,
31836408Ssklower 		(caddr_t) &tp_isopcb,
31936408Ssklower 		},
32037469Ssklower #else
32137469Ssklower 	{ 0 },
32237469Ssklower #endif ISO_CONS
32337469Ssklower 	/* End of protosw marker */
32437469Ssklower 	{ 0 }
32536408Ssklower };
32636408Ssklower 
32751264Ssklower u_long tp_sendspace = 1024 * 4;
32851264Ssklower u_long tp_recvspace = 1024 * 4;
32951264Ssklower 
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;
43751007Ssklower 	IFPERF(tpcb)
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 
45051007Ssklower 	tpcb->tp_refstate = REF_FROZEN;
45151007Ssklower 	tp_recycle_tsuffix(tpcb);
45251204Ssklower 	tp_etimeout(tpcb, TM_reference, (int)tpcb->tp_refer_ticks);
45336408Ssklower }
45436408Ssklower 
45536408Ssklower /*
45636408Ssklower  * NAME:	tp_freeref()
45736408Ssklower  *
45836408Ssklower  * CALLED FROM:
45936408Ssklower  *  tp.trans when the reference timer goes off, and
46036408Ssklower  *  from tp_attach() and tp_detach() when a tpcb is partially set up but not
46136408Ssklower  *  set up enough to have a ref timer set for it, and it's discarded
46236408Ssklower  *  due to some sort of error or an early close()
46336408Ssklower  *
46436408Ssklower  * FUNCTION and ARGUMENTS:
46536408Ssklower  *  Frees the reference represented by (r) for re-use.
46636408Ssklower  *
46736408Ssklower  * RETURNS: Nothing
46836408Ssklower  *
46936408Ssklower  * SIDE EFFECTS:
47036408Ssklower  *
47136408Ssklower  * NOTES:	better be called at clock priority !!!!!
47236408Ssklower  */
47336408Ssklower void
47451213Ssklower tp_freeref(n)
47551213Ssklower RefNum n;
47636408Ssklower {
47751213Ssklower 	register struct tp_ref *r = tp_ref + n;
47851213Ssklower 	register struct tp_pcb *tpcb;
47951213Ssklower 
48051213Ssklower 	tpcb = r->tpr_pcb;
48136408Ssklower 	IFDEBUG(D_TIMER)
48251213Ssklower 		printf("tp_freeref called for ref %d pcb %x maxrefopen %d\n",
48351213Ssklower 		n, tpcb, tp_refinfo.tpr_maxopen);
48436408Ssklower 	ENDDEBUG
48536408Ssklower 	IFTRACE(D_TIMER)
48651213Ssklower 		tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb",
48751213Ssklower 		n, tp_refinfo.tpr_maxopen, tpcb, 0);
48836408Ssklower 	ENDTRACE
48951213Ssklower 	if (tpcb == 0)
49051213Ssklower 		return;
49136408Ssklower 	IFDEBUG(D_CONN)
49251213Ssklower 		printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", tpcb);
49336408Ssklower 	ENDDEBUG
49436408Ssklower 	r->tpr_pcb = (struct tp_pcb *)0;
49551213Ssklower 	tpcb->tp_refstate = REF_FREE;
49636408Ssklower 
49751007Ssklower 	for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--)
49851007Ssklower 		if (r->tpr_pcb)
49951007Ssklower 			break;
50051007Ssklower 	tp_refinfo.tpr_maxopen = r - tp_ref;
50151007Ssklower 	tp_refinfo.tpr_numopen--;
50236408Ssklower 
50336408Ssklower 	IFDEBUG(D_TIMER)
50451007Ssklower 		printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen);
50536408Ssklower 	ENDDEBUG
50636408Ssklower }
50736408Ssklower 
50836408Ssklower /*
50936408Ssklower  * NAME:  tp_getref()
51036408Ssklower  *
51136408Ssklower  * CALLED FROM:
51236408Ssklower  *  tp_attach()
51336408Ssklower  *
51436408Ssklower  * FUNCTION and ARGUMENTS:
51536408Ssklower  *  obtains the next free reference and allocates the appropriate
51636408Ssklower  *  ref structure, links that structure to (tpcb)
51736408Ssklower  *
51836408Ssklower  * RETURN VALUE:
51936408Ssklower  *	a reference number
52036408Ssklower  *  or TP_ENOREF
52136408Ssklower  *
52236408Ssklower  * SIDE EFFECTS:
52336408Ssklower  *
52436408Ssklower  * NOTES:
52536408Ssklower  */
52651204Ssklower u_long
52736408Ssklower tp_getref(tpcb)
52836408Ssklower 	register struct tp_pcb *tpcb;
52936408Ssklower {
53051007Ssklower 	register struct tp_ref	*r, *rlim;
53151007Ssklower 	register int 			i;
53251007Ssklower 	caddr_t obase;
53351007Ssklower 	unsigned size;
53436408Ssklower 
53551007Ssklower 	if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size)
53651007Ssklower 		for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size;
53751007Ssklower 								++r < rlim; ) 	/* tp_ref[0] is never used */
53851007Ssklower 			if (r->tpr_pcb == 0)
53951007Ssklower 				goto got_one;
54051007Ssklower 	/* else have to allocate more space */
54136408Ssklower 
54251007Ssklower 	obase = (caddr_t)tp_refinfo.tpr_base;
54351007Ssklower 	size = tp_refinfo.tpr_size * sizeof(struct tp_ref);
54451007Ssklower 	r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT);
54551007Ssklower 	if (r == 0)
54651007Ssklower 		return (--tp_refinfo.tpr_numopen, TP_ENOREF);
54751007Ssklower 	tp_refinfo.tpr_base = tp_ref = r;
54851007Ssklower 	tp_refinfo.tpr_size *= 2;
54951007Ssklower 	bcopy(obase, (caddr_t)r, size);
55051007Ssklower 	free(obase, M_PCB);
55151007Ssklower 	r = (struct tp_ref *)(size + (caddr_t)r);
55251007Ssklower 	bzero((caddr_t)r, size);
55351007Ssklower 
55451007Ssklower got_one:
55551007Ssklower 	r->tpr_pcb = tpcb;
55651213Ssklower 	tpcb->tp_refstate = REF_OPENING;
55751007Ssklower 	i = r - tp_refinfo.tpr_base;
55851007Ssklower 	if (tp_refinfo.tpr_maxopen < i)
55951007Ssklower 		tp_refinfo.tpr_maxopen = i;
56051213Ssklower 	return (u_long)i;
56136408Ssklower }
56236408Ssklower 
56336408Ssklower /*
56450648Ssklower  * NAME: tp_set_npcb()
56550648Ssklower  *
56650648Ssklower  * CALLED FROM:
56750648Ssklower  *	tp_attach(), tp_route_to()
56850648Ssklower  *
56950648Ssklower  * FUNCTION and ARGUMENTS:
57050648Ssklower  *  given a tpcb, allocate an appropriate lower-lever npcb, freeing
57150648Ssklower  *  any old ones that might need re-assigning.
57250648Ssklower  */
57350648Ssklower tp_set_npcb(tpcb)
57450648Ssklower register struct tp_pcb *tpcb;
57550648Ssklower {
57650648Ssklower 	register struct socket *so = tpcb->tp_sock;
57750648Ssklower 	int error;
57850648Ssklower 
57950648Ssklower 	if (tpcb->tp_nlproto && tpcb->tp_npcb) {
58050648Ssklower 		short so_state = so->so_state;
58150648Ssklower 		so->so_state &= ~SS_NOFDREF;
58250648Ssklower 		tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb);
58350648Ssklower 		so->so_state = so_state;
58450648Ssklower 	}
58550648Ssklower 	tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice];
58650648Ssklower 	/* xx_pcballoc sets so_pcb */
58750648Ssklower 	error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist);
58850648Ssklower 	tpcb->tp_npcb = so->so_pcb;
58950648Ssklower 	so->so_pcb = (caddr_t)tpcb;
59050648Ssklower 	return (error);
59150648Ssklower }
59250648Ssklower /*
59336408Ssklower  * NAME: tp_attach()
59436408Ssklower  *
59536408Ssklower  * CALLED FROM:
59636408Ssklower  *	tp_usrreq, PRU_ATTACH
59736408Ssklower  *
59836408Ssklower  * FUNCTION and ARGUMENTS:
59936408Ssklower  *  given a socket (so) and a protocol family (dom), allocate a tpcb
60036408Ssklower  *  and ref structure, initialize everything in the structures that
60136408Ssklower  *  needs to be initialized.
60236408Ssklower  *
60336408Ssklower  * RETURN VALUE:
60436408Ssklower  *  0 ok
60536408Ssklower  *  EINVAL if DEBUG(X) in is on and a disaster has occurred
60636408Ssklower  *  ENOPROTOOPT if TP hasn't been configured or if the
60736408Ssklower  *   socket wasn't created with tp as its protocol
60836408Ssklower  *  EISCONN if this socket is already part of a connection
60936408Ssklower  *  ETOOMANYREFS if ran out of tp reference numbers.
61036408Ssklower  *  E* whatever error is returned from soreserve()
61136408Ssklower  *    for from the network-layer pcb allocation routine
61236408Ssklower  *
61336408Ssklower  * SIDE EFFECTS:
61436408Ssklower  *
61536408Ssklower  * NOTES:
61636408Ssklower  */
61750648Ssklower tp_attach(so, protocol)
61850648Ssklower 	struct socket 			*so;
61950648Ssklower 	int 					protocol;
62036408Ssklower {
62136408Ssklower 	register struct tp_pcb	*tpcb;
62251264Ssklower 	int 					error = 0;
62350648Ssklower 	int 					dom = so->so_proto->pr_domain->dom_family;
62451204Ssklower 	u_long					lref;
62536408Ssklower 	extern struct tp_conn_param tp_conn_param[];
62636408Ssklower 
62736408Ssklower 	IFDEBUG(D_CONN)
62836408Ssklower 		printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
62936408Ssklower 	ENDDEBUG
63036408Ssklower 	IFTRACE(D_CONN)
63136408Ssklower 		tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
63236408Ssklower 	ENDTRACE
63336408Ssklower 
63436408Ssklower 	if (so->so_pcb != NULL) {
63536408Ssklower 		return EISCONN;	/* socket already part of a connection*/
63636408Ssklower 	}
63736408Ssklower 
63851264Ssklower 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0)
63951266Ssklower 		error = soreserve(so, tp_sendspace, tp_recvspace);
64036408Ssklower 		/* later an ioctl will allow reallocation IF still in closed state */
64136408Ssklower 
64236408Ssklower 	if (error)
64336408Ssklower 		goto bad2;
64436408Ssklower 
64537469Ssklower 	MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
64637469Ssklower 	if (tpcb == NULL) {
64736408Ssklower 		error = ENOBUFS;
64836408Ssklower 		goto bad2;
64936408Ssklower 	}
65036408Ssklower 	bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
65136408Ssklower 
65251204Ssklower 	if ( ((lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) {
65336408Ssklower 		error = ETOOMANYREFS;
65436408Ssklower 		goto bad3;
65536408Ssklower 	}
65651204Ssklower 	tpcb->tp_lref = lref;
65736408Ssklower 	tpcb->tp_sock =  so;
65836408Ssklower 	tpcb->tp_domain = dom;
659*53687Ssklower 	tpcb->tp_rhiwat = so->so_rcv.sb_hiwat;
66050648Ssklower 	/* tpcb->tp_proto = protocol; someday maybe? */
66150648Ssklower 	if (protocol && protocol<ISOPROTO_TP4) {
66236408Ssklower 		tpcb->tp_netservice = ISO_CONS;
66336408Ssklower 		tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
66436408Ssklower 								 * will generate correct fake-ack values
66536408Ssklower 								 */
66636408Ssklower 	} else {
66736408Ssklower 		tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
66836408Ssklower 		/* the default */
66936408Ssklower 	}
67036408Ssklower 	tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
67136408Ssklower 
67236408Ssklower 	tpcb->tp_state = TP_CLOSED;
67336408Ssklower 	tpcb->tp_vers  = TP_VERSION;
67450940Ssklower 	tpcb->tp_notdetached = 1;
67536408Ssklower 
67636408Ssklower 		   /* Spec says default is 128 octets,
67736408Ssklower 			* that is, if the tpdusize argument never appears, use 128.
67836408Ssklower 			* As the initiator, we will always "propose" the 2048
67936408Ssklower 			* size, that is, we will put this argument in the CR
68036408Ssklower 			* always, but accept what the other side sends on the CC.
68136408Ssklower 			* If the initiator sends us something larger on a CR,
68236408Ssklower 			* we'll respond w/ this.
68336408Ssklower 			* Our maximum is 4096.  See tp_chksum.c comments.
68436408Ssklower 			*/
68551204Ssklower 	tpcb->tp_cong_win =
68651204Ssklower 		tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
68736408Ssklower 
68836408Ssklower 	tpcb->tp_seqmask  = TP_NML_FMT_MASK;
68936408Ssklower 	tpcb->tp_seqbit  =  TP_NML_FMT_BIT;
69036408Ssklower 	tpcb->tp_seqhalf  =  tpcb->tp_seqbit >> 1;
69136408Ssklower 
69236408Ssklower 	/* attach to a network-layer protoswitch */
69350648Ssklower 	if ( error =  tp_set_npcb(tpcb))
69450648Ssklower 		goto bad4;
69536408Ssklower 	ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
69636408Ssklower 
69750648Ssklower 	/* nothing to do for iso case */
69836408Ssklower 	if( dom == AF_INET )
69936408Ssklower 		sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
70036408Ssklower 
70136408Ssklower 	return 0;
70236408Ssklower 
70336408Ssklower bad4:
70436408Ssklower 	IFDEBUG(D_CONN)
70536408Ssklower 		printf("BAD4 in tp_attach, so 0x%x\n", so);
70636408Ssklower 	ENDDEBUG
70751213Ssklower 	tp_freeref(tpcb->tp_lref);
70836408Ssklower 
70936408Ssklower bad3:
71036408Ssklower 	IFDEBUG(D_CONN)
71136408Ssklower 		printf("BAD3 in tp_attach, so 0x%x\n", so);
71236408Ssklower 	ENDDEBUG
71336408Ssklower 
71437469Ssklower 	free((caddr_t)tpcb, M_PCB); /* never a cluster  */
71536408Ssklower 
71636408Ssklower bad2:
71736408Ssklower 	IFDEBUG(D_CONN)
71836408Ssklower 		printf("BAD2 in tp_attach, so 0x%x\n", so);
71936408Ssklower 	ENDDEBUG
72036408Ssklower 	so->so_pcb = 0;
72136408Ssklower 
72237469Ssklower /*bad:*/
72336408Ssklower 	IFDEBUG(D_CONN)
72436408Ssklower 		printf("BAD in tp_attach, so 0x%x\n", so);
72536408Ssklower 	ENDDEBUG
72636408Ssklower 	return error;
72736408Ssklower }
72836408Ssklower 
72936408Ssklower /*
73036408Ssklower  * NAME:  tp_detach()
73136408Ssklower  *
73236408Ssklower  * CALLED FROM:
73336408Ssklower  *	tp.trans, on behalf of a user close request
73436408Ssklower  *  and when the reference timer goes off
73536408Ssklower  * (if the disconnect  was initiated by the protocol entity
73636408Ssklower  * rather than by the user)
73736408Ssklower  *
73836408Ssklower  * FUNCTION and ARGUMENTS:
73936408Ssklower  *  remove the tpcb structure from the list of active or
74036408Ssklower  *  partially active connections, recycle all the mbufs
74136408Ssklower  *  associated with the pcb, ref structure, sockbufs, etc.
74236408Ssklower  *  Only free the ref structure if you know that a ref timer
74336408Ssklower  *  wasn't set for this tpcb.
74436408Ssklower  *
74536408Ssklower  * RETURNS:  Nada
74636408Ssklower  *
74736408Ssklower  * SIDE EFFECTS:
74836408Ssklower  *
74936408Ssklower  * NOTES:
75036408Ssklower  *  tp_soisdisconnected() was already when this is called
75136408Ssklower  */
75236408Ssklower void
75336408Ssklower tp_detach(tpcb)
75436408Ssklower 	register struct tp_pcb 	*tpcb;
75536408Ssklower {
75650904Ssklower 	void					tp_freeref(), tp_rsyflush();
75736408Ssklower 	register struct socket	 *so = tpcb->tp_sock;
75836408Ssklower 
75936408Ssklower 	IFDEBUG(D_CONN)
76037469Ssklower 		printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
76137469Ssklower 			tpcb,so);
76236408Ssklower 	ENDDEBUG
76336408Ssklower 	IFTRACE(D_CONN)
76436408Ssklower 		tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
76539196Ssklower 			tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0);
76636408Ssklower 	ENDTRACE
76736408Ssklower 
76836408Ssklower 	IFDEBUG(D_CONN)
76947278Ssklower 		printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv);
77047278Ssklower 		dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
77147278Ssklower 		printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n",
77247278Ssklower 				tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
77347278Ssklower 	ENDDEBUG
77447278Ssklower 
77550648Ssklower 	if (tpcb->tp_Xsnd.sb_mb) {
77650648Ssklower 		printf("Unsent Xdata on detach; would panic");
77750648Ssklower 		sbflush(&tpcb->tp_Xsnd);
77850648Ssklower 	}
77947278Ssklower 	if (tpcb->tp_ucddata)
78047278Ssklower 		m_freem(tpcb->tp_ucddata);
78147278Ssklower 
78247278Ssklower 	IFDEBUG(D_CONN)
78350904Ssklower 		printf("reassembly info cnt %d rsyq 0x%x\n",
78450904Ssklower 		    tpcb->tp_rsycnt, tpcb->tp_rsyq);
78550904Ssklower 	ENDDEBUG
78650904Ssklower 	if (tpcb->tp_rsyq)
78750904Ssklower 		tp_rsyflush(tpcb);
78850904Ssklower 
78950940Ssklower 	if (tpcb->tp_next) {
79050940Ssklower 		remque(tpcb);
79150940Ssklower 		tpcb->tp_next = tpcb->tp_prev = 0;
79250940Ssklower 	}
79350940Ssklower 	tpcb->tp_notdetached = 0;
79450940Ssklower 
79550904Ssklower 	IFDEBUG(D_CONN)
79636408Ssklower 		printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
79750435Ssklower 			tpcb->tp_npcb, so);
79836408Ssklower 		printf("so 0x%x so_head 0x%x,  qlen %d q0len %d qlimit %d\n",
79936408Ssklower 		so,  so->so_head,
80036408Ssklower 		so->so_q0len, so->so_qlen, so->so_qlimit);
80136408Ssklower 	ENDDEBUG
80236408Ssklower 
80350435Ssklower 	(tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
80450648Ssklower 				/* does an so->so_pcb = 0; sofree(so) */
80537469Ssklower 
80636408Ssklower 	IFDEBUG(D_CONN)
80736408Ssklower 		printf("after xxx_pcbdetach\n");
80836408Ssklower 	ENDDEBUG
80936408Ssklower 
81050940Ssklower 	if (tpcb->tp_state == TP_LISTENING) {
81150940Ssklower 		register struct tp_pcb **tt;
81250940Ssklower 		for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
81350940Ssklower 			if (*tt == tpcb)
81450940Ssklower 				break;
81550940Ssklower 		if (*tt)
81650940Ssklower 			*tt = tpcb->tp_nextlisten;
81750940Ssklower 		else
81850940Ssklower 			printf("tp_detach from listen: should panic\n");
81950940Ssklower 	}
82051213Ssklower 	if (tpcb->tp_refstate == REF_OPENING ) {
82136408Ssklower 		/* no connection existed here so no reference timer will be called */
82236408Ssklower 		IFDEBUG(D_CONN)
82351213Ssklower 			printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref);
82436408Ssklower 		ENDDEBUG
82536408Ssklower 
82651213Ssklower 		tp_freeref(tpcb->tp_lref);
82736408Ssklower 	}
82850648Ssklower #ifdef TP_PERF_MEAS
82936408Ssklower 	/*
83036408Ssklower 	 * Get rid of the cluster mbuf allocated for performance measurements, if
83136408Ssklower 	 * there is one.  Note that tpcb->tp_perf_on says nothing about whether or
83236408Ssklower 	 * not a cluster mbuf was allocated, so you have to check for a pointer
83336408Ssklower 	 * to one (that is, we need the TP_PERF_MEASs around the following section
83436408Ssklower 	 * of code, not the IFPERFs)
83536408Ssklower 	 */
83647278Ssklower 	if (tpcb->tp_p_mbuf) {
83737469Ssklower 		register struct mbuf *m = tpcb->tp_p_mbuf;
83837469Ssklower 		struct mbuf *n;
83936408Ssklower 		IFDEBUG(D_PERF_MEAS)
84036408Ssklower 			printf("freeing tp_p_meas 0x%x  ", tpcb->tp_p_meas);
84136408Ssklower 		ENDDEBUG
84237469Ssklower 		do {
84337469Ssklower 		    MFREE(m, n);
84437469Ssklower 		    m = n;
84537469Ssklower 		} while (n);
84637469Ssklower 		tpcb->tp_p_meas = 0;
84737469Ssklower 		tpcb->tp_p_mbuf = 0;
84836408Ssklower 	}
84936408Ssklower #endif TP_PERF_MEAS
85036408Ssklower 
85136408Ssklower 	IFDEBUG(D_CONN)
85237469Ssklower 		printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
85336408Ssklower 	ENDDEBUG
85437469Ssklower 	/* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
85536408Ssklower }
85650501Ssklower 
85750501Ssklower struct que {
85850501Ssklower 	struct tp_pcb *next;
85950501Ssklower 	struct tp_pcb *prev;
86050501Ssklower } tp_bound_pcbs =
86150501Ssklower {(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs};
86250501Ssklower 
86350501Ssklower u_short tp_unique;
86450501Ssklower 
86550501Ssklower tp_tselinuse(tlen, tsel, siso, reuseaddr)
86650501Ssklower caddr_t tsel;
86750501Ssklower register struct sockaddr_iso *siso;
86850501Ssklower {
86950501Ssklower 	struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
87050501Ssklower 	register struct tp_pcb *t;
87150501Ssklower 
87250501Ssklower 	for (;;) {
87350501Ssklower 		if (b != (struct tp_pcb *)&tp_bound_pcbs) {
87450501Ssklower 			t = b; b = t->tp_next;
87550501Ssklower 		} else if (l) {
87650501Ssklower 			t = l; l = t->tp_nextlisten;
87750501Ssklower 		} else
87850501Ssklower 			break;
87950501Ssklower 		if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
88050501Ssklower 			if (t->tp_flags & TPF_GENERAL_ADDR) {
88150501Ssklower 				if (siso == 0 || reuseaddr == 0)
88250501Ssklower 					return 1;
88350501Ssklower 			} else if (siso) {
88450501Ssklower 				if (siso->siso_family == t->tp_domain &&
88550501Ssklower 					t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL))
88650501Ssklower 						return 1;
88750501Ssklower 			} else if (reuseaddr == 0)
88850501Ssklower 						return 1;
88950501Ssklower 		}
89050501Ssklower 	}
89150501Ssklower 	return 0;
89250501Ssklower 
89350501Ssklower }
89450501Ssklower 
89550501Ssklower 
89650501Ssklower tp_pcbbind(tpcb, nam)
89750501Ssklower register struct tp_pcb *tpcb;
89850501Ssklower register struct mbuf *nam;
89950501Ssklower {
90050501Ssklower 	register struct sockaddr_iso *siso = 0;
90150501Ssklower 	int tlen = 0, wrapped = 0;
90250501Ssklower 	caddr_t tsel;
90350501Ssklower 	u_short tutil;
90450501Ssklower 
90550501Ssklower 	if (tpcb->tp_state != TP_CLOSED)
90650501Ssklower 		return (EINVAL);
90750501Ssklower 	if (nam) {
90850501Ssklower 		siso = mtod(nam, struct sockaddr_iso *);
90950501Ssklower 		switch (siso->siso_family) {
91050501Ssklower 		default:
91150501Ssklower 			return (EAFNOSUPPORT);
91250501Ssklower #ifdef ISO
91350501Ssklower 		case AF_ISO:
91450501Ssklower 			tlen = siso->siso_tlen;
91550501Ssklower 			tsel = TSEL(siso);
91650501Ssklower 			if (siso->siso_nlen == 0)
91750501Ssklower 				siso = 0;
91850501Ssklower 			break;
91950501Ssklower #endif
92050501Ssklower #ifdef INET
92150501Ssklower 		case AF_INET:
92250501Ssklower 			tsel = (caddr_t)&tutil;
92350501Ssklower 			if (tutil =  ((struct sockaddr_in *)siso)->sin_port) {
92450501Ssklower 				tlen = 2;
92550501Ssklower 			}
92650501Ssklower 			if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0)
92750501Ssklower 				siso = 0;
92850501Ssklower 		}
92950501Ssklower #endif
93050501Ssklower 	}
93150501Ssklower 	if (tpcb->tp_lsuffixlen == 0) {
93250501Ssklower 		if (tlen) {
93350648Ssklower 			if (tp_tselinuse(tlen, tsel, siso,
93450501Ssklower 								tpcb->tp_sock->so_options & SO_REUSEADDR))
93550501Ssklower 				return (EINVAL);
93653185Ssklower 		} else {
93753185Ssklower 			for (tsel = (caddr_t)&tutil, tlen = 2;;){
93853185Ssklower 				if (tp_unique++ < ISO_PORT_RESERVED ||
93953185Ssklower 					tp_unique > ISO_PORT_USERRESERVED) {
94053185Ssklower 						if (wrapped++)
94153185Ssklower 							return ESRCH;
94253185Ssklower 						tp_unique = ISO_PORT_RESERVED;
94353185Ssklower 				}
94453185Ssklower 				tutil = htons(tp_unique);
94553185Ssklower 				if (tp_tselinuse(tlen, tsel, siso, 0) == 0)
94653185Ssklower 					break;
94750501Ssklower 			}
94853185Ssklower 			if (siso) switch (siso->siso_family) {
94953185Ssklower #ifdef ISO
95053185Ssklower 				case AF_ISO:
95153185Ssklower 					bcopy(tsel, TSEL(siso), tlen);
95253185Ssklower 					siso->siso_tlen = tlen;
95353185Ssklower 					break;
95453185Ssklower #endif
95553185Ssklower #ifdef INET
95653185Ssklower 				case AF_INET:
95753185Ssklower 					((struct sockaddr_in *)siso)->sin_port = tutil;
95853185Ssklower #endif
95953185Ssklower 				}
96050501Ssklower 		}
96150501Ssklower 		bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
96250501Ssklower 		insque(tpcb, &tp_bound_pcbs);
96350501Ssklower 	} else {
96450501Ssklower 		if (tlen || siso == 0)
96550501Ssklower 			return (EINVAL);
96650501Ssklower 	}
96750501Ssklower 	if (siso == 0) {
96850501Ssklower 		tpcb->tp_flags |= TPF_GENERAL_ADDR;
96950501Ssklower 		return (0);
97050501Ssklower 	}
97150501Ssklower 	return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam);
97250501Ssklower }
973