home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / tp_usrreq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  22.4 KB  |  846 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)tp_usrreq.c    7.17 (Berkeley) 6/27/91
  34.  */
  35.  
  36. /***********************************************************
  37.                 Copyright IBM Corporation 1987
  38.  
  39.                       All Rights Reserved
  40.  
  41. Permission to use, copy, modify, and distribute this software and its 
  42. documentation for any purpose and without fee is hereby granted, 
  43. provided that the above copyright notice appear in all copies and that
  44. both that copyright notice and this permission notice appear in 
  45. supporting documentation, and that the name of IBM not be
  46. used in advertising or publicity pertaining to distribution of the
  47. software without specific, written prior permission.  
  48.  
  49. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  50. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  51. IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  52. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  53. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  54. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  55. SOFTWARE.
  56.  
  57. ******************************************************************/
  58.  
  59. /*
  60.  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
  61.  */
  62. /* 
  63.  * ARGO TP
  64.  *
  65.  * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $
  66.  * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $
  67.  *
  68.  * tp_usrreq(), the fellow that gets called from most of the socket code.
  69.  * Pretty straighforward.
  70.  * THe only really awful stuff here is the OOB processing, which is done
  71.  * wholly here.
  72.  * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
  73.  */
  74.  
  75. #include "param.h"
  76. #include "systm.h"
  77. #include "mbuf.h"
  78. #include "socket.h"
  79. #include "socketvar.h"
  80. #include "domain.h"
  81. #include "protosw.h"
  82. #include "errno.h"
  83. #include "time.h"
  84.  
  85. #include "tp_param.h"
  86. #include "tp_timer.h"
  87. #include "tp_stat.h"
  88. #include "tp_seq.h"
  89. #include "tp_ip.h"
  90. #include "tp_pcb.h"
  91. #include "argo_debug.h"
  92. #include "tp_trace.h"
  93. #include "tp_meas.h"
  94. #include "iso.h"
  95. #include "iso_errno.h"
  96.  
  97. int tp_attach(), tp_driver();
  98. int TNew;
  99. int TPNagle1, TPNagle2;
  100. struct tp_pcb *tp_listeners, *tp_intercepts;
  101.  
  102. #ifdef ARGO_DEBUG
  103. /*
  104.  * CALLED FROM:
  105.  *  anywhere you want to debug...
  106.  * FUNCTION and ARGUMENTS:
  107.  *  print (str) followed by the control info in the mbufs of an mbuf chain (n)
  108.  */
  109. void
  110. dump_mbuf(n, str)
  111.     struct mbuf *n;
  112.     char *str;
  113. {
  114.     struct mbuf *nextrecord;
  115.  
  116.     printf("dump %s\n", str);
  117.  
  118.     if (n == MNULL)  {
  119.         printf("EMPTY:\n");
  120.         return;
  121.     }
  122.         
  123.     while (n) {
  124.         nextrecord = n->m_act;
  125.         printf("RECORD:\n");
  126.         while (n) {
  127.             printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
  128.                 n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
  129. #ifdef notdef
  130.             {
  131.                 register char *p = mtod(n, char *);
  132.                 register int i;
  133.  
  134.                 printf("data: ");
  135.                 for (i = 0; i < n->m_len; i++) {
  136.                     if (i%8 == 0)
  137.                         printf("\n");
  138.                     printf("0x%x ", *(p+i));
  139.                 }
  140.                 printf("\n");
  141.             }
  142. #endif notdef
  143.             if (n->m_next == n) {
  144.                 printf("LOOP!\n");
  145.                 return;
  146.             }
  147.             n = n->m_next;
  148.         }
  149.         n = nextrecord;
  150.     }
  151.     printf("\n");
  152. }
  153.  
  154. #endif ARGO_DEBUG
  155.  
  156. /*
  157.  * CALLED FROM:
  158.  *  tp_usrreq(), PRU_RCVOOB
  159.  * FUNCTION and ARGUMENTS:
  160.  *     Copy data from the expedited data socket buffer into
  161.  *     the pre-allocated mbuf m.
  162.  *     There is an isomorphism between XPD TPDUs and expedited data TSDUs.
  163.  *     XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
  164.  * RETURN VALUE:
  165.  *  EINVAL if debugging is on and a disaster has occurred
  166.  *  ENOTCONN if the socket isn't connected
  167.  *  EWOULDBLOCK if the socket is in non-blocking mode and there's no
  168.  *        xpd data in the buffer
  169.  *  E* whatever is returned from the fsm.
  170.  */
  171. tp_rcvoob(tpcb, so, m, outflags, inflags)
  172.     struct tp_pcb    *tpcb;
  173.     register struct socket    *so;
  174.     register struct mbuf     *m;
  175.     int              *outflags;
  176.     int              inflags;
  177. {
  178.     register struct mbuf *n;
  179.     register struct sockbuf *sb = &so->so_rcv;
  180.     struct tp_event E;
  181.     int error = 0;
  182.     register struct mbuf **nn;
  183.  
  184.     IFDEBUG(D_XPD)
  185.         printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
  186.     ENDDEBUG
  187.  
  188.     /* if you use soreceive */
  189.     if (m == MNULL)
  190.         return ENOBUFS;
  191.  
  192. restart:
  193.     if ((((so->so_state & SS_ISCONNECTED) == 0)
  194.          || (so->so_state & SS_ISDISCONNECTING) != 0) &&
  195.         (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
  196.             return ENOTCONN;
  197.     }
  198.  
  199.     /* Take the first mbuf off the chain.
  200.      * Each XPD TPDU gives you a complete TSDU so the chains don't get 
  201.      * coalesced, but one TSDU may span several mbufs.
  202.      * Nevertheless, since n should have a most 16 bytes, it
  203.      * will fit into m.  (size was checked in tp_input() )
  204.      */
  205.  
  206.     /*
  207.      * Code for excision of OOB data should be added to
  208.      * uipc_socket2.c (like sbappend).
  209.      */
  210.     
  211.     sblock(sb);
  212.     for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
  213.         if (n->m_type == MT_OOBDATA)
  214.             break;
  215.  
  216.     if (n == 0) {
  217.         IFDEBUG(D_XPD)
  218.             printf("RCVOOB: empty queue!\n");
  219.         ENDDEBUG
  220.         sbunlock(sb);
  221.         if (so->so_state & SS_NBIO) {
  222.             return  EWOULDBLOCK;
  223.         }
  224.         sbwait(sb);
  225.         goto restart;
  226.     }
  227.     m->m_len = 0;
  228.  
  229.     /* Assuming at most one xpd tpdu is in the buffer at once */
  230.     while (n != MNULL) {
  231.         m->m_len += n->m_len;
  232.         bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
  233.         m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
  234.         n = n->m_next;
  235.     }
  236.     m->m_data = m->m_dat;
  237.     m->m_flags |= M_EOR;
  238.  
  239.     IFDEBUG(D_XPD)
  240.         printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
  241.         dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
  242.         dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
  243.     ENDDEBUG
  244.  
  245.     if ((inflags & MSG_PEEK) == 0) {
  246.         n = *nn;
  247.         *nn = n->m_act;
  248.         sb->sb_cc -= m->m_len;
  249.     }
  250.  
  251. release:
  252.     sbunlock(sb);
  253.  
  254.     IFTRACE(D_XPD)
  255.         tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
  256.             tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
  257.     ENDTRACE
  258.     if (error == 0)
  259.         error = DoEvent(T_USR_Xrcvd); 
  260.     return error;
  261. }
  262.  
  263. /*
  264.  * CALLED FROM:
  265.  *  tp_usrreq(), PRU_SENDOOB
  266.  * FUNCTION and ARGUMENTS:
  267.  *     Send what's in the mbuf chain (m) as an XPD TPDU.
  268.  *     The mbuf may not contain more then 16 bytes of data.
  269.  *     XPD TSDUs aren't segmented, so they translate into
  270.  *     exactly one XPD TPDU, with EOT bit set.
  271.  * RETURN VALUE:
  272.  *  EWOULDBLOCK if socket is in non-blocking mode and the previous
  273.  *   xpd data haven't been acked yet.
  274.  *  EMSGSIZE if trying to send > max-xpd bytes (16)
  275.  *  ENOBUFS if ran out of mbufs
  276.  */
  277. tp_sendoob(tpcb, so, xdata, outflags)
  278.     struct tp_pcb    *tpcb;
  279.     register struct socket    *so;
  280.     register struct mbuf     *xdata;
  281.     int              *outflags; /* not used */
  282. {
  283.     /*
  284.      * Each mbuf chain represents a sequence # in the XPD seq space.
  285.      * The first one in the queue has sequence # tp_Xuna.
  286.      * When we add to the XPD queue, we stuff a zero-length
  287.      * mbuf (mark) into the DATA queue, with its sequence number in m_next
  288.      * to be assigned to this XPD tpdu, so data xfer can stop
  289.      * when it reaches the zero-length mbuf if this XPD TPDU hasn't
  290.      * yet been acknowledged.  
  291.      */
  292.     register struct sockbuf *sb = &(tpcb->tp_Xsnd);
  293.     register struct mbuf     *xmark;
  294.     register int             len=0;
  295.     struct tp_event E;
  296.  
  297.     IFDEBUG(D_XPD)
  298.         printf("tp_sendoob:");
  299.         if (xdata)
  300.             printf("xdata len 0x%x\n", xdata->m_len);
  301.     ENDDEBUG
  302.     /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 
  303.      * socket buf locked at any time!!! (otherwise you might
  304.      * sleep() in sblock() w/ a signal pending and cause the
  305.      * system call to be aborted w/ a locked socketbuf, which
  306.      * is a problem.  So the so_snd buffer lock
  307.      * (done in sosend()) serves as the lock for Xpd.
  308.      */
  309.     if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
  310.         if (so->so_state & SS_NBIO) {
  311.             return EWOULDBLOCK;
  312.         }
  313.         while (sb->sb_mb) {
  314.             sbunlock(&so->so_snd); /* already locked by sosend */
  315.             sbwait(&so->so_snd);
  316.             sblock(&so->so_snd);  /* sosend will unlock on return */
  317.         }
  318.     }
  319.  
  320.     if (xdata == (struct mbuf *)0) {
  321.         /* empty xpd packet */
  322.         MGETHDR(xdata, M_WAIT, MT_OOBDATA);
  323.         if (xdata == NULL) {
  324.             return ENOBUFS;
  325.         }
  326.         xdata->m_len = 0;
  327.         xdata->m_pkthdr.len = 0;
  328.     }
  329.     IFDEBUG(D_XPD)
  330.         printf("tp_sendoob 1:");
  331.         if (xdata)
  332.             printf("xdata len 0x%x\n", xdata->m_len);
  333.     ENDDEBUG
  334.     xmark = xdata; /* temporary use of variable xmark */
  335.     while (xmark) {
  336.         len += xmark->m_len;
  337.         xmark = xmark->m_next;
  338.     }
  339.     if (len > TP_MAX_XPD_DATA) {
  340.         return EMSGSIZE;
  341.     }
  342.     IFDEBUG(D_XPD)
  343.         printf("tp_sendoob 2:");
  344.         if (xdata)
  345.             printf("xdata len 0x%x\n", len);
  346.     ENDDEBUG
  347.  
  348.  
  349.     IFTRACE(D_XPD)
  350.         tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
  351.     ENDTRACE
  352.  
  353.     sbappendrecord(sb, xdata);    
  354.  
  355.     IFDEBUG(D_XPD)
  356.         printf("tp_sendoob len 0x%x\n", len);
  357.         dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
  358.         dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
  359.     ENDDEBUG
  360.     return DoEvent(T_XPD_req); 
  361. }
  362.  
  363. /*
  364.  * CALLED FROM:
  365.  *  the socket routines
  366.  * FUNCTION and ARGUMENTS:
  367.  *     Handles all "user requests" except the [gs]ockopts() requests.
  368.  *     The argument (req) is the request type (PRU*), 
  369.  *     (m) is an mbuf chain, generally used for send and
  370.  *     receive type requests only.
  371.  *     (nam) is used for addresses usually, in particular for the bind request.
  372.  * 
  373.  */
  374. /*ARGSUSED*/
  375. ProtoHook
  376. tp_usrreq(so, req, m, nam, controlp)
  377.     struct socket *so;
  378.     u_int req;
  379.     struct mbuf *m, *nam, *controlp;
  380. {    
  381.     register struct tp_pcb *tpcb =  sototpcb(so);
  382.     int s = splnet();
  383.     int error = 0;
  384.     int flags, *outflags = &flags; 
  385.     u_long eotsdu = 0;
  386.     struct tp_event E;
  387.  
  388.     IFDEBUG(D_REQUEST)
  389.         printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
  390.         if (so->so_error)
  391.             printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
  392.     ENDDEBUG
  393.     IFTRACE(D_REQUEST)
  394.         tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, 
  395.             tpcb?tpcb->tp_state:0);
  396.     ENDTRACE
  397.  
  398.     if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
  399.         IFTRACE(D_REQUEST)
  400.             tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
  401.         ENDTRACE
  402.         splx(s);
  403.         return ENOTCONN;
  404.     }
  405.  
  406.     switch (req) {
  407.  
  408.     case PRU_ATTACH:
  409.         if (tpcb) {
  410.             error = EISCONN;
  411.             break;
  412.         }
  413.         if (error = tp_attach(so, so->so_proto->pr_domain->dom_family))
  414.             break;
  415.         tpcb = sototpcb(so);
  416.         break;
  417.  
  418.     case PRU_ABORT:     /* called from close() */
  419.         /* called for each incoming connect queued on the 
  420.          *    parent (accepting) socket 
  421.          */
  422.         if (tpcb->tp_state == TP_OPEN) {
  423.             E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
  424.             error = DoEvent(T_DISC_req); /* pretend it was a close() */
  425.             break;
  426.         } /* else DROP THROUGH */
  427.  
  428.     case PRU_DETACH:     /* called from close() */
  429.         /* called only after disconnect was called */
  430.         if (tpcb->tp_state == TP_LISTENING) {
  431.             register struct tp_pcb **tt;
  432.             for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
  433.                 if (*tt == tpcb)
  434.                     break;
  435.             if (*tt)
  436.                 *tt = tpcb->tp_nextlisten;
  437.             else {
  438.                 for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten))
  439.                     if (*tt == tpcb)
  440.                         break;
  441.                 if (*tt)
  442.                     *tt = tpcb->tp_nextlisten;
  443.                 else
  444.                     printf("tp_usrreq - detach: should panic\n");
  445.             }
  446.         }
  447.         if (tpcb->tp_next)
  448.             remque(tpcb);
  449.         error = DoEvent(T_DETACH);
  450.         if (tpcb->tp_state == TP_CLOSED) {
  451.             free((caddr_t)tpcb, M_PCB);
  452.             tpcb = 0;
  453.         }
  454.         break;
  455.  
  456.     case PRU_SHUTDOWN:
  457.         /* recv end may have been released; local credit might be zero  */
  458.     case PRU_DISCONNECT:
  459.         E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
  460.         error = DoEvent(T_DISC_req);
  461.         break;
  462.  
  463.     case PRU_BIND:
  464.         error =  (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam);
  465.         if (error == 0) {
  466.             (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
  467.                 tpcb->tp_lsuffix, TP_LOCAL);
  468.         }
  469.         break;
  470.  
  471.     case PRU_LISTEN:
  472.         if (tpcb->tp_lsuffixlen == 0) {
  473.             if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL))
  474.                 break;
  475.             (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
  476.                 tpcb->tp_lsuffix, TP_LOCAL);
  477.         }
  478.         if (tpcb->tp_next == 0) {
  479.             tpcb->tp_next = tpcb->tp_prev = tpcb;
  480.             tpcb->tp_nextlisten = tp_listeners;
  481.             tp_listeners = tpcb;
  482.         }
  483.         IFDEBUG(D_TPISO)
  484.             if (tpcb->tp_state != TP_CLOSED)
  485.                 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
  486.         ENDDEBUG
  487.         error = DoEvent(T_LISTEN_req);
  488.         break;
  489.  
  490.     case PRU_CONNECT2:
  491.         error = EOPNOTSUPP; /* for unix domain sockets */
  492.         break;
  493.  
  494.     case PRU_CONNECT:
  495.         IFTRACE(D_CONN)
  496.             tptraceTPCB(TPPTmisc, 
  497.             "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
  498.             tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
  499.                 tpcb->tp_class);
  500.         ENDTRACE
  501.         IFDEBUG(D_CONN)
  502.             printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
  503.             tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
  504.                 tpcb->tp_class);
  505.         ENDDEBUG
  506.         if (tpcb->tp_lsuffixlen == 0) {
  507.             if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) {
  508.                 IFDEBUG(D_CONN)
  509.                     printf("pcbbind returns error 0x%x\n", error);
  510.                 ENDDEBUG
  511.                 break;
  512.             }
  513.             (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
  514.                 tpcb->tp_lsuffix, TP_LOCAL);
  515.         }
  516.  
  517.         IFDEBUG(D_CONN)
  518.             printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
  519.             dump_buf(tpcb->tp_npcb, 16);
  520.         ENDDEBUG
  521.         if (error = tp_route_to(nam, tpcb, /* channel */0))
  522.             break;
  523.         IFDEBUG(D_CONN)
  524.             printf(
  525.                 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 
  526.                 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
  527.             printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
  528.             dump_buf(tpcb->tp_npcb, 16);
  529.         ENDDEBUG
  530.         if (tpcb->tp_fsuffixlen ==  0) {
  531.             /* didn't set peer extended suffix */
  532.             (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
  533.                 tpcb->tp_fsuffix, TP_FOREIGN);
  534.         }
  535.         (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
  536.                     &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
  537.         if (tpcb->tp_state == TP_CLOSED) {
  538.             soisconnecting(so);  
  539.             error = DoEvent(T_CONN_req);
  540.         } else {
  541.             (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
  542.             error = EISCONN;
  543.         }
  544.         IFPERF(tpcb)
  545.             u_int lsufx, fsufx;
  546.             lsufx = *(u_short *)(tpcb->tp_lsuffix);
  547.             fsufx = *(u_short *)(tpcb->tp_fsuffix);
  548.  
  549.             tpmeas(tpcb->tp_lref, 
  550.                 TPtime_open | (tpcb->tp_xtd_format << 4), 
  551.                 &time, lsufx, fsufx, tpcb->tp_fref);
  552.         ENDPERF
  553.         break;
  554.  
  555.     case PRU_ACCEPT: 
  556.         (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
  557.         IFDEBUG(D_REQUEST)
  558.             printf("ACCEPT PEERADDDR:");
  559.             dump_buf(mtod(nam, char *), nam->m_len);
  560.         ENDDEBUG
  561.         IFPERF(tpcb)
  562.             u_int lsufx, fsufx;
  563.             lsufx = *(u_short *)(tpcb->tp_lsuffix);
  564.             fsufx = *(u_short *)(tpcb->tp_fsuffix);
  565.  
  566.             tpmeas(tpcb->tp_lref, TPtime_open, 
  567.                 &time, lsufx, fsufx, tpcb->tp_fref);
  568.         ENDPERF
  569.         break;
  570.  
  571.     case PRU_RCVD:
  572.         if (so->so_state & SS_ISCONFIRMING) {
  573.             if (tpcb->tp_state == TP_CONFIRMING)
  574.                 error = tp_confirm(tpcb);
  575.             break;
  576.         }
  577.         IFTRACE(D_DATA)
  578.             tptraceTPCB(TPPTmisc,
  579.             "RCVD BF: lcredit sent_lcdt cc hiwat \n",
  580.                 tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
  581.                 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
  582.             LOCAL_CREDIT(tpcb);
  583.             tptraceTPCB(TPPTmisc, 
  584.                 "PRU_RCVD AF sbspace lcredit hiwat cc",
  585.                 sbspace(&so->so_rcv), tpcb->tp_lcredit,
  586.                 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
  587.         ENDTRACE
  588.         IFDEBUG(D_REQUEST)
  589.             printf("RCVD: cc %d space %d hiwat %d\n",
  590.                 so->so_rcv.sb_cc, sbspace(&so->so_rcv),
  591.                 so->so_rcv.sb_hiwat);
  592.         ENDDEBUG
  593.         if (((int)nam) & MSG_OOB)
  594.             error = DoEvent(T_USR_Xrcvd); 
  595.         else 
  596.             error = DoEvent(T_USR_rcvd); 
  597.         break;
  598.  
  599.     case PRU_RCVOOB:
  600.         if ((so->so_state & SS_ISCONNECTED) == 0) {
  601.             error = ENOTCONN;
  602.             break;
  603.         }
  604.         if (! tpcb->tp_xpd_service) {
  605.             error = EOPNOTSUPP;
  606.             break;
  607.         }
  608.         /* kludge - nam is really flags here */
  609.         error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
  610.         break;
  611.  
  612.     case PRU_SEND:
  613.     case PRU_SENDOOB:
  614.         if (controlp) {
  615.             error = tp_snd_control(controlp, so, &m);
  616.             controlp = NULL;
  617.             if (error)
  618.                 break;
  619.         }
  620.         if ((so->so_state & SS_ISCONFIRMING) &&
  621.             (tpcb->tp_state == TP_CONFIRMING) &&
  622.             (error = tp_confirm(tpcb)))
  623.                 break;
  624.         if (req == PRU_SENDOOB) {
  625.             error = (tpcb->tp_xpd_service == 0) ?
  626.                         EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags);
  627.             break;
  628.         }
  629.         if (m == 0)
  630.             break;
  631.         if (m->m_flags & M_EOR) {
  632.             eotsdu = 1;
  633.             m->m_flags &= ~M_EOR;
  634.         }
  635.         if (eotsdu == 0 && m->m_pkthdr.len == 0)
  636.             break;
  637.         if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) {
  638.             error = ENOTCONN;
  639.             break;
  640.         }
  641.         /*
  642.          * The protocol machine copies mbuf chains,
  643.          * prepends headers, assigns seq numbers, and
  644.          * puts the packets on the device.
  645.          * When they are acked they are removed from the socket buf.
  646.          *
  647.          * sosend calls this up until sbspace goes negative.
  648.          * Sbspace may be made negative by appending this mbuf chain,
  649.          * possibly by a whole cluster.
  650.          */
  651.         {
  652.             register struct mbuf *n = m;
  653.             register struct sockbuf *sb = &so->so_snd;
  654.             int    maxsize = tpcb->tp_l_tpdusize 
  655.                     - tp_headersize(DT_TPDU_type, tpcb)
  656.                     - (tpcb->tp_use_checksum?4:0) ;
  657.             int totlen = n->m_pkthdr.len;
  658.             int    mbufcnt = 0;
  659.             struct mbuf *nn;
  660.  
  661.             /*
  662.              * Could have eotsdu and no data.(presently MUST have
  663.              * an mbuf though, even if its length == 0) 
  664.              */
  665.             IFPERF(tpcb)
  666.                PStat(tpcb, Nb_from_sess) += totlen;
  667.                tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 
  668.                     PStat(tpcb, Nb_from_sess), totlen);
  669.             ENDPERF
  670.             IFDEBUG(D_SYSCALL)
  671.                 printf(
  672.                 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
  673.                     eotsdu, m, totlen, sb);
  674.                 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
  675.                 dump_mbuf(m, "m : to be added");
  676.             ENDDEBUG
  677.             /*
  678.              * Pre-packetize the data in the sockbuf
  679.              * according to negotiated mtu.  Do it here
  680.              * where we can safely wait for mbufs.
  681.              *
  682.              * This presumes knowledge of sockbuf conventions.
  683.              */
  684.             if (n = sb->sb_mb)
  685.                 while (n->m_act)
  686.                     n = n->m_act;
  687.             if ((nn = n) && n->m_pkthdr.len < maxsize) {
  688.                 u_int space = maxsize - n->m_pkthdr.len;
  689.  
  690.                 do {
  691.                     if (n->m_flags & M_EOR)
  692.                         goto on1;
  693.                 } while (n->m_next && (n = n->m_next));
  694.                 if (totlen <= space) {
  695.                     TPNagle1++;
  696.                     n->m_next = m; 
  697.                     nn->m_pkthdr.len += totlen;
  698.                     while (n = n->m_next)
  699.                         sballoc(sb, n);
  700.                     if (eotsdu)
  701.                         nn->m_flags |= M_EOR; 
  702.                     goto on2; 
  703.                 } else {
  704.                     /*
  705.                      * Can't sleep here, because when you wake up
  706.                      * packet you want to attach to may be gone!
  707.                      */
  708.                     if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) {
  709.                         nn->m_pkthdr.len += space;
  710.                         TPNagle2++;
  711.                         while (n = n->m_next)
  712.                             sballoc(sb, n);
  713.                         m_adj(m, space);
  714.                     }
  715.                 }
  716.             }    
  717.     on1:    mbufcnt++;
  718.             for (n = m; n->m_pkthdr.len > maxsize;) {
  719.                 nn = m_copym(n, 0, maxsize, M_WAIT);
  720.                 sbappendrecord(sb, nn);
  721.                 m_adj(n, maxsize);
  722.                 mbufcnt++;
  723.             }
  724.             if (eotsdu)
  725.                 n->m_flags |= M_EOR;
  726.             sbappendrecord(sb, n);
  727.     on2:    
  728.             IFTRACE(D_DATA)
  729.                 tptraceTPCB(TPPTmisc,
  730.                 "SEND BF: maxsize totlen mbufcnt eotsdu",
  731.                     maxsize, totlen, mbufcnt, eotsdu);
  732.             ENDTRACE
  733.             IFDEBUG(D_SYSCALL)
  734.                 printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n",
  735.                     eotsdu, n, mbufcnt);
  736.                 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
  737.             ENDDEBUG
  738.             if (tpcb->tp_state == TP_OPEN)
  739.                 error = DoEvent(T_DATA_req); 
  740.             IFDEBUG(D_SYSCALL)
  741.                 printf("PRU_SEND: after driver error 0x%x \n",error);
  742.                 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
  743.                         sb, sb->sb_cc, sb->sb_mbcnt);
  744.                 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
  745.             ENDDEBUG
  746.         }
  747.         break;
  748.  
  749.     case PRU_SOCKADDR:
  750.         (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
  751.         break;
  752.  
  753.     case PRU_PEERADDR:
  754.         (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
  755.         break;
  756.  
  757.     case PRU_CONTROL:
  758.         error = EOPNOTSUPP;
  759.         break;
  760.  
  761.     case PRU_PROTOSEND:
  762.     case PRU_PROTORCV:
  763.     case PRU_SENSE:
  764.     case PRU_SLOWTIMO:
  765.     case PRU_FASTTIMO:
  766.         error = EOPNOTSUPP;
  767.         break;
  768.  
  769.     default:
  770. #ifdef ARGO_DEBUG
  771.         printf("tp_usrreq UNKNOWN PRU %d\n", req);
  772. #endif ARGO_DEBUG
  773.         error = EOPNOTSUPP;
  774.     }
  775.  
  776.     IFDEBUG(D_REQUEST)
  777.         printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
  778.             "returning from tp_usrreq", so, tpcb, error,
  779.             tpcb ? 0 : tpcb->tp_state);
  780.     ENDDEBUG
  781.     IFTRACE(D_REQUEST)
  782.         tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 
  783.             tpcb?0:tpcb->tp_state);
  784.     ENDTRACE
  785.     if (controlp) {
  786.         m_freem(controlp);
  787.         printf("control data unexpectedly retained in tp_usrreq()");
  788.     }
  789.     splx(s);
  790.     return error;
  791. }
  792. tp_ltrace(so, uio)
  793. struct socket *so;
  794. struct uio *uio;
  795. {
  796.     IFTRACE(D_DATA)
  797.         register struct tp_pcb *tpcb =  sototpcb(so);
  798.         if (tpcb) {
  799.             tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
  800.                 uio->uio_resid, uio->uio_iovcnt, 0);
  801.         }
  802.     ENDTRACE
  803. }
  804.  
  805. tp_confirm(tpcb)
  806. register struct tp_pcb *tpcb;
  807. {
  808.     struct tp_event E;
  809.     if (tpcb->tp_state == TP_CONFIRMING)
  810.         return DoEvent(T_ACPT_req);
  811.     printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
  812.         tpcb, tpcb->tp_state);
  813.     return 0;
  814. }
  815.  
  816. /*
  817.  * Process control data sent with sendmsg()
  818.  */
  819. tp_snd_control(m, so, data)
  820.     struct mbuf *m;
  821.     struct socket *so;
  822.     register struct mbuf **data;
  823. {
  824.     register struct cmsghdr *ch;
  825.     int error = 0;
  826.  
  827.     if (m && m->m_len) {
  828.         ch = mtod(m, struct cmsghdr *);
  829.         m->m_len -= sizeof (*ch);
  830.         m->m_data += sizeof (*ch);
  831.         error = tp_ctloutput(PRCO_SETOPT,
  832.                              so, ch->cmsg_level, ch->cmsg_type, &m);
  833.         if (ch->cmsg_type == TPOPT_DISC_DATA) {
  834.             if (data && *data) {
  835.                 m_freem(*data);
  836.                 *data = 0;
  837.             }
  838.             error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
  839.                                 (caddr_t)0, (struct mbuf *)0);
  840.         }
  841.     }
  842.     if (m)
  843.         m_freem(m);
  844.     return error;
  845. }
  846.