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