Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cifs: Make big endian multiplex ID sequences monotonic on the wire

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>

authored by

Tim Gardner and committed by
Steve French
3d378d3f 944d6f1a

+35 -10
+24 -1
fs/cifs/cifsglob.h
··· 622 622 } 623 623 624 624 static inline __u64 625 - get_next_mid(struct TCP_Server_Info *server) 625 + get_next_mid64(struct TCP_Server_Info *server) 626 626 { 627 627 return server->ops->get_next_mid(server); 628 + } 629 + 630 + static inline __le16 631 + get_next_mid(struct TCP_Server_Info *server) 632 + { 633 + __u16 mid = get_next_mid64(server); 634 + /* 635 + * The value in the SMB header should be little endian for easy 636 + * on-the-wire decoding. 637 + */ 638 + return cpu_to_le16(mid); 639 + } 640 + 641 + static inline __u16 642 + get_mid(const struct smb_hdr *smb) 643 + { 644 + return le16_to_cpu(smb->Mid); 645 + } 646 + 647 + static inline bool 648 + compare_mid(__u16 mid, const struct smb_hdr *smb) 649 + { 650 + return mid == le16_to_cpu(smb->Mid); 628 651 } 629 652 630 653 /*
+1 -1
fs/cifs/cifspdu.h
··· 428 428 __u16 Tid; 429 429 __le16 Pid; 430 430 __u16 Uid; 431 - __u16 Mid; 431 + __le16 Mid; 432 432 __u8 WordCount; 433 433 } __attribute__((packed)); 434 434
+6 -4
fs/cifs/misc.c
··· 295 295 if (smb->Command == SMB_COM_LOCKING_ANDX) 296 296 return 0; 297 297 298 - cifs_dbg(VFS, "Server sent request, not response. mid=%u\n", smb->Mid); 298 + cifs_dbg(VFS, "Server sent request, not response. mid=%u\n", 299 + get_mid(smb)); 299 300 return 1; 300 301 } 301 302 ··· 352 351 } 353 352 354 353 if (4 + rfclen != clc_len) { 354 + __u16 mid = get_mid(smb); 355 355 /* check if bcc wrapped around for large read responses */ 356 356 if ((rfclen > 64 * 1024) && (rfclen > clc_len)) { 357 357 /* check if lengths match mod 64K */ ··· 360 358 return 0; /* bcc wrapped */ 361 359 } 362 360 cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n", 363 - clc_len, 4 + rfclen, smb->Mid); 361 + clc_len, 4 + rfclen, mid); 364 362 365 363 if (4 + rfclen < clc_len) { 366 364 cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n", 367 - rfclen, smb->Mid); 365 + rfclen, mid); 368 366 return -EIO; 369 367 } else if (rfclen > clc_len + 512) { 370 368 /* ··· 377 375 * data to 512 bytes. 378 376 */ 379 377 cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n", 380 - rfclen, smb->Mid); 378 + rfclen, mid); 381 379 return -EIO; 382 380 } 383 381 }
+2 -2
fs/cifs/smb1ops.c
··· 67 67 mutex_unlock(&server->srv_mutex); 68 68 69 69 cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n", 70 - in_buf->Mid, rc); 70 + get_mid(in_buf), rc); 71 71 72 72 return rc; 73 73 } ··· 101 101 102 102 spin_lock(&GlobalMid_Lock); 103 103 list_for_each_entry(mid, &server->pending_mid_q, qhead) { 104 - if (mid->mid == buf->Mid && 104 + if (compare_mid(mid->mid, buf) && 105 105 mid->mid_state == MID_REQUEST_SUBMITTED && 106 106 le16_to_cpu(mid->command) == buf->Command) { 107 107 spin_unlock(&GlobalMid_Lock);
+1 -1
fs/cifs/smb2transport.c
··· 466 466 static inline void 467 467 smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr) 468 468 { 469 - hdr->MessageId = get_next_mid(server); 469 + hdr->MessageId = get_next_mid64(server); 470 470 } 471 471 472 472 static struct mid_q_entry *
+1 -1
fs/cifs/transport.c
··· 58 58 return temp; 59 59 else { 60 60 memset(temp, 0, sizeof(struct mid_q_entry)); 61 - temp->mid = smb_buffer->Mid; /* always LE */ 61 + temp->mid = get_mid(smb_buffer); 62 62 temp->pid = current->pid; 63 63 temp->command = cpu_to_le16(smb_buffer->Command); 64 64 cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);