home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / tp_output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  19.7 KB  |  702 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_output.c    7.10 (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_output.c,v 5.4 88/11/18 17:28:08 nhall Exp $
  66.  * $Source: /usr/argo/sys/netiso/RCS/tp_output.c,v $
  67.  *
  68.  * In here is tp_ctloutput(), the guy called by [sg]etsockopt(),
  69.  */
  70.  
  71. #include "param.h"
  72. #include "mbuf.h"
  73. #include "systm.h"
  74. #include "socket.h"
  75. #include "socketvar.h"
  76. #include "protosw.h"
  77. #include "errno.h"
  78. #include "time.h"
  79. #include "tp_param.h"
  80. #include "tp_user.h"
  81. #include "tp_stat.h"
  82. #include "tp_ip.h"
  83. #include "tp_clnp.h"
  84. #include "tp_timer.h"
  85. #include "argo_debug.h"
  86. #include "tp_pcb.h"
  87. #include "tp_trace.h"
  88. #include "kernel.h"
  89.  
  90. #define USERFLAGSMASK_G 0x0f00643b
  91. #define USERFLAGSMASK_S 0x0f000432
  92. #define TPDUSIZESHIFT 24
  93. #define CLASSHIFT 16
  94.  
  95. /*
  96.  * NAME:     tp_consistency()
  97.  *
  98.  * CALLED FROM:
  99.  *     tp_ctloutput(), tp_input()
  100.  *
  101.  * FUNCTION and ARGUMENTS:
  102.  *     Checks the consistency of options and tpdusize with class,
  103.  *    using the parameters passed in via (param).
  104.  *    (cmd) may be TP_STRICT or TP_FORCE or both.
  105.  *  Force means it will set all the values in (tpcb) to those in
  106.  *  the input arguements iff no errors were encountered.
  107.  *  Strict means that no inconsistency will be tolerated.  If it's
  108.  *  not used, checksum and tpdusize inconsistencies will be tolerated.
  109.  *  The reason for this is that in some cases, when we're negotiating down 
  110.  *    from class  4, these options should be changed but should not 
  111.  *  cause negotiation to fail.
  112.  *
  113.  * RETURNS
  114.  *  E* or EOK
  115.  *  E* if the various parms aren't ok for a given class
  116.  *  EOK if they are ok for a given class
  117.  */
  118.  
  119. int
  120. tp_consistency( tpcb, cmd, param )
  121.     u_int cmd;
  122.     struct tp_conn_param *param;
  123.     struct tp_pcb *tpcb;
  124. {
  125.     register int    error = EOK;
  126.     int             class_to_use  = tp_mask_to_num(param->p_class);
  127.  
  128.     IFTRACE(D_SETPARAMS)
  129.         tptrace(TPPTmisc, 
  130.         "tp_consist enter class_to_use dontchange param.class cmd", 
  131.         class_to_use, param->p_dont_change_params, param->p_class, cmd);
  132.     ENDTRACE
  133.     IFDEBUG(D_SETPARAMS)
  134.         printf("tp_consistency %s %s\n", 
  135.             cmd& TP_FORCE?    "TP_FORCE":    "",
  136.             cmd& TP_STRICT?    "TP_STRICT":"");
  137.     ENDDEBUG
  138.     if ((cmd & TP_FORCE) && (param->p_dont_change_params)) {
  139.         cmd &= ~TP_FORCE;
  140.     }
  141.     /* can switch net services within a domain, but
  142.      * cannot switch domains 
  143.      */
  144.     switch( param->p_netservice) {
  145.     case ISO_CONS:
  146.     case ISO_CLNS:
  147.     case ISO_COSNS:
  148.         /* param->p_netservice in ISO DOMAIN */
  149.         if(tpcb->tp_domain != AF_ISO ) {
  150.             error = EINVAL; goto done;
  151.         }
  152.         break;
  153.     case IN_CLNS:
  154.         /* param->p_netservice in INET DOMAIN */
  155.         if( tpcb->tp_domain != AF_INET ) {
  156.             error = EINVAL; goto done;
  157.         }
  158.         break;
  159.         /* no others not possible-> netservice is a 2-bit field! */
  160.     }
  161.  
  162.     IFDEBUG(D_SETPARAMS)
  163.         printf("p_class 0x%x, class_to_use 0x%x\n",  param->p_class,
  164.             class_to_use);
  165.     ENDDEBUG
  166.     if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){
  167.         error = EINVAL; goto done;
  168.     }
  169.     if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) {
  170.         error = EINVAL; goto done;
  171.     } 
  172.     IFDEBUG(D_SETPARAMS)
  173.         printf("Nretrans 0x%x\n",  param->p_Nretrans );
  174.     ENDDEBUG
  175.     if( ( param->p_Nretrans < 1 ) ||
  176.           (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) {
  177.             /* bad for any class because negot has to be done a la class 4 */
  178.             error = EINVAL; goto done;
  179.     }
  180.     IFDEBUG(D_SETPARAMS)
  181.         printf("winsize 0x%x\n",  param->p_winsize );
  182.     ENDDEBUG
  183.     if( (param->p_winsize < 128 ) || 
  184.         (param->p_winsize < param->p_tpdusize ) ||
  185.         (param->p_winsize > ((1+SB_MAX)>>2 /* 1/4 of the max */)) ) {
  186.             error = EINVAL; goto done;
  187.     } else {
  188.         if( tpcb->tp_state == TP_CLOSED )
  189.             soreserve(tpcb->tp_sock, (u_long)param->p_winsize,
  190.                         (u_long)param->p_winsize);
  191.     }
  192.     IFDEBUG(D_SETPARAMS)
  193.         printf("use_csum 0x%x\n",  param->p_use_checksum );
  194.         printf("xtd_format 0x%x\n",  param->p_xtd_format );
  195.         printf("xpd_service 0x%x\n",  param->p_xpd_service );
  196.         printf("tpdusize 0x%x\n",  param->p_tpdusize );
  197.         printf("tpcb->flags 0x%x\n",  tpcb->tp_flags );
  198.     ENDDEBUG
  199.     switch( class_to_use ) {
  200.  
  201.     case 0:
  202.         /* do not use checksums, xtd format, or XPD */
  203.  
  204.         if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) {
  205.             if(cmd & TP_STRICT) {
  206.                 error = EINVAL;
  207.             } else {
  208.                 param->p_use_checksum = 0;
  209.                 param->p_xtd_format = 0;
  210.                 param->p_xpd_service = 0;
  211.             }
  212.             break;
  213.         }
  214.  
  215.         if (param->p_tpdusize < TP_MIN_TPDUSIZE) {
  216.             if(cmd & TP_STRICT) {
  217.                 error = EINVAL;
  218.             } else {
  219.                 param->p_tpdusize = TP_MIN_TPDUSIZE;
  220.             }
  221.             break;
  222.         }
  223.         if (param->p_tpdusize > TP0_TPDUSIZE)  {
  224.             if (cmd & TP_STRICT) {
  225.                 error = EINVAL; 
  226.             } else {
  227.                 param->p_tpdusize = TP0_TPDUSIZE;
  228.             }
  229.             break;
  230.         } 
  231.  
  232.         /* connect/disc data not allowed for class 0 */
  233.         if (tpcb->tp_ucddata) {
  234.             if(cmd & TP_STRICT) {
  235.                 error = EINVAL;
  236.             } else if(cmd & TP_FORCE) {
  237.                 m_freem(tpcb->tp_ucddata);
  238.                 tpcb->tp_ucddata = 0;
  239.             }
  240.         }
  241.         break;
  242.         
  243.     case 4:
  244.         IFDEBUG(D_SETPARAMS)
  245.             printf("dt_ticks 0x%x\n",  param->p_dt_ticks );
  246.             printf("x_ticks 0x%x\n",  param->p_x_ticks );
  247.             printf("dr_ticks 0x%x\n",  param->p_dr_ticks );
  248.             printf("keepalive 0x%x\n",  param->p_keepalive_ticks );
  249.             printf("sendack 0x%x\n",  param->p_sendack_ticks );
  250.             printf("inact 0x%x\n",  param->p_inact_ticks );
  251.             printf("ref 0x%x\n",  param->p_ref_ticks );
  252.         ENDDEBUG
  253.         if( (param->p_class & TP_CLASS_4 ) && (
  254.               (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 
  255.               (param->p_x_ticks < 1)    || (param->p_keepalive_ticks < 1) ||
  256.               (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) ||
  257.               (param->p_inact_ticks < 1) ) ) {
  258.                 error = EINVAL;
  259.                 break;
  260.         }
  261.         IFDEBUG(D_SETPARAMS)
  262.             printf("rx_strat 0x%x\n",  param->p_rx_strat );
  263.         ENDDEBUG
  264.         if(param->p_rx_strat > 
  265.             ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) {
  266.                 if(cmd & TP_STRICT) {
  267.                     error = EINVAL;
  268.                 } else {
  269.                     param->p_rx_strat = TPRX_USE_CW;
  270.                 }
  271.                 break;
  272.         }
  273.         IFDEBUG(D_SETPARAMS)
  274.             printf("ack_strat 0x%x\n",  param->p_ack_strat );
  275.         ENDDEBUG
  276.         if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) {
  277.             if(cmd & TP_STRICT) {
  278.                 error = EINVAL;
  279.             } else {
  280.                 param->p_ack_strat = TPACK_WINDOW;
  281.             }
  282.             break;
  283.         }
  284.         if (param->p_tpdusize < TP_MIN_TPDUSIZE) {
  285.             if(cmd & TP_STRICT) {
  286.                 error = EINVAL;
  287.             } else {
  288.                 param->p_tpdusize = TP_MIN_TPDUSIZE;
  289.             }
  290.             break;
  291.         }
  292.         if (param->p_tpdusize > TP_TPDUSIZE)  {
  293.             if(cmd & TP_STRICT) {
  294.                 error = EINVAL; 
  295.             } else {
  296.                 param->p_tpdusize = TP_TPDUSIZE;
  297.             }
  298.             break;
  299.         } 
  300.         break;
  301.     }
  302.  
  303.     if ((error==0) && (cmd & TP_FORCE)) {
  304.         /* Enforce Negotation rules below */
  305.         if (tpcb->tp_tpdusize > param->p_tpdusize)
  306.             tpcb->tp_tpdusize = param->p_tpdusize;
  307.         tpcb->tp_class = param->p_class;
  308.         if (tpcb->tp_use_checksum || param->p_use_checksum)
  309.             tpcb->tp_use_checksum = 1;
  310.         if (!tpcb->tp_xpd_service || !param->p_xpd_service)
  311.             tpcb->tp_xpd_service = 0;
  312.         if (!tpcb->tp_xtd_format || !param->p_xtd_format)
  313.             tpcb->tp_xtd_format = 0;
  314.     }
  315.  
  316. done:
  317.  
  318.     IFTRACE(D_CONN)
  319.         tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 
  320.             error, tpcb->tp_class, tpcb->tp_xtd_format, cmd);
  321.     ENDTRACE
  322.     IFDEBUG(D_CONN)
  323.         printf(
  324.         "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n",
  325.             error, tpcb->tp_class, tpcb->tp_xtd_format, cmd);
  326.     ENDDEBUG
  327.     return error;
  328. }
  329.  
  330. /*
  331.  * NAME:     tp_ctloutput()
  332.  *
  333.  * CALLED FROM:
  334.  *     [sg]etsockopt(), via so[sg]etopt(). 
  335.  *
  336.  * FUNCTION and ARGUMENTS:
  337.  *     Implements the socket options at transport level.
  338.  *     (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h).
  339.  *     (so) is the socket.
  340.  *     (level) is SOL_TRANSPORT (see ../sys/socket.h)
  341.  *     (optname) is the particular command or option to be set.
  342.  *     (**mp) is an mbuf structure.  
  343.  *
  344.  * RETURN VALUE:
  345.  *     ENOTSOCK if the socket hasn't got an associated tpcb
  346.  *  EINVAL if 
  347.  *         trying to set window too big
  348.  *         trying to set illegal max tpdu size 
  349.  *         trying to set illegal credit fraction
  350.  *         trying to use unknown or unimplemented class of TP
  351.  *        structure passed to set timer values is wrong size
  352.  *      illegal combination of command/GET-SET option, 
  353.  *            e.g., GET w/ TPOPT_CDDATA_CLEAR: 
  354.  *  EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET
  355.  *   or if the transport-specific command is not implemented
  356.  *  EISCONN if trying a command that isn't allowed after a connection
  357.  *   is established
  358.  *  ENOTCONN if trying a command that is allowed only if a connection is
  359.  *   established
  360.  *  EMSGSIZE if trying to give too much data on connect/disconnect
  361.  *
  362.  * SIDE EFFECTS:
  363.  *
  364.  * NOTES:
  365.  */
  366. ProtoHook 
  367. tp_ctloutput(cmd, so, level, optname, mp)
  368.     int             cmd, level, optname;
  369.     struct socket    *so;
  370.     struct mbuf     **mp;
  371. {
  372.     struct        tp_pcb    *tpcb = sototpcb(so);
  373.     int         s = splnet();
  374.     caddr_t        value;
  375.     unsigned    val_len;
  376.     int            error = 0;
  377.  
  378.     IFTRACE(D_REQUEST)
  379.         tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 
  380.             cmd, so, optname, mp);
  381.     ENDTRACE
  382.     IFDEBUG(D_REQUEST)
  383.         printf(
  384.     "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 
  385.             so, cmd, optname, mp, mp?*mp:0, tpcb);
  386.     ENDDEBUG
  387.     if( tpcb == (struct tp_pcb *)0 ) {
  388.         error = ENOTSOCK; goto done;
  389.     }
  390.     if(*mp == MNULL) {
  391.         register struct mbuf *m;
  392.  
  393.         MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */
  394.         if (m == NULL) {
  395.             splx(s);
  396.             return ENOBUFS;
  397.         }
  398.         m->m_len = 0;
  399.         m->m_act = 0;
  400.         *mp = m;
  401.     }
  402.  
  403.     /*
  404.      *    Hook so one can set network options via a tp socket.
  405.      */
  406.     if ( level == SOL_NETWORK ) {
  407.         if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL))
  408.             error = ENOTSOCK;
  409.         else if (tpcb->tp_nlproto->nlp_ctloutput == NULL)
  410.             error = EOPNOTSUPP;
  411.         else
  412.             error = (tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 
  413.                 tpcb->tp_npcb, *mp);
  414.         goto done;
  415.     } else if ( level !=  SOL_TRANSPORT ) {
  416.         error = EOPNOTSUPP; goto done;
  417.     } 
  418.     if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) {
  419.         error = EOPNOTSUPP; goto done;
  420.     } 
  421.     if ( so->so_error ) {
  422.         error = so->so_error; goto done;
  423.     }
  424.  
  425.     /* The only options allowed after connection is established
  426.      * are GET (anything) and SET DISC DATA and SET PERF MEAS
  427.      */
  428.     if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED))
  429.         &&
  430.         (cmd == PRCO_SETOPT  && 
  431.             optname != TPOPT_DISC_DATA && 
  432.             optname != TPOPT_CFRM_DATA && 
  433.             optname != TPOPT_PERF_MEAS &&
  434.             optname != TPOPT_CDDATA_CLEAR ) ) {
  435.         error = EISCONN; goto done;
  436.     } 
  437.     /* The only options allowed after disconnection are GET DISC DATA,
  438.      * and TPOPT_PSTATISTICS
  439.      * and they're not allowed if the ref timer has gone off, because
  440.      * the tpcb is gone 
  441.      */
  442.     if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) ==  0) {
  443.         if ( so->so_tpcb == (caddr_t)0 ) {
  444.             error = ENOTCONN; goto done;
  445.         }
  446.         if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) &&
  447.                 (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) {
  448.             error = ENOTCONN; goto done;
  449.         }
  450.     }
  451.  
  452.     value = mtod(*mp, caddr_t);  /* it's aligned, don't worry,
  453.                                   * but lint complains about it 
  454.                                   */
  455.     val_len = (*mp)->m_len;
  456.  
  457.     switch (optname) {
  458.  
  459.     case TPOPT_INTERCEPT:
  460.         if ((so->so_state & SS_PRIV) == 0) {
  461.             error = EPERM;
  462.             break;
  463.         } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_LISTENING)
  464.             error = EINVAL;
  465.         else {
  466.             register struct tp_pcb *t = 0;
  467.             struct mbuf *m = m_getclr(M_WAIT, MT_SONAME);
  468.             struct sockaddr *sa = mtod(m, struct sockaddr *);
  469.             (*tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, m, TP_LOCAL);
  470.             switch (sa->sa_family) {
  471.             case AF_ISO:
  472.                 if (((struct sockaddr_iso *)sa)->siso_nlen == 0)
  473.                     default: error = EINVAL;
  474.                 break;
  475.             case AF_INET:
  476.                 if (((struct sockaddr_in *)sa)->sin_addr.s_addr == 0)
  477.                     error = EINVAL;
  478.                 break;
  479.             }
  480.             for (t = tp_intercepts; t; t = t->tp_nextlisten) {
  481.                 if (t->tp_nlproto->nlp_afamily != tpcb->tp_nlproto->nlp_afamily)
  482.                     continue;
  483.                 if ((*t->tp_nlproto->nlp_cmpnetaddr)(t->tp_npcb, sa, TP_LOCAL))
  484.                     error = EADDRINUSE;
  485.             }
  486.             m_freem(m);
  487.             if (error)
  488.                 break;
  489.         }
  490.         {
  491.             register struct tp_pcb **tt;
  492.             for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
  493.                 if (*tt == tpcb)
  494.                     break;
  495.             if (*tt)
  496.                 *tt = tpcb->tp_nextlisten;
  497.             else
  498.                 {error = EHOSTUNREACH; goto done; }
  499.         }
  500.         tpcb->tp_nextlisten = tp_intercepts;
  501.         tp_intercepts = tpcb;
  502.         break;
  503.  
  504.     case TPOPT_MY_TSEL:
  505.         if ( cmd == PRCO_GETOPT ) {
  506.             ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN );
  507.             bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen);
  508.             (*mp)->m_len = tpcb->tp_lsuffixlen;
  509.         } else /* cmd == PRCO_SETOPT  */ {
  510.             if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) {
  511.                 printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp));
  512.                 error = EINVAL;
  513.             } else {
  514.                 bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len);
  515.                 tpcb->tp_lsuffixlen = val_len;
  516.             }
  517.         }
  518.         break;
  519.  
  520.     case TPOPT_PEER_TSEL:
  521.         if ( cmd == PRCO_GETOPT ) {
  522.             ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN );
  523.             bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen);
  524.             (*mp)->m_len = tpcb->tp_fsuffixlen;
  525.         } else /* cmd == PRCO_SETOPT  */ {
  526.             if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) {
  527.                 printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp));
  528.                 error = EINVAL; 
  529.             } else {
  530.                 bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len);
  531.                 tpcb->tp_fsuffixlen = val_len;
  532.             }
  533.         }
  534.         break;
  535.  
  536.     case TPOPT_FLAGS:
  537.         IFDEBUG(D_REQUEST)
  538.             printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 
  539.                 cmd==PRCO_GETOPT?"GET":"SET", 
  540.                 value,
  541.                 *value, 
  542.                 tpcb->tp_flags);
  543.         ENDDEBUG
  544.  
  545.         if ( cmd == PRCO_GETOPT ) {
  546.             *(int *)value = (int)tpcb->tp_flags;
  547.             (*mp)->m_len = sizeof(u_int);
  548.         } else /* cmd == PRCO_SETOPT  */ {
  549.             error = EINVAL; goto done;
  550.         }
  551.         break;
  552.  
  553.     case TPOPT_PARAMS:
  554.         /* This handles:
  555.          * timer values,
  556.          * class, use of transport expedited data,
  557.          * max tpdu size, checksum, xtd format and
  558.          * disconnect indications, and may get rid of connect/disc data
  559.          */
  560.         IFDEBUG(D_SETPARAMS)
  561.             printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value,
  562.                 cmd==PRCO_GETOPT?"GET":"SET");
  563.         ENDDEBUG
  564.         IFDEBUG(D_REQUEST)
  565.             printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value,
  566.                 cmd==PRCO_GETOPT?"GET":"SET");
  567.         ENDDEBUG
  568.  
  569.         if ( cmd == PRCO_GETOPT ) {
  570.             *(struct tp_conn_param *)value = tpcb->_tp_param;
  571.             (*mp)->m_len = sizeof(tpcb->_tp_param);
  572.         } else /* cmd == PRCO_SETOPT  */ {
  573.             if( (error = 
  574.                 tp_consistency(tpcb, TP_STRICT | TP_FORCE, 
  575.                                 (struct tp_conn_param *)value))==0) {
  576.                 /* 
  577.                  * tp_consistency doesn't copy the whole set of params 
  578.                  */
  579.                 tpcb->_tp_param = *(struct tp_conn_param *)value;
  580.                 (*mp)->m_len = sizeof(tpcb->_tp_param);
  581.             }
  582.         }
  583.         break;
  584.  
  585.     case TPOPT_PSTATISTICS: 
  586. #ifdef TP_PERF_MEAS
  587.         if (cmd == PRCO_SETOPT) {
  588.             error = EINVAL; goto done;
  589.         } 
  590.         IFPERF(tpcb)
  591.             if (*mp) {
  592.                 struct mbuf * n;
  593.                 do {
  594.                     MFREE(*mp, n);
  595.                     *mp = n;
  596.                 } while (n);
  597.             }
  598.             *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK);
  599.         ENDPERF 
  600.         else {
  601.             error = EINVAL; goto done;
  602.         } 
  603.         break;
  604. #else
  605.         error = EOPNOTSUPP;
  606.         goto done;
  607. #endif TP_PERF_MEAS
  608.         
  609.     case TPOPT_CDDATA_CLEAR: 
  610.         if (cmd == PRCO_GETOPT) {
  611.             error = EINVAL;
  612.         } else {
  613.             if (tpcb->tp_ucddata) {
  614.                 m_freem(tpcb->tp_ucddata);
  615.                 tpcb->tp_ucddata = 0;
  616.             }
  617.         }
  618.         break;
  619.  
  620.     case TPOPT_CFRM_DATA:
  621.     case TPOPT_DISC_DATA: 
  622.     case TPOPT_CONN_DATA: 
  623.         if( tpcb->tp_class == TP_CLASS_0 ) {
  624.             error = EOPNOTSUPP;
  625.             break;
  626.         }
  627.         IFDEBUG(D_REQUEST)
  628.             printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data");
  629.             printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 
  630.                 (*mp)->m_len, val_len, so->so_snd.sb_cc);
  631.             dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd ");
  632.         ENDDEBUG
  633.         if (cmd == PRCO_SETOPT) {
  634.             int len = tpcb->tp_ucddata ?  tpcb->tp_ucddata->m_len : 0;
  635.             /* can append connect data in several calls */
  636.             if (len + val_len > 
  637.                 (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) {
  638.                 error = EMSGSIZE; goto done;
  639.             } 
  640.             (*mp)->m_next = MNULL;
  641.             (*mp)->m_act = 0;
  642.             if (tpcb->tp_ucddata)
  643.                 m_cat(tpcb->tp_ucddata, *mp);
  644.             else
  645.                 tpcb->tp_ucddata = *mp;
  646.             IFDEBUG(D_REQUEST)
  647.                 dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA");
  648.             ENDDEBUG
  649.             IFTRACE(D_REQUEST)
  650.                 tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len",
  651.                     tpcb->tp_flags, so->so_snd.sb_cc,val_len,0);
  652.             ENDTRACE
  653.             *mp = MNULL; /* prevent sosetopt from freeing it! */
  654.             if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING))
  655.                 (void) tp_confirm(tpcb);
  656.         }
  657.         break;
  658.  
  659.     case TPOPT_PERF_MEAS: 
  660. #ifdef TP_PERF_MEAS
  661.         if (cmd == PRCO_GETOPT) {
  662.             *value = (u_int)tpcb->tp_perf_on;
  663.             (*mp)->m_len = sizeof(u_int);
  664.         } else if (cmd == PRCO_SETOPT) {
  665.             (*mp)->m_len = 0;
  666.             if ((*value) != 0 && (*value) != 1 )
  667.                 error = EINVAL;
  668.             else  tpcb->tp_perf_on = (*value);
  669.         }
  670.         if( tpcb->tp_perf_on ) 
  671.             error = tp_setup_perf(tpcb);
  672. #else  TP_PERF_MEAS
  673.         error = EOPNOTSUPP;
  674. #endif TP_PERF_MEAS
  675.         break;
  676.  
  677.     default:
  678.         error = EOPNOTSUPP;
  679.     }
  680.     
  681. done:
  682.     IFDEBUG(D_REQUEST)
  683.         dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end");
  684.         dump_mbuf(*mp, "tp_ctloutput *mp");
  685.     ENDDEBUG
  686.     /* 
  687.      * sigh: getsockopt looks only at m_len : all output data must 
  688.      * reside in the first mbuf 
  689.      */
  690.     if ( error  && (*mp) != MNULL )
  691.         (*mp)->m_len = 0;
  692.     if( (*mp) != MNULL ) {
  693.         ASSERT ( m_compress(*mp, mp) <= MLEN );
  694.         IFDEBUG(D_REQUEST)
  695.             dump_mbuf(*mp, "tp_ctloutput *mp after compress");
  696.         ENDDEBUG
  697.     }
  698.         
  699.     splx(s);
  700.     return error;
  701. }
  702.