|
@@ -34,15 +34,99 @@
|
|
|
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
|
|
|
unsigned char *p24);
|
|
|
|
|
|
+/* Checks if this is the first smb session to be reconnected after
|
|
|
+ the socket has been reestablished (so we know whether to use vc 0).
|
|
|
+ Called while holding the cifs_tcp_ses_lock, so do not block */
|
|
|
+static bool is_first_ses_reconnect(struct cifsSesInfo *ses)
|
|
|
+{
|
|
|
+ struct list_head *tmp;
|
|
|
+ struct cifsSesInfo *tmp_ses;
|
|
|
+
|
|
|
+ list_for_each(tmp, &ses->server->smb_ses_list) {
|
|
|
+ tmp_ses = list_entry(tmp, struct cifsSesInfo,
|
|
|
+ smb_ses_list);
|
|
|
+ if (tmp_ses->need_reconnect == false)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /* could not find a session that was already connected,
|
|
|
+ this must be the first one we are reconnecting */
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * vc number 0 is treated specially by some servers, and should be the
|
|
|
+ * first one we request. After that we can use vcnumbers up to maxvcs,
|
|
|
+ * one for each smb session (some Windows versions set maxvcs incorrectly
|
|
|
+ * so maxvc=1 can be ignored). If we have too many vcs, we can reuse
|
|
|
+ * any vc but zero (some servers reset the connection on vcnum zero)
|
|
|
+ *
|
|
|
+ */
|
|
|
+static __le16 get_next_vcnum(struct cifsSesInfo *ses)
|
|
|
+{
|
|
|
+ __u16 vcnum = 0;
|
|
|
+ struct list_head *tmp;
|
|
|
+ struct cifsSesInfo *tmp_ses;
|
|
|
+ __u16 max_vcs = ses->server->max_vcs;
|
|
|
+ __u16 i;
|
|
|
+ int free_vc_found = 0;
|
|
|
+
|
|
|
+ /* Quoting the MS-SMB specification: "Windows-based SMB servers set this
|
|
|
+ field to one but do not enforce this limit, which allows an SMB client
|
|
|
+ to establish more virtual circuits than allowed by this value ... but
|
|
|
+ other server implementations can enforce this limit." */
|
|
|
+ if (max_vcs < 2)
|
|
|
+ max_vcs = 0xFFFF;
|
|
|
+
|
|
|
+ write_lock(&cifs_tcp_ses_lock);
|
|
|
+ if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
|
|
|
+ goto get_vc_num_exit; /* vcnum will be zero */
|
|
|
+ for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
|
|
|
+ if (i == 0) /* this is the only connection, use vc 0 */
|
|
|
+ break;
|
|
|
+
|
|
|
+ free_vc_found = 1;
|
|
|
+
|
|
|
+ list_for_each(tmp, &ses->server->smb_ses_list) {
|
|
|
+ tmp_ses = list_entry(tmp, struct cifsSesInfo,
|
|
|
+ smb_ses_list);
|
|
|
+ if (tmp_ses->vcnum == i) {
|
|
|
+ free_vc_found = 0;
|
|
|
+ break; /* found duplicate, try next vcnum */
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (free_vc_found)
|
|
|
+ break; /* we found a vcnumber that will work - use it */
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i == 0)
|
|
|
+ vcnum = 0; /* for most common case, ie if one smb session, use
|
|
|
+ vc zero. Also for case when no free vcnum, zero
|
|
|
+ is safest to send (some clients only send zero) */
|
|
|
+ else if (free_vc_found == 0)
|
|
|
+ vcnum = 1; /* we can not reuse vc=0 safely, since some servers
|
|
|
+ reset all uids on that, but 1 is ok. */
|
|
|
+ else
|
|
|
+ vcnum = i;
|
|
|
+ ses->vcnum = vcnum;
|
|
|
+get_vc_num_exit:
|
|
|
+ write_unlock(&cifs_tcp_ses_lock);
|
|
|
+
|
|
|
+ return le16_to_cpu(vcnum);
|
|
|
+}
|
|
|
+
|
|
|
static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
|
|
|
{
|
|
|
__u32 capabilities = 0;
|
|
|
|
|
|
/* init fields common to all four types of SessSetup */
|
|
|
- /* note that header is initialized to zero in header_assemble */
|
|
|
+ /* Note that offsets for first seven fields in req struct are same */
|
|
|
+ /* in CIFS Specs so does not matter which of 3 forms of struct */
|
|
|
+ /* that we use in next few lines */
|
|
|
+ /* Note that header is initialized to zero in header_assemble */
|
|
|
pSMB->req.AndXCommand = 0xFF;
|
|
|
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
|
|
|
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
|
|
|
+ pSMB->req.VcNumber = get_next_vcnum(ses);
|
|
|
|
|
|
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
|
|
|
|
|
@@ -71,7 +155,6 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
|
|
|
if (ses->capabilities & CAP_UNIX)
|
|
|
capabilities |= CAP_UNIX;
|
|
|
|
|
|
- /* BB check whether to init vcnum BB */
|
|
|
return capabilities;
|
|
|
}
|
|
|
|