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 /*
  32  * This module establishes a unique connection on
  33  * a STREAMS-based pipe.
  34  */
  35 #include <sys/types.h>
  36 #include <sys/sysmacros.h>
  37 #include <sys/param.h>
  38 #include <sys/systm.h>
  39 #include <sys/errno.h>
  40 #include <sys/signal.h>
  41 #include <sys/user.h>
  42 #include <sys/fstyp.h>
  43 #include <sys/stropts.h>
  44 #include <sys/stream.h>
  45 #include <sys/strsubr.h>
  46 #include <sys/vnode.h>
  47 #include <sys/file.h>
  48 #include <sys/fs/fifonode.h>
  49 #include <sys/debug.h>
  50 #include <sys/ddi.h>
  51 
  52 /*
  53  * This is the loadable module wrapper.
  54  */
  55 #include <sys/conf.h>
  56 #include <sys/modctl.h>
  57 
  58 extern struct streamtab conninfo;
  59 
  60 static struct fmodsw fsw = {
  61         "connld",
  62         &conninfo,
  63         D_NEW | D_MP
  64 };
  65 
  66 /*
  67  * Module linkage information for the kernel.
  68  */
  69 
  70 static struct modlstrmod modlstrmod = {
  71         &mod_strmodops, "Streams-based pipes", &fsw
  72 };
  73 
  74 static struct modlinkage modlinkage = {
  75         MODREV_1, { (void *)&modlstrmod, NULL }
  76 };
  77 
  78 int
  79 _init()
  80 {
  81         return (mod_install(&modlinkage));
  82 }
  83 
  84 int
  85 _fini()
  86 {
  87         return (mod_remove(&modlinkage));
  88 }
  89 
  90 int
  91 _info(struct modinfo *modinfop)
  92 {
  93         return (mod_info(&modlinkage, modinfop));
  94 }
  95 
  96 /*
  97  * Define local and external routines.
  98  */
  99 int connopen(queue_t *, dev_t *, int, int, cred_t *);
 100 int connclose(queue_t *, int, cred_t *);
 101 int connput(queue_t *, mblk_t *);
 102 
 103 /*
 104  * Define STREAMS header information.
 105  */
 106 static struct module_info conn_info = {
 107         1003,
 108         "connld",
 109         0,
 110         INFPSZ,
 111         STRHIGH,
 112         STRLOW
 113 };
 114 static struct qinit connrinit = {
 115         connput,
 116         NULL,
 117         connopen,
 118         connclose,
 119         NULL,
 120         &conn_info,
 121         NULL
 122 };
 123 static struct qinit connwinit = {
 124         connput,
 125         NULL,
 126         NULL,
 127         NULL,
 128         NULL,
 129         &conn_info,
 130         NULL
 131 };
 132 struct streamtab conninfo = {
 133         &connrinit,
 134         &connwinit
 135 };
 136 
 137 /*
 138  * For each invocation of connopen(), create a new pipe. One end of the pipe
 139  * is sent to the process on the other end of this STREAM. The vnode for
 140  * the other end is returned to the open() system call as the vnode for
 141  * the opened object.
 142  *
 143  * On the first invocation of connopen(), a flag is set and the routine
 144  * returns 0, since the first open corresponds to the pushing of the module.
 145  */
 146 /*ARGSUSED*/
 147 int
 148 connopen(queue_t *rqp, dev_t *devp, int flag, int sflag, cred_t *crp)
 149 {
 150         int error = 0;
 151         vnode_t *streamvp;
 152         fifonode_t *streamfnp;
 153 
 154         if ((streamvp = strq2vp(rqp)) == NULL) {
 155                 return (EINVAL);
 156         }
 157 
 158         /*
 159          * CONNLD is only allowed to be pushed onto a "pipe" that has both
 160          * of its ends open.
 161          */
 162         if (streamvp->v_type != VFIFO) {
 163                 error = EINVAL;
 164                 goto out;
 165         }
 166 
 167         streamfnp = VTOF(streamvp);
 168 
 169         if (!(streamfnp->fn_flag & ISPIPE) ||
 170             streamfnp->fn_dest->fn_open == 0) {
 171                 error = EPIPE;
 172                 goto out;
 173         }
 174 
 175         /*
 176          * If this is the first time CONNLD was opened while on this stream,
 177          * it is being pushed. Therefore, set a flag and return 0.
 178          */
 179         if (rqp->q_ptr == 0) {
 180                 if (streamfnp->fn_flag & FIFOCONNLD) {
 181                         error = ENXIO;
 182                         goto out;
 183                 }
 184                 rqp->q_ptr = (caddr_t)1;
 185                 streamfnp->fn_flag |= FIFOCONNLD;
 186                 qprocson(rqp);
 187         }
 188 out:
 189         VN_RELE(streamvp);
 190         return (error);
 191 }
 192 
 193 /*ARGSUSED*/
 194 int
 195 connclose(queue_t *q, int cflag, cred_t *crp)
 196 {
 197         vnode_t *streamvp;
 198         fifonode_t *streamfnp;
 199 
 200         qprocsoff(q);
 201         streamvp = strq2vp(q);
 202 
 203         ASSERT(streamvp != NULL);
 204         ASSERT(streamvp->v_type == VFIFO);
 205 
 206         streamfnp = VTOF(streamvp);
 207         streamfnp->fn_flag &= ~FIFOCONNLD;
 208         VN_RELE(streamvp);
 209         return (0);
 210 }
 211 
 212 /*
 213  * Use same put procedure for write and read queues.
 214  */
 215 int
 216 connput(queue_t *q, mblk_t *bp)
 217 {
 218         putnext(q, bp);
 219         return (0);
 220 }