move link numbers from <netinet/in.h>
[unix-history] / usr / src / sys / netiso / tp_usrreq.c
index 578e516..b30523c 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.11 (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.
@@ -64,6 +65,8 @@ static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
 #include "iso_errno.h"
 
 int tp_attach(), tp_driver();
 #include "iso_errno.h"
 
 int tp_attach(), tp_driver();
+int TNew;
+int TPNagle1, TPNagle2;
 
 #ifdef ARGO_DEBUG
 /*
 
 #ifdef ARGO_DEBUG
 /*
@@ -81,12 +84,12 @@ dump_mbuf(n, str)
 
        printf("dump %s\n", str);
 
 
        printf("dump %s\n", str);
 
-       ifn == MNULL)  {
+       if (n == MNULL)  {
                printf("EMPTY:\n");
                return;
        }
                
                printf("EMPTY:\n");
                return;
        }
                
-       for(;n;) {
+       while (n) {
                nextrecord = n->m_act;
                printf("RECORD:\n");
                while (n) {
                nextrecord = n->m_act;
                printf("RECORD:\n");
                while (n) {
@@ -98,15 +101,15 @@ dump_mbuf(n, str)
                                register int i;
 
                                printf("data: ");
                                register int i;
 
                                printf("data: ");
-                               for(i=0; i < n->m_len; i++ ) {
-                                       if(i%8 == 0)
+                               for (i = 0; i < n->m_len; i++) {
+                                       if (i%8 == 0)
                                                printf("\n");
                                        printf("0x%x ", *(p+i));
                                }
                                printf("\n");
                        }
 #endif notdef
                                                printf("\n");
                                        printf("0x%x ", *(p+i));
                                }
                                printf("\n");
                        }
 #endif notdef
-                       if( n->m_next == n ) {
+                       if (n->m_next == n) {
                                printf("LOOP!\n");
                                return;
                        }
                                printf("LOOP!\n");
                                return;
                        }
@@ -152,12 +155,10 @@ tp_rcvoob(tpcb, so, m, outflags, inflags)
        ENDDEBUG
 
        /* if you use soreceive */
        ENDDEBUG
 
        /* if you use soreceive */
-       if (m==MNULL)
+       if (m == MNULL)
                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)) {
        if ((((so->so_state & SS_ISCONNECTED) == 0)
                 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
                (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
@@ -176,26 +177,27 @@ restart:
         * uipc_socket2.c (like sbappend).
         */
        
         * 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) {
        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 );
+               ASSERT((tpcb->tp_flags & TPF_DISC_DATA_IN) == 0);
                IFDEBUG(D_XPD)
                        printf("RCVOOB: empty queue!\n");
                ENDDEBUG
                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;
        }
        m->m_len = 0;
 
        /* Assuming at most one xpd tpdu is in the buffer at once */
                sbwait(sb);
                goto restart;
        }
        m->m_len = 0;
 
        /* Assuming at most one xpd tpdu is in the buffer at once */
-       while ( n != MNULL ) {
+       while (n != MNULL) {
                m->m_len += n->m_len;
                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 */
                m->m_len += n->m_len;
                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 */
@@ -210,7 +212,7 @@ restart:
                dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
        ENDDEBUG
 
                dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
        ENDDEBUG
 
-       if( (inflags & MSG_PEEK) == 0 ) {
+       if ((inflags & MSG_PEEK) == 0) {
                n = *nn;
                *nn = n->m_act;
                sb->sb_cc -= m->m_len;
                n = *nn;
                *nn = n->m_act;
                sb->sb_cc -= m->m_len;
@@ -221,7 +223,7 @@ release:
 
        IFTRACE(D_XPD)
                tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
 
        IFTRACE(D_XPD)
                tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
-                       tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 );
+                       tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
        ENDTRACE
        if (error == 0)
                error = DoEvent(T_USR_Xrcvd); 
        ENDTRACE
        if (error == 0)
                error = DoEvent(T_USR_Xrcvd); 
@@ -264,10 +266,9 @@ tp_sendoob(tpcb, so, xdata, outflags)
 
        IFDEBUG(D_XPD)
                printf("tp_sendoob:");
 
        IFDEBUG(D_XPD)
                printf("tp_sendoob:");
-               if(xdata)
+               if (xdata)
                        printf("xdata len 0x%x\n", xdata->m_len);
        ENDDEBUG
                        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
@@ -275,14 +276,15 @@ 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) {
        }
 
        if (xdata == (struct mbuf *)0) {
@@ -296,7 +298,7 @@ oob_again:
        }
        IFDEBUG(D_XPD)
                printf("tp_sendoob 1:");
        }
        IFDEBUG(D_XPD)
                printf("tp_sendoob 1:");
-               if(xdata)
+               if (xdata)
                        printf("xdata len 0x%x\n", xdata->m_len);
        ENDDEBUG
        xmark = xdata; /* temporary use of variable xmark */
                        printf("xdata len 0x%x\n", xdata->m_len);
        ENDDEBUG
        xmark = xdata; /* temporary use of variable xmark */
@@ -309,13 +311,13 @@ oob_again:
        }
        IFDEBUG(D_XPD)
                printf("tp_sendoob 2:");
        }
        IFDEBUG(D_XPD)
                printf("tp_sendoob 2:");
-               if(xdata)
+               if (xdata)
                        printf("xdata len 0x%x\n", len);
        ENDDEBUG
 
 
        IFTRACE(D_XPD)
                        printf("xdata len 0x%x\n", len);
        ENDDEBUG
 
 
        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
 
        sbappendrecord(sb, xdata);      
        ENDTRACE
 
        sbappendrecord(sb, xdata);      
@@ -326,7 +328,6 @@ oob_again:
                dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
        ENDDEBUG
        return DoEvent(T_XPD_req); 
                dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
        ENDDEBUG
        return DoEvent(T_XPD_req); 
-
 }
 
 /*
 }
 
 /*
@@ -339,18 +340,13 @@ 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, controlp)
+tp_usrreq(so, req, m, nam, controlp)
        struct socket *so;
        u_int req;
        struct socket *so;
        u_int req;
-       struct mbuf *m, *nam, *rightsp, *controlp;
+       struct mbuf *m, *nam, *controlp;
 {      
        register struct tp_pcb *tpcb =  sototpcb(so);
        int s = splnet();
 {      
        register struct tp_pcb *tpcb =  sototpcb(so);
        int s = splnet();
@@ -361,7 +357,7 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
 
        IFDEBUG(D_REQUEST)
                printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
 
        IFDEBUG(D_REQUEST)
                printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
-               if(so->so_error)
+               if (so->so_error)
                        printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
        ENDDEBUG
        IFTRACE(D_REQUEST)
                        printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
        ENDDEBUG
        IFTRACE(D_REQUEST)
@@ -384,7 +380,7 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                        error = EISCONN;
                        break;
                }
                        error = EISCONN;
                        break;
                }
-               if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) )
+               if (error = tp_attach(so, so->so_proto->pr_domain->dom_family))
                        break;
                tpcb = sototpcb(so);
                break;
                        break;
                tpcb = sototpcb(so);
                break;
@@ -393,7 +389,7 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                /* called for each incoming connect queued on the 
                 *      parent (accepting) socket 
                 */
                /* called for each incoming connect queued on the 
                 *      parent (accepting) socket 
                 */
-               if( tpcb->tp_state == TP_OPEN ) {
+               if (tpcb->tp_state == TP_OPEN) {
                        E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
                        error = DoEvent(T_DISC_req); /* pretend it was a close() */
                        break;
                        E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
                        error = DoEvent(T_DISC_req); /* pretend it was a close() */
                        break;
@@ -416,25 +412,22 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                break;
 
        case PRU_BIND:
                break;
 
        case PRU_BIND:
-               error =  (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam );
+               error =  (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam);
                if (error == 0) {
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
                if (error == 0) {
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
-                               tpcb->tp_lsuffix, TP_LOCAL );
+                               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( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) )
+               if (tpcb->tp_lsuffixlen == 0) {
+                       if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL))
                                break;
                                break;
-               }
-               if( tpcb->tp_lsuffixlen ==  0) {
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
-                               tpcb->tp_lsuffix, TP_LOCAL );
+                               tpcb->tp_lsuffix, TP_LOCAL);
                }
                IFDEBUG(D_TPISO)
                }
                IFDEBUG(D_TPISO)
-                       if(tpcb->tp_state != TP_CLOSED)
+                       if (tpcb->tp_state != TP_CLOSED)
                                printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
                ENDDEBUG
                error = DoEvent(T_LISTEN_req);
                                printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
                ENDDEBUG
                error = DoEvent(T_LISTEN_req);
@@ -456,42 +449,38 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                        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( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) {
+               if (tpcb->tp_lsuffixlen == 0) {
+                       if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) {
                                IFDEBUG(D_CONN)
                                IFDEBUG(D_CONN)
-                                       printf("pcbbind returns error 0x%x\n", error );
+                                       printf("pcbbind returns error 0x%x\n", error);
                                ENDDEBUG
                                break;
                        }
                                ENDDEBUG
                                break;
                        }
-               }
-               if( tpcb->tp_lsuffixlen ==  0) {
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
-                               tpcb->tp_lsuffix, TP_LOCAL );
+                               tpcb->tp_lsuffix, 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);
-                       dump_buf( tpcb->tp_npcb, 16);
+                       dump_buf(tpcb->tp_npcb, 16);
                ENDDEBUG
                ENDDEBUG
-               if( error = tp_route_to( nam, tpcb, /* channel */0) )
+               if (error = tp_route_to(nam, tpcb, /* channel */0))
                        break;
                IFDEBUG(D_CONN)
                        printf(
                                "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 
                                tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
                        printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
                        break;
                IFDEBUG(D_CONN)
                        printf(
                                "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 
                                tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
                        printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
-                       dump_buf( tpcb->tp_npcb, 16);
+                       dump_buf(tpcb->tp_npcb, 16);
                ENDDEBUG
                ENDDEBUG
-               iftpcb->tp_fsuffixlen ==  0) {
+               if (tpcb->tp_fsuffixlen ==  0) {
                        /* didn't set peer extended suffix */
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
                        /* didn't set peer extended suffix */
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
-                               tpcb->tp_fsuffix, TP_FOREIGN );
+                               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);
-               iftpcb->tp_state == TP_CLOSED) {
+               if (tpcb->tp_state == TP_CLOSED) {
                        soisconnecting(so);  
                        error = DoEvent(T_CONN_req);
                } else {
                        soisconnecting(so);  
                        error = DoEvent(T_CONN_req);
                } else {
@@ -500,51 +489,37 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                }
                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 <<), 
+                       tpmeas(tpcb->tp_lref, 
+                               TPtime_open | (tpcb->tp_xtd_format << 4), 
                                &time, lsufx, fsufx, tpcb->tp_fref);
                ENDPERF
                break;
 
        case PRU_ACCEPT: 
                                &time, lsufx, fsufx, tpcb->tp_fref);
                ENDPERF
                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 {
-                       (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
-                       IFDEBUG(D_REQUEST)
-                               printf("ACCEPT PEERADDDR:");
-                               dump_buf(mtod(nam, char *), nam->m_len);
-                       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, 
+                       tpmeas(tpcb->tp_lref, TPtime_open, 
                                &time, lsufx, fsufx, tpcb->tp_fref);
                ENDPERF
                break;
 
        case PRU_RCVD:
                                &time, lsufx, fsufx, tpcb->tp_fref);
                ENDPERF
                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",
@@ -572,7 +547,7 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                        error = ENOTCONN;
                        break;
                }
                        error = ENOTCONN;
                        break;
                }
-               if( ! tpcb->tp_xpd_service ) {
+               if (! tpcb->tp_xpd_service) {
                        error = EOPNOTSUPP;
                        break;
                }
                        error = EOPNOTSUPP;
                        break;
                }
@@ -580,21 +555,36 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                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 (controlp && (error = tp_snd_control(controlp, so, &m)))
+               if (controlp) {
+                       error = tp_snd_control(controlp, so, &m);
+                       controlp = NULL;
+                       if (error)
+                               break;
+               }
+               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;
+               }
                if (m == 0)
                        break;
                if (m == 0)
                        break;
-               if (so->so_state & SS_ISCONFIRMING)
-                       tp_confirm();
-               if( ! tpcb->tp_xpd_service ) {
-                       error = EOPNOTSUPP;
+
+               if (req == PRU_SENDOOB) {
+                       if (tpcb->tp_xpd_service == 0) {
+                               error = EOPNOTSUPP;
+                               break;
+                       }
+                       error = tp_sendoob(tpcb, so, m, outflags);
                        break;
                }
                        break;
                }
-               error = tp_sendoob(tpcb, so, m, outflags);
-               break;
-
-       case PRU_SEND:
                /*
                 * The protocol machine copies mbuf chains,
                 * prepends headers, assigns seq numbers, and
                /*
                 * The protocol machine copies mbuf chains,
                 * prepends headers, assigns seq numbers, and
@@ -605,27 +595,24 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                 * 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 (controlp && (error = tp_snd_control(controlp, so, &m)))
-                       break;
-               if (m == 0)
-                       break;
-               if (so->so_state & SS_ISCONFIRMING)
-                       tp_confirm();
                {
                        register struct mbuf *n = m;
                {
                        register struct mbuf *n = m;
-                       register int len=0;
                        register struct sockbuf *sb = &so->so_snd;
                        int     maxsize = tpcb->tp_l_tpdusize 
                                    - tp_headersize(DT_TPDU_type, tpcb)
                                    - (tpcb->tp_use_checksum?4:0) ;
                        int totlen = n->m_pkthdr.len;
                        register struct sockbuf *sb = &so->so_snd;
                        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) 
                         */
 
                        /*
                         * Could have eotsdu and no data.(presently MUST have
                         * an mbuf though, even if its length == 0) 
                         */
-                       if (n->m_flags & M_EOR)
+                       if (n->m_flags & M_EOR) {
                                eotsdu = 1;
                                eotsdu = 1;
+                               n->m_flags &= ~M_EOR;
+                       }
                        IFPERF(tpcb)
                           PStat(tpcb, Nb_from_sess) += totlen;
                           tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 
                        IFPERF(tpcb)
                           PStat(tpcb, Nb_from_sess) += totlen;
                           tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 
@@ -634,7 +621,7 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                        IFDEBUG(D_SYSCALL)
                                printf(
                                "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
                        IFDEBUG(D_SYSCALL)
                                printf(
                                "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
-                                       eotsdu, m,len, sb);
+                                       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
@@ -642,19 +629,61 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                         * Pre-packetize the data in the sockbuf
                         * according to negotiated mtu.  Do it here
                         * where we can safely wait for mbufs.
                         * 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.
                         */
                         */
-                       while (n->m_pkthdr.len > maxsize) {
-                               struct mbuf *nn
-                                           = m_copym(n, 0, maxsize, M_WAIT);
-                               if (eotsdu)
-                                       n->m_flags &= ~M_EOR;
+                       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);
                                sbappendrecord(sb, nn);
                                m_adj(n, maxsize);
+                               mbufcnt++;
                        }
                        }
+                       if (eotsdu)
+                               n->m_flags |= M_EOR;
                        sbappendrecord(sb, n);
                        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, n, 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
                        error = DoEvent(T_DATA_req); 
                                dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
                        ENDDEBUG
                        error = DoEvent(T_DATA_req); 
@@ -672,15 +701,7 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                break;
 
        case PRU_PEERADDR:
                break;
 
        case PRU_PEERADDR:
-               if ((so->so_state & SS_ISCONNECTED) && 
-                   (so->so_state & SS_ISDISCONNECTING) == 0) {
-                               (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
-                               IFDEBUG(D_REQUEST)
-                                       printf("PEERADDDR:");
-                                       dump_buf(mtod(nam, char *), nam->m_len);
-                               ENDDEBUG
-               } else 
-                       error = ENOTCONN;
+               (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
                break;
 
        case PRU_CONTROL:
                break;
 
        case PRU_CONTROL:
@@ -703,52 +724,72 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
        }
 
        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, 
                        tpcb?0:tpcb->tp_state);
        ENDTRACE
        ENDDEBUG
        IFTRACE(D_REQUEST)
                tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 
                        tpcb?0:tpcb->tp_state);
        ENDTRACE
+       if (controlp) {
+               m_freem(controlp);
+               printf("control data unexpectedly retained in tp_usrreq()");
+       }
        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
+}
 
 
-/*
- * Stub for future negotiated confirmation of connections.
- */
-tp_confirm()
+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()
  */
 }
 
 /*
  * Process control data sent with sendmsg()
  */
-tp_snd_control(m0, so, data)
-       register struct mbuf *m0;
+tp_snd_control(m, so, data)
+       struct mbuf *m;
        struct socket *so;
        register struct mbuf **data;
 {
        struct socket *so;
        register struct mbuf **data;
 {
-       register struct tp_control_hdr *ch;
-       struct mbuf *m;
+       register struct cmsghdr *ch;
        int error = 0;
 
        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);
+       if (m && m->m_len) {
+               ch = mtod(m, struct cmsghdr *);
+               m->m_len -= sizeof (*ch);
+               m->m_data += sizeof (*ch);
                error = tp_ctloutput(PRCO_SETOPT,
                                                         so, ch->cmsg_level, ch->cmsg_type, &m);
                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;
                        }
                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, m0);
+                       error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
+                                                               (caddr_t)0, (struct mbuf *)0);
                }
        }
                }
        }
+       if (m)
+               m_freem(m);
        return error;
 }
        return error;
 }