From: Keith Sklower Date: Thu, 15 Dec 1988 07:30:08 +0000 (-0800) Subject: date and time created 88/12/14 15:30:08 by sklower X-Git-Tag: BSD-4_3_Net_1-Snapshot-Development~82 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/c32c2ec1973bea9aeafddd0110308b1765b32e4e date and time created 88/12/14 15:30:08 by sklower SCCS-vsn: sys/netiso/tp_pcb.c 7.1 --- diff --git a/usr/src/sys/netiso/tp_pcb.c b/usr/src/sys/netiso/tp_pcb.c new file mode 100644 index 0000000000..6d2a82ab59 --- /dev/null +++ b/usr/src/sys/netiso/tp_pcb.c @@ -0,0 +1,913 @@ +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $ + * + * + * This is the initialization and cleanup stuff - + * for the tp machine in general as well as for the individual pcbs. + * tp_init() is called at system startup. tp_attach() and tp_getref() are + * called when a socket is created. tp_detach() and tp_freeref() + * are called during the closing stage and/or when the reference timer + * goes off. + * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific + * versions of soisconnect* + * and are called (obviously) during the closing phase. + * + */ + +#ifndef lint +static char *rcsid = "$Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $"; +#endif lint + +#include "argoxtwentyfive.h" +#include "types.h" +#include "param.h" +#include "mbuf.h" +#include "socket.h" +#include "socketvar.h" +#include "protosw.h" +#include "errno.h" +#include "time.h" +#include "../netiso/tp_param.h" +#include "../netiso/tp_timer.h" +#include "../netiso/tp_ip.h" +#include "../netiso/tp_stat.h" +#include "../netiso/tp_pcb.h" +#include "../netiso/argo_debug.h" +#include "../netiso/tp_tpdu.h" +#include "../netiso/tp_trace.h" +#include "../netiso/tp_meas.h" +#include "../netiso/tp_seq.h" +#include "../netiso/tp_clnp.h" + +/* list of reference structures */ +struct tp_ref tp_ref[N_TPREF]; + +struct tp_param tp_param = { + 1, /* configured */ +}; + +/* ticks are in units of: + * 500 nano-fortnights ;-) or + * 500 ms or + * 1/2 second + */ + +struct tp_conn_param tp_conn_param[] = { + /* ISO_CLNS: TP4 CONNECTION LESS */ + { + TP_NRETRANS, /* short p_Nretrans; */ + 20, /* 10 sec */ /* short p_dr_ticks; */ + + 20, /* 10 sec */ /* short p_cc_ticks; */ + 20, /* 10 sec */ /* short p_dt_ticks; */ + + 40, /* 20 sec */ /* short p_x_ticks; */ + 80, /* 40 sec */ /* short p_cr_ticks;*/ + + 240, /* 2 min */ /* short p_keepalive_ticks;*/ + 10, /* 5 sec */ /* short p_sendack_ticks; */ + + 600, /* 5 min */ /* short p_ref_ticks; */ + 360, /* 3 min */ /* short p_inact_ticks; */ + + (short) 100, /* short p_lcdtfract */ + (short) TP_SOCKBUFSIZE, /* short p_winsize */ + TP_TPDUSIZE, /* u_char p_tpdusize */ + + TPACK_WINDOW, /* 4 bits p_ack_strat */ + TPRX_USE_CW | TPRX_FASTSTART, + /* 4 bits p_rx_strat*/ + TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ + 1, /* 1 bit xtd format */ + 1, /* 1 bit xpd service */ + 1, /* 1 bit use_checksum */ + 0, /* 1 bit use net xpd */ + 0, /* 1 bit use rcc */ + 0, /* 1 bit use efc */ + 0, /* no disc indications */ + 0, /* don't change params */ + ISO_CLNS, /* p_netservice */ + }, + /* IN_CLNS: TP4 CONNECTION LESS */ + { + TP_NRETRANS, /* short p_Nretrans; */ + 20, /* 10 sec */ /* short p_dr_ticks; */ + + 20, /* 10 sec */ /* short p_cc_ticks; */ + 20, /* 10 sec */ /* short p_dt_ticks; */ + + 40, /* 20 sec */ /* short p_x_ticks; */ + 80, /* 40 sec */ /* short p_cr_ticks;*/ + + 240, /* 2 min */ /* short p_keepalive_ticks;*/ + 10, /* 5 sec */ /* short p_sendack_ticks; */ + + 600, /* 5 min */ /* short p_ref_ticks; */ + 360, /* 3 min */ /* short p_inact_ticks; */ + + (short) 100, /* short p_lcdtfract */ + (short) TP_SOCKBUFSIZE, /* short p_winsize */ + TP_TPDUSIZE, /* u_char p_tpdusize */ + + TPACK_WINDOW, /* 4 bits p_ack_strat */ + TPRX_USE_CW | TPRX_FASTSTART, + /* 4 bits p_rx_strat*/ + TP_CLASS_4, /* 5 bits p_class */ + 1, /* 1 bit xtd format */ + 1, /* 1 bit xpd service */ + 1, /* 1 bit use_checksum */ + 0, /* 1 bit use net xpd */ + 0, /* 1 bit use rcc */ + 0, /* 1 bit use efc */ + 0, /* no disc indications */ + 0, /* don't change params */ + IN_CLNS, /* p_netservice */ + }, + /* ISO_CONS: TP0 CONNECTION MODE */ + { + TP_NRETRANS, /* short p_Nretrans; */ + 0, /* n/a */ /* short p_dr_ticks; */ + + 40, /* 20 sec */ /* short p_cc_ticks; */ + 0, /* n/a */ /* short p_dt_ticks; */ + + 0, /* n/a */ /* short p_x_ticks; */ + 360, /* 3 min */ /* short p_cr_ticks;*/ + + 0, /* n/a */ /* short p_keepalive_ticks;*/ + 0, /* n/a */ /* short p_sendack_ticks; */ + + 600, /* for cr/cc to clear *//* short p_ref_ticks; */ + 0, /* n/a */ /* short p_inact_ticks; */ + + /* Use tp4 defaults just in case the user changes ONLY + * the class + */ + (short) 100, /* short p_lcdtfract */ + (short) TP0_SOCKBUFSIZE, /* short p_winsize */ + TP0_TPDUSIZE, /* 8 bits p_tpdusize */ + + 0, /* 4 bits p_ack_strat */ + 0, /* 4 bits p_rx_strat*/ + TP_CLASS_0, /* 5 bits p_class */ + 0, /* 1 bit xtd format */ + 0, /* 1 bit xpd service */ + 0, /* 1 bit use_checksum */ + 0, /* 1 bit use net xpd */ + 0, /* 1 bit use rcc */ + 0, /* 1 bit use efc */ + 0, /* no disc indications */ + 0, /* don't change params */ + ISO_CONS, /* p_netservice */ + }, + /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */ + { + TP_NRETRANS, /* short p_Nretrans; */ + 40, /* 20 sec */ /* short p_dr_ticks; */ + + 40, /* 20 sec */ /* short p_cc_ticks; */ + 80, /* 40 sec */ /* short p_dt_ticks; */ + + 120, /* 1 min */ /* short p_x_ticks; */ + 360, /* 3 min */ /* short p_cr_ticks;*/ + + 360, /* 3 min */ /* short p_keepalive_ticks;*/ + 20, /* 10 sec */ /* short p_sendack_ticks; */ + + 600, /* 5 min */ /* short p_ref_ticks; */ + 480, /* 4 min */ /* short p_inact_ticks; */ + + (short) 100, /* short p_lcdtfract */ + (short) TP0_SOCKBUFSIZE, /* short p_winsize */ + TP0_TPDUSIZE, /* u_char p_tpdusize */ + + TPACK_WINDOW, /* 4 bits p_ack_strat */ + TPRX_USE_CW , /* No fast start */ + /* 4 bits p_rx_strat*/ + TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ + 0, /* 1 bit xtd format */ + 1, /* 1 bit xpd service */ + 1, /* 1 bit use_checksum */ + 0, /* 1 bit use net xpd */ + 0, /* 1 bit use rcc */ + 0, /* 1 bit use efc */ + 0, /* no disc indications */ + 0, /* don't change params */ + ISO_COSNS, /* p_netservice */ + }, +}; + +#ifdef INET +int in_putnetaddr(); +int in_getnetaddr(); +int in_putsufx(); +int in_getsufx(); +int in_recycle_tsuffix(); +int tpip_mtu(); +int in_pcbbind(); +int in_pcbconnect(); +int in_pcbdisconnect(); +int in_pcbdetach(); +int in_pcballoc(); +int tpip_output(); +int tpip_output_dg(); +struct inpcb tp_inpcb; +#endif INET +#ifdef ISO +int iso_putnetaddr(); +int iso_getnetaddr(); +int iso_putsufx(); +int iso_getsufx(); +int iso_recycle_tsuffix(); +int tpclnp_mtu(); +int iso_pcbbind(); +int iso_pcbconnect(); +int iso_pcbdisconnect(); +int iso_pcbdetach(); +int iso_pcballoc(); +int tpclnp_output(); +int tpclnp_output_dg(); +int iso_nlctloutput(); +struct isopcb tp_isopcb; +#endif ISO +#if NARGOXTWENTYFIVE > 0 +int iso_putnetaddr(); +int iso_getnetaddr(); +int iso_putsufx(); +int iso_getsufx(); +int iso_recycle_tsuffix(); +int tpcons_mtu(); +int iso_pcbbind(); +int iso_pcbconnect(); +int iso_pcbdisconnect(); +int iso_pcbdetach(); +int iso_pcballoc(); +int tpcons_output(); +int tpcons_output_dg(); +struct isopcb tp_isopcb; +#endif NARGOXTWENTYFIVE + +struct nl_protosw nl_protosw[] = { + /* ISO_CLNS */ +#ifdef ISO + { AF_ISO, iso_putnetaddr, iso_getnetaddr, + iso_putsufx, iso_getsufx, + iso_recycle_tsuffix, + tpclnp_mtu, iso_pcbbind, iso_pcbconnect, + iso_pcbdisconnect, iso_pcbdetach, + iso_pcballoc, + tpclnp_output, tpclnp_output_dg, iso_nlctloutput, + (caddr_t) &tp_isopcb, + }, +#endif ISO + /* IN_CLNS */ +#ifdef INET + { AF_INET, in_putnetaddr, in_getnetaddr, + in_putsufx, in_getsufx, + in_recycle_tsuffix, + tpip_mtu, in_pcbbind, in_pcbconnect, + in_pcbdisconnect, in_pcbdetach, + in_pcballoc, + tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL, + (caddr_t) &tp_inpcb, + }, +#endif INET + /* ISO_CONS */ +#ifdef ISO +#if NARGOXTWENTYFIVE > 0 + { AF_ISO, iso_putnetaddr, iso_getnetaddr, + iso_putsufx, iso_getsufx, + iso_recycle_tsuffix, + tpcons_mtu, iso_pcbbind, iso_pcbconnect, + iso_pcbdisconnect, iso_pcbdetach, + iso_pcballoc, + tpcons_output, tpcons_output_dg, iso_nlctloutput, + (caddr_t) &tp_isopcb, + }, +#endif NARGOXTWENTYFIVE +#endif ISO + { 0, 0, 0, + 0, 0, + 0, + 0, 0, 0, + 0, 0, + 0, + 0, 0, 0, + (caddr_t) 0, + } +}; + +/* + * NAME: tp_init() + * + * CALLED FROM: + * autoconf through the protosw structure + * + * FUNCTION: + * initialize tp machine + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ +void +tp_init() +{ + static int init_done=0; + void tp_timerinit(); + + if (init_done++) + return; + +#ifndef lint + if ( (sizeof(struct tp_pcb) >= MLEN) || (sizeof(struct tp_pcb_aux) >= MLEN) ){ + tp_param.tpp_configed = 0; + printf( + "TP not configured !!! pcb (0x%x, %d) or aux (0x%x, %d) too big!\n", + sizeof(struct tp_pcb), sizeof(struct tp_pcb), + sizeof(struct tp_pcb_aux), sizeof(struct tp_pcb_aux)); + printf("MLEN (0x%x, %d)\n", MLEN, MLEN); + } +#endif lint + + /* FOR INET */ + tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb; + /* FOR ISO */ + tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb; + + tp_timerinit(); + bzero((caddr_t)&tp_stat, sizeof(struct tp_stat)); +} + +/* + * NAME: tp_soisdisconnecting() + * + * CALLED FROM: + * tp.trans + * + * FUNCTION and ARGUMENTS: + * Set state of the socket (so) to reflect that fact that we're disconnectING + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + * This differs from the regular soisdisconnecting() in that the latter + * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. + * We don't want to set those flags because those flags will cause + * a SIGPIPE to be delivered in sosend() and we don't like that. + * If anyone else is sleeping on this socket, wake 'em up. + */ +void +tp_soisdisconnecting(so) + register struct socket *so; +{ + so->so_state &= ~SS_ISCONNECTING; + so->so_state |= SS_ISDISCONNECTING; + if (so->so_head) { + if (!soqremque(so, 0) && !soqremque(so, 1)) + panic("tp_soisdisconnecting"); + so->so_head = 0; + } + wakeup((caddr_t)&so->so_timeo); + sowwakeup(so); + sorwakeup(so); + IFPERF(sototpcb(so)) + register struct tp_pcb *tpcb = sototpcb(so); + u_int fsufx, lsufx; + + bcopy ( tpcb->tp_fsuffix, &fsufx, sizeof(u_int) ); + bcopy ( tpcb->tp_lsuffix, &lsufx, sizeof(u_int) ); + + tpmeas( tpcb->tp_lref, TPtime_close, + &time, fsufx, lsufx, tpcb->tp_fref); + tpcb->tp_perf_on = 0; /* turn perf off */ + ENDPERF +} + + +/* + * NAME: tp_soisdisconnected() + * + * CALLED FROM: + * tp.trans + * + * FUNCTION and ARGUMENTS: + * Set state of the socket (so) to reflect that fact that we're disconnectED + * Set the state of the reference structure to closed, and + * recycle the suffix. + * Start a reference timer. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + * This differs from the regular soisdisconnected() in that the latter + * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. + * We don't want to set those flags because those flags will cause + * a SIGPIPE to be delivered in sosend() and we don't like that. + * If anyone else is sleeping on this socket, wake 'em up. + */ +void +tp_soisdisconnected(tpcb) + register struct tp_pcb *tpcb; +{ + register struct socket *so = tpcb->tp_sock; + + so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); + if (so->so_head) { + if (!soqremque(so, 0) && !soqremque(so, 1)) + panic("tp_soisdisconnected"); + so->so_head = 0; + } + wakeup((caddr_t)&so->so_timeo); + sowwakeup(so); + sorwakeup(so); + IFPERF(sototpcb(so)) + register struct tp_pcb *tpcb = sototpcb(so); + u_int fsufx, lsufx; + + /* CHOKE */ + bcopy ( tpcb->tp_fsuffix, &fsufx, sizeof(u_int) ); + bcopy ( tpcb->tp_lsuffix, &lsufx, sizeof(u_int) ); + + tpmeas( tpcb->tp_lref, TPtime_close, + &time, &lsufx, &fsufx, tpcb->tp_fref); + tpcb->tp_perf_on = 0; /* turn perf off */ + ENDPERF + + tpcb->tp_refp->tpr_state = REF_FROZEN; + tp_recycle_tsuffix( tpcb ); + tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks); +} + +int tp_maxrefopen; /* highest reference # of the set of open tp connections */ + +/* + * NAME: tp_freeref() + * + * CALLED FROM: + * tp.trans when the reference timer goes off, and + * from tp_attach() and tp_detach() when a tpcb is partially set up but not + * set up enough to have a ref timer set for it, and it's discarded + * due to some sort of error or an early close() + * + * FUNCTION and ARGUMENTS: + * Frees the reference represented by (r) for re-use. + * + * RETURNS: Nothing + * + * SIDE EFFECTS: + * + * NOTES: better be called at clock priority !!!!! + */ +void +tp_freeref(r) + register struct tp_ref *r; +{ + IFDEBUG(D_TIMER) + printf("tp_freeref called for ref %d maxrefopen %d\n", + r - tp_ref, tp_maxrefopen); + ENDDEBUG + IFTRACE(D_TIMER) + tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen", + r - tp_ref, tp_maxrefopen, 0, 0); + ENDTRACE + r->tpr_state = REF_FREE; + IFDEBUG(D_CONN) + printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb); + ENDDEBUG + r->tpr_pcb = (struct tp_pcb *)0; + + r = &tp_ref[tp_maxrefopen]; + + while( tp_maxrefopen > 0 ) { + if(r->tpr_state ) + break; + tp_maxrefopen--; + r--; + } + IFDEBUG(D_TIMER) + printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen); + ENDDEBUG +} + +/* + * NAME: tp_getref() + * + * CALLED FROM: + * tp_attach() + * + * FUNCTION and ARGUMENTS: + * obtains the next free reference and allocates the appropriate + * ref structure, links that structure to (tpcb) + * + * RETURN VALUE: + * a reference number + * or TP_ENOREF + * + * SIDE EFFECTS: + * + * NOTES: + */ +static RefNum +tp_getref(tpcb) + register struct tp_pcb *tpcb; +{ + register struct tp_ref *r = tp_ref; + register int i=1; + + r++; /* tp_ref[0] is never used */ + + /* REF_FREE is zero */ + while( r->tpr_state ) { + r++; + if ( i == N_TPREF ) { + return TP_ENOREF; + } + i++; + } + r->tpr_state = REF_OPENING; + if (tp_maxrefopen < i) + tp_maxrefopen = i; + r->tpr_pcb = tpcb; + tpcb->tp_refp = r; + + return i; +} + +/* + * NAME: tp_attach() + * + * CALLED FROM: + * tp_usrreq, PRU_ATTACH + * + * FUNCTION and ARGUMENTS: + * given a socket (so) and a protocol family (dom), allocate a tpcb + * and ref structure, initialize everything in the structures that + * needs to be initialized. + * + * RETURN VALUE: + * 0 ok + * EINVAL if DEBUG(X) in is on and a disaster has occurred + * ENOPROTOOPT if TP hasn't been configured or if the + * socket wasn't created with tp as its protocol + * EISCONN if this socket is already part of a connection + * ETOOMANYREFS if ran out of tp reference numbers. + * E* whatever error is returned from soreserve() + * for from the network-layer pcb allocation routine + * + * SIDE EFFECTS: + * + * NOTES: + */ +int +tp_attach(so,dom) + struct socket *so; + int dom; +{ + register struct tp_pcb *tpcb; + register struct mbuf *m; + register struct mbuf *p; + int error; + int protocol = so->so_proto->pr_protocol; + extern struct tp_conn_param tp_conn_param[]; + + IFDEBUG(D_CONN) + printf("tp_attach:dom 0x%x so 0x%x ", dom, so); + ENDDEBUG + IFTRACE(D_CONN) + tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); + ENDTRACE + if ( ! tp_param.tpp_configed ) { + error = ENOPROTOOPT; /* protocol not available */ + goto bad2; + } + + if (so->so_pcb != NULL) { + return EISCONN; /* socket already part of a connection*/ + } + + error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE); + /* later an ioctl will allow reallocation IF still in closed state */ + + if (error) + goto bad2; + + MGET(m, M_DONTWAIT, TPMT_PCB); /* for tpcb, main half */ + if (m == NULL) { + error = ENOBUFS; + goto bad2; + } + + tpcb = mtod( m, struct tp_pcb * ); + bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); + + MGET(p, M_DONTWAIT, TPMT_PCB); /* for the tpcb, auxilliary half */ + if (p == NULL) { + error = ENOBUFS; + m_free(m); /* which is tpcb */ + goto bad2; + } else { + p->m_len = sizeof(struct tp_pcb_aux); + p->m_act = MNULL; + tpcb->tp_aux = mtod(p, struct tp_pcb_aux *); + bzero( (caddr_t)tpcb->tp_aux, sizeof (struct tp_pcb_aux) ); + } + + if ( ((tpcb->tp_lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { + error = ETOOMANYREFS; + goto bad3; + } + tpcb->tp_sock = so; + tpcb->tp_domain = dom; + if (protocoltp_netservice = ISO_CONS; + tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC + * will generate correct fake-ack values + */ + } else { + tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; + /* the default */ + } + tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; + + tpcb->tp_cong_win = 1; + tpcb->tp_state = TP_CLOSED; + tpcb->tp_vers = TP_VERSION; + + /* Spec says default is 128 octets, + * that is, if the tpdusize argument never appears, use 128. + * As the initiator, we will always "propose" the 2048 + * size, that is, we will put this argument in the CR + * always, but accept what the other side sends on the CC. + * If the initiator sends us something larger on a CR, + * we'll respond w/ this. + * Our maximum is 4096. See tp_chksum.c comments. + */ + tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; + + tpcb->tp_seqmask = TP_NML_FMT_MASK; + tpcb->tp_seqbit = TP_NML_FMT_BIT; + tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; + tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */ + tpcb->tp_s_subseq = 0; + + /* attach to a network-layer protoswitch */ + /* new way */ + tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice]; + ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); +#ifdef notdef + /* OLD WAY */ + /* TODO: properly, this search would be on the basis of + * domain,netservice or just netservice only (if you have + * IN_CLNS, ISO_CLNS, and ISO_CONS) + */ + tpcb->tp_nlproto = nl_protosw; + while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain ) { + if( tpcb->tp_nlproto->nlp_afamily == 0 ) { + error = EAFNOSUPPORT; + goto bad4; + } + tpcb->tp_nlproto ++; + } +#endif notdef + + /* xx_pcballoc sets so_pcb */ + if ( error = (tpcb->tp_nlproto->nlp_pcballoc) ( + so, tpcb->tp_nlproto->nlp_pcblist ) ) { + goto bad4; + } + + if( dom == AF_INET ) + sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; + /* nothing to do for iso case */ + + tpcb->tp_npcb = (caddr_t) so->so_pcb; + so->so_tpcb = (caddr_t) tpcb; + + return 0; + +bad4: + IFDEBUG(D_CONN) + printf("BAD4 in tp_attach, so 0x%x\n", so); + ENDDEBUG + tp_freeref(tpcb->tp_refp); + +bad3: + IFDEBUG(D_CONN) + printf("BAD3 in tp_attach, so 0x%x\n", so); + ENDDEBUG + + m_free(dtom(tpcb)); /* never a cluster */ + m_free(dtom(tpcb->tp_aux)); /* never a cluster */ + +bad2: + IFDEBUG(D_CONN) + printf("BAD2 in tp_attach, so 0x%x\n", so); + ENDDEBUG + so->so_pcb = 0; + so->so_tpcb = 0; + sofree(so); + +bad: + IFDEBUG(D_CONN) + printf("BAD in tp_attach, so 0x%x\n", so); + ENDDEBUG + return error; +} + +/* + * NAME: tp_detach() + * + * CALLED FROM: + * tp.trans, on behalf of a user close request + * and when the reference timer goes off + * (if the disconnect was initiated by the protocol entity + * rather than by the user) + * + * FUNCTION and ARGUMENTS: + * remove the tpcb structure from the list of active or + * partially active connections, recycle all the mbufs + * associated with the pcb, ref structure, sockbufs, etc. + * Only free the ref structure if you know that a ref timer + * wasn't set for this tpcb. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + * tp_soisdisconnected() was already when this is called + */ +void +tp_detach(tpcb) + register struct tp_pcb *tpcb; +{ + void tp_freeref(); + register struct socket *so = tpcb->tp_sock; + + IFDEBUG(D_CONN) + printf("tp_detach(tpcb 0x%x, so 0x%x) freelist 0%x\n", + tpcb,so, mfree); + ENDDEBUG + IFTRACE(D_CONN) + tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", + tpcb, so, *(int *)(tpcb->tp_lsuffix), 0); + ENDTRACE + + if (so->so_head) { + if (!soqremque(so, 0) && !soqremque(so, 1)) + panic("sofree dq"); + so->so_head = 0; + } + + IFDEBUG(D_CONN) + printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n", + tpcb->tp_snduna_rtc, + tpcb->tp_rcvnxt_rtc); + ENDDEBUG + +#define FREE_RTC_LIST(XXX)\ + { register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\ + xxs = xxr->tprt_next;\ + m_freem( xxr->tprt_data );\ + m_free( dtom(xxr) ); xxr = xxs; }\ + XXX = (struct tp_rtc *)0;\ + } + + FREE_RTC_LIST( tpcb->tp_snduna_rtc ); + tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0; + + FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc ); + +#undef FREE_RTC_LIST + + IFDEBUG(D_CONN) + printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", + so->so_pcb, so); + printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", + so, so->so_head, + so->so_q0len, so->so_qlen, so->so_qlimit); + ENDDEBUG + + if ( tpcb->tp_flags & (TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT ) ) { + ASSERT( so->so_snd.sb_cc != 0 ); + IFDEBUG(D_CONN) + printf( + "detach, flags 0x%x doing sbdrop on so_snd, mb 0x%x cc 0x%x\n", + tpcb->tp_flags, so->so_snd.sb_mb, so->so_snd.sb_cc); + dump_mbuf( so->so_snd.sb_mb, "detach so snd: \n"); + ENDDEBUG + if ( so->so_snd.sb_cc != 0 ) + sbdrop( &so->so_snd, so->so_snd.sb_cc); + tpcb->tp_flags &= ~(TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT); + } + if ( tpcb->tp_flags & (TPF_DISC_DATA_IN | TPF_CONN_DATA_IN ) ) { + ASSERT( tpcb->tp_Xrcv.sb_cc != 0 ); + IFDEBUG(D_CONN) + printf( + "detach, flags 0x%x doing sbdrop on tp_Xrcv, mb 0x%x cc 0x%x\n", + tpcb->tp_flags, tpcb->tp_Xrcv.sb_mb, tpcb->tp_Xrcv.sb_cc); + dump_mbuf( tpcb->tp_Xrcv.sb_mb, "detach Xrcv: \n"); + ENDDEBUG + if( tpcb->tp_Xrcv.sb_cc != 0 ) + sbdrop( &tpcb->tp_Xrcv, tpcb->tp_Xrcv.sb_cc); + tpcb->tp_flags &= ~(TPF_CONN_DATA_IN | TPF_DISC_DATA_IN); + } + + IFDEBUG(D_CONN) + printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); + dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); + printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", + tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); + ENDDEBUG + + if ((tpcb->tp_nlproto->nlp_pcbdetach) ( + (struct inpcb *)so->so_pcb) /* does an sofree(so) */ < 0 ) { +#ifdef ARGO_DEBUG + printf("tp: nl_detach failed: tpcb 0x%x so 0x%x\n", tpcb, so); +#endif ARGO_DEBUG + } + + IFDEBUG(D_CONN) + printf("after xxx_pcbdetach\n"); + ENDDEBUG + + if( tpcb->tp_refp->tpr_state == REF_OPENING ) { + /* no connection existed here so no reference timer will be called */ + IFDEBUG(D_CONN) + printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref, + tpcb->tp_refp - &tp_ref[0]); + ENDDEBUG + + tp_freeref(tpcb->tp_refp); + } + + so->so_tpcb = (caddr_t)0; + + /* + * Get rid of the cluster mbuf allocated for performance measurements, if + * there is one. Note that tpcb->tp_perf_on says nothing about whether or + * not a cluster mbuf was allocated, so you have to check for a pointer + * to one (that is, we need the TP_PERF_MEASs around the following section + * of code, not the IFPERFs) + */ +#ifdef TP_PERF_MEAS + if( tpcb->tp_p_meas != (struct tp_pmeas *)0 ) { + register struct mbuf *n; + + n = MTOCL((struct mbuf *)(tpcb->tp_p_meas)); + IFDEBUG(D_PERF_MEAS) + printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); + printf("n = 0x%x\n", n); + ENDDEBUG + if (--mclrefcnt[mtocl(n)] == 0) { + n->m_next = mclfree; + mclfree = n; + mbstat.m_clfree++; + } + } +#endif TP_PERF_MEAS + + IFDEBUG(D_CONN) + printf( +"end of detach, NOT single, tpcb 0x%x, dtom(tpcb) 0x%x tp_aux 0x%x dtom(aux) 0x%x\n", + tpcb, dtom(tpcb), tpcb->tp_aux, dtom(tpcb->tp_aux)); + ENDDEBUG + m_free(dtom(tpcb->tp_aux)); + m_free(dtom(tpcb)); +}