xref: /illumos-gate/usr/src/uts/common/io/ib/clients/sdp/sdpddi.c (revision 3cf6f95f0e20ed31de99608fdb0a120190d5438f)
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 2008 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/stropts.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/sunldi.h>
38 #include <sys/file.h>
39 #include <sys/priv_names.h>
40 #include <inet/common.h>
41 
42 #define	_SUN_TPI_VERSION 2
43 #include <sys/tihdr.h>
44 #include <sys/timod.h>
45 #include <sys/tiuser.h>
46 #include <sys/suntpi.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <inet/common.h>
50 #include <inet/ip.h>
51 #include <inet/mi.h>
52 #include <sys/policy.h>
53 #include "sys/random.h"
54 #include <inet/sdp_itf.h>
55 #include <sys/ib/ibtl/ibti.h>
56 
57 
58 /*
59  * This is a pseudo driver which creates an entry for /dev/sdp in the device
60  * tree. A regular installation will end up modifying sock2path file announcing
61  * support for sdp using AF_INET/SOCK_STREAM/PROTO_SDP parameters in socket
62  * call. On a non IB hardware, following are the constraints within which
63  * the sdp project operates. The sdpib driver which is the real driver
64  * (in terms of moving data) should not be loaded since it has dependency on
65  * ibcm and ibtl modules which will be loaded in the memory. This will consume
66  * precious memory and needs to be avoided. As a result the sdpib driver
67  * should fail its init() call to disallow loading on other modules. Due to
68  * this we do not get a chance to create a /dev/sdp entry in the device tree
69  * in the regular sdpib driver. During the boottime, this will cause a warning
70  * message when  soconfig processes the entry for sdp in sock2path file . In
71  * order to avoid this a pseudo driver is introduced which creates an entry
72  * for /dev/sdp regardless of the hardware. When a socket  call is made on the
73  * sdp subsystem, the call will end up in this driver, which then forwards
74  * this call to the real sdp driver.  On a non-ib hardware system the call
75  * will fail
76  */
77 
78 #define	SDP_NAME	"sdp"
79 #define	SDP_DEVDESC	"SDP STREAMS driver %I%"
80 #define	SDP_DEVMINOR	0
81 
82 static dev_info_t *sdp_dev_info;
83 
84 ldi_ident_t sdp_li;
85 krwlock_t	sdp_transport_lock;
86 ldi_handle_t	sdp_transport_handle = NULL;
87 
88 static int
89 sdp_gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
90 {
91 	int	ret;
92 
93 	if (cmd != DDI_ATTACH)
94 		return (DDI_FAILURE);
95 
96 	sdp_dev_info = devi;
97 
98 	ret = ddi_create_minor_node(devi, SDP_NAME, S_IFCHR,
99 	    SDP_DEVMINOR, DDI_PSEUDO, 0);
100 	if (ret != DDI_SUCCESS) {
101 		return (ret);
102 	}
103 	return (DDI_SUCCESS);
104 }
105 
106 static int
107 sdp_gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
108 {
109 	if (cmd != DDI_DETACH)
110 		return (DDI_FAILURE);
111 
112 	ASSERT(devi == sdp_dev_info);
113 
114 	ddi_remove_minor_node(devi, NULL);
115 
116 	return (DDI_SUCCESS);
117 }
118 
119 /* open routine. */
120 /*ARGSUSED*/
121 static int
122 sdp_gen_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
123 {
124 	qprocson(q);
125 	qenable(q);
126 	return (0);
127 }
128 
129 /* open routine. */
130 /*ARGSUSED*/
131 static int
132 sdp_gen_close(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
133 {
134 	qprocsoff(q);
135 	return (0);
136 }
137 
138 static int
139 sdp_open_sdpib_driver()
140 {
141 	int ret = 0;
142 
143 	rw_enter(&sdp_transport_lock, RW_WRITER);
144 	if (sdp_transport_handle != 0) {
145 		/*
146 		 * Someone beat us to it.
147 		 */
148 		goto done;
149 	}
150 
151 	if (ibt_hw_is_present() == 0) {
152 		ret = ENODEV;
153 		goto done;
154 	}
155 
156 	if (sdp_li == NULL) {
157 		ret = EPROTONOSUPPORT;
158 		goto done;
159 	}
160 
161 	ret = ldi_open_by_name("/devices/ib/sdpib@0:sdpib",
162 	    FREAD | FWRITE, kcred, &sdp_transport_handle, sdp_li);
163 	if (ret != 0) {
164 		ret = EPROTONOSUPPORT;
165 		sdp_transport_handle = NULL;
166 		goto done;
167 	}
168 
169 done:
170 	rw_exit(&sdp_transport_lock);
171 	return (ret);
172 }
173 
174 
175 static void
176 sdp_gen_ioctl(queue_t *q, mblk_t *mp)
177 {
178 	struct iocblk *iocp;
179 	int32_t enable = 0;
180 	int ret;
181 	boolean_t priv = B_TRUE;
182 
183 	/* LINTED */
184 	iocp = (struct iocblk *)mp->b_rptr;
185 	switch (iocp->ioc_cmd) {
186 		case SIOCSENABLESDP:
187 			bcopy(mp->b_cont->b_rptr, &enable, sizeof (int));
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 ((enable == 1) && (sdp_transport_handle == NULL) &&
207 			    (priv == B_TRUE)) {
208 				/* Initialize sdpib transport driver */
209 				rw_exit(&sdp_transport_lock);
210 				ret = sdp_open_sdpib_driver();
211 				rw_enter(&sdp_transport_lock,
212 				    RW_READER);
213 				if (ret != 0) {
214 					/* Transport failed to load */
215 					rw_exit(&sdp_transport_lock);
216 					enable = 0;
217 					goto done;
218 				}
219 				(void) sdp_ioctl(NULL, iocp->ioc_cmd, &enable,
220 				    CRED());
221 			} else if ((enable == 0) &&
222 			    (sdp_transport_handle != NULL) &&
223 			    (priv == B_TRUE)) {
224 				(void) sdp_ioctl(NULL, iocp->ioc_cmd, &enable,
225 				    CRED());
226 				(void) ldi_close(sdp_transport_handle,
227 				    FNDELAY, kcred);
228 				sdp_transport_handle = NULL;
229 			} else {
230 				ret = sdp_ioctl(NULL, iocp->ioc_cmd, &enable,
231 				    CRED());
232 				if (ret == EINVAL)
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 void
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;
270 	}
271 }
272 
273 static struct module_info info = {
274 	0, "sdp", 1, INFPSZ, 65536, 1024
275 };
276 
277 static struct qinit rinit = {
278 	NULL, (pfi_t)NULL, (pfi_t)sdp_gen_open, (pfi_t)sdp_gen_close, NULL,
279 	&info, NULL, NULL, NULL, STRUIOT_NONE
280 };
281 
282 static struct qinit winit = {
283 	(pfi_t)sdp_gen_wput, NULL,  (pfi_t)sdp_gen_open,  (pfi_t)sdp_gen_close,
284 	NULL, &info, NULL, NULL, NULL, STRUIOT_NONE
285 };
286 
287 struct streamtab sdpinfo = {
288 	&rinit, &winit, NULL, NULL
289 };
290 
291 DDI_DEFINE_STREAM_OPS(sdp_devops, nulldev, nulldev, sdp_gen_attach,
292     sdp_gen_detach, nodev, NULL, D_MP, &sdpinfo);
293 
294 /*
295  * Module linkage information for the kernel.
296  */
297 static struct modldrv modldrv = {
298 	&mod_driverops,
299 	SDP_DEVDESC,
300 	&sdp_devops
301 };
302 
303 static struct modlinkage modlinkage = {
304 	MODREV_1,
305 	&modldrv,
306 	NULL
307 };
308 
309 int
310 _init(void)
311 {
312 	int	ret;
313 
314 	ret = mod_install(&modlinkage);
315 	if (ret != 0)
316 		goto done;
317 	ret = ldi_ident_from_mod(&modlinkage, &sdp_li);
318 	if (ret != 0)
319 		sdp_li = NULL;
320 done:
321 	return (ret);
322 }
323 
324 int
325 _fini(void)
326 {
327 	int	ret;
328 
329 	ret = mod_remove(&modlinkage);
330 	if (ret != 0) {
331 		return (ret);
332 	}
333 
334 	ldi_ident_release(sdp_li);
335 	return (0);
336 }
337 
338 int
339 _info(struct modinfo *modinfop)
340 {
341 	return (mod_info(&modlinkage, modinfop));
342 }
343