diff options
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r-- | fs/cifs/smb2ops.c | 314 |
1 files changed, 208 insertions, 106 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 9c6d95ffca97..950d0ab2cc61 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -123,7 +123,7 @@ 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); + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf; return le16_to_cpu(shdr->CreditRequest); } @@ -190,7 +190,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) { @@ -212,15 +212,16 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf) } static void -smb2_dump_detail(void *buf) +smb2_dump_detail(void *buf, struct TCP_Server_Info *server) { #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, shdr->ProcessId); - cifs_dbg(VFS, "smb buf %p len %u\n", buf, smb2_calc_size(buf)); + cifs_dbg(VFS, "smb buf %p len %u\n", buf, + server->ops->calc_smb_size(buf, server)); #endif } @@ -322,6 +323,40 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) } #endif /* STATS2 */ +/* + * Open the directory at the root of a share + */ +int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) +{ + struct cifs_open_parms oparams; + int rc; + __le16 srch_path = 0; /* Null - since an open of top of share */ + u8 oplock = SMB2_OPLOCK_LEVEL_NONE; + + mutex_lock(&tcon->prfid_mutex); + if (tcon->valid_root_fid) { + cifs_dbg(FYI, "found a cached root file handle\n"); + memcpy(pfid, tcon->prfid, sizeof(struct cifs_fid)); + mutex_unlock(&tcon->prfid_mutex); + return 0; + } + + oparams.tcon = tcon; + oparams.create_options = 0; + oparams.desired_access = FILE_READ_ATTRIBUTES; + oparams.disposition = FILE_OPEN; + oparams.fid = pfid; + oparams.reconnect = false; + + rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL); + if (rc == 0) { + memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid)); + tcon->valid_root_fid = true; + } + mutex_unlock(&tcon->prfid_mutex); + return rc; +} + static void smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) { @@ -330,6 +365,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct cifs_open_parms oparms; struct cifs_fid fid; + bool no_cached_open = tcon->nohandlecache; oparms.tcon = tcon; oparms.desired_access = FILE_READ_ATTRIBUTES; @@ -338,7 +374,11 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) oparms.fid = &fid; oparms.reconnect = false; - rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL); + if (no_cached_open) + rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL); + else + rc = open_shroot(xid, tcon, &fid); + if (rc) return; @@ -352,7 +392,8 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) FS_DEVICE_INFORMATION); SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, FS_SECTOR_SIZE_INFORMATION); /* SMB3 specific */ - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + if (no_cached_open) + SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); return; } @@ -394,6 +435,9 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_open_parms oparms; struct cifs_fid fid; + if ((*full_path == 0) && tcon->valid_root_fid) + return 0; + utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); if (!utf16_path) return -ENOMEM; @@ -704,9 +748,11 @@ smb2_dump_share_caps(struct seq_file *m, struct cifs_tcon *tcon) seq_puts(m, " TRIM-support,"); seq_printf(m, "\tShare Flags: 0x%x", tcon->share_flags); + seq_printf(m, "\n\ttid: 0x%x", tcon->tid); if (tcon->perf_sector_size) seq_printf(m, "\tOptimal sector size: 0x%x", tcon->perf_sector_size); + seq_printf(m, "\tMaximal Access: 0x%x", tcon->maximal_access); } static void @@ -1257,7 +1303,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; @@ -1275,12 +1321,13 @@ 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) + if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED && + shdr->Status != STATUS_USER_SESSION_DELETED) return false; - cifs_dbg(FYI, "Session expired\n"); + cifs_dbg(FYI, "Session expired or deleted\n"); return true; } @@ -1474,8 +1521,6 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, unsigned int sub_offset; unsigned int print_len; unsigned int print_offset; - struct cifs_ses *ses = tcon->ses; - struct TCP_Server_Info *server = ses->server; cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); @@ -1499,7 +1544,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, err_buf = err_iov.iov_base; if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) || - err_iov.iov_len + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) { + err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) { kfree(utf16_path); return -ENOENT; } @@ -1512,14 +1557,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 (err_iov.iov_len + server->vals->header_preamble_size < - SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) { + if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) { kfree(utf16_path); return -ENOENT; } - if (err_iov.iov_len + server->vals->header_preamble_size < - SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) { + if (err_iov.iov_len < + SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) { kfree(utf16_path); return -ENOENT; } @@ -1593,8 +1637,11 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, oparms.create_options = 0; utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); - if (!utf16_path) - return ERR_PTR(-ENOMEM); + if (!utf16_path) { + rc = -ENOMEM; + free_xid(xid); + return ERR_PTR(rc); + } oparms.tcon = tcon; oparms.desired_access = READ_CONTROL; @@ -1652,8 +1699,11 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen, access_flags = WRITE_DAC; utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); - if (!utf16_path) - return -ENOMEM; + if (!utf16_path) { + rc = -ENOMEM; + free_xid(xid); + return rc; + } oparms.tcon = tcon; oparms.desired_access = access_flags; @@ -1713,15 +1763,21 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, /* if file not oplocked can't be sure whether asking to extend size */ if (!CIFS_CACHE_READ(cifsi)) - if (keep_size == false) - return -EOPNOTSUPP; + if (keep_size == false) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } /* * Must check if file sparse since fallocate -z (zero range) assumes * non-sparse allocation */ - if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) - return -EOPNOTSUPP; + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } /* * need to make sure we are not asked to extend the file since the SMB3 @@ -1730,8 +1786,11 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, * which for a non sparse file would zero the newly extended range */ if (keep_size == false) - if (i_size_read(inode) < offset + len) - return -EOPNOTSUPP; + if (i_size_read(inode) < offset + len) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } cifs_dbg(FYI, "offset %lld len %lld", offset, len); @@ -1764,8 +1823,11 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, /* Need to make file sparse, if not already, before freeing range. */ /* Consider adding equivalent for compressed since it could also work */ - if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) - return -EOPNOTSUPP; + if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } cifs_dbg(FYI, "offset %lld len %lld", offset, len); @@ -1796,8 +1858,10 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, /* if file not oplocked can't be sure whether asking to extend size */ if (!CIFS_CACHE_READ(cifsi)) - if (keep_size == false) - return -EOPNOTSUPP; + if (keep_size == false) { + free_xid(xid); + return rc; + } /* * Files are non-sparse by default so falloc may be a no-op @@ -1806,14 +1870,16 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, */ if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) { if (keep_size == true) - return 0; + rc = 0; /* check if extending file */ else if (i_size_read(inode) >= off + len) /* not extending file and already not sparse */ - return 0; + rc = 0; /* BB: in future add else clause to extend file */ else - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; } if ((keep_size == true) || (i_size_read(inode) >= off + len)) { @@ -1825,8 +1891,11 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, * ie potentially making a few extra pages at the beginning * or end of the file non-sparse via set_sparse is harmless. */ - if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) - return -EOPNOTSUPP; + if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } rc = smb2_set_sparse(xid, tcon, cfile, inode, false); } @@ -2035,7 +2104,7 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock) } static __u8 -smb2_parse_lease_buf(void *buf, unsigned int *epoch) +smb2_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key) { struct create_lease *lc = (struct create_lease *)buf; @@ -2046,13 +2115,16 @@ smb2_parse_lease_buf(void *buf, unsigned int *epoch) } static __u8 -smb3_parse_lease_buf(void *buf, unsigned int *epoch) +smb3_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key) { struct create_lease_v2 *lc = (struct create_lease_v2 *)buf; *epoch = le16_to_cpu(lc->lcontext.Epoch); if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) return SMB2_OPLOCK_LEVEL_NOCHANGE; + if (lease_key) + memcpy(lease_key, &lc->lcontext.LeaseKeyLow, + SMB2_LEASE_KEY_SIZE); return le32_to_cpu(lc->lcontext.LeaseState); } @@ -2070,12 +2142,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; @@ -2083,8 +2154,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 @@ -2096,11 +2165,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; @@ -2110,10 +2184,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; @@ -2145,9 +2219,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 @@ -2155,7 +2230,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) { struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; - unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20 - server->vals->header_preamble_size; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; int rc = 0; struct scatterlist *sg; u8 sign[SMB2_SIGNATURE_SIZE] = {}; @@ -2242,6 +2317,10 @@ free_req: 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) @@ -2250,6 +2329,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; @@ -2268,24 +2348,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++) { @@ -2325,7 +2415,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); } @@ -2342,18 +2432,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; @@ -2365,10 +2456,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, iov[2].iov_base, buf_data_size); + + server->total_read = buf_data_size + page_data_size; return rc; } @@ -2393,7 +2483,7 @@ read_data_into_pages(struct TCP_Server_Info *server, struct page **pages, zero_user(page, len, PAGE_SIZE - len); len = 0; } - length = cifs_read_page_from_socket(server, page, n); + length = cifs_read_page_from_socket(server, page, 0, n); if (length < 0) return length; server->total_read += length; @@ -2441,7 +2531,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; @@ -2472,7 +2562,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, return 0; } - data_offset = server->ops->read_data_offset(buf) + server->vals->header_preamble_size; + data_offset = server->ops->read_data_offset(buf); #ifdef CONFIG_CIFS_SMB_DIRECT use_rdma_mr = rdata->mr; #endif @@ -2568,12 +2658,11 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) unsigned int npages; struct page **pages; unsigned int len; - unsigned int buflen = server->pdu_size + server->vals->header_preamble_size; + unsigned int buflen = server->pdu_size; int rc; int i = 0; - len = min_t(unsigned int, buflen, server->vals->read_rsp_size - - server->vals->header_preamble_size + + len = min_t(unsigned int, buflen, server->vals->read_rsp_size + sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1; rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len); @@ -2581,8 +2670,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) return rc; server->total_read += rc; - len = le32_to_cpu(tr_hdr->OriginalMessageSize) + - server->vals->header_preamble_size - + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - server->vals->read_rsp_size; npages = DIV_ROUND_UP(len, PAGE_SIZE); @@ -2609,8 +2697,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) if (rc) goto free_pages; - rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size - - server->vals->header_preamble_size, + rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size, pages, npages, len); if (rc) goto free_pages; @@ -2647,7 +2734,7 @@ receive_encrypted_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid_entry; /* switch to large buffer if too big for a small one */ - if (pdu_length + server->vals->header_preamble_size > MAX_CIFS_SMALL_BUFFER_SIZE) { + if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { server->large_buf = true; memcpy(server->bigbuf, buf, server->total_read); buf = server->bigbuf; @@ -2655,13 +2742,12 @@ receive_encrypted_standard(struct TCP_Server_Info *server, /* now read the rest */ length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, - pdu_length - HEADER_SIZE(server) + 1 + - server->vals->header_preamble_size); + pdu_length - HEADER_SIZE(server) + 1); if (length < 0) return length; server->total_read += length; - buf_size = pdu_length + server->vals->header_preamble_size - sizeof(struct smb2_transform_hdr); + buf_size = pdu_length - sizeof(struct smb2_transform_hdr); length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0); if (length) return length; @@ -2690,7 +2776,7 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf; unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize); - if (pdu_length + server->vals->header_preamble_size < sizeof(struct smb2_transform_hdr) + + if (pdu_length < sizeof(struct smb2_transform_hdr) + sizeof(struct smb2_sync_hdr)) { cifs_dbg(VFS, "Transform message is too small (%u)\n", pdu_length); @@ -2699,14 +2785,14 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) return -ECONNABORTED; } - if (pdu_length + server->vals->header_preamble_size < orig_len + sizeof(struct smb2_transform_hdr)) { + if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) { cifs_dbg(VFS, "Transform message is broken\n"); cifs_reconnect(server); wake_up(&server->response_q); return -ECONNABORTED; } - if (pdu_length + server->vals->header_preamble_size > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) + if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) return receive_encrypted_read(server, mid); return receive_encrypted_standard(server, mid); @@ -2717,11 +2803,23 @@ 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, server->pdu_size + - server->vals->header_preamble_size, + return handle_read_data(server, mid, buf, server->pdu_size, NULL, 0, 0); } +static int +smb2_next_header(char *buf) +{ + struct smb2_sync_hdr *hdr = (struct smb2_sync_hdr *)buf; + struct smb2_transform_hdr *t_hdr = (struct smb2_transform_hdr *)buf; + + if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) + return sizeof(struct smb2_transform_hdr) + + le32_to_cpu(t_hdr->OriginalMessageSize); + + return le32_to_cpu(hdr->NextCommand); +} + struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -2813,6 +2911,7 @@ struct smb_version_operations smb20_operations = { .get_acl_by_fid = get_smb2_acl_by_fid, .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ + .next_header = smb2_next_header, }; struct smb_version_operations smb21_operations = { @@ -2907,6 +3006,7 @@ struct smb_version_operations smb21_operations = { .get_acl_by_fid = get_smb2_acl_by_fid, .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ + .next_header = smb2_next_header, }; struct smb_version_operations smb30_operations = { @@ -3011,6 +3111,7 @@ struct smb_version_operations smb30_operations = { .get_acl_by_fid = get_smb2_acl_by_fid, .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ + .next_header = smb2_next_header, }; #ifdef CONFIG_CIFS_SMB311 @@ -3111,6 +3212,7 @@ struct smb_version_operations smb311_operations = { .query_all_EAs = smb2_query_eas, .set_EA = smb2_set_ea, #endif /* CIFS_XATTR */ + .next_header = smb2_next_header, }; #endif /* CIFS_SMB311 */ @@ -3122,8 +3224,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, @@ -3143,8 +3245,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, @@ -3164,8 +3266,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, @@ -3185,8 +3287,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, @@ -3206,8 +3308,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, @@ -3227,8 +3329,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, @@ -3249,8 +3351,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, |