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