blob: e286db9f5ee2c66d34b0c3c4deedf851b18b7687 [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
Steve French5d941ca2008-04-15 18:40:48 +0000145
146void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
147{
148 struct oplock_q_entry *temp;
149
150 if (tcon == NULL)
151 return;
152
153 spin_lock(&GlobalMid_Lock);
154 list_for_each_entry(temp, &GlobalOplock_Q, qhead) {
155 if ((temp->tcon) && (temp->tcon == tcon)) {
156 list_del(&temp->qhead);
157 kmem_cache_free(cifs_oplock_cachep, temp);
158 }
159 }
160 spin_unlock(&GlobalMid_Lock);
161}
162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163int
164smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
165 unsigned int smb_buf_length, struct sockaddr *sin)
166{
167 int rc = 0;
168 int i = 0;
169 struct msghdr smb_msg;
170 struct kvec iov;
171 unsigned len = smb_buf_length + 4;
172
Steve French79a58d12007-07-06 22:44:50 +0000173 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 return -ENOTSOCK; /* BB eventually add reconnect code here */
175 iov.iov_base = smb_buffer;
176 iov.iov_len = len;
177
178 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000179 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 smb_msg.msg_control = NULL;
181 smb_msg.msg_controllen = 0;
182 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
183
184 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000185 area, and byte area if necessary, is converted to littleendian in
186 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 Flags2 is converted in SendReceive */
188
189 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700190 cFYI(1, ("Sending smb of length %d", smb_buf_length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 dump_smb(smb_buffer, len);
192
193 while (len > 0) {
194 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
195 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
196 i++;
Steve French3e844692005-10-03 13:37:24 -0700197 /* smaller timeout here than send2 since smaller size */
Steve French79a58d12007-07-06 22:44:50 +0000198 /* Although it may not be required, this also is smaller
199 oplock break time */
200 if (i > 12) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700202 ("sends on sock %p stuck for 7 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 ssocket));
204 rc = -EAGAIN;
205 break;
206 }
Steve French68058e72005-10-10 10:34:22 -0700207 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 continue;
209 }
Steve French79a58d12007-07-06 22:44:50 +0000210 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 break;
Steve French5e1253b2005-10-10 14:06:37 -0700212 else
213 i = 0; /* reset i after each successful send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 iov.iov_base += rc;
215 iov.iov_len -= rc;
216 len -= rc;
217 }
218
219 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000220 cERROR(1, ("Error %d sending data on socket to server", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 } else {
222 rc = 0;
223 }
224
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000225 /* Don't want to modify the buffer as a
226 side effect of this call. */
227 smb_buffer->smb_buf_length = smb_buf_length;
228
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 return rc;
230}
231
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500232static int
Steve French3e844692005-10-03 13:37:24 -0700233smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
234 struct sockaddr *sin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235{
236 int rc = 0;
237 int i = 0;
238 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700239 struct smb_hdr *smb_buffer = iov[0].iov_base;
240 unsigned int len = iov[0].iov_len;
241 unsigned int total_len;
242 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000243 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve French50c2f752007-07-13 00:33:32 +0000244
Steve French79a58d12007-07-06 22:44:50 +0000245 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000249 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 smb_msg.msg_control = NULL;
251 smb_msg.msg_controllen = 0;
252 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
253
254 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000255 area, and byte area if necessary, is converted to littleendian in
256 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 Flags2 is converted in SendReceive */
258
Steve French3e844692005-10-03 13:37:24 -0700259
260 total_len = 0;
261 for (i = 0; i < n_vec; i++)
262 total_len += iov[i].iov_len;
263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700265 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 dump_smb(smb_buffer, len);
267
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000268 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700269 while (total_len) {
270 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
271 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
273 i++;
Steve French79a58d12007-07-06 22:44:50 +0000274 if (i >= 14) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700276 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 ssocket));
278 rc = -EAGAIN;
279 break;
280 }
Steve French68058e72005-10-10 10:34:22 -0700281 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 continue;
283 }
Steve French79a58d12007-07-06 22:44:50 +0000284 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 break;
Steve French3e844692005-10-03 13:37:24 -0700286
287 if (rc >= total_len) {
288 WARN_ON(rc > total_len);
289 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500290 }
Steve French79a58d12007-07-06 22:44:50 +0000291 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700292 /* should never happen, letting socket clear before
293 retrying is our only obvious option here */
Steve French79a58d12007-07-06 22:44:50 +0000294 cERROR(1, ("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700295 msleep(500);
296 continue;
297 }
298 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700299 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700300 for (i = first_vec; i < n_vec; i++) {
301 if (iov[i].iov_len) {
302 if (rc > iov[i].iov_len) {
303 rc -= iov[i].iov_len;
304 iov[i].iov_len = 0;
305 } else {
306 iov[i].iov_base += rc;
307 iov[i].iov_len -= rc;
308 first_vec = i;
309 break;
310 }
311 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500312 }
Steve French5e1253b2005-10-10 14:06:37 -0700313 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 }
315
316 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000317 cERROR(1, ("Error %d sending data on socket to server", rc));
Steve French3e844692005-10-03 13:37:24 -0700318 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000321 /* Don't want to modify the buffer as a
322 side effect of this call. */
323 smb_buffer->smb_buf_length = smb_buf_length;
324
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 return rc;
326}
327
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000328static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
329{
Steve French133672e2007-11-13 22:41:37 +0000330 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000331 /* oplock breaks must not be held up */
332 atomic_inc(&ses->server->inFlight);
333 } else {
Steve French79a58d12007-07-06 22:44:50 +0000334 spin_lock(&GlobalMid_Lock);
335 while (1) {
336 if (atomic_read(&ses->server->inFlight) >=
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000337 cifs_max_pending){
338 spin_unlock(&GlobalMid_Lock);
339#ifdef CONFIG_CIFS_STATS2
340 atomic_inc(&ses->server->num_waiters);
341#endif
342 wait_event(ses->server->request_q,
343 atomic_read(&ses->server->inFlight)
344 < cifs_max_pending);
345#ifdef CONFIG_CIFS_STATS2
346 atomic_dec(&ses->server->num_waiters);
347#endif
348 spin_lock(&GlobalMid_Lock);
349 } else {
Steve French79a58d12007-07-06 22:44:50 +0000350 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000351 spin_unlock(&GlobalMid_Lock);
352 return -ENOENT;
353 }
354
Steve French79a58d12007-07-06 22:44:50 +0000355 /* can not count locking commands against total
356 as they are allowed to block on server */
Steve French50c2f752007-07-13 00:33:32 +0000357
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000358 /* update # of requests on the wire to server */
Steve French133672e2007-11-13 22:41:37 +0000359 if (long_op != CIFS_BLOCKING_OP)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000360 atomic_inc(&ses->server->inFlight);
361 spin_unlock(&GlobalMid_Lock);
362 break;
363 }
364 }
365 }
366 return 0;
367}
368
369static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
370 struct mid_q_entry **ppmidQ)
371{
372 if (ses->server->tcpStatus == CifsExiting) {
373 return -ENOENT;
374 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
Steve French79a58d12007-07-06 22:44:50 +0000375 cFYI(1, ("tcp session dead - return to caller to retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000376 return -EAGAIN;
377 } else if (ses->status != CifsGood) {
378 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000379 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000380 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000381 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000382 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000383 }
384 *ppmidQ = AllocMidQEntry(in_buf, ses);
Steve French26f57362007-08-30 22:09:15 +0000385 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000386 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000387 return 0;
388}
389
Steve French79a58d12007-07-06 22:44:50 +0000390static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000391 struct mid_q_entry *midQ,
392 unsigned long timeout,
393 unsigned long time_to_wait)
394{
395 unsigned long curr_timeout;
396
397 for (;;) {
398 curr_timeout = timeout + jiffies;
399 wait_event(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000400 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
401 time_after(jiffies, curr_timeout) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000402 ((ses->server->tcpStatus != CifsGood) &&
403 (ses->server->tcpStatus != CifsNew)));
404
405 if (time_after(jiffies, curr_timeout) &&
406 (midQ->midState == MID_REQUEST_SUBMITTED) &&
407 ((ses->server->tcpStatus == CifsGood) ||
408 (ses->server->tcpStatus == CifsNew))) {
409
410 unsigned long lrt;
411
412 /* We timed out. Is the server still
413 sending replies ? */
414 spin_lock(&GlobalMid_Lock);
415 lrt = ses->server->lstrp;
416 spin_unlock(&GlobalMid_Lock);
417
418 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000419 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000420 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000421 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000422 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000423 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000424 other threads on the client within 10 seconds */
425 lrt += time_to_wait;
426 if (time_after(jiffies, lrt)) {
427 /* No replies for time_to_wait. */
Steve French79a58d12007-07-06 22:44:50 +0000428 cERROR(1, ("server not responding"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000429 return -1;
430 }
431 } else {
432 return 0;
433 }
434 }
435}
436
Steve French133672e2007-11-13 22:41:37 +0000437
438/*
439 *
440 * Send an SMB Request. No response info (other than return code)
441 * needs to be parsed.
442 *
443 * flags indicate the type of request buffer and how long to wait
444 * and whether to log NT STATUS code (error) before mapping it to POSIX error
445 *
446 */
447int
448SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
449 struct smb_hdr *in_buf, int flags)
450{
451 int rc;
452 struct kvec iov[1];
453 int resp_buf_type;
454
455 iov[0].iov_base = (char *)in_buf;
456 iov[0].iov_len = in_buf->smb_buf_length + 4;
457 flags |= CIFS_NO_RESP;
458 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Steve French90c81e02008-02-12 20:32:36 +0000459 cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));
460
Steve French133672e2007-11-13 22:41:37 +0000461 return rc;
462}
463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464int
Steve French79a58d12007-07-06 22:44:50 +0000465SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
466 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000467 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468{
469 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000470 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500471 unsigned int receive_len;
472 unsigned long timeout;
473 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700474 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000475
Steve French133672e2007-11-13 22:41:37 +0000476 long_op = flags & CIFS_TIMEOUT_MASK;
477
Steve Frenchec637e32005-12-12 20:53:18 -0800478 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Steve French4b8f9302006-02-26 16:41:18 +0000480 if ((ses == NULL) || (ses->server == NULL)) {
481 cifs_small_buf_release(in_buf);
Steve French79a58d12007-07-06 22:44:50 +0000482 cERROR(1, ("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return -EIO;
484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
Steve French79a58d12007-07-06 22:44:50 +0000486 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000487 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700488 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000489 }
Steve French31ca3bc2005-04-28 22:41:11 -0700490
Steve French79a58d12007-07-06 22:44:50 +0000491 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 to the same server. We may make this configurable later or
493 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000495 rc = wait_for_free_request(ses, long_op);
496 if (rc) {
497 cifs_small_buf_release(in_buf);
498 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000500
Steve French79a58d12007-07-06 22:44:50 +0000501 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 and avoid races inside tcp sendmsg code that could cause corruption
503 of smb data */
504
Steve French79a58d12007-07-06 22:44:50 +0000505 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000507 rc = allocate_mid(ses, in_buf, &midQ);
508 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 up(&ses->server->tcpSem);
Steve French4b8f9302006-02-26 16:41:18 +0000510 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000511 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000512 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000513 wake_up(&ses->server->request_q);
514 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
Steve French79a58d12007-07-06 22:44:50 +0000516 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700519#ifdef CONFIG_CIFS_STATS2
520 atomic_inc(&ses->server->inSend);
521#endif
Steve French3e844692005-10-03 13:37:24 -0700522 rc = smb_send2(ses->server->ssocket, iov, n_vec,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500523 (struct sockaddr *) &(ses->server->addr.sockAddr));
Steve French131afd0b2005-10-07 09:51:05 -0700524#ifdef CONFIG_CIFS_STATS2
525 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700526 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700527#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000528
529 up(&ses->server->tcpSem);
530 cifs_small_buf_release(in_buf);
531
Steve French79a58d12007-07-06 22:44:50 +0000532 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000533 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000534
Steve French133672e2007-11-13 22:41:37 +0000535 if (long_op == CIFS_STD_OP)
536 timeout = 15 * HZ;
537 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700538 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000539 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000540 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500541 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000542 else if (long_op == CIFS_ASYNC_OP)
543 goto out;
544 else if (long_op == CIFS_BLOCKING_OP)
545 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
546 else {
547 cERROR(1, ("unknown timeout flag %d", long_op));
548 rc = -EIO;
549 goto out;
550 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000551
Steve French79a58d12007-07-06 22:44:50 +0000552 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500553 due to last connection to this server being unmounted */
554 if (signal_pending(current)) {
555 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000556 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500557 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000558 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500559
560 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000561 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500562
563 spin_lock(&GlobalMid_Lock);
564 if (midQ->resp_buf) {
565 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700566 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500567 } else {
Steve French79a58d12007-07-06 22:44:50 +0000568 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700569 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000570 if (midQ->midState == MID_REQUEST_SUBMITTED) {
571 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500572 rc = -EHOSTDOWN;
573 else {
574 ses->server->tcpStatus = CifsNeedReconnect;
575 midQ->midState = MID_RETRY_NEEDED;
576 }
577 }
578
579 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000580 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500581 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000582 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500583 } else {
584 rc = -EIO;
585 }
586 }
587 spin_unlock(&GlobalMid_Lock);
588 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000589 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000590 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000591 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500592 return rc;
593 }
Steve French50c2f752007-07-13 00:33:32 +0000594
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500595 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
596 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
597 receive_len, xid));
598 rc = -EIO;
599 } else { /* rcvd frame is ok */
Steve French79a58d12007-07-06 22:44:50 +0000600 if (midQ->resp_buf &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500601 (midQ->midState == MID_RESPONSE_RECEIVED)) {
Steve French84afc292005-12-02 13:32:45 -0800602
Steve Frenchec637e32005-12-12 20:53:18 -0800603 iov[0].iov_base = (char *)midQ->resp_buf;
Steve French79a58d12007-07-06 22:44:50 +0000604 if (midQ->largeBuf)
Steve Frenchec637e32005-12-12 20:53:18 -0800605 *pRespBufType = CIFS_LARGE_BUFFER;
606 else
607 *pRespBufType = CIFS_SMALL_BUFFER;
608 iov[0].iov_len = receive_len + 4;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500609
Steve Frenchec637e32005-12-12 20:53:18 -0800610 dump_smb(midQ->resp_buf, 80);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500611 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000612 if ((receive_len > 24) &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500613 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
614 SECMODE_SIGN_ENABLED))) {
Steve Frenchec637e32005-12-12 20:53:18 -0800615 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000616 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500617 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000618 if (rc) {
619 cERROR(1, ("Unexpected SMB signature"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500620 /* BB FIXME add code to kill session */
621 }
622 }
623
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500624 /* BB special case reconnect tid and uid here? */
Steve French133672e2007-11-13 22:41:37 +0000625 rc = map_smb_to_linux_error(midQ->resp_buf,
626 flags & CIFS_LOG_ERROR);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500627
628 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000629 if (receive_len >= sizeof(struct smb_hdr) - 4
630 /* do not count RFC1001 header */ +
Steve Frenchec637e32005-12-12 20:53:18 -0800631 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
Steve French79a58d12007-07-06 22:44:50 +0000632 BCC(midQ->resp_buf) =
Steve Frenchec637e32005-12-12 20:53:18 -0800633 le16_to_cpu(BCC_LE(midQ->resp_buf));
Steve French133672e2007-11-13 22:41:37 +0000634 if ((flags & CIFS_NO_RESP) == 0)
635 midQ->resp_buf = NULL; /* mark it so buf will
636 not be freed by
637 DeleteMidQEntry */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500638 } else {
639 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000640 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500641 }
642 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000643
644out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500645 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000646 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000647 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 return rc;
650}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652int
653SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
654 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
655 int *pbytes_returned, const int long_op)
656{
657 int rc = 0;
658 unsigned int receive_len;
659 unsigned long timeout;
660 struct mid_q_entry *midQ;
661
662 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000663 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 return -EIO;
665 }
Steve French79a58d12007-07-06 22:44:50 +0000666 if (ses->server == NULL) {
667 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 return -EIO;
669 }
670
Steve French79a58d12007-07-06 22:44:50 +0000671 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700672 return -ENOENT;
673
Steve French79a58d12007-07-06 22:44:50 +0000674 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 to the same server. We may make this configurable later or
676 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000678 rc = wait_for_free_request(ses, long_op);
679 if (rc)
680 return rc;
681
Steve French79a58d12007-07-06 22:44:50 +0000682 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 and avoid races inside tcp sendmsg code that could cause corruption
684 of smb data */
685
Steve French79a58d12007-07-06 22:44:50 +0000686 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000688 rc = allocate_mid(ses, in_buf, &midQ);
689 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000691 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000692 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000693 wake_up(&ses->server->request_q);
694 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
696
697 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Steve French26a21b92006-05-31 18:05:34 +0000698 cERROR(1, ("Illegal length, greater than maximum frame, %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 in_buf->smb_buf_length));
700 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000701 up(&ses->server->tcpSem);
702 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000703 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000704 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return -EIO;
706 }
707
Steve Frenchad009ac2005-04-28 22:41:05 -0700708 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700711#ifdef CONFIG_CIFS_STATS2
712 atomic_inc(&ses->server->inSend);
713#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
715 (struct sockaddr *) &(ses->server->addr.sockAddr));
Steve French131afd0b2005-10-07 09:51:05 -0700716#ifdef CONFIG_CIFS_STATS2
717 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700718 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700719#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000720 up(&ses->server->tcpSem);
721
Steve French79a58d12007-07-06 22:44:50 +0000722 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000723 goto out;
724
Steve French133672e2007-11-13 22:41:37 +0000725 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000727 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000729 else if (long_op == CIFS_ASYNC_OP)
730 goto out;
731 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
732 timeout = 180 * HZ;
733 else if (long_op == CIFS_LONG_OP)
734 timeout = 45 * HZ; /* should be greater than
735 servers oplock break timeout (about 43 seconds) */
736 else if (long_op == CIFS_BLOCKING_OP)
737 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
738 else {
739 cERROR(1, ("unknown timeout flag %d", long_op));
740 rc = -EIO;
741 goto out;
742 }
743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if (signal_pending(current)) {
745 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000746 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000751 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 spin_lock(&GlobalMid_Lock);
754 if (midQ->resp_buf) {
755 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700756 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 } else {
Steve French79a58d12007-07-06 22:44:50 +0000758 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700759 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000760 if (midQ->midState == MID_REQUEST_SUBMITTED) {
761 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 rc = -EHOSTDOWN;
763 else {
764 ses->server->tcpStatus = CifsNeedReconnect;
765 midQ->midState = MID_RETRY_NEEDED;
766 }
767 }
768
769 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000770 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000772 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 } else {
774 rc = -EIO;
775 }
776 }
777 spin_unlock(&GlobalMid_Lock);
778 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000779 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000780 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000781 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return rc;
783 }
Steve French50c2f752007-07-13 00:33:32 +0000784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700786 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 receive_len, xid));
788 rc = -EIO;
789 } else { /* rcvd frame is ok */
790
791 if (midQ->resp_buf && out_buf
792 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
793 out_buf->smb_buf_length = receive_len;
794 memcpy((char *)out_buf + 4,
795 (char *)midQ->resp_buf + 4,
796 receive_len);
797
798 dump_smb(out_buf, 92);
799 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000800 if ((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700801 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
802 SECMODE_SIGN_ENABLED))) {
803 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000804 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700805 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000806 if (rc) {
807 cERROR(1, ("Unexpected SMB signature"));
Steve French275cde12005-04-28 22:41:10 -0700808 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 }
811
812 *pbytes_returned = out_buf->smb_buf_length;
813
Steve Frenchad009ac2005-04-28 22:41:05 -0700814 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +0000815 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000818 if (receive_len >= sizeof(struct smb_hdr) - 4
819 /* do not count RFC1001 header */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 (2 * out_buf->WordCount) + 2 /* bcc */ )
Steve French0f2b27c2005-11-16 14:25:50 -0800821 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 } else {
823 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000824 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 }
826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000828out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000829 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000830 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000831 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000834}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000836/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
837
838static int
839send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
840 struct mid_q_entry *midQ)
841{
842 int rc = 0;
843 struct cifsSesInfo *ses = tcon->ses;
844 __u16 mid = in_buf->Mid;
845
846 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
847 in_buf->Mid = mid;
Steve French79a58d12007-07-06 22:44:50 +0000848 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000849 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
850 if (rc) {
851 up(&ses->server->tcpSem);
852 return rc;
853 }
854 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
855 (struct sockaddr *) &(ses->server->addr.sockAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000857 return rc;
858}
859
860/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
861 blocking lock to return. */
862
863static int
864send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
865 struct smb_hdr *in_buf,
866 struct smb_hdr *out_buf)
867{
868 int bytes_returned;
869 struct cifsSesInfo *ses = tcon->ses;
870 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
871
872 /* We just modify the current in_buf to change
873 the type of lock from LOCKING_ANDX_SHARED_LOCK
874 or LOCKING_ANDX_EXCLUSIVE_LOCK to
875 LOCKING_ANDX_CANCEL_LOCK. */
876
877 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
878 pSMB->Timeout = 0;
879 pSMB->hdr.Mid = GetNextMid(ses->server);
880
881 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000882 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000883}
884
885int
886SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
887 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
888 int *pbytes_returned)
889{
890 int rc = 0;
891 int rstart = 0;
892 unsigned int receive_len;
893 struct mid_q_entry *midQ;
894 struct cifsSesInfo *ses;
895
896 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000897 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000898 return -EIO;
899 }
900 ses = tcon->ses;
901
Steve French79a58d12007-07-06 22:44:50 +0000902 if (ses->server == NULL) {
903 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000904 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
906
Steve French79a58d12007-07-06 22:44:50 +0000907 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000908 return -ENOENT;
909
Steve French79a58d12007-07-06 22:44:50 +0000910 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000911 to the same server. We may make this configurable later or
912 use ses->maxReq */
913
Steve French133672e2007-11-13 22:41:37 +0000914 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000915 if (rc)
916 return rc;
917
Steve French79a58d12007-07-06 22:44:50 +0000918 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000919 and avoid races inside tcp sendmsg code that could cause corruption
920 of smb data */
921
Steve French79a58d12007-07-06 22:44:50 +0000922 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000923
924 rc = allocate_mid(ses, in_buf, &midQ);
925 if (rc) {
926 up(&ses->server->tcpSem);
927 return rc;
928 }
929
930 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
931 up(&ses->server->tcpSem);
932 cERROR(1, ("Illegal length, greater than maximum frame, %d",
933 in_buf->smb_buf_length));
934 DeleteMidQEntry(midQ);
935 return -EIO;
936 }
937
938 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
939
940 midQ->midState = MID_REQUEST_SUBMITTED;
941#ifdef CONFIG_CIFS_STATS2
942 atomic_inc(&ses->server->inSend);
943#endif
944 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
945 (struct sockaddr *) &(ses->server->addr.sockAddr));
946#ifdef CONFIG_CIFS_STATS2
947 atomic_dec(&ses->server->inSend);
948 midQ->when_sent = jiffies;
949#endif
950 up(&ses->server->tcpSem);
951
Steve French79a58d12007-07-06 22:44:50 +0000952 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000953 DeleteMidQEntry(midQ);
954 return rc;
955 }
956
957 /* Wait for a reply - allow signals to interrupt. */
958 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000959 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000960 ((ses->server->tcpStatus != CifsGood) &&
961 (ses->server->tcpStatus != CifsNew)));
962
963 /* Were we interrupted by a signal ? */
964 if ((rc == -ERESTARTSYS) &&
965 (midQ->midState == MID_REQUEST_SUBMITTED) &&
966 ((ses->server->tcpStatus == CifsGood) ||
967 (ses->server->tcpStatus == CifsNew))) {
968
969 if (in_buf->Command == SMB_COM_TRANSACTION2) {
970 /* POSIX lock. We send a NT_CANCEL SMB to cause the
971 blocking lock to return. */
972
973 rc = send_nt_cancel(tcon, in_buf, midQ);
974 if (rc) {
975 DeleteMidQEntry(midQ);
976 return rc;
977 }
978 } else {
979 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
980 to cause the blocking lock to return. */
981
982 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
983
984 /* If we get -ENOLCK back the lock may have
985 already been removed. Don't exit in this case. */
986 if (rc && rc != -ENOLCK) {
987 DeleteMidQEntry(midQ);
988 return rc;
989 }
990 }
991
992 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +0000993 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000994 /* We got the response - restart system call. */
995 rstart = 1;
996 }
997 }
998
999 spin_lock(&GlobalMid_Lock);
1000 if (midQ->resp_buf) {
1001 spin_unlock(&GlobalMid_Lock);
1002 receive_len = midQ->resp_buf->smb_buf_length;
1003 } else {
Steve French79a58d12007-07-06 22:44:50 +00001004 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001005 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +00001006 if (midQ->midState == MID_REQUEST_SUBMITTED) {
1007 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001008 rc = -EHOSTDOWN;
1009 else {
1010 ses->server->tcpStatus = CifsNeedReconnect;
1011 midQ->midState = MID_RETRY_NEEDED;
1012 }
1013 }
1014
1015 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +00001016 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001017 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +00001018 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001019 } else {
1020 rc = -EIO;
1021 }
1022 }
1023 spin_unlock(&GlobalMid_Lock);
1024 DeleteMidQEntry(midQ);
1025 return rc;
1026 }
Steve French50c2f752007-07-13 00:33:32 +00001027
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001028 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1029 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1030 receive_len, xid));
1031 rc = -EIO;
1032 } else { /* rcvd frame is ok */
1033
1034 if (midQ->resp_buf && out_buf
1035 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
1036 out_buf->smb_buf_length = receive_len;
1037 memcpy((char *)out_buf + 4,
1038 (char *)midQ->resp_buf + 4,
1039 receive_len);
1040
1041 dump_smb(out_buf, 92);
1042 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +00001043 if ((receive_len > 24) &&
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001044 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1045 SECMODE_SIGN_ENABLED))) {
1046 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +00001047 &ses->server->mac_signing_key,
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001048 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +00001049 if (rc) {
1050 cERROR(1, ("Unexpected SMB signature"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001051 /* BB FIXME add code to kill session */
1052 }
1053 }
1054
1055 *pbytes_returned = out_buf->smb_buf_length;
1056
1057 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +00001058 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001059
1060 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +00001061 if (receive_len >= sizeof(struct smb_hdr) - 4
1062 /* do not count RFC1001 header */ +
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001063 (2 * out_buf->WordCount) + 2 /* bcc */ )
1064 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1065 } else {
1066 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +00001067 cERROR(1, ("Bad MID state?"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001068 }
1069 }
1070 DeleteMidQEntry(midQ);
1071 if (rstart && rc == -EACCES)
1072 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 return rc;
1074}