xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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 
72 static struct smb_connobj smb_vclist;
73 
74 void smb_co_init(struct smb_connobj *cp, int level, char *objname);
75 void smb_co_done(struct smb_connobj *cp);
76 void smb_co_hold(struct smb_connobj *cp);
77 void smb_co_rele(struct smb_connobj *cp);
78 void smb_co_kill(struct smb_connobj *cp);
79 
80 static void smb_vc_free(struct smb_connobj *cp);
81 static void smb_vc_gone(struct smb_connobj *cp);
82 
83 static void smb_share_free(struct smb_connobj *cp);
84 static void smb_share_gone(struct smb_connobj *cp);
85 
86 static void smb_fh_free(struct smb_connobj *cp);
87 static void smb_fh_gone(struct smb_connobj *cp);
88 
89 int
90 smb_sm_init(void)
91 {
92 	smb_co_init(&smb_vclist, SMBL_SM, "smbsm");
93 	return (0);
94 }
95 
96 int
97 smb_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 
110 void
111 smb_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*/
127 void
128 smb_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  */
143 void
144 smb_co_done(struct smb_connobj *cp)
145 {
146 	ASSERT(SLIST_EMPTY(&cp->co_children));
147 	mutex_destroy(&cp->co_lock);
148 }
149 
150 static void
151 smb_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 
172 void
173 smb_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  */
183 void
184 smb_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  */
281 void
282 smb_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 
309 void
310 smb_vc_hold(struct smb_vc *vcp)
311 {
312 	smb_co_hold(VCTOCP(vcp));
313 }
314 
315 void
316 smb_vc_rele(struct smb_vc *vcp)
317 {
318 	smb_co_rele(VCTOCP(vcp));
319 }
320 
321 void
322 smb_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*/
336 static void
337 smb_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  */
351 static void
352 smb_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*/
396 int
397 smb_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 
439 errout:
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*/
453 int
454 smb_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 
540 out:
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  */
555 void *
556 smb_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 
581 void
582 smb_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 
606 void
607 smb_share_hold(struct smb_share *ssp)
608 {
609 	smb_co_hold(SSTOCP(ssp));
610 }
611 
612 void
613 smb_share_rele(struct smb_share *ssp)
614 {
615 	smb_co_rele(SSTOCP(ssp));
616 }
617 
618 void
619 smb_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  */
629 static void
630 smb_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  */
649 static void
650 smb_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*/
665 int
666 smb_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 
697 int
698 smb_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 
757 out:
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  */
777 void
778 smb_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  */
794 int
795 smb_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 
853 out:
854 	SMB_SS_UNLOCK(ssp);
855 
856 	return (error);
857 }
858 
859 /*
860  * File handle level functions
861  */
862 
863 void
864 smb_fh_hold(struct smb_fh *fhp)
865 {
866 	smb_co_hold(FHTOCP(fhp));
867 }
868 
869 void
870 smb_fh_rele(struct smb_fh *fhp)
871 {
872 	smb_co_rele(FHTOCP(fhp));
873 }
874 
875 void
876 smb_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  */
886 static void
887 smb_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  */
916 static void
917 smb_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*/
930 int
931 smb_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 
955 void
956 smb_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*/
971 void
972 lingering_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 */
982 void
983 nsmb_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 */
1008 void
1009 nsmb_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