transport.c 28.4 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
    /* should we check if list empty first? */
	list_del(&oplockEntry->qhead);
	spin_unlock(&GlobalMid_Lock);
	kmem_cache_free(cifs_oplock_cachep, oplockEntry);
}

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
{
	struct oplock_q_entry *temp;

	if (tcon == NULL)
		return;

	spin_lock(&GlobalMid_Lock);
	list_for_each_entry(temp, &GlobalOplock_Q, qhead) {
		if ((temp->tcon) && (temp->tcon == tcon)) {
			list_del(&temp->qhead);
			kmem_cache_free(cifs_oplock_cachep, temp);
		}
	}
	spin_unlock(&GlobalMid_Lock);
}

L
Linus Torvalds 已提交
163 164 165 166 167 168 169 170 171 172
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 已提交
173
	if (ssocket == NULL)
L
Linus Torvalds 已提交
174 175 176 177 178
		return -ENOTSOCK; /* BB eventually add reconnect code here */
	iov.iov_base = smb_buffer;
	iov.iov_len = len;

	smb_msg.msg_name = sin;
179
	smb_msg.msg_namelen = sizeof(struct sockaddr);
L
Linus Torvalds 已提交
180 181 182 183 184
	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 已提交
185 186
	   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 已提交
187 188 189
	   Flags2 is converted in SendReceive */

	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
190
	cFYI(1, ("Sending smb of length %d", smb_buf_length));
L
Linus Torvalds 已提交
191 192 193 194 195 196
	dump_smb(smb_buffer, len);

	while (len > 0) {
		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
			i++;
197
		/* smaller timeout here than send2 since smaller size */
S
Steve French 已提交
198 199 200
		/* Although it may not be required, this also is smaller
		   oplock break time */
			if (i > 12) {
L
Linus Torvalds 已提交
201
				cERROR(1,
202
				   ("sends on sock %p stuck for 7 seconds",
L
Linus Torvalds 已提交
203 204 205 206
				    ssocket));
				rc = -EAGAIN;
				break;
			}
207
			msleep(1 << i);
L
Linus Torvalds 已提交
208 209
			continue;
		}
S
Steve French 已提交
210
		if (rc < 0)
L
Linus Torvalds 已提交
211
			break;
212 213
		else
			i = 0; /* reset i after each successful send */
L
Linus Torvalds 已提交
214 215 216 217 218 219
		iov.iov_base += rc;
		iov.iov_len -= rc;
		len -= rc;
	}

	if (rc < 0) {
S
Steve French 已提交
220
		cERROR(1, ("Error %d sending data on socket to server", rc));
L
Linus Torvalds 已提交
221 222 223 224
	} else {
		rc = 0;
	}

J
[CIFS]  
Jeremy Allison 已提交
225 226 227 228
	/* 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 已提交
229 230 231
	return rc;
}

232
static int
233 234
smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
	  struct sockaddr *sin)
L
Linus Torvalds 已提交
235 236 237 238
{
	int rc = 0;
	int i = 0;
	struct msghdr smb_msg;
239 240 241 242
	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 已提交
243
	unsigned int smb_buf_length = smb_buffer->smb_buf_length;
244

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

L
Linus Torvalds 已提交
248
	smb_msg.msg_name = sin;
249
	smb_msg.msg_namelen = sizeof(struct sockaddr);
L
Linus Torvalds 已提交
250 251 252 253 254
	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 已提交
255 256
	   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 已提交
257 258
	   Flags2 is converted in SendReceive */

259 260 261 262 263

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

L
Linus Torvalds 已提交
264
	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
265
	cFYI(1, ("Sending smb:  total_len %d", total_len));
L
Linus Torvalds 已提交
266 267
	dump_smb(smb_buffer, len);

268
	i = 0;
269 270 271
	while (total_len) {
		rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
				    n_vec - first_vec, total_len);
L
Linus Torvalds 已提交
272 273
		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
			i++;
S
Steve French 已提交
274
			if (i >= 14) {
L
Linus Torvalds 已提交
275
				cERROR(1,
276
				   ("sends on sock %p stuck for 15 seconds",
L
Linus Torvalds 已提交
277 278 279 280
				    ssocket));
				rc = -EAGAIN;
				break;
			}
281
			msleep(1 << i);
L
Linus Torvalds 已提交
282 283
			continue;
		}
S
Steve French 已提交
284
		if (rc < 0)
L
Linus Torvalds 已提交
285
			break;
286 287 288 289 290

		if (rc >= total_len) {
			WARN_ON(rc > total_len);
			break;
		}
S
Steve French 已提交
291
		if (rc == 0) {
292 293
			/* should never happen, letting socket clear before
			   retrying is our only obvious option here */
S
Steve French 已提交
294
			cERROR(1, ("tcp sent no data"));
295 296
			msleep(500);
			continue;
297
		}
298
		total_len -= rc;
299
		/* the line below resets i */
300 301 302 303 304 305 306 307 308 309 310 311
		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;
				}
			}
312
		}
313
		i = 0; /* in case we get ENOSPC on the next send */
L
Linus Torvalds 已提交
314 315 316
	}

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

J
[CIFS]  
Jeremy Allison 已提交
321 322 323 324
	/* 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 已提交
325 326 327
	return rc;
}

J
[CIFS]  
Jeremy Allison 已提交
328
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
L
Linus Torvalds 已提交
329
{
330
	if (long_op == CIFS_ASYNC_OP) {
L
Linus Torvalds 已提交
331 332 333
		/* oplock breaks must not be held up */
		atomic_inc(&ses->server->inFlight);
	} else {
S
Steve French 已提交
334 335 336
		spin_lock(&GlobalMid_Lock);
		while (1) {
			if (atomic_read(&ses->server->inFlight) >=
337
					cifs_max_pending){
L
Linus Torvalds 已提交
338
				spin_unlock(&GlobalMid_Lock);
339 340 341
#ifdef CONFIG_CIFS_STATS2
				atomic_inc(&ses->server->num_waiters);
#endif
L
Linus Torvalds 已提交
342 343 344
				wait_event(ses->server->request_q,
					atomic_read(&ses->server->inFlight)
					 < cifs_max_pending);
345 346 347
#ifdef CONFIG_CIFS_STATS2
				atomic_dec(&ses->server->num_waiters);
#endif
L
Linus Torvalds 已提交
348 349
				spin_lock(&GlobalMid_Lock);
			} else {
S
Steve French 已提交
350
				if (ses->server->tcpStatus == CifsExiting) {
L
Linus Torvalds 已提交
351 352 353 354
					spin_unlock(&GlobalMid_Lock);
					return -ENOENT;
				}

S
Steve French 已提交
355 356
				/* can not count locking commands against total
				   as they are allowed to block on server */
357

L
Linus Torvalds 已提交
358
				/* update # of requests on the wire to server */
359
				if (long_op != CIFS_BLOCKING_OP)
L
Linus Torvalds 已提交
360 361 362 363 364 365
					atomic_inc(&ses->server->inFlight);
				spin_unlock(&GlobalMid_Lock);
				break;
			}
		}
	}
J
[CIFS]  
Jeremy Allison 已提交
366 367
	return 0;
}
L
Linus Torvalds 已提交
368

J
[CIFS]  
Jeremy Allison 已提交
369 370 371
static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
			struct mid_q_entry **ppmidQ)
{
L
Linus Torvalds 已提交
372
	if (ses->server->tcpStatus == CifsExiting) {
J
[CIFS]  
Jeremy Allison 已提交
373
		return -ENOENT;
L
Linus Torvalds 已提交
374
	} else if (ses->server->tcpStatus == CifsNeedReconnect) {
S
Steve French 已提交
375
		cFYI(1, ("tcp session dead - return to caller to retry"));
J
[CIFS]  
Jeremy Allison 已提交
376
		return -EAGAIN;
L
Linus Torvalds 已提交
377 378
	} else if (ses->status != CifsGood) {
		/* check if SMB session is bad because we are setting it up */
S
Steve French 已提交
379
		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
S
Steve French 已提交
380
			(in_buf->Command != SMB_COM_NEGOTIATE))
J
[CIFS]  
Jeremy Allison 已提交
381
			return -EAGAIN;
S
Steve French 已提交
382
		/* else ok - we are setting up session */
L
Linus Torvalds 已提交
383
	}
J
[CIFS]  
Jeremy Allison 已提交
384
	*ppmidQ = AllocMidQEntry(in_buf, ses);
385
	if (*ppmidQ == NULL)
J
[CIFS]  
Jeremy Allison 已提交
386 387 388 389
		return -ENOMEM;
	return 0;
}

S
Steve French 已提交
390
static int wait_for_response(struct cifsSesInfo *ses,
J
[CIFS]  
Jeremy Allison 已提交
391 392 393 394 395 396 397 398 399
			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 已提交
400 401
			(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
			time_after(jiffies, curr_timeout) ||
J
[CIFS]  
Jeremy Allison 已提交
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
			((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 已提交
419
			 Although we prefer not to time out if the
J
[CIFS]  
Jeremy Allison 已提交
420
			 server is still responding - we will time
S
Steve French 已提交
421
			 out if the server takes more than 15 (or 45
J
[CIFS]  
Jeremy Allison 已提交
422
			 or 180) seconds to respond to this request
S
Steve French 已提交
423
			 and has not responded to any request from
J
[CIFS]  
Jeremy Allison 已提交
424 425 426 427
			 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 已提交
428
				cERROR(1, ("server not responding"));
J
[CIFS]  
Jeremy Allison 已提交
429 430 431 432 433 434 435 436
				return -1;
			}
		} else {
			return 0;
		}
	}
}

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458

/*
 *
 * 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);
459 460
	cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));

461 462 463
	return rc;
}

J
[CIFS]  
Jeremy Allison 已提交
464
int
S
Steve French 已提交
465 466
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
467
	     const int flags)
J
[CIFS]  
Jeremy Allison 已提交
468 469
{
	int rc = 0;
470
	int long_op;
J
[CIFS]  
Jeremy Allison 已提交
471 472 473 474
	unsigned int receive_len;
	unsigned long timeout;
	struct mid_q_entry *midQ;
	struct smb_hdr *in_buf = iov[0].iov_base;
475

476 477
	long_op = flags & CIFS_TIMEOUT_MASK;

J
[CIFS]  
Jeremy Allison 已提交
478 479 480 481
	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */

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

S
Steve French 已提交
486
	if (ses->server->tcpStatus == CifsExiting) {
J
[CIFS]  
Jeremy Allison 已提交
487 488 489 490
		cifs_small_buf_release(in_buf);
		return -ENOENT;
	}

S
Steve French 已提交
491
	/* Ensure that we do not send more than 50 overlapping requests
J
[CIFS]  
Jeremy Allison 已提交
492 493 494 495 496 497 498 499 500
	   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 已提交
501
	/* make sure that we sign in the same order that we send on this socket
J
[CIFS]  
Jeremy Allison 已提交
502 503 504
	   and avoid races inside tcp sendmsg code that could cause corruption
	   of smb data */

S
Steve French 已提交
505
	down(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
506 507 508

	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
L
Linus Torvalds 已提交
509
		up(&ses->server->tcpSem);
510
		cifs_small_buf_release(in_buf);
J
[CIFS]  
Jeremy Allison 已提交
511
		/* Update # of requests on wire to server */
S
Steve French 已提交
512
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
513 514
		wake_up(&ses->server->request_q);
		return rc;
L
Linus Torvalds 已提交
515
	}
S
Steve French 已提交
516
	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
L
Linus Torvalds 已提交
517 518

	midQ->midState = MID_REQUEST_SUBMITTED;
519 520 521
#ifdef CONFIG_CIFS_STATS2
	atomic_inc(&ses->server->inSend);
#endif
522
	rc = smb_send2(ses->server->ssocket, iov, n_vec,
523
		      (struct sockaddr *) &(ses->server->addr.sockAddr));
524 525
#ifdef CONFIG_CIFS_STATS2
	atomic_dec(&ses->server->inSend);
S
Steve French 已提交
526
	midQ->when_sent = jiffies;
527
#endif
J
[CIFS]  
Jeremy Allison 已提交
528 529 530 531

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

S
Steve French 已提交
532
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
533
		goto out;
534

535 536 537
	if (long_op == CIFS_STD_OP)
		timeout = 15 * HZ;
	else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
538
		timeout = 180 * HZ;
539
	else if (long_op == CIFS_LONG_OP)
S
Steve French 已提交
540
		timeout = 45 * HZ; /* should be greater than
541
			servers oplock break timeout (about 43 seconds) */
542 543 544 545 546 547 548 549 550
	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 已提交
551

S
Steve French 已提交
552
	/* wait for 15 seconds or until woken up due to response arriving or
553 554 555
	   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
556
		but we still give response a chance to complete */
557
		timeout = 2 * HZ;
S
Steve French 已提交
558
	}
559 560

	/* No user interrupts in wait - wreaks havoc with performance */
J
[CIFS]  
Jeremy Allison 已提交
561
	wait_for_response(ses, midQ, timeout, 10 * HZ);
562 563 564 565

	spin_lock(&GlobalMid_Lock);
	if (midQ->resp_buf) {
		spin_unlock(&GlobalMid_Lock);
566
		receive_len = midQ->resp_buf->smb_buf_length;
567
	} else {
S
Steve French 已提交
568
		cERROR(1, ("No response to cmd %d mid %d",
569
			midQ->command, midQ->mid));
S
Steve French 已提交
570 571
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
572 573 574 575 576 577 578 579
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
580
			if (midQ->midState == MID_RETRY_NEEDED) {
581
				rc = -EAGAIN;
S
Steve French 已提交
582
				cFYI(1, ("marking request for retry"));
583 584 585 586 587 588
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
J
[CIFS]  
Jeremy Allison 已提交
589
		/* Update # of requests on wire to server */
S
Steve French 已提交
590
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
591
		wake_up(&ses->server->request_q);
592 593
		return rc;
	}
594

595 596 597 598 599
	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 已提交
600
		if (midQ->resp_buf &&
601
			(midQ->midState == MID_RESPONSE_RECEIVED)) {
602

603
			iov[0].iov_base = (char *)midQ->resp_buf;
S
Steve French 已提交
604
			if (midQ->largeBuf)
605 606 607 608
				*pRespBufType = CIFS_LARGE_BUFFER;
			else
				*pRespBufType = CIFS_SMALL_BUFFER;
			iov[0].iov_len = receive_len + 4;
609

610
			dump_smb(midQ->resp_buf, 80);
611
			/* convert the length into a more usable form */
S
Steve French 已提交
612
			if ((receive_len > 24) &&
613 614
			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
					SECMODE_SIGN_ENABLED))) {
615
				rc = cifs_verify_signature(midQ->resp_buf,
616
						&ses->server->mac_signing_key,
617
						midQ->sequence_number+1);
S
Steve French 已提交
618 619
				if (rc) {
					cERROR(1, ("Unexpected SMB signature"));
620 621 622 623 624
					/* BB FIXME add code to kill session */
				}
			}

			/* BB special case reconnect tid and uid here? */
625 626
			rc = map_smb_to_linux_error(midQ->resp_buf,
						flags & CIFS_LOG_ERROR);
627 628

			/* convert ByteCount if necessary */
629 630
			if (receive_len >= sizeof(struct smb_hdr) - 4
			    /* do not count RFC1001 header */  +
631
			    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
S
Steve French 已提交
632
				BCC(midQ->resp_buf) =
633
					le16_to_cpu(BCC_LE(midQ->resp_buf));
634 635 636 637
			if ((flags & CIFS_NO_RESP) == 0)
				midQ->resp_buf = NULL;  /* mark it so buf will
							   not be freed by
							   DeleteMidQEntry */
638 639
		} else {
			rc = -EIO;
S
Steve French 已提交
640
			cFYI(1, ("Bad MID state?"));
641 642
		}
	}
L
Linus Torvalds 已提交
643

J
[CIFS]  
Jeremy Allison 已提交
644 645
out:
	DeleteMidQEntry(midQ);
S
Steve French 已提交
646
	atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
647
	wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
648

649 650
	return rc;
}
L
Linus Torvalds 已提交
651 652 653 654 655 656 657 658 659 660 661 662

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 已提交
663
		cERROR(1, ("Null smb session"));
L
Linus Torvalds 已提交
664 665
		return -EIO;
	}
S
Steve French 已提交
666 667
	if (ses->server == NULL) {
		cERROR(1, ("Null tcp session"));
L
Linus Torvalds 已提交
668 669 670
		return -EIO;
	}

S
Steve French 已提交
671
	if (ses->server->tcpStatus == CifsExiting)
672 673
		return -ENOENT;

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

J
[CIFS]  
Jeremy Allison 已提交
678 679 680 681
	rc = wait_for_free_request(ses, long_op);
	if (rc)
		return rc;

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

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

J
[CIFS]  
Jeremy Allison 已提交
688 689
	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
L
Linus Torvalds 已提交
690
		up(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
691
		/* Update # of requests on wire to server */
S
Steve French 已提交
692
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
693 694
		wake_up(&ses->server->request_q);
		return rc;
L
Linus Torvalds 已提交
695 696 697
	}

	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
698
		cERROR(1, ("Illegal length, greater than maximum frame, %d",
L
Linus Torvalds 已提交
699 700
			in_buf->smb_buf_length));
		DeleteMidQEntry(midQ);
J
[CIFS]  
Jeremy Allison 已提交
701 702
		up(&ses->server->tcpSem);
		/* Update # of requests on wire to server */
S
Steve French 已提交
703
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
704
		wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
705 706 707
		return -EIO;
	}

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

	midQ->midState = MID_REQUEST_SUBMITTED;
711 712 713
#ifdef CONFIG_CIFS_STATS2
	atomic_inc(&ses->server->inSend);
#endif
L
Linus Torvalds 已提交
714 715
	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
		      (struct sockaddr *) &(ses->server->addr.sockAddr));
716 717
#ifdef CONFIG_CIFS_STATS2
	atomic_dec(&ses->server->inSend);
S
Steve French 已提交
718
	midQ->when_sent = jiffies;
719
#endif
J
[CIFS]  
Jeremy Allison 已提交
720 721
	up(&ses->server->tcpSem);

S
Steve French 已提交
722
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
723 724
		goto out;

725 726 727 728 729
	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 已提交
730
		goto out;
731
	else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
732
		timeout = 180 * HZ;
733
	else if (long_op == CIFS_LONG_OP)
S
Steve French 已提交
734
		timeout = 45 * HZ; /* should be greater than
L
Linus Torvalds 已提交
735
			servers oplock break timeout (about 43 seconds) */
736 737 738 739 740 741 742 743
	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 已提交
744 745
	if (signal_pending(current)) {
		/* if signal pending do not hold up user for full smb timeout
746
		but we still give response a chance to complete */
L
Linus Torvalds 已提交
747
		timeout = 2 * HZ;
S
Steve French 已提交
748
	}
L
Linus Torvalds 已提交
749 750

	/* No user interrupts in wait - wreaks havoc with performance */
J
[CIFS]  
Jeremy Allison 已提交
751
	wait_for_response(ses, midQ, timeout, 10 * HZ);
L
Linus Torvalds 已提交
752 753 754 755

	spin_lock(&GlobalMid_Lock);
	if (midQ->resp_buf) {
		spin_unlock(&GlobalMid_Lock);
756
		receive_len = midQ->resp_buf->smb_buf_length;
L
Linus Torvalds 已提交
757
	} else {
S
Steve French 已提交
758
		cERROR(1, ("No response for cmd %d mid %d",
759
			  midQ->command, midQ->mid));
S
Steve French 已提交
760 761
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
L
Linus Torvalds 已提交
762 763 764 765 766 767 768 769
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
770
			if (midQ->midState == MID_RETRY_NEEDED) {
L
Linus Torvalds 已提交
771
				rc = -EAGAIN;
S
Steve French 已提交
772
				cFYI(1, ("marking request for retry"));
L
Linus Torvalds 已提交
773 774 775 776 777 778
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
J
[CIFS]  
Jeremy Allison 已提交
779
		/* Update # of requests on wire to server */
S
Steve French 已提交
780
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
781
		wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
782 783
		return rc;
	}
784

L
Linus Torvalds 已提交
785
	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
786
		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
L
Linus Torvalds 已提交
787 788 789 790 791 792 793 794 795 796 797 798 799
			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 已提交
800
			if ((receive_len > 24) &&
801 802 803
			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
					SECMODE_SIGN_ENABLED))) {
				rc = cifs_verify_signature(out_buf,
804
						&ses->server->mac_signing_key,
805
						midQ->sequence_number+1);
S
Steve French 已提交
806 807
				if (rc) {
					cERROR(1, ("Unexpected SMB signature"));
808
					/* BB FIXME add code to kill session */
809
				}
L
Linus Torvalds 已提交
810 811 812 813
			}

			*pbytes_returned = out_buf->smb_buf_length;

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

			/* convert ByteCount if necessary */
818 819
			if (receive_len >= sizeof(struct smb_hdr) - 4
			    /* do not count RFC1001 header */  +
L
Linus Torvalds 已提交
820
			    (2 * out_buf->WordCount) + 2 /* bcc */ )
821
				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
L
Linus Torvalds 已提交
822 823
		} else {
			rc = -EIO;
S
Steve French 已提交
824
			cERROR(1, ("Bad MID state?"));
L
Linus Torvalds 已提交
825 826
		}
	}
J
[CIFS]  
Jeremy Allison 已提交
827 828

out:
L
Linus Torvalds 已提交
829
	DeleteMidQEntry(midQ);
S
Steve French 已提交
830
	atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
831
	wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
832

J
[CIFS]  
Jeremy Allison 已提交
833 834
	return rc;
}
L
Linus Torvalds 已提交
835

J
[CIFS]  
Jeremy Allison 已提交
836 837 838 839 840 841 842 843 844 845 846 847
/* 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 已提交
848
	down(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
849 850 851 852 853 854 855 856
	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 已提交
857
	return rc;
J
[CIFS]  
Jeremy Allison 已提交
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
}

/* 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,
882
			&bytes_returned, CIFS_STD_OP);
J
[CIFS]  
Jeremy Allison 已提交
883 884 885 886 887 888 889 890 891 892 893 894 895 896
}

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 已提交
897
		cERROR(1, ("Null smb session"));
J
[CIFS]  
Jeremy Allison 已提交
898 899 900 901
		return -EIO;
	}
	ses = tcon->ses;

S
Steve French 已提交
902 903
	if (ses->server == NULL) {
		cERROR(1, ("Null tcp session"));
J
[CIFS]  
Jeremy Allison 已提交
904 905 906
		return -EIO;
	}

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

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

914
	rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
J
[CIFS]  
Jeremy Allison 已提交
915 916 917
	if (rc)
		return rc;

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

S
Steve French 已提交
922
	down(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938

	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 已提交
939

J
[CIFS]  
Jeremy Allison 已提交
940 941 942 943 944 945 946 947 948 949
	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 已提交
950
	up(&ses->server->tcpSem);
J
[CIFS]  
Jeremy Allison 已提交
951

S
Steve French 已提交
952
	if (rc < 0) {
J
[CIFS]  
Jeremy Allison 已提交
953 954 955 956 957 958
		DeleteMidQEntry(midQ);
		return rc;
	}

	/* Wait for a reply - allow signals to interrupt. */
	rc = wait_event_interruptible(ses->server->response_q,
S
Steve French 已提交
959
		(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
J
[CIFS]  
Jeremy Allison 已提交
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
		((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 已提交
993
		if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
J
[CIFS]  
Jeremy Allison 已提交
994 995 996 997 998 999 1000 1001 1002 1003
			/* 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 已提交
1004
		cERROR(1, ("No response for cmd %d mid %d",
J
[CIFS]  
Jeremy Allison 已提交
1005
			  midQ->command, midQ->mid));
S
Steve French 已提交
1006 1007
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
J
[CIFS]  
Jeremy Allison 已提交
1008 1009 1010 1011 1012 1013 1014 1015
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
1016
			if (midQ->midState == MID_RETRY_NEEDED) {
J
[CIFS]  
Jeremy Allison 已提交
1017
				rc = -EAGAIN;
S
Steve French 已提交
1018
				cFYI(1, ("marking request for retry"));
J
[CIFS]  
Jeremy Allison 已提交
1019 1020 1021 1022 1023 1024 1025
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
		return rc;
L
Linus Torvalds 已提交
1026
	}
1027

J
[CIFS]  
Jeremy Allison 已提交
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
	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 已提交
1043
			if ((receive_len > 24) &&
J
[CIFS]  
Jeremy Allison 已提交
1044 1045 1046
			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
					SECMODE_SIGN_ENABLED))) {
				rc = cifs_verify_signature(out_buf,
1047
						&ses->server->mac_signing_key,
J
[CIFS]  
Jeremy Allison 已提交
1048
						midQ->sequence_number+1);
S
Steve French 已提交
1049 1050
				if (rc) {
					cERROR(1, ("Unexpected SMB signature"));
J
[CIFS]  
Jeremy Allison 已提交
1051 1052 1053 1054 1055 1056 1057
					/* BB FIXME add code to kill session */
				}
			}

			*pbytes_returned = out_buf->smb_buf_length;

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

J
[CIFS]  
Jeremy Allison 已提交
1060
			/* convert ByteCount if necessary */
1061 1062
			if (receive_len >= sizeof(struct smb_hdr) - 4
			    /* do not count RFC1001 header */  +
J
[CIFS]  
Jeremy Allison 已提交
1063 1064 1065 1066
			    (2 * out_buf->WordCount) + 2 /* bcc */ )
				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
		} else {
			rc = -EIO;
S
Steve French 已提交
1067
			cERROR(1, ("Bad MID state?"));
J
[CIFS]  
Jeremy Allison 已提交
1068 1069 1070 1071 1072
		}
	}
	DeleteMidQEntry(midQ);
	if (rstart && rc == -EACCES)
		return -ERESTARTSYS;
L
Linus Torvalds 已提交
1073 1074
	return rc;
}