xref: /onnv-gate/usr/src/uts/common/io/ib/clients/sdp/sdpddi.c (revision 13055:5b1463e9bb94)
13422Snh145002 /*
23422Snh145002  * CDDL HEADER START
33422Snh145002  *
43422Snh145002  * The contents of this file are subject to the terms of the
53422Snh145002  * Common Development and Distribution License (the "License").
63422Snh145002  * You may not use this file except in compliance with the License.
73422Snh145002  *
83422Snh145002  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93422Snh145002  * or http://www.opensolaris.org/os/licensing.
103422Snh145002  * See the License for the specific language governing permissions
113422Snh145002  * and limitations under the License.
123422Snh145002  *
133422Snh145002  * When distributing Covered Code, include this CDDL HEADER in each
143422Snh145002  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153422Snh145002  * If applicable, add the following below this CDDL HEADER, with the
163422Snh145002  * fields enclosed by brackets "[]" replaced with your own identifying
173422Snh145002  * information: Portions Copyright [yyyy] [name of copyright owner]
183422Snh145002  *
193422Snh145002  * CDDL HEADER END
203422Snh145002  */
213422Snh145002 /*
22*13055SAnders.Persson@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
233422Snh145002  */
243422Snh145002 
253422Snh145002 #include <sys/types.h>
263422Snh145002 #include <sys/conf.h>
273422Snh145002 #include <sys/modctl.h>
283422Snh145002 #include <sys/stat.h>
293422Snh145002 #include <sys/stream.h>
303422Snh145002 #include <sys/strsun.h>
317150Snh145002 #include <sys/stropts.h>
323422Snh145002 #include <sys/ddi.h>
333422Snh145002 #include <sys/sunddi.h>
343422Snh145002 #include <sys/sunldi.h>
353422Snh145002 #include <sys/file.h>
363422Snh145002 #include <sys/priv_names.h>
373422Snh145002 #include <inet/common.h>
383422Snh145002 
393422Snh145002 #define	_SUN_TPI_VERSION 2
403422Snh145002 #include <sys/tihdr.h>
413422Snh145002 #include <sys/timod.h>
423422Snh145002 #include <sys/tiuser.h>
433422Snh145002 #include <sys/suntpi.h>
443422Snh145002 #include <sys/socket.h>
453422Snh145002 #include <sys/sockio.h>
463422Snh145002 #include <inet/common.h>
473422Snh145002 #include <inet/ip.h>
483422Snh145002 #include <inet/mi.h>
493422Snh145002 #include <sys/policy.h>
503422Snh145002 #include "sys/random.h"
513422Snh145002 #include <inet/sdp_itf.h>
523422Snh145002 #include <sys/ib/ibtl/ibti.h>
533422Snh145002 
543422Snh145002 
553422Snh145002 /*
563422Snh145002  * This is a pseudo driver which creates an entry for /dev/sdp in the device
57*13055SAnders.Persson@Sun.COM  * tree. A regular installation will end up adding a file to sock2path.d
58*13055SAnders.Persson@Sun.COM  * announcing support for sdp using AF_INET/SOCK_STREAM/PROTO_SDP parameters in
59*13055SAnders.Persson@Sun.COM  * socket call. On a non IB hardware, following are the constraints within
60*13055SAnders.Persson@Sun.COM  * which the sdp project operates. The sdpib driver which is the real driver
613422Snh145002  * (in terms of moving data) should not be loaded since it has dependency on
623422Snh145002  * ibcm and ibtl modules which will be loaded in the memory. This will consume
633422Snh145002  * precious memory and needs to be avoided. As a result the sdpib driver
643422Snh145002  * should fail its init() call to disallow loading on other modules. Due to
653422Snh145002  * this we do not get a chance to create a /dev/sdp entry in the device tree
663422Snh145002  * in the regular sdpib driver. During the boottime, this will cause a warning
673422Snh145002  * message when  soconfig processes the entry for sdp in sock2path file . In
683422Snh145002  * order to avoid this a pseudo driver is introduced which creates an entry
693422Snh145002  * for /dev/sdp regardless of the hardware. When a socket  call is made on the
703422Snh145002  * sdp subsystem, the call will end up in this driver, which then forwards
713422Snh145002  * this call to the real sdp driver.  On a non-ib hardware system the call
723422Snh145002  * will fail
733422Snh145002  */
743422Snh145002 
753422Snh145002 #define	SDP_NAME	"sdp"
767656SSherry.Moore@Sun.COM #define	SDP_DEVDESC	"SDP STREAMS driver"
773422Snh145002 #define	SDP_DEVMINOR	0
783422Snh145002 
793422Snh145002 static dev_info_t *sdp_dev_info;
803422Snh145002 
813422Snh145002 ldi_ident_t sdp_li;
823422Snh145002 krwlock_t	sdp_transport_lock;
833422Snh145002 ldi_handle_t	sdp_transport_handle = NULL;
843422Snh145002 
853422Snh145002 static int
sdp_gen_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)863422Snh145002 sdp_gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
873422Snh145002 {
883422Snh145002 	int	ret;
893422Snh145002 
903422Snh145002 	if (cmd != DDI_ATTACH)
913422Snh145002 		return (DDI_FAILURE);
923422Snh145002 
933422Snh145002 	sdp_dev_info = devi;
943422Snh145002 
953422Snh145002 	ret = ddi_create_minor_node(devi, SDP_NAME, S_IFCHR,
963422Snh145002 	    SDP_DEVMINOR, DDI_PSEUDO, 0);
973422Snh145002 	if (ret != DDI_SUCCESS) {
983422Snh145002 		return (ret);
993422Snh145002 	}
1003422Snh145002 	return (DDI_SUCCESS);
1013422Snh145002 }
1023422Snh145002 
1033422Snh145002 static int
sdp_gen_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)1043422Snh145002 sdp_gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
1053422Snh145002 {
1063422Snh145002 	if (cmd != DDI_DETACH)
1073422Snh145002 		return (DDI_FAILURE);
1083422Snh145002 
1093422Snh145002 	ASSERT(devi == sdp_dev_info);
1103422Snh145002 
1113422Snh145002 	ddi_remove_minor_node(devi, NULL);
1123422Snh145002 
1133422Snh145002 	return (DDI_SUCCESS);
1143422Snh145002 }
1153422Snh145002 
1163422Snh145002 /* open routine. */
1173422Snh145002 /*ARGSUSED*/
1183422Snh145002 static int
sdp_gen_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)1193422Snh145002 sdp_gen_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
1203422Snh145002 {
1213422Snh145002 	qprocson(q);
1223422Snh145002 	qenable(q);
1233422Snh145002 	return (0);
1243422Snh145002 }
1253422Snh145002 
1263422Snh145002 /* open routine. */
1273422Snh145002 /*ARGSUSED*/
1283422Snh145002 static int
sdp_gen_close(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)1293422Snh145002 sdp_gen_close(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
1303422Snh145002 {
1313422Snh145002 	qprocsoff(q);
1323422Snh145002 	return (0);
1333422Snh145002 }
1343422Snh145002 
1353422Snh145002 static int
sdp_open_sdpib_driver()1363422Snh145002 sdp_open_sdpib_driver()
1373422Snh145002 {
1383422Snh145002 	int ret = 0;
1393422Snh145002 
1403422Snh145002 	rw_enter(&sdp_transport_lock, RW_WRITER);
1413422Snh145002 	if (sdp_transport_handle != 0) {
1423422Snh145002 		/*
1433422Snh145002 		 * Someone beat us to it.
1443422Snh145002 		 */
1453422Snh145002 		goto done;
1463422Snh145002 	}
1473422Snh145002 
1483422Snh145002 	if (ibt_hw_is_present() == 0) {
1493422Snh145002 		ret = ENODEV;
1503422Snh145002 		goto done;
1513422Snh145002 	}
1523422Snh145002 
1533422Snh145002 	if (sdp_li == NULL) {
1543422Snh145002 		ret = EPROTONOSUPPORT;
1553422Snh145002 		goto done;
1563422Snh145002 	}
1573422Snh145002 
1583422Snh145002 	ret = ldi_open_by_name("/devices/ib/sdpib@0:sdpib",
1593422Snh145002 	    FREAD | FWRITE, kcred, &sdp_transport_handle, sdp_li);
1603422Snh145002 	if (ret != 0) {
1613422Snh145002 		ret = EPROTONOSUPPORT;
1623422Snh145002 		sdp_transport_handle = NULL;
1633422Snh145002 		goto done;
1643422Snh145002 	}
1653422Snh145002 
1663422Snh145002 done:
1673422Snh145002 	rw_exit(&sdp_transport_lock);
1683422Snh145002 	return (ret);
1693422Snh145002 }
1703422Snh145002 
1713422Snh145002 
1723422Snh145002 static void
sdp_gen_ioctl(queue_t * q,mblk_t * mp)1733422Snh145002 sdp_gen_ioctl(queue_t *q, mblk_t *mp)
1743422Snh145002 {
1753422Snh145002 	struct iocblk *iocp;
1763422Snh145002 	int32_t enable = 0;
1773422Snh145002 	int ret;
1783422Snh145002 	boolean_t priv = B_TRUE;
1793422Snh145002 
1803422Snh145002 	/* LINTED */
1813422Snh145002 	iocp = (struct iocblk *)mp->b_rptr;
1823422Snh145002 	switch (iocp->ioc_cmd) {
1838891SLida.Horn@Sun.COM 			int32_t send_enable;
1844996Sse146197 		case SIOCSENABLESDP:
1853422Snh145002 			bcopy(mp->b_cont->b_rptr, &enable, sizeof (int));
1863422Snh145002 
1878348SEric.Yu@Sun.COM 			send_enable = enable;
1888348SEric.Yu@Sun.COM 
1893422Snh145002 			/*
1903422Snh145002 			 * Check for root privs.
1913422Snh145002 			 * if not net config privs - return state of system SDP
1923422Snh145002 			 */
1933422Snh145002 			if (secpolicy_net_config(CRED(), B_FALSE) != 0) {
1943422Snh145002 				priv = B_FALSE;
1953422Snh145002 			}
1963422Snh145002 
1973422Snh145002 
1983422Snh145002 			/*
1993422Snh145002 			 * The sdpib driver is loaded if root enables sdp the
2003422Snh145002 			 * first time (sdp_transport_handle is NULL). It is
2013422Snh145002 			 * unloaded during the following first disable. At all
2023422Snh145002 			 * other times for root as well as non-root users, the
2033422Snh145002 			 * action of enabling/disabling sdp is simply acked.
2043422Snh145002 			 */
2053422Snh145002 			rw_enter(&sdp_transport_lock, RW_READER);
2068348SEric.Yu@Sun.COM 			if ((send_enable == 1) &&
2078348SEric.Yu@Sun.COM 			    (sdp_transport_handle == NULL) &&
2087150Snh145002 			    (priv == B_TRUE)) {
2093422Snh145002 				/* Initialize sdpib transport driver */
2103422Snh145002 				rw_exit(&sdp_transport_lock);
2113422Snh145002 				ret = sdp_open_sdpib_driver();
2123422Snh145002 				rw_enter(&sdp_transport_lock,
2133422Snh145002 				    RW_READER);
2143422Snh145002 				if (ret != 0) {
2153422Snh145002 					/* Transport failed to load */
2163422Snh145002 					rw_exit(&sdp_transport_lock);
2173422Snh145002 					enable = 0;
2183422Snh145002 					goto done;
2193422Snh145002 				}
2208348SEric.Yu@Sun.COM 				(void) ldi_ioctl(sdp_transport_handle,
2218348SEric.Yu@Sun.COM 				    iocp->ioc_cmd, (intptr_t)&send_enable,
2228348SEric.Yu@Sun.COM 				    FKIOCTL, CRED(), (int *)&enable);
2238348SEric.Yu@Sun.COM 			} else if (sdp_transport_handle != NULL) {
2248348SEric.Yu@Sun.COM 				(void) ldi_ioctl(sdp_transport_handle,
2258348SEric.Yu@Sun.COM 				    iocp->ioc_cmd, (intptr_t)&send_enable,
2268348SEric.Yu@Sun.COM 				    FKIOCTL, CRED(), (int *)&enable);
2278348SEric.Yu@Sun.COM 				if (send_enable == 0 && priv == B_TRUE) {
2288348SEric.Yu@Sun.COM 					(void) ldi_close(sdp_transport_handle,
2298348SEric.Yu@Sun.COM 					    FNDELAY, kcred);
2308348SEric.Yu@Sun.COM 					sdp_transport_handle = NULL;
2318348SEric.Yu@Sun.COM 				}
2323422Snh145002 			} else {
2338348SEric.Yu@Sun.COM 				enable = 0;
2343422Snh145002 			}
2353422Snh145002 			rw_exit(&sdp_transport_lock);
2363422Snh145002 
2373422Snh145002 done:
2383422Snh145002 			bcopy(&enable, mp->b_cont->b_rptr, sizeof (int));
2393422Snh145002 
2403422Snh145002 			/* ACK the ioctl */
2413422Snh145002 			mp->b_datap->db_type = M_IOCACK;
2423422Snh145002 			iocp->ioc_count = sizeof (int);
2433422Snh145002 			qreply(q, mp);
2443422Snh145002 			break;
2453422Snh145002 		default:
2463422Snh145002 			miocnak(q, mp, 0, ENOTSUP);
2473422Snh145002 	}
2483422Snh145002 }
2493422Snh145002 
2503422Snh145002 /*
2513422Snh145002  * Received a put from sockfs. We only support ndd get/set
2523422Snh145002  */
2533422Snh145002 static void
sdp_gen_wput(queue_t * q,mblk_t * mp)2543422Snh145002 sdp_gen_wput(queue_t *q, mblk_t *mp)
2553422Snh145002 {
2563422Snh145002 	switch (mp->b_datap->db_type) {
2577150Snh145002 	case M_IOCTL:
2587150Snh145002 		sdp_gen_ioctl(q, mp);
2597150Snh145002 		break;
2607150Snh145002 	case M_FLUSH:
2617150Snh145002 		*mp->b_rptr &= ~FLUSHW;
2627150Snh145002 		if (*mp->b_rptr & FLUSHR)
2637150Snh145002 			qreply(q, mp);
2647150Snh145002 		else
2657150Snh145002 			freemsg(mp);
2667150Snh145002 		break;
2677150Snh145002 	default:
2687150Snh145002 		freemsg(mp);
2697150Snh145002 		return;
2703422Snh145002 	}
2713422Snh145002 }
2723422Snh145002 
2733422Snh145002 static struct module_info info = {
2743422Snh145002 	0, "sdp", 1, INFPSZ, 65536, 1024
2753422Snh145002 };
2763422Snh145002 
2773422Snh145002 static struct qinit rinit = {
2783422Snh145002 	NULL, (pfi_t)NULL, (pfi_t)sdp_gen_open, (pfi_t)sdp_gen_close, NULL,
2793422Snh145002 	&info, NULL, NULL, NULL, STRUIOT_NONE
2803422Snh145002 };
2813422Snh145002 
2823422Snh145002 static struct qinit winit = {
2833422Snh145002 	(pfi_t)sdp_gen_wput, NULL,  (pfi_t)sdp_gen_open,  (pfi_t)sdp_gen_close,
2843422Snh145002 	NULL, &info, NULL, NULL, NULL, STRUIOT_NONE
2853422Snh145002 };
2863422Snh145002 
2873422Snh145002 struct streamtab sdpinfo = {
2883422Snh145002 	&rinit, &winit, NULL, NULL
2893422Snh145002 };
2903422Snh145002 
2917150Snh145002 DDI_DEFINE_STREAM_OPS(sdp_devops, nulldev, nulldev, sdp_gen_attach,
2927656SSherry.Moore@Sun.COM     sdp_gen_detach, nodev, NULL, D_MP, &sdpinfo, ddi_quiesce_not_needed);
2933422Snh145002 
2943422Snh145002 /*
2953422Snh145002  * Module linkage information for the kernel.
2963422Snh145002  */
2973422Snh145002 static struct modldrv modldrv = {
2983422Snh145002 	&mod_driverops,
2993422Snh145002 	SDP_DEVDESC,
3003422Snh145002 	&sdp_devops
3013422Snh145002 };
3023422Snh145002 
3033422Snh145002 static struct modlinkage modlinkage = {
3043422Snh145002 	MODREV_1,
3053422Snh145002 	&modldrv,
3063422Snh145002 	NULL
3073422Snh145002 };
3083422Snh145002 
3093422Snh145002 int
_init(void)3103422Snh145002 _init(void)
3113422Snh145002 {
3123422Snh145002 	int	ret;
3133422Snh145002 
3143422Snh145002 	ret = mod_install(&modlinkage);
3153422Snh145002 	if (ret != 0)
3163422Snh145002 		goto done;
3173422Snh145002 	ret = ldi_ident_from_mod(&modlinkage, &sdp_li);
3183422Snh145002 	if (ret != 0)
3193422Snh145002 		sdp_li = NULL;
3203422Snh145002 done:
3213422Snh145002 	return (ret);
3223422Snh145002 }
3233422Snh145002 
3243422Snh145002 int
_fini(void)3253422Snh145002 _fini(void)
3263422Snh145002 {
3273422Snh145002 	int	ret;
3283422Snh145002 
3293422Snh145002 	ret = mod_remove(&modlinkage);
3303422Snh145002 	if (ret != 0) {
3313422Snh145002 		return (ret);
3323422Snh145002 	}
3333422Snh145002 
3343422Snh145002 	ldi_ident_release(sdp_li);
3353422Snh145002 	return (0);
3363422Snh145002 }
3373422Snh145002 
3383422Snh145002 int
_info(struct modinfo * modinfop)3393422Snh145002 _info(struct modinfo *modinfop)
3403422Snh145002 {
3413422Snh145002 	return (mod_info(&modlinkage, modinfop));
3423422Snh145002 }
343