blob: 3612d6c0a0bbc1a4c9f64c2ce0f674517ce86d72 [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>
25#include <linux/wait.h>
26#include <linux/net.h>
27#include <linux/delay.h>
28#include <asm/uaccess.h>
29#include <asm/processor.h>
30#include <linux/mempool.h>
31#include "cifspdu.h"
32#include "cifsglob.h"
33#include "cifsproto.h"
34#include "cifs_debug.h"
Steve French50c2f752007-07-13 00:33:32 +000035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036extern mempool_t *cifs_mid_poolp;
Christoph Lametere18b8902006-12-06 20:33:20 -080037extern struct kmem_cache *cifs_oplock_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39static struct mid_q_entry *
Jeremy Allison7ee1af72006-08-02 21:56:33 +000040AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
42 struct mid_q_entry *temp;
43
44 if (ses == NULL) {
Steve French275cde12005-04-28 22:41:10 -070045 cERROR(1, ("Null session passed in to AllocMidQEntry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 return NULL;
47 }
48 if (ses->server == NULL) {
49 cERROR(1, ("Null TCP session in AllocMidQEntry"));
50 return NULL;
51 }
Steve French50c2f752007-07-13 00:33:32 +000052
Steve Frenchd6e04ae2005-06-13 13:24:43 -050053 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
Christoph Lametere94b1762006-12-06 20:33:17 -080054 GFP_KERNEL | GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 if (temp == NULL)
56 return temp;
57 else {
Steve French26f57362007-08-30 22:09:15 +000058 memset(temp, 0, sizeof(struct mid_q_entry));
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 temp->mid = smb_buffer->Mid; /* always LE */
60 temp->pid = current->pid;
61 temp->command = smb_buffer->Command;
62 cFYI(1, ("For smb_command %d", temp->command));
Steve French1047abc2005-10-11 19:58:06 -070063 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
64 /* when mid allocated can be before when sent */
65 temp->when_alloc = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 temp->ses = ses;
67 temp->tsk = current;
68 }
69
70 spin_lock(&GlobalMid_Lock);
71 list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
72 atomic_inc(&midCount);
73 temp->midState = MID_REQUEST_ALLOCATED;
74 spin_unlock(&GlobalMid_Lock);
75 return temp;
76}
77
78static void
79DeleteMidQEntry(struct mid_q_entry *midEntry)
80{
Steve French1047abc2005-10-11 19:58:06 -070081#ifdef CONFIG_CIFS_STATS2
82 unsigned long now;
83#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 spin_lock(&GlobalMid_Lock);
85 midEntry->midState = MID_FREE;
86 list_del(&midEntry->qhead);
87 atomic_dec(&midCount);
88 spin_unlock(&GlobalMid_Lock);
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
112struct oplock_q_entry *
Steve French79a58d12007-07-06 22:44:50 +0000113AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
115 struct oplock_q_entry *temp;
Steve French79a58d12007-07-06 22:44:50 +0000116 if ((pinode == NULL) || (tcon == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
118 return NULL;
119 }
120 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
Christoph Lametere94b1762006-12-06 20:33:17 -0800121 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 if (temp == NULL)
123 return temp;
124 else {
125 temp->pinode = pinode;
126 temp->tcon = tcon;
127 temp->netfid = fid;
128 spin_lock(&GlobalMid_Lock);
129 list_add_tail(&temp->qhead, &GlobalOplock_Q);
130 spin_unlock(&GlobalMid_Lock);
131 }
132 return temp;
133
134}
135
Steve French79a58d12007-07-06 22:44:50 +0000136void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
Steve French79a58d12007-07-06 22:44:50 +0000138 spin_lock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 /* should we check if list empty first? */
140 list_del(&oplockEntry->qhead);
141 spin_unlock(&GlobalMid_Lock);
142 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
143}
144
145int
146smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
147 unsigned int smb_buf_length, struct sockaddr *sin)
148{
149 int rc = 0;
150 int i = 0;
151 struct msghdr smb_msg;
152 struct kvec iov;
153 unsigned len = smb_buf_length + 4;
154
Steve French79a58d12007-07-06 22:44:50 +0000155 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 return -ENOTSOCK; /* BB eventually add reconnect code here */
157 iov.iov_base = smb_buffer;
158 iov.iov_len = len;
159
160 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000161 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 smb_msg.msg_control = NULL;
163 smb_msg.msg_controllen = 0;
164 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
165
166 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000167 area, and byte area if necessary, is converted to littleendian in
168 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 Flags2 is converted in SendReceive */
170
171 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700172 cFYI(1, ("Sending smb of length %d", smb_buf_length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 dump_smb(smb_buffer, len);
174
175 while (len > 0) {
176 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
177 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
178 i++;
Steve French3e844692005-10-03 13:37:24 -0700179 /* smaller timeout here than send2 since smaller size */
Steve French79a58d12007-07-06 22:44:50 +0000180 /* Although it may not be required, this also is smaller
181 oplock break time */
182 if (i > 12) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700184 ("sends on sock %p stuck for 7 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 ssocket));
186 rc = -EAGAIN;
187 break;
188 }
Steve French68058e72005-10-10 10:34:22 -0700189 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 continue;
191 }
Steve French79a58d12007-07-06 22:44:50 +0000192 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 break;
Steve French5e1253b2005-10-10 14:06:37 -0700194 else
195 i = 0; /* reset i after each successful send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 iov.iov_base += rc;
197 iov.iov_len -= rc;
198 len -= rc;
199 }
200
201 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000202 cERROR(1, ("Error %d sending data on socket to server", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 } else {
204 rc = 0;
205 }
206
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000207 /* Don't want to modify the buffer as a
208 side effect of this call. */
209 smb_buffer->smb_buf_length = smb_buf_length;
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 return rc;
212}
213
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500214static int
Steve French3e844692005-10-03 13:37:24 -0700215smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
216 struct sockaddr *sin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217{
218 int rc = 0;
219 int i = 0;
220 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700221 struct smb_hdr *smb_buffer = iov[0].iov_base;
222 unsigned int len = iov[0].iov_len;
223 unsigned int total_len;
224 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000225 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve French50c2f752007-07-13 00:33:32 +0000226
Steve French79a58d12007-07-06 22:44:50 +0000227 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000231 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 smb_msg.msg_control = NULL;
233 smb_msg.msg_controllen = 0;
234 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
235
236 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000237 area, and byte area if necessary, is converted to littleendian in
238 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 Flags2 is converted in SendReceive */
240
Steve French3e844692005-10-03 13:37:24 -0700241
242 total_len = 0;
243 for (i = 0; i < n_vec; i++)
244 total_len += iov[i].iov_len;
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700247 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 dump_smb(smb_buffer, len);
249
Steve French3e844692005-10-03 13:37:24 -0700250 while (total_len) {
251 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
252 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
254 i++;
Steve French79a58d12007-07-06 22:44:50 +0000255 if (i >= 14) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700257 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 ssocket));
259 rc = -EAGAIN;
260 break;
261 }
Steve French68058e72005-10-10 10:34:22 -0700262 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 continue;
264 }
Steve French79a58d12007-07-06 22:44:50 +0000265 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 break;
Steve French3e844692005-10-03 13:37:24 -0700267
268 if (rc >= total_len) {
269 WARN_ON(rc > total_len);
270 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500271 }
Steve French79a58d12007-07-06 22:44:50 +0000272 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700273 /* should never happen, letting socket clear before
274 retrying is our only obvious option here */
Steve French79a58d12007-07-06 22:44:50 +0000275 cERROR(1, ("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700276 msleep(500);
277 continue;
278 }
279 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700280 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700281 for (i = first_vec; i < n_vec; i++) {
282 if (iov[i].iov_len) {
283 if (rc > iov[i].iov_len) {
284 rc -= iov[i].iov_len;
285 iov[i].iov_len = 0;
286 } else {
287 iov[i].iov_base += rc;
288 iov[i].iov_len -= rc;
289 first_vec = i;
290 break;
291 }
292 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500293 }
Steve French5e1253b2005-10-10 14:06:37 -0700294 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296
297 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000298 cERROR(1, ("Error %d sending data on socket to server", rc));
Steve French3e844692005-10-03 13:37:24 -0700299 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000302 /* Don't want to modify the buffer as a
303 side effect of this call. */
304 smb_buffer->smb_buf_length = smb_buf_length;
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 return rc;
307}
308
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000309static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
310{
Steve French133672e2007-11-13 22:41:37 +0000311 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000312 /* oplock breaks must not be held up */
313 atomic_inc(&ses->server->inFlight);
314 } else {
Steve French79a58d12007-07-06 22:44:50 +0000315 spin_lock(&GlobalMid_Lock);
316 while (1) {
317 if (atomic_read(&ses->server->inFlight) >=
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000318 cifs_max_pending){
319 spin_unlock(&GlobalMid_Lock);
320#ifdef CONFIG_CIFS_STATS2
321 atomic_inc(&ses->server->num_waiters);
322#endif
323 wait_event(ses->server->request_q,
324 atomic_read(&ses->server->inFlight)
325 < cifs_max_pending);
326#ifdef CONFIG_CIFS_STATS2
327 atomic_dec(&ses->server->num_waiters);
328#endif
329 spin_lock(&GlobalMid_Lock);
330 } else {
Steve French79a58d12007-07-06 22:44:50 +0000331 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000332 spin_unlock(&GlobalMid_Lock);
333 return -ENOENT;
334 }
335
Steve French79a58d12007-07-06 22:44:50 +0000336 /* can not count locking commands against total
337 as they are allowed to block on server */
Steve French50c2f752007-07-13 00:33:32 +0000338
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000339 /* update # of requests on the wire to server */
Steve French133672e2007-11-13 22:41:37 +0000340 if (long_op != CIFS_BLOCKING_OP)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000341 atomic_inc(&ses->server->inFlight);
342 spin_unlock(&GlobalMid_Lock);
343 break;
344 }
345 }
346 }
347 return 0;
348}
349
350static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
351 struct mid_q_entry **ppmidQ)
352{
353 if (ses->server->tcpStatus == CifsExiting) {
354 return -ENOENT;
355 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
Steve French79a58d12007-07-06 22:44:50 +0000356 cFYI(1, ("tcp session dead - return to caller to retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000357 return -EAGAIN;
358 } else if (ses->status != CifsGood) {
359 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000360 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000361 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000362 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000363 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000364 }
365 *ppmidQ = AllocMidQEntry(in_buf, ses);
Steve French26f57362007-08-30 22:09:15 +0000366 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000367 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000368 return 0;
369}
370
Steve French79a58d12007-07-06 22:44:50 +0000371static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000372 struct mid_q_entry *midQ,
373 unsigned long timeout,
374 unsigned long time_to_wait)
375{
376 unsigned long curr_timeout;
377
378 for (;;) {
379 curr_timeout = timeout + jiffies;
380 wait_event(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000381 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
382 time_after(jiffies, curr_timeout) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000383 ((ses->server->tcpStatus != CifsGood) &&
384 (ses->server->tcpStatus != CifsNew)));
385
386 if (time_after(jiffies, curr_timeout) &&
387 (midQ->midState == MID_REQUEST_SUBMITTED) &&
388 ((ses->server->tcpStatus == CifsGood) ||
389 (ses->server->tcpStatus == CifsNew))) {
390
391 unsigned long lrt;
392
393 /* We timed out. Is the server still
394 sending replies ? */
395 spin_lock(&GlobalMid_Lock);
396 lrt = ses->server->lstrp;
397 spin_unlock(&GlobalMid_Lock);
398
399 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000400 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000401 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000402 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000403 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000404 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000405 other threads on the client within 10 seconds */
406 lrt += time_to_wait;
407 if (time_after(jiffies, lrt)) {
408 /* No replies for time_to_wait. */
Steve French79a58d12007-07-06 22:44:50 +0000409 cERROR(1, ("server not responding"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000410 return -1;
411 }
412 } else {
413 return 0;
414 }
415 }
416}
417
Steve French133672e2007-11-13 22:41:37 +0000418
419/*
420 *
421 * Send an SMB Request. No response info (other than return code)
422 * needs to be parsed.
423 *
424 * flags indicate the type of request buffer and how long to wait
425 * and whether to log NT STATUS code (error) before mapping it to POSIX error
426 *
427 */
428int
429SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
430 struct smb_hdr *in_buf, int flags)
431{
432 int rc;
433 struct kvec iov[1];
434 int resp_buf_type;
435
436 iov[0].iov_base = (char *)in_buf;
437 iov[0].iov_len = in_buf->smb_buf_length + 4;
438 flags |= CIFS_NO_RESP;
439 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Steve French90c81e02008-02-12 20:32:36 +0000440 cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));
441
Steve French133672e2007-11-13 22:41:37 +0000442 return rc;
443}
444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445int
Steve French79a58d12007-07-06 22:44:50 +0000446SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
447 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000448 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000451 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500452 unsigned int receive_len;
453 unsigned long timeout;
454 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700455 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000456
Steve French133672e2007-11-13 22:41:37 +0000457 long_op = flags & CIFS_TIMEOUT_MASK;
458
Steve Frenchec637e32005-12-12 20:53:18 -0800459 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Steve French4b8f9302006-02-26 16:41:18 +0000461 if ((ses == NULL) || (ses->server == NULL)) {
462 cifs_small_buf_release(in_buf);
Steve French79a58d12007-07-06 22:44:50 +0000463 cERROR(1, ("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 return -EIO;
465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Steve French79a58d12007-07-06 22:44:50 +0000467 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000468 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700469 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000470 }
Steve French31ca3bc2005-04-28 22:41:11 -0700471
Steve French79a58d12007-07-06 22:44:50 +0000472 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 to the same server. We may make this configurable later or
474 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000476 rc = wait_for_free_request(ses, long_op);
477 if (rc) {
478 cifs_small_buf_release(in_buf);
479 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000481
Steve French79a58d12007-07-06 22:44:50 +0000482 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 and avoid races inside tcp sendmsg code that could cause corruption
484 of smb data */
485
Steve French79a58d12007-07-06 22:44:50 +0000486 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000488 rc = allocate_mid(ses, in_buf, &midQ);
489 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 up(&ses->server->tcpSem);
Steve French4b8f9302006-02-26 16:41:18 +0000491 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000492 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000493 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000494 wake_up(&ses->server->request_q);
495 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 }
Steve French79a58d12007-07-06 22:44:50 +0000497 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700500#ifdef CONFIG_CIFS_STATS2
501 atomic_inc(&ses->server->inSend);
502#endif
Steve French3e844692005-10-03 13:37:24 -0700503 rc = smb_send2(ses->server->ssocket, iov, n_vec,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500504 (struct sockaddr *) &(ses->server->addr.sockAddr));
Steve French131afd0b2005-10-07 09:51:05 -0700505#ifdef CONFIG_CIFS_STATS2
506 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700507 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700508#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000509
510 up(&ses->server->tcpSem);
511 cifs_small_buf_release(in_buf);
512
Steve French79a58d12007-07-06 22:44:50 +0000513 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000514 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000515
Steve French133672e2007-11-13 22:41:37 +0000516 if (long_op == CIFS_STD_OP)
517 timeout = 15 * HZ;
518 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700519 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000520 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000521 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500522 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000523 else if (long_op == CIFS_ASYNC_OP)
524 goto out;
525 else if (long_op == CIFS_BLOCKING_OP)
526 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
527 else {
528 cERROR(1, ("unknown timeout flag %d", long_op));
529 rc = -EIO;
530 goto out;
531 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000532
Steve French79a58d12007-07-06 22:44:50 +0000533 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500534 due to last connection to this server being unmounted */
535 if (signal_pending(current)) {
536 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000537 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500538 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000539 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500540
541 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000542 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500543
544 spin_lock(&GlobalMid_Lock);
545 if (midQ->resp_buf) {
546 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700547 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500548 } else {
Steve French79a58d12007-07-06 22:44:50 +0000549 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700550 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000551 if (midQ->midState == MID_REQUEST_SUBMITTED) {
552 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500553 rc = -EHOSTDOWN;
554 else {
555 ses->server->tcpStatus = CifsNeedReconnect;
556 midQ->midState = MID_RETRY_NEEDED;
557 }
558 }
559
560 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000561 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500562 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000563 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500564 } else {
565 rc = -EIO;
566 }
567 }
568 spin_unlock(&GlobalMid_Lock);
569 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000570 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000571 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000572 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500573 return rc;
574 }
Steve French50c2f752007-07-13 00:33:32 +0000575
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500576 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
577 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
578 receive_len, xid));
579 rc = -EIO;
580 } else { /* rcvd frame is ok */
Steve French79a58d12007-07-06 22:44:50 +0000581 if (midQ->resp_buf &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500582 (midQ->midState == MID_RESPONSE_RECEIVED)) {
Steve French84afc292005-12-02 13:32:45 -0800583
Steve Frenchec637e32005-12-12 20:53:18 -0800584 iov[0].iov_base = (char *)midQ->resp_buf;
Steve French79a58d12007-07-06 22:44:50 +0000585 if (midQ->largeBuf)
Steve Frenchec637e32005-12-12 20:53:18 -0800586 *pRespBufType = CIFS_LARGE_BUFFER;
587 else
588 *pRespBufType = CIFS_SMALL_BUFFER;
589 iov[0].iov_len = receive_len + 4;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500590
Steve Frenchec637e32005-12-12 20:53:18 -0800591 dump_smb(midQ->resp_buf, 80);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500592 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000593 if ((receive_len > 24) &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500594 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
595 SECMODE_SIGN_ENABLED))) {
Steve Frenchec637e32005-12-12 20:53:18 -0800596 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000597 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500598 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000599 if (rc) {
600 cERROR(1, ("Unexpected SMB signature"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500601 /* BB FIXME add code to kill session */
602 }
603 }
604
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500605 /* BB special case reconnect tid and uid here? */
Steve French133672e2007-11-13 22:41:37 +0000606 rc = map_smb_to_linux_error(midQ->resp_buf,
607 flags & CIFS_LOG_ERROR);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500608
609 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000610 if (receive_len >= sizeof(struct smb_hdr) - 4
611 /* do not count RFC1001 header */ +
Steve Frenchec637e32005-12-12 20:53:18 -0800612 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
Steve French79a58d12007-07-06 22:44:50 +0000613 BCC(midQ->resp_buf) =
Steve Frenchec637e32005-12-12 20:53:18 -0800614 le16_to_cpu(BCC_LE(midQ->resp_buf));
Steve French133672e2007-11-13 22:41:37 +0000615 if ((flags & CIFS_NO_RESP) == 0)
616 midQ->resp_buf = NULL; /* mark it so buf will
617 not be freed by
618 DeleteMidQEntry */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500619 } else {
620 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000621 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500622 }
623 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000624
625out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500626 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000627 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000628 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 return rc;
631}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633int
634SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
635 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
636 int *pbytes_returned, const int long_op)
637{
638 int rc = 0;
639 unsigned int receive_len;
640 unsigned long timeout;
641 struct mid_q_entry *midQ;
642
643 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000644 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return -EIO;
646 }
Steve French79a58d12007-07-06 22:44:50 +0000647 if (ses->server == NULL) {
648 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 return -EIO;
650 }
651
Steve French79a58d12007-07-06 22:44:50 +0000652 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700653 return -ENOENT;
654
Steve French79a58d12007-07-06 22:44:50 +0000655 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 to the same server. We may make this configurable later or
657 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000659 rc = wait_for_free_request(ses, long_op);
660 if (rc)
661 return rc;
662
Steve French79a58d12007-07-06 22:44:50 +0000663 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 and avoid races inside tcp sendmsg code that could cause corruption
665 of smb data */
666
Steve French79a58d12007-07-06 22:44:50 +0000667 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000669 rc = allocate_mid(ses, in_buf, &midQ);
670 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000672 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000673 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000674 wake_up(&ses->server->request_q);
675 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 }
677
678 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Steve French26a21b92006-05-31 18:05:34 +0000679 cERROR(1, ("Illegal length, greater than maximum frame, %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 in_buf->smb_buf_length));
681 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000682 up(&ses->server->tcpSem);
683 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000684 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000685 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return -EIO;
687 }
688
Steve Frenchad009ac2005-04-28 22:41:05 -0700689 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700692#ifdef CONFIG_CIFS_STATS2
693 atomic_inc(&ses->server->inSend);
694#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
696 (struct sockaddr *) &(ses->server->addr.sockAddr));
Steve French131afd0b2005-10-07 09:51:05 -0700697#ifdef CONFIG_CIFS_STATS2
698 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700699 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700700#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000701 up(&ses->server->tcpSem);
702
Steve French79a58d12007-07-06 22:44:50 +0000703 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000704 goto out;
705
Steve French133672e2007-11-13 22:41:37 +0000706 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000708 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000710 else if (long_op == CIFS_ASYNC_OP)
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)
715 timeout = 45 * HZ; /* should be greater than
716 servers oplock break timeout (about 43 seconds) */
717 else if (long_op == CIFS_BLOCKING_OP)
718 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
719 else {
720 cERROR(1, ("unknown timeout flag %d", long_op));
721 rc = -EIO;
722 goto out;
723 }
724
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 if (signal_pending(current)) {
726 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000727 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
731 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000732 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 spin_lock(&GlobalMid_Lock);
735 if (midQ->resp_buf) {
736 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700737 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 } else {
Steve French79a58d12007-07-06 22:44:50 +0000739 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700740 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000741 if (midQ->midState == MID_REQUEST_SUBMITTED) {
742 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 rc = -EHOSTDOWN;
744 else {
745 ses->server->tcpStatus = CifsNeedReconnect;
746 midQ->midState = MID_RETRY_NEEDED;
747 }
748 }
749
750 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000751 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000753 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 } else {
755 rc = -EIO;
756 }
757 }
758 spin_unlock(&GlobalMid_Lock);
759 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000760 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000761 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000762 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return rc;
764 }
Steve French50c2f752007-07-13 00:33:32 +0000765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700767 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 receive_len, xid));
769 rc = -EIO;
770 } else { /* rcvd frame is ok */
771
772 if (midQ->resp_buf && out_buf
773 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
774 out_buf->smb_buf_length = receive_len;
775 memcpy((char *)out_buf + 4,
776 (char *)midQ->resp_buf + 4,
777 receive_len);
778
779 dump_smb(out_buf, 92);
780 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000781 if ((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700782 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
783 SECMODE_SIGN_ENABLED))) {
784 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000785 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700786 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000787 if (rc) {
788 cERROR(1, ("Unexpected SMB signature"));
Steve French275cde12005-04-28 22:41:10 -0700789 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
792
793 *pbytes_returned = out_buf->smb_buf_length;
794
Steve Frenchad009ac2005-04-28 22:41:05 -0700795 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +0000796 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000799 if (receive_len >= sizeof(struct smb_hdr) - 4
800 /* do not count RFC1001 header */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 (2 * out_buf->WordCount) + 2 /* bcc */ )
Steve French0f2b27c2005-11-16 14:25:50 -0800802 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 } else {
804 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000805 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000809out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000810 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000811 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000812 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000815}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000817/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
818
819static int
820send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
821 struct mid_q_entry *midQ)
822{
823 int rc = 0;
824 struct cifsSesInfo *ses = tcon->ses;
825 __u16 mid = in_buf->Mid;
826
827 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
828 in_buf->Mid = mid;
Steve French79a58d12007-07-06 22:44:50 +0000829 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000830 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
831 if (rc) {
832 up(&ses->server->tcpSem);
833 return rc;
834 }
835 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
836 (struct sockaddr *) &(ses->server->addr.sockAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000838 return rc;
839}
840
841/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
842 blocking lock to return. */
843
844static int
845send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
846 struct smb_hdr *in_buf,
847 struct smb_hdr *out_buf)
848{
849 int bytes_returned;
850 struct cifsSesInfo *ses = tcon->ses;
851 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
852
853 /* We just modify the current in_buf to change
854 the type of lock from LOCKING_ANDX_SHARED_LOCK
855 or LOCKING_ANDX_EXCLUSIVE_LOCK to
856 LOCKING_ANDX_CANCEL_LOCK. */
857
858 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
859 pSMB->Timeout = 0;
860 pSMB->hdr.Mid = GetNextMid(ses->server);
861
862 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000863 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000864}
865
866int
867SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
868 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
869 int *pbytes_returned)
870{
871 int rc = 0;
872 int rstart = 0;
873 unsigned int receive_len;
874 struct mid_q_entry *midQ;
875 struct cifsSesInfo *ses;
876
877 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000878 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000879 return -EIO;
880 }
881 ses = tcon->ses;
882
Steve French79a58d12007-07-06 22:44:50 +0000883 if (ses->server == NULL) {
884 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000885 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 }
887
Steve French79a58d12007-07-06 22:44:50 +0000888 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000889 return -ENOENT;
890
Steve French79a58d12007-07-06 22:44:50 +0000891 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000892 to the same server. We may make this configurable later or
893 use ses->maxReq */
894
Steve French133672e2007-11-13 22:41:37 +0000895 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000896 if (rc)
897 return rc;
898
Steve French79a58d12007-07-06 22:44:50 +0000899 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000900 and avoid races inside tcp sendmsg code that could cause corruption
901 of smb data */
902
Steve French79a58d12007-07-06 22:44:50 +0000903 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000904
905 rc = allocate_mid(ses, in_buf, &midQ);
906 if (rc) {
907 up(&ses->server->tcpSem);
908 return rc;
909 }
910
911 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
912 up(&ses->server->tcpSem);
913 cERROR(1, ("Illegal length, greater than maximum frame, %d",
914 in_buf->smb_buf_length));
915 DeleteMidQEntry(midQ);
916 return -EIO;
917 }
918
919 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
920
921 midQ->midState = MID_REQUEST_SUBMITTED;
922#ifdef CONFIG_CIFS_STATS2
923 atomic_inc(&ses->server->inSend);
924#endif
925 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
926 (struct sockaddr *) &(ses->server->addr.sockAddr));
927#ifdef CONFIG_CIFS_STATS2
928 atomic_dec(&ses->server->inSend);
929 midQ->when_sent = jiffies;
930#endif
931 up(&ses->server->tcpSem);
932
Steve French79a58d12007-07-06 22:44:50 +0000933 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000934 DeleteMidQEntry(midQ);
935 return rc;
936 }
937
938 /* Wait for a reply - allow signals to interrupt. */
939 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000940 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000941 ((ses->server->tcpStatus != CifsGood) &&
942 (ses->server->tcpStatus != CifsNew)));
943
944 /* Were we interrupted by a signal ? */
945 if ((rc == -ERESTARTSYS) &&
946 (midQ->midState == MID_REQUEST_SUBMITTED) &&
947 ((ses->server->tcpStatus == CifsGood) ||
948 (ses->server->tcpStatus == CifsNew))) {
949
950 if (in_buf->Command == SMB_COM_TRANSACTION2) {
951 /* POSIX lock. We send a NT_CANCEL SMB to cause the
952 blocking lock to return. */
953
954 rc = send_nt_cancel(tcon, in_buf, midQ);
955 if (rc) {
956 DeleteMidQEntry(midQ);
957 return rc;
958 }
959 } else {
960 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
961 to cause the blocking lock to return. */
962
963 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
964
965 /* If we get -ENOLCK back the lock may have
966 already been removed. Don't exit in this case. */
967 if (rc && rc != -ENOLCK) {
968 DeleteMidQEntry(midQ);
969 return rc;
970 }
971 }
972
973 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +0000974 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000975 /* We got the response - restart system call. */
976 rstart = 1;
977 }
978 }
979
980 spin_lock(&GlobalMid_Lock);
981 if (midQ->resp_buf) {
982 spin_unlock(&GlobalMid_Lock);
983 receive_len = midQ->resp_buf->smb_buf_length;
984 } else {
Steve French79a58d12007-07-06 22:44:50 +0000985 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000986 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000987 if (midQ->midState == MID_REQUEST_SUBMITTED) {
988 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000989 rc = -EHOSTDOWN;
990 else {
991 ses->server->tcpStatus = CifsNeedReconnect;
992 midQ->midState = MID_RETRY_NEEDED;
993 }
994 }
995
996 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000997 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000998 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000999 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001000 } else {
1001 rc = -EIO;
1002 }
1003 }
1004 spin_unlock(&GlobalMid_Lock);
1005 DeleteMidQEntry(midQ);
1006 return rc;
1007 }
Steve French50c2f752007-07-13 00:33:32 +00001008
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001009 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1010 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1011 receive_len, xid));
1012 rc = -EIO;
1013 } else { /* rcvd frame is ok */
1014
1015 if (midQ->resp_buf && out_buf
1016 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
1017 out_buf->smb_buf_length = receive_len;
1018 memcpy((char *)out_buf + 4,
1019 (char *)midQ->resp_buf + 4,
1020 receive_len);
1021
1022 dump_smb(out_buf, 92);
1023 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +00001024 if ((receive_len > 24) &&
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001025 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1026 SECMODE_SIGN_ENABLED))) {
1027 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +00001028 &ses->server->mac_signing_key,
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001029 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +00001030 if (rc) {
1031 cERROR(1, ("Unexpected SMB signature"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001032 /* BB FIXME add code to kill session */
1033 }
1034 }
1035
1036 *pbytes_returned = out_buf->smb_buf_length;
1037
1038 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +00001039 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001040
1041 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +00001042 if (receive_len >= sizeof(struct smb_hdr) - 4
1043 /* do not count RFC1001 header */ +
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001044 (2 * out_buf->WordCount) + 2 /* bcc */ )
1045 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1046 } else {
1047 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +00001048 cERROR(1, ("Bad MID state?"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001049 }
1050 }
1051 DeleteMidQEntry(midQ);
1052 if (rstart && rc == -EACCES)
1053 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 return rc;
1055}