174e20cfeSnh /*
274e20cfeSnh  * CDDL HEADER START
374e20cfeSnh  *
474e20cfeSnh  * The contents of this file are subject to the terms of the
574e20cfeSnh  * Common Development and Distribution License (the "License").
674e20cfeSnh  * You may not use this file except in compliance with the License.
774e20cfeSnh  *
874e20cfeSnh  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
974e20cfeSnh  * or http://www.opensolaris.org/os/licensing.
1074e20cfeSnh  * See the License for the specific language governing permissions
1174e20cfeSnh  * and limitations under the License.
1274e20cfeSnh  *
1374e20cfeSnh  * When distributing Covered Code, include this CDDL HEADER in each
1474e20cfeSnh  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1574e20cfeSnh  * If applicable, add the following below this CDDL HEADER, with the
1674e20cfeSnh  * fields enclosed by brackets "[]" replaced with your own identifying
1774e20cfeSnh  * information: Portions Copyright [yyyy] [name of copyright owner]
1874e20cfeSnh  *
1974e20cfeSnh  * CDDL HEADER END
2074e20cfeSnh  */
2174e20cfeSnh /*
22d2b5b2d3SAnders Persson  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2374e20cfeSnh  */
2474e20cfeSnh 
2574e20cfeSnh #include <sys/types.h>
2674e20cfeSnh #include <sys/conf.h>
2774e20cfeSnh #include <sys/modctl.h>
2874e20cfeSnh #include <sys/stat.h>
2974e20cfeSnh #include <sys/stream.h>
3074e20cfeSnh #include <sys/strsun.h>
3109cb82caSnh #include <sys/stropts.h>
3274e20cfeSnh #include <sys/ddi.h>
3374e20cfeSnh #include <sys/sunddi.h>
3474e20cfeSnh #include <sys/sunldi.h>
3574e20cfeSnh #include <sys/file.h>
3674e20cfeSnh #include <sys/priv_names.h>
3774e20cfeSnh #include <inet/common.h>
3874e20cfeSnh 
3974e20cfeSnh #define	_SUN_TPI_VERSION 2
4074e20cfeSnh #include <sys/tihdr.h>
4174e20cfeSnh #include <sys/timod.h>
4274e20cfeSnh #include <sys/tiuser.h>
4374e20cfeSnh #include <sys/suntpi.h>
4474e20cfeSnh #include <sys/socket.h>
4574e20cfeSnh #include <sys/sockio.h>
4674e20cfeSnh #include <inet/common.h>
4774e20cfeSnh #include <inet/ip.h>
4874e20cfeSnh #include <inet/mi.h>
4974e20cfeSnh #include <sys/policy.h>
5074e20cfeSnh #include "sys/random.h"
5174e20cfeSnh #include <inet/sdp_itf.h>
5274e20cfeSnh #include <sys/ib/ibtl/ibti.h>
5374e20cfeSnh 
5474e20cfeSnh 
5574e20cfeSnh /*
5674e20cfeSnh  * This is a pseudo driver which creates an entry for /dev/sdp in the device
57d2b5b2d3SAnders Persson  * tree. A regular installation will end up adding a file to sock2path.d
58d2b5b2d3SAnders Persson  * announcing support for sdp using AF_INET/SOCK_STREAM/PROTO_SDP parameters in
59d2b5b2d3SAnders Persson  * socket call. On a non IB hardware, following are the constraints within
60d2b5b2d3SAnders Persson  * which the sdp project operates. The sdpib driver which is the real driver
6174e20cfeSnh  * (in terms of moving data) should not be loaded since it has dependency on
6274e20cfeSnh  * ibcm and ibtl modules which will be loaded in the memory. This will consume
6374e20cfeSnh  * precious memory and needs to be avoided. As a result the sdpib driver
6474e20cfeSnh  * should fail its init() call to disallow loading on other modules. Due to
6574e20cfeSnh  * this we do not get a chance to create a /dev/sdp entry in the device tree
6674e20cfeSnh  * in the regular sdpib driver. During the boottime, this will cause a warning
6774e20cfeSnh  * message when  soconfig processes the entry for sdp in sock2path file . In
6874e20cfeSnh  * order to avoid this a pseudo driver is introduced which creates an entry
6974e20cfeSnh  * for /dev/sdp regardless of the hardware. When a socket  call is made on the
7074e20cfeSnh  * sdp subsystem, the call will end up in this driver, which then forwards
7174e20cfeSnh  * this call to the real sdp driver.  On a non-ib hardware system the call
7274e20cfeSnh  * will fail
7374e20cfeSnh  */
7474e20cfeSnh 
7574e20cfeSnh #define	SDP_NAME	"sdp"
7619397407SSherry Moore #define	SDP_DEVDESC	"SDP STREAMS driver"
7774e20cfeSnh #define	SDP_DEVMINOR	0
7874e20cfeSnh 
7974e20cfeSnh static dev_info_t *sdp_dev_info;
8074e20cfeSnh 
8174e20cfeSnh ldi_ident_t sdp_li;
8274e20cfeSnh krwlock_t	sdp_transport_lock;
8374e20cfeSnh ldi_handle_t	sdp_transport_handle = NULL;
8474e20cfeSnh 
8574e20cfeSnh static int
sdp_gen_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)8674e20cfeSnh sdp_gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
8774e20cfeSnh {
8874e20cfeSnh 	int	ret;
8974e20cfeSnh 
9074e20cfeSnh 	if (cmd != DDI_ATTACH)
9174e20cfeSnh 		return (DDI_FAILURE);
9274e20cfeSnh 
9374e20cfeSnh 	sdp_dev_info = devi;
9474e20cfeSnh 
9574e20cfeSnh 	ret = ddi_create_minor_node(devi, SDP_NAME, S_IFCHR,
9674e20cfeSnh 	    SDP_DEVMINOR, DDI_PSEUDO, 0);
9774e20cfeSnh 	if (ret != DDI_SUCCESS) {
9874e20cfeSnh 		return (ret);
9974e20cfeSnh 	}
10074e20cfeSnh 	return (DDI_SUCCESS);
10174e20cfeSnh }
10274e20cfeSnh 
10374e20cfeSnh static int
sdp_gen_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)10474e20cfeSnh sdp_gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
10574e20cfeSnh {
10674e20cfeSnh 	if (cmd != DDI_DETACH)
10774e20cfeSnh 		return (DDI_FAILURE);
10874e20cfeSnh 
10974e20cfeSnh 	ASSERT(devi == sdp_dev_info);
11074e20cfeSnh 
11174e20cfeSnh 	ddi_remove_minor_node(devi, NULL);
11274e20cfeSnh 
11374e20cfeSnh 	return (DDI_SUCCESS);
11474e20cfeSnh }
11574e20cfeSnh 
11674e20cfeSnh /* open routine. */
11774e20cfeSnh /*ARGSUSED*/
11874e20cfeSnh static int
sdp_gen_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)11974e20cfeSnh sdp_gen_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
12074e20cfeSnh {
12174e20cfeSnh 	qprocson(q);
12274e20cfeSnh 	qenable(q);
12374e20cfeSnh 	return (0);
12474e20cfeSnh }
12574e20cfeSnh 
12674e20cfeSnh /* open routine. */
12774e20cfeSnh /*ARGSUSED*/
12874e20cfeSnh static int
sdp_gen_close(queue_t * q,int flag,cred_t * credp)129*067a68e3SToomas Soome sdp_gen_close(queue_t *q, int flag, cred_t *credp)
13074e20cfeSnh {
13174e20cfeSnh 	qprocsoff(q);
13274e20cfeSnh 	return (0);
13374e20cfeSnh }
13474e20cfeSnh 
13574e20cfeSnh static int
sdp_open_sdpib_driver()13674e20cfeSnh sdp_open_sdpib_driver()
13774e20cfeSnh {
13874e20cfeSnh 	int ret = 0;
13974e20cfeSnh 
14074e20cfeSnh 	rw_enter(&sdp_transport_lock, RW_WRITER);
14174e20cfeSnh 	if (sdp_transport_handle != 0) {
14274e20cfeSnh 		/*
14374e20cfeSnh 		 * Someone beat us to it.
14474e20cfeSnh 		 */
14574e20cfeSnh 		goto done;
14674e20cfeSnh 	}
14774e20cfeSnh 
14874e20cfeSnh 	if (ibt_hw_is_present() == 0) {
14974e20cfeSnh 		ret = ENODEV;
15074e20cfeSnh 		goto done;
15174e20cfeSnh 	}
15274e20cfeSnh 
15374e20cfeSnh 	if (sdp_li == NULL) {
15474e20cfeSnh 		ret = EPROTONOSUPPORT;
15574e20cfeSnh 		goto done;
15674e20cfeSnh 	}
15774e20cfeSnh 
15874e20cfeSnh 	ret = ldi_open_by_name("/devices/ib/sdpib@0:sdpib",
15974e20cfeSnh 	    FREAD | FWRITE, kcred, &sdp_transport_handle, sdp_li);
16074e20cfeSnh 	if (ret != 0) {
16174e20cfeSnh 		ret = EPROTONOSUPPORT;
16274e20cfeSnh 		sdp_transport_handle = NULL;
16374e20cfeSnh 		goto done;
16474e20cfeSnh 	}
16574e20cfeSnh 
16674e20cfeSnh done:
16774e20cfeSnh 	rw_exit(&sdp_transport_lock);
16874e20cfeSnh 	return (ret);
16974e20cfeSnh }
17074e20cfeSnh 
17174e20cfeSnh 
17274e20cfeSnh static void
sdp_gen_ioctl(queue_t * q,mblk_t * mp)17374e20cfeSnh sdp_gen_ioctl(queue_t *q, mblk_t *mp)
17474e20cfeSnh {
17574e20cfeSnh 	struct iocblk *iocp;
17674e20cfeSnh 	int32_t enable = 0;
17774e20cfeSnh 	int ret;
17874e20cfeSnh 	boolean_t priv = B_TRUE;
17974e20cfeSnh 
18074e20cfeSnh 	/* LINTED */
18174e20cfeSnh 	iocp = (struct iocblk *)mp->b_rptr;
18274e20cfeSnh 	switch (iocp->ioc_cmd) {
1832876fe8aSLida.Horn 			int32_t send_enable;
184bbfe764eSse 		case SIOCSENABLESDP:
18574e20cfeSnh 			bcopy(mp->b_cont->b_rptr, &enable, sizeof (int));
18674e20cfeSnh 
1870f1702c5SYu Xiangning 			send_enable = enable;
1880f1702c5SYu Xiangning 
18974e20cfeSnh 			/*
19074e20cfeSnh 			 * Check for root privs.
19174e20cfeSnh 			 * if not net config privs - return state of system SDP
19274e20cfeSnh 			 */
19374e20cfeSnh 			if (secpolicy_net_config(CRED(), B_FALSE) != 0) {
19474e20cfeSnh 				priv = B_FALSE;
19574e20cfeSnh 			}
19674e20cfeSnh 
19774e20cfeSnh 
19874e20cfeSnh 			/*
19974e20cfeSnh 			 * The sdpib driver is loaded if root enables sdp the
20074e20cfeSnh 			 * first time (sdp_transport_handle is NULL). It is
20174e20cfeSnh 			 * unloaded during the following first disable. At all
20274e20cfeSnh 			 * other times for root as well as non-root users, the
20374e20cfeSnh 			 * action of enabling/disabling sdp is simply acked.
20474e20cfeSnh 			 */
20574e20cfeSnh 			rw_enter(&sdp_transport_lock, RW_READER);
2060f1702c5SYu Xiangning 			if ((send_enable == 1) &&
2070f1702c5SYu Xiangning 			    (sdp_transport_handle == NULL) &&
20809cb82caSnh 			    (priv == B_TRUE)) {
20974e20cfeSnh 				/* Initialize sdpib transport driver */
21074e20cfeSnh 				rw_exit(&sdp_transport_lock);
21174e20cfeSnh 				ret = sdp_open_sdpib_driver();
21274e20cfeSnh 				rw_enter(&sdp_transport_lock,
21374e20cfeSnh 				    RW_READER);
21474e20cfeSnh 				if (ret != 0) {
21574e20cfeSnh 					/* Transport failed to load */
21674e20cfeSnh 					rw_exit(&sdp_transport_lock);
21774e20cfeSnh 					enable = 0;
21874e20cfeSnh 					goto done;
21974e20cfeSnh 				}
2200f1702c5SYu Xiangning 				(void) ldi_ioctl(sdp_transport_handle,
2210f1702c5SYu Xiangning 				    iocp->ioc_cmd, (intptr_t)&send_enable,
2220f1702c5SYu Xiangning 				    FKIOCTL, CRED(), (int *)&enable);
2230f1702c5SYu Xiangning 			} else if (sdp_transport_handle != NULL) {
2240f1702c5SYu Xiangning 				(void) ldi_ioctl(sdp_transport_handle,
2250f1702c5SYu Xiangning 				    iocp->ioc_cmd, (intptr_t)&send_enable,
2260f1702c5SYu Xiangning 				    FKIOCTL, CRED(), (int *)&enable);
2270f1702c5SYu Xiangning 				if (send_enable == 0 && priv == B_TRUE) {
2280f1702c5SYu Xiangning 					(void) ldi_close(sdp_transport_handle,
2290f1702c5SYu Xiangning 					    FNDELAY, kcred);
2300f1702c5SYu Xiangning 					sdp_transport_handle = NULL;
2310f1702c5SYu Xiangning 				}
23274e20cfeSnh 			} else {
2330f1702c5SYu Xiangning 				enable = 0;
23474e20cfeSnh 			}
23574e20cfeSnh 			rw_exit(&sdp_transport_lock);
23674e20cfeSnh 
23774e20cfeSnh done:
23874e20cfeSnh 			bcopy(&enable, mp->b_cont->b_rptr, sizeof (int));
23974e20cfeSnh 
24074e20cfeSnh 			/* ACK the ioctl */
24174e20cfeSnh 			mp->b_datap->db_type = M_IOCACK;
24274e20cfeSnh 			iocp->ioc_count = sizeof (int);
24374e20cfeSnh 			qreply(q, mp);
24474e20cfeSnh 			break;
24574e20cfeSnh 		default:
24674e20cfeSnh 			miocnak(q, mp, 0, ENOTSUP);
24774e20cfeSnh 	}
24874e20cfeSnh }
24974e20cfeSnh 
25074e20cfeSnh /*
25174e20cfeSnh  * Received a put from sockfs. We only support ndd get/set
25274e20cfeSnh  */
253*067a68e3SToomas Soome static int
sdp_gen_wput(queue_t * q,mblk_t * mp)25474e20cfeSnh sdp_gen_wput(queue_t *q, mblk_t *mp)
25574e20cfeSnh {
25674e20cfeSnh 	switch (mp->b_datap->db_type) {
25709cb82caSnh 	case M_IOCTL:
25809cb82caSnh 		sdp_gen_ioctl(q, mp);
25909cb82caSnh 		break;
26009cb82caSnh 	case M_FLUSH:
26109cb82caSnh 		*mp->b_rptr &= ~FLUSHW;
26209cb82caSnh 		if (*mp->b_rptr & FLUSHR)
26309cb82caSnh 			qreply(q, mp);
26409cb82caSnh 		else
26509cb82caSnh 			freemsg(mp);
26609cb82caSnh 		break;
26709cb82caSnh 	default:
26809cb82caSnh 		freemsg(mp);
269*067a68e3SToomas Soome 		return (0);
27074e20cfeSnh 	}
271*067a68e3SToomas Soome 	return (0);
27274e20cfeSnh }
27374e20cfeSnh 
27474e20cfeSnh static struct module_info info = {
27574e20cfeSnh 	0, "sdp", 1, INFPSZ, 65536, 1024
27674e20cfeSnh };
27774e20cfeSnh 
27874e20cfeSnh static struct qinit rinit = {
279*067a68e3SToomas Soome 	NULL, NULL, sdp_gen_open, sdp_gen_close, NULL,
28074e20cfeSnh 	&info, NULL, NULL, NULL, STRUIOT_NONE
28174e20cfeSnh };
28274e20cfeSnh 
28374e20cfeSnh static struct qinit winit = {
284*067a68e3SToomas Soome 	sdp_gen_wput, NULL,  sdp_gen_open, sdp_gen_close,
28574e20cfeSnh 	NULL, &info, NULL, NULL, NULL, STRUIOT_NONE
28674e20cfeSnh };
28774e20cfeSnh 
28874e20cfeSnh struct streamtab sdpinfo = {
28974e20cfeSnh 	&rinit, &winit, NULL, NULL
29074e20cfeSnh };
29174e20cfeSnh 
29209cb82caSnh DDI_DEFINE_STREAM_OPS(sdp_devops, nulldev, nulldev, sdp_gen_attach,
29319397407SSherry Moore     sdp_gen_detach, nodev, NULL, D_MP, &sdpinfo, ddi_quiesce_not_needed);
29474e20cfeSnh 
29574e20cfeSnh /*
29674e20cfeSnh  * Module linkage information for the kernel.
29774e20cfeSnh  */
29874e20cfeSnh static struct modldrv modldrv = {
29974e20cfeSnh 	&mod_driverops,
30074e20cfeSnh 	SDP_DEVDESC,
30174e20cfeSnh 	&sdp_devops
30274e20cfeSnh };
30374e20cfeSnh 
30474e20cfeSnh static struct modlinkage modlinkage = {
30574e20cfeSnh 	MODREV_1,
30674e20cfeSnh 	&modldrv,
30774e20cfeSnh 	NULL
30874e20cfeSnh };
30974e20cfeSnh 
31074e20cfeSnh int
_init(void)31174e20cfeSnh _init(void)
31274e20cfeSnh {
31374e20cfeSnh 	int	ret;
31474e20cfeSnh 
31574e20cfeSnh 	ret = mod_install(&modlinkage);
31674e20cfeSnh 	if (ret != 0)
31774e20cfeSnh 		goto done;
31874e20cfeSnh 	ret = ldi_ident_from_mod(&modlinkage, &sdp_li);
31974e20cfeSnh 	if (ret != 0)
32074e20cfeSnh 		sdp_li = NULL;
32174e20cfeSnh done:
32274e20cfeSnh 	return (ret);
32374e20cfeSnh }
32474e20cfeSnh 
32574e20cfeSnh int
_fini(void)32674e20cfeSnh _fini(void)
32774e20cfeSnh {
32874e20cfeSnh 	int	ret;
32974e20cfeSnh 
33074e20cfeSnh 	ret = mod_remove(&modlinkage);
33174e20cfeSnh 	if (ret != 0) {
33274e20cfeSnh 		return (ret);
33374e20cfeSnh 	}
33474e20cfeSnh 
33574e20cfeSnh 	ldi_ident_release(sdp_li);
33674e20cfeSnh 	return (0);
33774e20cfeSnh }
33874e20cfeSnh 
33974e20cfeSnh int
_info(struct modinfo * modinfop)34074e20cfeSnh _info(struct modinfo *modinfop)
34174e20cfeSnh {
34274e20cfeSnh 	return (mod_info(&modlinkage, modinfop));
34374e20cfeSnh }
344