blob: e104c1ad2da3d285ef89b434164a207e10a20c61 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/transport.c
3 *
Steve Frenchb8643e12005-04-28 22:41:07 -07004 * Copyright (C) International Business Machines Corp., 2002,2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <linux/fs.h>
23#include <linux/list.h>
24#include <linux/wait.h>
25#include <linux/net.h>
26#include <linux/delay.h>
27#include <asm/uaccess.h>
28#include <asm/processor.h>
29#include <linux/mempool.h>
30#include "cifspdu.h"
31#include "cifsglob.h"
32#include "cifsproto.h"
33#include "cifs_debug.h"
34
35extern mempool_t *cifs_mid_poolp;
36extern kmem_cache_t *cifs_oplock_cachep;
37
38static struct mid_q_entry *
39AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
40{
41 struct mid_q_entry *temp;
42
43 if (ses == NULL) {
Steve French275cde12005-04-28 22:41:10 -070044 cERROR(1, ("Null session passed in to AllocMidQEntry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 return NULL;
46 }
47 if (ses->server == NULL) {
48 cERROR(1, ("Null TCP session in AllocMidQEntry"));
49 return NULL;
50 }
51
Steve Frenchd6e04ae2005-06-13 13:24:43 -050052 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
53 SLAB_KERNEL | SLAB_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 if (temp == NULL)
55 return temp;
56 else {
57 memset(temp, 0, sizeof (struct mid_q_entry));
58 temp->mid = smb_buffer->Mid; /* always LE */
59 temp->pid = current->pid;
60 temp->command = smb_buffer->Command;
61 cFYI(1, ("For smb_command %d", temp->command));
62 do_gettimeofday(&temp->when_sent);
63 temp->ses = ses;
64 temp->tsk = current;
65 }
66
67 spin_lock(&GlobalMid_Lock);
68 list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
69 atomic_inc(&midCount);
70 temp->midState = MID_REQUEST_ALLOCATED;
71 spin_unlock(&GlobalMid_Lock);
72 return temp;
73}
74
75static void
76DeleteMidQEntry(struct mid_q_entry *midEntry)
77{
78 spin_lock(&GlobalMid_Lock);
79 midEntry->midState = MID_FREE;
80 list_del(&midEntry->qhead);
81 atomic_dec(&midCount);
82 spin_unlock(&GlobalMid_Lock);
Steve Frenchb8643e12005-04-28 22:41:07 -070083 if(midEntry->largeBuf)
84 cifs_buf_release(midEntry->resp_buf);
85 else
86 cifs_small_buf_release(midEntry->resp_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 mempool_free(midEntry, cifs_mid_poolp);
88}
89
90struct oplock_q_entry *
91AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
92{
93 struct oplock_q_entry *temp;
94 if ((pinode== NULL) || (tcon == NULL)) {
95 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
96 return NULL;
97 }
98 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
99 SLAB_KERNEL);
100 if (temp == NULL)
101 return temp;
102 else {
103 temp->pinode = pinode;
104 temp->tcon = tcon;
105 temp->netfid = fid;
106 spin_lock(&GlobalMid_Lock);
107 list_add_tail(&temp->qhead, &GlobalOplock_Q);
108 spin_unlock(&GlobalMid_Lock);
109 }
110 return temp;
111
112}
113
114void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
115{
116 spin_lock(&GlobalMid_Lock);
117 /* should we check if list empty first? */
118 list_del(&oplockEntry->qhead);
119 spin_unlock(&GlobalMid_Lock);
120 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
121}
122
123int
124smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
125 unsigned int smb_buf_length, struct sockaddr *sin)
126{
127 int rc = 0;
128 int i = 0;
129 struct msghdr smb_msg;
130 struct kvec iov;
131 unsigned len = smb_buf_length + 4;
132
133 if(ssocket == NULL)
134 return -ENOTSOCK; /* BB eventually add reconnect code here */
135 iov.iov_base = smb_buffer;
136 iov.iov_len = len;
137
138 smb_msg.msg_name = sin;
139 smb_msg.msg_namelen = sizeof (struct sockaddr);
140 smb_msg.msg_control = NULL;
141 smb_msg.msg_controllen = 0;
142 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
143
144 /* smb header is converted in header_assemble. bcc and rest of SMB word
145 area, and byte area if necessary, is converted to littleendian in
146 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
147 Flags2 is converted in SendReceive */
148
149 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700150 cFYI(1, ("Sending smb of length %d", smb_buf_length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 dump_smb(smb_buffer, len);
152
153 while (len > 0) {
154 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
155 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
156 i++;
Steve French3e844692005-10-03 13:37:24 -0700157 /* smaller timeout here than send2 since smaller size */
158 /* Although it may not be required, this also is smaller
159 oplock break time */
160 if(i > 30) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 cERROR(1,
Steve French3e844692005-10-03 13:37:24 -0700162 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 ssocket));
164 rc = -EAGAIN;
165 break;
166 }
167 msleep(500);
168 continue;
169 }
170 if (rc < 0)
171 break;
172 iov.iov_base += rc;
173 iov.iov_len -= rc;
174 len -= rc;
175 }
176
177 if (rc < 0) {
Steve French3e844692005-10-03 13:37:24 -0700178 cERROR(1,("Error %d sending data on socket to server", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 } else {
180 rc = 0;
181 }
182
183 return rc;
184}
185
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500186#ifdef CONFIG_CIFS_EXPERIMENTAL
187static int
Steve French3e844692005-10-03 13:37:24 -0700188smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
189 struct sockaddr *sin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
191 int rc = 0;
192 int i = 0;
193 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700194 struct smb_hdr *smb_buffer = iov[0].iov_base;
195 unsigned int len = iov[0].iov_len;
196 unsigned int total_len;
197 int first_vec = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 if(ssocket == NULL)
200 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 smb_msg.msg_name = sin;
203 smb_msg.msg_namelen = sizeof (struct sockaddr);
204 smb_msg.msg_control = NULL;
205 smb_msg.msg_controllen = 0;
206 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
207
208 /* smb header is converted in header_assemble. bcc and rest of SMB word
209 area, and byte area if necessary, is converted to littleendian in
210 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
211 Flags2 is converted in SendReceive */
212
Steve French3e844692005-10-03 13:37:24 -0700213
214 total_len = 0;
215 for (i = 0; i < n_vec; i++)
216 total_len += iov[i].iov_len;
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700219 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 dump_smb(smb_buffer, len);
221
Steve French3e844692005-10-03 13:37:24 -0700222 while (total_len) {
223 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
224 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
226 i++;
Steve French3e844692005-10-03 13:37:24 -0700227 if(i > 40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 cERROR(1,
Steve French3e844692005-10-03 13:37:24 -0700229 ("sends on sock %p stuck for 20 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 ssocket));
231 rc = -EAGAIN;
232 break;
233 }
234 msleep(500);
235 continue;
236 }
237 if (rc < 0)
238 break;
Steve French3e844692005-10-03 13:37:24 -0700239
240 if (rc >= total_len) {
241 WARN_ON(rc > total_len);
242 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500243 }
Steve French3e844692005-10-03 13:37:24 -0700244 if(rc == 0) {
245 /* should never happen, letting socket clear before
246 retrying is our only obvious option here */
Steve French04c08812005-10-03 19:33:15 -0700247 cERROR(1,("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700248 msleep(500);
249 continue;
250 }
251 total_len -= rc;
252 for (i = first_vec; i < n_vec; i++) {
253 if (iov[i].iov_len) {
254 if (rc > iov[i].iov_len) {
255 rc -= iov[i].iov_len;
256 iov[i].iov_len = 0;
257 } else {
258 iov[i].iov_base += rc;
259 iov[i].iov_len -= rc;
260 first_vec = i;
261 break;
262 }
263 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 }
266
267 if (rc < 0) {
Steve French3e844692005-10-03 13:37:24 -0700268 cERROR(1,("Error %d sending data on socket to server", rc));
269 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272 return rc;
273}
274
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275int
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500276SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
Steve French3e844692005-10-03 13:37:24 -0700277 struct kvec *iov, int n_vec, int *pbytes_returned,
278 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
280 int rc = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500281 unsigned int receive_len;
282 unsigned long timeout;
283 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700284 struct smb_hdr *in_buf = iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 if (ses == NULL) {
287 cERROR(1,("Null smb session"));
288 return -EIO;
289 }
290 if(ses->server == NULL) {
291 cERROR(1,("Null tcp session"));
292 return -EIO;
293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500295 if(ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700296 return -ENOENT;
297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 /* Ensure that we do not send more than 50 overlapping requests
299 to the same server. We may make this configurable later or
300 use ses->maxReq */
301 if(long_op == -1) {
302 /* oplock breaks must not be held up */
303 atomic_inc(&ses->server->inFlight);
304 } else {
305 spin_lock(&GlobalMid_Lock);
306 while(1) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500307 if(atomic_read(&ses->server->inFlight) >=
308 cifs_max_pending){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 spin_unlock(&GlobalMid_Lock);
310 wait_event(ses->server->request_q,
311 atomic_read(&ses->server->inFlight)
312 < cifs_max_pending);
313 spin_lock(&GlobalMid_Lock);
314 } else {
315 if(ses->server->tcpStatus == CifsExiting) {
316 spin_unlock(&GlobalMid_Lock);
317 return -ENOENT;
318 }
319
320 /* can not count locking commands against total since
321 they are allowed to block on server */
322
323 if(long_op < 3) {
324 /* update # of requests on the wire to server */
325 atomic_inc(&ses->server->inFlight);
326 }
327 spin_unlock(&GlobalMid_Lock);
328 break;
329 }
330 }
331 }
332 /* make sure that we sign in the same order that we send on this socket
333 and avoid races inside tcp sendmsg code that could cause corruption
334 of smb data */
335
336 down(&ses->server->tcpSem);
337
338 if (ses->server->tcpStatus == CifsExiting) {
339 rc = -ENOENT;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500340 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
342 cFYI(1,("tcp session dead - return to caller to retry"));
343 rc = -EAGAIN;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500344 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 } else if (ses->status != CifsGood) {
346 /* check if SMB session is bad because we are setting it up */
347 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
348 (in_buf->Command != SMB_COM_NEGOTIATE)) {
349 rc = -EAGAIN;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500350 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 } /* else ok - we are setting up session */
352 }
353 midQ = AllocMidQEntry(in_buf, ses);
354 if (midQ == NULL) {
355 up(&ses->server->tcpSem);
356 /* If not lock req, update # of requests on wire to server */
357 if(long_op < 3) {
358 atomic_dec(&ses->server->inFlight);
359 wake_up(&ses->server->request_q);
360 }
361 return -ENOMEM;
362 }
363
364 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
365 up(&ses->server->tcpSem);
366 cERROR(1,
367 ("Illegal length, greater than maximum frame, %d ",
368 in_buf->smb_buf_length));
369 DeleteMidQEntry(midQ);
370 /* If not lock req, update # of requests on wire to server */
371 if(long_op < 3) {
372 atomic_dec(&ses->server->inFlight);
373 wake_up(&ses->server->request_q);
374 }
375 return -EIO;
376 }
377
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500378/* BB FIXME */
379/* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French3e844692005-10-03 13:37:24 -0700382 rc = smb_send2(ses->server->ssocket, iov, n_vec,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500383 (struct sockaddr *) &(ses->server->addr.sockAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 if(rc < 0) {
385 DeleteMidQEntry(midQ);
386 up(&ses->server->tcpSem);
387 /* If not lock req, update # of requests on wire to server */
388 if(long_op < 3) {
389 atomic_dec(&ses->server->inFlight);
390 wake_up(&ses->server->request_q);
391 }
392 return rc;
393 } else
394 up(&ses->server->tcpSem);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500395 if (long_op == -1)
396 goto cifs_no_response_exit2;
397 else if (long_op == 2) /* writes past end of file can take loong time */
Steve French37c0eb42005-10-05 14:50:29 -0700398 timeout = 180 * HZ;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500399 else if (long_op == 1)
400 timeout = 45 * HZ; /* should be greater than
401 servers oplock break timeout (about 43 seconds) */
402 else if (long_op > 2) {
403 timeout = MAX_SCHEDULE_TIMEOUT;
404 } else
405 timeout = 15 * HZ;
406 /* wait for 15 seconds or until woken up due to response arriving or
407 due to last connection to this server being unmounted */
408 if (signal_pending(current)) {
409 /* if signal pending do not hold up user for full smb timeout
410 but we still give response a change to complete */
411 timeout = 2 * HZ;
412 }
413
414 /* No user interrupts in wait - wreaks havoc with performance */
415 if(timeout != MAX_SCHEDULE_TIMEOUT) {
416 timeout += jiffies;
417 wait_event(ses->server->response_q,
418 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
419 time_after(jiffies, timeout) ||
420 ((ses->server->tcpStatus != CifsGood) &&
421 (ses->server->tcpStatus != CifsNew)));
422 } else {
423 wait_event(ses->server->response_q,
424 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
425 ((ses->server->tcpStatus != CifsGood) &&
426 (ses->server->tcpStatus != CifsNew)));
427 }
428
429 spin_lock(&GlobalMid_Lock);
430 if (midQ->resp_buf) {
431 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700432 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500433 } else {
Steve French37c0eb42005-10-05 14:50:29 -0700434 cERROR(1,("No response to cmd %d mid %d",
435 midQ->command, midQ->mid));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500436 if(midQ->midState == MID_REQUEST_SUBMITTED) {
437 if(ses->server->tcpStatus == CifsExiting)
438 rc = -EHOSTDOWN;
439 else {
440 ses->server->tcpStatus = CifsNeedReconnect;
441 midQ->midState = MID_RETRY_NEEDED;
442 }
443 }
444
445 if (rc != -EHOSTDOWN) {
446 if(midQ->midState == MID_RETRY_NEEDED) {
447 rc = -EAGAIN;
448 cFYI(1,("marking request for retry"));
449 } else {
450 rc = -EIO;
451 }
452 }
453 spin_unlock(&GlobalMid_Lock);
454 DeleteMidQEntry(midQ);
455 /* If not lock req, update # of requests on wire to server */
456 if(long_op < 3) {
457 atomic_dec(&ses->server->inFlight);
458 wake_up(&ses->server->request_q);
459 }
460 return rc;
461 }
462
463 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
464 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
465 receive_len, xid));
466 rc = -EIO;
467 } else { /* rcvd frame is ok */
468
469 if (midQ->resp_buf &&
470 (midQ->midState == MID_RESPONSE_RECEIVED)) {
471 in_buf->smb_buf_length = receive_len;
472 /* BB verify that length would not overrun small buf */
473 memcpy((char *)in_buf + 4,
474 (char *)midQ->resp_buf + 4,
475 receive_len);
476
477 dump_smb(in_buf, 80);
478 /* convert the length into a more usable form */
479 if((receive_len > 24) &&
480 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
481 SECMODE_SIGN_ENABLED))) {
482 rc = cifs_verify_signature(in_buf,
483 ses->server->mac_signing_key,
484 midQ->sequence_number+1);
485 if(rc) {
486 cERROR(1,("Unexpected SMB signature"));
487 /* BB FIXME add code to kill session */
488 }
489 }
490
491 *pbytes_returned = in_buf->smb_buf_length;
492
493 /* BB special case reconnect tid and uid here? */
494 rc = map_smb_to_linux_error(in_buf);
495
496 /* convert ByteCount if necessary */
497 if (receive_len >=
498 sizeof (struct smb_hdr) -
499 4 /* do not count RFC1001 header */ +
500 (2 * in_buf->WordCount) + 2 /* bcc */ )
501 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
502 } else {
503 rc = -EIO;
Steve Frenchab2f2182005-09-15 20:44:50 -0700504 cFYI(1,("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500505 }
506 }
507cifs_no_response_exit2:
508 DeleteMidQEntry(midQ);
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 if(long_op < 3) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500511 atomic_dec(&ses->server->inFlight);
512 wake_up(&ses->server->request_q);
513 }
514
515 return rc;
516
517out_unlock2:
518 up(&ses->server->tcpSem);
519 /* If not lock req, update # of requests on wire to server */
520 if(long_op < 3) {
521 atomic_dec(&ses->server->inFlight);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 wake_up(&ses->server->request_q);
523 }
524
525 return rc;
526}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527#endif /* CIFS_EXPERIMENTAL */
528
529int
530SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
531 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
532 int *pbytes_returned, const int long_op)
533{
534 int rc = 0;
535 unsigned int receive_len;
536 unsigned long timeout;
537 struct mid_q_entry *midQ;
538
539 if (ses == NULL) {
540 cERROR(1,("Null smb session"));
541 return -EIO;
542 }
543 if(ses->server == NULL) {
544 cERROR(1,("Null tcp session"));
545 return -EIO;
546 }
547
Steve French31ca3bc2005-04-28 22:41:11 -0700548 if(ses->server->tcpStatus == CifsExiting)
549 return -ENOENT;
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 /* Ensure that we do not send more than 50 overlapping requests
552 to the same server. We may make this configurable later or
553 use ses->maxReq */
554 if(long_op == -1) {
555 /* oplock breaks must not be held up */
556 atomic_inc(&ses->server->inFlight);
557 } else {
558 spin_lock(&GlobalMid_Lock);
559 while(1) {
Steve French275cde12005-04-28 22:41:10 -0700560 if(atomic_read(&ses->server->inFlight) >=
561 cifs_max_pending){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 spin_unlock(&GlobalMid_Lock);
563 wait_event(ses->server->request_q,
564 atomic_read(&ses->server->inFlight)
565 < cifs_max_pending);
566 spin_lock(&GlobalMid_Lock);
567 } else {
568 if(ses->server->tcpStatus == CifsExiting) {
569 spin_unlock(&GlobalMid_Lock);
570 return -ENOENT;
571 }
572
573 /* can not count locking commands against total since
574 they are allowed to block on server */
575
576 if(long_op < 3) {
577 /* update # of requests on the wire to server */
578 atomic_inc(&ses->server->inFlight);
579 }
580 spin_unlock(&GlobalMid_Lock);
581 break;
582 }
583 }
584 }
585 /* make sure that we sign in the same order that we send on this socket
586 and avoid races inside tcp sendmsg code that could cause corruption
587 of smb data */
588
589 down(&ses->server->tcpSem);
590
591 if (ses->server->tcpStatus == CifsExiting) {
592 rc = -ENOENT;
593 goto out_unlock;
594 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
595 cFYI(1,("tcp session dead - return to caller to retry"));
596 rc = -EAGAIN;
597 goto out_unlock;
598 } else if (ses->status != CifsGood) {
599 /* check if SMB session is bad because we are setting it up */
600 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
601 (in_buf->Command != SMB_COM_NEGOTIATE)) {
602 rc = -EAGAIN;
603 goto out_unlock;
604 } /* else ok - we are setting up session */
605 }
606 midQ = AllocMidQEntry(in_buf, ses);
607 if (midQ == NULL) {
608 up(&ses->server->tcpSem);
609 /* If not lock req, update # of requests on wire to server */
610 if(long_op < 3) {
611 atomic_dec(&ses->server->inFlight);
612 wake_up(&ses->server->request_q);
613 }
614 return -ENOMEM;
615 }
616
617 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
618 up(&ses->server->tcpSem);
619 cERROR(1,
620 ("Illegal length, greater than maximum frame, %d ",
621 in_buf->smb_buf_length));
622 DeleteMidQEntry(midQ);
623 /* If not lock req, update # of requests on wire to server */
624 if(long_op < 3) {
625 atomic_dec(&ses->server->inFlight);
626 wake_up(&ses->server->request_q);
627 }
628 return -EIO;
629 }
630
Steve Frenchad009ac2005-04-28 22:41:05 -0700631 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 midQ->midState = MID_REQUEST_SUBMITTED;
634 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
635 (struct sockaddr *) &(ses->server->addr.sockAddr));
636 if(rc < 0) {
637 DeleteMidQEntry(midQ);
638 up(&ses->server->tcpSem);
639 /* If not lock req, update # of requests on wire to server */
640 if(long_op < 3) {
641 atomic_dec(&ses->server->inFlight);
642 wake_up(&ses->server->request_q);
643 }
644 return rc;
645 } else
646 up(&ses->server->tcpSem);
647 if (long_op == -1)
648 goto cifs_no_response_exit;
Steve French275cde12005-04-28 22:41:10 -0700649 else if (long_op == 2) /* writes past end of file can take loong time */
Steve French37c0eb42005-10-05 14:50:29 -0700650 timeout = 180 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 else if (long_op == 1)
652 timeout = 45 * HZ; /* should be greater than
653 servers oplock break timeout (about 43 seconds) */
654 else if (long_op > 2) {
655 timeout = MAX_SCHEDULE_TIMEOUT;
656 } else
657 timeout = 15 * HZ;
658 /* wait for 15 seconds or until woken up due to response arriving or
659 due to last connection to this server being unmounted */
660 if (signal_pending(current)) {
661 /* if signal pending do not hold up user for full smb timeout
662 but we still give response a change to complete */
663 timeout = 2 * HZ;
664 }
665
666 /* No user interrupts in wait - wreaks havoc with performance */
667 if(timeout != MAX_SCHEDULE_TIMEOUT) {
668 timeout += jiffies;
669 wait_event(ses->server->response_q,
670 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
671 time_after(jiffies, timeout) ||
672 ((ses->server->tcpStatus != CifsGood) &&
673 (ses->server->tcpStatus != CifsNew)));
674 } else {
675 wait_event(ses->server->response_q,
676 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
677 ((ses->server->tcpStatus != CifsGood) &&
678 (ses->server->tcpStatus != CifsNew)));
679 }
680
681 spin_lock(&GlobalMid_Lock);
682 if (midQ->resp_buf) {
683 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700684 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 } else {
Steve French37c0eb42005-10-05 14:50:29 -0700686 cERROR(1,("No response for cmd %d mid %d",
687 midQ->command, midQ->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 if(midQ->midState == MID_REQUEST_SUBMITTED) {
689 if(ses->server->tcpStatus == CifsExiting)
690 rc = -EHOSTDOWN;
691 else {
692 ses->server->tcpStatus = CifsNeedReconnect;
693 midQ->midState = MID_RETRY_NEEDED;
694 }
695 }
696
697 if (rc != -EHOSTDOWN) {
698 if(midQ->midState == MID_RETRY_NEEDED) {
699 rc = -EAGAIN;
700 cFYI(1,("marking request for retry"));
701 } else {
702 rc = -EIO;
703 }
704 }
705 spin_unlock(&GlobalMid_Lock);
706 DeleteMidQEntry(midQ);
707 /* If not lock req, update # of requests on wire to server */
708 if(long_op < 3) {
709 atomic_dec(&ses->server->inFlight);
710 wake_up(&ses->server->request_q);
711 }
712 return rc;
713 }
714
715 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700716 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 receive_len, xid));
718 rc = -EIO;
719 } else { /* rcvd frame is ok */
720
721 if (midQ->resp_buf && out_buf
722 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
723 out_buf->smb_buf_length = receive_len;
724 memcpy((char *)out_buf + 4,
725 (char *)midQ->resp_buf + 4,
726 receive_len);
727
728 dump_smb(out_buf, 92);
729 /* convert the length into a more usable form */
730 if((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700731 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
732 SECMODE_SIGN_ENABLED))) {
733 rc = cifs_verify_signature(out_buf,
734 ses->server->mac_signing_key,
735 midQ->sequence_number+1);
736 if(rc) {
Steve French275cde12005-04-28 22:41:10 -0700737 cERROR(1,("Unexpected SMB signature"));
738 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
741
742 *pbytes_returned = out_buf->smb_buf_length;
743
Steve Frenchad009ac2005-04-28 22:41:05 -0700744 /* BB special case reconnect tid and uid here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 rc = map_smb_to_linux_error(out_buf);
746
747 /* convert ByteCount if necessary */
748 if (receive_len >=
749 sizeof (struct smb_hdr) -
750 4 /* do not count RFC1001 header */ +
751 (2 * out_buf->WordCount) + 2 /* bcc */ )
752 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
753 } else {
754 rc = -EIO;
Steve Frencha5a2b482005-08-20 21:42:53 -0700755 cERROR(1,("Bad MID state? "));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 }
757 }
758cifs_no_response_exit:
759 DeleteMidQEntry(midQ);
760
761 if(long_op < 3) {
762 atomic_dec(&ses->server->inFlight);
763 wake_up(&ses->server->request_q);
764 }
765
766 return rc;
767
768out_unlock:
769 up(&ses->server->tcpSem);
770 /* If not lock req, update # of requests on wire to server */
771 if(long_op < 3) {
772 atomic_dec(&ses->server->inFlight);
773 wake_up(&ses->server->request_q);
774 }
775
776 return rc;
777}