cifs: Make big endian multiplex ID sequences monotonic on the wire
authorTim Gardner <tim.gardner@canonical.com>
Sat, 2 Nov 2013 17:50:34 +0000 (12:50 -0500)
committerSteve French <smfrench@gmail.com>
Sat, 2 Nov 2013 17:51:53 +0000 (12:51 -0500)
The multiplex identifier (MID) in the SMB header is only
ever used by the client, in conjunction with PID, to match responses
from the server. As such, the endianess of the MID is not important.
However, When tracing packet sequences on the wire, protocol analyzers
such as wireshark display MID as little endian. It is much more informative
for the on-the-wire MID sequences to match debug information emitted by the
CIFS driver.  Therefore, one should write and read MID in the SMB header
assuming it is always little endian.

Observed from wireshark during the protocol negotiation
and session setup:

        Multiplex ID: 256
        Multiplex ID: 256
        Multiplex ID: 512
        Multiplex ID: 512
        Multiplex ID: 768
        Multiplex ID: 768

After this patch on-the-wire MID values begin at 1 and increase monotonically.

Introduce get_next_mid64() for the internal consumers that use the full 64 bit
multiplex identifier.

Introduce the helpers get_mid() and compare_mid() to make the endian
translation clear.

Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Tim Gardner <timg@tpi.com>
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/misc.c
fs/cifs/smb1ops.c
fs/cifs/smb2transport.c
fs/cifs/transport.c

index 06e8947fc3705870f87b04ede0ded1a05c6d459e..670da1e55be70adc17539d21a7bf066d0383b6fd 100644 (file)
@@ -622,11 +622,34 @@ set_credits(struct TCP_Server_Info *server, const int val)
 }
 
 static inline __u64
-get_next_mid(struct TCP_Server_Info *server)
+get_next_mid64(struct TCP_Server_Info *server)
 {
        return server->ops->get_next_mid(server);
 }
 
+static inline __le16
+get_next_mid(struct TCP_Server_Info *server)
+{
+       __u16 mid = get_next_mid64(server);
+       /*
+        * The value in the SMB header should be little endian for easy
+        * on-the-wire decoding.
+        */
+       return cpu_to_le16(mid);
+}
+
+static inline __u16
+get_mid(const struct smb_hdr *smb)
+{
+       return le16_to_cpu(smb->Mid);
+}
+
+static inline bool
+compare_mid(__u16 mid, const struct smb_hdr *smb)
+{
+       return mid == le16_to_cpu(smb->Mid);
+}
+
 /*
  * When the server supports very large reads and writes via POSIX extensions,
  * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
index d40bd77a2392e6857aa1795fb9d07bbd429552bc..f80f98f5ef9c14f72ee7134b2595d113d6976fe2 100644 (file)
@@ -428,7 +428,7 @@ struct smb_hdr {
        __u16 Tid;
        __le16 Pid;
        __u16 Uid;
-       __u16 Mid;
+       __le16 Mid;
        __u8 WordCount;
 } __attribute__((packed));
 
index 298e31e3bdc62e2a78fbe02ad39de628babfc39f..2f9f3790679d9137cddc89d141b0be434716a42a 100644 (file)
@@ -295,7 +295,8 @@ check_smb_hdr(struct smb_hdr *smb)
        if (smb->Command == SMB_COM_LOCKING_ANDX)
                return 0;
 
-       cifs_dbg(VFS, "Server sent request, not response. mid=%u\n", smb->Mid);
+       cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
+                get_mid(smb));
        return 1;
 }
 
@@ -351,6 +352,7 @@ checkSMB(char *buf, unsigned int total_read)
        }
 
        if (4 + rfclen != clc_len) {
+               __u16 mid = get_mid(smb);
                /* check if bcc wrapped around for large read responses */
                if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
                        /* check if lengths match mod 64K */
@@ -358,11 +360,11 @@ checkSMB(char *buf, unsigned int total_read)
                                return 0; /* bcc wrapped */
                }
                cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
-                        clc_len, 4 + rfclen, smb->Mid);
+                        clc_len, 4 + rfclen, mid);
 
                if (4 + rfclen < clc_len) {
                        cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
-                                rfclen, smb->Mid);
+                                rfclen, mid);
                        return -EIO;
                } else if (rfclen > clc_len + 512) {
                        /*
@@ -375,7 +377,7 @@ checkSMB(char *buf, unsigned int total_read)
                         * data to 512 bytes.
                         */
                        cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
-                                rfclen, smb->Mid);
+                                rfclen, mid);
                        return -EIO;
                }
        }
index 8233b174de3d62c6e5a3223919e83db8f7c57016..09ef8f322c2a51b444e10ba51fda6becf3b83cc0 100644 (file)
@@ -67,7 +67,7 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
        mutex_unlock(&server->srv_mutex);
 
        cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n",
-                in_buf->Mid, rc);
+                get_mid(in_buf), rc);
 
        return rc;
 }
@@ -101,7 +101,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
 
        spin_lock(&GlobalMid_Lock);
        list_for_each_entry(mid, &server->pending_mid_q, qhead) {
-               if (mid->mid == buf->Mid &&
+               if (compare_mid(mid->mid, buf) &&
                    mid->mid_state == MID_REQUEST_SUBMITTED &&
                    le16_to_cpu(mid->command) == buf->Command) {
                        spin_unlock(&GlobalMid_Lock);
index 340abca3aa522f31490d0c483e76b60aa08d582a..c523617eade27cb8eeeedba7a7644d0b8c8815fc 100644 (file)
@@ -466,7 +466,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 static inline void
 smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
 {
-       hdr->MessageId = get_next_mid(server);
+       hdr->MessageId = get_next_mid64(server);
 }
 
 static struct mid_q_entry *
index 800b938e4061768f5f55ee414b45afa56e6d6aa2..0ee6d249ef6f7fe2d008067091bcc56f6145a5cd 100644 (file)
@@ -58,7 +58,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
                return temp;
        else {
                memset(temp, 0, sizeof(struct mid_q_entry));
-               temp->mid = smb_buffer->Mid;    /* always LE */
+               temp->mid = get_mid(smb_buffer);
                temp->pid = current->pid;
                temp->command = cpu_to_le16(smb_buffer->Command);
                cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);