minor changes to compile under both new and old vm systems
[unix-history] / usr / src / sys / netiso / tp_usrreq.c
index 368d83d..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.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.
@@ -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"
@@ -67,6 +71,7 @@ static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
 int tp_attach(), tp_driver();
 int TNew;
 int TPNagle1, TPNagle2;
 int tp_attach(), tp_driver();
 int TNew;
 int TPNagle1, TPNagle2;
+struct tp_pcb *tp_listeners, *tp_intercepts;
 
 #ifdef ARGO_DEBUG
 /*
 
 #ifdef ARGO_DEBUG
 /*
@@ -84,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) {
@@ -101,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;
                        }
@@ -155,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:
@@ -183,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
@@ -197,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 */
@@ -212,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;
@@ -223,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); 
@@ -266,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 
@@ -298,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 */
@@ -311,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
 
@@ -357,7 +361,7 @@ tp_usrreq(so, req, m, nam, 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)
@@ -380,7 +384,7 @@ tp_usrreq(so, req, m, nam, 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;
@@ -389,7 +393,7 @@ tp_usrreq(so, req, m, nam, 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;
@@ -397,6 +401,25 @@ tp_usrreq(so, req, m, nam, 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);
@@ -412,22 +435,27 @@ tp_usrreq(so, req, m, nam, 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);
@@ -449,38 +477,38 @@ tp_usrreq(so, req, m, nam, 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 {
@@ -492,8 +520,8 @@ tp_usrreq(so, req, m, nam, 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;
@@ -509,7 +537,7 @@ tp_usrreq(so, req, m, nam, 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;
@@ -547,7 +575,7 @@ tp_usrreq(so, req, m, nam, controlp)
                        error = ENOTCONN;
                        break;
                }
                        error = ENOTCONN;
                        break;
                }
-               if( ! tpcb->tp_xpd_service ) {
+               if (! tpcb->tp_xpd_service) {
                        error = EOPNOTSUPP;
                        break;
                }
                        error = EOPNOTSUPP;
                        break;
                }
@@ -557,28 +585,31 @@ tp_usrreq(so, req, m, nam, 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;
                }
                /*
@@ -605,10 +636,6 @@ tp_usrreq(so, req, m, nam, controlp)
                         * 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) {
-                               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, 
@@ -682,7 +709,8 @@ tp_usrreq(so, req, m, nam, controlp)
                                        eotsdu, n, mbufcnt);
                                dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
                        ENDDEBUG
                                        eotsdu, n, mbufcnt);
                                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",
@@ -728,6 +756,10 @@ tp_usrreq(so, req, m, nam, 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;
 }
@@ -758,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);
+                       error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
+                                                               (caddr_t)0, (struct mbuf *)0);
                }
        }
                }
        }
+       if (m)
+               m_freem(m);
        return error;
 }
        return error;
 }