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