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