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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/types.h>
26 #include <sys/conf.h>
27 #include <sys/modctl.h>
28 #include <sys/stat.h>
29 #include <sys/stream.h>
30 #include <sys/strsun.h>
31 #include <sys/stropts.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <sys/sunldi.h>
35 #include <sys/file.h>
36 #include <sys/priv_names.h>
37 #include <inet/common.h>
38
39 #define _SUN_TPI_VERSION 2
40 #include <sys/tihdr.h>
41 #include <sys/timod.h>
42 #include <sys/tiuser.h>
43 #include <sys/suntpi.h>
44 #include <sys/socket.h>
45 #include <sys/sockio.h>
46 #include <inet/common.h>
47 #include <inet/ip.h>
48 #include <inet/mi.h>
49 #include <sys/policy.h>
50 #include "sys/random.h"
51 #include <inet/sdp_itf.h>
52 #include <sys/ib/ibtl/ibti.h>
53
54
55 /*
56 * This is a pseudo driver which creates an entry for /dev/sdp in the device
57 * tree. A regular installation will end up adding a file to sock2path.d
58 * announcing support for sdp using AF_INET/SOCK_STREAM/PROTO_SDP parameters in
59 * socket call. On a non IB hardware, following are the constraints within
60 * which the sdp project operates. The sdpib driver which is the real driver
61 * (in terms of moving data) should not be loaded since it has dependency on
62 * ibcm and ibtl modules which will be loaded in the memory. This will consume
63 * precious memory and needs to be avoided. As a result the sdpib driver
64 * should fail its init() call to disallow loading on other modules. Due to
65 * this we do not get a chance to create a /dev/sdp entry in the device tree
66 * in the regular sdpib driver. During the boottime, this will cause a warning
67 * message when soconfig processes the entry for sdp in sock2path file . In
68 * order to avoid this a pseudo driver is introduced which creates an entry
69 * for /dev/sdp regardless of the hardware. When a socket call is made on the
70 * sdp subsystem, the call will end up in this driver, which then forwards
71 * this call to the real sdp driver. On a non-ib hardware system the call
72 * will fail
73 */
74
75 #define SDP_NAME "sdp"
76 #define SDP_DEVDESC "SDP STREAMS driver"
77 #define SDP_DEVMINOR 0
78
79 static dev_info_t *sdp_dev_info;
80
81 ldi_ident_t sdp_li;
82 krwlock_t sdp_transport_lock;
83 ldi_handle_t sdp_transport_handle = NULL;
84
85 static int
sdp_gen_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)86 sdp_gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
87 {
88 int ret;
89
90 if (cmd != DDI_ATTACH)
91 return (DDI_FAILURE);
92
93 sdp_dev_info = devi;
94
95 ret = ddi_create_minor_node(devi, SDP_NAME, S_IFCHR,
96 SDP_DEVMINOR, DDI_PSEUDO, 0);
97 if (ret != DDI_SUCCESS) {
98 return (ret);
99 }
100 return (DDI_SUCCESS);
101 }
102
103 static int
sdp_gen_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)104 sdp_gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
105 {
106 if (cmd != DDI_DETACH)
107 return (DDI_FAILURE);
108
109 ASSERT(devi == sdp_dev_info);
110
111 ddi_remove_minor_node(devi, NULL);
112
113 return (DDI_SUCCESS);
114 }
115
116 /* open routine. */
117 /*ARGSUSED*/
118 static int
sdp_gen_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)119 sdp_gen_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
120 {
121 qprocson(q);
122 qenable(q);
123 return (0);
124 }
125
126 /* open routine. */
127 /*ARGSUSED*/
128 static int
sdp_gen_close(queue_t * q,int flag,cred_t * credp)129 sdp_gen_close(queue_t *q, int flag, cred_t *credp)
130 {
131 qprocsoff(q);
132 return (0);
133 }
134
135 static int
sdp_open_sdpib_driver()136 sdp_open_sdpib_driver()
137 {
138 int ret = 0;
139
140 rw_enter(&sdp_transport_lock, RW_WRITER);
141 if (sdp_transport_handle != 0) {
142 /*
143 * Someone beat us to it.
144 */
145 goto done;
146 }
147
148 if (ibt_hw_is_present() == 0) {
149 ret = ENODEV;
150 goto done;
151 }
152
153 if (sdp_li == NULL) {
154 ret = EPROTONOSUPPORT;
155 goto done;
156 }
157
158 ret = ldi_open_by_name("/devices/ib/sdpib@0:sdpib",
159 FREAD | FWRITE, kcred, &sdp_transport_handle, sdp_li);
160 if (ret != 0) {
161 ret = EPROTONOSUPPORT;
162 sdp_transport_handle = NULL;
163 goto done;
164 }
165
166 done:
167 rw_exit(&sdp_transport_lock);
168 return (ret);
169 }
170
171
172 static void
sdp_gen_ioctl(queue_t * q,mblk_t * mp)173 sdp_gen_ioctl(queue_t *q, mblk_t *mp)
174 {
175 struct iocblk *iocp;
176 int32_t enable = 0;
177 int ret;
178 boolean_t priv = B_TRUE;
179
180 /* LINTED */
181 iocp = (struct iocblk *)mp->b_rptr;
182 switch (iocp->ioc_cmd) {
183 int32_t send_enable;
184 case SIOCSENABLESDP:
185 bcopy(mp->b_cont->b_rptr, &enable, sizeof (int));
186
187 send_enable = enable;
188
189 /*
190 * Check for root privs.
191 * if not net config privs - return state of system SDP
192 */
193 if (secpolicy_net_config(CRED(), B_FALSE) != 0) {
194 priv = B_FALSE;
195 }
196
197
198 /*
199 * The sdpib driver is loaded if root enables sdp the
200 * first time (sdp_transport_handle is NULL). It is
201 * unloaded during the following first disable. At all
202 * other times for root as well as non-root users, the
203 * action of enabling/disabling sdp is simply acked.
204 */
205 rw_enter(&sdp_transport_lock, RW_READER);
206 if ((send_enable == 1) &&
207 (sdp_transport_handle == NULL) &&
208 (priv == B_TRUE)) {
209 /* Initialize sdpib transport driver */
210 rw_exit(&sdp_transport_lock);
211 ret = sdp_open_sdpib_driver();
212 rw_enter(&sdp_transport_lock,
213 RW_READER);
214 if (ret != 0) {
215 /* Transport failed to load */
216 rw_exit(&sdp_transport_lock);
217 enable = 0;
218 goto done;
219 }
220 (void) ldi_ioctl(sdp_transport_handle,
221 iocp->ioc_cmd, (intptr_t)&send_enable,
222 FKIOCTL, CRED(), (int *)&enable);
223 } else if (sdp_transport_handle != NULL) {
224 (void) ldi_ioctl(sdp_transport_handle,
225 iocp->ioc_cmd, (intptr_t)&send_enable,
226 FKIOCTL, CRED(), (int *)&enable);
227 if (send_enable == 0 && priv == B_TRUE) {
228 (void) ldi_close(sdp_transport_handle,
229 FNDELAY, kcred);
230 sdp_transport_handle = NULL;
231 }
232 } else {
233 enable = 0;
234 }
235 rw_exit(&sdp_transport_lock);
236
237 done:
238 bcopy(&enable, mp->b_cont->b_rptr, sizeof (int));
239
240 /* ACK the ioctl */
241 mp->b_datap->db_type = M_IOCACK;
242 iocp->ioc_count = sizeof (int);
243 qreply(q, mp);
244 break;
245 default:
246 miocnak(q, mp, 0, ENOTSUP);
247 }
248 }
249
250 /*
251 * Received a put from sockfs. We only support ndd get/set
252 */
253 static int
sdp_gen_wput(queue_t * q,mblk_t * mp)254 sdp_gen_wput(queue_t *q, mblk_t *mp)
255 {
256 switch (mp->b_datap->db_type) {
257 case M_IOCTL:
258 sdp_gen_ioctl(q, mp);
259 break;
260 case M_FLUSH:
261 *mp->b_rptr &= ~FLUSHW;
262 if (*mp->b_rptr & FLUSHR)
263 qreply(q, mp);
264 else
265 freemsg(mp);
266 break;
267 default:
268 freemsg(mp);
269 return (0);
270 }
271 return (0);
272 }
273
274 static struct module_info info = {
275 0, "sdp", 1, INFPSZ, 65536, 1024
276 };
277
278 static struct qinit rinit = {
279 NULL, NULL, sdp_gen_open, sdp_gen_close, NULL,
280 &info, NULL, NULL, NULL, STRUIOT_NONE
281 };
282
283 static struct qinit winit = {
284 sdp_gen_wput, NULL, sdp_gen_open, sdp_gen_close,
285 NULL, &info, NULL, NULL, NULL, STRUIOT_NONE
286 };
287
288 struct streamtab sdpinfo = {
289 &rinit, &winit, NULL, NULL
290 };
291
292 DDI_DEFINE_STREAM_OPS(sdp_devops, nulldev, nulldev, sdp_gen_attach,
293 sdp_gen_detach, nodev, NULL, D_MP, &sdpinfo, ddi_quiesce_not_needed);
294
295 /*
296 * Module linkage information for the kernel.
297 */
298 static struct modldrv modldrv = {
299 &mod_driverops,
300 SDP_DEVDESC,
301 &sdp_devops
302 };
303
304 static struct modlinkage modlinkage = {
305 MODREV_1,
306 &modldrv,
307 NULL
308 };
309
310 int
_init(void)311 _init(void)
312 {
313 int ret;
314
315 ret = mod_install(&modlinkage);
316 if (ret != 0)
317 goto done;
318 ret = ldi_ident_from_mod(&modlinkage, &sdp_li);
319 if (ret != 0)
320 sdp_li = NULL;
321 done:
322 return (ret);
323 }
324
325 int
_fini(void)326 _fini(void)
327 {
328 int ret;
329
330 ret = mod_remove(&modlinkage);
331 if (ret != 0) {
332 return (ret);
333 }
334
335 ldi_ident_release(sdp_li);
336 return (0);
337 }
338
339 int
_info(struct modinfo * modinfop)340 _info(struct modinfo *modinfop)
341 {
342 return (mod_info(&modlinkage, modinfop));
343 }
344