xref: /csrg-svn/sys/netiso/tp_pcb.c (revision 50501)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)tp_pcb.c	7.13 (Berkeley) 07/23/91
8  */
9 
10 /***********************************************************
11 				Copyright IBM Corporation 1987
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 
31 ******************************************************************/
32 
33 /*
34  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35  */
36 /*
37  * ARGO TP
38  *
39  * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $
40  * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $
41  *
42  *
43  * This is the initialization and cleanup stuff -
44  * for the tp machine in general as well as  for the individual pcbs.
45  * tp_init() is called at system startup.  tp_attach() and tp_getref() are
46  * called when a socket is created.  tp_detach() and tp_freeref()
47  * are called during the closing stage and/or when the reference timer
48  * goes off.
49  * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific
50  * versions of soisconnect*
51  * and are called (obviously) during the closing phase.
52  *
53  */
54 
55 #include "types.h"
56 #include "param.h"
57 #include "mbuf.h"
58 #include "socket.h"
59 #include "socketvar.h"
60 #include "protosw.h"
61 #include "errno.h"
62 #include "time.h"
63 #include "argo_debug.h"
64 #include "tp_param.h"
65 #include "tp_timer.h"
66 #include "tp_ip.h"
67 #include "tp_stat.h"
68 #include "tp_pcb.h"
69 #include "tp_tpdu.h"
70 #include "tp_trace.h"
71 #include "tp_meas.h"
72 #include "tp_seq.h"
73 #include "tp_clnp.h"
74 
75 struct tp_param tp_param = {
76 	1,				/*  configured 		*/
77 };
78 
79 /* ticks are in units of:
80  * 500 nano-fortnights ;-) or
81  * 500 ms or
82  * 1/2 second
83  */
84 
85 struct tp_conn_param tp_conn_param[] = {
86 	/* ISO_CLNS: TP4 CONNECTION LESS */
87 	{
88 		TP_NRETRANS, 	/* short p_Nretrans;  */
89 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
90 
91 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
92 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
93 
94 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
95 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
96 
97 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
98 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
99 
100 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
101 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
102 
103 		(short) 100, 			/* short p_lcdtfract */
104 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
105 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
106 
107 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
108 		TPRX_USE_CW | TPRX_FASTSTART,
109 								/* 4 bits p_rx_strat*/
110 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
111 		1,						/* 1 bit xtd format */
112 		1,						/* 1 bit xpd service */
113 		1,						/* 1 bit use_checksum */
114 		0,						/* 1 bit use net xpd */
115 		0,						/* 1 bit use rcc */
116 		0,						/* 1 bit use efc */
117 		1,						/* no disc indications */
118 		0,						/* don't change params */
119 		ISO_CLNS,				/* p_netservice */
120 	},
121 	/* IN_CLNS: TP4 CONNECTION LESS */
122 	{
123 		TP_NRETRANS, 	/* short p_Nretrans;  */
124 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
125 
126 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
127 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
128 
129 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
130 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
131 
132 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
133 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
134 
135 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
136 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
137 
138 		(short) 100, 			/* short p_lcdtfract */
139 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
140 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
141 
142 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
143 		TPRX_USE_CW | TPRX_FASTSTART,
144 								/* 4 bits p_rx_strat*/
145 		TP_CLASS_4,				/* 5 bits p_class */
146 		1,						/* 1 bit xtd format */
147 		1,						/* 1 bit xpd service */
148 		1,						/* 1 bit use_checksum */
149 		0,						/* 1 bit use net xpd */
150 		0,						/* 1 bit use rcc */
151 		0,						/* 1 bit use efc */
152 		1,						/* no disc indications */
153 		0,						/* don't change params */
154 		IN_CLNS,				/* p_netservice */
155 	},
156 	/* ISO_CONS: TP0 CONNECTION MODE */
157 	{
158 		TP_NRETRANS, 			/* short p_Nretrans;  */
159 		0,		/* n/a */		/* short p_dr_ticks; */
160 
161 		40,		/* 20 sec */	/* short p_cc_ticks; */
162 		0,		/* n/a */		/* short p_dt_ticks; */
163 
164 		0,		/* n/a */		/* short p_x_ticks;	*/
165 		360,	/* 3  min */	/* short p_cr_ticks;*/
166 
167 		0,		/* n/a */		/* short p_keepalive_ticks;*/
168 		0,		/* n/a */		/* short p_sendack_ticks; */
169 
170 		600,	/* for cr/cc to clear *//* short p_ref_ticks;	*/
171 		0,		/* n/a */		/* short p_inact_ticks;	*/
172 
173 		/* Use tp4 defaults just in case the user changes ONLY
174 		 * the class
175 		 */
176 		(short) 100, 			/* short p_lcdtfract */
177 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
178 		TP0_TPDUSIZE, 			/* 8 bits p_tpdusize */
179 
180 		0, 						/* 4 bits p_ack_strat */
181 		0, 						/* 4 bits p_rx_strat*/
182 		TP_CLASS_0,				/* 5 bits p_class */
183 		0,						/* 1 bit xtd format */
184 		0,						/* 1 bit xpd service */
185 		0,						/* 1 bit use_checksum */
186 		0,						/* 1 bit use net xpd */
187 		0,						/* 1 bit use rcc */
188 		0,						/* 1 bit use efc */
189 		0,						/* no disc indications */
190 		0,						/* don't change params */
191 		ISO_CONS,				/* p_netservice */
192 	},
193 	/* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */
194 	{
195 		TP_NRETRANS, 	/* short p_Nretrans;  */
196 		40,		/* 20 sec */ 	/* short p_dr_ticks;  */
197 
198 		40,		/* 20 sec */ 	/* short p_cc_ticks; */
199 		80,		/* 40 sec */ 	/* short p_dt_ticks; */
200 
201 		120,		/* 1 min */ 	/* short p_x_ticks;	 */
202 		360,		/* 3 min */ 	/* short p_cr_ticks;*/
203 
204 		360,	/* 3 min */ 	/* short p_keepalive_ticks;*/
205 		20,		/* 10 sec */ 	/* short p_sendack_ticks;  */
206 
207 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
208 		480,	/* 4 min */ 	/* short p_inact_ticks;	*/
209 
210 		(short) 100, 			/* short p_lcdtfract */
211 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
212 		TP0_TPDUSIZE, 			/* u_char p_tpdusize */
213 
214 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
215 		TPRX_USE_CW ,			/* No fast start */
216 								/* 4 bits p_rx_strat*/
217 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
218 		0,						/* 1 bit xtd format */
219 		1,						/* 1 bit xpd service */
220 		1,						/* 1 bit use_checksum */
221 		0,						/* 1 bit use net xpd */
222 		0,						/* 1 bit use rcc */
223 		0,						/* 1 bit use efc */
224 		0,						/* no disc indications */
225 		0,						/* don't change params */
226 		ISO_COSNS,				/* p_netservice */
227 	},
228 };
229 
230 #ifdef INET
231 int		in_putnetaddr();
232 int		in_getnetaddr();
233 int		in_cmpnetaddr();
234 int 	in_putsufx();
235 int 	in_getsufx();
236 int 	in_recycle_tsuffix();
237 int 	tpip_mtu();
238 int 	in_pcbbind();
239 int 	in_pcbconnect();
240 int 	in_pcbdisconnect();
241 int 	in_pcbdetach();
242 int 	in_pcballoc();
243 int 	tpip_output();
244 int 	tpip_output_dg();
245 struct inpcb	tp_inpcb;
246 #endif INET
247 #ifdef ISO
248 int		iso_putnetaddr();
249 int		iso_getnetaddr();
250 int		iso_cmpnetaddr();
251 int 	iso_putsufx();
252 int 	iso_getsufx();
253 int 	iso_recycle_tsuffix();
254 int		tpclnp_mtu();
255 int		iso_pcbbind();
256 int		iso_pcbconnect();
257 int		iso_pcbdisconnect();
258 int 	iso_pcbdetach();
259 int 	iso_pcballoc();
260 int 	tpclnp_output();
261 int 	tpclnp_output_dg();
262 int		iso_nlctloutput();
263 struct isopcb	tp_isopcb;
264 #endif ISO
265 #ifdef TPCONS
266 int		iso_putnetaddr();
267 int		iso_getnetaddr();
268 int		iso_cmpnetaddr();
269 int 	iso_putsufx();
270 int 	iso_getsufx();
271 int 	iso_recycle_tsuffix();
272 int		iso_pcbbind();
273 int		tpcons_pcbconnect();
274 int		tpclnp_mtu();
275 int		iso_pcbdisconnect();
276 int 	iso_pcbdetach();
277 int 	iso_pcballoc();
278 int 	tpcons_output();
279 struct isopcb	tp_isopcb;
280 #endif TPCONS
281 
282 
283 struct nl_protosw nl_protosw[] = {
284 	/* ISO_CLNS */
285 #ifdef ISO
286 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
287 		iso_putsufx, iso_getsufx,
288 		iso_recycle_tsuffix,
289 		tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
290 		iso_pcbdisconnect,	iso_pcbdetach,
291 		iso_pcballoc,
292 		tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
293 		(caddr_t) &tp_isopcb,
294 		},
295 #else
296 	{ 0 },
297 #endif ISO
298 	/* IN_CLNS */
299 #ifdef INET
300 	{ AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr,
301 		in_putsufx, in_getsufx,
302 		in_recycle_tsuffix,
303 		tpip_mtu, in_pcbbind, in_pcbconnect,
304 		in_pcbdisconnect,	in_pcbdetach,
305 		in_pcballoc,
306 		tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
307 		(caddr_t) &tp_inpcb,
308 		},
309 #else
310 	{ 0 },
311 #endif INET
312 	/* ISO_CONS */
313 #if defined(ISO) && defined(TPCONS)
314 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
315 		iso_putsufx, iso_getsufx,
316 		iso_recycle_tsuffix,
317 		tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect,
318 		iso_pcbdisconnect,	iso_pcbdetach,
319 		iso_pcballoc,
320 		tpcons_output, tpcons_output, iso_nlctloutput,
321 		(caddr_t) &tp_isopcb,
322 		},
323 #else
324 	{ 0 },
325 #endif ISO_CONS
326 	/* End of protosw marker */
327 	{ 0 }
328 };
329 
330 /*
331  * NAME:  tp_init()
332  *
333  * CALLED FROM:
334  *  autoconf through the protosw structure
335  *
336  * FUNCTION:
337  *  initialize tp machine
338  *
339  * RETURNS:  Nada
340  *
341  * SIDE EFFECTS:
342  *
343  * NOTES:
344  */
345 int
346 tp_init()
347 {
348 	static int 	init_done=0;
349 	void	 	tp_timerinit();
350 
351 	if (init_done++)
352 		return 0;
353 
354 
355 	/* FOR INET */
356 	tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb;
357 	/* FOR ISO */
358 	tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
359 
360     tp_start_win = 2;
361 
362 	tp_timerinit();
363 	bzero((caddr_t)&tp_stat, sizeof(struct tp_stat));
364 	return 0;
365 }
366 
367 /*
368  * NAME: 	tp_soisdisconnecting()
369  *
370  * CALLED FROM:
371  *  tp.trans
372  *
373  * FUNCTION and ARGUMENTS:
374  *  Set state of the socket (so) to reflect that fact that we're disconnectING
375  *
376  * RETURNS: 	Nada
377  *
378  * SIDE EFFECTS:
379  *
380  * NOTES:
381  *  This differs from the regular soisdisconnecting() in that the latter
382  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
383  *  We don't want to set those flags because those flags will cause
384  *  a SIGPIPE to be delivered in sosend() and we don't like that.
385  *  If anyone else is sleeping on this socket, wake 'em up.
386  */
387 void
388 tp_soisdisconnecting(so)
389 	register struct socket *so;
390 {
391 	soisdisconnecting(so);
392 	so->so_state &= ~SS_CANTSENDMORE;
393 	IFPERF(sototpcb(so))
394 		register struct tp_pcb *tpcb = sototpcb(so);
395 		u_int 	fsufx, lsufx;
396 
397 		bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
398 		bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
399 
400 		tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref);
401 		tpcb->tp_perf_on = 0; /* turn perf off */
402 	ENDPERF
403 }
404 
405 
406 /*
407  * NAME: tp_soisdisconnected()
408  *
409  * CALLED FROM:
410  *	tp.trans
411  *
412  * FUNCTION and ARGUMENTS:
413  *  Set state of the socket (so) to reflect that fact that we're disconnectED
414  *  Set the state of the reference structure to closed, and
415  *  recycle the suffix.
416  *  Start a reference timer.
417  *
418  * RETURNS:	Nada
419  *
420  * SIDE EFFECTS:
421  *
422  * NOTES:
423  *  This differs from the regular soisdisconnected() in that the latter
424  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
425  *  We don't want to set those flags because those flags will cause
426  *  a SIGPIPE to be delivered in sosend() and we don't like that.
427  *  If anyone else is sleeping on this socket, wake 'em up.
428  */
429 void
430 tp_soisdisconnected(tpcb)
431 	register struct tp_pcb	*tpcb;
432 {
433 	register struct socket	*so = tpcb->tp_sock;
434 
435 	soisdisconnecting(so);
436 	so->so_state &= ~SS_CANTSENDMORE;
437 	IFPERF(sototpcb(so))
438 		register struct tp_pcb *ttpcb = sototpcb(so);
439 		u_int 	fsufx, lsufx;
440 
441 		/* CHOKE */
442 		bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
443 		bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
444 
445 		tpmeas(ttpcb->tp_lref, TPtime_close,
446 		   &time, &lsufx, &fsufx, ttpcb->tp_fref);
447 		tpcb->tp_perf_on = 0; /* turn perf off */
448 	ENDPERF
449 
450 	tpcb->tp_refp->tpr_state = REF_FROZEN;
451 	tp_recycle_tsuffix( tpcb );
452 	tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks);
453 }
454 
455 int tp_maxrefopen;  /* highest reference # of the set of open tp connections */
456 
457 /*
458  * NAME:	tp_freeref()
459  *
460  * CALLED FROM:
461  *  tp.trans when the reference timer goes off, and
462  *  from tp_attach() and tp_detach() when a tpcb is partially set up but not
463  *  set up enough to have a ref timer set for it, and it's discarded
464  *  due to some sort of error or an early close()
465  *
466  * FUNCTION and ARGUMENTS:
467  *  Frees the reference represented by (r) for re-use.
468  *
469  * RETURNS: Nothing
470  *
471  * SIDE EFFECTS:
472  *
473  * NOTES:	better be called at clock priority !!!!!
474  */
475 void
476 tp_freeref(r)
477 	register struct tp_ref *r;
478 {
479 	IFDEBUG(D_TIMER)
480 		printf("tp_freeref called for ref %d maxrefopen %d\n",
481 		r - tp_ref, tp_maxrefopen);
482 	ENDDEBUG
483 	IFTRACE(D_TIMER)
484 		tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen",
485 		r - tp_ref, tp_maxrefopen, 0, 0);
486 	ENDTRACE
487 	r->tpr_state = REF_FREE;
488 	IFDEBUG(D_CONN)
489 		printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb);
490 	ENDDEBUG
491 	r->tpr_pcb = (struct tp_pcb *)0;
492 
493 	r = &tp_ref[tp_maxrefopen];
494 
495 	while( tp_maxrefopen > 0 ) {
496 		if(r->tpr_state )
497 			break;
498 		tp_maxrefopen--;
499 		r--;
500 	}
501 	IFDEBUG(D_TIMER)
502 		printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen);
503 	ENDDEBUG
504 }
505 
506 /*
507  * NAME:  tp_getref()
508  *
509  * CALLED FROM:
510  *  tp_attach()
511  *
512  * FUNCTION and ARGUMENTS:
513  *  obtains the next free reference and allocates the appropriate
514  *  ref structure, links that structure to (tpcb)
515  *
516  * RETURN VALUE:
517  *	a reference number
518  *  or TP_ENOREF
519  *
520  * SIDE EFFECTS:
521  *
522  * NOTES:
523  */
524 static RefNum
525 tp_getref(tpcb)
526 	register struct tp_pcb *tpcb;
527 {
528 	register struct tp_ref	*r = tp_ref; /* tp_ref[0] is never used */
529 	register int 			i=1;
530 
531 
532 	while ((++r)->tpr_state != REF_FREE) {
533 		if (++i == N_TPREF)
534 			return TP_ENOREF;
535 	}
536 	r->tpr_state = REF_OPENING;
537 	if (tp_maxrefopen < i)
538 		tp_maxrefopen = i;
539 	r->tpr_pcb = tpcb;
540 	tpcb->tp_refp = r;
541 
542 	return i;
543 }
544 
545 /*
546  * NAME: tp_attach()
547  *
548  * CALLED FROM:
549  *	tp_usrreq, PRU_ATTACH
550  *
551  * FUNCTION and ARGUMENTS:
552  *  given a socket (so) and a protocol family (dom), allocate a tpcb
553  *  and ref structure, initialize everything in the structures that
554  *  needs to be initialized.
555  *
556  * RETURN VALUE:
557  *  0 ok
558  *  EINVAL if DEBUG(X) in is on and a disaster has occurred
559  *  ENOPROTOOPT if TP hasn't been configured or if the
560  *   socket wasn't created with tp as its protocol
561  *  EISCONN if this socket is already part of a connection
562  *  ETOOMANYREFS if ran out of tp reference numbers.
563  *  E* whatever error is returned from soreserve()
564  *    for from the network-layer pcb allocation routine
565  *
566  * SIDE EFFECTS:
567  *
568  * NOTES:
569  */
570 tp_attach(so, dom)
571 	struct socket 	*so;
572 	int 			dom;
573 {
574 	register struct tp_pcb	*tpcb;
575 	int 					error;
576 	int 					protocol = so->so_proto->pr_protocol;
577 	extern struct tp_conn_param tp_conn_param[];
578 
579 	IFDEBUG(D_CONN)
580 		printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
581 	ENDDEBUG
582 	IFTRACE(D_CONN)
583 		tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
584 	ENDTRACE
585 	if ( ! tp_param.tpp_configed ) {
586 		error = ENOPROTOOPT; /* protocol not available */
587 		goto bad2;
588 	}
589 
590 	if (so->so_pcb != NULL) {
591 		return EISCONN;	/* socket already part of a connection*/
592 	}
593 
594 	error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE);
595 		/* later an ioctl will allow reallocation IF still in closed state */
596 
597 	if (error)
598 		goto bad2;
599 
600 	MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
601 	if (tpcb == NULL) {
602 		error = ENOBUFS;
603 		goto bad2;
604 	}
605 	bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
606 
607 	if ( ((tpcb->tp_lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) {
608 		error = ETOOMANYREFS;
609 		goto bad3;
610 	}
611 	tpcb->tp_sock =  so;
612 	tpcb->tp_domain = dom;
613 	if (protocol<ISOPROTO_TP4) {
614 		tpcb->tp_netservice = ISO_CONS;
615 		tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
616 								 * will generate correct fake-ack values
617 								 */
618 	} else {
619 		tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
620 		/* the default */
621 	}
622 	tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
623 
624 	tpcb->tp_cong_win = 1;
625 	tpcb->tp_state = TP_CLOSED;
626 	tpcb->tp_vers  = TP_VERSION;
627 
628 		   /* Spec says default is 128 octets,
629 			* that is, if the tpdusize argument never appears, use 128.
630 			* As the initiator, we will always "propose" the 2048
631 			* size, that is, we will put this argument in the CR
632 			* always, but accept what the other side sends on the CC.
633 			* If the initiator sends us something larger on a CR,
634 			* we'll respond w/ this.
635 			* Our maximum is 4096.  See tp_chksum.c comments.
636 			*/
637 	tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
638 
639 	tpcb->tp_seqmask  = TP_NML_FMT_MASK;
640 	tpcb->tp_seqbit  =  TP_NML_FMT_BIT;
641 	tpcb->tp_seqhalf  =  tpcb->tp_seqbit >> 1;
642 	tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */
643 	tpcb->tp_s_subseq = 0;
644 
645 	/* attach to a network-layer protoswitch */
646 	/* new way */
647 	tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice];
648 	ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
649 #ifdef notdef
650 	/* OLD WAY */
651 	/* TODO: properly, this search would be on the basis of
652 	* domain,netservice or just netservice only (if you have
653 	* IN_CLNS, ISO_CLNS, and ISO_CONS)
654 	*/
655 	tpcb->tp_nlproto = nl_protosw;
656 	while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain )  {
657 		if( tpcb->tp_nlproto->nlp_afamily == 0 ) {
658 			error = EAFNOSUPPORT;
659 			goto bad4;
660 		}
661 		tpcb->tp_nlproto ++;
662 	}
663 #endif notdef
664 
665 	/* xx_pcballoc sets so_pcb */
666 	if ( error =  (tpcb->tp_nlproto->nlp_pcballoc) (
667 							so, tpcb->tp_nlproto->nlp_pcblist ) ) {
668 		goto bad4;
669 	}
670 
671 	if( dom == AF_INET )
672 		sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
673 		/* nothing to do for iso case */
674 
675 	tpcb->tp_npcb = so->so_pcb;
676 	so->so_pcb = (caddr_t) tpcb;
677 
678 	return 0;
679 
680 bad4:
681 	IFDEBUG(D_CONN)
682 		printf("BAD4 in tp_attach, so 0x%x\n", so);
683 	ENDDEBUG
684 	tp_freeref(tpcb->tp_refp);
685 
686 bad3:
687 	IFDEBUG(D_CONN)
688 		printf("BAD3 in tp_attach, so 0x%x\n", so);
689 	ENDDEBUG
690 
691 	free((caddr_t)tpcb, M_PCB); /* never a cluster  */
692 
693 bad2:
694 	IFDEBUG(D_CONN)
695 		printf("BAD2 in tp_attach, so 0x%x\n", so);
696 	ENDDEBUG
697 	so->so_pcb = 0;
698 
699 /*bad:*/
700 	IFDEBUG(D_CONN)
701 		printf("BAD in tp_attach, so 0x%x\n", so);
702 	ENDDEBUG
703 	return error;
704 }
705 
706 /*
707  * NAME:  tp_detach()
708  *
709  * CALLED FROM:
710  *	tp.trans, on behalf of a user close request
711  *  and when the reference timer goes off
712  * (if the disconnect  was initiated by the protocol entity
713  * rather than by the user)
714  *
715  * FUNCTION and ARGUMENTS:
716  *  remove the tpcb structure from the list of active or
717  *  partially active connections, recycle all the mbufs
718  *  associated with the pcb, ref structure, sockbufs, etc.
719  *  Only free the ref structure if you know that a ref timer
720  *  wasn't set for this tpcb.
721  *
722  * RETURNS:  Nada
723  *
724  * SIDE EFFECTS:
725  *
726  * NOTES:
727  *  tp_soisdisconnected() was already when this is called
728  */
729 void
730 tp_detach(tpcb)
731 	register struct tp_pcb 	*tpcb;
732 {
733 	void					tp_freeref();
734 	register struct socket	 *so = tpcb->tp_sock;
735 
736 	IFDEBUG(D_CONN)
737 		printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
738 			tpcb,so);
739 	ENDDEBUG
740 	IFTRACE(D_CONN)
741 		tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
742 			tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0);
743 	ENDTRACE
744 
745 	if (so->so_head) {
746 		if (!soqremque(so, 0) && !soqremque(so, 1))
747 			panic("sofree dq");
748 		so->so_head = 0;
749 	}
750 
751 	IFDEBUG(D_CONN)
752 		printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n",
753 		tpcb->tp_snduna_rtc,
754 		tpcb->tp_rcvnxt_rtc);
755 	ENDDEBUG
756 
757 #define FREE_RTC_LIST(XXX)\
758 	{ register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\
759 		xxs = xxr->tprt_next;\
760 		m_freem( xxr->tprt_data );\
761 		m_free( dtom(xxr) ); xxr = xxs; }\
762 		XXX = (struct tp_rtc *)0;\
763 	}
764 
765 	FREE_RTC_LIST( tpcb->tp_snduna_rtc );
766 	tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0;
767 
768 	FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc );
769 
770 #undef FREE_RTC_LIST
771 
772 	IFDEBUG(D_CONN)
773 		printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv);
774 		dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
775 		printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n",
776 				tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
777 	ENDDEBUG
778 
779 	if (so->so_snd.sb_cc != 0)
780 		sbflush(&so->so_snd);
781 	if (tpcb->tp_Xrcv.sb_cc != 0)
782 		sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc);
783 	if (tpcb->tp_ucddata)
784 		m_freem(tpcb->tp_ucddata);
785 
786 	IFDEBUG(D_CONN)
787 		printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
788 			tpcb->tp_npcb, so);
789 		printf("so 0x%x so_head 0x%x,  qlen %d q0len %d qlimit %d\n",
790 		so,  so->so_head,
791 		so->so_q0len, so->so_qlen, so->so_qlimit);
792 	ENDDEBUG
793 
794 
795 	(tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
796 				/* does an sofree(so) */
797 
798 	IFDEBUG(D_CONN)
799 		printf("after xxx_pcbdetach\n");
800 	ENDDEBUG
801 
802 	if( tpcb->tp_refp->tpr_state == REF_OPENING ) {
803 		/* no connection existed here so no reference timer will be called */
804 		IFDEBUG(D_CONN)
805 			printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref,
806 			tpcb->tp_refp - &tp_ref[0]);
807 		ENDDEBUG
808 
809 		tp_freeref(tpcb->tp_refp);
810 	}
811 
812 	if (tpcb->tp_Xsnd.sb_mb) {
813 		printf("Unsent Xdata on detach; would panic");
814 		sbflush(&tpcb->tp_Xsnd);
815 	}
816 	so->so_pcb = 0;
817 
818 	/*
819 	 * Get rid of the cluster mbuf allocated for performance measurements, if
820 	 * there is one.  Note that tpcb->tp_perf_on says nothing about whether or
821 	 * not a cluster mbuf was allocated, so you have to check for a pointer
822 	 * to one (that is, we need the TP_PERF_MEASs around the following section
823 	 * of code, not the IFPERFs)
824 	 */
825 #ifdef TP_PERF_MEAS
826 	if (tpcb->tp_p_mbuf) {
827 		register struct mbuf *m = tpcb->tp_p_mbuf;
828 		struct mbuf *n;
829 		IFDEBUG(D_PERF_MEAS)
830 			printf("freeing tp_p_meas 0x%x  ", tpcb->tp_p_meas);
831 		ENDDEBUG
832 		do {
833 		    MFREE(m, n);
834 		    m = n;
835 		} while (n);
836 		tpcb->tp_p_meas = 0;
837 		tpcb->tp_p_mbuf = 0;
838 	}
839 #endif TP_PERF_MEAS
840 
841 	IFDEBUG(D_CONN)
842 		printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
843 	ENDDEBUG
844 	/* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
845 }
846 
847 struct que {
848 	struct tp_pcb *next;
849 	struct tp_pcb *prev;
850 } tp_bound_pcbs =
851 {(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs};
852 
853 u_short tp_unique;
854 
855 tp_tselinuse(tlen, tsel, siso, reuseaddr)
856 caddr_t tsel;
857 register struct sockaddr_iso *siso;
858 {
859 	struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
860 	register struct tp_pcb *t;
861 
862 	for (;;) {
863 		if (b != (struct tp_pcb *)&tp_bound_pcbs) {
864 			t = b; b = t->tp_next;
865 		} else if (l) {
866 			t = l; l = t->tp_nextlisten;
867 		} else
868 			break;
869 		if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
870 			if (t->tp_flags & TPF_GENERAL_ADDR) {
871 				if (siso == 0 || reuseaddr == 0)
872 					return 1;
873 			} else if (siso) {
874 				if (siso->siso_family == t->tp_domain &&
875 					t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL))
876 						return 1;
877 			} else if (reuseaddr == 0)
878 						return 1;
879 		}
880 	}
881 	return 0;
882 
883 }
884 
885 
886 tp_pcbbind(tpcb, nam)
887 register struct tp_pcb *tpcb;
888 register struct mbuf *nam;
889 {
890 	register struct sockaddr_iso *siso = 0;
891 	int tlen = 0, wrapped = 0;
892 	caddr_t tsel;
893 	u_short tutil;
894 
895 	if (tpcb->tp_state != TP_CLOSED)
896 		return (EINVAL);
897 	if (nam) {
898 		siso = mtod(nam, struct sockaddr_iso *);
899 		switch (siso->siso_family) {
900 		default:
901 			return (EAFNOSUPPORT);
902 #ifdef ISO
903 		case AF_ISO:
904 			tlen = siso->siso_tlen;
905 			tsel = TSEL(siso);
906 			if (siso->siso_nlen == 0)
907 				siso = 0;
908 			break;
909 #endif
910 #ifdef INET
911 		case AF_INET:
912 			tsel = (caddr_t)&tutil;
913 			if (tutil =  ((struct sockaddr_in *)siso)->sin_port) {
914 				tlen = 2;
915 			}
916 			if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0)
917 				siso = 0;
918 		}
919 #endif
920 	}
921 	if (tpcb->tp_lsuffixlen == 0) {
922 		if (tlen) {
923 			if (tp_tselinuse(tsel, tlen, siso,
924 								tpcb->tp_sock->so_options & SO_REUSEADDR))
925 				return (EINVAL);
926 		} else for (tsel = (caddr_t)&tp_unique, tlen = 2;;){
927 			if (tp_unique++ < ISO_PORT_RESERVED ||
928 				tp_unique > ISO_PORT_USERRESERVED) {
929 					if (wrapped++)
930 						return ESRCH;
931 					tp_unique = ISO_PORT_RESERVED;
932 			}
933 			if (tp_tselinuse(tsel, tlen, siso, 0) == 0)
934 				break;
935 		}
936 		bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
937 		insque(tpcb, &tp_bound_pcbs);
938 	} else {
939 		if (tlen || siso == 0)
940 			return (EINVAL);
941 	}
942 	if (siso == 0) {
943 		tpcb->tp_flags |= TPF_GENERAL_ADDR;
944 		return (0);
945 	}
946 	return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam);
947 }
948