xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c (revision b1d7ec75953cd517f5b7c3d9cb427ff8ec5d7d07)
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