diff options
author | Ronnie Sahlberg <lsahlber@redhat.com> | 2018-08-08 15:07:45 +1000 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2018-08-09 21:19:45 -0500 |
commit | b24df3e30cbf48255db866720fb71f14bf9d2f39 (patch) | |
tree | 9ca3cb0b9f8be1814f87b24dfe85b7714bbea3ad /fs/cifs/smb2ops.c | |
parent | 1eb9fb52040fc6e5656c277b562229f09467c9f8 (diff) |
cifs: update receive_encrypted_standard to handle compounded responses
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Paulo Alcantara <palcantara@suse.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r-- | fs/cifs/smb2ops.c | 61 |
1 files changed, 53 insertions, 8 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ebc13ebebddf..d23715062c8e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2942,13 +2942,20 @@ discard_data: static int receive_encrypted_standard(struct TCP_Server_Info *server, - struct mid_q_entry **mid) + struct mid_q_entry **mids, char **bufs, + int *num_mids) { - int length; + int ret, length; char *buf = server->smallbuf; + char *tmpbuf; + struct smb2_sync_hdr *shdr; unsigned int pdu_length = server->pdu_size; unsigned int buf_size; struct mid_q_entry *mid_entry; + int next_is_large; + char *next_buffer = NULL; + + *num_mids = 0; /* switch to large buffer if too big for a small one */ if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { @@ -2969,24 +2976,61 @@ receive_encrypted_standard(struct TCP_Server_Info *server, if (length) return length; + next_is_large = server->large_buf; + one_more: + shdr = (struct smb2_sync_hdr *)buf; + if (shdr->NextCommand) { + if (next_is_large) { + tmpbuf = server->bigbuf; + next_buffer = (char *)cifs_buf_get(); + } else { + tmpbuf = server->smallbuf; + next_buffer = (char *)cifs_small_buf_get(); + } + memcpy(next_buffer, + tmpbuf + le32_to_cpu(shdr->NextCommand), + pdu_length - le32_to_cpu(shdr->NextCommand)); + } + mid_entry = smb2_find_mid(server, buf); if (mid_entry == NULL) cifs_dbg(FYI, "mid not found\n"); else { cifs_dbg(FYI, "mid found\n"); mid_entry->decrypted = true; + mid_entry->resp_buf_size = server->pdu_size; } - *mid = mid_entry; + if (*num_mids >= MAX_COMPOUND) { + cifs_dbg(VFS, "too many PDUs in compound\n"); + return -1; + } + bufs[*num_mids] = buf; + mids[(*num_mids)++] = mid_entry; if (mid_entry && mid_entry->handle) - return mid_entry->handle(server, mid_entry); + ret = mid_entry->handle(server, mid_entry); + else + ret = cifs_handle_standard(server, mid_entry); + + if (ret == 0 && shdr->NextCommand) { + pdu_length -= le32_to_cpu(shdr->NextCommand); + server->large_buf = next_is_large; + if (next_is_large) + server->bigbuf = next_buffer; + else + server->smallbuf = next_buffer; + + buf += le32_to_cpu(shdr->NextCommand); + goto one_more; + } - return cifs_handle_standard(server, mid_entry); + return ret; } static int -smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) +smb3_receive_transform(struct TCP_Server_Info *server, + struct mid_q_entry **mids, char **bufs, int *num_mids) { char *buf = server->smallbuf; unsigned int pdu_length = server->pdu_size; @@ -3009,10 +3053,11 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) return -ECONNABORTED; } + /* TODO: add support for compounds containing READ. */ if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) - return receive_encrypted_read(server, mid); + return receive_encrypted_read(server, &mids[0]); - return receive_encrypted_standard(server, mid); + return receive_encrypted_standard(server, mids, bufs, num_mids); } int |