Checkpoint as of first successful tp connection, before posix, &
[unix-history] / usr / src / sys / netiso / tp_pcb.c
CommitLineData
c32c2ec1
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
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
47static 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"
a50e2bc0
KS
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"
c32c2ec1
KS
70
71/* list of reference structures */
72struct tp_ref tp_ref[N_TPREF];
73
74struct 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
84struct 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
230int in_putnetaddr();
231int in_getnetaddr();
232int in_putsufx();
233int in_getsufx();
234int in_recycle_tsuffix();
235int tpip_mtu();
236int in_pcbbind();
237int in_pcbconnect();
238int in_pcbdisconnect();
239int in_pcbdetach();
240int in_pcballoc();
241int tpip_output();
242int tpip_output_dg();
243struct inpcb tp_inpcb;
244#endif INET
245#ifdef ISO
246int iso_putnetaddr();
247int iso_getnetaddr();
248int iso_putsufx();
249int iso_getsufx();
250int iso_recycle_tsuffix();
251int tpclnp_mtu();
252int iso_pcbbind();
253int iso_pcbconnect();
254int iso_pcbdisconnect();
255int iso_pcbdetach();
256int iso_pcballoc();
257int tpclnp_output();
258int tpclnp_output_dg();
259int iso_nlctloutput();
260struct isopcb tp_isopcb;
261#endif ISO
262#if NARGOXTWENTYFIVE > 0
263int iso_putnetaddr();
264int iso_getnetaddr();
265int iso_putsufx();
266int iso_getsufx();
267int iso_recycle_tsuffix();
268int tpcons_mtu();
269int iso_pcbbind();
270int iso_pcbconnect();
271int iso_pcbdisconnect();
272int iso_pcbdetach();
273int iso_pcballoc();
274int tpcons_output();
275int tpcons_output_dg();
276struct isopcb tp_isopcb;
277#endif NARGOXTWENTYFIVE
278
a50e2bc0 279
c32c2ec1
KS
280struct 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 },
a50e2bc0
KS
292#else
293 { 0 },
c32c2ec1
KS
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 },
a50e2bc0
KS
306#else
307 { 0 },
c32c2ec1
KS
308#endif INET
309 /* ISO_CONS */
a50e2bc0 310#if defined(ISO) && (NARGOXTWENTYFIVE > 0)
c32c2ec1
KS
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 },
a50e2bc0
KS
320#else
321 { 0 },
322#endif ISO_CONS
323 /* End of protosw marker */
324 { 0 }
c32c2ec1
KS
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 */
a50e2bc0 342int
c32c2ec1
KS
343tp_init()
344{
345 static int init_done=0;
346 void tp_timerinit();
347
348 if (init_done++)
a50e2bc0 349 return 0;
c32c2ec1 350
c32c2ec1
KS
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));
a50e2bc0 359 return 0;
c32c2ec1
KS
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 */
382void
383tp_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
a50e2bc0
KS
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) );
c32c2ec1 402
a50e2bc0 403 tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref);
c32c2ec1
KS
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 */
432void
433tp_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))
a50e2bc0 448 register struct tp_pcb *ttpcb = sototpcb(so);
c32c2ec1
KS
449 u_int fsufx, lsufx;
450
451 /* CHOKE */
a50e2bc0
KS
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) );
c32c2ec1 454
a50e2bc0
KS
455 tpmeas(ttpcb->tp_lref, TPtime_close,
456 &time, &lsufx, &fsufx, ttpcb->tp_fref);
c32c2ec1
KS
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
465int 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 */
485void
486tp_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 */
534static RefNum
535tp_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 */
a50e2bc0 585tp_attach(so, dom)
c32c2ec1
KS
586 struct socket *so;
587 int dom;
588{
589 register struct tp_pcb *tpcb;
c32c2ec1
KS
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
a50e2bc0
KS
615 MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
616 if (tpcb == NULL) {
c32c2ec1
KS
617 error = ENOBUFS;
618 goto bad2;
619 }
c32c2ec1
KS
620 bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
621
c32c2ec1
KS
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
695bad4:
696 IFDEBUG(D_CONN)
697 printf("BAD4 in tp_attach, so 0x%x\n", so);
698 ENDDEBUG
699 tp_freeref(tpcb->tp_refp);
700
701bad3:
702 IFDEBUG(D_CONN)
703 printf("BAD3 in tp_attach, so 0x%x\n", so);
704 ENDDEBUG
705
a50e2bc0 706 free((caddr_t)tpcb, M_PCB); /* never a cluster */
c32c2ec1
KS
707
708bad2:
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
a50e2bc0 716/*bad:*/
c32c2ec1
KS
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 */
746void
747tp_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)
a50e2bc0
KS
754 printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
755 tpcb,so);
c32c2ec1
KS
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
a50e2bc0 797 if ( tpcb->tp_flags & (TPF_DISC_DATA_OUT | TPF_CONN_DATA_OUT ) ) {
c32c2ec1
KS
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 )
a50e2bc0 806 sbflush(&so->so_snd);
c32c2ec1
KS
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 )
a50e2bc0 818 sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc);
c32c2ec1
KS
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
c32c2ec1 829
a50e2bc0
KS
830
831 (tpcb->tp_nlproto->nlp_pcbdetach)((struct inpcb *)so->so_pcb);
832 /* does an sofree(so) */
833
c32c2ec1
KS
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
a50e2bc0
KS
848 if (tpcb->tp_Xsnd.sb_mb) {
849 printf("Unsent Xdata on detach; would panic");
850 sbflush(&tpcb->tp_Xsnd);
851 }
c32c2ec1
KS
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
a50e2bc0
KS
862 if(tpcb->tp_p_mbuf) {
863 register struct mbuf *m = tpcb->tp_p_mbuf;
864 struct mbuf *n;
c32c2ec1
KS
865 IFDEBUG(D_PERF_MEAS)
866 printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas);
c32c2ec1 867 ENDDEBUG
a50e2bc0
KS
868 do {
869 MFREE(m, n);
870 m = n;
871 } while (n);
872 tpcb->tp_p_meas = 0;
873 tpcb->tp_p_mbuf = 0;
c32c2ec1
KS
874 }
875#endif TP_PERF_MEAS
876
877 IFDEBUG(D_CONN)
a50e2bc0 878 printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
c32c2ec1 879 ENDDEBUG
a50e2bc0 880 /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
c32c2ec1 881}