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