xref: /original-bsd/sys/netiso/tp_pcb.c (revision 95a66346)
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.8 (Berkeley) 03/12/91 *
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 "types.h"
52 #include "param.h"
53 #include "mbuf.h"
54 #include "socket.h"
55 #include "socketvar.h"
56 #include "protosw.h"
57 #include "errno.h"
58 #include "time.h"
59 #include "argo_debug.h"
60 #include "tp_param.h"
61 #include "tp_timer.h"
62 #include "tp_ip.h"
63 #include "tp_stat.h"
64 #include "tp_pcb.h"
65 #include "tp_tpdu.h"
66 #include "tp_trace.h"
67 #include "tp_meas.h"
68 #include "tp_seq.h"
69 #include "tp_clnp.h"
70 
71 /* list of reference structures */
72 struct tp_ref tp_ref[N_TPREF];
73 
74 struct tp_param tp_param = {
75 	1,				/*  configured 		*/
76 };
77 
78 /* ticks are in units of:
79  * 500 nano-fortnights ;-) or
80  * 500 ms or
81  * 1/2 second
82  */
83 
84 struct tp_conn_param tp_conn_param[] = {
85 	/* ISO_CLNS: TP4 CONNECTION LESS */
86 	{
87 		TP_NRETRANS, 	/* short p_Nretrans;  */
88 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
89 
90 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
91 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
92 
93 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
94 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
95 
96 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
97 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
98 
99 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
100 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
101 
102 		(short) 100, 			/* short p_lcdtfract */
103 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
104 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
105 
106 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
107 		TPRX_USE_CW | TPRX_FASTSTART,
108 								/* 4 bits p_rx_strat*/
109 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
110 		1,						/* 1 bit xtd format */
111 		1,						/* 1 bit xpd service */
112 		1,						/* 1 bit use_checksum */
113 		0,						/* 1 bit use net xpd */
114 		0,						/* 1 bit use rcc */
115 		0,						/* 1 bit use efc */
116 		1,						/* no disc indications */
117 		0,						/* don't change params */
118 		ISO_CLNS,				/* p_netservice */
119 	},
120 	/* IN_CLNS: TP4 CONNECTION LESS */
121 	{
122 		TP_NRETRANS, 	/* short p_Nretrans;  */
123 		20,		/* 10 sec */ 	/* short p_dr_ticks;  */
124 
125 		20,		/* 10 sec */ 	/* short p_cc_ticks; */
126 		20,		/* 10 sec */ 	/* short p_dt_ticks; */
127 
128 		40,		/* 20 sec */ 	/* short p_x_ticks;	 */
129 		80,		/* 40 sec */ 	/* short p_cr_ticks;*/
130 
131 		240,	/* 2 min */ 	/* short p_keepalive_ticks;*/
132 		10,		/* 5 sec */ 	/* short p_sendack_ticks;  */
133 
134 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
135 		360,	/* 3 min */ 	/* short p_inact_ticks;	*/
136 
137 		(short) 100, 			/* short p_lcdtfract */
138 		(short) TP_SOCKBUFSIZE,	/* short p_winsize */
139 		TP_TPDUSIZE, 			/* u_char p_tpdusize */
140 
141 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
142 		TPRX_USE_CW | TPRX_FASTSTART,
143 								/* 4 bits p_rx_strat*/
144 		TP_CLASS_4,				/* 5 bits p_class */
145 		1,						/* 1 bit xtd format */
146 		1,						/* 1 bit xpd service */
147 		1,						/* 1 bit use_checksum */
148 		0,						/* 1 bit use net xpd */
149 		0,						/* 1 bit use rcc */
150 		0,						/* 1 bit use efc */
151 		1,						/* no disc indications */
152 		0,						/* don't change params */
153 		IN_CLNS,				/* p_netservice */
154 	},
155 	/* ISO_CONS: TP0 CONNECTION MODE */
156 	{
157 		TP_NRETRANS, 			/* short p_Nretrans;  */
158 		0,		/* n/a */		/* short p_dr_ticks; */
159 
160 		40,		/* 20 sec */	/* short p_cc_ticks; */
161 		0,		/* n/a */		/* short p_dt_ticks; */
162 
163 		0,		/* n/a */		/* short p_x_ticks;	*/
164 		360,	/* 3  min */	/* short p_cr_ticks;*/
165 
166 		0,		/* n/a */		/* short p_keepalive_ticks;*/
167 		0,		/* n/a */		/* short p_sendack_ticks; */
168 
169 		600,	/* for cr/cc to clear *//* short p_ref_ticks;	*/
170 		0,		/* n/a */		/* short p_inact_ticks;	*/
171 
172 		/* Use tp4 defaults just in case the user changes ONLY
173 		 * the class
174 		 */
175 		(short) 100, 			/* short p_lcdtfract */
176 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
177 		TP0_TPDUSIZE, 			/* 8 bits p_tpdusize */
178 
179 		0, 						/* 4 bits p_ack_strat */
180 		0, 						/* 4 bits p_rx_strat*/
181 		TP_CLASS_0,				/* 5 bits p_class */
182 		0,						/* 1 bit xtd format */
183 		0,						/* 1 bit xpd service */
184 		0,						/* 1 bit use_checksum */
185 		0,						/* 1 bit use net xpd */
186 		0,						/* 1 bit use rcc */
187 		0,						/* 1 bit use efc */
188 		0,						/* no disc indications */
189 		0,						/* don't change params */
190 		ISO_CONS,				/* p_netservice */
191 	},
192 	/* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */
193 	{
194 		TP_NRETRANS, 	/* short p_Nretrans;  */
195 		40,		/* 20 sec */ 	/* short p_dr_ticks;  */
196 
197 		40,		/* 20 sec */ 	/* short p_cc_ticks; */
198 		80,		/* 40 sec */ 	/* short p_dt_ticks; */
199 
200 		120,		/* 1 min */ 	/* short p_x_ticks;	 */
201 		360,		/* 3 min */ 	/* short p_cr_ticks;*/
202 
203 		360,	/* 3 min */ 	/* short p_keepalive_ticks;*/
204 		20,		/* 10 sec */ 	/* short p_sendack_ticks;  */
205 
206 		600,	/* 5 min */ 	/* short p_ref_ticks;	*/
207 		480,	/* 4 min */ 	/* short p_inact_ticks;	*/
208 
209 		(short) 100, 			/* short p_lcdtfract */
210 		(short) TP0_SOCKBUFSIZE,	/* short p_winsize */
211 		TP0_TPDUSIZE, 			/* u_char p_tpdusize */
212 
213 		TPACK_WINDOW, 			/* 4 bits p_ack_strat */
214 		TPRX_USE_CW ,			/* No fast start */
215 								/* 4 bits p_rx_strat*/
216 		TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */
217 		0,						/* 1 bit xtd format */
218 		1,						/* 1 bit xpd service */
219 		1,						/* 1 bit use_checksum */
220 		0,						/* 1 bit use net xpd */
221 		0,						/* 1 bit use rcc */
222 		0,						/* 1 bit use efc */
223 		0,						/* no disc indications */
224 		0,						/* don't change params */
225 		ISO_COSNS,				/* p_netservice */
226 	},
227 };
228 
229 #ifdef INET
230 int		in_putnetaddr();
231 int		in_getnetaddr();
232 int		in_cmpnetaddr();
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_cmpnetaddr();
250 int 	iso_putsufx();
251 int 	iso_getsufx();
252 int 	iso_recycle_tsuffix();
253 int		tpclnp_mtu();
254 int		iso_pcbbind();
255 int		iso_pcbconnect();
256 int		iso_pcbdisconnect();
257 int 	iso_pcbdetach();
258 int 	iso_pcballoc();
259 int 	tpclnp_output();
260 int 	tpclnp_output_dg();
261 int		iso_nlctloutput();
262 struct isopcb	tp_isopcb;
263 #endif ISO
264 #ifdef TPCONS
265 int		iso_putnetaddr();
266 int		iso_getnetaddr();
267 int		iso_cmpnetaddr();
268 int 	iso_putsufx();
269 int 	iso_getsufx();
270 int 	iso_recycle_tsuffix();
271 int		tpcons_mtu();
272 int		iso_pcbbind();
273 int		tpcons_pcbconnect();
274 int		iso_pcbdisconnect();
275 int 	iso_pcbdetach();
276 int 	iso_pcballoc();
277 int 	tpcons_output();
278 struct isopcb	tp_isopcb;
279 #endif TPCONS
280 
281 
282 struct nl_protosw nl_protosw[] = {
283 	/* ISO_CLNS */
284 #ifdef ISO
285 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
286 		iso_putsufx, iso_getsufx,
287 		iso_recycle_tsuffix,
288 		tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
289 		iso_pcbdisconnect,	iso_pcbdetach,
290 		iso_pcballoc,
291 		tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
292 		(caddr_t) &tp_isopcb,
293 		},
294 #else
295 	{ 0 },
296 #endif ISO
297 	/* IN_CLNS */
298 #ifdef INET
299 	{ AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr,
300 		in_putsufx, in_getsufx,
301 		in_recycle_tsuffix,
302 		tpip_mtu, in_pcbbind, in_pcbconnect,
303 		in_pcbdisconnect,	in_pcbdetach,
304 		in_pcballoc,
305 		tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
306 		(caddr_t) &tp_inpcb,
307 		},
308 #else
309 	{ 0 },
310 #endif INET
311 	/* ISO_CONS */
312 #if defined(ISO) && defined(TPCONS)
313 	{ AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
314 		iso_putsufx, iso_getsufx,
315 		iso_recycle_tsuffix,
316 		tpcons_mtu, iso_pcbbind, tpcons_pcbconnect,
317 		iso_pcbdisconnect,	iso_pcbdetach,
318 		iso_pcballoc,
319 		tpcons_output, tpcons_output, iso_nlctloutput,
320 		(caddr_t) &tp_isopcb,
321 		},
322 #else
323 	{ 0 },
324 #endif ISO_CONS
325 	/* End of protosw marker */
326 	{ 0 }
327 };
328 
329 /*
330  * NAME:  tp_init()
331  *
332  * CALLED FROM:
333  *  autoconf through the protosw structure
334  *
335  * FUNCTION:
336  *  initialize tp machine
337  *
338  * RETURNS:  Nada
339  *
340  * SIDE EFFECTS:
341  *
342  * NOTES:
343  */
344 int
345 tp_init()
346 {
347 	static int 	init_done=0;
348 	void	 	tp_timerinit();
349 
350 	if (init_done++)
351 		return 0;
352 
353 
354 	/* FOR INET */
355 	tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb;
356 	/* FOR ISO */
357 	tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
358 
359     tp_start_win = 2;
360 
361 	tp_timerinit();
362 	bzero((caddr_t)&tp_stat, sizeof(struct tp_stat));
363 	return 0;
364 }
365 
366 /*
367  * NAME: 	tp_soisdisconnecting()
368  *
369  * CALLED FROM:
370  *  tp.trans
371  *
372  * FUNCTION and ARGUMENTS:
373  *  Set state of the socket (so) to reflect that fact that we're disconnectING
374  *
375  * RETURNS: 	Nada
376  *
377  * SIDE EFFECTS:
378  *
379  * NOTES:
380  *  This differs from the regular soisdisconnecting() in that the latter
381  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
382  *  We don't want to set those flags because those flags will cause
383  *  a SIGPIPE to be delivered in sosend() and we don't like that.
384  *  If anyone else is sleeping on this socket, wake 'em up.
385  */
386 void
387 tp_soisdisconnecting(so)
388 	register struct socket *so;
389 {
390 	soisdisconnecting(so);
391 	so->so_state &= ~SS_CANTSENDMORE;
392 	IFPERF(sototpcb(so))
393 		register struct tp_pcb *tpcb = sototpcb(so);
394 		u_int 	fsufx, lsufx;
395 
396 		bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
397 		bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
398 
399 		tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref);
400 		tpcb->tp_perf_on = 0; /* turn perf off */
401 	ENDPERF
402 }
403 
404 
405 /*
406  * NAME: tp_soisdisconnected()
407  *
408  * CALLED FROM:
409  *	tp.trans
410  *
411  * FUNCTION and ARGUMENTS:
412  *  Set state of the socket (so) to reflect that fact that we're disconnectED
413  *  Set the state of the reference structure to closed, and
414  *  recycle the suffix.
415  *  Start a reference timer.
416  *
417  * RETURNS:	Nada
418  *
419  * SIDE EFFECTS:
420  *
421  * NOTES:
422  *  This differs from the regular soisdisconnected() in that the latter
423  *  also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
424  *  We don't want to set those flags because those flags will cause
425  *  a SIGPIPE to be delivered in sosend() and we don't like that.
426  *  If anyone else is sleeping on this socket, wake 'em up.
427  */
428 void
429 tp_soisdisconnected(tpcb)
430 	register struct tp_pcb	*tpcb;
431 {
432 	register struct socket	*so = tpcb->tp_sock;
433 
434 	soisdisconnecting(so);
435 	so->so_state &= ~SS_CANTSENDMORE;
436 	IFPERF(sototpcb(so))
437 		register struct tp_pcb *ttpcb = sototpcb(so);
438 		u_int 	fsufx, lsufx;
439 
440 		/* CHOKE */
441 		bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
442 		bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
443 
444 		tpmeas(ttpcb->tp_lref, TPtime_close,
445 		   &time, &lsufx, &fsufx, ttpcb->tp_fref);
446 		tpcb->tp_perf_on = 0; /* turn perf off */
447 	ENDPERF
448 
449 	tpcb->tp_refp->tpr_state = REF_FROZEN;
450 	tp_recycle_tsuffix( tpcb );
451 	tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks);
452 }
453 
454 int tp_maxrefopen;  /* highest reference # of the set of open tp connections */
455 
456 /*
457  * NAME:	tp_freeref()
458  *
459  * CALLED FROM:
460  *  tp.trans when the reference timer goes off, and
461  *  from tp_attach() and tp_detach() when a tpcb is partially set up but not
462  *  set up enough to have a ref timer set for it, and it's discarded
463  *  due to some sort of error or an early close()
464  *
465  * FUNCTION and ARGUMENTS:
466  *  Frees the reference represented by (r) for re-use.
467  *
468  * RETURNS: Nothing
469  *
470  * SIDE EFFECTS:
471  *
472  * NOTES:	better be called at clock priority !!!!!
473  */
474 void
475 tp_freeref(r)
476 	register struct tp_ref *r;
477 {
478 	IFDEBUG(D_TIMER)
479 		printf("tp_freeref called for ref %d maxrefopen %d\n",
480 		r - tp_ref, tp_maxrefopen);
481 	ENDDEBUG
482 	IFTRACE(D_TIMER)
483 		tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen",
484 		r - tp_ref, tp_maxrefopen, 0, 0);
485 	ENDTRACE
486 	r->tpr_state = REF_FREE;
487 	IFDEBUG(D_CONN)
488 		printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb);
489 	ENDDEBUG
490 	r->tpr_pcb = (struct tp_pcb *)0;
491 
492 	r = &tp_ref[tp_maxrefopen];
493 
494 	while( tp_maxrefopen > 0 ) {
495 		if(r->tpr_state )
496 			break;
497 		tp_maxrefopen--;
498 		r--;
499 	}
500 	IFDEBUG(D_TIMER)
501 		printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen);
502 	ENDDEBUG
503 }
504 
505 /*
506  * NAME:  tp_getref()
507  *
508  * CALLED FROM:
509  *  tp_attach()
510  *
511  * FUNCTION and ARGUMENTS:
512  *  obtains the next free reference and allocates the appropriate
513  *  ref structure, links that structure to (tpcb)
514  *
515  * RETURN VALUE:
516  *	a reference number
517  *  or TP_ENOREF
518  *
519  * SIDE EFFECTS:
520  *
521  * NOTES:
522  */
523 static RefNum
524 tp_getref(tpcb)
525 	register struct tp_pcb *tpcb;
526 {
527 	register struct tp_ref	*r = tp_ref;
528 	register int 			i=1;
529 
530 	r++; /* tp_ref[0] is never used */
531 
532 	/* REF_FREE is zero */
533 	while( r->tpr_state ) {
534 		r++;
535 		if ( i == N_TPREF ) {
536 			return TP_ENOREF;
537 		}
538 		i++;
539 	}
540 	r->tpr_state = REF_OPENING;
541 	if (tp_maxrefopen < i)
542 		tp_maxrefopen = i;
543 	r->tpr_pcb = tpcb;
544 	tpcb->tp_refp = r;
545 
546 	return i;
547 }
548 
549 /*
550  * NAME: tp_attach()
551  *
552  * CALLED FROM:
553  *	tp_usrreq, PRU_ATTACH
554  *
555  * FUNCTION and ARGUMENTS:
556  *  given a socket (so) and a protocol family (dom), allocate a tpcb
557  *  and ref structure, initialize everything in the structures that
558  *  needs to be initialized.
559  *
560  * RETURN VALUE:
561  *  0 ok
562  *  EINVAL if DEBUG(X) in is on and a disaster has occurred
563  *  ENOPROTOOPT if TP hasn't been configured or if the
564  *   socket wasn't created with tp as its protocol
565  *  EISCONN if this socket is already part of a connection
566  *  ETOOMANYREFS if ran out of tp reference numbers.
567  *  E* whatever error is returned from soreserve()
568  *    for from the network-layer pcb allocation routine
569  *
570  * SIDE EFFECTS:
571  *
572  * NOTES:
573  */
574 tp_attach(so, dom)
575 	struct socket 	*so;
576 	int 			dom;
577 {
578 	register struct tp_pcb	*tpcb;
579 	int 					error;
580 	int 					protocol = so->so_proto->pr_protocol;
581 	extern struct tp_conn_param tp_conn_param[];
582 
583 	IFDEBUG(D_CONN)
584 		printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
585 	ENDDEBUG
586 	IFTRACE(D_CONN)
587 		tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
588 	ENDTRACE
589 	if ( ! tp_param.tpp_configed ) {
590 		error = ENOPROTOOPT; /* protocol not available */
591 		goto bad2;
592 	}
593 
594 	if (so->so_pcb != NULL) {
595 		return EISCONN;	/* socket already part of a connection*/
596 	}
597 
598 	error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE);
599 		/* later an ioctl will allow reallocation IF still in closed state */
600 
601 	if (error)
602 		goto bad2;
603 
604 	MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
605 	if (tpcb == NULL) {
606 		error = ENOBUFS;
607 		goto bad2;
608 	}
609 	bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
610 
611 	if ( ((tpcb->tp_lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) {
612 		error = ETOOMANYREFS;
613 		goto bad3;
614 	}
615 	tpcb->tp_sock =  so;
616 	tpcb->tp_domain = dom;
617 	if (protocol<ISOPROTO_TP4) {
618 		tpcb->tp_netservice = ISO_CONS;
619 		tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
620 								 * will generate correct fake-ack values
621 								 */
622 	} else {
623 		tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
624 		/* the default */
625 	}
626 	tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
627 
628 	tpcb->tp_cong_win = 1;
629 	tpcb->tp_state = TP_CLOSED;
630 	tpcb->tp_vers  = TP_VERSION;
631 
632 		   /* Spec says default is 128 octets,
633 			* that is, if the tpdusize argument never appears, use 128.
634 			* As the initiator, we will always "propose" the 2048
635 			* size, that is, we will put this argument in the CR
636 			* always, but accept what the other side sends on the CC.
637 			* If the initiator sends us something larger on a CR,
638 			* we'll respond w/ this.
639 			* Our maximum is 4096.  See tp_chksum.c comments.
640 			*/
641 	tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
642 
643 	tpcb->tp_seqmask  = TP_NML_FMT_MASK;
644 	tpcb->tp_seqbit  =  TP_NML_FMT_BIT;
645 	tpcb->tp_seqhalf  =  tpcb->tp_seqbit >> 1;
646 	tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */
647 	tpcb->tp_s_subseq = 0;
648 
649 	/* attach to a network-layer protoswitch */
650 	/* new way */
651 	tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice];
652 	ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
653 #ifdef notdef
654 	/* OLD WAY */
655 	/* TODO: properly, this search would be on the basis of
656 	* domain,netservice or just netservice only (if you have
657 	* IN_CLNS, ISO_CLNS, and ISO_CONS)
658 	*/
659 	tpcb->tp_nlproto = nl_protosw;
660 	while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain )  {
661 		if( tpcb->tp_nlproto->nlp_afamily == 0 ) {
662 			error = EAFNOSUPPORT;
663 			goto bad4;
664 		}
665 		tpcb->tp_nlproto ++;
666 	}
667 #endif notdef
668 
669 	/* xx_pcballoc sets so_pcb */
670 	if ( error =  (tpcb->tp_nlproto->nlp_pcballoc) (
671 							so, tpcb->tp_nlproto->nlp_pcblist ) ) {
672 		goto bad4;
673 	}
674 
675 	if( dom == AF_INET )
676 		sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
677 		/* nothing to do for iso case */
678 
679 	tpcb->tp_npcb = (caddr_t) so->so_pcb;
680 	so->so_tpcb = (caddr_t) tpcb;
681 
682 	return 0;
683 
684 bad4:
685 	IFDEBUG(D_CONN)
686 		printf("BAD4 in tp_attach, so 0x%x\n", so);
687 	ENDDEBUG
688 	tp_freeref(tpcb->tp_refp);
689 
690 bad3:
691 	IFDEBUG(D_CONN)
692 		printf("BAD3 in tp_attach, so 0x%x\n", so);
693 	ENDDEBUG
694 
695 	free((caddr_t)tpcb, M_PCB); /* never a cluster  */
696 
697 bad2:
698 	IFDEBUG(D_CONN)
699 		printf("BAD2 in tp_attach, so 0x%x\n", so);
700 	ENDDEBUG
701 	so->so_pcb = 0;
702 	so->so_tpcb = 0;
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("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv);
779 		dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
780 		printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n",
781 				tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
782 	ENDDEBUG
783 
784 	if (so->so_snd.sb_cc != 0)
785 		sbflush(&so->so_snd);
786 	if (tpcb->tp_Xrcv.sb_cc != 0)
787 		sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc);
788 	if (tpcb->tp_ucddata)
789 		m_freem(tpcb->tp_ucddata);
790 
791 	IFDEBUG(D_CONN)
792 		printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
793 			so->so_pcb, so);
794 		printf("so 0x%x so_head 0x%x,  qlen %d q0len %d qlimit %d\n",
795 		so,  so->so_head,
796 		so->so_q0len, so->so_qlen, so->so_qlimit);
797 	ENDDEBUG
798 
799 
800 	(tpcb->tp_nlproto->nlp_pcbdetach)(so->so_pcb);
801 				/* does an sofree(so) */
802 
803 	IFDEBUG(D_CONN)
804 		printf("after xxx_pcbdetach\n");
805 	ENDDEBUG
806 
807 	if( tpcb->tp_refp->tpr_state == REF_OPENING ) {
808 		/* no connection existed here so no reference timer will be called */
809 		IFDEBUG(D_CONN)
810 			printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref,
811 			tpcb->tp_refp - &tp_ref[0]);
812 		ENDDEBUG
813 
814 		tp_freeref(tpcb->tp_refp);
815 	}
816 
817 	if (tpcb->tp_Xsnd.sb_mb) {
818 		printf("Unsent Xdata on detach; would panic");
819 		sbflush(&tpcb->tp_Xsnd);
820 	}
821 	so->so_tpcb = (caddr_t)0;
822 
823 	/*
824 	 * Get rid of the cluster mbuf allocated for performance measurements, if
825 	 * there is one.  Note that tpcb->tp_perf_on says nothing about whether or
826 	 * not a cluster mbuf was allocated, so you have to check for a pointer
827 	 * to one (that is, we need the TP_PERF_MEASs around the following section
828 	 * of code, not the IFPERFs)
829 	 */
830 #ifdef TP_PERF_MEAS
831 	if (tpcb->tp_p_mbuf) {
832 		register struct mbuf *m = tpcb->tp_p_mbuf;
833 		struct mbuf *n;
834 		IFDEBUG(D_PERF_MEAS)
835 			printf("freeing tp_p_meas 0x%x  ", tpcb->tp_p_meas);
836 		ENDDEBUG
837 		do {
838 		    MFREE(m, n);
839 		    m = n;
840 		} while (n);
841 		tpcb->tp_p_meas = 0;
842 		tpcb->tp_p_mbuf = 0;
843 	}
844 #endif TP_PERF_MEAS
845 
846 	IFDEBUG(D_CONN)
847 		printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
848 	ENDDEBUG
849 	/* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
850 }
851