blob: 9e8e85a8d186b62a781c49e71d9dfa0c2cb4517c [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);
150 cFYI(1, ("Sending smb of length %d ", smb_buf_length));
151 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++;
157 if(i > 60) {
158 cERROR(1,
159 ("sends on sock %p stuck for 30 seconds",
160 ssocket));
161 rc = -EAGAIN;
162 break;
163 }
164 msleep(500);
165 continue;
166 }
167 if (rc < 0)
168 break;
169 iov.iov_base += rc;
170 iov.iov_len -= rc;
171 len -= rc;
172 }
173
174 if (rc < 0) {
175 cERROR(1,("Error %d sending data on socket to server.", rc));
176 } else {
177 rc = 0;
178 }
179
180 return rc;
181}
182
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500183#ifdef CONFIG_CIFS_EXPERIMENTAL
184static int
185smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
186 unsigned int smb_hdr_length, const char * data, unsigned int datalen,
187 struct sockaddr *sin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188{
189 int rc = 0;
190 int i = 0;
191 struct msghdr smb_msg;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500192 struct kvec iov[2];
193 unsigned len = smb_hdr_length + 4;
194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 if(ssocket == NULL)
196 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500197 iov[0].iov_base = smb_buffer;
198 iov[0].iov_len = len;
199 iov[1].iov_base = data;
Steve French0c0ff092005-06-23 19:31:17 -0500200 iov[1].iov_len = datalen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 smb_msg.msg_name = sin;
202 smb_msg.msg_namelen = sizeof (struct sockaddr);
203 smb_msg.msg_control = NULL;
204 smb_msg.msg_controllen = 0;
205 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
206
207 /* smb header is converted in header_assemble. bcc and rest of SMB word
208 area, and byte area if necessary, is converted to littleendian in
209 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
210 Flags2 is converted in SendReceive */
211
212 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French0c0ff092005-06-23 19:31:17 -0500213 cFYI(1, ("Sending smb: hdrlen %d datalen %d",
214 smb_hdr_length,datalen));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 dump_smb(smb_buffer, len);
216
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500217 while (len + datalen > 0) {
218 rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
220 i++;
221 if(i > 60) {
222 cERROR(1,
223 ("sends on sock %p stuck for 30 seconds",
224 ssocket));
225 rc = -EAGAIN;
226 break;
227 }
228 msleep(500);
229 continue;
230 }
231 if (rc < 0)
232 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500233 if(iov[0].iov_len > 0) {
234 if(rc >= len) {
235 iov[0].iov_len = 0;
236 rc -= len;
Steve French0c0ff092005-06-23 19:31:17 -0500237 len = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500238 } else { /* some of hdr was not sent */
239 len -= rc;
240 iov[0].iov_len -= rc;
241 iov[0].iov_base += rc;
242 continue;
243 }
244 }
245 if((iov[0].iov_len == 0) && (rc > 0)){
246 iov[1].iov_base += rc;
247 iov[1].iov_len -= rc;
248 datalen -= rc;
249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 }
251
252 if (rc < 0) {
253 cERROR(1,("Error %d sending data on socket to server.", rc));
254 } else {
255 rc = 0;
256 }
257
258 return rc;
259}
260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261int
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500262SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
263 struct smb_hdr *in_buf, int hdrlen, const char * data,
264 int datalen, int *pbytes_returned, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 int rc = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500267 unsigned int receive_len;
268 unsigned long timeout;
269 struct mid_q_entry *midQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 if (ses == NULL) {
272 cERROR(1,("Null smb session"));
273 return -EIO;
274 }
275 if(ses->server == NULL) {
276 cERROR(1,("Null tcp session"));
277 return -EIO;
278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500280 if(ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700281 return -ENOENT;
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 /* Ensure that we do not send more than 50 overlapping requests
284 to the same server. We may make this configurable later or
285 use ses->maxReq */
286 if(long_op == -1) {
287 /* oplock breaks must not be held up */
288 atomic_inc(&ses->server->inFlight);
289 } else {
290 spin_lock(&GlobalMid_Lock);
291 while(1) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500292 if(atomic_read(&ses->server->inFlight) >=
293 cifs_max_pending){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 spin_unlock(&GlobalMid_Lock);
295 wait_event(ses->server->request_q,
296 atomic_read(&ses->server->inFlight)
297 < cifs_max_pending);
298 spin_lock(&GlobalMid_Lock);
299 } else {
300 if(ses->server->tcpStatus == CifsExiting) {
301 spin_unlock(&GlobalMid_Lock);
302 return -ENOENT;
303 }
304
305 /* can not count locking commands against total since
306 they are allowed to block on server */
307
308 if(long_op < 3) {
309 /* update # of requests on the wire to server */
310 atomic_inc(&ses->server->inFlight);
311 }
312 spin_unlock(&GlobalMid_Lock);
313 break;
314 }
315 }
316 }
317 /* make sure that we sign in the same order that we send on this socket
318 and avoid races inside tcp sendmsg code that could cause corruption
319 of smb data */
320
321 down(&ses->server->tcpSem);
322
323 if (ses->server->tcpStatus == CifsExiting) {
324 rc = -ENOENT;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500325 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
327 cFYI(1,("tcp session dead - return to caller to retry"));
328 rc = -EAGAIN;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500329 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 } else if (ses->status != CifsGood) {
331 /* check if SMB session is bad because we are setting it up */
332 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
333 (in_buf->Command != SMB_COM_NEGOTIATE)) {
334 rc = -EAGAIN;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500335 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 } /* else ok - we are setting up session */
337 }
338 midQ = AllocMidQEntry(in_buf, ses);
339 if (midQ == NULL) {
340 up(&ses->server->tcpSem);
341 /* If not lock req, update # of requests on wire to server */
342 if(long_op < 3) {
343 atomic_dec(&ses->server->inFlight);
344 wake_up(&ses->server->request_q);
345 }
346 return -ENOMEM;
347 }
348
349 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
350 up(&ses->server->tcpSem);
351 cERROR(1,
352 ("Illegal length, greater than maximum frame, %d ",
353 in_buf->smb_buf_length));
354 DeleteMidQEntry(midQ);
355 /* If not lock req, update # of requests on wire to server */
356 if(long_op < 3) {
357 atomic_dec(&ses->server->inFlight);
358 wake_up(&ses->server->request_q);
359 }
360 return -EIO;
361 }
362
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500363/* BB FIXME */
364/* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 midQ->midState = MID_REQUEST_SUBMITTED;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500367 rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen,
368 (struct sockaddr *) &(ses->server->addr.sockAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 if(rc < 0) {
370 DeleteMidQEntry(midQ);
371 up(&ses->server->tcpSem);
372 /* If not lock req, update # of requests on wire to server */
373 if(long_op < 3) {
374 atomic_dec(&ses->server->inFlight);
375 wake_up(&ses->server->request_q);
376 }
377 return rc;
378 } else
379 up(&ses->server->tcpSem);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500380 if (long_op == -1)
381 goto cifs_no_response_exit2;
382 else if (long_op == 2) /* writes past end of file can take loong time */
383 timeout = 300 * HZ;
384 else if (long_op == 1)
385 timeout = 45 * HZ; /* should be greater than
386 servers oplock break timeout (about 43 seconds) */
387 else if (long_op > 2) {
388 timeout = MAX_SCHEDULE_TIMEOUT;
389 } else
390 timeout = 15 * HZ;
391 /* wait for 15 seconds or until woken up due to response arriving or
392 due to last connection to this server being unmounted */
393 if (signal_pending(current)) {
394 /* if signal pending do not hold up user for full smb timeout
395 but we still give response a change to complete */
396 timeout = 2 * HZ;
397 }
398
399 /* No user interrupts in wait - wreaks havoc with performance */
400 if(timeout != MAX_SCHEDULE_TIMEOUT) {
401 timeout += jiffies;
402 wait_event(ses->server->response_q,
403 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
404 time_after(jiffies, timeout) ||
405 ((ses->server->tcpStatus != CifsGood) &&
406 (ses->server->tcpStatus != CifsNew)));
407 } else {
408 wait_event(ses->server->response_q,
409 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
410 ((ses->server->tcpStatus != CifsGood) &&
411 (ses->server->tcpStatus != CifsNew)));
412 }
413
414 spin_lock(&GlobalMid_Lock);
415 if (midQ->resp_buf) {
416 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700417 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500418 } else {
419 cERROR(1,("No response buffer"));
420 if(midQ->midState == MID_REQUEST_SUBMITTED) {
421 if(ses->server->tcpStatus == CifsExiting)
422 rc = -EHOSTDOWN;
423 else {
424 ses->server->tcpStatus = CifsNeedReconnect;
425 midQ->midState = MID_RETRY_NEEDED;
426 }
427 }
428
429 if (rc != -EHOSTDOWN) {
430 if(midQ->midState == MID_RETRY_NEEDED) {
431 rc = -EAGAIN;
432 cFYI(1,("marking request for retry"));
433 } else {
434 rc = -EIO;
435 }
436 }
437 spin_unlock(&GlobalMid_Lock);
438 DeleteMidQEntry(midQ);
439 /* If not lock req, update # of requests on wire to server */
440 if(long_op < 3) {
441 atomic_dec(&ses->server->inFlight);
442 wake_up(&ses->server->request_q);
443 }
444 return rc;
445 }
446
447 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
448 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
449 receive_len, xid));
450 rc = -EIO;
451 } else { /* rcvd frame is ok */
452
453 if (midQ->resp_buf &&
454 (midQ->midState == MID_RESPONSE_RECEIVED)) {
455 in_buf->smb_buf_length = receive_len;
456 /* BB verify that length would not overrun small buf */
457 memcpy((char *)in_buf + 4,
458 (char *)midQ->resp_buf + 4,
459 receive_len);
460
461 dump_smb(in_buf, 80);
462 /* convert the length into a more usable form */
463 if((receive_len > 24) &&
464 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
465 SECMODE_SIGN_ENABLED))) {
466 rc = cifs_verify_signature(in_buf,
467 ses->server->mac_signing_key,
468 midQ->sequence_number+1);
469 if(rc) {
470 cERROR(1,("Unexpected SMB signature"));
471 /* BB FIXME add code to kill session */
472 }
473 }
474
475 *pbytes_returned = in_buf->smb_buf_length;
476
477 /* BB special case reconnect tid and uid here? */
478 rc = map_smb_to_linux_error(in_buf);
479
480 /* convert ByteCount if necessary */
481 if (receive_len >=
482 sizeof (struct smb_hdr) -
483 4 /* do not count RFC1001 header */ +
484 (2 * in_buf->WordCount) + 2 /* bcc */ )
485 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
486 } else {
487 rc = -EIO;
Steve Frenchab2f2182005-09-15 20:44:50 -0700488 cFYI(1,("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500489 }
490 }
491cifs_no_response_exit2:
492 DeleteMidQEntry(midQ);
493
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if(long_op < 3) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500495 atomic_dec(&ses->server->inFlight);
496 wake_up(&ses->server->request_q);
497 }
498
499 return rc;
500
501out_unlock2:
502 up(&ses->server->tcpSem);
503 /* If not lock req, update # of requests on wire to server */
504 if(long_op < 3) {
505 atomic_dec(&ses->server->inFlight);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 wake_up(&ses->server->request_q);
507 }
508
509 return rc;
510}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511#endif /* CIFS_EXPERIMENTAL */
512
513int
514SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
515 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
516 int *pbytes_returned, const int long_op)
517{
518 int rc = 0;
519 unsigned int receive_len;
520 unsigned long timeout;
521 struct mid_q_entry *midQ;
522
523 if (ses == NULL) {
524 cERROR(1,("Null smb session"));
525 return -EIO;
526 }
527 if(ses->server == NULL) {
528 cERROR(1,("Null tcp session"));
529 return -EIO;
530 }
531
Steve French31ca3bc2005-04-28 22:41:11 -0700532 if(ses->server->tcpStatus == CifsExiting)
533 return -ENOENT;
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 /* Ensure that we do not send more than 50 overlapping requests
536 to the same server. We may make this configurable later or
537 use ses->maxReq */
538 if(long_op == -1) {
539 /* oplock breaks must not be held up */
540 atomic_inc(&ses->server->inFlight);
541 } else {
542 spin_lock(&GlobalMid_Lock);
543 while(1) {
Steve French275cde12005-04-28 22:41:10 -0700544 if(atomic_read(&ses->server->inFlight) >=
545 cifs_max_pending){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 spin_unlock(&GlobalMid_Lock);
547 wait_event(ses->server->request_q,
548 atomic_read(&ses->server->inFlight)
549 < cifs_max_pending);
550 spin_lock(&GlobalMid_Lock);
551 } else {
552 if(ses->server->tcpStatus == CifsExiting) {
553 spin_unlock(&GlobalMid_Lock);
554 return -ENOENT;
555 }
556
557 /* can not count locking commands against total since
558 they are allowed to block on server */
559
560 if(long_op < 3) {
561 /* update # of requests on the wire to server */
562 atomic_inc(&ses->server->inFlight);
563 }
564 spin_unlock(&GlobalMid_Lock);
565 break;
566 }
567 }
568 }
569 /* make sure that we sign in the same order that we send on this socket
570 and avoid races inside tcp sendmsg code that could cause corruption
571 of smb data */
572
573 down(&ses->server->tcpSem);
574
575 if (ses->server->tcpStatus == CifsExiting) {
576 rc = -ENOENT;
577 goto out_unlock;
578 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
579 cFYI(1,("tcp session dead - return to caller to retry"));
580 rc = -EAGAIN;
581 goto out_unlock;
582 } else if (ses->status != CifsGood) {
583 /* check if SMB session is bad because we are setting it up */
584 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
585 (in_buf->Command != SMB_COM_NEGOTIATE)) {
586 rc = -EAGAIN;
587 goto out_unlock;
588 } /* else ok - we are setting up session */
589 }
590 midQ = AllocMidQEntry(in_buf, ses);
591 if (midQ == NULL) {
592 up(&ses->server->tcpSem);
593 /* If not lock req, update # of requests on wire to server */
594 if(long_op < 3) {
595 atomic_dec(&ses->server->inFlight);
596 wake_up(&ses->server->request_q);
597 }
598 return -ENOMEM;
599 }
600
601 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
602 up(&ses->server->tcpSem);
603 cERROR(1,
604 ("Illegal length, greater than maximum frame, %d ",
605 in_buf->smb_buf_length));
606 DeleteMidQEntry(midQ);
607 /* If not lock req, update # of requests on wire to server */
608 if(long_op < 3) {
609 atomic_dec(&ses->server->inFlight);
610 wake_up(&ses->server->request_q);
611 }
612 return -EIO;
613 }
614
Steve Frenchad009ac2005-04-28 22:41:05 -0700615 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 midQ->midState = MID_REQUEST_SUBMITTED;
618 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
619 (struct sockaddr *) &(ses->server->addr.sockAddr));
620 if(rc < 0) {
621 DeleteMidQEntry(midQ);
622 up(&ses->server->tcpSem);
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 rc;
629 } else
630 up(&ses->server->tcpSem);
631 if (long_op == -1)
632 goto cifs_no_response_exit;
Steve French275cde12005-04-28 22:41:10 -0700633 else if (long_op == 2) /* writes past end of file can take loong time */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 timeout = 300 * HZ;
635 else if (long_op == 1)
636 timeout = 45 * HZ; /* should be greater than
637 servers oplock break timeout (about 43 seconds) */
638 else if (long_op > 2) {
639 timeout = MAX_SCHEDULE_TIMEOUT;
640 } else
641 timeout = 15 * HZ;
642 /* wait for 15 seconds or until woken up due to response arriving or
643 due to last connection to this server being unmounted */
644 if (signal_pending(current)) {
645 /* if signal pending do not hold up user for full smb timeout
646 but we still give response a change to complete */
647 timeout = 2 * HZ;
648 }
649
650 /* No user interrupts in wait - wreaks havoc with performance */
651 if(timeout != MAX_SCHEDULE_TIMEOUT) {
652 timeout += jiffies;
653 wait_event(ses->server->response_q,
654 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
655 time_after(jiffies, timeout) ||
656 ((ses->server->tcpStatus != CifsGood) &&
657 (ses->server->tcpStatus != CifsNew)));
658 } else {
659 wait_event(ses->server->response_q,
660 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
661 ((ses->server->tcpStatus != CifsGood) &&
662 (ses->server->tcpStatus != CifsNew)));
663 }
664
665 spin_lock(&GlobalMid_Lock);
666 if (midQ->resp_buf) {
667 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700668 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 } else {
670 cERROR(1,("No response buffer"));
671 if(midQ->midState == MID_REQUEST_SUBMITTED) {
672 if(ses->server->tcpStatus == CifsExiting)
673 rc = -EHOSTDOWN;
674 else {
675 ses->server->tcpStatus = CifsNeedReconnect;
676 midQ->midState = MID_RETRY_NEEDED;
677 }
678 }
679
680 if (rc != -EHOSTDOWN) {
681 if(midQ->midState == MID_RETRY_NEEDED) {
682 rc = -EAGAIN;
683 cFYI(1,("marking request for retry"));
684 } else {
685 rc = -EIO;
686 }
687 }
688 spin_unlock(&GlobalMid_Lock);
689 DeleteMidQEntry(midQ);
690 /* If not lock req, update # of requests on wire to server */
691 if(long_op < 3) {
692 atomic_dec(&ses->server->inFlight);
693 wake_up(&ses->server->request_q);
694 }
695 return rc;
696 }
697
698 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700699 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 receive_len, xid));
701 rc = -EIO;
702 } else { /* rcvd frame is ok */
703
704 if (midQ->resp_buf && out_buf
705 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
706 out_buf->smb_buf_length = receive_len;
707 memcpy((char *)out_buf + 4,
708 (char *)midQ->resp_buf + 4,
709 receive_len);
710
711 dump_smb(out_buf, 92);
712 /* convert the length into a more usable form */
713 if((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700714 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
715 SECMODE_SIGN_ENABLED))) {
716 rc = cifs_verify_signature(out_buf,
717 ses->server->mac_signing_key,
718 midQ->sequence_number+1);
719 if(rc) {
Steve French275cde12005-04-28 22:41:10 -0700720 cERROR(1,("Unexpected SMB signature"));
721 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724
725 *pbytes_returned = out_buf->smb_buf_length;
726
Steve Frenchad009ac2005-04-28 22:41:05 -0700727 /* BB special case reconnect tid and uid here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 rc = map_smb_to_linux_error(out_buf);
729
730 /* convert ByteCount if necessary */
731 if (receive_len >=
732 sizeof (struct smb_hdr) -
733 4 /* do not count RFC1001 header */ +
734 (2 * out_buf->WordCount) + 2 /* bcc */ )
735 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
736 } else {
737 rc = -EIO;
Steve Frencha5a2b482005-08-20 21:42:53 -0700738 cERROR(1,("Bad MID state? "));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
740 }
741cifs_no_response_exit:
742 DeleteMidQEntry(midQ);
743
744 if(long_op < 3) {
745 atomic_dec(&ses->server->inFlight);
746 wake_up(&ses->server->request_q);
747 }
748
749 return rc;
750
751out_unlock:
752 up(&ses->server->tcpSem);
753 /* If not lock req, update # of requests on wire to server */
754 if(long_op < 3) {
755 atomic_dec(&ses->server->inFlight);
756 wake_up(&ses->server->request_q);
757 }
758
759 return rc;
760}