[02/16] cifs: remove rfc1002 header from all SMB2 response structures

Message ID 20180331004536.27346-3-lsahlber@redhat.com
State New
Headers show
Series
  • initial part of compounding patches
Related show

Commit Message

Ronnie Sahlberg March 31, 2018, 12:45 a.m.
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.

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
---
 fs/cifs/cifsglob.h      |   3 +
 fs/cifs/cifssmb.c       |   2 +-
 fs/cifs/connect.c       |  10 +++-
 fs/cifs/misc.c          |   2 +-
 fs/cifs/smb2glob.h      |   5 --
 fs/cifs/smb2maperror.c  |   2 +-
 fs/cifs/smb2misc.c      |  88 +++++++++++++----------------
 fs/cifs/smb2ops.c       | 143 +++++++++++++++++++++++++++---------------------
 fs/cifs/smb2pdu.c       |  93 +++++++++++++++----------------
 fs/cifs/smb2pdu.h       |  65 +++++++---------------
 fs/cifs/smb2proto.h     |   5 +-
 fs/cifs/smb2transport.c |  12 ++--
 fs/cifs/transport.c     |   3 +-
 13 files changed, 206 insertions(+), 227 deletions(-)

Comments

Pavel Shilovsky April 5, 2018, 12:35 a.m. | #1
2018-03-30 17:45 GMT-07:00 Ronnie Sahlberg <lsahlber@redhat.com>:
> 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.
>
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
>  fs/cifs/cifsglob.h      |   3 +
>  fs/cifs/cifssmb.c       |   2 +-
>  fs/cifs/connect.c       |  10 +++-
>  fs/cifs/misc.c          |   2 +-
>  fs/cifs/smb2glob.h      |   5 --
>  fs/cifs/smb2maperror.c  |   2 +-
>  fs/cifs/smb2misc.c      |  88 +++++++++++++----------------
>  fs/cifs/smb2ops.c       | 143 +++++++++++++++++++++++++++---------------------
>  fs/cifs/smb2pdu.c       |  93 +++++++++++++++----------------
>  fs/cifs/smb2pdu.h       |  65 +++++++---------------
>  fs/cifs/smb2proto.h     |   5 +-
>  fs/cifs/smb2transport.c |  12 ++--
>  fs/cifs/transport.c     |   3 +-
>  13 files changed, 206 insertions(+), 227 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 3e3f86841372..0045d85ec76d 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -665,6 +665,8 @@ 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 */
> +       /* Total size of this PDU. Only valid from cifs_demultiplex_thread */
> +       unsigned int pdu_size;
>         unsigned int total_read; /* total amount of data read in this pass */
>  #ifdef CONFIG_CIFS_FSCACHE
>         struct fscache_cookie   *fscache; /* client index cache cookie */
> @@ -1373,6 +1375,7 @@ struct mid_q_entry {
>         mid_handle_t *handle; /* call handle mid callback */
>         void *callback_data;      /* general purpose pointer for callback */
>         void *resp_buf;         /* pointer to received SMB header */
> +       unsigned int resp_buf_size;
>         int mid_state;  /* wish this were enum but can not pass to wait_event */
>         unsigned int mid_flags;
>         __le16 command;         /* smb command code */
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 59c09a596c0a..991e9d9ef90a 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -1454,7 +1454,7 @@ 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) +
> +       unsigned int buflen = server->pdu_size +
>                 server->vals->header_preamble_size;
>         bool use_rdma_mr = false;

In we face of an error during reading, we will call
cifs_discard_remaining_data() which calls
get_rfc1002_length(server->smallbuf). server->smallbuf contains the
SMB2 packet without RFC1002 length, so this will calculate the
remaining length incorrectly and that's why xfstests probably fails
with the patch.

In order to avoid similar problems we should consider re-examining
every use of get_rfc1002_length() as well as server->smallbuf in the
code.

>
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 1f2e3b15b2b1..0fad48d081d8 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -772,7 +772,7 @@ 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->pdu_size;

I would suggest to split the patch into 2: the 1st part eliminate the
use of get_rfc1002_length() ...

>
>         /* make sure this will fit in a large buffer */
>         if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
> @@ -874,13 +874,18 @@ cifs_demultiplex_thread(void *p)
>                 length = cifs_read_from_socket(server, buf, pdu_length);
>                 if (length < 0)
>                         continue;
> -               server->total_read = length;
> +
> +               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->pdu_size = pdu_length;
>
>                 cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
>                 if (!is_smb_response(server, buf[0]))
> @@ -927,6 +932,7 @@ cifs_demultiplex_thread(void *p)
>
>                 server->lstrp = jiffies;
>                 if (mid_entry != NULL) {
> +                       mid_entry->resp_buf_size = server->pdu_size;
>                         if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
>                              mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
>                                         server->ops->handle_cancelled_mid)
> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
> index 460084a8eac5..d5d7eb2ae3c4 100644
> --- a/fs/cifs/misc.c
> +++ b/fs/cifs/misc.c
> @@ -145,7 +145,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/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..8fe30288805f 100644
> --- a/fs/cifs/smb2maperror.c
> +++ b/fs/cifs/smb2maperror.c
> @@ -2450,7 +2450,7 @@ 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 = (struct smb2_sync_hdr *)buf;

...and the 2nd one removes RFC1002 length from the header.


>         unsigned int i;
>         int rc = -EIO;
>         __le32 smb2err = shdr->Status;
> diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
> index dfa5d9f4e00b..c65a9dfcb988 100644
> --- a/fs/cifs/smb2misc.c
> +++ b/fs/cifs/smb2misc.c
> @@ -94,25 +94,20 @@ 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)
> +smb2_check_message(char *buf, unsigned int len, 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_hdr *shdr = (struct smb2_sync_hdr *)buf;
> +       struct smb2_sync_pdu *pdu = (struct smb2_sync_pdu *)shdr;
>         __u64 mid;
> -       __u32 len = get_rfc1002_length(buf);
>         __u32 clc_len;  /* calculated length */
>         int command;
> -
> -       /* BB disable following printk later */
> -       cifs_dbg(FYI, "%s length: 0x%x, smb_buf_length: 0x%x\n",
> -                __func__, length, len);
> +       int pdu_size = sizeof(struct smb2_sync_pdu);
> +       int hdr_size = sizeof(struct smb2_sync_hdr);
>
>         /*
>          * Add function to do table lookup of StructureSize by command
>          * ie Validate the wct via smb2_struct_sizes table above
>          */
> -
>         if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
>                 struct smb2_transform_hdr *thdr =
>                         (struct smb2_transform_hdr *)buf;
> @@ -136,8 +131,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 (len < pdu_size) {
> +               if ((len >= hdr_size)
>                     && (shdr->Status != 0)) {
>                         pdu->StructureSize2 = 0;
>                         /*
> @@ -190,13 +185,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
>                 }
>         }
>
> -       if (srvr->vals->header_preamble_size + len != length) {
> -               cifs_dbg(VFS, "Total length %u RFC1002 length %u mismatch mid %llu\n",
> -                        length, srvr->vals->header_preamble_size + len, mid);
> -               return 1;
> -       }
> -
> -       clc_len = smb2_calc_size(hdr);
> +       clc_len = smb2_calc_size(buf);
>
>         if (srvr->vals->header_preamble_size + len != clc_len) {
>                 cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n",
> @@ -263,15 +252,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;
>
> @@ -283,42 +271,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_sess_setup_rsp *)shdr)->SecurityBufferOffset);
>                 *len = le16_to_cpu(
> -                   ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferLength);
> +                 ((struct smb2_sess_setup_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:
> @@ -363,13 +353,12 @@ 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_pdu *)buf;
> +       struct smb2_sync_hdr *shdr = &pdu->sync_hdr;
>         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 = le16_to_cpu(shdr->StructureSize);
>
>         /*
>          * StructureSize2, ie length of fixed parameter area has already
> @@ -380,7 +369,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) {
> @@ -388,15 +377,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:
> @@ -579,7 +567,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;
> @@ -588,7 +576,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 !=
> @@ -679,8 +667,8 @@ 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_sync_hdr *)buffer;
> +       struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)sync_hdr;
>         struct cifs_tcon *tcon;
>         struct close_cancelled_open *cancelled;
>
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 04a70e78fefa..b1716165e0e4 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -123,7 +123,8 @@ 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  = (struct smb2_sync_hdr *)buf;
>
>         return le16_to_cpu(shdr->CreditRequest);
>  }
> @@ -190,7 +191,7 @@ 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);
> +       struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
>         __u64 wire_mid = le64_to_cpu(shdr->MessageId);
>
>         if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
> @@ -215,7 +216,7 @@ 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 = (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,
> @@ -1241,7 +1242,7 @@ 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 = (struct smb2_sync_hdr *)buf;
>
>         if (shdr->Status != STATUS_PENDING)
>                 return false;
> @@ -1259,7 +1260,7 @@ 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 = (struct smb2_sync_hdr *)buf;
>
>         if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED)
>                 return false;
> @@ -1451,6 +1452,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;
> @@ -1473,15 +1475,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) + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
> +           err_iov.iov_len + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
>                 kfree(utf16_path);
>                 return -ENOENT;
>         }
> @@ -1494,13 +1497,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) + server->vals->header_preamble_size <
> +       if (err_iov.iov_len + server->vals->header_preamble_size <
>                         SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
>                 kfree(utf16_path);
>                 return -ENOENT;
>         }
>
> -       if (get_rfc1002_length(err_buf) + server->vals->header_preamble_size <
> +       if (err_iov.iov_len + server->vals->header_preamble_size <
>                         SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
>                 kfree(utf16_path);
>                 return -ENOENT;
> @@ -2052,12 +2055,11 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
>  }
>
>  static void
> -fill_transform_hdr(struct TCP_Server_Info *server,
> -                  struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
> +fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
> +                  struct smb_rqst *old_rq)
>  {
>         struct smb2_sync_hdr *shdr =
>                         (struct smb2_sync_hdr *)old_rq->rq_iov[1].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));
>         tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
> @@ -2065,8 +2067,6 @@ fill_transform_hdr(struct TCP_Server_Info *server,
>         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) - server->vals->header_preamble_size);
> -       inc_rfc1001_len(tr_hdr, orig_len);
>  }
>
>  /* We can not use the normal sg_set_buf() as we will sometimes pass a
> @@ -2078,11 +2078,16 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
>         sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
>  }
>
> +/* Assumes:
> + * rqst->rq_iov[0]  is rfc1002 length
> + * rqst->rq_iov[1]  is tranform header
> + * rqst->rq_iov[2+] data to be encrypted/decrypted
> + */
>  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 sg_len = rqst->rq_nvec + rqst->rq_npages;
> +       unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
>         struct scatterlist *sg;
>         unsigned int i;
>         unsigned int j;
> @@ -2092,10 +2097,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign)
>                 return NULL;
>
>         sg_init_table(sg, sg_len);
> -       smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
> -       for (i = 1; i < rqst->rq_nvec; i++)
> -               smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
> -                                               rqst->rq_iov[i].iov_len);
> +       smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len);
> +       for (i = 1; i < rqst->rq_nvec - 1; i++)
> +               smb2_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;
> @@ -2127,9 +2132,10 @@ 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
> @@ -2224,6 +2230,10 @@ 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)
> @@ -2232,6 +2242,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
>         struct page **pages;
>         struct smb2_transform_hdr *tr_hdr;
>         unsigned int npages = old_rq->rq_npages;
> +       unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);

Could we calculate orig_len from sum of iovecs here (move this from
patch #5) to eliminate adding more get_rfc1002_length() calls?

>         int i;
>         int rc = -ENOMEM;
>
> @@ -2250,24 +2261,34 @@ 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 */
> +       iov[0].iov_base = old_rq->rq_iov[0].iov_base;
> +       iov[0].iov_len  = 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_transform_hdr(server, 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);
> +       /* fill the 2nd iov with a transform header */
> +       fill_transform_hdr(tr_hdr, orig_len, old_rq);
> +       new_rq->rq_iov[1].iov_base = tr_hdr;
> +       new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr);
> +
> +       /* Update rfc1002 header */
> +       inc_rfc1001_len(new_rq->rq_iov[0].iov_base,
> +                       sizeof(struct smb2_transform_hdr));
>
>         /* copy pages form the old */
>         for (i = 0; i < npages; i++) {
> @@ -2307,7 +2328,7 @@ smb3_free_transform_rq(struct smb_rqst *rqst)
>                 put_page(rqst->rq_pages[i]);
>         kfree(rqst->rq_pages);
>         /* free transform header */
> -       kfree(rqst->rq_iov[0].iov_base);
> +       kfree(rqst->rq_iov[1].iov_base);
>         kfree(rqst->rq_iov);
>  }
>
> @@ -2324,18 +2345,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;
> @@ -2347,10 +2369,9 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
>         if (rc)
>                 return rc;
>
> -       memmove(buf + server->vals->header_preamble_size, 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 + server->vals->header_preamble_size;
> +       memmove(buf + server->vals->header_preamble_size, iov[2].iov_base, buf_data_size);
> +
> +       server->total_read = buf_data_size + page_data_size;
>
>         return rc;
>  }
> @@ -2423,7 +2444,7 @@ 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 smb2_sync_hdr *)buf;
>         struct bio_vec *bvec = NULL;
>         struct iov_iter iter;
>         struct kvec iov;
> @@ -2550,7 +2571,7 @@ 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) + server->vals->header_preamble_size;
> +       unsigned int buflen = server->pdu_size + server->vals->header_preamble_size;
>         int rc;
>         int i = 0;
>
> @@ -2624,7 +2645,7 @@ 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->pdu_size;
>         unsigned int buf_size;
>         struct mid_q_entry *mid_entry;
>
> @@ -2668,7 +2689,7 @@ 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->pdu_size;
>         struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
>         unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
>
> @@ -2699,7 +2720,7 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
>  {
>         char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
>
> -       return handle_read_data(server, mid, buf, get_rfc1002_length(buf) +
> +       return handle_read_data(server, mid, buf, server->pdu_size +
>                                 server->vals->header_preamble_size,
>                                 NULL, 0, 0);
>  }
> @@ -3104,8 +3125,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 = 4,
> +       .header_size = sizeof(struct smb2_sync_hdr),
> +       .header_preamble_size = 0,
>         .max_header_size = MAX_SMB2_HDR_SIZE,
>         .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
>         .lock_cmd = SMB2_LOCK,
> @@ -3125,8 +3146,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 = 4,
> +       .header_size = sizeof(struct smb2_sync_hdr),
> +       .header_preamble_size = 0,
>         .max_header_size = MAX_SMB2_HDR_SIZE,
>         .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
>         .lock_cmd = SMB2_LOCK,
> @@ -3146,8 +3167,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 = 4,
> +       .header_size = sizeof(struct smb2_sync_hdr),
> +       .header_preamble_size = 0,
>         .max_header_size = MAX_SMB2_HDR_SIZE,
>         .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
>         .lock_cmd = SMB2_LOCK,
> @@ -3167,8 +3188,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 = 4,
> +       .header_size = sizeof(struct smb2_sync_hdr),
> +       .header_preamble_size = 0,
>         .max_header_size = MAX_SMB2_HDR_SIZE,
>         .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
>         .lock_cmd = SMB2_LOCK,
> @@ -3188,8 +3209,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 = 4,
> +       .header_size = sizeof(struct smb2_sync_hdr),
> +       .header_preamble_size = 0,
>         .max_header_size = MAX_SMB2_HDR_SIZE,
>         .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
>         .lock_cmd = SMB2_LOCK,
> @@ -3209,8 +3230,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 = 4,
> +       .header_size = sizeof(struct smb2_sync_hdr),
> +       .header_preamble_size = 0,
>         .max_header_size = MAX_SMB2_HDR_SIZE,
>         .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
>         .lock_cmd = SMB2_LOCK,
> @@ -3231,8 +3252,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 = 4,
> +       .header_size = sizeof(struct smb2_sync_hdr),
> +       .header_preamble_size = 0,
>         .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 1e765b31eb88..892d40233858 100644
> --- a/fs/cifs/smb2pdu.c
> +++ b/fs/cifs/smb2pdu.c
> @@ -591,7 +591,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
> @@ -942,7 +942,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);
>
> @@ -1018,13 +1018,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));
> @@ -1039,7 +1039,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:
> @@ -1097,7 +1097,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);
> @@ -1340,7 +1340,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) &&
> @@ -1360,7 +1360,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;
> @@ -1694,7 +1694,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;
> @@ -1834,9 +1834,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;
>         }
>
> @@ -1875,7 +1876,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;
> @@ -1996,7 +1996,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;
> @@ -2010,8 +2010,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;
> @@ -2091,13 +2090,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;
>
>
> @@ -2127,18 +2125,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;
>
> @@ -2216,9 +2213,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);
> @@ -2287,7 +2284,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);
> @@ -2684,7 +2681,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;
> @@ -2725,10 +2721,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;
> @@ -2755,7 +2749,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;
> @@ -3131,7 +3125,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;
>                 }
> @@ -3139,8 +3133,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;
> @@ -3154,10 +3148,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);
> @@ -3393,7 +3386,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;
> @@ -3509,9 +3502,9 @@ 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 *)(server->vals->header_preamble_size +
> -               le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
> -       rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
> -                         le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
> +               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);
> @@ -3567,20 +3560,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, server->vals->header_preamble_size + offset
> -                       + (char *)&rsp->hdr, min_t(unsigned int,
> +                       + (char *)rsp, min_t(unsigned int,
>                         rsp_len, max_len));
>         else if (level == FS_DEVICE_INFORMATION)
>                 memcpy(&tcon->fsDevInfo, server->vals->header_preamble_size + offset
> -                       + (char *)&rsp->hdr, sizeof(FILE_SYSTEM_DEVICE_INFO));
> +                       + (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 *)
> -                       (server->vals->header_preamble_size + offset + (char *)&rsp->hdr);
> +                       (server->vals->header_preamble_size + 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 8b901c69a65a..6bf243a45d64 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 */
> @@ -289,7 +274,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;
> @@ -329,7 +314,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;
> @@ -344,7 +329,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;
> @@ -440,7 +425,7 @@ struct smb2_tree_connect_req_extension {
>  } __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;
> @@ -491,7 +476,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;
> @@ -626,7 +611,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;
> @@ -882,7 +867,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;
> @@ -909,7 +894,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;
> @@ -932,7 +917,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;
> @@ -964,7 +949,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;
> @@ -995,7 +980,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;
> @@ -1029,7 +1014,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;
> @@ -1041,7 +1026,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;
> @@ -1067,7 +1052,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;
> @@ -1116,7 +1101,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;
> @@ -1138,12 +1123,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;
> @@ -1153,21 +1137,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 cbcce3f7e86f..30cdc0aa4e8e 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, char *in_data, u32 indatalen,
> diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
> index bf49cb73b9e6..8372a0cecdb0 100644
> --- a/fs/cifs/smb2transport.c
> +++ b/fs/cifs/smb2transport.c
> @@ -480,7 +480,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>         unsigned int rc;
>         char server_response_sig[16];
>         struct smb2_sync_hdr *shdr =
> -                       (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
> +                       (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
>
>         if ((shdr->Command == SMB2_NEGOTIATE) ||
>             (shdr->Command == SMB2_SESSION_SETUP) ||
> @@ -604,15 +604,13 @@ int
>  smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
>                    bool log_error)
>  {
> -       unsigned int len = get_rfc1002_length(mid->resp_buf);
> -       struct kvec iov[2];
> +       unsigned int len = server->total_read;
> +       struct kvec iov[1];
>         struct smb_rqst rqst = { .rq_iov = iov,
> -                                .rq_nvec = 2 };
> +                                .rq_nvec = 1 };
>
>         iov[0].iov_base = (char *)mid->resp_buf;
> -       iov[0].iov_len = 4;
> -       iov[1].iov_base = (char *)mid->resp_buf + 4;
> -       iov[1].iov_len = len;
> +       iov[0].iov_len = mid->resp_buf_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 279718dcb2ed..3abce580b056 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -790,8 +790,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) +
> +       resp_iov->iov_len = midQ->resp_buf_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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
Best regards,
Pavel Shilovsky
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3e3f86841372..0045d85ec76d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -665,6 +665,8 @@  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 */
+	/* Total size of this PDU. Only valid from cifs_demultiplex_thread */
+	unsigned int pdu_size;
 	unsigned int total_read; /* total amount of data read in this pass */
 #ifdef CONFIG_CIFS_FSCACHE
 	struct fscache_cookie   *fscache; /* client index cache cookie */
@@ -1373,6 +1375,7 @@  struct mid_q_entry {
 	mid_handle_t *handle; /* call handle mid callback */
 	void *callback_data;	  /* general purpose pointer for callback */
 	void *resp_buf;		/* pointer to received SMB header */
+	unsigned int resp_buf_size;
 	int mid_state;	/* wish this were enum but can not pass to wait_event */
 	unsigned int mid_flags;
 	__le16 command;		/* smb command code */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 59c09a596c0a..991e9d9ef90a 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1454,7 +1454,7 @@  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) +
+	unsigned int buflen = server->pdu_size +
 		server->vals->header_preamble_size;
 	bool use_rdma_mr = false;
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 1f2e3b15b2b1..0fad48d081d8 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -772,7 +772,7 @@  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->pdu_size;
 
 	/* make sure this will fit in a large buffer */
 	if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
@@ -874,13 +874,18 @@  cifs_demultiplex_thread(void *p)
 		length = cifs_read_from_socket(server, buf, pdu_length);
 		if (length < 0)
 			continue;
-		server->total_read = length;
+
+		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->pdu_size = pdu_length;
 
 		cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
 		if (!is_smb_response(server, buf[0]))
@@ -927,6 +932,7 @@  cifs_demultiplex_thread(void *p)
 
 		server->lstrp = jiffies;
 		if (mid_entry != NULL) {
+			mid_entry->resp_buf_size = server->pdu_size;
 			if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
 			     mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
 					server->ops->handle_cancelled_mid)
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 460084a8eac5..d5d7eb2ae3c4 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -145,7 +145,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/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..8fe30288805f 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -2450,7 +2450,7 @@  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 = (struct smb2_sync_hdr *)buf;
 	unsigned int i;
 	int rc = -EIO;
 	__le32 smb2err = shdr->Status;
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index dfa5d9f4e00b..c65a9dfcb988 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -94,25 +94,20 @@  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)
+smb2_check_message(char *buf, unsigned int len, 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_hdr *shdr = (struct smb2_sync_hdr *)buf;
+	struct smb2_sync_pdu *pdu = (struct smb2_sync_pdu *)shdr;
 	__u64 mid;
-	__u32 len = get_rfc1002_length(buf);
 	__u32 clc_len;  /* calculated length */
 	int command;
-
-	/* BB disable following printk later */
-	cifs_dbg(FYI, "%s length: 0x%x, smb_buf_length: 0x%x\n",
-		 __func__, length, len);
+	int pdu_size = sizeof(struct smb2_sync_pdu);
+	int hdr_size = sizeof(struct smb2_sync_hdr);
 
 	/*
 	 * Add function to do table lookup of StructureSize by command
 	 * ie Validate the wct via smb2_struct_sizes table above
 	 */
-
 	if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
 		struct smb2_transform_hdr *thdr =
 			(struct smb2_transform_hdr *)buf;
@@ -136,8 +131,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 (len < pdu_size) {
+		if ((len >= hdr_size)
 		    && (shdr->Status != 0)) {
 			pdu->StructureSize2 = 0;
 			/*
@@ -190,13 +185,7 @@  smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 		}
 	}
 
-	if (srvr->vals->header_preamble_size + len != length) {
-		cifs_dbg(VFS, "Total length %u RFC1002 length %u mismatch mid %llu\n",
-			 length, srvr->vals->header_preamble_size + len, mid);
-		return 1;
-	}
-
-	clc_len = smb2_calc_size(hdr);
+	clc_len = smb2_calc_size(buf);
 
 	if (srvr->vals->header_preamble_size + len != clc_len) {
 		cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n",
@@ -263,15 +252,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;
 
@@ -283,42 +271,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_sess_setup_rsp *)shdr)->SecurityBufferOffset);
 		*len = le16_to_cpu(
-		    ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferLength);
+		  ((struct smb2_sess_setup_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:
@@ -363,13 +353,12 @@  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_pdu *)buf;
+	struct smb2_sync_hdr *shdr = &pdu->sync_hdr;
 	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 = le16_to_cpu(shdr->StructureSize);
 
 	/*
 	 * StructureSize2, ie length of fixed parameter area has already
@@ -380,7 +369,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) {
@@ -388,15 +377,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:
@@ -579,7 +567,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;
@@ -588,7 +576,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 !=
@@ -679,8 +667,8 @@  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_sync_hdr *)buffer;
+	struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)sync_hdr;
 	struct cifs_tcon *tcon;
 	struct close_cancelled_open *cancelled;
 
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 04a70e78fefa..b1716165e0e4 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -123,7 +123,8 @@  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  = (struct smb2_sync_hdr *)buf;
 
 	return le16_to_cpu(shdr->CreditRequest);
 }
@@ -190,7 +191,7 @@  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);
+	struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
 	__u64 wire_mid = le64_to_cpu(shdr->MessageId);
 
 	if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
@@ -215,7 +216,7 @@  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 = (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,
@@ -1241,7 +1242,7 @@  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 = (struct smb2_sync_hdr *)buf;
 
 	if (shdr->Status != STATUS_PENDING)
 		return false;
@@ -1259,7 +1260,7 @@  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 = (struct smb2_sync_hdr *)buf;
 
 	if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED)
 		return false;
@@ -1451,6 +1452,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;
@@ -1473,15 +1475,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) + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
+	    err_iov.iov_len + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
 		kfree(utf16_path);
 		return -ENOENT;
 	}
@@ -1494,13 +1497,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) + server->vals->header_preamble_size <
+	if (err_iov.iov_len + server->vals->header_preamble_size <
 			SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
 		kfree(utf16_path);
 		return -ENOENT;
 	}
 
-	if (get_rfc1002_length(err_buf) + server->vals->header_preamble_size <
+	if (err_iov.iov_len + server->vals->header_preamble_size <
 			SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
 		kfree(utf16_path);
 		return -ENOENT;
@@ -2052,12 +2055,11 @@  smb2_dir_needs_close(struct cifsFileInfo *cfile)
 }
 
 static void
-fill_transform_hdr(struct TCP_Server_Info *server,
-		   struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
+fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
+		   struct smb_rqst *old_rq)
 {
 	struct smb2_sync_hdr *shdr =
 			(struct smb2_sync_hdr *)old_rq->rq_iov[1].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));
 	tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
@@ -2065,8 +2067,6 @@  fill_transform_hdr(struct TCP_Server_Info *server,
 	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) - server->vals->header_preamble_size);
-	inc_rfc1001_len(tr_hdr, orig_len);
 }
 
 /* We can not use the normal sg_set_buf() as we will sometimes pass a
@@ -2078,11 +2078,16 @@  static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
 	sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
 }
 
+/* Assumes:
+ * rqst->rq_iov[0]  is rfc1002 length
+ * rqst->rq_iov[1]  is tranform header
+ * rqst->rq_iov[2+] data to be encrypted/decrypted
+ */
 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 sg_len = rqst->rq_nvec + rqst->rq_npages;
+	unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
 	struct scatterlist *sg;
 	unsigned int i;
 	unsigned int j;
@@ -2092,10 +2097,10 @@  init_sg(struct smb_rqst *rqst, u8 *sign)
 		return NULL;
 
 	sg_init_table(sg, sg_len);
-	smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
-	for (i = 1; i < rqst->rq_nvec; i++)
-		smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
-						rqst->rq_iov[i].iov_len);
+	smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len);
+	for (i = 1; i < rqst->rq_nvec - 1; i++)
+		smb2_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;
@@ -2127,9 +2132,10 @@  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
@@ -2224,6 +2230,10 @@  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)
@@ -2232,6 +2242,7 @@  smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
 	struct page **pages;
 	struct smb2_transform_hdr *tr_hdr;
 	unsigned int npages = old_rq->rq_npages;
+	unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
 	int i;
 	int rc = -ENOMEM;
 
@@ -2250,24 +2261,34 @@  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 */
+	iov[0].iov_base = old_rq->rq_iov[0].iov_base;
+	iov[0].iov_len  = 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_transform_hdr(server, 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);
+	/* fill the 2nd iov with a transform header */
+	fill_transform_hdr(tr_hdr, orig_len, old_rq);
+	new_rq->rq_iov[1].iov_base = tr_hdr;
+	new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr);
+
+	/* Update rfc1002 header */
+	inc_rfc1001_len(new_rq->rq_iov[0].iov_base,
+			sizeof(struct smb2_transform_hdr));
 
 	/* copy pages form the old */
 	for (i = 0; i < npages; i++) {
@@ -2307,7 +2328,7 @@  smb3_free_transform_rq(struct smb_rqst *rqst)
 		put_page(rqst->rq_pages[i]);
 	kfree(rqst->rq_pages);
 	/* free transform header */
-	kfree(rqst->rq_iov[0].iov_base);
+	kfree(rqst->rq_iov[1].iov_base);
 	kfree(rqst->rq_iov);
 }
 
@@ -2324,18 +2345,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;
@@ -2347,10 +2369,9 @@  decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
 	if (rc)
 		return rc;
 
-	memmove(buf + server->vals->header_preamble_size, 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 + server->vals->header_preamble_size;
+	memmove(buf + server->vals->header_preamble_size, iov[2].iov_base, buf_data_size);
+
+	server->total_read = buf_data_size + page_data_size;
 
 	return rc;
 }
@@ -2423,7 +2444,7 @@  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 smb2_sync_hdr *)buf;
 	struct bio_vec *bvec = NULL;
 	struct iov_iter iter;
 	struct kvec iov;
@@ -2550,7 +2571,7 @@  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) + server->vals->header_preamble_size;
+	unsigned int buflen = server->pdu_size + server->vals->header_preamble_size;
 	int rc;
 	int i = 0;
 
@@ -2624,7 +2645,7 @@  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->pdu_size;
 	unsigned int buf_size;
 	struct mid_q_entry *mid_entry;
 
@@ -2668,7 +2689,7 @@  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->pdu_size;
 	struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
 	unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
 
@@ -2699,7 +2720,7 @@  smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
 	char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
 
-	return handle_read_data(server, mid, buf, get_rfc1002_length(buf) +
+	return handle_read_data(server, mid, buf, server->pdu_size +
 				server->vals->header_preamble_size,
 				NULL, 0, 0);
 }
@@ -3104,8 +3125,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 = 4,
+	.header_size = sizeof(struct smb2_sync_hdr),
+	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
 	.lock_cmd = SMB2_LOCK,
@@ -3125,8 +3146,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 = 4,
+	.header_size = sizeof(struct smb2_sync_hdr),
+	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
 	.lock_cmd = SMB2_LOCK,
@@ -3146,8 +3167,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 = 4,
+	.header_size = sizeof(struct smb2_sync_hdr),
+	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
 	.lock_cmd = SMB2_LOCK,
@@ -3167,8 +3188,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 = 4,
+	.header_size = sizeof(struct smb2_sync_hdr),
+	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
 	.lock_cmd = SMB2_LOCK,
@@ -3188,8 +3209,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 = 4,
+	.header_size = sizeof(struct smb2_sync_hdr),
+	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
 	.lock_cmd = SMB2_LOCK,
@@ -3209,8 +3230,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 = 4,
+	.header_size = sizeof(struct smb2_sync_hdr),
+	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
 	.lock_cmd = SMB2_LOCK,
@@ -3231,8 +3252,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 = 4,
+	.header_size = sizeof(struct smb2_sync_hdr),
+	.header_preamble_size = 0,
 	.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 1e765b31eb88..892d40233858 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -591,7 +591,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
@@ -942,7 +942,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);
 
@@ -1018,13 +1018,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));
@@ -1039,7 +1039,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:
@@ -1097,7 +1097,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);
@@ -1340,7 +1340,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) &&
@@ -1360,7 +1360,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;
@@ -1694,7 +1694,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;
@@ -1834,9 +1834,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;
 	}
 
@@ -1875,7 +1876,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;
@@ -1996,7 +1996,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;
@@ -2010,8 +2010,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;
@@ -2091,13 +2090,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;
 
 
@@ -2127,18 +2125,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;
 
@@ -2216,9 +2213,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);
@@ -2287,7 +2284,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);
@@ -2684,7 +2681,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;
@@ -2725,10 +2721,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;
@@ -2755,7 +2749,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;
@@ -3131,7 +3125,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;
 		}
@@ -3139,8 +3133,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;
@@ -3154,10 +3148,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);
@@ -3393,7 +3386,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;
@@ -3509,9 +3502,9 @@  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 *)(server->vals->header_preamble_size +
-		le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
-	rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
-			  le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+		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);
@@ -3567,20 +3560,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, server->vals->header_preamble_size + offset
-			+ (char *)&rsp->hdr, min_t(unsigned int,
+			+ (char *)rsp, min_t(unsigned int,
 			rsp_len, max_len));
 	else if (level == FS_DEVICE_INFORMATION)
 		memcpy(&tcon->fsDevInfo, server->vals->header_preamble_size + offset
-			+ (char *)&rsp->hdr, sizeof(FILE_SYSTEM_DEVICE_INFO));
+			+ (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 *)
-			(server->vals->header_preamble_size + offset + (char *)&rsp->hdr);
+			(server->vals->header_preamble_size + 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 8b901c69a65a..6bf243a45d64 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 */
@@ -289,7 +274,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;
@@ -329,7 +314,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;
@@ -344,7 +329,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;
@@ -440,7 +425,7 @@  struct smb2_tree_connect_req_extension {
 } __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;
@@ -491,7 +476,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;
@@ -626,7 +611,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;
@@ -882,7 +867,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;
@@ -909,7 +894,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;
@@ -932,7 +917,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;
@@ -964,7 +949,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;
@@ -995,7 +980,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;
@@ -1029,7 +1014,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;
@@ -1041,7 +1026,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;
@@ -1067,7 +1052,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;
@@ -1116,7 +1101,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;
@@ -1138,12 +1123,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;
@@ -1153,21 +1137,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 cbcce3f7e86f..30cdc0aa4e8e 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, char *in_data, u32 indatalen,
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index bf49cb73b9e6..8372a0cecdb0 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -480,7 +480,7 @@  smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 	unsigned int rc;
 	char server_response_sig[16];
 	struct smb2_sync_hdr *shdr =
-			(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
+			(struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
 
 	if ((shdr->Command == SMB2_NEGOTIATE) ||
 	    (shdr->Command == SMB2_SESSION_SETUP) ||
@@ -604,15 +604,13 @@  int
 smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 		   bool log_error)
 {
-	unsigned int len = get_rfc1002_length(mid->resp_buf);
-	struct kvec iov[2];
+	unsigned int len = server->total_read;
+	struct kvec iov[1];
 	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = 2 };
+				 .rq_nvec = 1 };
 
 	iov[0].iov_base = (char *)mid->resp_buf;
-	iov[0].iov_len = 4;
-	iov[1].iov_base = (char *)mid->resp_buf + 4;
-	iov[1].iov_len = len;
+	iov[0].iov_len = mid->resp_buf_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 279718dcb2ed..3abce580b056 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -790,8 +790,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) +
+	resp_iov->iov_len = midQ->resp_buf_size +
 		ses->server->vals->header_preamble_size;
+
 	if (midQ->large_buf)
 		*resp_buf_type = CIFS_LARGE_BUFFER;
 	else