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