minor changes to compile under both new and old vm systems
[unix-history] / usr / src / sys / netiso / tp_usrreq.c
index ddc5718..ab20115 100644 (file)
@@ -1,3 +1,12 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)tp_usrreq.c 7.17 (Berkeley) %G%
+ */
+
 /***********************************************************
                                Copyright IBM Corporation 1987
 
 /***********************************************************
                                Copyright IBM Corporation 1987
 
@@ -29,7 +38,6 @@ 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.5 (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.
@@ -38,19 +46,15 @@ SOFTWARE.
  * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
  */
 
  * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
  */
 
-#ifndef lint
-static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
-#endif lint
-
 #include "param.h"
 #include "systm.h"
 #include "param.h"
 #include "systm.h"
-#include "user.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "domain.h"
 #include "protosw.h"
 #include "errno.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "domain.h"
 #include "protosw.h"
 #include "errno.h"
+#include "time.h"
 
 #include "tp_param.h"
 #include "tp_timer.h"
 
 #include "tp_param.h"
 #include "tp_timer.h"
@@ -65,6 +69,9 @@ 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;
+struct tp_pcb *tp_listeners, *tp_intercepts;
 
 #ifdef ARGO_DEBUG
 /*
 
 #ifdef ARGO_DEBUG
 /*
@@ -82,12 +89,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) {
@@ -99,15 +106,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;
                        }
@@ -153,7 +160,7 @@ 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:
@@ -181,7 +188,6 @@ restart:
                        break;
 
        if (n == 0) {
                        break;
 
        if (n == 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
@@ -195,7 +201,7 @@ restart:
        m->m_len = 0;
 
        /* Assuming at most one xpd tpdu is in the buffer at once */
        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 +216,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 +227,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,7 +270,7 @@ 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
        /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 
                        printf("xdata len 0x%x\n", xdata->m_len);
        ENDDEBUG
        /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 
@@ -296,7 +302,7 @@ tp_sendoob(tpcb, so, xdata, outflags)
        }
        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,7 +315,7 @@ tp_sendoob(tpcb, so, xdata, outflags)
        }
        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
 
                        printf("xdata len 0x%x\n", len);
        ENDDEBUG
 
@@ -341,10 +347,10 @@ tp_sendoob(tpcb, so, xdata, outflags)
  */
 /*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();
@@ -355,7 +361,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)
@@ -378,7 +384,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;
@@ -387,7 +393,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;
@@ -395,6 +401,25 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
 
        case PRU_DETACH:        /* called from close() */
                /* called only after disconnect was called */
 
        case PRU_DETACH:        /* called from close() */
                /* called only after disconnect was called */
+               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 {
+                               for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten))
+                                       if (*tt == tpcb)
+                                               break;
+                               if (*tt)
+                                       *tt = tpcb->tp_nextlisten;
+                               else
+                                       printf("tp_usrreq - detach: should panic\n");
+                       }
+               }
+               if (tpcb->tp_next)
+                       remque(tpcb);
                error = DoEvent(T_DETACH);
                if (tpcb->tp_state == TP_CLOSED) {
                        free((caddr_t)tpcb, M_PCB);
                error = DoEvent(T_DETACH);
                if (tpcb->tp_state == TP_CLOSED) {
                        free((caddr_t)tpcb, M_PCB);
@@ -410,22 +435,27 @@ 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( tpcb->tp_lsuffixlen ==  0) {
-                       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;
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
                                break;
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
-                               tpcb->tp_lsuffix, TP_LOCAL );
+                               tpcb->tp_lsuffix, TP_LOCAL);
+               }
+               if (tpcb->tp_next == 0) {
+                       tpcb->tp_next = tpcb->tp_prev = tpcb;
+                       tpcb->tp_nextlisten = tp_listeners;
+                       tp_listeners = tpcb;
                }
                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);
@@ -447,38 +477,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( tpcb->tp_lsuffixlen ==  0) {
-                       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;
                        }
                        (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
                                ENDDEBUG
                                break;
                        }
                        (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 {
@@ -490,8 +520,8 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                        lsufx = *(u_short *)(tpcb->tp_lsuffix);
                        fsufx = *(u_short *)(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;
                                &time, lsufx, fsufx, tpcb->tp_fref);
                ENDPERF
                break;
@@ -507,7 +537,7 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                        lsufx = *(u_short *)(tpcb->tp_lsuffix);
                        fsufx = *(u_short *)(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;
                                &time, lsufx, fsufx, tpcb->tp_fref);
                ENDPERF
                break;
@@ -545,7 +575,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;
                }
@@ -555,28 +585,31 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
 
        case PRU_SEND:
        case PRU_SENDOOB:
 
        case PRU_SEND:
        case PRU_SENDOOB:
-               if (controlp && (error = tp_snd_control(controlp, so, &m)))
-                       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;
-                       }
+               if (controlp) {
+                       error = tp_snd_control(controlp, so, &m);
+                       controlp = NULL;
+                       if (error)
+                               break;
+               }
+               if ((so->so_state & SS_ISCONFIRMING) &&
+                   (tpcb->tp_state == TP_CONFIRMING) &&
+                   (error = tp_confirm(tpcb)))
+                           break;
+               if (req == PRU_SENDOOB) {
+                       error = (tpcb->tp_xpd_service == 0) ?
+                                               EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags);
                        break;
                }
                if (m == 0)
                        break;
                        break;
                }
                if (m == 0)
                        break;
-
-               if (req == PRU_SENDOOB) {
-                       if (tpcb->tp_xpd_service == 0) {
-                               error = EOPNOTSUPP;
-                               break;
-                       }
-                       error = tp_sendoob(tpcb, so, m, outflags);
+               if (m->m_flags & M_EOR) {
+                       eotsdu = 1;
+                       m->m_flags &= ~M_EOR;
+               }
+               if (eotsdu == 0 && m->m_pkthdr.len == 0)
+                       break;
+               if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) {
+                       error = ENOTCONN;
                        break;
                }
                /*
                        break;
                }
                /*
@@ -591,22 +624,18 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                 */
                {
                        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) 
                         */
                        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)
                           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, 
@@ -615,7 +644,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
@@ -626,37 +655,45 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                         *
                         * This presumes knowledge of sockbuf conventions.
                         */
                         *
                         * This presumes knowledge of sockbuf conventions.
                         */
-                       len = 0;
                        if (n = sb->sb_mb)
                                while (n->m_act)
                                        n = n->m_act;
                        if (n = sb->sb_mb)
                                while (n->m_act)
                                        n = n->m_act;
-                       if (n && n->m_pkthdr.len < maxsize) {
-                               int space = maxsize - n->m_pkthdr.len;
-                               int eorseen = 0;
-                               nn = n; 
-                               for (;; n = n->m_next) {
-                                eorseen |= n->m_flags & M_EOR;
-                                       if (n->m_next == 0)
-                                               break;
-                               }  
-                               if (eorseen)
-                                       goto on1;
-                               if (m->m_pkthdr.len <= space) {
+                       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; 
                                        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; 
                                        if (eotsdu)
                                                nn->m_flags |= M_EOR; 
                                        goto on2; 
-                               } else {   
-                                       nn->m_next = m_copym(n, 0, space, M_WAIT);
-                                       m_adj(n, space);
+                               } 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:    len++;
+       on1:    mbufcnt++;
                        for (n = m; n->m_pkthdr.len > maxsize;) {
                        for (n = m; n->m_pkthdr.len > maxsize;) {
-                               nn = m_copym(n, 0, len, M_WAIT);
+                               nn = m_copym(n, 0, maxsize, M_WAIT);
                                sbappendrecord(sb, nn);
                                m_adj(n, maxsize);
                                sbappendrecord(sb, nn);
                                m_adj(n, maxsize);
-                               len++;
+                               mbufcnt++;
                        }
                        if (eotsdu)
                                n->m_flags |= M_EOR;
                        }
                        if (eotsdu)
                                n->m_flags |= M_EOR;
@@ -664,15 +701,16 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
        on2:    
                        IFTRACE(D_DATA)
                                tptraceTPCB(TPPTmisc,
        on2:    
                        IFTRACE(D_DATA)
                                tptraceTPCB(TPPTmisc,
-                               "SEND BF: maxsize totlen frags eotsdu",
-                                       maxsize, totlen, len, eotsdu);
+                               "SEND BF: maxsize totlen mbufcnt eotsdu",
+                                       maxsize, totlen, mbufcnt, eotsdu);
                        ENDTRACE
                        IFDEBUG(D_SYSCALL)
                        ENDTRACE
                        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
                                dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
                        ENDDEBUG
-                       error = DoEvent(T_DATA_req); 
+                       if (tpcb->tp_state == TP_OPEN)
+                               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",
                        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",
@@ -718,6 +756,10 @@ tp_usrreq(so, req, m, nam, rightsp, controlp)
                tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 
                        tpcb?0:tpcb->tp_state);
        ENDTRACE
                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;
 }
@@ -748,32 +790,30 @@ register struct tp_pcb *tpcb;
 /*
  * 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;
 }