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