xref: /linux/fs/smb/client/cifstransport.c (revision 55ddcff7358aa7cb20ff71fd2ec3131133b1fc3d)
11cdd5a26SSteve French // SPDX-License-Identifier: LGPL-2.1
21cdd5a26SSteve French /*
31cdd5a26SSteve French  *
41cdd5a26SSteve French  *   Copyright (C) International Business Machines  Corp., 2002,2008
51cdd5a26SSteve French  *   Author(s): Steve French (sfrench@us.ibm.com)
61cdd5a26SSteve French  *   Jeremy Allison (jra@samba.org) 2006.
71cdd5a26SSteve French  *
81cdd5a26SSteve French  */
91cdd5a26SSteve French 
101cdd5a26SSteve French #include <linux/fs.h>
111cdd5a26SSteve French #include <linux/list.h>
121cdd5a26SSteve French #include <linux/gfp.h>
131cdd5a26SSteve French #include <linux/wait.h>
141cdd5a26SSteve French #include <linux/net.h>
151cdd5a26SSteve French #include <linux/delay.h>
161cdd5a26SSteve French #include <linux/freezer.h>
171cdd5a26SSteve French #include <linux/tcp.h>
181cdd5a26SSteve French #include <linux/bvec.h>
191cdd5a26SSteve French #include <linux/highmem.h>
201cdd5a26SSteve French #include <linux/uaccess.h>
211cdd5a26SSteve French #include <linux/processor.h>
221cdd5a26SSteve French #include <linux/mempool.h>
231cdd5a26SSteve French #include <linux/sched/signal.h>
241cdd5a26SSteve French #include <linux/task_io_accounting_ops.h>
251cdd5a26SSteve French #include "cifspdu.h"
261cdd5a26SSteve French #include "cifsglob.h"
271cdd5a26SSteve French #include "cifsproto.h"
281cdd5a26SSteve French #include "cifs_debug.h"
291cdd5a26SSteve French #include "smb2proto.h"
301cdd5a26SSteve French #include "smbdirect.h"
311cdd5a26SSteve French #include "compress.h"
321cdd5a26SSteve French 
331cdd5a26SSteve French /* Max number of iovectors we can use off the stack when sending requests. */
341cdd5a26SSteve French #define CIFS_MAX_IOV_SIZE 8
351cdd5a26SSteve French 
361cdd5a26SSteve French static struct mid_q_entry *
alloc_mid(const struct smb_hdr * smb_buffer,struct TCP_Server_Info * server)371cdd5a26SSteve French alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
381cdd5a26SSteve French {
391cdd5a26SSteve French 	struct mid_q_entry *temp;
401cdd5a26SSteve French 
411cdd5a26SSteve French 	if (server == NULL) {
421cdd5a26SSteve French 		cifs_dbg(VFS, "%s: null TCP session\n", __func__);
431cdd5a26SSteve French 		return NULL;
441cdd5a26SSteve French 	}
451cdd5a26SSteve French 
461cdd5a26SSteve French 	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
471cdd5a26SSteve French 	memset(temp, 0, sizeof(struct mid_q_entry));
481cdd5a26SSteve French 	kref_init(&temp->refcount);
49*e3835731SWang Zhaolong 	spin_lock_init(&temp->mid_lock);
501cdd5a26SSteve French 	temp->mid = get_mid(smb_buffer);
511cdd5a26SSteve French 	temp->pid = current->pid;
521cdd5a26SSteve French 	temp->command = cpu_to_le16(smb_buffer->Command);
531cdd5a26SSteve French 	cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
541cdd5a26SSteve French 	/* easier to use jiffies */
551cdd5a26SSteve French 	/* when mid allocated can be before when sent */
561cdd5a26SSteve French 	temp->when_alloc = jiffies;
571cdd5a26SSteve French 	temp->server = server;
581cdd5a26SSteve French 
591cdd5a26SSteve French 	/*
601cdd5a26SSteve French 	 * The default is for the mid to be synchronous, so the
611cdd5a26SSteve French 	 * default callback just wakes up the current task.
621cdd5a26SSteve French 	 */
631cdd5a26SSteve French 	get_task_struct(current);
641cdd5a26SSteve French 	temp->creator = current;
651cdd5a26SSteve French 	temp->callback = cifs_wake_up_task;
661cdd5a26SSteve French 	temp->callback_data = current;
671cdd5a26SSteve French 
681cdd5a26SSteve French 	atomic_inc(&mid_count);
691cdd5a26SSteve French 	temp->mid_state = MID_REQUEST_ALLOCATED;
701cdd5a26SSteve French 	return temp;
711cdd5a26SSteve French }
721cdd5a26SSteve French 
731cdd5a26SSteve French int
smb_send(struct TCP_Server_Info * server,struct smb_hdr * smb_buffer,unsigned int smb_buf_length)741cdd5a26SSteve French smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
751cdd5a26SSteve French 	 unsigned int smb_buf_length)
761cdd5a26SSteve French {
771cdd5a26SSteve French 	struct kvec iov[2];
781cdd5a26SSteve French 	struct smb_rqst rqst = { .rq_iov = iov,
791cdd5a26SSteve French 				 .rq_nvec = 2 };
801cdd5a26SSteve French 
811cdd5a26SSteve French 	iov[0].iov_base = smb_buffer;
821cdd5a26SSteve French 	iov[0].iov_len = 4;
831cdd5a26SSteve French 	iov[1].iov_base = (char *)smb_buffer + 4;
841cdd5a26SSteve French 	iov[1].iov_len = smb_buf_length;
851cdd5a26SSteve French 
861cdd5a26SSteve French 	return __smb_send_rqst(server, 1, &rqst);
871cdd5a26SSteve French }
881cdd5a26SSteve French 
allocate_mid(struct cifs_ses * ses,struct smb_hdr * in_buf,struct mid_q_entry ** ppmidQ)891cdd5a26SSteve French static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
901cdd5a26SSteve French 			struct mid_q_entry **ppmidQ)
911cdd5a26SSteve French {
921cdd5a26SSteve French 	spin_lock(&ses->ses_lock);
931cdd5a26SSteve French 	if (ses->ses_status == SES_NEW) {
941cdd5a26SSteve French 		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
951cdd5a26SSteve French 			(in_buf->Command != SMB_COM_NEGOTIATE)) {
961cdd5a26SSteve French 			spin_unlock(&ses->ses_lock);
971cdd5a26SSteve French 			return -EAGAIN;
981cdd5a26SSteve French 		}
991cdd5a26SSteve French 		/* else ok - we are setting up session */
1001cdd5a26SSteve French 	}
1011cdd5a26SSteve French 
1021cdd5a26SSteve French 	if (ses->ses_status == SES_EXITING) {
1031cdd5a26SSteve French 		/* check if SMB session is bad because we are setting it up */
1041cdd5a26SSteve French 		if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
1051cdd5a26SSteve French 			spin_unlock(&ses->ses_lock);
1061cdd5a26SSteve French 			return -EAGAIN;
1071cdd5a26SSteve French 		}
1081cdd5a26SSteve French 		/* else ok - we are shutting down session */
1091cdd5a26SSteve French 	}
1101cdd5a26SSteve French 	spin_unlock(&ses->ses_lock);
1111cdd5a26SSteve French 
1121cdd5a26SSteve French 	*ppmidQ = alloc_mid(in_buf, ses->server);
1131cdd5a26SSteve French 	if (*ppmidQ == NULL)
1141cdd5a26SSteve French 		return -ENOMEM;
1151cdd5a26SSteve French 	spin_lock(&ses->server->mid_queue_lock);
1161cdd5a26SSteve French 	list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
1171cdd5a26SSteve French 	spin_unlock(&ses->server->mid_queue_lock);
1181cdd5a26SSteve French 	return 0;
1191cdd5a26SSteve French }
1201cdd5a26SSteve French 
1211cdd5a26SSteve French struct mid_q_entry *
cifs_setup_async_request(struct TCP_Server_Info * server,struct smb_rqst * rqst)1221cdd5a26SSteve French cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
1231cdd5a26SSteve French {
1241cdd5a26SSteve French 	int rc;
1251cdd5a26SSteve French 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
1261cdd5a26SSteve French 	struct mid_q_entry *mid;
1271cdd5a26SSteve French 
1281cdd5a26SSteve French 	if (rqst->rq_iov[0].iov_len != 4 ||
1291cdd5a26SSteve French 	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
1301cdd5a26SSteve French 		return ERR_PTR(-EIO);
1311cdd5a26SSteve French 
1321cdd5a26SSteve French 	/* enable signing if server requires it */
1331cdd5a26SSteve French 	if (server->sign)
1341cdd5a26SSteve French 		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1351cdd5a26SSteve French 
1361cdd5a26SSteve French 	mid = alloc_mid(hdr, server);
1371cdd5a26SSteve French 	if (mid == NULL)
1381cdd5a26SSteve French 		return ERR_PTR(-ENOMEM);
1391cdd5a26SSteve French 
1401cdd5a26SSteve French 	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
1411cdd5a26SSteve French 	if (rc) {
1421cdd5a26SSteve French 		release_mid(mid);
1431cdd5a26SSteve French 		return ERR_PTR(rc);
1441cdd5a26SSteve French 	}
1451cdd5a26SSteve French 
1461cdd5a26SSteve French 	return mid;
1471cdd5a26SSteve French }
1481cdd5a26SSteve French 
1491cdd5a26SSteve French /*
1501cdd5a26SSteve French  *
1511cdd5a26SSteve French  * Send an SMB Request.  No response info (other than return code)
1521cdd5a26SSteve French  * needs to be parsed.
1531cdd5a26SSteve French  *
1541cdd5a26SSteve French  * flags indicate the type of request buffer and how long to wait
1551cdd5a26SSteve French  * and whether to log NT STATUS code (error) before mapping it to POSIX error
1561cdd5a26SSteve French  *
1571cdd5a26SSteve French  */
1581cdd5a26SSteve French int
SendReceiveNoRsp(const unsigned int xid,struct cifs_ses * ses,char * in_buf,int flags)1591cdd5a26SSteve French SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
1601cdd5a26SSteve French 		 char *in_buf, int flags)
1611cdd5a26SSteve French {
1621cdd5a26SSteve French 	int rc;
1631cdd5a26SSteve French 	struct kvec iov[1];
1641cdd5a26SSteve French 	struct kvec rsp_iov;
1651cdd5a26SSteve French 	int resp_buf_type;
1661cdd5a26SSteve French 
1671cdd5a26SSteve French 	iov[0].iov_base = in_buf;
1681cdd5a26SSteve French 	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
1691cdd5a26SSteve French 	flags |= CIFS_NO_RSP_BUF;
1701cdd5a26SSteve French 	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
1711cdd5a26SSteve French 	cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
1721cdd5a26SSteve French 
1731cdd5a26SSteve French 	return rc;
1741cdd5a26SSteve French }
1751cdd5a26SSteve French 
1761cdd5a26SSteve French int
cifs_check_receive(struct mid_q_entry * mid,struct TCP_Server_Info * server,bool log_error)1771cdd5a26SSteve French cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
1781cdd5a26SSteve French 		   bool log_error)
1791cdd5a26SSteve French {
1801cdd5a26SSteve French 	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
1811cdd5a26SSteve French 
1821cdd5a26SSteve French 	dump_smb(mid->resp_buf, min_t(u32, 92, len));
1831cdd5a26SSteve French 
1841cdd5a26SSteve French 	/* convert the length into a more usable form */
1851cdd5a26SSteve French 	if (server->sign) {
1861cdd5a26SSteve French 		struct kvec iov[2];
1871cdd5a26SSteve French 		int rc = 0;
1881cdd5a26SSteve French 		struct smb_rqst rqst = { .rq_iov = iov,
1891cdd5a26SSteve French 					 .rq_nvec = 2 };
1901cdd5a26SSteve French 
1911cdd5a26SSteve French 		iov[0].iov_base = mid->resp_buf;
1921cdd5a26SSteve French 		iov[0].iov_len = 4;
1931cdd5a26SSteve French 		iov[1].iov_base = (char *)mid->resp_buf + 4;
1941cdd5a26SSteve French 		iov[1].iov_len = len - 4;
1951cdd5a26SSteve French 		/* FIXME: add code to kill session */
1961cdd5a26SSteve French 		rc = cifs_verify_signature(&rqst, server,
1971cdd5a26SSteve French 					   mid->sequence_number);
1981cdd5a26SSteve French 		if (rc)
1991cdd5a26SSteve French 			cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
2001cdd5a26SSteve French 				 rc);
2011cdd5a26SSteve French 	}
2021cdd5a26SSteve French 
2031cdd5a26SSteve French 	/* BB special case reconnect tid and uid here? */
2041cdd5a26SSteve French 	return map_and_check_smb_error(mid, log_error);
2051cdd5a26SSteve French }
2061cdd5a26SSteve French 
2071cdd5a26SSteve French struct mid_q_entry *
cifs_setup_request(struct cifs_ses * ses,struct TCP_Server_Info * ignored,struct smb_rqst * rqst)2081cdd5a26SSteve French cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
2091cdd5a26SSteve French 		   struct smb_rqst *rqst)
2101cdd5a26SSteve French {
2111cdd5a26SSteve French 	int rc;
2121cdd5a26SSteve French 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
2131cdd5a26SSteve French 	struct mid_q_entry *mid;
2141cdd5a26SSteve French 
2151cdd5a26SSteve French 	if (rqst->rq_iov[0].iov_len != 4 ||
2161cdd5a26SSteve French 	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
2171cdd5a26SSteve French 		return ERR_PTR(-EIO);
2181cdd5a26SSteve French 
2191cdd5a26SSteve French 	rc = allocate_mid(ses, hdr, &mid);
2201cdd5a26SSteve French 	if (rc)
2211cdd5a26SSteve French 		return ERR_PTR(rc);
2221cdd5a26SSteve French 	rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
2231cdd5a26SSteve French 	if (rc) {
2241cdd5a26SSteve French 		delete_mid(mid);
2251cdd5a26SSteve French 		return ERR_PTR(rc);
2261cdd5a26SSteve French 	}
2271cdd5a26SSteve French 	return mid;
2281cdd5a26SSteve French }
2291cdd5a26SSteve French 
2301cdd5a26SSteve French int
SendReceive2(const unsigned int xid,struct cifs_ses * ses,struct kvec * iov,int n_vec,int * resp_buf_type,const int flags,struct kvec * resp_iov)2311cdd5a26SSteve French SendReceive2(const unsigned int xid, struct cifs_ses *ses,
2321cdd5a26SSteve French 	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
2331cdd5a26SSteve French 	     const int flags, struct kvec *resp_iov)
2341cdd5a26SSteve French {
2351cdd5a26SSteve French 	struct smb_rqst rqst;
2361cdd5a26SSteve French 	struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
2371cdd5a26SSteve French 	int rc;
2381cdd5a26SSteve French 
2391cdd5a26SSteve French 	if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
2401cdd5a26SSteve French 		new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
2411cdd5a26SSteve French 					GFP_KERNEL);
2421cdd5a26SSteve French 		if (!new_iov) {
2431cdd5a26SSteve French 			/* otherwise cifs_send_recv below sets resp_buf_type */
2441cdd5a26SSteve French 			*resp_buf_type = CIFS_NO_BUFFER;
2451cdd5a26SSteve French 			return -ENOMEM;
2461cdd5a26SSteve French 		}
2471cdd5a26SSteve French 	} else
2481cdd5a26SSteve French 		new_iov = s_iov;
2491cdd5a26SSteve French 
2501cdd5a26SSteve French 	/* 1st iov is a RFC1001 length followed by the rest of the packet */
2511cdd5a26SSteve French 	memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
2521cdd5a26SSteve French 
2531cdd5a26SSteve French 	new_iov[0].iov_base = new_iov[1].iov_base;
2541cdd5a26SSteve French 	new_iov[0].iov_len = 4;
2551cdd5a26SSteve French 	new_iov[1].iov_base += 4;
2561cdd5a26SSteve French 	new_iov[1].iov_len -= 4;
2571cdd5a26SSteve French 
2581cdd5a26SSteve French 	memset(&rqst, 0, sizeof(struct smb_rqst));
2591cdd5a26SSteve French 	rqst.rq_iov = new_iov;
2601cdd5a26SSteve French 	rqst.rq_nvec = n_vec + 1;
2611cdd5a26SSteve French 
2621cdd5a26SSteve French 	rc = cifs_send_recv(xid, ses, ses->server,
2631cdd5a26SSteve French 			    &rqst, resp_buf_type, flags, resp_iov);
2641cdd5a26SSteve French 	if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
2651cdd5a26SSteve French 		kfree(new_iov);
2661cdd5a26SSteve French 	return rc;
2671cdd5a26SSteve French }
2681cdd5a26SSteve French 
2691cdd5a26SSteve French int
SendReceive(const unsigned int xid,struct cifs_ses * ses,struct smb_hdr * in_buf,struct smb_hdr * out_buf,int * pbytes_returned,const int flags)2701cdd5a26SSteve French SendReceive(const unsigned int xid, struct cifs_ses *ses,
2711cdd5a26SSteve French 	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
2721cdd5a26SSteve French 	    int *pbytes_returned, const int flags)
2731cdd5a26SSteve French {
2741cdd5a26SSteve French 	int rc = 0;
2751cdd5a26SSteve French 	struct mid_q_entry *midQ;
2761cdd5a26SSteve French 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
2771cdd5a26SSteve French 	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
2781cdd5a26SSteve French 	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
2791cdd5a26SSteve French 	struct cifs_credits credits = { .value = 1, .instance = 0 };
2801cdd5a26SSteve French 	struct TCP_Server_Info *server;
2811cdd5a26SSteve French 
2821cdd5a26SSteve French 	if (ses == NULL) {
2831cdd5a26SSteve French 		cifs_dbg(VFS, "Null smb session\n");
2841cdd5a26SSteve French 		return -EIO;
2851cdd5a26SSteve French 	}
2861cdd5a26SSteve French 	server = ses->server;
2871cdd5a26SSteve French 	if (server == NULL) {
2881cdd5a26SSteve French 		cifs_dbg(VFS, "Null tcp session\n");
2891cdd5a26SSteve French 		return -EIO;
2901cdd5a26SSteve French 	}
2911cdd5a26SSteve French 
2921cdd5a26SSteve French 	spin_lock(&server->srv_lock);
2931cdd5a26SSteve French 	if (server->tcpStatus == CifsExiting) {
2941cdd5a26SSteve French 		spin_unlock(&server->srv_lock);
2951cdd5a26SSteve French 		return -ENOENT;
2961cdd5a26SSteve French 	}
2971cdd5a26SSteve French 	spin_unlock(&server->srv_lock);
2981cdd5a26SSteve French 
2991cdd5a26SSteve French 	/* Ensure that we do not send more than 50 overlapping requests
3001cdd5a26SSteve French 	   to the same server. We may make this configurable later or
3011cdd5a26SSteve French 	   use ses->maxReq */
3021cdd5a26SSteve French 
3031cdd5a26SSteve French 	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
3041cdd5a26SSteve French 		cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
3051cdd5a26SSteve French 				len);
3061cdd5a26SSteve French 		return -EIO;
3071cdd5a26SSteve French 	}
3081cdd5a26SSteve French 
3091cdd5a26SSteve French 	rc = wait_for_free_request(server, flags, &credits.instance);
3101cdd5a26SSteve French 	if (rc)
3111cdd5a26SSteve French 		return rc;
3121cdd5a26SSteve French 
3131cdd5a26SSteve French 	/* make sure that we sign in the same order that we send on this socket
3141cdd5a26SSteve French 	   and avoid races inside tcp sendmsg code that could cause corruption
3151cdd5a26SSteve French 	   of smb data */
3161cdd5a26SSteve French 
3171cdd5a26SSteve French 	cifs_server_lock(server);
3181cdd5a26SSteve French 
3191cdd5a26SSteve French 	rc = allocate_mid(ses, in_buf, &midQ);
3201cdd5a26SSteve French 	if (rc) {
3211cdd5a26SSteve French 		cifs_server_unlock(server);
3221cdd5a26SSteve French 		/* Update # of requests on wire to server */
3231cdd5a26SSteve French 		add_credits(server, &credits, 0);
3241cdd5a26SSteve French 		return rc;
3251cdd5a26SSteve French 	}
3261cdd5a26SSteve French 
3271cdd5a26SSteve French 	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
3281cdd5a26SSteve French 	if (rc) {
3291cdd5a26SSteve French 		cifs_server_unlock(server);
3301cdd5a26SSteve French 		goto out;
3311cdd5a26SSteve French 	}
3321cdd5a26SSteve French 
3331cdd5a26SSteve French 	midQ->mid_state = MID_REQUEST_SUBMITTED;
3341cdd5a26SSteve French 
3351cdd5a26SSteve French 	rc = smb_send(server, in_buf, len);
3361cdd5a26SSteve French 	cifs_save_when_sent(midQ);
3371cdd5a26SSteve French 
3381cdd5a26SSteve French 	if (rc < 0)
3391cdd5a26SSteve French 		server->sequence_number -= 2;
3401cdd5a26SSteve French 
3411cdd5a26SSteve French 	cifs_server_unlock(server);
3421cdd5a26SSteve French 
3431cdd5a26SSteve French 	if (rc < 0)
3441cdd5a26SSteve French 		goto out;
3451cdd5a26SSteve French 
3461cdd5a26SSteve French 	rc = wait_for_response(server, midQ);
3471cdd5a26SSteve French 	if (rc != 0) {
3481cdd5a26SSteve French 		send_cancel(server, &rqst, midQ);
349*e3835731SWang Zhaolong 		spin_lock(&midQ->mid_lock);
350*e3835731SWang Zhaolong 		if (midQ->callback) {
3511cdd5a26SSteve French 			/* no longer considered to be "in-flight" */
3521cdd5a26SSteve French 			midQ->callback = release_mid;
353*e3835731SWang Zhaolong 			spin_unlock(&midQ->mid_lock);
3541cdd5a26SSteve French 			add_credits(server, &credits, 0);
3551cdd5a26SSteve French 			return rc;
3561cdd5a26SSteve French 		}
357*e3835731SWang Zhaolong 		spin_unlock(&midQ->mid_lock);
3581cdd5a26SSteve French 	}
3591cdd5a26SSteve French 
3601cdd5a26SSteve French 	rc = cifs_sync_mid_result(midQ, server);
3611cdd5a26SSteve French 	if (rc != 0) {
3621cdd5a26SSteve French 		add_credits(server, &credits, 0);
3631cdd5a26SSteve French 		return rc;
3641cdd5a26SSteve French 	}
3651cdd5a26SSteve French 
3661cdd5a26SSteve French 	if (!midQ->resp_buf || !out_buf ||
3671cdd5a26SSteve French 	    midQ->mid_state != MID_RESPONSE_READY) {
3681cdd5a26SSteve French 		rc = -EIO;
3691cdd5a26SSteve French 		cifs_server_dbg(VFS, "Bad MID state?\n");
3701cdd5a26SSteve French 		goto out;
3711cdd5a26SSteve French 	}
3721cdd5a26SSteve French 
3731cdd5a26SSteve French 	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
3741cdd5a26SSteve French 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
3751cdd5a26SSteve French 	rc = cifs_check_receive(midQ, server, 0);
3761cdd5a26SSteve French out:
3771cdd5a26SSteve French 	delete_mid(midQ);
3781cdd5a26SSteve French 	add_credits(server, &credits, 0);
3791cdd5a26SSteve French 
3801cdd5a26SSteve French 	return rc;
3811cdd5a26SSteve French }
3821cdd5a26SSteve French 
3831cdd5a26SSteve French /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
3841cdd5a26SSteve French    blocking lock to return. */
3851cdd5a26SSteve French 
3861cdd5a26SSteve French static int
send_lock_cancel(const unsigned int xid,struct cifs_tcon * tcon,struct smb_hdr * in_buf,struct smb_hdr * out_buf)3871cdd5a26SSteve French send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
3881cdd5a26SSteve French 			struct smb_hdr *in_buf,
3891cdd5a26SSteve French 			struct smb_hdr *out_buf)
3901cdd5a26SSteve French {
3911cdd5a26SSteve French 	int bytes_returned;
3921cdd5a26SSteve French 	struct cifs_ses *ses = tcon->ses;
3931cdd5a26SSteve French 	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
3941cdd5a26SSteve French 
3951cdd5a26SSteve French 	/* We just modify the current in_buf to change
3961cdd5a26SSteve French 	   the type of lock from LOCKING_ANDX_SHARED_LOCK
3971cdd5a26SSteve French 	   or LOCKING_ANDX_EXCLUSIVE_LOCK to
3981cdd5a26SSteve French 	   LOCKING_ANDX_CANCEL_LOCK. */
3991cdd5a26SSteve French 
4001cdd5a26SSteve French 	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
4011cdd5a26SSteve French 	pSMB->Timeout = 0;
4021cdd5a26SSteve French 	pSMB->hdr.Mid = get_next_mid(ses->server);
4031cdd5a26SSteve French 
4041cdd5a26SSteve French 	return SendReceive(xid, ses, in_buf, out_buf,
4051cdd5a26SSteve French 			&bytes_returned, 0);
4061cdd5a26SSteve French }
4071cdd5a26SSteve French 
4081cdd5a26SSteve French int
SendReceiveBlockingLock(const unsigned int xid,struct cifs_tcon * tcon,struct smb_hdr * in_buf,struct smb_hdr * out_buf,int * pbytes_returned)4091cdd5a26SSteve French SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
4101cdd5a26SSteve French 	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
4111cdd5a26SSteve French 	    int *pbytes_returned)
4121cdd5a26SSteve French {
4131cdd5a26SSteve French 	int rc = 0;
4141cdd5a26SSteve French 	int rstart = 0;
4151cdd5a26SSteve French 	struct mid_q_entry *midQ;
4161cdd5a26SSteve French 	struct cifs_ses *ses;
4171cdd5a26SSteve French 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
4181cdd5a26SSteve French 	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
4191cdd5a26SSteve French 	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
4201cdd5a26SSteve French 	unsigned int instance;
4211cdd5a26SSteve French 	struct TCP_Server_Info *server;
4221cdd5a26SSteve French 
4231cdd5a26SSteve French 	if (tcon == NULL || tcon->ses == NULL) {
4241cdd5a26SSteve French 		cifs_dbg(VFS, "Null smb session\n");
4251cdd5a26SSteve French 		return -EIO;
4261cdd5a26SSteve French 	}
4271cdd5a26SSteve French 	ses = tcon->ses;
4281cdd5a26SSteve French 	server = ses->server;
4291cdd5a26SSteve French 
4301cdd5a26SSteve French 	if (server == NULL) {
4311cdd5a26SSteve French 		cifs_dbg(VFS, "Null tcp session\n");
4321cdd5a26SSteve French 		return -EIO;
4331cdd5a26SSteve French 	}
4341cdd5a26SSteve French 
4351cdd5a26SSteve French 	spin_lock(&server->srv_lock);
4361cdd5a26SSteve French 	if (server->tcpStatus == CifsExiting) {
4371cdd5a26SSteve French 		spin_unlock(&server->srv_lock);
4381cdd5a26SSteve French 		return -ENOENT;
4391cdd5a26SSteve French 	}
4401cdd5a26SSteve French 	spin_unlock(&server->srv_lock);
4411cdd5a26SSteve French 
4421cdd5a26SSteve French 	/* Ensure that we do not send more than 50 overlapping requests
4431cdd5a26SSteve French 	   to the same server. We may make this configurable later or
4441cdd5a26SSteve French 	   use ses->maxReq */
4451cdd5a26SSteve French 
4461cdd5a26SSteve French 	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
4471cdd5a26SSteve French 		cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
4481cdd5a26SSteve French 			      len);
4491cdd5a26SSteve French 		return -EIO;
4501cdd5a26SSteve French 	}
4511cdd5a26SSteve French 
4521cdd5a26SSteve French 	rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
4531cdd5a26SSteve French 	if (rc)
4541cdd5a26SSteve French 		return rc;
4551cdd5a26SSteve French 
4561cdd5a26SSteve French 	/* make sure that we sign in the same order that we send on this socket
4571cdd5a26SSteve French 	   and avoid races inside tcp sendmsg code that could cause corruption
4581cdd5a26SSteve French 	   of smb data */
4591cdd5a26SSteve French 
4601cdd5a26SSteve French 	cifs_server_lock(server);
4611cdd5a26SSteve French 
4621cdd5a26SSteve French 	rc = allocate_mid(ses, in_buf, &midQ);
4631cdd5a26SSteve French 	if (rc) {
4641cdd5a26SSteve French 		cifs_server_unlock(server);
4651cdd5a26SSteve French 		return rc;
4661cdd5a26SSteve French 	}
4671cdd5a26SSteve French 
4681cdd5a26SSteve French 	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
4691cdd5a26SSteve French 	if (rc) {
4701cdd5a26SSteve French 		delete_mid(midQ);
4711cdd5a26SSteve French 		cifs_server_unlock(server);
4721cdd5a26SSteve French 		return rc;
4731cdd5a26SSteve French 	}
4741cdd5a26SSteve French 
4751cdd5a26SSteve French 	midQ->mid_state = MID_REQUEST_SUBMITTED;
4761cdd5a26SSteve French 	rc = smb_send(server, in_buf, len);
4771cdd5a26SSteve French 	cifs_save_when_sent(midQ);
4781cdd5a26SSteve French 
4791cdd5a26SSteve French 	if (rc < 0)
4801cdd5a26SSteve French 		server->sequence_number -= 2;
4811cdd5a26SSteve French 
4821cdd5a26SSteve French 	cifs_server_unlock(server);
4831cdd5a26SSteve French 
4841cdd5a26SSteve French 	if (rc < 0) {
4851cdd5a26SSteve French 		delete_mid(midQ);
4861cdd5a26SSteve French 		return rc;
4871cdd5a26SSteve French 	}
4881cdd5a26SSteve French 
4891cdd5a26SSteve French 	/* Wait for a reply - allow signals to interrupt. */
4901cdd5a26SSteve French 	rc = wait_event_interruptible(server->response_q,
4911cdd5a26SSteve French 		(!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
4921cdd5a26SSteve French 		   midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
4931cdd5a26SSteve French 		((server->tcpStatus != CifsGood) &&
4941cdd5a26SSteve French 		 (server->tcpStatus != CifsNew)));
4951cdd5a26SSteve French 
4961cdd5a26SSteve French 	/* Were we interrupted by a signal ? */
4971cdd5a26SSteve French 	spin_lock(&server->srv_lock);
4981cdd5a26SSteve French 	if ((rc == -ERESTARTSYS) &&
4991cdd5a26SSteve French 		(midQ->mid_state == MID_REQUEST_SUBMITTED ||
5001cdd5a26SSteve French 		 midQ->mid_state == MID_RESPONSE_RECEIVED) &&
5011cdd5a26SSteve French 		((server->tcpStatus == CifsGood) ||
5021cdd5a26SSteve French 		 (server->tcpStatus == CifsNew))) {
5031cdd5a26SSteve French 		spin_unlock(&server->srv_lock);
5041cdd5a26SSteve French 
5051cdd5a26SSteve French 		if (in_buf->Command == SMB_COM_TRANSACTION2) {
5061cdd5a26SSteve French 			/* POSIX lock. We send a NT_CANCEL SMB to cause the
5071cdd5a26SSteve French 			   blocking lock to return. */
5081cdd5a26SSteve French 			rc = send_cancel(server, &rqst, midQ);
5091cdd5a26SSteve French 			if (rc) {
5101cdd5a26SSteve French 				delete_mid(midQ);
5111cdd5a26SSteve French 				return rc;
5121cdd5a26SSteve French 			}
5131cdd5a26SSteve French 		} else {
5141cdd5a26SSteve French 			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
5151cdd5a26SSteve French 			   to cause the blocking lock to return. */
5161cdd5a26SSteve French 
5171cdd5a26SSteve French 			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
5181cdd5a26SSteve French 
5191cdd5a26SSteve French 			/* If we get -ENOLCK back the lock may have
5201cdd5a26SSteve French 			   already been removed. Don't exit in this case. */
5211cdd5a26SSteve French 			if (rc && rc != -ENOLCK) {
5221cdd5a26SSteve French 				delete_mid(midQ);
5231cdd5a26SSteve French 				return rc;
5241cdd5a26SSteve French 			}
5251cdd5a26SSteve French 		}
5261cdd5a26SSteve French 
5271cdd5a26SSteve French 		rc = wait_for_response(server, midQ);
5281cdd5a26SSteve French 		if (rc) {
5291cdd5a26SSteve French 			send_cancel(server, &rqst, midQ);
530*e3835731SWang Zhaolong 			spin_lock(&midQ->mid_lock);
531*e3835731SWang Zhaolong 			if (midQ->callback) {
5321cdd5a26SSteve French 				/* no longer considered to be "in-flight" */
5331cdd5a26SSteve French 				midQ->callback = release_mid;
534*e3835731SWang Zhaolong 				spin_unlock(&midQ->mid_lock);
5351cdd5a26SSteve French 				return rc;
5361cdd5a26SSteve French 			}
537*e3835731SWang Zhaolong 			spin_unlock(&midQ->mid_lock);
5381cdd5a26SSteve French 		}
5391cdd5a26SSteve French 
5401cdd5a26SSteve French 		/* We got the response - restart system call. */
5411cdd5a26SSteve French 		rstart = 1;
5421cdd5a26SSteve French 		spin_lock(&server->srv_lock);
5431cdd5a26SSteve French 	}
5441cdd5a26SSteve French 	spin_unlock(&server->srv_lock);
5451cdd5a26SSteve French 
5461cdd5a26SSteve French 	rc = cifs_sync_mid_result(midQ, server);
5471cdd5a26SSteve French 	if (rc != 0)
5481cdd5a26SSteve French 		return rc;
5491cdd5a26SSteve French 
5501cdd5a26SSteve French 	/* rcvd frame is ok */
5511cdd5a26SSteve French 	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
5521cdd5a26SSteve French 		rc = -EIO;
5531cdd5a26SSteve French 		cifs_tcon_dbg(VFS, "Bad MID state?\n");
5541cdd5a26SSteve French 		goto out;
5551cdd5a26SSteve French 	}
5561cdd5a26SSteve French 
5571cdd5a26SSteve French 	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
5581cdd5a26SSteve French 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
5591cdd5a26SSteve French 	rc = cifs_check_receive(midQ, server, 0);
5601cdd5a26SSteve French out:
5611cdd5a26SSteve French 	delete_mid(midQ);
5621cdd5a26SSteve French 	if (rstart && rc == -EACCES)
5631cdd5a26SSteve French 		return -ERESTARTSYS;
5641cdd5a26SSteve French 	return rc;
5651cdd5a26SSteve French }
566