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