Tue Oct 27 20:31:15 2009 UTC ()
Pull up following revision(s) (requested by tron in ticket #1104):
	sys/netsmb/smb_smb.c: revision 1.31
	sys/netsmb/smb_smb.c: revision 1.32
Fix detection of SMB capabilities according to the CIFS spec:
1.) SMB_CAP_LARGE_FILES advertises support for 64-bit file offsets.
2.) SMB_CAP_LARGE_READX and SMB_CAP_LARGE_WRITEX advertise support for
    large reads and writes (larger than 64KB).
The code previously only used SMB_CAP_LARGE_READX and SMB_CAP_LARGE_WRITEX
which is not correct and doesn't work for the Apple Time Capsule which
only supports SMB_CAP_LARGE_FILES. With these changes SMBFS can copy a
5GB to a Time Capsule and read it back without problems.
Thanks a lot to Allen Briggs for pointing out the broke assumptions
and explaining the CIFS spec to me. This fixes PR kern/42175.
Fix cut & paste error spotted by Nicolas Joly.


(bouyer)
diff -r1.29 -r1.29.6.1 src/sys/netsmb/smb_smb.c

cvs diff -r1.29 -r1.29.6.1 src/sys/netsmb/Attic/smb_smb.c (expand / switch to unified diff)

--- src/sys/netsmb/Attic/smb_smb.c 2008/06/24 10:37:19 1.29
+++ src/sys/netsmb/Attic/smb_smb.c 2009/10/27 20:31:15 1.29.6.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: smb_smb.c,v 1.29 2008/06/24 10:37:19 gmcgarry Exp $ */ 1/* $NetBSD: smb_smb.c,v 1.29.6.1 2009/10/27 20:31:15 bouyer Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000-2001 Boris Popov 4 * Copyright (c) 2000-2001 Boris Popov
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -28,27 +28,27 @@ @@ -28,27 +28,27 @@
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 * 33 *
34 * FreeBSD: src/sys/netsmb/smb_smb.c,v 1.10 2003/02/19 05:47:38 imp Exp 34 * FreeBSD: src/sys/netsmb/smb_smb.c,v 1.10 2003/02/19 05:47:38 imp Exp
35 */ 35 */
36/* 36/*
37 * various SMB requests. Most of the routines merely packs data into mbufs. 37 * various SMB requests. Most of the routines merely packs data into mbufs.
38 */ 38 */
39 39
40#include <sys/cdefs.h> 40#include <sys/cdefs.h>
41__KERNEL_RCSID(0, "$NetBSD: smb_smb.c,v 1.29 2008/06/24 10:37:19 gmcgarry Exp $"); 41__KERNEL_RCSID(0, "$NetBSD: smb_smb.c,v 1.29.6.1 2009/10/27 20:31:15 bouyer Exp $");
42 42
43#include <sys/param.h> 43#include <sys/param.h>
44#include <sys/systm.h> 44#include <sys/systm.h>
45#include <sys/kernel.h> 45#include <sys/kernel.h>
46#include <sys/malloc.h> 46#include <sys/malloc.h>
47#include <sys/proc.h> 47#include <sys/proc.h>
48#include <sys/lock.h> 48#include <sys/lock.h>
49#include <sys/sysctl.h> 49#include <sys/sysctl.h>
50#include <sys/socket.h> 50#include <sys/socket.h>
51#include <sys/uio.h> 51#include <sys/uio.h>
52 52
53#include <netsmb/iconv.h> 53#include <netsmb/iconv.h>
54 54
@@ -584,26 +584,42 @@ smb_smb_treedisconnect(struct smb_share  @@ -584,26 +584,42 @@ smb_smb_treedisconnect(struct smb_share
584 584
585static inline int 585static inline int
586smb_smb_readx(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, 586smb_smb_readx(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
587 struct uio *uio, struct smb_cred *scred) 587 struct uio *uio, struct smb_cred *scred)
588{ 588{
589 struct smb_rq *rqp; 589 struct smb_rq *rqp;
590 struct mbchain *mbp; 590 struct mbchain *mbp;
591 struct mdchain *mdp; 591 struct mdchain *mdp;
592 u_int8_t wc; 592 u_int8_t wc;
593 int error; 593 int error;
594 u_int16_t residhi, residlo, off, doff; 594 u_int16_t residhi, residlo, off, doff;
595 u_int32_t resid; 595 u_int32_t resid;
596 596
 597 if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES) &&
 598 uio->uio_offset >= (1LL << 32)) {
 599 /* Cannot read at/beyond 4G */
 600 return (EFBIG);
 601 }
 602
 603 if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_READX)) {
 604 size_t blksz;
 605
 606 blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 64;
 607 if (blksz > 0xffff)
 608 blksz = 0xffff;
 609
 610 *len = min(blksz, *len);
 611 }
 612
597 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); 613 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
598 if (error) 614 if (error)
599 return error; 615 return error;
600 smb_rq_getrequest(rqp, &mbp); 616 smb_rq_getrequest(rqp, &mbp);
601 smb_rq_wstart(rqp); 617 smb_rq_wstart(rqp);
602 mb_put_uint8(mbp, 0xff); /* no secondary command */ 618 mb_put_uint8(mbp, 0xff); /* no secondary command */
603 mb_put_uint8(mbp, 0); /* MBZ */ 619 mb_put_uint8(mbp, 0); /* MBZ */
604 mb_put_uint16le(mbp, 0); /* offset to secondary */ 620 mb_put_uint16le(mbp, 0); /* offset to secondary */
605 mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); 621 mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM);
606 mb_put_uint32le(mbp, uio->uio_offset); 622 mb_put_uint32le(mbp, uio->uio_offset);
607 *len = min(SSTOVC(ssp)->vc_rxmax, *len); 623 *len = min(SSTOVC(ssp)->vc_rxmax, *len);
608 mb_put_uint16le(mbp, *len); /* MaxCount */ 624 mb_put_uint16le(mbp, *len); /* MaxCount */
609 mb_put_uint16le(mbp, *len); /* MinCount (only indicates blocking) */ 625 mb_put_uint16le(mbp, *len); /* MinCount (only indicates blocking) */
@@ -664,40 +680,57 @@ smb_smb_readx(struct smb_share *ssp, u_i @@ -664,40 +680,57 @@ smb_smb_readx(struct smb_share *ssp, u_i
664} 680}
665 681
666static inline int 682static inline int
667smb_smb_writex(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, 683smb_smb_writex(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
668 struct uio *uio, struct smb_cred *scred) 684 struct uio *uio, struct smb_cred *scred)
669{ 685{
670 struct smb_rq *rqp; 686 struct smb_rq *rqp;
671 struct mbchain *mbp; 687 struct mbchain *mbp;
672 struct mdchain *mdp; 688 struct mdchain *mdp;
673 int error; 689 int error;
674 u_int8_t wc; 690 u_int8_t wc;
675 u_int16_t resid; 691 u_int16_t resid;
676 692
 693 if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES) &&
 694 uio->uio_offset >= (1LL << 32)) {
 695 /* Cannot write at/beyond 4G */
 696 return (EFBIG);
 697 }
 698
 699 if (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_WRITEX) {
 700 *len = min(SSTOVC(ssp)->vc_wxmax, *len);
 701 } else {
 702 size_t blksz;
 703
 704 blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 64;
 705 if (blksz > 0xffff)
 706 blksz = 0xffff;
 707
 708 *len = min(blksz, *len);
 709 }
 710
677 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); 711 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
678 if (error) 712 if (error != 0)
679 return (error); 713 return (error);
680 smb_rq_getrequest(rqp, &mbp); 714 smb_rq_getrequest(rqp, &mbp);
681 smb_rq_wstart(rqp); 715 smb_rq_wstart(rqp);
682 mb_put_uint8(mbp, 0xff); /* no secondary command */ 716 mb_put_uint8(mbp, 0xff); /* no secondary command */
683 mb_put_uint8(mbp, 0); /* MBZ */ 717 mb_put_uint8(mbp, 0); /* MBZ */
684 mb_put_uint16le(mbp, 0); /* offset to secondary */ 718 mb_put_uint16le(mbp, 0); /* offset to secondary */
685 mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); 719 mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM);
686 mb_put_uint32le(mbp, uio->uio_offset); 720 mb_put_uint32le(mbp, uio->uio_offset);
687 mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ 721 mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
688 mb_put_uint16le(mbp, 0); /* !write-thru */ 722 mb_put_uint16le(mbp, 0); /* !write-thru */
689 mb_put_uint16le(mbp, 0); 723 mb_put_uint16le(mbp, 0);
690 *len = min(SSTOVC(ssp)->vc_wxmax, *len); 
691 mb_put_uint16le(mbp, *len >> 16); 724 mb_put_uint16le(mbp, *len >> 16);
692 mb_put_uint16le(mbp, *len); 725 mb_put_uint16le(mbp, *len);
693 mb_put_uint16le(mbp, 64); /* data offset from header start */ 726 mb_put_uint16le(mbp, 64); /* data offset from header start */
694 mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ 727 mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */
695 smb_rq_wend(rqp); 728 smb_rq_wend(rqp);
696 smb_rq_bstart(rqp); 729 smb_rq_bstart(rqp);
697 do { 730 do {
698 mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */ 731 mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */
699 error = mb_put_uio(mbp, uio, *len); 732 error = mb_put_uio(mbp, uio, *len);
700 if (error) 733 if (error)
701 break; 734 break;
702 smb_rq_bend(rqp); 735 smb_rq_bend(rqp);
703 error = smb_rq_simple(rqp); 736 error = smb_rq_simple(rqp);
@@ -775,27 +808,28 @@ smb_smb_read(struct smb_share *ssp, u_in @@ -775,27 +808,28 @@ smb_smb_read(struct smb_share *ssp, u_in
775 break; 808 break;
776 *rresid = resid; 809 *rresid = resid;
777 } while(0); 810 } while(0);
778 smb_rq_done(rqp); 811 smb_rq_done(rqp);
779 return error; 812 return error;
780} 813}
781 814
782int 815int
783smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 816smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
784 struct smb_cred *scred) 817 struct smb_cred *scred)
785{ 818{
786 size_t tsize, len, resid; 819 size_t tsize, len, resid;
787 int error = 0; 820 int error = 0;
788 int rx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_READX); 821 bool rx = (SMB_CAPS(SSTOVC(ssp)) &
 822 (SMB_CAP_LARGE_FILES|SMB_CAP_LARGE_READX)) != 0;
789 823
790 resid = 0; /* XXX gcc */ 824 resid = 0; /* XXX gcc */
791 825
792 tsize = uio->uio_resid; 826 tsize = uio->uio_resid;
793 while (tsize > 0) { 827 while (tsize > 0) {
794 len = tsize; 828 len = tsize;
795 if (rx) 829 if (rx)
796 error = smb_smb_readx(ssp, fid, &len, &resid, uio, scred); 830 error = smb_smb_readx(ssp, fid, &len, &resid, uio, scred);
797 else 831 else
798 error = smb_smb_read(ssp, fid, &len, &resid, uio, scred); 832 error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
799 if (error) 833 if (error)
800 break; 834 break;
801 tsize -= resid; 835 tsize -= resid;
@@ -856,38 +890,39 @@ smb_smb_write(struct smb_share *ssp, u_i @@ -856,38 +890,39 @@ smb_smb_write(struct smb_share *ssp, u_i
856 md_get_uint16le(mdp, &resid); 890 md_get_uint16le(mdp, &resid);
857 *rresid = resid; 891 *rresid = resid;
858 } while(0); 892 } while(0);
859 smb_rq_done(rqp); 893 smb_rq_done(rqp);
860 return error; 894 return error;
861} 895}
862 896
863int 897int
864smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 898smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
865 struct smb_cred *scred) 899 struct smb_cred *scred)
866{ 900{
867 int error = 0; 901 int error = 0;
868 size_t len, tsize, resid; 902 size_t len, tsize, resid;
869 int wx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_WRITEX); 903 bool wx = (SMB_CAPS(SSTOVC(ssp)) &
 904 (SMB_CAP_LARGE_FILES|SMB_CAP_LARGE_WRITEX)) != 0;
870 905
871 resid = 0; /* XXX gcc */ 906 resid = 0; /* XXX gcc */
872 907
873 tsize = uio->uio_resid; 908 tsize = uio->uio_resid;
874 while (tsize > 0) { 909 while (tsize > 0) {
875 len = tsize; 910 len = tsize;
876 if (wx) 911 if (wx)
877 error = smb_smb_writex(ssp, fid, &len, &resid, uio, scred); 912 error = smb_smb_writex(ssp, fid, &len, &resid, uio, scred);
878 else 913 else
879 error = smb_smb_write(ssp, fid, &len, &resid, uio, scred); 914 error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
880 if (error) 915 if (error != 0)
881 break; 916 break;
882 if (resid < len) { 917 if (resid < len) {
883 error = EIO; 918 error = EIO;
884 break; 919 break;
885 } 920 }
886 tsize -= resid; 921 tsize -= resid;
887 } 922 }
888 return error; 923 return error;
889} 924}
890 925
891#if 0 926#if 0
892int 927int
893smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred) 928smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)