14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000-2001 Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  */
324bff34e3Sthurlow 
334bff34e3Sthurlow /*
3439f633a0SBayard Bell  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
35613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
364bff34e3Sthurlow  * Use is subject to license terms.
374bff34e3Sthurlow  */
384bff34e3Sthurlow 
394bff34e3Sthurlow #include <sys/types.h>
404bff34e3Sthurlow #include <sys/param.h>
414bff34e3Sthurlow #include <sys/errno.h>
424bff34e3Sthurlow #include <sys/sysmacros.h>
434bff34e3Sthurlow #include <sys/uio.h>
444bff34e3Sthurlow #include <sys/buf.h>
454bff34e3Sthurlow #include <sys/modctl.h>
464bff34e3Sthurlow #include <sys/open.h>
474bff34e3Sthurlow #include <sys/file.h>
484bff34e3Sthurlow #include <sys/kmem.h>
494bff34e3Sthurlow #include <sys/conf.h>
504bff34e3Sthurlow #include <sys/cmn_err.h>
514bff34e3Sthurlow #include <sys/stat.h>
524bff34e3Sthurlow #include <sys/ddi.h>
534bff34e3Sthurlow #include <sys/sunddi.h>
544bff34e3Sthurlow #include <sys/sunldi.h>
554bff34e3Sthurlow #include <sys/policy.h>
564bff34e3Sthurlow #include <sys/zone.h>
574bff34e3Sthurlow #include <sys/pathname.h>
584bff34e3Sthurlow #include <sys/mount.h>
594bff34e3Sthurlow #include <sys/sdt.h>
604bff34e3Sthurlow #include <fs/fs_subr.h>
614bff34e3Sthurlow #include <sys/modctl.h>
624bff34e3Sthurlow #include <sys/devops.h>
634bff34e3Sthurlow #include <sys/thread.h>
644bff34e3Sthurlow #include <sys/types.h>
654bff34e3Sthurlow #include <sys/zone.h>
664bff34e3Sthurlow 
674bff34e3Sthurlow #include <netsmb/smb_osdep.h>
684bff34e3Sthurlow #include <netsmb/mchain.h>		/* for "htoles()" */
694bff34e3Sthurlow 
704bff34e3Sthurlow #include <netsmb/smb.h>
714bff34e3Sthurlow #include <netsmb/smb_conn.h>
724bff34e3Sthurlow #include <netsmb/smb_subr.h>
734bff34e3Sthurlow #include <netsmb/smb_dev.h>
744bff34e3Sthurlow #include <netsmb/smb_pass.h>
754bff34e3Sthurlow 
765ab8bad6SGordon Ross #define	NSMB_MIN_MINOR	1
775ab8bad6SGordon Ross #define	NSMB_MAX_MINOR	L_MAXMIN32
785ab8bad6SGordon Ross 
794bff34e3Sthurlow /* for version checks */
804bff34e3Sthurlow const uint32_t nsmb_version = NSMB_VERSION;
814bff34e3Sthurlow 
824bff34e3Sthurlow static void *statep;
834bff34e3Sthurlow static major_t nsmb_major;
845ab8bad6SGordon Ross static minor_t last_minor = NSMB_MIN_MINOR;
855ab8bad6SGordon Ross static dev_info_t *nsmb_dip;
864bff34e3Sthurlow static kmutex_t  dev_lck;
874bff34e3Sthurlow 
884bff34e3Sthurlow /* Zone support */
894bff34e3Sthurlow zone_key_t nsmb_zone_key;
904bff34e3Sthurlow extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
914bff34e3Sthurlow extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
924bff34e3Sthurlow 
934bff34e3Sthurlow /*
944bff34e3Sthurlow  * cb_ops device operations.
954bff34e3Sthurlow  */
964bff34e3Sthurlow static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
974bff34e3Sthurlow static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
984bff34e3Sthurlow static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
994bff34e3Sthurlow 				cred_t *credp, int *rvalp);
100613a2f6bSGordon Ross static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
101613a2f6bSGordon Ross 
1024bff34e3Sthurlow /* smbfs cb_ops */
1034bff34e3Sthurlow static struct cb_ops nsmb_cbops = {
1044bff34e3Sthurlow 	nsmb_open,	/* open */
1054bff34e3Sthurlow 	nsmb_close,	/* close */
1064bff34e3Sthurlow 	nodev,		/* strategy */
1074bff34e3Sthurlow 	nodev,		/* print */
1084bff34e3Sthurlow 	nodev,		/* dump */
1094bff34e3Sthurlow 	nodev,		/* read */
1104bff34e3Sthurlow 	nodev,		/* write */
1114bff34e3Sthurlow 	nsmb_ioctl,	/* ioctl */
1124bff34e3Sthurlow 	nodev,		/* devmap */
1134bff34e3Sthurlow 	nodev,		/* mmap */
1144bff34e3Sthurlow 	nodev,		/* segmap */
1154bff34e3Sthurlow 	nochpoll,	/* poll */
1164bff34e3Sthurlow 	ddi_prop_op,	/* prop_op */
1174bff34e3Sthurlow 	NULL,		/* stream */
1184bff34e3Sthurlow 	D_MP,		/* cb_flag */
1194bff34e3Sthurlow 	CB_REV,		/* rev */
1204bff34e3Sthurlow 	nodev,		/* int (*cb_aread)() */
1214bff34e3Sthurlow 	nodev		/* int (*cb_awrite)() */
1224bff34e3Sthurlow };
1234bff34e3Sthurlow 
1244bff34e3Sthurlow /*
1254bff34e3Sthurlow  * Device options
1264bff34e3Sthurlow  */
1274bff34e3Sthurlow static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1284bff34e3Sthurlow static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1294bff34e3Sthurlow static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
1304bff34e3Sthurlow 	void *arg, void **result);
1314bff34e3Sthurlow 
1324bff34e3Sthurlow static struct dev_ops nsmb_ops = {
1334bff34e3Sthurlow 	DEVO_REV,	/* devo_rev, */
1344bff34e3Sthurlow 	0,		/* refcnt  */
1354bff34e3Sthurlow 	nsmb_getinfo,	/* info */
1364bff34e3Sthurlow 	nulldev,	/* identify */
1374bff34e3Sthurlow 	nulldev,	/* probe */
1384bff34e3Sthurlow 	nsmb_attach,	/* attach */
1394bff34e3Sthurlow 	nsmb_detach,	/* detach */
1404bff34e3Sthurlow 	nodev,		/* reset */
1414bff34e3Sthurlow 	&nsmb_cbops,	/* driver ops - devctl interfaces */
1424bff34e3Sthurlow 	NULL,		/* bus operations */
14319397407SSherry Moore 	NULL,		/* power */
14419397407SSherry Moore 	ddi_quiesce_not_needed,	/* quiesce */
1454bff34e3Sthurlow };
1464bff34e3Sthurlow 
1474bff34e3Sthurlow /*
1484bff34e3Sthurlow  * Module linkage information.
1494bff34e3Sthurlow  */
1504bff34e3Sthurlow 
1514bff34e3Sthurlow static struct modldrv nsmb_modldrv = {
1524bff34e3Sthurlow 	&mod_driverops,				/* Driver module */
153613a2f6bSGordon Ross 	"SMBFS network driver",
1544bff34e3Sthurlow 	&nsmb_ops				/* Driver ops */
1554bff34e3Sthurlow };
1564bff34e3Sthurlow 
1574bff34e3Sthurlow static struct modlinkage nsmb_modlinkage = {
1584bff34e3Sthurlow 	MODREV_1,
1594bff34e3Sthurlow 	(void *)&nsmb_modldrv,
1604bff34e3Sthurlow 	NULL
1614bff34e3Sthurlow };
1624bff34e3Sthurlow 
1634bff34e3Sthurlow int
1644bff34e3Sthurlow _init(void)
1654bff34e3Sthurlow {
1664bff34e3Sthurlow 	int error;
1674bff34e3Sthurlow 
16802d09e03SGordon Ross 	(void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
1694bff34e3Sthurlow 
1704bff34e3Sthurlow 	/* Can initialize some mutexes also. */
1714bff34e3Sthurlow 	mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);
1724bff34e3Sthurlow 
1734bff34e3Sthurlow 	/* Connection data structures. */
1744bff34e3Sthurlow 	(void) smb_sm_init();
1754bff34e3Sthurlow 
1764bff34e3Sthurlow 	/* Initialize password Key chain DB. */
1774bff34e3Sthurlow 	smb_pkey_init();
1784bff34e3Sthurlow 
17902d09e03SGordon Ross 	/* Time conversion stuff. */
18002d09e03SGordon Ross 	smb_time_init();
18102d09e03SGordon Ross 
1829c9af259SGordon Ross 	/* Initialize crypto mechanisms. */
1839c9af259SGordon Ross 	smb_crypto_mech_init();
1849c9af259SGordon Ross 
1854bff34e3Sthurlow 	zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
1864bff34e3Sthurlow 	    nsmb_zone_destroy);
1874bff34e3Sthurlow 
1884bff34e3Sthurlow 	/*
1894bff34e3Sthurlow 	 * Install the module.  Do this after other init,
1904bff34e3Sthurlow 	 * to prevent entrances before we're ready.
1914bff34e3Sthurlow 	 */
1924bff34e3Sthurlow 	if ((error = mod_install((&nsmb_modlinkage))) != 0) {
1934bff34e3Sthurlow 
1944bff34e3Sthurlow 		/* Same as 2nd half of _fini */
1954bff34e3Sthurlow 		(void) zone_key_delete(nsmb_zone_key);
1964bff34e3Sthurlow 		smb_pkey_fini();
1974bff34e3Sthurlow 		smb_sm_done();
1984bff34e3Sthurlow 		mutex_destroy(&dev_lck);
1994bff34e3Sthurlow 		ddi_soft_state_fini(&statep);
2004bff34e3Sthurlow 
2014bff34e3Sthurlow 		return (error);
2024bff34e3Sthurlow 	}
2034bff34e3Sthurlow 
2044bff34e3Sthurlow 	return (0);
2054bff34e3Sthurlow }
2064bff34e3Sthurlow 
2074bff34e3Sthurlow int
2084bff34e3Sthurlow _fini(void)
2094bff34e3Sthurlow {
2104bff34e3Sthurlow 	int status;
2114bff34e3Sthurlow 
2124bff34e3Sthurlow 	/*
2134bff34e3Sthurlow 	 * Prevent unload if we have active VCs
2144bff34e3Sthurlow 	 * or stored passwords
2154bff34e3Sthurlow 	 */
2164bff34e3Sthurlow 	if ((status = smb_sm_idle()) != 0)
2174bff34e3Sthurlow 		return (status);
2184bff34e3Sthurlow 	if ((status = smb_pkey_idle()) != 0)
2194bff34e3Sthurlow 		return (status);
2204bff34e3Sthurlow 
2214bff34e3Sthurlow 	/*
2224bff34e3Sthurlow 	 * Remove the module.  Do this before destroying things,
2234bff34e3Sthurlow 	 * to prevent new entrances while we're destorying.
2244bff34e3Sthurlow 	 */
2254bff34e3Sthurlow 	if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
2264bff34e3Sthurlow 		return (status);
2274bff34e3Sthurlow 	}
2284bff34e3Sthurlow 
2294bff34e3Sthurlow 	(void) zone_key_delete(nsmb_zone_key);
2304bff34e3Sthurlow 
23102d09e03SGordon Ross 	/* Time conversion stuff. */
23202d09e03SGordon Ross 	smb_time_fini();
23302d09e03SGordon Ross 
2344bff34e3Sthurlow 	/* Destroy password Key chain DB. */
2354bff34e3Sthurlow 	smb_pkey_fini();
2364bff34e3Sthurlow 
2374bff34e3Sthurlow 	smb_sm_done();
2384bff34e3Sthurlow 
2394bff34e3Sthurlow 	mutex_destroy(&dev_lck);
2404bff34e3Sthurlow 	ddi_soft_state_fini(&statep);
2414bff34e3Sthurlow 
2424bff34e3Sthurlow 	return (status);
2434bff34e3Sthurlow }
2444bff34e3Sthurlow 
2454bff34e3Sthurlow int
2464bff34e3Sthurlow _info(struct modinfo *modinfop)
2474bff34e3Sthurlow {
2484bff34e3Sthurlow 	return (mod_info(&nsmb_modlinkage, modinfop));
2494bff34e3Sthurlow }
2504bff34e3Sthurlow 
2514bff34e3Sthurlow /*ARGSUSED*/
2524bff34e3Sthurlow static int
2534bff34e3Sthurlow nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2544bff34e3Sthurlow {
2554bff34e3Sthurlow 	int ret = DDI_SUCCESS;
2564bff34e3Sthurlow 
2574bff34e3Sthurlow 	switch (cmd) {
2584bff34e3Sthurlow 	case DDI_INFO_DEVT2DEVINFO:
2595ab8bad6SGordon Ross 		*result = nsmb_dip;
2604bff34e3Sthurlow 		break;
2614bff34e3Sthurlow 	case DDI_INFO_DEVT2INSTANCE:
2625ab8bad6SGordon Ross 		*result = NULL;
2634bff34e3Sthurlow 		break;
2644bff34e3Sthurlow 	default:
2654bff34e3Sthurlow 		ret = DDI_FAILURE;
2664bff34e3Sthurlow 	}
2674bff34e3Sthurlow 	return (ret);
2684bff34e3Sthurlow }
2694bff34e3Sthurlow 
2704bff34e3Sthurlow static int
2714bff34e3Sthurlow nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2724bff34e3Sthurlow {
2734bff34e3Sthurlow 
2744bff34e3Sthurlow 	if (cmd != DDI_ATTACH)
2754bff34e3Sthurlow 		return (DDI_FAILURE);
2765ab8bad6SGordon Ross 
2774bff34e3Sthurlow 	/*
2785ab8bad6SGordon Ross 	 * We only support only one "instance".  Note that
2795ab8bad6SGordon Ross 	 * "instances" are different from minor units.
2805ab8bad6SGordon Ross 	 * We get one (unique) minor unit per open.
2814bff34e3Sthurlow 	 */
2824bff34e3Sthurlow 	if (ddi_get_instance(dip) > 0)
2834bff34e3Sthurlow 		return (DDI_FAILURE);
2844bff34e3Sthurlow 
2854bff34e3Sthurlow 	if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
2864bff34e3Sthurlow 	    NULL) == DDI_FAILURE) {
2874bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: create minor");
2885ab8bad6SGordon Ross 		return (DDI_FAILURE);
2894bff34e3Sthurlow 	}
2904bff34e3Sthurlow 
2915ab8bad6SGordon Ross 	/*
2925ab8bad6SGordon Ross 	 * We need the major number a couple places,
2935ab8bad6SGordon Ross 	 * i.e. in smb_dev2share()
2945ab8bad6SGordon Ross 	 */
2955ab8bad6SGordon Ross 	nsmb_major = ddi_name_to_major(NSMB_NAME);
2965ab8bad6SGordon Ross 
2975ab8bad6SGordon Ross 	nsmb_dip = dip;
2984bff34e3Sthurlow 	ddi_report_dev(dip);
2994bff34e3Sthurlow 	return (DDI_SUCCESS);
3004bff34e3Sthurlow }
3014bff34e3Sthurlow 
3024bff34e3Sthurlow /*ARGSUSED*/
3034bff34e3Sthurlow static int
3044bff34e3Sthurlow nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3054bff34e3Sthurlow {
3064bff34e3Sthurlow 
3074bff34e3Sthurlow 	if (cmd != DDI_DETACH)
3084bff34e3Sthurlow 		return (DDI_FAILURE);
3094bff34e3Sthurlow 	if (ddi_get_instance(dip) > 0)
3104bff34e3Sthurlow 		return (DDI_FAILURE);
3114bff34e3Sthurlow 
3125ab8bad6SGordon Ross 	nsmb_dip = NULL;
3134bff34e3Sthurlow 	ddi_remove_minor_node(dip, NULL);
3144bff34e3Sthurlow 
3154bff34e3Sthurlow 	return (DDI_SUCCESS);
3164bff34e3Sthurlow }
3174bff34e3Sthurlow 
3184bff34e3Sthurlow /*ARGSUSED*/
3194bff34e3Sthurlow static int
320613a2f6bSGordon Ross nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags,	/* model.h */
321*216041c4SGordon Ross     cred_t *cr, int *rvalp)
3224bff34e3Sthurlow {
3234bff34e3Sthurlow 	smb_dev_t *sdp;
324613a2f6bSGordon Ross 	int err;
3254bff34e3Sthurlow 
3264bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, getminor(dev));
3274bff34e3Sthurlow 	if (sdp == NULL) {
3284bff34e3Sthurlow 		return (DDI_FAILURE);
3294bff34e3Sthurlow 	}
3304bff34e3Sthurlow 	if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
3314bff34e3Sthurlow 		return (EBADF);
3324bff34e3Sthurlow 	}
3334bff34e3Sthurlow 
3344bff34e3Sthurlow 	/*
3354bff34e3Sthurlow 	 * Dont give access if the zone id is not as the same as we
3364bff34e3Sthurlow 	 * set in the nsmb_open or dont belong to the global zone.
3374bff34e3Sthurlow 	 * Check if the user belongs to this zone..
3384bff34e3Sthurlow 	 */
3394bff34e3Sthurlow 	if (sdp->zoneid != getzoneid())
3404bff34e3Sthurlow 		return (EIO);
3414bff34e3Sthurlow 
342613a2f6bSGordon Ross 	/*
343613a2f6bSGordon Ross 	 * We have a zone_shutdown call back that kills all the VCs
344613a2f6bSGordon Ross 	 * in a zone that's shutting down.  That action will cause
345613a2f6bSGordon Ross 	 * all of these ioctls to fail on such VCs, so no need to
346613a2f6bSGordon Ross 	 * check the zone status here on every ioctl call.
347613a2f6bSGordon Ross 	 */
3484bff34e3Sthurlow 
349*216041c4SGordon Ross 	/*
350*216041c4SGordon Ross 	 * Serialize ioctl calls.  The smb_usr_... functions
351*216041c4SGordon Ross 	 * don't expect concurrent calls on a given sdp.
352*216041c4SGordon Ross 	 */
353*216041c4SGordon Ross 	mutex_enter(&sdp->sd_lock);
354*216041c4SGordon Ross 	if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
355*216041c4SGordon Ross 		mutex_exit(&sdp->sd_lock);
356*216041c4SGordon Ross 		return (EBUSY);
357*216041c4SGordon Ross 	}
358*216041c4SGordon Ross 	sdp->sd_flags |= NSMBFL_IOCTL;
359*216041c4SGordon Ross 	mutex_exit(&sdp->sd_lock);
360*216041c4SGordon Ross 
361613a2f6bSGordon Ross 	err = 0;
3624bff34e3Sthurlow 	switch (cmd) {
363613a2f6bSGordon Ross 	case SMBIOC_GETVERS:
36402d09e03SGordon Ross 		(void) ddi_copyout(&nsmb_version, (void *)arg,
365613a2f6bSGordon Ross 		    sizeof (nsmb_version), flags);
366613a2f6bSGordon Ross 		break;
3674bff34e3Sthurlow 
368613a2f6bSGordon Ross 	case SMBIOC_FLAGS2:
369613a2f6bSGordon Ross 		err = smb_usr_get_flags2(sdp, arg, flags);
370613a2f6bSGordon Ross 		break;
3714bff34e3Sthurlow 
372613a2f6bSGordon Ross 	case SMBIOC_GETSSNKEY:
373613a2f6bSGordon Ross 		err = smb_usr_get_ssnkey(sdp, arg, flags);
374613a2f6bSGordon Ross 		break;
3754bff34e3Sthurlow 
376430b4c46SGordon Ross 	case SMBIOC_DUP_DEV:
377430b4c46SGordon Ross 		err = smb_usr_dup_dev(sdp, arg, flags);
378430b4c46SGordon Ross 		break;
379430b4c46SGordon Ross 
380613a2f6bSGordon Ross 	case SMBIOC_REQUEST:
381613a2f6bSGordon Ross 		err = smb_usr_simplerq(sdp, arg, flags, cr);
382613a2f6bSGordon Ross 		break;
3834bff34e3Sthurlow 
384613a2f6bSGordon Ross 	case SMBIOC_T2RQ:
385613a2f6bSGordon Ross 		err = smb_usr_t2request(sdp, arg, flags, cr);
386613a2f6bSGordon Ross 		break;
3874bff34e3Sthurlow 
388613a2f6bSGordon Ross 	case SMBIOC_READ:
389613a2f6bSGordon Ross 	case SMBIOC_WRITE:
390613a2f6bSGordon Ross 		err = smb_usr_rw(sdp, cmd, arg, flags, cr);
391613a2f6bSGordon Ross 		break;
3924bff34e3Sthurlow 
393430b4c46SGordon Ross 	case SMBIOC_NTCREATE:
394430b4c46SGordon Ross 		err = smb_usr_ntcreate(sdp, arg, flags, cr);
395430b4c46SGordon Ross 		break;
396430b4c46SGordon Ross 
397430b4c46SGordon Ross 	case SMBIOC_PRINTJOB:
398430b4c46SGordon Ross 		err = smb_usr_printjob(sdp, arg, flags, cr);
399430b4c46SGordon Ross 		break;
400430b4c46SGordon Ross 
401430b4c46SGordon Ross 	case SMBIOC_CLOSEFH:
402430b4c46SGordon Ross 		err = smb_usr_closefh(sdp, cr);
403430b4c46SGordon Ross 		break;
404430b4c46SGordon Ross 
405613a2f6bSGordon Ross 	case SMBIOC_SSN_CREATE:
406613a2f6bSGordon Ross 	case SMBIOC_SSN_FIND:
407613a2f6bSGordon Ross 		err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
408613a2f6bSGordon Ross 		break;
4094bff34e3Sthurlow 
410613a2f6bSGordon Ross 	case SMBIOC_SSN_KILL:
411613a2f6bSGordon Ross 	case SMBIOC_SSN_RELE:
412613a2f6bSGordon Ross 		err = smb_usr_drop_ssn(sdp, cmd);
413613a2f6bSGordon Ross 		break;
4144bff34e3Sthurlow 
415613a2f6bSGordon Ross 	case SMBIOC_TREE_CONNECT:
416613a2f6bSGordon Ross 	case SMBIOC_TREE_FIND:
417613a2f6bSGordon Ross 		err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
418613a2f6bSGordon Ross 		break;
4194bff34e3Sthurlow 
420613a2f6bSGordon Ross 	case SMBIOC_TREE_KILL:
421613a2f6bSGordon Ross 	case SMBIOC_TREE_RELE:
422613a2f6bSGordon Ross 		err = smb_usr_drop_tree(sdp, cmd);
423613a2f6bSGordon Ross 		break;
4244bff34e3Sthurlow 
425613a2f6bSGordon Ross 	case SMBIOC_IOD_WORK:
426613a2f6bSGordon Ross 		err = smb_usr_iod_work(sdp, arg, flags, cr);
427613a2f6bSGordon Ross 		break;
4284bff34e3Sthurlow 
429613a2f6bSGordon Ross 	case SMBIOC_IOD_IDLE:
430613a2f6bSGordon Ross 	case SMBIOC_IOD_RCFAIL:
431613a2f6bSGordon Ross 		err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
432613a2f6bSGordon Ross 		break;
4334bff34e3Sthurlow 
434613a2f6bSGordon Ross 	case SMBIOC_PK_ADD:
435613a2f6bSGordon Ross 	case SMBIOC_PK_DEL:
436613a2f6bSGordon Ross 	case SMBIOC_PK_CHK:
437613a2f6bSGordon Ross 	case SMBIOC_PK_DEL_OWNER:
438613a2f6bSGordon Ross 	case SMBIOC_PK_DEL_EVERYONE:
439613a2f6bSGordon Ross 		err = smb_pkey_ioctl(cmd, arg, flags, cr);
440613a2f6bSGordon Ross 		break;
4414bff34e3Sthurlow 
442613a2f6bSGordon Ross 	default:
443613a2f6bSGordon Ross 		err = ENOTTY;
444613a2f6bSGordon Ross 		break;
4454bff34e3Sthurlow 	}
4464bff34e3Sthurlow 
447*216041c4SGordon Ross 	mutex_enter(&sdp->sd_lock);
448*216041c4SGordon Ross 	sdp->sd_flags &= ~NSMBFL_IOCTL;
449*216041c4SGordon Ross 	mutex_exit(&sdp->sd_lock);
450*216041c4SGordon Ross 
451613a2f6bSGordon Ross 	return (err);
4524bff34e3Sthurlow }
4534bff34e3Sthurlow 
4545ab8bad6SGordon Ross /*
4555ab8bad6SGordon Ross  * This does "clone" open, meaning it automatically
4565ab8bad6SGordon Ross  * assigns an available minor unit for each open.
4575ab8bad6SGordon Ross  */
4584bff34e3Sthurlow /*ARGSUSED*/
4594bff34e3Sthurlow static int
4604bff34e3Sthurlow nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
4614bff34e3Sthurlow {
4625ab8bad6SGordon Ross 	smb_dev_t *sdp;
4635ab8bad6SGordon Ross 	minor_t m;
4644bff34e3Sthurlow 
4654bff34e3Sthurlow 	mutex_enter(&dev_lck);
4665ab8bad6SGordon Ross 
4675ab8bad6SGordon Ross 	for (m = last_minor + 1; m != last_minor; m++) {
4685ab8bad6SGordon Ross 		if (m > NSMB_MAX_MINOR)
4695ab8bad6SGordon Ross 			m = NSMB_MIN_MINOR;
4705ab8bad6SGordon Ross 
4715ab8bad6SGordon Ross 		if (ddi_get_soft_state(statep, m) == NULL) {
4725ab8bad6SGordon Ross 			last_minor = m;
4735ab8bad6SGordon Ross 			goto found;
4744bff34e3Sthurlow 		}
4754bff34e3Sthurlow 	}
4764bff34e3Sthurlow 
4775ab8bad6SGordon Ross 	/* No available minor units. */
4785ab8bad6SGordon Ross 	mutex_exit(&dev_lck);
4795ab8bad6SGordon Ross 	return (ENXIO);
4804bff34e3Sthurlow 
4815ab8bad6SGordon Ross found:
4825ab8bad6SGordon Ross 	/* NB: dev_lck still held */
4835ab8bad6SGordon Ross 	if (ddi_soft_state_zalloc(statep, m) == DDI_FAILURE) {
4844bff34e3Sthurlow 		mutex_exit(&dev_lck);
4854bff34e3Sthurlow 		return (ENXIO);
4864bff34e3Sthurlow 	}
4875ab8bad6SGordon Ross 	if ((sdp = ddi_get_soft_state(statep, m)) == NULL) {
4884bff34e3Sthurlow 		mutex_exit(&dev_lck);
4894bff34e3Sthurlow 		return (ENXIO);
4904bff34e3Sthurlow 	}
4915ab8bad6SGordon Ross 	*dev = makedevice(nsmb_major, m);
4925ab8bad6SGordon Ross 	mutex_exit(&dev_lck);
4934bff34e3Sthurlow 
494430b4c46SGordon Ross 	sdp->sd_smbfid = -1;
4954bff34e3Sthurlow 	sdp->sd_flags |= NSMBFL_OPEN;
4964bff34e3Sthurlow 	sdp->zoneid = crgetzoneid(cr);
497*216041c4SGordon Ross 	mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL);
4984bff34e3Sthurlow 
4994bff34e3Sthurlow 	return (0);
5004bff34e3Sthurlow }
5014bff34e3Sthurlow 
5024bff34e3Sthurlow /*ARGSUSED*/
5034bff34e3Sthurlow static int
5044bff34e3Sthurlow nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
5054bff34e3Sthurlow {
5064bff34e3Sthurlow 	minor_t inst = getminor(dev);
5074bff34e3Sthurlow 	smb_dev_t *sdp;
508613a2f6bSGordon Ross 	int err;
5094bff34e3Sthurlow 
5104bff34e3Sthurlow 	/*
5114bff34e3Sthurlow 	 * 1. Check the validity of the minor number.
5124bff34e3Sthurlow 	 * 2. Release any shares/vc associated  with the connection.
5134bff34e3Sthurlow 	 * 3. Can close the minor number.
5144bff34e3Sthurlow 	 * 4. Deallocate any resources allocated in open() call.
5154bff34e3Sthurlow 	 */
5164bff34e3Sthurlow 
5174bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, inst);
518613a2f6bSGordon Ross 	if (sdp != NULL)
519613a2f6bSGordon Ross 		err = nsmb_close2(sdp, cr);
520613a2f6bSGordon Ross 	else
521613a2f6bSGordon Ross 		err = ENXIO;
5224bff34e3Sthurlow 
5234bff34e3Sthurlow 	/*
524613a2f6bSGordon Ross 	 * Free the instance
5254bff34e3Sthurlow 	 */
52639f633a0SBayard Bell 	mutex_enter(&dev_lck);
527613a2f6bSGordon Ross 	ddi_soft_state_free(statep, inst);
528613a2f6bSGordon Ross 	mutex_exit(&dev_lck);
529613a2f6bSGordon Ross 	return (err);
530613a2f6bSGordon Ross }
531613a2f6bSGordon Ross 
532613a2f6bSGordon Ross static int
533613a2f6bSGordon Ross nsmb_close2(smb_dev_t *sdp, cred_t *cr)
534613a2f6bSGordon Ross {
535613a2f6bSGordon Ross 	struct smb_vc *vcp;
536613a2f6bSGordon Ross 	struct smb_share *ssp;
537613a2f6bSGordon Ross 
538430b4c46SGordon Ross 	if (sdp->sd_smbfid != -1)
539430b4c46SGordon Ross 		(void) smb_usr_closefh(sdp, cr);
540430b4c46SGordon Ross 
5414bff34e3Sthurlow 	ssp = sdp->sd_share;
5424bff34e3Sthurlow 	if (ssp != NULL)
5434bff34e3Sthurlow 		smb_share_rele(ssp);
544430b4c46SGordon Ross 
5454bff34e3Sthurlow 	vcp = sdp->sd_vc;
5464bff34e3Sthurlow 	if (vcp != NULL) {
5474bff34e3Sthurlow 		/*
548613a2f6bSGordon Ross 		 * If this dev minor was opened by smbiod,
549613a2f6bSGordon Ross 		 * mark this VC as "dead" because it now
550613a2f6bSGordon Ross 		 * will have no IOD to service it.
5514bff34e3Sthurlow 		 */
552613a2f6bSGordon Ross 		if (sdp->sd_flags & NSMBFL_IOD)
5536723e17fSGordon Ross 			smb_iod_disconnect(vcp);
5544bff34e3Sthurlow 		smb_vc_rele(vcp);
5554bff34e3Sthurlow 	}
556*216041c4SGordon Ross 	mutex_destroy(&sdp->sd_lock);
5574bff34e3Sthurlow 
5584bff34e3Sthurlow 	return (0);
5594bff34e3Sthurlow }
5604bff34e3Sthurlow 
561430b4c46SGordon Ross /*
562430b4c46SGordon Ross  * Helper for SMBIOC_DUP_DEV
563430b4c46SGordon Ross  * Duplicate state from the FD @arg ("from") onto
564430b4c46SGordon Ross  * the FD for this device instance.
565430b4c46SGordon Ross  */
566430b4c46SGordon Ross int
567430b4c46SGordon Ross smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
568430b4c46SGordon Ross {
569430b4c46SGordon Ross 	file_t *fp = NULL;
570430b4c46SGordon Ross 	vnode_t *vp;
571430b4c46SGordon Ross 	smb_dev_t *from_sdp;
572430b4c46SGordon Ross 	dev_t dev;
573430b4c46SGordon Ross 	int32_t ufd;
574430b4c46SGordon Ross 	int err;
575430b4c46SGordon Ross 
576430b4c46SGordon Ross 	/* Should be no VC */
577430b4c46SGordon Ross 	if (sdp->sd_vc != NULL)
578430b4c46SGordon Ross 		return (EISCONN);
579430b4c46SGordon Ross 
580430b4c46SGordon Ross 	/*
581430b4c46SGordon Ross 	 * Get from_sdp (what we will duplicate)
582430b4c46SGordon Ross 	 */
583430b4c46SGordon Ross 	if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
584430b4c46SGordon Ross 		return (EFAULT);
585430b4c46SGordon Ross 	if ((fp = getf(ufd)) == NULL)
586430b4c46SGordon Ross 		return (EBADF);
587430b4c46SGordon Ross 	/* rele fp below */
588430b4c46SGordon Ross 	vp = fp->f_vnode;
589430b4c46SGordon Ross 	dev = vp->v_rdev;
590430b4c46SGordon Ross 	if (dev == 0 || dev == NODEV ||
591430b4c46SGordon Ross 	    getmajor(dev) != nsmb_major) {
592430b4c46SGordon Ross 		err = EINVAL;
593430b4c46SGordon Ross 		goto out;
594430b4c46SGordon Ross 	}
595430b4c46SGordon Ross 	from_sdp = ddi_get_soft_state(statep, getminor(dev));
596430b4c46SGordon Ross 	if (from_sdp == NULL) {
597430b4c46SGordon Ross 		err = EINVAL;
598430b4c46SGordon Ross 		goto out;
599430b4c46SGordon Ross 	}
600430b4c46SGordon Ross 
601430b4c46SGordon Ross 	/*
602430b4c46SGordon Ross 	 * Duplicate VC and share references onto this FD.
603430b4c46SGordon Ross 	 */
604430b4c46SGordon Ross 	if ((sdp->sd_vc = from_sdp->sd_vc) != NULL)
605430b4c46SGordon Ross 		smb_vc_hold(sdp->sd_vc);
606430b4c46SGordon Ross 	if ((sdp->sd_share = from_sdp->sd_share) != NULL)
607430b4c46SGordon Ross 		smb_share_hold(sdp->sd_share);
608430b4c46SGordon Ross 	sdp->sd_level = from_sdp->sd_level;
609430b4c46SGordon Ross 	err = 0;
610430b4c46SGordon Ross 
611430b4c46SGordon Ross out:
612430b4c46SGordon Ross 	if (fp)
613430b4c46SGordon Ross 		releasef(ufd);
614430b4c46SGordon Ross 	return (err);
615430b4c46SGordon Ross }
616430b4c46SGordon Ross 
617430b4c46SGordon Ross 
618430b4c46SGordon Ross /*
619430b4c46SGordon Ross  * Helper used by smbfs_mount
620430b4c46SGordon Ross  */
6214bff34e3Sthurlow int
6224bff34e3Sthurlow smb_dev2share(int fd, struct smb_share **sspp)
6234bff34e3Sthurlow {
624613a2f6bSGordon Ross 	file_t *fp = NULL;
625613a2f6bSGordon Ross 	vnode_t *vp;
6264bff34e3Sthurlow 	smb_dev_t *sdp;
627613a2f6bSGordon Ross 	smb_share_t *ssp;
6284bff34e3Sthurlow 	dev_t dev;
629613a2f6bSGordon Ross 	int err;
6304bff34e3Sthurlow 
6314bff34e3Sthurlow 	if ((fp = getf(fd)) == NULL)
632613a2f6bSGordon Ross 		return (EBADF);
633430b4c46SGordon Ross 	/* rele fp below */
634613a2f6bSGordon Ross 
6354bff34e3Sthurlow 	vp = fp->f_vnode;
6364bff34e3Sthurlow 	dev = vp->v_rdev;
637613a2f6bSGordon Ross 	if (dev == 0 || dev == NODEV ||
638613a2f6bSGordon Ross 	    getmajor(dev) != nsmb_major) {
639430b4c46SGordon Ross 		err = EINVAL;
640613a2f6bSGordon Ross 		goto out;
6414bff34e3Sthurlow 	}
642613a2f6bSGordon Ross 
6434bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, getminor(dev));
6444bff34e3Sthurlow 	if (sdp == NULL) {
645613a2f6bSGordon Ross 		err = EINVAL;
646613a2f6bSGordon Ross 		goto out;
6474bff34e3Sthurlow 	}
648613a2f6bSGordon Ross 
6494bff34e3Sthurlow 	ssp = sdp->sd_share;
6504bff34e3Sthurlow 	if (ssp == NULL) {
651613a2f6bSGordon Ross 		err = ENOTCONN;
652613a2f6bSGordon Ross 		goto out;
6534bff34e3Sthurlow 	}
654613a2f6bSGordon Ross 
6554bff34e3Sthurlow 	/*
656613a2f6bSGordon Ross 	 * Our caller gains a ref. to this share.
6574bff34e3Sthurlow 	 */
6584bff34e3Sthurlow 	*sspp = ssp;
659613a2f6bSGordon Ross 	smb_share_hold(ssp);
660613a2f6bSGordon Ross 	err = 0;
661613a2f6bSGordon Ross 
662613a2f6bSGordon Ross out:
663613a2f6bSGordon Ross 	if (fp)
664613a2f6bSGordon Ross 		releasef(fd);
665613a2f6bSGordon Ross 	return (err);
6664bff34e3Sthurlow }
667