SMB2: Separate RawNTLMSSP authentication from SMB2_sess_setup
[cascardo/linux.git] / fs / cifs / smb2pdu.c
index 29e06db..5ca5ea4 100644 (file)
@@ -100,7 +100,21 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
        hdr->ProtocolId = SMB2_PROTO_NUMBER;
        hdr->StructureSize = cpu_to_le16(64);
        hdr->Command = smb2_cmd;
-       hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */
+       if (tcon && tcon->ses && tcon->ses->server) {
+               struct TCP_Server_Info *server = tcon->ses->server;
+
+               spin_lock(&server->req_lock);
+               /* Request up to 2 credits but don't go over the limit. */
+               if (server->credits >= server->max_credits)
+                       hdr->CreditRequest = cpu_to_le16(0);
+               else
+                       hdr->CreditRequest = cpu_to_le16(
+                               min_t(int, server->max_credits -
+                                               server->credits, 2));
+               spin_unlock(&server->req_lock);
+       } else {
+               hdr->CreditRequest = cpu_to_le16(2);
+       }
        hdr->ProcessId = cpu_to_le32((__u16)current->tgid);
 
        if (!tcon)
@@ -236,8 +250,13 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
        }
 
        cifs_mark_open_files_invalid(tcon);
+
        rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
        mutex_unlock(&tcon->ses->session_mutex);
+
+       if (tcon->use_persistent)
+               cifs_reopen_persistent_handles(tcon);
+
        cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
        if (rc)
                goto out;
@@ -574,59 +593,42 @@ vneg_out:
        return -EIO;
 }
 
-int
-SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
-               const struct nls_table *nls_cp)
+struct SMB2_sess_data {
+       unsigned int xid;
+       struct cifs_ses *ses;
+       struct nls_table *nls_cp;
+       void (*func)(struct SMB2_sess_data *);
+       int result;
+       u64 previous_session;
+
+       /* we will send the SMB in three pieces:
+        * a fixed length beginning part, an optional
+        * SPNEGO blob (which can be zero length), and a
+        * last part which will include the strings
+        * and rest of bcc area. This allows us to avoid
+        * a large buffer 17K allocation
+        */
+       int buf0_type;
+       struct kvec iov[2];
+};
+
+static int
+SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
 {
+       int rc;
+       struct cifs_ses *ses = sess_data->ses;
        struct smb2_sess_setup_req *req;
-       struct smb2_sess_setup_rsp *rsp = NULL;
-       struct kvec iov[2];
-       int rc = 0;
-       int resp_buftype = CIFS_NO_BUFFER;
-       __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
        struct TCP_Server_Info *server = ses->server;
-       u16 blob_length = 0;
-       struct key *spnego_key = NULL;
-       char *security_blob = NULL;
-       unsigned char *ntlmssp_blob = NULL;
-       bool use_spnego = false; /* else use raw ntlmssp */
-
-       cifs_dbg(FYI, "Session Setup\n");
-
-       if (!server) {
-               WARN(1, "%s: server is NULL!\n", __func__);
-               return -EIO;
-       }
-
-       /*
-        * If we are here due to reconnect, free per-smb session key
-        * in case signing was required.
-        */
-       kfree(ses->auth_key.response);
-       ses->auth_key.response = NULL;
-
-       /*
-        * If memory allocation is successful, caller of this function
-        * frees it.
-        */
-       ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
-       if (!ses->ntlmssp)
-               return -ENOMEM;
-       ses->ntlmssp->sesskey_per_smbsess = true;
-
-       /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */
-       if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP)
-               ses->sectype = RawNTLMSSP;
-
-ssetup_ntlmssp_authenticate:
-       if (phase == NtLmChallenge)
-               phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
 
        rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &req);
        if (rc)
                return rc;
 
        req->hdr.SessionId = 0; /* First session, not a reauthenticate */
+
+       /* if reconnect, we need to send previous sess id, otherwise it is 0 */
+       req->PreviousSessionId = sess_data->previous_session;
+
        req->Flags = 0; /* MBZ */
        /* to enable echos and oplocks */
        req->hdr.CreditRequest = cpu_to_le16(3);
@@ -642,199 +644,368 @@ ssetup_ntlmssp_authenticate:
        req->Capabilities = 0;
        req->Channel = 0; /* MBZ */
 
-       iov[0].iov_base = (char *)req;
+       sess_data->iov[0].iov_base = (char *)req;
        /* 4 for rfc1002 length field and 1 for pad */
-       iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+       sess_data->iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+       /*
+        * This variable will be used to clear the buffer
+        * allocated above in case of any error in the calling function.
+        */
+       sess_data->buf0_type = CIFS_SMALL_BUFFER;
 
-       if (ses->sectype == Kerberos) {
-#ifdef CONFIG_CIFS_UPCALL
-               struct cifs_spnego_msg *msg;
+       return 0;
+}
 
-               spnego_key = cifs_get_spnego_key(ses);
-               if (IS_ERR(spnego_key)) {
-                       rc = PTR_ERR(spnego_key);
-                       spnego_key = NULL;
-                       goto ssetup_exit;
-               }
+static void
+SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data)
+{
+       free_rsp_buf(sess_data->buf0_type, sess_data->iov[0].iov_base);
+       sess_data->buf0_type = CIFS_NO_BUFFER;
+}
 
-               msg = spnego_key->payload.data[0];
-               /*
-                * check version field to make sure that cifs.upcall is
-                * sending us a response in an expected form
-                */
-               if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
-                       cifs_dbg(VFS,
-                                 "bad cifs.upcall version. Expected %d got %d",
-                                 CIFS_SPNEGO_UPCALL_VERSION, msg->version);
-                       rc = -EKEYREJECTED;
-                       goto ssetup_exit;
-               }
-               ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
-                                                GFP_KERNEL);
-               if (!ses->auth_key.response) {
-                       cifs_dbg(VFS,
-                               "Kerberos can't allocate (%u bytes) memory",
-                               msg->sesskey_len);
-                       rc = -ENOMEM;
-                       goto ssetup_exit;
-               }
-               ses->auth_key.len = msg->sesskey_len;
-               blob_length = msg->secblob_len;
-               iov[1].iov_base = msg->data + msg->sesskey_len;
-               iov[1].iov_len = blob_length;
-#else
-               rc = -EOPNOTSUPP;
-               goto ssetup_exit;
-#endif /* CONFIG_CIFS_UPCALL */
-       } else if (phase == NtLmNegotiate) { /* if not krb5 must be ntlmssp */
-               ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
-                                      GFP_KERNEL);
-               if (ntlmssp_blob == NULL) {
-                       rc = -ENOMEM;
-                       goto ssetup_exit;
-               }
-               build_ntlmssp_negotiate_blob(ntlmssp_blob, ses);
-               if (use_spnego) {
-                       /* blob_length = build_spnego_ntlmssp_blob(
-                                       &security_blob,
-                                       sizeof(struct _NEGOTIATE_MESSAGE),
-                                       ntlmssp_blob); */
-                       /* BB eventually need to add this */
-                       cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
-                       rc = -EOPNOTSUPP;
-                       kfree(ntlmssp_blob);
-                       goto ssetup_exit;
-               } else {
-                       blob_length = sizeof(struct _NEGOTIATE_MESSAGE);
-                       /* with raw NTLMSSP we don't encapsulate in SPNEGO */
-                       security_blob = ntlmssp_blob;
-               }
-               iov[1].iov_base = security_blob;
-               iov[1].iov_len = blob_length;
-       } else if (phase == NtLmAuthenticate) {
-               req->hdr.SessionId = ses->Suid;
-               rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses,
-                                            nls_cp);
-               if (rc) {
-                       cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n",
-                                rc);
-                       goto ssetup_exit; /* BB double check error handling */
-               }
-               if (use_spnego) {
-                       /* blob_length = build_spnego_ntlmssp_blob(
-                                                       &security_blob,
-                                                       blob_length,
-                                                       ntlmssp_blob); */
-                       cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
-                       rc = -EOPNOTSUPP;
-                       kfree(ntlmssp_blob);
-                       goto ssetup_exit;
-               } else {
-                       security_blob = ntlmssp_blob;
-               }
-               iov[1].iov_base = security_blob;
-               iov[1].iov_len = blob_length;
-       } else {
-               cifs_dbg(VFS, "illegal ntlmssp phase\n");
-               rc = -EIO;
-               goto ssetup_exit;
-       }
+static int
+SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
+{
+       int rc;
+       struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base;
 
        /* Testing shows that buffer offset must be at location of Buffer[0] */
        req->SecurityBufferOffset =
-                               cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
-                                           1 /* pad */ - 4 /* rfc1001 len */);
-       req->SecurityBufferLength = cpu_to_le16(blob_length);
+               cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
+                       1 /* pad */ - 4 /* rfc1001 len */);
+       req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len);
 
-       inc_rfc1001_len(req, blob_length - 1 /* pad */);
+       inc_rfc1001_len(req, sess_data->iov[1].iov_len - 1 /* pad */);
 
        /* BB add code to build os and lm fields */
 
-       rc = SendReceive2(xid, ses, iov, 2, &resp_buftype,
-                         CIFS_LOG_ERROR | CIFS_NEG_OP);
+       rc = SendReceive2(sess_data->xid, sess_data->ses,
+                               sess_data->iov, 2,
+                               &sess_data->buf0_type,
+                               CIFS_LOG_ERROR | CIFS_NEG_OP);
 
-       kfree(security_blob);
-       rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
-       ses->Suid = rsp->hdr.SessionId;
-       if (resp_buftype != CIFS_NO_BUFFER &&
-           rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
-               if (phase != NtLmNegotiate) {
-                       cifs_dbg(VFS, "Unexpected more processing error\n");
-                       goto ssetup_exit;
-               }
-               if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 !=
-                               le16_to_cpu(rsp->SecurityBufferOffset)) {
-                       cifs_dbg(VFS, "Invalid security buffer offset %d\n",
-                                le16_to_cpu(rsp->SecurityBufferOffset));
-                       rc = -EIO;
-                       goto ssetup_exit;
+       return rc;
+}
+
+static int
+SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
+{
+       int rc = 0;
+       struct cifs_ses *ses = sess_data->ses;
+
+       mutex_lock(&ses->server->srv_mutex);
+       if (ses->server->sign && ses->server->ops->generate_signingkey) {
+               rc = ses->server->ops->generate_signingkey(ses);
+               kfree(ses->auth_key.response);
+               ses->auth_key.response = NULL;
+               if (rc) {
+                       cifs_dbg(FYI,
+                               "SMB3 session key generation failed\n");
+                       mutex_unlock(&ses->server->srv_mutex);
+                       goto keygen_exit;
                }
+       }
+       if (!ses->server->session_estab) {
+               ses->server->sequence_number = 0x2;
+               ses->server->session_estab = true;
+       }
+       mutex_unlock(&ses->server->srv_mutex);
+
+       cifs_dbg(FYI, "SMB2/3 session established successfully\n");
+       spin_lock(&GlobalMid_Lock);
+       ses->status = CifsGood;
+       ses->need_reconnect = false;
+       spin_unlock(&GlobalMid_Lock);
 
-               /* NTLMSSP Negotiate sent now processing challenge (response) */
-               phase = NtLmChallenge; /* process ntlmssp challenge */
-               rc = 0; /* MORE_PROCESSING is not an error here but expected */
-               rc = decode_ntlmssp_challenge(rsp->Buffer,
-                               le16_to_cpu(rsp->SecurityBufferLength), ses);
+keygen_exit:
+       if (!ses->server->sign) {
+               kfree(ses->auth_key.response);
+               ses->auth_key.response = NULL;
+       }
+       return rc;
+}
+
+#ifdef CONFIG_CIFS_UPCALL
+static void
+SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
+{
+       int rc;
+       struct cifs_ses *ses = sess_data->ses;
+       struct cifs_spnego_msg *msg;
+       struct key *spnego_key = NULL;
+       struct smb2_sess_setup_rsp *rsp = NULL;
+
+       rc = SMB2_sess_alloc_buffer(sess_data);
+       if (rc)
+               goto out;
+
+       spnego_key = cifs_get_spnego_key(ses);
+       if (IS_ERR(spnego_key)) {
+               rc = PTR_ERR(spnego_key);
+               spnego_key = NULL;
+               goto out;
        }
 
+       msg = spnego_key->payload.data[0];
        /*
-        * BB eventually add code for SPNEGO decoding of NtlmChallenge blob,
-        * but at least the raw NTLMSSP case works.
+        * check version field to make sure that cifs.upcall is
+        * sending us a response in an expected form
         */
+       if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
+               cifs_dbg(VFS,
+                         "bad cifs.upcall version. Expected %d got %d",
+                         CIFS_SPNEGO_UPCALL_VERSION, msg->version);
+               rc = -EKEYREJECTED;
+               goto out_put_spnego_key;
+       }
+
+       ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
+                                        GFP_KERNEL);
+       if (!ses->auth_key.response) {
+               cifs_dbg(VFS,
+                       "Kerberos can't allocate (%u bytes) memory",
+                       msg->sesskey_len);
+               rc = -ENOMEM;
+               goto out_put_spnego_key;
+       }
+       ses->auth_key.len = msg->sesskey_len;
+
+       sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
+       sess_data->iov[1].iov_len = msg->secblob_len;
+
+       rc = SMB2_sess_sendreceive(sess_data);
+       if (rc)
+               goto out_put_spnego_key;
+
+       rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+       ses->Suid = rsp->hdr.SessionId;
+
+       ses->session_flags = le16_to_cpu(rsp->SessionFlags);
+       if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
+               cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
+
+       rc = SMB2_sess_establish_session(sess_data);
+out_put_spnego_key:
+       key_invalidate(spnego_key);
+       key_put(spnego_key);
+out:
+       sess_data->result = rc;
+       sess_data->func = NULL;
+       SMB2_sess_free_buffer(sess_data);
+}
+#else
+static void
+SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
+{
+       cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
+       sess_data->result = -EOPNOTSUPP;
+       sess_data->func = NULL;
+}
+#endif
+
+static void
+SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data);
+
+static void
+SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
+{
+       int rc;
+       struct cifs_ses *ses = sess_data->ses;
+       struct smb2_sess_setup_rsp *rsp = NULL;
+       char *ntlmssp_blob = NULL;
+       bool use_spnego = false; /* else use raw ntlmssp */
+       u16 blob_length = 0;
+
        /*
-        * No tcon so can't do
-        * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
+        * If memory allocation is successful, caller of this function
+        * frees it.
         */
-       if (rc != 0)
-               goto ssetup_exit;
+       ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
+       if (!ses->ntlmssp) {
+               rc = -ENOMEM;
+               goto out_err;
+       }
+       ses->ntlmssp->sesskey_per_smbsess = true;
+
+       rc = SMB2_sess_alloc_buffer(sess_data);
+       if (rc)
+               goto out_err;
+
+       ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
+                              GFP_KERNEL);
+       if (ntlmssp_blob == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       build_ntlmssp_negotiate_blob(ntlmssp_blob, ses);
+       if (use_spnego) {
+               /* BB eventually need to add this */
+               cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
+               rc = -EOPNOTSUPP;
+               goto out;
+       } else {
+               blob_length = sizeof(struct _NEGOTIATE_MESSAGE);
+               /* with raw NTLMSSP we don't encapsulate in SPNEGO */
+       }
+       sess_data->iov[1].iov_base = ntlmssp_blob;
+       sess_data->iov[1].iov_len = blob_length;
+
+       rc = SMB2_sess_sendreceive(sess_data);
+       rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+
+       /* If true, rc here is expected and not an error */
+       if (sess_data->buf0_type != CIFS_NO_BUFFER &&
+               rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED)
+               rc = 0;
+
+       if (rc)
+               goto out;
+
+       if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 !=
+                       le16_to_cpu(rsp->SecurityBufferOffset)) {
+               cifs_dbg(VFS, "Invalid security buffer offset %d\n",
+                       le16_to_cpu(rsp->SecurityBufferOffset));
+               rc = -EIO;
+               goto out;
+       }
+       rc = decode_ntlmssp_challenge(rsp->Buffer,
+                       le16_to_cpu(rsp->SecurityBufferLength), ses);
+       if (rc)
+               goto out;
+
+       cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
+
 
+       ses->Suid = rsp->hdr.SessionId;
        ses->session_flags = le16_to_cpu(rsp->SessionFlags);
        if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
                cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
-ssetup_exit:
-       free_rsp_buf(resp_buftype, rsp);
-
-       /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
-       if ((phase == NtLmChallenge) && (rc == 0))
-               goto ssetup_ntlmssp_authenticate;
 
+out:
+       kfree(ntlmssp_blob);
+       SMB2_sess_free_buffer(sess_data);
        if (!rc) {
-               mutex_lock(&server->srv_mutex);
-               if (server->sign && server->ops->generate_signingkey) {
-                       rc = server->ops->generate_signingkey(ses);
-                       kfree(ses->auth_key.response);
-                       ses->auth_key.response = NULL;
-                       if (rc) {
-                               cifs_dbg(FYI,
-                                       "SMB3 session key generation failed\n");
-                               mutex_unlock(&server->srv_mutex);
-                               goto keygen_exit;
-                       }
-               }
-               if (!server->session_estab) {
-                       server->sequence_number = 0x2;
-                       server->session_estab = true;
-               }
-               mutex_unlock(&server->srv_mutex);
-
-               cifs_dbg(FYI, "SMB2/3 session established successfully\n");
-               spin_lock(&GlobalMid_Lock);
-               ses->status = CifsGood;
-               ses->need_reconnect = false;
-               spin_unlock(&GlobalMid_Lock);
+               sess_data->result = 0;
+               sess_data->func = SMB2_sess_auth_rawntlmssp_authenticate;
+               return;
        }
+out_err:
+       kfree(ses->ntlmssp);
+       ses->ntlmssp = NULL;
+       sess_data->result = rc;
+       sess_data->func = NULL;
+}
 
-keygen_exit:
-       if (!server->sign) {
-               kfree(ses->auth_key.response);
-               ses->auth_key.response = NULL;
+static void
+SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
+{
+       int rc;
+       struct cifs_ses *ses = sess_data->ses;
+       struct smb2_sess_setup_req *req;
+       struct smb2_sess_setup_rsp *rsp = NULL;
+       unsigned char *ntlmssp_blob = NULL;
+       bool use_spnego = false; /* else use raw ntlmssp */
+       u16 blob_length = 0;
+
+       rc = SMB2_sess_alloc_buffer(sess_data);
+       if (rc)
+               goto out;
+
+       req = (struct smb2_sess_setup_req *) sess_data->iov[0].iov_base;
+       req->hdr.SessionId = ses->Suid;
+
+       rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses,
+                                       sess_data->nls_cp);
+       if (rc) {
+               cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", rc);
+               goto out;
        }
-       if (spnego_key) {
-               key_invalidate(spnego_key);
-               key_put(spnego_key);
+
+       if (use_spnego) {
+               /* BB eventually need to add this */
+               cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
+               rc = -EOPNOTSUPP;
+               goto out;
        }
+       sess_data->iov[1].iov_base = ntlmssp_blob;
+       sess_data->iov[1].iov_len = blob_length;
+
+       rc = SMB2_sess_sendreceive(sess_data);
+       if (rc)
+               goto out;
+
+       rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+
+       ses->Suid = rsp->hdr.SessionId;
+       ses->session_flags = le16_to_cpu(rsp->SessionFlags);
+       if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
+               cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
+
+       rc = SMB2_sess_establish_session(sess_data);
+out:
+       kfree(ntlmssp_blob);
+       SMB2_sess_free_buffer(sess_data);
        kfree(ses->ntlmssp);
+       ses->ntlmssp = NULL;
+       sess_data->result = rc;
+       sess_data->func = NULL;
+}
 
+static int
+SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data)
+{
+       if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP)
+               ses->sectype = RawNTLMSSP;
+
+       switch (ses->sectype) {
+       case Kerberos:
+               sess_data->func = SMB2_auth_kerberos;
+               break;
+       case RawNTLMSSP:
+               sess_data->func = SMB2_sess_auth_rawntlmssp_negotiate;
+               break;
+       default:
+               cifs_dbg(VFS, "secType %d not supported!\n", ses->sectype);
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+int
+SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
+               const struct nls_table *nls_cp)
+{
+       int rc = 0;
+       struct TCP_Server_Info *server = ses->server;
+       struct SMB2_sess_data *sess_data;
+
+       cifs_dbg(FYI, "Session Setup\n");
+
+       if (!server) {
+               WARN(1, "%s: server is NULL!\n", __func__);
+               return -EIO;
+       }
+
+       sess_data = kzalloc(sizeof(struct SMB2_sess_data), GFP_KERNEL);
+       if (!sess_data)
+               return -ENOMEM;
+
+       rc = SMB2_select_sec(ses, sess_data);
+       if (rc)
+               goto out;
+       sess_data->xid = xid;
+       sess_data->ses = ses;
+       sess_data->buf0_type = CIFS_NO_BUFFER;
+       sess_data->nls_cp = (struct nls_table *) nls_cp;
+
+       while (sess_data->func)
+               sess_data->func(sess_data);
+
+       rc = sess_data->result;
+out:
+       kfree(sess_data);
        return rc;
 }
 
@@ -1164,7 +1335,7 @@ create_durable_v2_buf(struct cifs_fid *pfid)
 
        buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
        buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
-       get_random_bytes(buf->dcontext.CreateGuid, 16);
+       generate_random_uuid(buf->dcontext.CreateGuid);
        memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
 
        /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
@@ -2057,6 +2228,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
        if (rdata->credits) {
                buf->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
                                                SMB2_MAX_BUFFER_SIZE));
+               buf->CreditRequest = buf->CreditCharge;
                spin_lock(&server->req_lock);
                server->credits += rdata->credits -
                                                le16_to_cpu(buf->CreditCharge);
@@ -2243,6 +2415,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
        if (wdata->credits) {
                req->hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
                                                    SMB2_MAX_BUFFER_SIZE));
+               req->hdr.CreditRequest = req->hdr.CreditCharge;
                spin_lock(&server->req_lock);
                server->credits += wdata->credits -
                                        le16_to_cpu(req->hdr.CreditCharge);