> Subject: [PATCH 1/2] cifs: remove rfc1002 header from all SMB2 response > structures > > Separate out all the 4 byte rfc1002 headers so that they are no longer > part of the SMB2 header structures to prepare for future work to add > compounding support. > > When using compounding, the wire format will consist of a single > rfc1002 length header followed by one, or more, SMB2 headers, like this : > > * 4 byte rfc1002 length > * SMB2 header > * SMB2 header > * ... > > Signed-off-by: Ronnie Sahlberg <lsahlber@xxxxxxxxxx> > --- > fs/cifs/cifsglob.h | 2 + > fs/cifs/cifssmb.c | 9 ++- > fs/cifs/connect.c | 28 ++++++--- > fs/cifs/misc.c | 2 +- > fs/cifs/smb1ops.c | 1 + > fs/cifs/smb2glob.h | 5 -- > fs/cifs/smb2maperror.c | 8 ++- > fs/cifs/smb2misc.c | 110 +++++++++++++++++---------------- > fs/cifs/smb2ops.c | 159 ++++++++++++++++++++++++++++++------------ > ------ > fs/cifs/smb2pdu.c | 105 +++++++++++++++----------------- > fs/cifs/smb2pdu.h | 65 ++++++-------------- > fs/cifs/smb2proto.h | 5 +- > fs/cifs/smb2transport.c | 6 +- > fs/cifs/transport.c | 4 +- > 14 files changed, 268 insertions(+), 241 deletions(-) > > diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h > index 3fb1a2fe1ea9..14db722c4b0d 100644 > --- a/fs/cifs/cifsglob.h > +++ b/fs/cifs/cifsglob.h > @@ -460,6 +460,7 @@ struct smb_version_values { > __u32 exclusive_lock_type; > __u32 shared_lock_type; > __u32 unlock_lock_type; > + size_t header_preamble_size; > size_t header_size; > size_t max_header_size; > size_t read_rsp_size; > @@ -656,6 +657,7 @@ struct TCP_Server_Info { > struct delayed_work echo; /* echo ping workqueue job */ > char *smallbuf; /* pointer to current "small" buffer */ > char *bigbuf; /* pointer to current "big" buffer */ > + unsigned int total_size; /* Total size of this PDU */ > unsigned int total_read; /* total amount of data read in this pass */ > #ifdef CONFIG_CIFS_FSCACHE > struct fscache_cookie *fscache; /* client index cache cookie */ > diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c > index 35dc5bf01ee2..114e2a7ca77f 100644 > --- a/fs/cifs/cifssmb.c > +++ b/fs/cifs/cifssmb.c > @@ -1453,7 +1453,9 @@ cifs_readv_receive(struct TCP_Server_Info > *server, struct mid_q_entry *mid) > unsigned int data_offset, data_len; > struct cifs_readdata *rdata = mid->callback_data; > char *buf = server->smallbuf; > - unsigned int buflen = get_rfc1002_length(buf) + 4; > + unsigned int buflen; > + > + buflen = server->total_size + server->vals->header_preamble_size; > > cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n", > __func__, mid->mid, rdata->offset, rdata->bytes); > @@ -1464,7 +1466,7 @@ cifs_readv_receive(struct TCP_Server_Info > *server, struct mid_q_entry *mid) > * the Mid. > */ > len = min_t(unsigned int, buflen, server->vals->read_rsp_size) - > - HEADER_SIZE(server) > + 1; > + HEADER_SIZE(server) + 1; > > length = cifs_read_from_socket(server, > buf + HEADER_SIZE(server) - 1, len); > @@ -1502,7 +1504,8 @@ cifs_readv_receive(struct TCP_Server_Info > *server, struct mid_q_entry *mid) > return cifs_readv_discard(server, mid); > } > > - data_offset = server->ops->read_data_offset(buf) + 4; > + data_offset = server->ops->read_data_offset(buf) + > + server->vals->header_preamble_size; > if (data_offset < server->total_read) { > /* > * win2k8 sometimes sends an offset of 0 when the read > diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c > index 64be6f9e54a2..23d69657ca06 100644 > --- a/fs/cifs/connect.c > +++ b/fs/cifs/connect.c > @@ -763,10 +763,11 @@ standard_receive3(struct TCP_Server_Info *server, > struct mid_q_entry *mid) > { > int length; > char *buf = server->smallbuf; > - unsigned int pdu_length = get_rfc1002_length(buf); > + unsigned int pdu_length = server->total_size; > > /* make sure this will fit in a large buffer */ > - if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - 4) { > + if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - > + server->vals->header_preamble_size) { > cifs_dbg(VFS, "SMB response too long (%u bytes)\n", > pdu_length); > cifs_reconnect(server); > wake_up(&server->response_q); > @@ -781,8 +782,11 @@ standard_receive3(struct TCP_Server_Info *server, > struct mid_q_entry *mid) > } > > /* now read the rest */ > - length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - > 1, > - pdu_length - HEADER_SIZE(server) + 1 + 4); > + length = cifs_read_from_socket(server, > + buf + HEADER_SIZE(server) - 1, > + pdu_length - HEADER_SIZE(server) + 1 > + + server->vals->header_preamble_size); > + > if (length < 0) > return length; > server->total_read += length; > @@ -862,20 +866,26 @@ cifs_demultiplex_thread(void *p) > length = cifs_read_from_socket(server, buf, pdu_length); > if (length < 0) > continue; > - server->total_read = length; With this patch, most of the SMB upper layer code will no longer call get_rfc1002_length(). This is slightly out of topic. Maybe we should also look at implementing a transport layer to further abstract the transport details. E.g. the call to cifs_read_from_socket() above is for reading the payload size (with one or more SMB2 PDUs). How about renaming it to cifs_read_payload_size(), and then depending on what transport is, do the following: TCP: read from socket and return the payload size RDMA: return the SMB Direct payload size future transport: return the payload size Adding a transport layer will hide those details, and make cifs_demultiplex_thread() cleaner. It also becomes easier to implement multiple channels and more transport support (e.g. HV Socket). > + > + if (server->vals->header_preamble_size == 0) > + server->total_read = 0; > + else > + server->total_read = length; > > /* > * The right amount was read from socket - 4 bytes, > * so we can now interpret the length field. > */ > pdu_length = get_rfc1002_length(buf); > + server->total_size = pdu_length; > > cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length); > if (!is_smb_response(server, buf[0])) > continue; > > /* make sure we have enough to get to the MID */ > - if (pdu_length < HEADER_SIZE(server) - 1 - 4) { > + if (pdu_length < HEADER_SIZE(server) - 1 - > + server->vals->header_preamble_size) { > cifs_dbg(VFS, "SMB response too short (%u > bytes)\n", > pdu_length); > cifs_reconnect(server); > @@ -884,8 +894,10 @@ cifs_demultiplex_thread(void *p) > } > > /* read down to the MID */ > - length = cifs_read_from_socket(server, buf + 4, > - HEADER_SIZE(server) - 1 - 4); > + length = cifs_read_from_socket(server, > + buf + server->vals->header_preamble_size, > + HEADER_SIZE(server) - 1 > + - server->vals->header_preamble_size); > if (length < 0) > continue; > server->total_read += length; > diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c > index eea93ac15ef0..37022a34982b 100644 > --- a/fs/cifs/misc.c > +++ b/fs/cifs/misc.c > @@ -151,7 +151,7 @@ cifs_buf_get(void) > * SMB2 header is bigger than CIFS one - no problems to clean some > * more bytes for CIFS. > */ > - size_t buf_size = sizeof(struct smb2_hdr); > + size_t buf_size = sizeof(struct smb2_sync_hdr); > > /* > * We could use negotiated size instead of max_msgsize - > diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c > index a723df3e0197..4c87265050fc 100644 > --- a/fs/cifs/smb1ops.c > +++ b/fs/cifs/smb1ops.c > @@ -1120,6 +1120,7 @@ struct smb_version_values smb1_values = { > .exclusive_lock_type = 0, > .shared_lock_type = LOCKING_ANDX_SHARED_LOCK, > .unlock_lock_type = 0, > + .header_preamble_size = 4, > .header_size = sizeof(struct smb_hdr), > .max_header_size = MAX_CIFS_HDR_SIZE, > .read_rsp_size = sizeof(READ_RSP), > diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h > index 401a5d856636..0ffa18094335 100644 > --- a/fs/cifs/smb2glob.h > +++ b/fs/cifs/smb2glob.h > @@ -61,9 +61,4 @@ > /* Maximum buffer size value we can send with 1 credit */ > #define SMB2_MAX_BUFFER_SIZE 65536 > > -static inline struct smb2_sync_hdr *get_sync_hdr(void *buf) > -{ > - return &(((struct smb2_hdr *)buf)->sync_hdr); > -} > - > #endif /* _SMB2_GLOB_H */ > diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c > index 62c88dfed57b..8484058346cd 100644 > --- a/fs/cifs/smb2maperror.c > +++ b/fs/cifs/smb2maperror.c > @@ -2450,10 +2450,14 @@ smb2_print_status(__le32 status) > int > map_smb2_to_linux_error(char *buf, bool log_err) > { > - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); > + struct smb2_sync_hdr *shdr; > unsigned int i; > int rc = -EIO; > - __le32 smb2err = shdr->Status; > + __le32 smb2err; > + > + shdr = (struct smb2_sync_hdr *)buf; > + > + smb2err = shdr->Status; > > if (smb2err == 0) > return 0; > diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c > index 76d03abaa38c..339c32a10936 100644 > --- a/fs/cifs/smb2misc.c > +++ b/fs/cifs/smb2misc.c > @@ -96,17 +96,18 @@ static const __le16 > smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { > int > smb2_check_message(char *buf, unsigned int length, struct > TCP_Server_Info *srvr) > { > - struct smb2_pdu *pdu = (struct smb2_pdu *)buf; > - struct smb2_hdr *hdr = &pdu->hdr; > - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); > + struct smb2_sync_pdu *pdu; > + struct smb2_sync_hdr *shdr; > __u64 mid; > - __u32 len = get_rfc1002_length(buf); > __u32 clc_len; /* calculated length */ > int command; > + int pdu_size; > + int hdr_size; > > - /* BB disable following printk later */ > - cifs_dbg(FYI, "%s length: 0x%x, smb_buf_length: 0x%x\n", > - __func__, length, len); > + shdr = (struct smb2_sync_hdr *)buf; > + pdu_size = sizeof(struct smb2_sync_pdu); > + hdr_size = sizeof(struct smb2_sync_hdr); > + pdu = (struct smb2_sync_pdu *)shdr; > > /* > * Add function to do table lookup of StructureSize by command > @@ -136,8 +137,8 @@ smb2_check_message(char *buf, unsigned int length, > struct TCP_Server_Info *srvr) > } > > mid = le64_to_cpu(shdr->MessageId); > - if (length < sizeof(struct smb2_pdu)) { > - if ((length >= sizeof(struct smb2_hdr)) > + if (length < pdu_size) { > + if ((length >= hdr_size) > && (shdr->Status != 0)) { > pdu->StructureSize2 = 0; > /* > @@ -150,7 +151,7 @@ smb2_check_message(char *buf, unsigned int length, > struct TCP_Server_Info *srvr) > } > return 1; > } > - if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) { > + if (length > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE) { > cifs_dbg(VFS, "SMB length greater than maximum, > mid=%llu\n", > mid); > return 1; > @@ -189,26 +190,20 @@ smb2_check_message(char *buf, unsigned int > length, struct TCP_Server_Info *srvr) > } > } > > - if (4 + len != length) { > - cifs_dbg(VFS, "Total length %u RFC1002 length %u mismatch > mid %llu\n", > - length, 4 + len, mid); > - return 1; > - } > + clc_len = smb2_calc_size(buf); > > - clc_len = smb2_calc_size(hdr); > - > - if (4 + len != clc_len) { > + if (length != clc_len) { > cifs_dbg(FYI, "Calculated size %u length %u mismatch mid > %llu\n", > - clc_len, 4 + len, mid); > + clc_len, length, mid); > /* create failed on symlink */ > if (command == SMB2_CREATE_HE && > shdr->Status == STATUS_STOPPED_ON_SYMLINK) > return 0; > /* Windows 7 server returns 24 bytes more */ > - if (clc_len + 20 == len && command == > SMB2_OPLOCK_BREAK_HE) > + if (clc_len + 24 == length && command == > SMB2_OPLOCK_BREAK_HE) > return 0; > /* server can return one byte more due to implied bcc[0] */ > - if (clc_len == 4 + len + 1) > + if (clc_len == length + 1) > return 0; > > /* > @@ -218,10 +213,10 @@ smb2_check_message(char *buf, unsigned int > length, struct TCP_Server_Info *srvr) > * Log the server error (once), but allow it and continue > * since the frame is parseable. > */ > - if (clc_len < 4 /* RFC1001 header size */ + len) { > + if (clc_len < length) { > printk_once(KERN_WARNING > "SMB2 server sent bad RFC1001 len %d not > %d\n", > - len, clc_len - 4); > + length, clc_len); > return 0; > } > > @@ -262,15 +257,14 @@ static const bool > has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = { > * area and the offset to it (from the beginning of the smb are also returned. > */ > char * > -smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) > +smb2_get_data_area_len(int *off, int *len, struct smb2_sync_hdr *shdr) > { > - struct smb2_sync_hdr *shdr = get_sync_hdr(hdr); > *off = 0; > *len = 0; > > /* error responses do not have data area */ > if (shdr->Status && shdr->Status != > STATUS_MORE_PROCESSING_REQUIRED && > - (((struct smb2_err_rsp *)hdr)->StructureSize) == > + (((struct smb2_err_rsp *)shdr)->StructureSize) == > > SMB2_ERROR_STRUCTURE_SIZE2) > return NULL; > > @@ -282,42 +276,44 @@ smb2_get_data_area_len(int *off, int *len, struct > smb2_hdr *hdr) > switch (shdr->Command) { > case SMB2_NEGOTIATE: > *off = le16_to_cpu( > - ((struct smb2_negotiate_rsp *)hdr)- > >SecurityBufferOffset); > + ((struct smb2_negotiate_rsp *)shdr)- > >SecurityBufferOffset); > *len = le16_to_cpu( > - ((struct smb2_negotiate_rsp *)hdr)- > >SecurityBufferLength); > + ((struct smb2_negotiate_rsp *)shdr)- > >SecurityBufferLength); > break; > case SMB2_SESSION_SETUP: > *off = le16_to_cpu( > - ((struct smb2_sess_setup_rsp *)hdr)- > >SecurityBufferOffset); > + ((struct smb2_sess_setup_rsp *)shdr)- > >SecurityBufferOffset); > *len = le16_to_cpu( > - ((struct smb2_sess_setup_rsp *)hdr)- > >SecurityBufferLength); > + ((struct smb2_sess_setup_rsp *)shdr)- > >SecurityBufferLength); > break; > case SMB2_CREATE: > *off = le32_to_cpu( > - ((struct smb2_create_rsp *)hdr)->CreateContextsOffset); > + ((struct smb2_create_rsp *)shdr)->CreateContextsOffset); > *len = le32_to_cpu( > - ((struct smb2_create_rsp *)hdr)->CreateContextsLength); > + ((struct smb2_create_rsp *)shdr)- > >CreateContextsLength); > break; > case SMB2_QUERY_INFO: > *off = le16_to_cpu( > - ((struct smb2_query_info_rsp *)hdr)- > >OutputBufferOffset); > + ((struct smb2_query_info_rsp *)shdr)- > >OutputBufferOffset); > *len = le32_to_cpu( > - ((struct smb2_query_info_rsp *)hdr)- > >OutputBufferLength); > + ((struct smb2_query_info_rsp *)shdr)- > >OutputBufferLength); > break; > case SMB2_READ: > - *off = ((struct smb2_read_rsp *)hdr)->DataOffset; > - *len = le32_to_cpu(((struct smb2_read_rsp *)hdr)- > >DataLength); > + /* TODO: is this a bug ? */ > + *off = ((struct smb2_read_rsp *)shdr)->DataOffset; > + *len = le32_to_cpu(((struct smb2_read_rsp *)shdr)- > >DataLength); > break; > case SMB2_QUERY_DIRECTORY: > *off = le16_to_cpu( > - ((struct smb2_query_directory_rsp *)hdr)- > >OutputBufferOffset); > + ((struct smb2_query_directory_rsp *)shdr)- > >OutputBufferOffset); > *len = le32_to_cpu( > - ((struct smb2_query_directory_rsp *)hdr)- > >OutputBufferLength); > + ((struct smb2_query_directory_rsp *)shdr)- > >OutputBufferLength); > break; > case SMB2_IOCTL: > *off = le32_to_cpu( > - ((struct smb2_ioctl_rsp *)hdr)->OutputOffset); > - *len = le32_to_cpu(((struct smb2_ioctl_rsp *)hdr)- > >OutputCount); > + ((struct smb2_ioctl_rsp *)shdr)->OutputOffset); > + *len = le32_to_cpu( > + ((struct smb2_ioctl_rsp *)shdr)->OutputCount); > break; > case SMB2_CHANGE_NOTIFY: > default: > @@ -362,13 +358,16 @@ smb2_get_data_area_len(int *off, int *len, struct > smb2_hdr *hdr) > unsigned int > smb2_calc_size(void *buf) > { > - struct smb2_pdu *pdu = (struct smb2_pdu *)buf; > - struct smb2_hdr *hdr = &pdu->hdr; > - struct smb2_sync_hdr *shdr = get_sync_hdr(hdr); > + struct smb2_sync_pdu *pdu; > + struct smb2_sync_hdr *shdr; > int offset; /* the offset from the beginning of SMB to data area */ > int data_length; /* the length of the variable length data area */ > /* Structure Size has already been checked to make sure it is 64 */ > - int len = 4 + le16_to_cpu(shdr->StructureSize); > + int len; > + > + pdu = (struct smb2_sync_pdu *)buf; > + shdr = &pdu->sync_hdr; > + len = le16_to_cpu(shdr->StructureSize); > > /* > * StructureSize2, ie length of fixed parameter area has already > @@ -379,7 +378,7 @@ smb2_calc_size(void *buf) > if (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false) > goto calc_size_exit; > > - smb2_get_data_area_len(&offset, &data_length, hdr); > + smb2_get_data_area_len(&offset, &data_length, shdr); > cifs_dbg(FYI, "SMB2 data length %d offset %d\n", data_length, > offset); > > if (data_length > 0) { > @@ -387,15 +386,14 @@ smb2_calc_size(void *buf) > * Check to make sure that data area begins after fixed area, > * Note that last byte of the fixed area is part of data area > * for some commands, typically those with odd > StructureSize, > - * so we must add one to the calculation (and 4 to account for > - * the size of the RFC1001 hdr. > + * so we must add one to the calculation. > */ > - if (offset + 4 + 1 < len) { > + if (offset + 1 < len) { > cifs_dbg(VFS, "data area offset %d overlaps SMB2 > header %d\n", > - offset + 4 + 1, len); > + offset + 1, len); > data_length = 0; > } else { > - len = 4 + offset + data_length; > + len = offset + data_length; > } > } > calc_size_exit: > @@ -578,7 +576,7 @@ smb2_is_valid_lease_break(char *buffer) > bool > smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) > { > - struct smb2_oplock_break_rsp *rsp = (struct > smb2_oplock_break_rsp *)buffer; > + struct smb2_oplock_break *rsp = (struct smb2_oplock_break > *)buffer; > struct list_head *tmp, *tmp1, *tmp2; > struct cifs_ses *ses; > struct cifs_tcon *tcon; > @@ -587,7 +585,7 @@ smb2_is_valid_oplock_break(char *buffer, struct > TCP_Server_Info *server) > > cifs_dbg(FYI, "Checking for oplock break\n"); > > - if (rsp->hdr.sync_hdr.Command != SMB2_OPLOCK_BREAK) > + if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK) > return false; > > if (rsp->StructureSize != > @@ -678,11 +676,15 @@ smb2_cancelled_close_fid(struct work_struct > *work) > int > smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) > { > - struct smb2_sync_hdr *sync_hdr = get_sync_hdr(buffer); > - struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer; > + struct smb2_sync_hdr *sync_hdr; > + struct smb2_create_rsp *rsp; > struct cifs_tcon *tcon; > struct close_cancelled_open *cancelled; > > + sync_hdr = (struct smb2_sync_hdr *)buffer; > + > + rsp = (struct smb2_create_rsp *)sync_hdr; > + > if (sync_hdr->Command != SMB2_CREATE || > sync_hdr->Status != STATUS_SUCCESS) > return 0; > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index ed88ab8a4774..590c5e4b7b1d 100644 > --- a/fs/cifs/smb2ops.c > +++ b/fs/cifs/smb2ops.c > @@ -122,7 +122,14 @@ smb2_get_credits_field(struct TCP_Server_Info > *server, const int optype) > static unsigned int > smb2_get_credits(struct mid_q_entry *mid) > { > - struct smb2_sync_hdr *shdr = get_sync_hdr(mid->resp_buf); > + char *buf = mid->resp_buf; > + struct smb2_sync_hdr *shdr; > + > + if ( *(__u32 *)buf == SMB2_PROTO_NUMBER || > + *(__u32 *)buf == SMB2_TRANSFORM_PROTO_NUM) > + shdr = (struct smb2_sync_hdr *)buf; > + else > + shdr = (struct smb2_sync_hdr *)(buf + 4); > > return le16_to_cpu(shdr->CreditRequest); > } > @@ -189,8 +196,12 @@ static struct mid_q_entry * > smb2_find_mid(struct TCP_Server_Info *server, char *buf) > { > struct mid_q_entry *mid; > - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); > - __u64 wire_mid = le64_to_cpu(shdr->MessageId); > + struct smb2_sync_hdr *shdr; > + __u64 wire_mid; > + > + shdr = (struct smb2_sync_hdr *)buf; > + > + wire_mid = le64_to_cpu(shdr->MessageId); > > if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { > cifs_dbg(VFS, "encrypted frame parsing not supported yet"); > @@ -214,7 +225,9 @@ static void > smb2_dump_detail(void *buf) > { > #ifdef CONFIG_CIFS_DEBUG2 > - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); > + struct smb2_sync_hdr *shdr; > + > + shdr = (struct smb2_sync_hdr *)buf; > > cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n", > shdr->Command, shdr->Status, shdr->Flags, shdr- > >MessageId, > @@ -1230,7 +1243,9 @@ smb2_close_dir(const unsigned int xid, struct > cifs_tcon *tcon, > static bool > smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int > length) > { > - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); > + struct smb2_sync_hdr *shdr; > + > + shdr = (struct smb2_sync_hdr *)buf; > > if (shdr->Status != STATUS_PENDING) > return false; > @@ -1248,7 +1263,9 @@ smb2_is_status_pending(char *buf, struct > TCP_Server_Info *server, int length) > static bool > smb2_is_session_expired(char *buf) > { > - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); > + struct smb2_sync_hdr *shdr; > + > + shdr = (struct smb2_sync_hdr *)buf; > > if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED) > return false; > @@ -1444,6 +1461,7 @@ smb2_query_symlink(const unsigned int xid, struct > cifs_tcon *tcon, > __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; > struct cifs_open_parms oparms; > struct cifs_fid fid; > + struct kvec err_iov = {NULL, 0}; > struct smb2_err_rsp *err_buf = NULL; > struct smb2_symlink_err_rsp *symlink; > unsigned int sub_len; > @@ -1464,15 +1482,16 @@ smb2_query_symlink(const unsigned int xid, > struct cifs_tcon *tcon, > oparms.fid = &fid; > oparms.reconnect = false; > > - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, > &err_buf); > + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, > &err_iov); > > if (!rc || !err_buf) { > kfree(utf16_path); > return -ENOENT; > } > > + err_buf = err_iov.iov_base; > if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct > smb2_symlink_err_rsp) || > - get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) { > + err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) { > kfree(utf16_path); > return -ENOENT; > } > @@ -1485,13 +1504,13 @@ smb2_query_symlink(const unsigned int xid, > struct cifs_tcon *tcon, > print_len = le16_to_cpu(symlink->PrintNameLength); > print_offset = le16_to_cpu(symlink->PrintNameOffset); > > - if (get_rfc1002_length(err_buf) + 4 < > + if (err_iov.iov_len < > SMB2_SYMLINK_STRUCT_SIZE + sub_offset + > sub_len) { > kfree(utf16_path); > return -ENOENT; > } > > - if (get_rfc1002_length(err_buf) + 4 < > + if (err_iov.iov_len < > SMB2_SYMLINK_STRUCT_SIZE + print_offset + > print_len) { > kfree(utf16_path); > return -ENOENT; > @@ -2048,7 +2067,7 @@ static void > fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst > *old_rq) > { > struct smb2_sync_hdr *shdr = > - (struct smb2_sync_hdr *)old_rq- > >rq_iov[1].iov_base; > + (struct smb2_sync_hdr *)old_rq- > >rq_iov[2].iov_base; > unsigned int orig_len = get_rfc1002_length(old_rq- > >rq_iov[0].iov_base); > > memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); > @@ -2057,15 +2076,13 @@ fill_transform_hdr(struct smb2_transform_hdr > *tr_hdr, struct smb_rqst *old_rq) > tr_hdr->Flags = cpu_to_le16(0x01); > get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE); > memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8); > - inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4); > - inc_rfc1001_len(tr_hdr, orig_len); > } > > static struct scatterlist * > init_sg(struct smb_rqst *rqst, u8 *sign) > { > unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1; > - unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - > 24; > + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - > 20; > struct scatterlist *sg; > unsigned int i; > unsigned int j; > @@ -2075,10 +2092,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign) > return NULL; > > sg_init_table(sg, sg_len); > - sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len); > + sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len); > for (i = 1; i < rqst->rq_nvec; i++) > - sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, > - rqst->rq_iov[i].iov_len); > + sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base, > + rqst->rq_iov[i+1].iov_len); > for (j = 0; i < sg_len - 1; i++, j++) { > unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz > : rqst->rq_tailsz; > @@ -2110,17 +2127,18 @@ smb2_get_enc_key(struct TCP_Server_Info > *server, __u64 ses_id, int enc, u8 *key) > } > /* > * Encrypt or decrypt @rqst message. @rqst has the following format: > - * iov[0] - transform header (associate data), > - * iov[1-N] and pages - data to encrypt. > - * On success return encrypted data in iov[1-N] and pages, leave iov[0] > + * iov[0] - rfc1002 length > + * iov[1] - transform header (associate data), > + * iov[2-N] and pages - data to encrypt. > + * On success return encrypted data in iov[2-N] and pages, leave iov[0-1] > * untouched. > */ > static int > crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int > enc) > { > struct smb2_transform_hdr *tr_hdr = > - (struct smb2_transform_hdr *)rqst- > >rq_iov[0].iov_base; > - unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - > 24; > + (struct smb2_transform_hdr *)rqst- > >rq_iov[1].iov_base; > + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - > 20; > int rc = 0; > struct scatterlist *sg; > u8 sign[SMB2_SIGNATURE_SIZE] = {}; > @@ -2207,6 +2225,9 @@ crypt_message(struct TCP_Server_Info *server, > struct smb_rqst *rqst, int enc) > return rc; > } > > +/* This is called from smb_send_rqst. At this point we have the rfc1002 > + * header as the first element in the vector. > + */ > static int > smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst > *new_rq, > struct smb_rqst *old_rq) > @@ -2233,24 +2254,32 @@ smb3_init_transform_rq(struct TCP_Server_Info > *server, struct smb_rqst *new_rq, > goto err_free_pages; > } > > - iov = kmalloc_array(old_rq->rq_nvec, sizeof(struct kvec), > GFP_KERNEL); > + /* Make space for one extra iov to hold the transform header */ > + iov = kmalloc_array(old_rq->rq_nvec + 1, sizeof(struct kvec), > + GFP_KERNEL); > if (!iov) > goto err_free_pages; > > /* copy all iovs from the old except the 1st one (rfc1002 length) */ > - memcpy(&iov[1], &old_rq->rq_iov[1], > + memcpy(&iov[2], &old_rq->rq_iov[1], > sizeof(struct kvec) * (old_rq->rq_nvec - 1)); > + /* copy the rfc1002 iov */ > + memcpy(iov[0].iov_base, old_rq->rq_iov[0].iov_base, > + old_rq->rq_iov[0].iov_len); > + > new_rq->rq_iov = iov; > - new_rq->rq_nvec = old_rq->rq_nvec; > + new_rq->rq_nvec = old_rq->rq_nvec + 1; > > tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL); > if (!tr_hdr) > goto err_free_iov; > > - /* fill the 1st iov with a transform header */ > + /* fill the 2nd iov with a transform header */ > fill_transform_hdr(tr_hdr, old_rq); > - new_rq->rq_iov[0].iov_base = tr_hdr; > - new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr); > + inc_rfc1001_len(new_rq->rq_iov[0].iov_base, > + sizeof(struct smb2_transform_hdr)); > + new_rq->rq_iov[1].iov_base = tr_hdr; > + new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr); > > /* copy pages form the old */ > for (i = 0; i < npages; i++) { > @@ -2307,18 +2336,19 @@ decrypt_raw_data(struct TCP_Server_Info > *server, char *buf, > unsigned int buf_data_size, struct page **pages, > unsigned int npages, unsigned int page_data_size) > { > - struct kvec iov[2]; > + struct kvec iov[3]; > struct smb_rqst rqst = {NULL}; > - struct smb2_hdr *hdr; > int rc; > > - iov[0].iov_base = buf; > - iov[0].iov_len = sizeof(struct smb2_transform_hdr); > - iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr); > - iov[1].iov_len = buf_data_size; > + iov[0].iov_base = NULL; > + iov[0].iov_len = 0; > + iov[1].iov_base = buf; > + iov[1].iov_len = sizeof(struct smb2_transform_hdr); > + iov[2].iov_base = buf + sizeof(struct smb2_transform_hdr); > + iov[2].iov_len = buf_data_size; > > rqst.rq_iov = iov; > - rqst.rq_nvec = 2; > + rqst.rq_nvec = 3; > rqst.rq_pages = pages; > rqst.rq_npages = npages; > rqst.rq_pagesz = PAGE_SIZE; > @@ -2330,10 +2360,10 @@ decrypt_raw_data(struct TCP_Server_Info > *server, char *buf, > if (rc) > return rc; > > - memmove(buf + 4, iov[1].iov_base, buf_data_size); > - hdr = (struct smb2_hdr *)buf; > - hdr->smb2_buf_length = cpu_to_be32(buf_data_size + > page_data_size); > - server->total_read = buf_data_size + page_data_size + 4; > + > + memmove(buf, iov[0].iov_base, buf_data_size); > + > + server->total_read = buf_data_size + page_data_size; > > return rc; > } > @@ -2406,12 +2436,14 @@ handle_read_data(struct TCP_Server_Info > *server, struct mid_q_entry *mid, > unsigned int cur_page_idx; > unsigned int pad_len; > struct cifs_readdata *rdata = mid->callback_data; > - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); > + struct smb2_sync_hdr *shdr; > struct bio_vec *bvec = NULL; > struct iov_iter iter; > struct kvec iov; > int length; > > + shdr = (struct smb2_sync_hdr *)buf; > + > if (shdr->Command != SMB2_READ) { > cifs_dbg(VFS, "only big read responses are supported\n"); > return -ENOTSUPP; > @@ -2529,11 +2561,11 @@ receive_encrypted_read(struct TCP_Server_Info > *server, struct mid_q_entry **mid) > unsigned int npages; > struct page **pages; > unsigned int len; > - unsigned int buflen = get_rfc1002_length(buf) + 4; > + unsigned int buflen = server->total_read; > int rc; > int i = 0; > > - len = min_t(unsigned int, buflen, server->vals->read_rsp_size - 4 + > + len = min_t(unsigned int, buflen, server->vals->read_rsp_size + > sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + > 1; > > rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, > len); > @@ -2541,7 +2573,7 @@ receive_encrypted_read(struct TCP_Server_Info > *server, struct mid_q_entry **mid) > return rc; > server->total_read += rc; > > - len = le32_to_cpu(tr_hdr->OriginalMessageSize) + 4 - > + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - > server->vals->read_rsp_size; > npages = DIV_ROUND_UP(len, PAGE_SIZE); > > @@ -2568,7 +2600,7 @@ receive_encrypted_read(struct TCP_Server_Info > *server, struct mid_q_entry **mid) > if (rc) > goto free_pages; > > - rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size - 4, > + rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size, > pages, npages, len); > if (rc) > goto free_pages; > @@ -2600,12 +2632,12 @@ receive_encrypted_standard(struct > TCP_Server_Info *server, > { > int length; > char *buf = server->smallbuf; > - unsigned int pdu_length = get_rfc1002_length(buf); > + unsigned int pdu_length = server->total_read; > unsigned int buf_size; > struct mid_q_entry *mid_entry; > > /* switch to large buffer if too big for a small one */ > - if (pdu_length + 4 > MAX_CIFS_SMALL_BUFFER_SIZE) { > + if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { > server->large_buf = true; > memcpy(server->bigbuf, buf, server->total_read); > buf = server->bigbuf; > @@ -2613,12 +2645,12 @@ receive_encrypted_standard(struct > TCP_Server_Info *server, > > /* now read the rest */ > length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - > 1, > - pdu_length - HEADER_SIZE(server) + 1 + 4); > + pdu_length - HEADER_SIZE(server) + 1); > if (length < 0) > return length; > server->total_read += length; > > - buf_size = pdu_length + 4 - sizeof(struct smb2_transform_hdr); > + buf_size = pdu_length - sizeof(struct smb2_transform_hdr); > length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0); > if (length) > return length; > @@ -2643,12 +2675,12 @@ static int > smb3_receive_transform(struct TCP_Server_Info *server, struct > mid_q_entry **mid) > { > char *buf = server->smallbuf; > - unsigned int pdu_length = get_rfc1002_length(buf); > + unsigned int pdu_length = server->total_read; > struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr > *)buf; > unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize); > > - if (pdu_length + 4 < sizeof(struct smb2_transform_hdr) + > - sizeof(struct > smb2_sync_hdr)) { > + if (pdu_length < sizeof(struct smb2_transform_hdr) + > + sizeof(struct smb2_sync_hdr)) { > cifs_dbg(VFS, "Transform message is too small (%u)\n", > pdu_length); > cifs_reconnect(server); > @@ -2656,14 +2688,14 @@ smb3_receive_transform(struct > TCP_Server_Info *server, struct mid_q_entry **mid) > return -ECONNABORTED; > } > > - if (pdu_length + 4 < orig_len + sizeof(struct smb2_transform_hdr)) { > + if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) { > cifs_dbg(VFS, "Transform message is broken\n"); > cifs_reconnect(server); > wake_up(&server->response_q); > return -ECONNABORTED; > } > > - if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) > + if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) > return receive_encrypted_read(server, mid); > > return receive_encrypted_standard(server, mid); > @@ -3078,7 +3110,8 @@ struct smb_version_values smb20_values = { > .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, > .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, > .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, > - .header_size = sizeof(struct smb2_hdr), > + .header_preamble_size = 0, > + .header_size = sizeof(struct smb2_sync_hdr), > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3098,7 +3131,8 @@ struct smb_version_values smb21_values = { > .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, > .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, > .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, > - .header_size = sizeof(struct smb2_hdr), > + .header_preamble_size = 0, > + .header_size = sizeof(struct smb2_sync_hdr), > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3118,7 +3152,8 @@ struct smb_version_values smb3any_values = { > .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, > .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, > .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, > - .header_size = sizeof(struct smb2_hdr), > + .header_preamble_size = 0, > + .header_size = sizeof(struct smb2_sync_hdr), > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3138,7 +3173,8 @@ struct smb_version_values smbdefault_values = { > .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, > .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, > .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, > - .header_size = sizeof(struct smb2_hdr), > + .header_preamble_size = 0, > + .header_size = sizeof(struct smb2_sync_hdr), > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3158,7 +3194,8 @@ struct smb_version_values smb30_values = { > .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, > .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, > .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, > - .header_size = sizeof(struct smb2_hdr), > + .header_preamble_size = 0, > + .header_size = sizeof(struct smb2_sync_hdr), > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3178,7 +3215,8 @@ struct smb_version_values smb302_values = { > .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, > .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, > .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, > - .header_size = sizeof(struct smb2_hdr), > + .header_preamble_size = 0, > + .header_size = sizeof(struct smb2_sync_hdr), > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3199,7 +3237,8 @@ struct smb_version_values smb311_values = { > .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, > .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, > .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, > - .header_size = sizeof(struct smb2_hdr), > + .header_preamble_size = 0, > + .header_size = sizeof(struct smb2_sync_hdr), > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c > index c0dc0491af93..ad178150fbf3 100644 > --- a/fs/cifs/smb2pdu.c > +++ b/fs/cifs/smb2pdu.c > @@ -577,7 +577,7 @@ SMB2_negotiate(const unsigned int xid, struct > cifs_ses *ses) > server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES; > > security_blob = smb2_get_data_area_len(&blob_offset, > &blob_length, > - &rsp->hdr); > + (struct smb2_sync_hdr *)rsp); > /* > * See MS-SMB2 section 2.2.4: if no blob, client picks default which > * for us will be > @@ -921,7 +921,7 @@ SMB2_auth_kerberos(struct SMB2_sess_data > *sess_data) > goto out_put_spnego_key; > > rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; > - ses->Suid = rsp->hdr.sync_hdr.SessionId; > + ses->Suid = rsp->sync_hdr.SessionId; > > ses->session_flags = le16_to_cpu(rsp->SessionFlags); > > @@ -997,13 +997,13 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct > SMB2_sess_data *sess_data) > > /* If true, rc here is expected and not an error */ > if (sess_data->buf0_type != CIFS_NO_BUFFER && > - rsp->hdr.sync_hdr.Status == > STATUS_MORE_PROCESSING_REQUIRED) > + rsp->sync_hdr.Status == > STATUS_MORE_PROCESSING_REQUIRED) > rc = 0; > > if (rc) > goto out; > > - if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 != > + if (offsetof(struct smb2_sess_setup_rsp, Buffer) != > le16_to_cpu(rsp->SecurityBufferOffset)) { > cifs_dbg(VFS, "Invalid security buffer offset %d\n", > le16_to_cpu(rsp->SecurityBufferOffset)); > @@ -1018,7 +1018,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct > SMB2_sess_data *sess_data) > cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n"); > > > - ses->Suid = rsp->hdr.sync_hdr.SessionId; > + ses->Suid = rsp->sync_hdr.SessionId; > ses->session_flags = le16_to_cpu(rsp->SessionFlags); > > out: > @@ -1076,7 +1076,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct > SMB2_sess_data *sess_data) > > rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; > > - ses->Suid = rsp->hdr.sync_hdr.SessionId; > + ses->Suid = rsp->sync_hdr.SessionId; > ses->session_flags = le16_to_cpu(rsp->SessionFlags); > > rc = SMB2_sess_establish_session(sess_data); > @@ -1298,7 +1298,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses > *ses, const char *tree, > } > > if (tcon == NULL) { > - ses->ipc_tid = rsp->hdr.sync_hdr.TreeId; > + ses->ipc_tid = rsp->sync_hdr.TreeId; > goto tcon_exit; > } > > @@ -1325,7 +1325,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses > *ses, const char *tree, > tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess); > tcon->tidStatus = CifsGood; > tcon->need_reconnect = false; > - tcon->tid = rsp->hdr.sync_hdr.TreeId; > + tcon->tid = rsp->sync_hdr.TreeId; > strlcpy(tcon->treeName, tree, sizeof(tcon->treeName)); > > if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) && > @@ -1345,7 +1345,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses > *ses, const char *tree, > return rc; > > tcon_error_exit: > - if (rsp && rsp->hdr.sync_hdr.Status == > STATUS_BAD_NETWORK_NAME) { > + if (rsp && rsp->sync_hdr.Status == STATUS_BAD_NETWORK_NAME) > { > cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); > } > goto tcon_exit; > @@ -1451,7 +1451,7 @@ parse_lease_state(struct TCP_Server_Info *server, > struct smb2_create_rsp *rsp, > unsigned int remaining; > char *name; > > - data_offset = (char *)rsp + 4 + le32_to_cpu(rsp- > >CreateContextsOffset); > + data_offset = (char *)rsp + le32_to_cpu(rsp- > >CreateContextsOffset); > remaining = le32_to_cpu(rsp->CreateContextsLength); > cc = (struct create_context *)data_offset; > while (remaining >= sizeof(struct create_context)) { > @@ -1679,7 +1679,7 @@ alloc_path_with_tree_prefix(__le16 **out_path, > int *out_size, int *out_len, > int > SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, > __le16 *path, > __u8 *oplock, struct smb2_file_all_info *buf, > - struct smb2_err_rsp **err_buf) > + struct kvec *err_iov) > { > struct smb2_create_req *req; > struct smb2_create_rsp *rsp; > @@ -1815,9 +1815,10 @@ SMB2_open(const unsigned int xid, struct > cifs_open_parms *oparms, __le16 *path, > > if (rc != 0) { > cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); > - if (err_buf && rsp) > - *err_buf = kmemdup(rsp, get_rfc1002_length(rsp) + > 4, > - GFP_KERNEL); > + if (err_iov && rsp) { > + *err_iov = rsp_iov; > + rsp = NULL; > + } > goto creat_exit; > } > > @@ -1856,7 +1857,6 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon > *tcon, u64 persistent_fid, > { > struct smb2_ioctl_req *req; > struct smb2_ioctl_rsp *rsp; > - struct smb2_sync_hdr *shdr; > struct cifs_ses *ses; > struct kvec iov[2]; > struct kvec rsp_iov; > @@ -1987,7 +1987,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon > *tcon, u64 persistent_fid, > goto ioctl_exit; > } > > - if (get_rfc1002_length(rsp) < le32_to_cpu(rsp->OutputOffset) + > *plen) { > + if (rsp_iov.iov_len < le32_to_cpu(rsp->OutputOffset) + *plen) { > cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", > *plen, > le32_to_cpu(rsp->OutputOffset)); > *plen = 0; > @@ -2001,8 +2001,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon > *tcon, u64 persistent_fid, > goto ioctl_exit; > } > > - shdr = get_sync_hdr(rsp); > - memcpy(*out_data, (char *)shdr + le32_to_cpu(rsp->OutputOffset), > *plen); > + memcpy(*out_data, (char *)rsp + le32_to_cpu(rsp->OutputOffset), > *plen); > ioctl_exit: > free_rsp_buf(resp_buftype, rsp); > return rc; > @@ -2083,13 +2082,12 @@ SMB2_close(const unsigned int xid, struct > cifs_tcon *tcon, > } > > static int > -validate_buf(unsigned int offset, unsigned int buffer_length, > - struct smb2_hdr *hdr, unsigned int min_buf_size) > - > +validate_iov(unsigned int offset, unsigned int buffer_length, > + struct kvec *iov, unsigned int min_buf_size) > { > - unsigned int smb_len = be32_to_cpu(hdr->smb2_buf_length); > - char *end_of_smb = smb_len + 4 /* RFC1001 length field */ + (char > *)hdr; > - char *begin_of_buf = 4 /* RFC1001 len field */ + offset + (char *)hdr; > + unsigned int smb_len = iov->iov_len; > + char *end_of_smb = smb_len + (char *)iov->iov_base; > + char *begin_of_buf = offset + (char *)iov->iov_base; > char *end_of_buf = begin_of_buf + buffer_length; > > > @@ -2119,18 +2117,17 @@ validate_buf(unsigned int offset, unsigned int > buffer_length, > * Caller must free buffer. > */ > static int > -validate_and_copy_buf(unsigned int offset, unsigned int buffer_length, > - struct smb2_hdr *hdr, unsigned int minbufsize, > +validate_and_copy_iov(unsigned int offset, unsigned int buffer_length, > + struct kvec *iov, unsigned int minbufsize, > char *data) > - > { > - char *begin_of_buf = 4 /* RFC1001 len field */ + offset + (char *)hdr; > + char *begin_of_buf = offset + (char *)iov->iov_base; > int rc; > > if (!data) > return -EINVAL; > > - rc = validate_buf(offset, buffer_length, hdr, minbufsize); > + rc = validate_iov(offset, buffer_length, iov, minbufsize); > if (rc) > return rc; > > @@ -2208,9 +2205,9 @@ query_info(const unsigned int xid, struct cifs_tcon > *tcon, > } > } > > - rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset), > + rc = validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset), > le32_to_cpu(rsp->OutputBufferLength), > - &rsp->hdr, min_len, *data); > + &rsp_iov, min_len, *data); > > qinf_exit: > free_rsp_buf(resp_buftype, rsp); > @@ -2279,7 +2276,7 @@ smb2_echo_callback(struct mid_q_entry *mid) > unsigned int credits_received = 1; > > if (mid->mid_state == MID_RESPONSE_RECEIVED) > - credits_received = le16_to_cpu(rsp- > >hdr.sync_hdr.CreditRequest); > + credits_received = le16_to_cpu(rsp- > >sync_hdr.CreditRequest); > > DeleteMidQEntry(mid); > add_credits(server, credits_received, CIFS_ECHO_OP); > @@ -2629,7 +2626,6 @@ SMB2_read(const unsigned int xid, struct > cifs_io_parms *io_parms, > int resp_buftype, rc = -EACCES; > struct smb2_read_plain_req *req = NULL; > struct smb2_read_rsp *rsp = NULL; > - struct smb2_sync_hdr *shdr; > struct kvec iov[1]; > struct kvec rsp_iov; > unsigned int total_len; > @@ -2670,10 +2666,8 @@ SMB2_read(const unsigned int xid, struct > cifs_io_parms *io_parms, > *nbytes = 0; > } > > - shdr = get_sync_hdr(rsp); > - > if (*buf) { > - memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes); > + memcpy(*buf, (char *)rsp + rsp->DataOffset, *nbytes); > free_rsp_buf(resp_buftype, rsp_iov.iov_base); > } else if (resp_buftype != CIFS_NO_BUFFER) { > *buf = rsp_iov.iov_base; > @@ -2700,7 +2694,7 @@ smb2_writev_callback(struct mid_q_entry *mid) > > switch (mid->mid_state) { > case MID_RESPONSE_RECEIVED: > - credits_received = le16_to_cpu(rsp- > >hdr.sync_hdr.CreditRequest); > + credits_received = le16_to_cpu(rsp- > >sync_hdr.CreditRequest); > wdata->result = smb2_check_receive(mid, tcon->ses- > >server, 0); > if (wdata->result != 0) > break; > @@ -3018,7 +3012,7 @@ SMB2_query_directory(const unsigned int xid, > struct cifs_tcon *tcon, > > if (rc) { > if (rc == -ENODATA && > - rsp->hdr.sync_hdr.Status == STATUS_NO_MORE_FILES) { > + rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { > srch_inf->endOfSearch = true; > rc = 0; > } > @@ -3026,8 +3020,8 @@ SMB2_query_directory(const unsigned int xid, > struct cifs_tcon *tcon, > goto qdir_exit; > } > > - rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset), > - le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr, > + rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), > + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, > info_buf_size); > if (rc) > goto qdir_exit; > @@ -3041,10 +3035,9 @@ SMB2_query_directory(const unsigned int xid, > struct cifs_tcon *tcon, > cifs_buf_release(srch_inf->ntwrk_buf_start); > } > srch_inf->ntwrk_buf_start = (char *)rsp; > - srch_inf->srch_entries_start = srch_inf->last_entry = 4 /* rfclen */ + > - (char *)&rsp->hdr + le16_to_cpu(rsp->OutputBufferOffset); > - /* 4 for rfc1002 length field */ > - end_of_smb = get_rfc1002_length(rsp) + 4 + (char *)&rsp->hdr; > + srch_inf->srch_entries_start = srch_inf->last_entry = > + (char *)rsp + le16_to_cpu(rsp->OutputBufferOffset); > + end_of_smb = rsp_iov.iov_len + (char *)rsp; > srch_inf->entries_in_buffer = > num_entries(srch_inf->srch_entries_start, > end_of_smb, > &srch_inf->last_entry, info_buf_size); > @@ -3280,7 +3273,7 @@ SMB2_oplock_break(const unsigned int xid, struct > cifs_tcon *tcon, > __u8 oplock_level) > { > int rc; > - struct smb2_oplock_break_req *req = NULL; > + struct smb2_oplock_break *req = NULL; > struct cifs_ses *ses = tcon->ses; > int flags = CIFS_OBREAK_OP; > unsigned int total_len; > @@ -3356,7 +3349,7 @@ build_qfs_info_req(struct kvec *iov, struct > cifs_tcon *tcon, int level, > req->InputBufferOffset = > cpu_to_le16(sizeof(struct smb2_query_info_req) - > 1); > req->OutputBufferLength = cpu_to_le32( > - outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4); > + outbuf_len + sizeof(struct smb2_query_info_rsp) - 1); > > iov->iov_base = (char *)req; > iov->iov_len = total_len; > @@ -3393,10 +3386,10 @@ SMB2_QFS_info(const unsigned int xid, struct > cifs_tcon *tcon, > } > rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; > > - info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ + > - le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr); > - rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset), > - le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr, > + info = (struct smb2_fs_full_size_info *)( > + le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); > + rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), > + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, > sizeof(struct smb2_fs_full_size_info)); > if (!rc) > copy_fs_info_to_kstatfs(info, fsdata); > @@ -3451,20 +3444,20 @@ SMB2_QFS_attr(const unsigned int xid, struct > cifs_tcon *tcon, > > rsp_len = le32_to_cpu(rsp->OutputBufferLength); > offset = le16_to_cpu(rsp->OutputBufferOffset); > - rc = validate_buf(offset, rsp_len, &rsp->hdr, min_len); > + rc = validate_iov(offset, rsp_len, &rsp_iov, min_len); > if (rc) > goto qfsattr_exit; > > if (level == FS_ATTRIBUTE_INFORMATION) > - memcpy(&tcon->fsAttrInfo, 4 /* RFC1001 len */ + offset > - + (char *)&rsp->hdr, min_t(unsigned int, > + memcpy(&tcon->fsAttrInfo, offset > + + (char *)rsp, min_t(unsigned int, > rsp_len, max_len)); > else if (level == FS_DEVICE_INFORMATION) > - memcpy(&tcon->fsDevInfo, 4 /* RFC1001 len */ + offset > - + (char *)&rsp->hdr, > sizeof(FILE_SYSTEM_DEVICE_INFO)); > + memcpy(&tcon->fsDevInfo, offset > + + (char *)rsp, sizeof(FILE_SYSTEM_DEVICE_INFO)); > else if (level == FS_SECTOR_SIZE_INFORMATION) { > struct smb3_fs_ss_info *ss_info = (struct smb3_fs_ss_info *) > - (4 /* RFC1001 len */ + offset + (char *)&rsp->hdr); > + (offset + (char *)rsp); > tcon->ss_flags = le32_to_cpu(ss_info->Flags); > tcon->perf_sector_size = > le32_to_cpu(ss_info- > >PhysicalBytesPerSectorForPerf); > diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h > index 19d34881815f..91fd17f5c2eb 100644 > --- a/fs/cifs/smb2pdu.h > +++ b/fs/cifs/smb2pdu.h > @@ -122,25 +122,10 @@ struct smb2_sync_pdu { > __le16 StructureSize2; /* size of wct area (varies, request specific) */ > } __packed; > > -struct smb2_hdr { > - __be32 smb2_buf_length; /* big endian on wire */ > - /* length is only two or three bytes - with */ > - /* one or two byte type preceding it that > MBZ */ > - struct smb2_sync_hdr sync_hdr; > -} __packed; > - > -struct smb2_pdu { > - struct smb2_hdr hdr; > - __le16 StructureSize2; /* size of wct area (varies, request specific) */ > -} __packed; > - > #define SMB3_AES128CMM_NONCE 11 > #define SMB3_AES128GCM_NONCE 12 > > struct smb2_transform_hdr { > - __be32 smb2_buf_length; /* big endian on wire */ > - /* length is only two or three bytes - with > - one or two byte type preceding it that MBZ > */ > __le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */ > __u8 Signature[16]; > __u8 Nonce[16]; > @@ -171,7 +156,7 @@ struct smb2_transform_hdr { > #define SMB2_ERROR_STRUCTURE_SIZE2 cpu_to_le16(9) > > struct smb2_err_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; > __le16 Reserved; /* MBZ */ > __le32 ByteCount; /* even if zero, at least one byte follows */ > @@ -259,7 +244,7 @@ struct smb2_encryption_neg_context { > } __packed; > > struct smb2_negotiate_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 65 */ > __le16 SecurityMode; > __le16 DialectRevision; > @@ -299,7 +284,7 @@ struct smb2_sess_setup_req { > #define SMB2_SESSION_FLAG_IS_NULL 0x0002 > #define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004 > struct smb2_sess_setup_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 9 */ > __le16 SessionFlags; > __le16 SecurityBufferOffset; > @@ -314,7 +299,7 @@ struct smb2_logoff_req { > } __packed; > > struct smb2_logoff_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 4 */ > __le16 Reserved; > } __packed; > @@ -332,7 +317,7 @@ struct smb2_tree_connect_req { > } __packed; > > struct smb2_tree_connect_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 16 */ > __u8 ShareType; /* see below */ > __u8 Reserved; > @@ -381,7 +366,7 @@ struct smb2_tree_disconnect_req { > } __packed; > > struct smb2_tree_disconnect_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 4 */ > __le16 Reserved; > } __packed; > @@ -516,7 +501,7 @@ struct smb2_create_req { > } __packed; > > struct smb2_create_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 89 */ > __u8 OplockLevel; > __u8 Reserved; > @@ -771,7 +756,7 @@ struct smb2_ioctl_req { > } __packed; > > struct smb2_ioctl_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 57 */ > __u16 Reserved; > __le32 CtlCode; > @@ -798,7 +783,7 @@ struct smb2_close_req { > } __packed; > > struct smb2_close_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* 60 */ > __le16 Flags; > __le32 Reserved; > @@ -821,7 +806,7 @@ struct smb2_flush_req { > } __packed; > > struct smb2_flush_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; > __le16 Reserved; > } __packed; > @@ -853,7 +838,7 @@ struct smb2_read_plain_req { > } __packed; > > struct smb2_read_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 17 */ > __u8 DataOffset; > __u8 Reserved; > @@ -884,7 +869,7 @@ struct smb2_write_req { > } __packed; > > struct smb2_write_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 17 */ > __u8 DataOffset; > __u8 Reserved; > @@ -918,7 +903,7 @@ struct smb2_lock_req { > } __packed; > > struct smb2_lock_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 4 */ > __le16 Reserved; > } __packed; > @@ -930,7 +915,7 @@ struct smb2_echo_req { > } __packed; > > struct smb2_echo_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 4 */ > __u16 Reserved; > } __packed; > @@ -956,7 +941,7 @@ struct smb2_query_directory_req { > } __packed; > > struct smb2_query_directory_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 9 */ > __le16 OutputBufferOffset; > __le32 OutputBufferLength; > @@ -1005,7 +990,7 @@ struct smb2_query_info_req { > } __packed; > > struct smb2_query_info_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 9 */ > __le16 OutputBufferOffset; > __le32 OutputBufferLength; > @@ -1027,12 +1012,11 @@ struct smb2_set_info_req { > } __packed; > > struct smb2_set_info_rsp { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 2 */ > } __packed; > > -/* oplock break without an rfc1002 header */ > -struct smb2_oplock_break_req { > +struct smb2_oplock_break { > struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 24 */ > __u8 OplockLevel; > @@ -1042,21 +1026,10 @@ struct smb2_oplock_break_req { > __u64 VolatileFid; > } __packed; > > -/* oplock break with an rfc1002 header */ > -struct smb2_oplock_break_rsp { > - struct smb2_hdr hdr; > - __le16 StructureSize; /* Must be 24 */ > - __u8 OplockLevel; > - __u8 Reserved; > - __le32 Reserved2; > - __u64 PersistentFid; > - __u64 VolatileFid; > -} __packed; > - > #define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED > cpu_to_le32(0x01) > > struct smb2_lease_break { > - struct smb2_hdr hdr; > + struct smb2_sync_hdr sync_hdr; > __le16 StructureSize; /* Must be 44 */ > __le16 Reserved; > __le32 Flags; > diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h > index e9ab5227e7a8..089a6ef936b8 100644 > --- a/fs/cifs/smb2proto.h > +++ b/fs/cifs/smb2proto.h > @@ -37,7 +37,8 @@ extern int map_smb2_to_linux_error(char *buf, bool > log_err); > extern int smb2_check_message(char *buf, unsigned int length, > struct TCP_Server_Info *server); > extern unsigned int smb2_calc_size(void *buf); > -extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr > *hdr); > +extern char *smb2_get_data_area_len(int *off, int *len, > + struct smb2_sync_hdr *shdr); > extern __le16 *cifs_convert_path_to_utf16(const char *from, > struct cifs_sb_info *cifs_sb); > > @@ -122,7 +123,7 @@ extern int SMB2_tdis(const unsigned int xid, struct > cifs_tcon *tcon); > extern int SMB2_open(const unsigned int xid, struct cifs_open_parms > *oparms, > __le16 *path, __u8 *oplock, > struct smb2_file_all_info *buf, > - struct smb2_err_rsp **err_buf); > + struct kvec *err_iov); > extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, > u64 persistent_fid, u64 volatile_fid, u32 opcode, > bool is_fsctl, bool use_ipc, > diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c > index 99493946e2f9..cf37c6651bf6 100644 > --- a/fs/cifs/smb2transport.c > +++ b/fs/cifs/smb2transport.c > @@ -624,10 +624,10 @@ smb2_check_receive(struct mid_q_entry *mid, > struct TCP_Server_Info *server, > struct smb_rqst rqst = { .rq_iov = iov, > .rq_nvec = 2 }; > > - iov[0].iov_base = (char *)mid->resp_buf; > + iov[0].iov_base = NULL; > iov[0].iov_len = 4; > - iov[1].iov_base = (char *)mid->resp_buf + 4; > - iov[1].iov_len = len; > + iov[1].iov_base = (char *)mid->resp_buf; > + iov[1].iov_len = server->total_size; > > dump_smb(mid->resp_buf, min_t(u32, 80, len)); > /* convert the length into a more usable form */ > diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c > index 510f41a435c8..5cecf67af8f1 100644 > --- a/fs/cifs/transport.c > +++ b/fs/cifs/transport.c > @@ -779,7 +779,9 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses > *ses, > > buf = (char *)midQ->resp_buf; > resp_iov->iov_base = buf; > - resp_iov->iov_len = get_rfc1002_length(buf) + 4; > + resp_iov->iov_len = ses->server->total_size + > + ses->server->vals->header_preamble_size; > + > if (midQ->large_buf) > *resp_buf_type = CIFS_LARGE_BUFFER; > else > -- > 2.13.3 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at > https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger.ke > rnel.org%2Fmajordomo- > info.html&data=02%7C01%7Clongli%40microsoft.com%7C87c5835933204099 > df5808d552312c01%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C63 > 6505293516357233&sdata=krI0mR4ST9isrQpCQ5xQ4yAbkqEf10SYaZb4FP%2B > k2GA%3D&reserved=0 -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html