The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netiso/tp_output.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: tp_output.c,v 1.35 2008/08/06 15:01:23 plunky Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)tp_output.c 8.2 (Berkeley) 2/9/95
   32  */
   33 
   34 /***********************************************************
   35                 Copyright IBM Corporation 1987
   36 
   37                       All Rights Reserved
   38 
   39 Permission to use, copy, modify, and distribute this software and its
   40 documentation for any purpose and without fee is hereby granted,
   41 provided that the above copyright notice appear in all copies and that
   42 both that copyright notice and this permission notice appear in
   43 supporting documentation, and that the name of IBM not be
   44 used in advertising or publicity pertaining to distribution of the
   45 software without specific, written prior permission.
   46 
   47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
   49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
   51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
   52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   53 SOFTWARE.
   54 
   55 ******************************************************************/
   56 
   57 /*
   58  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
   59  */
   60 /*
   61  * In here is tp_ctloutput(), the guy called by [sg]etsockopt(),
   62  */
   63 
   64 #include <sys/cdefs.h>
   65 __KERNEL_RCSID(0, "$NetBSD: tp_output.c,v 1.35 2008/08/06 15:01:23 plunky Exp $");
   66 
   67 #include "opt_inet.h"
   68 #include "opt_iso.h"
   69 
   70 #include <sys/param.h>
   71 #include <sys/mbuf.h>
   72 #include <sys/systm.h>
   73 #include <sys/socket.h>
   74 #include <sys/socketvar.h>
   75 #include <sys/protosw.h>
   76 #include <sys/errno.h>
   77 #include <sys/time.h>
   78 #include <sys/kernel.h>
   79 #include <sys/proc.h>
   80 #include <sys/kauth.h>
   81 
   82 #include <netiso/tp_param.h>
   83 #include <netiso/tp_var.h>
   84 #include <netiso/tp_user.h>
   85 #include <netiso/tp_stat.h>
   86 #include <netiso/tp_ip.h>
   87 #include <netiso/tp_clnp.h>
   88 #include <netiso/tp_timer.h>
   89 #include <netiso/argo_debug.h>
   90 #include <netiso/tp_pcb.h>
   91 #include <netiso/tp_trace.h>
   92 
   93 #define TPDUSIZESHIFT 24
   94 #define CLASSHIFT 16
   95 
   96 /*
   97  * NAME:        tp_consistency()
   98  *
   99  * CALLED FROM:
  100  *      tp_ctloutput(), tp_input()
  101  *
  102  * FUNCTION and ARGUMENTS:
  103  *      Checks the consistency of options and tpdusize with class,
  104  *      using the parameters passed in via (param).
  105  *      (cmd) may be TP_STRICT or TP_FORCE or both.
  106  *  Force means it will set all the values in (tpcb) to those in
  107  *  the input arguments iff no errors were encountered.
  108  *  Strict means that no inconsistency will be tolerated.  If it's
  109  *  not used, checksum and tpdusize inconsistencies will be tolerated.
  110  *  The reason for this is that in some cases, when we're negotiating down
  111  *      from class  4, these options should be changed but should not
  112  *  cause negotiation to fail.
  113  *
  114  * RETURNS
  115  *  E* or EOK
  116  *  E* if the various parms aren't ok for a given class
  117  *  EOK if they are ok for a given class
  118  */
  119 
  120 int
  121 tp_consistency(struct tp_pcb *tpcb, u_int cmd, struct tp_conn_param *param)
  122 {
  123         int    error = EOK;
  124         int             class_to_use = tp_mask_to_num(param->p_class);
  125 
  126 #ifdef TPPT
  127         if (tp_traceflags[D_SETPARAMS]) {
  128                 tptrace(TPPTmisc,
  129                  "tp_consist enter class_to_use dontchange param.class cmd",
  130             class_to_use, param->p_dont_change_params, param->p_class, cmd);
  131         }
  132 #endif
  133 #ifdef ARGO_DEBUG
  134         if (argo_debug[D_SETPARAMS]) {
  135                 printf("tp_consistency %s %s\n",
  136                        cmd & TP_FORCE ? "TP_FORCE" : "",
  137                        cmd & TP_STRICT ? "TP_STRICT" : "");
  138         }
  139 #endif
  140         if ((cmd & TP_FORCE) && (param->p_dont_change_params)) {
  141                 cmd &= ~TP_FORCE;
  142         }
  143         /*
  144          * can switch net services within a domain, but cannot switch domains
  145          */
  146         switch (param->p_netservice) {
  147         case ISO_CONS:
  148         case ISO_CLNS:
  149         case ISO_COSNS:
  150                 /* param->p_netservice in ISO DOMAIN */
  151                 if (tpcb->tp_domain != AF_ISO) {
  152                         error = EINVAL;
  153                         goto done;
  154                 }
  155                 break;
  156         case IN_CLNS:
  157                 /* param->p_netservice in INET DOMAIN */
  158                 if (tpcb->tp_domain != AF_INET) {
  159                         error = EINVAL;
  160                         goto done;
  161                 }
  162                 break;
  163                 /* no others not possible-> netservice is a 2-bit field! */
  164         }
  165 
  166 #ifdef ARGO_DEBUG
  167         if (argo_debug[D_SETPARAMS]) {
  168                 printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class,
  169                        class_to_use);
  170         }
  171 #endif
  172         if ((param->p_netservice > TP_MAX_NETSERVICES)) {
  173                 error = EINVAL;
  174                 goto done;
  175         }
  176         if ((param->p_class & TP_CLASSES_IMPLEMENTED) == 0) {
  177                 error = EINVAL;
  178                 goto done;
  179         }
  180 #ifdef ARGO_DEBUG
  181         if (argo_debug[D_SETPARAMS]) {
  182                 printf("Nretrans 0x%x\n", param->p_Nretrans);
  183         }
  184 #endif
  185         if ((param->p_Nretrans < 1) ||
  186             (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1)) {
  187                 /*
  188                  * bad for any class because negot has to be done a la class
  189                  * 4
  190                  */
  191                 error = EINVAL;
  192                 goto done;
  193         }
  194 #ifdef ARGO_DEBUG
  195         if (argo_debug[D_SETPARAMS]) {
  196                 printf("use_csum 0x%x\n", param->p_use_checksum);
  197                 printf("xtd_format 0x%x\n", param->p_xtd_format);
  198                 printf("xpd_service 0x%x\n", param->p_xpd_service);
  199                 printf("tpdusize 0x%x\n", param->p_tpdusize);
  200                 printf("tpcb->flags 0x%x\n", tpcb->tp_flags);
  201         }
  202 #endif
  203         switch (class_to_use) {
  204 
  205         case 0:
  206                 /* do not use checksums, xtd format, or XPD */
  207 
  208                 if (param->p_use_checksum | param->p_xtd_format | param->p_xpd_service) {
  209                         if (cmd & TP_STRICT) {
  210                                 error = EINVAL;
  211                         } else {
  212                                 param->p_use_checksum = 0;
  213                                 param->p_xtd_format = 0;
  214                                 param->p_xpd_service = 0;
  215                         }
  216                         break;
  217                 }
  218                 if (param->p_tpdusize < TP_MIN_TPDUSIZE) {
  219                         if (cmd & TP_STRICT) {
  220                                 error = EINVAL;
  221                         } else {
  222                                 param->p_tpdusize = TP_MIN_TPDUSIZE;
  223                         }
  224                         break;
  225                 }
  226                 if (param->p_tpdusize > TP0_TPDUSIZE) {
  227                         if (cmd & TP_STRICT) {
  228                                 error = EINVAL;
  229                         } else {
  230                                 param->p_tpdusize = TP0_TPDUSIZE;
  231                         }
  232                         break;
  233                 }
  234                 /* connect/disc data not allowed for class 0 */
  235                 if (tpcb->tp_ucddata) {
  236                         if (cmd & TP_STRICT) {
  237                                 error = EINVAL;
  238                         } else if (cmd & TP_FORCE) {
  239                                 m_freem(tpcb->tp_ucddata);
  240                                 tpcb->tp_ucddata = 0;
  241                         }
  242                 }
  243                 break;
  244 
  245         case 4:
  246 #ifdef ARGO_DEBUG
  247                 if (argo_debug[D_SETPARAMS]) {
  248                         printf("dt_ticks 0x%x\n", param->p_dt_ticks);
  249                         printf("x_ticks 0x%x\n", param->p_x_ticks);
  250                         printf("dr_ticks 0x%x\n", param->p_dr_ticks);
  251                         printf("keepalive 0x%x\n", param->p_keepalive_ticks);
  252                         printf("sendack 0x%x\n", param->p_sendack_ticks);
  253                         printf("inact 0x%x\n", param->p_inact_ticks);
  254                         printf("ref 0x%x\n", param->p_ref_ticks);
  255                 }
  256 #endif
  257                 if ((param->p_class & TP_CLASS_4) && (
  258                        (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) ||
  259                  (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) ||
  260                  (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) ||
  261                                               (param->p_inact_ticks < 1))) {
  262                         error = EINVAL;
  263                         break;
  264                 }
  265 #ifdef ARGO_DEBUG
  266                 if (argo_debug[D_SETPARAMS]) {
  267                         printf("rx_strat 0x%x\n", param->p_rx_strat);
  268                 }
  269 #endif
  270                 if (param->p_rx_strat >
  271                     (TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART)) {
  272                         if (cmd & TP_STRICT) {
  273                                 error = EINVAL;
  274                         } else {
  275                                 param->p_rx_strat = TPRX_USE_CW;
  276                         }
  277                         break;
  278                 }
  279 #ifdef ARGO_DEBUG
  280                 if (argo_debug[D_SETPARAMS]) {
  281                         printf("ack_strat 0x%x\n", param->p_ack_strat);
  282                 }
  283 #endif
  284                 if ((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) {
  285                         if (cmd & TP_STRICT) {
  286                                 error = EINVAL;
  287                         } else {
  288                                 param->p_ack_strat = TPACK_WINDOW;
  289                         }
  290                         break;
  291                 }
  292                 if (param->p_tpdusize < TP_MIN_TPDUSIZE) {
  293                         if (cmd & TP_STRICT) {
  294                                 error = EINVAL;
  295                         } else {
  296                                 param->p_tpdusize = TP_MIN_TPDUSIZE;
  297                         }
  298                         break;
  299                 }
  300                 if (param->p_tpdusize > TP_TPDUSIZE) {
  301                         if (cmd & TP_STRICT) {
  302                                 error = EINVAL;
  303                         } else {
  304                                 param->p_tpdusize = TP_TPDUSIZE;
  305                         }
  306                         break;
  307                 }
  308                 break;
  309         }
  310 
  311         if ((error == 0) && (cmd & TP_FORCE)) {
  312                 long            dusize = ((long) param->p_ptpdusize) << 7;
  313                 /* Enforce Negotation rules below */
  314                 tpcb->tp_class = param->p_class;
  315                 if (tpcb->tp_use_checksum || param->p_use_checksum)
  316                         tpcb->tp_use_checksum = 1;
  317                 if (!tpcb->tp_xpd_service || !param->p_xpd_service)
  318                         tpcb->tp_xpd_service = 0;
  319                 if (!tpcb->tp_xtd_format || !param->p_xtd_format)
  320                         tpcb->tp_xtd_format = 0;
  321                 if (dusize) {
  322                         if (tpcb->tp_l_tpdusize > dusize)
  323                                 tpcb->tp_l_tpdusize = dusize;
  324                         if (tpcb->tp_ptpdusize == 0 ||
  325                             tpcb->tp_ptpdusize > param->p_ptpdusize)
  326                                 tpcb->tp_ptpdusize = param->p_ptpdusize;
  327                 } else {
  328                         if (param->p_tpdusize != 0 &&
  329                             tpcb->tp_tpdusize > param->p_tpdusize)
  330                                 tpcb->tp_tpdusize = param->p_tpdusize;
  331                         tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
  332                 }
  333         }
  334 done:
  335 
  336 #ifdef TPPT
  337         if (tp_traceflags[D_CONN]) {
  338                 tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd",
  339                         error, tpcb->tp_class, tpcb->tp_xtd_format, cmd);
  340         }
  341 #endif
  342 #ifdef ARGO_DEBUG
  343                 if (argo_debug[D_CONN]) {
  344                 printf(
  345                   "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n",
  346                        error, tpcb->tp_class, tpcb->tp_xtd_format, cmd);
  347         }
  348 #endif
  349         return error;
  350 }
  351 
  352 /*
  353  * NAME:        tp_ctloutput1()
  354  *
  355  * CALLED FROM:
  356  *      [sg]etsockopt(), via so[sg]etopt().
  357  *      via tp_ctloutput() below
  358  *
  359  * FUNCTION and ARGUMENTS:
  360  *      Implements the socket options at transport level.
  361  *      (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h).
  362  *      (so) is the socket.
  363  *      (level) is SOL_TRANSPORT (see ../sys/socket.h)
  364  *      (optname) is the particular command or option to be set.
  365  *      (**mp) is an mbuf structure.
  366  *
  367  * RETURN VALUE:
  368  *      ENOTSOCK if the socket hasn't got an associated tpcb
  369  *  EINVAL if
  370  *              trying to set window too big
  371  *              trying to set illegal max tpdu size
  372  *              trying to set illegal credit fraction
  373  *              trying to use unknown or unimplemented class of TP
  374  *              structure passed to set timer values is wrong size
  375  *      illegal combination of command/GET-SET option,
  376  *                      e.g., GET w/ TPOPT_CDDATA_CLEAR:
  377  *  EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET
  378  *   or if the transport-specific command is not implemented
  379  *  EISCONN if trying a command that isn't allowed after a connection
  380  *   is established
  381  *  ENOTCONN if trying a command that is allowed only if a connection is
  382  *   established
  383  *  EMSGSIZE if trying to give too much data on connect/disconnect
  384  *
  385  * SIDE EFFECTS:
  386  *
  387  * NOTES:
  388  */
  389 static int
  390 tp_ctloutput1(int cmd, struct socket  *so, int level, int optname,
  391         struct mbuf **mp)
  392 {
  393         struct lwp *l = curlwp;         /* XXX */
  394         struct tp_pcb  *tpcb = sototpcb(so);
  395         int             s = splsoftnet();
  396         void *        value;
  397         unsigned        val_len;
  398         int             error = 0;
  399 
  400 #ifdef TPPT
  401         if (tp_traceflags[D_REQUEST]) {
  402                 tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp",
  403                         cmd, so, optname, mp);
  404         }
  405 #endif
  406 #ifdef ARGO_DEBUG
  407         if (argo_debug[D_REQUEST]) {
  408                 printf(
  409                        "tp_ctloutput so %p cmd 0x%x optname 0x%x, mp %p *mp %p tpcb %p\n",
  410                        so, cmd, optname, mp, mp ? *mp : 0, tpcb);
  411         }
  412 #endif
  413         if (tpcb == (struct tp_pcb *) 0) {
  414                 error = ENOTSOCK;
  415                 goto done;
  416         }
  417         if (mp && *mp == NULL) {
  418                 struct mbuf *m;
  419 
  420                 MGET(m, M_DONTWAIT, TPMT_SONAME);       /* does off, type, next */
  421                 if (m == NULL) {
  422                         splx(s);
  423                         return ENOBUFS;
  424                 }
  425                 m->m_len = 0;
  426                 m->m_nextpkt = 0;
  427                 *mp = m;
  428         }
  429         /*
  430          *      Hook so one can set network options via a tp socket.
  431          */
  432         if (level == SOL_NETWORK) {
  433                 if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL))
  434                         error = ENOTSOCK;
  435                 else if (tpcb->tp_nlproto->nlp_ctloutput == NULL)
  436                         error = EOPNOTSUPP;
  437                 else
  438                         return ((tpcb->tp_nlproto->nlp_ctloutput) (cmd, optname,
  439                                                        tpcb->tp_npcb, *mp));
  440                 goto done;
  441         } else if (level == SOL_SOCKET) {
  442                 if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) {
  443                         u_long          old_credit = tpcb->tp_maxlcredit;
  444                         tp_rsyset(tpcb);
  445                         if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat &&
  446                             tpcb->tp_state == TP_OPEN &&
  447                             (old_credit < tpcb->tp_maxlcredit))
  448                                 tp_emit(AK_TPDU_type, tpcb,
  449                                         tpcb->tp_rcvnxt, 0, NULL);
  450                         tpcb->tp_rhiwat = so->so_rcv.sb_hiwat;
  451                 }
  452                 goto done;
  453         } else if (level != SOL_TRANSPORT) {
  454                 error = EOPNOTSUPP;
  455                 goto done;
  456         }
  457         if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) {
  458                 error = EOPNOTSUPP;
  459                 goto done;
  460         }
  461         if (so->so_error) {
  462                 error = so->so_error;
  463                 goto done;
  464         }
  465         /*
  466          * The only options allowed after connection is established are GET
  467          * (anything) and SET DISC DATA and SET PERF MEAS
  468          */
  469         if (((so->so_state & SS_ISCONNECTING) || (so->so_state & SS_ISCONNECTED))
  470             &&
  471             (cmd == PRCO_SETOPT &&
  472              optname != TPOPT_DISC_DATA &&
  473              optname != TPOPT_CFRM_DATA &&
  474              optname != TPOPT_PERF_MEAS &&
  475              optname != TPOPT_CDDATA_CLEAR)) {
  476                 error = EISCONN;
  477                 goto done;
  478         }
  479         /*
  480          * The only options allowed after disconnection are GET DISC DATA,
  481          * and TPOPT_PSTATISTICS and they're not allowed if the ref timer has
  482          * gone off, because the tpcb is gone
  483          */
  484         if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) {
  485                 if (so->so_pcb == 0) {
  486                         error = ENOTCONN;
  487                         goto done;
  488                 }
  489                 if ((tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) &&
  490                     (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) {
  491                         error = ENOTCONN;
  492                         goto done;
  493                 }
  494         }
  495         value = mtod(*mp, void *);      /* it's aligned, don't worry, but
  496                                          * lint complains about it */
  497         val_len = (*mp)->m_len;
  498 
  499         switch (optname) {
  500 
  501         case TPOPT_INTERCEPT:
  502 #define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr)
  503 #define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr)
  504 
  505                 if (l == 0 || (error = kauth_authorize_generic(l->l_cred,
  506                     KAUTH_GENERIC_ISSUSER, NULL))) {
  507                         error = EPERM;
  508                 } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED ||
  509                            (tpcb->tp_flags & TPF_GENERAL_ADDR) ||
  510                            tpcb->tp_next == 0)
  511                         error = EINVAL;
  512                 else {
  513                         struct tp_pcb *t;
  514                         error = EADDRINUSE;
  515                         for (t = tp_listeners; t; t = t->tp_nextlisten)
  516                                 if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 &&
  517                                     t->tp_domain == tpcb->tp_domain)
  518                                         switch (tpcb->tp_domain) {
  519                                         default:
  520                                                 goto done;
  521 #ifdef  INET
  522                                         case AF_INET:
  523                                                 if (INA(t) == INA(tpcb))
  524                                                         goto done;
  525                                                 continue;
  526 #endif
  527 #ifdef ISO
  528                                         case AF_ISO:
  529                                                 if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr,
  530                                                      ISOA(t).isoa_len) == 0)
  531                                                         goto done;
  532                                                 continue;
  533 #endif
  534                                         }
  535                         tpcb->tp_lsuffixlen = 0;
  536                         tpcb->tp_state = TP_LISTENING;
  537                         error = 0;
  538                         iso_remque(tpcb);
  539                         tpcb->tp_next = tpcb->tp_prev = tpcb;
  540                         tpcb->tp_nextlisten = tp_listeners;
  541                         tp_listeners = tpcb;
  542                 }
  543                 break;
  544 
  545         case TPOPT_MY_TSEL:
  546                 if (cmd == PRCO_GETOPT) {
  547                         ASSERT(tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN);
  548                         bcopy((void *) tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen);
  549                         (*mp)->m_len = tpcb->tp_lsuffixlen;
  550                 } else {        /* cmd == PRCO_SETOPT  */
  551                         if ((val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0)) {
  552                                 printf("val_len 0x%x (*mp)->m_len %p\n",
  553                                     val_len, (*mp));
  554                                 error = EINVAL;
  555                         } else {
  556                                 bcopy(value, (void *) tpcb->tp_lsuffix, val_len);
  557                                 tpcb->tp_lsuffixlen = val_len;
  558                         }
  559                 }
  560                 break;
  561 
  562         case TPOPT_PEER_TSEL:
  563                 if (cmd == PRCO_GETOPT) {
  564                         ASSERT(tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN);
  565                         bcopy((void *) tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen);
  566                         (*mp)->m_len = tpcb->tp_fsuffixlen;
  567                 } else {        /* cmd == PRCO_SETOPT  */
  568                         if ((val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0)) {
  569                                 printf("val_len 0x%x (*mp)->m_len %p\n",
  570                                     val_len, (*mp));
  571                                 error = EINVAL;
  572                         } else {
  573                                 bcopy(value, (void *) tpcb->tp_fsuffix, val_len);
  574                                 tpcb->tp_fsuffixlen = val_len;
  575                         }
  576                 }
  577                 break;
  578 
  579         case TPOPT_FLAGS:
  580 #ifdef ARGO_DEBUG
  581                 if (argo_debug[D_REQUEST]) {
  582                         printf("%s TPOPT_FLAGS value %p *value 0x%x, flags 0x%x \n",
  583                                cmd == PRCO_GETOPT ? "GET" : "SET",
  584                                value,
  585                                *(unsigned char *)value,
  586                                tpcb->tp_flags);
  587                 }
  588 #endif
  589 
  590                 if (cmd == PRCO_GETOPT) {
  591                         *(int *) value = (int) tpcb->tp_flags;
  592                         (*mp)->m_len = sizeof(u_int);
  593                 } else {        /* cmd == PRCO_SETOPT  */
  594                         error = EINVAL;
  595                         goto done;
  596                 }
  597                 break;
  598 
  599         case TPOPT_PARAMS:
  600                 /*
  601                  * This handles: timer values, class, use of transport
  602                  * expedited data, max tpdu size, checksum, xtd format and
  603                  * disconnect indications, and may get rid of connect/disc
  604                  * data
  605                  */
  606 #ifdef ARGO_DEBUG
  607                 if (argo_debug[D_SETPARAMS]) {
  608                         printf("TPOPT_PARAMS value %p, cmd %s \n", value,
  609                                cmd == PRCO_GETOPT ? "GET" : "SET");
  610                 }
  611 #endif
  612 #ifdef ARGO_DEBUG
  613                 if (argo_debug[D_REQUEST]) {
  614                         printf("TPOPT_PARAMS value %p, cmd %s \n", value,
  615                                cmd == PRCO_GETOPT ? "GET" : "SET");
  616                 }
  617 #endif
  618 
  619                 if (cmd == PRCO_GETOPT) {
  620                         *(struct tp_conn_param *) value = tpcb->_tp_param;
  621                         (*mp)->m_len = sizeof(tpcb->_tp_param);
  622                 } else {        /* cmd == PRCO_SETOPT  */
  623                         if ((error =
  624                              tp_consistency(tpcb, TP_STRICT | TP_FORCE,
  625                                     (struct tp_conn_param *) value)) == 0) {
  626                                 /*
  627                                  * tp_consistency doesn't copy the whole set
  628                                  * of params
  629                                  */
  630                                 tpcb->_tp_param = *(struct tp_conn_param *) value;
  631                                 (*mp)->m_len = sizeof(tpcb->_tp_param);
  632                         }
  633                 }
  634                 break;
  635 
  636         case TPOPT_PSTATISTICS:
  637 #ifdef TP_PERF_MEAS
  638                 if (cmd == PRCO_SETOPT) {
  639                         error = EINVAL;
  640                         goto done;
  641                 }
  642                 if (tpcb->tp_perf_on) {
  643                         m_clget(*mp, M_WAIT);
  644                         if (((*mp)->m_flags & M_EXT) == 0) {
  645                                 error = ENOBUFS; goto done;
  646                         }
  647                         (*mp)->m_len = sizeof(struct tp_pmeas);
  648                         bcopy(tpcb->tp_p_meas, mtod(*mp), sizeof(struct tp_pmeas));
  649                 }
  650                 else {
  651                         error = EINVAL;
  652                         goto done;
  653                 }
  654                 break;
  655 #else
  656                 error = EOPNOTSUPP;
  657                 goto done;
  658 #endif                          /* TP_PERF_MEAS */
  659 
  660         case TPOPT_CDDATA_CLEAR:
  661                 if (cmd == PRCO_GETOPT) {
  662                         error = EINVAL;
  663                 } else {
  664                         if (tpcb->tp_ucddata) {
  665                                 m_freem(tpcb->tp_ucddata);
  666                                 tpcb->tp_ucddata = 0;
  667                         }
  668                 }
  669                 break;
  670 
  671         case TPOPT_CFRM_DATA:
  672         case TPOPT_DISC_DATA:
  673         case TPOPT_CONN_DATA:
  674                 if (tpcb->tp_class == TP_CLASS_0) {
  675                         error = EOPNOTSUPP;
  676                         break;
  677                 }
  678 #ifdef ARGO_DEBUG
  679                 if (argo_debug[D_REQUEST]) {
  680                         printf("%s\n", optname == TPOPT_DISC_DATA ? "DISC data" : "CONN data");
  681                         printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%lx\n",
  682                                (*mp)->m_len, val_len, so->so_snd.sb_cc);
  683                         dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd ");
  684                 }
  685 #endif
  686                 if (cmd == PRCO_SETOPT) {
  687                         int             len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0;
  688                         /* can append connect data in several calls */
  689                         if (len + val_len >
  690                             (optname == TPOPT_CONN_DATA ? TP_MAX_CR_DATA : TP_MAX_DR_DATA)) {
  691                                 error = EMSGSIZE;
  692                                 goto done;
  693                         }
  694                         (*mp)->m_next = NULL;
  695                         (*mp)->m_nextpkt = 0;
  696                         if (tpcb->tp_ucddata)
  697                                 m_cat(tpcb->tp_ucddata, *mp);
  698                         else
  699                                 tpcb->tp_ucddata = *mp;
  700 #ifdef ARGO_DEBUG
  701                         if (argo_debug[D_REQUEST]) {
  702                                 dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA");
  703                         }
  704 #endif
  705 #ifdef TPPT
  706                         if (tp_traceflags[D_REQUEST]) {
  707                                 tptrace(TPPTmisc, "C/D DATA: flags snd.sbcc val_len",
  708                               tpcb->tp_flags, so->so_snd.sb_cc, val_len, 0);
  709                         }
  710 #endif
  711                         *mp = NULL;
  712                         if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING))
  713                                 (void) tp_confirm(tpcb);
  714                 }
  715                 break;
  716 
  717         case TPOPT_PERF_MEAS:
  718 #ifdef TP_PERF_MEAS
  719                 if (cmd == PRCO_GETOPT) {
  720                         *value = (u_int) tpcb->tp_perf_on;
  721                         (*mp)->m_len = sizeof(u_int);
  722                 } else if (cmd == PRCO_SETOPT) {
  723                         (*mp)->m_len = 0;
  724                         if ((*value) != 0 && (*value) != 1)
  725                                 error = EINVAL;
  726                         else
  727                                 tpcb->tp_perf_on = (*value);
  728                 }
  729                 if (tpcb->tp_perf_on)
  730                         error = tp_setup_perf(tpcb);
  731 #else                           /* TP_PERF_MEAS */
  732                 error = EOPNOTSUPP;
  733 #endif                          /* TP_PERF_MEAS */
  734                 break;
  735 
  736         default:
  737                 error = EOPNOTSUPP;
  738         }
  739 
  740 done:
  741 #ifdef ARGO_DEBUG
  742         if (argo_debug[D_REQUEST]) {
  743                 dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end");
  744                 dump_mbuf(*mp, "tp_ctloutput *mp");
  745         }
  746 #endif
  747         /*
  748          * sigh: getsockopt looks only at m_len : all output data must reside
  749          * in the first mbuf
  750          */
  751         if (*mp) {
  752                 if (cmd == PRCO_SETOPT) {
  753                         m_freem(*mp);
  754                         *mp = NULL;
  755                 } else {
  756                         ASSERT(m_compress(*mp, mp) <= MLEN);
  757                         if (error)
  758                                 (*mp)->m_len = 0;
  759 #ifdef ARGO_DEBUG
  760                         if (argo_debug[D_REQUEST]) {
  761                                 dump_mbuf(*mp, "tp_ctloutput *mp after compress");
  762                         }
  763 #endif
  764                 }
  765         }
  766         splx(s);
  767         return error;
  768 }
  769 
  770 /*
  771  * temporary sockopt wrapper, the above needs to be worked through
  772  */
  773 int
  774 tp_ctloutput(int cmd, struct socket  *so, struct sockopt *sopt)
  775 {
  776         struct mbuf *m;
  777         int err;
  778 
  779         switch(cmd) {
  780         case PRCO_SETOPT:
  781                 m = sockopt_getmbuf(sopt);
  782                 if (m == NULL) {
  783                         err = ENOMEM;
  784                         break;
  785                 }
  786 
  787                 err = tp_ctloutput1(cmd, so, sopt->sopt_level, sopt->sopt_name, &m);
  788                 break;
  789 
  790         case PRCO_GETOPT:
  791                 m = NULL;
  792                 err = tp_ctloutput1(cmd, so, sopt->sopt_level, sopt->sopt_name, &m);
  793                 if (err)
  794                         break;
  795 
  796                 err = sockopt_setmbuf(sopt, m);
  797                 break;
  798 
  799         default:
  800                 err = ENOPROTOOPT;
  801                 break;
  802         }
  803 
  804         return err;
  805 }

Cache object: f8a0da9a3325b75a30f96e3276ddd9d5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.