Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
[linux-2.6] / fs / cifs / transport.c
1 /*
2  *   fs/cifs/transport.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2005
5  *   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   
35 extern mempool_t *cifs_mid_poolp;
36 extern kmem_cache_t *cifs_oplock_cachep;
37
38 static struct mid_q_entry *
39 AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
40 {
41         struct mid_q_entry *temp;
42
43         if (ses == NULL) {
44                 cERROR(1, ("Null session passed in to AllocMidQEntry"));
45                 return NULL;
46         }
47         if (ses->server == NULL) {
48                 cERROR(1, ("Null TCP session in AllocMidQEntry"));
49                 return NULL;
50         }
51         
52         temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
53                                                     SLAB_KERNEL | SLAB_NOFS);
54         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
75 static void
76 DeleteMidQEntry(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);
83         if(midEntry->largeBuf)
84                 cifs_buf_release(midEntry->resp_buf);
85         else
86                 cifs_small_buf_release(midEntry->resp_buf);
87         mempool_free(midEntry, cifs_mid_poolp);
88 }
89
90 struct oplock_q_entry *
91 AllocOplockQEntry(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
114 void 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
123 int
124 smb_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
183 #ifdef CONFIG_CIFS_EXPERIMENTAL
184 static int
185 smb_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)
188 {
189         int rc = 0;
190         int i = 0;
191         struct msghdr smb_msg;
192         struct kvec iov[2];
193         unsigned len = smb_hdr_length + 4;
194         
195         if(ssocket == NULL)
196                 return -ENOTSOCK; /* BB eventually add reconnect code here */
197         iov[0].iov_base = smb_buffer;
198         iov[0].iov_len = len;
199         iov[1].iov_base = data;
200         iov[2].iov_len = datalen;
201         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);
213         cFYI(1, ("Sending smb of length %d ", len + datalen));
214         dump_smb(smb_buffer, len);
215
216         while (len + datalen > 0) {
217                 rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len);
218                 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
219                         i++;
220                         if(i > 60) {
221                                 cERROR(1,
222                                    ("sends on sock %p stuck for 30 seconds",
223                                     ssocket));
224                                 rc = -EAGAIN;
225                                 break;
226                         }
227                         msleep(500);
228                         continue;
229                 }
230                 if (rc < 0) 
231                         break;
232                 if(iov[0].iov_len > 0) {
233                         if(rc >= len) {
234                                 iov[0].iov_len = 0;
235                                 rc -= len;
236                         } else {  /* some of hdr was not sent */
237                                 len -= rc;
238                                 iov[0].iov_len -= rc;
239                                 iov[0].iov_base += rc;
240                                 continue;
241                         }
242                 }
243                 if((iov[0].iov_len == 0) && (rc > 0)){
244                         iov[1].iov_base += rc;
245                         iov[1].iov_len -= rc;
246                         datalen -= rc;
247                 }
248         }
249
250         if (rc < 0) {
251                 cERROR(1,("Error %d sending data on socket to server.", rc));
252         } else {
253                 rc = 0;
254         }
255
256         return rc;
257 }
258
259 int
260 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
261              struct smb_hdr *in_buf, int hdrlen, const char * data,
262              int datalen, int *pbytes_returned, const int long_op)
263 {
264         int rc = 0;
265         unsigned int receive_len;
266         unsigned long timeout;
267         struct mid_q_entry *midQ;
268
269         if (ses == NULL) {
270                 cERROR(1,("Null smb session"));
271                 return -EIO;
272         }
273         if(ses->server == NULL) {
274                 cERROR(1,("Null tcp session"));
275                 return -EIO;
276         }
277
278         if(ses->server->tcpStatus == CifsExiting)
279                 return -ENOENT;
280
281         /* Ensure that we do not send more than 50 overlapping requests 
282            to the same server. We may make this configurable later or
283            use ses->maxReq */
284         if(long_op == -1) {
285                 /* oplock breaks must not be held up */
286                 atomic_inc(&ses->server->inFlight);
287         } else {
288                 spin_lock(&GlobalMid_Lock); 
289                 while(1) {        
290                         if(atomic_read(&ses->server->inFlight) >= 
291                                         cifs_max_pending){
292                                 spin_unlock(&GlobalMid_Lock);
293                                 wait_event(ses->server->request_q,
294                                         atomic_read(&ses->server->inFlight)
295                                          < cifs_max_pending);
296                                 spin_lock(&GlobalMid_Lock);
297                         } else {
298                                 if(ses->server->tcpStatus == CifsExiting) {
299                                         spin_unlock(&GlobalMid_Lock);
300                                         return -ENOENT;
301                                 }
302
303                         /* can not count locking commands against total since
304                            they are allowed to block on server */
305                                         
306                                 if(long_op < 3) {
307                                 /* update # of requests on the wire to server */
308                                         atomic_inc(&ses->server->inFlight);
309                                 }
310                                 spin_unlock(&GlobalMid_Lock);
311                                 break;
312                         }
313                 }
314         }
315         /* make sure that we sign in the same order that we send on this socket 
316            and avoid races inside tcp sendmsg code that could cause corruption
317            of smb data */
318
319         down(&ses->server->tcpSem); 
320
321         if (ses->server->tcpStatus == CifsExiting) {
322                 rc = -ENOENT;
323                 goto out_unlock2;
324         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
325                 cFYI(1,("tcp session dead - return to caller to retry"));
326                 rc = -EAGAIN;
327                 goto out_unlock2;
328         } else if (ses->status != CifsGood) {
329                 /* check if SMB session is bad because we are setting it up */
330                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
331                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
332                         rc = -EAGAIN;
333                         goto out_unlock2;
334                 } /* else ok - we are setting up session */
335         }
336         midQ = AllocMidQEntry(in_buf, ses);
337         if (midQ == NULL) {
338                 up(&ses->server->tcpSem);
339                 /* If not lock req, update # of requests on wire to server */
340                 if(long_op < 3) {
341                         atomic_dec(&ses->server->inFlight); 
342                         wake_up(&ses->server->request_q);
343                 }
344                 return -ENOMEM;
345         }
346
347         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
348                 up(&ses->server->tcpSem);
349                 cERROR(1,
350                        ("Illegal length, greater than maximum frame, %d ",
351                         in_buf->smb_buf_length));
352                 DeleteMidQEntry(midQ);
353                 /* If not lock req, update # of requests on wire to server */
354                 if(long_op < 3) {
355                         atomic_dec(&ses->server->inFlight); 
356                         wake_up(&ses->server->request_q);
357                 }
358                 return -EIO;
359         }
360
361 /* BB FIXME */
362 /*      rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
363
364         midQ->midState = MID_REQUEST_SUBMITTED;
365         rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen,
366                       (struct sockaddr *) &(ses->server->addr.sockAddr));
367         if(rc < 0) {
368                 DeleteMidQEntry(midQ);
369                 up(&ses->server->tcpSem);
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 rc;
376         } else
377                 up(&ses->server->tcpSem);
378         if (long_op == -1)
379                 goto cifs_no_response_exit2;
380         else if (long_op == 2) /* writes past end of file can take loong time */
381                 timeout = 300 * HZ;
382         else if (long_op == 1)
383                 timeout = 45 * HZ; /* should be greater than 
384                         servers oplock break timeout (about 43 seconds) */
385         else if (long_op > 2) {
386                 timeout = MAX_SCHEDULE_TIMEOUT;
387         } else
388                 timeout = 15 * HZ;
389         /* wait for 15 seconds or until woken up due to response arriving or 
390            due to last connection to this server being unmounted */
391         if (signal_pending(current)) {
392                 /* if signal pending do not hold up user for full smb timeout
393                 but we still give response a change to complete */
394                 timeout = 2 * HZ;
395         }   
396
397         /* No user interrupts in wait - wreaks havoc with performance */
398         if(timeout != MAX_SCHEDULE_TIMEOUT) {
399                 timeout += jiffies;
400                 wait_event(ses->server->response_q,
401                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
402                         time_after(jiffies, timeout) || 
403                         ((ses->server->tcpStatus != CifsGood) &&
404                          (ses->server->tcpStatus != CifsNew)));
405         } else {
406                 wait_event(ses->server->response_q,
407                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
408                         ((ses->server->tcpStatus != CifsGood) &&
409                          (ses->server->tcpStatus != CifsNew)));
410         }
411
412         spin_lock(&GlobalMid_Lock);
413         if (midQ->resp_buf) {
414                 spin_unlock(&GlobalMid_Lock);
415                 receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
416         } else {
417                 cERROR(1,("No response buffer"));
418                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
419                         if(ses->server->tcpStatus == CifsExiting)
420                                 rc = -EHOSTDOWN;
421                         else {
422                                 ses->server->tcpStatus = CifsNeedReconnect;
423                                 midQ->midState = MID_RETRY_NEEDED;
424                         }
425                 }
426
427                 if (rc != -EHOSTDOWN) {
428                         if(midQ->midState == MID_RETRY_NEEDED) {
429                                 rc = -EAGAIN;
430                                 cFYI(1,("marking request for retry"));
431                         } else {
432                                 rc = -EIO;
433                         }
434                 }
435                 spin_unlock(&GlobalMid_Lock);
436                 DeleteMidQEntry(midQ);
437                 /* If not lock req, update # of requests on wire to server */
438                 if(long_op < 3) {
439                         atomic_dec(&ses->server->inFlight); 
440                         wake_up(&ses->server->request_q);
441                 }
442                 return rc;
443         }
444   
445         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
446                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
447                         receive_len, xid));
448                 rc = -EIO;
449         } else {                /* rcvd frame is ok */
450
451                 if (midQ->resp_buf && 
452                         (midQ->midState == MID_RESPONSE_RECEIVED)) {
453                         in_buf->smb_buf_length = receive_len;
454                         /* BB verify that length would not overrun small buf */
455                         memcpy((char *)in_buf + 4,
456                                (char *)midQ->resp_buf + 4,
457                                receive_len);
458
459                         dump_smb(in_buf, 80);
460                         /* convert the length into a more usable form */
461                         if((receive_len > 24) &&
462                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
463                                         SECMODE_SIGN_ENABLED))) {
464                                 rc = cifs_verify_signature(in_buf,
465                                                 ses->server->mac_signing_key,
466                                                 midQ->sequence_number+1);
467                                 if(rc) {
468                                         cERROR(1,("Unexpected SMB signature"));
469                                         /* BB FIXME add code to kill session */
470                                 }
471                         }
472
473                         *pbytes_returned = in_buf->smb_buf_length;
474
475                         /* BB special case reconnect tid and uid here? */
476                         rc = map_smb_to_linux_error(in_buf);
477
478                         /* convert ByteCount if necessary */
479                         if (receive_len >=
480                             sizeof (struct smb_hdr) -
481                             4 /* do not count RFC1001 header */  +
482                             (2 * in_buf->WordCount) + 2 /* bcc */ )
483                                 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
484                 } else {
485                         rc = -EIO;
486                         cFYI(1,("Bad MID state? "));
487                 }
488         }
489 cifs_no_response_exit2:
490         DeleteMidQEntry(midQ);
491
492         if(long_op < 3) {
493                 atomic_dec(&ses->server->inFlight); 
494                 wake_up(&ses->server->request_q);
495         }
496
497         return rc;
498
499 out_unlock2:
500         up(&ses->server->tcpSem);
501         /* If not lock req, update # of requests on wire to server */
502         if(long_op < 3) {
503                 atomic_dec(&ses->server->inFlight); 
504                 wake_up(&ses->server->request_q);
505         }
506
507         return rc;
508 }
509 #endif /* CIFS_EXPERIMENTAL */
510
511 int
512 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
513             struct smb_hdr *in_buf, struct smb_hdr *out_buf,
514             int *pbytes_returned, const int long_op)
515 {
516         int rc = 0;
517         unsigned int receive_len;
518         unsigned long timeout;
519         struct mid_q_entry *midQ;
520
521         if (ses == NULL) {
522                 cERROR(1,("Null smb session"));
523                 return -EIO;
524         }
525         if(ses->server == NULL) {
526                 cERROR(1,("Null tcp session"));
527                 return -EIO;
528         }
529
530         if(ses->server->tcpStatus == CifsExiting)
531                 return -ENOENT;
532
533         /* Ensure that we do not send more than 50 overlapping requests 
534            to the same server. We may make this configurable later or
535            use ses->maxReq */
536         if(long_op == -1) {
537                 /* oplock breaks must not be held up */
538                 atomic_inc(&ses->server->inFlight);
539         } else {
540                 spin_lock(&GlobalMid_Lock); 
541                 while(1) {        
542                         if(atomic_read(&ses->server->inFlight) >= 
543                                         cifs_max_pending){
544                                 spin_unlock(&GlobalMid_Lock);
545                                 wait_event(ses->server->request_q,
546                                         atomic_read(&ses->server->inFlight)
547                                          < cifs_max_pending);
548                                 spin_lock(&GlobalMid_Lock);
549                         } else {
550                                 if(ses->server->tcpStatus == CifsExiting) {
551                                         spin_unlock(&GlobalMid_Lock);
552                                         return -ENOENT;
553                                 }
554
555                         /* can not count locking commands against total since
556                            they are allowed to block on server */
557                                         
558                                 if(long_op < 3) {
559                                 /* update # of requests on the wire to server */
560                                         atomic_inc(&ses->server->inFlight);
561                                 }
562                                 spin_unlock(&GlobalMid_Lock);
563                                 break;
564                         }
565                 }
566         }
567         /* make sure that we sign in the same order that we send on this socket 
568            and avoid races inside tcp sendmsg code that could cause corruption
569            of smb data */
570
571         down(&ses->server->tcpSem); 
572
573         if (ses->server->tcpStatus == CifsExiting) {
574                 rc = -ENOENT;
575                 goto out_unlock;
576         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
577                 cFYI(1,("tcp session dead - return to caller to retry"));
578                 rc = -EAGAIN;
579                 goto out_unlock;
580         } else if (ses->status != CifsGood) {
581                 /* check if SMB session is bad because we are setting it up */
582                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
583                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
584                         rc = -EAGAIN;
585                         goto out_unlock;
586                 } /* else ok - we are setting up session */
587         }
588         midQ = AllocMidQEntry(in_buf, ses);
589         if (midQ == NULL) {
590                 up(&ses->server->tcpSem);
591                 /* If not lock req, update # of requests on wire to server */
592                 if(long_op < 3) {
593                         atomic_dec(&ses->server->inFlight); 
594                         wake_up(&ses->server->request_q);
595                 }
596                 return -ENOMEM;
597         }
598
599         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
600                 up(&ses->server->tcpSem);
601                 cERROR(1,
602                        ("Illegal length, greater than maximum frame, %d ",
603                         in_buf->smb_buf_length));
604                 DeleteMidQEntry(midQ);
605                 /* If not lock req, update # of requests on wire to server */
606                 if(long_op < 3) {
607                         atomic_dec(&ses->server->inFlight); 
608                         wake_up(&ses->server->request_q);
609                 }
610                 return -EIO;
611         }
612
613         rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
614
615         midQ->midState = MID_REQUEST_SUBMITTED;
616         rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
617                       (struct sockaddr *) &(ses->server->addr.sockAddr));
618         if(rc < 0) {
619                 DeleteMidQEntry(midQ);
620                 up(&ses->server->tcpSem);
621                 /* If not lock req, update # of requests on wire to server */
622                 if(long_op < 3) {
623                         atomic_dec(&ses->server->inFlight); 
624                         wake_up(&ses->server->request_q);
625                 }
626                 return rc;
627         } else
628                 up(&ses->server->tcpSem);
629         if (long_op == -1)
630                 goto cifs_no_response_exit;
631         else if (long_op == 2) /* writes past end of file can take loong time */
632                 timeout = 300 * HZ;
633         else if (long_op == 1)
634                 timeout = 45 * HZ; /* should be greater than 
635                         servers oplock break timeout (about 43 seconds) */
636         else if (long_op > 2) {
637                 timeout = MAX_SCHEDULE_TIMEOUT;
638         } else
639                 timeout = 15 * HZ;
640         /* wait for 15 seconds or until woken up due to response arriving or 
641            due to last connection to this server being unmounted */
642         if (signal_pending(current)) {
643                 /* if signal pending do not hold up user for full smb timeout
644                 but we still give response a change to complete */
645                 timeout = 2 * HZ;
646         }   
647
648         /* No user interrupts in wait - wreaks havoc with performance */
649         if(timeout != MAX_SCHEDULE_TIMEOUT) {
650                 timeout += jiffies;
651                 wait_event(ses->server->response_q,
652                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
653                         time_after(jiffies, timeout) || 
654                         ((ses->server->tcpStatus != CifsGood) &&
655                          (ses->server->tcpStatus != CifsNew)));
656         } else {
657                 wait_event(ses->server->response_q,
658                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
659                         ((ses->server->tcpStatus != CifsGood) &&
660                          (ses->server->tcpStatus != CifsNew)));
661         }
662
663         spin_lock(&GlobalMid_Lock);
664         if (midQ->resp_buf) {
665                 spin_unlock(&GlobalMid_Lock);
666                 receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
667         } else {
668                 cERROR(1,("No response buffer"));
669                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
670                         if(ses->server->tcpStatus == CifsExiting)
671                                 rc = -EHOSTDOWN;
672                         else {
673                                 ses->server->tcpStatus = CifsNeedReconnect;
674                                 midQ->midState = MID_RETRY_NEEDED;
675                         }
676                 }
677
678                 if (rc != -EHOSTDOWN) {
679                         if(midQ->midState == MID_RETRY_NEEDED) {
680                                 rc = -EAGAIN;
681                                 cFYI(1,("marking request for retry"));
682                         } else {
683                                 rc = -EIO;
684                         }
685                 }
686                 spin_unlock(&GlobalMid_Lock);
687                 DeleteMidQEntry(midQ);
688                 /* If not lock req, update # of requests on wire to server */
689                 if(long_op < 3) {
690                         atomic_dec(&ses->server->inFlight); 
691                         wake_up(&ses->server->request_q);
692                 }
693                 return rc;
694         }
695   
696         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
697                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
698                         receive_len, xid));
699                 rc = -EIO;
700         } else {                /* rcvd frame is ok */
701
702                 if (midQ->resp_buf && out_buf
703                     && (midQ->midState == MID_RESPONSE_RECEIVED)) {
704                         out_buf->smb_buf_length = receive_len;
705                         memcpy((char *)out_buf + 4,
706                                (char *)midQ->resp_buf + 4,
707                                receive_len);
708
709                         dump_smb(out_buf, 92);
710                         /* convert the length into a more usable form */
711                         if((receive_len > 24) &&
712                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
713                                         SECMODE_SIGN_ENABLED))) {
714                                 rc = cifs_verify_signature(out_buf,
715                                                 ses->server->mac_signing_key,
716                                                 midQ->sequence_number+1);
717                                 if(rc) {
718                                         cERROR(1,("Unexpected SMB signature"));
719                                         /* BB FIXME add code to kill session */
720                                 }
721                         }
722
723                         *pbytes_returned = out_buf->smb_buf_length;
724
725                         /* BB special case reconnect tid and uid here? */
726                         rc = map_smb_to_linux_error(out_buf);
727
728                         /* convert ByteCount if necessary */
729                         if (receive_len >=
730                             sizeof (struct smb_hdr) -
731                             4 /* do not count RFC1001 header */  +
732                             (2 * out_buf->WordCount) + 2 /* bcc */ )
733                                 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
734                 } else {
735                         rc = -EIO;
736                         cFYI(1,("Bad MID state? "));
737                 }
738         }
739 cifs_no_response_exit:
740         DeleteMidQEntry(midQ);
741
742         if(long_op < 3) {
743                 atomic_dec(&ses->server->inFlight); 
744                 wake_up(&ses->server->request_q);
745         }
746
747         return rc;
748
749 out_unlock:
750         up(&ses->server->tcpSem);
751         /* If not lock req, update # of requests on wire to server */
752         if(long_op < 3) {
753                 atomic_dec(&ses->server->inFlight); 
754                 wake_up(&ses->server->request_q);
755         }
756
757         return rc;
758 }