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

Cache object: 07f9a8e903f0fa48fd61d0dcbb2b3230


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