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  * $Id: smb_dev.c,v 1.21 2004/12/13 00:25:18 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
354bff34e3Sthurlow /*
36*613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
374bff34e3Sthurlow  * Use is subject to license terms.
384bff34e3Sthurlow  */
394bff34e3Sthurlow 
404bff34e3Sthurlow #include <sys/types.h>
414bff34e3Sthurlow #include <sys/param.h>
424bff34e3Sthurlow #include <sys/errno.h>
434bff34e3Sthurlow #include <sys/sysmacros.h>
444bff34e3Sthurlow #include <sys/uio.h>
454bff34e3Sthurlow #include <sys/buf.h>
464bff34e3Sthurlow #include <sys/modctl.h>
474bff34e3Sthurlow #include <sys/open.h>
484bff34e3Sthurlow #include <sys/file.h>
494bff34e3Sthurlow #include <sys/kmem.h>
504bff34e3Sthurlow #include <sys/conf.h>
514bff34e3Sthurlow #include <sys/cmn_err.h>
524bff34e3Sthurlow #include <sys/stat.h>
534bff34e3Sthurlow #include <sys/ddi.h>
544bff34e3Sthurlow #include <sys/sunddi.h>
554bff34e3Sthurlow #include <sys/sunldi.h>
564bff34e3Sthurlow #include <sys/policy.h>
574bff34e3Sthurlow #include <sys/zone.h>
584bff34e3Sthurlow #include <sys/pathname.h>
594bff34e3Sthurlow #include <sys/mount.h>
604bff34e3Sthurlow #include <sys/sdt.h>
614bff34e3Sthurlow #include <fs/fs_subr.h>
624bff34e3Sthurlow #include <sys/modctl.h>
634bff34e3Sthurlow #include <sys/devops.h>
644bff34e3Sthurlow #include <sys/thread.h>
654bff34e3Sthurlow #include <sys/mkdev.h>
664bff34e3Sthurlow #include <sys/types.h>
674bff34e3Sthurlow #include <sys/zone.h>
684bff34e3Sthurlow 
694bff34e3Sthurlow #ifdef APPLE
704bff34e3Sthurlow #include <sys/smb_apple.h>
714bff34e3Sthurlow #else
724bff34e3Sthurlow #include <netsmb/smb_osdep.h>
734bff34e3Sthurlow #endif
744bff34e3Sthurlow 
754bff34e3Sthurlow #include <netsmb/mchain.h>		/* for "htoles()" */
764bff34e3Sthurlow 
774bff34e3Sthurlow #include <netsmb/smb.h>
784bff34e3Sthurlow #include <netsmb/smb_conn.h>
794bff34e3Sthurlow #include <netsmb/smb_subr.h>
804bff34e3Sthurlow #include <netsmb/smb_dev.h>
814bff34e3Sthurlow #include <netsmb/smb_pass.h>
824bff34e3Sthurlow 
834bff34e3Sthurlow /* for version checks */
844bff34e3Sthurlow const uint32_t nsmb_version = NSMB_VERSION;
854bff34e3Sthurlow 
864bff34e3Sthurlow /*
874bff34e3Sthurlow  * Userland code loops through minor #s 0 to 1023, looking for one which opens.
884bff34e3Sthurlow  * Intially we create minor 0 and leave it for anyone.  Minor zero will never
894bff34e3Sthurlow  * actually get used - opening triggers creation of another (but private) minor,
904bff34e3Sthurlow  * which userland code will get to and mark busy.
914bff34e3Sthurlow  */
924bff34e3Sthurlow #define	SMBMINORS 1024
934bff34e3Sthurlow static void *statep;
944bff34e3Sthurlow static major_t nsmb_major;
954bff34e3Sthurlow static minor_t nsmb_minor = 1;
964bff34e3Sthurlow 
974bff34e3Sthurlow #define	NSMB_MAX_MINOR  (1 << 8)
984bff34e3Sthurlow #define	NSMB_MIN_MINOR   (NSMB_MAX_MINOR + 1)
994bff34e3Sthurlow 
1004bff34e3Sthurlow #define	ILP32	1
1014bff34e3Sthurlow #define	LP64	2
1024bff34e3Sthurlow 
1034bff34e3Sthurlow static kmutex_t  dev_lck;
1044bff34e3Sthurlow 
1054bff34e3Sthurlow /* Zone support */
1064bff34e3Sthurlow zone_key_t nsmb_zone_key;
1074bff34e3Sthurlow extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
1084bff34e3Sthurlow extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
1094bff34e3Sthurlow 
1104bff34e3Sthurlow /*
1114bff34e3Sthurlow  * cb_ops device operations.
1124bff34e3Sthurlow  */
1134bff34e3Sthurlow static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
1144bff34e3Sthurlow static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
1154bff34e3Sthurlow static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1164bff34e3Sthurlow 				cred_t *credp, int *rvalp);
117*613a2f6bSGordon Ross static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
118*613a2f6bSGordon Ross 
1194bff34e3Sthurlow /* smbfs cb_ops */
1204bff34e3Sthurlow static struct cb_ops nsmb_cbops = {
1214bff34e3Sthurlow 	nsmb_open,	/* open */
1224bff34e3Sthurlow 	nsmb_close,	/* close */
1234bff34e3Sthurlow 	nodev,		/* strategy */
1244bff34e3Sthurlow 	nodev,		/* print */
1254bff34e3Sthurlow 	nodev,		/* dump */
1264bff34e3Sthurlow 	nodev,		/* read */
1274bff34e3Sthurlow 	nodev,		/* write */
1284bff34e3Sthurlow 	nsmb_ioctl,	/* ioctl */
1294bff34e3Sthurlow 	nodev,		/* devmap */
1304bff34e3Sthurlow 	nodev,		/* mmap */
1314bff34e3Sthurlow 	nodev,		/* segmap */
1324bff34e3Sthurlow 	nochpoll,	/* poll */
1334bff34e3Sthurlow 	ddi_prop_op,	/* prop_op */
1344bff34e3Sthurlow 	NULL,		/* stream */
1354bff34e3Sthurlow 	D_MP,		/* cb_flag */
1364bff34e3Sthurlow 	CB_REV,		/* rev */
1374bff34e3Sthurlow 	nodev,		/* int (*cb_aread)() */
1384bff34e3Sthurlow 	nodev		/* int (*cb_awrite)() */
1394bff34e3Sthurlow };
1404bff34e3Sthurlow 
1414bff34e3Sthurlow /*
1424bff34e3Sthurlow  * Device options
1434bff34e3Sthurlow  */
1444bff34e3Sthurlow static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1454bff34e3Sthurlow static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1464bff34e3Sthurlow static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
1474bff34e3Sthurlow 	void *arg, void **result);
1484bff34e3Sthurlow 
1494bff34e3Sthurlow static struct dev_ops nsmb_ops = {
1504bff34e3Sthurlow 	DEVO_REV,	/* devo_rev, */
1514bff34e3Sthurlow 	0,		/* refcnt  */
1524bff34e3Sthurlow 	nsmb_getinfo,	/* info */
1534bff34e3Sthurlow 	nulldev,	/* identify */
1544bff34e3Sthurlow 	nulldev,	/* probe */
1554bff34e3Sthurlow 	nsmb_attach,	/* attach */
1564bff34e3Sthurlow 	nsmb_detach,	/* detach */
1574bff34e3Sthurlow 	nodev,		/* reset */
1584bff34e3Sthurlow 	&nsmb_cbops,	/* driver ops - devctl interfaces */
1594bff34e3Sthurlow 	NULL,		/* bus operations */
16019397407SSherry Moore 	NULL,		/* power */
16119397407SSherry Moore 	ddi_quiesce_not_needed,	/* quiesce */
1624bff34e3Sthurlow };
1634bff34e3Sthurlow 
1644bff34e3Sthurlow /*
1654bff34e3Sthurlow  * Module linkage information.
1664bff34e3Sthurlow  */
1674bff34e3Sthurlow 
1684bff34e3Sthurlow static struct modldrv nsmb_modldrv = {
1694bff34e3Sthurlow 	&mod_driverops,				/* Driver module */
170*613a2f6bSGordon Ross 	"SMBFS network driver",
1714bff34e3Sthurlow 	&nsmb_ops				/* Driver ops */
1724bff34e3Sthurlow };
1734bff34e3Sthurlow 
1744bff34e3Sthurlow static struct modlinkage nsmb_modlinkage = {
1754bff34e3Sthurlow 	MODREV_1,
1764bff34e3Sthurlow 	(void *)&nsmb_modldrv,
1774bff34e3Sthurlow 	NULL
1784bff34e3Sthurlow };
1794bff34e3Sthurlow 
1804bff34e3Sthurlow int
1814bff34e3Sthurlow _init(void)
1824bff34e3Sthurlow {
1834bff34e3Sthurlow 	int error;
1844bff34e3Sthurlow 
1854bff34e3Sthurlow 	ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
1864bff34e3Sthurlow 
1874bff34e3Sthurlow 	/* Can initialize some mutexes also. */
1884bff34e3Sthurlow 	mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);
1894bff34e3Sthurlow 	/*
1904bff34e3Sthurlow 	 * Create a major name and number.
1914bff34e3Sthurlow 	 */
1924bff34e3Sthurlow 	nsmb_major = ddi_name_to_major(NSMB_NAME);
1934bff34e3Sthurlow 	nsmb_minor = 0;
1944bff34e3Sthurlow 
1954bff34e3Sthurlow 	/* Connection data structures. */
1964bff34e3Sthurlow 	(void) smb_sm_init();
1974bff34e3Sthurlow 
1984bff34e3Sthurlow 	/* Initialize password Key chain DB. */
1994bff34e3Sthurlow 	smb_pkey_init();
2004bff34e3Sthurlow 
2019c9af259SGordon Ross 	/* Initialize crypto mechanisms. */
2029c9af259SGordon Ross 	smb_crypto_mech_init();
2039c9af259SGordon Ross 
2044bff34e3Sthurlow 	zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
2054bff34e3Sthurlow 	    nsmb_zone_destroy);
2064bff34e3Sthurlow 
2074bff34e3Sthurlow 	/*
2084bff34e3Sthurlow 	 * Install the module.  Do this after other init,
2094bff34e3Sthurlow 	 * to prevent entrances before we're ready.
2104bff34e3Sthurlow 	 */
2114bff34e3Sthurlow 	if ((error = mod_install((&nsmb_modlinkage))) != 0) {
2124bff34e3Sthurlow 
2134bff34e3Sthurlow 		/* Same as 2nd half of _fini */
2144bff34e3Sthurlow 		(void) zone_key_delete(nsmb_zone_key);
2154bff34e3Sthurlow 		smb_pkey_fini();
2164bff34e3Sthurlow 		smb_sm_done();
2174bff34e3Sthurlow 		mutex_destroy(&dev_lck);
2184bff34e3Sthurlow 		ddi_soft_state_fini(&statep);
2194bff34e3Sthurlow 
2204bff34e3Sthurlow 		return (error);
2214bff34e3Sthurlow 	}
2224bff34e3Sthurlow 
2234bff34e3Sthurlow 	return (0);
2244bff34e3Sthurlow }
2254bff34e3Sthurlow 
2264bff34e3Sthurlow int
2274bff34e3Sthurlow _fini(void)
2284bff34e3Sthurlow {
2294bff34e3Sthurlow 	int status;
2304bff34e3Sthurlow 
2314bff34e3Sthurlow 	/*
2324bff34e3Sthurlow 	 * Prevent unload if we have active VCs
2334bff34e3Sthurlow 	 * or stored passwords
2344bff34e3Sthurlow 	 */
2354bff34e3Sthurlow 	if ((status = smb_sm_idle()) != 0)
2364bff34e3Sthurlow 		return (status);
2374bff34e3Sthurlow 	if ((status = smb_pkey_idle()) != 0)
2384bff34e3Sthurlow 		return (status);
2394bff34e3Sthurlow 
2404bff34e3Sthurlow 	/*
2414bff34e3Sthurlow 	 * Remove the module.  Do this before destroying things,
2424bff34e3Sthurlow 	 * to prevent new entrances while we're destorying.
2434bff34e3Sthurlow 	 */
2444bff34e3Sthurlow 	if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
2454bff34e3Sthurlow 		return (status);
2464bff34e3Sthurlow 	}
2474bff34e3Sthurlow 
2484bff34e3Sthurlow 	(void) zone_key_delete(nsmb_zone_key);
2494bff34e3Sthurlow 
2504bff34e3Sthurlow 	/* Destroy password Key chain DB. */
2514bff34e3Sthurlow 	smb_pkey_fini();
2524bff34e3Sthurlow 
2534bff34e3Sthurlow 	smb_sm_done();
2544bff34e3Sthurlow 
2554bff34e3Sthurlow 	mutex_destroy(&dev_lck);
2564bff34e3Sthurlow 	ddi_soft_state_fini(&statep);
2574bff34e3Sthurlow 
2584bff34e3Sthurlow 	return (status);
2594bff34e3Sthurlow }
2604bff34e3Sthurlow 
2614bff34e3Sthurlow int
2624bff34e3Sthurlow _info(struct modinfo *modinfop)
2634bff34e3Sthurlow {
2644bff34e3Sthurlow 	return (mod_info(&nsmb_modlinkage, modinfop));
2654bff34e3Sthurlow }
2664bff34e3Sthurlow 
2674bff34e3Sthurlow /*ARGSUSED*/
2684bff34e3Sthurlow static int
2694bff34e3Sthurlow nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2704bff34e3Sthurlow {
2714bff34e3Sthurlow 	int ret = DDI_SUCCESS;
2724bff34e3Sthurlow 
2734bff34e3Sthurlow 	switch (cmd) {
2744bff34e3Sthurlow 	case DDI_INFO_DEVT2DEVINFO:
2754bff34e3Sthurlow 		*result = 0;
2764bff34e3Sthurlow 		break;
2774bff34e3Sthurlow 	case DDI_INFO_DEVT2INSTANCE:
2784bff34e3Sthurlow 		*result = 0;
2794bff34e3Sthurlow 		break;
2804bff34e3Sthurlow 	default:
2814bff34e3Sthurlow 		ret = DDI_FAILURE;
2824bff34e3Sthurlow 	}
2834bff34e3Sthurlow 	return (ret);
2844bff34e3Sthurlow }
2854bff34e3Sthurlow 
2864bff34e3Sthurlow static int
2874bff34e3Sthurlow nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2884bff34e3Sthurlow {
2894bff34e3Sthurlow 	smb_dev_t *sdp;
2904bff34e3Sthurlow 
2914bff34e3Sthurlow 	if (cmd != DDI_ATTACH)
2924bff34e3Sthurlow 		return (DDI_FAILURE);
2934bff34e3Sthurlow 	/*
2944bff34e3Sthurlow 	 * only one instance - but we clone using the open routine
2954bff34e3Sthurlow 	 */
2964bff34e3Sthurlow 	if (ddi_get_instance(dip) > 0)
2974bff34e3Sthurlow 		return (DDI_FAILURE);
2984bff34e3Sthurlow 
2994bff34e3Sthurlow 	mutex_enter(&dev_lck);
3004bff34e3Sthurlow 
3014bff34e3Sthurlow 	/*
3024bff34e3Sthurlow 	 * This is the Zero'th minor device which is created.
3034bff34e3Sthurlow 	 */
3044bff34e3Sthurlow 	if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) {
3054bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: soft state alloc");
3064bff34e3Sthurlow 		goto attach_failed;
3074bff34e3Sthurlow 	}
3084bff34e3Sthurlow 	if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
3094bff34e3Sthurlow 	    NULL) == DDI_FAILURE) {
3104bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: create minor");
3114bff34e3Sthurlow 		goto attach_failed;
3124bff34e3Sthurlow 	}
3134bff34e3Sthurlow 	if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) {
3144bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: get soft state");
3154bff34e3Sthurlow 		ddi_remove_minor_node(dip, NULL);
3164bff34e3Sthurlow 		goto attach_failed;
3174bff34e3Sthurlow 	}
3184bff34e3Sthurlow 
3194bff34e3Sthurlow 	/*
3204bff34e3Sthurlow 	 * Need to see if this field is required.
3214bff34e3Sthurlow 	 * REVISIT
3224bff34e3Sthurlow 	 */
3234bff34e3Sthurlow 	sdp->smb_dip = dip;
3244bff34e3Sthurlow 	sdp->sd_seq = 0;
3254bff34e3Sthurlow 	sdp->sd_opened = 1;
3264bff34e3Sthurlow 
3274bff34e3Sthurlow 	mutex_exit(&dev_lck);
3284bff34e3Sthurlow 	ddi_report_dev(dip);
3294bff34e3Sthurlow 	return (DDI_SUCCESS);
3304bff34e3Sthurlow 
3314bff34e3Sthurlow attach_failed:
3324bff34e3Sthurlow 	ddi_soft_state_free(statep, 0);
3334bff34e3Sthurlow 	mutex_exit(&dev_lck);
3344bff34e3Sthurlow 	return (DDI_FAILURE);
3354bff34e3Sthurlow }
3364bff34e3Sthurlow 
3374bff34e3Sthurlow /*ARGSUSED*/
3384bff34e3Sthurlow static int
3394bff34e3Sthurlow nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3404bff34e3Sthurlow {
3414bff34e3Sthurlow 
3424bff34e3Sthurlow 	if (cmd != DDI_DETACH)
3434bff34e3Sthurlow 		return (DDI_FAILURE);
3444bff34e3Sthurlow 	if (ddi_get_instance(dip) > 0)
3454bff34e3Sthurlow 		return (DDI_FAILURE);
3464bff34e3Sthurlow 
3474bff34e3Sthurlow 	ddi_soft_state_free(statep, 0);
3484bff34e3Sthurlow 	ddi_remove_minor_node(dip, NULL);
3494bff34e3Sthurlow 
3504bff34e3Sthurlow 	return (DDI_SUCCESS);
3514bff34e3Sthurlow }
3524bff34e3Sthurlow 
3534bff34e3Sthurlow /*ARGSUSED*/
3544bff34e3Sthurlow static int
355*613a2f6bSGordon Ross nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags,	/* model.h */
356*613a2f6bSGordon Ross 	cred_t *cr, int *rvalp)
3574bff34e3Sthurlow {
3584bff34e3Sthurlow 	smb_dev_t *sdp;
359*613a2f6bSGordon Ross 	int err;
3604bff34e3Sthurlow 
3614bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, getminor(dev));
3624bff34e3Sthurlow 	if (sdp == NULL) {
3634bff34e3Sthurlow 		return (DDI_FAILURE);
3644bff34e3Sthurlow 	}
3654bff34e3Sthurlow 	if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
3664bff34e3Sthurlow 		return (EBADF);
3674bff34e3Sthurlow 	}
3684bff34e3Sthurlow 
3694bff34e3Sthurlow 	/*
3704bff34e3Sthurlow 	 * Dont give access if the zone id is not as the same as we
3714bff34e3Sthurlow 	 * set in the nsmb_open or dont belong to the global zone.
3724bff34e3Sthurlow 	 * Check if the user belongs to this zone..
3734bff34e3Sthurlow 	 */
3744bff34e3Sthurlow 	if (sdp->zoneid != getzoneid())
3754bff34e3Sthurlow 		return (EIO);
3764bff34e3Sthurlow 
377*613a2f6bSGordon Ross 	/*
378*613a2f6bSGordon Ross 	 * We have a zone_shutdown call back that kills all the VCs
379*613a2f6bSGordon Ross 	 * in a zone that's shutting down.  That action will cause
380*613a2f6bSGordon Ross 	 * all of these ioctls to fail on such VCs, so no need to
381*613a2f6bSGordon Ross 	 * check the zone status here on every ioctl call.
382*613a2f6bSGordon Ross 	 */
3834bff34e3Sthurlow 
384*613a2f6bSGordon Ross 	err = 0;
3854bff34e3Sthurlow 	switch (cmd) {
386*613a2f6bSGordon Ross 	case SMBIOC_GETVERS:
387*613a2f6bSGordon Ross 		ddi_copyout(&nsmb_version, (void *)arg,
388*613a2f6bSGordon Ross 		    sizeof (nsmb_version), flags);
389*613a2f6bSGordon Ross 		break;
3904bff34e3Sthurlow 
391*613a2f6bSGordon Ross 	case SMBIOC_FLAGS2:
392*613a2f6bSGordon Ross 		err = smb_usr_get_flags2(sdp, arg, flags);
393*613a2f6bSGordon Ross 		break;
3944bff34e3Sthurlow 
395*613a2f6bSGordon Ross 	case SMBIOC_GETSSNKEY:
396*613a2f6bSGordon Ross 		err = smb_usr_get_ssnkey(sdp, arg, flags);
397*613a2f6bSGordon Ross 		break;
3984bff34e3Sthurlow 
399*613a2f6bSGordon Ross 	case SMBIOC_REQUEST:
400*613a2f6bSGordon Ross 		err = smb_usr_simplerq(sdp, arg, flags, cr);
401*613a2f6bSGordon Ross 		break;
4024bff34e3Sthurlow 
403*613a2f6bSGordon Ross 	case SMBIOC_T2RQ:
404*613a2f6bSGordon Ross 		err = smb_usr_t2request(sdp, arg, flags, cr);
405*613a2f6bSGordon Ross 		break;
4064bff34e3Sthurlow 
407*613a2f6bSGordon Ross 	case SMBIOC_READ:
408*613a2f6bSGordon Ross 	case SMBIOC_WRITE:
409*613a2f6bSGordon Ross 		err = smb_usr_rw(sdp, cmd, arg, flags, cr);
410*613a2f6bSGordon Ross 		break;
4114bff34e3Sthurlow 
412*613a2f6bSGordon Ross 	case SMBIOC_SSN_CREATE:
413*613a2f6bSGordon Ross 	case SMBIOC_SSN_FIND:
414*613a2f6bSGordon Ross 		err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
415*613a2f6bSGordon Ross 		break;
4164bff34e3Sthurlow 
417*613a2f6bSGordon Ross 	case SMBIOC_SSN_KILL:
418*613a2f6bSGordon Ross 	case SMBIOC_SSN_RELE:
419*613a2f6bSGordon Ross 		err = smb_usr_drop_ssn(sdp, cmd);
420*613a2f6bSGordon Ross 		break;
4214bff34e3Sthurlow 
422*613a2f6bSGordon Ross 	case SMBIOC_TREE_CONNECT:
423*613a2f6bSGordon Ross 	case SMBIOC_TREE_FIND:
424*613a2f6bSGordon Ross 		err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
425*613a2f6bSGordon Ross 		break;
4264bff34e3Sthurlow 
427*613a2f6bSGordon Ross 	case SMBIOC_TREE_KILL:
428*613a2f6bSGordon Ross 	case SMBIOC_TREE_RELE:
429*613a2f6bSGordon Ross 		err = smb_usr_drop_tree(sdp, cmd);
430*613a2f6bSGordon Ross 		break;
4314bff34e3Sthurlow 
432*613a2f6bSGordon Ross 	case SMBIOC_IOD_WORK:
433*613a2f6bSGordon Ross 		err = smb_usr_iod_work(sdp, arg, flags, cr);
434*613a2f6bSGordon Ross 		break;
4354bff34e3Sthurlow 
436*613a2f6bSGordon Ross 	case SMBIOC_IOD_IDLE:
437*613a2f6bSGordon Ross 	case SMBIOC_IOD_RCFAIL:
438*613a2f6bSGordon Ross 		err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
439*613a2f6bSGordon Ross 		break;
4404bff34e3Sthurlow 
441*613a2f6bSGordon Ross 	case SMBIOC_PK_ADD:
442*613a2f6bSGordon Ross 	case SMBIOC_PK_DEL:
443*613a2f6bSGordon Ross 	case SMBIOC_PK_CHK:
444*613a2f6bSGordon Ross 	case SMBIOC_PK_DEL_OWNER:
445*613a2f6bSGordon Ross 	case SMBIOC_PK_DEL_EVERYONE:
446*613a2f6bSGordon Ross 		err = smb_pkey_ioctl(cmd, arg, flags, cr);
447*613a2f6bSGordon Ross 		break;
4484bff34e3Sthurlow 
449*613a2f6bSGordon Ross 	default:
450*613a2f6bSGordon Ross 		err = ENOTTY;
451*613a2f6bSGordon Ross 		break;
4524bff34e3Sthurlow 	}
4534bff34e3Sthurlow 
454*613a2f6bSGordon Ross 	return (err);
4554bff34e3Sthurlow }
4564bff34e3Sthurlow 
4574bff34e3Sthurlow /*ARGSUSED*/
4584bff34e3Sthurlow static int
4594bff34e3Sthurlow nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
4604bff34e3Sthurlow {
4614bff34e3Sthurlow 	major_t new_major;
4624bff34e3Sthurlow 	smb_dev_t *sdp, *sdv;
4634bff34e3Sthurlow 
4644bff34e3Sthurlow 	mutex_enter(&dev_lck);
4654bff34e3Sthurlow 	for (; ; ) {
4664bff34e3Sthurlow 		minor_t start = nsmb_minor;
4674bff34e3Sthurlow 		do {
4684bff34e3Sthurlow 			if (nsmb_minor >= MAXMIN32) {
4694bff34e3Sthurlow 				if (nsmb_major == getmajor(*dev))
4704bff34e3Sthurlow 					nsmb_minor = NSMB_MIN_MINOR;
4714bff34e3Sthurlow 				else
4724bff34e3Sthurlow 					nsmb_minor = 0;
4734bff34e3Sthurlow 			} else {
4744bff34e3Sthurlow 				nsmb_minor++;
4754bff34e3Sthurlow 			}
4764bff34e3Sthurlow 			sdv = ddi_get_soft_state(statep, nsmb_minor);
4774bff34e3Sthurlow 		} while ((sdv != NULL) && (nsmb_minor != start));
4784bff34e3Sthurlow 		if (nsmb_minor == start) {
4794bff34e3Sthurlow 			/*
4804bff34e3Sthurlow 			 * The condition we need to solve here is  all the
4814bff34e3Sthurlow 			 * MAXMIN32(~262000) minors numbers are reached. We
4824bff34e3Sthurlow 			 * need to create a new major number.
4834bff34e3Sthurlow 			 * zfs uses getudev() to create a new major number.
4844bff34e3Sthurlow 			 */
4854bff34e3Sthurlow 			if ((new_major = getudev()) == (major_t)-1) {
4864bff34e3Sthurlow 				cmn_err(CE_WARN,
4874bff34e3Sthurlow 				    "nsmb: Can't get unique major "
4884bff34e3Sthurlow 				    "device number.");
4894bff34e3Sthurlow 				mutex_exit(&dev_lck);
4904bff34e3Sthurlow 				return (-1);
4914bff34e3Sthurlow 			}
4924bff34e3Sthurlow 			nsmb_major = new_major;
4934bff34e3Sthurlow 			nsmb_minor = 0;
4944bff34e3Sthurlow 		} else {
4954bff34e3Sthurlow 			break;
4964bff34e3Sthurlow 		}
4974bff34e3Sthurlow 	}
4984bff34e3Sthurlow 
4994bff34e3Sthurlow 	/*
5004bff34e3Sthurlow 	 * This is called by mount or open call.
5014bff34e3Sthurlow 	 * The open() routine is passed a pointer to a device number so
5024bff34e3Sthurlow 	 * that  the  driver  can  change the minor number. This allows
5034bff34e3Sthurlow 	 * drivers to dynamically  create minor instances of  the  dev-
5044bff34e3Sthurlow 	 * ice.  An  example of this might be a  pseudo-terminal driver
5054bff34e3Sthurlow 	 * that creates a new pseudo-terminal whenever it   is  opened.
5064bff34e3Sthurlow 	 * A driver that chooses the minor number dynamically, normally
5074bff34e3Sthurlow 	 * creates only one  minor  device  node  in   attach(9E)  with
5084bff34e3Sthurlow 	 * ddi_create_minor_node(9F) then changes the minor number com-
5094bff34e3Sthurlow 	 * ponent of *devp using makedevice(9F)  and  getmajor(9F)  The
5104bff34e3Sthurlow 	 * driver needs to keep track of available minor numbers inter-
5114bff34e3Sthurlow 	 * nally.
5124bff34e3Sthurlow 	 * Stuff the structure smb_dev.
5134bff34e3Sthurlow 	 * return.
5144bff34e3Sthurlow 	 */
5154bff34e3Sthurlow 
5164bff34e3Sthurlow 	if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) {
5174bff34e3Sthurlow 		mutex_exit(&dev_lck);
5184bff34e3Sthurlow 		return (ENXIO);
5194bff34e3Sthurlow 	}
5204bff34e3Sthurlow 	if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) {
5214bff34e3Sthurlow 		mutex_exit(&dev_lck);
5224bff34e3Sthurlow 		return (ENXIO);
5234bff34e3Sthurlow 	}
5244bff34e3Sthurlow 
5254bff34e3Sthurlow 	sdp->sd_opened = 1;
5264bff34e3Sthurlow 	sdp->sd_seq = nsmb_minor;
5274bff34e3Sthurlow 	sdp->smb_cred = cr;
5284bff34e3Sthurlow 	sdp->sd_flags |= NSMBFL_OPEN;
5294bff34e3Sthurlow 	sdp->zoneid = crgetzoneid(cr);
5304bff34e3Sthurlow 	mutex_exit(&dev_lck);
5314bff34e3Sthurlow 
5324bff34e3Sthurlow 	*dev = makedevice(nsmb_major, nsmb_minor);
5334bff34e3Sthurlow 
5344bff34e3Sthurlow 	return (0);
5354bff34e3Sthurlow }
5364bff34e3Sthurlow 
5374bff34e3Sthurlow /*ARGSUSED*/
5384bff34e3Sthurlow static int
5394bff34e3Sthurlow nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
5404bff34e3Sthurlow {
5414bff34e3Sthurlow 	minor_t inst = getminor(dev);
5424bff34e3Sthurlow 	smb_dev_t *sdp;
543*613a2f6bSGordon Ross 	int err;
5444bff34e3Sthurlow 
5454bff34e3Sthurlow 	mutex_enter(&dev_lck);
5464bff34e3Sthurlow 	/*
5474bff34e3Sthurlow 	 * 1. Check the validity of the minor number.
5484bff34e3Sthurlow 	 * 2. Release any shares/vc associated  with the connection.
5494bff34e3Sthurlow 	 * 3. Can close the minor number.
5504bff34e3Sthurlow 	 * 4. Deallocate any resources allocated in open() call.
5514bff34e3Sthurlow 	 */
5524bff34e3Sthurlow 
5534bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, inst);
554*613a2f6bSGordon Ross 	if (sdp != NULL)
555*613a2f6bSGordon Ross 		err = nsmb_close2(sdp, cr);
556*613a2f6bSGordon Ross 	else
557*613a2f6bSGordon Ross 		err = ENXIO;
5584bff34e3Sthurlow 
5594bff34e3Sthurlow 	/*
560*613a2f6bSGordon Ross 	 * Free the instance
5614bff34e3Sthurlow 	 */
562*613a2f6bSGordon Ross 	ddi_soft_state_free(statep, inst);
563*613a2f6bSGordon Ross 	mutex_exit(&dev_lck);
564*613a2f6bSGordon Ross 	return (err);
565*613a2f6bSGordon Ross }
566*613a2f6bSGordon Ross 
567*613a2f6bSGordon Ross static int
568*613a2f6bSGordon Ross nsmb_close2(smb_dev_t *sdp, cred_t *cr)
569*613a2f6bSGordon Ross {
570*613a2f6bSGordon Ross 	struct smb_vc *vcp;
571*613a2f6bSGordon Ross 	struct smb_share *ssp;
572*613a2f6bSGordon Ross 	struct smb_cred scred;
573*613a2f6bSGordon Ross 
574*613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
5754bff34e3Sthurlow 	ssp = sdp->sd_share;
5764bff34e3Sthurlow 	if (ssp != NULL)
5774bff34e3Sthurlow 		smb_share_rele(ssp);
5784bff34e3Sthurlow 	vcp = sdp->sd_vc;
5794bff34e3Sthurlow 	if (vcp != NULL) {
5804bff34e3Sthurlow 		/*
581*613a2f6bSGordon Ross 		 * If this dev minor was opened by smbiod,
582*613a2f6bSGordon Ross 		 * mark this VC as "dead" because it now
583*613a2f6bSGordon Ross 		 * will have no IOD to service it.
5844bff34e3Sthurlow 		 */
585*613a2f6bSGordon Ross 		if (sdp->sd_flags & NSMBFL_IOD)
5866723e17fSGordon Ross 			smb_iod_disconnect(vcp);
5874bff34e3Sthurlow 		smb_vc_rele(vcp);
5884bff34e3Sthurlow 	}
5894bff34e3Sthurlow 
590*613a2f6bSGordon Ross 	smb_credrele(&scred);
5914bff34e3Sthurlow 	return (0);
5924bff34e3Sthurlow }
5934bff34e3Sthurlow 
5944bff34e3Sthurlow int
5954bff34e3Sthurlow smb_dev2share(int fd, struct smb_share **sspp)
5964bff34e3Sthurlow {
597*613a2f6bSGordon Ross 	file_t *fp = NULL;
598*613a2f6bSGordon Ross 	vnode_t *vp;
5994bff34e3Sthurlow 	smb_dev_t *sdp;
600*613a2f6bSGordon Ross 	smb_share_t *ssp;
6014bff34e3Sthurlow 	dev_t dev;
602*613a2f6bSGordon Ross 	int err;
6034bff34e3Sthurlow 
6044bff34e3Sthurlow 	if ((fp = getf(fd)) == NULL)
605*613a2f6bSGordon Ross 		return (EBADF);
606*613a2f6bSGordon Ross 
6074bff34e3Sthurlow 	vp = fp->f_vnode;
6084bff34e3Sthurlow 	dev = vp->v_rdev;
609*613a2f6bSGordon Ross 	if (dev == 0 || dev == NODEV ||
610*613a2f6bSGordon Ross 	    getmajor(dev) != nsmb_major) {
611*613a2f6bSGordon Ross 		err = EBADF;
612*613a2f6bSGordon Ross 		goto out;
6134bff34e3Sthurlow 	}
614*613a2f6bSGordon Ross 
6154bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, getminor(dev));
6164bff34e3Sthurlow 	if (sdp == NULL) {
617*613a2f6bSGordon Ross 		err = EINVAL;
618*613a2f6bSGordon Ross 		goto out;
6194bff34e3Sthurlow 	}
620*613a2f6bSGordon Ross 
6214bff34e3Sthurlow 	ssp = sdp->sd_share;
6224bff34e3Sthurlow 	if (ssp == NULL) {
623*613a2f6bSGordon Ross 		err = ENOTCONN;
624*613a2f6bSGordon Ross 		goto out;
6254bff34e3Sthurlow 	}
626*613a2f6bSGordon Ross 
6274bff34e3Sthurlow 	/*
628*613a2f6bSGordon Ross 	 * Our caller gains a ref. to this share.
6294bff34e3Sthurlow 	 */
6304bff34e3Sthurlow 	*sspp = ssp;
631*613a2f6bSGordon Ross 	smb_share_hold(ssp);
632*613a2f6bSGordon Ross 	err = 0;
633*613a2f6bSGordon Ross 
634*613a2f6bSGordon Ross out:
635*613a2f6bSGordon Ross 	if (fp)
636*613a2f6bSGordon Ross 		releasef(fd);
637*613a2f6bSGordon Ross 	return (err);
6384bff34e3Sthurlow }
639