xref: /illumos-gate/usr/src/uts/common/io/ib/clients/sdp/sdpddi.c (revision bbfe764ef179c2f606b093b6ec6bb149cde0e31b)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/conf.h>
30 #include <sys/modctl.h>
31 #include <sys/stat.h>
32 #include <sys/stream.h>
33 #include <sys/strsun.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/sunldi.h>
37 #include <sys/file.h>
38 #include <sys/priv_names.h>
39 #include <inet/common.h>
40 
41 #define	_SUN_TPI_VERSION 2
42 #include <sys/tihdr.h>
43 #include <sys/timod.h>
44 #include <sys/tiuser.h>
45 #include <sys/suntpi.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <inet/common.h>
49 #include <inet/ip.h>
50 #include <inet/mi.h>
51 #include <sys/policy.h>
52 #include "sys/random.h"
53 #include <inet/sdp_itf.h>
54 #include <sys/ib/ibtl/ibti.h>
55 
56 
57 /*
58  * This is a pseudo driver which creates an entry for /dev/sdp in the device
59  * tree. A regular installation will end up modifying sock2path file announcing
60  * support for sdp using AF_INET/SOCK_STREAM/PROTO_SDP parameters in socket
61  * call. On a non IB hardware, following are the constraints within which
62  * the sdp project operates. The sdpib driver which is the real driver
63  * (in terms of moving data) should not be loaded since it has dependency on
64  * ibcm and ibtl modules which will be loaded in the memory. This will consume
65  * precious memory and needs to be avoided. As a result the sdpib driver
66  * should fail its init() call to disallow loading on other modules. Due to
67  * this we do not get a chance to create a /dev/sdp entry in the device tree
68  * in the regular sdpib driver. During the boottime, this will cause a warning
69  * message when  soconfig processes the entry for sdp in sock2path file . In
70  * order to avoid this a pseudo driver is introduced which creates an entry
71  * for /dev/sdp regardless of the hardware. When a socket  call is made on the
72  * sdp subsystem, the call will end up in this driver, which then forwards
73  * this call to the real sdp driver.  On a non-ib hardware system the call
74  * will fail
75  */
76 
77 #define	SDP_NAME	"sdp"
78 #define	SDP_DEVDESC	"SDP STREAMS driver %I%"
79 #define	SDP_DEVMINOR	0
80 
81 static dev_info_t *sdp_dev_info;
82 
83 ldi_ident_t sdp_li;
84 krwlock_t	sdp_transport_lock;
85 ldi_handle_t	sdp_transport_handle = NULL;
86 
87 static int
88 sdp_gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
89 {
90 	int	ret;
91 
92 	if (cmd != DDI_ATTACH)
93 		return (DDI_FAILURE);
94 
95 	sdp_dev_info = devi;
96 
97 	ret = ddi_create_minor_node(devi, SDP_NAME, S_IFCHR,
98 	    SDP_DEVMINOR, DDI_PSEUDO, 0);
99 	if (ret != DDI_SUCCESS) {
100 		return (ret);
101 	}
102 	return (DDI_SUCCESS);
103 }
104 
105 static int
106 sdp_gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
107 {
108 	if (cmd != DDI_DETACH)
109 		return (DDI_FAILURE);
110 
111 	ASSERT(devi == sdp_dev_info);
112 
113 	ddi_remove_minor_node(devi, NULL);
114 
115 	return (DDI_SUCCESS);
116 }
117 
118 /* open routine. */
119 /*ARGSUSED*/
120 static int
121 sdp_gen_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
122 {
123 	qprocson(q);
124 	qenable(q);
125 	return (0);
126 }
127 
128 /* open routine. */
129 /*ARGSUSED*/
130 static int
131 sdp_gen_close(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
132 {
133 	qprocsoff(q);
134 	return (0);
135 }
136 
137 static int
138 sdp_open_sdpib_driver()
139 {
140 	int ret = 0;
141 
142 	rw_enter(&sdp_transport_lock, RW_WRITER);
143 	if (sdp_transport_handle != 0) {
144 		/*
145 		 * Someone beat us to it.
146 		 */
147 		goto done;
148 	}
149 
150 	if (ibt_hw_is_present() == 0) {
151 		ret = ENODEV;
152 		goto done;
153 	}
154 
155 	if (sdp_li == NULL) {
156 		ret = EPROTONOSUPPORT;
157 		goto done;
158 	}
159 
160 	ret = ldi_open_by_name("/devices/ib/sdpib@0:sdpib",
161 	    FREAD | FWRITE, kcred, &sdp_transport_handle, sdp_li);
162 	if (ret != 0) {
163 		ret = EPROTONOSUPPORT;
164 		sdp_transport_handle = NULL;
165 		goto done;
166 	}
167 
168 done:
169 	rw_exit(&sdp_transport_lock);
170 	return (ret);
171 }
172 
173 
174 static void
175 sdp_gen_ioctl(queue_t *q, mblk_t *mp)
176 {
177 	struct iocblk *iocp;
178 	int32_t enable = 0;
179 	int ret;
180 	boolean_t priv = B_TRUE;
181 
182 	/* LINTED */
183 	iocp = (struct iocblk *)mp->b_rptr;
184 	switch (iocp->ioc_cmd) {
185 		case SIOCSENABLESDP:
186 			bcopy(mp->b_cont->b_rptr, &enable, sizeof (int));
187 
188 			/*
189 			 * Check for root privs.
190 			 * if not net config privs - return state of system SDP
191 			 */
192 			if (secpolicy_net_config(CRED(), B_FALSE) != 0) {
193 				priv = B_FALSE;
194 			}
195 
196 
197 			/*
198 			 * The sdpib driver is loaded if root enables sdp the
199 			 * first time (sdp_transport_handle is NULL). It is
200 			 * unloaded during the following first disable. At all
201 			 * other times for root as well as non-root users, the
202 			 * action of enabling/disabling sdp is simply acked.
203 			 */
204 			rw_enter(&sdp_transport_lock, RW_READER);
205 			if ((enable == 1) && (sdp_transport_handle == NULL) &&
206 				(priv == B_TRUE)) {
207 				/* Initialize sdpib transport driver */
208 				rw_exit(&sdp_transport_lock);
209 				ret = sdp_open_sdpib_driver();
210 				rw_enter(&sdp_transport_lock,
211 				    RW_READER);
212 				if (ret != 0) {
213 					/* Transport failed to load */
214 					rw_exit(&sdp_transport_lock);
215 					enable = 0;
216 					goto done;
217 				}
218 				(void) sdp_ioctl(NULL, iocp->ioc_cmd, &enable,
219 				    CRED());
220 			} else if ((enable == 0) &&
221 			    (sdp_transport_handle != NULL) &&
222 			    (priv == B_TRUE)) {
223 				(void) sdp_ioctl(NULL, iocp->ioc_cmd, &enable,
224 				    CRED());
225 				(void) ldi_close(sdp_transport_handle,
226 				    FNDELAY, kcred);
227 				sdp_transport_handle = NULL;
228 			} else {
229 				ret = sdp_ioctl(NULL, iocp->ioc_cmd, &enable,
230 				    CRED());
231 				if (ret == EINVAL)
232 					enable = 0;
233 			}
234 			rw_exit(&sdp_transport_lock);
235 
236 done:
237 			bcopy(&enable, mp->b_cont->b_rptr, sizeof (int));
238 
239 			/* ACK the ioctl */
240 			mp->b_datap->db_type = M_IOCACK;
241 			iocp->ioc_count = sizeof (int);
242 			qreply(q, mp);
243 			break;
244 		default:
245 			miocnak(q, mp, 0, ENOTSUP);
246 	}
247 }
248 
249 /*
250  * Received a put from sockfs. We only support ndd get/set
251  */
252 static void
253 sdp_gen_wput(queue_t *q, mblk_t *mp)
254 {
255 	switch (mp->b_datap->db_type) {
256 		case M_IOCTL:
257 			sdp_gen_ioctl(q, mp);
258 			break;
259 		default:
260 			return;
261 	}
262 }
263 
264 static struct module_info info = {
265 	0, "sdp", 1, INFPSZ, 65536, 1024
266 };
267 
268 static struct qinit rinit = {
269 	NULL, (pfi_t)NULL, (pfi_t)sdp_gen_open, (pfi_t)sdp_gen_close, NULL,
270 	&info, NULL, NULL, NULL, STRUIOT_NONE
271 };
272 
273 static struct qinit winit = {
274 	(pfi_t)sdp_gen_wput, NULL,  (pfi_t)sdp_gen_open,  (pfi_t)sdp_gen_close,
275 	NULL, &info, NULL, NULL, NULL, STRUIOT_NONE
276 };
277 
278 struct streamtab sdpinfo = {
279 	&rinit, &winit, NULL, NULL
280 };
281 
282 /* Stream operations */
283 static struct streamtab sdp_streamtab = {
284 	&rinit,	/* read queue */
285 	&winit,	/* write queue */
286 };
287 
288 /* Character/block operations */
289 static struct cb_ops sdp_cb_ops = {
290 	nodev,		/* open */
291 	nodev,		/* close */
292 	nodev,		/* strategy */
293 	nodev,		/* print */
294 	nodev,		/* dump */
295 	nodev,		/* read */
296 	nodev,		/* write */
297 	nodev,	/* ioctl */
298 	nodev,		/* devmap */
299 	nodev,		/* mmap */
300 	nodev,		/* segmap */
301 	nochpoll,	/* chpoll */
302 	ddi_prop_op,	/* prop_op (sun DDI-specific) */
303 	&sdp_streamtab,	/* streams */
304 	D_MP,
305 	CB_REV
306 };
307 
308 /* Driver operations */
309 static struct dev_ops sdp_devops = {
310 	DEVO_REV,	/* struct rev */
311 	0,		/* refcnt */
312 	nodev,		/* getinfo */
313 	nulldev,	/* identify */
314 	nulldev,	/* probe */
315 	sdp_gen_attach,	/* attach */
316 	sdp_gen_detach,	/* detach */
317 	nodev,		/* reset */
318 	&sdp_cb_ops,	/* cb_ops */
319 	NULL,		/* bus_ops */
320 	nodev		/* power */
321 };
322 
323 /*
324  * Module linkage information for the kernel.
325  */
326 static struct modldrv modldrv = {
327 	&mod_driverops,
328 	SDP_DEVDESC,
329 	&sdp_devops
330 };
331 
332 static struct modlinkage modlinkage = {
333 	MODREV_1,
334 	&modldrv,
335 	NULL
336 };
337 
338 int
339 _init(void)
340 {
341 	int	ret;
342 
343 	ret = mod_install(&modlinkage);
344 	if (ret != 0)
345 		goto done;
346 	ret = ldi_ident_from_mod(&modlinkage, &sdp_li);
347 	if (ret != 0)
348 		sdp_li = NULL;
349 done:
350 	return (ret);
351 }
352 
353 int
354 _fini(void)
355 {
356 	int	ret;
357 
358 	ret = mod_remove(&modlinkage);
359 	if (ret != 0) {
360 		return (ret);
361 	}
362 
363 	ldi_ident_release(sdp_li);
364 	return (0);
365 }
366 
367 int
368 _info(struct modinfo *modinfop)
369 {
370 	return (mod_info(&modlinkage, modinfop));
371 }
372