1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 
  31 #pragma ident   "%Z%%M% %I%     %E% SMI"        /* SVr4 1.8     */
  32 
  33 /*
  34  * This module establishes a unique connection on
  35  * a STREAMS-based pipe.
  36  */
  37 #include <sys/types.h>
  38 #include <sys/sysmacros.h>
  39 #include <sys/param.h>
  40 #include <sys/systm.h>
  41 #include <sys/errno.h>
  42 #include <sys/signal.h>
  43 #include <sys/user.h>
  44 #include <sys/fstyp.h>
  45 #include <sys/stropts.h>
  46 #include <sys/stream.h>
  47 #include <sys/strsubr.h>
  48 #include <sys/vnode.h>
  49 #include <sys/file.h>
  50 #include <sys/fs/fifonode.h>
  51 #include <sys/debug.h>
  52 #include <sys/ddi.h>
  53 
  54 /*
  55  * This is the loadable module wrapper.
  56  */
  57 #include <sys/conf.h>
  58 #include <sys/modctl.h>
  59 
  60 extern struct streamtab conninfo;
  61 
  62 static struct fmodsw fsw = {
  63         "connld",
  64         &conninfo,
  65         D_NEW | D_MP
  66 };
  67 
  68 /*
  69  * Module linkage information for the kernel.
  70  */
  71 
  72 static struct modlstrmod modlstrmod = {
  73         &mod_strmodops, "Streams-based pipes", &fsw
  74 };
  75 
  76 static struct modlinkage modlinkage = {
  77         MODREV_1, (void *)&modlstrmod, NULL
  78 };
  79 
  80 int
  81 _init()
  82 {
  83         return (mod_install(&modlinkage));
  84 }
  85 
  86 int
  87 _fini()
  88 {
  89         return (mod_remove(&modlinkage));
  90 }
  91 
  92 int
  93 _info(struct modinfo *modinfop)
  94 {
  95         return (mod_info(&modlinkage, modinfop));
  96 }
  97 
  98 /*
  99  * Define local and external routines.
 100  */
 101 int connopen(queue_t *, dev_t *, int, int, cred_t *);
 102 int connclose(queue_t *, int, cred_t *);
 103 int connput(queue_t *, mblk_t *);
 104 
 105 /*
 106  * Define STREAMS header information.
 107  */
 108 static struct module_info conn_info = {
 109         1003,
 110         "connld",
 111         0,
 112         INFPSZ,
 113         STRHIGH,
 114         STRLOW
 115 };
 116 static struct qinit connrinit = {
 117         connput,
 118         NULL,
 119         connopen,
 120         connclose,
 121         NULL,
 122         &conn_info,
 123         NULL
 124 };
 125 static struct qinit connwinit = {
 126         connput,
 127         NULL,
 128         NULL,
 129         NULL,
 130         NULL,
 131         &conn_info,
 132         NULL
 133 };
 134 struct streamtab conninfo = {
 135         &connrinit,
 136         &connwinit
 137 };
 138 
 139 /*
 140  * For each invocation of connopen(), create a new pipe. One end of the pipe
 141  * is sent to the process on the other end of this STREAM. The vnode for
 142  * the other end is returned to the open() system call as the vnode for
 143  * the opened object.
 144  *
 145  * On the first invocation of connopen(), a flag is set and the routine
 146  * returns 0, since the first open corresponds to the pushing of the module.
 147  */
 148 /*ARGSUSED*/
 149 int
 150 connopen(queue_t *rqp, dev_t *devp, int flag, int sflag, cred_t *crp)
 151 {
 152         int error = 0;
 153         vnode_t *streamvp;
 154         fifonode_t *streamfnp;
 155 
 156         if ((streamvp = strq2vp(rqp)) == NULL) {
 157                 return (EINVAL);
 158         }
 159 
 160         /*
 161          * CONNLD is only allowed to be pushed onto a "pipe" that has both
 162          * of its ends open.
 163          */
 164         if (streamvp->v_type != VFIFO) {
 165                 error = EINVAL;
 166                 goto out;
 167         }
 168 
 169         streamfnp = VTOF(streamvp);
 170 
 171         if (!(streamfnp->fn_flag & ISPIPE) ||
 172             streamfnp->fn_dest->fn_open == 0) {
 173                 error = EPIPE;
 174                 goto out;
 175         }
 176 
 177         /*
 178          * If this is the first time CONNLD was opened while on this stream,
 179          * it is being pushed. Therefore, set a flag and return 0.
 180          */
 181         if (rqp->q_ptr == 0) {
 182                 if (streamfnp->fn_flag & FIFOCONNLD) {
 183                         error = ENXIO;
 184                         goto out;
 185                 }
 186                 rqp->q_ptr = (caddr_t)1;
 187                 streamfnp->fn_flag |= FIFOCONNLD;
 188                 qprocson(rqp);
 189         }
 190 out:
 191         VN_RELE(streamvp);
 192         return (error);
 193 }
 194 
 195 /*ARGSUSED*/
 196 int
 197 connclose(queue_t *q, int cflag, cred_t *crp)
 198 {
 199         vnode_t *streamvp;
 200         fifonode_t *streamfnp;
 201 
 202         qprocsoff(q);
 203         streamvp = strq2vp(q);
 204 
 205         ASSERT(streamvp != NULL);
 206         ASSERT(streamvp->v_type == VFIFO);
 207 
 208         streamfnp = VTOF(streamvp);
 209         streamfnp->fn_flag &= ~FIFOCONNLD;
 210         VN_RELE(streamvp);
 211         return (0);
 212 }
 213 
 214 /*
 215  * Use same put procedure for write and read queues.
 216  */
 217 int
 218 connput(queue_t *q, mblk_t *bp)
 219 {
 220         putnext(q, bp);
 221         return (0);
 222 }