--- old/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c	Mon Aug  5 17:26:11 2019
+++ new/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c	Mon Aug  5 17:26:11 2019
@@ -34,6 +34,8 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -61,6 +63,7 @@
 #include <netsmb/smb_osdep.h>
 
 #include <netsmb/smb.h>
+#include <netsmb/smb2.h>
 #include <netsmb/smb_conn.h>
 #include <netsmb/smb_subr.h>
 #include <netsmb/smb_tran.h>
@@ -80,6 +83,9 @@
 static void smb_share_free(struct smb_connobj *cp);
 static void smb_share_gone(struct smb_connobj *cp);
 
+static void smb_fh_free(struct smb_connobj *cp);
+static void smb_fh_gone(struct smb_connobj *cp);
+
 int
 smb_sm_init(void)
 {
@@ -105,7 +111,7 @@
 smb_sm_done(void)
 {
 	/*
-	 * XXX Q4BP why are we not iterating on smb_vclist here?
+	 * Why are we not iterating on smb_vclist here?
 	 * Because the caller has just called smb_sm_idle() to
 	 * make sure we have no VCs before calling this.
 	 */
@@ -181,6 +187,16 @@
 	int old_flags;
 
 	SMB_CO_LOCK(co);
+
+	/*
+	 * When VC usecount goes from 2 to 1, signal the iod_idle CV.
+	 * It's unfortunate to have object type-specific logic here,
+	 * but it's hard to do this anywhere else.
+	 */
+	if (co->co_level == SMBL_VC && co->co_usecount == 2) {
+		smb_vc_t *vcp = CPTOVC(co);
+		cv_signal(&vcp->iod_idle);
+	}
 	if (co->co_usecount > 1) {
 		co->co_usecount--;
 		SMB_CO_UNLOCK(co);
@@ -365,10 +381,12 @@
 
 	if (vcp->vc_mackey != NULL)
 		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+	if (vcp->vc_ssnkey != NULL)
+		kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
 
+	cv_destroy(&vcp->iod_muxwait);
 	cv_destroy(&vcp->iod_idle);
 	rw_destroy(&vcp->iod_rqlock);
-	sema_destroy(&vcp->vc_sendlock);
 	cv_destroy(&vcp->vc_statechg);
 	smb_co_done(VCTOCP(vcp));
 	kmem_free(vcp, sizeof (*vcp));
@@ -392,14 +410,15 @@
 	vcp->vc_co.co_gone = smb_vc_gone;
 
 	cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
-	sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
 	rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
 	cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
+	cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL);
 
 	/* Expanded TAILQ_HEAD_INITIALIZER */
 	vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
 
-	vcp->vc_state = SMBIOD_ST_IDLE;
+	/* A brand new VC should connect. */
+	vcp->vc_state = SMBIOD_ST_RECONNECT;
 
 	/*
 	 * These identify the connection.
@@ -612,10 +631,14 @@
 {
 	struct smb_cred scred;
 	struct smb_share *ssp = CPTOSS(cp);
+	smb_vc_t *vcp = SSTOVC(ssp);
 
 	smb_credinit(&scred, NULL);
 	smb_iod_shutdown_share(ssp);
-	(void) smb_smb_treedisconnect(ssp, &scred);
+	if (vcp->vc_flags & SMBV_SMB2)
+		(void) smb2_smb_treedisconnect(ssp, &scred);
+	else
+		(void) smb_smb_treedisconnect(ssp, &scred);
 	smb_credrele(&scred);
 }
 
@@ -655,6 +678,7 @@
 
 	cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
 	ssp->ss_tid = SMB_TID_UNKNOWN;
+	ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
 
 	bcopy(&tcon->tc_sh, &ssp->ss_ioc,
 	    sizeof (smbioc_oshare_t));
@@ -770,6 +794,7 @@
 int
 smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
 {
+	smb_vc_t *vcp = SSTOVC(ssp);
 	clock_t tmo;
 	int error;
 
@@ -813,7 +838,10 @@
 	 * and ss_flags |= SMBS_CONNECTED;
 	 */
 	SMB_SS_UNLOCK(ssp);
-	error = smb_smb_treeconnect(ssp, scred);
+	if (vcp->vc_flags & SMBV_SMB2)
+		error = smb2_smb_treeconnect(ssp, scred);
+	else
+		error = smb_smb_treeconnect(ssp, scred);
 	SMB_SS_LOCK(ssp);
 
 	ssp->ss_flags &= ~SMBS_RECONNECTING;
@@ -829,6 +857,114 @@
 }
 
 /*
+ * File handle level functions
+ */
+
+void
+smb_fh_hold(struct smb_fh *fhp)
+{
+	smb_co_hold(FHTOCP(fhp));
+}
+
+void
+smb_fh_rele(struct smb_fh *fhp)
+{
+	smb_co_rele(FHTOCP(fhp));
+}
+
+void
+smb_fh_close(struct smb_fh *fhp)
+{
+	smb_co_kill(FHTOCP(fhp));
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ * Also called via: smb_fh_kill()
+ */
+static void
+smb_fh_gone(struct smb_connobj *cp)
+{
+	struct smb_cred scred;
+	struct smb_fh *fhp = CPTOFH(cp);
+	smb_share_t *ssp = FHTOSS(fhp);
+	int err;
+
+	if ((fhp->fh_flags & SMBFH_VALID) == 0)
+		return;
+
+	/*
+	 * We have no durable handles (yet) so if there has been a
+	 * reconnect, don't bother to close this handle.
+	 */
+	if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+		return;
+
+	smb_credinit(&scred, NULL);
+	err = smb_smb_close(ssp, fhp, &scred);
+	smb_credrele(&scred);
+	if (err) {
+		SMBSDEBUG("close err=%d\n", err);
+	}
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ */
+static void
+smb_fh_free(struct smb_connobj *cp)
+{
+	struct smb_fh *fhp = CPTOFH(cp);
+
+	smb_co_done(FHTOCP(fhp));
+	kmem_free(fhp, sizeof (*fhp));
+}
+
+/*
+ * Allocate fh structure and attach it to the given share.
+ * Share expected to be locked on entry.
+ */
+/*ARGSUSED*/
+int
+smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp)
+{
+	static char objtype[] = "smb_fh";
+	struct smb_fh *fhp;
+
+	fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP);
+	smb_co_init(FHTOCP(fhp), SMBL_FH, objtype);
+	fhp->fh_co.co_free = smb_fh_free;
+	fhp->fh_co.co_gone = smb_fh_gone;
+
+	SMB_SS_LOCK(ssp);
+	if ((ssp->ss_flags & SMBS_GONE) != 0) {
+		SMB_SS_UNLOCK(ssp);
+		smb_fh_free(FHTOCP(fhp));
+		return (ENOTCONN);
+	}
+
+	smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp));
+	*fhpp = fhp;
+	SMB_SS_UNLOCK(ssp);
+
+	return (0);
+}
+
+void
+smb_fh_opened(struct smb_fh *fhp)
+{
+	smb_share_t *ssp = FHTOSS(fhp);
+
+	SMB_FH_LOCK(fhp);
+	fhp->fh_vcgenid = ssp->ss_vcgenid;
+	fhp->fh_flags |= SMBFH_VALID;
+	SMB_FH_UNLOCK(fhp);
+}
+
+
+/*
  * Solaris zones support
  */
 /*ARGSUSED*/
