xref: /illumos-gate/usr/src/uts/common/io/ib/clients/sdp/sdpddi.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/conf.h>
28 #include <sys/modctl.h>
29 #include <sys/stat.h>
30 #include <sys/stream.h>
31 #include <sys/strsun.h>
32 #include <sys/stropts.h>
33 #include <sys/ddi.h>
34 #include <sys/sunddi.h>
35 #include <sys/sunldi.h>
36 #include <sys/file.h>
37 #include <sys/priv_names.h>
38 #include <inet/common.h>
39 
40 #define	_SUN_TPI_VERSION 2
41 #include <sys/tihdr.h>
42 #include <sys/timod.h>
43 #include <sys/tiuser.h>
44 #include <sys/suntpi.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
47 #include <inet/common.h>
48 #include <inet/ip.h>
49 #include <inet/mi.h>
50 #include <sys/policy.h>
51 #include "sys/random.h"
52 #include <inet/sdp_itf.h>
53 #include <sys/ib/ibtl/ibti.h>
54 
55 
56 /*
57  * This is a pseudo driver which creates an entry for /dev/sdp in the device
58  * tree. A regular installation will end up modifying sock2path file announcing
59  * support for sdp using AF_INET/SOCK_STREAM/PROTO_SDP parameters in socket
60  * call. On a non IB hardware, following are the constraints within which
61  * the sdp project operates. The sdpib driver which is the real driver
62  * (in terms of moving data) should not be loaded since it has dependency on
63  * ibcm and ibtl modules which will be loaded in the memory. This will consume
64  * precious memory and needs to be avoided. As a result the sdpib driver
65  * should fail its init() call to disallow loading on other modules. Due to
66  * this we do not get a chance to create a /dev/sdp entry in the device tree
67  * in the regular sdpib driver. During the boottime, this will cause a warning
68  * message when  soconfig processes the entry for sdp in sock2path file . In
69  * order to avoid this a pseudo driver is introduced which creates an entry
70  * for /dev/sdp regardless of the hardware. When a socket  call is made on the
71  * sdp subsystem, the call will end up in this driver, which then forwards
72  * this call to the real sdp driver.  On a non-ib hardware system the call
73  * will fail
74  */
75 
76 #define	SDP_NAME	"sdp"
77 #define	SDP_DEVDESC	"SDP STREAMS driver"
78 #define	SDP_DEVMINOR	0
79 
80 static dev_info_t *sdp_dev_info;
81 
82 ldi_ident_t sdp_li;
83 krwlock_t	sdp_transport_lock;
84 ldi_handle_t	sdp_transport_handle = NULL;
85 
86 static int
87 sdp_gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
88 {
89 	int	ret;
90 
91 	if (cmd != DDI_ATTACH)
92 		return (DDI_FAILURE);
93 
94 	sdp_dev_info = devi;
95 
96 	ret = ddi_create_minor_node(devi, SDP_NAME, S_IFCHR,
97 	    SDP_DEVMINOR, DDI_PSEUDO, 0);
98 	if (ret != DDI_SUCCESS) {
99 		return (ret);
100 	}
101 	return (DDI_SUCCESS);
102 }
103 
104 static int
105 sdp_gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
106 {
107 	if (cmd != DDI_DETACH)
108 		return (DDI_FAILURE);
109 
110 	ASSERT(devi == sdp_dev_info);
111 
112 	ddi_remove_minor_node(devi, NULL);
113 
114 	return (DDI_SUCCESS);
115 }
116 
117 /* open routine. */
118 /*ARGSUSED*/
119 static int
120 sdp_gen_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
121 {
122 	qprocson(q);
123 	qenable(q);
124 	return (0);
125 }
126 
127 /* open routine. */
128 /*ARGSUSED*/
129 static int
130 sdp_gen_close(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
131 {
132 	qprocsoff(q);
133 	return (0);
134 }
135 
136 static int
137 sdp_open_sdpib_driver()
138 {
139 	int ret = 0;
140 
141 	rw_enter(&sdp_transport_lock, RW_WRITER);
142 	if (sdp_transport_handle != 0) {
143 		/*
144 		 * Someone beat us to it.
145 		 */
146 		goto done;
147 	}
148 
149 	if (ibt_hw_is_present() == 0) {
150 		ret = ENODEV;
151 		goto done;
152 	}
153 
154 	if (sdp_li == NULL) {
155 		ret = EPROTONOSUPPORT;
156 		goto done;
157 	}
158 
159 	ret = ldi_open_by_name("/devices/ib/sdpib@0:sdpib",
160 	    FREAD | FWRITE, kcred, &sdp_transport_handle, sdp_li);
161 	if (ret != 0) {
162 		ret = EPROTONOSUPPORT;
163 		sdp_transport_handle = NULL;
164 		goto done;
165 	}
166 
167 done:
168 	rw_exit(&sdp_transport_lock);
169 	return (ret);
170 }
171 
172 
173 static void
174 sdp_gen_ioctl(queue_t *q, mblk_t *mp)
175 {
176 	struct iocblk *iocp;
177 	int32_t enable = 0;
178 	int ret;
179 	boolean_t priv = B_TRUE;
180 
181 	/* LINTED */
182 	iocp = (struct iocblk *)mp->b_rptr;
183 	switch (iocp->ioc_cmd) {
184 			int32_t send_enable;
185 		case SIOCSENABLESDP:
186 			bcopy(mp->b_cont->b_rptr, &enable, sizeof (int));
187 
188 			send_enable = enable;
189 
190 			/*
191 			 * Check for root privs.
192 			 * if not net config privs - return state of system SDP
193 			 */
194 			if (secpolicy_net_config(CRED(), B_FALSE) != 0) {
195 				priv = B_FALSE;
196 			}
197 
198 
199 			/*
200 			 * The sdpib driver is loaded if root enables sdp the
201 			 * first time (sdp_transport_handle is NULL). It is
202 			 * unloaded during the following first disable. At all
203 			 * other times for root as well as non-root users, the
204 			 * action of enabling/disabling sdp is simply acked.
205 			 */
206 			rw_enter(&sdp_transport_lock, RW_READER);
207 			if ((send_enable == 1) &&
208 			    (sdp_transport_handle == NULL) &&
209 			    (priv == B_TRUE)) {
210 				/* Initialize sdpib transport driver */
211 				rw_exit(&sdp_transport_lock);
212 				ret = sdp_open_sdpib_driver();
213 				rw_enter(&sdp_transport_lock,
214 				    RW_READER);
215 				if (ret != 0) {
216 					/* Transport failed to load */
217 					rw_exit(&sdp_transport_lock);
218 					enable = 0;
219 					goto done;
220 				}
221 				(void) ldi_ioctl(sdp_transport_handle,
222 				    iocp->ioc_cmd, (intptr_t)&send_enable,
223 				    FKIOCTL, CRED(), (int *)&enable);
224 			} else if (sdp_transport_handle != NULL) {
225 				(void) ldi_ioctl(sdp_transport_handle,
226 				    iocp->ioc_cmd, (intptr_t)&send_enable,
227 				    FKIOCTL, CRED(), (int *)&enable);
228 				if (send_enable == 0 && priv == B_TRUE) {
229 					(void) ldi_close(sdp_transport_handle,
230 					    FNDELAY, kcred);
231 					sdp_transport_handle = NULL;
232 				}
233 			} else {
234 				enable = 0;
235 			}
236 			rw_exit(&sdp_transport_lock);
237 
238 done:
239 			bcopy(&enable, mp->b_cont->b_rptr, sizeof (int));
240 
241 			/* ACK the ioctl */
242 			mp->b_datap->db_type = M_IOCACK;
243 			iocp->ioc_count = sizeof (int);
244 			qreply(q, mp);
245 			break;
246 		default:
247 			miocnak(q, mp, 0, ENOTSUP);
248 	}
249 }
250 
251 /*
252  * Received a put from sockfs. We only support ndd get/set
253  */
254 static void
255 sdp_gen_wput(queue_t *q, mblk_t *mp)
256 {
257 	switch (mp->b_datap->db_type) {
258 	case M_IOCTL:
259 		sdp_gen_ioctl(q, mp);
260 		break;
261 	case M_FLUSH:
262 		*mp->b_rptr &= ~FLUSHW;
263 		if (*mp->b_rptr & FLUSHR)
264 			qreply(q, mp);
265 		else
266 			freemsg(mp);
267 		break;
268 	default:
269 		freemsg(mp);
270 		return;
271 	}
272 }
273 
274 static struct module_info info = {
275 	0, "sdp", 1, INFPSZ, 65536, 1024
276 };
277 
278 static struct qinit rinit = {
279 	NULL, (pfi_t)NULL, (pfi_t)sdp_gen_open, (pfi_t)sdp_gen_close, NULL,
280 	&info, NULL, NULL, NULL, STRUIOT_NONE
281 };
282 
283 static struct qinit winit = {
284 	(pfi_t)sdp_gen_wput, NULL,  (pfi_t)sdp_gen_open,  (pfi_t)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
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
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
340 _info(struct modinfo *modinfop)
341 {
342 	return (mod_info(&modlinkage, modinfop));
343 }
344