Commit 8ce79ec3 authored by Ronnie Sahlberg's avatar Ronnie Sahlberg Committed by Steve French

cifs: update multiplex loop to handle compounded responses

Signed-off-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 1fc6ad2f
...@@ -458,7 +458,7 @@ struct smb_version_operations { ...@@ -458,7 +458,7 @@ struct smb_version_operations {
struct mid_q_entry **); struct mid_q_entry **);
enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
enum securityEnum); enum securityEnum);
int (*next_header)(char *);
}; };
struct smb_version_values { struct smb_version_values {
......
...@@ -856,6 +856,7 @@ cifs_demultiplex_thread(void *p) ...@@ -856,6 +856,7 @@ cifs_demultiplex_thread(void *p)
int length; int length;
struct TCP_Server_Info *server = p; struct TCP_Server_Info *server = p;
unsigned int pdu_length; unsigned int pdu_length;
unsigned int next_offset;
char *buf = NULL; char *buf = NULL;
struct task_struct *task_to_wake = NULL; struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry; struct mid_q_entry *mid_entry;
...@@ -893,17 +894,18 @@ cifs_demultiplex_thread(void *p) ...@@ -893,17 +894,18 @@ cifs_demultiplex_thread(void *p)
* so we can now interpret the length field. * so we can now interpret the length field.
*/ */
pdu_length = get_rfc1002_length(buf); pdu_length = get_rfc1002_length(buf);
server->pdu_size = pdu_length;
cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length); cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
if (!is_smb_response(server, buf[0])) if (!is_smb_response(server, buf[0]))
continue; continue;
next_pdu:
server->pdu_size = pdu_length;
/* make sure we have enough to get to the MID */ /* make sure we have enough to get to the MID */
if (pdu_length < HEADER_SIZE(server) - 1 - if (server->pdu_size < HEADER_SIZE(server) - 1 -
server->vals->header_preamble_size) { server->vals->header_preamble_size) {
cifs_dbg(VFS, "SMB response too short (%u bytes)\n", cifs_dbg(VFS, "SMB response too short (%u bytes)\n",
pdu_length); server->pdu_size);
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q); wake_up(&server->response_q);
continue; continue;
...@@ -918,6 +920,12 @@ cifs_demultiplex_thread(void *p) ...@@ -918,6 +920,12 @@ cifs_demultiplex_thread(void *p)
continue; continue;
server->total_read += length; server->total_read += length;
if (server->ops->next_header) {
next_offset = server->ops->next_header(buf);
if (next_offset)
server->pdu_size = next_offset;
}
if (server->ops->is_transform_hdr && if (server->ops->is_transform_hdr &&
server->ops->receive_transform && server->ops->receive_transform &&
server->ops->is_transform_hdr(buf)) { server->ops->is_transform_hdr(buf)) {
...@@ -963,7 +971,15 @@ cifs_demultiplex_thread(void *p) ...@@ -963,7 +971,15 @@ cifs_demultiplex_thread(void *p)
server->ops->dump_detail(buf, server); server->ops->dump_detail(buf, server);
cifs_dump_mids(server); cifs_dump_mids(server);
#endif /* CIFS_DEBUG2 */ #endif /* CIFS_DEBUG2 */
}
if (pdu_length > server->pdu_size) {
if (!allocate_buffers(server))
continue;
pdu_length -= server->pdu_size;
server->total_read = 0;
server->large_buf = false;
buf = server->smallbuf;
goto next_pdu;
} }
} /* end while !EXITING */ } /* end while !EXITING */
......
...@@ -244,6 +244,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *srvr) ...@@ -244,6 +244,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *srvr)
* MacOS server pads after SMB2.1 write response with 3 bytes * MacOS server pads after SMB2.1 write response with 3 bytes
* of junk. Other servers match RFC1001 len to actual * of junk. Other servers match RFC1001 len to actual
* SMB2/SMB3 frame length (header + smb2 response specific data) * SMB2/SMB3 frame length (header + smb2 response specific data)
* Some windows servers do too when compounding is used.
* Log the server error (once), but allow it and continue * Log the server error (once), but allow it and continue
* since the frame is parseable. * since the frame is parseable.
*/ */
......
...@@ -2807,6 +2807,19 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -2807,6 +2807,19 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
NULL, 0, 0); NULL, 0, 0);
} }
static int
smb2_next_header(char *buf)
{
struct smb2_sync_hdr *hdr = (struct smb2_sync_hdr *)buf;
struct smb2_transform_hdr *t_hdr = (struct smb2_transform_hdr *)buf;
if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM)
return sizeof(struct smb2_transform_hdr) +
le32_to_cpu(t_hdr->OriginalMessageSize);
return le32_to_cpu(hdr->NextCommand);
}
struct smb_version_operations smb20_operations = { struct smb_version_operations smb20_operations = {
.compare_fids = smb2_compare_fids, .compare_fids = smb2_compare_fids,
.setup_request = smb2_setup_request, .setup_request = smb2_setup_request,
...@@ -2898,6 +2911,7 @@ struct smb_version_operations smb20_operations = { ...@@ -2898,6 +2911,7 @@ struct smb_version_operations smb20_operations = {
.get_acl_by_fid = get_smb2_acl_by_fid, .get_acl_by_fid = get_smb2_acl_by_fid,
.set_acl = set_smb2_acl, .set_acl = set_smb2_acl,
#endif /* CIFS_ACL */ #endif /* CIFS_ACL */
.next_header = smb2_next_header,
}; };
struct smb_version_operations smb21_operations = { struct smb_version_operations smb21_operations = {
...@@ -2992,6 +3006,7 @@ struct smb_version_operations smb21_operations = { ...@@ -2992,6 +3006,7 @@ struct smb_version_operations smb21_operations = {
.get_acl_by_fid = get_smb2_acl_by_fid, .get_acl_by_fid = get_smb2_acl_by_fid,
.set_acl = set_smb2_acl, .set_acl = set_smb2_acl,
#endif /* CIFS_ACL */ #endif /* CIFS_ACL */
.next_header = smb2_next_header,
}; };
struct smb_version_operations smb30_operations = { struct smb_version_operations smb30_operations = {
...@@ -3096,6 +3111,7 @@ struct smb_version_operations smb30_operations = { ...@@ -3096,6 +3111,7 @@ struct smb_version_operations smb30_operations = {
.get_acl_by_fid = get_smb2_acl_by_fid, .get_acl_by_fid = get_smb2_acl_by_fid,
.set_acl = set_smb2_acl, .set_acl = set_smb2_acl,
#endif /* CIFS_ACL */ #endif /* CIFS_ACL */
.next_header = smb2_next_header,
}; };
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
...@@ -3196,6 +3212,7 @@ struct smb_version_operations smb311_operations = { ...@@ -3196,6 +3212,7 @@ struct smb_version_operations smb311_operations = {
.query_all_EAs = smb2_query_eas, .query_all_EAs = smb2_query_eas,
.set_EA = smb2_set_ea, .set_EA = smb2_set_ea,
#endif /* CIFS_XATTR */ #endif /* CIFS_XATTR */
.next_header = smb2_next_header,
}; };
#endif /* CIFS_SMB311 */ #endif /* CIFS_SMB311 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment