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