cifs: update multiplex loop to handle compounded responses
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
parent
1fc6ad2f10
commit
8ce79ec359
@ -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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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 = {
|
|||||||
.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 = {
|
|||||||
.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 = {
|
|||||||
.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 = {
|
|||||||
.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 */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user