mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS/SMB3 updates from Steve French: "Includes support for a critical SMB3 security feature: per-share encryption from Pavel, and a cleanup from Jean Delvare. Will have another cifs/smb3 merge next week" * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: CIFS: Allow to switch on encryption with seal mount option CIFS: Add capability to decrypt big read responses CIFS: Decrypt and process small encrypted packets CIFS: Add copy into pages callback for a read operation CIFS: Add mid handle callback CIFS: Add transform header handling callbacks CIFS: Encrypt SMB3 requests before sending CIFS: Enable encryption during session setup phase CIFS: Add capability to transform requests before sending CIFS: Separate RFC1001 length processing for SMB2 read CIFS: Separate SMB2 sync header processing CIFS: Send RFC1001 length in a separate iov CIFS: Make send_cancel take rqst as argument CIFS: Make SendReceive2() takes resp iov CIFS: Separate SMB2 header structure CIFS: Fix splice read for non-cached files cifs: Add soft dependencies cifs: Only select the required crypto modules cifs: Simplify SMB2 and SMB311 dependencies
This commit is contained in:
		
						commit
						2bfe01eff4
					
				
					 19 changed files with 1589 additions and 486 deletions
				
			
		| 
						 | 
					@ -9,8 +9,6 @@ config CIFS
 | 
				
			||||||
	select CRYPTO_ARC4
 | 
						select CRYPTO_ARC4
 | 
				
			||||||
	select CRYPTO_ECB
 | 
						select CRYPTO_ECB
 | 
				
			||||||
	select CRYPTO_DES
 | 
						select CRYPTO_DES
 | 
				
			||||||
	select CRYPTO_SHA256
 | 
					 | 
				
			||||||
	select CRYPTO_CMAC
 | 
					 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  This is the client VFS module for the Common Internet File System
 | 
						  This is the client VFS module for the Common Internet File System
 | 
				
			||||||
	  (CIFS) protocol which is the successor to the Server Message Block
 | 
						  (CIFS) protocol which is the successor to the Server Message Block
 | 
				
			||||||
| 
						 | 
					@ -169,11 +167,15 @@ config CIFS_NFSD_EXPORT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config CIFS_SMB2
 | 
					config CIFS_SMB2
 | 
				
			||||||
	bool "SMB2 and SMB3 network file system support"
 | 
						bool "SMB2 and SMB3 network file system support"
 | 
				
			||||||
	depends on CIFS && INET
 | 
						depends on CIFS
 | 
				
			||||||
	select NLS
 | 
					 | 
				
			||||||
	select KEYS
 | 
						select KEYS
 | 
				
			||||||
	select FSCACHE
 | 
						select FSCACHE
 | 
				
			||||||
	select DNS_RESOLVER
 | 
						select DNS_RESOLVER
 | 
				
			||||||
 | 
						select CRYPTO_AES
 | 
				
			||||||
 | 
						select CRYPTO_SHA256
 | 
				
			||||||
 | 
						select CRYPTO_CMAC
 | 
				
			||||||
 | 
						select CRYPTO_AEAD2
 | 
				
			||||||
 | 
						select CRYPTO_CCM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  This enables support for the Server Message Block version 2
 | 
						  This enables support for the Server Message Block version 2
 | 
				
			||||||
| 
						 | 
					@ -194,7 +196,7 @@ config CIFS_SMB2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config CIFS_SMB311
 | 
					config CIFS_SMB311
 | 
				
			||||||
	bool "SMB3.1.1 network file system support (Experimental)"
 | 
						bool "SMB3.1.1 network file system support (Experimental)"
 | 
				
			||||||
	depends on CIFS_SMB2 && INET
 | 
						depends on CIFS_SMB2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  This enables experimental support for the newest, SMB3.1.1, dialect.
 | 
						  This enables experimental support for the newest, SMB3.1.1, dialect.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,7 @@
 | 
				
			||||||
#include <linux/random.h>
 | 
					#include <linux/random.h>
 | 
				
			||||||
#include <linux/highmem.h>
 | 
					#include <linux/highmem.h>
 | 
				
			||||||
#include <crypto/skcipher.h>
 | 
					#include <crypto/skcipher.h>
 | 
				
			||||||
 | 
					#include <crypto/aead.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
 | 
					cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
 | 
				
			||||||
| 
						 | 
					@ -75,24 +76,20 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
 | 
				
			||||||
	struct kvec *iov = rqst->rq_iov;
 | 
						struct kvec *iov = rqst->rq_iov;
 | 
				
			||||||
	int n_vec = rqst->rq_nvec;
 | 
						int n_vec = rqst->rq_nvec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_vec; i++) {
 | 
						if (n_vec < 2 || iov[0].iov_len != 4)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 1; i < n_vec; i++) {
 | 
				
			||||||
		if (iov[i].iov_len == 0)
 | 
							if (iov[i].iov_len == 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (iov[i].iov_base == NULL) {
 | 
							if (iov[i].iov_base == NULL) {
 | 
				
			||||||
			cifs_dbg(VFS, "null iovec entry\n");
 | 
								cifs_dbg(VFS, "null iovec entry\n");
 | 
				
			||||||
			return -EIO;
 | 
								return -EIO;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* The first entry includes a length field (which does not get
 | 
							if (i == 1 && iov[1].iov_len <= 4)
 | 
				
			||||||
		   signed that occupies the first 4 bytes before the header */
 | 
					 | 
				
			||||||
		if (i == 0) {
 | 
					 | 
				
			||||||
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
 | 
					 | 
				
			||||||
			break; /* nothing to sign or corrupt header */
 | 
								break; /* nothing to sign or corrupt header */
 | 
				
			||||||
			rc = crypto_shash_update(shash,
 | 
					 | 
				
			||||||
				iov[i].iov_base + 4, iov[i].iov_len - 4);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
		rc = crypto_shash_update(shash,
 | 
							rc = crypto_shash_update(shash,
 | 
				
			||||||
					 iov[i].iov_base, iov[i].iov_len);
 | 
										 iov[i].iov_base, iov[i].iov_len);
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (rc) {
 | 
							if (rc) {
 | 
				
			||||||
			cifs_dbg(VFS, "%s: Could not update with payload\n",
 | 
								cifs_dbg(VFS, "%s: Could not update with payload\n",
 | 
				
			||||||
				 __func__);
 | 
									 __func__);
 | 
				
			||||||
| 
						 | 
					@ -168,6 +165,10 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 | 
				
			||||||
	char smb_signature[20];
 | 
						char smb_signature[20];
 | 
				
			||||||
	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
						struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rqst->rq_iov[0].iov_len != 4 ||
 | 
				
			||||||
 | 
						    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((cifs_pdu == NULL) || (server == NULL))
 | 
						if ((cifs_pdu == NULL) || (server == NULL))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -209,12 +210,14 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
 | 
				
			||||||
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
 | 
					int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
 | 
				
			||||||
		  __u32 *pexpected_response_sequence_number)
 | 
							  __u32 *pexpected_response_sequence_number)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct kvec iov;
 | 
						struct kvec iov[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iov.iov_base = cifs_pdu;
 | 
						iov[0].iov_base = cifs_pdu;
 | 
				
			||||||
	iov.iov_len = be32_to_cpu(cifs_pdu->smb_buf_length) + 4;
 | 
						iov[0].iov_len = 4;
 | 
				
			||||||
 | 
						iov[1].iov_base = (char *)cifs_pdu + 4;
 | 
				
			||||||
 | 
						iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cifs_sign_smbv(&iov, 1, server,
 | 
						return cifs_sign_smbv(iov, 2, server,
 | 
				
			||||||
			      pexpected_response_sequence_number);
 | 
								      pexpected_response_sequence_number);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -227,6 +230,10 @@ int cifs_verify_signature(struct smb_rqst *rqst,
 | 
				
			||||||
	char what_we_think_sig_should_be[20];
 | 
						char what_we_think_sig_should_be[20];
 | 
				
			||||||
	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
						struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rqst->rq_iov[0].iov_len != 4 ||
 | 
				
			||||||
 | 
						    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cifs_pdu == NULL || server == NULL)
 | 
						if (cifs_pdu == NULL || server == NULL)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -868,7 +875,7 @@ calc_seckey(struct cifs_ses *ses)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
cifs_crypto_shash_release(struct TCP_Server_Info *server)
 | 
					cifs_crypto_secmech_release(struct TCP_Server_Info *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (server->secmech.cmacaes) {
 | 
						if (server->secmech.cmacaes) {
 | 
				
			||||||
		crypto_free_shash(server->secmech.cmacaes);
 | 
							crypto_free_shash(server->secmech.cmacaes);
 | 
				
			||||||
| 
						 | 
					@ -890,6 +897,16 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server)
 | 
				
			||||||
		server->secmech.hmacmd5 = NULL;
 | 
							server->secmech.hmacmd5 = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (server->secmech.ccmaesencrypt) {
 | 
				
			||||||
 | 
							crypto_free_aead(server->secmech.ccmaesencrypt);
 | 
				
			||||||
 | 
							server->secmech.ccmaesencrypt = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (server->secmech.ccmaesdecrypt) {
 | 
				
			||||||
 | 
							crypto_free_aead(server->secmech.ccmaesdecrypt);
 | 
				
			||||||
 | 
							server->secmech.ccmaesdecrypt = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(server->secmech.sdesccmacaes);
 | 
						kfree(server->secmech.sdesccmacaes);
 | 
				
			||||||
	server->secmech.sdesccmacaes = NULL;
 | 
						server->secmech.sdesccmacaes = NULL;
 | 
				
			||||||
	kfree(server->secmech.sdeschmacsha256);
 | 
						kfree(server->secmech.sdeschmacsha256);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1365,5 +1365,19 @@ MODULE_DESCRIPTION
 | 
				
			||||||
    ("VFS to access servers complying with the SNIA CIFS Specification "
 | 
					    ("VFS to access servers complying with the SNIA CIFS Specification "
 | 
				
			||||||
     "e.g. Samba and Windows");
 | 
					     "e.g. Samba and Windows");
 | 
				
			||||||
MODULE_VERSION(CIFS_VERSION);
 | 
					MODULE_VERSION(CIFS_VERSION);
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: arc4");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: des");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: ecb");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: hmac");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: md4");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: md5");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: nls");
 | 
				
			||||||
 | 
					#ifdef CONFIG_CIFS_SMB2
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: aes");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: cmac");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: sha256");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: aead2");
 | 
				
			||||||
 | 
					MODULE_SOFTDEP("pre: ccm");
 | 
				
			||||||
 | 
					#endif /* CONFIG_CIFS_SMB2 */
 | 
				
			||||||
module_init(init_cifs)
 | 
					module_init(init_cifs)
 | 
				
			||||||
module_exit(exit_cifs)
 | 
					module_exit(exit_cifs)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,6 +136,8 @@ struct cifs_secmech {
 | 
				
			||||||
	struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
 | 
						struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
 | 
				
			||||||
	struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
 | 
						struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
 | 
				
			||||||
	struct sdesc *sdesccmacaes;  /* ctxt to generate smb3 signature */
 | 
						struct sdesc *sdesccmacaes;  /* ctxt to generate smb3 signature */
 | 
				
			||||||
 | 
						struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */
 | 
				
			||||||
 | 
						struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* per smb session structure/fields */
 | 
					/* per smb session structure/fields */
 | 
				
			||||||
| 
						 | 
					@ -208,7 +210,7 @@ struct cifsInodeInfo;
 | 
				
			||||||
struct cifs_open_parms;
 | 
					struct cifs_open_parms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct smb_version_operations {
 | 
					struct smb_version_operations {
 | 
				
			||||||
	int (*send_cancel)(struct TCP_Server_Info *, void *,
 | 
						int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
 | 
				
			||||||
			   struct mid_q_entry *);
 | 
								   struct mid_q_entry *);
 | 
				
			||||||
	bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
 | 
						bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
 | 
				
			||||||
	/* setup request: allocate mid, sign message */
 | 
						/* setup request: allocate mid, sign message */
 | 
				
			||||||
| 
						 | 
					@ -433,6 +435,14 @@ struct smb_version_operations {
 | 
				
			||||||
	bool (*dir_needs_close)(struct cifsFileInfo *);
 | 
						bool (*dir_needs_close)(struct cifsFileInfo *);
 | 
				
			||||||
	long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
 | 
						long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
 | 
				
			||||||
			  loff_t);
 | 
								  loff_t);
 | 
				
			||||||
 | 
						/* init transform request - used for encryption for now */
 | 
				
			||||||
 | 
						int (*init_transform_rq)(struct TCP_Server_Info *, struct smb_rqst *,
 | 
				
			||||||
 | 
									 struct smb_rqst *);
 | 
				
			||||||
 | 
						/* free transform request */
 | 
				
			||||||
 | 
						void (*free_transform_rq)(struct smb_rqst *);
 | 
				
			||||||
 | 
						int (*is_transform_hdr)(void *buf);
 | 
				
			||||||
 | 
						int (*receive_transform)(struct TCP_Server_Info *,
 | 
				
			||||||
 | 
									 struct mid_q_entry **);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct smb_version_values {
 | 
					struct smb_version_values {
 | 
				
			||||||
| 
						 | 
					@ -1119,7 +1129,10 @@ struct cifs_readdata {
 | 
				
			||||||
	int (*read_into_pages)(struct TCP_Server_Info *server,
 | 
						int (*read_into_pages)(struct TCP_Server_Info *server,
 | 
				
			||||||
				struct cifs_readdata *rdata,
 | 
									struct cifs_readdata *rdata,
 | 
				
			||||||
				unsigned int len);
 | 
									unsigned int len);
 | 
				
			||||||
	struct kvec			iov;
 | 
						int (*copy_into_pages)(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
									struct cifs_readdata *rdata,
 | 
				
			||||||
 | 
									struct iov_iter *iter);
 | 
				
			||||||
 | 
						struct kvec			iov[2];
 | 
				
			||||||
	unsigned int			pagesz;
 | 
						unsigned int			pagesz;
 | 
				
			||||||
	unsigned int			tailsz;
 | 
						unsigned int			tailsz;
 | 
				
			||||||
	unsigned int			credits;
 | 
						unsigned int			credits;
 | 
				
			||||||
| 
						 | 
					@ -1302,6 +1315,13 @@ typedef int (mid_receive_t)(struct TCP_Server_Info *server,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef void (mid_callback_t)(struct mid_q_entry *mid);
 | 
					typedef void (mid_callback_t)(struct mid_q_entry *mid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the protopyte for mid handle function. This is called once the mid
 | 
				
			||||||
 | 
					 * has been recognized after decryption of the message.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef int (mid_handle_t)(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
								    struct mid_q_entry *mid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* one of these for every pending CIFS request to the server */
 | 
					/* one of these for every pending CIFS request to the server */
 | 
				
			||||||
struct mid_q_entry {
 | 
					struct mid_q_entry {
 | 
				
			||||||
	struct list_head qhead;	/* mids waiting on reply from this server */
 | 
						struct list_head qhead;	/* mids waiting on reply from this server */
 | 
				
			||||||
| 
						 | 
					@ -1316,6 +1336,7 @@ struct mid_q_entry {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	mid_receive_t *receive; /* call receive callback */
 | 
						mid_receive_t *receive; /* call receive callback */
 | 
				
			||||||
	mid_callback_t *callback; /* call completion callback */
 | 
						mid_callback_t *callback; /* call completion callback */
 | 
				
			||||||
 | 
						mid_handle_t *handle; /* call handle mid callback */
 | 
				
			||||||
	void *callback_data;	  /* general purpose pointer for callback */
 | 
						void *callback_data;	  /* general purpose pointer for callback */
 | 
				
			||||||
	void *resp_buf;		/* pointer to received SMB header */
 | 
						void *resp_buf;		/* pointer to received SMB header */
 | 
				
			||||||
	int mid_state;	/* wish this were enum but can not pass to wait_event */
 | 
						int mid_state;	/* wish this were enum but can not pass to wait_event */
 | 
				
			||||||
| 
						 | 
					@ -1323,6 +1344,7 @@ struct mid_q_entry {
 | 
				
			||||||
	bool large_buf:1;	/* if valid response, is pointer to large buf */
 | 
						bool large_buf:1;	/* if valid response, is pointer to large buf */
 | 
				
			||||||
	bool multiRsp:1;	/* multiple trans2 responses for one request  */
 | 
						bool multiRsp:1;	/* multiple trans2 responses for one request  */
 | 
				
			||||||
	bool multiEnd:1;	/* both received */
 | 
						bool multiEnd:1;	/* both received */
 | 
				
			||||||
 | 
						bool decrypted:1;	/* decrypted entry */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	Make code in transport.c a little cleaner by moving
 | 
					/*	Make code in transport.c a little cleaner by moving
 | 
				
			||||||
| 
						 | 
					@ -1475,7 +1497,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
 | 
				
			||||||
#define   CIFS_OBREAK_OP   0x0100    /* oplock break request */
 | 
					#define   CIFS_OBREAK_OP   0x0100    /* oplock break request */
 | 
				
			||||||
#define   CIFS_NEG_OP      0x0200    /* negotiate request */
 | 
					#define   CIFS_NEG_OP      0x0200    /* negotiate request */
 | 
				
			||||||
#define   CIFS_OP_MASK     0x0380    /* mask request type */
 | 
					#define   CIFS_OP_MASK     0x0380    /* mask request type */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define   CIFS_HAS_CREDITS 0x0400    /* already has credits */
 | 
					#define   CIFS_HAS_CREDITS 0x0400    /* already has credits */
 | 
				
			||||||
 | 
					#define   CIFS_TRANSFORM_REQ 0x0800    /* transform request before sending */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Security Flags: indicate type of session setup needed */
 | 
					/* Security Flags: indicate type of session setup needed */
 | 
				
			||||||
#define   CIFSSEC_MAY_SIGN	0x00001
 | 
					#define   CIFSSEC_MAY_SIGN	0x00001
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,10 +75,16 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
 | 
				
			||||||
extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
 | 
					extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
 | 
				
			||||||
extern void cifs_delete_mid(struct mid_q_entry *mid);
 | 
					extern void cifs_delete_mid(struct mid_q_entry *mid);
 | 
				
			||||||
extern void cifs_wake_up_task(struct mid_q_entry *mid);
 | 
					extern void cifs_wake_up_task(struct mid_q_entry *mid);
 | 
				
			||||||
 | 
					extern int cifs_handle_standard(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
									struct mid_q_entry *mid);
 | 
				
			||||||
 | 
					extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 | 
				
			||||||
extern int cifs_call_async(struct TCP_Server_Info *server,
 | 
					extern int cifs_call_async(struct TCP_Server_Info *server,
 | 
				
			||||||
			struct smb_rqst *rqst,
 | 
								struct smb_rqst *rqst,
 | 
				
			||||||
			mid_receive_t *receive, mid_callback_t *callback,
 | 
								mid_receive_t *receive, mid_callback_t *callback,
 | 
				
			||||||
			void *cbdata, const int flags);
 | 
								mid_handle_t *handle, void *cbdata, const int flags);
 | 
				
			||||||
 | 
					extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
 | 
								  struct smb_rqst *rqst, int *resp_buf_type,
 | 
				
			||||||
 | 
								  const int flags, struct kvec *resp_iov);
 | 
				
			||||||
extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 | 
					extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 | 
				
			||||||
			struct smb_hdr * /* input */ ,
 | 
								struct smb_hdr * /* input */ ,
 | 
				
			||||||
			struct smb_hdr * /* out */ ,
 | 
								struct smb_hdr * /* out */ ,
 | 
				
			||||||
| 
						 | 
					@ -96,7 +102,8 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
 | 
				
			||||||
				 unsigned int *credits);
 | 
									 unsigned int *credits);
 | 
				
			||||||
extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
 | 
					extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
 | 
				
			||||||
			struct kvec *, int /* nvec to send */,
 | 
								struct kvec *, int /* nvec to send */,
 | 
				
			||||||
			int * /* type of buf returned */ , const int flags);
 | 
								int * /* type of buf returned */, const int flags,
 | 
				
			||||||
 | 
								struct kvec * /* resp vec */);
 | 
				
			||||||
extern int SendReceiveBlockingLock(const unsigned int xid,
 | 
					extern int SendReceiveBlockingLock(const unsigned int xid,
 | 
				
			||||||
			struct cifs_tcon *ptcon,
 | 
								struct cifs_tcon *ptcon,
 | 
				
			||||||
			struct smb_hdr *in_buf ,
 | 
								struct smb_hdr *in_buf ,
 | 
				
			||||||
| 
						 | 
					@ -441,7 +448,7 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
 | 
				
			||||||
			const struct nls_table *);
 | 
								const struct nls_table *);
 | 
				
			||||||
extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
 | 
					extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
 | 
				
			||||||
extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
 | 
					extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
 | 
				
			||||||
extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
 | 
					extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
 | 
				
			||||||
extern int calc_seckey(struct cifs_ses *);
 | 
					extern int calc_seckey(struct cifs_ses *);
 | 
				
			||||||
extern int generate_smb30signingkey(struct cifs_ses *);
 | 
					extern int generate_smb30signingkey(struct cifs_ses *);
 | 
				
			||||||
extern int generate_smb311signingkey(struct cifs_ses *);
 | 
					extern int generate_smb311signingkey(struct cifs_ses *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -673,6 +673,7 @@ CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
 | 
						rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(smb_buffer);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
 | 
							cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -707,9 +708,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ECHO_REQ *smb;
 | 
						ECHO_REQ *smb;
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	struct kvec iov;
 | 
						struct kvec iov[2];
 | 
				
			||||||
	struct smb_rqst rqst = { .rq_iov = &iov,
 | 
						struct smb_rqst rqst = { .rq_iov = iov,
 | 
				
			||||||
				 .rq_nvec = 1 };
 | 
									 .rq_nvec = 2 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_dbg(FYI, "In echo request\n");
 | 
						cifs_dbg(FYI, "In echo request\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -724,10 +725,13 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 | 
				
			||||||
	put_bcc(1, &smb->hdr);
 | 
						put_bcc(1, &smb->hdr);
 | 
				
			||||||
	smb->Data[0] = 'a';
 | 
						smb->Data[0] = 'a';
 | 
				
			||||||
	inc_rfc1001_len(smb, 3);
 | 
						inc_rfc1001_len(smb, 3);
 | 
				
			||||||
	iov.iov_base = smb;
 | 
					 | 
				
			||||||
	iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
 | 
						iov[0].iov_len = 4;
 | 
				
			||||||
 | 
						iov[0].iov_base = smb;
 | 
				
			||||||
 | 
						iov[1].iov_len = get_rfc1002_length(smb);
 | 
				
			||||||
 | 
						iov[1].iov_base = (char *)smb + 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
 | 
				
			||||||
			     server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
 | 
								     server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
 | 
							cifs_dbg(FYI, "Echo request failed: %d\n", rc);
 | 
				
			||||||
| 
						 | 
					@ -772,6 +776,7 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pSMB->AndXCommand = 0xFF;
 | 
						pSMB->AndXCommand = 0xFF;
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
 | 
						rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
session_already_dead:
 | 
					session_already_dead:
 | 
				
			||||||
	mutex_unlock(&ses->session_mutex);
 | 
						mutex_unlock(&ses->session_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1394,8 +1399,8 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
 | 
				
			||||||
 * Discard any remaining data in the current SMB. To do this, we borrow the
 | 
					 * Discard any remaining data in the current SMB. To do this, we borrow the
 | 
				
			||||||
 * current bigbuf.
 | 
					 * current bigbuf.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int
 | 
					int
 | 
				
			||||||
discard_remaining_data(struct TCP_Server_Info *server)
 | 
					cifs_discard_remaining_data(struct TCP_Server_Info *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int rfclen = get_rfc1002_length(server->smallbuf);
 | 
						unsigned int rfclen = get_rfc1002_length(server->smallbuf);
 | 
				
			||||||
	int remaining = rfclen + 4 - server->total_read;
 | 
						int remaining = rfclen + 4 - server->total_read;
 | 
				
			||||||
| 
						 | 
					@ -1421,7 +1426,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 | 
				
			||||||
	int length;
 | 
						int length;
 | 
				
			||||||
	struct cifs_readdata *rdata = mid->callback_data;
 | 
						struct cifs_readdata *rdata = mid->callback_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	length = discard_remaining_data(server);
 | 
						length = cifs_discard_remaining_data(server);
 | 
				
			||||||
	dequeue_mid(mid, rdata->result);
 | 
						dequeue_mid(mid, rdata->result);
 | 
				
			||||||
	return length;
 | 
						return length;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1454,7 +1459,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (server->ops->is_status_pending &&
 | 
						if (server->ops->is_status_pending &&
 | 
				
			||||||
	    server->ops->is_status_pending(buf, server, 0)) {
 | 
						    server->ops->is_status_pending(buf, server, 0)) {
 | 
				
			||||||
		discard_remaining_data(server);
 | 
							cifs_discard_remaining_data(server);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1507,10 +1512,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* set up first iov for signature check */
 | 
						/* set up first iov for signature check */
 | 
				
			||||||
	rdata->iov.iov_base = buf;
 | 
						rdata->iov[0].iov_base = buf;
 | 
				
			||||||
	rdata->iov.iov_len = server->total_read;
 | 
						rdata->iov[0].iov_len = 4;
 | 
				
			||||||
	cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
 | 
						rdata->iov[1].iov_base = buf + 4;
 | 
				
			||||||
		 rdata->iov.iov_base, rdata->iov.iov_len);
 | 
						rdata->iov[1].iov_len = server->total_read - 4;
 | 
				
			||||||
 | 
						cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
 | 
				
			||||||
 | 
							 rdata->iov[0].iov_base, server->total_read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* how much data is in the response? */
 | 
						/* how much data is in the response? */
 | 
				
			||||||
	data_len = server->ops->read_data_length(buf);
 | 
						data_len = server->ops->read_data_length(buf);
 | 
				
			||||||
| 
						 | 
					@ -1543,8 +1550,8 @@ cifs_readv_callback(struct mid_q_entry *mid)
 | 
				
			||||||
	struct cifs_readdata *rdata = mid->callback_data;
 | 
						struct cifs_readdata *rdata = mid->callback_data;
 | 
				
			||||||
	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 | 
						struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 | 
				
			||||||
	struct TCP_Server_Info *server = tcon->ses->server;
 | 
						struct TCP_Server_Info *server = tcon->ses->server;
 | 
				
			||||||
	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
 | 
						struct smb_rqst rqst = { .rq_iov = rdata->iov,
 | 
				
			||||||
				 .rq_nvec = 1,
 | 
									 .rq_nvec = 2,
 | 
				
			||||||
				 .rq_pages = rdata->pages,
 | 
									 .rq_pages = rdata->pages,
 | 
				
			||||||
				 .rq_npages = rdata->nr_pages,
 | 
									 .rq_npages = rdata->nr_pages,
 | 
				
			||||||
				 .rq_pagesz = rdata->pagesz,
 | 
									 .rq_pagesz = rdata->pagesz,
 | 
				
			||||||
| 
						 | 
					@ -1599,8 +1606,8 @@ cifs_async_readv(struct cifs_readdata *rdata)
 | 
				
			||||||
	READ_REQ *smb = NULL;
 | 
						READ_REQ *smb = NULL;
 | 
				
			||||||
	int wct;
 | 
						int wct;
 | 
				
			||||||
	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 | 
						struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 | 
				
			||||||
	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
 | 
						struct smb_rqst rqst = { .rq_iov = rdata->iov,
 | 
				
			||||||
				 .rq_nvec = 1 };
 | 
									 .rq_nvec = 2 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
 | 
						cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
 | 
				
			||||||
		 __func__, rdata->offset, rdata->bytes);
 | 
							 __func__, rdata->offset, rdata->bytes);
 | 
				
			||||||
| 
						 | 
					@ -1640,12 +1647,14 @@ cifs_async_readv(struct cifs_readdata *rdata)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 4 for RFC1001 length + 1 for BCC */
 | 
						/* 4 for RFC1001 length + 1 for BCC */
 | 
				
			||||||
	rdata->iov.iov_base = smb;
 | 
						rdata->iov[0].iov_base = smb;
 | 
				
			||||||
	rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 | 
						rdata->iov[0].iov_len = 4;
 | 
				
			||||||
 | 
						rdata->iov[1].iov_base = (char *)smb + 4;
 | 
				
			||||||
 | 
						rdata->iov[1].iov_len = get_rfc1002_length(smb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kref_get(&rdata->refcount);
 | 
						kref_get(&rdata->refcount);
 | 
				
			||||||
	rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
 | 
						rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
 | 
				
			||||||
			     cifs_readv_callback, rdata, 0);
 | 
								     cifs_readv_callback, NULL, rdata, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc == 0)
 | 
						if (rc == 0)
 | 
				
			||||||
		cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
 | 
							cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
 | 
				
			||||||
| 
						 | 
					@ -1667,6 +1676,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
 | 
				
			||||||
	int wct;
 | 
						int wct;
 | 
				
			||||||
	int resp_buf_type = 0;
 | 
						int resp_buf_type = 0;
 | 
				
			||||||
	struct kvec iov[1];
 | 
						struct kvec iov[1];
 | 
				
			||||||
 | 
						struct kvec rsp_iov;
 | 
				
			||||||
	__u32 pid = io_parms->pid;
 | 
						__u32 pid = io_parms->pid;
 | 
				
			||||||
	__u16 netfid = io_parms->netfid;
 | 
						__u16 netfid = io_parms->netfid;
 | 
				
			||||||
	__u64 offset = io_parms->offset;
 | 
						__u64 offset = io_parms->offset;
 | 
				
			||||||
| 
						 | 
					@ -1716,10 +1726,11 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iov[0].iov_base = (char *)pSMB;
 | 
						iov[0].iov_base = (char *)pSMB;
 | 
				
			||||||
	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 | 
						iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 | 
				
			||||||
	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
 | 
						rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
 | 
				
			||||||
			 &resp_buf_type, CIFS_LOG_ERROR);
 | 
								  CIFS_LOG_ERROR, &rsp_iov);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
 | 
						cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
 | 
				
			||||||
	pSMBr = (READ_RSP *)iov[0].iov_base;
 | 
						pSMBr = (READ_RSP *)rsp_iov.iov_base;
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		cifs_dbg(VFS, "Send error in read = %d\n", rc);
 | 
							cifs_dbg(VFS, "Send error in read = %d\n", rc);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -1747,12 +1758,11 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 | 
					 | 
				
			||||||
	if (*buf) {
 | 
						if (*buf) {
 | 
				
			||||||
		free_rsp_buf(resp_buf_type, iov[0].iov_base);
 | 
							free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
 | 
				
			||||||
	} else if (resp_buf_type != CIFS_NO_BUFFER) {
 | 
						} else if (resp_buf_type != CIFS_NO_BUFFER) {
 | 
				
			||||||
		/* return buffer to caller to free */
 | 
							/* return buffer to caller to free */
 | 
				
			||||||
		*buf = iov[0].iov_base;
 | 
							*buf = rsp_iov.iov_base;
 | 
				
			||||||
		if (resp_buf_type == CIFS_SMALL_BUFFER)
 | 
							if (resp_buf_type == CIFS_SMALL_BUFFER)
 | 
				
			||||||
			*pbuf_type = CIFS_SMALL_BUFFER;
 | 
								*pbuf_type = CIFS_SMALL_BUFFER;
 | 
				
			||||||
		else if (resp_buf_type == CIFS_LARGE_BUFFER)
 | 
							else if (resp_buf_type == CIFS_LARGE_BUFFER)
 | 
				
			||||||
| 
						 | 
					@ -2093,7 +2103,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
 | 
				
			||||||
	WRITE_REQ *smb = NULL;
 | 
						WRITE_REQ *smb = NULL;
 | 
				
			||||||
	int wct;
 | 
						int wct;
 | 
				
			||||||
	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
 | 
						struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
 | 
				
			||||||
	struct kvec iov;
 | 
						struct kvec iov[2];
 | 
				
			||||||
	struct smb_rqst rqst = { };
 | 
						struct smb_rqst rqst = { };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
 | 
						if (tcon->ses->capabilities & CAP_LARGE_FILES) {
 | 
				
			||||||
| 
						 | 
					@ -2126,11 +2136,13 @@ cifs_async_writev(struct cifs_writedata *wdata,
 | 
				
			||||||
	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 | 
						    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 4 for RFC1001 length + 1 for BCC */
 | 
						/* 4 for RFC1001 length + 1 for BCC */
 | 
				
			||||||
	iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
 | 
						iov[0].iov_len = 4;
 | 
				
			||||||
	iov.iov_base = smb;
 | 
						iov[0].iov_base = smb;
 | 
				
			||||||
 | 
						iov[1].iov_len = get_rfc1002_length(smb) + 1;
 | 
				
			||||||
 | 
						iov[1].iov_base = (char *)smb + 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rqst.rq_iov = &iov;
 | 
						rqst.rq_iov = iov;
 | 
				
			||||||
	rqst.rq_nvec = 1;
 | 
						rqst.rq_nvec = 2;
 | 
				
			||||||
	rqst.rq_pages = wdata->pages;
 | 
						rqst.rq_pages = wdata->pages;
 | 
				
			||||||
	rqst.rq_npages = wdata->nr_pages;
 | 
						rqst.rq_npages = wdata->nr_pages;
 | 
				
			||||||
	rqst.rq_pagesz = wdata->pagesz;
 | 
						rqst.rq_pagesz = wdata->pagesz;
 | 
				
			||||||
| 
						 | 
					@ -2151,12 +2163,12 @@ cifs_async_writev(struct cifs_writedata *wdata,
 | 
				
			||||||
				(struct smb_com_writex_req *)smb;
 | 
									(struct smb_com_writex_req *)smb;
 | 
				
			||||||
		inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
 | 
							inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
 | 
				
			||||||
		put_bcc(wdata->bytes + 5, &smbw->hdr);
 | 
							put_bcc(wdata->bytes + 5, &smbw->hdr);
 | 
				
			||||||
		iov.iov_len += 4; /* pad bigger by four bytes */
 | 
							iov[1].iov_len += 4; /* pad bigger by four bytes */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kref_get(&wdata->refcount);
 | 
						kref_get(&wdata->refcount);
 | 
				
			||||||
	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
 | 
						rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
 | 
				
			||||||
				cifs_writev_callback, wdata, 0);
 | 
									cifs_writev_callback, NULL, wdata, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc == 0)
 | 
						if (rc == 0)
 | 
				
			||||||
		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 | 
							cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 | 
				
			||||||
| 
						 | 
					@ -2182,6 +2194,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
 | 
				
			||||||
	__u64 offset = io_parms->offset;
 | 
						__u64 offset = io_parms->offset;
 | 
				
			||||||
	struct cifs_tcon *tcon = io_parms->tcon;
 | 
						struct cifs_tcon *tcon = io_parms->tcon;
 | 
				
			||||||
	unsigned int count = io_parms->length;
 | 
						unsigned int count = io_parms->length;
 | 
				
			||||||
 | 
						struct kvec rsp_iov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*nbytes = 0;
 | 
						*nbytes = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2240,8 +2253,9 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
 | 
				
			||||||
	else /* wct == 12 pad bigger by four bytes */
 | 
						else /* wct == 12 pad bigger by four bytes */
 | 
				
			||||||
		iov[0].iov_len = smb_hdr_len + 8;
 | 
							iov[0].iov_len = smb_hdr_len + 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
 | 
				
			||||||
	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
 | 
								  &rsp_iov);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 | 
						cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
 | 
							cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
 | 
				
			||||||
| 
						 | 
					@ -2249,7 +2263,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
 | 
				
			||||||
		/* presumably this can not happen, but best to be safe */
 | 
							/* presumably this can not happen, but best to be safe */
 | 
				
			||||||
		rc = -EIO;
 | 
							rc = -EIO;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
 | 
							WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
 | 
				
			||||||
		*nbytes = le16_to_cpu(pSMBr->CountHigh);
 | 
							*nbytes = le16_to_cpu(pSMBr->CountHigh);
 | 
				
			||||||
		*nbytes = (*nbytes) << 16;
 | 
							*nbytes = (*nbytes) << 16;
 | 
				
			||||||
		*nbytes += le16_to_cpu(pSMBr->Count);
 | 
							*nbytes += le16_to_cpu(pSMBr->Count);
 | 
				
			||||||
| 
						 | 
					@ -2263,8 +2277,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
 | 
				
			||||||
			*nbytes &= 0xFFFF;
 | 
								*nbytes &= 0xFFFF;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 | 
						free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
 | 
				
			||||||
	free_rsp_buf(resp_buf_type, iov[0].iov_base);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: On -EAGAIN error only caller can retry on handle based calls
 | 
						/* Note: On -EAGAIN error only caller can retry on handle based calls
 | 
				
			||||||
		since file handle passed in no longer valid */
 | 
							since file handle passed in no longer valid */
 | 
				
			||||||
| 
						 | 
					@ -2279,6 +2292,7 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	LOCK_REQ *pSMB = NULL;
 | 
						LOCK_REQ *pSMB = NULL;
 | 
				
			||||||
	struct kvec iov[2];
 | 
						struct kvec iov[2];
 | 
				
			||||||
 | 
						struct kvec rsp_iov;
 | 
				
			||||||
	int resp_buf_type;
 | 
						int resp_buf_type;
 | 
				
			||||||
	__u16 count;
 | 
						__u16 count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2307,7 +2321,9 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
 | 
						iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
 | 
						cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
 | 
				
			||||||
	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
 | 
						rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
 | 
				
			||||||
 | 
								  &rsp_iov);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
 | 
							cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2368,14 +2384,12 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	inc_rfc1001_len(pSMB, count);
 | 
						inc_rfc1001_len(pSMB, count);
 | 
				
			||||||
	pSMB->ByteCount = cpu_to_le16(count);
 | 
						pSMB->ByteCount = cpu_to_le16(count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (waitFlag) {
 | 
						if (waitFlag)
 | 
				
			||||||
		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
 | 
							rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
 | 
				
			||||||
			(struct smb_hdr *) pSMB, &bytes_returned);
 | 
								(struct smb_hdr *) pSMB, &bytes_returned);
 | 
				
			||||||
		cifs_small_buf_release(pSMB);
 | 
						else
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
 | 
							rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
 | 
				
			||||||
		/* SMB buffer freed by function above */
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
 | 
						cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
 | 
							cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
 | 
				
			||||||
| 
						 | 
					@ -2401,6 +2415,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	int resp_buf_type = 0;
 | 
						int resp_buf_type = 0;
 | 
				
			||||||
	__u16 params, param_offset, offset, byte_count, count;
 | 
						__u16 params, param_offset, offset, byte_count, count;
 | 
				
			||||||
	struct kvec iov[1];
 | 
						struct kvec iov[1];
 | 
				
			||||||
 | 
						struct kvec rsp_iov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_dbg(FYI, "Posix Lock\n");
 | 
						cifs_dbg(FYI, "Posix Lock\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2462,11 +2477,10 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
		iov[0].iov_base = (char *)pSMB;
 | 
							iov[0].iov_base = (char *)pSMB;
 | 
				
			||||||
		iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 | 
							iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 | 
				
			||||||
		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
 | 
							rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
 | 
				
			||||||
				&resp_buf_type, timeout);
 | 
									&resp_buf_type, timeout, &rsp_iov);
 | 
				
			||||||
		pSMB = NULL; /* request buf already freed by SendReceive2. Do
 | 
							pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
 | 
				
			||||||
				not try to free it twice below on exit */
 | 
					 | 
				
			||||||
		pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
 | 
							cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
 | 
				
			||||||
| 
						 | 
					@ -2506,10 +2520,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plk_err_exit:
 | 
					plk_err_exit:
 | 
				
			||||||
	if (pSMB)
 | 
						free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
 | 
				
			||||||
		cifs_small_buf_release(pSMB);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free_rsp_buf(resp_buf_type, iov[0].iov_base);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: On -EAGAIN error only caller can retry on handle based calls
 | 
						/* Note: On -EAGAIN error only caller can retry on handle based calls
 | 
				
			||||||
	   since file handle passed in no longer valid */
 | 
						   since file handle passed in no longer valid */
 | 
				
			||||||
| 
						 | 
					@ -2536,6 +2547,7 @@ CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
 | 
				
			||||||
	pSMB->LastWriteTime = 0xFFFFFFFF;
 | 
						pSMB->LastWriteTime = 0xFFFFFFFF;
 | 
				
			||||||
	pSMB->ByteCount = 0;
 | 
						pSMB->ByteCount = 0;
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
						rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
 | 
						cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		if (rc != -EINTR) {
 | 
							if (rc != -EINTR) {
 | 
				
			||||||
| 
						 | 
					@ -2565,6 +2577,7 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
 | 
				
			||||||
	pSMB->FileID = (__u16) smb_file_id;
 | 
						pSMB->FileID = (__u16) smb_file_id;
 | 
				
			||||||
	pSMB->ByteCount = 0;
 | 
						pSMB->ByteCount = 0;
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
						rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
 | 
						cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
 | 
							cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
 | 
				
			||||||
| 
						 | 
					@ -3820,6 +3833,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
 | 
				
			||||||
	int buf_type = 0;
 | 
						int buf_type = 0;
 | 
				
			||||||
	QUERY_SEC_DESC_REQ *pSMB;
 | 
						QUERY_SEC_DESC_REQ *pSMB;
 | 
				
			||||||
	struct kvec iov[1];
 | 
						struct kvec iov[1];
 | 
				
			||||||
 | 
						struct kvec rsp_iov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_dbg(FYI, "GetCifsACL\n");
 | 
						cifs_dbg(FYI, "GetCifsACL\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3843,7 +3857,8 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
 | 
				
			||||||
	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 | 
						iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
 | 
						rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
 | 
				
			||||||
			 0);
 | 
								  0, &rsp_iov);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
 | 
						cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
 | 
							cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
 | 
				
			||||||
| 
						 | 
					@ -3855,11 +3870,11 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
 | 
				
			||||||
		char *pdata;
 | 
							char *pdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* validate_nttransact */
 | 
					/* validate_nttransact */
 | 
				
			||||||
		rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
 | 
							rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
 | 
				
			||||||
					&pdata, &parm_len, pbuflen);
 | 
										&pdata, &parm_len, pbuflen);
 | 
				
			||||||
		if (rc)
 | 
							if (rc)
 | 
				
			||||||
			goto qsec_out;
 | 
								goto qsec_out;
 | 
				
			||||||
		pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
 | 
							pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cifs_dbg(FYI, "smb %p parm %p data %p\n",
 | 
							cifs_dbg(FYI, "smb %p parm %p data %p\n",
 | 
				
			||||||
			 pSMBr, parm, *acl_inf);
 | 
								 pSMBr, parm, *acl_inf);
 | 
				
			||||||
| 
						 | 
					@ -3896,8 +3911,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
qsec_out:
 | 
					qsec_out:
 | 
				
			||||||
	free_rsp_buf(buf_type, iov[0].iov_base);
 | 
						free_rsp_buf(buf_type, rsp_iov.iov_base);
 | 
				
			||||||
/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 | 
					 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4666,6 +4680,7 @@ CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	pSMB->FileID = searchHandle;
 | 
						pSMB->FileID = searchHandle;
 | 
				
			||||||
	pSMB->ByteCount = 0;
 | 
						pSMB->ByteCount = 0;
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
						rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
 | 
							cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5687,6 +5702,7 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	inc_rfc1001_len(pSMB, byte_count);
 | 
						inc_rfc1001_len(pSMB, byte_count);
 | 
				
			||||||
	pSMB->ByteCount = cpu_to_le16(byte_count);
 | 
						pSMB->ByteCount = cpu_to_le16(byte_count);
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
						rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
 | 
							cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
 | 
				
			||||||
			 rc);
 | 
								 rc);
 | 
				
			||||||
| 
						 | 
					@ -5758,6 +5774,7 @@ CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	pSMB->ByteCount = cpu_to_le16(byte_count);
 | 
						pSMB->ByteCount = cpu_to_le16(byte_count);
 | 
				
			||||||
	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
 | 
						memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
						rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
 | 
							cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
 | 
				
			||||||
			 rc);
 | 
								 rc);
 | 
				
			||||||
| 
						 | 
					@ -5818,6 +5835,7 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	pSMB->ByteCount = cpu_to_le16(byte_count);
 | 
						pSMB->ByteCount = cpu_to_le16(byte_count);
 | 
				
			||||||
	*data_offset = delete_file ? 1 : 0;
 | 
						*data_offset = delete_file ? 1 : 0;
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
						rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
 | 
							cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6057,6 +6075,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
 | 
						cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
						rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 | 
				
			||||||
 | 
						cifs_small_buf_release(pSMB);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
 | 
							cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
 | 
				
			||||||
			 rc);
 | 
								 rc);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -787,6 +787,15 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dump_smb(buf, server->total_read);
 | 
						dump_smb(buf, server->total_read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cifs_handle_standard(server, mid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
 | 
				
			||||||
 | 
						int length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * We know that we received enough to get to the MID as we
 | 
						 * We know that we received enough to get to the MID as we
 | 
				
			||||||
	 * checked the pdu_length earlier. Now check to see
 | 
						 * checked the pdu_length earlier. Now check to see
 | 
				
			||||||
| 
						 | 
					@ -872,12 +881,19 @@ cifs_demultiplex_thread(void *p)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		server->total_read += length;
 | 
							server->total_read += length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (server->ops->is_transform_hdr &&
 | 
				
			||||||
 | 
							    server->ops->receive_transform &&
 | 
				
			||||||
 | 
							    server->ops->is_transform_hdr(buf)) {
 | 
				
			||||||
 | 
								length = server->ops->receive_transform(server,
 | 
				
			||||||
 | 
													&mid_entry);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			mid_entry = server->ops->find_mid(server, buf);
 | 
								mid_entry = server->ops->find_mid(server, buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!mid_entry || !mid_entry->receive)
 | 
								if (!mid_entry || !mid_entry->receive)
 | 
				
			||||||
				length = standard_receive3(server, mid_entry);
 | 
									length = standard_receive3(server, mid_entry);
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				length = mid_entry->receive(server, mid_entry);
 | 
									length = mid_entry->receive(server, mid_entry);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (length < 0)
 | 
							if (length < 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
| 
						 | 
					@ -2154,7 +2170,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
 | 
				
			||||||
	server->tcpStatus = CifsExiting;
 | 
						server->tcpStatus = CifsExiting;
 | 
				
			||||||
	spin_unlock(&GlobalMid_Lock);
 | 
						spin_unlock(&GlobalMid_Lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_crypto_shash_release(server);
 | 
						cifs_crypto_secmech_release(server);
 | 
				
			||||||
	cifs_fscache_release_client_cookie(server);
 | 
						cifs_fscache_release_client_cookie(server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(server->session_key.response);
 | 
						kfree(server->session_key.response);
 | 
				
			||||||
| 
						 | 
					@ -2273,7 +2289,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
 | 
				
			||||||
	return tcp_ses;
 | 
						return tcp_ses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_err_crypto_release:
 | 
					out_err_crypto_release:
 | 
				
			||||||
	cifs_crypto_shash_release(tcp_ses);
 | 
						cifs_crypto_secmech_release(tcp_ses);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	put_net(cifs_net_ns(tcp_ses));
 | 
						put_net(cifs_net_ns(tcp_ses));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2614,12 +2630,18 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 | 
				
			||||||
	return ERR_PTR(rc);
 | 
						return ERR_PTR(rc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int match_tcon(struct cifs_tcon *tcon, const char *unc)
 | 
					static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (tcon->tidStatus == CifsExiting)
 | 
						if (tcon->tidStatus == CifsExiting)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
 | 
						if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
						if (tcon->seal != volume_info->seal)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					#ifdef CONFIG_CIFS_SMB2
 | 
				
			||||||
 | 
						if (tcon->snapshot_time != volume_info->snapshot_time)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					#endif /* CONFIG_CIFS_SMB2 */
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2632,14 +2654,8 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 | 
				
			||||||
	spin_lock(&cifs_tcp_ses_lock);
 | 
						spin_lock(&cifs_tcp_ses_lock);
 | 
				
			||||||
	list_for_each(tmp, &ses->tcon_list) {
 | 
						list_for_each(tmp, &ses->tcon_list) {
 | 
				
			||||||
		tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
 | 
							tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
 | 
				
			||||||
		if (!match_tcon(tcon, volume_info->UNC))
 | 
							if (!match_tcon(tcon, volume_info))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_CIFS_SMB2
 | 
					 | 
				
			||||||
		if (tcon->snapshot_time != volume_info->snapshot_time)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
#endif /* CONFIG_CIFS_SMB2 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		++tcon->tc_count;
 | 
							++tcon->tc_count;
 | 
				
			||||||
		spin_unlock(&cifs_tcp_ses_lock);
 | 
							spin_unlock(&cifs_tcp_ses_lock);
 | 
				
			||||||
		return tcon;
 | 
							return tcon;
 | 
				
			||||||
| 
						 | 
					@ -2685,8 +2701,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 | 
				
			||||||
		cifs_dbg(FYI, "Found match on UNC path\n");
 | 
							cifs_dbg(FYI, "Found match on UNC path\n");
 | 
				
			||||||
		/* existing tcon already has a reference */
 | 
							/* existing tcon already has a reference */
 | 
				
			||||||
		cifs_put_smb_ses(ses);
 | 
							cifs_put_smb_ses(ses);
 | 
				
			||||||
		if (tcon->seal != volume_info->seal)
 | 
					 | 
				
			||||||
			cifs_dbg(VFS, "transport encryption setting conflicts with existing tid\n");
 | 
					 | 
				
			||||||
		return tcon;
 | 
							return tcon;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2742,7 +2756,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 | 
				
			||||||
		tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
 | 
							tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
 | 
				
			||||||
		cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
 | 
							cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tcon->seal = volume_info->seal;
 | 
					 | 
				
			||||||
	tcon->use_persistent = false;
 | 
						tcon->use_persistent = false;
 | 
				
			||||||
	/* check if SMB2 or later, CIFS does not support persistent handles */
 | 
						/* check if SMB2 or later, CIFS does not support persistent handles */
 | 
				
			||||||
	if (volume_info->persistent) {
 | 
						if (volume_info->persistent) {
 | 
				
			||||||
| 
						 | 
					@ -2779,6 +2792,24 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 | 
				
			||||||
		tcon->use_resilient = true;
 | 
							tcon->use_resilient = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (volume_info->seal) {
 | 
				
			||||||
 | 
							if (ses->server->vals->protocol_id == 0) {
 | 
				
			||||||
 | 
								cifs_dbg(VFS,
 | 
				
			||||||
 | 
									 "SMB3 or later required for encryption\n");
 | 
				
			||||||
 | 
								rc = -EOPNOTSUPP;
 | 
				
			||||||
 | 
								goto out_fail;
 | 
				
			||||||
 | 
					#ifdef CONFIG_CIFS_SMB2
 | 
				
			||||||
 | 
							} else if (tcon->ses->server->capabilities &
 | 
				
			||||||
 | 
										SMB2_GLOBAL_CAP_ENCRYPTION)
 | 
				
			||||||
 | 
								tcon->seal = true;
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								cifs_dbg(VFS, "Encryption is not supported on share\n");
 | 
				
			||||||
 | 
								rc = -EOPNOTSUPP;
 | 
				
			||||||
 | 
								goto out_fail;
 | 
				
			||||||
 | 
					#endif /* CONFIG_CIFS_SMB2 */
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * We can have only one retry value for a connection to a share so for
 | 
						 * We can have only one retry value for a connection to a share so for
 | 
				
			||||||
	 * resources mounted more than once to the same server share the last
 | 
						 * resources mounted more than once to the same server share the last
 | 
				
			||||||
| 
						 | 
					@ -2910,7 +2941,7 @@ cifs_match_super(struct super_block *sb, void *data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!match_server(tcp_srv, volume_info) ||
 | 
						if (!match_server(tcp_srv, volume_info) ||
 | 
				
			||||||
	    !match_session(ses, volume_info) ||
 | 
						    !match_session(ses, volume_info) ||
 | 
				
			||||||
	    !match_tcon(tcon, volume_info->UNC) ||
 | 
						    !match_tcon(tcon, volume_info) ||
 | 
				
			||||||
	    !match_prepath(sb, mnt_data)) {
 | 
						    !match_prepath(sb, mnt_data)) {
 | 
				
			||||||
		rc = 0;
 | 
							rc = 0;
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2884,7 +2884,15 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter)
 | 
				
			||||||
	for (i = 0; i < rdata->nr_pages; i++) {
 | 
						for (i = 0; i < rdata->nr_pages; i++) {
 | 
				
			||||||
		struct page *page = rdata->pages[i];
 | 
							struct page *page = rdata->pages[i];
 | 
				
			||||||
		size_t copy = min_t(size_t, remaining, PAGE_SIZE);
 | 
							size_t copy = min_t(size_t, remaining, PAGE_SIZE);
 | 
				
			||||||
		size_t written = copy_page_to_iter(page, 0, copy, iter);
 | 
							size_t written;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (unlikely(iter->type & ITER_PIPE)) {
 | 
				
			||||||
 | 
								void *addr = kmap_atomic(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								written = copy_to_iter(addr, copy, iter);
 | 
				
			||||||
 | 
								kunmap_atomic(addr);
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								written = copy_page_to_iter(page, 0, copy, iter);
 | 
				
			||||||
		remaining -= written;
 | 
							remaining -= written;
 | 
				
			||||||
		if (written < copy && iov_iter_count(iter) > 0)
 | 
							if (written < copy && iov_iter_count(iter) > 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -2903,8 +2911,9 @@ cifs_uncached_readv_complete(struct work_struct *work)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
 | 
					uncached_fill_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
			struct cifs_readdata *rdata, unsigned int len)
 | 
							    struct cifs_readdata *rdata, struct iov_iter *iter,
 | 
				
			||||||
 | 
							    unsigned int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int result = 0;
 | 
						int result = 0;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
| 
						 | 
					@ -2933,6 +2942,9 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
			rdata->tailsz = len;
 | 
								rdata->tailsz = len;
 | 
				
			||||||
			len = 0;
 | 
								len = 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (iter)
 | 
				
			||||||
 | 
								result = copy_page_from_iter(page, 0, n, iter);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
			result = cifs_read_page_from_socket(server, page, n);
 | 
								result = cifs_read_page_from_socket(server, page, n);
 | 
				
			||||||
		if (result < 0)
 | 
							if (result < 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -2944,6 +2956,21 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
						rdata->got_bytes : result;
 | 
											rdata->got_bytes : result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
								      struct cifs_readdata *rdata, unsigned int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return uncached_fill_pages(server, rdata, NULL, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					cifs_uncached_copy_into_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
								      struct cifs_readdata *rdata,
 | 
				
			||||||
 | 
								      struct iov_iter *iter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return uncached_fill_pages(server, rdata, iter, iter->count);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
 | 
					cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
 | 
				
			||||||
		     struct cifs_sb_info *cifs_sb, struct list_head *rdata_list)
 | 
							     struct cifs_sb_info *cifs_sb, struct list_head *rdata_list)
 | 
				
			||||||
| 
						 | 
					@ -2991,6 +3018,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
 | 
				
			||||||
		rdata->pid = pid;
 | 
							rdata->pid = pid;
 | 
				
			||||||
		rdata->pagesz = PAGE_SIZE;
 | 
							rdata->pagesz = PAGE_SIZE;
 | 
				
			||||||
		rdata->read_into_pages = cifs_uncached_read_into_pages;
 | 
							rdata->read_into_pages = cifs_uncached_read_into_pages;
 | 
				
			||||||
 | 
							rdata->copy_into_pages = cifs_uncached_copy_into_pages;
 | 
				
			||||||
		rdata->credits = credits;
 | 
							rdata->credits = credits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!rdata->cfile->invalidHandle ||
 | 
							if (!rdata->cfile->invalidHandle ||
 | 
				
			||||||
| 
						 | 
					@ -3341,8 +3369,9 @@ cifs_readv_complete(struct work_struct *work)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
 | 
					readpages_fill_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
			struct cifs_readdata *rdata, unsigned int len)
 | 
							     struct cifs_readdata *rdata, struct iov_iter *iter,
 | 
				
			||||||
 | 
							     unsigned int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int result = 0;
 | 
						int result = 0;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
| 
						 | 
					@ -3396,6 +3425,9 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (iter)
 | 
				
			||||||
 | 
								result = copy_page_from_iter(page, 0, n, iter);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
			result = cifs_read_page_from_socket(server, page, n);
 | 
								result = cifs_read_page_from_socket(server, page, n);
 | 
				
			||||||
		if (result < 0)
 | 
							if (result < 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -3407,6 +3439,21 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
						rdata->got_bytes : result;
 | 
											rdata->got_bytes : result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
								       struct cifs_readdata *rdata, unsigned int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return readpages_fill_pages(server, rdata, NULL, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					cifs_readpages_copy_into_pages(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
								       struct cifs_readdata *rdata,
 | 
				
			||||||
 | 
								       struct iov_iter *iter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return readpages_fill_pages(server, rdata, iter, iter->count);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
 | 
					readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
 | 
				
			||||||
		    unsigned int rsize, struct list_head *tmplist,
 | 
							    unsigned int rsize, struct list_head *tmplist,
 | 
				
			||||||
| 
						 | 
					@ -3561,6 +3608,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 | 
				
			||||||
		rdata->pid = pid;
 | 
							rdata->pid = pid;
 | 
				
			||||||
		rdata->pagesz = PAGE_SIZE;
 | 
							rdata->pagesz = PAGE_SIZE;
 | 
				
			||||||
		rdata->read_into_pages = cifs_readpages_read_into_pages;
 | 
							rdata->read_into_pages = cifs_readpages_read_into_pages;
 | 
				
			||||||
 | 
							rdata->copy_into_pages = cifs_readpages_copy_into_pages;
 | 
				
			||||||
		rdata->credits = credits;
 | 
							rdata->credits = credits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		list_for_each_entry_safe(page, tpage, &tmplist, lru) {
 | 
							list_for_each_entry_safe(page, tpage, &tmplist, lru) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -344,13 +344,12 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
 | 
				
			||||||
	/* BB is NTLMV2 session security format easier to use here? */
 | 
						/* BB is NTLMV2 session security format easier to use here? */
 | 
				
			||||||
	flags = NTLMSSP_NEGOTIATE_56 |	NTLMSSP_REQUEST_TARGET |
 | 
						flags = NTLMSSP_NEGOTIATE_56 |	NTLMSSP_REQUEST_TARGET |
 | 
				
			||||||
		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
 | 
							NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
 | 
				
			||||||
		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
 | 
							NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
 | 
				
			||||||
	if (ses->server->sign) {
 | 
							NTLMSSP_NEGOTIATE_SEAL;
 | 
				
			||||||
 | 
						if (ses->server->sign)
 | 
				
			||||||
		flags |= NTLMSSP_NEGOTIATE_SIGN;
 | 
							flags |= NTLMSSP_NEGOTIATE_SIGN;
 | 
				
			||||||
		if (!ses->server->session_estab ||
 | 
						if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
 | 
				
			||||||
				ses->ntlmssp->sesskey_per_smbsess)
 | 
					 | 
				
			||||||
		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 | 
							flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec_blob->NegotiateFlags = cpu_to_le32(flags);
 | 
						sec_blob->NegotiateFlags = cpu_to_le32(flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -407,13 +406,12 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
 | 
				
			||||||
	flags = NTLMSSP_NEGOTIATE_56 |
 | 
						flags = NTLMSSP_NEGOTIATE_56 |
 | 
				
			||||||
		NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
 | 
							NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
 | 
				
			||||||
		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
 | 
							NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
 | 
				
			||||||
		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
 | 
							NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
 | 
				
			||||||
	if (ses->server->sign) {
 | 
							NTLMSSP_NEGOTIATE_SEAL;
 | 
				
			||||||
 | 
						if (ses->server->sign)
 | 
				
			||||||
		flags |= NTLMSSP_NEGOTIATE_SIGN;
 | 
							flags |= NTLMSSP_NEGOTIATE_SIGN;
 | 
				
			||||||
		if (!ses->server->session_estab ||
 | 
						if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
 | 
				
			||||||
				ses->ntlmssp->sesskey_per_smbsess)
 | 
					 | 
				
			||||||
		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 | 
							flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
 | 
						tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
 | 
				
			||||||
	sec_blob->NegotiateFlags = cpu_to_le32(flags);
 | 
						sec_blob->NegotiateFlags = cpu_to_le32(flags);
 | 
				
			||||||
| 
						 | 
					@ -652,6 +650,7 @@ sess_sendreceive(struct sess_data *sess_data)
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base;
 | 
						struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base;
 | 
				
			||||||
	__u16 count;
 | 
						__u16 count;
 | 
				
			||||||
 | 
						struct kvec rsp_iov = { NULL, 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
 | 
						count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
 | 
				
			||||||
	smb_buf->smb_buf_length =
 | 
						smb_buf->smb_buf_length =
 | 
				
			||||||
| 
						 | 
					@ -661,7 +660,9 @@ sess_sendreceive(struct sess_data *sess_data)
 | 
				
			||||||
	rc = SendReceive2(sess_data->xid, sess_data->ses,
 | 
						rc = SendReceive2(sess_data->xid, sess_data->ses,
 | 
				
			||||||
			  sess_data->iov, 3 /* num_iovecs */,
 | 
								  sess_data->iov, 3 /* num_iovecs */,
 | 
				
			||||||
			  &sess_data->buf0_type,
 | 
								  &sess_data->buf0_type,
 | 
				
			||||||
			  CIFS_LOG_ERROR);
 | 
								  CIFS_LOG_ERROR, &rsp_iov);
 | 
				
			||||||
 | 
						cifs_small_buf_release(sess_data->iov[0].iov_base);
 | 
				
			||||||
 | 
						memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,11 +36,11 @@
 | 
				
			||||||
 * SMB_COM_NT_CANCEL request and then sends it.
 | 
					 * SMB_COM_NT_CANCEL request and then sends it.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
send_nt_cancel(struct TCP_Server_Info *server, void *buf,
 | 
					send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 | 
				
			||||||
	       struct mid_q_entry *mid)
 | 
						       struct mid_q_entry *mid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	struct smb_hdr *in_buf = (struct smb_hdr *)buf;
 | 
						struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* -4 for RFC1001 length and +2 for BCC field */
 | 
						/* -4 for RFC1001 length and +2 for BCC field */
 | 
				
			||||||
	in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4  + 2);
 | 
						in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4  + 2);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,4 +61,9 @@
 | 
				
			||||||
/* Maximum buffer size value we can send with 1 credit */
 | 
					/* Maximum buffer size value we can send with 1 credit */
 | 
				
			||||||
#define SMB2_MAX_BUFFER_SIZE 65536
 | 
					#define SMB2_MAX_BUFFER_SIZE 65536
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct smb2_sync_hdr *get_sync_hdr(void *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return &(((struct smb2_hdr *)buf)->sync_hdr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif	/* _SMB2_GLOB_H */
 | 
					#endif	/* _SMB2_GLOB_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
#include "smb2pdu.h"
 | 
					#include "smb2pdu.h"
 | 
				
			||||||
#include "smb2proto.h"
 | 
					#include "smb2proto.h"
 | 
				
			||||||
#include "smb2status.h"
 | 
					#include "smb2status.h"
 | 
				
			||||||
 | 
					#include "smb2glob.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct status_to_posix_error {
 | 
					struct status_to_posix_error {
 | 
				
			||||||
	__le32 smb2_status;
 | 
						__le32 smb2_status;
 | 
				
			||||||
| 
						 | 
					@ -2449,10 +2450,10 @@ smb2_print_status(__le32 status)
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
map_smb2_to_linux_error(char *buf, bool log_err)
 | 
					map_smb2_to_linux_error(char *buf, bool log_err)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	int rc = -EIO;
 | 
						int rc = -EIO;
 | 
				
			||||||
	__le32 smb2err = hdr->Status;
 | 
						__le32 smb2err = shdr->Status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (smb2err == 0)
 | 
						if (smb2err == 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,31 +28,32 @@
 | 
				
			||||||
#include "cifs_debug.h"
 | 
					#include "cifs_debug.h"
 | 
				
			||||||
#include "cifs_unicode.h"
 | 
					#include "cifs_unicode.h"
 | 
				
			||||||
#include "smb2status.h"
 | 
					#include "smb2status.h"
 | 
				
			||||||
 | 
					#include "smb2glob.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
 | 
					check_smb2_hdr(struct smb2_sync_hdr *shdr, __u64 mid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__u64 wire_mid = le64_to_cpu(hdr->MessageId);
 | 
						__u64 wire_mid = le64_to_cpu(shdr->MessageId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Make sure that this really is an SMB, that it is a response,
 | 
						 * Make sure that this really is an SMB, that it is a response,
 | 
				
			||||||
	 * and that the message ids match.
 | 
						 * and that the message ids match.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if ((hdr->ProtocolId == SMB2_PROTO_NUMBER) &&
 | 
						if ((shdr->ProtocolId == SMB2_PROTO_NUMBER) &&
 | 
				
			||||||
	    (mid == wire_mid)) {
 | 
						    (mid == wire_mid)) {
 | 
				
			||||||
		if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
 | 
							if (shdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			/* only one valid case where server sends us request */
 | 
								/* only one valid case where server sends us request */
 | 
				
			||||||
			if (hdr->Command == SMB2_OPLOCK_BREAK)
 | 
								if (shdr->Command == SMB2_OPLOCK_BREAK)
 | 
				
			||||||
				return 0;
 | 
									return 0;
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				cifs_dbg(VFS, "Received Request not response\n");
 | 
									cifs_dbg(VFS, "Received Request not response\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else { /* bad signature or mid */
 | 
						} else { /* bad signature or mid */
 | 
				
			||||||
		if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
 | 
							if (shdr->ProtocolId != SMB2_PROTO_NUMBER)
 | 
				
			||||||
			cifs_dbg(VFS, "Bad protocol string signature header %x\n",
 | 
								cifs_dbg(VFS, "Bad protocol string signature header %x\n",
 | 
				
			||||||
				 le32_to_cpu(hdr->ProtocolId));
 | 
									 le32_to_cpu(shdr->ProtocolId));
 | 
				
			||||||
		if (mid != wire_mid)
 | 
							if (mid != wire_mid)
 | 
				
			||||||
			cifs_dbg(VFS, "Mids do not match: %llu and %llu\n",
 | 
								cifs_dbg(VFS, "Mids do not match: %llu and %llu\n",
 | 
				
			||||||
				 mid, wire_mid);
 | 
									 mid, wire_mid);
 | 
				
			||||||
| 
						 | 
					@ -95,8 +96,9 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 | 
					smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
 | 
						struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
 | 
				
			||||||
	struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
 | 
						struct smb2_hdr *hdr = &pdu->hdr;
 | 
				
			||||||
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 | 
				
			||||||
	__u64 mid;
 | 
						__u64 mid;
 | 
				
			||||||
	__u32 len = get_rfc1002_length(buf);
 | 
						__u32 len = get_rfc1002_length(buf);
 | 
				
			||||||
	__u32 clc_len;  /* calculated length */
 | 
						__u32 clc_len;  /* calculated length */
 | 
				
			||||||
| 
						 | 
					@ -111,7 +113,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 | 
				
			||||||
	 * ie Validate the wct via smb2_struct_sizes table above
 | 
						 * ie Validate the wct via smb2_struct_sizes table above
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
 | 
						if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
 | 
				
			||||||
		struct smb2_transform_hdr *thdr =
 | 
							struct smb2_transform_hdr *thdr =
 | 
				
			||||||
			(struct smb2_transform_hdr *)buf;
 | 
								(struct smb2_transform_hdr *)buf;
 | 
				
			||||||
		struct cifs_ses *ses = NULL;
 | 
							struct cifs_ses *ses = NULL;
 | 
				
			||||||
| 
						 | 
					@ -133,10 +135,10 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mid = le64_to_cpu(shdr->MessageId);
 | 
				
			||||||
	mid = le64_to_cpu(hdr->MessageId);
 | 
					 | 
				
			||||||
	if (length < sizeof(struct smb2_pdu)) {
 | 
						if (length < sizeof(struct smb2_pdu)) {
 | 
				
			||||||
		if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) {
 | 
							if ((length >= sizeof(struct smb2_hdr))
 | 
				
			||||||
 | 
							    && (shdr->Status != 0)) {
 | 
				
			||||||
			pdu->StructureSize2 = 0;
 | 
								pdu->StructureSize2 = 0;
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * As with SMB/CIFS, on some error cases servers may
 | 
								 * As with SMB/CIFS, on some error cases servers may
 | 
				
			||||||
| 
						 | 
					@ -154,29 +156,30 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (check_smb2_hdr(hdr, mid))
 | 
						if (check_smb2_hdr(shdr, mid))
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
 | 
						if (shdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
 | 
				
			||||||
		cifs_dbg(VFS, "Illegal structure size %u\n",
 | 
							cifs_dbg(VFS, "Illegal structure size %u\n",
 | 
				
			||||||
			 le16_to_cpu(hdr->StructureSize));
 | 
								 le16_to_cpu(shdr->StructureSize));
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	command = le16_to_cpu(hdr->Command);
 | 
						command = le16_to_cpu(shdr->Command);
 | 
				
			||||||
	if (command >= NUMBER_OF_SMB2_COMMANDS) {
 | 
						if (command >= NUMBER_OF_SMB2_COMMANDS) {
 | 
				
			||||||
		cifs_dbg(VFS, "Illegal SMB2 command %d\n", command);
 | 
							cifs_dbg(VFS, "Illegal SMB2 command %d\n", command);
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
 | 
						if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
 | 
				
			||||||
		if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 ||
 | 
							if (command != SMB2_OPLOCK_BREAK_HE && (shdr->Status == 0 ||
 | 
				
			||||||
		    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
 | 
							    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
 | 
				
			||||||
			/* error packets have 9 byte structure size */
 | 
								/* error packets have 9 byte structure size */
 | 
				
			||||||
			cifs_dbg(VFS, "Illegal response size %u for command %d\n",
 | 
								cifs_dbg(VFS, "Illegal response size %u for command %d\n",
 | 
				
			||||||
				 le16_to_cpu(pdu->StructureSize2), command);
 | 
									 le16_to_cpu(pdu->StructureSize2), command);
 | 
				
			||||||
			return 1;
 | 
								return 1;
 | 
				
			||||||
		} else if (command == SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0)
 | 
							} else if (command == SMB2_OPLOCK_BREAK_HE
 | 
				
			||||||
 | 
								   && (shdr->Status == 0)
 | 
				
			||||||
			   && (le16_to_cpu(pdu->StructureSize2) != 44)
 | 
								   && (le16_to_cpu(pdu->StructureSize2) != 44)
 | 
				
			||||||
			   && (le16_to_cpu(pdu->StructureSize2) != 36)) {
 | 
								   && (le16_to_cpu(pdu->StructureSize2) != 36)) {
 | 
				
			||||||
			/* special case for SMB2.1 lease break message */
 | 
								/* special case for SMB2.1 lease break message */
 | 
				
			||||||
| 
						 | 
					@ -199,7 +202,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 | 
				
			||||||
			 clc_len, 4 + len, mid);
 | 
								 clc_len, 4 + len, mid);
 | 
				
			||||||
		/* create failed on symlink */
 | 
							/* create failed on symlink */
 | 
				
			||||||
		if (command == SMB2_CREATE_HE &&
 | 
							if (command == SMB2_CREATE_HE &&
 | 
				
			||||||
		    hdr->Status == STATUS_STOPPED_ON_SYMLINK)
 | 
							    shdr->Status == STATUS_STOPPED_ON_SYMLINK)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		/* Windows 7 server returns 24 bytes more */
 | 
							/* Windows 7 server returns 24 bytes more */
 | 
				
			||||||
		if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
 | 
							if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
 | 
				
			||||||
| 
						 | 
					@ -261,11 +264,12 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {
 | 
				
			||||||
char *
 | 
					char *
 | 
				
			||||||
smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 | 
					smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
 | 
				
			||||||
	*off = 0;
 | 
						*off = 0;
 | 
				
			||||||
	*len = 0;
 | 
						*len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* error responses do not have data area */
 | 
						/* error responses do not have data area */
 | 
				
			||||||
	if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
 | 
						if (shdr->Status && shdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
 | 
				
			||||||
	    (((struct smb2_err_rsp *)hdr)->StructureSize) ==
 | 
						    (((struct smb2_err_rsp *)hdr)->StructureSize) ==
 | 
				
			||||||
						SMB2_ERROR_STRUCTURE_SIZE2)
 | 
											SMB2_ERROR_STRUCTURE_SIZE2)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
| 
						 | 
					@ -275,7 +279,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 | 
				
			||||||
	 * of the data buffer offset and data buffer length for the particular
 | 
						 * of the data buffer offset and data buffer length for the particular
 | 
				
			||||||
	 * command.
 | 
						 * command.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	switch (hdr->Command) {
 | 
						switch (shdr->Command) {
 | 
				
			||||||
	case SMB2_NEGOTIATE:
 | 
						case SMB2_NEGOTIATE:
 | 
				
			||||||
		*off = le16_to_cpu(
 | 
							*off = le16_to_cpu(
 | 
				
			||||||
		    ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset);
 | 
							    ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset);
 | 
				
			||||||
| 
						 | 
					@ -346,7 +350,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* return pointer to beginning of data area, ie offset from SMB start */
 | 
						/* return pointer to beginning of data area, ie offset from SMB start */
 | 
				
			||||||
	if ((*off != 0) && (*len != 0))
 | 
						if ((*off != 0) && (*len != 0))
 | 
				
			||||||
		return (char *)(&hdr->ProtocolId) + *off;
 | 
							return (char *)shdr + *off;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -358,12 +362,13 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 | 
				
			||||||
unsigned int
 | 
					unsigned int
 | 
				
			||||||
smb2_calc_size(void *buf)
 | 
					smb2_calc_size(void *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
 | 
						struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
 | 
				
			||||||
	struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
 | 
						struct smb2_hdr *hdr = &pdu->hdr;
 | 
				
			||||||
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
 | 
				
			||||||
	int offset; /* the offset from the beginning of SMB to data area */
 | 
						int offset; /* the offset from the beginning of SMB to data area */
 | 
				
			||||||
	int data_length; /* the length of the variable length data area */
 | 
						int data_length; /* the length of the variable length data area */
 | 
				
			||||||
	/* Structure Size has already been checked to make sure it is 64 */
 | 
						/* Structure Size has already been checked to make sure it is 64 */
 | 
				
			||||||
	int len = 4 + le16_to_cpu(pdu->hdr.StructureSize);
 | 
						int len = 4 + le16_to_cpu(shdr->StructureSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * StructureSize2, ie length of fixed parameter area has already
 | 
						 * StructureSize2, ie length of fixed parameter area has already
 | 
				
			||||||
| 
						 | 
					@ -371,7 +376,7 @@ smb2_calc_size(void *buf)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	len += le16_to_cpu(pdu->StructureSize2);
 | 
						len += le16_to_cpu(pdu->StructureSize2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false)
 | 
						if (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false)
 | 
				
			||||||
		goto calc_size_exit;
 | 
							goto calc_size_exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smb2_get_data_area_len(&offset, &data_length, hdr);
 | 
						smb2_get_data_area_len(&offset, &data_length, hdr);
 | 
				
			||||||
| 
						 | 
					@ -582,7 +587,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_dbg(FYI, "Checking for oplock break\n");
 | 
						cifs_dbg(FYI, "Checking for oplock break\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
 | 
						if (rsp->hdr.sync_hdr.Command != SMB2_OPLOCK_BREAK)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rsp->StructureSize !=
 | 
						if (rsp->StructureSize !=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,8 @@
 | 
				
			||||||
#include <linux/pagemap.h>
 | 
					#include <linux/pagemap.h>
 | 
				
			||||||
#include <linux/vfs.h>
 | 
					#include <linux/vfs.h>
 | 
				
			||||||
#include <linux/falloc.h>
 | 
					#include <linux/falloc.h>
 | 
				
			||||||
 | 
					#include <linux/scatterlist.h>
 | 
				
			||||||
 | 
					#include <crypto/aead.h>
 | 
				
			||||||
#include "cifsglob.h"
 | 
					#include "cifsglob.h"
 | 
				
			||||||
#include "smb2pdu.h"
 | 
					#include "smb2pdu.h"
 | 
				
			||||||
#include "smb2proto.h"
 | 
					#include "smb2proto.h"
 | 
				
			||||||
| 
						 | 
					@ -119,7 +121,9 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
 | 
				
			||||||
static unsigned int
 | 
					static unsigned int
 | 
				
			||||||
smb2_get_credits(struct mid_q_entry *mid)
 | 
					smb2_get_credits(struct mid_q_entry *mid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(mid->resp_buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return le16_to_cpu(shdr->CreditRequest);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
| 
						 | 
					@ -184,10 +188,10 @@ static struct mid_q_entry *
 | 
				
			||||||
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
 | 
					smb2_find_mid(struct TCP_Server_Info *server, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mid_q_entry *mid;
 | 
						struct mid_q_entry *mid;
 | 
				
			||||||
	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 | 
				
			||||||
	__u64 wire_mid = le64_to_cpu(hdr->MessageId);
 | 
						__u64 wire_mid = le64_to_cpu(shdr->MessageId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
 | 
						if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
 | 
				
			||||||
		cifs_dbg(VFS, "encrypted frame parsing not supported yet");
 | 
							cifs_dbg(VFS, "encrypted frame parsing not supported yet");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -196,7 +200,7 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
 | 
				
			||||||
	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
 | 
						list_for_each_entry(mid, &server->pending_mid_q, qhead) {
 | 
				
			||||||
		if ((mid->mid == wire_mid) &&
 | 
							if ((mid->mid == wire_mid) &&
 | 
				
			||||||
		    (mid->mid_state == MID_REQUEST_SUBMITTED) &&
 | 
							    (mid->mid_state == MID_REQUEST_SUBMITTED) &&
 | 
				
			||||||
		    (mid->command == hdr->Command)) {
 | 
							    (mid->command == shdr->Command)) {
 | 
				
			||||||
			spin_unlock(&GlobalMid_Lock);
 | 
								spin_unlock(&GlobalMid_Lock);
 | 
				
			||||||
			return mid;
 | 
								return mid;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -209,12 +213,12 @@ static void
 | 
				
			||||||
smb2_dump_detail(void *buf)
 | 
					smb2_dump_detail(void *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_CIFS_DEBUG2
 | 
					#ifdef CONFIG_CIFS_DEBUG2
 | 
				
			||||||
	struct smb2_hdr *smb = (struct smb2_hdr *)buf;
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
 | 
						cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
 | 
				
			||||||
		 smb->Command, smb->Status, smb->Flags, smb->MessageId,
 | 
							 shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
 | 
				
			||||||
		 smb->ProcessId);
 | 
							 shdr->ProcessId);
 | 
				
			||||||
	cifs_dbg(VFS, "smb buf %p len %u\n", smb, smb2_calc_size(smb));
 | 
						cifs_dbg(VFS, "smb buf %p len %u\n", buf, smb2_calc_size(buf));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1002,14 +1006,14 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
 | 
					smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (hdr->Status != STATUS_PENDING)
 | 
						if (shdr->Status != STATUS_PENDING)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!length) {
 | 
						if (!length) {
 | 
				
			||||||
		spin_lock(&server->req_lock);
 | 
							spin_lock(&server->req_lock);
 | 
				
			||||||
		server->credits += le16_to_cpu(hdr->CreditRequest);
 | 
							server->credits += le16_to_cpu(shdr->CreditRequest);
 | 
				
			||||||
		spin_unlock(&server->req_lock);
 | 
							spin_unlock(&server->req_lock);
 | 
				
			||||||
		wake_up(&server->request_q);
 | 
							wake_up(&server->request_q);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1545,6 +1549,633 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
 | 
				
			||||||
	return !cfile->invalidHandle;
 | 
						return !cfile->invalidHandle;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct smb2_sync_hdr *shdr =
 | 
				
			||||||
 | 
								(struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base;
 | 
				
			||||||
 | 
						unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
 | 
				
			||||||
 | 
						tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
 | 
				
			||||||
 | 
						tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
 | 
				
			||||||
 | 
						tr_hdr->Flags = cpu_to_le16(0x01);
 | 
				
			||||||
 | 
						get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
 | 
				
			||||||
 | 
						memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
 | 
				
			||||||
 | 
						inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4);
 | 
				
			||||||
 | 
						inc_rfc1001_len(tr_hdr, orig_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct scatterlist *
 | 
				
			||||||
 | 
					init_sg(struct smb_rqst *rqst, u8 *sign)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
 | 
				
			||||||
 | 
						unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
 | 
				
			||||||
 | 
						struct scatterlist *sg;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						unsigned int j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!sg)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sg_init_table(sg, sg_len);
 | 
				
			||||||
 | 
						sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
 | 
				
			||||||
 | 
						for (i = 1; i < rqst->rq_nvec; i++)
 | 
				
			||||||
 | 
							sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
 | 
				
			||||||
 | 
											rqst->rq_iov[i].iov_len);
 | 
				
			||||||
 | 
						for (j = 0; i < sg_len - 1; i++, j++) {
 | 
				
			||||||
 | 
							unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz
 | 
				
			||||||
 | 
												: rqst->rq_tailsz;
 | 
				
			||||||
 | 
							sg_set_page(&sg[i], rqst->rq_pages[j], len, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
						return sg;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cifs_crypt_result {
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						struct completion completion;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cifs_crypt_complete(struct crypto_async_request *req, int err)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cifs_crypt_result *res = req->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err == -EINPROGRESS)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res->err = err;
 | 
				
			||||||
 | 
						complete(&res->completion);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Encrypt or decrypt @rqst message. @rqst has the following format:
 | 
				
			||||||
 | 
					 * iov[0] - transform header (associate data),
 | 
				
			||||||
 | 
					 * iov[1-N] and pages - data to encrypt.
 | 
				
			||||||
 | 
					 * On success return encrypted data in iov[1-N] and pages, leave iov[0]
 | 
				
			||||||
 | 
					 * untouched.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct smb2_transform_hdr *tr_hdr =
 | 
				
			||||||
 | 
								(struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
 | 
				
			||||||
 | 
						unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
 | 
				
			||||||
 | 
						struct cifs_ses *ses;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						struct scatterlist *sg;
 | 
				
			||||||
 | 
						u8 sign[SMB2_SIGNATURE_SIZE] = {};
 | 
				
			||||||
 | 
						struct aead_request *req;
 | 
				
			||||||
 | 
						char *iv;
 | 
				
			||||||
 | 
						unsigned int iv_len;
 | 
				
			||||||
 | 
						struct cifs_crypt_result result = {0, };
 | 
				
			||||||
 | 
						struct crypto_aead *tfm;
 | 
				
			||||||
 | 
						unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						init_completion(&result.completion);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ses = smb2_find_smb_ses(server, tr_hdr->SessionId);
 | 
				
			||||||
 | 
						if (!ses) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "%s: Could not find session\n", __func__);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = smb3_crypto_aead_allocate(server);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tfm = enc ? server->secmech.ccmaesencrypt :
 | 
				
			||||||
 | 
											server->secmech.ccmaesdecrypt;
 | 
				
			||||||
 | 
						rc = crypto_aead_setkey(tfm, enc ? ses->smb3encryptionkey :
 | 
				
			||||||
 | 
									ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc);
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req = aead_request_alloc(tfm, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!req) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "%s: Failed to alloc aead request", __func__);
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!enc) {
 | 
				
			||||||
 | 
							memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
							crypt_len += SMB2_SIGNATURE_SIZE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sg = init_sg(rqst, sign);
 | 
				
			||||||
 | 
						if (!sg) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "%s: Failed to init sg %d", __func__, rc);
 | 
				
			||||||
 | 
							goto free_req;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iv_len = crypto_aead_ivsize(tfm);
 | 
				
			||||||
 | 
						iv = kzalloc(iv_len, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!iv) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "%s: Failed to alloc IV", __func__);
 | 
				
			||||||
 | 
							goto free_sg;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						iv[0] = 3;
 | 
				
			||||||
 | 
						memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aead_request_set_crypt(req, sg, sg, crypt_len, iv);
 | 
				
			||||||
 | 
						aead_request_set_ad(req, assoc_data_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
 | 
				
			||||||
 | 
									  cifs_crypt_complete, &result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc == -EINPROGRESS || rc == -EBUSY) {
 | 
				
			||||||
 | 
							wait_for_completion(&result.completion);
 | 
				
			||||||
 | 
							rc = result.err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!rc && enc)
 | 
				
			||||||
 | 
							memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(iv);
 | 
				
			||||||
 | 
					free_sg:
 | 
				
			||||||
 | 
						kfree(sg);
 | 
				
			||||||
 | 
					free_req:
 | 
				
			||||||
 | 
						kfree(req);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
 | 
				
			||||||
 | 
							       struct smb_rqst *old_rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct kvec *iov;
 | 
				
			||||||
 | 
						struct page **pages;
 | 
				
			||||||
 | 
						struct smb2_transform_hdr *tr_hdr;
 | 
				
			||||||
 | 
						unsigned int npages = old_rq->rq_npages;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int rc = -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!pages)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_rq->rq_pages = pages;
 | 
				
			||||||
 | 
						new_rq->rq_npages = old_rq->rq_npages;
 | 
				
			||||||
 | 
						new_rq->rq_pagesz = old_rq->rq_pagesz;
 | 
				
			||||||
 | 
						new_rq->rq_tailsz = old_rq->rq_tailsz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < npages; i++) {
 | 
				
			||||||
 | 
							pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
 | 
				
			||||||
 | 
							if (!pages[i])
 | 
				
			||||||
 | 
								goto err_free_pages;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iov = kmalloc_array(old_rq->rq_nvec, sizeof(struct kvec), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!iov)
 | 
				
			||||||
 | 
							goto err_free_pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* copy all iovs from the old except the 1st one (rfc1002 length) */
 | 
				
			||||||
 | 
						memcpy(&iov[1], &old_rq->rq_iov[1],
 | 
				
			||||||
 | 
									sizeof(struct kvec) * (old_rq->rq_nvec - 1));
 | 
				
			||||||
 | 
						new_rq->rq_iov = iov;
 | 
				
			||||||
 | 
						new_rq->rq_nvec = old_rq->rq_nvec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!tr_hdr)
 | 
				
			||||||
 | 
							goto err_free_iov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* fill the 1st iov with a transform header */
 | 
				
			||||||
 | 
						fill_transform_hdr(tr_hdr, old_rq);
 | 
				
			||||||
 | 
						new_rq->rq_iov[0].iov_base = tr_hdr;
 | 
				
			||||||
 | 
						new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* copy pages form the old */
 | 
				
			||||||
 | 
						for (i = 0; i < npages; i++) {
 | 
				
			||||||
 | 
							char *dst = kmap(new_rq->rq_pages[i]);
 | 
				
			||||||
 | 
							char *src = kmap(old_rq->rq_pages[i]);
 | 
				
			||||||
 | 
							unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz :
 | 
				
			||||||
 | 
												new_rq->rq_tailsz;
 | 
				
			||||||
 | 
							memcpy(dst, src, len);
 | 
				
			||||||
 | 
							kunmap(new_rq->rq_pages[i]);
 | 
				
			||||||
 | 
							kunmap(old_rq->rq_pages[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = crypt_message(server, new_rq, 1);
 | 
				
			||||||
 | 
						cifs_dbg(FYI, "encrypt message returned %d", rc);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							goto err_free_tr_hdr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_free_tr_hdr:
 | 
				
			||||||
 | 
						kfree(tr_hdr);
 | 
				
			||||||
 | 
					err_free_iov:
 | 
				
			||||||
 | 
						kfree(iov);
 | 
				
			||||||
 | 
					err_free_pages:
 | 
				
			||||||
 | 
						for (i = i - 1; i >= 0; i--)
 | 
				
			||||||
 | 
							put_page(pages[i]);
 | 
				
			||||||
 | 
						kfree(pages);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					smb3_free_transform_rq(struct smb_rqst *rqst)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i = rqst->rq_npages - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (; i >= 0; i--)
 | 
				
			||||||
 | 
							put_page(rqst->rq_pages[i]);
 | 
				
			||||||
 | 
						kfree(rqst->rq_pages);
 | 
				
			||||||
 | 
						/* free transform header */
 | 
				
			||||||
 | 
						kfree(rqst->rq_iov[0].iov_base);
 | 
				
			||||||
 | 
						kfree(rqst->rq_iov);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					smb3_is_transform_hdr(void *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct smb2_transform_hdr *trhdr = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
 | 
				
			||||||
 | 
							 unsigned int buf_data_size, struct page **pages,
 | 
				
			||||||
 | 
							 unsigned int npages, unsigned int page_data_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct kvec iov[2];
 | 
				
			||||||
 | 
						struct smb_rqst rqst = {NULL};
 | 
				
			||||||
 | 
						struct smb2_hdr *hdr;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iov[0].iov_base = buf;
 | 
				
			||||||
 | 
						iov[0].iov_len = sizeof(struct smb2_transform_hdr);
 | 
				
			||||||
 | 
						iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
 | 
				
			||||||
 | 
						iov[1].iov_len = buf_data_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rqst.rq_iov = iov;
 | 
				
			||||||
 | 
						rqst.rq_nvec = 2;
 | 
				
			||||||
 | 
						rqst.rq_pages = pages;
 | 
				
			||||||
 | 
						rqst.rq_npages = npages;
 | 
				
			||||||
 | 
						rqst.rq_pagesz = PAGE_SIZE;
 | 
				
			||||||
 | 
						rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = crypt_message(server, &rqst, 0);
 | 
				
			||||||
 | 
						cifs_dbg(FYI, "decrypt message returned %d\n", rc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memmove(buf + 4, iov[1].iov_base, buf_data_size);
 | 
				
			||||||
 | 
						hdr = (struct smb2_hdr *)buf;
 | 
				
			||||||
 | 
						hdr->smb2_buf_length = cpu_to_be32(buf_data_size + page_data_size);
 | 
				
			||||||
 | 
						server->total_read = buf_data_size + page_data_size + 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					read_data_into_pages(struct TCP_Server_Info *server, struct page **pages,
 | 
				
			||||||
 | 
							     unsigned int npages, unsigned int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < npages; i++) {
 | 
				
			||||||
 | 
							struct page *page = pages[i];
 | 
				
			||||||
 | 
							size_t n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							n = len;
 | 
				
			||||||
 | 
							if (len >= PAGE_SIZE) {
 | 
				
			||||||
 | 
								/* enough data to fill the page */
 | 
				
			||||||
 | 
								n = PAGE_SIZE;
 | 
				
			||||||
 | 
								len -= n;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								zero_user(page, len, PAGE_SIZE - len);
 | 
				
			||||||
 | 
								len = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							length = cifs_read_page_from_socket(server, page, n);
 | 
				
			||||||
 | 
							if (length < 0)
 | 
				
			||||||
 | 
								return length;
 | 
				
			||||||
 | 
							server->total_read += length;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					init_read_bvec(struct page **pages, unsigned int npages, unsigned int data_size,
 | 
				
			||||||
 | 
						       unsigned int cur_off, struct bio_vec **page_vec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bio_vec *bvec;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bvec = kcalloc(npages, sizeof(struct bio_vec), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!bvec)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < npages; i++) {
 | 
				
			||||||
 | 
							bvec[i].bv_page = pages[i];
 | 
				
			||||||
 | 
							bvec[i].bv_offset = (i == 0) ? cur_off : 0;
 | 
				
			||||||
 | 
							bvec[i].bv_len = min_t(unsigned int, PAGE_SIZE, data_size);
 | 
				
			||||||
 | 
							data_size -= bvec[i].bv_len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data_size != 0) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "%s: something went wrong\n", __func__);
 | 
				
			||||||
 | 
							kfree(bvec);
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*page_vec = bvec;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 | 
				
			||||||
 | 
							 char *buf, unsigned int buf_len, struct page **pages,
 | 
				
			||||||
 | 
							 unsigned int npages, unsigned int page_data_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int data_offset;
 | 
				
			||||||
 | 
						unsigned int data_len;
 | 
				
			||||||
 | 
						unsigned int cur_off;
 | 
				
			||||||
 | 
						unsigned int cur_page_idx;
 | 
				
			||||||
 | 
						unsigned int pad_len;
 | 
				
			||||||
 | 
						struct cifs_readdata *rdata = mid->callback_data;
 | 
				
			||||||
 | 
						struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 | 
				
			||||||
 | 
						struct bio_vec *bvec = NULL;
 | 
				
			||||||
 | 
						struct iov_iter iter;
 | 
				
			||||||
 | 
						struct kvec iov;
 | 
				
			||||||
 | 
						int length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (shdr->Command != SMB2_READ) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "only big read responses are supported\n");
 | 
				
			||||||
 | 
							return -ENOTSUPP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (server->ops->is_status_pending &&
 | 
				
			||||||
 | 
								server->ops->is_status_pending(buf, server, 0))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rdata->result = server->ops->map_error(buf, false);
 | 
				
			||||||
 | 
						if (rdata->result != 0) {
 | 
				
			||||||
 | 
							cifs_dbg(FYI, "%s: server returned error %d\n",
 | 
				
			||||||
 | 
								 __func__, rdata->result);
 | 
				
			||||||
 | 
							dequeue_mid(mid, rdata->result);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data_offset = server->ops->read_data_offset(buf) + 4;
 | 
				
			||||||
 | 
						data_len = server->ops->read_data_length(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data_offset < server->vals->read_rsp_size) {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * win2k8 sometimes sends an offset of 0 when the read
 | 
				
			||||||
 | 
							 * is beyond the EOF. Treat it as if the data starts just after
 | 
				
			||||||
 | 
							 * the header.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
 | 
				
			||||||
 | 
								 __func__, data_offset);
 | 
				
			||||||
 | 
							data_offset = server->vals->read_rsp_size;
 | 
				
			||||||
 | 
						} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
 | 
				
			||||||
 | 
							/* data_offset is beyond the end of smallbuf */
 | 
				
			||||||
 | 
							cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
 | 
				
			||||||
 | 
								 __func__, data_offset);
 | 
				
			||||||
 | 
							rdata->result = -EIO;
 | 
				
			||||||
 | 
							dequeue_mid(mid, rdata->result);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pad_len = data_offset - server->vals->read_rsp_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buf_len <= data_offset) {
 | 
				
			||||||
 | 
							/* read response payload is in pages */
 | 
				
			||||||
 | 
							cur_page_idx = pad_len / PAGE_SIZE;
 | 
				
			||||||
 | 
							cur_off = pad_len % PAGE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (cur_page_idx != 0) {
 | 
				
			||||||
 | 
								/* data offset is beyond the 1st page of response */
 | 
				
			||||||
 | 
								cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
 | 
				
			||||||
 | 
									 __func__, data_offset);
 | 
				
			||||||
 | 
								rdata->result = -EIO;
 | 
				
			||||||
 | 
								dequeue_mid(mid, rdata->result);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (data_len > page_data_size - pad_len) {
 | 
				
			||||||
 | 
								/* data_len is corrupt -- discard frame */
 | 
				
			||||||
 | 
								rdata->result = -EIO;
 | 
				
			||||||
 | 
								dequeue_mid(mid, rdata->result);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rdata->result = init_read_bvec(pages, npages, page_data_size,
 | 
				
			||||||
 | 
										       cur_off, &bvec);
 | 
				
			||||||
 | 
							if (rdata->result != 0) {
 | 
				
			||||||
 | 
								dequeue_mid(mid, rdata->result);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							iov_iter_bvec(&iter, WRITE | ITER_BVEC, bvec, npages, data_len);
 | 
				
			||||||
 | 
						} else if (buf_len >= data_offset + data_len) {
 | 
				
			||||||
 | 
							/* read response payload is in buf */
 | 
				
			||||||
 | 
							WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
 | 
				
			||||||
 | 
							iov.iov_base = buf + data_offset;
 | 
				
			||||||
 | 
							iov.iov_len = data_len;
 | 
				
			||||||
 | 
							iov_iter_kvec(&iter, WRITE | ITER_KVEC, &iov, 1, data_len);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* read response payload cannot be in both buf and pages */
 | 
				
			||||||
 | 
							WARN_ONCE(1, "buf can not contain only a part of read data");
 | 
				
			||||||
 | 
							rdata->result = -EIO;
 | 
				
			||||||
 | 
							dequeue_mid(mid, rdata->result);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set up first iov for signature check */
 | 
				
			||||||
 | 
						rdata->iov[0].iov_base = buf;
 | 
				
			||||||
 | 
						rdata->iov[0].iov_len = 4;
 | 
				
			||||||
 | 
						rdata->iov[1].iov_base = buf + 4;
 | 
				
			||||||
 | 
						rdata->iov[1].iov_len = server->vals->read_rsp_size - 4;
 | 
				
			||||||
 | 
						cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
 | 
				
			||||||
 | 
							 rdata->iov[0].iov_base, server->vals->read_rsp_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						length = rdata->copy_into_pages(server, rdata, &iter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(bvec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (length < 0)
 | 
				
			||||||
 | 
							return length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dequeue_mid(mid, false);
 | 
				
			||||||
 | 
						return length;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *buf = server->smallbuf;
 | 
				
			||||||
 | 
						struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
 | 
				
			||||||
 | 
						unsigned int npages;
 | 
				
			||||||
 | 
						struct page **pages;
 | 
				
			||||||
 | 
						unsigned int len;
 | 
				
			||||||
 | 
						unsigned int buflen = get_rfc1002_length(buf) + 4;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = min_t(unsigned int, buflen, server->vals->read_rsp_size - 4 +
 | 
				
			||||||
 | 
							sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						server->total_read += rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = le32_to_cpu(tr_hdr->OriginalMessageSize) + 4 -
 | 
				
			||||||
 | 
											server->vals->read_rsp_size;
 | 
				
			||||||
 | 
						npages = DIV_ROUND_UP(len, PAGE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!pages) {
 | 
				
			||||||
 | 
							rc = -ENOMEM;
 | 
				
			||||||
 | 
							goto discard_data;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (; i < npages; i++) {
 | 
				
			||||||
 | 
							pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
 | 
				
			||||||
 | 
							if (!pages[i]) {
 | 
				
			||||||
 | 
								rc = -ENOMEM;
 | 
				
			||||||
 | 
								goto discard_data;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* read read data into pages */
 | 
				
			||||||
 | 
						rc = read_data_into_pages(server, pages, npages, len);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							goto free_pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = cifs_discard_remaining_data(server);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							goto free_pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size - 4,
 | 
				
			||||||
 | 
								      pages, npages, len);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							goto free_pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*mid = smb2_find_mid(server, buf);
 | 
				
			||||||
 | 
						if (*mid == NULL)
 | 
				
			||||||
 | 
							cifs_dbg(FYI, "mid not found\n");
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							cifs_dbg(FYI, "mid found\n");
 | 
				
			||||||
 | 
							(*mid)->decrypted = true;
 | 
				
			||||||
 | 
							rc = handle_read_data(server, *mid, buf,
 | 
				
			||||||
 | 
									      server->vals->read_rsp_size,
 | 
				
			||||||
 | 
									      pages, npages, len);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					free_pages:
 | 
				
			||||||
 | 
						for (i = i - 1; i >= 0; i--)
 | 
				
			||||||
 | 
							put_page(pages[i]);
 | 
				
			||||||
 | 
						kfree(pages);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					discard_data:
 | 
				
			||||||
 | 
						cifs_discard_remaining_data(server);
 | 
				
			||||||
 | 
						goto free_pages;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					receive_encrypted_standard(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
								   struct mid_q_entry **mid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int length;
 | 
				
			||||||
 | 
						char *buf = server->smallbuf;
 | 
				
			||||||
 | 
						unsigned int pdu_length = get_rfc1002_length(buf);
 | 
				
			||||||
 | 
						unsigned int buf_size;
 | 
				
			||||||
 | 
						struct mid_q_entry *mid_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* switch to large buffer if too big for a small one */
 | 
				
			||||||
 | 
						if (pdu_length + 4 > MAX_CIFS_SMALL_BUFFER_SIZE) {
 | 
				
			||||||
 | 
							server->large_buf = true;
 | 
				
			||||||
 | 
							memcpy(server->bigbuf, buf, server->total_read);
 | 
				
			||||||
 | 
							buf = server->bigbuf;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* now read the rest */
 | 
				
			||||||
 | 
						length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
 | 
				
			||||||
 | 
									pdu_length - HEADER_SIZE(server) + 1 + 4);
 | 
				
			||||||
 | 
						if (length < 0)
 | 
				
			||||||
 | 
							return length;
 | 
				
			||||||
 | 
						server->total_read += length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf_size = pdu_length + 4 - sizeof(struct smb2_transform_hdr);
 | 
				
			||||||
 | 
						length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0);
 | 
				
			||||||
 | 
						if (length)
 | 
				
			||||||
 | 
							return length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mid_entry = smb2_find_mid(server, buf);
 | 
				
			||||||
 | 
						if (mid_entry == NULL)
 | 
				
			||||||
 | 
							cifs_dbg(FYI, "mid not found\n");
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							cifs_dbg(FYI, "mid found\n");
 | 
				
			||||||
 | 
							mid_entry->decrypted = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*mid = mid_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mid_entry && mid_entry->handle)
 | 
				
			||||||
 | 
							return mid_entry->handle(server, mid_entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cifs_handle_standard(server, mid_entry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *buf = server->smallbuf;
 | 
				
			||||||
 | 
						unsigned int pdu_length = get_rfc1002_length(buf);
 | 
				
			||||||
 | 
						struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
 | 
				
			||||||
 | 
						unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pdu_length + 4 < sizeof(struct smb2_transform_hdr) +
 | 
				
			||||||
 | 
											sizeof(struct smb2_sync_hdr)) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "Transform message is too small (%u)\n",
 | 
				
			||||||
 | 
								 pdu_length);
 | 
				
			||||||
 | 
							cifs_reconnect(server);
 | 
				
			||||||
 | 
							wake_up(&server->response_q);
 | 
				
			||||||
 | 
							return -ECONNABORTED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pdu_length + 4 < orig_len + sizeof(struct smb2_transform_hdr)) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "Transform message is broken\n");
 | 
				
			||||||
 | 
							cifs_reconnect(server);
 | 
				
			||||||
 | 
							wake_up(&server->response_q);
 | 
				
			||||||
 | 
							return -ECONNABORTED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
 | 
				
			||||||
 | 
							return receive_encrypted_read(server, mid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return receive_encrypted_standard(server, mid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return handle_read_data(server, mid, buf, get_rfc1002_length(buf) + 4,
 | 
				
			||||||
 | 
									NULL, 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct smb_version_operations smb20_operations = {
 | 
					struct smb_version_operations smb20_operations = {
 | 
				
			||||||
	.compare_fids = smb2_compare_fids,
 | 
						.compare_fids = smb2_compare_fids,
 | 
				
			||||||
	.setup_request = smb2_setup_request,
 | 
						.setup_request = smb2_setup_request,
 | 
				
			||||||
| 
						 | 
					@ -1791,6 +2422,10 @@ struct smb_version_operations smb30_operations = {
 | 
				
			||||||
	.dir_needs_close = smb2_dir_needs_close,
 | 
						.dir_needs_close = smb2_dir_needs_close,
 | 
				
			||||||
	.fallocate = smb3_fallocate,
 | 
						.fallocate = smb3_fallocate,
 | 
				
			||||||
	.enum_snapshots = smb3_enum_snapshots,
 | 
						.enum_snapshots = smb3_enum_snapshots,
 | 
				
			||||||
 | 
						.init_transform_rq = smb3_init_transform_rq,
 | 
				
			||||||
 | 
						.free_transform_rq = smb3_free_transform_rq,
 | 
				
			||||||
 | 
						.is_transform_hdr = smb3_is_transform_hdr,
 | 
				
			||||||
 | 
						.receive_transform = smb3_receive_transform,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_CIFS_SMB311
 | 
					#ifdef CONFIG_CIFS_SMB311
 | 
				
			||||||
| 
						 | 
					@ -1879,6 +2514,10 @@ struct smb_version_operations smb311_operations = {
 | 
				
			||||||
	.dir_needs_close = smb2_dir_needs_close,
 | 
						.dir_needs_close = smb2_dir_needs_close,
 | 
				
			||||||
	.fallocate = smb3_fallocate,
 | 
						.fallocate = smb3_fallocate,
 | 
				
			||||||
	.enum_snapshots = smb3_enum_snapshots,
 | 
						.enum_snapshots = smb3_enum_snapshots,
 | 
				
			||||||
 | 
						.init_transform_rq = smb3_init_transform_rq,
 | 
				
			||||||
 | 
						.free_transform_rq = smb3_free_transform_rq,
 | 
				
			||||||
 | 
						.is_transform_hdr = smb3_is_transform_hdr,
 | 
				
			||||||
 | 
						.receive_transform = smb3_receive_transform,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
#endif /* CIFS_SMB311 */
 | 
					#endif /* CIFS_SMB311 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -101,10 +101,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SMB2_HEADER_STRUCTURE_SIZE cpu_to_le16(64)
 | 
					#define SMB2_HEADER_STRUCTURE_SIZE cpu_to_le16(64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct smb2_hdr {
 | 
					struct smb2_sync_hdr {
 | 
				
			||||||
	__be32 smb2_buf_length;	/* big endian on wire */
 | 
					 | 
				
			||||||
				/* length is only two or three bytes - with
 | 
					 | 
				
			||||||
				 one or two byte type preceding it that MBZ */
 | 
					 | 
				
			||||||
	__le32 ProtocolId;	/* 0xFE 'S' 'M' 'B' */
 | 
						__le32 ProtocolId;	/* 0xFE 'S' 'M' 'B' */
 | 
				
			||||||
	__le16 StructureSize;	/* 64 */
 | 
						__le16 StructureSize;	/* 64 */
 | 
				
			||||||
	__le16 CreditCharge;	/* MBZ */
 | 
						__le16 CreditCharge;	/* MBZ */
 | 
				
			||||||
| 
						 | 
					@ -120,16 +117,31 @@ struct smb2_hdr {
 | 
				
			||||||
	__u8   Signature[16];
 | 
						__u8   Signature[16];
 | 
				
			||||||
} __packed;
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct smb2_sync_pdu {
 | 
				
			||||||
 | 
						struct smb2_sync_hdr sync_hdr;
 | 
				
			||||||
 | 
						__le16 StructureSize2; /* size of wct area (varies, request specific) */
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct smb2_hdr {
 | 
				
			||||||
 | 
						__be32 smb2_buf_length;	/* big endian on wire */
 | 
				
			||||||
 | 
									/* length is only two or three bytes - with */
 | 
				
			||||||
 | 
									/* one or two byte type preceding it that MBZ */
 | 
				
			||||||
 | 
						struct smb2_sync_hdr sync_hdr;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct smb2_pdu {
 | 
					struct smb2_pdu {
 | 
				
			||||||
	struct smb2_hdr hdr;
 | 
						struct smb2_hdr hdr;
 | 
				
			||||||
	__le16 StructureSize2; /* size of wct area (varies, request specific) */
 | 
						__le16 StructureSize2; /* size of wct area (varies, request specific) */
 | 
				
			||||||
} __packed;
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SMB3_AES128CMM_NONCE 11
 | 
				
			||||||
 | 
					#define SMB3_AES128GCM_NONCE 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct smb2_transform_hdr {
 | 
					struct smb2_transform_hdr {
 | 
				
			||||||
	__be32 smb2_buf_length;	/* big endian on wire */
 | 
						__be32 smb2_buf_length;	/* big endian on wire */
 | 
				
			||||||
				/* length is only two or three bytes - with
 | 
									/* length is only two or three bytes - with
 | 
				
			||||||
				 one or two byte type preceding it that MBZ */
 | 
									 one or two byte type preceding it that MBZ */
 | 
				
			||||||
	__u8   ProtocolId[4];	/* 0xFD 'S' 'M' 'B' */
 | 
						__le32 ProtocolId;	/* 0xFD 'S' 'M' 'B' */
 | 
				
			||||||
	__u8   Signature[16];
 | 
						__u8   Signature[16];
 | 
				
			||||||
	__u8   Nonce[16];
 | 
						__u8   Nonce[16];
 | 
				
			||||||
	__le32 OriginalMessageSize;
 | 
						__le32 OriginalMessageSize;
 | 
				
			||||||
| 
						 | 
					@ -814,8 +826,9 @@ struct smb2_flush_rsp {
 | 
				
			||||||
#define SMB2_CHANNEL_RDMA_V1		0x00000001 /* SMB3 or later */
 | 
					#define SMB2_CHANNEL_RDMA_V1		0x00000001 /* SMB3 or later */
 | 
				
			||||||
#define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */
 | 
					#define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct smb2_read_req {
 | 
					/* SMB2 read request without RFC1001 length at the beginning */
 | 
				
			||||||
	struct smb2_hdr hdr;
 | 
					struct smb2_read_plain_req {
 | 
				
			||||||
 | 
						struct smb2_sync_hdr sync_hdr;
 | 
				
			||||||
	__le16 StructureSize; /* Must be 49 */
 | 
						__le16 StructureSize; /* Must be 49 */
 | 
				
			||||||
	__u8   Padding; /* offset from start of SMB2 header to place read */
 | 
						__u8   Padding; /* offset from start of SMB2 header to place read */
 | 
				
			||||||
	__u8   Flags; /* MBZ unless SMB3.02 or later */
 | 
						__u8   Flags; /* MBZ unless SMB3.02 or later */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,10 @@ extern void smb2_echo_request(struct work_struct *work);
 | 
				
			||||||
extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
 | 
					extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
 | 
				
			||||||
extern bool smb2_is_valid_oplock_break(char *buffer,
 | 
					extern bool smb2_is_valid_oplock_break(char *buffer,
 | 
				
			||||||
				       struct TCP_Server_Info *srv);
 | 
									       struct TCP_Server_Info *srv);
 | 
				
			||||||
 | 
					extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
										  __u64 ses_id);
 | 
				
			||||||
 | 
					extern int smb3_handle_read_data(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
									 struct mid_q_entry *mid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
 | 
					extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
 | 
				
			||||||
				   struct smb2_file_all_info *src);
 | 
									   struct smb2_file_all_info *src);
 | 
				
			||||||
| 
						 | 
					@ -97,6 +101,7 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
 | 
				
			||||||
			     struct file_lock *flock, const unsigned int xid);
 | 
								     struct file_lock *flock, const unsigned int xid);
 | 
				
			||||||
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
 | 
					extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
 | 
				
			||||||
extern void smb2_reconnect_server(struct work_struct *work);
 | 
					extern void smb2_reconnect_server(struct work_struct *work);
 | 
				
			||||||
 | 
					extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * SMB2 Worker functions - most of protocol specific implementation details
 | 
					 * SMB2 Worker functions - most of protocol specific implementation details
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@
 | 
				
			||||||
#include <asm/processor.h>
 | 
					#include <asm/processor.h>
 | 
				
			||||||
#include <linux/mempool.h>
 | 
					#include <linux/mempool.h>
 | 
				
			||||||
#include <linux/highmem.h>
 | 
					#include <linux/highmem.h>
 | 
				
			||||||
 | 
					#include <crypto/aead.h>
 | 
				
			||||||
#include "smb2pdu.h"
 | 
					#include "smb2pdu.h"
 | 
				
			||||||
#include "cifsglob.h"
 | 
					#include "cifsglob.h"
 | 
				
			||||||
#include "cifsproto.h"
 | 
					#include "cifsproto.h"
 | 
				
			||||||
| 
						 | 
					@ -114,14 +115,14 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cifs_ses *
 | 
					struct cifs_ses *
 | 
				
			||||||
smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
 | 
					smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cifs_ses *ses;
 | 
						struct cifs_ses *ses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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->Suid != smb2hdr->SessionId)
 | 
							if (ses->Suid != ses_id)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		spin_unlock(&cifs_tcp_ses_lock);
 | 
							spin_unlock(&cifs_tcp_ses_lock);
 | 
				
			||||||
		return ses;
 | 
							return ses;
 | 
				
			||||||
| 
						 | 
					@ -131,7 +132,6 @@ smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
					smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -139,17 +139,17 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
 | 
						unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
 | 
				
			||||||
	unsigned char *sigptr = smb2_signature;
 | 
						unsigned char *sigptr = smb2_signature;
 | 
				
			||||||
	struct kvec *iov = rqst->rq_iov;
 | 
						struct kvec *iov = rqst->rq_iov;
 | 
				
			||||||
	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
 | 
						struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
 | 
				
			||||||
	struct cifs_ses *ses;
 | 
						struct cifs_ses *ses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ses = smb2_find_smb_ses(smb2_pdu, server);
 | 
						ses = smb2_find_smb_ses(server, shdr->SessionId);
 | 
				
			||||||
	if (!ses) {
 | 
						if (!ses) {
 | 
				
			||||||
		cifs_dbg(VFS, "%s: Could not find session\n", __func__);
 | 
							cifs_dbg(VFS, "%s: Could not find session\n", __func__);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
 | 
						memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
 | 
				
			||||||
	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 | 
						memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = smb2_crypto_shash_allocate(server);
 | 
						rc = smb2_crypto_shash_allocate(server);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
| 
						 | 
					@ -174,7 +174,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
		&server->secmech.sdeschmacsha256->shash);
 | 
							&server->secmech.sdeschmacsha256->shash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rc)
 | 
						if (!rc)
 | 
				
			||||||
		memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 | 
							memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -356,17 +356,17 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
 | 
						unsigned char smb3_signature[SMB2_CMACAES_SIZE];
 | 
				
			||||||
	unsigned char *sigptr = smb3_signature;
 | 
						unsigned char *sigptr = smb3_signature;
 | 
				
			||||||
	struct kvec *iov = rqst->rq_iov;
 | 
						struct kvec *iov = rqst->rq_iov;
 | 
				
			||||||
	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
 | 
						struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
 | 
				
			||||||
	struct cifs_ses *ses;
 | 
						struct cifs_ses *ses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ses = smb2_find_smb_ses(smb2_pdu, server);
 | 
						ses = smb2_find_smb_ses(server, shdr->SessionId);
 | 
				
			||||||
	if (!ses) {
 | 
						if (!ses) {
 | 
				
			||||||
		cifs_dbg(VFS, "%s: Could not find session\n", __func__);
 | 
							cifs_dbg(VFS, "%s: Could not find session\n", __func__);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
 | 
						memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
 | 
				
			||||||
	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 | 
						memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = crypto_shash_setkey(server->secmech.cmacaes,
 | 
						rc = crypto_shash_setkey(server->secmech.cmacaes,
 | 
				
			||||||
		ses->smb3signingkey, SMB2_CMACAES_SIZE);
 | 
							ses->smb3signingkey, SMB2_CMACAES_SIZE);
 | 
				
			||||||
| 
						 | 
					@ -391,7 +391,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
				   &server->secmech.sdesccmacaes->shash);
 | 
									   &server->secmech.sdesccmacaes->shash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rc)
 | 
						if (!rc)
 | 
				
			||||||
		memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 | 
							memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -401,14 +401,15 @@ static int
 | 
				
			||||||
smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
					smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	struct smb2_hdr *smb2_pdu = rqst->rq_iov[0].iov_base;
 | 
						struct smb2_sync_hdr *shdr =
 | 
				
			||||||
 | 
								(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) ||
 | 
						if (!(shdr->Flags & SMB2_FLAGS_SIGNED) ||
 | 
				
			||||||
	    server->tcpStatus == CifsNeedNegotiate)
 | 
						    server->tcpStatus == CifsNeedNegotiate)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!server->session_estab) {
 | 
						if (!server->session_estab) {
 | 
				
			||||||
		strncpy(smb2_pdu->Signature, "BSRSPYL", 8);
 | 
							strncpy(shdr->Signature, "BSRSPYL", 8);
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -422,11 +423,12 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int rc;
 | 
						unsigned int rc;
 | 
				
			||||||
	char server_response_sig[16];
 | 
						char server_response_sig[16];
 | 
				
			||||||
	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 | 
						struct smb2_sync_hdr *shdr =
 | 
				
			||||||
 | 
								(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
 | 
						if ((shdr->Command == SMB2_NEGOTIATE) ||
 | 
				
			||||||
	    (smb2_pdu->Command == SMB2_SESSION_SETUP) ||
 | 
						    (shdr->Command == SMB2_SESSION_SETUP) ||
 | 
				
			||||||
	    (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
 | 
						    (shdr->Command == SMB2_OPLOCK_BREAK) ||
 | 
				
			||||||
	    (!server->session_estab))
 | 
						    (!server->session_estab))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -436,17 +438,17 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Do not need to verify session setups with signature "BSRSPYL " */
 | 
						/* Do not need to verify session setups with signature "BSRSPYL " */
 | 
				
			||||||
	if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0)
 | 
						if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0)
 | 
				
			||||||
		cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
 | 
							cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
 | 
				
			||||||
			 smb2_pdu->Command);
 | 
								 shdr->Command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Save off the origiginal signature so we can modify the smb and check
 | 
						 * Save off the origiginal signature so we can modify the smb and check
 | 
				
			||||||
	 * our calculated signature against what the server sent.
 | 
						 * our calculated signature against what the server sent.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE);
 | 
						memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE);
 | 
						memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&server->srv_mutex);
 | 
						mutex_lock(&server->srv_mutex);
 | 
				
			||||||
	rc = server->ops->calc_signature(rqst, server);
 | 
						rc = server->ops->calc_signature(rqst, server);
 | 
				
			||||||
| 
						 | 
					@ -455,8 +457,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (memcmp(server_response_sig, smb2_pdu->Signature,
 | 
						if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE))
 | 
				
			||||||
		   SMB2_SIGNATURE_SIZE))
 | 
					 | 
				
			||||||
		return -EACCES;
 | 
							return -EACCES;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
| 
						 | 
					@ -467,18 +468,19 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 | 
				
			||||||
 * and when srv_mutex is held.
 | 
					 * and when srv_mutex is held.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline void
 | 
					static inline void
 | 
				
			||||||
smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
 | 
					smb2_seq_num_into_buf(struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
							      struct smb2_sync_hdr *shdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i, num = le16_to_cpu(hdr->CreditCharge);
 | 
						unsigned int i, num = le16_to_cpu(shdr->CreditCharge);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdr->MessageId = get_next_mid64(server);
 | 
						shdr->MessageId = get_next_mid64(server);
 | 
				
			||||||
	/* skip message numbers according to CreditCharge field */
 | 
						/* skip message numbers according to CreditCharge field */
 | 
				
			||||||
	for (i = 1; i < num; i++)
 | 
						for (i = 1; i < num; i++)
 | 
				
			||||||
		get_next_mid(server);
 | 
							get_next_mid(server);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mid_q_entry *
 | 
					static struct mid_q_entry *
 | 
				
			||||||
smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
 | 
					smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
 | 
				
			||||||
		     struct TCP_Server_Info *server)
 | 
							     struct TCP_Server_Info *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mid_q_entry *temp;
 | 
						struct mid_q_entry *temp;
 | 
				
			||||||
| 
						 | 
					@ -493,9 +495,9 @@ smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
 | 
				
			||||||
		return temp;
 | 
							return temp;
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		memset(temp, 0, sizeof(struct mid_q_entry));
 | 
							memset(temp, 0, sizeof(struct mid_q_entry));
 | 
				
			||||||
		temp->mid = le64_to_cpu(smb_buffer->MessageId);
 | 
							temp->mid = le64_to_cpu(shdr->MessageId);
 | 
				
			||||||
		temp->pid = current->pid;
 | 
							temp->pid = current->pid;
 | 
				
			||||||
		temp->command = smb_buffer->Command;	/* Always LE */
 | 
							temp->command = shdr->Command; /* Always LE */
 | 
				
			||||||
		temp->when_alloc = jiffies;
 | 
							temp->when_alloc = jiffies;
 | 
				
			||||||
		temp->server = server;
 | 
							temp->server = server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -513,7 +515,7 @@ smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
 | 
					smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr,
 | 
				
			||||||
		   struct mid_q_entry **mid)
 | 
							   struct mid_q_entry **mid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (ses->server->tcpStatus == CifsExiting)
 | 
						if (ses->server->tcpStatus == CifsExiting)
 | 
				
			||||||
| 
						 | 
					@ -525,19 +527,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ses->status == CifsNew) {
 | 
						if (ses->status == CifsNew) {
 | 
				
			||||||
		if ((buf->Command != SMB2_SESSION_SETUP) &&
 | 
							if ((shdr->Command != SMB2_SESSION_SETUP) &&
 | 
				
			||||||
		    (buf->Command != SMB2_NEGOTIATE))
 | 
							    (shdr->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 (ses->status == CifsExiting) {
 | 
				
			||||||
		if (buf->Command != SMB2_LOGOFF)
 | 
							if (shdr->Command != SMB2_LOGOFF)
 | 
				
			||||||
			return -EAGAIN;
 | 
								return -EAGAIN;
 | 
				
			||||||
		/* else ok - we are shutting down the session */
 | 
							/* else ok - we are shutting down the session */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*mid = smb2_mid_entry_alloc(buf, ses->server);
 | 
						*mid = smb2_mid_entry_alloc(shdr, ses->server);
 | 
				
			||||||
	if (*mid == NULL)
 | 
						if (*mid == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	spin_lock(&GlobalMid_Lock);
 | 
						spin_lock(&GlobalMid_Lock);
 | 
				
			||||||
| 
						 | 
					@ -551,16 +553,18 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 | 
				
			||||||
		   bool log_error)
 | 
							   bool log_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int len = get_rfc1002_length(mid->resp_buf);
 | 
						unsigned int len = get_rfc1002_length(mid->resp_buf);
 | 
				
			||||||
	struct kvec iov;
 | 
						struct kvec iov[2];
 | 
				
			||||||
	struct smb_rqst rqst = { .rq_iov = &iov,
 | 
						struct smb_rqst rqst = { .rq_iov = iov,
 | 
				
			||||||
				 .rq_nvec = 1 };
 | 
									 .rq_nvec = 2 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iov.iov_base = (char *)mid->resp_buf;
 | 
						iov[0].iov_base = (char *)mid->resp_buf;
 | 
				
			||||||
	iov.iov_len = get_rfc1002_length(mid->resp_buf) + 4;
 | 
						iov[0].iov_len = 4;
 | 
				
			||||||
 | 
						iov[1].iov_base = (char *)mid->resp_buf + 4;
 | 
				
			||||||
 | 
						iov[1].iov_len = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dump_smb(mid->resp_buf, min_t(u32, 80, len));
 | 
						dump_smb(mid->resp_buf, min_t(u32, 80, len));
 | 
				
			||||||
	/* convert the length into a more usable form */
 | 
						/* convert the length into a more usable form */
 | 
				
			||||||
	if (len > 24 && server->sign) {
 | 
						if (len > 24 && server->sign && !mid->decrypted) {
 | 
				
			||||||
		int rc;
 | 
							int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rc = smb2_verify_signature(&rqst, server);
 | 
							rc = smb2_verify_signature(&rqst, server);
 | 
				
			||||||
| 
						 | 
					@ -576,12 +580,13 @@ struct mid_q_entry *
 | 
				
			||||||
smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 | 
					smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct smb2_hdr *hdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 | 
						struct smb2_sync_hdr *shdr =
 | 
				
			||||||
 | 
								(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 | 
				
			||||||
	struct mid_q_entry *mid;
 | 
						struct mid_q_entry *mid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smb2_seq_num_into_buf(ses->server, hdr);
 | 
						smb2_seq_num_into_buf(ses->server, shdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = smb2_get_mid_entry(ses, hdr, &mid);
 | 
						rc = smb2_get_mid_entry(ses, shdr, &mid);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return ERR_PTR(rc);
 | 
							return ERR_PTR(rc);
 | 
				
			||||||
	rc = smb2_sign_rqst(rqst, ses->server);
 | 
						rc = smb2_sign_rqst(rqst, ses->server);
 | 
				
			||||||
| 
						 | 
					@ -596,12 +601,13 @@ struct mid_q_entry *
 | 
				
			||||||
smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
					smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct smb2_hdr *hdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 | 
						struct smb2_sync_hdr *shdr =
 | 
				
			||||||
 | 
								(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 | 
				
			||||||
	struct mid_q_entry *mid;
 | 
						struct mid_q_entry *mid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smb2_seq_num_into_buf(server, hdr);
 | 
						smb2_seq_num_into_buf(server, shdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mid = smb2_mid_entry_alloc(hdr, server);
 | 
						mid = smb2_mid_entry_alloc(shdr, server);
 | 
				
			||||||
	if (mid == NULL)
 | 
						if (mid == NULL)
 | 
				
			||||||
		return ERR_PTR(-ENOMEM);
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -613,3 +619,33 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mid;
 | 
						return mid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					smb3_crypto_aead_allocate(struct TCP_Server_Info *server)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct crypto_aead *tfm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!server->secmech.ccmaesencrypt) {
 | 
				
			||||||
 | 
							tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
 | 
				
			||||||
 | 
							if (IS_ERR(tfm)) {
 | 
				
			||||||
 | 
								cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n",
 | 
				
			||||||
 | 
									 __func__);
 | 
				
			||||||
 | 
								return PTR_ERR(tfm);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							server->secmech.ccmaesencrypt = tfm;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!server->secmech.ccmaesdecrypt) {
 | 
				
			||||||
 | 
							tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
 | 
				
			||||||
 | 
							if (IS_ERR(tfm)) {
 | 
				
			||||||
 | 
								crypto_free_aead(server->secmech.ccmaesencrypt);
 | 
				
			||||||
 | 
								server->secmech.ccmaesencrypt = NULL;
 | 
				
			||||||
 | 
								cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n",
 | 
				
			||||||
 | 
									 __func__);
 | 
				
			||||||
 | 
								return PTR_ERR(tfm);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							server->secmech.ccmaesdecrypt = tfm;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -221,7 +221,7 @@ rqst_len(struct smb_rqst *rqst)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
					__smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct kvec *iov = rqst->rq_iov;
 | 
						struct kvec *iov = rqst->rq_iov;
 | 
				
			||||||
| 
						 | 
					@ -245,8 +245,12 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (n_vec < 2)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
 | 
						cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
 | 
				
			||||||
	dump_smb(iov[0].iov_base, iov[0].iov_len);
 | 
						dump_smb(iov[0].iov_base, iov[0].iov_len);
 | 
				
			||||||
 | 
						dump_smb(iov[1].iov_base, iov[1].iov_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* cork the socket */
 | 
						/* cork the socket */
 | 
				
			||||||
	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
 | 
						kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
 | 
				
			||||||
| 
						 | 
					@ -309,24 +313,43 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
 | 
					smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct smb_rqst rqst = { .rq_iov = iov,
 | 
						struct smb_rqst cur_rqst;
 | 
				
			||||||
				 .rq_nvec = n_vec };
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return smb_send_rqst(server, &rqst);
 | 
						if (!(flags & CIFS_TRANSFORM_REQ))
 | 
				
			||||||
 | 
							return __smb_send_rqst(server, rqst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!server->ops->init_transform_rq ||
 | 
				
			||||||
 | 
						    !server->ops->free_transform_rq) {
 | 
				
			||||||
 | 
							cifs_dbg(VFS, "Encryption requested but transform callbacks are missed\n");
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = server->ops->init_transform_rq(server, &cur_rqst, rqst);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = __smb_send_rqst(server, &cur_rqst);
 | 
				
			||||||
 | 
						server->ops->free_transform_rq(&cur_rqst);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 | 
					smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 | 
				
			||||||
	 unsigned int smb_buf_length)
 | 
						 unsigned int smb_buf_length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct kvec iov;
 | 
						struct kvec iov[2];
 | 
				
			||||||
 | 
						struct smb_rqst rqst = { .rq_iov = iov,
 | 
				
			||||||
 | 
									 .rq_nvec = 2 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iov.iov_base = smb_buffer;
 | 
						iov[0].iov_base = smb_buffer;
 | 
				
			||||||
	iov.iov_len = smb_buf_length + 4;
 | 
						iov[0].iov_len = 4;
 | 
				
			||||||
 | 
						iov[1].iov_base = (char *)smb_buffer + 4;
 | 
				
			||||||
 | 
						iov[1].iov_len = smb_buf_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return smb_sendv(server, &iov, 1);
 | 
						return __smb_send_rqst(server, &rqst);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
| 
						 | 
					@ -454,6 +477,10 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
				
			||||||
	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
						struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
				
			||||||
	struct mid_q_entry *mid;
 | 
						struct mid_q_entry *mid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rqst->rq_iov[0].iov_len != 4 ||
 | 
				
			||||||
 | 
						    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
 | 
				
			||||||
 | 
							return ERR_PTR(-EIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* enable signing if server requires it */
 | 
						/* enable signing if server requires it */
 | 
				
			||||||
	if (server->sign)
 | 
						if (server->sign)
 | 
				
			||||||
		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 | 
							hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 | 
				
			||||||
| 
						 | 
					@ -478,7 +505,7 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 | 
					cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 | 
				
			||||||
		mid_receive_t *receive, mid_callback_t *callback,
 | 
							mid_receive_t *receive, mid_callback_t *callback,
 | 
				
			||||||
		void *cbdata, const int flags)
 | 
							mid_handle_t *handle, void *cbdata, const int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc, timeout, optype;
 | 
						int rc, timeout, optype;
 | 
				
			||||||
	struct mid_q_entry *mid;
 | 
						struct mid_q_entry *mid;
 | 
				
			||||||
| 
						 | 
					@ -505,6 +532,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 | 
				
			||||||
	mid->receive = receive;
 | 
						mid->receive = receive;
 | 
				
			||||||
	mid->callback = callback;
 | 
						mid->callback = callback;
 | 
				
			||||||
	mid->callback_data = cbdata;
 | 
						mid->callback_data = cbdata;
 | 
				
			||||||
 | 
						mid->handle = handle;
 | 
				
			||||||
	mid->mid_state = MID_REQUEST_SUBMITTED;
 | 
						mid->mid_state = MID_REQUEST_SUBMITTED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* put it on the pending_mid_q */
 | 
						/* put it on the pending_mid_q */
 | 
				
			||||||
| 
						 | 
					@ -514,7 +542,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_in_send_inc(server);
 | 
						cifs_in_send_inc(server);
 | 
				
			||||||
	rc = smb_send_rqst(server, rqst);
 | 
						rc = smb_send_rqst(server, rqst, flags);
 | 
				
			||||||
	cifs_in_send_dec(server);
 | 
						cifs_in_send_dec(server);
 | 
				
			||||||
	cifs_save_when_sent(mid);
 | 
						cifs_save_when_sent(mid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -547,12 +575,13 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct kvec iov[1];
 | 
						struct kvec iov[1];
 | 
				
			||||||
 | 
						struct kvec rsp_iov;
 | 
				
			||||||
	int resp_buf_type;
 | 
						int resp_buf_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iov[0].iov_base = in_buf;
 | 
						iov[0].iov_base = in_buf;
 | 
				
			||||||
	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
 | 
						iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
 | 
				
			||||||
	flags |= CIFS_NO_RESP;
 | 
						flags |= CIFS_NO_RESP;
 | 
				
			||||||
	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
 | 
						rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
 | 
				
			||||||
	cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
 | 
						cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
| 
						 | 
					@ -595,10 +624,11 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int
 | 
					static inline int
 | 
				
			||||||
send_cancel(struct TCP_Server_Info *server, void *buf, struct mid_q_entry *mid)
 | 
					send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 | 
				
			||||||
 | 
						    struct mid_q_entry *mid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return server->ops->send_cancel ?
 | 
						return server->ops->send_cancel ?
 | 
				
			||||||
				server->ops->send_cancel(server, buf, mid) : 0;
 | 
									server->ops->send_cancel(server, rqst, mid) : 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
| 
						 | 
					@ -611,13 +641,15 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* convert the length into a more usable form */
 | 
						/* convert the length into a more usable form */
 | 
				
			||||||
	if (server->sign) {
 | 
						if (server->sign) {
 | 
				
			||||||
		struct kvec iov;
 | 
							struct kvec iov[2];
 | 
				
			||||||
		int rc = 0;
 | 
							int rc = 0;
 | 
				
			||||||
		struct smb_rqst rqst = { .rq_iov = &iov,
 | 
							struct smb_rqst rqst = { .rq_iov = iov,
 | 
				
			||||||
					 .rq_nvec = 1 };
 | 
										 .rq_nvec = 2 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		iov.iov_base = mid->resp_buf;
 | 
							iov[0].iov_base = mid->resp_buf;
 | 
				
			||||||
		iov.iov_len = len;
 | 
							iov[0].iov_len = 4;
 | 
				
			||||||
 | 
							iov[1].iov_base = (char *)mid->resp_buf + 4;
 | 
				
			||||||
 | 
							iov[1].iov_len = len - 4;
 | 
				
			||||||
		/* FIXME: add code to kill session */
 | 
							/* FIXME: add code to kill session */
 | 
				
			||||||
		rc = cifs_verify_signature(&rqst, server,
 | 
							rc = cifs_verify_signature(&rqst, server,
 | 
				
			||||||
					   mid->sequence_number);
 | 
										   mid->sequence_number);
 | 
				
			||||||
| 
						 | 
					@ -637,6 +669,10 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 | 
				
			||||||
	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
						struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 | 
				
			||||||
	struct mid_q_entry *mid;
 | 
						struct mid_q_entry *mid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rqst->rq_iov[0].iov_len != 4 ||
 | 
				
			||||||
 | 
						    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
 | 
				
			||||||
 | 
							return ERR_PTR(-EIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = allocate_mid(ses, hdr, &mid);
 | 
						rc = allocate_mid(ses, hdr, &mid);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return ERR_PTR(rc);
 | 
							return ERR_PTR(rc);
 | 
				
			||||||
| 
						 | 
					@ -649,17 +685,15 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
					cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
 | 
						       struct smb_rqst *rqst, int *resp_buf_type, const int flags,
 | 
				
			||||||
	     const int flags)
 | 
						       struct kvec *resp_iov)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	int timeout, optype;
 | 
						int timeout, optype;
 | 
				
			||||||
	struct mid_q_entry *midQ;
 | 
						struct mid_q_entry *midQ;
 | 
				
			||||||
	char *buf = iov[0].iov_base;
 | 
					 | 
				
			||||||
	unsigned int credits = 1;
 | 
						unsigned int credits = 1;
 | 
				
			||||||
	struct smb_rqst rqst = { .rq_iov = iov,
 | 
						char *buf;
 | 
				
			||||||
				 .rq_nvec = n_vec };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	timeout = flags & CIFS_TIMEOUT_MASK;
 | 
						timeout = flags & CIFS_TIMEOUT_MASK;
 | 
				
			||||||
	optype = flags & CIFS_OP_MASK;
 | 
						optype = flags & CIFS_OP_MASK;
 | 
				
			||||||
| 
						 | 
					@ -667,15 +701,12 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
	*resp_buf_type = CIFS_NO_BUFFER;  /* no response buf yet */
 | 
						*resp_buf_type = CIFS_NO_BUFFER;  /* no response buf yet */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((ses == NULL) || (ses->server == NULL)) {
 | 
						if ((ses == NULL) || (ses->server == NULL)) {
 | 
				
			||||||
		cifs_small_buf_release(buf);
 | 
					 | 
				
			||||||
		cifs_dbg(VFS, "Null session\n");
 | 
							cifs_dbg(VFS, "Null session\n");
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ses->server->tcpStatus == CifsExiting) {
 | 
						if (ses->server->tcpStatus == CifsExiting)
 | 
				
			||||||
		cifs_small_buf_release(buf);
 | 
					 | 
				
			||||||
		return -ENOENT;
 | 
							return -ENOENT;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Ensure that we do not send more than 50 overlapping requests
 | 
						 * Ensure that we do not send more than 50 overlapping requests
 | 
				
			||||||
| 
						 | 
					@ -684,10 +715,8 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = wait_for_free_request(ses->server, timeout, optype);
 | 
						rc = wait_for_free_request(ses->server, timeout, optype);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc)
 | 
				
			||||||
		cifs_small_buf_release(buf);
 | 
					 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Make sure that we sign in the same order that we send on this socket
 | 
						 * Make sure that we sign in the same order that we send on this socket
 | 
				
			||||||
| 
						 | 
					@ -697,10 +726,9 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&ses->server->srv_mutex);
 | 
						mutex_lock(&ses->server->srv_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	midQ = ses->server->ops->setup_request(ses, &rqst);
 | 
						midQ = ses->server->ops->setup_request(ses, rqst);
 | 
				
			||||||
	if (IS_ERR(midQ)) {
 | 
						if (IS_ERR(midQ)) {
 | 
				
			||||||
		mutex_unlock(&ses->server->srv_mutex);
 | 
							mutex_unlock(&ses->server->srv_mutex);
 | 
				
			||||||
		cifs_small_buf_release(buf);
 | 
					 | 
				
			||||||
		/* Update # of requests on wire to server */
 | 
							/* Update # of requests on wire to server */
 | 
				
			||||||
		add_credits(ses->server, 1, optype);
 | 
							add_credits(ses->server, 1, optype);
 | 
				
			||||||
		return PTR_ERR(midQ);
 | 
							return PTR_ERR(midQ);
 | 
				
			||||||
| 
						 | 
					@ -708,7 +736,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	midQ->mid_state = MID_REQUEST_SUBMITTED;
 | 
						midQ->mid_state = MID_REQUEST_SUBMITTED;
 | 
				
			||||||
	cifs_in_send_inc(ses->server);
 | 
						cifs_in_send_inc(ses->server);
 | 
				
			||||||
	rc = smb_sendv(ses->server, iov, n_vec);
 | 
						rc = smb_send_rqst(ses->server, rqst, flags);
 | 
				
			||||||
	cifs_in_send_dec(ses->server);
 | 
						cifs_in_send_dec(ses->server);
 | 
				
			||||||
	cifs_save_when_sent(midQ);
 | 
						cifs_save_when_sent(midQ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -716,32 +744,25 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
		ses->server->sequence_number -= 2;
 | 
							ses->server->sequence_number -= 2;
 | 
				
			||||||
	mutex_unlock(&ses->server->srv_mutex);
 | 
						mutex_unlock(&ses->server->srv_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0)
 | 
				
			||||||
		cifs_small_buf_release(buf);
 | 
					 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (timeout == CIFS_ASYNC_OP) {
 | 
						if (timeout == CIFS_ASYNC_OP)
 | 
				
			||||||
		cifs_small_buf_release(buf);
 | 
					 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = wait_for_response(ses->server, midQ);
 | 
						rc = wait_for_response(ses->server, midQ);
 | 
				
			||||||
	if (rc != 0) {
 | 
						if (rc != 0) {
 | 
				
			||||||
		send_cancel(ses->server, buf, midQ);
 | 
							send_cancel(ses->server, rqst, midQ);
 | 
				
			||||||
		spin_lock(&GlobalMid_Lock);
 | 
							spin_lock(&GlobalMid_Lock);
 | 
				
			||||||
		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 | 
							if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 | 
				
			||||||
			midQ->callback = DeleteMidQEntry;
 | 
								midQ->callback = DeleteMidQEntry;
 | 
				
			||||||
			spin_unlock(&GlobalMid_Lock);
 | 
								spin_unlock(&GlobalMid_Lock);
 | 
				
			||||||
			cifs_small_buf_release(buf);
 | 
					 | 
				
			||||||
			add_credits(ses->server, 1, optype);
 | 
								add_credits(ses->server, 1, optype);
 | 
				
			||||||
			return rc;
 | 
								return rc;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		spin_unlock(&GlobalMid_Lock);
 | 
							spin_unlock(&GlobalMid_Lock);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_small_buf_release(buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = cifs_sync_mid_result(midQ, ses->server);
 | 
						rc = cifs_sync_mid_result(midQ, ses->server);
 | 
				
			||||||
	if (rc != 0) {
 | 
						if (rc != 0) {
 | 
				
			||||||
		add_credits(ses->server, 1, optype);
 | 
							add_credits(ses->server, 1, optype);
 | 
				
			||||||
| 
						 | 
					@ -755,8 +776,8 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf = (char *)midQ->resp_buf;
 | 
						buf = (char *)midQ->resp_buf;
 | 
				
			||||||
	iov[0].iov_base = buf;
 | 
						resp_iov->iov_base = buf;
 | 
				
			||||||
	iov[0].iov_len = get_rfc1002_length(buf) + 4;
 | 
						resp_iov->iov_len = get_rfc1002_length(buf) + 4;
 | 
				
			||||||
	if (midQ->large_buf)
 | 
						if (midQ->large_buf)
 | 
				
			||||||
		*resp_buf_type = CIFS_LARGE_BUFFER;
 | 
							*resp_buf_type = CIFS_LARGE_BUFFER;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -777,6 +798,36 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
 | 
						     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
 | 
				
			||||||
 | 
						     const int flags, struct kvec *resp_iov)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct smb_rqst rqst;
 | 
				
			||||||
 | 
						struct kvec *new_iov;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!new_iov)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 1st iov is a RFC1001 length followed by the rest of the packet */
 | 
				
			||||||
 | 
						memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_iov[0].iov_base = new_iov[1].iov_base;
 | 
				
			||||||
 | 
						new_iov[0].iov_len = 4;
 | 
				
			||||||
 | 
						new_iov[1].iov_base += 4;
 | 
				
			||||||
 | 
						new_iov[1].iov_len -= 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&rqst, 0, sizeof(struct smb_rqst));
 | 
				
			||||||
 | 
						rqst.rq_iov = new_iov;
 | 
				
			||||||
 | 
						rqst.rq_nvec = n_vec + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
 | 
				
			||||||
 | 
						kfree(new_iov);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
SendReceive(const unsigned int xid, struct cifs_ses *ses,
 | 
					SendReceive(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
 | 
						    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
 | 
				
			||||||
| 
						 | 
					@ -784,6 +835,9 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	struct mid_q_entry *midQ;
 | 
						struct mid_q_entry *midQ;
 | 
				
			||||||
 | 
						unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
 | 
				
			||||||
 | 
						struct kvec iov = { .iov_base = in_buf, .iov_len = len };
 | 
				
			||||||
 | 
						struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ses == NULL) {
 | 
						if (ses == NULL) {
 | 
				
			||||||
		cifs_dbg(VFS, "Null smb session\n");
 | 
							cifs_dbg(VFS, "Null smb session\n");
 | 
				
			||||||
| 
						 | 
					@ -801,10 +855,9 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
	   to the same server. We may make this configurable later or
 | 
						   to the same server. We may make this configurable later or
 | 
				
			||||||
	   use ses->maxReq */
 | 
						   use ses->maxReq */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
 | 
						if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
 | 
				
			||||||
			MAX_CIFS_HDR_SIZE - 4) {
 | 
					 | 
				
			||||||
		cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
 | 
							cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
 | 
				
			||||||
			 be32_to_cpu(in_buf->smb_buf_length));
 | 
								 len);
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -835,7 +888,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
	midQ->mid_state = MID_REQUEST_SUBMITTED;
 | 
						midQ->mid_state = MID_REQUEST_SUBMITTED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cifs_in_send_inc(ses->server);
 | 
						cifs_in_send_inc(ses->server);
 | 
				
			||||||
	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
 | 
						rc = smb_send(ses->server, in_buf, len);
 | 
				
			||||||
	cifs_in_send_dec(ses->server);
 | 
						cifs_in_send_dec(ses->server);
 | 
				
			||||||
	cifs_save_when_sent(midQ);
 | 
						cifs_save_when_sent(midQ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -852,7 +905,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = wait_for_response(ses->server, midQ);
 | 
						rc = wait_for_response(ses->server, midQ);
 | 
				
			||||||
	if (rc != 0) {
 | 
						if (rc != 0) {
 | 
				
			||||||
		send_cancel(ses->server, in_buf, midQ);
 | 
							send_cancel(ses->server, &rqst, midQ);
 | 
				
			||||||
		spin_lock(&GlobalMid_Lock);
 | 
							spin_lock(&GlobalMid_Lock);
 | 
				
			||||||
		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 | 
							if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 | 
				
			||||||
			/* no longer considered to be "in-flight" */
 | 
								/* no longer considered to be "in-flight" */
 | 
				
			||||||
| 
						 | 
					@ -921,6 +974,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	int rstart = 0;
 | 
						int rstart = 0;
 | 
				
			||||||
	struct mid_q_entry *midQ;
 | 
						struct mid_q_entry *midQ;
 | 
				
			||||||
	struct cifs_ses *ses;
 | 
						struct cifs_ses *ses;
 | 
				
			||||||
 | 
						unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
 | 
				
			||||||
 | 
						struct kvec iov = { .iov_base = in_buf, .iov_len = len };
 | 
				
			||||||
 | 
						struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tcon == NULL || tcon->ses == NULL) {
 | 
						if (tcon == NULL || tcon->ses == NULL) {
 | 
				
			||||||
		cifs_dbg(VFS, "Null smb session\n");
 | 
							cifs_dbg(VFS, "Null smb session\n");
 | 
				
			||||||
| 
						 | 
					@ -940,10 +996,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
	   to the same server. We may make this configurable later or
 | 
						   to the same server. We may make this configurable later or
 | 
				
			||||||
	   use ses->maxReq */
 | 
						   use ses->maxReq */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
 | 
						if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
 | 
				
			||||||
			MAX_CIFS_HDR_SIZE - 4) {
 | 
					 | 
				
			||||||
		cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
 | 
							cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
 | 
				
			||||||
			 be32_to_cpu(in_buf->smb_buf_length));
 | 
								 len);
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -972,7 +1027,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	midQ->mid_state = MID_REQUEST_SUBMITTED;
 | 
						midQ->mid_state = MID_REQUEST_SUBMITTED;
 | 
				
			||||||
	cifs_in_send_inc(ses->server);
 | 
						cifs_in_send_inc(ses->server);
 | 
				
			||||||
	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
 | 
						rc = smb_send(ses->server, in_buf, len);
 | 
				
			||||||
	cifs_in_send_dec(ses->server);
 | 
						cifs_in_send_dec(ses->server);
 | 
				
			||||||
	cifs_save_when_sent(midQ);
 | 
						cifs_save_when_sent(midQ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1001,7 +1056,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
		if (in_buf->Command == SMB_COM_TRANSACTION2) {
 | 
							if (in_buf->Command == SMB_COM_TRANSACTION2) {
 | 
				
			||||||
			/* POSIX lock. We send a NT_CANCEL SMB to cause the
 | 
								/* POSIX lock. We send a NT_CANCEL SMB to cause the
 | 
				
			||||||
			   blocking lock to return. */
 | 
								   blocking lock to return. */
 | 
				
			||||||
			rc = send_cancel(ses->server, in_buf, midQ);
 | 
								rc = send_cancel(ses->server, &rqst, midQ);
 | 
				
			||||||
			if (rc) {
 | 
								if (rc) {
 | 
				
			||||||
				cifs_delete_mid(midQ);
 | 
									cifs_delete_mid(midQ);
 | 
				
			||||||
				return rc;
 | 
									return rc;
 | 
				
			||||||
| 
						 | 
					@ -1022,7 +1077,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rc = wait_for_response(ses->server, midQ);
 | 
							rc = wait_for_response(ses->server, midQ);
 | 
				
			||||||
		if (rc) {
 | 
							if (rc) {
 | 
				
			||||||
			send_cancel(ses->server, in_buf, midQ);
 | 
								send_cancel(ses->server, &rqst, midQ);
 | 
				
			||||||
			spin_lock(&GlobalMid_Lock);
 | 
								spin_lock(&GlobalMid_Lock);
 | 
				
			||||||
			if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 | 
								if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 | 
				
			||||||
				/* no longer considered to be "in-flight" */
 | 
									/* no longer considered to be "in-flight" */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue