Home | History | Annotate | Download | only in netsmb
      1 /*
      2  * Copyright (c) 2000-2001 Boris Popov
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *    This product includes software developed by Boris Popov.
     16  * 4. Neither the name of the author nor the names of any co-contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  *
     32  * $Id: smb_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
     33  */
     34 /*
     35  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     36  * Use is subject to license terms.
     37  */
     38 
     39 /*
     40  * Connection engine.
     41  */
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/kmem.h>
     46 #include <sys/proc.h>
     47 #include <sys/lock.h>
     48 #include <sys/vnode.h>
     49 #include <sys/stream.h>
     50 #include <sys/stropts.h>
     51 #include <sys/socketvar.h>
     52 #include <sys/cred.h>
     53 #include <netinet/in.h>
     54 #include <inet/ip.h>
     55 #include <inet/ip6.h>
     56 #include <sys/cmn_err.h>
     57 #include <sys/thread.h>
     58 #include <sys/atomic.h>
     59 #include <sys/u8_textprep.h>
     60 
     61 #include <netsmb/smb_osdep.h>
     62 
     63 #include <netsmb/smb.h>
     64 #include <netsmb/smb_conn.h>
     65 #include <netsmb/smb_subr.h>
     66 #include <netsmb/smb_tran.h>
     67 #include <netsmb/smb_pass.h>
     68 
     69 static struct smb_connobj smb_vclist;
     70 
     71 void smb_co_init(struct smb_connobj *cp, int level, char *objname);
     72 void smb_co_done(struct smb_connobj *cp);
     73 void smb_co_hold(struct smb_connobj *cp);
     74 void smb_co_rele(struct smb_connobj *cp);
     75 void smb_co_kill(struct smb_connobj *cp);
     76 
     77 static void smb_vc_free(struct smb_connobj *cp);
     78 static void smb_vc_gone(struct smb_connobj *cp);
     79 
     80 static void smb_share_free(struct smb_connobj *cp);
     81 static void smb_share_gone(struct smb_connobj *cp);
     82 
     83 int
     84 smb_sm_init(void)
     85 {
     86 	smb_co_init(&smb_vclist, SMBL_SM, "smbsm");
     87 	return (0);
     88 }
     89 
     90 int
     91 smb_sm_idle(void)
     92 {
     93 	int error = 0;
     94 	SMB_CO_LOCK(&smb_vclist);
     95 	if (smb_vclist.co_usecount > 1) {
     96 		SMBSDEBUG("%d connections still active\n",
     97 		    smb_vclist.co_usecount - 1);
     98 		error = EBUSY;
     99 	}
    100 	SMB_CO_UNLOCK(&smb_vclist);
    101 	return (error);
    102 }
    103 
    104 void
    105 smb_sm_done(void)
    106 {
    107 	/*
    108 	 * XXX Q4BP why are we not iterating on smb_vclist here?
    109 	 * Because the caller has just called smb_sm_idle() to
    110 	 * make sure we have no VCs before calling this.
    111 	 */
    112 	smb_co_done(&smb_vclist);
    113 }
    114 
    115 
    116 
    117 /*
    118  * Common code for connection object
    119  */
    120 /*ARGSUSED*/
    121 void
    122 smb_co_init(struct smb_connobj *cp, int level, char *objname)
    123 {
    124 
    125 	mutex_init(&cp->co_lock, objname,  MUTEX_DRIVER, NULL);
    126 
    127 	cp->co_level = level;
    128 	cp->co_usecount = 1;
    129 	SLIST_INIT(&cp->co_children);
    130 }
    131 
    132 /*
    133  * Called just before free of an object
    134  * of which smb_connobj is a part, i.e.
    135  * _vc_free, _share_free, also sm_done.
    136  */
    137 void
    138 smb_co_done(struct smb_connobj *cp)
    139 {
    140 	ASSERT(SLIST_EMPTY(&cp->co_children));
    141 	mutex_destroy(&cp->co_lock);
    142 }
    143 
    144 static void
    145 smb_co_addchild(
    146 	struct smb_connobj *parent,
    147 	struct smb_connobj *child)
    148 {
    149 
    150 	/*
    151 	 * Set the child's pointer to the parent.
    152 	 * No references yet, so no need to lock.
    153 	 */
    154 	ASSERT(child->co_usecount == 1);
    155 	child->co_parent = parent;
    156 
    157 	/*
    158 	 * Add the child to the parent's list of
    159 	 * children, and in-line smb_co_hold
    160 	 */
    161 	ASSERT(MUTEX_HELD(&parent->co_lock));
    162 	parent->co_usecount++;
    163 	SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
    164 }
    165 
    166 void
    167 smb_co_hold(struct smb_connobj *cp)
    168 {
    169 	SMB_CO_LOCK(cp);
    170 	cp->co_usecount++;
    171 	SMB_CO_UNLOCK(cp);
    172 }
    173 
    174 /*
    175  * Called via smb_vc_rele, smb_share_rele
    176  */
    177 void
    178 smb_co_rele(struct smb_connobj *co)
    179 {
    180 	struct smb_connobj *parent;
    181 	int old_flags;
    182 
    183 	SMB_CO_LOCK(co);
    184 	if (co->co_usecount > 1) {
    185 		co->co_usecount--;
    186 		SMB_CO_UNLOCK(co);
    187 		return;
    188 	}
    189 	ASSERT(co->co_usecount == 1);
    190 	co->co_usecount = 0;
    191 
    192 	/*
    193 	 * This list of children should be empty now.
    194 	 * Check this while we're still linked, so
    195 	 * we have a better chance of debugging.
    196 	 */
    197 	ASSERT(SLIST_EMPTY(&co->co_children));
    198 
    199 	/*
    200 	 * OK, this element is going away.
    201 	 *
    202 	 * We need to drop the lock on this CO so we can take the
    203 	 * parent CO lock. The _GONE flag prevents this CO from
    204 	 * getting new references before we can unlink it from the
    205 	 * parent list.
    206 	 *
    207 	 * The _GONE flag is also used to ensure that the co_gone
    208 	 * function is called only once.  Note that smb_co_kill may
    209 	 * do this before we get here.  If we find that the _GONE
    210 	 * flag was not already set, then call the co_gone hook
    211 	 * (smb_share_gone, smb_vc_gone) which will disconnect
    212 	 * the share or the VC, respectively.
    213 	 *
    214 	 * Note the old: smb_co_gone(co, scred);
    215 	 * is now in-line here.
    216 	 */
    217 	old_flags = co->co_flags;
    218 	co->co_flags |= SMBO_GONE;
    219 	SMB_CO_UNLOCK(co);
    220 
    221 	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
    222 		co->co_gone(co);
    223 
    224 	/*
    225 	 * If we have a parent (only smb_vclist does not)
    226 	 * then unlink from parent's list of children.
    227 	 * We have the only reference to the child.
    228 	 */
    229 	parent = co->co_parent;
    230 	if (parent) {
    231 		SMB_CO_LOCK(parent);
    232 		ASSERT(SLIST_FIRST(&parent->co_children));
    233 		if (SLIST_FIRST(&parent->co_children)) {
    234 			SLIST_REMOVE(&parent->co_children, co,
    235 			    smb_connobj, co_next);
    236 		}
    237 		SMB_CO_UNLOCK(parent);
    238 	}
    239 
    240 	/*
    241 	 * Now it's safe to free the CO
    242 	 */
    243 	if (co->co_free) {
    244 		co->co_free(co);
    245 	}
    246 
    247 	/*
    248 	 * Finally, if the CO had a parent, decrement
    249 	 * the parent's hold count for the lost child.
    250 	 */
    251 	if (parent) {
    252 		/*
    253 		 * Recursive call here (easier for debugging).
    254 		 * Can only go two levels.
    255 		 */
    256 		smb_co_rele(parent);
    257 	}
    258 }
    259 
    260 /*
    261  * Do just the first part of what co_gone does,
    262  * i.e. tree disconnect, or disconnect a VC.
    263  * This is used to forcibly close things.
    264  */
    265 void
    266 smb_co_kill(struct smb_connobj *co)
    267 {
    268 	int old_flags;
    269 
    270 	SMB_CO_LOCK(co);
    271 	old_flags = co->co_flags;
    272 	co->co_flags |= SMBO_GONE;
    273 	SMB_CO_UNLOCK(co);
    274 
    275 	/*
    276 	 * Do the same "call only once" logic here as in
    277 	 * smb_co_rele, though it's probably not possible
    278 	 * for this to be called after smb_co_rele.
    279 	 */
    280 	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
    281 		co->co_gone(co);
    282 
    283 	/* XXX: Walk list of children and kill those too? */
    284 }
    285 
    286 
    287 /*
    288  * Session objects, which are referred to as "VC" for
    289  * "virtual cirtuit". This has nothing to do with the
    290  * CIFS notion of a "virtual cirtuit".  See smb_conn.h
    291  */
    292 
    293 void
    294 smb_vc_hold(struct smb_vc *vcp)
    295 {
    296 	smb_co_hold(VCTOCP(vcp));
    297 }
    298 
    299 void
    300 smb_vc_rele(struct smb_vc *vcp)
    301 {
    302 	smb_co_rele(VCTOCP(vcp));
    303 }
    304 
    305 void
    306 smb_vc_kill(struct smb_vc *vcp)
    307 {
    308 	smb_co_kill(VCTOCP(vcp));
    309 }
    310 
    311 /*
    312  * Normally called via smb_vc_rele()
    313  * after co_usecount drops to zero.
    314  * Also called via: smb_vc_kill()
    315  *
    316  * Shutdown the VC to this server,
    317  * invalidate shares linked with it.
    318  */
    319 /*ARGSUSED*/
    320 static void
    321 smb_vc_gone(struct smb_connobj *cp)
    322 {
    323 	struct smb_vc *vcp = CPTOVC(cp);
    324 
    325 	/*
    326 	 * Was smb_vc_disconnect(vcp);
    327 	 */
    328 	smb_iod_disconnect(vcp);
    329 }
    330 
    331 /*
    332  * The VC has no more references.  Free it.
    333  * No locks needed here.
    334  */
    335 static void
    336 smb_vc_free(struct smb_connobj *cp)
    337 {
    338 	struct smb_vc *vcp = CPTOVC(cp);
    339 
    340 	/*
    341 	 * The _gone call should have emptied the request list,
    342 	 * but let's make sure, as requests may have references
    343 	 * to this VC without taking a hold.  (The hold is the
    344 	 * responsibility of threads placing requests.)
    345 	 */
    346 	ASSERT(vcp->iod_rqlist.tqh_first == NULL);
    347 
    348 	if (vcp->vc_tdata)
    349 		SMB_TRAN_DONE(vcp);
    350 
    351 /*
    352  * We are not using the iconv routines here. So commenting them for now.
    353  * REVISIT.
    354  */
    355 #ifdef NOTYETDEFINED
    356 	if (vcp->vc_tolower)
    357 		iconv_close(vcp->vc_tolower);
    358 	if (vcp->vc_toupper)
    359 		iconv_close(vcp->vc_toupper);
    360 	if (vcp->vc_tolocal)
    361 		iconv_close(vcp->vc_tolocal);
    362 	if (vcp->vc_toserver)
    363 		iconv_close(vcp->vc_toserver);
    364 #endif
    365 
    366 	if (vcp->vc_mackey != NULL)
    367 		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
    368 
    369 	cv_destroy(&vcp->iod_idle);
    370 	rw_destroy(&vcp->iod_rqlock);
    371 	sema_destroy(&vcp->vc_sendlock);
    372 	cv_destroy(&vcp->vc_statechg);
    373 	smb_co_done(VCTOCP(vcp));
    374 	kmem_free(vcp, sizeof (*vcp));
    375 }
    376 
    377 /*ARGSUSED*/
    378 int
    379 smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
    380 {
    381 	static char objtype[] = "smb_vc";
    382 	cred_t *cr = scred->scr_cred;
    383 	struct smb_vc *vcp;
    384 	int error = 0;
    385 
    386 	ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
    387 
    388 	vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
    389 
    390 	smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
    391 	vcp->vc_co.co_free = smb_vc_free;
    392 	vcp->vc_co.co_gone = smb_vc_gone;
    393 
    394 	cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
    395 	sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
    396 	rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
    397 	cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
    398 
    399 	/* Expanded TAILQ_HEAD_INITIALIZER */
    400 	vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
    401 
    402 	vcp->vc_state = SMBIOD_ST_IDLE;
    403 
    404 	/*
    405 	 * These identify the connection.
    406 	 */
    407 	vcp->vc_zoneid = getzoneid();
    408 	bcopy(ossn, &vcp->vc_ssn, sizeof (*ossn));
    409 
    410 	/* This fills in vcp->vc_tdata */
    411 	vcp->vc_tdesc = &smb_tran_nbtcp_desc;
    412 	if ((error = SMB_TRAN_CREATE(vcp, cr)) != 0)
    413 		goto errout;
    414 
    415 	/* Success! */
    416 	smb_co_addchild(&smb_vclist, VCTOCP(vcp));
    417 	*vcpp = vcp;
    418 	return (0);
    419 
    420 errout:
    421 	/*
    422 	 * This will destroy the new vc.
    423 	 * See: smb_vc_free
    424 	 */
    425 	smb_vc_rele(vcp);
    426 	return (error);
    427 }
    428 
    429 /*
    430  * Find or create a VC identified by the info in ossn
    431  * and return it with a "hold", but not locked.
    432  */
    433 /*ARGSUSED*/
    434 int
    435 smb_vc_findcreate(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
    436 {
    437 	struct smb_connobj *co;
    438 	struct smb_vc *vcp;
    439 	smbioc_ssn_ident_t *vc_id;
    440 	int error;
    441 	zoneid_t zoneid = getzoneid();
    442 
    443 	*vcpp = vcp = NULL;
    444 
    445 	SMB_CO_LOCK(&smb_vclist);
    446 
    447 	/* var, head, next_field */
    448 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
    449 		vcp = CPTOVC(co);
    450 
    451 		/*
    452 		 * Some things we can check without
    453 		 * holding the lock (those that are
    454 		 * set at creation and never change).
    455 		 */
    456 
    457 		/* VCs in other zones are invisibile. */
    458 		if (vcp->vc_zoneid != zoneid)
    459 			continue;
    460 
    461 		/* Also segregate by Unix owner. */
    462 		if (vcp->vc_owner != ossn->ssn_owner)
    463 			continue;
    464 
    465 		/*
    466 		 * Compare identifying info:
    467 		 * server address, user, domain
    468 		 * names are case-insensitive
    469 		 */
    470 		vc_id = &vcp->vc_ssn.ssn_id;
    471 		if (bcmp(&vc_id->id_srvaddr,
    472 		    &ossn->ssn_id.id_srvaddr,
    473 		    sizeof (vc_id->id_srvaddr)))
    474 			continue;
    475 		if (u8_strcmp(vc_id->id_user, ossn->ssn_id.id_user, 0,
    476 		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
    477 			continue;
    478 		if (u8_strcmp(vc_id->id_domain, ossn->ssn_id.id_domain, 0,
    479 		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
    480 			continue;
    481 
    482 		/*
    483 		 * We have a match, but still have to check
    484 		 * the _GONE flag, and do that with a lock.
    485 		 * No new references when _GONE is set.
    486 		 *
    487 		 * Also clear SMBVOPT_CREATE which the caller
    488 		 * may check to find out if we did create.
    489 		 */
    490 		SMB_VC_LOCK(vcp);
    491 		if ((vcp->vc_flags & SMBV_GONE) == 0) {
    492 			ossn->ssn_vopt &= ~SMBVOPT_CREATE;
    493 			/*
    494 			 * Return it held, unlocked.
    495 			 * In-line smb_vc_hold here.
    496 			 */
    497 			co->co_usecount++;
    498 			SMB_VC_UNLOCK(vcp);
    499 			*vcpp = vcp;
    500 			error = 0;
    501 			goto out;
    502 		}
    503 		SMB_VC_UNLOCK(vcp);
    504 		/* keep looking. */
    505 	}
    506 	vcp = NULL;
    507 
    508 	/* Note: smb_vclist is still locked. */
    509 
    510 	if (ossn->ssn_vopt & SMBVOPT_CREATE) {
    511 		/*
    512 		 * Create a new VC.  It starts out with
    513 		 * hold count = 1, so don't incr. here.
    514 		 */
    515 		error = smb_vc_create(ossn, scred, &vcp);
    516 		if (error == 0)
    517 			*vcpp = vcp;
    518 	} else
    519 		error = ENOENT;
    520 
    521 out:
    522 	SMB_CO_UNLOCK(&smb_vclist);
    523 	return (error);
    524 }
    525 
    526 
    527 /*
    528  * Helper functions that operate on VCs
    529  */
    530 
    531 /*
    532  * Get a pointer to the IP address suitable for passing to Trusted
    533  * Extensions find_tpc() routine.  Used by smbfs_mount_label_policy().
    534  * Compare this code to nfs_mount_label_policy() if problems arise.
    535  */
    536 void *
    537 smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers)
    538 {
    539 	smbioc_ssn_ident_t *id = &vcp->vc_ssn.ssn_id;
    540 	void *ret;
    541 
    542 	switch (id->id_srvaddr.sa.sa_family) {
    543 	case AF_INET:
    544 		*ipvers = IPV4_VERSION;
    545 		ret = &id->id_srvaddr.sin.sin_addr;
    546 		break;
    547 
    548 	case AF_INET6:
    549 		*ipvers = IPV6_VERSION;
    550 		ret = &id->id_srvaddr.sin6.sin6_addr;
    551 		break;
    552 	default:
    553 		SMBSDEBUG("invalid address family %d\n",
    554 		    id->id_srvaddr.sa.sa_family);
    555 		*ipvers = 0;
    556 		ret = NULL;
    557 		break;
    558 	}
    559 	return (ret);
    560 }
    561 
    562 void
    563 smb_vc_walkshares(struct smb_vc *vcp,
    564 	walk_share_func_t func)
    565 {
    566 	smb_connobj_t *co;
    567 	smb_share_t *ssp;
    568 
    569 	/*
    570 	 * Walk the share list calling func(ssp, arg)
    571 	 */
    572 	SMB_VC_LOCK(vcp);
    573 	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
    574 		ssp = CPTOSS(co);
    575 		SMB_SS_LOCK(ssp);
    576 		func(ssp);
    577 		SMB_SS_UNLOCK(ssp);
    578 	}
    579 	SMB_VC_UNLOCK(vcp);
    580 }
    581 
    582 
    583 /*
    584  * Share implementation
    585  */
    586 
    587 void
    588 smb_share_hold(struct smb_share *ssp)
    589 {
    590 	smb_co_hold(SSTOCP(ssp));
    591 }
    592 
    593 void
    594 smb_share_rele(struct smb_share *ssp)
    595 {
    596 	smb_co_rele(SSTOCP(ssp));
    597 }
    598 
    599 void
    600 smb_share_kill(struct smb_share *ssp)
    601 {
    602 	smb_co_kill(SSTOCP(ssp));
    603 }
    604 
    605 /*
    606  * Normally called via smb_share_rele()
    607  * after co_usecount drops to zero.
    608  * Also called via: smb_share_kill()
    609  */
    610 static void
    611 smb_share_gone(struct smb_connobj *cp)
    612 {
    613 	struct smb_cred scred;
    614 	struct smb_share *ssp = CPTOSS(cp);
    615 
    616 	smb_credinit(&scred, NULL);
    617 	smb_iod_shutdown_share(ssp);
    618 	(void) smb_smb_treedisconnect(ssp, &scred);
    619 	smb_credrele(&scred);
    620 }
    621 
    622 /*
    623  * Normally called via smb_share_rele()
    624  * after co_usecount drops to zero.
    625  */
    626 static void
    627 smb_share_free(struct smb_connobj *cp)
    628 {
    629 	struct smb_share *ssp = CPTOSS(cp);
    630 
    631 	cv_destroy(&ssp->ss_conn_done);
    632 	smb_co_done(SSTOCP(ssp));
    633 	kmem_free(ssp, sizeof (*ssp));
    634 }
    635 
    636 /*
    637  * Allocate share structure and attach it to the given VC
    638  * Connection expected to be locked on entry. Share will be returned
    639  * in locked state.
    640  */
    641 /*ARGSUSED*/
    642 int
    643 smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
    644 	struct smb_share **sspp, struct smb_cred *scred)
    645 {
    646 	static char objtype[] = "smb_ss";
    647 	struct smb_share *ssp;
    648 
    649 	ASSERT(MUTEX_HELD(&vcp->vc_lock));
    650 
    651 	ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
    652 	smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
    653 	ssp->ss_co.co_free = smb_share_free;
    654 	ssp->ss_co.co_gone = smb_share_gone;
    655 
    656 	cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
    657 	ssp->ss_tid = SMB_TID_UNKNOWN;
    658 
    659 	bcopy(&tcon->tc_sh, &ssp->ss_ioc,
    660 	    sizeof (smbioc_oshare_t));
    661 
    662 	smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
    663 	*sspp = ssp;
    664 
    665 	return (0);
    666 }
    667 
    668 /*
    669  * Find or create a share under the given VC
    670  * and return it with a "hold", but not locked.
    671  */
    672 
    673 int
    674 smb_share_findcreate(smbioc_tcon_t *tcon, struct smb_vc *vcp,
    675 	struct smb_share **sspp, struct smb_cred *scred)
    676 {
    677 	struct smb_connobj *co;
    678 	struct smb_share *ssp = NULL;
    679 	int error = 0;
    680 
    681 	*sspp = NULL;
    682 
    683 	SMB_VC_LOCK(vcp);
    684 
    685 	/* var, head, next_field */
    686 	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
    687 		ssp = CPTOSS(co);
    688 
    689 		/* Share name */
    690 		if (u8_strcmp(ssp->ss_name, tcon->tc_sh.sh_name, 0,
    691 		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
    692 			continue;
    693 
    694 		/*
    695 		 * We have a match, but still have to check
    696 		 * the _GONE flag, and do that with a lock.
    697 		 * No new references when _GONE is set.
    698 		 *
    699 		 * Also clear SMBSOPT_CREATE which the caller
    700 		 * may check to find out if we did create.
    701 		 */
    702 		SMB_SS_LOCK(ssp);
    703 		if ((ssp->ss_flags & SMBS_GONE) == 0) {
    704 			tcon->tc_opt &= ~SMBSOPT_CREATE;
    705 			/*
    706 			 * Return it held, unlocked.
    707 			 * In-line smb_share_hold here.
    708 			 */
    709 			co->co_usecount++;
    710 			SMB_SS_UNLOCK(ssp);
    711 			*sspp = ssp;
    712 			error = 0;
    713 			goto out;
    714 		}
    715 		SMB_SS_UNLOCK(ssp);
    716 		/* keep looking. */
    717 	}
    718 	ssp = NULL;
    719 
    720 	/* Note: vcp (list of shares) is still locked. */
    721 
    722 	if (tcon->tc_opt & SMBSOPT_CREATE) {
    723 		/*
    724 		 * Create a new share.  It starts out with
    725 		 * hold count = 1, so don't incr. here.
    726 		 */
    727 		error = smb_share_create(tcon, vcp, &ssp, scred);
    728 		if (error == 0)
    729 			*sspp = ssp;
    730 	} else
    731 		error = ENOENT;
    732 
    733 out:
    734 	SMB_VC_UNLOCK(vcp);
    735 	return (error);
    736 }
    737 
    738 
    739 /*
    740  * Helper functions that operate on shares
    741  */
    742 
    743 /*
    744  * Mark this share as invalid, so consumers will know
    745  * their file handles have become invalid.
    746  *
    747  * Most share consumers store a copy of ss_vcgenid when
    748  * opening a file handle and compare that with what's in
    749  * the share before using a file handle.  If the genid
    750  * doesn't match, the file handle has become "stale"
    751  * due to disconnect.  Therefore, zap ss_vcgenid here.
    752  */
    753 void
    754 smb_share_invalidate(struct smb_share *ssp)
    755 {
    756 
    757 	ASSERT(MUTEX_HELD(&ssp->ss_lock));
    758 
    759 	ssp->ss_flags &= ~SMBS_CONNECTED;
    760 	ssp->ss_tid = SMB_TID_UNKNOWN;
    761 	ssp->ss_vcgenid = 0;
    762 }
    763 
    764 /*
    765  * Connect (or reconnect) a share object.
    766  *
    767  * Called by smb_usr_get_tree() for new connections,
    768  * and called by smb_rq_enqueue() for reconnect.
    769  */
    770 int
    771 smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
    772 {
    773 	clock_t tmo;
    774 	int error;
    775 
    776 	SMB_SS_LOCK(ssp);
    777 
    778 	if (ssp->ss_flags & SMBS_CONNECTED) {
    779 		SMBIODEBUG("alread connected?");
    780 		error = 0;
    781 		goto out;
    782 	}
    783 
    784 	/*
    785 	 * Wait for completion of any state changes
    786 	 * that might be underway.
    787 	 */
    788 	while (ssp->ss_flags & SMBS_RECONNECTING) {
    789 		ssp->ss_conn_waiters++;
    790 		tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock);
    791 		ssp->ss_conn_waiters--;
    792 		if (tmo == 0) {
    793 			/* Interrupt! */
    794 			error = EINTR;
    795 			goto out;
    796 		}
    797 	}
    798 
    799 	/* Did someone else do it for us? */
    800 	if (ssp->ss_flags & SMBS_CONNECTED) {
    801 		error = 0;
    802 		goto out;
    803 	}
    804 
    805 	/*
    806 	 * OK, we'll do the work.
    807 	 */
    808 	ssp->ss_flags |= SMBS_RECONNECTING;
    809 
    810 	/*
    811 	 * Drop the lock while doing the TCON.
    812 	 * On success, sets ss_tid, ss_vcgenid,
    813 	 * and ss_flags |= SMBS_CONNECTED;
    814 	 */
    815 	SMB_SS_UNLOCK(ssp);
    816 	error = smb_smb_treeconnect(ssp, scred);
    817 	SMB_SS_LOCK(ssp);
    818 
    819 	ssp->ss_flags &= ~SMBS_RECONNECTING;
    820 
    821 	/* They can all go ahead! */
    822 	if (ssp->ss_conn_waiters)
    823 		cv_broadcast(&ssp->ss_conn_done);
    824 
    825 out:
    826 	SMB_SS_UNLOCK(ssp);
    827 
    828 	return (error);
    829 }
    830 
    831 /*
    832  * Solaris zones support
    833  */
    834 /*ARGSUSED*/
    835 void
    836 lingering_vc(struct smb_vc *vc)
    837 {
    838 	/* good place for a breakpoint */
    839 	DEBUG_ENTER("lingering VC");
    840 }
    841 
    842 /*
    843  * On zone shutdown, kill any IOD threads still running in this zone.
    844  */
    845 /* ARGSUSED */
    846 void
    847 nsmb_zone_shutdown(zoneid_t zoneid, void *data)
    848 {
    849 	struct smb_connobj *co;
    850 	struct smb_vc *vcp;
    851 
    852 	SMB_CO_LOCK(&smb_vclist);
    853 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
    854 		vcp = CPTOVC(co);
    855 
    856 		if (vcp->vc_zoneid != zoneid)
    857 			continue;
    858 
    859 		/*
    860 		 * This will close the connection, and
    861 		 * cause the IOD thread to terminate.
    862 		 */
    863 		smb_vc_kill(vcp);
    864 	}
    865 	SMB_CO_UNLOCK(&smb_vclist);
    866 }
    867 
    868 /*
    869  * On zone destroy, kill any IOD threads and free all resources they used.
    870  */
    871 /* ARGSUSED */
    872 void
    873 nsmb_zone_destroy(zoneid_t zoneid, void *data)
    874 {
    875 	struct smb_connobj *co;
    876 	struct smb_vc *vcp;
    877 
    878 	/*
    879 	 * We will repeat what should have already happened
    880 	 * in zone_shutdown to make things go away.
    881 	 *
    882 	 * There should have been an smb_vc_rele call
    883 	 * by now for all VCs in the zone.  If not,
    884 	 * there's probably more we needed to do in
    885 	 * the shutdown call.
    886 	 */
    887 
    888 	SMB_CO_LOCK(&smb_vclist);
    889 
    890 	if (smb_vclist.co_usecount > 1) {
    891 		SMBERROR("%d connections still active\n",
    892 		    smb_vclist.co_usecount - 1);
    893 	}
    894 
    895 	/* var, head, next_field */
    896 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
    897 		vcp = CPTOVC(co);
    898 
    899 		if (vcp->vc_zoneid != zoneid)
    900 			continue;
    901 
    902 		/* Debugging */
    903 		lingering_vc(vcp);
    904 	}
    905 
    906 	SMB_CO_UNLOCK(&smb_vclist);
    907 }
    908