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