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 }