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