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.30 2006/07/23 22:06:14 ad 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.30 2006/07/23 22:06:14 ad 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 arguements 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_ctloutput()
  354  *
  355  * CALLED FROM:
  356  *      [sg]etsockopt(), via so[sg]etopt().
  357  *
  358  * FUNCTION and ARGUMENTS:
  359  *      Implements the socket options at transport level.
  360  *      (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h).
  361  *      (so) is the socket.
  362  *      (level) is SOL_TRANSPORT (see ../sys/socket.h)
  363  *      (optname) is the particular command or option to be set.
  364  *      (**mp) is an mbuf structure.
  365  *
  366  * RETURN VALUE:
  367  *      ENOTSOCK if the socket hasn't got an associated tpcb
  368  *  EINVAL if
  369  *              trying to set window too big
  370  *              trying to set illegal max tpdu size
  371  *              trying to set illegal credit fraction
  372  *              trying to use unknown or unimplemented class of TP
  373  *              structure passed to set timer values is wrong size
  374  *      illegal combination of command/GET-SET option,
  375  *                      e.g., GET w/ TPOPT_CDDATA_CLEAR:
  376  *  EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET
  377  *   or if the transport-specific command is not implemented
  378  *  EISCONN if trying a command that isn't allowed after a connection
  379  *   is established
  380  *  ENOTCONN if trying a command that is allowed only if a connection is
  381  *   established
  382  *  EMSGSIZE if trying to give too much data on connect/disconnect
  383  *
  384  * SIDE EFFECTS:
  385  *
  386  * NOTES:
  387  */
  388 int
  389 tp_ctloutput(int cmd, struct socket  *so, int level, int optname,
  390         struct mbuf **mp)
  391 {
  392         struct lwp *l = curlwp;         /* XXX */
  393         struct tp_pcb  *tpcb = sototpcb(so);
  394         int             s = splsoftnet();
  395         caddr_t         value;
  396         unsigned        val_len;
  397         int             error = 0;
  398 
  399 #ifdef TPPT
  400         if (tp_traceflags[D_REQUEST]) {
  401                 tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp",
  402                         cmd, so, optname, mp);
  403         }
  404 #endif
  405 #ifdef ARGO_DEBUG
  406         if (argo_debug[D_REQUEST]) {
  407                 printf(
  408                        "tp_ctloutput so %p cmd 0x%x optname 0x%x, mp %p *mp %p tpcb %p\n",
  409                        so, cmd, optname, mp, mp ? *mp : 0, tpcb);
  410         }
  411 #endif
  412         if (tpcb == (struct tp_pcb *) 0) {
  413                 error = ENOTSOCK;
  414                 goto done;
  415         }
  416         if (mp && *mp == NULL) {
  417                 struct mbuf *m;
  418 
  419                 MGET(m, M_DONTWAIT, TPMT_SONAME);       /* does off, type, next */
  420                 if (m == NULL) {
  421                         splx(s);
  422                         return ENOBUFS;
  423                 }
  424                 m->m_len = 0;
  425                 m->m_nextpkt = 0;
  426                 *mp = m;
  427         }
  428         /*
  429          *      Hook so one can set network options via a tp socket.
  430          */
  431         if (level == SOL_NETWORK) {
  432                 if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL))
  433                         error = ENOTSOCK;
  434                 else if (tpcb->tp_nlproto->nlp_ctloutput == NULL)
  435                         error = EOPNOTSUPP;
  436                 else
  437                         return ((tpcb->tp_nlproto->nlp_ctloutput) (cmd, optname,
  438                                                        tpcb->tp_npcb, *mp));
  439                 goto done;
  440         } else if (level == SOL_SOCKET) {
  441                 if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) {
  442                         u_long          old_credit = tpcb->tp_maxlcredit;
  443                         tp_rsyset(tpcb);
  444                         if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat &&
  445                             tpcb->tp_state == TP_OPEN &&
  446                             (old_credit < tpcb->tp_maxlcredit))
  447                                 tp_emit(AK_TPDU_type, tpcb,
  448                                         tpcb->tp_rcvnxt, 0, NULL);
  449                         tpcb->tp_rhiwat = so->so_rcv.sb_hiwat;
  450                 }
  451                 goto done;
  452         } else if (level != SOL_TRANSPORT) {
  453                 error = EOPNOTSUPP;
  454                 goto done;
  455         }
  456         if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) {
  457                 error = EOPNOTSUPP;
  458                 goto done;
  459         }
  460         if (so->so_error) {
  461                 error = so->so_error;
  462                 goto done;
  463         }
  464         /*
  465          * The only options allowed after connection is established are GET
  466          * (anything) and SET DISC DATA and SET PERF MEAS
  467          */
  468         if (((so->so_state & SS_ISCONNECTING) || (so->so_state & SS_ISCONNECTED))
  469             &&
  470             (cmd == PRCO_SETOPT &&
  471              optname != TPOPT_DISC_DATA &&
  472              optname != TPOPT_CFRM_DATA &&
  473              optname != TPOPT_PERF_MEAS &&
  474              optname != TPOPT_CDDATA_CLEAR)) {
  475                 error = EISCONN;
  476                 goto done;
  477         }
  478         /*
  479          * The only options allowed after disconnection are GET DISC DATA,
  480          * and TPOPT_PSTATISTICS and they're not allowed if the ref timer has
  481          * gone off, because the tpcb is gone
  482          */
  483         if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) {
  484                 if (so->so_pcb == 0) {
  485                         error = ENOTCONN;
  486                         goto done;
  487                 }
  488                 if ((tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) &&
  489                     (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) {
  490                         error = ENOTCONN;
  491                         goto done;
  492                 }
  493         }
  494         value = mtod(*mp, caddr_t);     /* it's aligned, don't worry, but
  495                                          * lint complains about it */
  496         val_len = (*mp)->m_len;
  497 
  498         switch (optname) {
  499 
  500         case TPOPT_INTERCEPT:
  501 #define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr)
  502 #define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr)
  503 
  504                 if (l == 0 || (error = kauth_authorize_generic(l->l_cred,
  505                     KAUTH_GENERIC_ISSUSER, &l->l_acflag))) {
  506                         error = EPERM;
  507                 } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED ||
  508                            (tpcb->tp_flags & TPF_GENERAL_ADDR) ||
  509                            tpcb->tp_next == 0)
  510                         error = EINVAL;
  511                 else {
  512                         struct tp_pcb *t;
  513                         error = EADDRINUSE;
  514                         for (t = tp_listeners; t; t = t->tp_nextlisten)
  515                                 if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 &&
  516                                     t->tp_domain == tpcb->tp_domain)
  517                                         switch (tpcb->tp_domain) {
  518                                         default:
  519                                                 goto done;
  520 #ifdef  INET
  521                                         case AF_INET:
  522                                                 if (INA(t) == INA(tpcb))
  523                                                         goto done;
  524                                                 continue;
  525 #endif
  526 #ifdef ISO
  527                                         case AF_ISO:
  528                                                 if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr,
  529                                                      ISOA(t).isoa_len) == 0)
  530                                                         goto done;
  531                                                 continue;
  532 #endif
  533                                         }
  534                         tpcb->tp_lsuffixlen = 0;
  535                         tpcb->tp_state = TP_LISTENING;
  536                         error = 0;
  537                         remque(tpcb);
  538                         tpcb->tp_next = tpcb->tp_prev = tpcb;
  539                         tpcb->tp_nextlisten = tp_listeners;
  540                         tp_listeners = tpcb;
  541                 }
  542                 break;
  543 
  544         case TPOPT_MY_TSEL:
  545                 if (cmd == PRCO_GETOPT) {
  546                         ASSERT(tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN);
  547                         bcopy((caddr_t) tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen);
  548                         (*mp)->m_len = tpcb->tp_lsuffixlen;
  549                 } else {        /* cmd == PRCO_SETOPT  */
  550                         if ((val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0)) {
  551                                 printf("val_len 0x%x (*mp)->m_len %p\n",
  552                                     val_len, (*mp));
  553                                 error = EINVAL;
  554                         } else {
  555                                 bcopy(value, (caddr_t) tpcb->tp_lsuffix, val_len);
  556                                 tpcb->tp_lsuffixlen = val_len;
  557                         }
  558                 }
  559                 break;
  560 
  561         case TPOPT_PEER_TSEL:
  562                 if (cmd == PRCO_GETOPT) {
  563                         ASSERT(tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN);
  564                         bcopy((caddr_t) tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen);
  565                         (*mp)->m_len = tpcb->tp_fsuffixlen;
  566                 } else {        /* cmd == PRCO_SETOPT  */
  567                         if ((val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0)) {
  568                                 printf("val_len 0x%x (*mp)->m_len %p\n",
  569                                     val_len, (*mp));
  570                                 error = EINVAL;
  571                         } else {
  572                                 bcopy(value, (caddr_t) tpcb->tp_fsuffix, val_len);
  573                                 tpcb->tp_fsuffixlen = val_len;
  574                         }
  575                 }
  576                 break;
  577 
  578         case TPOPT_FLAGS:
  579 #ifdef ARGO_DEBUG
  580                 if (argo_debug[D_REQUEST]) {
  581                         printf("%s TPOPT_FLAGS value %p *value 0x%x, flags 0x%x \n",
  582                                cmd == PRCO_GETOPT ? "GET" : "SET",
  583                                value,
  584                                *value,
  585                                tpcb->tp_flags);
  586                 }
  587 #endif
  588 
  589                 if (cmd == PRCO_GETOPT) {
  590                         *(int *) value = (int) tpcb->tp_flags;
  591                         (*mp)->m_len = sizeof(u_int);
  592                 } else {        /* cmd == PRCO_SETOPT  */
  593                         error = EINVAL;
  594                         goto done;
  595                 }
  596                 break;
  597 
  598         case TPOPT_PARAMS:
  599                 /*
  600                  * This handles: timer values, class, use of transport
  601                  * expedited data, max tpdu size, checksum, xtd format and
  602                  * disconnect indications, and may get rid of connect/disc
  603                  * data
  604                  */
  605 #ifdef ARGO_DEBUG
  606                 if (argo_debug[D_SETPARAMS]) {
  607                         printf("TPOPT_PARAMS value %p, cmd %s \n", value,
  608                                cmd == PRCO_GETOPT ? "GET" : "SET");
  609                 }
  610 #endif
  611 #ifdef ARGO_DEBUG
  612                 if (argo_debug[D_REQUEST]) {
  613                         printf("TPOPT_PARAMS value %p, cmd %s \n", value,
  614                                cmd == PRCO_GETOPT ? "GET" : "SET");
  615                 }
  616 #endif
  617 
  618                 if (cmd == PRCO_GETOPT) {
  619                         *(struct tp_conn_param *) value = tpcb->_tp_param;
  620                         (*mp)->m_len = sizeof(tpcb->_tp_param);
  621                 } else {        /* cmd == PRCO_SETOPT  */
  622                         if ((error =
  623                              tp_consistency(tpcb, TP_STRICT | TP_FORCE,
  624                                     (struct tp_conn_param *) value)) == 0) {
  625                                 /*
  626                                  * tp_consistency doesn't copy the whole set
  627                                  * of params
  628                                  */
  629                                 tpcb->_tp_param = *(struct tp_conn_param *) value;
  630                                 (*mp)->m_len = sizeof(tpcb->_tp_param);
  631                         }
  632                 }
  633                 break;
  634 
  635         case TPOPT_PSTATISTICS:
  636 #ifdef TP_PERF_MEAS
  637                 if (cmd == PRCO_SETOPT) {
  638                         error = EINVAL;
  639                         goto done;
  640                 }
  641                 if (tpcb->tp_perf_on) {
  642                         m_clget(*mp, M_WAIT);
  643                         if (((*mp)->m_flags & M_EXT) == 0) {
  644                                 error = ENOBUFS; goto done;
  645                         }
  646                         (*mp)->m_len = sizeof(struct tp_pmeas);
  647                         bcopy(tpcb->tp_p_meas, mtod(*mp), sizeof(struct tp_pmeas));
  648                 }
  649                 else {
  650                         error = EINVAL;
  651                         goto done;
  652                 }
  653                 break;
  654 #else
  655                 error = EOPNOTSUPP;
  656                 goto done;
  657 #endif                          /* TP_PERF_MEAS */
  658 
  659         case TPOPT_CDDATA_CLEAR:
  660                 if (cmd == PRCO_GETOPT) {
  661                         error = EINVAL;
  662                 } else {
  663                         if (tpcb->tp_ucddata) {
  664                                 m_freem(tpcb->tp_ucddata);
  665                                 tpcb->tp_ucddata = 0;
  666                         }
  667                 }
  668                 break;
  669 
  670         case TPOPT_CFRM_DATA:
  671         case TPOPT_DISC_DATA:
  672         case TPOPT_CONN_DATA:
  673                 if (tpcb->tp_class == TP_CLASS_0) {
  674                         error = EOPNOTSUPP;
  675                         break;
  676                 }
  677 #ifdef ARGO_DEBUG
  678                 if (argo_debug[D_REQUEST]) {
  679                         printf("%s\n", optname == TPOPT_DISC_DATA ? "DISC data" : "CONN data");
  680                         printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%lx\n",
  681                                (*mp)->m_len, val_len, so->so_snd.sb_cc);
  682                         dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd ");
  683                 }
  684 #endif
  685                 if (cmd == PRCO_SETOPT) {
  686                         int             len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0;
  687                         /* can append connect data in several calls */
  688                         if (len + val_len >
  689                             (optname == TPOPT_CONN_DATA ? TP_MAX_CR_DATA : TP_MAX_DR_DATA)) {
  690                                 error = EMSGSIZE;
  691                                 goto done;
  692                         }
  693                         (*mp)->m_next = NULL;
  694                         (*mp)->m_nextpkt = 0;
  695                         if (tpcb->tp_ucddata)
  696                                 m_cat(tpcb->tp_ucddata, *mp);
  697                         else
  698                                 tpcb->tp_ucddata = *mp;
  699 #ifdef ARGO_DEBUG
  700                         if (argo_debug[D_REQUEST]) {
  701                                 dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA");
  702                         }
  703 #endif
  704 #ifdef TPPT
  705                         if (tp_traceflags[D_REQUEST]) {
  706                                 tptrace(TPPTmisc, "C/D DATA: flags snd.sbcc val_len",
  707                               tpcb->tp_flags, so->so_snd.sb_cc, val_len, 0);
  708                         }
  709 #endif
  710                         *mp = NULL;
  711                         if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING))
  712                                 (void) tp_confirm(tpcb);
  713                 }
  714                 break;
  715 
  716         case TPOPT_PERF_MEAS:
  717 #ifdef TP_PERF_MEAS
  718                 if (cmd == PRCO_GETOPT) {
  719                         *value = (u_int) tpcb->tp_perf_on;
  720                         (*mp)->m_len = sizeof(u_int);
  721                 } else if (cmd == PRCO_SETOPT) {
  722                         (*mp)->m_len = 0;
  723                         if ((*value) != 0 && (*value) != 1)
  724                                 error = EINVAL;
  725                         else
  726                                 tpcb->tp_perf_on = (*value);
  727                 }
  728                 if (tpcb->tp_perf_on)
  729                         error = tp_setup_perf(tpcb);
  730 #else                           /* TP_PERF_MEAS */
  731                 error = EOPNOTSUPP;
  732 #endif                          /* TP_PERF_MEAS */
  733                 break;
  734 
  735         default:
  736                 error = EOPNOTSUPP;
  737         }
  738 
  739 done:
  740 #ifdef ARGO_DEBUG
  741         if (argo_debug[D_REQUEST]) {
  742                 dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end");
  743                 dump_mbuf(*mp, "tp_ctloutput *mp");
  744         }
  745 #endif
  746         /*
  747          * sigh: getsockopt looks only at m_len : all output data must reside
  748          * in the first mbuf
  749          */
  750         if (*mp) {
  751                 if (cmd == PRCO_SETOPT) {
  752                         m_freem(*mp);
  753                         *mp = NULL;
  754                 } else {
  755                         ASSERT(m_compress(*mp, mp) <= MLEN);
  756                         if (error)
  757                                 (*mp)->m_len = 0;
  758 #ifdef ARGO_DEBUG
  759                         if (argo_debug[D_REQUEST]) {
  760                                 dump_mbuf(*mp, "tp_ctloutput *mp after compress");
  761                         }
  762 #endif
  763                 }
  764         }
  765         splx(s);
  766         return error;
  767 }

Cache object: 91703a2dc0d7d91cb089a49bdaf3c318


[ 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.