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