Reflow to < 80 chars.
[netbsd-mini2440.git] / sys / netiso / tp_pcb.c
bloba3c19d7933eeb150914b8e4c94342a5a6cab91a2
1 /* $NetBSD: tp_pcb.c,v 1.40 2009/03/18 17:06:53 cegger Exp $ */
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 * @(#)tp_pcb.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
37 All Rights Reserved
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 SOFTWARE.
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 * This is the initialization and cleanup stuff - for the tp machine in
62 * general as well as for the individual pcbs. tp_init() is called at system
63 * startup. tp_attach() and tp_getref() are called when a socket is created.
64 * tp_detach() and tp_freeref() are called during the closing stage and/or
65 * when the reference timer goes off. tp_soisdisconnecting() and
66 * tp_soisdisconnected() are tp-specific versions of soisconnect* and are
67 * called (obviously) during the closing phase.
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: tp_pcb.c,v 1.40 2009/03/18 17:06:53 cegger Exp $");
73 #include "opt_inet.h"
74 #include "opt_iso.h"
76 #include <sys/param.h>
77 #include <sys/systm.h>
78 #include <sys/mbuf.h>
79 #include <sys/socket.h>
80 #include <sys/socketvar.h>
81 #include <sys/domain.h>
82 #include <sys/protosw.h>
83 #include <sys/errno.h>
84 #include <sys/time.h>
86 #include <netiso/argo_debug.h>
87 #include <netiso/tp_param.h>
88 #include <netiso/tp_timer.h>
89 #include <netiso/tp_ip.h>
90 #include <netiso/tp_stat.h>
91 #include <netiso/tp_pcb.h>
92 #include <netiso/tp_tpdu.h>
93 #include <netiso/tp_trace.h>
94 #include <netiso/tp_meas.h>
95 #include <netiso/tp_seq.h>
96 #include <netiso/tp_clnp.h>
97 #include <netiso/tp_var.h>
100 * ticks are in units of: 500 nano-fortnights ;-) or 500 ms or 1/2 second
103 const struct tp_conn_param tp_conn_param[] = {
104 /* ISO_CLNS: TP4 CONNECTION LESS */
106 TP_NRETRANS, /* short p_Nretrans; */
107 20, /* 10 sec *//* short p_dr_ticks; */
109 20, /* 10 sec *//* short p_cc_ticks; */
110 20, /* 10 sec *//* short p_dt_ticks; */
112 40, /* 20 sec *//* short p_x_ticks; */
113 80, /* 40 sec *//* short p_cr_ticks; */
115 240, /* 2 min *//* short p_keepalive_ticks; */
116 10, /* 5 sec *//* short p_sendack_ticks; */
118 600, /* 5 min *//* short p_ref_ticks; */
119 360, /* 3 min *//* short p_inact_ticks; */
121 (short) 100, /* short p_lcdtfract */
122 (short) TP_SOCKBUFSIZE, /* short p_winsize */
123 TP_TPDUSIZE, /* u_char p_tpdusize */
125 TPACK_WINDOW, /* 4 bits p_ack_strat */
126 TPRX_USE_CW | TPRX_FASTSTART,
127 /* 4 bits p_rx_strat */
128 TP_CLASS_4 | TP_CLASS_0, /* 5 bits p_class */
129 1, /* 1 bit xtd format */
130 1, /* 1 bit xpd service */
131 1, /* 1 bit use_checksum */
132 0, /* 1 bit use net xpd */
133 0, /* 1 bit use rcc */
134 0, /* 1 bit use efc */
135 1, /* no disc indications */
136 0, /* don't change params */
137 ISO_CLNS, /* p_netservice */
140 /* IN_CLNS: TP4 CONNECTION LESS */
142 TP_NRETRANS, /* short p_Nretrans; */
143 20, /* 10 sec *//* short p_dr_ticks; */
145 20, /* 10 sec *//* short p_cc_ticks; */
146 20, /* 10 sec *//* short p_dt_ticks; */
148 40, /* 20 sec *//* short p_x_ticks; */
149 80, /* 40 sec *//* short p_cr_ticks; */
151 240, /* 2 min *//* short p_keepalive_ticks; */
152 10, /* 5 sec *//* short p_sendack_ticks; */
154 600, /* 5 min *//* short p_ref_ticks; */
155 360, /* 3 min *//* short p_inact_ticks; */
157 (short) 100, /* short p_lcdtfract */
158 (short) TP_SOCKBUFSIZE, /* short p_winsize */
159 TP_TPDUSIZE, /* u_char p_tpdusize */
161 TPACK_WINDOW, /* 4 bits p_ack_strat */
162 TPRX_USE_CW | TPRX_FASTSTART,
163 /* 4 bits p_rx_strat */
164 TP_CLASS_4, /* 5 bits p_class */
165 1, /* 1 bit xtd format */
166 1, /* 1 bit xpd service */
167 1, /* 1 bit use_checksum */
168 0, /* 1 bit use net xpd */
169 0, /* 1 bit use rcc */
170 0, /* 1 bit use efc */
171 1, /* no disc indications */
172 0, /* don't change params */
173 IN_CLNS, /* p_netservice */
176 /* ISO_CONS: TP0 CONNECTION MODE */
178 TP_NRETRANS, /* short p_Nretrans; */
179 0, /* n/a *//* short p_dr_ticks; */
181 40, /* 20 sec *//* short p_cc_ticks; */
182 0, /* n/a *//* short p_dt_ticks; */
184 0, /* n/a *//* short p_x_ticks; */
185 360, /* 3 min *//* short p_cr_ticks; */
187 0, /* n/a *//* short p_keepalive_ticks; */
188 0, /* n/a *//* short p_sendack_ticks; */
190 600, /* for cr/cc to clear *//* short p_ref_ticks; */
191 0, /* n/a *//* short p_inact_ticks; */
194 * Use tp4 defaults just in case the user changes ONLY the
195 * class
197 (short) 100, /* short p_lcdtfract */
198 (short) TP0_SOCKBUFSIZE, /* short p_winsize */
199 TP0_TPDUSIZE, /* 8 bits p_tpdusize */
201 0, /* 4 bits p_ack_strat */
202 0, /* 4 bits p_rx_strat */
203 TP_CLASS_0, /* 5 bits p_class */
204 0, /* 1 bit xtd format */
205 0, /* 1 bit xpd service */
206 0, /* 1 bit use_checksum */
207 0, /* 1 bit use net xpd */
208 0, /* 1 bit use rcc */
209 0, /* 1 bit use efc */
210 0, /* no disc indications */
211 0, /* don't change params */
212 ISO_CONS, /* p_netservice */
215 /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */
217 TP_NRETRANS, /* short p_Nretrans; */
218 40, /* 20 sec *//* short p_dr_ticks; */
220 40, /* 20 sec *//* short p_cc_ticks; */
221 80, /* 40 sec *//* short p_dt_ticks; */
223 120, /* 1 min *//* short p_x_ticks; */
224 360, /* 3 min *//* short p_cr_ticks; */
226 360, /* 3 min *//* short p_keepalive_ticks; */
227 20, /* 10 sec *//* short p_sendack_ticks; */
229 600, /* 5 min *//* short p_ref_ticks; */
230 480, /* 4 min *//* short p_inact_ticks; */
232 (short) 100, /* short p_lcdtfract */
233 (short) TP0_SOCKBUFSIZE, /* short p_winsize */
234 TP0_TPDUSIZE, /* u_char p_tpdusize */
236 TPACK_WINDOW, /* 4 bits p_ack_strat */
237 TPRX_USE_CW, /* No fast start */
238 /* 4 bits p_rx_strat */
239 TP_CLASS_4 | TP_CLASS_0, /* 5 bits p_class */
240 0, /* 1 bit xtd format */
241 1, /* 1 bit xpd service */
242 1, /* 1 bit use_checksum */
243 0, /* 1 bit use net xpd */
244 0, /* 1 bit use rcc */
245 0, /* 1 bit use efc */
246 0, /* no disc indications */
247 0, /* don't change params */
248 ISO_COSNS, /* p_netservice */
253 #ifdef INET
254 struct inpcbtable tp_inpcb;
255 #endif /* INET */
256 #ifdef ISO
257 struct isopcb tp_isopcb;
258 #endif /* ISO */
260 struct tp_stat tp_stat;
261 u_int tp_start_win;
263 struct nl_protosw nl_protosw[] = {
264 /* ISO_CLNS */
265 #ifdef ISO
266 {AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
267 iso_putsufx, iso_getsufx,
268 iso_recycle_tsuffix,
269 tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
270 iso_pcbdisconnect, iso_pcbdetach,
271 iso_pcballoc,
272 tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
273 (void *) & tp_isopcb,
275 #else
276 { .nlp_afamily = 0, },
277 #endif /* ISO */
278 /* IN_CLNS */
279 #ifdef INET
280 {AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr,
281 in_putsufx, in_getsufx,
282 in_recycle_tsuffix,
283 tpip_mtu, in_pcbbind, in_pcbconnect,
284 in_pcbdisconnect, in_pcbdetach,
285 in_pcballoc,
286 tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
287 (void *) & tp_inpcb,
289 #else
290 { .nlp_afamily = 0, },
291 #endif /* INET */
292 /* ISO_CONS */
293 { .nlp_afamily = 0, },
294 /* End of protosw marker */
295 { .nlp_afamily = 0, },
298 u_long tp_sendspace = 1024 * 4;
299 u_long tp_recvspace = 1024 * 4;
302 * NAME: tp_init()
304 * CALLED FROM:
305 * autoconf through the protosw structure
307 * FUNCTION:
308 * initialize tp machine
310 * RETURNS: Nada
312 * SIDE EFFECTS:
314 * NOTES:
316 void
317 tp_init(void)
319 static int init_done = 0;
321 if (init_done++)
322 return;
324 #ifdef INET
325 /* FOR INET */
326 in_pcbinit(&tp_inpcb, 1, 1);
327 #endif
328 #ifdef ISO
329 /* FOR ISO */
330 tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
331 #endif
333 tp_start_win = 2;
335 tp_timerinit();
336 memset((void *) & tp_stat, 0, sizeof(struct tp_stat));
340 * NAME: tp_soisdisconnecting()
342 * CALLED FROM:
343 * tp.trans
345 * FUNCTION and ARGUMENTS:
346 * Set state of the socket (so) to reflect that fact that we're disconnectING
348 * RETURNS: Nada
350 * SIDE EFFECTS:
352 * NOTES:
353 * This differs from the regular soisdisconnecting() in that the latter
354 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
355 * We don't want to set those flags because those flags will cause
356 * a SIGPIPE to be delivered in sosend() and we don't like that.
357 * If anyone else is sleeping on this socket, wake 'em up.
359 void
360 tp_soisdisconnecting(struct socket *so)
362 soisdisconnecting(so);
363 so->so_state &= ~SS_CANTSENDMORE;
364 #ifdef TP_PERF_MEAS
365 if (DOPERF(sototpcb(so))) {
366 struct tp_pcb *tpcb = sototpcb(so);
367 u_int fsufx, lsufx;
368 struct timeval now;
370 memcpy((void *) &fsufx, (void *) tpcb->tp_fsuffix,
371 sizeof(u_int));
372 memcpy((void *) &lsufx, (void *) tpcb->tp_lsuffix,
373 sizeof(u_int));
375 getmicrotime(&now);
376 tpmeas(tpcb->tp_lref, TPtime_close, &now, fsufx, lsufx,
377 tpcb->tp_fref);
378 tpcb->tp_perf_on = 0; /* turn perf off */
380 #endif
385 * NAME: tp_soisdisconnected()
387 * CALLED FROM:
388 * tp.trans
390 * FUNCTION and ARGUMENTS:
391 * Set state of the socket (so) to reflect that fact that we're disconnectED
392 * Set the state of the reference structure to closed, and
393 * recycle the suffix.
394 * Start a reference timer.
396 * RETURNS: Nada
398 * SIDE EFFECTS:
400 * NOTES:
401 * This differs from the regular soisdisconnected() in that the latter
402 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
403 * We don't want to set those flags because those flags will cause
404 * a SIGPIPE to be delivered in sosend() and we don't like that.
405 * If anyone else is sleeping on this socket, wake 'em up.
407 void
408 tp_soisdisconnected(struct tp_pcb *tpcb)
410 struct socket *so = tpcb->tp_sock;
412 soisdisconnecting(so);
413 so->so_state &= ~SS_CANTSENDMORE;
414 #ifdef TP_PERF_MEAS
415 if (DOPERF(tpcb)) {
416 struct tp_pcb *ttpcb = sototpcb(so);
417 u_int fsufx, lsufx;
418 struct timeval now;
420 /* CHOKE */
421 memcpy((void *) &fsufx, (void *) ttpcb->tp_fsuffix,
422 sizeof(u_int));
423 memcpy((void *) &lsufx, (void *) ttpcb->tp_lsuffix,
424 sizeof(u_int));
426 getmicrotime(&now);
427 tpmeas(ttpcb->tp_lref, TPtime_close,
428 &now, &lsufx, &fsufx, ttpcb->tp_fref);
429 tpcb->tp_perf_on = 0; /* turn perf off */
431 #endif
433 tpcb->tp_refstate = REF_FROZEN;
434 tp_recycle_tsuffix(tpcb);
435 tp_etimeout(tpcb, TM_reference, (int) tpcb->tp_refer_ticks);
439 * NAME: tp_freeref()
441 * CALLED FROM:
442 * tp.trans when the reference timer goes off, and
443 * from tp_attach() and tp_detach() when a tpcb is partially set up but not
444 * set up enough to have a ref timer set for it, and it's discarded
445 * due to some sort of error or an early close()
447 * FUNCTION and ARGUMENTS:
448 * Frees the reference represented by (r) for re-use.
450 * RETURNS: Nothing
452 * SIDE EFFECTS:
454 * NOTES: better be called at clock priority !!!!!
456 void
457 tp_freeref(RefNum n)
459 struct tp_ref *r = tp_ref + n;
460 struct tp_pcb *tpcb;
462 tpcb = r->tpr_pcb;
463 #ifdef ARGO_DEBUG
464 if (argo_debug[D_TIMER]) {
465 printf("tp_freeref called for ref %d pcb %p maxrefopen %d\n",
466 n, tpcb, tp_refinfo.tpr_maxopen);
468 #endif
469 #ifdef TPPT
470 if (tp_traceflags[D_TIMER]) {
471 tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb",
472 n, tp_refinfo.tpr_maxopen, tpcb, 0);
474 #endif
475 if (tpcb == 0)
476 return;
477 #ifdef ARGO_DEBUG
478 if (argo_debug[D_CONN]) {
479 printf("tp_freeref: CLEARING tpr_pcb %p\n", tpcb);
481 #endif
482 r->tpr_pcb = (struct tp_pcb *) 0;
483 tpcb->tp_refstate = REF_FREE;
485 for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--)
486 if (r->tpr_pcb)
487 break;
488 tp_refinfo.tpr_maxopen = r - tp_ref;
489 tp_refinfo.tpr_numopen--;
491 #ifdef ARGO_DEBUG
492 if (argo_debug[D_TIMER]) {
493 printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen);
495 #endif
499 * NAME: tp_getref()
501 * CALLED FROM:
502 * tp_attach()
504 * FUNCTION and ARGUMENTS:
505 * obtains the next free reference and allocates the appropriate
506 * ref structure, links that structure to (tpcb)
508 * RETURN VALUE:
509 * a reference number
510 * or TP_ENOREF
512 * SIDE EFFECTS:
514 * NOTES:
516 u_long
517 tp_getref(struct tp_pcb *tpcb)
519 struct tp_ref *r, *rlim;
520 int i;
521 void * obase;
522 unsigned size;
524 if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size)
525 for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size;
526 ++r < rlim;) /* tp_ref[0] is never used */
527 if (r->tpr_pcb == 0)
528 goto got_one;
529 /* else have to allocate more space */
531 obase = (void *) tp_refinfo.tpr_base;
532 size = tp_refinfo.tpr_size * sizeof(struct tp_ref);
533 r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT);
534 if (r == 0)
535 return (--tp_refinfo.tpr_numopen, TP_ENOREF);
536 tp_refinfo.tpr_base = tp_ref = r;
537 tp_refinfo.tpr_size *= 2;
538 memcpy(r, obase, size);
539 free(obase, M_PCB);
540 r = (struct tp_ref *)(size + (char *)r);
541 memset((void *) r, 0, size);
543 got_one:
544 r->tpr_pcb = tpcb;
545 tpcb->tp_refstate = REF_OPENING;
546 i = r - tp_refinfo.tpr_base;
547 if (tp_refinfo.tpr_maxopen < i)
548 tp_refinfo.tpr_maxopen = i;
549 return (u_long) i;
553 * NAME: tp_set_npcb()
555 * CALLED FROM:
556 * tp_attach(), tp_route_to()
558 * FUNCTION and ARGUMENTS:
559 * given a tpcb, allocate an appropriate lower-lever npcb, freeing
560 * any old ones that might need re-assigning.
563 tp_set_npcb(struct tp_pcb *tpcb)
565 struct socket *so = tpcb->tp_sock;
566 int error;
568 if (tpcb->tp_nlproto && tpcb->tp_npcb) {
569 short so_state = so->so_state;
570 so->so_state &= ~SS_NOFDREF;
571 (*tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
572 so->so_state = so_state;
574 tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice];
575 /* xx_pcballoc sets so_pcb */
576 error = (*tpcb->tp_nlproto->nlp_pcballoc)(so,
577 tpcb->tp_nlproto->nlp_pcblist);
578 tpcb->tp_npcb = so->so_pcb;
579 so->so_pcb = tpcb;
580 return (error);
583 * NAME: tp_attach()
585 * CALLED FROM:
586 * tp_usrreq, PRU_ATTACH
588 * FUNCTION and ARGUMENTS:
589 * given a socket (so) and a protocol family (dom), allocate a tpcb
590 * and ref structure, initialize everything in the structures that
591 * needs to be initialized.
593 * RETURN VALUE:
594 * 0 ok
595 * EINVAL if DEBUG(X) in is on and a disaster has occurred
596 * ENOPROTOOPT if TP hasn't been configured or if the
597 * socket wasn't created with tp as its protocol
598 * EISCONN if this socket is already part of a connection
599 * ETOOMANYREFS if ran out of tp reference numbers.
600 * E* whatever error is returned from soreserve()
601 * for from the network-layer pcb allocation routine
603 * SIDE EFFECTS:
605 * NOTES:
608 tp_attach(struct socket *so, int protocol)
610 struct tp_pcb *tpcb;
611 int error = 0;
612 int dom = so->so_proto->pr_domain->dom_family;
613 u_long lref;
615 #ifdef ARGO_DEBUG
616 if (argo_debug[D_CONN]) {
617 printf("tp_attach:dom 0x%x so %p ", dom, so);
619 #endif
620 #ifdef TPPT
621 if (tp_traceflags[D_CONN]) {
622 tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
624 #endif
626 if (so->so_pcb != NULL) {
627 return EISCONN; /* socket already part of a connection */
629 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0)
630 error = soreserve(so, tp_sendspace, tp_recvspace);
631 /* later an ioctl will allow reallocation IF still in closed state */
633 if (error)
634 goto bad2;
636 tpcb = malloc(sizeof(*tpcb), M_PCB, M_NOWAIT|M_ZERO);
637 if (tpcb == NULL) {
638 error = ENOBUFS;
639 goto bad2;
642 if (((lref = tp_getref(tpcb)) & TP_ENOREF) != 0) {
643 error = ETOOMANYREFS;
644 goto bad3;
646 tpcb->tp_lref = lref;
647 tpcb->tp_sock = so;
648 tpcb->tp_domain = dom;
649 tpcb->tp_rhiwat = so->so_rcv.sb_hiwat;
650 /* tpcb->tp_proto = protocol; someday maybe? */
651 if (protocol && protocol < ISOPROTO_TP4) {
652 tpcb->tp_netservice = ISO_CONS;
653 tpcb->tp_snduna = (SeqNum) - 1; /* kludge so the pseudo-ack
654 * from the CR/CC will
655 * generate correct fake-ack
656 * values */
657 } else {
658 tpcb->tp_netservice = (dom == AF_INET) ? IN_CLNS : ISO_CLNS;
659 /* the default */
661 tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
663 tpcb->tp_state = TP_CLOSED;
664 tpcb->tp_vers = TP_VERSION;
665 tpcb->tp_notdetached = 1;
668 * Spec says default is 128 octets, that is, if the tpdusize argument
669 * never appears, use 128. As the initiator, we will always "propose"
670 * the 2048 size, that is, we will put this argument in the CR
671 * always, but accept what the other side sends on the CC. If the
672 * initiator sends us something larger on a CR, we'll respond w/
673 * this. Our maximum is 4096. See tp_chksum.c comments.
675 tpcb->tp_cong_win =
676 tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
678 tpcb->tp_seqmask = TP_NML_FMT_MASK;
679 tpcb->tp_seqbit = TP_NML_FMT_BIT;
680 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
682 /* attach to a network-layer protoswitch */
683 if ((error = tp_set_npcb(tpcb)) != 0)
684 goto bad4;
685 ASSERT(tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
687 /* nothing to do for iso case */
688 if (dom == AF_INET) {
689 /* tp_set_npcb sets it */
690 KASSERT(so->so_pcb != NULL);
691 sotoinpcb(so)->inp_ppcb = (void *) tpcb;
694 return 0;
696 bad4:
697 #ifdef ARGO_DEBUG
698 if (argo_debug[D_CONN]) {
699 printf("BAD4 in tp_attach, so %p\n", so);
701 #endif
702 tp_freeref(tpcb->tp_lref);
704 bad3:
705 #ifdef ARGO_DEBUG
706 if (argo_debug[D_CONN]) {
707 printf("BAD3 in tp_attach, so %p\n", so);
709 #endif
711 free((void *) tpcb, M_PCB); /* never a cluster */
713 bad2:
714 #ifdef ARGO_DEBUG
715 if (argo_debug[D_CONN]) {
716 printf("BAD2 in tp_attach, so %p\n", so);
718 #endif
719 so->so_pcb = 0;
721 /* bad: */
722 #ifdef ARGO_DEBUG
723 if (argo_debug[D_CONN]) {
724 printf("BAD in tp_attach, so %p\n", so);
726 #endif
727 return error;
731 * NAME: tp_detach()
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)
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.
746 * RETURNS: Nada
748 * SIDE EFFECTS:
750 * NOTES:
751 * tp_soisdisconnected() was already when this is called
753 void
754 tp_detach(struct tp_pcb *tpcb)
756 struct socket *so = tpcb->tp_sock;
758 #ifdef ARGO_DEBUG
759 if (argo_debug[D_CONN]) {
760 printf("tp_detach(tpcb %p, so %p)\n",
761 tpcb, so);
763 #endif
764 #ifdef TPPT
765 if (tp_traceflags[D_CONN]) {
766 tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
767 tpcb, so, *(u_short *) (tpcb->tp_lsuffix), 0);
769 #endif
771 #ifdef ARGO_DEBUG
772 if (argo_debug[D_CONN]) {
773 printf("so_snd at %p so_rcv at %p\n", &so->so_snd, &so->so_rcv);
774 dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
775 printf("about to call LL detach, nlproto %p, nl_detach %p\n",
776 tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
778 #endif
780 if (tpcb->tp_Xsnd.sb_mb) {
781 printf("Unsent Xdata on detach; would panic");
782 sbflush(&tpcb->tp_Xsnd);
784 if (tpcb->tp_ucddata)
785 m_freem(tpcb->tp_ucddata);
787 #ifdef ARGO_DEBUG
788 if (argo_debug[D_CONN]) {
789 printf("reassembly info cnt %d rsyq %p\n",
790 tpcb->tp_rsycnt, tpcb->tp_rsyq);
792 #endif
793 if (tpcb->tp_rsyq)
794 tp_rsyflush(tpcb);
796 if (tpcb->tp_next) {
797 iso_remque(tpcb);
798 tpcb->tp_next = tpcb->tp_prev = 0;
800 tpcb->tp_notdetached = 0;
802 #ifdef ARGO_DEBUG
803 if (argo_debug[D_CONN]) {
804 printf("calling (...nlproto->...)(%p, so %p)\n",
805 tpcb->tp_npcb, so);
806 printf("so %p so_head %p, qlen %d q0len %d qlimit %d\n",
807 so, so->so_head,
808 so->so_q0len, so->so_qlen, so->so_qlimit);
810 #endif
812 (*tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
813 /* does an so->so_pcb = 0; sofree(so) */
815 #ifdef ARGO_DEBUG
816 if (argo_debug[D_CONN]) {
817 printf("after xxx_pcbdetach\n");
819 #endif
821 if (tpcb->tp_state == TP_LISTENING) {
822 struct tp_pcb **tt;
823 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
824 if (*tt == tpcb)
825 break;
826 if (*tt)
827 *tt = tpcb->tp_nextlisten;
828 else
829 printf("tp_detach from listen: should panic\n");
831 if (tpcb->tp_refstate == REF_OPENING) {
833 * no connection existed here so no reference timer will be
834 * called
836 #ifdef ARGO_DEBUG
837 if (argo_debug[D_CONN]) {
838 printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref);
840 #endif
842 tp_freeref(tpcb->tp_lref);
844 #ifdef TP_PERF_MEAS
846 * Get rid of the cluster mbuf allocated for performance
847 * measurements, if there is one. Note that tpcb->tp_perf_on says
848 * nothing about whether or not a cluster mbuf was allocated, so you
849 * have to check for a pointer to one (that is, we need the
850 * TP_PERF_MEASs around the following section of code, not the
851 * IFPERFs)
853 if (tpcb->tp_p_meas) {
854 struct mbuf *m = tpcb->tp_p_mbuf;
855 struct mbuf *n;
856 #ifdef ARGO_DEBUG
857 if (argo_debug[D_PERF_MEAS]) {
858 printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas);
860 #endif
861 free(tpcb->tp_p_meas, M_PCB);
862 tpcb->tp_p_meas = 0;
864 #endif /* TP_PERF_MEAS */
866 #ifdef ARGO_DEBUG
867 if (argo_debug[D_CONN]) {
868 printf("end of detach, NOT single, tpcb %p\n", tpcb);
870 #endif
871 /* free((void *)tpcb, M_PCB); WHere to put this ? */
874 struct que {
875 struct tp_pcb *next;
876 struct tp_pcb *prev;
877 } tp_bound_pcbs =
879 (struct tp_pcb *) & tp_bound_pcbs, (struct tp_pcb *) & tp_bound_pcbs
882 u_short tp_unique;
885 tp_tselinuse(int tlen, const char *tsel, struct sockaddr_iso *siso,
886 int reuseaddr)
888 struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
889 struct tp_pcb *t;
891 for (;;) {
892 if (b != (struct tp_pcb *) & tp_bound_pcbs) {
893 t = b;
894 b = t->tp_next;
895 } else if (l) {
896 t = l;
897 l = t->tp_nextlisten;
898 } else
899 break;
900 if (tlen == t->tp_lsuffixlen && memcmp(tsel, t->tp_lsuffix, tlen) == 0) {
901 if (t->tp_flags & TPF_GENERAL_ADDR) {
902 if (siso == 0 || reuseaddr == 0)
903 return 1;
904 } else if (siso) {
905 if (siso->siso_family == t->tp_domain &&
906 (*t->tp_nlproto->nlp_cmpnetaddr)(t->tp_npcb,
907 (struct sockaddr *) siso, TP_LOCAL))
908 return 1;
909 } else if (reuseaddr == 0)
910 return 1;
913 return 0;
919 tp_pcbbind(void *v, struct mbuf *nam, struct lwp *l)
921 struct tp_pcb *tpcb = v;
922 struct sockaddr_iso *siso = 0;
923 int tlen = 0, wrapped = 0;
924 const char *tsel = NULL;
925 u_short tutil;
927 if (tpcb->tp_state != TP_CLOSED)
928 return (EINVAL);
929 if (nam) {
930 siso = mtod(nam, struct sockaddr_iso *);
931 switch (siso->siso_family) {
932 default:
933 return (EAFNOSUPPORT);
934 #ifdef ISO
935 case AF_ISO:
936 tlen = siso->siso_tlen;
937 tsel = TSEL(siso);
938 if (siso->siso_nlen == 0)
939 siso = 0;
940 break;
941 #endif
942 #ifdef INET
943 case AF_INET:
944 tsel = (void *) & tutil;
945 if ((tutil = satosin(siso)->sin_port) != 0)
946 tlen = 2;
947 if (satosin(siso)->sin_addr.s_addr == 0)
948 siso = 0;
949 #endif
952 if (tpcb->tp_lsuffixlen == 0) {
953 if (tlen) {
954 if (tp_tselinuse(tlen, tsel, siso,
955 tpcb->tp_sock->so_options & SO_REUSEADDR))
956 return (EINVAL);
957 } else {
958 for (tsel = (void *) & tutil, tlen = 2;;) {
959 if (tp_unique++ < ISO_PORT_RESERVED ||
960 tp_unique > ISO_PORT_USERRESERVED) {
961 if (wrapped++)
962 return ESRCH;
963 tp_unique = ISO_PORT_RESERVED;
965 tutil = htons(tp_unique);
966 if (tp_tselinuse(tlen, tsel, siso, 0) == 0)
967 break;
969 if (siso)
970 switch (siso->siso_family) {
971 #ifdef ISO
972 case AF_ISO:
973 memcpy(WRITABLE_TSEL(siso), tsel, tlen);
974 siso->siso_tlen = tlen;
975 break;
976 #endif
977 #ifdef INET
978 case AF_INET:
979 satosin(siso)->sin_port = tutil;
980 #endif
983 memcpy(tpcb->tp_lsuffix, tsel, (tpcb->tp_lsuffixlen = tlen));
984 iso_insque(tpcb, &tp_bound_pcbs);
985 } else {
986 if (tlen || siso == 0)
987 return (EINVAL);
989 if (siso == 0) {
990 tpcb->tp_flags |= TPF_GENERAL_ADDR;
991 return (0);
993 return (*tpcb->tp_nlproto->nlp_pcbbind)(tpcb->tp_npcb, nam, l);