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 * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
39 */
40
41/*
42 * Connection engine.
43 */
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kmem.h>
48#include <sys/proc.h>
49#include <sys/lock.h>
50#include <sys/vnode.h>
51#include <sys/stream.h>
52#include <sys/stropts.h>
53#include <sys/socketvar.h>
54#include <sys/cred.h>
55#include <netinet/in.h>
56#include <inet/ip.h>
57#include <inet/ip6.h>
58#include <sys/cmn_err.h>
59#include <sys/thread.h>
60#include <sys/atomic.h>
61#include <sys/u8_textprep.h>
62
63#include <netsmb/smb_osdep.h>
64
65#include <netsmb/smb.h>
66#include <netsmb/smb2.h>
67#include <netsmb/smb_conn.h>
68#include <netsmb/smb_subr.h>
69#include <netsmb/smb_tran.h>
70#include <netsmb/smb_pass.h>
71
72static struct smb_connobj smb_vclist;
73
74void smb_co_init(struct smb_connobj *cp, int level, char *objname);
75void smb_co_done(struct smb_connobj *cp);
76void smb_co_hold(struct smb_connobj *cp);
77void smb_co_rele(struct smb_connobj *cp);
78void smb_co_kill(struct smb_connobj *cp);
79
80static void smb_vc_free(struct smb_connobj *cp);
81static void smb_vc_gone(struct smb_connobj *cp);
82
83static void smb_share_free(struct smb_connobj *cp);
84static void smb_share_gone(struct smb_connobj *cp);
85
86static void smb_fh_free(struct smb_connobj *cp);
87static void smb_fh_gone(struct smb_connobj *cp);
88
89int
90smb_sm_init(void)
91{
92	smb_co_init(&smb_vclist, SMBL_SM, "smbsm");
93	return (0);
94}
95
96int
97smb_sm_idle(void)
98{
99	int error = 0;
100	SMB_CO_LOCK(&smb_vclist);
101	if (smb_vclist.co_usecount > 1) {
102		SMBSDEBUG("%d connections still active\n",
103		    smb_vclist.co_usecount - 1);
104		error = EBUSY;
105	}
106	SMB_CO_UNLOCK(&smb_vclist);
107	return (error);
108}
109
110void
111smb_sm_done(void)
112{
113	/*
114	 * Why are we not iterating on smb_vclist here?
115	 * Because the caller has just called smb_sm_idle() to
116	 * make sure we have no VCs before calling this.
117	 */
118	smb_co_done(&smb_vclist);
119}
120
121
122
123/*
124 * Common code for connection object
125 */
126/*ARGSUSED*/
127void
128smb_co_init(struct smb_connobj *cp, int level, char *objname)
129{
130
131	mutex_init(&cp->co_lock, objname,  MUTEX_DRIVER, NULL);
132
133	cp->co_level = level;
134	cp->co_usecount = 1;
135	SLIST_INIT(&cp->co_children);
136}
137
138/*
139 * Called just before free of an object
140 * of which smb_connobj is a part, i.e.
141 * _vc_free, _share_free, also sm_done.
142 */
143void
144smb_co_done(struct smb_connobj *cp)
145{
146	ASSERT(SLIST_EMPTY(&cp->co_children));
147	mutex_destroy(&cp->co_lock);
148}
149
150static void
151smb_co_addchild(
152	struct smb_connobj *parent,
153	struct smb_connobj *child)
154{
155
156	/*
157	 * Set the child's pointer to the parent.
158	 * No references yet, so no need to lock.
159	 */
160	ASSERT(child->co_usecount == 1);
161	child->co_parent = parent;
162
163	/*
164	 * Add the child to the parent's list of
165	 * children, and in-line smb_co_hold
166	 */
167	ASSERT(MUTEX_HELD(&parent->co_lock));
168	parent->co_usecount++;
169	SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
170}
171
172void
173smb_co_hold(struct smb_connobj *cp)
174{
175	SMB_CO_LOCK(cp);
176	cp->co_usecount++;
177	SMB_CO_UNLOCK(cp);
178}
179
180/*
181 * Called via smb_vc_rele, smb_share_rele
182 */
183void
184smb_co_rele(struct smb_connobj *co)
185{
186	struct smb_connobj *parent;
187	int old_flags;
188
189	SMB_CO_LOCK(co);
190
191	/*
192	 * When VC usecount goes from 2 to 1, signal the iod_idle CV.
193	 * It's unfortunate to have object type-specific logic here,
194	 * but it's hard to do this anywhere else.
195	 */
196	if (co->co_level == SMBL_VC && co->co_usecount == 2) {
197		smb_vc_t *vcp = CPTOVC(co);
198		cv_signal(&vcp->iod_idle);
199	}
200	if (co->co_usecount > 1) {
201		co->co_usecount--;
202		SMB_CO_UNLOCK(co);
203		return;
204	}
205	ASSERT(co->co_usecount == 1);
206	co->co_usecount = 0;
207
208	/*
209	 * This list of children should be empty now.
210	 * Check this while we're still linked, so
211	 * we have a better chance of debugging.
212	 */
213	ASSERT(SLIST_EMPTY(&co->co_children));
214
215	/*
216	 * OK, this element is going away.
217	 *
218	 * We need to drop the lock on this CO so we can take the
219	 * parent CO lock. The _GONE flag prevents this CO from
220	 * getting new references before we can unlink it from the
221	 * parent list.
222	 *
223	 * The _GONE flag is also used to ensure that the co_gone
224	 * function is called only once.  Note that smb_co_kill may
225	 * do this before we get here.  If we find that the _GONE
226	 * flag was not already set, then call the co_gone hook
227	 * (smb_share_gone, smb_vc_gone) which will disconnect
228	 * the share or the VC, respectively.
229	 *
230	 * Note the old: smb_co_gone(co, scred);
231	 * is now in-line here.
232	 */
233	old_flags = co->co_flags;
234	co->co_flags |= SMBO_GONE;
235	SMB_CO_UNLOCK(co);
236
237	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
238		co->co_gone(co);
239
240	/*
241	 * If we have a parent (only smb_vclist does not)
242	 * then unlink from parent's list of children.
243	 * We have the only reference to the child.
244	 */
245	parent = co->co_parent;
246	if (parent) {
247		SMB_CO_LOCK(parent);
248		ASSERT(SLIST_FIRST(&parent->co_children));
249		if (SLIST_FIRST(&parent->co_children)) {
250			SLIST_REMOVE(&parent->co_children, co,
251			    smb_connobj, co_next);
252		}
253		SMB_CO_UNLOCK(parent);
254	}
255
256	/*
257	 * Now it's safe to free the CO
258	 */
259	if (co->co_free) {
260		co->co_free(co);
261	}
262
263	/*
264	 * Finally, if the CO had a parent, decrement
265	 * the parent's hold count for the lost child.
266	 */
267	if (parent) {
268		/*
269		 * Recursive call here (easier for debugging).
270		 * Can only go two levels.
271		 */
272		smb_co_rele(parent);
273	}
274}
275
276/*
277 * Do just the first part of what co_gone does,
278 * i.e. tree disconnect, or disconnect a VC.
279 * This is used to forcibly close things.
280 */
281void
282smb_co_kill(struct smb_connobj *co)
283{
284	int old_flags;
285
286	SMB_CO_LOCK(co);
287	old_flags = co->co_flags;
288	co->co_flags |= SMBO_GONE;
289	SMB_CO_UNLOCK(co);
290
291	/*
292	 * Do the same "call only once" logic here as in
293	 * smb_co_rele, though it's probably not possible
294	 * for this to be called after smb_co_rele.
295	 */
296	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
297		co->co_gone(co);
298
299	/* XXX: Walk list of children and kill those too? */
300}
301
302
303/*
304 * Session objects, which are referred to as "VC" for
305 * "virtual cirtuit". This has nothing to do with the
306 * CIFS notion of a "virtual cirtuit".  See smb_conn.h
307 */
308
309void
310smb_vc_hold(struct smb_vc *vcp)
311{
312	smb_co_hold(VCTOCP(vcp));
313}
314
315void
316smb_vc_rele(struct smb_vc *vcp)
317{
318	smb_co_rele(VCTOCP(vcp));
319}
320
321void
322smb_vc_kill(struct smb_vc *vcp)
323{
324	smb_co_kill(VCTOCP(vcp));
325}
326
327/*
328 * Normally called via smb_vc_rele()
329 * after co_usecount drops to zero.
330 * Also called via: smb_vc_kill()
331 *
332 * Shutdown the VC to this server,
333 * invalidate shares linked with it.
334 */
335/*ARGSUSED*/
336static void
337smb_vc_gone(struct smb_connobj *cp)
338{
339	struct smb_vc *vcp = CPTOVC(cp);
340
341	/*
342	 * Was smb_vc_disconnect(vcp);
343	 */
344	smb_iod_disconnect(vcp);
345}
346
347/*
348 * The VC has no more references.  Free it.
349 * No locks needed here.
350 */
351static void
352smb_vc_free(struct smb_connobj *cp)
353{
354	struct smb_vc *vcp = CPTOVC(cp);
355
356	/*
357	 * The _gone call should have emptied the request list,
358	 * but let's make sure, as requests may have references
359	 * to this VC without taking a hold.  (The hold is the
360	 * responsibility of threads placing requests.)
361	 */
362	ASSERT(vcp->iod_rqlist.tqh_first == NULL);
363
364	if (vcp->vc_tdata)
365		SMB_TRAN_DONE(vcp);
366
367/*
368 * We are not using the iconv routines here. So commenting them for now.
369 * REVISIT.
370 */
371#ifdef NOTYETDEFINED
372	if (vcp->vc_tolower)
373		iconv_close(vcp->vc_tolower);
374	if (vcp->vc_toupper)
375		iconv_close(vcp->vc_toupper);
376	if (vcp->vc_tolocal)
377		iconv_close(vcp->vc_tolocal);
378	if (vcp->vc_toserver)
379		iconv_close(vcp->vc_toserver);
380#endif
381
382	if (vcp->vc_mackey != NULL)
383		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
384	if (vcp->vc_ssnkey != NULL)
385		kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
386
387	cv_destroy(&vcp->iod_muxwait);
388	cv_destroy(&vcp->iod_idle);
389	rw_destroy(&vcp->iod_rqlock);
390	cv_destroy(&vcp->vc_statechg);
391	smb_co_done(VCTOCP(vcp));
392	kmem_free(vcp, sizeof (*vcp));
393}
394
395/*ARGSUSED*/
396int
397smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
398{
399	static char objtype[] = "smb_vc";
400	cred_t *cr = scred->scr_cred;
401	struct smb_vc *vcp;
402	int error = 0;
403
404	ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
405
406	vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
407
408	smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
409	vcp->vc_co.co_free = smb_vc_free;
410	vcp->vc_co.co_gone = smb_vc_gone;
411
412	cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
413	rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
414	cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
415	cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL);
416
417	/* Expanded TAILQ_HEAD_INITIALIZER */
418	vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
419
420	/* A brand new VC should connect. */
421	vcp->vc_state = SMBIOD_ST_RECONNECT;
422
423	/*
424	 * These identify the connection.
425	 */
426	vcp->vc_zoneid = getzoneid();
427	bcopy(ossn, &vcp->vc_ssn, sizeof (*ossn));
428
429	/* This fills in vcp->vc_tdata */
430	vcp->vc_tdesc = &smb_tran_nbtcp_desc;
431	if ((error = SMB_TRAN_CREATE(vcp, cr)) != 0)
432		goto errout;
433
434	/* Success! */
435	smb_co_addchild(&smb_vclist, VCTOCP(vcp));
436	*vcpp = vcp;
437	return (0);
438
439errout:
440	/*
441	 * This will destroy the new vc.
442	 * See: smb_vc_free
443	 */
444	smb_vc_rele(vcp);
445	return (error);
446}
447
448/*
449 * Find or create a VC identified by the info in ossn
450 * and return it with a "hold", but not locked.
451 */
452/*ARGSUSED*/
453int
454smb_vc_findcreate(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
455{
456	struct smb_connobj *co;
457	struct smb_vc *vcp;
458	smbioc_ssn_ident_t *vc_id;
459	int error;
460	zoneid_t zoneid = getzoneid();
461
462	*vcpp = vcp = NULL;
463
464	SMB_CO_LOCK(&smb_vclist);
465
466	/* var, head, next_field */
467	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
468		vcp = CPTOVC(co);
469
470		/*
471		 * Some things we can check without
472		 * holding the lock (those that are
473		 * set at creation and never change).
474		 */
475
476		/* VCs in other zones are invisibile. */
477		if (vcp->vc_zoneid != zoneid)
478			continue;
479
480		/* Also segregate by Unix owner. */
481		if (vcp->vc_owner != ossn->ssn_owner)
482			continue;
483
484		/*
485		 * Compare identifying info:
486		 * server address, user, domain
487		 * names are case-insensitive
488		 */
489		vc_id = &vcp->vc_ssn.ssn_id;
490		if (bcmp(&vc_id->id_srvaddr,
491		    &ossn->ssn_id.id_srvaddr,
492		    sizeof (vc_id->id_srvaddr)))
493			continue;
494		if (u8_strcmp(vc_id->id_user, ossn->ssn_id.id_user, 0,
495		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
496			continue;
497		if (u8_strcmp(vc_id->id_domain, ossn->ssn_id.id_domain, 0,
498		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
499			continue;
500
501		/*
502		 * We have a match, but still have to check
503		 * the _GONE flag, and do that with a lock.
504		 * No new references when _GONE is set.
505		 *
506		 * Also clear SMBVOPT_CREATE which the caller
507		 * may check to find out if we did create.
508		 */
509		SMB_VC_LOCK(vcp);
510		if ((vcp->vc_flags & SMBV_GONE) == 0) {
511			ossn->ssn_vopt &= ~SMBVOPT_CREATE;
512			/*
513			 * Return it held, unlocked.
514			 * In-line smb_vc_hold here.
515			 */
516			co->co_usecount++;
517			SMB_VC_UNLOCK(vcp);
518			*vcpp = vcp;
519			error = 0;
520			goto out;
521		}
522		SMB_VC_UNLOCK(vcp);
523		/* keep looking. */
524	}
525	vcp = NULL;
526
527	/* Note: smb_vclist is still locked. */
528
529	if (ossn->ssn_vopt & SMBVOPT_CREATE) {
530		/*
531		 * Create a new VC.  It starts out with
532		 * hold count = 1, so don't incr. here.
533		 */
534		error = smb_vc_create(ossn, scred, &vcp);
535		if (error == 0)
536			*vcpp = vcp;
537	} else
538		error = ENOENT;
539
540out:
541	SMB_CO_UNLOCK(&smb_vclist);
542	return (error);
543}
544
545
546/*
547 * Helper functions that operate on VCs
548 */
549
550/*
551 * Get a pointer to the IP address suitable for passing to Trusted
552 * Extensions find_tpc() routine.  Used by smbfs_mount_label_policy().
553 * Compare this code to nfs_mount_label_policy() if problems arise.
554 */
555void *
556smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers)
557{
558	smbioc_ssn_ident_t *id = &vcp->vc_ssn.ssn_id;
559	void *ret;
560
561	switch (id->id_srvaddr.sa.sa_family) {
562	case AF_INET:
563		*ipvers = IPV4_VERSION;
564		ret = &id->id_srvaddr.sin.sin_addr;
565		break;
566
567	case AF_INET6:
568		*ipvers = IPV6_VERSION;
569		ret = &id->id_srvaddr.sin6.sin6_addr;
570		break;
571	default:
572		SMBSDEBUG("invalid address family %d\n",
573		    id->id_srvaddr.sa.sa_family);
574		*ipvers = 0;
575		ret = NULL;
576		break;
577	}
578	return (ret);
579}
580
581void
582smb_vc_walkshares(struct smb_vc *vcp,
583	walk_share_func_t func)
584{
585	smb_connobj_t *co;
586	smb_share_t *ssp;
587
588	/*
589	 * Walk the share list calling func(ssp, arg)
590	 */
591	SMB_VC_LOCK(vcp);
592	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
593		ssp = CPTOSS(co);
594		SMB_SS_LOCK(ssp);
595		func(ssp);
596		SMB_SS_UNLOCK(ssp);
597	}
598	SMB_VC_UNLOCK(vcp);
599}
600
601
602/*
603 * Share implementation
604 */
605
606void
607smb_share_hold(struct smb_share *ssp)
608{
609	smb_co_hold(SSTOCP(ssp));
610}
611
612void
613smb_share_rele(struct smb_share *ssp)
614{
615	smb_co_rele(SSTOCP(ssp));
616}
617
618void
619smb_share_kill(struct smb_share *ssp)
620{
621	smb_co_kill(SSTOCP(ssp));
622}
623
624/*
625 * Normally called via smb_share_rele()
626 * after co_usecount drops to zero.
627 * Also called via: smb_share_kill()
628 */
629static void
630smb_share_gone(struct smb_connobj *cp)
631{
632	struct smb_cred scred;
633	struct smb_share *ssp = CPTOSS(cp);
634	smb_vc_t *vcp = SSTOVC(ssp);
635
636	smb_credinit(&scred, NULL);
637	smb_iod_shutdown_share(ssp);
638	if (vcp->vc_flags & SMBV_SMB2)
639		(void) smb2_smb_treedisconnect(ssp, &scred);
640	else
641		(void) smb_smb_treedisconnect(ssp, &scred);
642	smb_credrele(&scred);
643}
644
645/*
646 * Normally called via smb_share_rele()
647 * after co_usecount drops to zero.
648 */
649static void
650smb_share_free(struct smb_connobj *cp)
651{
652	struct smb_share *ssp = CPTOSS(cp);
653
654	cv_destroy(&ssp->ss_conn_done);
655	smb_co_done(SSTOCP(ssp));
656	kmem_free(ssp, sizeof (*ssp));
657}
658
659/*
660 * Allocate share structure and attach it to the given VC
661 * Connection expected to be locked on entry. Share will be returned
662 * in locked state.
663 */
664/*ARGSUSED*/
665int
666smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
667	struct smb_share **sspp, struct smb_cred *scred)
668{
669	static char objtype[] = "smb_ss";
670	struct smb_share *ssp;
671
672	ASSERT(MUTEX_HELD(&vcp->vc_lock));
673
674	ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
675	smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
676	ssp->ss_co.co_free = smb_share_free;
677	ssp->ss_co.co_gone = smb_share_gone;
678
679	cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
680	ssp->ss_tid = SMB_TID_UNKNOWN;
681	ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
682
683	bcopy(&tcon->tc_sh, &ssp->ss_ioc,
684	    sizeof (smbioc_oshare_t));
685
686	smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
687	*sspp = ssp;
688
689	return (0);
690}
691
692/*
693 * Find or create a share under the given VC
694 * and return it with a "hold", but not locked.
695 */
696
697int
698smb_share_findcreate(smbioc_tcon_t *tcon, struct smb_vc *vcp,
699	struct smb_share **sspp, struct smb_cred *scred)
700{
701	struct smb_connobj *co;
702	struct smb_share *ssp = NULL;
703	int error = 0;
704
705	*sspp = NULL;
706
707	SMB_VC_LOCK(vcp);
708
709	/* var, head, next_field */
710	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
711		ssp = CPTOSS(co);
712
713		/* Share name */
714		if (u8_strcmp(ssp->ss_name, tcon->tc_sh.sh_name, 0,
715		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
716			continue;
717
718		/*
719		 * We have a match, but still have to check
720		 * the _GONE flag, and do that with a lock.
721		 * No new references when _GONE is set.
722		 *
723		 * Also clear SMBSOPT_CREATE which the caller
724		 * may check to find out if we did create.
725		 */
726		SMB_SS_LOCK(ssp);
727		if ((ssp->ss_flags & SMBS_GONE) == 0) {
728			tcon->tc_opt &= ~SMBSOPT_CREATE;
729			/*
730			 * Return it held, unlocked.
731			 * In-line smb_share_hold here.
732			 */
733			co->co_usecount++;
734			SMB_SS_UNLOCK(ssp);
735			*sspp = ssp;
736			error = 0;
737			goto out;
738		}
739		SMB_SS_UNLOCK(ssp);
740		/* keep looking. */
741	}
742	ssp = NULL;
743
744	/* Note: vcp (list of shares) is still locked. */
745
746	if (tcon->tc_opt & SMBSOPT_CREATE) {
747		/*
748		 * Create a new share.  It starts out with
749		 * hold count = 1, so don't incr. here.
750		 */
751		error = smb_share_create(tcon, vcp, &ssp, scred);
752		if (error == 0)
753			*sspp = ssp;
754	} else
755		error = ENOENT;
756
757out:
758	SMB_VC_UNLOCK(vcp);
759	return (error);
760}
761
762
763/*
764 * Helper functions that operate on shares
765 */
766
767/*
768 * Mark this share as invalid, so consumers will know
769 * their file handles have become invalid.
770 *
771 * Most share consumers store a copy of ss_vcgenid when
772 * opening a file handle and compare that with what's in
773 * the share before using a file handle.  If the genid
774 * doesn't match, the file handle has become "stale"
775 * due to disconnect.  Therefore, zap ss_vcgenid here.
776 */
777void
778smb_share_invalidate(struct smb_share *ssp)
779{
780
781	ASSERT(MUTEX_HELD(&ssp->ss_lock));
782
783	ssp->ss_flags &= ~SMBS_CONNECTED;
784	ssp->ss_tid = SMB_TID_UNKNOWN;
785	ssp->ss_vcgenid = 0;
786}
787
788/*
789 * Connect (or reconnect) a share object.
790 *
791 * Called by smb_usr_get_tree() for new connections,
792 * and called by smb_rq_enqueue() for reconnect.
793 */
794int
795smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
796{
797	smb_vc_t *vcp = SSTOVC(ssp);
798	clock_t tmo;
799	int error;
800
801	SMB_SS_LOCK(ssp);
802
803	if (ssp->ss_flags & SMBS_CONNECTED) {
804		SMBIODEBUG("alread connected?");
805		error = 0;
806		goto out;
807	}
808
809	/*
810	 * Wait for completion of any state changes
811	 * that might be underway.
812	 */
813	while (ssp->ss_flags & SMBS_RECONNECTING) {
814		ssp->ss_conn_waiters++;
815		tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock);
816		ssp->ss_conn_waiters--;
817		if (tmo == 0) {
818			/* Interrupt! */
819			error = EINTR;
820			goto out;
821		}
822	}
823
824	/* Did someone else do it for us? */
825	if (ssp->ss_flags & SMBS_CONNECTED) {
826		error = 0;
827		goto out;
828	}
829
830	/*
831	 * OK, we'll do the work.
832	 */
833	ssp->ss_flags |= SMBS_RECONNECTING;
834
835	/*
836	 * Drop the lock while doing the TCON.
837	 * On success, sets ss_tid, ss_vcgenid,
838	 * and ss_flags |= SMBS_CONNECTED;
839	 */
840	SMB_SS_UNLOCK(ssp);
841	if (vcp->vc_flags & SMBV_SMB2)
842		error = smb2_smb_treeconnect(ssp, scred);
843	else
844		error = smb_smb_treeconnect(ssp, scred);
845	SMB_SS_LOCK(ssp);
846
847	ssp->ss_flags &= ~SMBS_RECONNECTING;
848
849	/* They can all go ahead! */
850	if (ssp->ss_conn_waiters)
851		cv_broadcast(&ssp->ss_conn_done);
852
853out:
854	SMB_SS_UNLOCK(ssp);
855
856	return (error);
857}
858
859/*
860 * File handle level functions
861 */
862
863void
864smb_fh_hold(struct smb_fh *fhp)
865{
866	smb_co_hold(FHTOCP(fhp));
867}
868
869void
870smb_fh_rele(struct smb_fh *fhp)
871{
872	smb_co_rele(FHTOCP(fhp));
873}
874
875void
876smb_fh_close(struct smb_fh *fhp)
877{
878	smb_co_kill(FHTOCP(fhp));
879}
880
881/*
882 * Normally called via smb_fh_rele()
883 * after co_usecount drops to zero.
884 * Also called via: smb_fh_kill()
885 */
886static void
887smb_fh_gone(struct smb_connobj *cp)
888{
889	struct smb_cred scred;
890	struct smb_fh *fhp = CPTOFH(cp);
891	smb_share_t *ssp = FHTOSS(fhp);
892	int err;
893
894	if ((fhp->fh_flags & SMBFH_VALID) == 0)
895		return;
896
897	/*
898	 * We have no durable handles (yet) so if there has been a
899	 * reconnect, don't bother to close this handle.
900	 */
901	if (fhp->fh_vcgenid != ssp->ss_vcgenid)
902		return;
903
904	smb_credinit(&scred, NULL);
905	err = smb_smb_close(ssp, fhp, &scred);
906	smb_credrele(&scred);
907	if (err) {
908		SMBSDEBUG("close err=%d\n", err);
909	}
910}
911
912/*
913 * Normally called via smb_fh_rele()
914 * after co_usecount drops to zero.
915 */
916static void
917smb_fh_free(struct smb_connobj *cp)
918{
919	struct smb_fh *fhp = CPTOFH(cp);
920
921	smb_co_done(FHTOCP(fhp));
922	kmem_free(fhp, sizeof (*fhp));
923}
924
925/*
926 * Allocate fh structure and attach it to the given share.
927 * Share expected to be locked on entry.
928 */
929/*ARGSUSED*/
930int
931smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp)
932{
933	static char objtype[] = "smb_fh";
934	struct smb_fh *fhp;
935
936	fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP);
937	smb_co_init(FHTOCP(fhp), SMBL_FH, objtype);
938	fhp->fh_co.co_free = smb_fh_free;
939	fhp->fh_co.co_gone = smb_fh_gone;
940
941	SMB_SS_LOCK(ssp);
942	if ((ssp->ss_flags & SMBS_GONE) != 0) {
943		SMB_SS_UNLOCK(ssp);
944		smb_fh_free(FHTOCP(fhp));
945		return (ENOTCONN);
946	}
947
948	smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp));
949	*fhpp = fhp;
950	SMB_SS_UNLOCK(ssp);
951
952	return (0);
953}
954
955void
956smb_fh_opened(struct smb_fh *fhp)
957{
958	smb_share_t *ssp = FHTOSS(fhp);
959
960	SMB_FH_LOCK(fhp);
961	fhp->fh_vcgenid = ssp->ss_vcgenid;
962	fhp->fh_flags |= SMBFH_VALID;
963	SMB_FH_UNLOCK(fhp);
964}
965
966
967/*
968 * Solaris zones support
969 */
970/*ARGSUSED*/
971void
972lingering_vc(struct smb_vc *vc)
973{
974	/* good place for a breakpoint */
975	DEBUG_ENTER("lingering VC");
976}
977
978/*
979 * On zone shutdown, kill any IOD threads still running in this zone.
980 */
981/* ARGSUSED */
982void
983nsmb_zone_shutdown(zoneid_t zoneid, void *data)
984{
985	struct smb_connobj *co;
986	struct smb_vc *vcp;
987
988	SMB_CO_LOCK(&smb_vclist);
989	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
990		vcp = CPTOVC(co);
991
992		if (vcp->vc_zoneid != zoneid)
993			continue;
994
995		/*
996		 * This will close the connection, and
997		 * cause the IOD thread to terminate.
998		 */
999		smb_vc_kill(vcp);
1000	}
1001	SMB_CO_UNLOCK(&smb_vclist);
1002}
1003
1004/*
1005 * On zone destroy, kill any IOD threads and free all resources they used.
1006 */
1007/* ARGSUSED */
1008void
1009nsmb_zone_destroy(zoneid_t zoneid, void *data)
1010{
1011	struct smb_connobj *co;
1012	struct smb_vc *vcp;
1013
1014	/*
1015	 * We will repeat what should have already happened
1016	 * in zone_shutdown to make things go away.
1017	 *
1018	 * There should have been an smb_vc_rele call
1019	 * by now for all VCs in the zone.  If not,
1020	 * there's probably more we needed to do in
1021	 * the shutdown call.
1022	 */
1023
1024	SMB_CO_LOCK(&smb_vclist);
1025
1026	if (smb_vclist.co_usecount > 1) {
1027		SMBERROR("%d connections still active\n",
1028		    smb_vclist.co_usecount - 1);
1029	}
1030
1031	/* var, head, next_field */
1032	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
1033		vcp = CPTOVC(co);
1034
1035		if (vcp->vc_zoneid != zoneid)
1036			continue;
1037
1038		/* Debugging */
1039		lingering_vc(vcp);
1040	}
1041
1042	SMB_CO_UNLOCK(&smb_vclist);
1043}
1044