Commit a67172a0 authored by Shirish Pargaonkar's avatar Shirish Pargaonkar Committed by Jiri Slaby

cifs: Send a logoff request before removing a smb session

commit 7f48558e upstream.

Send a smb session logoff request before removing smb session off of the list.
On a signed smb session, remvoing a session off of the list before sending
a logoff request results in server returning an error for lack of
smb signature.

Never seen an error during smb logoff, so as per MS-SMB2 3.2.5.1,
not sure how an error during logoff should be retried. So for now,
if a server returns an error to a logoff request, log the error and
remove the session off of the list.
Signed-off-by: default avatarShirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
parent 6f767a31
...@@ -2245,6 +2245,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) ...@@ -2245,6 +2245,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
if (ses->status == CifsExiting)
continue;
if (!match_session(ses, vol)) if (!match_session(ses, vol))
continue; continue;
++ses->ses_count; ++ses->ses_count;
...@@ -2258,24 +2260,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) ...@@ -2258,24 +2260,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
static void static void
cifs_put_smb_ses(struct cifs_ses *ses) cifs_put_smb_ses(struct cifs_ses *ses)
{ {
unsigned int xid; unsigned int rc, xid;
struct TCP_Server_Info *server = ses->server; struct TCP_Server_Info *server = ses->server;
cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
if (ses->status == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return;
}
if (--ses->ses_count > 0) { if (--ses->ses_count > 0) {
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return; return;
} }
if (ses->status == CifsGood)
list_del_init(&ses->smb_ses_list); ses->status = CifsExiting;
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
if (ses->status == CifsGood && server->ops->logoff) { if (ses->status == CifsExiting && server->ops->logoff) {
xid = get_xid(); xid = get_xid();
server->ops->logoff(xid, ses); rc = server->ops->logoff(xid, ses);
if (rc)
cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
__func__, rc);
_free_xid(xid); _free_xid(xid);
} }
spin_lock(&cifs_tcp_ses_lock);
list_del_init(&ses->smb_ses_list);
spin_unlock(&cifs_tcp_ses_lock);
sesInfoFree(ses); sesInfoFree(ses);
cifs_put_tcp_session(server); cifs_put_tcp_session(server);
} }
......
...@@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf, ...@@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
return -EAGAIN; return -EAGAIN;
} }
if (ses->status != CifsGood) { if (ses->status == CifsNew) {
/* check if SMB2 session is bad because we are setting it up */
if ((buf->Command != SMB2_SESSION_SETUP) && if ((buf->Command != SMB2_SESSION_SETUP) &&
(buf->Command != SMB2_NEGOTIATE)) (buf->Command != SMB2_NEGOTIATE))
return -EAGAIN; return -EAGAIN;
/* else ok - we are setting up session */ /* else ok - we are setting up session */
} }
if (ses->status == CifsExiting) {
if (buf->Command != SMB2_LOGOFF)
return -EAGAIN;
/* else ok - we are shutting down the session */
}
*mid = smb2_mid_entry_alloc(buf, ses->server); *mid = smb2_mid_entry_alloc(buf, ses->server);
if (*mid == NULL) if (*mid == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -431,13 +431,20 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, ...@@ -431,13 +431,20 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
return -EAGAIN; return -EAGAIN;
} }
if (ses->status != CifsGood) { if (ses->status == CifsNew) {
/* check if SMB session is bad because we are setting it up */
if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) (in_buf->Command != SMB_COM_NEGOTIATE))
return -EAGAIN; return -EAGAIN;
/* else ok - we are setting up session */ /* else ok - we are setting up session */
} }
if (ses->status == CifsExiting) {
/* check if SMB session is bad because we are setting it up */
if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
return -EAGAIN;
/* else ok - we are shutting down session */
}
*ppmidQ = AllocMidQEntry(in_buf, ses->server); *ppmidQ = AllocMidQEntry(in_buf, ses->server);
if (*ppmidQ == NULL) if (*ppmidQ == NULL)
return -ENOMEM; return -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment