swab turns off special semantics of bs
[unix-history] / usr / src / sys / netiso / tp_pcb.c
CommitLineData
7bcd1bb8
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
f2ae1840 7 * @(#)tp_pcb.c 7.13 (Berkeley) %G%
7bcd1bb8
KB
8 */
9
c32c2ec1 10/***********************************************************
7b25382f 11 Copyright IBM Corporation 1987
c32c2ec1
KS
12
13 All Rights Reserved
14
15Permission to use, copy, modify, and distribute this software and its
16documentation for any purpose and without fee is hereby granted,
17provided that the above copyright notice appear in all copies and that
18both that copyright notice and this permission notice appear in
19supporting documentation, and that the name of IBM not be
20used in advertising or publicity pertaining to distribution of the
21software without specific, written prior permission.
22
23IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29SOFTWARE.
30
31******************************************************************/
32
33/*
34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35 */
36/*
37 * ARGO TP
38 *
39 * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $
40 * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $
41 *
42 *
43 * This is the initialization and cleanup stuff -
44 * for the tp machine in general as well as for the individual pcbs.
45 * tp_init() is called at system startup. tp_attach() and tp_getref() are
46 * called when a socket is created. tp_detach() and tp_freeref()
47 * are called during the closing stage and/or when the reference timer
48 * goes off.
49 * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific
50 * versions of soisconnect*
51 * and are called (obviously) during the closing phase.
52 *
53 */
54
c32c2ec1
KS
55#include "types.h"
56#include "param.h"
57#include "mbuf.h"
58#include "socket.h"
59#include "socketvar.h"
60#include "protosw.h"
61#include "errno.h"
62#include "time.h"
a50e2bc0
KS
63#include "argo_debug.h"
64#include "tp_param.h"
65#include "tp_timer.h"
66#include "tp_ip.h"
67#include "tp_stat.h"
68#include "tp_pcb.h"
69#include "tp_tpdu.h"
70#include "tp_trace.h"
71#include "tp_meas.h"
72#include "tp_seq.h"
73#include "tp_clnp.h"
c32c2ec1 74
c32c2ec1
KS
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();
63f88aec 233int in_cmpnetaddr();
c32c2ec1
KS
234int in_putsufx();
235int in_getsufx();
236int in_recycle_tsuffix();
237int tpip_mtu();
238int in_pcbbind();
239int in_pcbconnect();
240int in_pcbdisconnect();
241int in_pcbdetach();
242int in_pcballoc();
243int tpip_output();
244int tpip_output_dg();
245struct inpcb tp_inpcb;
246#endif INET
247#ifdef ISO
248int iso_putnetaddr();
249int iso_getnetaddr();
63f88aec 250int iso_cmpnetaddr();
c32c2ec1
KS
251int iso_putsufx();
252int iso_getsufx();
253int iso_recycle_tsuffix();
254int tpclnp_mtu();
255int iso_pcbbind();
256int iso_pcbconnect();
257int iso_pcbdisconnect();
258int iso_pcbdetach();
259int iso_pcballoc();
260int tpclnp_output();
261int tpclnp_output_dg();
262int iso_nlctloutput();
263struct isopcb tp_isopcb;
264#endif ISO
194a383a 265#ifdef TPCONS
c32c2ec1
KS
266int iso_putnetaddr();
267int iso_getnetaddr();
63f88aec 268int iso_cmpnetaddr();
c32c2ec1
KS
269int iso_putsufx();
270int iso_getsufx();
271int iso_recycle_tsuffix();
c32c2ec1 272int iso_pcbbind();
194a383a 273int tpcons_pcbconnect();
80a3ea26 274int tpclnp_mtu();
c32c2ec1
KS
275int iso_pcbdisconnect();
276int iso_pcbdetach();
277int iso_pcballoc();
278int tpcons_output();
c32c2ec1 279struct isopcb tp_isopcb;
194a383a 280#endif TPCONS
c32c2ec1 281
a50e2bc0 282
c32c2ec1
KS
283struct nl_protosw nl_protosw[] = {
284 /* ISO_CLNS */
285#ifdef ISO
63f88aec 286 { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
c32c2ec1
KS
287 iso_putsufx, iso_getsufx,
288 iso_recycle_tsuffix,
289 tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
290 iso_pcbdisconnect, iso_pcbdetach,
291 iso_pcballoc,
292 tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
293 (caddr_t) &tp_isopcb,
294 },
a50e2bc0
KS
295#else
296 { 0 },
c32c2ec1
KS
297#endif ISO
298 /* IN_CLNS */
299#ifdef INET
63f88aec 300 { AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr,
c32c2ec1
KS
301 in_putsufx, in_getsufx,
302 in_recycle_tsuffix,
303 tpip_mtu, in_pcbbind, in_pcbconnect,
304 in_pcbdisconnect, in_pcbdetach,
305 in_pcballoc,
306 tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
307 (caddr_t) &tp_inpcb,
308 },
a50e2bc0
KS
309#else
310 { 0 },
c32c2ec1
KS
311#endif INET
312 /* ISO_CONS */
194a383a 313#if defined(ISO) && defined(TPCONS)
63f88aec 314 { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
c32c2ec1
KS
315 iso_putsufx, iso_getsufx,
316 iso_recycle_tsuffix,
80a3ea26 317 tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect,
c32c2ec1
KS
318 iso_pcbdisconnect, iso_pcbdetach,
319 iso_pcballoc,
194a383a 320 tpcons_output, tpcons_output, iso_nlctloutput,
c32c2ec1
KS
321 (caddr_t) &tp_isopcb,
322 },
a50e2bc0
KS
323#else
324 { 0 },
325#endif ISO_CONS
326 /* End of protosw marker */
327 { 0 }
c32c2ec1
KS
328};
329
330/*
331 * NAME: tp_init()
332 *
333 * CALLED FROM:
334 * autoconf through the protosw structure
335 *
336 * FUNCTION:
337 * initialize tp machine
338 *
339 * RETURNS: Nada
340 *
341 * SIDE EFFECTS:
342 *
343 * NOTES:
344 */
a50e2bc0 345int
c32c2ec1
KS
346tp_init()
347{
348 static int init_done=0;
349 void tp_timerinit();
350
351 if (init_done++)
a50e2bc0 352 return 0;
c32c2ec1 353
c32c2ec1
KS
354
355 /* FOR INET */
356 tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb;
357 /* FOR ISO */
358 tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
359
620f4252
KS
360 tp_start_win = 2;
361
c32c2ec1
KS
362 tp_timerinit();
363 bzero((caddr_t)&tp_stat, sizeof(struct tp_stat));
a50e2bc0 364 return 0;
c32c2ec1
KS
365}
366
367/*
368 * NAME: tp_soisdisconnecting()
369 *
370 * CALLED FROM:
371 * tp.trans
372 *
373 * FUNCTION and ARGUMENTS:
374 * Set state of the socket (so) to reflect that fact that we're disconnectING
375 *
376 * RETURNS: Nada
377 *
378 * SIDE EFFECTS:
379 *
380 * NOTES:
381 * This differs from the regular soisdisconnecting() in that the latter
382 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
383 * We don't want to set those flags because those flags will cause
384 * a SIGPIPE to be delivered in sosend() and we don't like that.
385 * If anyone else is sleeping on this socket, wake 'em up.
386 */
387void
388tp_soisdisconnecting(so)
389 register struct socket *so;
390{
44f52ea5
KS
391 soisdisconnecting(so);
392 so->so_state &= ~SS_CANTSENDMORE;
c32c2ec1
KS
393 IFPERF(sototpcb(so))
394 register struct tp_pcb *tpcb = sototpcb(so);
395 u_int fsufx, lsufx;
396
a50e2bc0
KS
397 bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
398 bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
c32c2ec1 399
a50e2bc0 400 tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref);
c32c2ec1
KS
401 tpcb->tp_perf_on = 0; /* turn perf off */
402 ENDPERF
403}
404
405
406/*
407 * NAME: tp_soisdisconnected()
408 *
409 * CALLED FROM:
410 * tp.trans
411 *
412 * FUNCTION and ARGUMENTS:
413 * Set state of the socket (so) to reflect that fact that we're disconnectED
414 * Set the state of the reference structure to closed, and
415 * recycle the suffix.
416 * Start a reference timer.
417 *
418 * RETURNS: Nada
419 *
420 * SIDE EFFECTS:
421 *
422 * NOTES:
423 * This differs from the regular soisdisconnected() in that the latter
424 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
425 * We don't want to set those flags because those flags will cause
426 * a SIGPIPE to be delivered in sosend() and we don't like that.
427 * If anyone else is sleeping on this socket, wake 'em up.
428 */
429void
430tp_soisdisconnected(tpcb)
431 register struct tp_pcb *tpcb;
432{
433 register struct socket *so = tpcb->tp_sock;
434
44f52ea5
KS
435 soisdisconnecting(so);
436 so->so_state &= ~SS_CANTSENDMORE;
c32c2ec1 437 IFPERF(sototpcb(so))
a50e2bc0 438 register struct tp_pcb *ttpcb = sototpcb(so);
c32c2ec1
KS
439 u_int fsufx, lsufx;
440
441 /* CHOKE */
a50e2bc0
KS
442 bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) );
443 bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) );
c32c2ec1 444
a50e2bc0
KS
445 tpmeas(ttpcb->tp_lref, TPtime_close,
446 &time, &lsufx, &fsufx, ttpcb->tp_fref);
c32c2ec1
KS
447 tpcb->tp_perf_on = 0; /* turn perf off */
448 ENDPERF
449
450 tpcb->tp_refp->tpr_state = REF_FROZEN;
451 tp_recycle_tsuffix( tpcb );
452 tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks);
453}
454
455int tp_maxrefopen; /* highest reference # of the set of open tp connections */
456
457/*
458 * NAME: tp_freeref()
459 *
460 * CALLED FROM:
461 * tp.trans when the reference timer goes off, and
462 * from tp_attach() and tp_detach() when a tpcb is partially set up but not
463 * set up enough to have a ref timer set for it, and it's discarded
464 * due to some sort of error or an early close()
465 *
466 * FUNCTION and ARGUMENTS:
467 * Frees the reference represented by (r) for re-use.
468 *
469 * RETURNS: Nothing
470 *
471 * SIDE EFFECTS:
472 *
473 * NOTES: better be called at clock priority !!!!!
474 */
475void
476tp_freeref(r)
477 register struct tp_ref *r;
478{
479 IFDEBUG(D_TIMER)
480 printf("tp_freeref called for ref %d maxrefopen %d\n",
481 r - tp_ref, tp_maxrefopen);
482 ENDDEBUG
483 IFTRACE(D_TIMER)
484 tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen",
485 r - tp_ref, tp_maxrefopen, 0, 0);
486 ENDTRACE
487 r->tpr_state = REF_FREE;
488 IFDEBUG(D_CONN)
489 printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb);
490 ENDDEBUG
491 r->tpr_pcb = (struct tp_pcb *)0;
492
493 r = &tp_ref[tp_maxrefopen];
494
495 while( tp_maxrefopen > 0 ) {
496 if(r->tpr_state )
497 break;
498 tp_maxrefopen--;
499 r--;
500 }
501 IFDEBUG(D_TIMER)
502 printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen);
503 ENDDEBUG
504}
505
506/*
507 * NAME: tp_getref()
508 *
509 * CALLED FROM:
510 * tp_attach()
511 *
512 * FUNCTION and ARGUMENTS:
513 * obtains the next free reference and allocates the appropriate
514 * ref structure, links that structure to (tpcb)
515 *
516 * RETURN VALUE:
517 * a reference number
518 * or TP_ENOREF
519 *
520 * SIDE EFFECTS:
521 *
522 * NOTES:
523 */
524static RefNum
525tp_getref(tpcb)
526 register struct tp_pcb *tpcb;
527{
4a43bed3 528 register struct tp_ref *r = tp_ref; /* tp_ref[0] is never used */
c32c2ec1
KS
529 register int i=1;
530
c32c2ec1 531
4a43bed3
KS
532 while ((++r)->tpr_state != REF_FREE) {
533 if (++i == N_TPREF)
c32c2ec1 534 return TP_ENOREF;
c32c2ec1
KS
535 }
536 r->tpr_state = REF_OPENING;
537 if (tp_maxrefopen < i)
538 tp_maxrefopen = i;
539 r->tpr_pcb = tpcb;
540 tpcb->tp_refp = r;
541
542 return i;
543}
544
545/*
546 * NAME: tp_attach()
547 *
548 * CALLED FROM:
549 * tp_usrreq, PRU_ATTACH
550 *
551 * FUNCTION and ARGUMENTS:
552 * given a socket (so) and a protocol family (dom), allocate a tpcb
553 * and ref structure, initialize everything in the structures that
554 * needs to be initialized.
555 *
556 * RETURN VALUE:
557 * 0 ok
558 * EINVAL if DEBUG(X) in is on and a disaster has occurred
559 * ENOPROTOOPT if TP hasn't been configured or if the
560 * socket wasn't created with tp as its protocol
561 * EISCONN if this socket is already part of a connection
562 * ETOOMANYREFS if ran out of tp reference numbers.
563 * E* whatever error is returned from soreserve()
564 * for from the network-layer pcb allocation routine
565 *
566 * SIDE EFFECTS:
567 *
568 * NOTES:
569 */
a50e2bc0 570tp_attach(so, dom)
c32c2ec1
KS
571 struct socket *so;
572 int dom;
573{
574 register struct tp_pcb *tpcb;
c32c2ec1
KS
575 int error;
576 int protocol = so->so_proto->pr_protocol;
577 extern struct tp_conn_param tp_conn_param[];
578
579 IFDEBUG(D_CONN)
580 printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
581 ENDDEBUG
582 IFTRACE(D_CONN)
583 tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
584 ENDTRACE
585 if ( ! tp_param.tpp_configed ) {
586 error = ENOPROTOOPT; /* protocol not available */
587 goto bad2;
588 }
589
590 if (so->so_pcb != NULL) {
591 return EISCONN; /* socket already part of a connection*/
592 }
593
594 error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE);
595 /* later an ioctl will allow reallocation IF still in closed state */
596
597 if (error)
598 goto bad2;
599
a50e2bc0
KS
600 MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
601 if (tpcb == NULL) {
c32c2ec1
KS
602 error = ENOBUFS;
603 goto bad2;
604 }
c32c2ec1
KS
605 bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
606
c32c2ec1
KS
607 if ( ((tpcb->tp_lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) {
608 error = ETOOMANYREFS;
609 goto bad3;
610 }
611 tpcb->tp_sock = so;
612 tpcb->tp_domain = dom;
613 if (protocol<ISOPROTO_TP4) {
614 tpcb->tp_netservice = ISO_CONS;
615 tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
616 * will generate correct fake-ack values
617 */
618 } else {
619 tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
620 /* the default */
621 }
622 tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
623
624 tpcb->tp_cong_win = 1;
625 tpcb->tp_state = TP_CLOSED;
626 tpcb->tp_vers = TP_VERSION;
627
628 /* Spec says default is 128 octets,
629 * that is, if the tpdusize argument never appears, use 128.
630 * As the initiator, we will always "propose" the 2048
631 * size, that is, we will put this argument in the CR
632 * always, but accept what the other side sends on the CC.
633 * If the initiator sends us something larger on a CR,
634 * we'll respond w/ this.
635 * Our maximum is 4096. See tp_chksum.c comments.
636 */
637 tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
638
639 tpcb->tp_seqmask = TP_NML_FMT_MASK;
640 tpcb->tp_seqbit = TP_NML_FMT_BIT;
641 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
642 tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */
643 tpcb->tp_s_subseq = 0;
644
645 /* attach to a network-layer protoswitch */
646 /* new way */
647 tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice];
648 ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
649#ifdef notdef
650 /* OLD WAY */
651 /* TODO: properly, this search would be on the basis of
652 * domain,netservice or just netservice only (if you have
653 * IN_CLNS, ISO_CLNS, and ISO_CONS)
654 */
655 tpcb->tp_nlproto = nl_protosw;
656 while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain ) {
657 if( tpcb->tp_nlproto->nlp_afamily == 0 ) {
658 error = EAFNOSUPPORT;
659 goto bad4;
660 }
661 tpcb->tp_nlproto ++;
662 }
663#endif notdef
664
665 /* xx_pcballoc sets so_pcb */
666 if ( error = (tpcb->tp_nlproto->nlp_pcballoc) (
667 so, tpcb->tp_nlproto->nlp_pcblist ) ) {
668 goto bad4;
669 }
670
671 if( dom == AF_INET )
672 sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
673 /* nothing to do for iso case */
674
f15f73d2
KS
675 tpcb->tp_npcb = so->so_pcb;
676 so->so_pcb = (caddr_t) tpcb;
c32c2ec1
KS
677
678 return 0;
679
680bad4:
681 IFDEBUG(D_CONN)
682 printf("BAD4 in tp_attach, so 0x%x\n", so);
683 ENDDEBUG
684 tp_freeref(tpcb->tp_refp);
685
686bad3:
687 IFDEBUG(D_CONN)
688 printf("BAD3 in tp_attach, so 0x%x\n", so);
689 ENDDEBUG
690
a50e2bc0 691 free((caddr_t)tpcb, M_PCB); /* never a cluster */
c32c2ec1
KS
692
693bad2:
694 IFDEBUG(D_CONN)
695 printf("BAD2 in tp_attach, so 0x%x\n", so);
696 ENDDEBUG
697 so->so_pcb = 0;
c32c2ec1 698
a50e2bc0 699/*bad:*/
c32c2ec1
KS
700 IFDEBUG(D_CONN)
701 printf("BAD in tp_attach, so 0x%x\n", so);
702 ENDDEBUG
703 return error;
704}
705
706/*
707 * NAME: tp_detach()
708 *
709 * CALLED FROM:
710 * tp.trans, on behalf of a user close request
711 * and when the reference timer goes off
712 * (if the disconnect was initiated by the protocol entity
713 * rather than by the user)
714 *
715 * FUNCTION and ARGUMENTS:
716 * remove the tpcb structure from the list of active or
717 * partially active connections, recycle all the mbufs
718 * associated with the pcb, ref structure, sockbufs, etc.
719 * Only free the ref structure if you know that a ref timer
720 * wasn't set for this tpcb.
721 *
722 * RETURNS: Nada
723 *
724 * SIDE EFFECTS:
725 *
726 * NOTES:
727 * tp_soisdisconnected() was already when this is called
728 */
729void
730tp_detach(tpcb)
731 register struct tp_pcb *tpcb;
732{
733 void tp_freeref();
734 register struct socket *so = tpcb->tp_sock;
735
736 IFDEBUG(D_CONN)
a50e2bc0
KS
737 printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
738 tpcb,so);
c32c2ec1
KS
739 ENDDEBUG
740 IFTRACE(D_CONN)
741 tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
7b25382f 742 tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0);
c32c2ec1
KS
743 ENDTRACE
744
745 if (so->so_head) {
746 if (!soqremque(so, 0) && !soqremque(so, 1))
747 panic("sofree dq");
748 so->so_head = 0;
749 }
750
751 IFDEBUG(D_CONN)
752 printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n",
753 tpcb->tp_snduna_rtc,
754 tpcb->tp_rcvnxt_rtc);
755 ENDDEBUG
756
757#define FREE_RTC_LIST(XXX)\
758 { register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\
759 xxs = xxr->tprt_next;\
760 m_freem( xxr->tprt_data );\
761 m_free( dtom(xxr) ); xxr = xxs; }\
762 XXX = (struct tp_rtc *)0;\
763 }
764
765 FREE_RTC_LIST( tpcb->tp_snduna_rtc );
766 tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0;
767
768 FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc );
769
770#undef FREE_RTC_LIST
771
3c642c63
KS
772 IFDEBUG(D_CONN)
773 printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv);
774 dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
775 printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n",
776 tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
777 ENDDEBUG
778
779 if (so->so_snd.sb_cc != 0)
780 sbflush(&so->so_snd);
781 if (tpcb->tp_Xrcv.sb_cc != 0)
782 sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc);
783 if (tpcb->tp_ucddata)
784 m_freem(tpcb->tp_ucddata);
785
c32c2ec1
KS
786 IFDEBUG(D_CONN)
787 printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
f15f73d2 788 tpcb->tp_npcb, so);
c32c2ec1
KS
789 printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n",
790 so, so->so_head,
791 so->so_q0len, so->so_qlen, so->so_qlimit);
792 ENDDEBUG
793
c32c2ec1 794
f15f73d2 795 (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
a50e2bc0
KS
796 /* does an sofree(so) */
797
c32c2ec1
KS
798 IFDEBUG(D_CONN)
799 printf("after xxx_pcbdetach\n");
800 ENDDEBUG
801
802 if( tpcb->tp_refp->tpr_state == REF_OPENING ) {
803 /* no connection existed here so no reference timer will be called */
804 IFDEBUG(D_CONN)
805 printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref,
806 tpcb->tp_refp - &tp_ref[0]);
807 ENDDEBUG
808
809 tp_freeref(tpcb->tp_refp);
810 }
811
a50e2bc0
KS
812 if (tpcb->tp_Xsnd.sb_mb) {
813 printf("Unsent Xdata on detach; would panic");
814 sbflush(&tpcb->tp_Xsnd);
815 }
f15f73d2 816 so->so_pcb = 0;
c32c2ec1
KS
817
818 /*
819 * Get rid of the cluster mbuf allocated for performance measurements, if
820 * there is one. Note that tpcb->tp_perf_on says nothing about whether or
821 * not a cluster mbuf was allocated, so you have to check for a pointer
822 * to one (that is, we need the TP_PERF_MEASs around the following section
823 * of code, not the IFPERFs)
824 */
825#ifdef TP_PERF_MEAS
3c642c63 826 if (tpcb->tp_p_mbuf) {
a50e2bc0
KS
827 register struct mbuf *m = tpcb->tp_p_mbuf;
828 struct mbuf *n;
c32c2ec1
KS
829 IFDEBUG(D_PERF_MEAS)
830 printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas);
c32c2ec1 831 ENDDEBUG
a50e2bc0
KS
832 do {
833 MFREE(m, n);
834 m = n;
835 } while (n);
836 tpcb->tp_p_meas = 0;
837 tpcb->tp_p_mbuf = 0;
c32c2ec1
KS
838 }
839#endif TP_PERF_MEAS
840
841 IFDEBUG(D_CONN)
a50e2bc0 842 printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
c32c2ec1 843 ENDDEBUG
a50e2bc0 844 /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
c32c2ec1 845}
f2ae1840
KS
846
847struct que {
848 struct tp_pcb *next;
849 struct tp_pcb *prev;
850} tp_bound_pcbs =
851{(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs};
852
853u_short tp_unique;
854
855tp_tselinuse(tlen, tsel, siso, reuseaddr)
856caddr_t tsel;
857register struct sockaddr_iso *siso;
858{
859 struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
860 register struct tp_pcb *t;
861
862 for (;;) {
863 if (b != (struct tp_pcb *)&tp_bound_pcbs) {
864 t = b; b = t->tp_next;
865 } else if (l) {
866 t = l; l = t->tp_nextlisten;
867 } else
868 break;
869 if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
870 if (t->tp_flags & TPF_GENERAL_ADDR) {
871 if (siso == 0 || reuseaddr == 0)
872 return 1;
873 } else if (siso) {
874 if (siso->siso_family == t->tp_domain &&
875 t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL))
876 return 1;
877 } else if (reuseaddr == 0)
878 return 1;
879 }
880 }
881 return 0;
882
883}
884
885
886tp_pcbbind(tpcb, nam)
887register struct tp_pcb *tpcb;
888register struct mbuf *nam;
889{
890 register struct sockaddr_iso *siso = 0;
891 int tlen = 0, wrapped = 0;
892 caddr_t tsel;
893 u_short tutil;
894
895 if (tpcb->tp_state != TP_CLOSED)
896 return (EINVAL);
897 if (nam) {
898 siso = mtod(nam, struct sockaddr_iso *);
899 switch (siso->siso_family) {
900 default:
901 return (EAFNOSUPPORT);
902#ifdef ISO
903 case AF_ISO:
904 tlen = siso->siso_tlen;
905 tsel = TSEL(siso);
906 if (siso->siso_nlen == 0)
907 siso = 0;
908 break;
909#endif
910#ifdef INET
911 case AF_INET:
912 tsel = (caddr_t)&tutil;
913 if (tutil = ((struct sockaddr_in *)siso)->sin_port) {
914 tlen = 2;
915 }
916 if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0)
917 siso = 0;
918 }
919#endif
920 }
921 if (tpcb->tp_lsuffixlen == 0) {
922 if (tlen) {
923 if (tp_tselinuse(tsel, tlen, siso,
924 tpcb->tp_sock->so_options & SO_REUSEADDR))
925 return (EINVAL);
926 } else for (tsel = (caddr_t)&tp_unique, tlen = 2;;){
927 if (tp_unique++ < ISO_PORT_RESERVED ||
928 tp_unique > ISO_PORT_USERRESERVED) {
929 if (wrapped++)
930 return ESRCH;
931 tp_unique = ISO_PORT_RESERVED;
932 }
933 if (tp_tselinuse(tsel, tlen, siso, 0) == 0)
934 break;
935 }
936 bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
937 insque(tpcb, &tp_bound_pcbs);
938 } else {
939 if (tlen || siso == 0)
940 return (EINVAL);
941 }
942 if (siso == 0) {
943 tpcb->tp_flags |= TPF_GENERAL_ADDR;
944 return (0);
945 }
946 return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam);
947}