diff options
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r-- | fs/cifs/transport.c | 378 |
1 files changed, 196 insertions, 182 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index ff8243a8fe3e..7ebe6599ed3a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -37,15 +37,11 @@ extern mempool_t *cifs_mid_poolp; | |||
37 | extern struct kmem_cache *cifs_oplock_cachep; | 37 | extern struct kmem_cache *cifs_oplock_cachep; |
38 | 38 | ||
39 | static struct mid_q_entry * | 39 | static struct mid_q_entry * |
40 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | 40 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) |
41 | { | 41 | { |
42 | struct mid_q_entry *temp; | 42 | struct mid_q_entry *temp; |
43 | 43 | ||
44 | if (ses == NULL) { | 44 | if (server == NULL) { |
45 | cERROR(1, ("Null session passed in to AllocMidQEntry")); | ||
46 | return NULL; | ||
47 | } | ||
48 | if (ses->server == NULL) { | ||
49 | cERROR(1, ("Null TCP session in AllocMidQEntry")); | 45 | cERROR(1, ("Null TCP session in AllocMidQEntry")); |
50 | return NULL; | 46 | return NULL; |
51 | } | 47 | } |
@@ -62,12 +58,11 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
62 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ | 58 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
63 | /* when mid allocated can be before when sent */ | 59 | /* when mid allocated can be before when sent */ |
64 | temp->when_alloc = jiffies; | 60 | temp->when_alloc = jiffies; |
65 | temp->ses = ses; | ||
66 | temp->tsk = current; | 61 | temp->tsk = current; |
67 | } | 62 | } |
68 | 63 | ||
69 | spin_lock(&GlobalMid_Lock); | 64 | spin_lock(&GlobalMid_Lock); |
70 | list_add_tail(&temp->qhead, &ses->server->pending_mid_q); | 65 | list_add_tail(&temp->qhead, &server->pending_mid_q); |
71 | atomic_inc(&midCount); | 66 | atomic_inc(&midCount); |
72 | temp->midState = MID_REQUEST_ALLOCATED; | 67 | temp->midState = MID_REQUEST_ALLOCATED; |
73 | spin_unlock(&GlobalMid_Lock); | 68 | spin_unlock(&GlobalMid_Lock); |
@@ -349,37 +344,38 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | |||
349 | if (long_op == CIFS_ASYNC_OP) { | 344 | if (long_op == CIFS_ASYNC_OP) { |
350 | /* oplock breaks must not be held up */ | 345 | /* oplock breaks must not be held up */ |
351 | atomic_inc(&ses->server->inFlight); | 346 | atomic_inc(&ses->server->inFlight); |
352 | } else { | 347 | return 0; |
353 | spin_lock(&GlobalMid_Lock); | 348 | } |
354 | while (1) { | 349 | |
355 | if (atomic_read(&ses->server->inFlight) >= | 350 | spin_lock(&GlobalMid_Lock); |
356 | cifs_max_pending){ | 351 | while (1) { |
357 | spin_unlock(&GlobalMid_Lock); | 352 | if (atomic_read(&ses->server->inFlight) >= |
353 | cifs_max_pending){ | ||
354 | spin_unlock(&GlobalMid_Lock); | ||
358 | #ifdef CONFIG_CIFS_STATS2 | 355 | #ifdef CONFIG_CIFS_STATS2 |
359 | atomic_inc(&ses->server->num_waiters); | 356 | atomic_inc(&ses->server->num_waiters); |
360 | #endif | 357 | #endif |
361 | wait_event(ses->server->request_q, | 358 | wait_event(ses->server->request_q, |
362 | atomic_read(&ses->server->inFlight) | 359 | atomic_read(&ses->server->inFlight) |
363 | < cifs_max_pending); | 360 | < cifs_max_pending); |
364 | #ifdef CONFIG_CIFS_STATS2 | 361 | #ifdef CONFIG_CIFS_STATS2 |
365 | atomic_dec(&ses->server->num_waiters); | 362 | atomic_dec(&ses->server->num_waiters); |
366 | #endif | 363 | #endif |
367 | spin_lock(&GlobalMid_Lock); | 364 | spin_lock(&GlobalMid_Lock); |
368 | } else { | 365 | } else { |
369 | if (ses->server->tcpStatus == CifsExiting) { | 366 | if (ses->server->tcpStatus == CifsExiting) { |
370 | spin_unlock(&GlobalMid_Lock); | ||
371 | return -ENOENT; | ||
372 | } | ||
373 | |||
374 | /* can not count locking commands against total | ||
375 | as they are allowed to block on server */ | ||
376 | |||
377 | /* update # of requests on the wire to server */ | ||
378 | if (long_op != CIFS_BLOCKING_OP) | ||
379 | atomic_inc(&ses->server->inFlight); | ||
380 | spin_unlock(&GlobalMid_Lock); | 367 | spin_unlock(&GlobalMid_Lock); |
381 | break; | 368 | return -ENOENT; |
382 | } | 369 | } |
370 | |||
371 | /* can not count locking commands against total | ||
372 | as they are allowed to block on server */ | ||
373 | |||
374 | /* update # of requests on the wire to server */ | ||
375 | if (long_op != CIFS_BLOCKING_OP) | ||
376 | atomic_inc(&ses->server->inFlight); | ||
377 | spin_unlock(&GlobalMid_Lock); | ||
378 | break; | ||
383 | } | 379 | } |
384 | } | 380 | } |
385 | return 0; | 381 | return 0; |
@@ -390,17 +386,21 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, | |||
390 | { | 386 | { |
391 | if (ses->server->tcpStatus == CifsExiting) { | 387 | if (ses->server->tcpStatus == CifsExiting) { |
392 | return -ENOENT; | 388 | return -ENOENT; |
393 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | 389 | } |
390 | |||
391 | if (ses->server->tcpStatus == CifsNeedReconnect) { | ||
394 | cFYI(1, ("tcp session dead - return to caller to retry")); | 392 | cFYI(1, ("tcp session dead - return to caller to retry")); |
395 | return -EAGAIN; | 393 | return -EAGAIN; |
396 | } else if (ses->status != CifsGood) { | 394 | } |
395 | |||
396 | if (ses->status != CifsGood) { | ||
397 | /* check if SMB session is bad because we are setting it up */ | 397 | /* check if SMB session is bad because we are setting it up */ |
398 | if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | 398 | if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && |
399 | (in_buf->Command != SMB_COM_NEGOTIATE)) | 399 | (in_buf->Command != SMB_COM_NEGOTIATE)) |
400 | return -EAGAIN; | 400 | return -EAGAIN; |
401 | /* else ok - we are setting up session */ | 401 | /* else ok - we are setting up session */ |
402 | } | 402 | } |
403 | *ppmidQ = AllocMidQEntry(in_buf, ses); | 403 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); |
404 | if (*ppmidQ == NULL) | 404 | if (*ppmidQ == NULL) |
405 | return -ENOMEM; | 405 | return -ENOMEM; |
406 | return 0; | 406 | return 0; |
@@ -415,11 +415,8 @@ static int wait_for_response(struct cifsSesInfo *ses, | |||
415 | 415 | ||
416 | for (;;) { | 416 | for (;;) { |
417 | curr_timeout = timeout + jiffies; | 417 | curr_timeout = timeout + jiffies; |
418 | wait_event(ses->server->response_q, | 418 | wait_event_timeout(ses->server->response_q, |
419 | (!(midQ->midState == MID_REQUEST_SUBMITTED)) || | 419 | midQ->midState != MID_REQUEST_SUBMITTED, timeout); |
420 | time_after(jiffies, curr_timeout) || | ||
421 | ((ses->server->tcpStatus != CifsGood) && | ||
422 | (ses->server->tcpStatus != CifsNew))); | ||
423 | 420 | ||
424 | if (time_after(jiffies, curr_timeout) && | 421 | if (time_after(jiffies, curr_timeout) && |
425 | (midQ->midState == MID_REQUEST_SUBMITTED) && | 422 | (midQ->midState == MID_REQUEST_SUBMITTED) && |
@@ -521,11 +518,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
521 | and avoid races inside tcp sendmsg code that could cause corruption | 518 | and avoid races inside tcp sendmsg code that could cause corruption |
522 | of smb data */ | 519 | of smb data */ |
523 | 520 | ||
524 | down(&ses->server->tcpSem); | 521 | mutex_lock(&ses->server->srv_mutex); |
525 | 522 | ||
526 | rc = allocate_mid(ses, in_buf, &midQ); | 523 | rc = allocate_mid(ses, in_buf, &midQ); |
527 | if (rc) { | 524 | if (rc) { |
528 | up(&ses->server->tcpSem); | 525 | mutex_unlock(&ses->server->srv_mutex); |
529 | cifs_small_buf_release(in_buf); | 526 | cifs_small_buf_release(in_buf); |
530 | /* Update # of requests on wire to server */ | 527 | /* Update # of requests on wire to server */ |
531 | atomic_dec(&ses->server->inFlight); | 528 | atomic_dec(&ses->server->inFlight); |
@@ -533,6 +530,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
533 | return rc; | 530 | return rc; |
534 | } | 531 | } |
535 | rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); | 532 | rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); |
533 | if (rc) { | ||
534 | mutex_unlock(&ses->server->srv_mutex); | ||
535 | cifs_small_buf_release(in_buf); | ||
536 | goto out; | ||
537 | } | ||
536 | 538 | ||
537 | midQ->midState = MID_REQUEST_SUBMITTED; | 539 | midQ->midState = MID_REQUEST_SUBMITTED; |
538 | #ifdef CONFIG_CIFS_STATS2 | 540 | #ifdef CONFIG_CIFS_STATS2 |
@@ -546,7 +548,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
546 | midQ->when_sent = jiffies; | 548 | midQ->when_sent = jiffies; |
547 | #endif | 549 | #endif |
548 | 550 | ||
549 | up(&ses->server->tcpSem); | 551 | mutex_unlock(&ses->server->srv_mutex); |
550 | cifs_small_buf_release(in_buf); | 552 | cifs_small_buf_release(in_buf); |
551 | 553 | ||
552 | if (rc < 0) | 554 | if (rc < 0) |
@@ -581,10 +583,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
581 | wait_for_response(ses, midQ, timeout, 10 * HZ); | 583 | wait_for_response(ses, midQ, timeout, 10 * HZ); |
582 | 584 | ||
583 | spin_lock(&GlobalMid_Lock); | 585 | spin_lock(&GlobalMid_Lock); |
584 | if (midQ->resp_buf) { | 586 | |
585 | spin_unlock(&GlobalMid_Lock); | 587 | if (midQ->resp_buf == NULL) { |
586 | receive_len = midQ->resp_buf->smb_buf_length; | ||
587 | } else { | ||
588 | cERROR(1, ("No response to cmd %d mid %d", | 588 | cERROR(1, ("No response to cmd %d mid %d", |
589 | midQ->command, midQ->mid)); | 589 | midQ->command, midQ->mid)); |
590 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | 590 | if (midQ->midState == MID_REQUEST_SUBMITTED) { |
@@ -612,53 +612,59 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
612 | return rc; | 612 | return rc; |
613 | } | 613 | } |
614 | 614 | ||
615 | spin_unlock(&GlobalMid_Lock); | ||
616 | receive_len = midQ->resp_buf->smb_buf_length; | ||
617 | |||
615 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 618 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
616 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", | 619 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", |
617 | receive_len, xid)); | 620 | receive_len, xid)); |
618 | rc = -EIO; | 621 | rc = -EIO; |
619 | } else { /* rcvd frame is ok */ | 622 | goto out; |
620 | if (midQ->resp_buf && | 623 | } |
621 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | 624 | |
622 | 625 | /* rcvd frame is ok */ | |
623 | iov[0].iov_base = (char *)midQ->resp_buf; | 626 | |
624 | if (midQ->largeBuf) | 627 | if (midQ->resp_buf && |
625 | *pRespBufType = CIFS_LARGE_BUFFER; | 628 | (midQ->midState == MID_RESPONSE_RECEIVED)) { |
626 | else | 629 | |
627 | *pRespBufType = CIFS_SMALL_BUFFER; | 630 | iov[0].iov_base = (char *)midQ->resp_buf; |
628 | iov[0].iov_len = receive_len + 4; | 631 | if (midQ->largeBuf) |
629 | 632 | *pRespBufType = CIFS_LARGE_BUFFER; | |
630 | dump_smb(midQ->resp_buf, 80); | 633 | else |
631 | /* convert the length into a more usable form */ | 634 | *pRespBufType = CIFS_SMALL_BUFFER; |
632 | if ((receive_len > 24) && | 635 | iov[0].iov_len = receive_len + 4; |
633 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 636 | |
634 | SECMODE_SIGN_ENABLED))) { | 637 | dump_smb(midQ->resp_buf, 80); |
635 | rc = cifs_verify_signature(midQ->resp_buf, | 638 | /* convert the length into a more usable form */ |
639 | if ((receive_len > 24) && | ||
640 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
641 | SECMODE_SIGN_ENABLED))) { | ||
642 | rc = cifs_verify_signature(midQ->resp_buf, | ||
636 | &ses->server->mac_signing_key, | 643 | &ses->server->mac_signing_key, |
637 | midQ->sequence_number+1); | 644 | midQ->sequence_number+1); |
638 | if (rc) { | 645 | if (rc) { |
639 | cERROR(1, ("Unexpected SMB signature")); | 646 | cERROR(1, ("Unexpected SMB signature")); |
640 | /* BB FIXME add code to kill session */ | 647 | /* BB FIXME add code to kill session */ |
641 | } | ||
642 | } | 648 | } |
643 | |||
644 | /* BB special case reconnect tid and uid here? */ | ||
645 | rc = map_smb_to_linux_error(midQ->resp_buf, | ||
646 | flags & CIFS_LOG_ERROR); | ||
647 | |||
648 | /* convert ByteCount if necessary */ | ||
649 | if (receive_len >= sizeof(struct smb_hdr) - 4 | ||
650 | /* do not count RFC1001 header */ + | ||
651 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) | ||
652 | BCC(midQ->resp_buf) = | ||
653 | le16_to_cpu(BCC_LE(midQ->resp_buf)); | ||
654 | if ((flags & CIFS_NO_RESP) == 0) | ||
655 | midQ->resp_buf = NULL; /* mark it so buf will | ||
656 | not be freed by | ||
657 | DeleteMidQEntry */ | ||
658 | } else { | ||
659 | rc = -EIO; | ||
660 | cFYI(1, ("Bad MID state?")); | ||
661 | } | 649 | } |
650 | |||
651 | /* BB special case reconnect tid and uid here? */ | ||
652 | rc = map_smb_to_linux_error(midQ->resp_buf, | ||
653 | flags & CIFS_LOG_ERROR); | ||
654 | |||
655 | /* convert ByteCount if necessary */ | ||
656 | if (receive_len >= sizeof(struct smb_hdr) - 4 | ||
657 | /* do not count RFC1001 header */ + | ||
658 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) | ||
659 | BCC(midQ->resp_buf) = | ||
660 | le16_to_cpu(BCC_LE(midQ->resp_buf)); | ||
661 | if ((flags & CIFS_NO_RESP) == 0) | ||
662 | midQ->resp_buf = NULL; /* mark it so buf will | ||
663 | not be freed by | ||
664 | DeleteMidQEntry */ | ||
665 | } else { | ||
666 | rc = -EIO; | ||
667 | cFYI(1, ("Bad MID state?")); | ||
662 | } | 668 | } |
663 | 669 | ||
664 | out: | 670 | out: |
@@ -695,6 +701,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
695 | to the same server. We may make this configurable later or | 701 | to the same server. We may make this configurable later or |
696 | use ses->maxReq */ | 702 | use ses->maxReq */ |
697 | 703 | ||
704 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | ||
705 | cERROR(1, ("Illegal length, greater than maximum frame, %d", | ||
706 | in_buf->smb_buf_length)); | ||
707 | return -EIO; | ||
708 | } | ||
709 | |||
698 | rc = wait_for_free_request(ses, long_op); | 710 | rc = wait_for_free_request(ses, long_op); |
699 | if (rc) | 711 | if (rc) |
700 | return rc; | 712 | return rc; |
@@ -703,29 +715,22 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
703 | and avoid races inside tcp sendmsg code that could cause corruption | 715 | and avoid races inside tcp sendmsg code that could cause corruption |
704 | of smb data */ | 716 | of smb data */ |
705 | 717 | ||
706 | down(&ses->server->tcpSem); | 718 | mutex_lock(&ses->server->srv_mutex); |
707 | 719 | ||
708 | rc = allocate_mid(ses, in_buf, &midQ); | 720 | rc = allocate_mid(ses, in_buf, &midQ); |
709 | if (rc) { | 721 | if (rc) { |
710 | up(&ses->server->tcpSem); | 722 | mutex_unlock(&ses->server->srv_mutex); |
711 | /* Update # of requests on wire to server */ | 723 | /* Update # of requests on wire to server */ |
712 | atomic_dec(&ses->server->inFlight); | 724 | atomic_dec(&ses->server->inFlight); |
713 | wake_up(&ses->server->request_q); | 725 | wake_up(&ses->server->request_q); |
714 | return rc; | 726 | return rc; |
715 | } | 727 | } |
716 | 728 | ||
717 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | ||
718 | cERROR(1, ("Illegal length, greater than maximum frame, %d", | ||
719 | in_buf->smb_buf_length)); | ||
720 | DeleteMidQEntry(midQ); | ||
721 | up(&ses->server->tcpSem); | ||
722 | /* Update # of requests on wire to server */ | ||
723 | atomic_dec(&ses->server->inFlight); | ||
724 | wake_up(&ses->server->request_q); | ||
725 | return -EIO; | ||
726 | } | ||
727 | |||
728 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 729 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
730 | if (rc) { | ||
731 | mutex_unlock(&ses->server->srv_mutex); | ||
732 | goto out; | ||
733 | } | ||
729 | 734 | ||
730 | midQ->midState = MID_REQUEST_SUBMITTED; | 735 | midQ->midState = MID_REQUEST_SUBMITTED; |
731 | #ifdef CONFIG_CIFS_STATS2 | 736 | #ifdef CONFIG_CIFS_STATS2 |
@@ -738,7 +743,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
738 | atomic_dec(&ses->server->inSend); | 743 | atomic_dec(&ses->server->inSend); |
739 | midQ->when_sent = jiffies; | 744 | midQ->when_sent = jiffies; |
740 | #endif | 745 | #endif |
741 | up(&ses->server->tcpSem); | 746 | mutex_unlock(&ses->server->srv_mutex); |
742 | 747 | ||
743 | if (rc < 0) | 748 | if (rc < 0) |
744 | goto out; | 749 | goto out; |
@@ -772,10 +777,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
772 | wait_for_response(ses, midQ, timeout, 10 * HZ); | 777 | wait_for_response(ses, midQ, timeout, 10 * HZ); |
773 | 778 | ||
774 | spin_lock(&GlobalMid_Lock); | 779 | spin_lock(&GlobalMid_Lock); |
775 | if (midQ->resp_buf) { | 780 | if (midQ->resp_buf == NULL) { |
776 | spin_unlock(&GlobalMid_Lock); | ||
777 | receive_len = midQ->resp_buf->smb_buf_length; | ||
778 | } else { | ||
779 | cERROR(1, ("No response for cmd %d mid %d", | 781 | cERROR(1, ("No response for cmd %d mid %d", |
780 | midQ->command, midQ->mid)); | 782 | midQ->command, midQ->mid)); |
781 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | 783 | if (midQ->midState == MID_REQUEST_SUBMITTED) { |
@@ -803,47 +805,52 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
803 | return rc; | 805 | return rc; |
804 | } | 806 | } |
805 | 807 | ||
808 | spin_unlock(&GlobalMid_Lock); | ||
809 | receive_len = midQ->resp_buf->smb_buf_length; | ||
810 | |||
806 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 811 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
807 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", | 812 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", |
808 | receive_len, xid)); | 813 | receive_len, xid)); |
809 | rc = -EIO; | 814 | rc = -EIO; |
810 | } else { /* rcvd frame is ok */ | 815 | goto out; |
811 | 816 | } | |
812 | if (midQ->resp_buf && out_buf | 817 | |
813 | && (midQ->midState == MID_RESPONSE_RECEIVED)) { | 818 | /* rcvd frame is ok */ |
814 | out_buf->smb_buf_length = receive_len; | 819 | |
815 | memcpy((char *)out_buf + 4, | 820 | if (midQ->resp_buf && out_buf |
816 | (char *)midQ->resp_buf + 4, | 821 | && (midQ->midState == MID_RESPONSE_RECEIVED)) { |
817 | receive_len); | 822 | out_buf->smb_buf_length = receive_len; |
818 | 823 | memcpy((char *)out_buf + 4, | |
819 | dump_smb(out_buf, 92); | 824 | (char *)midQ->resp_buf + 4, |
820 | /* convert the length into a more usable form */ | 825 | receive_len); |
821 | if ((receive_len > 24) && | 826 | |
822 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 827 | dump_smb(out_buf, 92); |
823 | SECMODE_SIGN_ENABLED))) { | 828 | /* convert the length into a more usable form */ |
824 | rc = cifs_verify_signature(out_buf, | 829 | if ((receive_len > 24) && |
830 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
831 | SECMODE_SIGN_ENABLED))) { | ||
832 | rc = cifs_verify_signature(out_buf, | ||
825 | &ses->server->mac_signing_key, | 833 | &ses->server->mac_signing_key, |
826 | midQ->sequence_number+1); | 834 | midQ->sequence_number+1); |
827 | if (rc) { | 835 | if (rc) { |
828 | cERROR(1, ("Unexpected SMB signature")); | 836 | cERROR(1, ("Unexpected SMB signature")); |
829 | /* BB FIXME add code to kill session */ | 837 | /* BB FIXME add code to kill session */ |
830 | } | ||
831 | } | 838 | } |
839 | } | ||
832 | 840 | ||
833 | *pbytes_returned = out_buf->smb_buf_length; | 841 | *pbytes_returned = out_buf->smb_buf_length; |
834 | 842 | ||
835 | /* BB special case reconnect tid and uid here? */ | 843 | /* BB special case reconnect tid and uid here? */ |
836 | rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); | 844 | rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); |
837 | 845 | ||
838 | /* convert ByteCount if necessary */ | 846 | /* convert ByteCount if necessary */ |
839 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 847 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
840 | /* do not count RFC1001 header */ + | 848 | /* do not count RFC1001 header */ + |
841 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | 849 | (2 * out_buf->WordCount) + 2 /* bcc */ ) |
842 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 850 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); |
843 | } else { | 851 | } else { |
844 | rc = -EIO; | 852 | rc = -EIO; |
845 | cERROR(1, ("Bad MID state?")); | 853 | cERROR(1, ("Bad MID state?")); |
846 | } | ||
847 | } | 854 | } |
848 | 855 | ||
849 | out: | 856 | out: |
@@ -866,16 +873,16 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, | |||
866 | 873 | ||
867 | header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); | 874 | header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); |
868 | in_buf->Mid = mid; | 875 | in_buf->Mid = mid; |
869 | down(&ses->server->tcpSem); | 876 | mutex_lock(&ses->server->srv_mutex); |
870 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 877 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
871 | if (rc) { | 878 | if (rc) { |
872 | up(&ses->server->tcpSem); | 879 | mutex_unlock(&ses->server->srv_mutex); |
873 | return rc; | 880 | return rc; |
874 | } | 881 | } |
875 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 882 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
876 | (struct sockaddr *) &(ses->server->addr.sockAddr), | 883 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
877 | ses->server->noblocksnd); | 884 | ses->server->noblocksnd); |
878 | up(&ses->server->tcpSem); | 885 | mutex_unlock(&ses->server->srv_mutex); |
879 | return rc; | 886 | return rc; |
880 | } | 887 | } |
881 | 888 | ||
@@ -933,6 +940,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
933 | to the same server. We may make this configurable later or | 940 | to the same server. We may make this configurable later or |
934 | use ses->maxReq */ | 941 | use ses->maxReq */ |
935 | 942 | ||
943 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | ||
944 | cERROR(1, ("Illegal length, greater than maximum frame, %d", | ||
945 | in_buf->smb_buf_length)); | ||
946 | return -EIO; | ||
947 | } | ||
948 | |||
936 | rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); | 949 | rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); |
937 | if (rc) | 950 | if (rc) |
938 | return rc; | 951 | return rc; |
@@ -941,24 +954,21 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
941 | and avoid races inside tcp sendmsg code that could cause corruption | 954 | and avoid races inside tcp sendmsg code that could cause corruption |
942 | of smb data */ | 955 | of smb data */ |
943 | 956 | ||
944 | down(&ses->server->tcpSem); | 957 | mutex_lock(&ses->server->srv_mutex); |
945 | 958 | ||
946 | rc = allocate_mid(ses, in_buf, &midQ); | 959 | rc = allocate_mid(ses, in_buf, &midQ); |
947 | if (rc) { | 960 | if (rc) { |
948 | up(&ses->server->tcpSem); | 961 | mutex_unlock(&ses->server->srv_mutex); |
949 | return rc; | 962 | return rc; |
950 | } | 963 | } |
951 | 964 | ||
952 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 965 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
953 | up(&ses->server->tcpSem); | 966 | if (rc) { |
954 | cERROR(1, ("Illegal length, greater than maximum frame, %d", | ||
955 | in_buf->smb_buf_length)); | ||
956 | DeleteMidQEntry(midQ); | 967 | DeleteMidQEntry(midQ); |
957 | return -EIO; | 968 | mutex_unlock(&ses->server->srv_mutex); |
969 | return rc; | ||
958 | } | 970 | } |
959 | 971 | ||
960 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | ||
961 | |||
962 | midQ->midState = MID_REQUEST_SUBMITTED; | 972 | midQ->midState = MID_REQUEST_SUBMITTED; |
963 | #ifdef CONFIG_CIFS_STATS2 | 973 | #ifdef CONFIG_CIFS_STATS2 |
964 | atomic_inc(&ses->server->inSend); | 974 | atomic_inc(&ses->server->inSend); |
@@ -970,7 +980,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
970 | atomic_dec(&ses->server->inSend); | 980 | atomic_dec(&ses->server->inSend); |
971 | midQ->when_sent = jiffies; | 981 | midQ->when_sent = jiffies; |
972 | #endif | 982 | #endif |
973 | up(&ses->server->tcpSem); | 983 | mutex_unlock(&ses->server->srv_mutex); |
974 | 984 | ||
975 | if (rc < 0) { | 985 | if (rc < 0) { |
976 | DeleteMidQEntry(midQ); | 986 | DeleteMidQEntry(midQ); |
@@ -1052,44 +1062,48 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
1052 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", | 1062 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", |
1053 | receive_len, xid)); | 1063 | receive_len, xid)); |
1054 | rc = -EIO; | 1064 | rc = -EIO; |
1055 | } else { /* rcvd frame is ok */ | 1065 | goto out; |
1056 | 1066 | } | |
1057 | if (midQ->resp_buf && out_buf | ||
1058 | && (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
1059 | out_buf->smb_buf_length = receive_len; | ||
1060 | memcpy((char *)out_buf + 4, | ||
1061 | (char *)midQ->resp_buf + 4, | ||
1062 | receive_len); | ||
1063 | |||
1064 | dump_smb(out_buf, 92); | ||
1065 | /* convert the length into a more usable form */ | ||
1066 | if ((receive_len > 24) && | ||
1067 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
1068 | SECMODE_SIGN_ENABLED))) { | ||
1069 | rc = cifs_verify_signature(out_buf, | ||
1070 | &ses->server->mac_signing_key, | ||
1071 | midQ->sequence_number+1); | ||
1072 | if (rc) { | ||
1073 | cERROR(1, ("Unexpected SMB signature")); | ||
1074 | /* BB FIXME add code to kill session */ | ||
1075 | } | ||
1076 | } | ||
1077 | 1067 | ||
1078 | *pbytes_returned = out_buf->smb_buf_length; | 1068 | /* rcvd frame is ok */ |
1079 | 1069 | ||
1080 | /* BB special case reconnect tid and uid here? */ | 1070 | if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) { |
1081 | rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); | 1071 | rc = -EIO; |
1072 | cERROR(1, ("Bad MID state?")); | ||
1073 | goto out; | ||
1074 | } | ||
1082 | 1075 | ||
1083 | /* convert ByteCount if necessary */ | 1076 | out_buf->smb_buf_length = receive_len; |
1084 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 1077 | memcpy((char *)out_buf + 4, |
1085 | /* do not count RFC1001 header */ + | 1078 | (char *)midQ->resp_buf + 4, |
1086 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | 1079 | receive_len); |
1087 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 1080 | |
1088 | } else { | 1081 | dump_smb(out_buf, 92); |
1089 | rc = -EIO; | 1082 | /* convert the length into a more usable form */ |
1090 | cERROR(1, ("Bad MID state?")); | 1083 | if ((receive_len > 24) && |
1084 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
1085 | SECMODE_SIGN_ENABLED))) { | ||
1086 | rc = cifs_verify_signature(out_buf, | ||
1087 | &ses->server->mac_signing_key, | ||
1088 | midQ->sequence_number+1); | ||
1089 | if (rc) { | ||
1090 | cERROR(1, ("Unexpected SMB signature")); | ||
1091 | /* BB FIXME add code to kill session */ | ||
1091 | } | 1092 | } |
1092 | } | 1093 | } |
1094 | |||
1095 | *pbytes_returned = out_buf->smb_buf_length; | ||
1096 | |||
1097 | /* BB special case reconnect tid and uid here? */ | ||
1098 | rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); | ||
1099 | |||
1100 | /* convert ByteCount if necessary */ | ||
1101 | if (receive_len >= sizeof(struct smb_hdr) - 4 | ||
1102 | /* do not count RFC1001 header */ + | ||
1103 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | ||
1104 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | ||
1105 | |||
1106 | out: | ||
1093 | DeleteMidQEntry(midQ); | 1107 | DeleteMidQEntry(midQ); |
1094 | if (rstart && rc == -EACCES) | 1108 | if (rstart && rc == -EACCES) |
1095 | return -ERESTARTSYS; | 1109 | return -ERESTARTSYS; |