add _SSIZE_T_
[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 *
45df47eb 7 * @(#)tp_pcb.c 7.22 (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
6b9d3cc3
KS
327u_long tp_sendspace = 1024 * 4;
328u_long tp_recvspace = 1024 * 4;
329
c32c2ec1
KS
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;
3a2fbed9 437 IFPERF(tpcb)
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
3a2fbed9
KS
450 tpcb->tp_refstate = REF_FROZEN;
451 tp_recycle_tsuffix(tpcb);
bdf41b09 452 tp_etimeout(tpcb, TM_reference, (int)tpcb->tp_refer_ticks);
c32c2ec1
KS
453}
454
c32c2ec1
KS
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
378ea02c
KS
474tp_freeref(n)
475RefNum n;
c32c2ec1 476{
378ea02c
KS
477 register struct tp_ref *r = tp_ref + n;
478 register struct tp_pcb *tpcb;
479
480 tpcb = r->tpr_pcb;
c32c2ec1 481 IFDEBUG(D_TIMER)
378ea02c
KS
482 printf("tp_freeref called for ref %d pcb %x maxrefopen %d\n",
483 n, tpcb, tp_refinfo.tpr_maxopen);
c32c2ec1
KS
484 ENDDEBUG
485 IFTRACE(D_TIMER)
378ea02c
KS
486 tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb",
487 n, tp_refinfo.tpr_maxopen, tpcb, 0);
c32c2ec1 488 ENDTRACE
378ea02c
KS
489 if (tpcb == 0)
490 return;
c32c2ec1 491 IFDEBUG(D_CONN)
378ea02c 492 printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", tpcb);
c32c2ec1
KS
493 ENDDEBUG
494 r->tpr_pcb = (struct tp_pcb *)0;
378ea02c 495 tpcb->tp_refstate = REF_FREE;
c32c2ec1 496
3a2fbed9
KS
497 for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--)
498 if (r->tpr_pcb)
c32c2ec1 499 break;
3a2fbed9
KS
500 tp_refinfo.tpr_maxopen = r - tp_ref;
501 tp_refinfo.tpr_numopen--;
502
c32c2ec1 503 IFDEBUG(D_TIMER)
3a2fbed9 504 printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen);
c32c2ec1
KS
505 ENDDEBUG
506}
507
508/*
509 * NAME: tp_getref()
510 *
511 * CALLED FROM:
512 * tp_attach()
513 *
514 * FUNCTION and ARGUMENTS:
515 * obtains the next free reference and allocates the appropriate
516 * ref structure, links that structure to (tpcb)
517 *
518 * RETURN VALUE:
519 * a reference number
520 * or TP_ENOREF
521 *
522 * SIDE EFFECTS:
523 *
524 * NOTES:
525 */
bdf41b09 526u_long
c32c2ec1
KS
527tp_getref(tpcb)
528 register struct tp_pcb *tpcb;
529{
3a2fbed9
KS
530 register struct tp_ref *r, *rlim;
531 register int i;
532 caddr_t obase;
533 unsigned size;
534
535 if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size)
536 for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size;
537 ++r < rlim; ) /* tp_ref[0] is never used */
538 if (r->tpr_pcb == 0)
539 goto got_one;
540 /* else have to allocate more space */
541
542 obase = (caddr_t)tp_refinfo.tpr_base;
543 size = tp_refinfo.tpr_size * sizeof(struct tp_ref);
544 r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT);
545 if (r == 0)
546 return (--tp_refinfo.tpr_numopen, TP_ENOREF);
547 tp_refinfo.tpr_base = tp_ref = r;
548 tp_refinfo.tpr_size *= 2;
549 bcopy(obase, (caddr_t)r, size);
550 free(obase, M_PCB);
551 r = (struct tp_ref *)(size + (caddr_t)r);
552 bzero((caddr_t)r, size);
553
554got_one:
c32c2ec1 555 r->tpr_pcb = tpcb;
378ea02c 556 tpcb->tp_refstate = REF_OPENING;
3a2fbed9
KS
557 i = r - tp_refinfo.tpr_base;
558 if (tp_refinfo.tpr_maxopen < i)
559 tp_refinfo.tpr_maxopen = i;
378ea02c 560 return (u_long)i;
c32c2ec1
KS
561}
562
01acbfa1
KS
563/*
564 * NAME: tp_set_npcb()
565 *
566 * CALLED FROM:
567 * tp_attach(), tp_route_to()
568 *
569 * FUNCTION and ARGUMENTS:
570 * given a tpcb, allocate an appropriate lower-lever npcb, freeing
571 * any old ones that might need re-assigning.
572 */
573tp_set_npcb(tpcb)
574register struct tp_pcb *tpcb;
575{
576 register struct socket *so = tpcb->tp_sock;
577 int error;
578
579 if (tpcb->tp_nlproto && tpcb->tp_npcb) {
580 short so_state = so->so_state;
581 so->so_state &= ~SS_NOFDREF;
582 tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb);
583 so->so_state = so_state;
584 }
585 tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice];
586 /* xx_pcballoc sets so_pcb */
587 error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist);
588 tpcb->tp_npcb = so->so_pcb;
589 so->so_pcb = (caddr_t)tpcb;
590 return (error);
591}
c32c2ec1
KS
592/*
593 * NAME: tp_attach()
594 *
595 * CALLED FROM:
596 * tp_usrreq, PRU_ATTACH
597 *
598 * FUNCTION and ARGUMENTS:
599 * given a socket (so) and a protocol family (dom), allocate a tpcb
600 * and ref structure, initialize everything in the structures that
601 * needs to be initialized.
602 *
603 * RETURN VALUE:
604 * 0 ok
605 * EINVAL if DEBUG(X) in is on and a disaster has occurred
606 * ENOPROTOOPT if TP hasn't been configured or if the
607 * socket wasn't created with tp as its protocol
608 * EISCONN if this socket is already part of a connection
609 * ETOOMANYREFS if ran out of tp reference numbers.
610 * E* whatever error is returned from soreserve()
611 * for from the network-layer pcb allocation routine
612 *
613 * SIDE EFFECTS:
614 *
615 * NOTES:
616 */
01acbfa1
KS
617tp_attach(so, protocol)
618 struct socket *so;
619 int protocol;
c32c2ec1
KS
620{
621 register struct tp_pcb *tpcb;
6b9d3cc3 622 int error = 0;
01acbfa1 623 int dom = so->so_proto->pr_domain->dom_family;
bdf41b09 624 u_long lref;
c32c2ec1
KS
625 extern struct tp_conn_param tp_conn_param[];
626
627 IFDEBUG(D_CONN)
628 printf("tp_attach:dom 0x%x so 0x%x ", dom, so);
629 ENDDEBUG
630 IFTRACE(D_CONN)
631 tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
632 ENDTRACE
c32c2ec1
KS
633
634 if (so->so_pcb != NULL) {
635 return EISCONN; /* socket already part of a connection*/
636 }
637
6b9d3cc3 638 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0)
45df47eb 639 error = soreserve(so, tp_sendspace, tp_recvspace);
c32c2ec1
KS
640 /* later an ioctl will allow reallocation IF still in closed state */
641
642 if (error)
643 goto bad2;
644
a50e2bc0
KS
645 MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
646 if (tpcb == NULL) {
c32c2ec1
KS
647 error = ENOBUFS;
648 goto bad2;
649 }
c32c2ec1
KS
650 bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
651
bdf41b09 652 if ( ((lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) {
c32c2ec1
KS
653 error = ETOOMANYREFS;
654 goto bad3;
655 }
bdf41b09 656 tpcb->tp_lref = lref;
c32c2ec1
KS
657 tpcb->tp_sock = so;
658 tpcb->tp_domain = dom;
01acbfa1
KS
659 /* tpcb->tp_proto = protocol; someday maybe? */
660 if (protocol && protocol<ISOPROTO_TP4) {
c32c2ec1
KS
661 tpcb->tp_netservice = ISO_CONS;
662 tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
663 * will generate correct fake-ack values
664 */
665 } else {
666 tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS;
667 /* the default */
668 }
669 tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
670
c32c2ec1
KS
671 tpcb->tp_state = TP_CLOSED;
672 tpcb->tp_vers = TP_VERSION;
fab7bc7c 673 tpcb->tp_notdetached = 1;
c32c2ec1
KS
674
675 /* Spec says default is 128 octets,
676 * that is, if the tpdusize argument never appears, use 128.
677 * As the initiator, we will always "propose" the 2048
678 * size, that is, we will put this argument in the CR
679 * always, but accept what the other side sends on the CC.
680 * If the initiator sends us something larger on a CR,
681 * we'll respond w/ this.
682 * Our maximum is 4096. See tp_chksum.c comments.
683 */
bdf41b09
KS
684 tpcb->tp_cong_win =
685 tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
c32c2ec1
KS
686
687 tpcb->tp_seqmask = TP_NML_FMT_MASK;
688 tpcb->tp_seqbit = TP_NML_FMT_BIT;
689 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
c32c2ec1
KS
690
691 /* attach to a network-layer protoswitch */
01acbfa1 692 if ( error = tp_set_npcb(tpcb))
c32c2ec1 693 goto bad4;
01acbfa1 694 ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
c32c2ec1 695
01acbfa1 696 /* nothing to do for iso case */
c32c2ec1
KS
697 if( dom == AF_INET )
698 sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
c32c2ec1
KS
699
700 return 0;
701
702bad4:
703 IFDEBUG(D_CONN)
704 printf("BAD4 in tp_attach, so 0x%x\n", so);
705 ENDDEBUG
378ea02c 706 tp_freeref(tpcb->tp_lref);
c32c2ec1
KS
707
708bad3:
709 IFDEBUG(D_CONN)
710 printf("BAD3 in tp_attach, so 0x%x\n", so);
711 ENDDEBUG
712
a50e2bc0 713 free((caddr_t)tpcb, M_PCB); /* never a cluster */
c32c2ec1
KS
714
715bad2:
716 IFDEBUG(D_CONN)
717 printf("BAD2 in tp_attach, so 0x%x\n", so);
718 ENDDEBUG
719 so->so_pcb = 0;
c32c2ec1 720
a50e2bc0 721/*bad:*/
c32c2ec1
KS
722 IFDEBUG(D_CONN)
723 printf("BAD in tp_attach, so 0x%x\n", so);
724 ENDDEBUG
725 return error;
726}
727
728/*
729 * NAME: tp_detach()
730 *
731 * CALLED FROM:
732 * tp.trans, on behalf of a user close request
733 * and when the reference timer goes off
734 * (if the disconnect was initiated by the protocol entity
735 * rather than by the user)
736 *
737 * FUNCTION and ARGUMENTS:
738 * remove the tpcb structure from the list of active or
739 * partially active connections, recycle all the mbufs
740 * associated with the pcb, ref structure, sockbufs, etc.
741 * Only free the ref structure if you know that a ref timer
742 * wasn't set for this tpcb.
743 *
744 * RETURNS: Nada
745 *
746 * SIDE EFFECTS:
747 *
748 * NOTES:
749 * tp_soisdisconnected() was already when this is called
750 */
751void
752tp_detach(tpcb)
753 register struct tp_pcb *tpcb;
754{
98af392b 755 void tp_freeref(), tp_rsyflush();
c32c2ec1
KS
756 register struct socket *so = tpcb->tp_sock;
757
758 IFDEBUG(D_CONN)
a50e2bc0
KS
759 printf("tp_detach(tpcb 0x%x, so 0x%x)\n",
760 tpcb,so);
c32c2ec1
KS
761 ENDDEBUG
762 IFTRACE(D_CONN)
763 tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
7b25382f 764 tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0);
c32c2ec1
KS
765 ENDTRACE
766
3c642c63
KS
767 IFDEBUG(D_CONN)
768 printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv);
769 dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
770 printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n",
771 tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
772 ENDDEBUG
773
01acbfa1
KS
774 if (tpcb->tp_Xsnd.sb_mb) {
775 printf("Unsent Xdata on detach; would panic");
776 sbflush(&tpcb->tp_Xsnd);
777 }
3c642c63
KS
778 if (tpcb->tp_ucddata)
779 m_freem(tpcb->tp_ucddata);
780
98af392b
KS
781 IFDEBUG(D_CONN)
782 printf("reassembly info cnt %d rsyq 0x%x\n",
783 tpcb->tp_rsycnt, tpcb->tp_rsyq);
784 ENDDEBUG
785 if (tpcb->tp_rsyq)
786 tp_rsyflush(tpcb);
787
fab7bc7c
KS
788 if (tpcb->tp_next) {
789 remque(tpcb);
790 tpcb->tp_next = tpcb->tp_prev = 0;
791 }
792 tpcb->tp_notdetached = 0;
793
c32c2ec1
KS
794 IFDEBUG(D_CONN)
795 printf("calling (...nlproto->...)(0x%x, so 0x%x)\n",
f15f73d2 796 tpcb->tp_npcb, so);
c32c2ec1
KS
797 printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n",
798 so, so->so_head,
799 so->so_q0len, so->so_qlen, so->so_qlimit);
800 ENDDEBUG
801
f15f73d2 802 (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
01acbfa1 803 /* does an so->so_pcb = 0; sofree(so) */
a50e2bc0 804
c32c2ec1
KS
805 IFDEBUG(D_CONN)
806 printf("after xxx_pcbdetach\n");
807 ENDDEBUG
808
fab7bc7c
KS
809 if (tpcb->tp_state == TP_LISTENING) {
810 register struct tp_pcb **tt;
811 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
812 if (*tt == tpcb)
813 break;
814 if (*tt)
815 *tt = tpcb->tp_nextlisten;
816 else
817 printf("tp_detach from listen: should panic\n");
818 }
378ea02c 819 if (tpcb->tp_refstate == REF_OPENING ) {
c32c2ec1
KS
820 /* no connection existed here so no reference timer will be called */
821 IFDEBUG(D_CONN)
378ea02c 822 printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref);
c32c2ec1
KS
823 ENDDEBUG
824
378ea02c 825 tp_freeref(tpcb->tp_lref);
c32c2ec1 826 }
01acbfa1 827#ifdef TP_PERF_MEAS
c32c2ec1
KS
828 /*
829 * Get rid of the cluster mbuf allocated for performance measurements, if
830 * there is one. Note that tpcb->tp_perf_on says nothing about whether or
831 * not a cluster mbuf was allocated, so you have to check for a pointer
832 * to one (that is, we need the TP_PERF_MEASs around the following section
833 * of code, not the IFPERFs)
834 */
3c642c63 835 if (tpcb->tp_p_mbuf) {
a50e2bc0
KS
836 register struct mbuf *m = tpcb->tp_p_mbuf;
837 struct mbuf *n;
c32c2ec1
KS
838 IFDEBUG(D_PERF_MEAS)
839 printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas);
c32c2ec1 840 ENDDEBUG
a50e2bc0
KS
841 do {
842 MFREE(m, n);
843 m = n;
844 } while (n);
845 tpcb->tp_p_meas = 0;
846 tpcb->tp_p_mbuf = 0;
c32c2ec1
KS
847 }
848#endif TP_PERF_MEAS
849
850 IFDEBUG(D_CONN)
a50e2bc0 851 printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb);
c32c2ec1 852 ENDDEBUG
a50e2bc0 853 /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
c32c2ec1 854}
f2ae1840
KS
855
856struct que {
857 struct tp_pcb *next;
858 struct tp_pcb *prev;
859} tp_bound_pcbs =
860{(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs};
861
862u_short tp_unique;
863
864tp_tselinuse(tlen, tsel, siso, reuseaddr)
865caddr_t tsel;
866register struct sockaddr_iso *siso;
867{
868 struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
869 register struct tp_pcb *t;
870
871 for (;;) {
872 if (b != (struct tp_pcb *)&tp_bound_pcbs) {
873 t = b; b = t->tp_next;
874 } else if (l) {
875 t = l; l = t->tp_nextlisten;
876 } else
877 break;
878 if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
879 if (t->tp_flags & TPF_GENERAL_ADDR) {
880 if (siso == 0 || reuseaddr == 0)
881 return 1;
882 } else if (siso) {
883 if (siso->siso_family == t->tp_domain &&
884 t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL))
885 return 1;
886 } else if (reuseaddr == 0)
887 return 1;
888 }
889 }
890 return 0;
891
892}
893
894
895tp_pcbbind(tpcb, nam)
896register struct tp_pcb *tpcb;
897register struct mbuf *nam;
898{
899 register struct sockaddr_iso *siso = 0;
900 int tlen = 0, wrapped = 0;
901 caddr_t tsel;
902 u_short tutil;
903
904 if (tpcb->tp_state != TP_CLOSED)
905 return (EINVAL);
906 if (nam) {
907 siso = mtod(nam, struct sockaddr_iso *);
908 switch (siso->siso_family) {
909 default:
910 return (EAFNOSUPPORT);
911#ifdef ISO
912 case AF_ISO:
913 tlen = siso->siso_tlen;
914 tsel = TSEL(siso);
915 if (siso->siso_nlen == 0)
916 siso = 0;
917 break;
918#endif
919#ifdef INET
920 case AF_INET:
921 tsel = (caddr_t)&tutil;
922 if (tutil = ((struct sockaddr_in *)siso)->sin_port) {
923 tlen = 2;
924 }
925 if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0)
926 siso = 0;
927 }
928#endif
929 }
930 if (tpcb->tp_lsuffixlen == 0) {
931 if (tlen) {
01acbfa1 932 if (tp_tselinuse(tlen, tsel, siso,
f2ae1840
KS
933 tpcb->tp_sock->so_options & SO_REUSEADDR))
934 return (EINVAL);
935 } else for (tsel = (caddr_t)&tp_unique, tlen = 2;;){
936 if (tp_unique++ < ISO_PORT_RESERVED ||
937 tp_unique > ISO_PORT_USERRESERVED) {
938 if (wrapped++)
939 return ESRCH;
940 tp_unique = ISO_PORT_RESERVED;
941 }
01acbfa1 942 if (tp_tselinuse(tlen, tsel, siso, 0) == 0)
f2ae1840
KS
943 break;
944 }
945 bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
946 insque(tpcb, &tp_bound_pcbs);
947 } else {
948 if (tlen || siso == 0)
949 return (EINVAL);
950 }
951 if (siso == 0) {
952 tpcb->tp_flags |= TPF_GENERAL_ADDR;
953 return (0);
954 }
955 return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam);
956}