blob: d77b6154cf22c7c478bb0c620e67e6aaa28bfe1e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/transport.c
3 *
Steve Frenchad7a2922008-02-07 23:25:02 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
Steve French14a441a2b2006-07-16 04:32:51 +00006 * Jeremy Allison (jra@samba.org) 2006.
Steve French79a58d12007-07-06 22:44:50 +00007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
16 * the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software
Steve French79a58d12007-07-06 22:44:50 +000020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
23#include <linux/fs.h>
24#include <linux/list.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/wait.h>
27#include <linux/net.h>
28#include <linux/delay.h>
29#include <asm/uaccess.h>
30#include <asm/processor.h>
31#include <linux/mempool.h>
32#include "cifspdu.h"
33#include "cifsglob.h"
34#include "cifsproto.h"
35#include "cifs_debug.h"
Steve French50c2f752007-07-13 00:33:32 +000036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037extern mempool_t *cifs_mid_poolp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Jeff Layton2b84a36c2011-01-11 07:24:21 -050039static void
40wake_up_task(struct mid_q_entry *mid)
41{
42 wake_up_process(mid->callback_data);
43}
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static struct mid_q_entry *
Jeff Layton24b9b062008-12-01 07:09:34 -050046AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -070047{
48 struct mid_q_entry *temp;
49
Jeff Layton24b9b062008-12-01 07:09:34 -050050 if (server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +000051 cERROR(1, "Null TCP session in AllocMidQEntry");
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 return NULL;
53 }
Steve French50c2f752007-07-13 00:33:32 +000054
Pekka Enberg232087c2008-09-15 13:22:54 +030055 temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 if (temp == NULL)
57 return temp;
58 else {
Steve French26f57362007-08-30 22:09:15 +000059 memset(temp, 0, sizeof(struct mid_q_entry));
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 temp->mid = smb_buffer->Mid; /* always LE */
61 temp->pid = current->pid;
62 temp->command = smb_buffer->Command;
Joe Perchesb6b38f72010-04-21 03:50:45 +000063 cFYI(1, "For smb_command %d", temp->command);
Steve French1047abc2005-10-11 19:58:06 -070064 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
65 /* when mid allocated can be before when sent */
66 temp->when_alloc = jiffies;
Jeff Layton2b84a36c2011-01-11 07:24:21 -050067
68 /*
69 * The default is for the mid to be synchronous, so the
70 * default callback just wakes up the current task.
71 */
72 temp->callback = wake_up_task;
73 temp->callback_data = current;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 }
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 atomic_inc(&midCount);
77 temp->midState = MID_REQUEST_ALLOCATED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 return temp;
79}
80
81static void
82DeleteMidQEntry(struct mid_q_entry *midEntry)
83{
Steve French1047abc2005-10-11 19:58:06 -070084#ifdef CONFIG_CIFS_STATS2
85 unsigned long now;
86#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 midEntry->midState = MID_FREE;
Jeff Layton80975312011-01-11 07:24:02 -050088 atomic_dec(&midCount);
Steve French79a58d12007-07-06 22:44:50 +000089 if (midEntry->largeBuf)
Steve Frenchb8643e12005-04-28 22:41:07 -070090 cifs_buf_release(midEntry->resp_buf);
91 else
92 cifs_small_buf_release(midEntry->resp_buf);
Steve French1047abc2005-10-11 19:58:06 -070093#ifdef CONFIG_CIFS_STATS2
94 now = jiffies;
95 /* commands taking longer than one second are indications that
96 something is wrong, unless it is quite a slow link or server */
Steve French79a58d12007-07-06 22:44:50 +000097 if ((now - midEntry->when_alloc) > HZ) {
98 if ((cifsFYI & CIFS_TIMER) &&
Steve French1047abc2005-10-11 19:58:06 -070099 (midEntry->command != SMB_COM_LOCKING_ANDX)) {
100 printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
101 midEntry->command, midEntry->mid);
102 printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
103 now - midEntry->when_alloc,
104 now - midEntry->when_sent,
105 now - midEntry->when_received);
106 }
107 }
108#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 mempool_free(midEntry, cifs_mid_poolp);
110}
111
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500112static void
113delete_mid(struct mid_q_entry *mid)
114{
115 spin_lock(&GlobalMid_Lock);
116 list_del(&mid->qhead);
117 spin_unlock(&GlobalMid_Lock);
118
119 DeleteMidQEntry(mid);
120}
121
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500122static int
Jeff Layton0496e022008-12-30 12:39:16 -0500123smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124{
125 int rc = 0;
126 int i = 0;
127 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700128 struct smb_hdr *smb_buffer = iov[0].iov_base;
129 unsigned int len = iov[0].iov_len;
130 unsigned int total_len;
131 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000132 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000133 struct socket *ssocket = server->ssocket;
Steve French50c2f752007-07-13 00:33:32 +0000134
Steve French79a58d12007-07-06 22:44:50 +0000135 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700137
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300138 smb_msg.msg_name = (struct sockaddr *) &server->dstaddr;
Steve French26f57362007-08-30 22:09:15 +0000139 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 smb_msg.msg_control = NULL;
141 smb_msg.msg_controllen = 0;
Jeff Layton0496e022008-12-30 12:39:16 -0500142 if (server->noblocksnd)
Steve Frenchedf1ae42008-10-29 00:47:57 +0000143 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
144 else
145 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
147 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000148 area, and byte area if necessary, is converted to littleendian in
149 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 Flags2 is converted in SendReceive */
151
Steve French3e844692005-10-03 13:37:24 -0700152
153 total_len = 0;
154 for (i = 0; i < n_vec; i++)
155 total_len += iov[i].iov_len;
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000158 cFYI(1, "Sending smb: total_len %d", total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 dump_smb(smb_buffer, len);
160
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000161 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700162 while (total_len) {
163 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
164 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
166 i++;
Steve Frenchda505c32009-01-19 03:49:35 +0000167 /* if blocking send we try 3 times, since each can block
168 for 5 seconds. For nonblocking we have to try more
169 but wait increasing amounts of time allowing time for
170 socket to clear. The overall time we wait in either
171 case to send on the socket is about 15 seconds.
172 Similarly we wait for 15 seconds for
173 a response from the server in SendReceive[2]
174 for the server to send a response back for
175 most types of requests (except SMB Write
176 past end of file which can be slow, and
177 blocking lock operations). NFS waits slightly longer
178 than CIFS, but this can make it take longer for
179 nonresponsive servers to be detected and 15 seconds
180 is more than enough time for modern networks to
181 send a packet. In most cases if we fail to send
182 after the retries we will kill the socket and
183 reconnect which may clear the network problem.
184 */
185 if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000186 cERROR(1, "sends on sock %p stuck for 15 seconds",
187 ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 rc = -EAGAIN;
189 break;
190 }
Steve French68058e72005-10-10 10:34:22 -0700191 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 continue;
193 }
Steve French79a58d12007-07-06 22:44:50 +0000194 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 break;
Steve French3e844692005-10-03 13:37:24 -0700196
Steve French61de8002008-10-30 20:15:22 +0000197 if (rc == total_len) {
198 total_len = 0;
199 break;
200 } else if (rc > total_len) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000201 cERROR(1, "sent %d requested %d", rc, total_len);
Steve French3e844692005-10-03 13:37:24 -0700202 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500203 }
Steve French79a58d12007-07-06 22:44:50 +0000204 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700205 /* should never happen, letting socket clear before
206 retrying is our only obvious option here */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000207 cERROR(1, "tcp sent no data");
Steve French3e844692005-10-03 13:37:24 -0700208 msleep(500);
209 continue;
210 }
211 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700212 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700213 for (i = first_vec; i < n_vec; i++) {
214 if (iov[i].iov_len) {
215 if (rc > iov[i].iov_len) {
216 rc -= iov[i].iov_len;
217 iov[i].iov_len = 0;
218 } else {
219 iov[i].iov_base += rc;
220 iov[i].iov_len -= rc;
221 first_vec = i;
222 break;
223 }
224 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500225 }
Steve French5e1253b2005-10-10 14:06:37 -0700226 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 }
228
Steve Frenchedf1ae42008-10-29 00:47:57 +0000229 if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000230 cFYI(1, "partial send (%d remaining), terminating session",
231 total_len);
Steve Frenchedf1ae42008-10-29 00:47:57 +0000232 /* If we have only sent part of an SMB then the next SMB
233 could be taken as the remainder of this one. We need
234 to kill the socket so the server throws away the partial
235 SMB */
236 server->tcpStatus = CifsNeedReconnect;
237 }
238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000240 cERROR(1, "Error %d sending data on socket to server", rc);
Steve French3e844692005-10-03 13:37:24 -0700241 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000244 /* Don't want to modify the buffer as a
245 side effect of this call. */
246 smb_buffer->smb_buf_length = smb_buf_length;
247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 return rc;
249}
250
Jeff Layton0496e022008-12-30 12:39:16 -0500251int
252smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
253 unsigned int smb_buf_length)
254{
255 struct kvec iov;
256
257 iov.iov_base = smb_buffer;
258 iov.iov_len = smb_buf_length + 4;
259
260 return smb_sendv(server, &iov, 1);
261}
262
Jeff Laytonc5797a92011-01-11 07:24:01 -0500263static int wait_for_free_request(struct TCP_Server_Info *server,
264 const int long_op)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000265{
Steve French133672e2007-11-13 22:41:37 +0000266 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000267 /* oplock breaks must not be held up */
Jeff Laytonc5797a92011-01-11 07:24:01 -0500268 atomic_inc(&server->inFlight);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000269 return 0;
270 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000271
Volker Lendecke27a97a62008-12-08 20:59:39 +0000272 spin_lock(&GlobalMid_Lock);
273 while (1) {
Jeff Laytonc5797a92011-01-11 07:24:01 -0500274 if (atomic_read(&server->inFlight) >= cifs_max_pending) {
Volker Lendecke27a97a62008-12-08 20:59:39 +0000275 spin_unlock(&GlobalMid_Lock);
276#ifdef CONFIG_CIFS_STATS2
Jeff Laytonc5797a92011-01-11 07:24:01 -0500277 atomic_inc(&server->num_waiters);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000278#endif
Jeff Laytonc5797a92011-01-11 07:24:01 -0500279 wait_event(server->request_q,
280 atomic_read(&server->inFlight)
Volker Lendecke27a97a62008-12-08 20:59:39 +0000281 < cifs_max_pending);
282#ifdef CONFIG_CIFS_STATS2
Jeff Laytonc5797a92011-01-11 07:24:01 -0500283 atomic_dec(&server->num_waiters);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000284#endif
285 spin_lock(&GlobalMid_Lock);
286 } else {
Jeff Laytonc5797a92011-01-11 07:24:01 -0500287 if (server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000288 spin_unlock(&GlobalMid_Lock);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000289 return -ENOENT;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000290 }
Volker Lendecke27a97a62008-12-08 20:59:39 +0000291
292 /* can not count locking commands against total
293 as they are allowed to block on server */
294
295 /* update # of requests on the wire to server */
296 if (long_op != CIFS_BLOCKING_OP)
Jeff Laytonc5797a92011-01-11 07:24:01 -0500297 atomic_inc(&server->inFlight);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000298 spin_unlock(&GlobalMid_Lock);
299 break;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000300 }
301 }
302 return 0;
303}
304
305static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
306 struct mid_q_entry **ppmidQ)
307{
308 if (ses->server->tcpStatus == CifsExiting) {
309 return -ENOENT;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100310 }
311
312 if (ses->server->tcpStatus == CifsNeedReconnect) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000313 cFYI(1, "tcp session dead - return to caller to retry");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000314 return -EAGAIN;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100315 }
316
317 if (ses->status != CifsGood) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000318 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000319 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000320 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000321 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000322 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000323 }
Jeff Layton24b9b062008-12-01 07:09:34 -0500324 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
Steve French26f57362007-08-30 22:09:15 +0000325 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000326 return -ENOMEM;
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500327 spin_lock(&GlobalMid_Lock);
328 list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
329 spin_unlock(&GlobalMid_Lock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000330 return 0;
331}
332
Jeff Layton0ade6402011-01-11 07:24:02 -0500333static int
334wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000335{
Jeff Layton0ade6402011-01-11 07:24:02 -0500336 int error;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000337
Jeff Layton0ade6402011-01-11 07:24:02 -0500338 error = wait_event_killable(server->response_q,
339 midQ->midState != MID_REQUEST_SUBMITTED);
340 if (error < 0)
341 return -ERESTARTSYS;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000342
Jeff Layton0ade6402011-01-11 07:24:02 -0500343 return 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000344}
345
Steve French133672e2007-11-13 22:41:37 +0000346
347/*
348 *
349 * Send an SMB Request. No response info (other than return code)
350 * needs to be parsed.
351 *
352 * flags indicate the type of request buffer and how long to wait
353 * and whether to log NT STATUS code (error) before mapping it to POSIX error
354 *
355 */
356int
357SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
358 struct smb_hdr *in_buf, int flags)
359{
360 int rc;
361 struct kvec iov[1];
362 int resp_buf_type;
363
364 iov[0].iov_base = (char *)in_buf;
365 iov[0].iov_len = in_buf->smb_buf_length + 4;
366 flags |= CIFS_NO_RESP;
367 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000368 cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
Steve French90c81e02008-02-12 20:32:36 +0000369
Steve French133672e2007-11-13 22:41:37 +0000370 return rc;
371}
372
Jeff Layton053d5032011-01-11 07:24:02 -0500373static int
374sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
375{
376 int rc = 0;
377
Jeff Layton74dd92a2011-01-11 07:24:02 -0500378 cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command,
379 mid->mid, mid->midState);
Jeff Layton053d5032011-01-11 07:24:02 -0500380
Jeff Layton74dd92a2011-01-11 07:24:02 -0500381 spin_lock(&GlobalMid_Lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500382 /* ensure that it's no longer on the pending_mid_q */
383 list_del_init(&mid->qhead);
384
Jeff Layton74dd92a2011-01-11 07:24:02 -0500385 switch (mid->midState) {
386 case MID_RESPONSE_RECEIVED:
Jeff Layton053d5032011-01-11 07:24:02 -0500387 spin_unlock(&GlobalMid_Lock);
388 return rc;
Jeff Layton74dd92a2011-01-11 07:24:02 -0500389 case MID_REQUEST_SUBMITTED:
390 /* socket is going down, reject all calls */
391 if (server->tcpStatus == CifsExiting) {
392 cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d",
393 __func__, mid->mid, mid->command, mid->midState);
Jeff Layton053d5032011-01-11 07:24:02 -0500394 rc = -EHOSTDOWN;
Jeff Layton74dd92a2011-01-11 07:24:02 -0500395 break;
Jeff Layton053d5032011-01-11 07:24:02 -0500396 }
Jeff Layton74dd92a2011-01-11 07:24:02 -0500397 case MID_RETRY_NEEDED:
398 rc = -EAGAIN;
399 break;
400 default:
401 cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
402 mid->mid, mid->midState);
403 rc = -EIO;
Jeff Layton053d5032011-01-11 07:24:02 -0500404 }
405 spin_unlock(&GlobalMid_Lock);
406
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500407 DeleteMidQEntry(mid);
Jeff Layton053d5032011-01-11 07:24:02 -0500408 return rc;
409}
410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411int
Steve French79a58d12007-07-06 22:44:50 +0000412SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
413 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000414 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000417 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500418 unsigned int receive_len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500419 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700420 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000421
Steve French133672e2007-11-13 22:41:37 +0000422 long_op = flags & CIFS_TIMEOUT_MASK;
423
Steve Frenchec637e32005-12-12 20:53:18 -0800424 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Steve French4b8f9302006-02-26 16:41:18 +0000426 if ((ses == NULL) || (ses->server == NULL)) {
427 cifs_small_buf_release(in_buf);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000428 cERROR(1, "Null session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return -EIO;
430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Steve French79a58d12007-07-06 22:44:50 +0000432 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000433 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700434 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000435 }
Steve French31ca3bc2005-04-28 22:41:11 -0700436
Steve French79a58d12007-07-06 22:44:50 +0000437 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 to the same server. We may make this configurable later or
439 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Jeff Laytonc5797a92011-01-11 07:24:01 -0500441 rc = wait_for_free_request(ses->server, long_op);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000442 if (rc) {
443 cifs_small_buf_release(in_buf);
444 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000446
Steve French79a58d12007-07-06 22:44:50 +0000447 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 and avoid races inside tcp sendmsg code that could cause corruption
449 of smb data */
450
Jeff Layton72ca5452008-12-01 07:09:36 -0500451 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000453 rc = allocate_mid(ses, in_buf, &midQ);
454 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500455 mutex_unlock(&ses->server->srv_mutex);
Steve French4b8f9302006-02-26 16:41:18 +0000456 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000457 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000458 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000459 wake_up(&ses->server->request_q);
460 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
Steve French79a58d12007-07-06 22:44:50 +0000462 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100463 if (rc) {
464 mutex_unlock(&ses->server->srv_mutex);
465 cifs_small_buf_release(in_buf);
466 goto out;
467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
469 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700470#ifdef CONFIG_CIFS_STATS2
471 atomic_inc(&ses->server->inSend);
472#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500473 rc = smb_sendv(ses->server, iov, n_vec);
Steve French131afd0b2005-10-07 09:51:05 -0700474#ifdef CONFIG_CIFS_STATS2
475 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700476 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700477#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000478
Jeff Layton72ca5452008-12-01 07:09:36 -0500479 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000480 cifs_small_buf_release(in_buf);
481
Steve French79a58d12007-07-06 22:44:50 +0000482 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000483 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000484
Jeff Layton0ade6402011-01-11 07:24:02 -0500485 if (long_op == CIFS_ASYNC_OP)
Steve French133672e2007-11-13 22:41:37 +0000486 goto out;
Jeff Layton0ade6402011-01-11 07:24:02 -0500487
488 rc = wait_for_response(ses->server, midQ);
489 if (rc != 0)
Steve French133672e2007-11-13 22:41:37 +0000490 goto out;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500491
Jeff Layton053d5032011-01-11 07:24:02 -0500492 rc = sync_mid_result(midQ, ses->server);
493 if (rc != 0) {
Steve French79a58d12007-07-06 22:44:50 +0000494 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000495 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500496 return rc;
497 }
Steve French50c2f752007-07-13 00:33:32 +0000498
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100499 receive_len = midQ->resp_buf->smb_buf_length;
500
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500501 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000502 cERROR(1, "Frame too large received. Length: %d Xid: %d",
503 receive_len, xid);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500504 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000505 goto out;
506 }
Steve French84afc292005-12-02 13:32:45 -0800507
Steve French2b2bdfb2008-12-11 17:26:54 +0000508 /* rcvd frame is ok */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500509
Steve French2b2bdfb2008-12-11 17:26:54 +0000510 if (midQ->resp_buf &&
511 (midQ->midState == MID_RESPONSE_RECEIVED)) {
512
513 iov[0].iov_base = (char *)midQ->resp_buf;
514 if (midQ->largeBuf)
515 *pRespBufType = CIFS_LARGE_BUFFER;
516 else
517 *pRespBufType = CIFS_SMALL_BUFFER;
518 iov[0].iov_len = receive_len + 4;
519
520 dump_smb(midQ->resp_buf, 80);
521 /* convert the length into a more usable form */
522 if ((receive_len > 24) &&
523 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
524 SECMODE_SIGN_ENABLED))) {
525 rc = cifs_verify_signature(midQ->resp_buf,
Shirish Pargaonkar21e73392010-10-21 06:42:55 -0500526 ses->server,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500527 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000528 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000529 cERROR(1, "Unexpected SMB signature");
Steve French2b2bdfb2008-12-11 17:26:54 +0000530 /* BB FIXME add code to kill session */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500531 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500532 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000533
534 /* BB special case reconnect tid and uid here? */
535 rc = map_smb_to_linux_error(midQ->resp_buf,
536 flags & CIFS_LOG_ERROR);
537
538 /* convert ByteCount if necessary */
539 if (receive_len >= sizeof(struct smb_hdr) - 4
540 /* do not count RFC1001 header */ +
541 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
542 BCC(midQ->resp_buf) =
543 le16_to_cpu(BCC_LE(midQ->resp_buf));
544 if ((flags & CIFS_NO_RESP) == 0)
545 midQ->resp_buf = NULL; /* mark it so buf will
546 not be freed by
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500547 delete_mid */
Steve French2b2bdfb2008-12-11 17:26:54 +0000548 } else {
549 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000550 cFYI(1, "Bad MID state?");
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500551 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000552
553out:
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500554 delete_mid(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000555 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000556 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
558 return rc;
559}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
561int
562SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
563 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
564 int *pbytes_returned, const int long_op)
565{
566 int rc = 0;
567 unsigned int receive_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 struct mid_q_entry *midQ;
569
570 if (ses == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000571 cERROR(1, "Null smb session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 return -EIO;
573 }
Steve French79a58d12007-07-06 22:44:50 +0000574 if (ses->server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000575 cERROR(1, "Null tcp session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return -EIO;
577 }
578
Steve French79a58d12007-07-06 22:44:50 +0000579 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700580 return -ENOENT;
581
Steve French79a58d12007-07-06 22:44:50 +0000582 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 to the same server. We may make this configurable later or
584 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000586 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000587 cERROR(1, "Illegal length, greater than maximum frame, %d",
588 in_buf->smb_buf_length);
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000589 return -EIO;
590 }
591
Jeff Laytonc5797a92011-01-11 07:24:01 -0500592 rc = wait_for_free_request(ses->server, long_op);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000593 if (rc)
594 return rc;
595
Steve French79a58d12007-07-06 22:44:50 +0000596 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 and avoid races inside tcp sendmsg code that could cause corruption
598 of smb data */
599
Jeff Layton72ca5452008-12-01 07:09:36 -0500600 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000602 rc = allocate_mid(ses, in_buf, &midQ);
603 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500604 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000605 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000606 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000607 wake_up(&ses->server->request_q);
608 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610
Steve Frenchad009ac2005-04-28 22:41:05 -0700611 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100612 if (rc) {
613 mutex_unlock(&ses->server->srv_mutex);
614 goto out;
615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700618#ifdef CONFIG_CIFS_STATS2
619 atomic_inc(&ses->server->inSend);
620#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500621 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Steve French131afd0b2005-10-07 09:51:05 -0700622#ifdef CONFIG_CIFS_STATS2
623 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700624 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700625#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500626 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000627
Steve French79a58d12007-07-06 22:44:50 +0000628 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000629 goto out;
630
Jeff Layton0ade6402011-01-11 07:24:02 -0500631 if (long_op == CIFS_ASYNC_OP)
Steve French133672e2007-11-13 22:41:37 +0000632 goto out;
Jeff Layton0ade6402011-01-11 07:24:02 -0500633
634 rc = wait_for_response(ses->server, midQ);
635 if (rc != 0)
Steve French133672e2007-11-13 22:41:37 +0000636 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Jeff Layton053d5032011-01-11 07:24:02 -0500638 rc = sync_mid_result(midQ, ses->server);
639 if (rc != 0) {
Steve French79a58d12007-07-06 22:44:50 +0000640 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000641 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return rc;
643 }
Steve French50c2f752007-07-13 00:33:32 +0000644
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100645 receive_len = midQ->resp_buf->smb_buf_length;
646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000648 cERROR(1, "Frame too large received. Length: %d Xid: %d",
649 receive_len, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000651 goto out;
652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Steve French2b2bdfb2008-12-11 17:26:54 +0000654 /* rcvd frame is ok */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Steve French2b2bdfb2008-12-11 17:26:54 +0000656 if (midQ->resp_buf && out_buf
657 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
658 out_buf->smb_buf_length = receive_len;
659 memcpy((char *)out_buf + 4,
660 (char *)midQ->resp_buf + 4,
661 receive_len);
662
663 dump_smb(out_buf, 92);
664 /* convert the length into a more usable form */
665 if ((receive_len > 24) &&
666 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
667 SECMODE_SIGN_ENABLED))) {
668 rc = cifs_verify_signature(out_buf,
Shirish Pargaonkar21e73392010-10-21 06:42:55 -0500669 ses->server,
Steve Frenchad009ac2005-04-28 22:41:05 -0700670 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000671 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000672 cERROR(1, "Unexpected SMB signature");
Steve French2b2bdfb2008-12-11 17:26:54 +0000673 /* BB FIXME add code to kill session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000676
677 *pbytes_returned = out_buf->smb_buf_length;
678
679 /* BB special case reconnect tid and uid here? */
680 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
681
682 /* convert ByteCount if necessary */
683 if (receive_len >= sizeof(struct smb_hdr) - 4
684 /* do not count RFC1001 header */ +
685 (2 * out_buf->WordCount) + 2 /* bcc */ )
686 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
687 } else {
688 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000689 cERROR(1, "Bad MID state?");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000692out:
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500693 delete_mid(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000694 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000695 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000698}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000700/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
701
702static int
703send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
704 struct mid_q_entry *midQ)
705{
706 int rc = 0;
707 struct cifsSesInfo *ses = tcon->ses;
708 __u16 mid = in_buf->Mid;
709
710 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
711 in_buf->Mid = mid;
Jeff Layton72ca5452008-12-01 07:09:36 -0500712 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000713 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
714 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500715 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000716 return rc;
717 }
Jeff Layton0496e022008-12-30 12:39:16 -0500718 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeff Layton72ca5452008-12-01 07:09:36 -0500719 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000720 return rc;
721}
722
723/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
724 blocking lock to return. */
725
726static int
727send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
728 struct smb_hdr *in_buf,
729 struct smb_hdr *out_buf)
730{
731 int bytes_returned;
732 struct cifsSesInfo *ses = tcon->ses;
733 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
734
735 /* We just modify the current in_buf to change
736 the type of lock from LOCKING_ANDX_SHARED_LOCK
737 or LOCKING_ANDX_EXCLUSIVE_LOCK to
738 LOCKING_ANDX_CANCEL_LOCK. */
739
740 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
741 pSMB->Timeout = 0;
742 pSMB->hdr.Mid = GetNextMid(ses->server);
743
744 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000745 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000746}
747
748int
749SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
750 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
751 int *pbytes_returned)
752{
753 int rc = 0;
754 int rstart = 0;
755 unsigned int receive_len;
756 struct mid_q_entry *midQ;
757 struct cifsSesInfo *ses;
758
759 if (tcon == NULL || tcon->ses == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000760 cERROR(1, "Null smb session");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000761 return -EIO;
762 }
763 ses = tcon->ses;
764
Steve French79a58d12007-07-06 22:44:50 +0000765 if (ses->server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000766 cERROR(1, "Null tcp session");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000767 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 }
769
Steve French79a58d12007-07-06 22:44:50 +0000770 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000771 return -ENOENT;
772
Steve French79a58d12007-07-06 22:44:50 +0000773 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000774 to the same server. We may make this configurable later or
775 use ses->maxReq */
776
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000777 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000778 cERROR(1, "Illegal length, greater than maximum frame, %d",
779 in_buf->smb_buf_length);
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000780 return -EIO;
781 }
782
Jeff Laytonc5797a92011-01-11 07:24:01 -0500783 rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000784 if (rc)
785 return rc;
786
Steve French79a58d12007-07-06 22:44:50 +0000787 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000788 and avoid races inside tcp sendmsg code that could cause corruption
789 of smb data */
790
Jeff Layton72ca5452008-12-01 07:09:36 -0500791 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000792
793 rc = allocate_mid(ses, in_buf, &midQ);
794 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500795 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000796 return rc;
797 }
798
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000799 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100800 if (rc) {
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500801 delete_mid(midQ);
Volker Lendecke829049c2008-12-06 16:00:53 +0100802 mutex_unlock(&ses->server->srv_mutex);
803 return rc;
804 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000805
806 midQ->midState = MID_REQUEST_SUBMITTED;
807#ifdef CONFIG_CIFS_STATS2
808 atomic_inc(&ses->server->inSend);
809#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500810 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000811#ifdef CONFIG_CIFS_STATS2
812 atomic_dec(&ses->server->inSend);
813 midQ->when_sent = jiffies;
814#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500815 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000816
Steve French79a58d12007-07-06 22:44:50 +0000817 if (rc < 0) {
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500818 delete_mid(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000819 return rc;
820 }
821
822 /* Wait for a reply - allow signals to interrupt. */
823 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000824 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000825 ((ses->server->tcpStatus != CifsGood) &&
826 (ses->server->tcpStatus != CifsNew)));
827
828 /* Were we interrupted by a signal ? */
829 if ((rc == -ERESTARTSYS) &&
830 (midQ->midState == MID_REQUEST_SUBMITTED) &&
831 ((ses->server->tcpStatus == CifsGood) ||
832 (ses->server->tcpStatus == CifsNew))) {
833
834 if (in_buf->Command == SMB_COM_TRANSACTION2) {
835 /* POSIX lock. We send a NT_CANCEL SMB to cause the
836 blocking lock to return. */
837
838 rc = send_nt_cancel(tcon, in_buf, midQ);
839 if (rc) {
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500840 delete_mid(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000841 return rc;
842 }
843 } else {
844 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
845 to cause the blocking lock to return. */
846
847 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
848
849 /* If we get -ENOLCK back the lock may have
850 already been removed. Don't exit in this case. */
851 if (rc && rc != -ENOLCK) {
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500852 delete_mid(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000853 return rc;
854 }
855 }
856
Jeff Layton0ade6402011-01-11 07:24:02 -0500857 if (wait_for_response(ses->server, midQ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000858 /* We got the response - restart system call. */
859 rstart = 1;
860 }
861 }
862
Jeff Layton053d5032011-01-11 07:24:02 -0500863 rc = sync_mid_result(midQ, ses->server);
864 if (rc != 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000865 return rc;
Steve French50c2f752007-07-13 00:33:32 +0000866
Jeff Layton053d5032011-01-11 07:24:02 -0500867 receive_len = midQ->resp_buf->smb_buf_length;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000868 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000869 cERROR(1, "Frame too large received. Length: %d Xid: %d",
870 receive_len, xid);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000871 rc = -EIO;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100872 goto out;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000873 }
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100874
875 /* rcvd frame is ok */
876
Volker Lendeckeac6a3ef2008-12-06 16:40:40 +0100877 if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100878 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000879 cERROR(1, "Bad MID state?");
Volker Lendecke698e96a2008-12-06 16:39:31 +0100880 goto out;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100881 }
882
Volker Lendecke698e96a2008-12-06 16:39:31 +0100883 out_buf->smb_buf_length = receive_len;
884 memcpy((char *)out_buf + 4,
885 (char *)midQ->resp_buf + 4,
886 receive_len);
887
888 dump_smb(out_buf, 92);
889 /* convert the length into a more usable form */
890 if ((receive_len > 24) &&
891 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
892 SECMODE_SIGN_ENABLED))) {
893 rc = cifs_verify_signature(out_buf,
Shirish Pargaonkar21e73392010-10-21 06:42:55 -0500894 ses->server,
Volker Lendecke698e96a2008-12-06 16:39:31 +0100895 midQ->sequence_number+1);
896 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000897 cERROR(1, "Unexpected SMB signature");
Volker Lendecke698e96a2008-12-06 16:39:31 +0100898 /* BB FIXME add code to kill session */
899 }
900 }
901
902 *pbytes_returned = out_buf->smb_buf_length;
903
904 /* BB special case reconnect tid and uid here? */
905 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
906
907 /* convert ByteCount if necessary */
908 if (receive_len >= sizeof(struct smb_hdr) - 4
909 /* do not count RFC1001 header */ +
910 (2 * out_buf->WordCount) + 2 /* bcc */ )
911 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
912
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100913out:
Jeff Laytonddc8cf82011-01-11 07:24:02 -0500914 delete_mid(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000915 if (rstart && rc == -EACCES)
916 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 return rc;
918}