2 * Copyright (c) 2000-2001 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 * $Id: smb_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
35 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
36 * Use is subject to license terms.
43 #include <sys/param.h>
44 #include <sys/systm.h>
48 #include <sys/vnode.h>
49 #include <sys/stream.h>
50 #include <sys/stropts.h>
51 #include <sys/socketvar.h>
53 #include <netinet/in.h>
56 #include <sys/cmn_err.h>
57 #include <sys/thread.h>
58 #include <sys/atomic.h>
59 #include <sys/u8_textprep.h>
61 #include <netsmb/smb_osdep.h>
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>
69 static struct smb_connobj smb_vclist
;
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
);
77 static void smb_vc_free(struct smb_connobj
*cp
);
78 static void smb_vc_gone(struct smb_connobj
*cp
);
80 static void smb_share_free(struct smb_connobj
*cp
);
81 static void smb_share_gone(struct smb_connobj
*cp
);
86 smb_co_init(&smb_vclist
, SMBL_SM
, "smbsm");
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);
100 SMB_CO_UNLOCK(&smb_vclist
);
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.
112 smb_co_done(&smb_vclist
);
118 * Common code for connection object
122 smb_co_init(struct smb_connobj
*cp
, int level
, char *objname
)
125 mutex_init(&cp
->co_lock
, objname
, MUTEX_DRIVER
, NULL
);
127 cp
->co_level
= level
;
129 SLIST_INIT(&cp
->co_children
);
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.
138 smb_co_done(struct smb_connobj
*cp
)
140 ASSERT(SLIST_EMPTY(&cp
->co_children
));
141 mutex_destroy(&cp
->co_lock
);
146 struct smb_connobj
*parent
,
147 struct smb_connobj
*child
)
151 * Set the child's pointer to the parent.
152 * No references yet, so no need to lock.
154 ASSERT(child
->co_usecount
== 1);
155 child
->co_parent
= parent
;
158 * Add the child to the parent's list of
159 * children, and in-line smb_co_hold
161 ASSERT(MUTEX_HELD(&parent
->co_lock
));
162 parent
->co_usecount
++;
163 SLIST_INSERT_HEAD(&parent
->co_children
, child
, co_next
);
167 smb_co_hold(struct smb_connobj
*cp
)
175 * Called via smb_vc_rele, smb_share_rele
178 smb_co_rele(struct smb_connobj
*co
)
180 struct smb_connobj
*parent
;
184 if (co
->co_usecount
> 1) {
189 ASSERT(co
->co_usecount
== 1);
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.
197 ASSERT(SLIST_EMPTY(&co
->co_children
));
200 * OK, this element is going away.
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
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.
214 * Note the old: smb_co_gone(co, scred);
215 * is now in-line here.
217 old_flags
= co
->co_flags
;
218 co
->co_flags
|= SMBO_GONE
;
221 if ((old_flags
& SMBO_GONE
) == 0 && co
->co_gone
)
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.
229 parent
= co
->co_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
);
237 SMB_CO_UNLOCK(parent
);
241 * Now it's safe to free the CO
248 * Finally, if the CO had a parent, decrement
249 * the parent's hold count for the lost child.
253 * Recursive call here (easier for debugging).
254 * Can only go two levels.
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.
266 smb_co_kill(struct smb_connobj
*co
)
271 old_flags
= co
->co_flags
;
272 co
->co_flags
|= SMBO_GONE
;
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.
280 if ((old_flags
& SMBO_GONE
) == 0 && co
->co_gone
)
283 /* XXX: Walk list of children and kill those too? */
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
294 smb_vc_hold(struct smb_vc
*vcp
)
296 smb_co_hold(VCTOCP(vcp
));
300 smb_vc_rele(struct smb_vc
*vcp
)
302 smb_co_rele(VCTOCP(vcp
));
306 smb_vc_kill(struct smb_vc
*vcp
)
308 smb_co_kill(VCTOCP(vcp
));
312 * Normally called via smb_vc_rele()
313 * after co_usecount drops to zero.
314 * Also called via: smb_vc_kill()
316 * Shutdown the VC to this server,
317 * invalidate shares linked with it.
321 smb_vc_gone(struct smb_connobj
*cp
)
323 struct smb_vc
*vcp
= CPTOVC(cp
);
326 * Was smb_vc_disconnect(vcp);
328 smb_iod_disconnect(vcp
);
332 * The VC has no more references. Free it.
333 * No locks needed here.
336 smb_vc_free(struct smb_connobj
*cp
)
338 struct smb_vc
*vcp
= CPTOVC(cp
);
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.)
346 ASSERT(vcp
->iod_rqlist
.tqh_first
== NULL
);
352 * We are not using the iconv routines here. So commenting them for now.
357 iconv_close(vcp
->vc_tolower
);
359 iconv_close(vcp
->vc_toupper
);
361 iconv_close(vcp
->vc_tolocal
);
362 if (vcp
->vc_toserver
)
363 iconv_close(vcp
->vc_toserver
);
366 if (vcp
->vc_mackey
!= NULL
)
367 kmem_free(vcp
->vc_mackey
, vcp
->vc_mackeylen
);
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
));
379 smb_vc_create(smbioc_ossn_t
*ossn
, smb_cred_t
*scred
, smb_vc_t
**vcpp
)
381 static char objtype
[] = "smb_vc";
382 cred_t
*cr
= scred
->scr_cred
;
386 ASSERT(MUTEX_HELD(&smb_vclist
.co_lock
));
388 vcp
= kmem_zalloc(sizeof (struct smb_vc
), KM_SLEEP
);
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
;
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
);
399 /* Expanded TAILQ_HEAD_INITIALIZER */
400 vcp
->iod_rqlist
.tqh_last
= &vcp
->iod_rqlist
.tqh_first
;
402 vcp
->vc_state
= SMBIOD_ST_IDLE
;
405 * These identify the connection.
407 vcp
->vc_zoneid
= getzoneid();
408 bcopy(ossn
, &vcp
->vc_ssn
, sizeof (*ossn
));
410 /* This fills in vcp->vc_tdata */
411 vcp
->vc_tdesc
= &smb_tran_nbtcp_desc
;
412 if ((error
= SMB_TRAN_CREATE(vcp
, cr
)) != 0)
416 smb_co_addchild(&smb_vclist
, VCTOCP(vcp
));
422 * This will destroy the new vc.
430 * Find or create a VC identified by the info in ossn
431 * and return it with a "hold", but not locked.
435 smb_vc_findcreate(smbioc_ossn_t
*ossn
, smb_cred_t
*scred
, smb_vc_t
**vcpp
)
437 struct smb_connobj
*co
;
439 smbioc_ssn_ident_t
*vc_id
;
441 zoneid_t zoneid
= getzoneid();
445 SMB_CO_LOCK(&smb_vclist
);
447 /* var, head, next_field */
448 SLIST_FOREACH(co
, &smb_vclist
.co_children
, co_next
) {
452 * Some things we can check without
453 * holding the lock (those that are
454 * set at creation and never change).
457 /* VCs in other zones are invisibile. */
458 if (vcp
->vc_zoneid
!= zoneid
)
461 /* Also segregate by Unix owner. */
462 if (vcp
->vc_owner
!= ossn
->ssn_owner
)
466 * Compare identifying info:
467 * server address, user, domain
468 * names are case-insensitive
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
)))
475 if (u8_strcmp(vc_id
->id_user
, ossn
->ssn_id
.id_user
, 0,
476 U8_STRCMP_CI_LOWER
, U8_UNICODE_LATEST
, &error
))
478 if (u8_strcmp(vc_id
->id_domain
, ossn
->ssn_id
.id_domain
, 0,
479 U8_STRCMP_CI_LOWER
, U8_UNICODE_LATEST
, &error
))
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.
487 * Also clear SMBVOPT_CREATE which the caller
488 * may check to find out if we did create.
491 if ((vcp
->vc_flags
& SMBV_GONE
) == 0) {
492 ossn
->ssn_vopt
&= ~SMBVOPT_CREATE
;
494 * Return it held, unlocked.
495 * In-line smb_vc_hold here.
508 /* Note: smb_vclist is still locked. */
510 if (ossn
->ssn_vopt
& SMBVOPT_CREATE
) {
512 * Create a new VC. It starts out with
513 * hold count = 1, so don't incr. here.
515 error
= smb_vc_create(ossn
, scred
, &vcp
);
522 SMB_CO_UNLOCK(&smb_vclist
);
528 * Helper functions that operate on VCs
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.
537 smb_vc_getipaddr(struct smb_vc
*vcp
, int *ipvers
)
539 smbioc_ssn_ident_t
*id
= &vcp
->vc_ssn
.ssn_id
;
542 switch (id
->id_srvaddr
.sa
.sa_family
) {
544 *ipvers
= IPV4_VERSION
;
545 ret
= &id
->id_srvaddr
.sin
.sin_addr
;
549 *ipvers
= IPV6_VERSION
;
550 ret
= &id
->id_srvaddr
.sin6
.sin6_addr
;
553 SMBSDEBUG("invalid address family %d\n",
554 id
->id_srvaddr
.sa
.sa_family
);
563 smb_vc_walkshares(struct smb_vc
*vcp
,
564 walk_share_func_t func
)
570 * Walk the share list calling func(ssp, arg)
573 SLIST_FOREACH(co
, &(VCTOCP(vcp
)->co_children
), co_next
) {
584 * Share implementation
588 smb_share_hold(struct smb_share
*ssp
)
590 smb_co_hold(SSTOCP(ssp
));
594 smb_share_rele(struct smb_share
*ssp
)
596 smb_co_rele(SSTOCP(ssp
));
600 smb_share_kill(struct smb_share
*ssp
)
602 smb_co_kill(SSTOCP(ssp
));
606 * Normally called via smb_share_rele()
607 * after co_usecount drops to zero.
608 * Also called via: smb_share_kill()
611 smb_share_gone(struct smb_connobj
*cp
)
613 struct smb_cred scred
;
614 struct smb_share
*ssp
= CPTOSS(cp
);
616 smb_credinit(&scred
, NULL
);
617 smb_iod_shutdown_share(ssp
);
618 (void) smb_smb_treedisconnect(ssp
, &scred
);
619 smb_credrele(&scred
);
623 * Normally called via smb_share_rele()
624 * after co_usecount drops to zero.
627 smb_share_free(struct smb_connobj
*cp
)
629 struct smb_share
*ssp
= CPTOSS(cp
);
631 cv_destroy(&ssp
->ss_conn_done
);
632 smb_co_done(SSTOCP(ssp
));
633 kmem_free(ssp
, sizeof (*ssp
));
637 * Allocate share structure and attach it to the given VC
638 * Connection expected to be locked on entry. Share will be returned
643 smb_share_create(smbioc_tcon_t
*tcon
, struct smb_vc
*vcp
,
644 struct smb_share
**sspp
, struct smb_cred
*scred
)
646 static char objtype
[] = "smb_ss";
647 struct smb_share
*ssp
;
649 ASSERT(MUTEX_HELD(&vcp
->vc_lock
));
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
;
656 cv_init(&ssp
->ss_conn_done
, objtype
, CV_DRIVER
, NULL
);
657 ssp
->ss_tid
= SMB_TID_UNKNOWN
;
659 bcopy(&tcon
->tc_sh
, &ssp
->ss_ioc
,
660 sizeof (smbioc_oshare_t
));
662 smb_co_addchild(VCTOCP(vcp
), SSTOCP(ssp
));
669 * Find or create a share under the given VC
670 * and return it with a "hold", but not locked.
674 smb_share_findcreate(smbioc_tcon_t
*tcon
, struct smb_vc
*vcp
,
675 struct smb_share
**sspp
, struct smb_cred
*scred
)
677 struct smb_connobj
*co
;
678 struct smb_share
*ssp
= NULL
;
685 /* var, head, next_field */
686 SLIST_FOREACH(co
, &(VCTOCP(vcp
)->co_children
), co_next
) {
690 if (u8_strcmp(ssp
->ss_name
, tcon
->tc_sh
.sh_name
, 0,
691 U8_STRCMP_CI_LOWER
, U8_UNICODE_LATEST
, &error
))
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.
699 * Also clear SMBSOPT_CREATE which the caller
700 * may check to find out if we did create.
703 if ((ssp
->ss_flags
& SMBS_GONE
) == 0) {
704 tcon
->tc_opt
&= ~SMBSOPT_CREATE
;
706 * Return it held, unlocked.
707 * In-line smb_share_hold here.
720 /* Note: vcp (list of shares) is still locked. */
722 if (tcon
->tc_opt
& SMBSOPT_CREATE
) {
724 * Create a new share. It starts out with
725 * hold count = 1, so don't incr. here.
727 error
= smb_share_create(tcon
, vcp
, &ssp
, scred
);
740 * Helper functions that operate on shares
744 * Mark this share as invalid, so consumers will know
745 * their file handles have become invalid.
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.
754 smb_share_invalidate(struct smb_share
*ssp
)
757 ASSERT(MUTEX_HELD(&ssp
->ss_lock
));
759 ssp
->ss_flags
&= ~SMBS_CONNECTED
;
760 ssp
->ss_tid
= SMB_TID_UNKNOWN
;
765 * Connect (or reconnect) a share object.
767 * Called by smb_usr_get_tree() for new connections,
768 * and called by smb_rq_enqueue() for reconnect.
771 smb_share_tcon(smb_share_t
*ssp
, smb_cred_t
*scred
)
778 if (ssp
->ss_flags
& SMBS_CONNECTED
) {
779 SMBIODEBUG("alread connected?");
785 * Wait for completion of any state changes
786 * that might be underway.
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
--;
799 /* Did someone else do it for us? */
800 if (ssp
->ss_flags
& SMBS_CONNECTED
) {
806 * OK, we'll do the work.
808 ssp
->ss_flags
|= SMBS_RECONNECTING
;
811 * Drop the lock while doing the TCON.
812 * On success, sets ss_tid, ss_vcgenid,
813 * and ss_flags |= SMBS_CONNECTED;
816 error
= smb_smb_treeconnect(ssp
, scred
);
819 ssp
->ss_flags
&= ~SMBS_RECONNECTING
;
821 /* They can all go ahead! */
822 if (ssp
->ss_conn_waiters
)
823 cv_broadcast(&ssp
->ss_conn_done
);
832 * Solaris zones support
836 lingering_vc(struct smb_vc
*vc
)
838 /* good place for a breakpoint */
839 DEBUG_ENTER("lingering VC");
843 * On zone shutdown, kill any IOD threads still running in this zone.
847 nsmb_zone_shutdown(zoneid_t zoneid
, void *data
)
849 struct smb_connobj
*co
;
852 SMB_CO_LOCK(&smb_vclist
);
853 SLIST_FOREACH(co
, &smb_vclist
.co_children
, co_next
) {
856 if (vcp
->vc_zoneid
!= zoneid
)
860 * This will close the connection, and
861 * cause the IOD thread to terminate.
865 SMB_CO_UNLOCK(&smb_vclist
);
869 * On zone destroy, kill any IOD threads and free all resources they used.
873 nsmb_zone_destroy(zoneid_t zoneid
, void *data
)
875 struct smb_connobj
*co
;
879 * We will repeat what should have already happened
880 * in zone_shutdown to make things go away.
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
888 SMB_CO_LOCK(&smb_vclist
);
890 if (smb_vclist
.co_usecount
> 1) {
891 SMBERROR("%d connections still active\n",
892 smb_vclist
.co_usecount
- 1);
895 /* var, head, next_field */
896 SLIST_FOREACH(co
, &smb_vclist
.co_children
, co_next
) {
899 if (vcp
->vc_zoneid
!= zoneid
)
906 SMB_CO_UNLOCK(&smb_vclist
);