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