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.24 2003/08/11 15:17:30 itojun 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.24 2003/08/11 15:17:30 itojun 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 
   81 #include <netiso/tp_param.h>
   82 #include <netiso/tp_user.h>
   83 #include <netiso/tp_stat.h>
   84 #include <netiso/tp_ip.h>
   85 #include <netiso/tp_clnp.h>
   86 #include <netiso/tp_timer.h>
   87 #include <netiso/argo_debug.h>
   88 #include <netiso/tp_pcb.h>
   89 #include <netiso/tp_trace.h>
   90 #include <netiso/tp_var.h>
   91 
   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         int    error = EOK;
  126         int             class_to_use = tp_mask_to_num(param->p_class);
  127 
  128 #ifdef TPPT
  129         if (tp_traceflags[D_SETPARAMS]) {
  130                 tptrace(TPPTmisc,
  131                  "tp_consist enter class_to_use dontchange param.class cmd",
  132             class_to_use, param->p_dont_change_params, param->p_class, cmd);
  133         }
  134 #endif
  135 #ifdef ARGO_DEBUG
  136         if (argo_debug[D_SETPARAMS]) {
  137                 printf("tp_consistency %s %s\n",
  138                        cmd & TP_FORCE ? "TP_FORCE" : "",
  139                        cmd & TP_STRICT ? "TP_STRICT" : "");
  140         }
  141 #endif
  142         if ((cmd & TP_FORCE) && (param->p_dont_change_params)) {
  143                 cmd &= ~TP_FORCE;
  144         }
  145         /*
  146          * can switch net services within a domain, but cannot switch domains
  147          */
  148         switch (param->p_netservice) {
  149         case ISO_CONS:
  150         case ISO_CLNS:
  151         case ISO_COSNS:
  152                 /* param->p_netservice in ISO DOMAIN */
  153                 if (tpcb->tp_domain != AF_ISO) {
  154                         error = EINVAL;
  155                         goto done;
  156                 }
  157                 break;
  158         case IN_CLNS:
  159                 /* param->p_netservice in INET DOMAIN */
  160                 if (tpcb->tp_domain != AF_INET) {
  161                         error = EINVAL;
  162                         goto done;
  163                 }
  164                 break;
  165                 /* no others not possible-> netservice is a 2-bit field! */
  166         }
  167 
  168 #ifdef ARGO_DEBUG
  169         if (argo_debug[D_SETPARAMS]) {
  170                 printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class,
  171                        class_to_use);
  172         }
  173 #endif
  174         if ((param->p_netservice > TP_MAX_NETSERVICES)) {
  175                 error = EINVAL;
  176                 goto done;
  177         }
  178         if ((param->p_class & TP_CLASSES_IMPLEMENTED) == 0) {
  179                 error = EINVAL;
  180                 goto done;
  181         }
  182 #ifdef ARGO_DEBUG
  183         if (argo_debug[D_SETPARAMS]) {
  184                 printf("Nretrans 0x%x\n", param->p_Nretrans);
  185         }
  186 #endif
  187         if ((param->p_Nretrans < 1) ||
  188             (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1)) {
  189                 /*
  190                  * bad for any class because negot has to be done a la class
  191                  * 4
  192                  */
  193                 error = EINVAL;
  194                 goto done;
  195         }
  196 #ifdef ARGO_DEBUG
  197         if (argo_debug[D_SETPARAMS]) {
  198                 printf("use_csum 0x%x\n", param->p_use_checksum);
  199                 printf("xtd_format 0x%x\n", param->p_xtd_format);
  200                 printf("xpd_service 0x%x\n", param->p_xpd_service);
  201                 printf("tpdusize 0x%x\n", param->p_tpdusize);
  202                 printf("tpcb->flags 0x%x\n", tpcb->tp_flags);
  203         }
  204 #endif
  205         switch (class_to_use) {
  206 
  207         case 0:
  208                 /* do not use checksums, xtd format, or XPD */
  209 
  210                 if (param->p_use_checksum | param->p_xtd_format | param->p_xpd_service) {
  211                         if (cmd & TP_STRICT) {
  212                                 error = EINVAL;
  213                         } else {
  214                                 param->p_use_checksum = 0;
  215                                 param->p_xtd_format = 0;
  216                                 param->p_xpd_service = 0;
  217                         }
  218                         break;
  219                 }
  220                 if (param->p_tpdusize < TP_MIN_TPDUSIZE) {
  221                         if (cmd & TP_STRICT) {
  222                                 error = EINVAL;
  223                         } else {
  224                                 param->p_tpdusize = TP_MIN_TPDUSIZE;
  225                         }
  226                         break;
  227                 }
  228                 if (param->p_tpdusize > TP0_TPDUSIZE) {
  229                         if (cmd & TP_STRICT) {
  230                                 error = EINVAL;
  231                         } else {
  232                                 param->p_tpdusize = TP0_TPDUSIZE;
  233                         }
  234                         break;
  235                 }
  236                 /* connect/disc data not allowed for class 0 */
  237                 if (tpcb->tp_ucddata) {
  238                         if (cmd & TP_STRICT) {
  239                                 error = EINVAL;
  240                         } else if (cmd & TP_FORCE) {
  241                                 m_freem(tpcb->tp_ucddata);
  242                                 tpcb->tp_ucddata = 0;
  243                         }
  244                 }
  245                 break;
  246 
  247         case 4:
  248 #ifdef ARGO_DEBUG
  249                 if (argo_debug[D_SETPARAMS]) {
  250                         printf("dt_ticks 0x%x\n", param->p_dt_ticks);
  251                         printf("x_ticks 0x%x\n", param->p_x_ticks);
  252                         printf("dr_ticks 0x%x\n", param->p_dr_ticks);
  253                         printf("keepalive 0x%x\n", param->p_keepalive_ticks);
  254                         printf("sendack 0x%x\n", param->p_sendack_ticks);
  255                         printf("inact 0x%x\n", param->p_inact_ticks);
  256                         printf("ref 0x%x\n", param->p_ref_ticks);
  257                 }
  258 #endif
  259                 if ((param->p_class & TP_CLASS_4) && (
  260                        (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) ||
  261                  (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) ||
  262                  (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) ||
  263                                               (param->p_inact_ticks < 1))) {
  264                         error = EINVAL;
  265                         break;
  266                 }
  267 #ifdef ARGO_DEBUG
  268                 if (argo_debug[D_SETPARAMS]) {
  269                         printf("rx_strat 0x%x\n", param->p_rx_strat);
  270                 }
  271 #endif
  272                 if (param->p_rx_strat >
  273                     (TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART)) {
  274                         if (cmd & TP_STRICT) {
  275                                 error = EINVAL;
  276                         } else {
  277                                 param->p_rx_strat = TPRX_USE_CW;
  278                         }
  279                         break;
  280                 }
  281 #ifdef ARGO_DEBUG
  282                 if (argo_debug[D_SETPARAMS]) {
  283                         printf("ack_strat 0x%x\n", param->p_ack_strat);
  284                 }
  285 #endif
  286                 if ((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) {
  287                         if (cmd & TP_STRICT) {
  288                                 error = EINVAL;
  289                         } else {
  290                                 param->p_ack_strat = TPACK_WINDOW;
  291                         }
  292                         break;
  293                 }
  294                 if (param->p_tpdusize < TP_MIN_TPDUSIZE) {
  295                         if (cmd & TP_STRICT) {
  296                                 error = EINVAL;
  297                         } else {
  298                                 param->p_tpdusize = TP_MIN_TPDUSIZE;
  299                         }
  300                         break;
  301                 }
  302                 if (param->p_tpdusize > TP_TPDUSIZE) {
  303                         if (cmd & TP_STRICT) {
  304                                 error = EINVAL;
  305                         } else {
  306                                 param->p_tpdusize = TP_TPDUSIZE;
  307                         }
  308                         break;
  309                 }
  310                 break;
  311         }
  312 
  313         if ((error == 0) && (cmd & TP_FORCE)) {
  314                 long            dusize = ((long) param->p_ptpdusize) << 7;
  315                 /* Enforce Negotation rules below */
  316                 tpcb->tp_class = param->p_class;
  317                 if (tpcb->tp_use_checksum || param->p_use_checksum)
  318                         tpcb->tp_use_checksum = 1;
  319                 if (!tpcb->tp_xpd_service || !param->p_xpd_service)
  320                         tpcb->tp_xpd_service = 0;
  321                 if (!tpcb->tp_xtd_format || !param->p_xtd_format)
  322                         tpcb->tp_xtd_format = 0;
  323                 if (dusize) {
  324                         if (tpcb->tp_l_tpdusize > dusize)
  325                                 tpcb->tp_l_tpdusize = dusize;
  326                         if (tpcb->tp_ptpdusize == 0 ||
  327                             tpcb->tp_ptpdusize > param->p_ptpdusize)
  328                                 tpcb->tp_ptpdusize = param->p_ptpdusize;
  329                 } else {
  330                         if (param->p_tpdusize != 0 &&
  331                             tpcb->tp_tpdusize > param->p_tpdusize)
  332                                 tpcb->tp_tpdusize = param->p_tpdusize;
  333                         tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
  334                 }
  335         }
  336 done:
  337 
  338 #ifdef TPPT
  339         if (tp_traceflags[D_CONN]) {
  340                 tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd",
  341                         error, tpcb->tp_class, tpcb->tp_xtd_format, cmd);
  342         }
  343 #endif
  344 #ifdef ARGO_DEBUG
  345                 if (argo_debug[D_CONN]) {
  346                 printf(
  347                   "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n",
  348                        error, tpcb->tp_class, tpcb->tp_xtd_format, cmd);
  349         }
  350 #endif
  351         return error;
  352 }
  353 
  354 /*
  355  * NAME:        tp_ctloutput()
  356  *
  357  * CALLED FROM:
  358  *      [sg]etsockopt(), via so[sg]etopt().
  359  *
  360  * FUNCTION and ARGUMENTS:
  361  *      Implements the socket options at transport level.
  362  *      (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h).
  363  *      (so) is the socket.
  364  *      (level) is SOL_TRANSPORT (see ../sys/socket.h)
  365  *      (optname) is the particular command or option to be set.
  366  *      (**mp) is an mbuf structure.
  367  *
  368  * RETURN VALUE:
  369  *      ENOTSOCK if the socket hasn't got an associated tpcb
  370  *  EINVAL if
  371  *              trying to set window too big
  372  *              trying to set illegal max tpdu size
  373  *              trying to set illegal credit fraction
  374  *              trying to use unknown or unimplemented class of TP
  375  *              structure passed to set timer values is wrong size
  376  *      illegal combination of command/GET-SET option,
  377  *                      e.g., GET w/ TPOPT_CDDATA_CLEAR:
  378  *  EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET
  379  *   or if the transport-specific command is not implemented
  380  *  EISCONN if trying a command that isn't allowed after a connection
  381  *   is established
  382  *  ENOTCONN if trying a command that is allowed only if a connection is
  383  *   established
  384  *  EMSGSIZE if trying to give too much data on connect/disconnect
  385  *
  386  * SIDE EFFECTS:
  387  *
  388  * NOTES:
  389  */
  390 int
  391 tp_ctloutput(cmd, so, level, optname, mp)
  392         int             cmd, level, optname;
  393         struct socket  *so;
  394         struct mbuf   **mp;
  395 {
  396         struct proc *p = curproc;               /* XXX */
  397         struct tp_pcb  *tpcb = sototpcb(so);
  398         int             s = splsoftnet();
  399         caddr_t         value;
  400         unsigned        val_len;
  401         int             error = 0;
  402 
  403 #ifdef TPPT
  404         if (tp_traceflags[D_REQUEST]) {
  405                 tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp",
  406                         cmd, so, optname, mp);
  407         }
  408 #endif
  409 #ifdef ARGO_DEBUG
  410         if (argo_debug[D_REQUEST]) {
  411                 printf(
  412                        "tp_ctloutput so %p cmd 0x%x optname 0x%x, mp %p *mp %p tpcb %p\n",
  413                        so, cmd, optname, mp, mp ? *mp : 0, tpcb);
  414         }
  415 #endif
  416         if (tpcb == (struct tp_pcb *) 0) {
  417                 error = ENOTSOCK;
  418                 goto done;
  419         }
  420         if (*mp == NULL) {
  421                 struct mbuf *m;
  422 
  423                 MGET(m, M_DONTWAIT, TPMT_SONAME);       /* does off, type, next */
  424                 if (m == NULL) {
  425                         splx(s);
  426                         return ENOBUFS;
  427                 }
  428                 m->m_len = 0;
  429                 m->m_nextpkt = 0;
  430                 *mp = m;
  431         }
  432         /*
  433          *      Hook so one can set network options via a tp socket.
  434          */
  435         if (level == SOL_NETWORK) {
  436                 if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL))
  437                         error = ENOTSOCK;
  438                 else if (tpcb->tp_nlproto->nlp_ctloutput == NULL)
  439                         error = EOPNOTSUPP;
  440                 else
  441                         return ((tpcb->tp_nlproto->nlp_ctloutput) (cmd, optname,
  442                                                        tpcb->tp_npcb, *mp));
  443                 goto done;
  444         } else if (level == SOL_SOCKET) {
  445                 if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) {
  446                         u_long          old_credit = tpcb->tp_maxlcredit;
  447                         tp_rsyset(tpcb);
  448                         if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat &&
  449                             tpcb->tp_state == TP_OPEN &&
  450                             (old_credit < tpcb->tp_maxlcredit))
  451                                 tp_emit(AK_TPDU_type, tpcb,
  452                                         tpcb->tp_rcvnxt, 0, NULL);
  453                         tpcb->tp_rhiwat = so->so_rcv.sb_hiwat;
  454                 }
  455                 goto done;
  456         } else if (level != SOL_TRANSPORT) {
  457                 error = EOPNOTSUPP;
  458                 goto done;
  459         }
  460         if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) {
  461                 error = EOPNOTSUPP;
  462                 goto done;
  463         }
  464         if (so->so_error) {
  465                 error = so->so_error;
  466                 goto done;
  467         }
  468         /*
  469          * The only options allowed after connection is established are GET
  470          * (anything) and SET DISC DATA and SET PERF MEAS
  471          */
  472         if (((so->so_state & SS_ISCONNECTING) || (so->so_state & SS_ISCONNECTED))
  473             &&
  474             (cmd == PRCO_SETOPT &&
  475              optname != TPOPT_DISC_DATA &&
  476              optname != TPOPT_CFRM_DATA &&
  477              optname != TPOPT_PERF_MEAS &&
  478              optname != TPOPT_CDDATA_CLEAR)) {
  479                 error = EISCONN;
  480                 goto done;
  481         }
  482         /*
  483          * The only options allowed after disconnection are GET DISC DATA,
  484          * and TPOPT_PSTATISTICS and they're not allowed if the ref timer has
  485          * gone off, because the tpcb is gone
  486          */
  487         if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) {
  488                 if (so->so_pcb == 0) {
  489                         error = ENOTCONN;
  490                         goto done;
  491                 }
  492                 if ((tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) &&
  493                     (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) {
  494                         error = ENOTCONN;
  495                         goto done;
  496                 }
  497         }
  498         value = mtod(*mp, caddr_t);     /* it's aligned, don't worry, but
  499                                          * lint complains about it */
  500         val_len = (*mp)->m_len;
  501 
  502         switch (optname) {
  503 
  504         case TPOPT_INTERCEPT:
  505 #define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr)
  506 #define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr)
  507 
  508                 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) {
  509                         error = EPERM;
  510                 } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED ||
  511                            (tpcb->tp_flags & TPF_GENERAL_ADDR) ||
  512                            tpcb->tp_next == 0)
  513                         error = EINVAL;
  514                 else {
  515                         struct tp_pcb *t;
  516                         error = EADDRINUSE;
  517                         for (t = tp_listeners; t; t = t->tp_nextlisten)
  518                                 if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 &&
  519                                     t->tp_domain == tpcb->tp_domain)
  520                                         switch (tpcb->tp_domain) {
  521                                         default:
  522                                                 goto done;
  523 #ifdef  INET
  524                                         case AF_INET:
  525                                                 if (INA(t) == INA(tpcb))
  526                                                         goto done;
  527                                                 continue;
  528 #endif
  529 #ifdef ISO
  530                                         case AF_ISO:
  531                                                 if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr,
  532                                                      ISOA(t).isoa_len) == 0)
  533                                                         goto done;
  534                                                 continue;
  535 #endif
  536                                         }
  537                         tpcb->tp_lsuffixlen = 0;
  538                         tpcb->tp_state = TP_LISTENING;
  539                         error = 0;
  540                         remque(tpcb);
  541                         tpcb->tp_next = tpcb->tp_prev = tpcb;
  542                         tpcb->tp_nextlisten = tp_listeners;
  543                         tp_listeners = tpcb;
  544                 }
  545                 break;
  546 
  547         case TPOPT_MY_TSEL:
  548                 if (cmd == PRCO_GETOPT) {
  549                         ASSERT(tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN);
  550                         bcopy((caddr_t) tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen);
  551                         (*mp)->m_len = tpcb->tp_lsuffixlen;
  552                 } else {        /* cmd == PRCO_SETOPT  */
  553                         if ((val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0)) {
  554                                 printf("val_len 0x%x (*mp)->m_len %p\n",
  555                                     val_len, (*mp));
  556                                 error = EINVAL;
  557                         } else {
  558                                 bcopy(value, (caddr_t) tpcb->tp_lsuffix, val_len);
  559                                 tpcb->tp_lsuffixlen = val_len;
  560                         }
  561                 }
  562                 break;
  563 
  564         case TPOPT_PEER_TSEL:
  565                 if (cmd == PRCO_GETOPT) {
  566                         ASSERT(tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN);
  567                         bcopy((caddr_t) tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen);
  568                         (*mp)->m_len = tpcb->tp_fsuffixlen;
  569                 } else {        /* cmd == PRCO_SETOPT  */
  570                         if ((val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0)) {
  571                                 printf("val_len 0x%x (*mp)->m_len %p\n",
  572                                     val_len, (*mp));
  573                                 error = EINVAL;
  574                         } else {
  575                                 bcopy(value, (caddr_t) tpcb->tp_fsuffix, val_len);
  576                                 tpcb->tp_fsuffixlen = val_len;
  577                         }
  578                 }
  579                 break;
  580 
  581         case TPOPT_FLAGS:
  582 #ifdef ARGO_DEBUG
  583                 if (argo_debug[D_REQUEST]) {
  584                         printf("%s TPOPT_FLAGS value %p *value 0x%x, flags 0x%x \n",
  585                                cmd == PRCO_GETOPT ? "GET" : "SET",
  586                                value,
  587                                *value,
  588                                tpcb->tp_flags);
  589                 }
  590 #endif
  591 
  592                 if (cmd == PRCO_GETOPT) {
  593                         *(int *) value = (int) tpcb->tp_flags;
  594                         (*mp)->m_len = sizeof(u_int);
  595                 } else {        /* cmd == PRCO_SETOPT  */
  596                         error = EINVAL;
  597                         goto done;
  598                 }
  599                 break;
  600 
  601         case TPOPT_PARAMS:
  602                 /*
  603                  * This handles: timer values, class, use of transport
  604                  * expedited data, max tpdu size, checksum, xtd format and
  605                  * disconnect indications, and may get rid of connect/disc
  606                  * data
  607                  */
  608 #ifdef ARGO_DEBUG
  609                 if (argo_debug[D_SETPARAMS]) {
  610                         printf("TPOPT_PARAMS value %p, cmd %s \n", value,
  611                                cmd == PRCO_GETOPT ? "GET" : "SET");
  612                 }
  613 #endif
  614 #ifdef ARGO_DEBUG
  615                 if (argo_debug[D_REQUEST]) {
  616                         printf("TPOPT_PARAMS value %p, cmd %s \n", value,
  617                                cmd == PRCO_GETOPT ? "GET" : "SET");
  618                 }
  619 #endif
  620 
  621                 if (cmd == PRCO_GETOPT) {
  622                         *(struct tp_conn_param *) value = tpcb->_tp_param;
  623                         (*mp)->m_len = sizeof(tpcb->_tp_param);
  624                 } else {        /* cmd == PRCO_SETOPT  */
  625                         if ((error =
  626                              tp_consistency(tpcb, TP_STRICT | TP_FORCE,
  627                                     (struct tp_conn_param *) value)) == 0) {
  628                                 /*
  629                                  * tp_consistency doesn't copy the whole set
  630                                  * of params
  631                                  */
  632                                 tpcb->_tp_param = *(struct tp_conn_param *) value;
  633                                 (*mp)->m_len = sizeof(tpcb->_tp_param);
  634                         }
  635                 }
  636                 break;
  637 
  638         case TPOPT_PSTATISTICS:
  639 #ifdef TP_PERF_MEAS
  640                 if (cmd == PRCO_SETOPT) {
  641                         error = EINVAL;
  642                         goto done;
  643                 }
  644                 if (tpcb->tp_perf_on) {
  645                         m_clget(*mp, M_WAIT);
  646                         if (((*mp)->m_flags & M_EXT) == 0) {
  647                                 error = ENOBUFS; goto done;
  648                         }
  649                         (*mp)->m_len = sizeof(struct tp_pmeas);
  650                         bcopy(tpcb->tp_p_meas, mtod(*mp), sizeof(struct tp_pmeas));
  651                 }
  652                 else {
  653                         error = EINVAL;
  654                         goto done;
  655                 }
  656                 break;
  657 #else
  658                 error = EOPNOTSUPP;
  659                 goto done;
  660 #endif                          /* TP_PERF_MEAS */
  661 
  662         case TPOPT_CDDATA_CLEAR:
  663                 if (cmd == PRCO_GETOPT) {
  664                         error = EINVAL;
  665                 } else {
  666                         if (tpcb->tp_ucddata) {
  667                                 m_freem(tpcb->tp_ucddata);
  668                                 tpcb->tp_ucddata = 0;
  669                         }
  670                 }
  671                 break;
  672 
  673         case TPOPT_CFRM_DATA:
  674         case TPOPT_DISC_DATA:
  675         case TPOPT_CONN_DATA:
  676                 if (tpcb->tp_class == TP_CLASS_0) {
  677                         error = EOPNOTSUPP;
  678                         break;
  679                 }
  680 #ifdef ARGO_DEBUG
  681                 if (argo_debug[D_REQUEST]) {
  682                         printf("%s\n", optname == TPOPT_DISC_DATA ? "DISC data" : "CONN data");
  683                         printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%lx\n",
  684                                (*mp)->m_len, val_len, so->so_snd.sb_cc);
  685                         dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd ");
  686                 }
  687 #endif
  688                 if (cmd == PRCO_SETOPT) {
  689                         int             len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0;
  690                         /* can append connect data in several calls */
  691                         if (len + val_len >
  692                             (optname == TPOPT_CONN_DATA ? TP_MAX_CR_DATA : TP_MAX_DR_DATA)) {
  693                                 error = EMSGSIZE;
  694                                 goto done;
  695                         }
  696                         (*mp)->m_next = NULL;
  697                         (*mp)->m_nextpkt = 0;
  698                         if (tpcb->tp_ucddata)
  699                                 m_cat(tpcb->tp_ucddata, *mp);
  700                         else
  701                                 tpcb->tp_ucddata = *mp;
  702 #ifdef ARGO_DEBUG
  703                         if (argo_debug[D_REQUEST]) {
  704                                 dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA");
  705                         }
  706 #endif
  707 #ifdef TPPT
  708                         if (tp_traceflags[D_REQUEST]) {
  709                                 tptrace(TPPTmisc, "C/D DATA: flags snd.sbcc val_len",
  710                               tpcb->tp_flags, so->so_snd.sb_cc, val_len, 0);
  711                         }
  712 #endif
  713                         *mp = NULL;
  714                         if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING))
  715                                 (void) tp_confirm(tpcb);
  716                 }
  717                 break;
  718 
  719         case TPOPT_PERF_MEAS:
  720 #ifdef TP_PERF_MEAS
  721                 if (cmd == PRCO_GETOPT) {
  722                         *value = (u_int) tpcb->tp_perf_on;
  723                         (*mp)->m_len = sizeof(u_int);
  724                 } else if (cmd == PRCO_SETOPT) {
  725                         (*mp)->m_len = 0;
  726                         if ((*value) != 0 && (*value) != 1)
  727                                 error = EINVAL;
  728                         else
  729                                 tpcb->tp_perf_on = (*value);
  730                 }
  731                 if (tpcb->tp_perf_on)
  732                         error = tp_setup_perf(tpcb);
  733 #else                           /* TP_PERF_MEAS */
  734                 error = EOPNOTSUPP;
  735 #endif                          /* TP_PERF_MEAS */
  736                 break;
  737 
  738         default:
  739                 error = EOPNOTSUPP;
  740         }
  741 
  742 done:
  743 #ifdef ARGO_DEBUG
  744         if (argo_debug[D_REQUEST]) {
  745                 dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end");
  746                 dump_mbuf(*mp, "tp_ctloutput *mp");
  747         }
  748 #endif
  749         /*
  750          * sigh: getsockopt looks only at m_len : all output data must reside
  751          * in the first mbuf
  752          */
  753         if (*mp) {
  754                 if (cmd == PRCO_SETOPT) {
  755                         m_freem(*mp);
  756                         *mp = NULL;
  757                 } else {
  758                         ASSERT(m_compress(*mp, mp) <= MLEN);
  759                         if (error)
  760                                 (*mp)->m_len = 0;
  761 #ifdef ARGO_DEBUG
  762                         if (argo_debug[D_REQUEST]) {
  763                                 dump_mbuf(*mp, "tp_ctloutput *mp after compress");
  764                         }
  765 #endif
  766                 }
  767         }
  768         splx(s);
  769         return error;
  770 }

Cache object: 022f7e40957f2e816cae822cdd51cb30


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