xref: /csrg-svn/sys/netiso/tp_pcb.c (revision 39923)
1 /***********************************************************
2 				Copyright IBM Corporation 1987
3 
4                       All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of IBM not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13 
14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 
22 ******************************************************************/
23 
24 /*
25  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26  */
27 /*
28  * ARGO TP
29  *
30  * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $
31  * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $
32  *	@(#)tp_pcb.c	7.5 (Berkeley) 01/16/90 *
33  *
34  *
35  * This is the initialization and cleanup stuff -
36  * for the tp machine in general as well as  for the individual pcbs.
37  * tp_init() is called at system startup.  tp_attach() and tp_getref() are
38  * called when a socket is created.  tp_detach() and tp_freeref()
39  * are called during the closing stage and/or when the reference timer
40  * goes off.
41  * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific
42  * versions of soisconnect*
43  * and are called (obviously) during the closing phase.
44  *
45  */
46 
47 #ifndef lint
48 static char *rcsid = "$Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $";
49 #endif lint
50 
51 #include "argoxtwentyfive.h"
52 #include "types.h"
53 #include "param.h"
54 #include "mbuf.h"
55 #include "socket.h"
56 #include "socketvar.h"
57 #include "protosw.h"
58 #include "errno.h"
59 #include "time.h"
60 #include "argo_debug.h"
61 #include "tp_param.h"
62 #include "tp_timer.h"
63 #include "tp_ip.h"
64 #include "tp_stat.h"
65 #include "tp_pcb.h"
66 #include "tp_tpdu.h"
67 #include "tp_trace.h"
68 #include "tp_meas.h"
69 #include "tp_seq.h"
70 #include "tp_clnp.h"
71 
72 /* list of reference structures */
73 struct tp_ref tp_ref[N_TPREF];
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_putsufx();
234 int 	in_getsufx();
235 int 	in_recycle_tsuffix();
236 int 	tpip_mtu();
237 int 	in_pcbbind();
238 int 	in_pcbconnect();
239 int 	in_pcbdisconnect();
240 int 	in_pcbdetach();
241 int 	in_pcballoc();
242 int 	tpip_output();
243 int 	tpip_output_dg();
244 struct inpcb	tp_inpcb;
245 #endif INET
246 #ifdef ISO
247 int		iso_putnetaddr();
248 int		iso_getnetaddr();
249 int 	iso_putsufx();
250 int 	iso_getsufx();
251 int 	iso_recycle_tsuffix();
252 int		tpclnp_mtu();
253 int		iso_pcbbind();
254 int		iso_pcbconnect();
255 int		iso_pcbdisconnect();
256 int 	iso_pcbdetach();
257 int 	iso_pcballoc();
258 int 	tpclnp_output();
259 int 	tpclnp_output_dg();
260 int		iso_nlctloutput();
261 struct isopcb	tp_isopcb;
262 #endif ISO
263 #if NARGOXTWENTYFIVE > 0
264 int		iso_putnetaddr();
265 int		iso_getnetaddr();
266 int 	iso_putsufx();
267 int 	iso_getsufx();
268 int 	iso_recycle_tsuffix();
269 int		tpcons_mtu();
270 int		iso_pcbbind();
271 int		iso_pcbconnect();
272 int		iso_pcbdisconnect();
273 int 	iso_pcbdetach();
274 int 	iso_pcballoc();
275 int 	tpcons_output();
276 int 	tpcons_output_dg();
277 struct isopcb	tp_isopcb;
278 #endif NARGOXTWENTYFIVE
279 
280 
281 struct nl_protosw nl_protosw[] = {
282 	/* ISO_CLNS */
283 #ifdef ISO
284 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr,
285 		iso_putsufx, iso_getsufx,
286 		iso_recycle_tsuffix,
287 		tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
288 		iso_pcbdisconnect,	iso_pcbdetach,
289 		iso_pcballoc,
290 		tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
291 		(caddr_t) &tp_isopcb,
292 		},
293 #else
294 	{ 0 },
295 #endif ISO
296 	/* IN_CLNS */
297 #ifdef INET
298 	{ AF_INET, in_putnetaddr, in_getnetaddr,
299 		in_putsufx, in_getsufx,
300 		in_recycle_tsuffix,
301 		tpip_mtu, in_pcbbind, in_pcbconnect,
302 		in_pcbdisconnect,	in_pcbdetach,
303 		in_pcballoc,
304 		tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
305 		(caddr_t) &tp_inpcb,
306 		},
307 #else
308 	{ 0 },
309 #endif INET
310 	/* ISO_CONS */
311 #if defined(ISO) && (NARGOXTWENTYFIVE > 0)
312 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr,
313 		iso_putsufx, iso_getsufx,
314 		iso_recycle_tsuffix,
315 		tpcons_mtu, iso_pcbbind, iso_pcbconnect,
316 		iso_pcbdisconnect,	iso_pcbdetach,
317 		iso_pcballoc,
318 		tpcons_output, tpcons_output_dg, iso_nlctloutput,
319 		(caddr_t) &tp_isopcb,
320 		},
321 #else
322 	{ 0 },
323 #endif ISO_CONS
324 	/* End of protosw marker */
325 	{ 0 }
326 };
327 
328 /*
329  * NAME:  tp_init()
330  *
331  * CALLED FROM:
332  *  autoconf through the protosw structure
333  *
334  * FUNCTION:
335  *  initialize tp machine
336  *
337  * RETURNS:  Nada
338  *
339  * SIDE EFFECTS:
340  *
341  * NOTES:
342  */
343 int
344 tp_init()
345 {
346 	static int 	init_done=0;
347 	void	 	tp_timerinit();
348 
349 	if (init_done++)
350 		return 0;
351 
352 
353 	/* FOR INET */
354 	tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb;
355 	/* FOR ISO */
356 	tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
357 
358     tp_start_win = 2;
359 
360 	tp_timerinit();
361 	bzero((caddr_t)&tp_stat, sizeof(struct tp_stat));
362 	return 0;
363 }
364 
365 /*
366  * NAME: 	tp_soisdisconnecting()
367  *
368  * CALLED FROM:
369  *  tp.trans
370  *
371  * FUNCTION and ARGUMENTS:
372  *  Set state of the socket (so) to reflect that fact that we're disconnectING
373  *
374  * RETURNS: 	Nada
375  *
376  * SIDE EFFECTS:
377  *
378  * NOTES:
379  *  This differs from the regular soisdisconnecting() in that the latter
380  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
381  *  We don't want to set those flags because those flags will cause
382  *  a SIGPIPE to be delivered in sosend() and we don't like that.
383  *  If anyone else is sleeping on this socket, wake 'em up.
384  */
385 void
386 tp_soisdisconnecting(so)
387 	register struct socket *so;
388 {
389 	soisdisconnecting(so);
390 	so->so_state &= ~SS_CANTSENDMORE;
391 	IFPERF(sototpcb(so))
392 		register struct tp_pcb *tpcb = sototpcb(so);
393 		u_int 	fsufx, lsufx;
394 
395 		bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
396 		bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
397 
398 		tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref);
399 		tpcb->tp_perf_on = 0; /* turn perf off */
400 	ENDPERF
401 }
402 
403 
404 /*
405  * NAME: tp_soisdisconnected()
406  *
407  * CALLED FROM:
408  *	tp.trans
409  *
410  * FUNCTION and ARGUMENTS:
411  *  Set state of the socket (so) to reflect that fact that we're disconnectED
412  *  Set the state of the reference structure to closed, and
413  *  recycle the suffix.
414  *  Start a reference timer.
415  *
416  * RETURNS:	Nada
417  *
418  * SIDE EFFECTS:
419  *
420  * NOTES:
421  *  This differs from the regular soisdisconnected() in that the latter
422  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
423  *  We don't want to set those flags because those flags will cause
424  *  a SIGPIPE to be delivered in sosend() and we don't like that.
425  *  If anyone else is sleeping on this socket, wake 'em up.
426  */
427 void
428 tp_soisdisconnected(tpcb)
429 	register struct tp_pcb	*tpcb;
430 {
431 	register struct socket	*so = tpcb->tp_sock;
432 
433 	soisdisconnecting(so);
434 	so->so_state &= ~SS_CANTSENDMORE;
435 	IFPERF(sototpcb(so))
436 		register struct tp_pcb *ttpcb = sototpcb(so);
437 		u_int 	fsufx, lsufx;
438 
439 		/* CHOKE */
440 		bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
441 		bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
442 
443 		tpmeas(ttpcb->tp_lref, TPtime_close,
444 		   &time, &lsufx, &fsufx, ttpcb->tp_fref);
445 		tpcb->tp_perf_on = 0; /* turn perf off */
446 	ENDPERF
447 
448 	tpcb->tp_refp->tpr_state = REF_FROZEN;
449 	tp_recycle_tsuffix( tpcb );
450 	tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks);
451 }
452 
453 int tp_maxrefopen;  /* highest reference # of the set of open tp connections */
454 
455 /*
456  * NAME:	tp_freeref()
457  *
458  * CALLED FROM:
459  *  tp.trans when the reference timer goes off, and
460  *  from tp_attach() and tp_detach() when a tpcb is partially set up but not
461  *  set up enough to have a ref timer set for it, and it's discarded
462  *  due to some sort of error or an early close()
463  *
464  * FUNCTION and ARGUMENTS:
465  *  Frees the reference represented by (r) for re-use.
466  *
467  * RETURNS: Nothing
468  *
469  * SIDE EFFECTS:
470  *
471  * NOTES:	better be called at clock priority !!!!!
472  */
473 void
474 tp_freeref(r)
475 	register struct tp_ref *r;
476 {
477 	IFDEBUG(D_TIMER)
478 		printf("tp_freeref called for ref %d maxrefopen %d\n",
479 		r - tp_ref, tp_maxrefopen);
480 	ENDDEBUG
481 	IFTRACE(D_TIMER)
482 		tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen",
483 		r - tp_ref, tp_maxrefopen, 0, 0);
484 	ENDTRACE
485 	r->tpr_state = REF_FREE;
486 	IFDEBUG(D_CONN)
487 		printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb);
488 	ENDDEBUG
489 	r->tpr_pcb = (struct tp_pcb *)0;
490 
491 	r = &tp_ref[tp_maxrefopen];
492 
493 	while( tp_maxrefopen > 0 ) {
494 		if(r->tpr_state )
495 			break;
496 		tp_maxrefopen--;
497 		r--;
498 	}
499 	IFDEBUG(D_TIMER)
500 		printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen);
501 	ENDDEBUG
502 }
503 
504 /*
505  * NAME:  tp_getref()
506  *
507  * CALLED FROM:
508  *  tp_attach()
509  *
510  * FUNCTION and ARGUMENTS:
511  *  obtains the next free reference and allocates the appropriate
512  *  ref structure, links that structure to (tpcb)
513  *
514  * RETURN VALUE:
515  *	a reference number
516  *  or TP_ENOREF
517  *
518  * SIDE EFFECTS:
519  *
520  * NOTES:
521  */
522 static RefNum
523 tp_getref(tpcb)
524 	register struct tp_pcb *tpcb;
525 {
526 	register struct tp_ref	*r = tp_ref;
527 	register int 			i=1;
528 
529 	r++; /* tp_ref[0] is never used */
530 
531 	/* REF_FREE is zero */
532 	while( r->tpr_state ) {
533 		r++;
534 		if ( i == N_TPREF ) {
535 			return TP_ENOREF;
536 		}
537 		i++;
538 	}
539 	r->tpr_state = REF_OPENING;
540 	if (tp_maxrefopen < i)
541 		tp_maxrefopen = i;
542 	r->tpr_pcb = tpcb;
543 	tpcb->tp_refp = r;
544 
545 	return i;
546 }
547 
548 /*
549  * NAME: tp_attach()
550  *
551  * CALLED FROM:
552  *	tp_usrreq, PRU_ATTACH
553  *
554  * FUNCTION and ARGUMENTS:
555  *  given a socket (so) and a protocol family (dom), allocate a tpcb
556  *  and ref structure, initialize everything in the structures that
557  *  needs to be initialized.
558  *
559  * RETURN VALUE:
560  *  0 ok
561  *  EINVAL if DEBUG(X) in is on and a disaster has occurred
562  *  ENOPROTOOPT if TP hasn't been configured or if the
563  *   socket wasn't created with tp as its protocol
564  *  EISCONN if this socket is already part of a connection
565  *  ETOOMANYREFS if ran out of tp reference numbers.
566  *  E* whatever error is returned from soreserve()
567  *    for from the network-layer pcb allocation routine
568  *
569  * SIDE EFFECTS:
570  *
571  * NOTES:
572  */
573 tp_attach(so, dom)
574 	struct socket 	*so;
575 	int 			dom;
576 {
577 	register struct tp_pcb	*tpcb;
578 	int 					error;
579 	int 					protocol = so->so_proto->pr_protocol;
580 	extern struct tp_conn_param tp_conn_param[];
581 
582 	IFDEBUG(D_CONN)
583 		printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
584 	ENDDEBUG
585 	IFTRACE(D_CONN)
586 		tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
587 	ENDTRACE
588 	if ( ! tp_param.tpp_configed ) {
589 		error = ENOPROTOOPT; /* protocol not available */
590 		goto bad2;
591 	}
592 
593 	if (so->so_pcb != NULL) {
594 		return EISCONN;	/* socket already part of a connection*/
595 	}
596 
597 	error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE);
598 		/* later an ioctl will allow reallocation IF still in closed state */
599 
600 	if (error)
601 		goto bad2;
602 
603 	MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
604 	if (tpcb == NULL) {
605 		error = ENOBUFS;
606 		goto bad2;
607 	}
608 	bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
609 
610 	if ( ((tpcb->tp_lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) {
611 		error = ETOOMANYREFS;
612 		goto bad3;
613 	}
614 	tpcb->tp_sock =  so;
615 	tpcb->tp_domain = dom;
616 	if (protocol<ISOPROTO_TP4) {
617 		tpcb->tp_netservice = ISO_CONS;
618 		tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
619 								 * will generate correct fake-ack values
620 								 */
621 	} else {
622 		tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
623 		/* the default */
624 	}
625 	tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
626 
627 	tpcb->tp_cong_win = 1;
628 	tpcb->tp_state = TP_CLOSED;
629 	tpcb->tp_vers  = TP_VERSION;
630 
631 		   /* Spec says default is 128 octets,
632 			* that is, if the tpdusize argument never appears, use 128.
633 			* As the initiator, we will always "propose" the 2048
634 			* size, that is, we will put this argument in the CR
635 			* always, but accept what the other side sends on the CC.
636 			* If the initiator sends us something larger on a CR,
637 			* we'll respond w/ this.
638 			* Our maximum is 4096.  See tp_chksum.c comments.
639 			*/
640 	tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
641 
642 	tpcb->tp_seqmask  = TP_NML_FMT_MASK;
643 	tpcb->tp_seqbit  =  TP_NML_FMT_BIT;
644 	tpcb->tp_seqhalf  =  tpcb->tp_seqbit >> 1;
645 	tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */
646 	tpcb->tp_s_subseq = 0;
647 
648 	/* attach to a network-layer protoswitch */
649 	/* new way */
650 	tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice];
651 	ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
652 #ifdef notdef
653 	/* OLD WAY */
654 	/* TODO: properly, this search would be on the basis of
655 	* domain,netservice or just netservice only (if you have
656 	* IN_CLNS, ISO_CLNS, and ISO_CONS)
657 	*/
658 	tpcb->tp_nlproto = nl_protosw;
659 	while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain )  {
660 		if( tpcb->tp_nlproto->nlp_afamily == 0 ) {
661 			error = EAFNOSUPPORT;
662 			goto bad4;
663 		}
664 		tpcb->tp_nlproto ++;
665 	}
666 #endif notdef
667 
668 	/* xx_pcballoc sets so_pcb */
669 	if ( error =  (tpcb->tp_nlproto->nlp_pcballoc) (
670 							so, tpcb->tp_nlproto->nlp_pcblist ) ) {
671 		goto bad4;
672 	}
673 
674 	if( dom == AF_INET )
675 		sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
676 		/* nothing to do for iso case */
677 
678 	tpcb->tp_npcb = (caddr_t) so->so_pcb;
679 	so->so_tpcb = (caddr_t) tpcb;
680 
681 	return 0;
682 
683 bad4:
684 	IFDEBUG(D_CONN)
685 		printf("BAD4 in tp_attach, so 0x%x\n", so);
686 	ENDDEBUG
687 	tp_freeref(tpcb->tp_refp);
688 
689 bad3:
690 	IFDEBUG(D_CONN)
691 		printf("BAD3 in tp_attach, so 0x%x\n", so);
692 	ENDDEBUG
693 
694 	free((caddr_t)tpcb, M_PCB); /* never a cluster  */
695 
696 bad2:
697 	IFDEBUG(D_CONN)
698 		printf("BAD2 in tp_attach, so 0x%x\n", so);
699 	ENDDEBUG
700 	so->so_pcb = 0;
701 	so->so_tpcb = 0;
702 	sofree(so);
703 
704 /*bad:*/
705 	IFDEBUG(D_CONN)
706 		printf("BAD in tp_attach, so 0x%x\n", so);
707 	ENDDEBUG
708 	return error;
709 }
710 
711 /*
712  * NAME:  tp_detach()
713  *
714  * CALLED FROM:
715  *	tp.trans, on behalf of a user close request
716  *  and when the reference timer goes off
717  * (if the disconnect  was initiated by the protocol entity
718  * rather than by the user)
719  *
720  * FUNCTION and ARGUMENTS:
721  *  remove the tpcb structure from the list of active or
722  *  partially active connections, recycle all the mbufs
723  *  associated with the pcb, ref structure, sockbufs, etc.
724  *  Only free the ref structure if you know that a ref timer
725  *  wasn't set for this tpcb.
726  *
727  * RETURNS:  Nada
728  *
729  * SIDE EFFECTS:
730  *
731  * NOTES:
732  *  tp_soisdisconnected() was already when this is called
733  */
734 void
735 tp_detach(tpcb)
736 	register struct tp_pcb 	*tpcb;
737 {
738 	void					tp_freeref();
739 	register struct socket	 *so = tpcb->tp_sock;
740 
741 	IFDEBUG(D_CONN)
742 		printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
743 			tpcb,so);
744 	ENDDEBUG
745 	IFTRACE(D_CONN)
746 		tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
747 			tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0);
748 	ENDTRACE
749 
750 	if (so->so_head) {
751 		if (!soqremque(so, 0) && !soqremque(so, 1))
752 			panic("sofree dq");
753 		so->so_head = 0;
754 	}
755 
756 	IFDEBUG(D_CONN)
757 		printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n",
758 		tpcb->tp_snduna_rtc,
759 		tpcb->tp_rcvnxt_rtc);
760 	ENDDEBUG
761 
762 #define FREE_RTC_LIST(XXX)\
763 	{ register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\
764 		xxs = xxr->tprt_next;\
765 		m_freem( xxr->tprt_data );\
766 		m_free( dtom(xxr) ); xxr = xxs; }\
767 		XXX = (struct tp_rtc *)0;\
768 	}
769 
770 	FREE_RTC_LIST( tpcb->tp_snduna_rtc );
771 	tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0;
772 
773 	FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc );
774 
775 #undef FREE_RTC_LIST
776 
777 	IFDEBUG(D_CONN)
778 		printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
779 			so->so_pcb, so);
780 		printf("so 0x%x so_head 0x%x,  qlen %d q0len %d qlimit %d\n",
781 		so,  so->so_head,
782 		so->so_q0len, so->so_qlen, so->so_qlimit);
783 	ENDDEBUG
784 
785 	if ( tpcb->tp_flags & (TPF_DISC_DATA_OUT | TPF_CONN_DATA_OUT ) )  {
786 		ASSERT( so->so_snd.sb_cc != 0 );
787 		IFDEBUG(D_CONN)
788 			printf(
789 			"detach, flags 0x%x doing sbdrop on so_snd, mb 0x%x cc 0x%x\n",
790 				tpcb->tp_flags, so->so_snd.sb_mb, so->so_snd.sb_cc);
791 			dump_mbuf( so->so_snd.sb_mb, "detach so snd: \n");
792 		ENDDEBUG
793 		if ( so->so_snd.sb_cc != 0 )
794 			sbflush(&so->so_snd);
795 		tpcb->tp_flags &= ~(TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT);
796 	}
797 	if ( tpcb->tp_flags & (TPF_DISC_DATA_IN | TPF_CONN_DATA_IN ) ) {
798 		ASSERT( tpcb->tp_Xrcv.sb_cc != 0 );
799 		IFDEBUG(D_CONN)
800 			printf(
801 			"detach, flags 0x%x doing sbdrop on tp_Xrcv, mb 0x%x cc 0x%x\n",
802 				tpcb->tp_flags, tpcb->tp_Xrcv.sb_mb, tpcb->tp_Xrcv.sb_cc);
803 			dump_mbuf( tpcb->tp_Xrcv.sb_mb, "detach Xrcv: \n");
804 		ENDDEBUG
805 		if( tpcb->tp_Xrcv.sb_cc != 0 )
806 			sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc);
807 		tpcb->tp_flags &= ~(TPF_CONN_DATA_IN | TPF_DISC_DATA_IN);
808 	}
809 
810 	IFDEBUG(D_CONN)
811 		printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv);
812 		dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
813 		printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n",
814 				tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
815 	ENDDEBUG
816 
817 
818 
819 	(tpcb->tp_nlproto->nlp_pcbdetach)((struct inpcb *)so->so_pcb);
820 				/* does an sofree(so) */
821 
822 	IFDEBUG(D_CONN)
823 		printf("after xxx_pcbdetach\n");
824 	ENDDEBUG
825 
826 	if( tpcb->tp_refp->tpr_state == REF_OPENING ) {
827 		/* no connection existed here so no reference timer will be called */
828 		IFDEBUG(D_CONN)
829 			printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref,
830 			tpcb->tp_refp - &tp_ref[0]);
831 		ENDDEBUG
832 
833 		tp_freeref(tpcb->tp_refp);
834 	}
835 
836 	if (tpcb->tp_Xsnd.sb_mb) {
837 		printf("Unsent Xdata on detach; would panic");
838 		sbflush(&tpcb->tp_Xsnd);
839 	}
840 	so->so_tpcb = (caddr_t)0;
841 
842 	/*
843 	 * Get rid of the cluster mbuf allocated for performance measurements, if
844 	 * there is one.  Note that tpcb->tp_perf_on says nothing about whether or
845 	 * not a cluster mbuf was allocated, so you have to check for a pointer
846 	 * to one (that is, we need the TP_PERF_MEASs around the following section
847 	 * of code, not the IFPERFs)
848 	 */
849 #ifdef TP_PERF_MEAS
850 	if(tpcb->tp_p_mbuf) {
851 		register struct mbuf *m = tpcb->tp_p_mbuf;
852 		struct mbuf *n;
853 		IFDEBUG(D_PERF_MEAS)
854 			printf("freeing tp_p_meas 0x%x  ", tpcb->tp_p_meas);
855 		ENDDEBUG
856 		do {
857 		    MFREE(m, n);
858 		    m = n;
859 		} while (n);
860 		tpcb->tp_p_meas = 0;
861 		tpcb->tp_p_mbuf = 0;
862 	}
863 #endif TP_PERF_MEAS
864 
865 	IFDEBUG(D_CONN)
866 		printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
867 	ENDDEBUG
868 	/* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
869 }
870