File Index
Files and directories
Sign in
FILE

cifstransport.c

File preview with syntax highlighting.

linux-6.19.14/fs/smb/client/cifstransport.c C
  1// SPDX-License-Identifier: LGPL-2.1
  2/*
  3 *
  4 *   Copyright (C) International Business Machines  Corp., 2002,2008
  5 *   Author(s): Steve French (sfrench@us.ibm.com)
  6 *   Jeremy Allison (jra@samba.org) 2006.
  7 *
  8 */
  9
 10#include <linux/fs.h>
 11#include <linux/list.h>
 12#include <linux/gfp.h>
 13#include <linux/wait.h>
 14#include <linux/net.h>
 15#include <linux/delay.h>
 16#include <linux/freezer.h>
 17#include <linux/tcp.h>
 18#include <linux/bvec.h>
 19#include <linux/highmem.h>
 20#include <linux/uaccess.h>
 21#include <linux/processor.h>
 22#include <linux/mempool.h>
 23#include <linux/sched/signal.h>
 24#include <linux/task_io_accounting_ops.h>
 25#include "cifspdu.h"
 26#include "cifsglob.h"
 27#include "cifsproto.h"
 28#include "cifs_debug.h"
 29#include "smb2proto.h"
 30#include "smbdirect.h"
 31#include "compress.h"
 32
 33/* Max number of iovectors we can use off the stack when sending requests. */
 34#define CIFS_MAX_IOV_SIZE 8
 35
 36static struct mid_q_entry *
 37alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 38{
 39	struct mid_q_entry *temp;
 40
 41	if (server == NULL) {
 42		cifs_dbg(VFS, "%s: null TCP session\n", __func__);
 43		return NULL;
 44	}
 45
 46	temp = mempool_alloc(&cifs_mid_pool, GFP_NOFS);
 47	memset(temp, 0, sizeof(struct mid_q_entry));
 48	refcount_set(&temp->refcount, 1);
 49	spin_lock_init(&temp->mid_lock);
 50	temp->mid = get_mid(smb_buffer);
 51	temp->pid = current->pid;
 52	temp->command = cpu_to_le16(smb_buffer->Command);
 53	cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
 54	/* easier to use jiffies */
 55	/* when mid allocated can be before when sent */
 56	temp->when_alloc = jiffies;
 57
 58	/*
 59	 * The default is for the mid to be synchronous, so the
 60	 * default callback just wakes up the current task.
 61	 */
 62	get_task_struct(current);
 63	temp->creator = current;
 64	temp->callback = cifs_wake_up_task;
 65	temp->callback_data = current;
 66
 67	atomic_inc(&mid_count);
 68	temp->mid_state = MID_REQUEST_ALLOCATED;
 69	return temp;
 70}
 71
 72static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
 73			struct mid_q_entry **ppmidQ)
 74{
 75	spin_lock(&ses->ses_lock);
 76	if (ses->ses_status == SES_NEW) {
 77		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
 78			(in_buf->Command != SMB_COM_NEGOTIATE)) {
 79			spin_unlock(&ses->ses_lock);
 80			return -EAGAIN;
 81		}
 82		/* else ok - we are setting up session */
 83	}
 84
 85	if (ses->ses_status == SES_EXITING) {
 86		/* check if SMB session is bad because we are setting it up */
 87		if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
 88			spin_unlock(&ses->ses_lock);
 89			return -EAGAIN;
 90		}
 91		/* else ok - we are shutting down session */
 92	}
 93	spin_unlock(&ses->ses_lock);
 94
 95	*ppmidQ = alloc_mid(in_buf, ses->server);
 96	if (*ppmidQ == NULL)
 97		return -ENOMEM;
 98	spin_lock(&ses->server->mid_queue_lock);
 99	list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
100	spin_unlock(&ses->server->mid_queue_lock);
101	return 0;
102}
103
104struct mid_q_entry *
105cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
106{
107	int rc;
108	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
109	struct mid_q_entry *mid;
110
111	/* enable signing if server requires it */
112	if (server->sign)
113		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
114
115	mid = alloc_mid(hdr, server);
116	if (mid == NULL)
117		return ERR_PTR(-ENOMEM);
118
119	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
120	if (rc) {
121		release_mid(server, mid);
122		return ERR_PTR(rc);
123	}
124
125	return mid;
126}
127
128/*
129 *
130 * Send an SMB Request.  No response info (other than return code)
131 * needs to be parsed.
132 *
133 * flags indicate the type of request buffer and how long to wait
134 * and whether to log NT STATUS code (error) before mapping it to POSIX error
135 *
136 */
137int
138SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
139		 char *in_buf, unsigned int in_len, int flags)
140{
141	int rc;
142	struct kvec iov[1];
143	struct kvec rsp_iov;
144	int resp_buf_type;
145
146	iov[0].iov_base = in_buf;
147	iov[0].iov_len = in_len;
148	flags |= CIFS_NO_RSP_BUF;
149	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
150	cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
151
152	return rc;
153}
154
155int
156cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
157		   bool log_error)
158{
159	unsigned int len = mid->response_pdu_len;
160
161	dump_smb(mid->resp_buf, min_t(u32, 92, len));
162
163	/* convert the length into a more usable form */
164	if (server->sign) {
165		struct kvec iov[1];
166		int rc = 0;
167		struct smb_rqst rqst = { .rq_iov = iov,
168					 .rq_nvec = ARRAY_SIZE(iov) };
169
170		iov[0].iov_base = mid->resp_buf;
171		iov[0].iov_len = len;
172		/* FIXME: add code to kill session */
173		rc = cifs_verify_signature(&rqst, server,
174					   mid->sequence_number);
175		if (rc)
176			cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
177				 rc);
178	}
179
180	/* BB special case reconnect tid and uid here? */
181	return map_and_check_smb_error(server, mid, log_error);
182}
183
184struct mid_q_entry *
185cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
186		   struct smb_rqst *rqst)
187{
188	int rc;
189	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
190	struct mid_q_entry *mid;
191
192	rc = allocate_mid(ses, hdr, &mid);
193	if (rc)
194		return ERR_PTR(rc);
195	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
196	if (rc) {
197		delete_mid(server, mid);
198		return ERR_PTR(rc);
199	}
200	return mid;
201}
202
203int
204SendReceive2(const unsigned int xid, struct cifs_ses *ses,
205	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
206	     const int flags, struct kvec *resp_iov)
207{
208	struct smb_rqst rqst = {
209		.rq_iov = iov,
210		.rq_nvec = n_vec,
211	};
212
213	return cifs_send_recv(xid, ses, ses->server,
214			      &rqst, resp_buf_type, flags, resp_iov);
215}
216
217int
218SendReceive(const unsigned int xid, struct cifs_ses *ses,
219	    struct smb_hdr *in_buf, unsigned int in_len,
220	    struct smb_hdr *out_buf, int *pbytes_returned, const int flags)
221{
222	struct TCP_Server_Info *server;
223	struct kvec resp_iov = {};
224	struct kvec iov = { .iov_base = in_buf, .iov_len = in_len };
225	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
226	int resp_buf_type;
227	int rc = 0;
228
229	if (WARN_ON_ONCE(in_len > 0xffffff))
230		return smb_EIO1(smb_eio_trace_tx_too_long, in_len);
231	if (ses == NULL) {
232		cifs_dbg(VFS, "Null smb session\n");
233		return smb_EIO(smb_eio_trace_null_pointers);
234	}
235	server = ses->server;
236	if (server == NULL) {
237		cifs_dbg(VFS, "Null tcp session\n");
238		return smb_EIO(smb_eio_trace_null_pointers);
239	}
240
241	/* Ensure that we do not send more than 50 overlapping requests
242	   to the same server. We may make this configurable later or
243	   use ses->maxReq */
244
245	if (in_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
246		cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
247				in_len);
248		return smb_EIO1(smb_eio_trace_tx_too_long, in_len);
249	}
250
251	rc = cifs_send_recv(xid, ses, ses->server,
252			    &rqst, &resp_buf_type, flags, &resp_iov);
253	if (rc < 0)
254		goto out;
255
256	if (out_buf) {
257		*pbytes_returned = resp_iov.iov_len;
258		if (resp_iov.iov_len)
259			memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
260	}
261
262out:
263	free_rsp_buf(resp_buf_type, resp_iov.iov_base);
264	return rc;
265}
~/ Read-only file preview.