cltp_usrreq.c made separate file in conf/files
[unix-history] / usr / src / sys / netiso / tp_usrreq.c
index 6781a47..368d83d 100644 (file)
@@ -1,5 +1,5 @@
 /***********************************************************
 /***********************************************************
-               Copyright IBM Corporation 1987
+                               Copyright IBM Corporation 1987
 
                       All Rights Reserved
 
 
                       All Rights Reserved
 
@@ -29,6 +29,7 @@ SOFTWARE.
  *
  * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $
  * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $
  *
  * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $
  * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $
+ *     @(#)tp_usrreq.c 7.8 (Berkeley) %G%
  *
  * tp_usrreq(), the fellow that gets called from most of the socket code.
  * Pretty straighforward.
  *
  * tp_usrreq(), the fellow that gets called from most of the socket code.
  * Pretty straighforward.
@@ -43,7 +44,6 @@ static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
 
 #include "param.h"
 #include "systm.h"
 
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "user.h"
 #include "mbuf.h"
 #include "socket.h"
@@ -52,19 +52,21 @@ static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
 #include "protosw.h"
 #include "errno.h"
 
 #include "protosw.h"
 #include "errno.h"
 
-#include "../netiso/tp_param.h"
-#include "../netiso/tp_timer.h"
-#include "../netiso/tp_stat.h"
-#include "../netiso/tp_seq.h"
-#include "../netiso/tp_ip.h"
-#include "../netiso/tp_pcb.h"
-#include "../netiso/argo_debug.h"
-#include "../netiso/tp_trace.h"
-#include "../netiso/tp_meas.h"
-#include "../netiso/iso.h"
-#include "../netiso/iso_errno.h"
+#include "tp_param.h"
+#include "tp_timer.h"
+#include "tp_stat.h"
+#include "tp_seq.h"
+#include "tp_ip.h"
+#include "tp_pcb.h"
+#include "argo_debug.h"
+#include "tp_trace.h"
+#include "tp_meas.h"
+#include "iso.h"
+#include "iso_errno.h"
 
 int tp_attach(), tp_driver();
 
 int tp_attach(), tp_driver();
+int TNew;
+int TPNagle1, TPNagle2;
 
 #ifdef ARGO_DEBUG
 /*
 
 #ifdef ARGO_DEBUG
 /*
@@ -91,8 +93,8 @@ dump_mbuf(n, str)
                nextrecord = n->m_act;
                printf("RECORD:\n");
                while (n) {
                nextrecord = n->m_act;
                printf("RECORD:\n");
                while (n) {
-                       printf("%x : Len %x Of %x A %x Nx %x Tp %x\n",
-                               n, n->m_len, n->m_off, n->m_act, n->m_next, n->m_type);
+                       printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
+                               n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
 #ifdef notdef
                        {
                                register char *p = mtod(n, char *);
 #ifdef notdef
                        {
                                register char *p = mtod(n, char *);
@@ -135,7 +137,6 @@ dump_mbuf(n, str)
  *             xpd data in the buffer
  *  E* whatever is returned from the fsm.
  */
  *             xpd data in the buffer
  *  E* whatever is returned from the fsm.
  */
-static int 
 tp_rcvoob(tpcb, so, m, outflags, inflags)
        struct tp_pcb   *tpcb;
        register struct socket  *so;
 tp_rcvoob(tpcb, so, m, outflags, inflags)
        struct tp_pcb   *tpcb;
        register struct socket  *so;
@@ -144,9 +145,10 @@ tp_rcvoob(tpcb, so, m, outflags, inflags)
        int                     inflags;
 {
        register struct mbuf *n;
        int                     inflags;
 {
        register struct mbuf *n;
-       register struct sockbuf *sb = &tpcb->tp_Xrcv;
+       register struct sockbuf *sb = &so->so_rcv;
        struct tp_event E;
        int error = 0;
        struct tp_event E;
        int error = 0;
+       register struct mbuf **nn;
 
        IFDEBUG(D_XPD)
                printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
 
        IFDEBUG(D_XPD)
                printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
@@ -157,56 +159,52 @@ tp_rcvoob(tpcb, so, m, outflags, inflags)
                return ENOBUFS;
 
 restart:
                return ENOBUFS;
 
 restart:
-       sblock(sb);
-
        if ((((so->so_state & SS_ISCONNECTED) == 0)
                 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
                (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
                        return ENOTCONN;
        }
 
        if ((((so->so_state & SS_ISCONNECTED) == 0)
                 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
                (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
                        return ENOTCONN;
        }
 
-       if ( sb->sb_cc == 0) {
+       /* Take the first mbuf off the chain.
+        * Each XPD TPDU gives you a complete TSDU so the chains don't get 
+        * coalesced, but one TSDU may span several mbufs.
+        * Nevertheless, since n should have a most 16 bytes, it
+        * will fit into m.  (size was checked in tp_input() )
+        */
+
+       /*
+        * Code for excision of OOB data should be added to
+        * uipc_socket2.c (like sbappend).
+        */
+       
+       sblock(sb);
+       for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
+               if (n->m_type == MT_OOBDATA)
+                       break;
+
+       if (n == 0) {
                ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN)  == 0 );
                IFDEBUG(D_XPD)
                        printf("RCVOOB: empty queue!\n");
                ENDDEBUG
                ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN)  == 0 );
                IFDEBUG(D_XPD)
                        printf("RCVOOB: empty queue!\n");
                ENDDEBUG
+               sbunlock(sb);
                if (so->so_state & SS_NBIO) {
                        return  EWOULDBLOCK;
                }
                if (so->so_state & SS_NBIO) {
                        return  EWOULDBLOCK;
                }
-               sbunlock(sb);
                sbwait(sb);
                goto restart;
        }
                sbwait(sb);
                goto restart;
        }
-       /* Take the first mbuf off the chain.
-        * Each XPD TPDU gives you a complete TSDU so the chains don't get 
-        * coalesced, but one TSDU may span several mbufs.
-        * Nevertheless, since n should have a most 16 bytes, it
-        * will fit into m.  (size was checked in tp_input() )
-        */
-
-       n = sb->sb_mb;
-       ASSERT((n->m_type == TPMT_DATA) ||
-               n->m_type == TPMT_IPHDR || n->m_type == TPMT_TPHDR);
-
-       /* 
-        * mtod doesn't work for cluster-type mbufs, hence this disaster check: 
-        */
-       if( n->m_off > MMAXOFF )
-               panic("tp_rcvoob: unexpected cluster ");
-
-       m->m_next = MNULL;
-       m->m_act = MNULL;
-       m->m_off = MMINOFF;
        m->m_len = 0;
 
        /* Assuming at most one xpd tpdu is in the buffer at once */
        while ( n != MNULL ) {
                m->m_len += n->m_len;
        m->m_len = 0;
 
        /* Assuming at most one xpd tpdu is in the buffer at once */
        while ( n != MNULL ) {
                m->m_len += n->m_len;
-               bcopy(mtod(n, caddr_t), mtod(m, caddr_t), n->m_len);
-               m->m_off += n->m_len; /* so mtod() in bcopy() above gives right addr */
+               bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
+               m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
                n = n->m_next;
        }
                n = n->m_next;
        }
-       m->m_off = MMINOFF; /* restore it to its proper value */
+       m->m_data = m->m_dat;
+       m->m_flags |= M_EOR;
 
        IFDEBUG(D_XPD)
                printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
 
        IFDEBUG(D_XPD)
                printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
@@ -214,8 +212,11 @@ restart:
                dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
        ENDDEBUG
 
                dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
        ENDDEBUG
 
-       if( (inflags & MSG_PEEK) == 0 )
-               sbdrop(sb, m->m_len);
+       if( (inflags & MSG_PEEK) == 0 ) {
+               n = *nn;
+               *nn = n->m_act;
+               sb->sb_cc -= m->m_len;
+       }
 
 release:
        sbunlock(sb);
 
 release:
        sbunlock(sb);
@@ -224,8 +225,6 @@ release:
                tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
                        tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 );
        ENDTRACE
                tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
                        tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 );
        ENDTRACE
-       if(outflags)
-               *outflags = MSG_OOB | MSG_EOTSDU | inflags; /* always on xpd recv */
        if (error == 0)
                error = DoEvent(T_USR_Xrcvd); 
        return error;
        if (error == 0)
                error = DoEvent(T_USR_Xrcvd); 
        return error;
@@ -245,7 +244,6 @@ release:
  *  EMSGSIZE if trying to send > max-xpd bytes (16)
  *  ENOBUFS if ran out of mbufs
  */
  *  EMSGSIZE if trying to send > max-xpd bytes (16)
  *  ENOBUFS if ran out of mbufs
  */
-static int
 tp_sendoob(tpcb, so, xdata, outflags)
        struct tp_pcb   *tpcb;
        register struct socket  *so;
 tp_sendoob(tpcb, so, xdata, outflags)
        struct tp_pcb   *tpcb;
        register struct socket  *so;
@@ -271,7 +269,6 @@ tp_sendoob(tpcb, so, xdata, outflags)
                if(xdata)
                        printf("xdata len 0x%x\n", xdata->m_len);
        ENDDEBUG
                if(xdata)
                        printf("xdata len 0x%x\n", xdata->m_len);
        ENDDEBUG
-oob_again:
        /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 
         * socket buf locked at any time!!! (otherwise you might
         * sleep() in sblock() w/ a signal pending and cause the
        /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 
         * socket buf locked at any time!!! (otherwise you might
         * sleep() in sblock() w/ a signal pending and cause the
@@ -279,24 +276,25 @@ oob_again:
         * is a problem.  So the so_snd buffer lock
         * (done in sosend()) serves as the lock for Xpd.
         */
         * is a problem.  So the so_snd buffer lock
         * (done in sosend()) serves as the lock for Xpd.
         */
-       if (sb->sb_mb) { /* anything already in this sockbuf? */
+       if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
                if (so->so_state & SS_NBIO) {
                        return EWOULDBLOCK;
                }
                if (so->so_state & SS_NBIO) {
                        return EWOULDBLOCK;
                }
-               sbunlock(&so->so_snd);
-               sbwait(&so->so_snd);
-               sblock(&so->so_snd);
-               goto oob_again;
+               while (sb->sb_mb) {
+                       sbunlock(&so->so_snd); /* already locked by sosend */
+                       sbwait(&so->so_snd);
+                       sblock(&so->so_snd);  /* sosend will unlock on return */
+               }
        }
 
        if (xdata == (struct mbuf *)0) {
                /* empty xpd packet */
        }
 
        if (xdata == (struct mbuf *)0) {
                /* empty xpd packet */
-               MGET(xdata, M_WAIT, TPMT_DATA);
+               MGETHDR(xdata, M_WAIT, MT_OOBDATA);
                if (xdata == NULL) {
                        return ENOBUFS;
                }
                xdata->m_len = 0;
                if (xdata == NULL) {
                        return ENOBUFS;
                }
                xdata->m_len = 0;
-               xdata->m_act = MNULL;
+               xdata->m_pkthdr.len = 0;
        }
        IFDEBUG(D_XPD)
                printf("tp_sendoob 1:");
        }
        IFDEBUG(D_XPD)
                printf("tp_sendoob 1:");
@@ -317,26 +315,11 @@ oob_again:
                        printf("xdata len 0x%x\n", len);
        ENDDEBUG
 
                        printf("xdata len 0x%x\n", len);
        ENDDEBUG
 
-       /* stick an xpd mark in the normal data queue
-        * make sure we have enough mbufs before we stick anything into any queues
-        */
-       MGET(xmark,M_WAIT, TPMT_XPD);
-       if (xmark == MNULL) {
-               return ENOBUFS;
-       }
-       xmark->m_len = 0;
-       xmark->m_act = MNULL;
-       
-       {       /* stash the xpd sequence number in the mark */ 
-               SeqNum *Xuna = mtod(xmark, SeqNum *);
-               *Xuna = tpcb->tp_Xuna;
-       }
 
        IFTRACE(D_XPD)
 
        IFTRACE(D_XPD)
-               tptraceTPCB(TPPTmisc, "XPD mark m_next ", xmark->m_next, 0, 0, 0);
+               tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
        ENDTRACE
 
        ENDTRACE
 
-       sbappendrecord(&so->so_snd, xmark); /* the mark */
        sbappendrecord(sb, xdata);      
 
        IFDEBUG(D_XPD)
        sbappendrecord(sb, xdata);      
 
        IFDEBUG(D_XPD)
@@ -344,9 +327,7 @@ oob_again:
                dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
                dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
        ENDDEBUG
                dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
                dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
        ENDDEBUG
-       u.u_r.r_val1  += len; 
        return DoEvent(T_XPD_req); 
        return DoEvent(T_XPD_req); 
-
 }
 
 /*
 }
 
 /*
@@ -359,23 +340,18 @@ oob_again:
  *     receive type requests only.
  *     (nam) is used for addresses usually, in particular for the bind request.
  * 
  *     receive type requests only.
  *     (nam) is used for addresses usually, in particular for the bind request.
  * 
- *     The last argument (rights in most usrreq()s) has been stolen for 
- *     returning flags values.  Since rights can't be passed around w/ tp,
- *     this field is used only for RCVOOB user requests, and is assumed
- *     to be either 0 (as soreceive() would have it) or a ptr to the int flags
- *     (as recvv()'s version of soreceive() would have it
  */
 /*ARGSUSED*/
 ProtoHook
  */
 /*ARGSUSED*/
 ProtoHook
-tp_usrreq(so, req, m, nam, rightsp, outflags)
+tp_usrreq(so, req, m, nam, controlp)
        struct socket *so;
        u_int req;
        struct socket *so;
        u_int req;
-       struct mbuf *m, *nam, *rightsp /* not used */;
-       int *outflags; 
+       struct mbuf *m, *nam, *controlp;
 {      
        register struct tp_pcb *tpcb =  sototpcb(so);
        int s = splnet();
        int error = 0;
 {      
        register struct tp_pcb *tpcb =  sototpcb(so);
        int s = splnet();
        int error = 0;
+       int flags, *outflags = &flags; 
        u_long eotsdu = 0;
        struct tp_event E;
 
        u_long eotsdu = 0;
        struct tp_event E;
 
@@ -397,23 +373,6 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                return ENOTCONN;
        }
 
                return ENOTCONN;
        }
 
-
-       IFDEBUG(D_XPD)
-               extern struct mbuf *mfree;
-               struct mbuf *m = mfree, *n=MNULL;
-
-               if ( (u_int) tpcb != 0 )  {
-                       n = tpcb->tp_Xrcv.sb_mb;
-                       if(n) while(m) {
-                               if(m == n) {
-                               printf("enter usrreq %d Xrcv sb_mb 0x%x is on freelist!\n",
-                                       req, n);
-                               }
-                               m = m->m_next;
-                       }
-               }
-       ENDDEBUG
-
        switch (req) {
 
        case PRU_ATTACH:
        switch (req) {
 
        case PRU_ATTACH:
@@ -439,6 +398,10 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
        case PRU_DETACH:        /* called from close() */
                /* called only after disconnect was called */
                error = DoEvent(T_DETACH);
        case PRU_DETACH:        /* called from close() */
                /* called only after disconnect was called */
                error = DoEvent(T_DETACH);
+               if (tpcb->tp_state == TP_CLOSED) {
+                       free((caddr_t)tpcb, M_PCB);
+                       tpcb = 0;
+               }
                break;
 
        case PRU_SHUTDOWN:
                break;
 
        case PRU_SHUTDOWN:
@@ -451,22 +414,17 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
        case PRU_BIND:
                error =  (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam );
                if (error == 0) {
        case PRU_BIND:
                error =  (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam );
                if (error == 0) {
-                       tpcb->tp_lsuffixlen = sizeof(short); /* default */ 
-                       *(u_short *)(tpcb->tp_lsuffix) = (u_short) 
-                               (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL );
+                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
+                               tpcb->tp_lsuffix, TP_LOCAL );
                }
                break;
 
        case PRU_LISTEN:
                }
                break;
 
        case PRU_LISTEN:
-               if ( *SHORT_LSUFXP(tpcb) == (short)0 ) {
-                       /* note: this suffix is independent of the extended suffix */
+               if( tpcb->tp_lsuffixlen ==  0) {
                        if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) )
                                break;
                        if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) )
                                break;
-               }
-               if( tpcb->tp_lsuffixlen ==  0) {
-                       tpcb->tp_lsuffixlen = sizeof(short); /* default */ 
-                       *SHORT_LSUFXP(tpcb)  = (short) 
-                               (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL );
+                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
+                               tpcb->tp_lsuffix, TP_LOCAL );
                }
                IFDEBUG(D_TPISO)
                        if(tpcb->tp_state != TP_CLOSED)
                }
                IFDEBUG(D_TPISO)
                        if(tpcb->tp_state != TP_CLOSED)
@@ -482,7 +440,7 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
        case PRU_CONNECT:
                IFTRACE(D_CONN)
                        tptraceTPCB(TPPTmisc, 
        case PRU_CONNECT:
                IFTRACE(D_CONN)
                        tptraceTPCB(TPPTmisc, 
-                       "PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
+                       "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
                        tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
                                tpcb->tp_class);
                ENDTRACE
                        tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
                                tpcb->tp_class);
                ENDTRACE
@@ -491,22 +449,16 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                        tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
                                tpcb->tp_class);
                ENDDEBUG
                        tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
                                tpcb->tp_class);
                ENDDEBUG
-               if (*SHORT_LSUFXP(tpcb) == (short)0) {
-                       /* no bind was done */
-                       /* note: this suffix is independent of the extended suffix */
+               if( tpcb->tp_lsuffixlen ==  0) {
                        if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) {
                                IFDEBUG(D_CONN)
                                        printf("pcbbind returns error 0x%x\n", error );
                                ENDDEBUG
                                break;
                        }
                        if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) {
                                IFDEBUG(D_CONN)
                                        printf("pcbbind returns error 0x%x\n", error );
                                ENDDEBUG
                                break;
                        }
+                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
+                               tpcb->tp_lsuffix, TP_LOCAL );
                }
                }
-               if (tpcb->tp_lsuffixlen == 0) { 
-                       /* didn't set an extended suffix */
-                       tpcb->tp_lsuffixlen = sizeof(short);
-                       *SHORT_LSUFXP(tpcb) = (short)
-                                       (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL );
-               } 
 
                IFDEBUG(D_CONN)
                        printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
 
                IFDEBUG(D_CONN)
                        printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
@@ -521,11 +473,10 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                        printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
                        dump_buf( tpcb->tp_npcb, 16);
                ENDDEBUG
                        printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
                        dump_buf( tpcb->tp_npcb, 16);
                ENDDEBUG
-               if( tpcb->tp_fsuffixlen == ) {
+               if( tpcb->tp_fsuffixlen ==  0) {
                        /* didn't set peer extended suffix */
                        /* didn't set peer extended suffix */
-                       tpcb->tp_fsuffixlen = sizeof(short);
-                       *SHORT_FSUFXP(tpcb) = (short)
-                                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
+                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
+                               tpcb->tp_fsuffix, TP_FOREIGN );
                }
                (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
                                        &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
                }
                (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
                                        &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
@@ -538,8 +489,8 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                }
                IFPERF(tpcb)
                        u_int lsufx, fsufx;
                }
                IFPERF(tpcb)
                        u_int lsufx, fsufx;
-                       lsufx = *(u_int *)(tpcb->tp_lsuffix);
-                       fsufx = *(u_int *)(tpcb->tp_fsuffix);
+                       lsufx = *(u_short *)(tpcb->tp_lsuffix);
+                       fsufx = *(u_short *)(tpcb->tp_fsuffix);
 
                        tpmeas( tpcb->tp_lref, 
                                TPtime_open | (tpcb->tp_xtd_format <<4 ), 
 
                        tpmeas( tpcb->tp_lref, 
                                TPtime_open | (tpcb->tp_xtd_format <<4 ), 
@@ -548,50 +499,15 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                break;
 
        case PRU_ACCEPT: 
                break;
 
        case PRU_ACCEPT: 
-               /* all this garbage is to keep accept from returning
-                * before the 3-way handshake is done in class 4.
-                * it'll have to be modified for other classes 
-                */
+               (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
                IFDEBUG(D_REQUEST)
                IFDEBUG(D_REQUEST)
-                       printf("PRU_ACCEPT so_error 0x%x\n", so->so_error);
+                       printf("ACCEPT PEERADDDR:");
+                       dump_buf(mtod(nam, char *), nam->m_len);
                ENDDEBUG
                ENDDEBUG
-               so->so_error = 0;
-               if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) {
-                       error = EWOULDBLOCK;
-                       break;
-               }
-               while ((so->so_state & SS_ISCONNECTED) == 0 && so->so_error == 0) {
-                       sleep((caddr_t)&so->so_timeo, PZERO+1);
-               }
-               if (so->so_error) {
-                       error = so->so_error;
-               } else {
-                       struct sockaddr *sa = mtod(nam, struct sockaddr *);
-
-                       nam->m_len = sizeof (struct sockaddr);
-                       (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_FOREIGN);
-
-                       switch(sa->sa_family = sototpcb(so)->tp_domain) {
-                       case AF_INET:
-                               satosin(sa)->sin_port =
-                                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
-                               break;
-                       case AF_ISO:
-                               satosiso(sa)->siso_tsuffix =
-                                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
-                               /* doesn't cover the case where the suffix is extended -
-                                * grotesque - the user *has* to do the getsockopt */
-                               break;
-                       }
-                       IFDEBUG(D_REQUEST)
-                               printf("ACCEPT PEERADDDR:");
-                               dump_buf(sa, sizeof(struct sockaddr));
-                       ENDDEBUG
-               }
                IFPERF(tpcb)
                        u_int lsufx, fsufx;
                IFPERF(tpcb)
                        u_int lsufx, fsufx;
-                       lsufx = *(u_int *)(tpcb->tp_lsuffix);
-                       fsufx = *(u_int *)(tpcb->tp_fsuffix);
+                       lsufx = *(u_short *)(tpcb->tp_lsuffix);
+                       fsufx = *(u_short *)(tpcb->tp_fsuffix);
 
                        tpmeas( tpcb->tp_lref, TPtime_open, 
                                &time, lsufx, fsufx, tpcb->tp_fref);
 
                        tpmeas( tpcb->tp_lref, TPtime_open, 
                                &time, lsufx, fsufx, tpcb->tp_fref);
@@ -599,6 +515,11 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                break;
 
        case PRU_RCVD:
                break;
 
        case PRU_RCVD:
+               if (so->so_state & SS_ISCONFIRMING) {
+                       if (tpcb->tp_state == TP_CONFIRMING)
+                               error = tp_confirm(tpcb);
+                       break;
+               }
                IFTRACE(D_DATA)
                        tptraceTPCB(TPPTmisc,
                        "RCVD BF: lcredit sent_lcdt cc hiwat \n",
                IFTRACE(D_DATA)
                        tptraceTPCB(TPPTmisc,
                        "RCVD BF: lcredit sent_lcdt cc hiwat \n",
@@ -610,7 +531,15 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                                sbspace(&so->so_rcv), tpcb->tp_lcredit,
                                so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
                ENDTRACE
                                sbspace(&so->so_rcv), tpcb->tp_lcredit,
                                so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
                ENDTRACE
-               error = DoEvent(T_USR_rcvd); 
+               IFDEBUG(D_REQUEST)
+                       printf("RCVD: cc %d space %d hiwat %d\n",
+                               so->so_rcv.sb_cc, sbspace(&so->so_rcv),
+                               so->so_rcv.sb_hiwat);
+               ENDDEBUG
+               if (((int)nam) & MSG_OOB)
+                       error = DoEvent(T_USR_Xrcvd); 
+               else 
+                       error = DoEvent(T_USR_rcvd); 
                break;
 
        case PRU_RCVOOB:
                break;
 
        case PRU_RCVOOB:
@@ -626,22 +555,32 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
                break;
 
                error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
                break;
 
+       case PRU_SEND:
        case PRU_SENDOOB:
        case PRU_SENDOOB:
-               if ((so->so_state & SS_ISCONNECTED) == 0) {
-                       error = ENOTCONN;
+               if (controlp && (error = tp_snd_control(controlp, so, &m)))
                        break;
                        break;
-               }
-               if( ! tpcb->tp_xpd_service ) {
-                       error = EOPNOTSUPP;
+               if (so->so_state & SS_ISCONFIRMING) {
+                       if (tpcb->tp_state == TP_CONFIRMING)
+                               error = tp_confirm(tpcb);
+                       if (m) {
+                               if (error == 0 && m->m_len != 0)
+                                       error =  ENOTCONN;
+                               m_freem(m);
+                               m = 0;
+                       }
                        break;
                }
                        break;
                }
-               error = tp_sendoob(tpcb, so, m, outflags);
-               break;
+               if (m == 0)
+                       break;
 
 
-       case PRU_SENDEOT:
-               eotsdu = 1;
-               /* fall through */
-       case PRU_SEND:
+               if (req == PRU_SENDOOB) {
+                       if (tpcb->tp_xpd_service == 0) {
+                               error = EOPNOTSUPP;
+                               break;
+                       }
+                       error = tp_sendoob(tpcb, so, m, outflags);
+                       break;
+               }
                /*
                 * The protocol machine copies mbuf chains,
                 * prepends headers, assigns seq numbers, and
                /*
                 * The protocol machine copies mbuf chains,
                 * prepends headers, assigns seq numbers, and
@@ -652,105 +591,113 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
                 * Sbspace may be made negative by appending this mbuf chain,
                 * possibly by a whole cluster.
                 */
                 * Sbspace may be made negative by appending this mbuf chain,
                 * possibly by a whole cluster.
                 */
-               if ((so->so_state & SS_ISCONNECTED) == 0) {
-                       error = ENOTCONN;
-                       break;
-               }
                {
                {
-                       register struct mbuf *n;
-                       register int len=0;
+                       register struct mbuf *n = m;
                        register struct sockbuf *sb = &so->so_snd;
                        register struct sockbuf *sb = &so->so_snd;
-
-                       n = m;
-                       while (n) { /* Could have eotsdu and no data.(presently MUST have
-                                                *      an mbuf though, even if its length == 0) 
-                                                */
-                               len += n->m_len;
-                               if( n->m_next == MNULL && eotsdu )  {
-                                       CHANGE_MTYPE(n, TPMT_EOT);
-                               }
-                               n = n->m_next;
+                       int     maxsize = tpcb->tp_l_tpdusize 
+                                   - tp_headersize(DT_TPDU_type, tpcb)
+                                   - (tpcb->tp_use_checksum?4:0) ;
+                       int totlen = n->m_pkthdr.len;
+                       int     mbufcnt = 0;
+                       struct mbuf *nn;
+
+                       /*
+                        * Could have eotsdu and no data.(presently MUST have
+                        * an mbuf though, even if its length == 0) 
+                        */
+                       if (n->m_flags & M_EOR) {
+                               eotsdu = 1;
+                               n->m_flags &= ~M_EOR;
                        }
                        IFPERF(tpcb)
                        }
                        IFPERF(tpcb)
-                          PStat(tpcb, Nb_from_sess) += len;
+                          PStat(tpcb, Nb_from_sess) += totlen;
                           tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 
                           tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 
-                                       PStat(tpcb, Nb_from_sess), len);
+                                       PStat(tpcb, Nb_from_sess), totlen);
                        ENDPERF
                        IFDEBUG(D_SYSCALL)
                                printf(
                                "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
                        ENDPERF
                        IFDEBUG(D_SYSCALL)
                                printf(
                                "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
-                                       eotsdu, m,len, &sb->sb_mb);
+                                       eotsdu, m, totlen, sb);
                                dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
                                dump_mbuf(m, "m : to be added");
                        ENDDEBUG
                                dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
                                dump_mbuf(m, "m : to be added");
                        ENDDEBUG
-                       /* The last mbuf has type TPMT_EOT so it will never be compressed
-                        * with TPMT_DATA mbufs, but if this was an EOTSDU request w/o
-                        * any data, the only way to keep this mbuf from being thrown
-                        * away is to link it through the m_act field
-                        * We are ASSUMING that if there are any data at all with this
-                        * request, the last mbuf will be non-empty!!!
+                       /*
+                        * Pre-packetize the data in the sockbuf
+                        * according to negotiated mtu.  Do it here
+                        * where we can safely wait for mbufs.
+                        *
+                        * This presumes knowledge of sockbuf conventions.
                         */
                         */
-                       if( m->m_type == TPMT_EOT ) /* first mbuf in chain is EOT? */
-                               sbappendrecord(sb, m);  /* to keep 2 TPMT_EOTs from being
-                                                                                               compressed */
-                       else
-                               sbappend(sb, m);
+                       if (n = sb->sb_mb)
+                               while (n->m_act)
+                                       n = n->m_act;
+                       if ((nn = n) && n->m_pkthdr.len < maxsize) {
+                               u_int space = maxsize - n->m_pkthdr.len;
+
+                               do {
+                                       if (n->m_flags & M_EOR)
+                                               goto on1;
+                               } while (n->m_next && (n = n->m_next));
+                               if (totlen <= space) {
+                                       TPNagle1++;
+                                       n->m_next = m; 
+                                       nn->m_pkthdr.len += totlen;
+                                       while (n = n->m_next)
+                                               sballoc(sb, n);
+                                       if (eotsdu)
+                                               nn->m_flags |= M_EOR; 
+                                       goto on2; 
+                               } else {
+                                       /*
+                                        * Can't sleep here, because when you wake up
+                                        * packet you want to attach to may be gone!
+                                        */
+                                       if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) {
+                                               nn->m_pkthdr.len += space;
+                                               TPNagle2++;
+                                               while (n = n->m_next)
+                                                       sballoc(sb, n);
+                                               m_adj(m, space);
+                                       }
+                               }
+                       }       
+       on1:    mbufcnt++;
+                       for (n = m; n->m_pkthdr.len > maxsize;) {
+                               nn = m_copym(n, 0, maxsize, M_WAIT);
+                               sbappendrecord(sb, nn);
+                               m_adj(n, maxsize);
+                               mbufcnt++;
+                       }
+                       if (eotsdu)
+                               n->m_flags |= M_EOR;
+                       sbappendrecord(sb, n);
+       on2:    
+                       IFTRACE(D_DATA)
+                               tptraceTPCB(TPPTmisc,
+                               "SEND BF: maxsize totlen mbufcnt eotsdu",
+                                       maxsize, totlen, mbufcnt, eotsdu);
+                       ENDTRACE
                        IFDEBUG(D_SYSCALL)
                        IFDEBUG(D_SYSCALL)
-                               printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n",
-                                       eotsdu, m,len);
+                               printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n",
+                                       eotsdu, n, mbufcnt);
                                dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
                        ENDDEBUG
                                dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
                        ENDDEBUG
-                       u.u_r.r_val1  += len; 
                        error = DoEvent(T_DATA_req); 
                        IFDEBUG(D_SYSCALL)
                                printf("PRU_SEND: after driver error 0x%x \n",error);
                        error = DoEvent(T_DATA_req); 
                        IFDEBUG(D_SYSCALL)
                                printf("PRU_SEND: after driver error 0x%x \n",error);
+                               printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
+                                               sb, sb->sb_cc, sb->sb_mbcnt);
+                               dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
                        ENDDEBUG
                }
                break;
 
                        ENDDEBUG
                }
                break;
 
-       case PRU_SOCKADDR: {
-                       struct sockaddr *sa = mtod(nam, struct sockaddr *);
-
-                       nam->m_len = sizeof (struct sockaddr);
-                       (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_LOCAL);
-                       switch ( sa->sa_family = sototpcb(so)->tp_domain ) {
-                       case AF_INET:
-                               satosin(sa)->sin_port =
-                                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_LOCAL);
-                               break;
-                       case AF_ISO:
-                               satosiso(sa)->siso_tsuffix =
-                                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_LOCAL);
-                               break;
-                       }
-               }
+       case PRU_SOCKADDR:
+               (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
                break;
 
        case PRU_PEERADDR:
                break;
 
        case PRU_PEERADDR:
-               if( (so->so_state & SS_ISCONNECTED) && 
-                       (so->so_state & SS_ISDISCONNECTING) == 0) {
-                               struct sockaddr *sa = mtod(nam, struct sockaddr *);
-
-                       nam->m_len = sizeof (struct sockaddr);
-
-                       (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_FOREIGN);
-
-                       switch ( sa->sa_family = sototpcb(so)->tp_domain ) {
-                       case AF_INET:
-                               satosin(sa)->sin_port =
-                                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
-                               break;
-                       case AF_ISO:
-                               satosiso(sa)->siso_tsuffix =
-                                       (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
-                               break;
-                       }
-                       IFDEBUG(D_REQUEST)
-                               printf("PEERADDDR:");
-                               dump_buf(sa, sizeof(struct sockaddr));
-                       ENDDEBUG
-               } else 
-                       error = ENOTCONN;
+               (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
                break;
 
        case PRU_CONTROL:
                break;
 
        case PRU_CONTROL:
@@ -773,7 +720,9 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
        }
 
        IFDEBUG(D_REQUEST)
        }
 
        IFDEBUG(D_REQUEST)
-               printf("returning from tp_usrreq(so 0x%x) error 0x%x\n", so, error);
+               printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
+                       "returning from tp_usrreq", so, tpcb, error,
+                       tpcb ? 0 : tpcb->tp_state);
        ENDDEBUG
        IFTRACE(D_REQUEST)
                tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 
        ENDDEBUG
        IFTRACE(D_REQUEST)
                tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 
@@ -782,3 +731,59 @@ tp_usrreq(so, req, m, nam, rightsp, outflags)
        splx(s);
        return error;
 }
        splx(s);
        return error;
 }
+tp_ltrace(so, uio)
+struct socket *so;
+struct uio *uio;
+{
+       IFTRACE(D_DATA)
+               register struct tp_pcb *tpcb =  sototpcb(so);
+               if (tpcb) {
+                       tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
+                               uio->uio_resid, uio->uio_iovcnt, 0);
+               }
+       ENDTRACE
+}
+
+tp_confirm(tpcb)
+register struct tp_pcb *tpcb;
+{
+       struct tp_event E;
+       if (tpcb->tp_state == TP_CONFIRMING)
+           return DoEvent(T_ACPT_req);
+       printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
+               tpcb, tpcb->tp_state);
+       return 0;
+}
+
+/*
+ * Process control data sent with sendmsg()
+ */
+tp_snd_control(m0, so, data)
+       register struct mbuf *m0;
+       struct socket *so;
+       register struct mbuf **data;
+{
+       register struct tp_control_hdr *ch;
+       struct mbuf *m;
+       int error = 0;
+
+       if (m0 && m0->m_len) {
+               ch = mtod(m0, struct tp_control_hdr *);
+               m0->m_len -= sizeof (*ch);
+               m0->m_data += sizeof (*ch);
+               m = m_copym(m0, 0, M_COPYALL, M_WAIT);
+               error = tp_ctloutput(PRCO_SETOPT,
+                                                        so, ch->cmsg_level, ch->cmsg_type, &m);
+               if (m)
+                       m_freem(m);
+               if (ch->cmsg_type == TPOPT_DISC_DATA) {
+                       if (data && *data) {
+                               m_freem(*data);
+                               *data = 0;
+                       }
+                       m0 = 0;
+                       error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0);
+               }
+       }
+       return error;
+}