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