transport.c 28.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/transport.c
 *
S
Steve French 已提交
4
 *   Copyright (C) International Business Machines  Corp., 2002,2008
L
Linus Torvalds 已提交
5
 *   Author(s): Steve French (sfrench@us.ibm.com)
6
 *   Jeremy Allison (jra@samba.org) 2006.
S
Steve French 已提交
7
 *
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16 17 18 19
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
S
Steve French 已提交
20
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
L
Linus Torvalds 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34
 */

#include <linux/fs.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/net.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <linux/mempool.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
35

L
Linus Torvalds 已提交
36
extern mempool_t *cifs_mid_poolp;
37
extern struct kmem_cache *cifs_oplock_cachep;
L
Linus Torvalds 已提交
38 39

static struct mid_q_entry *
J
[CIFS]  
Jeremy Allison 已提交
40
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
L
Linus Torvalds 已提交
41 42 43 44
{
	struct mid_q_entry *temp;

	if (ses == NULL) {
45
		cERROR(1, ("Null session passed in to AllocMidQEntry"));
L
Linus Torvalds 已提交
46 47 48 49 50 51
		return NULL;
	}
	if (ses->server == NULL) {
		cERROR(1, ("Null TCP session in AllocMidQEntry"));
		return NULL;
	}
52

53
	temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
54
						    GFP_KERNEL | GFP_NOFS);
L
Linus Torvalds 已提交
55 56 57
	if (temp == NULL)
		return temp;
	else {
58
		memset(temp, 0, sizeof(struct mid_q_entry));
L
Linus Torvalds 已提交
59 60 61 62
		temp->mid = smb_buffer->Mid;	/* always LE */
		temp->pid = current->pid;
		temp->command = smb_buffer->Command;
		cFYI(1, ("For smb_command %d", temp->command));
S
Steve French 已提交
63 64 65
	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
		/* when mid allocated can be before when sent */
		temp->when_alloc = jiffies;
L
Linus Torvalds 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
		temp->ses = ses;
		temp->tsk = current;
	}

	spin_lock(&GlobalMid_Lock);
	list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
	atomic_inc(&midCount);
	temp->midState = MID_REQUEST_ALLOCATED;
	spin_unlock(&GlobalMid_Lock);
	return temp;
}

static void
DeleteMidQEntry(struct mid_q_entry *midEntry)
{
S
Steve French 已提交
81 82 83
#ifdef CONFIG_CIFS_STATS2
	unsigned long now;
#endif
L
Linus Torvalds 已提交
84 85 86 87 88
	spin_lock(&GlobalMid_Lock);
	midEntry->midState = MID_FREE;
	list_del(&midEntry->qhead);
	atomic_dec(&midCount);
	spin_unlock(&GlobalMid_Lock);
S
Steve French 已提交
89
	if (midEntry->largeBuf)
90 91 92
		cifs_buf_release(midEntry->resp_buf);
	else
		cifs_small_buf_release(midEntry->resp_buf);
S
Steve French 已提交
93 94 95 96
#ifdef CONFIG_CIFS_STATS2
	now = jiffies;
	/* commands taking longer than one second are indications that
	   something is wrong, unless it is quite a slow link or server */
S
Steve French 已提交
97 98
	if ((now - midEntry->when_alloc) > HZ) {
		if ((cifsFYI & CIFS_TIMER) &&
S
Steve French 已提交
99 100 101 102 103 104 105 106 107 108
		   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
			       midEntry->command, midEntry->mid);
			printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
			       now - midEntry->when_alloc,
			       now - midEntry->when_sent,
			       now - midEntry->when_received);
		}
	}
#endif
L
Linus Torvalds 已提交
109 110 111 112
	mempool_free(midEntry, cifs_mid_poolp);
}

struct oplock_q_entry *
S
Steve French 已提交
113
AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
L
Linus Torvalds 已提交
114 115
{
	struct oplock_q_entry *temp;
S
Steve French 已提交
116
	if ((pinode == NULL) || (tcon == NULL)) {
L
Linus Torvalds 已提交
117 118 119 120
		cERROR(1, ("Null parms passed to AllocOplockQEntry"));
		return NULL;
	}
	temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
121
						       GFP_KERNEL);
L
Linus Torvalds 已提交
122 123 124 125 126 127 128 129 130 131 132 133 134 135
	if (temp == NULL)
		return temp;
	else {
		temp->pinode = pinode;
		temp->tcon = tcon;
		temp->netfid = fid;
		spin_lock(&GlobalMid_Lock);
		list_add_tail(&temp->qhead, &GlobalOplock_Q);
		spin_unlock(&GlobalMid_Lock);
	}
	return temp;

}

S
Steve French 已提交
136
void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
L
Linus Torvalds 已提交
137
{
S
Steve French 已提交
138
	spin_lock(&GlobalMid_Lock);
L
Linus Torvalds 已提交
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    /* should we check if list empty first? */
	list_del(&oplockEntry->qhead);
	spin_unlock(&GlobalMid_Lock);
	kmem_cache_free(cifs_oplock_cachep, oplockEntry);
}

int
smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
	 unsigned int smb_buf_length, struct sockaddr *sin)
{
	int rc = 0;
	int i = 0;
	struct msghdr smb_msg;
	struct kvec iov;
	unsigned len = smb_buf_length + 4;

S
Steve French 已提交
155
	if (ssocket == NULL)
L
Linus Torvalds 已提交
156 157 158 159 160
		return -ENOTSOCK; /* BB eventually add reconnect code here */
	iov.iov_base = smb_buffer;
	iov.iov_len = len;

	smb_msg.msg_name = sin;
161
	smb_msg.msg_namelen = sizeof(struct sockaddr);
L
Linus Torvalds 已提交
162 163 164 165 166
	smb_msg.msg_control = NULL;
	smb_msg.msg_controllen = 0;
	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/

	/* smb header is converted in header_assemble. bcc and rest of SMB word
S
Steve French 已提交
167 168
	   area, and byte area if necessary, is converted to littleendian in
	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send
L
Linus Torvalds 已提交
169 170 171
	   Flags2 is converted in SendReceive */

	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
172
	cFYI(1, ("Sending smb of length %d", smb_buf_length));
L
Linus Torvalds 已提交
173 174 175 176 177 178
	dump_smb(smb_buffer, len);

	while (len > 0) {
		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
			i++;
179
		/* smaller timeout here than send2 since smaller size */
S
Steve French 已提交
180 181 182
		/* Although it may not be required, this also is smaller
		   oplock break time */
			if (i > 12) {
L
Linus Torvalds 已提交
183
				cERROR(1,
184
				   ("sends on sock %p stuck for 7 seconds",
L
Linus Torvalds 已提交
185 186 187 188
				    ssocket));
				rc = -EAGAIN;
				break;
			}
189
			msleep(1 << i);
L
Linus Torvalds 已提交
190 191
			continue;
		}
S
Steve French 已提交
192
		if (rc < 0)
L
Linus Torvalds 已提交
193
			break;
194 195
		else
			i = 0; /* reset i after each successful send */
L
Linus Torvalds 已提交
196 197 198 199 200 201
		iov.iov_base += rc;
		iov.iov_len -= rc;
		len -= rc;
	}

	if (rc < 0) {
S
Steve French 已提交
202
		cERROR(1, ("Error %d sending data on socket to server", rc));
L
Linus Torvalds 已提交
203 204 205 206
	} else {
		rc = 0;
	}

J
[CIFS]  
Jeremy Allison 已提交
207 208 209 210
	/* Don't want to modify the buffer as a
	   side effect of this call. */
	smb_buffer->smb_buf_length = smb_buf_length;

L
Linus Torvalds 已提交
211 212 213
	return rc;
}

214
static int
215 216
smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
	  struct sockaddr *sin)
L
Linus Torvalds 已提交
217 218 219 220
{
	int rc = 0;
	int i = 0;
	struct msghdr smb_msg;
221 222 223 224
	struct smb_hdr *smb_buffer = iov[0].iov_base;
	unsigned int len = iov[0].iov_len;
	unsigned int total_len;
	int first_vec = 0;
J
[CIFS]  
Jeremy Allison 已提交
225
	unsigned int smb_buf_length = smb_buffer->smb_buf_length;
226

S
Steve French 已提交
227
	if (ssocket == NULL)
L
Linus Torvalds 已提交
228
		return -ENOTSOCK; /* BB eventually add reconnect code here */
229

L
Linus Torvalds 已提交
230
	smb_msg.msg_name = sin;
231
	smb_msg.msg_namelen = sizeof(struct sockaddr);
L
Linus Torvalds 已提交
232 233 234 235 236
	smb_msg.msg_control = NULL;
	smb_msg.msg_controllen = 0;
	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/

	/* smb header is converted in header_assemble. bcc and rest of SMB word
S
Steve French 已提交
237 238
	   area, and byte area if necessary, is converted to littleendian in
	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send
L
Linus Torvalds 已提交
239 240
	   Flags2 is converted in SendReceive */

241 242 243 244 245

	total_len = 0;
	for (i = 0; i < n_vec; i++)
		total_len += iov[i].iov_len;

L
Linus Torvalds 已提交
246
	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
247
	cFYI(1, ("Sending smb:  total_len %d", total_len));
L
Linus Torvalds 已提交
248 249
	dump_smb(smb_buffer, len);

250 251 252
	while (total_len) {
		rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
				    n_vec - first_vec, total_len);
L
Linus Torvalds 已提交
253 254
		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
			i++;
S
Steve French 已提交
255
			if (i >= 14) {
L
Linus Torvalds 已提交
256
				cERROR(1,
257
				   ("sends on sock %p stuck for 15 seconds",
L
Linus Torvalds 已提交
258 259 260 261
				    ssocket));
				rc = -EAGAIN;
				break;
			}
262
			msleep(1 << i);
L
Linus Torvalds 已提交
263 264
			continue;
		}
S
Steve French 已提交
265
		if (rc < 0)
L
Linus Torvalds 已提交
266
			break;
267 268 269 270 271

		if (rc >= total_len) {
			WARN_ON(rc > total_len);
			break;
		}
S
Steve French 已提交
272
		if (rc == 0) {
273 274
			/* should never happen, letting socket clear before
			   retrying is our only obvious option here */
S
Steve French 已提交
275
			cERROR(1, ("tcp sent no data"));
276 277
			msleep(500);
			continue;
278
		}
279
		total_len -= rc;
280
		/* the line below resets i */
281 282 283 284 285 286 287 288 289 290 291 292
		for (i = first_vec; i < n_vec; i++) {
			if (iov[i].iov_len) {
				if (rc > iov[i].iov_len) {
					rc -= iov[i].iov_len;
					iov[i].iov_len = 0;
				} else {
					iov[i].iov_base += rc;
					iov[i].iov_len -= rc;
					first_vec = i;
					break;
				}
			}
293
		}
294
		i = 0; /* in case we get ENOSPC on the next send */
L
Linus Torvalds 已提交
295 296 297
	}

	if (rc < 0) {
S
Steve French 已提交
298
		cERROR(1, ("Error %d sending data on socket to server", rc));
299
	} else
L
Linus Torvalds 已提交
300 301
		rc = 0;

J
[CIFS]  
Jeremy Allison 已提交
302 303 304 305
	/* Don't want to modify the buffer as a
	   side effect of this call. */
	smb_buffer->smb_buf_length = smb_buf_length;

L
Linus Torvalds 已提交
306 307 308
	return rc;
}

J
[CIFS]  
Jeremy Allison 已提交
309
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
L
Linus Torvalds 已提交
310
{
311
	if (long_op == CIFS_ASYNC_OP) {
L
Linus Torvalds 已提交
312 313 314
		/* oplock breaks must not be held up */
		atomic_inc(&ses->server->inFlight);
	} else {
S
Steve French 已提交
315 316 317
		spin_lock(&GlobalMid_Lock);
		while (1) {
			if (atomic_read(&ses->server->inFlight) >=
318
					cifs_max_pending){
L
Linus Torvalds 已提交
319
				spin_unlock(&GlobalMid_Lock);
320 321 322
#ifdef CONFIG_CIFS_STATS2
				atomic_inc(&ses->server->num_waiters);
#endif
L
Linus Torvalds 已提交
323 324 325
				wait_event(ses->server->request_q,
					atomic_read(&ses->server->inFlight)
					 < cifs_max_pending);
326 327 328
#ifdef CONFIG_CIFS_STATS2
				atomic_dec(&ses->server->num_waiters);
#endif
L
Linus Torvalds 已提交
329 330
				spin_lock(&GlobalMid_Lock);
			} else {
S
Steve French 已提交
331
				if (ses->server->tcpStatus == CifsExiting) {
L
Linus Torvalds 已提交
332 333 334 335
					spin_unlock(&GlobalMid_Lock);
					return -ENOENT;
				}

S
Steve French 已提交
336 337
				/* can not count locking commands against total
				   as they are allowed to block on server */
338

L
Linus Torvalds 已提交
339
				/* update # of requests on the wire to server */
340
				if (long_op != CIFS_BLOCKING_OP)
L
Linus Torvalds 已提交
341 342 343 344 345 346
					atomic_inc(&ses->server->inFlight);
				spin_unlock(&GlobalMid_Lock);
				break;
			}
		}
	}
J
[CIFS]  
Jeremy Allison 已提交
347 348
	return 0;
}
L
Linus Torvalds 已提交
349

J
[CIFS]  
Jeremy Allison 已提交
350 351 352
static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
			struct mid_q_entry **ppmidQ)
{
L
Linus Torvalds 已提交
353
	if (ses->server->tcpStatus == CifsExiting) {
J
[CIFS]  
Jeremy Allison 已提交
354
		return -ENOENT;
L
Linus Torvalds 已提交
355
	} else if (ses->server->tcpStatus == CifsNeedReconnect) {
S
Steve French 已提交
356
		cFYI(1, ("tcp session dead - return to caller to retry"));
J
[CIFS]  
Jeremy Allison 已提交
357
		return -EAGAIN;
L
Linus Torvalds 已提交
358 359
	} else if (ses->status != CifsGood) {
		/* check if SMB session is bad because we are setting it up */
S
Steve French 已提交
360
		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
S
Steve French 已提交
361
			(in_buf->Command != SMB_COM_NEGOTIATE))
J
[CIFS]  
Jeremy Allison 已提交
362
			return -EAGAIN;
S
Steve French 已提交
363
		/* else ok - we are setting up session */
L
Linus Torvalds 已提交
364
	}
J
[CIFS]  
Jeremy Allison 已提交
365
	*ppmidQ = AllocMidQEntry(in_buf, ses);
366
	if (*ppmidQ == NULL)
J
[CIFS]  
Jeremy Allison 已提交
367 368 369 370
		return -ENOMEM;
	return 0;
}

S
Steve French 已提交
371
static int wait_for_response(struct cifsSesInfo *ses,
J
[CIFS]  
Jeremy Allison 已提交
372 373 374 375 376 377 378 379 380
			struct mid_q_entry *midQ,
			unsigned long timeout,
			unsigned long time_to_wait)
{
	unsigned long curr_timeout;

	for (;;) {
		curr_timeout = timeout + jiffies;
		wait_event(ses->server->response_q,
S
Steve French 已提交
381 382
			(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
			time_after(jiffies, curr_timeout) ||
J
[CIFS]  
Jeremy Allison 已提交
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
			((ses->server->tcpStatus != CifsGood) &&
			 (ses->server->tcpStatus != CifsNew)));

		if (time_after(jiffies, curr_timeout) &&
			(midQ->midState == MID_REQUEST_SUBMITTED) &&
			((ses->server->tcpStatus == CifsGood) ||
			 (ses->server->tcpStatus == CifsNew))) {

			unsigned long lrt;

			/* We timed out. Is the server still
			   sending replies ? */
			spin_lock(&GlobalMid_Lock);
			lrt = ses->server->lstrp;
			spin_unlock(&GlobalMid_Lock);

			/* Calculate time_to_wait past last receive time.
S
Steve French 已提交
400
			 Although we prefer not to time out if the
J
[CIFS]  
Jeremy Allison 已提交
401
			 server is still responding - we will time
S
Steve French 已提交
402
			 out if the server takes more than 15 (or 45
J
[CIFS]  
Jeremy Allison 已提交
403
			 or 180) seconds to respond to this request
S
Steve French 已提交
404
			 and has not responded to any request from
J
[CIFS]  
Jeremy Allison 已提交
405 406 407 408
			 other threads on the client within 10 seconds */
			lrt += time_to_wait;
			if (time_after(jiffies, lrt)) {
				/* No replies for time_to_wait. */
S
Steve French 已提交
409
				cERROR(1, ("server not responding"));
J
[CIFS]  
Jeremy Allison 已提交
410 411 412 413 414 415 416 417
				return -1;
			}
		} else {
			return 0;
		}
	}
}

418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439

/*
 *
 * Send an SMB Request.  No response info (other than return code)
 * needs to be parsed.
 *
 * flags indicate the type of request buffer and how long to wait
 * and whether to log NT STATUS code (error) before mapping it to POSIX error
 *
 */
int
SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
		struct smb_hdr *in_buf, int flags)
{
	int rc;
	struct kvec iov[1];
	int resp_buf_type;

	iov[0].iov_base = (char *)in_buf;
	iov[0].iov_len = in_buf->smb_buf_length + 4;
	flags |= CIFS_NO_RESP;
	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
440 441
	cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));

442 443 444
	return rc;
}

J
[CIFS]  
Jeremy Allison 已提交
445
int
S
Steve French 已提交
446 447
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
448
	     const int flags)
J
[CIFS]  
Jeremy Allison 已提交
449 450
{
	int rc = 0;
451
	int long_op;
J
[CIFS]  
Jeremy Allison 已提交
452 453 454 455
	unsigned int receive_len;
	unsigned long timeout;
	struct mid_q_entry *midQ;
	struct smb_hdr *in_buf = iov[0].iov_base;
456

457 458
	long_op = flags & CIFS_TIMEOUT_MASK;

J
[CIFS]  
Jeremy Allison 已提交
459 460 461 462
	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */

	if ((ses == NULL) || (ses->server == NULL)) {
		cifs_small_buf_release(in_buf);
S
Steve French 已提交
463
		cERROR(1, ("Null session"));
J
[CIFS]  
Jeremy Allison 已提交
464 465 466
		return -EIO;
	}

S
Steve French 已提交
467
	if (ses->server->tcpStatus == CifsExiting) {
J
[CIFS]  
Jeremy Allison 已提交
468 469 470 471
		cifs_small_buf_release(in_buf);
		return -ENOENT;
	}

S
Steve French 已提交
472
	/* Ensure that we do not send more than 50 overlapping requests
J
[CIFS]  
Jeremy Allison 已提交
473 474 475 476 477 478 479 480 481
	   to the same server. We may make this configurable later or
	   use ses->maxReq */

	rc = wait_for_free_request(ses, long_op);
	if (rc) {
		cifs_small_buf_release(in_buf);
		return rc;
	}

S
Steve French 已提交
482
	/* make sure that we sign in the same order that we send on this socket
J
[CIFS]  
Jeremy Allison 已提交
483 484 485
	   and avoid races inside tcp sendmsg code that could cause corruption
	   of smb data */

S
Steve French 已提交
486
	down(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
487 488 489

	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
L
Linus Torvalds 已提交
490
		up(&ses->server->tcpSem);
491
		cifs_small_buf_release(in_buf);
J
[CIFS]  
Jeremy Allison 已提交
492
		/* Update # of requests on wire to server */
S
Steve French 已提交
493
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
494 495
		wake_up(&ses->server->request_q);
		return rc;
L
Linus Torvalds 已提交
496
	}
S
Steve French 已提交
497
	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
L
Linus Torvalds 已提交
498 499

	midQ->midState = MID_REQUEST_SUBMITTED;
500 501 502
#ifdef CONFIG_CIFS_STATS2
	atomic_inc(&ses->server->inSend);
#endif
503
	rc = smb_send2(ses->server->ssocket, iov, n_vec,
504
		      (struct sockaddr *) &(ses->server->addr.sockAddr));
505 506
#ifdef CONFIG_CIFS_STATS2
	atomic_dec(&ses->server->inSend);
S
Steve French 已提交
507
	midQ->when_sent = jiffies;
508
#endif
J
[CIFS]  
Jeremy Allison 已提交
509 510 511 512

	up(&ses->server->tcpSem);
	cifs_small_buf_release(in_buf);

S
Steve French 已提交
513
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
514
		goto out;
515

516 517 518
	if (long_op == CIFS_STD_OP)
		timeout = 15 * HZ;
	else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
519
		timeout = 180 * HZ;
520
	else if (long_op == CIFS_LONG_OP)
S
Steve French 已提交
521
		timeout = 45 * HZ; /* should be greater than
522
			servers oplock break timeout (about 43 seconds) */
523 524 525 526 527 528 529 530 531
	else if (long_op == CIFS_ASYNC_OP)
		goto out;
	else if (long_op == CIFS_BLOCKING_OP)
		timeout = 0x7FFFFFFF; /*  large, but not so large as to wrap */
	else {
		cERROR(1, ("unknown timeout flag %d", long_op));
		rc = -EIO;
		goto out;
	}
J
[CIFS]  
Jeremy Allison 已提交
532

S
Steve French 已提交
533
	/* wait for 15 seconds or until woken up due to response arriving or
534 535 536
	   due to last connection to this server being unmounted */
	if (signal_pending(current)) {
		/* if signal pending do not hold up user for full smb timeout
537
		but we still give response a chance to complete */
538
		timeout = 2 * HZ;
S
Steve French 已提交
539
	}
540 541

	/* No user interrupts in wait - wreaks havoc with performance */
J
[CIFS]  
Jeremy Allison 已提交
542
	wait_for_response(ses, midQ, timeout, 10 * HZ);
543 544 545 546

	spin_lock(&GlobalMid_Lock);
	if (midQ->resp_buf) {
		spin_unlock(&GlobalMid_Lock);
547
		receive_len = midQ->resp_buf->smb_buf_length;
548
	} else {
S
Steve French 已提交
549
		cERROR(1, ("No response to cmd %d mid %d",
550
			midQ->command, midQ->mid));
S
Steve French 已提交
551 552
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
553 554 555 556 557 558 559 560
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
561
			if (midQ->midState == MID_RETRY_NEEDED) {
562
				rc = -EAGAIN;
S
Steve French 已提交
563
				cFYI(1, ("marking request for retry"));
564 565 566 567 568 569
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
J
[CIFS]  
Jeremy Allison 已提交
570
		/* Update # of requests on wire to server */
S
Steve French 已提交
571
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
572
		wake_up(&ses->server->request_q);
573 574
		return rc;
	}
575

576 577 578 579 580
	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
			receive_len, xid));
		rc = -EIO;
	} else {		/* rcvd frame is ok */
S
Steve French 已提交
581
		if (midQ->resp_buf &&
582
			(midQ->midState == MID_RESPONSE_RECEIVED)) {
583

584
			iov[0].iov_base = (char *)midQ->resp_buf;
S
Steve French 已提交
585
			if (midQ->largeBuf)
586 587 588 589
				*pRespBufType = CIFS_LARGE_BUFFER;
			else
				*pRespBufType = CIFS_SMALL_BUFFER;
			iov[0].iov_len = receive_len + 4;
590

591
			dump_smb(midQ->resp_buf, 80);
592
			/* convert the length into a more usable form */
S
Steve French 已提交
593
			if ((receive_len > 24) &&
594 595
			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
					SECMODE_SIGN_ENABLED))) {
596
				rc = cifs_verify_signature(midQ->resp_buf,
597
						&ses->server->mac_signing_key,
598
						midQ->sequence_number+1);
S
Steve French 已提交
599 600
				if (rc) {
					cERROR(1, ("Unexpected SMB signature"));
601 602 603 604 605
					/* BB FIXME add code to kill session */
				}
			}

			/* BB special case reconnect tid and uid here? */
606 607
			rc = map_smb_to_linux_error(midQ->resp_buf,
						flags & CIFS_LOG_ERROR);
608 609

			/* convert ByteCount if necessary */
610 611
			if (receive_len >= sizeof(struct smb_hdr) - 4
			    /* do not count RFC1001 header */  +
612
			    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
S
Steve French 已提交
613
				BCC(midQ->resp_buf) =
614
					le16_to_cpu(BCC_LE(midQ->resp_buf));
615 616 617 618
			if ((flags & CIFS_NO_RESP) == 0)
				midQ->resp_buf = NULL;  /* mark it so buf will
							   not be freed by
							   DeleteMidQEntry */
619 620
		} else {
			rc = -EIO;
S
Steve French 已提交
621
			cFYI(1, ("Bad MID state?"));
622 623
		}
	}
L
Linus Torvalds 已提交
624

J
[CIFS]  
Jeremy Allison 已提交
625 626
out:
	DeleteMidQEntry(midQ);
S
Steve French 已提交
627
	atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
628
	wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
629

630 631
	return rc;
}
L
Linus Torvalds 已提交
632 633 634 635 636 637 638 639 640 641 642 643

int
SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
	    int *pbytes_returned, const int long_op)
{
	int rc = 0;
	unsigned int receive_len;
	unsigned long timeout;
	struct mid_q_entry *midQ;

	if (ses == NULL) {
S
Steve French 已提交
644
		cERROR(1, ("Null smb session"));
L
Linus Torvalds 已提交
645 646
		return -EIO;
	}
S
Steve French 已提交
647 648
	if (ses->server == NULL) {
		cERROR(1, ("Null tcp session"));
L
Linus Torvalds 已提交
649 650 651
		return -EIO;
	}

S
Steve French 已提交
652
	if (ses->server->tcpStatus == CifsExiting)
653 654
		return -ENOENT;

S
Steve French 已提交
655
	/* Ensure that we do not send more than 50 overlapping requests
L
Linus Torvalds 已提交
656 657 658
	   to the same server. We may make this configurable later or
	   use ses->maxReq */

J
[CIFS]  
Jeremy Allison 已提交
659 660 661 662
	rc = wait_for_free_request(ses, long_op);
	if (rc)
		return rc;

S
Steve French 已提交
663
	/* make sure that we sign in the same order that we send on this socket
L
Linus Torvalds 已提交
664 665 666
	   and avoid races inside tcp sendmsg code that could cause corruption
	   of smb data */

S
Steve French 已提交
667
	down(&ses->server->tcpSem);
L
Linus Torvalds 已提交
668

J
[CIFS]  
Jeremy Allison 已提交
669 670
	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
L
Linus Torvalds 已提交
671
		up(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
672
		/* Update # of requests on wire to server */
S
Steve French 已提交
673
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
674 675
		wake_up(&ses->server->request_q);
		return rc;
L
Linus Torvalds 已提交
676 677 678
	}

	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
679
		cERROR(1, ("Illegal length, greater than maximum frame, %d",
L
Linus Torvalds 已提交
680 681
			in_buf->smb_buf_length));
		DeleteMidQEntry(midQ);
J
[CIFS]  
Jeremy Allison 已提交
682 683
		up(&ses->server->tcpSem);
		/* Update # of requests on wire to server */
S
Steve French 已提交
684
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
685
		wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
686 687 688
		return -EIO;
	}

689
	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
L
Linus Torvalds 已提交
690 691

	midQ->midState = MID_REQUEST_SUBMITTED;
692 693 694
#ifdef CONFIG_CIFS_STATS2
	atomic_inc(&ses->server->inSend);
#endif
L
Linus Torvalds 已提交
695 696
	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
		      (struct sockaddr *) &(ses->server->addr.sockAddr));
697 698
#ifdef CONFIG_CIFS_STATS2
	atomic_dec(&ses->server->inSend);
S
Steve French 已提交
699
	midQ->when_sent = jiffies;
700
#endif
J
[CIFS]  
Jeremy Allison 已提交
701 702
	up(&ses->server->tcpSem);

S
Steve French 已提交
703
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
704 705
		goto out;

706 707 708 709 710
	if (long_op == CIFS_STD_OP)
		timeout = 15 * HZ;
	/* wait for 15 seconds or until woken up due to response arriving or
	   due to last connection to this server being unmounted */
	else if (long_op == CIFS_ASYNC_OP)
J
[CIFS]  
Jeremy Allison 已提交
711
		goto out;
712
	else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
713
		timeout = 180 * HZ;
714
	else if (long_op == CIFS_LONG_OP)
S
Steve French 已提交
715
		timeout = 45 * HZ; /* should be greater than
L
Linus Torvalds 已提交
716
			servers oplock break timeout (about 43 seconds) */
717 718 719 720 721 722 723 724
	else if (long_op == CIFS_BLOCKING_OP)
		timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
	else {
		cERROR(1, ("unknown timeout flag %d", long_op));
		rc = -EIO;
		goto out;
	}

L
Linus Torvalds 已提交
725 726
	if (signal_pending(current)) {
		/* if signal pending do not hold up user for full smb timeout
727
		but we still give response a chance to complete */
L
Linus Torvalds 已提交
728
		timeout = 2 * HZ;
S
Steve French 已提交
729
	}
L
Linus Torvalds 已提交
730 731

	/* No user interrupts in wait - wreaks havoc with performance */
J
[CIFS]  
Jeremy Allison 已提交
732
	wait_for_response(ses, midQ, timeout, 10 * HZ);
L
Linus Torvalds 已提交
733 734 735 736

	spin_lock(&GlobalMid_Lock);
	if (midQ->resp_buf) {
		spin_unlock(&GlobalMid_Lock);
737
		receive_len = midQ->resp_buf->smb_buf_length;
L
Linus Torvalds 已提交
738
	} else {
S
Steve French 已提交
739
		cERROR(1, ("No response for cmd %d mid %d",
740
			  midQ->command, midQ->mid));
S
Steve French 已提交
741 742
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
L
Linus Torvalds 已提交
743 744 745 746 747 748 749 750
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
751
			if (midQ->midState == MID_RETRY_NEEDED) {
L
Linus Torvalds 已提交
752
				rc = -EAGAIN;
S
Steve French 已提交
753
				cFYI(1, ("marking request for retry"));
L
Linus Torvalds 已提交
754 755 756 757 758 759
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
J
[CIFS]  
Jeremy Allison 已提交
760
		/* Update # of requests on wire to server */
S
Steve French 已提交
761
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
762
		wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
763 764
		return rc;
	}
765

L
Linus Torvalds 已提交
766
	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
767
		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
L
Linus Torvalds 已提交
768 769 770 771 772 773 774 775 776 777 778 779 780
			receive_len, xid));
		rc = -EIO;
	} else {		/* rcvd frame is ok */

		if (midQ->resp_buf && out_buf
		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
			out_buf->smb_buf_length = receive_len;
			memcpy((char *)out_buf + 4,
			       (char *)midQ->resp_buf + 4,
			       receive_len);

			dump_smb(out_buf, 92);
			/* convert the length into a more usable form */
S
Steve French 已提交
781
			if ((receive_len > 24) &&
782 783 784
			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
					SECMODE_SIGN_ENABLED))) {
				rc = cifs_verify_signature(out_buf,
785
						&ses->server->mac_signing_key,
786
						midQ->sequence_number+1);
S
Steve French 已提交
787 788
				if (rc) {
					cERROR(1, ("Unexpected SMB signature"));
789
					/* BB FIXME add code to kill session */
790
				}
L
Linus Torvalds 已提交
791 792 793 794
			}

			*pbytes_returned = out_buf->smb_buf_length;

795
			/* BB special case reconnect tid and uid here? */
796
			rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
L
Linus Torvalds 已提交
797 798

			/* convert ByteCount if necessary */
799 800
			if (receive_len >= sizeof(struct smb_hdr) - 4
			    /* do not count RFC1001 header */  +
L
Linus Torvalds 已提交
801
			    (2 * out_buf->WordCount) + 2 /* bcc */ )
802
				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
L
Linus Torvalds 已提交
803 804
		} else {
			rc = -EIO;
S
Steve French 已提交
805
			cERROR(1, ("Bad MID state?"));
L
Linus Torvalds 已提交
806 807
		}
	}
J
[CIFS]  
Jeremy Allison 已提交
808 809

out:
L
Linus Torvalds 已提交
810
	DeleteMidQEntry(midQ);
S
Steve French 已提交
811
	atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
812
	wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
813

J
[CIFS]  
Jeremy Allison 已提交
814 815
	return rc;
}
L
Linus Torvalds 已提交
816

J
[CIFS]  
Jeremy Allison 已提交
817 818 819 820 821 822 823 824 825 826 827 828
/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */

static int
send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
		struct mid_q_entry *midQ)
{
	int rc = 0;
	struct cifsSesInfo *ses = tcon->ses;
	__u16 mid = in_buf->Mid;

	header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
	in_buf->Mid = mid;
S
Steve French 已提交
829
	down(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
830 831 832 833 834 835 836 837
	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
	if (rc) {
		up(&ses->server->tcpSem);
		return rc;
	}
	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
	      (struct sockaddr *) &(ses->server->addr.sockAddr));
	up(&ses->server->tcpSem);
L
Linus Torvalds 已提交
838
	return rc;
J
[CIFS]  
Jeremy Allison 已提交
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
}

/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
   blocking lock to return. */

static int
send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
			struct smb_hdr *in_buf,
			struct smb_hdr *out_buf)
{
	int bytes_returned;
	struct cifsSesInfo *ses = tcon->ses;
	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;

	/* We just modify the current in_buf to change
	   the type of lock from LOCKING_ANDX_SHARED_LOCK
	   or LOCKING_ANDX_EXCLUSIVE_LOCK to
	   LOCKING_ANDX_CANCEL_LOCK. */

	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
	pSMB->Timeout = 0;
	pSMB->hdr.Mid = GetNextMid(ses->server);

	return SendReceive(xid, ses, in_buf, out_buf,
863
			&bytes_returned, CIFS_STD_OP);
J
[CIFS]  
Jeremy Allison 已提交
864 865 866 867 868 869 870 871 872 873 874 875 876 877
}

int
SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
	    int *pbytes_returned)
{
	int rc = 0;
	int rstart = 0;
	unsigned int receive_len;
	struct mid_q_entry *midQ;
	struct cifsSesInfo *ses;

	if (tcon == NULL || tcon->ses == NULL) {
S
Steve French 已提交
878
		cERROR(1, ("Null smb session"));
J
[CIFS]  
Jeremy Allison 已提交
879 880 881 882
		return -EIO;
	}
	ses = tcon->ses;

S
Steve French 已提交
883 884
	if (ses->server == NULL) {
		cERROR(1, ("Null tcp session"));
J
[CIFS]  
Jeremy Allison 已提交
885 886 887
		return -EIO;
	}

S
Steve French 已提交
888
	if (ses->server->tcpStatus == CifsExiting)
J
[CIFS]  
Jeremy Allison 已提交
889 890
		return -ENOENT;

S
Steve French 已提交
891
	/* Ensure that we do not send more than 50 overlapping requests
J
[CIFS]  
Jeremy Allison 已提交
892 893 894
	   to the same server. We may make this configurable later or
	   use ses->maxReq */

895
	rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
J
[CIFS]  
Jeremy Allison 已提交
896 897 898
	if (rc)
		return rc;

S
Steve French 已提交
899
	/* make sure that we sign in the same order that we send on this socket
J
[CIFS]  
Jeremy Allison 已提交
900 901 902
	   and avoid races inside tcp sendmsg code that could cause corruption
	   of smb data */

S
Steve French 已提交
903
	down(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919

	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
		up(&ses->server->tcpSem);
		return rc;
	}

	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
		up(&ses->server->tcpSem);
		cERROR(1, ("Illegal length, greater than maximum frame, %d",
			in_buf->smb_buf_length));
		DeleteMidQEntry(midQ);
		return -EIO;
	}

	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
L
Linus Torvalds 已提交
920

J
[CIFS]  
Jeremy Allison 已提交
921 922 923 924 925 926 927 928 929 930
	midQ->midState = MID_REQUEST_SUBMITTED;
#ifdef CONFIG_CIFS_STATS2
	atomic_inc(&ses->server->inSend);
#endif
	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
		      (struct sockaddr *) &(ses->server->addr.sockAddr));
#ifdef CONFIG_CIFS_STATS2
	atomic_dec(&ses->server->inSend);
	midQ->when_sent = jiffies;
#endif
L
Linus Torvalds 已提交
931
	up(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
932

S
Steve French 已提交
933
	if (rc < 0) {
J
[CIFS]  
Jeremy Allison 已提交
934 935 936 937 938 939
		DeleteMidQEntry(midQ);
		return rc;
	}

	/* Wait for a reply - allow signals to interrupt. */
	rc = wait_event_interruptible(ses->server->response_q,
S
Steve French 已提交
940
		(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
J
[CIFS]  
Jeremy Allison 已提交
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
		((ses->server->tcpStatus != CifsGood) &&
		 (ses->server->tcpStatus != CifsNew)));

	/* Were we interrupted by a signal ? */
	if ((rc == -ERESTARTSYS) &&
		(midQ->midState == MID_REQUEST_SUBMITTED) &&
		((ses->server->tcpStatus == CifsGood) ||
		 (ses->server->tcpStatus == CifsNew))) {

		if (in_buf->Command == SMB_COM_TRANSACTION2) {
			/* POSIX lock. We send a NT_CANCEL SMB to cause the
			   blocking lock to return. */

			rc = send_nt_cancel(tcon, in_buf, midQ);
			if (rc) {
				DeleteMidQEntry(midQ);
				return rc;
			}
		} else {
			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
			   to cause the blocking lock to return. */

			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);

			/* If we get -ENOLCK back the lock may have
			   already been removed. Don't exit in this case. */
			if (rc && rc != -ENOLCK) {
				DeleteMidQEntry(midQ);
				return rc;
			}
		}

		/* Wait 5 seconds for the response. */
S
Steve French 已提交
974
		if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
J
[CIFS]  
Jeremy Allison 已提交
975 976 977 978 979 980 981 982 983 984
			/* We got the response - restart system call. */
			rstart = 1;
		}
	}

	spin_lock(&GlobalMid_Lock);
	if (midQ->resp_buf) {
		spin_unlock(&GlobalMid_Lock);
		receive_len = midQ->resp_buf->smb_buf_length;
	} else {
S
Steve French 已提交
985
		cERROR(1, ("No response for cmd %d mid %d",
J
[CIFS]  
Jeremy Allison 已提交
986
			  midQ->command, midQ->mid));
S
Steve French 已提交
987 988
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
J
[CIFS]  
Jeremy Allison 已提交
989 990 991 992 993 994 995 996
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
997
			if (midQ->midState == MID_RETRY_NEEDED) {
J
[CIFS]  
Jeremy Allison 已提交
998
				rc = -EAGAIN;
S
Steve French 已提交
999
				cFYI(1, ("marking request for retry"));
J
[CIFS]  
Jeremy Allison 已提交
1000 1001 1002 1003 1004 1005 1006
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
		return rc;
L
Linus Torvalds 已提交
1007
	}
1008

J
[CIFS]  
Jeremy Allison 已提交
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
			receive_len, xid));
		rc = -EIO;
	} else {		/* rcvd frame is ok */

		if (midQ->resp_buf && out_buf
		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
			out_buf->smb_buf_length = receive_len;
			memcpy((char *)out_buf + 4,
			       (char *)midQ->resp_buf + 4,
			       receive_len);

			dump_smb(out_buf, 92);
			/* convert the length into a more usable form */
S
Steve French 已提交
1024
			if ((receive_len > 24) &&
J
[CIFS]  
Jeremy Allison 已提交
1025 1026 1027
			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
					SECMODE_SIGN_ENABLED))) {
				rc = cifs_verify_signature(out_buf,
1028
						&ses->server->mac_signing_key,
J
[CIFS]  
Jeremy Allison 已提交
1029
						midQ->sequence_number+1);
S
Steve French 已提交
1030 1031
				if (rc) {
					cERROR(1, ("Unexpected SMB signature"));
J
[CIFS]  
Jeremy Allison 已提交
1032 1033 1034 1035 1036 1037 1038
					/* BB FIXME add code to kill session */
				}
			}

			*pbytes_returned = out_buf->smb_buf_length;

			/* BB special case reconnect tid and uid here? */
1039
			rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
L
Linus Torvalds 已提交
1040

J
[CIFS]  
Jeremy Allison 已提交
1041
			/* convert ByteCount if necessary */
1042 1043
			if (receive_len >= sizeof(struct smb_hdr) - 4
			    /* do not count RFC1001 header */  +
J
[CIFS]  
Jeremy Allison 已提交
1044 1045 1046 1047
			    (2 * out_buf->WordCount) + 2 /* bcc */ )
				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
		} else {
			rc = -EIO;
S
Steve French 已提交
1048
			cERROR(1, ("Bad MID state?"));
J
[CIFS]  
Jeremy Allison 已提交
1049 1050 1051 1052 1053
		}
	}
	DeleteMidQEntry(midQ);
	if (rstart && rc == -EACCES)
		return -ERESTARTSYS;
L
Linus Torvalds 已提交
1054 1055
	return rc;
}