[CIFS] Fix sparse warnings on smb bcc (byte count)
[pandora-kernel.git] / 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 #ifdef CONFIG_CIFS_EXPERIMENTAL
210 static int
211 smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
212           struct sockaddr *sin)
213 {
214         int rc = 0;
215         int i = 0;
216         struct msghdr smb_msg;
217         struct smb_hdr *smb_buffer = iov[0].iov_base;
218         unsigned int len = iov[0].iov_len;
219         unsigned int total_len;
220         int first_vec = 0;
221         
222         if(ssocket == NULL)
223                 return -ENOTSOCK; /* BB eventually add reconnect code here */
224
225         smb_msg.msg_name = sin;
226         smb_msg.msg_namelen = sizeof (struct sockaddr);
227         smb_msg.msg_control = NULL;
228         smb_msg.msg_controllen = 0;
229         smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
230
231         /* smb header is converted in header_assemble. bcc and rest of SMB word
232            area, and byte area if necessary, is converted to littleendian in 
233            cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
234            Flags2 is converted in SendReceive */
235
236
237         total_len = 0;
238         for (i = 0; i < n_vec; i++)
239                 total_len += iov[i].iov_len;
240
241         smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
242         cFYI(1, ("Sending smb:  total_len %d", total_len));
243         dump_smb(smb_buffer, len);
244
245         while (total_len) {
246                 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
247                                     n_vec - first_vec, total_len);
248                 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
249                         i++;
250                         if(i >= 14) {
251                                 cERROR(1,
252                                    ("sends on sock %p stuck for 15 seconds",
253                                     ssocket));
254                                 rc = -EAGAIN;
255                                 break;
256                         }
257                         msleep(1 << i);
258                         continue;
259                 }
260                 if (rc < 0) 
261                         break;
262
263                 if (rc >= total_len) {
264                         WARN_ON(rc > total_len);
265                         break;
266                 }
267                 if(rc == 0) {
268                         /* should never happen, letting socket clear before
269                            retrying is our only obvious option here */
270                         cERROR(1,("tcp sent no data"));
271                         msleep(500);
272                         continue;
273                 }
274                 total_len -= rc;
275                 /* the line below resets i */
276                 for (i = first_vec; i < n_vec; i++) {
277                         if (iov[i].iov_len) {
278                                 if (rc > iov[i].iov_len) {
279                                         rc -= iov[i].iov_len;
280                                         iov[i].iov_len = 0;
281                                 } else {
282                                         iov[i].iov_base += rc;
283                                         iov[i].iov_len -= rc;
284                                         first_vec = i;
285                                         break;
286                                 }
287                         }
288                 }
289                 i = 0; /* in case we get ENOSPC on the next send */
290         }
291
292         if (rc < 0) {
293                 cERROR(1,("Error %d sending data on socket to server", rc));
294         } else
295                 rc = 0;
296
297         return rc;
298 }
299
300 int
301 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
302              struct kvec *iov, int n_vec, int *pbytes_returned,
303              const int long_op)
304 {
305         int rc = 0;
306         unsigned int receive_len;
307         unsigned long timeout;
308         struct mid_q_entry *midQ;
309         struct smb_hdr *in_buf = iov[0].iov_base;
310
311         if (ses == NULL) {
312                 cERROR(1,("Null smb session"));
313                 return -EIO;
314         }
315         if(ses->server == NULL) {
316                 cERROR(1,("Null tcp session"));
317                 return -EIO;
318         }
319
320         if(ses->server->tcpStatus == CifsExiting)
321                 return -ENOENT;
322
323         /* Ensure that we do not send more than 50 overlapping requests 
324            to the same server. We may make this configurable later or
325            use ses->maxReq */
326         if(long_op == -1) {
327                 /* oplock breaks must not be held up */
328                 atomic_inc(&ses->server->inFlight);
329         } else {
330                 spin_lock(&GlobalMid_Lock); 
331                 while(1) {        
332                         if(atomic_read(&ses->server->inFlight) >= 
333                                         cifs_max_pending){
334                                 spin_unlock(&GlobalMid_Lock);
335 #ifdef CONFIG_CIFS_STATS2
336                                 atomic_inc(&ses->server->num_waiters);
337 #endif
338                                 wait_event(ses->server->request_q,
339                                         atomic_read(&ses->server->inFlight)
340                                          < cifs_max_pending);
341 #ifdef CONFIG_CIFS_STATS2
342                                 atomic_dec(&ses->server->num_waiters);
343 #endif
344                                 spin_lock(&GlobalMid_Lock);
345                         } else {
346                                 if(ses->server->tcpStatus == CifsExiting) {
347                                         spin_unlock(&GlobalMid_Lock);
348                                         return -ENOENT;
349                                 }
350
351                         /* can not count locking commands against total since
352                            they are allowed to block on server */
353                                         
354                                 if(long_op < 3) {
355                                 /* update # of requests on the wire to server */
356                                         atomic_inc(&ses->server->inFlight);
357                                 }
358                                 spin_unlock(&GlobalMid_Lock);
359                                 break;
360                         }
361                 }
362         }
363         /* make sure that we sign in the same order that we send on this socket 
364            and avoid races inside tcp sendmsg code that could cause corruption
365            of smb data */
366
367         down(&ses->server->tcpSem); 
368
369         if (ses->server->tcpStatus == CifsExiting) {
370                 rc = -ENOENT;
371                 goto out_unlock2;
372         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
373                 cFYI(1,("tcp session dead - return to caller to retry"));
374                 rc = -EAGAIN;
375                 goto out_unlock2;
376         } else if (ses->status != CifsGood) {
377                 /* check if SMB session is bad because we are setting it up */
378                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
379                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
380                         rc = -EAGAIN;
381                         goto out_unlock2;
382                 } /* else ok - we are setting up session */
383         }
384         midQ = AllocMidQEntry(in_buf, ses);
385         if (midQ == NULL) {
386                 up(&ses->server->tcpSem);
387                 /* If not lock req, update # of requests on wire to server */
388                 if(long_op < 3) {
389                         atomic_dec(&ses->server->inFlight); 
390                         wake_up(&ses->server->request_q);
391                 }
392                 return -ENOMEM;
393         }
394
395 /* BB FIXME */
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
493                 if (midQ->resp_buf && 
494                         (midQ->midState == MID_RESPONSE_RECEIVED)) {
495                         in_buf->smb_buf_length = receive_len;
496                         /* BB verify that length would not overrun small buf */
497                         memcpy((char *)in_buf + 4,
498                                (char *)midQ->resp_buf + 4,
499                                receive_len);
500
501                         dump_smb(in_buf, 80);
502                         /* convert the length into a more usable form */
503                         if((receive_len > 24) &&
504                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
505                                         SECMODE_SIGN_ENABLED))) {
506                                 rc = cifs_verify_signature(in_buf,
507                                                 ses->server->mac_signing_key,
508                                                 midQ->sequence_number+1);
509                                 if(rc) {
510                                         cERROR(1,("Unexpected SMB signature"));
511                                         /* BB FIXME add code to kill session */
512                                 }
513                         }
514
515                         *pbytes_returned = in_buf->smb_buf_length;
516
517                         /* BB special case reconnect tid and uid here? */
518                         rc = map_smb_to_linux_error(in_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 * in_buf->WordCount) + 2 /* bcc */ )
525                                 BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf));
526                 } else {
527                         rc = -EIO;
528                         cFYI(1,("Bad MID state?"));
529                 }
530         }
531 cifs_no_response_exit2:
532         DeleteMidQEntry(midQ);
533
534         if(long_op < 3) {
535                 atomic_dec(&ses->server->inFlight); 
536                 wake_up(&ses->server->request_q);
537         }
538
539         return rc;
540
541 out_unlock2:
542         up(&ses->server->tcpSem);
543         /* If not lock req, update # of requests on wire to server */
544         if(long_op < 3) {
545                 atomic_dec(&ses->server->inFlight); 
546                 wake_up(&ses->server->request_q);
547         }
548
549         return rc;
550 }
551 #endif /* CIFS_EXPERIMENTAL */
552
553 int
554 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
555             struct smb_hdr *in_buf, struct smb_hdr *out_buf,
556             int *pbytes_returned, const int long_op)
557 {
558         int rc = 0;
559         unsigned int receive_len;
560         unsigned long timeout;
561         struct mid_q_entry *midQ;
562
563         if (ses == NULL) {
564                 cERROR(1,("Null smb session"));
565                 return -EIO;
566         }
567         if(ses->server == NULL) {
568                 cERROR(1,("Null tcp session"));
569                 return -EIO;
570         }
571
572         if(ses->server->tcpStatus == CifsExiting)
573                 return -ENOENT;
574
575         /* Ensure that we do not send more than 50 overlapping requests 
576            to the same server. We may make this configurable later or
577            use ses->maxReq */
578         if(long_op == -1) {
579                 /* oplock breaks must not be held up */
580                 atomic_inc(&ses->server->inFlight);
581         } else {
582                 spin_lock(&GlobalMid_Lock); 
583                 while(1) {        
584                         if(atomic_read(&ses->server->inFlight) >= 
585                                         cifs_max_pending){
586                                 spin_unlock(&GlobalMid_Lock);
587 #ifdef CONFIG_CIFS_STATS2
588                                 atomic_inc(&ses->server->num_waiters);
589 #endif
590                                 wait_event(ses->server->request_q,
591                                         atomic_read(&ses->server->inFlight)
592                                          < cifs_max_pending);
593 #ifdef CONFIG_CIFS_STATS2
594                                 atomic_dec(&ses->server->num_waiters);
595 #endif
596                                 spin_lock(&GlobalMid_Lock);
597                         } else {
598                                 if(ses->server->tcpStatus == CifsExiting) {
599                                         spin_unlock(&GlobalMid_Lock);
600                                         return -ENOENT;
601                                 }
602
603                         /* can not count locking commands against total since
604                            they are allowed to block on server */
605                                         
606                                 if(long_op < 3) {
607                                 /* update # of requests on the wire to server */
608                                         atomic_inc(&ses->server->inFlight);
609                                 }
610                                 spin_unlock(&GlobalMid_Lock);
611                                 break;
612                         }
613                 }
614         }
615         /* make sure that we sign in the same order that we send on this socket 
616            and avoid races inside tcp sendmsg code that could cause corruption
617            of smb data */
618
619         down(&ses->server->tcpSem); 
620
621         if (ses->server->tcpStatus == CifsExiting) {
622                 rc = -ENOENT;
623                 goto out_unlock;
624         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
625                 cFYI(1,("tcp session dead - return to caller to retry"));
626                 rc = -EAGAIN;
627                 goto out_unlock;
628         } else if (ses->status != CifsGood) {
629                 /* check if SMB session is bad because we are setting it up */
630                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
631                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
632                         rc = -EAGAIN;
633                         goto out_unlock;
634                 } /* else ok - we are setting up session */
635         }
636         midQ = AllocMidQEntry(in_buf, ses);
637         if (midQ == NULL) {
638                 up(&ses->server->tcpSem);
639                 /* If not lock req, update # of requests on wire to server */
640                 if(long_op < 3) {
641                         atomic_dec(&ses->server->inFlight); 
642                         wake_up(&ses->server->request_q);
643                 }
644                 return -ENOMEM;
645         }
646
647         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
648                 up(&ses->server->tcpSem);
649                 cERROR(1,
650                        ("Illegal length, greater than maximum frame, %d ",
651                         in_buf->smb_buf_length));
652                 DeleteMidQEntry(midQ);
653                 /* If not lock req, update # of requests on wire to server */
654                 if(long_op < 3) {
655                         atomic_dec(&ses->server->inFlight); 
656                         wake_up(&ses->server->request_q);
657                 }
658                 return -EIO;
659         }
660
661         rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
662
663         midQ->midState = MID_REQUEST_SUBMITTED;
664 #ifdef CONFIG_CIFS_STATS2
665         atomic_inc(&ses->server->inSend);
666 #endif
667         rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
668                       (struct sockaddr *) &(ses->server->addr.sockAddr));
669 #ifdef CONFIG_CIFS_STATS2
670         atomic_dec(&ses->server->inSend);
671         midQ->when_sent = jiffies;
672 #endif
673         if(rc < 0) {
674                 DeleteMidQEntry(midQ);
675                 up(&ses->server->tcpSem);
676                 /* If not lock req, update # of requests on wire to server */
677                 if(long_op < 3) {
678                         atomic_dec(&ses->server->inFlight); 
679                         wake_up(&ses->server->request_q);
680                 }
681                 return rc;
682         } else
683                 up(&ses->server->tcpSem);
684         if (long_op == -1)
685                 goto cifs_no_response_exit;
686         else if (long_op == 2) /* writes past end of file can take loong time */
687                 timeout = 180 * HZ;
688         else if (long_op == 1)
689                 timeout = 45 * HZ; /* should be greater than 
690                         servers oplock break timeout (about 43 seconds) */
691         else if (long_op > 2) {
692                 timeout = MAX_SCHEDULE_TIMEOUT;
693         } else
694                 timeout = 15 * HZ;
695         /* wait for 15 seconds or until woken up due to response arriving or 
696            due to last connection to this server being unmounted */
697         if (signal_pending(current)) {
698                 /* if signal pending do not hold up user for full smb timeout
699                 but we still give response a change to complete */
700                 timeout = 2 * HZ;
701         }   
702
703         /* No user interrupts in wait - wreaks havoc with performance */
704         if(timeout != MAX_SCHEDULE_TIMEOUT) {
705                 timeout += jiffies;
706                 wait_event(ses->server->response_q,
707                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
708                         time_after(jiffies, timeout) || 
709                         ((ses->server->tcpStatus != CifsGood) &&
710                          (ses->server->tcpStatus != CifsNew)));
711         } else {
712                 wait_event(ses->server->response_q,
713                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
714                         ((ses->server->tcpStatus != CifsGood) &&
715                          (ses->server->tcpStatus != CifsNew)));
716         }
717
718         spin_lock(&GlobalMid_Lock);
719         if (midQ->resp_buf) {
720                 spin_unlock(&GlobalMid_Lock);
721                 receive_len = midQ->resp_buf->smb_buf_length;
722         } else {
723                 cERROR(1,("No response for cmd %d mid %d",
724                           midQ->command, midQ->mid));
725                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
726                         if(ses->server->tcpStatus == CifsExiting)
727                                 rc = -EHOSTDOWN;
728                         else {
729                                 ses->server->tcpStatus = CifsNeedReconnect;
730                                 midQ->midState = MID_RETRY_NEEDED;
731                         }
732                 }
733
734                 if (rc != -EHOSTDOWN) {
735                         if(midQ->midState == MID_RETRY_NEEDED) {
736                                 rc = -EAGAIN;
737                                 cFYI(1,("marking request for retry"));
738                         } else {
739                                 rc = -EIO;
740                         }
741                 }
742                 spin_unlock(&GlobalMid_Lock);
743                 DeleteMidQEntry(midQ);
744                 /* If not lock req, update # of requests on wire to server */
745                 if(long_op < 3) {
746                         atomic_dec(&ses->server->inFlight); 
747                         wake_up(&ses->server->request_q);
748                 }
749                 return rc;
750         }
751   
752         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
753                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
754                         receive_len, xid));
755                 rc = -EIO;
756         } else {                /* rcvd frame is ok */
757
758                 if (midQ->resp_buf && out_buf
759                     && (midQ->midState == MID_RESPONSE_RECEIVED)) {
760                         out_buf->smb_buf_length = receive_len;
761                         memcpy((char *)out_buf + 4,
762                                (char *)midQ->resp_buf + 4,
763                                receive_len);
764
765                         dump_smb(out_buf, 92);
766                         /* convert the length into a more usable form */
767                         if((receive_len > 24) &&
768                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
769                                         SECMODE_SIGN_ENABLED))) {
770                                 rc = cifs_verify_signature(out_buf,
771                                                 ses->server->mac_signing_key,
772                                                 midQ->sequence_number+1);
773                                 if(rc) {
774                                         cERROR(1,("Unexpected SMB signature"));
775                                         /* BB FIXME add code to kill session */
776                                 }
777                         }
778
779                         *pbytes_returned = out_buf->smb_buf_length;
780
781                         /* BB special case reconnect tid and uid here? */
782                         rc = map_smb_to_linux_error(out_buf);
783
784                         /* convert ByteCount if necessary */
785                         if (receive_len >=
786                             sizeof (struct smb_hdr) -
787                             4 /* do not count RFC1001 header */  +
788                             (2 * out_buf->WordCount) + 2 /* bcc */ )
789                                 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
790                 } else {
791                         rc = -EIO;
792                         cERROR(1,("Bad MID state? "));
793                 }
794         }
795 cifs_no_response_exit:
796         DeleteMidQEntry(midQ);
797
798         if(long_op < 3) {
799                 atomic_dec(&ses->server->inFlight); 
800                 wake_up(&ses->server->request_q);
801         }
802
803         return rc;
804
805 out_unlock:
806         up(&ses->server->tcpSem);
807         /* If not lock req, update # of requests on wire to server */
808         if(long_op < 3) {
809                 atomic_dec(&ses->server->inFlight); 
810                 wake_up(&ses->server->request_q);
811         }
812
813         return rc;
814 }