Merge ../linux-2.6
[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);*/ /* easier to use jiffies */
63                 /* when mid allocated can be before when sent */
64                 temp->when_alloc = jiffies;
65                 temp->ses = ses;
66                 temp->tsk = current;
67         }
68
69         spin_lock(&GlobalMid_Lock);
70         list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
71         atomic_inc(&midCount);
72         temp->midState = MID_REQUEST_ALLOCATED;
73         spin_unlock(&GlobalMid_Lock);
74         return temp;
75 }
76
77 static void
78 DeleteMidQEntry(struct mid_q_entry *midEntry)
79 {
80 #ifdef CONFIG_CIFS_STATS2
81         unsigned long now;
82 #endif
83         spin_lock(&GlobalMid_Lock);
84         midEntry->midState = MID_FREE;
85         list_del(&midEntry->qhead);
86         atomic_dec(&midCount);
87         spin_unlock(&GlobalMid_Lock);
88         if(midEntry->largeBuf)
89                 cifs_buf_release(midEntry->resp_buf);
90         else
91                 cifs_small_buf_release(midEntry->resp_buf);
92 #ifdef CONFIG_CIFS_STATS2
93         now = jiffies;
94         /* commands taking longer than one second are indications that
95            something is wrong, unless it is quite a slow link or server */
96         if((now - midEntry->when_alloc) > HZ) {
97                 if((cifsFYI & CIFS_TIMER) && 
98                    (midEntry->command != SMB_COM_LOCKING_ANDX)) {
99                         printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
100                                midEntry->command, midEntry->mid);
101                         printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
102                                now - midEntry->when_alloc,
103                                now - midEntry->when_sent,
104                                now - midEntry->when_received);
105                 }
106         }
107 #endif
108         mempool_free(midEntry, cifs_mid_poolp);
109 }
110
111 struct oplock_q_entry *
112 AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
113 {
114         struct oplock_q_entry *temp;
115         if ((pinode== NULL) || (tcon == NULL)) {
116                 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
117                 return NULL;
118         }
119         temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
120                                                        SLAB_KERNEL);
121         if (temp == NULL)
122                 return temp;
123         else {
124                 temp->pinode = pinode;
125                 temp->tcon = tcon;
126                 temp->netfid = fid;
127                 spin_lock(&GlobalMid_Lock);
128                 list_add_tail(&temp->qhead, &GlobalOplock_Q);
129                 spin_unlock(&GlobalMid_Lock);
130         }
131         return temp;
132
133 }
134
135 void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
136 {
137         spin_lock(&GlobalMid_Lock); 
138     /* should we check if list empty first? */
139         list_del(&oplockEntry->qhead);
140         spin_unlock(&GlobalMid_Lock);
141         kmem_cache_free(cifs_oplock_cachep, oplockEntry);
142 }
143
144 int
145 smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
146          unsigned int smb_buf_length, struct sockaddr *sin)
147 {
148         int rc = 0;
149         int i = 0;
150         struct msghdr smb_msg;
151         struct kvec iov;
152         unsigned len = smb_buf_length + 4;
153
154         if(ssocket == NULL)
155                 return -ENOTSOCK; /* BB eventually add reconnect code here */
156         iov.iov_base = smb_buffer;
157         iov.iov_len = len;
158
159         smb_msg.msg_name = sin;
160         smb_msg.msg_namelen = sizeof (struct sockaddr);
161         smb_msg.msg_control = NULL;
162         smb_msg.msg_controllen = 0;
163         smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
164
165         /* smb header is converted in header_assemble. bcc and rest of SMB word
166            area, and byte area if necessary, is converted to littleendian in 
167            cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
168            Flags2 is converted in SendReceive */
169
170         smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
171         cFYI(1, ("Sending smb of length %d", smb_buf_length));
172         dump_smb(smb_buffer, len);
173
174         while (len > 0) {
175                 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
176                 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
177                         i++;
178                 /* smaller timeout here than send2 since smaller size */
179                 /* Although it may not be required, this also is smaller 
180                    oplock break time */  
181                         if(i > 12) {
182                                 cERROR(1,
183                                    ("sends on sock %p stuck for 7 seconds",
184                                     ssocket));
185                                 rc = -EAGAIN;
186                                 break;
187                         }
188                         msleep(1 << i);
189                         continue;
190                 }
191                 if (rc < 0) 
192                         break;
193                 else
194                         i = 0; /* reset i after each successful send */
195                 iov.iov_base += rc;
196                 iov.iov_len -= rc;
197                 len -= rc;
198         }
199
200         if (rc < 0) {
201                 cERROR(1,("Error %d sending data on socket to server", rc));
202         } else {
203                 rc = 0;
204         }
205
206         return rc;
207 }
208
209 static int
210 smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
211           struct sockaddr *sin)
212 {
213         int rc = 0;
214         int i = 0;
215         struct msghdr smb_msg;
216         struct smb_hdr *smb_buffer = iov[0].iov_base;
217         unsigned int len = iov[0].iov_len;
218         unsigned int total_len;
219         int first_vec = 0;
220         
221         if(ssocket == NULL)
222                 return -ENOTSOCK; /* BB eventually add reconnect code here */
223
224         smb_msg.msg_name = sin;
225         smb_msg.msg_namelen = sizeof (struct sockaddr);
226         smb_msg.msg_control = NULL;
227         smb_msg.msg_controllen = 0;
228         smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
229
230         /* smb header is converted in header_assemble. bcc and rest of SMB word
231            area, and byte area if necessary, is converted to littleendian in 
232            cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
233            Flags2 is converted in SendReceive */
234
235
236         total_len = 0;
237         for (i = 0; i < n_vec; i++)
238                 total_len += iov[i].iov_len;
239
240         smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
241         cFYI(1, ("Sending smb:  total_len %d", total_len));
242         dump_smb(smb_buffer, len);
243
244         while (total_len) {
245                 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
246                                     n_vec - first_vec, total_len);
247                 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
248                         i++;
249                         if(i >= 14) {
250                                 cERROR(1,
251                                    ("sends on sock %p stuck for 15 seconds",
252                                     ssocket));
253                                 rc = -EAGAIN;
254                                 break;
255                         }
256                         msleep(1 << i);
257                         continue;
258                 }
259                 if (rc < 0) 
260                         break;
261
262                 if (rc >= total_len) {
263                         WARN_ON(rc > total_len);
264                         break;
265                 }
266                 if(rc == 0) {
267                         /* should never happen, letting socket clear before
268                            retrying is our only obvious option here */
269                         cERROR(1,("tcp sent no data"));
270                         msleep(500);
271                         continue;
272                 }
273                 total_len -= rc;
274                 /* the line below resets i */
275                 for (i = first_vec; i < n_vec; i++) {
276                         if (iov[i].iov_len) {
277                                 if (rc > iov[i].iov_len) {
278                                         rc -= iov[i].iov_len;
279                                         iov[i].iov_len = 0;
280                                 } else {
281                                         iov[i].iov_base += rc;
282                                         iov[i].iov_len -= rc;
283                                         first_vec = i;
284                                         break;
285                                 }
286                         }
287                 }
288                 i = 0; /* in case we get ENOSPC on the next send */
289         }
290
291         if (rc < 0) {
292                 cERROR(1,("Error %d sending data on socket to server", rc));
293         } else
294                 rc = 0;
295
296         return rc;
297 }
298
299 int
300 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
301              struct kvec *iov, int n_vec, int * pRespBufType /* ret */, 
302              const int long_op)
303 {
304         int rc = 0;
305         unsigned int receive_len;
306         unsigned long timeout;
307         struct mid_q_entry *midQ;
308         struct smb_hdr *in_buf = iov[0].iov_base;
309         
310         *pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
311
312         if (ses == NULL) {
313                 cERROR(1,("Null smb session"));
314                 return -EIO;
315         }
316         if(ses->server == NULL) {
317                 cERROR(1,("Null tcp session"));
318                 return -EIO;
319         }
320
321         if(ses->server->tcpStatus == CifsExiting)
322                 return -ENOENT;
323
324         /* Ensure that we do not send more than 50 overlapping requests 
325            to the same server. We may make this configurable later or
326            use ses->maxReq */
327         if(long_op == -1) {
328                 /* oplock breaks must not be held up */
329                 atomic_inc(&ses->server->inFlight);
330         } else {
331                 spin_lock(&GlobalMid_Lock); 
332                 while(1) {        
333                         if(atomic_read(&ses->server->inFlight) >= 
334                                         cifs_max_pending){
335                                 spin_unlock(&GlobalMid_Lock);
336 #ifdef CONFIG_CIFS_STATS2
337                                 atomic_inc(&ses->server->num_waiters);
338 #endif
339                                 wait_event(ses->server->request_q,
340                                         atomic_read(&ses->server->inFlight)
341                                          < cifs_max_pending);
342 #ifdef CONFIG_CIFS_STATS2
343                                 atomic_dec(&ses->server->num_waiters);
344 #endif
345                                 spin_lock(&GlobalMid_Lock);
346                         } else {
347                                 if(ses->server->tcpStatus == CifsExiting) {
348                                         spin_unlock(&GlobalMid_Lock);
349                                         return -ENOENT;
350                                 }
351
352                         /* can not count locking commands against total since
353                            they are allowed to block on server */
354                                         
355                                 if(long_op < 3) {
356                                 /* update # of requests on the wire to server */
357                                         atomic_inc(&ses->server->inFlight);
358                                 }
359                                 spin_unlock(&GlobalMid_Lock);
360                                 break;
361                         }
362                 }
363         }
364         /* make sure that we sign in the same order that we send on this socket 
365            and avoid races inside tcp sendmsg code that could cause corruption
366            of smb data */
367
368         down(&ses->server->tcpSem); 
369
370         if (ses->server->tcpStatus == CifsExiting) {
371                 rc = -ENOENT;
372                 goto out_unlock2;
373         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
374                 cFYI(1,("tcp session dead - return to caller to retry"));
375                 rc = -EAGAIN;
376                 goto out_unlock2;
377         } else if (ses->status != CifsGood) {
378                 /* check if SMB session is bad because we are setting it up */
379                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
380                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
381                         rc = -EAGAIN;
382                         goto out_unlock2;
383                 } /* else ok - we are setting up session */
384         }
385         midQ = AllocMidQEntry(in_buf, ses);
386         if (midQ == NULL) {
387                 up(&ses->server->tcpSem);
388                 /* If not lock req, update # of requests on wire to server */
389                 if(long_op < 3) {
390                         atomic_dec(&ses->server->inFlight); 
391                         wake_up(&ses->server->request_q);
392                 }
393                 return -ENOMEM;
394         }
395
396         rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
397
398         midQ->midState = MID_REQUEST_SUBMITTED;
399 #ifdef CONFIG_CIFS_STATS2
400         atomic_inc(&ses->server->inSend);
401 #endif
402         rc = smb_send2(ses->server->ssocket, iov, n_vec,
403                       (struct sockaddr *) &(ses->server->addr.sockAddr));
404 #ifdef CONFIG_CIFS_STATS2
405         atomic_dec(&ses->server->inSend);
406         midQ->when_sent = jiffies;
407 #endif
408         if(rc < 0) {
409                 DeleteMidQEntry(midQ);
410                 up(&ses->server->tcpSem);
411                 /* If not lock req, update # of requests on wire to server */
412                 if(long_op < 3) {
413                         atomic_dec(&ses->server->inFlight); 
414                         wake_up(&ses->server->request_q);
415                 }
416                 return rc;
417         } else
418                 up(&ses->server->tcpSem);
419         if (long_op == -1)
420                 goto cifs_no_response_exit2;
421         else if (long_op == 2) /* writes past end of file can take loong time */
422                 timeout = 180 * HZ;
423         else if (long_op == 1)
424                 timeout = 45 * HZ; /* should be greater than 
425                         servers oplock break timeout (about 43 seconds) */
426         else if (long_op > 2) {
427                 timeout = MAX_SCHEDULE_TIMEOUT;
428         } else
429                 timeout = 15 * HZ;
430         /* wait for 15 seconds or until woken up due to response arriving or 
431            due to last connection to this server being unmounted */
432         if (signal_pending(current)) {
433                 /* if signal pending do not hold up user for full smb timeout
434                 but we still give response a change to complete */
435                 timeout = 2 * HZ;
436         }   
437
438         /* No user interrupts in wait - wreaks havoc with performance */
439         if(timeout != MAX_SCHEDULE_TIMEOUT) {
440                 timeout += jiffies;
441                 wait_event(ses->server->response_q,
442                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
443                         time_after(jiffies, timeout) || 
444                         ((ses->server->tcpStatus != CifsGood) &&
445                          (ses->server->tcpStatus != CifsNew)));
446         } else {
447                 wait_event(ses->server->response_q,
448                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
449                         ((ses->server->tcpStatus != CifsGood) &&
450                          (ses->server->tcpStatus != CifsNew)));
451         }
452
453         spin_lock(&GlobalMid_Lock);
454         if (midQ->resp_buf) {
455                 spin_unlock(&GlobalMid_Lock);
456                 receive_len = midQ->resp_buf->smb_buf_length;
457         } else {
458                 cERROR(1,("No response to cmd %d mid %d",
459                         midQ->command, midQ->mid));
460                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
461                         if(ses->server->tcpStatus == CifsExiting)
462                                 rc = -EHOSTDOWN;
463                         else {
464                                 ses->server->tcpStatus = CifsNeedReconnect;
465                                 midQ->midState = MID_RETRY_NEEDED;
466                         }
467                 }
468
469                 if (rc != -EHOSTDOWN) {
470                         if(midQ->midState == MID_RETRY_NEEDED) {
471                                 rc = -EAGAIN;
472                                 cFYI(1,("marking request for retry"));
473                         } else {
474                                 rc = -EIO;
475                         }
476                 }
477                 spin_unlock(&GlobalMid_Lock);
478                 DeleteMidQEntry(midQ);
479                 /* If not lock req, update # of requests on wire to server */
480                 if(long_op < 3) {
481                         atomic_dec(&ses->server->inFlight); 
482                         wake_up(&ses->server->request_q);
483                 }
484                 return rc;
485         }
486   
487         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
488                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
489                         receive_len, xid));
490                 rc = -EIO;
491         } else {                /* rcvd frame is ok */
492                 if (midQ->resp_buf && 
493                         (midQ->midState == MID_RESPONSE_RECEIVED)) {
494
495                         iov[0].iov_base = (char *)midQ->resp_buf;
496                         if(midQ->largeBuf)
497                                 *pRespBufType = CIFS_LARGE_BUFFER;
498                         else
499                                 *pRespBufType = CIFS_SMALL_BUFFER;
500                         iov[0].iov_len = receive_len + 4;
501
502                         dump_smb(midQ->resp_buf, 80);
503                         /* convert the length into a more usable form */
504                         if((receive_len > 24) &&
505                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
506                                         SECMODE_SIGN_ENABLED))) {
507                                 rc = cifs_verify_signature(midQ->resp_buf,
508                                                 ses->server->mac_signing_key,
509                                                 midQ->sequence_number+1);
510                                 if(rc) {
511                                         cERROR(1,("Unexpected SMB signature"));
512                                         /* BB FIXME add code to kill session */
513                                 }
514                         }
515
516                         /* BB special case reconnect tid and uid here? */
517                         /* BB special case Errbadpassword and pwdexpired here */
518                         rc = map_smb_to_linux_error(midQ->resp_buf);
519
520                         /* convert ByteCount if necessary */
521                         if (receive_len >=
522                             sizeof (struct smb_hdr) -
523                             4 /* do not count RFC1001 header */  +
524                             (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
525                                 BCC(midQ->resp_buf) = 
526                                         le16_to_cpu(BCC_LE(midQ->resp_buf));
527                         midQ->resp_buf = NULL;  /* mark it so will not be freed
528                                                 by DeleteMidQEntry */
529                 } else {
530                         rc = -EIO;
531                         cFYI(1,("Bad MID state?"));
532                 }
533         }
534 cifs_no_response_exit2:
535         DeleteMidQEntry(midQ);
536
537         if(long_op < 3) {
538                 atomic_dec(&ses->server->inFlight); 
539                 wake_up(&ses->server->request_q);
540         }
541
542         return rc;
543
544 out_unlock2:
545         up(&ses->server->tcpSem);
546         /* If not lock req, update # of requests on wire to server */
547         if(long_op < 3) {
548                 atomic_dec(&ses->server->inFlight); 
549                 wake_up(&ses->server->request_q);
550         }
551
552         return rc;
553 }
554
555 int
556 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
557             struct smb_hdr *in_buf, struct smb_hdr *out_buf,
558             int *pbytes_returned, const int long_op)
559 {
560         int rc = 0;
561         unsigned int receive_len;
562         unsigned long timeout;
563         struct mid_q_entry *midQ;
564
565         if (ses == NULL) {
566                 cERROR(1,("Null smb session"));
567                 return -EIO;
568         }
569         if(ses->server == NULL) {
570                 cERROR(1,("Null tcp session"));
571                 return -EIO;
572         }
573
574         if(ses->server->tcpStatus == CifsExiting)
575                 return -ENOENT;
576
577         /* Ensure that we do not send more than 50 overlapping requests 
578            to the same server. We may make this configurable later or
579            use ses->maxReq */
580         if(long_op == -1) {
581                 /* oplock breaks must not be held up */
582                 atomic_inc(&ses->server->inFlight);
583         } else {
584                 spin_lock(&GlobalMid_Lock); 
585                 while(1) {        
586                         if(atomic_read(&ses->server->inFlight) >= 
587                                         cifs_max_pending){
588                                 spin_unlock(&GlobalMid_Lock);
589 #ifdef CONFIG_CIFS_STATS2
590                                 atomic_inc(&ses->server->num_waiters);
591 #endif
592                                 wait_event(ses->server->request_q,
593                                         atomic_read(&ses->server->inFlight)
594                                          < cifs_max_pending);
595 #ifdef CONFIG_CIFS_STATS2
596                                 atomic_dec(&ses->server->num_waiters);
597 #endif
598                                 spin_lock(&GlobalMid_Lock);
599                         } else {
600                                 if(ses->server->tcpStatus == CifsExiting) {
601                                         spin_unlock(&GlobalMid_Lock);
602                                         return -ENOENT;
603                                 }
604
605                         /* can not count locking commands against total since
606                            they are allowed to block on server */
607                                         
608                                 if(long_op < 3) {
609                                 /* update # of requests on the wire to server */
610                                         atomic_inc(&ses->server->inFlight);
611                                 }
612                                 spin_unlock(&GlobalMid_Lock);
613                                 break;
614                         }
615                 }
616         }
617         /* make sure that we sign in the same order that we send on this socket 
618            and avoid races inside tcp sendmsg code that could cause corruption
619            of smb data */
620
621         down(&ses->server->tcpSem); 
622
623         if (ses->server->tcpStatus == CifsExiting) {
624                 rc = -ENOENT;
625                 goto out_unlock;
626         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
627                 cFYI(1,("tcp session dead - return to caller to retry"));
628                 rc = -EAGAIN;
629                 goto out_unlock;
630         } else if (ses->status != CifsGood) {
631                 /* check if SMB session is bad because we are setting it up */
632                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
633                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
634                         rc = -EAGAIN;
635                         goto out_unlock;
636                 } /* else ok - we are setting up session */
637         }
638         midQ = AllocMidQEntry(in_buf, ses);
639         if (midQ == NULL) {
640                 up(&ses->server->tcpSem);
641                 /* If not lock req, update # of requests on wire to server */
642                 if(long_op < 3) {
643                         atomic_dec(&ses->server->inFlight); 
644                         wake_up(&ses->server->request_q);
645                 }
646                 return -ENOMEM;
647         }
648
649         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
650                 up(&ses->server->tcpSem);
651                 cERROR(1,
652                        ("Illegal length, greater than maximum frame, %d ",
653                         in_buf->smb_buf_length));
654                 DeleteMidQEntry(midQ);
655                 /* If not lock req, update # of requests on wire to server */
656                 if(long_op < 3) {
657                         atomic_dec(&ses->server->inFlight); 
658                         wake_up(&ses->server->request_q);
659                 }
660                 return -EIO;
661         }
662
663         rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
664
665         midQ->midState = MID_REQUEST_SUBMITTED;
666 #ifdef CONFIG_CIFS_STATS2
667         atomic_inc(&ses->server->inSend);
668 #endif
669         rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
670                       (struct sockaddr *) &(ses->server->addr.sockAddr));
671 #ifdef CONFIG_CIFS_STATS2
672         atomic_dec(&ses->server->inSend);
673         midQ->when_sent = jiffies;
674 #endif
675         if(rc < 0) {
676                 DeleteMidQEntry(midQ);
677                 up(&ses->server->tcpSem);
678                 /* If not lock req, update # of requests on wire to server */
679                 if(long_op < 3) {
680                         atomic_dec(&ses->server->inFlight); 
681                         wake_up(&ses->server->request_q);
682                 }
683                 return rc;
684         } else
685                 up(&ses->server->tcpSem);
686         if (long_op == -1)
687                 goto cifs_no_response_exit;
688         else if (long_op == 2) /* writes past end of file can take loong time */
689                 timeout = 180 * HZ;
690         else if (long_op == 1)
691                 timeout = 45 * HZ; /* should be greater than 
692                         servers oplock break timeout (about 43 seconds) */
693         else if (long_op > 2) {
694                 timeout = MAX_SCHEDULE_TIMEOUT;
695         } else
696                 timeout = 15 * HZ;
697         /* wait for 15 seconds or until woken up due to response arriving or 
698            due to last connection to this server being unmounted */
699         if (signal_pending(current)) {
700                 /* if signal pending do not hold up user for full smb timeout
701                 but we still give response a change to complete */
702                 timeout = 2 * HZ;
703         }   
704
705         /* No user interrupts in wait - wreaks havoc with performance */
706         if(timeout != MAX_SCHEDULE_TIMEOUT) {
707                 timeout += jiffies;
708                 wait_event(ses->server->response_q,
709                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
710                         time_after(jiffies, timeout) || 
711                         ((ses->server->tcpStatus != CifsGood) &&
712                          (ses->server->tcpStatus != CifsNew)));
713         } else {
714                 wait_event(ses->server->response_q,
715                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
716                         ((ses->server->tcpStatus != CifsGood) &&
717                          (ses->server->tcpStatus != CifsNew)));
718         }
719
720         spin_lock(&GlobalMid_Lock);
721         if (midQ->resp_buf) {
722                 spin_unlock(&GlobalMid_Lock);
723                 receive_len = midQ->resp_buf->smb_buf_length;
724         } else {
725                 cERROR(1,("No response for cmd %d mid %d",
726                           midQ->command, midQ->mid));
727                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
728                         if(ses->server->tcpStatus == CifsExiting)
729                                 rc = -EHOSTDOWN;
730                         else {
731                                 ses->server->tcpStatus = CifsNeedReconnect;
732                                 midQ->midState = MID_RETRY_NEEDED;
733                         }
734                 }
735
736                 if (rc != -EHOSTDOWN) {
737                         if(midQ->midState == MID_RETRY_NEEDED) {
738                                 rc = -EAGAIN;
739                                 cFYI(1,("marking request for retry"));
740                         } else {
741                                 rc = -EIO;
742                         }
743                 }
744                 spin_unlock(&GlobalMid_Lock);
745                 DeleteMidQEntry(midQ);
746                 /* If not lock req, update # of requests on wire to server */
747                 if(long_op < 3) {
748                         atomic_dec(&ses->server->inFlight); 
749                         wake_up(&ses->server->request_q);
750                 }
751                 return rc;
752         }
753   
754         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
755                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
756                         receive_len, xid));
757                 rc = -EIO;
758         } else {                /* rcvd frame is ok */
759
760                 if (midQ->resp_buf && out_buf
761                     && (midQ->midState == MID_RESPONSE_RECEIVED)) {
762                         out_buf->smb_buf_length = receive_len;
763                         memcpy((char *)out_buf + 4,
764                                (char *)midQ->resp_buf + 4,
765                                receive_len);
766
767                         dump_smb(out_buf, 92);
768                         /* convert the length into a more usable form */
769                         if((receive_len > 24) &&
770                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
771                                         SECMODE_SIGN_ENABLED))) {
772                                 rc = cifs_verify_signature(out_buf,
773                                                 ses->server->mac_signing_key,
774                                                 midQ->sequence_number+1);
775                                 if(rc) {
776                                         cERROR(1,("Unexpected SMB signature"));
777                                         /* BB FIXME add code to kill session */
778                                 }
779                         }
780
781                         *pbytes_returned = out_buf->smb_buf_length;
782
783                         /* BB special case reconnect tid and uid here? */
784                         rc = map_smb_to_linux_error(out_buf);
785
786                         /* convert ByteCount if necessary */
787                         if (receive_len >=
788                             sizeof (struct smb_hdr) -
789                             4 /* do not count RFC1001 header */  +
790                             (2 * out_buf->WordCount) + 2 /* bcc */ )
791                                 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
792                 } else {
793                         rc = -EIO;
794                         cERROR(1,("Bad MID state?"));
795                 }
796         }
797 cifs_no_response_exit:
798         DeleteMidQEntry(midQ);
799
800         if(long_op < 3) {
801                 atomic_dec(&ses->server->inFlight); 
802                 wake_up(&ses->server->request_q);
803         }
804
805         return rc;
806
807 out_unlock:
808         up(&ses->server->tcpSem);
809         /* If not lock req, update # of requests on wire to server */
810         if(long_op < 3) {
811                 atomic_dec(&ses->server->inFlight); 
812                 wake_up(&ses->server->request_q);
813         }
814
815         return rc;
816 }