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