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_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
334bff34e3Sthurlow  */
346723e17fSGordon Ross /*
35613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
366723e17fSGordon Ross  * Use is subject to license terms.
3740c0e231SGordon Ross  *
3840c0e231SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
396723e17fSGordon Ross  */
404bff34e3Sthurlow 
414bff34e3Sthurlow /*
424bff34e3Sthurlow  * Connection engine.
434bff34e3Sthurlow  */
444bff34e3Sthurlow 
454bff34e3Sthurlow #include <sys/param.h>
464bff34e3Sthurlow #include <sys/systm.h>
474bff34e3Sthurlow #include <sys/kmem.h>
484bff34e3Sthurlow #include <sys/proc.h>
494bff34e3Sthurlow #include <sys/lock.h>
504bff34e3Sthurlow #include <sys/vnode.h>
514bff34e3Sthurlow #include <sys/stream.h>
524bff34e3Sthurlow #include <sys/stropts.h>
534bff34e3Sthurlow #include <sys/socketvar.h>
544bff34e3Sthurlow #include <sys/cred.h>
554bff34e3Sthurlow #include <netinet/in.h>
564bff34e3Sthurlow #include <inet/ip.h>
574bff34e3Sthurlow #include <inet/ip6.h>
584bff34e3Sthurlow #include <sys/cmn_err.h>
594bff34e3Sthurlow #include <sys/thread.h>
604bff34e3Sthurlow #include <sys/atomic.h>
61613a2f6bSGordon Ross #include <sys/u8_textprep.h>
624bff34e3Sthurlow 
634bff34e3Sthurlow #include <netsmb/smb_osdep.h>
644bff34e3Sthurlow 
654bff34e3Sthurlow #include <netsmb/smb.h>
66*adee6784SGordon Ross #include <netsmb/smb2.h>
674bff34e3Sthurlow #include <netsmb/smb_conn.h>
684bff34e3Sthurlow #include <netsmb/smb_subr.h>
694bff34e3Sthurlow #include <netsmb/smb_tran.h>
704bff34e3Sthurlow #include <netsmb/smb_pass.h>
714bff34e3Sthurlow 
724bff34e3Sthurlow static struct smb_connobj smb_vclist;
734bff34e3Sthurlow 
744bff34e3Sthurlow void smb_co_init(struct smb_connobj *cp, int level, char *objname);
754bff34e3Sthurlow void smb_co_done(struct smb_connobj *cp);
764bff34e3Sthurlow void smb_co_hold(struct smb_connobj *cp);
774bff34e3Sthurlow void smb_co_rele(struct smb_connobj *cp);
784bff34e3Sthurlow void smb_co_kill(struct smb_connobj *cp);
794bff34e3Sthurlow 
804bff34e3Sthurlow static void smb_vc_free(struct smb_connobj *cp);
814bff34e3Sthurlow static void smb_vc_gone(struct smb_connobj *cp);
824bff34e3Sthurlow 
834bff34e3Sthurlow static void smb_share_free(struct smb_connobj *cp);
844bff34e3Sthurlow static void smb_share_gone(struct smb_connobj *cp);
854bff34e3Sthurlow 
86*adee6784SGordon Ross static void smb_fh_free(struct smb_connobj *cp);
87*adee6784SGordon Ross static void smb_fh_gone(struct smb_connobj *cp);
88*adee6784SGordon Ross 
894bff34e3Sthurlow int
smb_sm_init(void)904bff34e3Sthurlow smb_sm_init(void)
914bff34e3Sthurlow {
924bff34e3Sthurlow 	smb_co_init(&smb_vclist, SMBL_SM, "smbsm");
934bff34e3Sthurlow 	return (0);
944bff34e3Sthurlow }
954bff34e3Sthurlow 
964bff34e3Sthurlow int
smb_sm_idle(void)974bff34e3Sthurlow smb_sm_idle(void)
984bff34e3Sthurlow {
994bff34e3Sthurlow 	int error = 0;
1004bff34e3Sthurlow 	SMB_CO_LOCK(&smb_vclist);
1014bff34e3Sthurlow 	if (smb_vclist.co_usecount > 1) {
1024bff34e3Sthurlow 		SMBSDEBUG("%d connections still active\n",
1034bff34e3Sthurlow 		    smb_vclist.co_usecount - 1);
1044bff34e3Sthurlow 		error = EBUSY;
1054bff34e3Sthurlow 	}
1064bff34e3Sthurlow 	SMB_CO_UNLOCK(&smb_vclist);
1074bff34e3Sthurlow 	return (error);
1084bff34e3Sthurlow }
1094bff34e3Sthurlow 
1104bff34e3Sthurlow void
smb_sm_done(void)1114bff34e3Sthurlow smb_sm_done(void)
1124bff34e3Sthurlow {
1134bff34e3Sthurlow 	/*
11440c0e231SGordon Ross 	 * Why are we not iterating on smb_vclist here?
1154bff34e3Sthurlow 	 * Because the caller has just called smb_sm_idle() to
1164bff34e3Sthurlow 	 * make sure we have no VCs before calling this.
1174bff34e3Sthurlow 	 */
1184bff34e3Sthurlow 	smb_co_done(&smb_vclist);
1194bff34e3Sthurlow }
1204bff34e3Sthurlow 
1214bff34e3Sthurlow 
1224bff34e3Sthurlow 
1234bff34e3Sthurlow /*
1244bff34e3Sthurlow  * Common code for connection object
1254bff34e3Sthurlow  */
1264bff34e3Sthurlow /*ARGSUSED*/
1274bff34e3Sthurlow void
smb_co_init(struct smb_connobj * cp,int level,char * objname)1284bff34e3Sthurlow smb_co_init(struct smb_connobj *cp, int level, char *objname)
1294bff34e3Sthurlow {
1304bff34e3Sthurlow 
1314bff34e3Sthurlow 	mutex_init(&cp->co_lock, objname,  MUTEX_DRIVER, NULL);
1324bff34e3Sthurlow 
1334bff34e3Sthurlow 	cp->co_level = level;
1344bff34e3Sthurlow 	cp->co_usecount = 1;
1354bff34e3Sthurlow 	SLIST_INIT(&cp->co_children);
1364bff34e3Sthurlow }
1374bff34e3Sthurlow 
1384bff34e3Sthurlow /*
1394bff34e3Sthurlow  * Called just before free of an object
1404bff34e3Sthurlow  * of which smb_connobj is a part, i.e.
1414bff34e3Sthurlow  * _vc_free, _share_free, also sm_done.
1424bff34e3Sthurlow  */
1434bff34e3Sthurlow void
smb_co_done(struct smb_connobj * cp)1444bff34e3Sthurlow smb_co_done(struct smb_connobj *cp)
1454bff34e3Sthurlow {
1464bff34e3Sthurlow 	ASSERT(SLIST_EMPTY(&cp->co_children));
1474bff34e3Sthurlow 	mutex_destroy(&cp->co_lock);
1484bff34e3Sthurlow }
1494bff34e3Sthurlow 
1504bff34e3Sthurlow static void
smb_co_addchild(struct smb_connobj * parent,struct smb_connobj * child)1514bff34e3Sthurlow smb_co_addchild(
1524bff34e3Sthurlow 	struct smb_connobj *parent,
1534bff34e3Sthurlow 	struct smb_connobj *child)
1544bff34e3Sthurlow {
1554bff34e3Sthurlow 
1564bff34e3Sthurlow 	/*
1574bff34e3Sthurlow 	 * Set the child's pointer to the parent.
1584bff34e3Sthurlow 	 * No references yet, so no need to lock.
1594bff34e3Sthurlow 	 */
1604bff34e3Sthurlow 	ASSERT(child->co_usecount == 1);
1614bff34e3Sthurlow 	child->co_parent = parent;
1624bff34e3Sthurlow 
1634bff34e3Sthurlow 	/*
1644bff34e3Sthurlow 	 * Add the child to the parent's list of
1654bff34e3Sthurlow 	 * children, and in-line smb_co_hold
1664bff34e3Sthurlow 	 */
1674bff34e3Sthurlow 	ASSERT(MUTEX_HELD(&parent->co_lock));
1684bff34e3Sthurlow 	parent->co_usecount++;
1694bff34e3Sthurlow 	SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
1704bff34e3Sthurlow }
1714bff34e3Sthurlow 
1724bff34e3Sthurlow void
smb_co_hold(struct smb_connobj * cp)1734bff34e3Sthurlow smb_co_hold(struct smb_connobj *cp)
1744bff34e3Sthurlow {
1754bff34e3Sthurlow 	SMB_CO_LOCK(cp);
1764bff34e3Sthurlow 	cp->co_usecount++;
1774bff34e3Sthurlow 	SMB_CO_UNLOCK(cp);
1784bff34e3Sthurlow }
1794bff34e3Sthurlow 
1804bff34e3Sthurlow /*
1814bff34e3Sthurlow  * Called via smb_vc_rele, smb_share_rele
1824bff34e3Sthurlow  */
1834bff34e3Sthurlow void
smb_co_rele(struct smb_connobj * co)1844bff34e3Sthurlow smb_co_rele(struct smb_connobj *co)
1854bff34e3Sthurlow {
1864bff34e3Sthurlow 	struct smb_connobj *parent;
1874bff34e3Sthurlow 	int old_flags;
1884bff34e3Sthurlow 
1894bff34e3Sthurlow 	SMB_CO_LOCK(co);
190*adee6784SGordon Ross 
191*adee6784SGordon Ross 	/*
192*adee6784SGordon Ross 	 * When VC usecount goes from 2 to 1, signal the iod_idle CV.
193*adee6784SGordon Ross 	 * It's unfortunate to have object type-specific logic here,
194*adee6784SGordon Ross 	 * but it's hard to do this anywhere else.
195*adee6784SGordon Ross 	 */
196*adee6784SGordon Ross 	if (co->co_level == SMBL_VC && co->co_usecount == 2) {
197*adee6784SGordon Ross 		smb_vc_t *vcp = CPTOVC(co);
198*adee6784SGordon Ross 		cv_signal(&vcp->iod_idle);
199*adee6784SGordon Ross 	}
2004bff34e3Sthurlow 	if (co->co_usecount > 1) {
2014bff34e3Sthurlow 		co->co_usecount--;
2024bff34e3Sthurlow 		SMB_CO_UNLOCK(co);
2034bff34e3Sthurlow 		return;
2044bff34e3Sthurlow 	}
2054bff34e3Sthurlow 	ASSERT(co->co_usecount == 1);
2064bff34e3Sthurlow 	co->co_usecount = 0;
2074bff34e3Sthurlow 
2084bff34e3Sthurlow 	/*
2094bff34e3Sthurlow 	 * This list of children should be empty now.
2104bff34e3Sthurlow 	 * Check this while we're still linked, so
2114bff34e3Sthurlow 	 * we have a better chance of debugging.
2124bff34e3Sthurlow 	 */
2134bff34e3Sthurlow 	ASSERT(SLIST_EMPTY(&co->co_children));
2144bff34e3Sthurlow 
2154bff34e3Sthurlow 	/*
2164bff34e3Sthurlow 	 * OK, this element is going away.
2174bff34e3Sthurlow 	 *
2184bff34e3Sthurlow 	 * We need to drop the lock on this CO so we can take the
2194bff34e3Sthurlow 	 * parent CO lock. The _GONE flag prevents this CO from
2204bff34e3Sthurlow 	 * getting new references before we can unlink it from the
2214bff34e3Sthurlow 	 * parent list.
2224bff34e3Sthurlow 	 *
2234bff34e3Sthurlow 	 * The _GONE flag is also used to ensure that the co_gone
2244bff34e3Sthurlow 	 * function is called only once.  Note that smb_co_kill may
2254bff34e3Sthurlow 	 * do this before we get here.  If we find that the _GONE
2264bff34e3Sthurlow 	 * flag was not already set, then call the co_gone hook
2274bff34e3Sthurlow 	 * (smb_share_gone, smb_vc_gone) which will disconnect
2284bff34e3Sthurlow 	 * the share or the VC, respectively.
2294bff34e3Sthurlow 	 *
2304bff34e3Sthurlow 	 * Note the old: smb_co_gone(co, scred);
2314bff34e3Sthurlow 	 * is now in-line here.
2324bff34e3Sthurlow 	 */
2334bff34e3Sthurlow 	old_flags = co->co_flags;
2344bff34e3Sthurlow 	co->co_flags |= SMBO_GONE;
2354bff34e3Sthurlow 	SMB_CO_UNLOCK(co);
2364bff34e3Sthurlow 
2374bff34e3Sthurlow 	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
2384bff34e3Sthurlow 		co->co_gone(co);
2394bff34e3Sthurlow 
2404bff34e3Sthurlow 	/*
2414bff34e3Sthurlow 	 * If we have a parent (only smb_vclist does not)
2424bff34e3Sthurlow 	 * then unlink from parent's list of children.
2434bff34e3Sthurlow 	 * We have the only reference to the child.
2444bff34e3Sthurlow 	 */
2454bff34e3Sthurlow 	parent = co->co_parent;
2464bff34e3Sthurlow 	if (parent) {
2474bff34e3Sthurlow 		SMB_CO_LOCK(parent);
2484bff34e3Sthurlow 		ASSERT(SLIST_FIRST(&parent->co_children));
2494bff34e3Sthurlow 		if (SLIST_FIRST(&parent->co_children)) {
2504bff34e3Sthurlow 			SLIST_REMOVE(&parent->co_children, co,
2514bff34e3Sthurlow 			    smb_connobj, co_next);
2524bff34e3Sthurlow 		}
2534bff34e3Sthurlow 		SMB_CO_UNLOCK(parent);
2544bff34e3Sthurlow 	}
2554bff34e3Sthurlow 
2564bff34e3Sthurlow 	/*
2574bff34e3Sthurlow 	 * Now it's safe to free the CO
2584bff34e3Sthurlow 	 */
2594bff34e3Sthurlow 	if (co->co_free) {
2604bff34e3Sthurlow 		co->co_free(co);
2614bff34e3Sthurlow 	}
2624bff34e3Sthurlow 
2634bff34e3Sthurlow 	/*
2644bff34e3Sthurlow 	 * Finally, if the CO had a parent, decrement
2654bff34e3Sthurlow 	 * the parent's hold count for the lost child.
2664bff34e3Sthurlow 	 */
2674bff34e3Sthurlow 	if (parent) {
2684bff34e3Sthurlow 		/*
2694bff34e3Sthurlow 		 * Recursive call here (easier for debugging).
2704bff34e3Sthurlow 		 * Can only go two levels.
2714bff34e3Sthurlow 		 */
2724bff34e3Sthurlow 		smb_co_rele(parent);
2734bff34e3Sthurlow 	}
2744bff34e3Sthurlow }
2754bff34e3Sthurlow 
2764bff34e3Sthurlow /*
2774bff34e3Sthurlow  * Do just the first part of what co_gone does,
2784bff34e3Sthurlow  * i.e. tree disconnect, or disconnect a VC.
2794bff34e3Sthurlow  * This is used to forcibly close things.
2804bff34e3Sthurlow  */
2814bff34e3Sthurlow void
smb_co_kill(struct smb_connobj * co)2824bff34e3Sthurlow smb_co_kill(struct smb_connobj *co)
2834bff34e3Sthurlow {
2844bff34e3Sthurlow 	int old_flags;
2854bff34e3Sthurlow 
2864bff34e3Sthurlow 	SMB_CO_LOCK(co);
2874bff34e3Sthurlow 	old_flags = co->co_flags;
2884bff34e3Sthurlow 	co->co_flags |= SMBO_GONE;
2894bff34e3Sthurlow 	SMB_CO_UNLOCK(co);
2904bff34e3Sthurlow 
2914bff34e3Sthurlow 	/*
2924bff34e3Sthurlow 	 * Do the same "call only once" logic here as in
2934bff34e3Sthurlow 	 * smb_co_rele, though it's probably not possible
2944bff34e3Sthurlow 	 * for this to be called after smb_co_rele.
2954bff34e3Sthurlow 	 */
2964bff34e3Sthurlow 	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
2974bff34e3Sthurlow 		co->co_gone(co);
2984bff34e3Sthurlow 
2994bff34e3Sthurlow 	/* XXX: Walk list of children and kill those too? */
3004bff34e3Sthurlow }
3014bff34e3Sthurlow 
3024bff34e3Sthurlow 
3034bff34e3Sthurlow /*
304613a2f6bSGordon Ross  * Session objects, which are referred to as "VC" for
305613a2f6bSGordon Ross  * "virtual cirtuit". This has nothing to do with the
306613a2f6bSGordon Ross  * CIFS notion of a "virtual cirtuit".  See smb_conn.h
3074bff34e3Sthurlow  */
3084bff34e3Sthurlow 
309613a2f6bSGordon Ross void
smb_vc_hold(struct smb_vc * vcp)310613a2f6bSGordon Ross smb_vc_hold(struct smb_vc *vcp)
311613a2f6bSGordon Ross {
312613a2f6bSGordon Ross 	smb_co_hold(VCTOCP(vcp));
313613a2f6bSGordon Ross }
314613a2f6bSGordon Ross 
315613a2f6bSGordon Ross void
smb_vc_rele(struct smb_vc * vcp)316613a2f6bSGordon Ross smb_vc_rele(struct smb_vc *vcp)
317613a2f6bSGordon Ross {
318613a2f6bSGordon Ross 	smb_co_rele(VCTOCP(vcp));
319613a2f6bSGordon Ross }
320613a2f6bSGordon Ross 
321613a2f6bSGordon Ross void
smb_vc_kill(struct smb_vc * vcp)322613a2f6bSGordon Ross smb_vc_kill(struct smb_vc *vcp)
323613a2f6bSGordon Ross {
324613a2f6bSGordon Ross 	smb_co_kill(VCTOCP(vcp));
325613a2f6bSGordon Ross }
326613a2f6bSGordon Ross 
3274bff34e3Sthurlow /*
328613a2f6bSGordon Ross  * Normally called via smb_vc_rele()
329613a2f6bSGordon Ross  * after co_usecount drops to zero.
330613a2f6bSGordon Ross  * Also called via: smb_vc_kill()
331613a2f6bSGordon Ross  *
332613a2f6bSGordon Ross  * Shutdown the VC to this server,
333613a2f6bSGordon Ross  * invalidate shares linked with it.
3344bff34e3Sthurlow  */
335613a2f6bSGordon Ross /*ARGSUSED*/
336613a2f6bSGordon Ross static void
smb_vc_gone(struct smb_connobj * cp)337613a2f6bSGordon Ross smb_vc_gone(struct smb_connobj *cp)
3384bff34e3Sthurlow {
339613a2f6bSGordon Ross 	struct smb_vc *vcp = CPTOVC(cp);
3404bff34e3Sthurlow 
341613a2f6bSGordon Ross 	/*
342613a2f6bSGordon Ross 	 * Was smb_vc_disconnect(vcp);
343613a2f6bSGordon Ross 	 */
344613a2f6bSGordon Ross 	smb_iod_disconnect(vcp);
345613a2f6bSGordon Ross }
3464bff34e3Sthurlow 
347613a2f6bSGordon Ross /*
348613a2f6bSGordon Ross  * The VC has no more references.  Free it.
349613a2f6bSGordon Ross  * No locks needed here.
350613a2f6bSGordon Ross  */
351613a2f6bSGordon Ross static void
smb_vc_free(struct smb_connobj * cp)352613a2f6bSGordon Ross smb_vc_free(struct smb_connobj *cp)
353613a2f6bSGordon Ross {
354613a2f6bSGordon Ross 	struct smb_vc *vcp = CPTOVC(cp);
3554bff34e3Sthurlow 
356613a2f6bSGordon Ross 	/*
357613a2f6bSGordon Ross 	 * The _gone call should have emptied the request list,
358613a2f6bSGordon Ross 	 * but let's make sure, as requests may have references
359613a2f6bSGordon Ross 	 * to this VC without taking a hold.  (The hold is the
360613a2f6bSGordon Ross 	 * responsibility of threads placing requests.)
361613a2f6bSGordon Ross 	 */
362613a2f6bSGordon Ross 	ASSERT(vcp->iod_rqlist.tqh_first == NULL);
3634bff34e3Sthurlow 
364613a2f6bSGordon Ross 	if (vcp->vc_tdata)
365613a2f6bSGordon Ross 		SMB_TRAN_DONE(vcp);
3664bff34e3Sthurlow 
367613a2f6bSGordon Ross /*
368613a2f6bSGordon Ross  * We are not using the iconv routines here. So commenting them for now.
369613a2f6bSGordon Ross  * REVISIT.
370613a2f6bSGordon Ross  */
371613a2f6bSGordon Ross #ifdef NOTYETDEFINED
372613a2f6bSGordon Ross 	if (vcp->vc_tolower)
373613a2f6bSGordon Ross 		iconv_close(vcp->vc_tolower);
374613a2f6bSGordon Ross 	if (vcp->vc_toupper)
375613a2f6bSGordon Ross 		iconv_close(vcp->vc_toupper);
376613a2f6bSGordon Ross 	if (vcp->vc_tolocal)
377613a2f6bSGordon Ross 		iconv_close(vcp->vc_tolocal);
378613a2f6bSGordon Ross 	if (vcp->vc_toserver)
379613a2f6bSGordon Ross 		iconv_close(vcp->vc_toserver);
380613a2f6bSGordon Ross #endif
3814bff34e3Sthurlow 
382613a2f6bSGordon Ross 	if (vcp->vc_mackey != NULL)
383613a2f6bSGordon Ross 		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
38440c0e231SGordon Ross 	if (vcp->vc_ssnkey != NULL)
38540c0e231SGordon Ross 		kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
3864bff34e3Sthurlow 
387*adee6784SGordon Ross 	cv_destroy(&vcp->iod_muxwait);
388613a2f6bSGordon Ross 	cv_destroy(&vcp->iod_idle);
389613a2f6bSGordon Ross 	rw_destroy(&vcp->iod_rqlock);
390613a2f6bSGordon Ross 	cv_destroy(&vcp->vc_statechg);
391613a2f6bSGordon Ross 	smb_co_done(VCTOCP(vcp));
392613a2f6bSGordon Ross 	kmem_free(vcp, sizeof (*vcp));
3934bff34e3Sthurlow }
3944bff34e3Sthurlow 
3954bff34e3Sthurlow /*ARGSUSED*/
3964bff34e3Sthurlow int
smb_vc_create(smbioc_ossn_t * ossn,smb_cred_t * scred,smb_vc_t ** vcpp)397613a2f6bSGordon Ross smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
3984bff34e3Sthurlow {
3994bff34e3Sthurlow 	static char objtype[] = "smb_vc";
400613a2f6bSGordon Ross 	cred_t *cr = scred->scr_cred;
4014bff34e3Sthurlow 	struct smb_vc *vcp;
4024bff34e3Sthurlow 	int error = 0;
4034bff34e3Sthurlow 
4044bff34e3Sthurlow 	ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
4054bff34e3Sthurlow 
4064bff34e3Sthurlow 	vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
4074bff34e3Sthurlow 
4084bff34e3Sthurlow 	smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
4094bff34e3Sthurlow 	vcp->vc_co.co_free = smb_vc_free;
4104bff34e3Sthurlow 	vcp->vc_co.co_gone = smb_vc_gone;
4114bff34e3Sthurlow 
4124bff34e3Sthurlow 	cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
4134bff34e3Sthurlow 	rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
414613a2f6bSGordon Ross 	cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
415*adee6784SGordon Ross 	cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL);
416613a2f6bSGordon Ross 
417613a2f6bSGordon Ross 	/* Expanded TAILQ_HEAD_INITIALIZER */
418613a2f6bSGordon Ross 	vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
419613a2f6bSGordon Ross 
42040c0e231SGordon Ross 	/* A brand new VC should connect. */
42140c0e231SGordon Ross 	vcp->vc_state = SMBIOD_ST_RECONNECT;
4224bff34e3Sthurlow 
4234bff34e3Sthurlow 	/*
4244bff34e3Sthurlow 	 * These identify the connection.
4254bff34e3Sthurlow 	 */
4264bff34e3Sthurlow 	vcp->vc_zoneid = getzoneid();
427613a2f6bSGordon Ross 	bcopy(ossn, &vcp->vc_ssn, sizeof (*ossn));
4284bff34e3Sthurlow 
4294bff34e3Sthurlow 	/* This fills in vcp->vc_tdata */
430613a2f6bSGordon Ross 	vcp->vc_tdesc = &smb_tran_nbtcp_desc;
431613a2f6bSGordon Ross 	if ((error = SMB_TRAN_CREATE(vcp, cr)) != 0)
4324bff34e3Sthurlow 		goto errout;
4334bff34e3Sthurlow 
4344bff34e3Sthurlow 	/* Success! */
4354bff34e3Sthurlow 	smb_co_addchild(&smb_vclist, VCTOCP(vcp));
4364bff34e3Sthurlow 	*vcpp = vcp;
4374bff34e3Sthurlow 	return (0);
4384bff34e3Sthurlow 
4394bff34e3Sthurlow errout:
4404bff34e3Sthurlow 	/*
4414bff34e3Sthurlow 	 * This will destroy the new vc.
4424bff34e3Sthurlow 	 * See: smb_vc_free
4434bff34e3Sthurlow 	 */
4444bff34e3Sthurlow 	smb_vc_rele(vcp);
4454bff34e3Sthurlow 	return (error);
4464bff34e3Sthurlow }
4474bff34e3Sthurlow 
4484bff34e3Sthurlow /*
449613a2f6bSGordon Ross  * Find or create a VC identified by the info in ossn
450613a2f6bSGordon Ross  * and return it with a "hold", but not locked.
4514bff34e3Sthurlow  */
4524bff34e3Sthurlow /*ARGSUSED*/
453613a2f6bSGordon Ross int
smb_vc_findcreate(smbioc_ossn_t * ossn,smb_cred_t * scred,smb_vc_t ** vcpp)454613a2f6bSGordon Ross smb_vc_findcreate(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
4554bff34e3Sthurlow {
456613a2f6bSGordon Ross 	struct smb_connobj *co;
457613a2f6bSGordon Ross 	struct smb_vc *vcp;
458613a2f6bSGordon Ross 	smbioc_ssn_ident_t *vc_id;
459613a2f6bSGordon Ross 	int error;
460613a2f6bSGordon Ross 	zoneid_t zoneid = getzoneid();
4614bff34e3Sthurlow 
462613a2f6bSGordon Ross 	*vcpp = vcp = NULL;
4634bff34e3Sthurlow 
464613a2f6bSGordon Ross 	SMB_CO_LOCK(&smb_vclist);
4654bff34e3Sthurlow 
466613a2f6bSGordon Ross 	/* var, head, next_field */
467613a2f6bSGordon Ross 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
468613a2f6bSGordon Ross 		vcp = CPTOVC(co);
4694bff34e3Sthurlow 
470613a2f6bSGordon Ross 		/*
471613a2f6bSGordon Ross 		 * Some things we can check without
472613a2f6bSGordon Ross 		 * holding the lock (those that are
473613a2f6bSGordon Ross 		 * set at creation and never change).
474613a2f6bSGordon Ross 		 */
4754bff34e3Sthurlow 
476613a2f6bSGordon Ross 		/* VCs in other zones are invisibile. */
477613a2f6bSGordon Ross 		if (vcp->vc_zoneid != zoneid)
478613a2f6bSGordon Ross 			continue;
479613a2f6bSGordon Ross 
480613a2f6bSGordon Ross 		/* Also segregate by Unix owner. */
481613a2f6bSGordon Ross 		if (vcp->vc_owner != ossn->ssn_owner)
482613a2f6bSGordon Ross 			continue;
483613a2f6bSGordon Ross 
484613a2f6bSGordon Ross 		/*
485613a2f6bSGordon Ross 		 * Compare identifying info:
486613a2f6bSGordon Ross 		 * server address, user, domain
487613a2f6bSGordon Ross 		 * names are case-insensitive
488613a2f6bSGordon Ross 		 */
489613a2f6bSGordon Ross 		vc_id = &vcp->vc_ssn.ssn_id;
490613a2f6bSGordon Ross 		if (bcmp(&vc_id->id_srvaddr,
491613a2f6bSGordon Ross 		    &ossn->ssn_id.id_srvaddr,
492613a2f6bSGordon Ross 		    sizeof (vc_id->id_srvaddr)))
493613a2f6bSGordon Ross 			continue;
494613a2f6bSGordon Ross 		if (u8_strcmp(vc_id->id_user, ossn->ssn_id.id_user, 0,
495613a2f6bSGordon Ross 		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
496613a2f6bSGordon Ross 			continue;
497613a2f6bSGordon Ross 		if (u8_strcmp(vc_id->id_domain, ossn->ssn_id.id_domain, 0,
498613a2f6bSGordon Ross 		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
499613a2f6bSGordon Ross 			continue;
500613a2f6bSGordon Ross 
501613a2f6bSGordon Ross 		/*
502613a2f6bSGordon Ross 		 * We have a match, but still have to check
503613a2f6bSGordon Ross 		 * the _GONE flag, and do that with a lock.
504613a2f6bSGordon Ross 		 * No new references when _GONE is set.
505613a2f6bSGordon Ross 		 *
506613a2f6bSGordon Ross 		 * Also clear SMBVOPT_CREATE which the caller
507613a2f6bSGordon Ross 		 * may check to find out if we did create.
508613a2f6bSGordon Ross 		 */
509613a2f6bSGordon Ross 		SMB_VC_LOCK(vcp);
510613a2f6bSGordon Ross 		if ((vcp->vc_flags & SMBV_GONE) == 0) {
511613a2f6bSGordon Ross 			ossn->ssn_vopt &= ~SMBVOPT_CREATE;
512613a2f6bSGordon Ross 			/*
513613a2f6bSGordon Ross 			 * Return it held, unlocked.
514613a2f6bSGordon Ross 			 * In-line smb_vc_hold here.
515613a2f6bSGordon Ross 			 */
516613a2f6bSGordon Ross 			co->co_usecount++;
517613a2f6bSGordon Ross 			SMB_VC_UNLOCK(vcp);
518613a2f6bSGordon Ross 			*vcpp = vcp;
519613a2f6bSGordon Ross 			error = 0;
520613a2f6bSGordon Ross 			goto out;
521613a2f6bSGordon Ross 		}
522613a2f6bSGordon Ross 		SMB_VC_UNLOCK(vcp);
523613a2f6bSGordon Ross 		/* keep looking. */
5244bff34e3Sthurlow 	}
525613a2f6bSGordon Ross 	vcp = NULL;
5264bff34e3Sthurlow 
527613a2f6bSGordon Ross 	/* Note: smb_vclist is still locked. */
5284bff34e3Sthurlow 
529613a2f6bSGordon Ross 	if (ossn->ssn_vopt & SMBVOPT_CREATE) {
530613a2f6bSGordon Ross 		/*
531613a2f6bSGordon Ross 		 * Create a new VC.  It starts out with
532613a2f6bSGordon Ross 		 * hold count = 1, so don't incr. here.
533613a2f6bSGordon Ross 		 */
534613a2f6bSGordon Ross 		error = smb_vc_create(ossn, scred, &vcp);
535613a2f6bSGordon Ross 		if (error == 0)
536613a2f6bSGordon Ross 			*vcpp = vcp;
537613a2f6bSGordon Ross 	} else
538613a2f6bSGordon Ross 		error = ENOENT;
5399c9af259SGordon Ross 
540613a2f6bSGordon Ross out:
541613a2f6bSGordon Ross 	SMB_CO_UNLOCK(&smb_vclist);
542613a2f6bSGordon Ross 	return (error);
5434bff34e3Sthurlow }
5444bff34e3Sthurlow 
5454bff34e3Sthurlow 
5464bff34e3Sthurlow /*
547613a2f6bSGordon Ross  * Helper functions that operate on VCs
5484bff34e3Sthurlow  */
549613a2f6bSGordon Ross 
550613a2f6bSGordon Ross /*
551613a2f6bSGordon Ross  * Get a pointer to the IP address suitable for passing to Trusted
552613a2f6bSGordon Ross  * Extensions find_tpc() routine.  Used by smbfs_mount_label_policy().
553613a2f6bSGordon Ross  * Compare this code to nfs_mount_label_policy() if problems arise.
554613a2f6bSGordon Ross  */
555613a2f6bSGordon Ross void *
smb_vc_getipaddr(struct smb_vc * vcp,int * ipvers)556613a2f6bSGordon Ross smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers)
5574bff34e3Sthurlow {
558613a2f6bSGordon Ross 	smbioc_ssn_ident_t *id = &vcp->vc_ssn.ssn_id;
559613a2f6bSGordon Ross 	void *ret;
5604bff34e3Sthurlow 
561613a2f6bSGordon Ross 	switch (id->id_srvaddr.sa.sa_family) {
562613a2f6bSGordon Ross 	case AF_INET:
563613a2f6bSGordon Ross 		*ipvers = IPV4_VERSION;
564613a2f6bSGordon Ross 		ret = &id->id_srvaddr.sin.sin_addr;
565613a2f6bSGordon Ross 		break;
5664bff34e3Sthurlow 
567613a2f6bSGordon Ross 	case AF_INET6:
568613a2f6bSGordon Ross 		*ipvers = IPV6_VERSION;
569613a2f6bSGordon Ross 		ret = &id->id_srvaddr.sin6.sin6_addr;
570613a2f6bSGordon Ross 		break;
571613a2f6bSGordon Ross 	default:
572613a2f6bSGordon Ross 		SMBSDEBUG("invalid address family %d\n",
573613a2f6bSGordon Ross 		    id->id_srvaddr.sa.sa_family);
574613a2f6bSGordon Ross 		*ipvers = 0;
575613a2f6bSGordon Ross 		ret = NULL;
576613a2f6bSGordon Ross 		break;
577613a2f6bSGordon Ross 	}
578613a2f6bSGordon Ross 	return (ret);
579613a2f6bSGordon Ross }
5804bff34e3Sthurlow 
581613a2f6bSGordon Ross void
smb_vc_walkshares(struct smb_vc * vcp,walk_share_func_t func)582613a2f6bSGordon Ross smb_vc_walkshares(struct smb_vc *vcp,
583613a2f6bSGordon Ross 	walk_share_func_t func)
584613a2f6bSGordon Ross {
585613a2f6bSGordon Ross 	smb_connobj_t *co;
586613a2f6bSGordon Ross 	smb_share_t *ssp;
587613a2f6bSGordon Ross 
588613a2f6bSGordon Ross 	/*
589613a2f6bSGordon Ross 	 * Walk the share list calling func(ssp, arg)
590613a2f6bSGordon Ross 	 */
591613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
5924bff34e3Sthurlow 	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
5934bff34e3Sthurlow 		ssp = CPTOSS(co);
594613a2f6bSGordon Ross 		SMB_SS_LOCK(ssp);
595613a2f6bSGordon Ross 		func(ssp);
596613a2f6bSGordon Ross 		SMB_SS_UNLOCK(ssp);
5974bff34e3Sthurlow 	}
598613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
5994bff34e3Sthurlow }
6004bff34e3Sthurlow 
6014bff34e3Sthurlow 
602613a2f6bSGordon Ross /*
603613a2f6bSGordon Ross  * Share implementation
604613a2f6bSGordon Ross  */
6054bff34e3Sthurlow 
606613a2f6bSGordon Ross void
smb_share_hold(struct smb_share * ssp)607613a2f6bSGordon Ross smb_share_hold(struct smb_share *ssp)
6084bff34e3Sthurlow {
609613a2f6bSGordon Ross 	smb_co_hold(SSTOCP(ssp));
6104bff34e3Sthurlow }
6114bff34e3Sthurlow 
612613a2f6bSGordon Ross void
smb_share_rele(struct smb_share * ssp)613613a2f6bSGordon Ross smb_share_rele(struct smb_share *ssp)
6144bff34e3Sthurlow {
615613a2f6bSGordon Ross 	smb_co_rele(SSTOCP(ssp));
616613a2f6bSGordon Ross }
6174bff34e3Sthurlow 
618613a2f6bSGordon Ross void
smb_share_kill(struct smb_share * ssp)619613a2f6bSGordon Ross smb_share_kill(struct smb_share *ssp)
620613a2f6bSGordon Ross {
621613a2f6bSGordon Ross 	smb_co_kill(SSTOCP(ssp));
6224bff34e3Sthurlow }
6234bff34e3Sthurlow 
6244bff34e3Sthurlow /*
625613a2f6bSGordon Ross  * Normally called via smb_share_rele()
626613a2f6bSGordon Ross  * after co_usecount drops to zero.
627613a2f6bSGordon Ross  * Also called via: smb_share_kill()
6284bff34e3Sthurlow  */
629613a2f6bSGordon Ross static void
smb_share_gone(struct smb_connobj * cp)630613a2f6bSGordon Ross smb_share_gone(struct smb_connobj *cp)
6314bff34e3Sthurlow {
632613a2f6bSGordon Ross 	struct smb_cred scred;
633613a2f6bSGordon Ross 	struct smb_share *ssp = CPTOSS(cp);
634*adee6784SGordon Ross 	smb_vc_t *vcp = SSTOVC(ssp);
6354bff34e3Sthurlow 
636613a2f6bSGordon Ross 	smb_credinit(&scred, NULL);
637613a2f6bSGordon Ross 	smb_iod_shutdown_share(ssp);
638*adee6784SGordon Ross 	if (vcp->vc_flags & SMBV_SMB2)
639*adee6784SGordon Ross 		(void) smb2_smb_treedisconnect(ssp, &scred);
640*adee6784SGordon Ross 	else
641*adee6784SGordon Ross 		(void) smb_smb_treedisconnect(ssp, &scred);
642613a2f6bSGordon Ross 	smb_credrele(&scred);
6434bff34e3Sthurlow }
6444bff34e3Sthurlow 
6454bff34e3Sthurlow /*
646613a2f6bSGordon Ross  * Normally called via smb_share_rele()
647613a2f6bSGordon Ross  * after co_usecount drops to zero.
6484bff34e3Sthurlow  */
649613a2f6bSGordon Ross static void
smb_share_free(struct smb_connobj * cp)650613a2f6bSGordon Ross smb_share_free(struct smb_connobj *cp)
651613a2f6bSGordon Ross {
652613a2f6bSGordon Ross 	struct smb_share *ssp = CPTOSS(cp);
653613a2f6bSGordon Ross 
654613a2f6bSGordon Ross 	cv_destroy(&ssp->ss_conn_done);
655613a2f6bSGordon Ross 	smb_co_done(SSTOCP(ssp));
656613a2f6bSGordon Ross 	kmem_free(ssp, sizeof (*ssp));
657613a2f6bSGordon Ross }
658613a2f6bSGordon Ross 
6594bff34e3Sthurlow /*
6604bff34e3Sthurlow  * Allocate share structure and attach it to the given VC
6614bff34e3Sthurlow  * Connection expected to be locked on entry. Share will be returned
6624bff34e3Sthurlow  * in locked state.
6634bff34e3Sthurlow  */
6644bff34e3Sthurlow /*ARGSUSED*/
6654bff34e3Sthurlow int
smb_share_create(smbioc_tcon_t * tcon,struct smb_vc * vcp,struct smb_share ** sspp,struct smb_cred * scred)666613a2f6bSGordon Ross smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
667613a2f6bSGordon Ross 	struct smb_share **sspp, struct smb_cred *scred)
6684bff34e3Sthurlow {
6694bff34e3Sthurlow 	static char objtype[] = "smb_ss";
6704bff34e3Sthurlow 	struct smb_share *ssp;
6714bff34e3Sthurlow 
6724bff34e3Sthurlow 	ASSERT(MUTEX_HELD(&vcp->vc_lock));
6734bff34e3Sthurlow 
6744bff34e3Sthurlow 	ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
6754bff34e3Sthurlow 	smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
6764bff34e3Sthurlow 	ssp->ss_co.co_free = smb_share_free;
6774bff34e3Sthurlow 	ssp->ss_co.co_gone = smb_share_gone;
6784bff34e3Sthurlow 
679613a2f6bSGordon Ross 	cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
6804bff34e3Sthurlow 	ssp->ss_tid = SMB_TID_UNKNOWN;
681*adee6784SGordon Ross 	ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
682613a2f6bSGordon Ross 
683613a2f6bSGordon Ross 	bcopy(&tcon->tc_sh, &ssp->ss_ioc,
684613a2f6bSGordon Ross 	    sizeof (smbioc_oshare_t));
685613a2f6bSGordon Ross 
6864bff34e3Sthurlow 	smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
6874bff34e3Sthurlow 	*sspp = ssp;
6884bff34e3Sthurlow 
6894bff34e3Sthurlow 	return (0);
6904bff34e3Sthurlow }
6914bff34e3Sthurlow 
6924bff34e3Sthurlow /*
693613a2f6bSGordon Ross  * Find or create a share under the given VC
694613a2f6bSGordon Ross  * and return it with a "hold", but not locked.
6954bff34e3Sthurlow  */
696613a2f6bSGordon Ross 
697613a2f6bSGordon Ross int
smb_share_findcreate(smbioc_tcon_t * tcon,struct smb_vc * vcp,struct smb_share ** sspp,struct smb_cred * scred)698613a2f6bSGordon Ross smb_share_findcreate(smbioc_tcon_t *tcon, struct smb_vc *vcp,
699613a2f6bSGordon Ross 	struct smb_share **sspp, struct smb_cred *scred)
7004bff34e3Sthurlow {
701613a2f6bSGordon Ross 	struct smb_connobj *co;
702613a2f6bSGordon Ross 	struct smb_share *ssp = NULL;
703613a2f6bSGordon Ross 	int error = 0;
7044bff34e3Sthurlow 
705613a2f6bSGordon Ross 	*sspp = NULL;
7064bff34e3Sthurlow 
707613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
7084bff34e3Sthurlow 
709613a2f6bSGordon Ross 	/* var, head, next_field */
710613a2f6bSGordon Ross 	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
711613a2f6bSGordon Ross 		ssp = CPTOSS(co);
7124bff34e3Sthurlow 
713613a2f6bSGordon Ross 		/* Share name */
714613a2f6bSGordon Ross 		if (u8_strcmp(ssp->ss_name, tcon->tc_sh.sh_name, 0,
715613a2f6bSGordon Ross 		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
716613a2f6bSGordon Ross 			continue;
7174bff34e3Sthurlow 
718613a2f6bSGordon Ross 		/*
719613a2f6bSGordon Ross 		 * We have a match, but still have to check
720613a2f6bSGordon Ross 		 * the _GONE flag, and do that with a lock.
721613a2f6bSGordon Ross 		 * No new references when _GONE is set.
722613a2f6bSGordon Ross 		 *
723613a2f6bSGordon Ross 		 * Also clear SMBSOPT_CREATE which the caller
724613a2f6bSGordon Ross 		 * may check to find out if we did create.
725613a2f6bSGordon Ross 		 */
726613a2f6bSGordon Ross 		SMB_SS_LOCK(ssp);
727613a2f6bSGordon Ross 		if ((ssp->ss_flags & SMBS_GONE) == 0) {
728613a2f6bSGordon Ross 			tcon->tc_opt &= ~SMBSOPT_CREATE;
729613a2f6bSGordon Ross 			/*
730613a2f6bSGordon Ross 			 * Return it held, unlocked.
731613a2f6bSGordon Ross 			 * In-line smb_share_hold here.
732613a2f6bSGordon Ross 			 */
733613a2f6bSGordon Ross 			co->co_usecount++;
734613a2f6bSGordon Ross 			SMB_SS_UNLOCK(ssp);
735613a2f6bSGordon Ross 			*sspp = ssp;
736613a2f6bSGordon Ross 			error = 0;
737613a2f6bSGordon Ross 			goto out;
738613a2f6bSGordon Ross 		}
739613a2f6bSGordon Ross 		SMB_SS_UNLOCK(ssp);
740613a2f6bSGordon Ross 		/* keep looking. */
741613a2f6bSGordon Ross 	}
742613a2f6bSGordon Ross 	ssp = NULL;
7434bff34e3Sthurlow 
744613a2f6bSGordon Ross 	/* Note: vcp (list of shares) is still locked. */
7454bff34e3Sthurlow 
746613a2f6bSGordon Ross 	if (tcon->tc_opt & SMBSOPT_CREATE) {
747613a2f6bSGordon Ross 		/*
748613a2f6bSGordon Ross 		 * Create a new share.  It starts out with
749613a2f6bSGordon Ross 		 * hold count = 1, so don't incr. here.
750613a2f6bSGordon Ross 		 */
751613a2f6bSGordon Ross 		error = smb_share_create(tcon, vcp, &ssp, scred);
752613a2f6bSGordon Ross 		if (error == 0)
753613a2f6bSGordon Ross 			*sspp = ssp;
754613a2f6bSGordon Ross 	} else
755613a2f6bSGordon Ross 		error = ENOENT;
7564bff34e3Sthurlow 
757613a2f6bSGordon Ross out:
758613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
759613a2f6bSGordon Ross 	return (error);
7604bff34e3Sthurlow }
7614bff34e3Sthurlow 
762613a2f6bSGordon Ross 
7634bff34e3Sthurlow /*
764613a2f6bSGordon Ross  * Helper functions that operate on shares
7654bff34e3Sthurlow  */
766613a2f6bSGordon Ross 
767613a2f6bSGordon Ross /*
768613a2f6bSGordon Ross  * Mark this share as invalid, so consumers will know
769613a2f6bSGordon Ross  * their file handles have become invalid.
770613a2f6bSGordon Ross  *
771613a2f6bSGordon Ross  * Most share consumers store a copy of ss_vcgenid when
772613a2f6bSGordon Ross  * opening a file handle and compare that with what's in
773613a2f6bSGordon Ross  * the share before using a file handle.  If the genid
774613a2f6bSGordon Ross  * doesn't match, the file handle has become "stale"
775613a2f6bSGordon Ross  * due to disconnect.  Therefore, zap ss_vcgenid here.
776613a2f6bSGordon Ross  */
777613a2f6bSGordon Ross void
smb_share_invalidate(struct smb_share * ssp)778613a2f6bSGordon Ross smb_share_invalidate(struct smb_share *ssp)
7794bff34e3Sthurlow {
7804bff34e3Sthurlow 
7814bff34e3Sthurlow 	ASSERT(MUTEX_HELD(&ssp->ss_lock));
7824bff34e3Sthurlow 
783613a2f6bSGordon Ross 	ssp->ss_flags &= ~SMBS_CONNECTED;
784613a2f6bSGordon Ross 	ssp->ss_tid = SMB_TID_UNKNOWN;
785613a2f6bSGordon Ross 	ssp->ss_vcgenid = 0;
7864bff34e3Sthurlow }
7874bff34e3Sthurlow 
7884bff34e3Sthurlow /*
7894bff34e3Sthurlow  * Connect (or reconnect) a share object.
790613a2f6bSGordon Ross  *
791613a2f6bSGordon Ross  * Called by smb_usr_get_tree() for new connections,
792613a2f6bSGordon Ross  * and called by smb_rq_enqueue() for reconnect.
7934bff34e3Sthurlow  */
7944bff34e3Sthurlow int
smb_share_tcon(smb_share_t * ssp,smb_cred_t * scred)795613a2f6bSGordon Ross smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
7964bff34e3Sthurlow {
797*adee6784SGordon Ross 	smb_vc_t *vcp = SSTOVC(ssp);
7984bff34e3Sthurlow 	clock_t tmo;
7994bff34e3Sthurlow 	int error;
8004bff34e3Sthurlow 
801613a2f6bSGordon Ross 	SMB_SS_LOCK(ssp);
8024bff34e3Sthurlow 
8034bff34e3Sthurlow 	if (ssp->ss_flags & SMBS_CONNECTED) {
8044bff34e3Sthurlow 		SMBIODEBUG("alread connected?");
805613a2f6bSGordon Ross 		error = 0;
806613a2f6bSGordon Ross 		goto out;
8074bff34e3Sthurlow 	}
8084bff34e3Sthurlow 
8094bff34e3Sthurlow 	/*
8104bff34e3Sthurlow 	 * Wait for completion of any state changes
8114bff34e3Sthurlow 	 * that might be underway.
8124bff34e3Sthurlow 	 */
8134bff34e3Sthurlow 	while (ssp->ss_flags & SMBS_RECONNECTING) {
8144bff34e3Sthurlow 		ssp->ss_conn_waiters++;
8154bff34e3Sthurlow 		tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock);
8164bff34e3Sthurlow 		ssp->ss_conn_waiters--;
8174bff34e3Sthurlow 		if (tmo == 0) {
8184bff34e3Sthurlow 			/* Interrupt! */
819613a2f6bSGordon Ross 			error = EINTR;
820613a2f6bSGordon Ross 			goto out;
8214bff34e3Sthurlow 		}
8224bff34e3Sthurlow 	}
8234bff34e3Sthurlow 
8244bff34e3Sthurlow 	/* Did someone else do it for us? */
825613a2f6bSGordon Ross 	if (ssp->ss_flags & SMBS_CONNECTED) {
826613a2f6bSGordon Ross 		error = 0;
827613a2f6bSGordon Ross 		goto out;
828613a2f6bSGordon Ross 	}
8294bff34e3Sthurlow 
8304bff34e3Sthurlow 	/*
8314bff34e3Sthurlow 	 * OK, we'll do the work.
8324bff34e3Sthurlow 	 */
8334bff34e3Sthurlow 	ssp->ss_flags |= SMBS_RECONNECTING;
8344bff34e3Sthurlow 
835613a2f6bSGordon Ross 	/*
836613a2f6bSGordon Ross 	 * Drop the lock while doing the TCON.
837613a2f6bSGordon Ross 	 * On success, sets ss_tid, ss_vcgenid,
838613a2f6bSGordon Ross 	 * and ss_flags |= SMBS_CONNECTED;
839613a2f6bSGordon Ross 	 */
8404bff34e3Sthurlow 	SMB_SS_UNLOCK(ssp);
841*adee6784SGordon Ross 	if (vcp->vc_flags & SMBV_SMB2)
842*adee6784SGordon Ross 		error = smb2_smb_treeconnect(ssp, scred);
843*adee6784SGordon Ross 	else
844*adee6784SGordon Ross 		error = smb_smb_treeconnect(ssp, scred);
8454bff34e3Sthurlow 	SMB_SS_LOCK(ssp);
8464bff34e3Sthurlow 
8474bff34e3Sthurlow 	ssp->ss_flags &= ~SMBS_RECONNECTING;
8484bff34e3Sthurlow 
8494bff34e3Sthurlow 	/* They can all go ahead! */
8504bff34e3Sthurlow 	if (ssp->ss_conn_waiters)
8514bff34e3Sthurlow 		cv_broadcast(&ssp->ss_conn_done);
8524bff34e3Sthurlow 
853613a2f6bSGordon Ross out:
854613a2f6bSGordon Ross 	SMB_SS_UNLOCK(ssp);
8554bff34e3Sthurlow 
856613a2f6bSGordon Ross 	return (error);
8574bff34e3Sthurlow }
8584bff34e3Sthurlow 
859*adee6784SGordon Ross /*
860*adee6784SGordon Ross  * File handle level functions
861*adee6784SGordon Ross  */
862*adee6784SGordon Ross 
863*adee6784SGordon Ross void
smb_fh_hold(struct smb_fh * fhp)864*adee6784SGordon Ross smb_fh_hold(struct smb_fh *fhp)
865*adee6784SGordon Ross {
866*adee6784SGordon Ross 	smb_co_hold(FHTOCP(fhp));
867*adee6784SGordon Ross }
868*adee6784SGordon Ross 
869*adee6784SGordon Ross void
smb_fh_rele(struct smb_fh * fhp)870*adee6784SGordon Ross smb_fh_rele(struct smb_fh *fhp)
871*adee6784SGordon Ross {
872*adee6784SGordon Ross 	smb_co_rele(FHTOCP(fhp));
873*adee6784SGordon Ross }
874*adee6784SGordon Ross 
875*adee6784SGordon Ross void
smb_fh_close(struct smb_fh * fhp)876*adee6784SGordon Ross smb_fh_close(struct smb_fh *fhp)
877*adee6784SGordon Ross {
878*adee6784SGordon Ross 	smb_co_kill(FHTOCP(fhp));
879*adee6784SGordon Ross }
880*adee6784SGordon Ross 
881*adee6784SGordon Ross /*
882*adee6784SGordon Ross  * Normally called via smb_fh_rele()
883*adee6784SGordon Ross  * after co_usecount drops to zero.
884*adee6784SGordon Ross  * Also called via: smb_fh_kill()
885*adee6784SGordon Ross  */
886*adee6784SGordon Ross static void
smb_fh_gone(struct smb_connobj * cp)887*adee6784SGordon Ross smb_fh_gone(struct smb_connobj *cp)
888*adee6784SGordon Ross {
889*adee6784SGordon Ross 	struct smb_cred scred;
890*adee6784SGordon Ross 	struct smb_fh *fhp = CPTOFH(cp);
891*adee6784SGordon Ross 	smb_share_t *ssp = FHTOSS(fhp);
892*adee6784SGordon Ross 	int err;
893*adee6784SGordon Ross 
894*adee6784SGordon Ross 	if ((fhp->fh_flags & SMBFH_VALID) == 0)
895*adee6784SGordon Ross 		return;
896*adee6784SGordon Ross 
897*adee6784SGordon Ross 	/*
898*adee6784SGordon Ross 	 * We have no durable handles (yet) so if there has been a
899*adee6784SGordon Ross 	 * reconnect, don't bother to close this handle.
900*adee6784SGordon Ross 	 */
901*adee6784SGordon Ross 	if (fhp->fh_vcgenid != ssp->ss_vcgenid)
902*adee6784SGordon Ross 		return;
903*adee6784SGordon Ross 
904*adee6784SGordon Ross 	smb_credinit(&scred, NULL);
905*adee6784SGordon Ross 	err = smb_smb_close(ssp, fhp, &scred);
906*adee6784SGordon Ross 	smb_credrele(&scred);
907*adee6784SGordon Ross 	if (err) {
908*adee6784SGordon Ross 		SMBSDEBUG("close err=%d\n", err);
909*adee6784SGordon Ross 	}
910*adee6784SGordon Ross }
911*adee6784SGordon Ross 
912*adee6784SGordon Ross /*
913*adee6784SGordon Ross  * Normally called via smb_fh_rele()
914*adee6784SGordon Ross  * after co_usecount drops to zero.
915*adee6784SGordon Ross  */
916*adee6784SGordon Ross static void
smb_fh_free(struct smb_connobj * cp)917*adee6784SGordon Ross smb_fh_free(struct smb_connobj *cp)
918*adee6784SGordon Ross {
919*adee6784SGordon Ross 	struct smb_fh *fhp = CPTOFH(cp);
920*adee6784SGordon Ross 
921*adee6784SGordon Ross 	smb_co_done(FHTOCP(fhp));
922*adee6784SGordon Ross 	kmem_free(fhp, sizeof (*fhp));
923*adee6784SGordon Ross }
924*adee6784SGordon Ross 
925*adee6784SGordon Ross /*
926*adee6784SGordon Ross  * Allocate fh structure and attach it to the given share.
927*adee6784SGordon Ross  * Share expected to be locked on entry.
928*adee6784SGordon Ross  */
929*adee6784SGordon Ross /*ARGSUSED*/
930*adee6784SGordon Ross int
smb_fh_create(smb_share_t * ssp,struct smb_fh ** fhpp)931*adee6784SGordon Ross smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp)
932*adee6784SGordon Ross {
933*adee6784SGordon Ross 	static char objtype[] = "smb_fh";
934*adee6784SGordon Ross 	struct smb_fh *fhp;
935*adee6784SGordon Ross 
936*adee6784SGordon Ross 	fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP);
937*adee6784SGordon Ross 	smb_co_init(FHTOCP(fhp), SMBL_FH, objtype);
938*adee6784SGordon Ross 	fhp->fh_co.co_free = smb_fh_free;
939*adee6784SGordon Ross 	fhp->fh_co.co_gone = smb_fh_gone;
940*adee6784SGordon Ross 
941*adee6784SGordon Ross 	SMB_SS_LOCK(ssp);
942*adee6784SGordon Ross 	if ((ssp->ss_flags & SMBS_GONE) != 0) {
943*adee6784SGordon Ross 		SMB_SS_UNLOCK(ssp);
944*adee6784SGordon Ross 		smb_fh_free(FHTOCP(fhp));
945*adee6784SGordon Ross 		return (ENOTCONN);
946*adee6784SGordon Ross 	}
947*adee6784SGordon Ross 
948*adee6784SGordon Ross 	smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp));
949*adee6784SGordon Ross 	*fhpp = fhp;
950*adee6784SGordon Ross 	SMB_SS_UNLOCK(ssp);
951*adee6784SGordon Ross 
952*adee6784SGordon Ross 	return (0);
953*adee6784SGordon Ross }
954*adee6784SGordon Ross 
955*adee6784SGordon Ross void
smb_fh_opened(struct smb_fh * fhp)956*adee6784SGordon Ross smb_fh_opened(struct smb_fh *fhp)
957*adee6784SGordon Ross {
958*adee6784SGordon Ross 	smb_share_t *ssp = FHTOSS(fhp);
959*adee6784SGordon Ross 
960*adee6784SGordon Ross 	SMB_FH_LOCK(fhp);
961*adee6784SGordon Ross 	fhp->fh_vcgenid = ssp->ss_vcgenid;
962*adee6784SGordon Ross 	fhp->fh_flags |= SMBFH_VALID;
963*adee6784SGordon Ross 	SMB_FH_UNLOCK(fhp);
964*adee6784SGordon Ross }
965*adee6784SGordon Ross 
966*adee6784SGordon Ross 
9674bff34e3Sthurlow /*
9684bff34e3Sthurlow  * Solaris zones support
9694bff34e3Sthurlow  */
9704bff34e3Sthurlow /*ARGSUSED*/
9714bff34e3Sthurlow void
lingering_vc(struct smb_vc * vc)9724bff34e3Sthurlow lingering_vc(struct smb_vc *vc)
9734bff34e3Sthurlow {
9744bff34e3Sthurlow 	/* good place for a breakpoint */
9754bff34e3Sthurlow 	DEBUG_ENTER("lingering VC");
9764bff34e3Sthurlow }
9774bff34e3Sthurlow 
9784bff34e3Sthurlow /*
9794bff34e3Sthurlow  * On zone shutdown, kill any IOD threads still running in this zone.
9804bff34e3Sthurlow  */
9814bff34e3Sthurlow /* ARGSUSED */
9824bff34e3Sthurlow void
nsmb_zone_shutdown(zoneid_t zoneid,void * data)9834bff34e3Sthurlow nsmb_zone_shutdown(zoneid_t zoneid, void *data)
9844bff34e3Sthurlow {
9854bff34e3Sthurlow 	struct smb_connobj *co;
9864bff34e3Sthurlow 	struct smb_vc *vcp;
9874bff34e3Sthurlow 
9884bff34e3Sthurlow 	SMB_CO_LOCK(&smb_vclist);
9894bff34e3Sthurlow 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
9904bff34e3Sthurlow 		vcp = CPTOVC(co);
9914bff34e3Sthurlow 
9924bff34e3Sthurlow 		if (vcp->vc_zoneid != zoneid)
9934bff34e3Sthurlow 			continue;
9944bff34e3Sthurlow 
9954bff34e3Sthurlow 		/*
9964bff34e3Sthurlow 		 * This will close the connection, and
9974bff34e3Sthurlow 		 * cause the IOD thread to terminate.
9984bff34e3Sthurlow 		 */
9994bff34e3Sthurlow 		smb_vc_kill(vcp);
10004bff34e3Sthurlow 	}
10014bff34e3Sthurlow 	SMB_CO_UNLOCK(&smb_vclist);
10024bff34e3Sthurlow }
10034bff34e3Sthurlow 
10044bff34e3Sthurlow /*
10054bff34e3Sthurlow  * On zone destroy, kill any IOD threads and free all resources they used.
10064bff34e3Sthurlow  */
10074bff34e3Sthurlow /* ARGSUSED */
10084bff34e3Sthurlow void
nsmb_zone_destroy(zoneid_t zoneid,void * data)10094bff34e3Sthurlow nsmb_zone_destroy(zoneid_t zoneid, void *data)
10104bff34e3Sthurlow {
10114bff34e3Sthurlow 	struct smb_connobj *co;
10124bff34e3Sthurlow 	struct smb_vc *vcp;
10134bff34e3Sthurlow 
10144bff34e3Sthurlow 	/*
10154bff34e3Sthurlow 	 * We will repeat what should have already happened
10164bff34e3Sthurlow 	 * in zone_shutdown to make things go away.
10174bff34e3Sthurlow 	 *
10184bff34e3Sthurlow 	 * There should have been an smb_vc_rele call
10194bff34e3Sthurlow 	 * by now for all VCs in the zone.  If not,
10204bff34e3Sthurlow 	 * there's probably more we needed to do in
10214bff34e3Sthurlow 	 * the shutdown call.
10224bff34e3Sthurlow 	 */
10234bff34e3Sthurlow 
10244bff34e3Sthurlow 	SMB_CO_LOCK(&smb_vclist);
10254bff34e3Sthurlow 
10264bff34e3Sthurlow 	if (smb_vclist.co_usecount > 1) {
10274bff34e3Sthurlow 		SMBERROR("%d connections still active\n",
10284bff34e3Sthurlow 		    smb_vclist.co_usecount - 1);
10294bff34e3Sthurlow 	}
10304bff34e3Sthurlow 
10314bff34e3Sthurlow 	/* var, head, next_field */
10324bff34e3Sthurlow 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
10334bff34e3Sthurlow 		vcp = CPTOVC(co);
10344bff34e3Sthurlow 
10354bff34e3Sthurlow 		if (vcp->vc_zoneid != zoneid)
10364bff34e3Sthurlow 			continue;
10374bff34e3Sthurlow 
10384bff34e3Sthurlow 		/* Debugging */
10394bff34e3Sthurlow 		lingering_vc(vcp);
10404bff34e3Sthurlow 	}
10414bff34e3Sthurlow 
10424bff34e3Sthurlow 	SMB_CO_UNLOCK(&smb_vclist);
10434bff34e3Sthurlow }
1044