diff options
author | Ronnie Sahlberg <lsahlber@redhat.com> | 2018-08-08 01:07:45 -0400 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2018-08-09 22:19:45 -0400 |
commit | b24df3e30cbf48255db866720fb71f14bf9d2f39 (patch) | |
tree | 9ca3cb0b9f8be1814f87b24dfe85b7714bbea3ad | |
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>
-rw-r--r-- | fs/cifs/cifsglob.h | 5 | ||||
-rw-r--r-- | fs/cifs/connect.c | 82 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 61 | ||||
-rw-r--r-- | fs/cifs/transport.c | 2 |
4 files changed, 107 insertions, 43 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 41803d374da0..0c9ab62c3df4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -76,6 +76,9 @@ | |||
76 | #define SMB_ECHO_INTERVAL_MAX 600 | 76 | #define SMB_ECHO_INTERVAL_MAX 600 |
77 | #define SMB_ECHO_INTERVAL_DEFAULT 60 | 77 | #define SMB_ECHO_INTERVAL_DEFAULT 60 |
78 | 78 | ||
79 | /* maximum number of PDUs in one compound */ | ||
80 | #define MAX_COMPOUND 5 | ||
81 | |||
79 | /* | 82 | /* |
80 | * Default number of credits to keep available for SMB3. | 83 | * Default number of credits to keep available for SMB3. |
81 | * This value is chosen somewhat arbitrarily. The Windows client | 84 | * This value is chosen somewhat arbitrarily. The Windows client |
@@ -458,7 +461,7 @@ struct smb_version_operations { | |||
458 | struct smb_rqst *, struct smb_rqst *); | 461 | struct smb_rqst *, struct smb_rqst *); |
459 | int (*is_transform_hdr)(void *buf); | 462 | int (*is_transform_hdr)(void *buf); |
460 | int (*receive_transform)(struct TCP_Server_Info *, | 463 | int (*receive_transform)(struct TCP_Server_Info *, |
461 | struct mid_q_entry **); | 464 | struct mid_q_entry **, char **, int *); |
462 | enum securityEnum (*select_sectype)(struct TCP_Server_Info *, | 465 | enum securityEnum (*select_sectype)(struct TCP_Server_Info *, |
463 | enum securityEnum); | 466 | enum securityEnum); |
464 | int (*next_header)(char *); | 467 | int (*next_header)(char *); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d9bd10d295a9..c832a8a1970a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -850,13 +850,14 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
850 | static int | 850 | static int |
851 | cifs_demultiplex_thread(void *p) | 851 | cifs_demultiplex_thread(void *p) |
852 | { | 852 | { |
853 | int length; | 853 | int i, num_mids, length; |
854 | struct TCP_Server_Info *server = p; | 854 | struct TCP_Server_Info *server = p; |
855 | unsigned int pdu_length; | 855 | unsigned int pdu_length; |
856 | unsigned int next_offset; | 856 | unsigned int next_offset; |
857 | char *buf = NULL; | 857 | char *buf = NULL; |
858 | struct task_struct *task_to_wake = NULL; | 858 | struct task_struct *task_to_wake = NULL; |
859 | struct mid_q_entry *mid_entry; | 859 | struct mid_q_entry *mids[MAX_COMPOUND]; |
860 | char *bufs[MAX_COMPOUND]; | ||
860 | 861 | ||
861 | current->flags |= PF_MEMALLOC; | 862 | current->flags |= PF_MEMALLOC; |
862 | cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); | 863 | cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); |
@@ -923,58 +924,75 @@ next_pdu: | |||
923 | server->pdu_size = next_offset; | 924 | server->pdu_size = next_offset; |
924 | } | 925 | } |
925 | 926 | ||
926 | mid_entry = NULL; | 927 | memset(mids, 0, sizeof(mids)); |
928 | memset(bufs, 0, sizeof(bufs)); | ||
929 | num_mids = 0; | ||
930 | |||
927 | if (server->ops->is_transform_hdr && | 931 | if (server->ops->is_transform_hdr && |
928 | server->ops->receive_transform && | 932 | server->ops->receive_transform && |
929 | server->ops->is_transform_hdr(buf)) { | 933 | server->ops->is_transform_hdr(buf)) { |
930 | length = server->ops->receive_transform(server, | 934 | length = server->ops->receive_transform(server, |
931 | &mid_entry); | 935 | mids, |
936 | bufs, | ||
937 | &num_mids); | ||
932 | } else { | 938 | } else { |
933 | mid_entry = server->ops->find_mid(server, buf); | 939 | mids[0] = server->ops->find_mid(server, buf); |
940 | bufs[0] = buf; | ||
941 | if (mids[0]) | ||
942 | num_mids = 1; | ||
934 | 943 | ||
935 | if (!mid_entry || !mid_entry->receive) | 944 | if (!mids[0] || !mids[0]->receive) |
936 | length = standard_receive3(server, mid_entry); | 945 | length = standard_receive3(server, mids[0]); |
937 | else | 946 | else |
938 | length = mid_entry->receive(server, mid_entry); | 947 | length = mids[0]->receive(server, mids[0]); |
939 | } | 948 | } |
940 | 949 | ||
941 | if (length < 0) { | 950 | if (length < 0) { |
942 | if (mid_entry) | 951 | for (i = 0; i < num_mids; i++) |
943 | cifs_mid_q_entry_release(mid_entry); | 952 | if (mids[i]) |
953 | cifs_mid_q_entry_release(mids[i]); | ||
944 | continue; | 954 | continue; |
945 | } | 955 | } |
946 | 956 | ||
947 | if (server->large_buf) | 957 | if (server->large_buf) |
948 | buf = server->bigbuf; | 958 | buf = server->bigbuf; |
949 | 959 | ||
960 | |||
950 | server->lstrp = jiffies; | 961 | server->lstrp = jiffies; |
951 | if (mid_entry != NULL) { | ||
952 | mid_entry->resp_buf_size = server->pdu_size; | ||
953 | if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) && | ||
954 | mid_entry->mid_state == MID_RESPONSE_RECEIVED && | ||
955 | server->ops->handle_cancelled_mid) | ||
956 | server->ops->handle_cancelled_mid( | ||
957 | mid_entry->resp_buf, | ||
958 | server); | ||
959 | 962 | ||
960 | if (!mid_entry->multiRsp || mid_entry->multiEnd) | 963 | for (i = 0; i < num_mids; i++) { |
961 | mid_entry->callback(mid_entry); | 964 | if (mids[i] != NULL) { |
965 | mids[i]->resp_buf_size = server->pdu_size; | ||
966 | if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) && | ||
967 | mids[i]->mid_state == MID_RESPONSE_RECEIVED && | ||
968 | server->ops->handle_cancelled_mid) | ||
969 | server->ops->handle_cancelled_mid( | ||
970 | mids[i]->resp_buf, | ||
971 | server); | ||
962 | 972 | ||
963 | cifs_mid_q_entry_release(mid_entry); | 973 | if (!mids[i]->multiRsp || mids[i]->multiEnd) |
964 | } else if (server->ops->is_oplock_break && | 974 | mids[i]->callback(mids[i]); |
965 | server->ops->is_oplock_break(buf, server)) { | 975 | |
966 | cifs_dbg(FYI, "Received oplock break\n"); | 976 | cifs_mid_q_entry_release(mids[i]); |
967 | } else { | 977 | } else if (server->ops->is_oplock_break && |
968 | cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", | 978 | server->ops->is_oplock_break(bufs[i], |
969 | atomic_read(&midCount)); | 979 | server)) { |
970 | cifs_dump_mem("Received Data is: ", buf, | 980 | cifs_dbg(FYI, "Received oplock break\n"); |
971 | HEADER_SIZE(server)); | 981 | } else { |
982 | cifs_dbg(VFS, "No task to wake, unknown frame " | ||
983 | "received! NumMids %d\n", | ||
984 | atomic_read(&midCount)); | ||
985 | cifs_dump_mem("Received Data is: ", bufs[i], | ||
986 | HEADER_SIZE(server)); | ||
972 | #ifdef CONFIG_CIFS_DEBUG2 | 987 | #ifdef CONFIG_CIFS_DEBUG2 |
973 | if (server->ops->dump_detail) | 988 | if (server->ops->dump_detail) |
974 | server->ops->dump_detail(buf, server); | 989 | server->ops->dump_detail(bufs[i], |
975 | cifs_dump_mids(server); | 990 | server); |
991 | cifs_dump_mids(server); | ||
976 | #endif /* CIFS_DEBUG2 */ | 992 | #endif /* CIFS_DEBUG2 */ |
993 | } | ||
977 | } | 994 | } |
995 | |||
978 | if (pdu_length > server->pdu_size) { | 996 | if (pdu_length > server->pdu_size) { |
979 | if (!allocate_buffers(server)) | 997 | if (!allocate_buffers(server)) |
980 | continue; | 998 | continue; |
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: | |||
2942 | 2942 | ||
2943 | static int | 2943 | static int |
2944 | receive_encrypted_standard(struct TCP_Server_Info *server, | 2944 | receive_encrypted_standard(struct TCP_Server_Info *server, |
2945 | struct mid_q_entry **mid) | 2945 | struct mid_q_entry **mids, char **bufs, |
2946 | int *num_mids) | ||
2946 | { | 2947 | { |
2947 | int length; | 2948 | int ret, length; |
2948 | char *buf = server->smallbuf; | 2949 | char *buf = server->smallbuf; |
2950 | char *tmpbuf; | ||
2951 | struct smb2_sync_hdr *shdr; | ||
2949 | unsigned int pdu_length = server->pdu_size; | 2952 | unsigned int pdu_length = server->pdu_size; |
2950 | unsigned int buf_size; | 2953 | unsigned int buf_size; |
2951 | struct mid_q_entry *mid_entry; | 2954 | struct mid_q_entry *mid_entry; |
2955 | int next_is_large; | ||
2956 | char *next_buffer = NULL; | ||
2957 | |||
2958 | *num_mids = 0; | ||
2952 | 2959 | ||
2953 | /* switch to large buffer if too big for a small one */ | 2960 | /* switch to large buffer if too big for a small one */ |
2954 | if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { | 2961 | if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { |
@@ -2969,24 +2976,61 @@ receive_encrypted_standard(struct TCP_Server_Info *server, | |||
2969 | if (length) | 2976 | if (length) |
2970 | return length; | 2977 | return length; |
2971 | 2978 | ||
2979 | next_is_large = server->large_buf; | ||
2980 | one_more: | ||
2981 | shdr = (struct smb2_sync_hdr *)buf; | ||
2982 | if (shdr->NextCommand) { | ||
2983 | if (next_is_large) { | ||
2984 | tmpbuf = server->bigbuf; | ||
2985 | next_buffer = (char *)cifs_buf_get(); | ||
2986 | } else { | ||
2987 | tmpbuf = server->smallbuf; | ||
2988 | next_buffer = (char *)cifs_small_buf_get(); | ||
2989 | } | ||
2990 | memcpy(next_buffer, | ||
2991 | tmpbuf + le32_to_cpu(shdr->NextCommand), | ||
2992 | pdu_length - le32_to_cpu(shdr->NextCommand)); | ||
2993 | } | ||
2994 | |||
2972 | mid_entry = smb2_find_mid(server, buf); | 2995 | mid_entry = smb2_find_mid(server, buf); |
2973 | if (mid_entry == NULL) | 2996 | if (mid_entry == NULL) |
2974 | cifs_dbg(FYI, "mid not found\n"); | 2997 | cifs_dbg(FYI, "mid not found\n"); |
2975 | else { | 2998 | else { |
2976 | cifs_dbg(FYI, "mid found\n"); | 2999 | cifs_dbg(FYI, "mid found\n"); |
2977 | mid_entry->decrypted = true; | 3000 | mid_entry->decrypted = true; |
3001 | mid_entry->resp_buf_size = server->pdu_size; | ||
2978 | } | 3002 | } |
2979 | 3003 | ||
2980 | *mid = mid_entry; | 3004 | if (*num_mids >= MAX_COMPOUND) { |
3005 | cifs_dbg(VFS, "too many PDUs in compound\n"); | ||
3006 | return -1; | ||
3007 | } | ||
3008 | bufs[*num_mids] = buf; | ||
3009 | mids[(*num_mids)++] = mid_entry; | ||
2981 | 3010 | ||
2982 | if (mid_entry && mid_entry->handle) | 3011 | if (mid_entry && mid_entry->handle) |
2983 | return mid_entry->handle(server, mid_entry); | 3012 | ret = mid_entry->handle(server, mid_entry); |
3013 | else | ||
3014 | ret = cifs_handle_standard(server, mid_entry); | ||
3015 | |||
3016 | if (ret == 0 && shdr->NextCommand) { | ||
3017 | pdu_length -= le32_to_cpu(shdr->NextCommand); | ||
3018 | server->large_buf = next_is_large; | ||
3019 | if (next_is_large) | ||
3020 | server->bigbuf = next_buffer; | ||
3021 | else | ||
3022 | server->smallbuf = next_buffer; | ||
3023 | |||
3024 | buf += le32_to_cpu(shdr->NextCommand); | ||
3025 | goto one_more; | ||
3026 | } | ||
2984 | 3027 | ||
2985 | return cifs_handle_standard(server, mid_entry); | 3028 | return ret; |
2986 | } | 3029 | } |
2987 | 3030 | ||
2988 | static int | 3031 | static int |
2989 | smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) | 3032 | smb3_receive_transform(struct TCP_Server_Info *server, |
3033 | struct mid_q_entry **mids, char **bufs, int *num_mids) | ||
2990 | { | 3034 | { |
2991 | char *buf = server->smallbuf; | 3035 | char *buf = server->smallbuf; |
2992 | unsigned int pdu_length = server->pdu_size; | 3036 | unsigned int pdu_length = server->pdu_size; |
@@ -3009,10 +3053,11 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) | |||
3009 | return -ECONNABORTED; | 3053 | return -ECONNABORTED; |
3010 | } | 3054 | } |
3011 | 3055 | ||
3056 | /* TODO: add support for compounds containing READ. */ | ||
3012 | if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) | 3057 | if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) |
3013 | return receive_encrypted_read(server, mid); | 3058 | return receive_encrypted_read(server, &mids[0]); |
3014 | 3059 | ||
3015 | return receive_encrypted_standard(server, mid); | 3060 | return receive_encrypted_standard(server, mids, bufs, num_mids); |
3016 | } | 3061 | } |
3017 | 3062 | ||
3018 | int | 3063 | int |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index c53c0908d4c6..78f96fa3d7d9 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -383,8 +383,6 @@ smbd_done: | |||
383 | return rc; | 383 | return rc; |
384 | } | 384 | } |
385 | 385 | ||
386 | #define MAX_COMPOUND 5 | ||
387 | |||
388 | static int | 386 | static int |
389 | smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, | 387 | smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, |
390 | struct smb_rqst *rqst, int flags) | 388 | struct smb_rqst *rqst, int flags) |