]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cifs: SMB1 split: Move some SMB1 receive bits to smb1transport.c
authorDavid Howells <dhowells@redhat.com>
Wed, 10 Sep 2025 07:47:09 +0000 (08:47 +0100)
committerSteve French <stfrench@microsoft.com>
Sun, 8 Feb 2026 23:07:45 +0000 (17:07 -0600)
Move some SMB1 receive bits to smb1transport.c from smb1ops.c where they're
mixed in with unrelated code to do with encoding, decoding and processing
PDUs.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Enzo Matsumiya <ematsumiya@suse.de>
cc: linux-cifs@vger.kernel.org
cc: linux-fsdevel@vger.kernel.org
cc: linux-kernel@vger.kernel.org
Acked-by: Enzo Matsumiya <ematsumiya@suse.de>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smb1ops.c
fs/smb/client/smb1proto.h
fs/smb/client/smb1transport.c

index 9729b56bd9d4b4a75ea70a48307458cacf05194d..2534113596c76d6c47121d5d26f84d56b9812156 100644 (file)
@@ -284,146 +284,6 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
        return mid;
 }
 
-/*
-       return codes:
-               0       not a transact2, or all data present
-               >0      transact2 with that much data missing
-               -EINVAL invalid transact2
- */
-static int
-check2ndT2(char *buf)
-{
-       struct smb_hdr *pSMB = (struct smb_hdr *)buf;
-       struct smb_t2_rsp *pSMBt;
-       int remaining;
-       __u16 total_data_size, data_in_this_rsp;
-
-       if (pSMB->Command != SMB_COM_TRANSACTION2)
-               return 0;
-
-       /* check for plausible wct, bcc and t2 data and parm sizes */
-       /* check for parm and data offset going beyond end of smb */
-       if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
-               cifs_dbg(FYI, "Invalid transact2 word count\n");
-               return -EINVAL;
-       }
-
-       pSMBt = (struct smb_t2_rsp *)pSMB;
-
-       total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
-       data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
-
-       if (total_data_size == data_in_this_rsp)
-               return 0;
-       else if (total_data_size < data_in_this_rsp) {
-               cifs_dbg(FYI, "total data %d smaller than data in frame %d\n",
-                        total_data_size, data_in_this_rsp);
-               return -EINVAL;
-       }
-
-       remaining = total_data_size - data_in_this_rsp;
-
-       cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n",
-                remaining);
-       if (total_data_size > CIFSMaxBufSize) {
-               cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n",
-                        total_data_size, CIFSMaxBufSize);
-               return -EINVAL;
-       }
-       return remaining;
-}
-
-static int
-coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pdu_len)
-{
-       struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
-       struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)target_hdr;
-       char *data_area_of_tgt;
-       char *data_area_of_src;
-       int remaining;
-       unsigned int byte_count, total_in_tgt;
-       __u16 tgt_total_cnt, src_total_cnt, total_in_src;
-
-       src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
-       tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
-
-       if (tgt_total_cnt != src_total_cnt)
-               cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n",
-                        src_total_cnt, tgt_total_cnt);
-
-       total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
-
-       remaining = tgt_total_cnt - total_in_tgt;
-
-       if (remaining < 0) {
-               cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
-                        tgt_total_cnt, total_in_tgt);
-               return -EPROTO;
-       }
-
-       if (remaining == 0) {
-               /* nothing to do, ignore */
-               cifs_dbg(FYI, "no more data remains\n");
-               return 0;
-       }
-
-       total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
-       if (remaining < total_in_src)
-               cifs_dbg(FYI, "transact2 2nd response contains too much data\n");
-
-       /* find end of first SMB data area */
-       data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
-                               get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
-
-       /* validate target area */
-       data_area_of_src = (char *)&pSMBs->hdr.Protocol +
-                               get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
-
-       data_area_of_tgt += total_in_tgt;
-
-       total_in_tgt += total_in_src;
-       /* is the result too big for the field? */
-       if (total_in_tgt > USHRT_MAX) {
-               cifs_dbg(FYI, "coalesced DataCount too large (%u)\n",
-                        total_in_tgt);
-               return -EPROTO;
-       }
-       put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
-
-       /* fix up the BCC */
-       byte_count = get_bcc(target_hdr);
-       byte_count += total_in_src;
-       /* is the result too big for the field? */
-       if (byte_count > USHRT_MAX) {
-               cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count);
-               return -EPROTO;
-       }
-       put_bcc(byte_count, target_hdr);
-
-       byte_count = *pdu_len;
-       byte_count += total_in_src;
-       /* don't allow buffer to overflow */
-       if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-               cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
-                        byte_count);
-               return -ENOBUFS;
-       }
-       *pdu_len = byte_count;
-
-       /* copy second buffer into end of first buffer */
-       memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
-
-       if (remaining != total_in_src) {
-               /* more responses to go */
-               cifs_dbg(FYI, "waiting for more secondary responses\n");
-               return 1;
-       }
-
-       /* we are done */
-       cifs_dbg(FYI, "found the last secondary response\n");
-       return 0;
-}
-
 static void
 cifs_downgrade_oplock(struct TCP_Server_Info *server,
                      struct cifsInodeInfo *cinode, __u32 oplock,
@@ -432,37 +292,6 @@ cifs_downgrade_oplock(struct TCP_Server_Info *server,
        cifs_set_oplock_level(cinode, oplock);
 }
 
-static bool
-cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
-                 char *buf, int malformed)
-{
-       if (malformed)
-               return false;
-       if (check2ndT2(buf) <= 0)
-               return false;
-       mid->multiRsp = true;
-       if (mid->resp_buf) {
-               /* merge response - fix up 1st*/
-               malformed = coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len);
-               if (malformed > 0)
-                       return true;
-               /* All parts received or packet is malformed. */
-               mid->multiEnd = true;
-               dequeue_mid(server, mid, malformed);
-               return true;
-       }
-       if (!server->large_buf) {
-               /*FIXME: switch to already allocated largebuf?*/
-               cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
-       } else {
-               /* Have first buffer */
-               mid->resp_buf = buf;
-               mid->large_buf = true;
-               server->bigbuf = NULL;
-       }
-       return true;
-}
-
 static bool
 cifs_need_neg(struct TCP_Server_Info *server)
 {
index cb8fa65674cdb06bbb7d77f4e48fb4a58099c052..445bb4b0582911774c89659a970c64308d71cafd 100644 (file)
@@ -233,6 +233,8 @@ int SendReceive(const unsigned int xid, struct cifs_ses *ses,
                struct smb_hdr *in_buf, unsigned int in_len,
                struct smb_hdr *out_buf, int *pbytes_returned,
                const int flags);
+bool cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+                      char *buf, int malformed);
 
 
 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
index 98287132626e34cf73a908c3c676b0b542578acc..dbe971374842cc9f9dce622bd7a9b7ebdb270697 100644 (file)
@@ -263,3 +263,174 @@ out:
        free_rsp_buf(resp_buf_type, resp_iov.iov_base);
        return rc;
 }
+
+/*
+       return codes:
+               0       not a transact2, or all data present
+               >0      transact2 with that much data missing
+               -EINVAL invalid transact2
+ */
+static int
+check2ndT2(char *buf)
+{
+       struct smb_hdr *pSMB = (struct smb_hdr *)buf;
+       struct smb_t2_rsp *pSMBt;
+       int remaining;
+       __u16 total_data_size, data_in_this_rsp;
+
+       if (pSMB->Command != SMB_COM_TRANSACTION2)
+               return 0;
+
+       /* check for plausible wct, bcc and t2 data and parm sizes */
+       /* check for parm and data offset going beyond end of smb */
+       if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
+               cifs_dbg(FYI, "Invalid transact2 word count\n");
+               return -EINVAL;
+       }
+
+       pSMBt = (struct smb_t2_rsp *)pSMB;
+
+       total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
+       data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
+
+       if (total_data_size == data_in_this_rsp)
+               return 0;
+       else if (total_data_size < data_in_this_rsp) {
+               cifs_dbg(FYI, "total data %d smaller than data in frame %d\n",
+                        total_data_size, data_in_this_rsp);
+               return -EINVAL;
+       }
+
+       remaining = total_data_size - data_in_this_rsp;
+
+       cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n",
+                remaining);
+       if (total_data_size > CIFSMaxBufSize) {
+               cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n",
+                        total_data_size, CIFSMaxBufSize);
+               return -EINVAL;
+       }
+       return remaining;
+}
+
+static int
+coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pdu_len)
+{
+       struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
+       struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)target_hdr;
+       char *data_area_of_tgt;
+       char *data_area_of_src;
+       int remaining;
+       unsigned int byte_count, total_in_tgt;
+       __u16 tgt_total_cnt, src_total_cnt, total_in_src;
+
+       src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
+       tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
+
+       if (tgt_total_cnt != src_total_cnt)
+               cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n",
+                        src_total_cnt, tgt_total_cnt);
+
+       total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
+
+       remaining = tgt_total_cnt - total_in_tgt;
+
+       if (remaining < 0) {
+               cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
+                        tgt_total_cnt, total_in_tgt);
+               return -EPROTO;
+       }
+
+       if (remaining == 0) {
+               /* nothing to do, ignore */
+               cifs_dbg(FYI, "no more data remains\n");
+               return 0;
+       }
+
+       total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
+       if (remaining < total_in_src)
+               cifs_dbg(FYI, "transact2 2nd response contains too much data\n");
+
+       /* find end of first SMB data area */
+       data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
+                               get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
+
+       /* validate target area */
+       data_area_of_src = (char *)&pSMBs->hdr.Protocol +
+                               get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
+
+       data_area_of_tgt += total_in_tgt;
+
+       total_in_tgt += total_in_src;
+       /* is the result too big for the field? */
+       if (total_in_tgt > USHRT_MAX) {
+               cifs_dbg(FYI, "coalesced DataCount too large (%u)\n",
+                        total_in_tgt);
+               return -EPROTO;
+       }
+       put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
+
+       /* fix up the BCC */
+       byte_count = get_bcc(target_hdr);
+       byte_count += total_in_src;
+       /* is the result too big for the field? */
+       if (byte_count > USHRT_MAX) {
+               cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count);
+               return -EPROTO;
+       }
+       put_bcc(byte_count, target_hdr);
+
+       byte_count = *pdu_len;
+       byte_count += total_in_src;
+       /* don't allow buffer to overflow */
+       if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
+               cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
+                        byte_count);
+               return -ENOBUFS;
+       }
+       *pdu_len = byte_count;
+
+       /* copy second buffer into end of first buffer */
+       memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
+
+       if (remaining != total_in_src) {
+               /* more responses to go */
+               cifs_dbg(FYI, "waiting for more secondary responses\n");
+               return 1;
+       }
+
+       /* we are done */
+       cifs_dbg(FYI, "found the last secondary response\n");
+       return 0;
+}
+
+bool
+cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+                 char *buf, int malformed)
+{
+       if (malformed)
+               return false;
+       if (check2ndT2(buf) <= 0)
+               return false;
+       mid->multiRsp = true;
+       if (mid->resp_buf) {
+               /* merge response - fix up 1st*/
+               malformed = coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len);
+               if (malformed > 0)
+                       return true;
+               /* All parts received or packet is malformed. */
+               mid->multiEnd = true;
+               dequeue_mid(server, mid, malformed);
+               return true;
+       }
+       if (!server->large_buf) {
+               /*FIXME: switch to already allocated largebuf?*/
+               cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
+       } else {
+               /* Have first buffer */
+               mid->resp_buf = buf;
+               mid->large_buf = true;
+               server->bigbuf = NULL;
+       }
+       return true;
+}