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