make kernel includes standard
[unix-history] / usr / src / sys / netiso / tp_pcb.c
index c9ba123..e864c8c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)tp_pcb.c    7.12 (Berkeley) %G%
+ *     @(#)tp_pcb.c    7.25 (Berkeley) %G%
  */
 
 /***********************************************************
  */
 
 /***********************************************************
@@ -52,29 +52,27 @@ SOFTWARE.
  *
  */
 
  *
  */
 
-#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 "argo_debug.h"
-#include "tp_param.h"
-#include "tp_timer.h"
-#include "tp_ip.h"
-#include "tp_stat.h"
-#include "tp_pcb.h"
-#include "tp_tpdu.h"
-#include "tp_trace.h"
-#include "tp_meas.h"
-#include "tp_seq.h"
-#include "tp_clnp.h"
-
-struct tp_param tp_param = {
-       1,                              /*  configured          */
-};
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+
+#include <netiso/argo_debug.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/tp_tpdu.h>
+#include <netiso/tp_trace.h>
+#include <netiso/tp_meas.h>
+#include <netiso/tp_seq.h>
+#include <netiso/tp_clnp.h>
 
 /* ticks are in units of: 
  * 500 nano-fortnights ;-) or
 
 /* ticks are in units of: 
  * 500 nano-fortnights ;-) or
@@ -327,6 +325,9 @@ struct nl_protosw nl_protosw[] = {
        { 0 }
 };
 
        { 0 }
 };
 
+u_long tp_sendspace = 1024 * 4;
+u_long tp_recvspace = 1024 * 4;
+
 /*
  * NAME:  tp_init()
  *
 /*
  * NAME:  tp_init()
  *
@@ -434,7 +435,7 @@ tp_soisdisconnected(tpcb)
 
        soisdisconnecting(so);
        so->so_state &= ~SS_CANTSENDMORE;
 
        soisdisconnecting(so);
        so->so_state &= ~SS_CANTSENDMORE;
-       IFPERF(sototpcb(so))
+       IFPERF(tpcb)
                register struct tp_pcb *ttpcb = sototpcb(so);
                u_int   fsufx, lsufx;
 
                register struct tp_pcb *ttpcb = sototpcb(so);
                u_int   fsufx, lsufx;
 
@@ -447,13 +448,11 @@ tp_soisdisconnected(tpcb)
                tpcb->tp_perf_on = 0; /* turn perf off */
        ENDPERF
 
                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);
+       tpcb->tp_refstate = REF_FROZEN;
+       tp_recycle_tsuffix(tpcb);
+       tp_etimeout(tpcb, TM_reference, (int)tpcb->tp_refer_ticks);
 }
 
 }
 
-int tp_maxrefopen;  /* highest reference # of the set of open tp connections */
-
 /*
  * NAME:       tp_freeref()
  *
 /*
  * NAME:       tp_freeref()
  *
@@ -473,33 +472,37 @@ int tp_maxrefopen;  /* highest reference # of the set of open tp connections */
  * NOTES:      better be called at clock priority !!!!!
  */
 void
  * NOTES:      better be called at clock priority !!!!!
  */
 void
-tp_freeref(r)
-       register struct tp_ref *r;
+tp_freeref(n)
+RefNum n;
 {
 {
+       register struct tp_ref *r = tp_ref + n;
+       register struct tp_pcb *tpcb;
+
+       tpcb = r->tpr_pcb;
        IFDEBUG(D_TIMER)
        IFDEBUG(D_TIMER)
-               printf("tp_freeref called for ref %d maxrefopen %d\n", 
-               r - tp_ref, tp_maxrefopen);
+               printf("tp_freeref called for ref %d pcb %x maxrefopen %d\n", 
+               n, tpcb, tp_refinfo.tpr_maxopen);
        ENDDEBUG
        IFTRACE(D_TIMER)
        ENDDEBUG
        IFTRACE(D_TIMER)
-               tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen",
-               r - tp_ref, tp_maxrefopen, 0, 0);
+               tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb",
+               n, tp_refinfo.tpr_maxopen, tpcb, 0);
        ENDTRACE
        ENDTRACE
-       r->tpr_state = REF_FREE;
+       if (tpcb == 0)
+               return;
        IFDEBUG(D_CONN)
        IFDEBUG(D_CONN)
-               printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb);
+               printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", tpcb);
        ENDDEBUG
        r->tpr_pcb = (struct tp_pcb *)0;
        ENDDEBUG
        r->tpr_pcb = (struct tp_pcb *)0;
+       tpcb->tp_refstate = REF_FREE;
 
 
-       r = &tp_ref[tp_maxrefopen];
-
-       while( tp_maxrefopen > 0 ) {
-               if(r->tpr_state )
+       for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--)
+               if (r->tpr_pcb)
                        break;
                        break;
-               tp_maxrefopen--;
-               r--;
-       }
+       tp_refinfo.tpr_maxopen = r - tp_ref;
+       tp_refinfo.tpr_numopen--;
+
        IFDEBUG(D_TIMER)
        IFDEBUG(D_TIMER)
-               printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen);
+               printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen);
        ENDDEBUG
 }
 
        ENDDEBUG
 }
 
@@ -521,27 +524,72 @@ tp_freeref(r)
  *
  * NOTES:
  */
  *
  * NOTES:
  */
-static RefNum
+u_long
 tp_getref(tpcb) 
        register struct tp_pcb *tpcb;
 {
 tp_getref(tpcb) 
        register struct tp_pcb *tpcb;
 {
-       register struct tp_ref  *r = tp_ref; /* tp_ref[0] is never used */
-       register int                    i=1;
-
-
-       while ((++r)->tpr_state != REF_FREE) {
-               if (++i == N_TPREF)
-                       return TP_ENOREF;
-       }
-       r->tpr_state = REF_OPENING;
-       if (tp_maxrefopen < i) 
-               tp_maxrefopen = i;
+       register struct tp_ref  *r, *rlim;
+       register int                    i;
+       caddr_t obase;
+       unsigned size;
+
+       if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size)
+               for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size;
+                                                               ++r < rlim; )   /* tp_ref[0] is never used */
+                       if (r->tpr_pcb == 0)
+                               goto got_one;
+       /* else have to allocate more space */
+
+       obase = (caddr_t)tp_refinfo.tpr_base;
+       size = tp_refinfo.tpr_size * sizeof(struct tp_ref);
+       r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT);
+       if (r == 0)
+               return (--tp_refinfo.tpr_numopen, TP_ENOREF);
+       tp_refinfo.tpr_base = tp_ref = r;
+       tp_refinfo.tpr_size *= 2;
+       bcopy(obase, (caddr_t)r, size);
+       free(obase, M_PCB);
+       r = (struct tp_ref *)(size + (caddr_t)r);
+       bzero((caddr_t)r, size);
+
+got_one:
        r->tpr_pcb = tpcb;
        r->tpr_pcb = tpcb;
-       tpcb->tp_refp = r;
-
-       return i;
+       tpcb->tp_refstate = REF_OPENING;
+       i = r - tp_refinfo.tpr_base;
+       if (tp_refinfo.tpr_maxopen < i) 
+               tp_refinfo.tpr_maxopen = i;
+       return (u_long)i;
 }
 
 }
 
+/*
+ * NAME: tp_set_npcb()
+ *
+ * CALLED FROM:
+ *     tp_attach(), tp_route_to()
+ *
+ * FUNCTION and ARGUMENTS:
+ *  given a tpcb, allocate an appropriate lower-lever npcb, freeing
+ *  any old ones that might need re-assigning.
+ */
+tp_set_npcb(tpcb)
+register struct tp_pcb *tpcb;
+{
+       register struct socket *so = tpcb->tp_sock;
+       int error;
+
+       if (tpcb->tp_nlproto && tpcb->tp_npcb) {
+               short so_state = so->so_state;
+               so->so_state &= ~SS_NOFDREF;
+               tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb);
+               so->so_state = so_state;
+       }
+       tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice];
+       /* xx_pcballoc sets so_pcb */
+       error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist);
+       tpcb->tp_npcb = so->so_pcb;
+       so->so_pcb = (caddr_t)tpcb;
+       return (error);
+}
 /*
  * NAME: tp_attach()
  *
 /*
  * NAME: tp_attach()
  *
@@ -567,13 +615,14 @@ tp_getref(tpcb)
  *
  * NOTES:
  */
  *
  * NOTES:
  */
-tp_attach(so, dom)
-       struct socket   *so;
-       int                     dom;
+tp_attach(so, protocol)
+       struct socket                   *so;
+       int                                     protocol;
 {
        register struct tp_pcb  *tpcb;
 {
        register struct tp_pcb  *tpcb;
-       int                                     error;
-       int                                     protocol = so->so_proto->pr_protocol;
+       int                                     error = 0;
+       int                                     dom = so->so_proto->pr_domain->dom_family;
+       u_long                                  lref;
        extern struct tp_conn_param tp_conn_param[];
 
        IFDEBUG(D_CONN)
        extern struct tp_conn_param tp_conn_param[];
 
        IFDEBUG(D_CONN)
@@ -582,16 +631,13 @@ tp_attach(so, dom)
        IFTRACE(D_CONN)
                tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
        ENDTRACE
        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*/
        }
 
 
        if (so->so_pcb != NULL) { 
                return EISCONN; /* socket already part of a connection*/
        }
 
-       error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE);
+       if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0)
+               error = soreserve(so, tp_sendspace, tp_recvspace);
                /* later an ioctl will allow reallocation IF still in closed state */
 
        if (error)
                /* later an ioctl will allow reallocation IF still in closed state */
 
        if (error)
@@ -604,13 +650,16 @@ tp_attach(so, dom)
        }
        bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
 
        }
        bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) );
 
-       if ( ((tpcb->tp_lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) { 
+       if ( ((lref = tp_getref(tpcb)) &  TP_ENOREF) != 0 ) { 
                error = ETOOMANYREFS; 
                goto bad3;
        }
                error = ETOOMANYREFS; 
                goto bad3;
        }
+       tpcb->tp_lref = lref;
        tpcb->tp_sock =  so;
        tpcb->tp_domain = dom;
        tpcb->tp_sock =  so;
        tpcb->tp_domain = dom;
-       if (protocol<ISOPROTO_TP4) {
+       tpcb->tp_rhiwat = so->so_rcv.sb_hiwat;
+       /* tpcb->tp_proto = protocol; someday maybe? */
+       if (protocol && protocol<ISOPROTO_TP4) {
                tpcb->tp_netservice = ISO_CONS;
                tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
                                                                 * will generate correct fake-ack values
                tpcb->tp_netservice = ISO_CONS;
                tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC
                                                                 * will generate correct fake-ack values
@@ -621,9 +670,9 @@ tp_attach(so, dom)
        }
        tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
 
        }
        tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
 
-       tpcb->tp_cong_win = 1;  
        tpcb->tp_state = TP_CLOSED;
        tpcb->tp_vers  = TP_VERSION;
        tpcb->tp_state = TP_CLOSED;
        tpcb->tp_vers  = TP_VERSION;
+       tpcb->tp_notdetached = 1;
 
                   /* Spec says default is 128 octets,
                        * that is, if the tpdusize argument never appears, use 128.
 
                   /* Spec says default is 128 octets,
                        * that is, if the tpdusize argument never appears, use 128.
@@ -634,46 +683,21 @@ tp_attach(so, dom)
                        * we'll respond w/ this.
                        * Our maximum is 4096.  See tp_chksum.c comments.
                        */
                        * we'll respond w/ this.
                        * Our maximum is 4096.  See tp_chksum.c comments.
                        */
-       tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
+       tpcb->tp_cong_win = 
+               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_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 */
 
        /* 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 ) ) {
+       if ( error =  tp_set_npcb(tpcb))
                goto bad4;
                goto bad4;
-       }
+       ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
 
 
+       /* nothing to do for iso case */
        if( dom == AF_INET )
                sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
        if( dom == AF_INET )
                sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
-               /* nothing to do for iso case */
-
-       tpcb->tp_npcb = so->so_pcb;
-       so->so_pcb = (caddr_t) tpcb;
 
        return 0;
 
 
        return 0;
 
@@ -681,7 +705,7 @@ bad4:
        IFDEBUG(D_CONN)
                printf("BAD4 in tp_attach, so 0x%x\n", so);
        ENDDEBUG
        IFDEBUG(D_CONN)
                printf("BAD4 in tp_attach, so 0x%x\n", so);
        ENDDEBUG
-       tp_freeref(tpcb->tp_refp);
+       tp_freeref(tpcb->tp_lref);
 
 bad3:
        IFDEBUG(D_CONN)
 
 bad3:
        IFDEBUG(D_CONN)
@@ -730,7 +754,7 @@ void
 tp_detach(tpcb)
        register struct tp_pcb  *tpcb;
 {
 tp_detach(tpcb)
        register struct tp_pcb  *tpcb;
 {
-       void                                    tp_freeref();
+       void                                    tp_freeref(), tp_rsyflush();
        register struct socket   *so = tpcb->tp_sock;
 
        IFDEBUG(D_CONN)
        register struct socket   *so = tpcb->tp_sock;
 
        IFDEBUG(D_CONN)
@@ -742,33 +766,6 @@ tp_detach(tpcb)
                        tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0);
        ENDTRACE
 
                        tpcb, so, *(u_short *)(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("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 ");
        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 ");
@@ -776,13 +773,26 @@ tp_detach(tpcb)
                                tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
        ENDDEBUG
 
                                tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
        ENDDEBUG
 
-       if (so->so_snd.sb_cc != 0)
-               sbflush(&so->so_snd);
-       if (tpcb->tp_Xrcv.sb_cc != 0)
-               sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc);
+       if (tpcb->tp_Xsnd.sb_mb) {
+               printf("Unsent Xdata on detach; would panic");
+               sbflush(&tpcb->tp_Xsnd);
+       }
        if (tpcb->tp_ucddata)
                m_freem(tpcb->tp_ucddata);
 
        if (tpcb->tp_ucddata)
                m_freem(tpcb->tp_ucddata);
 
+       IFDEBUG(D_CONN)
+               printf("reassembly info cnt %d rsyq 0x%x\n",
+                   tpcb->tp_rsycnt, tpcb->tp_rsyq);
+       ENDDEBUG
+       if (tpcb->tp_rsyq)
+               tp_rsyflush(tpcb);
+
+       if (tpcb->tp_next) {
+               remque(tpcb);
+               tpcb->tp_next = tpcb->tp_prev = 0;
+       }
+       tpcb->tp_notdetached = 0;
+
        IFDEBUG(D_CONN)
                printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", 
                        tpcb->tp_npcb, so);
        IFDEBUG(D_CONN)
                printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", 
                        tpcb->tp_npcb, so);
@@ -791,30 +801,32 @@ tp_detach(tpcb)
                so->so_q0len, so->so_qlen, so->so_qlimit);
        ENDDEBUG
 
                so->so_q0len, so->so_qlen, so->so_qlimit);
        ENDDEBUG
 
-
        (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
        (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
-                               /* does an sofree(so) */
+                               /* does an so->so_pcb = 0; sofree(so) */
 
        IFDEBUG(D_CONN)
                printf("after xxx_pcbdetach\n");
        ENDDEBUG
 
 
        IFDEBUG(D_CONN)
                printf("after xxx_pcbdetach\n");
        ENDDEBUG
 
-       if( tpcb->tp_refp->tpr_state == REF_OPENING ) {
+       if (tpcb->tp_state == TP_LISTENING) {
+               register struct tp_pcb **tt;
+               for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
+                       if (*tt == tpcb)
+                               break;
+               if (*tt)
+                       *tt = tpcb->tp_nextlisten;
+               else
+                       printf("tp_detach from listen: should panic\n");
+       }
+       if (tpcb->tp_refstate == REF_OPENING ) {
                /* no connection existed here so no reference timer will be called */
                IFDEBUG(D_CONN)
                /* 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]);
+                       printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref);
                ENDDEBUG
 
                ENDDEBUG
 
-               tp_freeref(tpcb->tp_refp);
+               tp_freeref(tpcb->tp_lref);
        }
        }
-
-       if (tpcb->tp_Xsnd.sb_mb) {
-               printf("Unsent Xdata on detach; would panic");
-               sbflush(&tpcb->tp_Xsnd);
-       }
-       so->so_pcb = 0;
-
+#ifdef TP_PERF_MEAS
        /* 
         * 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 
        /* 
         * 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 
@@ -822,7 +834,6 @@ tp_detach(tpcb)
         * to one (that is, we need the TP_PERF_MEASs around the following section 
         * of code, not the IFPERFs)
         */
         * 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_mbuf) {
                register struct mbuf *m = tpcb->tp_p_mbuf;
                struct mbuf *n;
        if (tpcb->tp_p_mbuf) {
                register struct mbuf *m = tpcb->tp_p_mbuf;
                struct mbuf *n;
@@ -843,3 +854,120 @@ tp_detach(tpcb)
        ENDDEBUG
        /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
 }
        ENDDEBUG
        /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
 }
+
+struct que {
+       struct tp_pcb *next;
+       struct tp_pcb *prev;
+} tp_bound_pcbs =
+{(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs};
+
+u_short tp_unique;
+
+tp_tselinuse(tlen, tsel, siso, reuseaddr)
+caddr_t tsel;
+register struct sockaddr_iso *siso;
+{
+       struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
+       register struct tp_pcb *t;
+
+       for (;;) {
+               if (b != (struct tp_pcb *)&tp_bound_pcbs) {
+                       t = b; b = t->tp_next;
+               } else if (l) {
+                       t = l; l = t->tp_nextlisten;
+               } else
+                       break;
+               if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
+                       if (t->tp_flags & TPF_GENERAL_ADDR) {
+                               if (siso == 0 || reuseaddr == 0)
+                                       return 1;
+                       } else if (siso) {
+                               if (siso->siso_family == t->tp_domain &&
+                                       t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL))
+                                               return 1;
+                       } else if (reuseaddr == 0)
+                                               return 1;
+               }
+       }
+       return 0;
+
+}
+
+
+tp_pcbbind(tpcb, nam)
+register struct tp_pcb *tpcb;
+register struct mbuf *nam;
+{
+       register struct sockaddr_iso *siso = 0;
+       int tlen = 0, wrapped = 0;
+       caddr_t tsel;
+       u_short tutil;
+
+       if (tpcb->tp_state != TP_CLOSED)
+               return (EINVAL);
+       if (nam) {
+               siso = mtod(nam, struct sockaddr_iso *);
+               switch (siso->siso_family) {
+               default:
+                       return (EAFNOSUPPORT);
+#ifdef ISO
+               case AF_ISO:
+                       tlen = siso->siso_tlen;
+                       tsel = TSEL(siso);
+                       if (siso->siso_nlen == 0)
+                               siso = 0;
+                       break;
+#endif
+#ifdef INET
+               case AF_INET:
+                       tsel = (caddr_t)&tutil;
+                       if (tutil =  ((struct sockaddr_in *)siso)->sin_port) {
+                               tlen = 2;
+                       }
+                       if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0)
+                               siso = 0;
+               }
+#endif
+       }
+       if (tpcb->tp_lsuffixlen == 0) {
+               if (tlen) {
+                       if (tp_tselinuse(tlen, tsel, siso,
+                                                               tpcb->tp_sock->so_options & SO_REUSEADDR))
+                               return (EINVAL);
+               } else {
+                       for (tsel = (caddr_t)&tutil, tlen = 2;;){
+                               if (tp_unique++ < ISO_PORT_RESERVED ||
+                                       tp_unique > ISO_PORT_USERRESERVED) {
+                                               if (wrapped++)
+                                                       return ESRCH;
+                                               tp_unique = ISO_PORT_RESERVED;
+                               }
+                               tutil = htons(tp_unique);
+                               if (tp_tselinuse(tlen, tsel, siso, 0) == 0)
+                                       break;
+                       }
+                       if (siso) switch (siso->siso_family) {
+#ifdef ISO
+                               case AF_ISO:
+                                       bcopy(tsel, TSEL(siso), tlen);
+                                       siso->siso_tlen = tlen;
+                                       break;
+#endif
+#ifdef INET
+                               case AF_INET:
+                                       ((struct sockaddr_in *)siso)->sin_port = tutil;
+#endif
+                               }
+               }
+               bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
+               insque(tpcb, &tp_bound_pcbs);
+       } else {
+               if (tlen || siso == 0)
+                       return (EINVAL);
+       }
+       if (siso == 0) {
+               tpcb->tp_flags |= TPF_GENERAL_ADDR;
+               return (0);
+       }
+       return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam);
+}