ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / smbfs / request.c
1 /*
2  *  request.c
3  *
4  *  Copyright (C) 2001 by Urban Widmark
5  *
6  *  Please add a note about your changes to smbfs in the ChangeLog file.
7  */
8
9 #include <linux/types.h>
10 #include <linux/fs.h>
11 #include <linux/slab.h>
12 #include <linux/net.h>
13
14 #include <linux/smb_fs.h>
15 #include <linux/smbno.h>
16 #include <linux/smb_mount.h>
17
18 #include "smb_debug.h"
19 #include "request.h"
20 #include "proto.h"
21
22 /* #define SMB_SLAB_DEBUG       (SLAB_RED_ZONE | SLAB_POISON) */
23 #define SMB_SLAB_DEBUG  0
24
25 #define ROUND_UP(x) (((x)+3) & ~3)
26
27 /* cache for request structures */
28 static kmem_cache_t *req_cachep;
29
30 /*
31   /proc/slabinfo:
32   name, active, num, objsize, active_slabs, num_slaps, #pages
33 */
34
35
36 int smb_init_request_cache(void)
37 {
38         req_cachep = kmem_cache_create("smb_request",
39                                        sizeof(struct smb_request), 0,
40                                        SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN,
41                                        NULL, NULL);
42         if (req_cachep == NULL)
43                 return -ENOMEM;
44
45         return 0;
46 }
47
48 void smb_destroy_request_cache(void)
49 {
50         if (kmem_cache_destroy(req_cachep))
51                 printk(KERN_INFO "smb_destroy_request_cache: not all structures were freed\n");
52 }
53
54 /*
55  * Allocate and initialise a request structure
56  */
57 static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server,
58                                                 int bufsize)
59 {
60         struct smb_request *req;
61         unsigned char *buf = NULL;
62
63         req = kmem_cache_alloc(req_cachep, SLAB_KERNEL);
64         VERBOSE("allocating request: %p\n", req);
65         if (!req)
66                 goto out;
67
68         if (bufsize > 0) {
69                 buf = smb_kmalloc(bufsize, GFP_NOFS);
70                 if (!buf) {
71                         kmem_cache_free(req_cachep, req);
72                         return NULL;
73                 }
74         }
75
76         memset(req, 0, sizeof(struct smb_request));
77         req->rq_buffer = buf;
78         req->rq_bufsize = bufsize;
79         req->rq_server = server;
80         init_waitqueue_head(&req->rq_wait);
81         INIT_LIST_HEAD(&req->rq_queue);
82         atomic_set(&req->rq_count, 1);
83
84 out:
85         return req;
86 }
87
88 struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize)
89 {
90         struct smb_request *req = NULL;
91
92         for (;;) {
93                 atomic_inc(&server->nr_requests);
94                 if (atomic_read(&server->nr_requests) <= MAX_REQUEST_HARD) {
95                         req = smb_do_alloc_request(server, bufsize);
96                         if (req != NULL)
97                                 break;
98                 }
99
100 #if 0
101                 /*
102                  * Try to free up at least one request in order to stay
103                  * below the hard limit
104                  */
105                 if (nfs_try_to_free_pages(server))
106                         continue;
107
108                 if (signalled() && (server->flags & NFS_MOUNT_INTR))
109                         return ERR_PTR(-ERESTARTSYS);
110                 current->policy = SCHED_YIELD;
111                 schedule();
112 #else
113                 /* FIXME: we want something like nfs does above, but that
114                    requires changes to all callers and can wait. */
115                 break;
116 #endif
117         }
118         return req;
119 }
120
121 static void smb_free_request(struct smb_request *req)
122 {
123         atomic_dec(&req->rq_server->nr_requests);
124         if (req->rq_buffer && !(req->rq_flags & SMB_REQ_STATIC))
125                 smb_kfree(req->rq_buffer);
126         if (req->rq_trans2buffer)
127                 smb_kfree(req->rq_trans2buffer);
128         kmem_cache_free(req_cachep, req);
129 }
130
131 /*
132  * What prevents a rget to race with a rput? The count must never drop to zero
133  * while it is in use. Only rput if it is ok that it is free'd.
134  */
135 void smb_rget(struct smb_request *req)
136 {
137         atomic_inc(&req->rq_count);
138 }
139 void smb_rput(struct smb_request *req)
140 {
141         if (atomic_dec_and_test(&req->rq_count)) {
142                 list_del_init(&req->rq_queue);
143                 smb_free_request(req);
144         }
145 }
146
147 /* setup to receive the data part of the SMB */
148 static int smb_setup_bcc(struct smb_request *req)
149 {
150         int result = 0;
151         req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;
152
153         if (req->rq_rlen > req->rq_bufsize) {
154                 PARANOIA("Packet too large %d > %d\n",
155                          req->rq_rlen, req->rq_bufsize);
156                 return -ENOBUFS;
157         }
158
159         req->rq_iov[0].iov_base = req->rq_buffer;
160         req->rq_iov[0].iov_len  = req->rq_rlen;
161         req->rq_iovlen = 1;
162
163         return result;
164 }
165
166 /*
167  * Prepare a "normal" request structure.
168  */
169 static int smb_setup_request(struct smb_request *req)
170 {
171         int len = smb_len(req->rq_header) + 4;
172         req->rq_slen = len;
173
174         /* if we expect a data part in the reply we set the iov's to read it */
175         if (req->rq_resp_bcc)
176                 req->rq_setup_read = smb_setup_bcc;
177
178         /* This tries to support re-using the same request */
179         req->rq_bytes_sent = 0;
180         req->rq_rcls = 0;
181         req->rq_err = 0;
182         req->rq_errno = 0;
183         req->rq_fragment = 0;
184         if (req->rq_trans2buffer)
185                 smb_kfree(req->rq_trans2buffer);
186
187         return 0;
188 }
189
190 /*
191  * Prepare a transaction2 request structure
192  */
193 static int smb_setup_trans2request(struct smb_request *req)
194 {
195         struct smb_sb_info *server = req->rq_server;
196         int mparam, mdata;
197         static unsigned char padding[4];
198
199         /* I know the following is very ugly, but I want to build the
200            smb packet as efficiently as possible. */
201
202         const int smb_parameters = 15;
203         const int header = SMB_HEADER_LEN + 2 * smb_parameters + 2;
204         const int oparam = ROUND_UP(header + 3);
205         const int odata  = ROUND_UP(oparam + req->rq_lparm);
206         const int bcc = (req->rq_data ? odata + req->rq_ldata :
207                                         oparam + req->rq_lparm) - header;
208
209         if ((bcc + oparam) > server->opt.max_xmit)
210                 return -ENOMEM;
211         smb_setup_header(req, SMBtrans2, smb_parameters, bcc);
212
213         /*
214          * max parameters + max data + max setup == bufsize to make NT4 happy
215          * and not abort the transfer or split into multiple responses. It also
216          * makes smbfs happy as handling packets larger than the buffer size
217          * is extra work.
218          *
219          * OS/2 is probably going to hate me for this ...
220          */
221         mparam = SMB_TRANS2_MAX_PARAM;
222         mdata = req->rq_bufsize - mparam;
223
224         mdata = server->opt.max_xmit - mparam - 100;
225         if (mdata < 1024) {
226                 mdata = 1024;
227                 mparam = 20;
228         }
229
230 #if 0
231         /* NT/win2k has ~4k max_xmit, so with this we request more than it wants
232            to return as one SMB. Useful for testing the fragmented trans2
233            handling. */
234         mdata = 8192;
235 #endif
236
237         WSET(req->rq_header, smb_tpscnt, req->rq_lparm);
238         WSET(req->rq_header, smb_tdscnt, req->rq_ldata);
239         WSET(req->rq_header, smb_mprcnt, mparam);
240         WSET(req->rq_header, smb_mdrcnt, mdata);
241         WSET(req->rq_header, smb_msrcnt, 0);    /* max setup always 0 ? */
242         WSET(req->rq_header, smb_flags, 0);
243         DSET(req->rq_header, smb_timeout, 0);
244         WSET(req->rq_header, smb_pscnt, req->rq_lparm);
245         WSET(req->rq_header, smb_psoff, oparam - 4);
246         WSET(req->rq_header, smb_dscnt, req->rq_ldata);
247         WSET(req->rq_header, smb_dsoff, req->rq_data ? odata - 4 : 0);
248         *(req->rq_header + smb_suwcnt) = 0x01;          /* setup count */
249         *(req->rq_header + smb_suwcnt + 1) = 0x00;      /* reserved */
250         WSET(req->rq_header, smb_setup0, req->rq_trans2_command);
251
252         req->rq_iovlen = 2;
253         req->rq_iov[0].iov_base = (void *) req->rq_header;
254         req->rq_iov[0].iov_len = oparam;
255         req->rq_iov[1].iov_base = (req->rq_parm==NULL) ? padding : req->rq_parm;
256         req->rq_iov[1].iov_len = req->rq_lparm;
257         req->rq_slen = oparam + req->rq_lparm;
258
259         if (req->rq_data) {
260                 req->rq_iovlen += 2;
261                 req->rq_iov[2].iov_base = padding;
262                 req->rq_iov[2].iov_len = odata - oparam - req->rq_lparm;
263                 req->rq_iov[3].iov_base = req->rq_data;
264                 req->rq_iov[3].iov_len = req->rq_ldata;
265                 req->rq_slen = odata + req->rq_ldata;
266         }
267
268         /* always a data part for trans2 replies */
269         req->rq_setup_read = smb_setup_bcc;
270
271         return 0;
272 }
273
274 /*
275  * Add a request and tell smbiod to process it
276  */
277 int smb_add_request(struct smb_request *req)
278 {
279         long timeleft;
280         struct smb_sb_info *server = req->rq_server;
281         int result = 0;
282
283         smb_setup_request(req);
284         if (req->rq_trans2_command) {
285                 if (req->rq_buffer == NULL) {
286                         PARANOIA("trans2 attempted without response buffer!\n");
287                         return -EIO;
288                 }
289                 result = smb_setup_trans2request(req);
290         }
291         if (result < 0)
292                 return result;
293
294 #ifdef SMB_DEBUG_PACKET_SIZE
295         add_xmit_stats(req);
296 #endif
297
298         /* add 'req' to the queue of requests */
299         if (smb_lock_server_interruptible(server))
300                 return -EINTR;
301
302         /*
303          * Try to send the request as the process. If that fails we queue the
304          * request and let smbiod send it later.
305          */
306
307         /* FIXME: each server has a number on the maximum number of parallel
308            requests. 10, 50 or so. We should not allow more requests to be
309            active. */
310         if (server->mid > 0xf000)
311                 server->mid = 0;
312         req->rq_mid = server->mid++;
313         WSET(req->rq_header, smb_mid, req->rq_mid);
314
315         result = 0;
316         if (server->state == CONN_VALID) {
317                 if (list_empty(&server->xmitq))
318                         result = smb_request_send_req(req);
319                 if (result < 0) {
320                         /* Connection lost? */
321                         server->conn_error = result;
322                         server->state = CONN_INVALID;
323                 }
324         }
325         if (result != 1)
326                 list_add_tail(&req->rq_queue, &server->xmitq);
327         smb_rget(req);
328
329         if (server->state != CONN_VALID)
330                 smbiod_retry(server);
331
332         smb_unlock_server(server);
333
334         smbiod_wake_up();
335
336         timeleft = wait_event_interruptible_timeout(req->rq_wait,
337                                     req->rq_flags & SMB_REQ_RECEIVED, 30*HZ);
338         if (!timeleft || signal_pending(current)) {
339                 /*
340                  * On timeout or on interrupt we want to try and remove the
341                  * request from the recvq/xmitq.
342                  */
343                 smb_lock_server(server);
344                 if (!(req->rq_flags & SMB_REQ_RECEIVED)) {
345                         list_del_init(&req->rq_queue);
346                         smb_rput(req);
347                 }
348                 smb_unlock_server(server);
349         }
350
351         if (!timeleft) {
352                 PARANOIA("request [%p, mid=%d] timed out!\n",
353                          req, req->rq_mid);
354                 VERBOSE("smb_com:  %02x\n", *(req->rq_header + smb_com));
355                 VERBOSE("smb_rcls: %02x\n", *(req->rq_header + smb_rcls));
356                 VERBOSE("smb_flg:  %02x\n", *(req->rq_header + smb_flg));
357                 VERBOSE("smb_tid:  %04x\n", WVAL(req->rq_header, smb_tid));
358                 VERBOSE("smb_pid:  %04x\n", WVAL(req->rq_header, smb_pid));
359                 VERBOSE("smb_uid:  %04x\n", WVAL(req->rq_header, smb_uid));
360                 VERBOSE("smb_mid:  %04x\n", WVAL(req->rq_header, smb_mid));
361                 VERBOSE("smb_wct:  %02x\n", *(req->rq_header + smb_wct));
362
363                 req->rq_rcls = ERRSRV;
364                 req->rq_err  = ERRtimeout;
365
366                 /* Just in case it was "stuck" */
367                 smbiod_wake_up();
368         }
369         VERBOSE("woke up, rcls=%d\n", req->rq_rcls);
370
371         if (req->rq_rcls != 0)
372                 req->rq_errno = smb_errno(req);
373         if (signal_pending(current))
374                 req->rq_errno = -ERESTARTSYS;
375         return req->rq_errno;
376 }
377
378 /*
379  * Send a request and place it on the recvq if successfully sent.
380  * Must be called with the server lock held.
381  */
382 int smb_request_send_req(struct smb_request *req)
383 {
384         struct smb_sb_info *server = req->rq_server;
385         int result;
386
387         if (req->rq_bytes_sent == 0) {
388                 WSET(req->rq_header, smb_tid, server->opt.tid);
389                 WSET(req->rq_header, smb_pid, 1);
390                 WSET(req->rq_header, smb_uid, server->opt.server_uid);
391         }
392
393         result = smb_send_request(req);
394         if (result < 0 && result != -EAGAIN)
395                 goto out;
396
397         result = 0;
398         if (!(req->rq_flags & SMB_REQ_TRANSMITTED))
399                 goto out;
400
401         list_del_init(&req->rq_queue);
402         list_add_tail(&req->rq_queue, &server->recvq);
403         result = 1;
404 out:
405         return result;
406 }
407
408 /*
409  * Sends one request for this server. (smbiod)
410  * Must be called with the server lock held.
411  * Returns: <0 on error
412  *           0 if no request could be completely sent
413  *           1 if all data for one request was sent
414  */
415 int smb_request_send_server(struct smb_sb_info *server)
416 {
417         struct list_head *head;
418         struct smb_request *req;
419         int result;
420
421         if (server->state != CONN_VALID)
422                 return 0;
423
424         /* dequeue first request, if any */
425         req = NULL;
426         head = server->xmitq.next;
427         if (head != &server->xmitq) {
428                 req = list_entry(head, struct smb_request, rq_queue);
429         }
430         if (!req)
431                 return 0;
432
433         result = smb_request_send_req(req);
434         if (result < 0) {
435                 server->conn_error = result;
436                 list_del_init(&req->rq_queue);
437                 list_add(&req->rq_queue, &server->xmitq);
438                 result = -EIO;
439                 goto out;
440         }
441
442 out:
443         return result;
444 }
445
446 /*
447  * Try to find a request matching this "mid". Typically the first entry will
448  * be the matching one.
449  */
450 static struct smb_request *find_request(struct smb_sb_info *server, int mid)
451 {
452         struct list_head *tmp;
453         struct smb_request *req = NULL;
454
455         list_for_each(tmp, &server->recvq) {
456                 req = list_entry(tmp, struct smb_request, rq_queue);
457                 if (req->rq_mid == mid) {
458                         break;
459                 }
460                 req = NULL;
461         }
462
463         if (!req) {
464                 VERBOSE("received reply with mid %d but no request!\n",
465                         WVAL(server->header, smb_mid));
466                 server->rstate = SMB_RECV_DROP;
467         }
468
469         return req;
470 }
471
472 /*
473  * Called when we have read the smb header and believe this is a response.
474  */
475 static int smb_init_request(struct smb_sb_info *server, struct smb_request *req)
476 {
477         int hdrlen, wct;
478
479         memcpy(req->rq_header, server->header, SMB_HEADER_LEN);
480
481         wct = *(req->rq_header + smb_wct);
482         if (wct > 20) { 
483                 PARANOIA("wct too large, %d > 20\n", wct);
484                 server->rstate = SMB_RECV_DROP;
485                 return 0;
486         }
487
488         req->rq_resp_wct = wct;
489         hdrlen = SMB_HEADER_LEN + wct*2 + 2;
490         VERBOSE("header length: %d   smb_wct: %2d\n", hdrlen, wct);
491
492         req->rq_bytes_recvd = SMB_HEADER_LEN;
493         req->rq_rlen = hdrlen;
494         req->rq_iov[0].iov_base = req->rq_header;
495         req->rq_iov[0].iov_len  = hdrlen;
496         req->rq_iovlen = 1;
497         server->rstate = SMB_RECV_PARAM;
498
499 #ifdef SMB_DEBUG_PACKET_SIZE
500         add_recv_stats(smb_len(server->header));
501 #endif
502         return 0;
503 }
504
505 /*
506  * Reads the SMB parameters
507  */
508 static int smb_recv_param(struct smb_sb_info *server, struct smb_request *req)
509 {
510         int result;
511
512         result = smb_receive(server, req);
513         if (result < 0)
514                 return result;
515         if (req->rq_bytes_recvd < req->rq_rlen)
516                 return 0;
517
518         VERBOSE("result: %d   smb_bcc:  %04x\n", result,
519                 WVAL(req->rq_header, SMB_HEADER_LEN +
520                      (*(req->rq_header + smb_wct) * 2)));
521
522         result = 0;
523         req->rq_iov[0].iov_base = NULL;
524         req->rq_rlen = 0;
525         if (req->rq_callback)
526                 req->rq_callback(req);
527         else if (req->rq_setup_read)
528                 result = req->rq_setup_read(req);
529         if (result < 0) {
530                 server->rstate = SMB_RECV_DROP;
531                 return result;
532         }
533
534         server->rstate = req->rq_rlen > 0 ? SMB_RECV_DATA : SMB_RECV_END;
535
536         req->rq_bytes_recvd = 0;        // recvd out of the iov
537
538         VERBOSE("rlen: %d\n", req->rq_rlen);
539         if (req->rq_rlen < 0) {
540                 PARANOIA("Parameters read beyond end of packet!\n");
541                 server->rstate = SMB_RECV_END;
542                 return -EIO;
543         }
544         return 0;
545 }
546
547 /*
548  * Reads the SMB data
549  */
550 static int smb_recv_data(struct smb_sb_info *server, struct smb_request *req)
551 {
552         int result;
553
554         result = smb_receive(server, req);
555         if (result < 0)
556                 goto out;
557         if (req->rq_bytes_recvd < req->rq_rlen)
558                 goto out;
559         server->rstate = SMB_RECV_END;
560 out:
561         VERBOSE("result: %d\n", result);
562         return result;
563 }
564
565 /*
566  * Receive a transaction2 response
567  * Return: 0 if the response has been fully read
568  *         1 if there are further "fragments" to read
569  *        <0 if there is an error
570  */
571 static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
572 {
573         unsigned char *inbuf;
574         unsigned int parm_disp, parm_offset, parm_count, parm_tot;
575         unsigned int data_disp, data_offset, data_count, data_tot;
576         int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2;
577
578         VERBOSE("handling trans2\n");
579
580         inbuf = req->rq_header;
581         data_tot    = WVAL(inbuf, smb_tdrcnt);
582         parm_tot    = WVAL(inbuf, smb_tprcnt);
583         parm_disp   = WVAL(inbuf, smb_prdisp);
584         parm_offset = WVAL(inbuf, smb_proff);
585         parm_count  = WVAL(inbuf, smb_prcnt);
586         data_disp   = WVAL(inbuf, smb_drdisp);
587         data_offset = WVAL(inbuf, smb_droff);
588         data_count  = WVAL(inbuf, smb_drcnt);
589
590         /* Modify offset for the split header/buffer we use */
591         data_offset -= hdrlen;
592         parm_offset -= hdrlen;
593
594         if (parm_count == parm_tot && data_count == data_tot) {
595                 /*
596                  * This packet has all the trans2 data.
597                  *
598                  * We setup the request so that this will be the common
599                  * case. It may be a server error to not return a
600                  * response that fits.
601                  */
602                 VERBOSE("single trans2 response  "
603                         "dcnt=%d, pcnt=%d, doff=%d, poff=%d\n",
604                         data_count, parm_count,
605                         data_offset, parm_offset);
606                 req->rq_ldata = data_count;
607                 req->rq_lparm = parm_count;
608                 req->rq_data = req->rq_buffer + data_offset;
609                 req->rq_parm = req->rq_buffer + parm_offset;
610                 return 0;
611         }
612
613         VERBOSE("multi trans2 response  "
614                 "frag=%d, dcnt=%d, pcnt=%d, doff=%d, poff=%d\n",
615                 req->rq_fragment,
616                 data_count, parm_count,
617                 data_offset, parm_offset);
618
619         if (!req->rq_fragment) {
620                 int buf_len;
621
622                 /* We got the first trans2 fragment */
623                 req->rq_fragment = 1;
624                 req->rq_total_data = data_tot;
625                 req->rq_total_parm = parm_tot;
626                 req->rq_ldata = 0;
627                 req->rq_lparm = 0;
628
629                 buf_len = data_tot + parm_tot;
630                 if (buf_len > SMB_MAX_PACKET_SIZE)
631                         goto out_too_long;
632
633                 req->rq_trans2bufsize = buf_len;
634                 req->rq_trans2buffer = smb_kmalloc(buf_len, GFP_NOFS);
635                 if (!req->rq_trans2buffer)
636                         goto out_no_mem;
637
638                 req->rq_parm = req->rq_trans2buffer;
639                 req->rq_data = req->rq_trans2buffer + parm_tot;
640         } else if (req->rq_total_data < data_tot ||
641                    req->rq_total_parm < parm_tot)
642                 goto out_data_grew;
643
644         if (parm_disp + parm_count > req->rq_total_parm)
645                 goto out_bad_parm;
646         if (data_disp + data_count > req->rq_total_data)
647                 goto out_bad_data;
648
649         inbuf = req->rq_buffer;
650         memcpy(req->rq_parm + parm_disp, inbuf + parm_offset, parm_count);
651         memcpy(req->rq_data + data_disp, inbuf + data_offset, data_count);
652
653         req->rq_ldata += data_count;
654         req->rq_lparm += parm_count;
655
656         /*
657          * Check whether we've received all of the data. Note that
658          * we use the packet totals -- total lengths might shrink!
659          */
660         if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot)
661                 return 0;
662         return 1;
663
664 out_too_long:
665         printk(KERN_ERR "smb_trans2: data/param too long, data=%d, parm=%d\n",
666                 data_tot, parm_tot);
667         req->rq_errno = -EIO;
668         goto out;
669 out_no_mem:
670         printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n",
671                req->rq_trans2bufsize);
672         req->rq_errno = -ENOMEM;
673         goto out;
674 out_data_grew:
675         printk(KERN_ERR "smb_trans2: data/params grew!\n");
676         req->rq_errno = -EIO;
677         goto out;
678 out_bad_parm:
679         printk(KERN_ERR "smb_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n",
680                parm_disp, parm_count, parm_tot);
681         req->rq_errno = -EIO;
682         goto out;
683 out_bad_data:
684         printk(KERN_ERR "smb_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n",
685                data_disp, data_count, data_tot);
686         req->rq_errno = -EIO;
687 out:
688         return req->rq_errno;
689 }
690
691 /*
692  * State machine for receiving responses. We handle the fact that we can't
693  * read the full response in one try by having states telling us how much we
694  * have read.
695  *
696  * Must be called with the server lock held (only called from smbiod).
697  *
698  * Return: <0 on error
699  */
700 int smb_request_recv(struct smb_sb_info *server)
701 {
702         struct smb_request *req = NULL;
703         int result = 0;
704
705         if (smb_recv_available(server) <= 0)
706                 return 0;
707
708         VERBOSE("state: %d\n", server->rstate);
709         switch (server->rstate) {
710         case SMB_RECV_DROP:
711                 result = smb_receive_drop(server);
712                 if (result < 0)
713                         break;
714                 if (server->rstate == SMB_RECV_DROP)
715                         break;
716                 server->rstate = SMB_RECV_START;
717                 /* fallthrough */
718         case SMB_RECV_START:
719                 server->smb_read = 0;
720                 server->rstate = SMB_RECV_HEADER;
721                 /* fallthrough */
722         case SMB_RECV_HEADER:
723                 result = smb_receive_header(server);
724                 if (result < 0)
725                         break;
726                 if (server->rstate == SMB_RECV_HEADER)
727                         break;
728                 if (! (*(server->header + smb_flg) & SMB_FLAGS_REPLY) ) {
729                         server->rstate = SMB_RECV_REQUEST;
730                         break;
731                 }
732                 if (server->rstate != SMB_RECV_HCOMPLETE)
733                         break;
734                 /* fallthrough */
735         case SMB_RECV_HCOMPLETE:
736                 req = find_request(server, WVAL(server->header, smb_mid));
737                 if (!req)
738                         break;
739                 smb_init_request(server, req);
740                 req->rq_rcls = *(req->rq_header + smb_rcls);
741                 req->rq_err  = WVAL(req->rq_header, smb_err);
742                 if (server->rstate != SMB_RECV_PARAM)
743                         break;
744                 /* fallthrough */
745         case SMB_RECV_PARAM:
746                 if (!req)
747                         req = find_request(server,WVAL(server->header,smb_mid));
748                 if (!req)
749                         break;
750                 result = smb_recv_param(server, req);
751                 if (result < 0)
752                         break;
753                 if (server->rstate != SMB_RECV_DATA)
754                         break;
755                 /* fallthrough */
756         case SMB_RECV_DATA:
757                 if (!req)
758                         req = find_request(server,WVAL(server->header,smb_mid));
759                 if (!req)
760                         break;
761                 result = smb_recv_data(server, req);
762                 if (result < 0)
763                         break;
764                 break;
765
766                 /* We should never be called with any of these states */
767         case SMB_RECV_END:
768         case SMB_RECV_REQUEST:
769                 server->rstate = SMB_RECV_END;
770                 break;
771         }
772
773         if (result < 0) {
774                 /* We saw an error */
775                 return result;
776         }
777
778         if (server->rstate != SMB_RECV_END)
779                 return 0;
780
781         result = 0;
782         if (req->rq_trans2_command && req->rq_rcls == SUCCESS)
783                 result = smb_recv_trans2(server, req);
784
785         /*
786          * Response completely read. Drop any extra bytes sent by the server.
787          * (Yes, servers sometimes add extra bytes to responses)
788          */
789         VERBOSE("smb_len: %d   smb_read: %d\n",
790                 server->smb_len, server->smb_read);
791         if (server->smb_read < server->smb_len)
792                 smb_receive_drop(server);
793
794         server->rstate = SMB_RECV_START;
795
796         if (!result) {
797                 list_del_init(&req->rq_queue);
798                 req->rq_flags |= SMB_REQ_RECEIVED;
799                 smb_rput(req);
800                 wake_up_interruptible(&req->rq_wait);
801         }
802         return 0;
803 }