Negotiate and save preferred compression algorithms
authorSteve French <smfrench@gmail.com>
Sat, 27 Apr 2019 03:36:08 +0000 (20:36 -0700)
committerSteve French <stfrench@microsoft.com>
Wed, 8 May 2019 04:24:55 +0000 (23:24 -0500)
New negotiate context (3) allows the server and client to
negotiate which compression algorithms to use. Add support
for this and save it off in the server structure.

Also now displayed in /proc/fs/cifs/DebugData (see below example
to Windows 10) where compression algoirthm "LZ77" was negotiated:

Servers:
Number of credits: 326 Dialect 0x311 COMPRESS_LZ77 signed
1) Name: 192.168.92.17 Uses: 1 Capability: 0x300067 Session Status: 1 TCP status: 1 Instance: 1

See MS-XCA and MS-SMB2 2.2.3.1 for more details.

Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
fs/cifs/cifs_debug.c
fs/cifs/cifsglob.h
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h

index 5ff0b3d4c48401de533b9ede9569b773843dcd6c..6a69f11aacf76b0825bddd0f25485b6f5f2189da 100644 (file)
@@ -332,6 +332,12 @@ skip_rdma:
 #endif
                seq_printf(m, "\nNumber of credits: %d Dialect 0x%x",
                        server->credits,  server->dialect);
+               if (server->compress_algorithm == SMB3_COMPRESS_LZNT1)
+                       seq_printf(m, " COMPRESS_LZNT1");
+               else if (server->compress_algorithm == SMB3_COMPRESS_LZ77)
+                       seq_printf(m, " COMPRESS_LZ77");
+               else if (server->compress_algorithm == SMB3_COMPRESS_LZ77_HUFF)
+                       seq_printf(m, " COMPRESS_LZ77_HUFF");
                if (server->sign)
                        seq_printf(m, " signed");
                if (server->posix_ext_supported)
index c22ab330238c509a4453f9bd31e1da2893e070a2..561f1395eddda9d6c98213cd20359c2abab35be7 100644 (file)
@@ -734,6 +734,7 @@ struct TCP_Server_Info {
 #endif /* STATS2 */
        unsigned int    max_read;
        unsigned int    max_write;
+       __le16  compress_algorithm;
        __le16  cipher_type;
         /* save initital negprot hash */
        __u8    preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
index 035a568b3dbde04fcfdbf74808e531317810358e..29f011d8d8e2a4ec54731909de25d7c985b55493 100644 (file)
@@ -472,6 +472,19 @@ build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
        pneg_ctxt->HashAlgorithms = SMB2_PREAUTH_INTEGRITY_SHA512;
 }
 
+static void
+build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt)
+{
+       pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES;
+       pneg_ctxt->DataLength =
+               cpu_to_le16(sizeof(struct smb2_compression_capabilities_context)
+                         - sizeof(struct smb2_neg_context));
+       pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(3);
+       pneg_ctxt->CompressionAlgorithms[0] = SMB3_COMPRESS_LZ77;
+       pneg_ctxt->CompressionAlgorithms[1] = SMB3_COMPRESS_LZ77_HUFF;
+       pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1;
+}
+
 static void
 build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
 {
@@ -538,10 +551,17 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
        *total_len += ctxt_len;
        pneg_ctxt += ctxt_len;
 
+       build_compression_ctxt((struct smb2_compression_capabilities_context *)
+                               pneg_ctxt);
+       ctxt_len = DIV_ROUND_UP(
+               sizeof(struct smb2_compression_capabilities_context), 8) * 8;
+       *total_len += ctxt_len;
+       pneg_ctxt += ctxt_len;
+
        build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
        *total_len += sizeof(struct smb2_posix_neg_context);
 
-       req->NegotiateContextCount = cpu_to_le16(3);
+       req->NegotiateContextCount = cpu_to_le16(4);
 }
 
 static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
@@ -559,6 +579,27 @@ static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
                printk_once(KERN_WARNING "unknown SMB3 hash algorithm\n");
 }
 
+static void decode_compress_ctx(struct TCP_Server_Info *server,
+                        struct smb2_compression_capabilities_context *ctxt)
+{
+       unsigned int len = le16_to_cpu(ctxt->DataLength);
+
+       /* sizeof compress context is a one element compression capbility struct */
+       if (len < 10) {
+               printk_once(KERN_WARNING "server sent bad compression cntxt\n");
+               return;
+       }
+       if (le16_to_cpu(ctxt->CompressionAlgorithmCount) != 1) {
+               printk_once(KERN_WARNING "illegal SMB3 compress algorithm count\n");
+               return;
+       }
+       if (le16_to_cpu(ctxt->CompressionAlgorithms[0]) > 3) {
+               printk_once(KERN_WARNING "unknown compression algorithm\n");
+               return;
+       }
+       server->compress_algorithm = ctxt->CompressionAlgorithms[0];
+}
+
 static int decode_encrypt_ctx(struct TCP_Server_Info *server,
                              struct smb2_encryption_neg_context *ctxt)
 {
@@ -623,6 +664,9 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
                else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES)
                        rc = decode_encrypt_ctx(server,
                                (struct smb2_encryption_neg_context *)pctx);
+               else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES)
+                       decode_compress_ctx(server,
+                               (struct smb2_compression_capabilities_context *)pctx);
                else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
                        server->posix_ext_supported = true;
                else
index 93dd3b4315855a0cbcb61898d098000273657624..c7d5813bebd814a4b9240d6497bf64ca3fecbdf3 100644 (file)
@@ -297,16 +297,19 @@ struct smb2_encryption_neg_context {
 } __packed;
 
 /* See MS-SMB2 2.2.3.1.3 */
-#define SMB3_COMPRESS_NONE     0x0000
-#define SMB3_COMPRESS_LZNT1    0x0001
-#define SMB3_COMPRESS_LZ77     0x0002
-#define SMB3_COMPRESS_LZ77_HUFF        0x0003
+#define SMB3_COMPRESS_NONE     cpu_to_le16(0x0000)
+#define SMB3_COMPRESS_LZNT1    cpu_to_le16(0x0001)
+#define SMB3_COMPRESS_LZ77     cpu_to_le16(0x0002)
+#define SMB3_COMPRESS_LZ77_HUFF        cpu_to_le16(0x0003)
 
 struct smb2_compression_capabilities_context {
+       __le16  ContextType; /* 3 */
+       __le16  DataLength;
+       __u32   Reserved;
        __le16  CompressionAlgorithmCount;
        __u16   Padding;
-       __u32   Reserved;
-       __u16   CompressionAlgorithms[1];
+       __u32   Reserved1;
+       __le16  CompressionAlgorithms[3];
 } __packed;
 
 /*