Commit 9ffc59d5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '4.18-rc1-more-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "Misc SMB3 fixes, including particularly important ones for signing,
  some minor documentation and debug improvements and another posix
  smb3.11 fix"

* tag '4.18-rc1-more-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Fix invalid check in __cifs_calc_signature()
  cifs: Use correct packet length in SMB2_TRANSFORM header
  smb3: fix corrupt path in subdirs on smb311 with posix
  smb3: do not display empty interface list
  smb3: Fix mode on mkdir on smb311 mounts
  cifs: Fix kernel oops when traceSMB is enabled
  CIFS: dump every session iface info
  CIFS: parse and store info on iface queries
  CIFS: add iface info to struct cifs_ses
  CIFS: complete PDU definitions for interface queries
  CIFS: move default port definitions to cifsglob.h
  cifs: Fix encryption/signing
  cifs: update __smb_send_rqst() to take an array of requests
  cifs: remove smb2_send_recv()
  cifs: push rfc1002 generation down the stack
  smb3: increase initial number of credits requested to allow write
  cifs: minor documentation updates
  cifs: add lease tracking to the cached root fid
  smb3: note that smb3.11 posix extensions mount option is experimental
parents a5696313 83ffdead
...@@ -42,9 +42,11 @@ Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) ...@@ -42,9 +42,11 @@ Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
Scott Lovenberg Scott Lovenberg
Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features) Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features)
Aurelien Aptel (for DFS SMB3 work and some key bug fixes) Aurelien Aptel (for DFS SMB3 work and some key bug fixes)
Ronnie Sahlberg (for SMB3 xattr work and bug fixes) Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding)
Shirish Pargaonkar (for many ACL patches over the years) Shirish Pargaonkar (for many ACL patches over the years)
Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security) Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security)
Paulo Alcantara
Long Li (some great work on RDMA, SMB Direct)
Test case and Bug Report contributors Test case and Bug Report contributors
...@@ -58,5 +60,4 @@ mention to the Stanford Checker (SWAT) which pointed out many minor ...@@ -58,5 +60,4 @@ mention to the Stanford Checker (SWAT) which pointed out many minor
bugs in error paths. Valuable suggestions also have come from Al Viro bugs in error paths. Valuable suggestions also have come from Al Viro
and Dave Miller. and Dave Miller.
And thanks to the IBM LTC and Power test teams and SuSE testers for And thanks to the IBM LTC and Power test teams and SuSE and Citrix and RedHat testers for finding multiple bugs during excellent stress test runs.
finding multiple bugs during excellent stress test runs.
See https://wiki.samba.org/index.php/LinuxCIFSKernel for
more current information.
Version 1.62 Version 1.62
------------ ------------
Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened
......
...@@ -9,14 +9,14 @@ is a partial list of the known problems and missing features: ...@@ -9,14 +9,14 @@ is a partial list of the known problems and missing features:
a) SMB3 (and SMB3.02) missing optional features: a) SMB3 (and SMB3.02) missing optional features:
- multichannel (started), integration with RDMA - multichannel (started), integration with RDMA
- directory leases (improved metadata caching) - directory leases (improved metadata caching), started (root dir only)
- T10 copy offload (copy chunk, and "Duplicate Extents" ioctl - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
currently the only two server side copy mechanisms supported) currently the only two server side copy mechanisms supported)
b) improved sparse file support b) improved sparse file support
c) Directory entry caching relies on a 1 second timer, rather than c) Directory entry caching relies on a 1 second timer, rather than
using Directory Leases using Directory Leases, currently only the root file handle is cached longer
d) quota support (needs minor kernel change since quota calls d) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems) to make it to network filesystems or deviceless filesystems)
...@@ -42,6 +42,8 @@ mount or a per server basis to client UIDs or nobody if no mapping ...@@ -42,6 +42,8 @@ mount or a per server basis to client UIDs or nobody if no mapping
exists. Also better integration with winbind for resolving SID owners exists. Also better integration with winbind for resolving SID owners
k) Add tools to take advantage of more smb3 specific ioctls and features k) Add tools to take advantage of more smb3 specific ioctls and features
(passthrough ioctl/fsctl for sending various SMB3 fsctls to the server
is in progress)
l) encrypted file support l) encrypted file support
...@@ -71,9 +73,8 @@ t) split cifs and smb3 support into separate modules so legacy (and less ...@@ -71,9 +73,8 @@ t) split cifs and smb3 support into separate modules so legacy (and less
secure) CIFS dialect can be disabled in environments that don't need it secure) CIFS dialect can be disabled in environments that don't need it
and simplify the code. and simplify the code.
u) Finish up SMB3.1.1 dialect support v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added
so far).
v) POSIX Extensions for SMB3.1.1
KNOWN BUGS KNOWN BUGS
==================================== ====================================
...@@ -92,8 +93,8 @@ Misc testing to do ...@@ -92,8 +93,8 @@ Misc testing to do
1) check out max path names and max path name components against various server 1) check out max path names and max path name components against various server
types. Try nested symlinks (8 deep). Return max path name in stat -f information types. Try nested symlinks (8 deep). Return max path name in stat -f information
2) Improve xfstest's cifs enablement and adapt xfstests where needed to test 2) Improve xfstest's cifs/smb3 enablement and adapt xfstests where needed to test
cifs better cifs/smb3 better
3) Additional performance testing and optimization using iozone and similar - 3) Additional performance testing and optimization using iozone and similar -
there are some easy changes that can be done to parallelize sequential writes, there are some easy changes that can be done to parallelize sequential writes,
......
...@@ -126,6 +126,25 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon) ...@@ -126,6 +126,25 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
seq_putc(m, '\n'); seq_putc(m, '\n');
} }
static void
cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface)
{
struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
seq_printf(m, "\t\tSpeed: %zu bps\n", iface->speed);
seq_puts(m, "\t\tCapabilities: ");
if (iface->rdma_capable)
seq_puts(m, "rdma ");
if (iface->rss_capable)
seq_puts(m, "rss ");
seq_putc(m, '\n');
if (iface->sockaddr.ss_family == AF_INET)
seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
else if (iface->sockaddr.ss_family == AF_INET6)
seq_printf(m, "\t\tIPv6: %pI6\n", &ipv6->sin6_addr);
}
static int cifs_debug_data_proc_show(struct seq_file *m, void *v) static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
{ {
struct list_head *tmp1, *tmp2, *tmp3; struct list_head *tmp1, *tmp2, *tmp3;
...@@ -312,6 +331,16 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -312,6 +331,16 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
mid_entry->mid); mid_entry->mid);
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
spin_lock(&ses->iface_lock);
if (ses->iface_count)
seq_printf(m, "\n\tServer interfaces: %zu\n",
ses->iface_count);
for (j = 0; j < ses->iface_count; j++) {
seq_printf(m, "\t%d)\n", j);
cifs_dump_iface(m, &ses->iface_list[j]);
}
spin_unlock(&ses->iface_lock);
} }
} }
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <crypto/aead.h> #include <crypto/aead.h>
int __cifs_calc_signature(struct smb_rqst *rqst, int __cifs_calc_signature(struct smb_rqst *rqst,
int start,
struct TCP_Server_Info *server, char *signature, struct TCP_Server_Info *server, char *signature,
struct shash_desc *shash) struct shash_desc *shash)
{ {
...@@ -45,16 +44,27 @@ int __cifs_calc_signature(struct smb_rqst *rqst, ...@@ -45,16 +44,27 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
int rc; int rc;
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec; int n_vec = rqst->rq_nvec;
int is_smb2 = server->vals->header_preamble_size == 0;
for (i = start; i < n_vec; i++) { /* iov[0] is actual data and not the rfc1002 length for SMB2+ */
if (is_smb2) {
if (iov[0].iov_len <= 4)
return -EIO;
i = 0;
} else {
if (n_vec < 2 || iov[0].iov_len != 4)
return -EIO;
i = 1; /* skip rfc1002 length */
}
for (; i < n_vec; i++) {
if (iov[i].iov_len == 0) if (iov[i].iov_len == 0)
continue; continue;
if (iov[i].iov_base == NULL) { if (iov[i].iov_base == NULL) {
cifs_dbg(VFS, "null iovec entry\n"); cifs_dbg(VFS, "null iovec entry\n");
return -EIO; return -EIO;
} }
if (i == 1 && iov[1].iov_len <= 4)
break; /* nothing to sign or corrupt header */
rc = crypto_shash_update(shash, rc = crypto_shash_update(shash,
iov[i].iov_base, iov[i].iov_len); iov[i].iov_base, iov[i].iov_len);
if (rc) { if (rc) {
...@@ -118,7 +128,7 @@ static int cifs_calc_signature(struct smb_rqst *rqst, ...@@ -118,7 +128,7 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
return rc; return rc;
} }
return __cifs_calc_signature(rqst, 1, server, signature, return __cifs_calc_signature(rqst, server, signature,
&server->secmech.sdescmd5->shash); &server->secmech.sdescmd5->shash);
} }
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
#define CIFS_PORT 445
#define RFC1001_PORT 139
/* /*
* The sizes of various internal tables and strings * The sizes of various internal tables and strings
*/ */
...@@ -312,6 +315,10 @@ struct smb_version_operations { ...@@ -312,6 +315,10 @@ struct smb_version_operations {
/* send echo request */ /* send echo request */
int (*echo)(struct TCP_Server_Info *); int (*echo)(struct TCP_Server_Info *);
/* create directory */ /* create directory */
int (*posix_mkdir)(const unsigned int xid, struct inode *inode,
umode_t mode, struct cifs_tcon *tcon,
const char *full_path,
struct cifs_sb_info *cifs_sb);
int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *, int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
struct cifs_sb_info *); struct cifs_sb_info *);
/* set info on created directory */ /* set info on created directory */
...@@ -838,6 +845,13 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net) ...@@ -838,6 +845,13 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
#endif #endif
struct cifs_server_iface {
size_t speed;
unsigned int rdma_capable : 1;
unsigned int rss_capable : 1;
struct sockaddr_storage sockaddr;
};
/* /*
* Session structure. One of these for each uid session with a particular host * Session structure. One of these for each uid session with a particular host
*/ */
...@@ -875,6 +889,20 @@ struct cifs_ses { ...@@ -875,6 +889,20 @@ struct cifs_ses {
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
#endif /* 3.1.1 */ #endif /* 3.1.1 */
/*
* Network interfaces available on the server this session is
* connected to.
*
* Other channels can be opened by connecting and binding this
* session to interfaces from this list.
*
* iface_lock should be taken when accessing any of these fields
*/
spinlock_t iface_lock;
struct cifs_server_iface *iface_list;
size_t iface_count;
unsigned long iface_last_update; /* jiffies */
}; };
static inline bool static inline bool
...@@ -883,6 +911,14 @@ cap_unix(struct cifs_ses *ses) ...@@ -883,6 +911,14 @@ cap_unix(struct cifs_ses *ses)
return ses->server->vals->cap_unix & ses->capabilities; return ses->server->vals->cap_unix & ses->capabilities;
} }
struct cached_fid {
bool is_valid:1; /* Do we have a useable root fid */
struct cifs_fid *fid;
struct mutex fid_mutex;
struct cifs_tcon *tcon;
struct work_struct lease_break;
};
/* /*
* there is one of these for each connection to a resource on a particular * there is one of these for each connection to a resource on a particular
* session * session
...@@ -987,9 +1023,7 @@ struct cifs_tcon { ...@@ -987,9 +1023,7 @@ struct cifs_tcon {
struct fscache_cookie *fscache; /* cookie for share */ struct fscache_cookie *fscache; /* cookie for share */
#endif #endif
struct list_head pending_opens; /* list of incomplete opens */ struct list_head pending_opens; /* list of incomplete opens */
bool valid_root_fid:1; /* Do we have a useable root fid */ struct cached_fid crfid; /* Cached root fid */
struct mutex prfid_mutex; /* prevents reopen race after dead ses*/
struct cifs_fid *prfid; /* handle to the directory at top of share */
/* BB add field for back pointer to sb struct(s)? */ /* BB add field for back pointer to sb struct(s)? */
}; };
......
...@@ -112,10 +112,6 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, ...@@ -112,10 +112,6 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
struct kvec *, int /* nvec to send */, struct kvec *, int /* nvec to send */,
int * /* type of buf returned */, const int flags, int * /* type of buf returned */, const int flags,
struct kvec * /* resp vec */); struct kvec * /* resp vec */);
extern int smb2_send_recv(const unsigned int xid, struct cifs_ses *pses,
struct kvec *pkvec, int nvec_to_send,
int *pbuftype, const int flags,
struct kvec *presp);
extern int SendReceiveBlockingLock(const unsigned int xid, extern int SendReceiveBlockingLock(const unsigned int xid,
struct cifs_tcon *ptcon, struct cifs_tcon *ptcon,
struct smb_hdr *in_buf , struct smb_hdr *in_buf ,
...@@ -544,7 +540,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -544,7 +540,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
const unsigned char *path, char *pbuf, const unsigned char *path, char *pbuf,
unsigned int *pbytes_written); unsigned int *pbytes_written);
int __cifs_calc_signature(struct smb_rqst *rqst, int start, int __cifs_calc_signature(struct smb_rqst *rqst,
struct TCP_Server_Info *server, char *signature, struct TCP_Server_Info *server, char *signature,
struct shash_desc *shash); struct shash_desc *shash);
enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
...@@ -552,6 +548,7 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, ...@@ -552,6 +548,7 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
struct cifs_aio_ctx *cifs_aio_ctx_alloc(void); struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
void cifs_aio_ctx_release(struct kref *refcount); void cifs_aio_ctx_release(struct kref *refcount);
int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw); int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
void smb2_cached_lease_break(struct work_struct *work);
int cifs_alloc_hash(const char *name, struct crypto_shash **shash, int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
struct sdesc **sdesc); struct sdesc **sdesc);
......
...@@ -107,10 +107,10 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon) ...@@ -107,10 +107,10 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
} }
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
mutex_lock(&tcon->prfid_mutex); mutex_lock(&tcon->crfid.fid_mutex);
tcon->valid_root_fid = false; tcon->crfid.is_valid = false;
memset(tcon->prfid, 0, sizeof(struct cifs_fid)); memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
mutex_unlock(&tcon->prfid_mutex); mutex_unlock(&tcon->crfid.fid_mutex);
/* /*
* BB Add call to invalidate_inodes(sb) for all superblocks mounted * BB Add call to invalidate_inodes(sb) for all superblocks mounted
......
...@@ -57,9 +57,6 @@ ...@@ -57,9 +57,6 @@
#include "smb2proto.h" #include "smb2proto.h"
#include "smbdirect.h" #include "smbdirect.h"
#define CIFS_PORT 445
#define RFC1001_PORT 139
extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_req_poolp;
extern bool disable_legacy_dialects; extern bool disable_legacy_dialects;
...@@ -3029,8 +3026,11 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -3029,8 +3026,11 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
if ((volume_info->linux_ext) && (ses->server->posix_ext_supported)) { if ((volume_info->linux_ext) && (ses->server->posix_ext_supported)) {
if (ses->server->vals->protocol_id == SMB311_PROT_ID) if (ses->server->vals->protocol_id == SMB311_PROT_ID) {
tcon->posix_extensions = true; tcon->posix_extensions = true;
printk_once(KERN_WARNING
"SMB3.11 POSIX Extensions are experimental\n");
}
} }
#endif /* 311 */ #endif /* 311 */
......
...@@ -1575,6 +1575,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) ...@@ -1575,6 +1575,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out; goto mkdir_out;
} }
server = tcon->ses->server;
#ifdef CONFIG_CIFS_SMB311
if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) {
rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path,
cifs_sb);
d_drop(direntry); /* for time being always refresh inode info */
goto mkdir_out;
}
#endif /* SMB311 */
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) { le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb, rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
...@@ -1583,8 +1594,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) ...@@ -1583,8 +1594,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out; goto mkdir_out;
} }
server = tcon->ses->server;
if (!server->ops->mkdir) { if (!server->ops->mkdir) {
rc = -ENOSYS; rc = -ENOSYS;
goto mkdir_out; goto mkdir_out;
......
...@@ -82,6 +82,7 @@ sesInfoAlloc(void) ...@@ -82,6 +82,7 @@ sesInfoAlloc(void)
INIT_LIST_HEAD(&ret_buf->smb_ses_list); INIT_LIST_HEAD(&ret_buf->smb_ses_list);
INIT_LIST_HEAD(&ret_buf->tcon_list); INIT_LIST_HEAD(&ret_buf->tcon_list);
mutex_init(&ret_buf->session_mutex); mutex_init(&ret_buf->session_mutex);
spin_lock_init(&ret_buf->iface_lock);
} }
return ret_buf; return ret_buf;
} }
...@@ -102,6 +103,7 @@ sesInfoFree(struct cifs_ses *buf_to_free) ...@@ -102,6 +103,7 @@ sesInfoFree(struct cifs_ses *buf_to_free)
kfree(buf_to_free->user_name); kfree(buf_to_free->user_name);
kfree(buf_to_free->domainName); kfree(buf_to_free->domainName);
kzfree(buf_to_free->auth_key.response); kzfree(buf_to_free->auth_key.response);
kfree(buf_to_free->iface_list);
kzfree(buf_to_free); kzfree(buf_to_free);
} }
...@@ -117,8 +119,9 @@ tconInfoAlloc(void) ...@@ -117,8 +119,9 @@ tconInfoAlloc(void)
INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->openFileList);
INIT_LIST_HEAD(&ret_buf->tcon_list); INIT_LIST_HEAD(&ret_buf->tcon_list);
spin_lock_init(&ret_buf->open_file_lock); spin_lock_init(&ret_buf->open_file_lock);
mutex_init(&ret_buf->prfid_mutex); mutex_init(&ret_buf->crfid.fid_mutex);
ret_buf->prfid = kzalloc(sizeof(struct cifs_fid), GFP_KERNEL); ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
GFP_KERNEL);
#ifdef CONFIG_CIFS_STATS #ifdef CONFIG_CIFS_STATS
spin_lock_init(&ret_buf->stat_lock); spin_lock_init(&ret_buf->stat_lock);
#endif #endif
...@@ -136,7 +139,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free) ...@@ -136,7 +139,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
atomic_dec(&tconInfoAllocCount); atomic_dec(&tconInfoAllocCount);
kfree(buf_to_free->nativeFileSystem); kfree(buf_to_free->nativeFileSystem);
kzfree(buf_to_free->password); kzfree(buf_to_free->password);
kfree(buf_to_free->prfid); kfree(buf_to_free->crfid.fid);
kfree(buf_to_free); kfree(buf_to_free);
} }
......
...@@ -454,7 +454,8 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb) ...@@ -454,7 +454,8 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
/* SMB311 POSIX extensions paths do not include leading slash */ /* SMB311 POSIX extensions paths do not include leading slash */
else if (cifs_sb_master_tlink(cifs_sb) && else if (cifs_sb_master_tlink(cifs_sb) &&
cifs_sb_master_tcon(cifs_sb)->posix_extensions) { cifs_sb_master_tcon(cifs_sb)->posix_extensions &&
(from[0] == '/')) {
start_of_path = from + 1; start_of_path = from + 1;
} }
#endif /* 311 */ #endif /* 311 */
...@@ -492,10 +493,11 @@ cifs_ses_oplock_break(struct work_struct *work) ...@@ -492,10 +493,11 @@ cifs_ses_oplock_break(struct work_struct *work)
{ {
struct smb2_lease_break_work *lw = container_of(work, struct smb2_lease_break_work *lw = container_of(work,
struct smb2_lease_break_work, lease_break); struct smb2_lease_break_work, lease_break);
int rc; int rc = 0;
rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key, rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
lw->lease_state); lw->lease_state);
cifs_dbg(FYI, "Lease release rc %d\n", rc); cifs_dbg(FYI, "Lease release rc %d\n", rc);
cifs_put_tlink(lw->tlink); cifs_put_tlink(lw->tlink);
kfree(lw); kfree(lw);
...@@ -561,6 +563,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, ...@@ -561,6 +563,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
open->oplock = lease_state; open->oplock = lease_state;
} }
return found; return found;
} }
...@@ -603,6 +606,18 @@ smb2_is_valid_lease_break(char *buffer) ...@@ -603,6 +606,18 @@ smb2_is_valid_lease_break(char *buffer)
return true; return true;
} }
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
if (tcon->crfid.is_valid &&
!memcmp(rsp->LeaseKey,
tcon->crfid.fid->lease_key,
SMB2_LEASE_KEY_SIZE)) {
INIT_WORK(&tcon->crfid.lease_break,
smb2_cached_lease_break);
queue_work(cifsiod_wq,
&tcon->crfid.lease_break);
spin_unlock(&cifs_tcp_ses_lock);
return true;
}
} }
} }
} }
......
...@@ -294,34 +294,191 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) ...@@ -294,34 +294,191 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
return rsize; return rsize;
} }
#ifdef CONFIG_CIFS_STATS2
static int
parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
size_t buf_len,
struct cifs_server_iface **iface_list,
size_t *iface_count)
{
struct network_interface_info_ioctl_rsp *p;
struct sockaddr_in *addr4;
struct sockaddr_in6 *addr6;
struct iface_info_ipv4 *p4;
struct iface_info_ipv6 *p6;
struct cifs_server_iface *info;
ssize_t bytes_left;
size_t next = 0;
int nb_iface = 0;
int rc = 0;
*iface_list = NULL;
*iface_count = 0;
/*
* Fist pass: count and sanity check
*/
bytes_left = buf_len;
p = buf;
while (bytes_left >= sizeof(*p)) {
nb_iface++;
next = le32_to_cpu(p->Next);
if (!next) {
bytes_left -= sizeof(*p);
break;
}
p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
bytes_left -= next;
}
if (!nb_iface) {
cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
rc = -EINVAL;
goto out;
}
if (bytes_left || p->Next)
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
/*
* Second pass: extract info to internal structure
*/
*iface_list = kcalloc(nb_iface, sizeof(**iface_list), GFP_KERNEL);
if (!*iface_list) {
rc = -ENOMEM;
goto out;
}
info = *iface_list;
bytes_left = buf_len;
p = buf;
while (bytes_left >= sizeof(*p)) {
info->speed = le64_to_cpu(p->LinkSpeed);
info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE);
info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE);
cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, *iface_count);
cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
le32_to_cpu(p->Capability));
switch (p->Family) {
/*
* The kernel and wire socket structures have the same
* layout and use network byte order but make the
* conversion explicit in case either one changes.
*/
case INTERNETWORK:
addr4 = (struct sockaddr_in *)&info->sockaddr;
p4 = (struct iface_info_ipv4 *)p->Buffer;
addr4->sin_family = AF_INET;
memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
/* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
addr4->sin_port = cpu_to_be16(CIFS_PORT);
cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
&addr4->sin_addr);
break;
case INTERNETWORKV6:
addr6 = (struct sockaddr_in6 *)&info->sockaddr;
p6 = (struct iface_info_ipv6 *)p->Buffer;
addr6->sin6_family = AF_INET6;
memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);
/* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0;
addr6->sin6_port = cpu_to_be16(CIFS_PORT);
cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
&addr6->sin6_addr);
break;
default:
cifs_dbg(VFS,
"%s: skipping unsupported socket family\n",
__func__);
goto next_iface;
}
(*iface_count)++;
info++;
next_iface:
next = le32_to_cpu(p->Next);
if (!next)
break;
p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
bytes_left -= next;
}
if (!*iface_count) {
rc = -EINVAL;
goto out;
}
out:
if (rc) {
kfree(*iface_list);
*iface_count = 0;
*iface_list = NULL;
}
return rc;
}
static int static int
SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
{ {
int rc; int rc;
unsigned int ret_data_len = 0; unsigned int ret_data_len = 0;
struct network_interface_info_ioctl_rsp *out_buf; struct network_interface_info_ioctl_rsp *out_buf = NULL;
struct cifs_server_iface *iface_list;
size_t iface_count;
struct cifs_ses *ses = tcon->ses;
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */, FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
NULL /* no data input */, 0 /* no data input */, NULL /* no data input */, 0 /* no data input */,
(char **)&out_buf, &ret_data_len); (char **)&out_buf, &ret_data_len);
if (rc != 0) if (rc != 0) {
cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc); cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
else if (ret_data_len < sizeof(struct network_interface_info_ioctl_rsp)) { goto out;
cifs_dbg(VFS, "server returned bad net interface info buf\n");
rc = -EINVAL;
} else {
/* Dump info on first interface */
cifs_dbg(FYI, "Adapter Capability 0x%x\t",
le32_to_cpu(out_buf->Capability));
cifs_dbg(FYI, "Link Speed %lld\n",
le64_to_cpu(out_buf->LinkSpeed));
} }
rc = parse_server_interfaces(out_buf, ret_data_len,
&iface_list, &iface_count);
if (rc)
goto out;
spin_lock(&ses->iface_lock);
kfree(ses->iface_list);
ses->iface_list = iface_list;
ses->iface_count = iface_count;
ses->iface_last_update = jiffies;
spin_unlock(&ses->iface_lock);
out:
kfree(out_buf); kfree(out_buf);
return rc; return rc;
} }
#endif /* STATS2 */
void
smb2_cached_lease_break(struct work_struct *work)
{
struct cached_fid *cfid = container_of(work,
struct cached_fid, lease_break);
mutex_lock(&cfid->fid_mutex);
if (cfid->is_valid) {
cifs_dbg(FYI, "clear cached root file handle\n");
SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid,
cfid->fid->volatile_fid);
cfid->is_valid = false;
}
mutex_unlock(&cfid->fid_mutex);
}
/* /*
* Open the directory at the root of a share * Open the directory at the root of a share
...@@ -331,13 +488,13 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) ...@@ -331,13 +488,13 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
struct cifs_open_parms oparams; struct cifs_open_parms oparams;
int rc; int rc;
__le16 srch_path = 0; /* Null - since an open of top of share */ __le16 srch_path = 0; /* Null - since an open of top of share */
u8 oplock = SMB2_OPLOCK_LEVEL_NONE; u8 oplock = SMB2_OPLOCK_LEVEL_II;
mutex_lock(&tcon->prfid_mutex); mutex_lock(&tcon->crfid.fid_mutex);
if (tcon->valid_root_fid) { if (tcon->crfid.is_valid) {
cifs_dbg(FYI, "found a cached root file handle\n"); cifs_dbg(FYI, "found a cached root file handle\n");
memcpy(pfid, tcon->prfid, sizeof(struct cifs_fid)); memcpy(pfid, tcon->crfid.fid, sizeof(struct cifs_fid));
mutex_unlock(&tcon->prfid_mutex); mutex_unlock(&tcon->crfid.fid_mutex);
return 0; return 0;
} }
...@@ -350,10 +507,11 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) ...@@ -350,10 +507,11 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL, NULL); rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL, NULL);
if (rc == 0) { if (rc == 0) {
memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid)); memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid));
tcon->valid_root_fid = true; tcon->crfid.tcon = tcon;
tcon->crfid.is_valid = true;
} }
mutex_unlock(&tcon->prfid_mutex); mutex_unlock(&tcon->crfid.fid_mutex);
return rc; return rc;
} }
...@@ -383,9 +541,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -383,9 +541,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
if (rc) if (rc)
return; return;
#ifdef CONFIG_CIFS_STATS2
SMB3_request_interfaces(xid, tcon); SMB3_request_interfaces(xid, tcon);
#endif /* STATS2 */
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
FS_ATTRIBUTE_INFORMATION); FS_ATTRIBUTE_INFORMATION);
...@@ -436,7 +592,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -436,7 +592,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_open_parms oparms; struct cifs_open_parms oparms;
struct cifs_fid fid; struct cifs_fid fid;
if ((*full_path == 0) && tcon->valid_root_fid) if ((*full_path == 0) && tcon->crfid.is_valid)
return 0; return 0;
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
...@@ -2151,7 +2307,7 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len, ...@@ -2151,7 +2307,7 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
struct smb_rqst *old_rq) struct smb_rqst *old_rq)
{ {
struct smb2_sync_hdr *shdr = struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base; (struct smb2_sync_hdr *)old_rq->rq_iov[0].iov_base;
memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
...@@ -2171,14 +2327,13 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, ...@@ -2171,14 +2327,13 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
} }
/* Assumes: /* Assumes:
* rqst->rq_iov[0] is rfc1002 length * rqst->rq_iov[0] is transform header
* rqst->rq_iov[1] is tranform header * rqst->rq_iov[1+] data to be encrypted/decrypted
* rqst->rq_iov[2+] data to be encrypted/decrypted
*/ */
static struct scatterlist * static struct scatterlist *
init_sg(struct smb_rqst *rqst, u8 *sign) init_sg(struct smb_rqst *rqst, u8 *sign)
{ {
unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages; unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
struct scatterlist *sg; struct scatterlist *sg;
unsigned int i; unsigned int i;
...@@ -2189,10 +2344,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign) ...@@ -2189,10 +2344,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign)
return NULL; return NULL;
sg_init_table(sg, sg_len); sg_init_table(sg, sg_len);
smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len); smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 20, assoc_data_len);
for (i = 1; i < rqst->rq_nvec - 1; i++) for (i = 1; i < rqst->rq_nvec; i++)
smb2_sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base, smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
rqst->rq_iov[i+1].iov_len); rqst->rq_iov[i].iov_len);
for (j = 0; i < sg_len - 1; i++, j++) { for (j = 0; i < sg_len - 1; i++, j++) {
unsigned int len, offset; unsigned int len, offset;
...@@ -2224,18 +2379,17 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) ...@@ -2224,18 +2379,17 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
return 1; return 1;
} }
/* /*
* Encrypt or decrypt @rqst message. @rqst has the following format: * Encrypt or decrypt @rqst message. @rqst[0] has the following format:
* iov[0] - rfc1002 length * iov[0] - transform header (associate data),
* iov[1] - transform header (associate data), * iov[1-N] - SMB2 header and pages - data to encrypt.
* iov[2-N] and pages - data to encrypt. * On success return encrypted data in iov[1-N] and pages, leave iov[0]
* On success return encrypted data in iov[2-N] and pages, leave iov[0-1]
* untouched. * untouched.
*/ */
static int static int
crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
{ {
struct smb2_transform_hdr *tr_hdr = struct smb2_transform_hdr *tr_hdr =
(struct smb2_transform_hdr *)rqst->rq_iov[1].iov_base; (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
int rc = 0; int rc = 0;
struct scatterlist *sg; struct scatterlist *sg;
...@@ -2323,10 +2477,6 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) ...@@ -2323,10 +2477,6 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
return rc; 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 static int
smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
struct smb_rqst *old_rq) struct smb_rqst *old_rq)
...@@ -2335,7 +2485,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, ...@@ -2335,7 +2485,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
struct page **pages; struct page **pages;
struct smb2_transform_hdr *tr_hdr; struct smb2_transform_hdr *tr_hdr;
unsigned int npages = old_rq->rq_npages; unsigned int npages = old_rq->rq_npages;
unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base); unsigned int orig_len;
int i; int i;
int rc = -ENOMEM; int rc = -ENOMEM;
...@@ -2355,18 +2505,14 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, ...@@ -2355,18 +2505,14 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
goto err_free_pages; goto err_free_pages;
} }
/* Make space for one extra iov to hold the transform header */
iov = kmalloc_array(old_rq->rq_nvec + 1, sizeof(struct kvec), iov = kmalloc_array(old_rq->rq_nvec + 1, sizeof(struct kvec),
GFP_KERNEL); GFP_KERNEL);
if (!iov) if (!iov)
goto err_free_pages; goto err_free_pages;
/* copy all iovs from the old except the 1st one (rfc1002 length) */ /* copy all iovs from the old */
memcpy(&iov[2], &old_rq->rq_iov[1], memcpy(&iov[1], &old_rq->rq_iov[0],
sizeof(struct kvec) * (old_rq->rq_nvec - 1)); sizeof(struct kvec) * old_rq->rq_nvec);
/* 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_iov = iov;
new_rq->rq_nvec = old_rq->rq_nvec + 1; new_rq->rq_nvec = old_rq->rq_nvec + 1;
...@@ -2375,14 +2521,12 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, ...@@ -2375,14 +2521,12 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
if (!tr_hdr) if (!tr_hdr)
goto err_free_iov; goto err_free_iov;
orig_len = smb2_rqst_len(old_rq, false);
/* fill the 2nd iov with a transform header */ /* fill the 2nd iov with a transform header */
fill_transform_hdr(tr_hdr, orig_len, old_rq); fill_transform_hdr(tr_hdr, orig_len, old_rq);
new_rq->rq_iov[1].iov_base = tr_hdr; new_rq->rq_iov[0].iov_base = tr_hdr;
new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr); new_rq->rq_iov[0].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 */ /* copy pages form the old */
for (i = 0; i < npages; i++) { for (i = 0; i < npages; i++) {
...@@ -2426,7 +2570,7 @@ smb3_free_transform_rq(struct smb_rqst *rqst) ...@@ -2426,7 +2570,7 @@ smb3_free_transform_rq(struct smb_rqst *rqst)
put_page(rqst->rq_pages[i]); put_page(rqst->rq_pages[i]);
kfree(rqst->rq_pages); kfree(rqst->rq_pages);
/* free transform header */ /* free transform header */
kfree(rqst->rq_iov[1].iov_base); kfree(rqst->rq_iov[0].iov_base);
kfree(rqst->rq_iov); kfree(rqst->rq_iov);
} }
...@@ -2443,19 +2587,17 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, ...@@ -2443,19 +2587,17 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
unsigned int buf_data_size, struct page **pages, unsigned int buf_data_size, struct page **pages,
unsigned int npages, unsigned int page_data_size) unsigned int npages, unsigned int page_data_size)
{ {
struct kvec iov[3]; struct kvec iov[2];
struct smb_rqst rqst = {NULL}; struct smb_rqst rqst = {NULL};
int rc; int rc;
iov[0].iov_base = NULL; iov[0].iov_base = buf;
iov[0].iov_len = 0; iov[0].iov_len = sizeof(struct smb2_transform_hdr);
iov[1].iov_base = buf; iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
iov[1].iov_len = sizeof(struct smb2_transform_hdr); iov[1].iov_len = buf_data_size;
iov[2].iov_base = buf + sizeof(struct smb2_transform_hdr);
iov[2].iov_len = buf_data_size;
rqst.rq_iov = iov; rqst.rq_iov = iov;
rqst.rq_nvec = 3; rqst.rq_nvec = 2;
rqst.rq_pages = pages; rqst.rq_pages = pages;
rqst.rq_npages = npages; rqst.rq_npages = npages;
rqst.rq_pagesz = PAGE_SIZE; rqst.rq_pagesz = PAGE_SIZE;
...@@ -2467,7 +2609,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, ...@@ -2467,7 +2609,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
if (rc) if (rc)
return rc; return rc;
memmove(buf, iov[2].iov_base, buf_data_size); memmove(buf, iov[1].iov_base, buf_data_size);
server->total_read = buf_data_size + page_data_size; server->total_read = buf_data_size + page_data_size;
...@@ -3170,6 +3312,7 @@ struct smb_version_operations smb311_operations = { ...@@ -3170,6 +3312,7 @@ struct smb_version_operations smb311_operations = {
.set_compression = smb2_set_compression, .set_compression = smb2_set_compression,
.mkdir = smb2_mkdir, .mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo, .mkdir_setinfo = smb2_mkdir_setinfo,
.posix_mkdir = smb311_posix_mkdir,
.rmdir = smb2_rmdir, .rmdir = smb2_rmdir,
.unlink = smb2_unlink, .unlink = smb2_unlink,
.rename = smb2_rename_path, .rename = smb2_rename_path,
......
...@@ -602,6 +602,7 @@ static void assemble_neg_contexts(struct smb2_negotiate_req *req, ...@@ -602,6 +602,7 @@ static void assemble_neg_contexts(struct smb2_negotiate_req *req,
int int
SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
{ {
struct smb_rqst rqst;
struct smb2_negotiate_req *req; struct smb2_negotiate_req *req;
struct smb2_negotiate_rsp *rsp; struct smb2_negotiate_rsp *rsp;
struct kvec iov[1]; struct kvec iov[1];
...@@ -673,7 +674,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -673,7 +674,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len; iov[0].iov_len = total_len;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base; rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base;
/* /*
...@@ -990,8 +995,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data) ...@@ -990,8 +995,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
req->PreviousSessionId = sess_data->previous_session; req->PreviousSessionId = sess_data->previous_session;
req->Flags = 0; /* MBZ */ req->Flags = 0; /* MBZ */
/* to enable echos and oplocks */
req->sync_hdr.CreditRequest = cpu_to_le16(3); /* enough to enable echos and oplocks and one max size write */
req->sync_hdr.CreditRequest = cpu_to_le16(130);
/* only one of SMB2 signing flags may be set in SMB2 request */ /* only one of SMB2 signing flags may be set in SMB2 request */
if (server->sign) if (server->sign)
...@@ -1027,6 +1033,7 @@ static int ...@@ -1027,6 +1033,7 @@ static int
SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data) SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
{ {
int rc; int rc;
struct smb_rqst rqst;
struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base; struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base;
struct kvec rsp_iov = { NULL, 0 }; struct kvec rsp_iov = { NULL, 0 };
...@@ -1035,10 +1042,13 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data) ...@@ -1035,10 +1042,13 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
cpu_to_le16(sizeof(struct smb2_sess_setup_req) - 1 /* pad */); cpu_to_le16(sizeof(struct smb2_sess_setup_req) - 1 /* pad */);
req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len); req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len);
/* BB add code to build os and lm fields */ memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = sess_data->iov;
rqst.rq_nvec = 2;
rc = smb2_send_recv(sess_data->xid, sess_data->ses, /* BB add code to build os and lm fields */
sess_data->iov, 2, rc = cifs_send_recv(sess_data->xid, sess_data->ses,
&rqst,
&sess_data->buf0_type, &sess_data->buf0_type,
CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov); CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov);
cifs_small_buf_release(sess_data->iov[0].iov_base); cifs_small_buf_release(sess_data->iov[0].iov_base);
...@@ -1376,6 +1386,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -1376,6 +1386,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
int int
SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
{ {
struct smb_rqst rqst;
struct smb2_logoff_req *req; /* response is also trivial struct */ struct smb2_logoff_req *req; /* response is also trivial struct */
int rc = 0; int rc = 0;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
...@@ -1413,7 +1424,11 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) ...@@ -1413,7 +1424,11 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len; iov[0].iov_len = total_len;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
/* /*
* No tcon so can't do * No tcon so can't do
...@@ -1443,6 +1458,7 @@ int ...@@ -1443,6 +1458,7 @@ int
SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
struct cifs_tcon *tcon, const struct nls_table *cp) struct cifs_tcon *tcon, const struct nls_table *cp)
{ {
struct smb_rqst rqst;
struct smb2_tree_connect_req *req; struct smb2_tree_connect_req *req;
struct smb2_tree_connect_rsp *rsp = NULL; struct smb2_tree_connect_rsp *rsp = NULL;
struct kvec iov[2]; struct kvec iov[2];
...@@ -1499,7 +1515,11 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1499,7 +1515,11 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
!smb3_encryption_required(tcon)) !smb3_encryption_required(tcon))
req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 2;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base; rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
...@@ -1563,6 +1583,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1563,6 +1583,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
int int
SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
{ {
struct smb_rqst rqst;
struct smb2_tree_disconnect_req *req; /* response is trivial */ struct smb2_tree_disconnect_req *req; /* response is trivial */
int rc = 0; int rc = 0;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
...@@ -1593,7 +1614,11 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -1593,7 +1614,11 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len; iov[0].iov_len = total_len;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
if (rc) if (rc)
cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE); cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE);
...@@ -1886,11 +1911,165 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, ...@@ -1886,11 +1911,165 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
return 0; return 0;
} }
#ifdef CONFIG_CIFS_SMB311
int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
umode_t mode, struct cifs_tcon *tcon,
const char *full_path,
struct cifs_sb_info *cifs_sb)
{
struct smb_rqst rqst;
struct smb2_create_req *req;
struct smb2_create_rsp *rsp;
struct TCP_Server_Info *server;
struct cifs_ses *ses = tcon->ses;
struct kvec iov[3]; /* make sure at least one for each open context */
struct kvec rsp_iov = {NULL, 0};
int resp_buftype;
int uni_path_len;
__le16 *copy_path = NULL;
int copy_size;
int rc = 0;
unsigned int n_iov = 2;
__u32 file_attributes = 0;
char *pc_buf = NULL;
int flags = 0;
unsigned int total_len;
__le16 *path = cifs_convert_path_to_utf16(full_path, cifs_sb);
if (!path)
return -ENOMEM;
cifs_dbg(FYI, "mkdir\n");
if (ses && (ses->server))
server = ses->server;
else
return -EIO;
rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);
if (rc)
return rc;
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
req->ImpersonationLevel = IL_IMPERSONATION;
req->DesiredAccess = cpu_to_le32(FILE_WRITE_ATTRIBUTES);
/* File attributes ignored on open (used in create though) */
req->FileAttributes = cpu_to_le32(file_attributes);
req->ShareAccess = FILE_SHARE_ALL_LE;
req->CreateDisposition = cpu_to_le32(FILE_CREATE);
req->CreateOptions = cpu_to_le32(CREATE_NOT_FILE);
iov[0].iov_base = (char *)req;
/* -1 since last byte is buf[0] which is sent below (path) */
iov[0].iov_len = total_len - 1;
req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req));
/* [MS-SMB2] 2.2.13 NameOffset:
* If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of
* the SMB2 header, the file name includes a prefix that will
* be processed during DFS name normalization as specified in
* section 3.3.5.9. Otherwise, the file name is relative to
* the share that is identified by the TreeId in the SMB2
* header.
*/
if (tcon->share_flags & SHI1005_FLAGS_DFS) {
int name_len;
req->sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
&name_len,
tcon->treeName, path);
if (rc) {
cifs_small_buf_release(req);
return rc;
}
req->NameLength = cpu_to_le16(name_len * 2);
uni_path_len = copy_size;
path = copy_path;
} else {
uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
/* MUST set path len (NameLength) to 0 opening root of share */
req->NameLength = cpu_to_le16(uni_path_len - 2);
if (uni_path_len % 8 != 0) {
copy_size = roundup(uni_path_len, 8);
copy_path = kzalloc(copy_size, GFP_KERNEL);
if (!copy_path) {
cifs_small_buf_release(req);
return -ENOMEM;
}
memcpy((char *)copy_path, (const char *)path,
uni_path_len);
uni_path_len = copy_size;
path = copy_path;
}
}
iov[1].iov_len = uni_path_len;
iov[1].iov_base = path;
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
if (tcon->posix_extensions) {
if (n_iov > 2) {
struct create_context *ccontext =
(struct create_context *)iov[n_iov-1].iov_base;
ccontext->Next =
cpu_to_le32(iov[n_iov-1].iov_len);
}
rc = add_posix_context(iov, &n_iov, mode);
if (rc) {
cifs_small_buf_release(req);
kfree(copy_path);
return rc;
}
pc_buf = iov[n_iov-1].iov_base;
}
memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = n_iov;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
&rsp_iov);
cifs_small_buf_release(req);
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
if (rc != 0) {
cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid,
CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES, rc);
goto smb311_mkdir_exit;
} else
trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid,
ses->Suid, CREATE_NOT_FILE,
FILE_WRITE_ATTRIBUTES);
SMB2_close(xid, tcon, rsp->PersistentFileId, rsp->VolatileFileId);
/* Eventually save off posix specific response info and timestaps */
smb311_mkdir_exit:
kfree(copy_path);
kfree(pc_buf);
free_rsp_buf(resp_buftype, rsp);
return rc;
}
#endif /* SMB311 */
int int
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
__u8 *oplock, struct smb2_file_all_info *buf, __u8 *oplock, struct smb2_file_all_info *buf,
struct kvec *err_iov, int *buftype) struct kvec *err_iov, int *buftype)
{ {
struct smb_rqst rqst;
struct smb2_create_req *req; struct smb2_create_req *req;
struct smb2_create_rsp *rsp; struct smb2_create_rsp *rsp;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
...@@ -2043,7 +2222,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -2043,7 +2222,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
} }
#endif /* SMB311 */ #endif /* SMB311 */
rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags, memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = n_iov;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
&rsp_iov); &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
...@@ -2099,6 +2282,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -2099,6 +2282,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
char *in_data, u32 indatalen, char *in_data, u32 indatalen,
char **out_data, u32 *plen /* returned data len */) char **out_data, u32 *plen /* returned data len */)
{ {
struct smb_rqst rqst;
struct smb2_ioctl_req *req; struct smb2_ioctl_req *req;
struct smb2_ioctl_rsp *rsp; struct smb2_ioctl_rsp *rsp;
struct cifs_ses *ses; struct cifs_ses *ses;
...@@ -2189,7 +2373,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -2189,7 +2373,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO)
req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags, memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = n_iov;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
&rsp_iov); &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base; rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base;
...@@ -2274,6 +2462,7 @@ int ...@@ -2274,6 +2462,7 @@ int
SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon, SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, int flags) u64 persistent_fid, u64 volatile_fid, int flags)
{ {
struct smb_rqst rqst;
struct smb2_close_req *req; struct smb2_close_req *req;
struct smb2_close_rsp *rsp; struct smb2_close_rsp *rsp;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
...@@ -2301,7 +2490,11 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2301,7 +2490,11 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len; iov[0].iov_len = total_len;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_close_rsp *)rsp_iov.iov_base; rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
...@@ -2387,6 +2580,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2387,6 +2580,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
u32 additional_info, size_t output_len, size_t min_len, void **data, u32 additional_info, size_t output_len, size_t min_len, void **data,
u32 *dlen) u32 *dlen)
{ {
struct smb_rqst rqst;
struct smb2_query_info_req *req; struct smb2_query_info_req *req;
struct smb2_query_info_rsp *rsp = NULL; struct smb2_query_info_rsp *rsp = NULL;
struct kvec iov[2]; struct kvec iov[2];
...@@ -2427,7 +2621,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2427,7 +2621,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
/* 1 for Buffer */ /* 1 for Buffer */
iov[0].iov_len = total_len - 1; iov[0].iov_len = total_len - 1;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
...@@ -2594,11 +2792,10 @@ SMB2_echo(struct TCP_Server_Info *server) ...@@ -2594,11 +2792,10 @@ SMB2_echo(struct TCP_Server_Info *server)
{ {
struct smb2_echo_req *req; struct smb2_echo_req *req;
int rc = 0; int rc = 0;
struct kvec iov[2]; struct kvec iov[1];
struct smb_rqst rqst = { .rq_iov = iov, struct smb_rqst rqst = { .rq_iov = iov,
.rq_nvec = 2 }; .rq_nvec = 1 };
unsigned int total_len; unsigned int total_len;
__be32 rfc1002_marker;
cifs_dbg(FYI, "In echo request\n"); cifs_dbg(FYI, "In echo request\n");
...@@ -2614,11 +2811,8 @@ SMB2_echo(struct TCP_Server_Info *server) ...@@ -2614,11 +2811,8 @@ SMB2_echo(struct TCP_Server_Info *server)
req->sync_hdr.CreditRequest = cpu_to_le16(1); req->sync_hdr.CreditRequest = cpu_to_le16(1);
iov[0].iov_len = 4; iov[0].iov_len = total_len;
rfc1002_marker = cpu_to_be32(total_len); iov[0].iov_base = (char *)req;
iov[0].iov_base = &rfc1002_marker;
iov[1].iov_len = total_len;
iov[1].iov_base = (char *)req;
rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL, rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL,
server, CIFS_ECHO_OP); server, CIFS_ECHO_OP);
...@@ -2633,6 +2827,7 @@ int ...@@ -2633,6 +2827,7 @@ int
SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
u64 volatile_fid) u64 volatile_fid)
{ {
struct smb_rqst rqst;
struct smb2_flush_req *req; struct smb2_flush_req *req;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct kvec iov[1]; struct kvec iov[1];
...@@ -2660,7 +2855,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -2660,7 +2855,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len; iov[0].iov_len = total_len;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
if (rc != 0) { if (rc != 0) {
...@@ -2848,10 +3047,9 @@ smb2_async_readv(struct cifs_readdata *rdata) ...@@ -2848,10 +3047,9 @@ smb2_async_readv(struct cifs_readdata *rdata)
struct smb2_sync_hdr *shdr; struct smb2_sync_hdr *shdr;
struct cifs_io_parms io_parms; struct cifs_io_parms io_parms;
struct smb_rqst rqst = { .rq_iov = rdata->iov, struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2 }; .rq_nvec = 1 };
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
unsigned int total_len; unsigned int total_len;
__be32 req_len;
cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
__func__, rdata->offset, rdata->bytes); __func__, rdata->offset, rdata->bytes);
...@@ -2882,12 +3080,8 @@ smb2_async_readv(struct cifs_readdata *rdata) ...@@ -2882,12 +3080,8 @@ smb2_async_readv(struct cifs_readdata *rdata)
if (smb3_encryption_required(io_parms.tcon)) if (smb3_encryption_required(io_parms.tcon))
flags |= CIFS_TRANSFORM_REQ; flags |= CIFS_TRANSFORM_REQ;
req_len = cpu_to_be32(total_len); rdata->iov[0].iov_base = buf;
rdata->iov[0].iov_len = total_len;
rdata->iov[0].iov_base = &req_len;
rdata->iov[0].iov_len = sizeof(__be32);
rdata->iov[1].iov_base = buf;
rdata->iov[1].iov_len = total_len;
shdr = (struct smb2_sync_hdr *)buf; shdr = (struct smb2_sync_hdr *)buf;
...@@ -2926,6 +3120,7 @@ int ...@@ -2926,6 +3120,7 @@ int
SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, char **buf, int *buf_type) unsigned int *nbytes, char **buf, int *buf_type)
{ {
struct smb_rqst rqst;
int resp_buftype, rc = -EACCES; int resp_buftype, rc = -EACCES;
struct smb2_read_plain_req *req = NULL; struct smb2_read_plain_req *req = NULL;
struct smb2_read_rsp *rsp = NULL; struct smb2_read_rsp *rsp = NULL;
...@@ -2946,7 +3141,11 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, ...@@ -2946,7 +3141,11 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len; iov[0].iov_len = total_len;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_read_rsp *)rsp_iov.iov_base; rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
...@@ -3062,10 +3261,9 @@ smb2_async_writev(struct cifs_writedata *wdata, ...@@ -3062,10 +3261,9 @@ smb2_async_writev(struct cifs_writedata *wdata,
struct smb2_sync_hdr *shdr; struct smb2_sync_hdr *shdr;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
struct kvec iov[2]; struct kvec iov[1];
struct smb_rqst rqst = { }; struct smb_rqst rqst = { };
unsigned int total_len; unsigned int total_len;
__be32 rfc1002_marker;
rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len); rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len);
if (rc) { if (rc) {
...@@ -3137,15 +3335,11 @@ smb2_async_writev(struct cifs_writedata *wdata, ...@@ -3137,15 +3335,11 @@ smb2_async_writev(struct cifs_writedata *wdata,
v1->length = cpu_to_le32(wdata->mr->mr->length); v1->length = cpu_to_le32(wdata->mr->mr->length);
} }
#endif #endif
/* 4 for rfc1002 length field and 1 for Buffer */ iov[0].iov_len = total_len - 1;
iov[0].iov_len = 4; iov[0].iov_base = (char *)req;
rfc1002_marker = cpu_to_be32(total_len - 1 + wdata->bytes);
iov[0].iov_base = &rfc1002_marker;
iov[1].iov_len = total_len - 1;
iov[1].iov_base = (char *)req;
rqst.rq_iov = iov; rqst.rq_iov = iov;
rqst.rq_nvec = 2; rqst.rq_nvec = 1;
rqst.rq_pages = wdata->pages; rqst.rq_pages = wdata->pages;
rqst.rq_offset = wdata->page_offset; rqst.rq_offset = wdata->page_offset;
rqst.rq_npages = wdata->nr_pages; rqst.rq_npages = wdata->nr_pages;
...@@ -3153,7 +3347,7 @@ smb2_async_writev(struct cifs_writedata *wdata, ...@@ -3153,7 +3347,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
rqst.rq_tailsz = wdata->tailsz; rqst.rq_tailsz = wdata->tailsz;
#ifdef CONFIG_CIFS_SMB_DIRECT #ifdef CONFIG_CIFS_SMB_DIRECT
if (wdata->mr) { if (wdata->mr) {
iov[1].iov_len += sizeof(struct smbd_buffer_descriptor_v1); iov[0].iov_len += sizeof(struct smbd_buffer_descriptor_v1);
rqst.rq_npages = 0; rqst.rq_npages = 0;
} }
#endif #endif
...@@ -3210,6 +3404,7 @@ int ...@@ -3210,6 +3404,7 @@ int
SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, struct kvec *iov, int n_vec) unsigned int *nbytes, struct kvec *iov, int n_vec)
{ {
struct smb_rqst rqst;
int rc = 0; int rc = 0;
struct smb2_write_req *req = NULL; struct smb2_write_req *req = NULL;
struct smb2_write_rsp *rsp = NULL; struct smb2_write_rsp *rsp = NULL;
...@@ -3251,7 +3446,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, ...@@ -3251,7 +3446,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
/* 1 for Buffer */ /* 1 for Buffer */
iov[0].iov_len = total_len - 1; iov[0].iov_len = total_len - 1;
rc = smb2_send_recv(xid, io_parms->tcon->ses, iov, n_vec + 1, memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = n_vec + 1;
rc = cifs_send_recv(xid, io_parms->tcon->ses, &rqst,
&resp_buftype, flags, &rsp_iov); &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_write_rsp *)rsp_iov.iov_base; rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
...@@ -3323,6 +3522,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3323,6 +3522,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, int index, u64 persistent_fid, u64 volatile_fid, int index,
struct cifs_search_info *srch_inf) struct cifs_search_info *srch_inf)
{ {
struct smb_rqst rqst;
struct smb2_query_directory_req *req; struct smb2_query_directory_req *req;
struct smb2_query_directory_rsp *rsp = NULL; struct smb2_query_directory_rsp *rsp = NULL;
struct kvec iov[2]; struct kvec iov[2];
...@@ -3395,7 +3595,11 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3395,7 +3595,11 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
iov[1].iov_base = (char *)(req->Buffer); iov[1].iov_base = (char *)(req->Buffer);
iov[1].iov_len = len; iov[1].iov_len = len;
rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 2;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base;
...@@ -3454,6 +3658,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3454,6 +3658,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
u8 info_type, u32 additional_info, unsigned int num, u8 info_type, u32 additional_info, unsigned int num,
void **data, unsigned int *size) void **data, unsigned int *size)
{ {
struct smb_rqst rqst;
struct smb2_set_info_req *req; struct smb2_set_info_req *req;
struct smb2_set_info_rsp *rsp = NULL; struct smb2_set_info_rsp *rsp = NULL;
struct kvec *iov; struct kvec *iov;
...@@ -3509,7 +3714,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3509,7 +3714,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
iov[i].iov_len = size[i]; iov[i].iov_len = size[i];
} }
rc = smb2_send_recv(xid, ses, iov, num, &resp_buftype, flags, memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = num;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
&rsp_iov); &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base; rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
...@@ -3664,6 +3873,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3664,6 +3873,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid, const u64 persistent_fid, const u64 volatile_fid,
__u8 oplock_level) __u8 oplock_level)
{ {
struct smb_rqst rqst;
int rc; int rc;
struct smb2_oplock_break *req = NULL; struct smb2_oplock_break *req = NULL;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
...@@ -3692,7 +3902,11 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3692,7 +3902,11 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len; iov[0].iov_len = total_len;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
if (rc) { if (rc) {
...@@ -3755,6 +3969,7 @@ int ...@@ -3755,6 +3969,7 @@ int
SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
{ {
struct smb_rqst rqst;
struct smb2_query_info_rsp *rsp = NULL; struct smb2_query_info_rsp *rsp = NULL;
struct kvec iov; struct kvec iov;
struct kvec rsp_iov; struct kvec rsp_iov;
...@@ -3773,7 +3988,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3773,7 +3988,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
if (smb3_encryption_required(tcon)) if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ; flags |= CIFS_TRANSFORM_REQ;
rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(iov.iov_base); cifs_small_buf_release(iov.iov_base);
if (rc) { if (rc) {
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
...@@ -3798,6 +4017,7 @@ int ...@@ -3798,6 +4017,7 @@ int
SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, int level) u64 persistent_fid, u64 volatile_fid, int level)
{ {
struct smb_rqst rqst;
struct smb2_query_info_rsp *rsp = NULL; struct smb2_query_info_rsp *rsp = NULL;
struct kvec iov; struct kvec iov;
struct kvec rsp_iov; struct kvec rsp_iov;
...@@ -3829,7 +4049,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3829,7 +4049,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
if (smb3_encryption_required(tcon)) if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ; flags |= CIFS_TRANSFORM_REQ;
rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(iov.iov_base); cifs_small_buf_release(iov.iov_base);
if (rc) { if (rc) {
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
...@@ -3868,6 +4092,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3868,6 +4092,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid, const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid,
const __u32 num_lock, struct smb2_lock_element *buf) const __u32 num_lock, struct smb2_lock_element *buf)
{ {
struct smb_rqst rqst;
int rc = 0; int rc = 0;
struct smb2_lock_req *req = NULL; struct smb2_lock_req *req = NULL;
struct kvec iov[2]; struct kvec iov[2];
...@@ -3900,7 +4125,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3900,7 +4125,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
iov[1].iov_len = count; iov[1].iov_len = count;
cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
rc = smb2_send_recv(xid, tcon->ses, iov, 2, &resp_buf_type, flags,
memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 2;
rc = cifs_send_recv(xid, tcon->ses, &rqst, &resp_buf_type, flags,
&rsp_iov); &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
if (rc) { if (rc) {
...@@ -3934,6 +4164,7 @@ int ...@@ -3934,6 +4164,7 @@ int
SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
__u8 *lease_key, const __le32 lease_state) __u8 *lease_key, const __le32 lease_state)
{ {
struct smb_rqst rqst;
int rc; int rc;
struct smb2_lease_ack *req = NULL; struct smb2_lease_ack *req = NULL;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
...@@ -3964,7 +4195,11 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3964,7 +4195,11 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len; iov[0].iov_len = total_len;
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
if (rc) { if (rc) {
......
...@@ -851,8 +851,11 @@ struct validate_negotiate_info_rsp { ...@@ -851,8 +851,11 @@ struct validate_negotiate_info_rsp {
__le16 Dialect; /* Dialect in use for the connection */ __le16 Dialect; /* Dialect in use for the connection */
} __packed; } __packed;
#define RSS_CAPABLE 0x00000001 #define RSS_CAPABLE cpu_to_le32(0x00000001)
#define RDMA_CAPABLE 0x00000002 #define RDMA_CAPABLE cpu_to_le32(0x00000002)
#define INTERNETWORK cpu_to_le16(0x0002)
#define INTERNETWORKV6 cpu_to_le16(0x0017)
struct network_interface_info_ioctl_rsp { struct network_interface_info_ioctl_rsp {
__le32 Next; /* next interface. zero if this is last one */ __le32 Next; /* next interface. zero if this is last one */
...@@ -860,7 +863,21 @@ struct network_interface_info_ioctl_rsp { ...@@ -860,7 +863,21 @@ struct network_interface_info_ioctl_rsp {
__le32 Capability; /* RSS or RDMA Capable */ __le32 Capability; /* RSS or RDMA Capable */
__le32 Reserved; __le32 Reserved;
__le64 LinkSpeed; __le64 LinkSpeed;
char SockAddr_Storage[128]; __le16 Family;
__u8 Buffer[126];
} __packed;
struct iface_info_ipv4 {
__be16 Port;
__be32 IPv4Address;
__be64 Reserved;
} __packed;
struct iface_info_ipv6 {
__be16 Port;
__be32 FlowInfo;
__u8 IPv6Address[16];
__be32 ScopeId;
} __packed; } __packed;
#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */ #define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
......
...@@ -79,6 +79,10 @@ extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -79,6 +79,10 @@ extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, bool set_alloc); struct cifs_sb_info *cifs_sb, bool set_alloc);
extern int smb2_set_file_info(struct inode *inode, const char *full_path, extern int smb2_set_file_info(struct inode *inode, const char *full_path,
FILE_BASIC_INFO *buf, const unsigned int xid); FILE_BASIC_INFO *buf, const unsigned int xid);
extern int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
umode_t mode, struct cifs_tcon *tcon,
const char *full_path,
struct cifs_sb_info *cifs_sb);
extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb); const char *name, struct cifs_sb_info *cifs_sb);
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path, extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
...@@ -109,6 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile, ...@@ -109,6 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
extern void smb2_reconnect_server(struct work_struct *work); extern void smb2_reconnect_server(struct work_struct *work);
extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server); extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
extern unsigned long
smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker);
/* /*
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
......
...@@ -171,9 +171,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -171,9 +171,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
unsigned char *sigptr = smb2_signature; unsigned char *sigptr = smb2_signature;
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
int iov_hdr_index = rqst->rq_nvec > 1 ? 1 : 0; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)iov[iov_hdr_index].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
ses = smb2_find_smb_ses(server, shdr->SessionId); ses = smb2_find_smb_ses(server, shdr->SessionId);
...@@ -204,7 +202,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -204,7 +202,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
return rc; return rc;
} }
rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr, rc = __cifs_calc_signature(rqst, server, sigptr,
&server->secmech.sdeschmacsha256->shash); &server->secmech.sdeschmacsha256->shash);
if (!rc) if (!rc)
...@@ -414,9 +412,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -414,9 +412,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
unsigned char smb3_signature[SMB2_CMACAES_SIZE]; unsigned char smb3_signature[SMB2_CMACAES_SIZE];
unsigned char *sigptr = smb3_signature; unsigned char *sigptr = smb3_signature;
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
int iov_hdr_index = rqst->rq_nvec > 1 ? 1 : 0; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)iov[iov_hdr_index].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
ses = smb2_find_smb_ses(server, shdr->SessionId); ses = smb2_find_smb_ses(server, shdr->SessionId);
...@@ -447,7 +443,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -447,7 +443,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
return rc; return rc;
} }
rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr, rc = __cifs_calc_signature(rqst, server, sigptr,
&server->secmech.sdesccmacaes->shash); &server->secmech.sdesccmacaes->shash);
if (!rc) if (!rc)
...@@ -462,7 +458,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -462,7 +458,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{ {
int rc = 0; int rc = 0;
struct smb2_sync_hdr *shdr = 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->Flags & SMB2_FLAGS_SIGNED) || if (!(shdr->Flags & SMB2_FLAGS_SIGNED) ||
server->tcpStatus == CifsNeedNegotiate) server->tcpStatus == CifsNeedNegotiate)
...@@ -635,7 +631,7 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) ...@@ -635,7 +631,7 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
{ {
int rc; int rc;
struct smb2_sync_hdr *shdr = 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;
struct mid_q_entry *mid; struct mid_q_entry *mid;
smb2_seq_num_into_buf(ses->server, shdr); smb2_seq_num_into_buf(ses->server, shdr);
...@@ -656,7 +652,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) ...@@ -656,7 +652,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{ {
int rc; int rc;
struct smb2_sync_hdr *shdr = 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;
struct mid_q_entry *mid; struct mid_q_entry *mid;
smb2_seq_num_into_buf(server, shdr); smb2_seq_num_into_buf(server, shdr);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "smbdirect.h" #include "smbdirect.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifsproto.h" #include "cifsproto.h"
#include "smb2proto.h"
static struct smbd_response *get_empty_queue_buffer( static struct smbd_response *get_empty_queue_buffer(
struct smbd_connection *info); struct smbd_connection *info);
...@@ -2087,7 +2088,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) ...@@ -2087,7 +2088,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
struct kvec vec; struct kvec vec;
int nvecs; int nvecs;
int size; int size;
unsigned int buflen = 0, remaining_data_length; unsigned int buflen, remaining_data_length;
int start, i, j; int start, i, j;
int max_iov_size = int max_iov_size =
info->max_send_size - sizeof(struct smbd_data_transfer); info->max_send_size - sizeof(struct smbd_data_transfer);
...@@ -2111,25 +2112,13 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) ...@@ -2111,25 +2112,13 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len); log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len);
return -EINVAL; return -EINVAL;
} }
iov = &rqst->rq_iov[1];
/* total up iov array first */
for (i = 0; i < rqst->rq_nvec-1; i++) {
buflen += iov[i].iov_len;
}
/* /*
* Add in the page array if there is one. The caller needs to set * Add in the page array if there is one. The caller needs to set
* rq_tailsz to PAGE_SIZE when the buffer has multiple pages and * rq_tailsz to PAGE_SIZE when the buffer has multiple pages and
* ends at page boundary * ends at page boundary
*/ */
if (rqst->rq_npages) { buflen = smb2_rqst_len(rqst, true);
if (rqst->rq_npages == 1)
buflen += rqst->rq_tailsz;
else
buflen += rqst->rq_pagesz * (rqst->rq_npages - 1) -
rqst->rq_offset + rqst->rq_tailsz;
}
if (buflen + sizeof(struct smbd_data_transfer) > if (buflen + sizeof(struct smbd_data_transfer) >
info->max_fragmented_send_size) { info->max_fragmented_send_size) {
...@@ -2139,6 +2128,8 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) ...@@ -2139,6 +2128,8 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
goto done; goto done;
} }
iov = &rqst->rq_iov[1];
cifs_dbg(FYI, "Sending smb (RDMA): smb_len=%u\n", buflen); cifs_dbg(FYI, "Sending smb (RDMA): smb_len=%u\n", buflen);
for (i = 0; i < rqst->rq_nvec-1; i++) for (i = 0; i < rqst->rq_nvec-1; i++)
dump_smb(iov[i].iov_base, iov[i].iov_len); dump_smb(iov[i].iov_base, iov[i].iov_len);
......
...@@ -378,7 +378,7 @@ DEFINE_EVENT(smb3_open_err_class, smb3_##name, \ ...@@ -378,7 +378,7 @@ DEFINE_EVENT(smb3_open_err_class, smb3_##name, \
TP_ARGS(xid, tid, sesid, create_options, desired_access, rc)) TP_ARGS(xid, tid, sesid, create_options, desired_access, rc))
DEFINE_SMB3_OPEN_ERR_EVENT(open_err); DEFINE_SMB3_OPEN_ERR_EVENT(open_err);
DEFINE_SMB3_OPEN_ERR_EVENT(posix_mkdir_err);
DECLARE_EVENT_CLASS(smb3_open_done_class, DECLARE_EVENT_CLASS(smb3_open_done_class,
TP_PROTO(unsigned int xid, TP_PROTO(unsigned int xid,
...@@ -420,6 +420,7 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \ ...@@ -420,6 +420,7 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
TP_ARGS(xid, fid, tid, sesid, create_options, desired_access)) TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))
DEFINE_SMB3_OPEN_DONE_EVENT(open_done); DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);
#endif /* _CIFS_TRACE_H */ #endif /* _CIFS_TRACE_H */
......
...@@ -201,15 +201,24 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, ...@@ -201,15 +201,24 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
return 0; return 0;
} }
static unsigned long unsigned long
rqst_len(struct smb_rqst *rqst) smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker)
{ {
unsigned int i; unsigned int i;
struct kvec *iov = rqst->rq_iov; struct kvec *iov;
int nvec;
unsigned long buflen = 0; unsigned long buflen = 0;
if (skip_rfc1002_marker && rqst->rq_iov[0].iov_len == 4) {
iov = &rqst->rq_iov[1];
nvec = rqst->rq_nvec - 1;
} else {
iov = rqst->rq_iov;
nvec = rqst->rq_nvec;
}
/* total up iov array first */ /* total up iov array first */
for (i = 0; i < rqst->rq_nvec; i++) for (i = 0; i < nvec; i++)
buflen += iov[i].iov_len; buflen += iov[i].iov_len;
/* /*
...@@ -236,18 +245,20 @@ rqst_len(struct smb_rqst *rqst) ...@@ -236,18 +245,20 @@ rqst_len(struct smb_rqst *rqst)
} }
static int static int
__smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct smb_rqst *rqst)
{ {
int rc; int rc = 0;
struct kvec *iov = rqst->rq_iov; struct kvec *iov;
int n_vec = rqst->rq_nvec; int n_vec;
unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); unsigned int send_length = 0;
unsigned long send_length; unsigned int i, j;
unsigned int i;
size_t total_len = 0, sent, size; size_t total_len = 0, sent, size;
struct socket *ssocket = server->ssocket; struct socket *ssocket = server->ssocket;
struct msghdr smb_msg; struct msghdr smb_msg;
int val = 1; int val = 1;
__be32 rfc1002_marker;
if (cifs_rdma_enabled(server) && server->smbd_conn) { if (cifs_rdma_enabled(server) && server->smbd_conn) {
rc = smbd_send(server->smbd_conn, rqst); rc = smbd_send(server->smbd_conn, rqst);
goto smbd_done; goto smbd_done;
...@@ -255,30 +266,44 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) ...@@ -255,30 +266,44 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
if (ssocket == NULL) if (ssocket == NULL)
return -ENOTSOCK; return -ENOTSOCK;
/* sanity check send length */
send_length = rqst_len(rqst);
if (send_length != smb_buf_length + 4) {
WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
send_length, smb_buf_length);
return -EIO;
}
if (n_vec < 2)
return -EIO;
cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
dump_smb(iov[0].iov_base, iov[0].iov_len);
dump_smb(iov[1].iov_base, iov[1].iov_len);
/* cork the socket */ /* cork the socket */
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
(char *)&val, sizeof(val)); (char *)&val, sizeof(val));
for (j = 0; j < num_rqst; j++)
send_length += smb2_rqst_len(&rqst[j], true);
rfc1002_marker = cpu_to_be32(send_length);
/* Generate a rfc1002 marker for SMB2+ */
if (server->vals->header_preamble_size == 0) {
struct kvec hiov = {
.iov_base = &rfc1002_marker,
.iov_len = 4
};
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, &hiov,
1, 4);
rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0)
goto uncork;
total_len += sent;
send_length += 4;
}
cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length);
for (j = 0; j < num_rqst; j++) {
iov = rqst[j].rq_iov;
n_vec = rqst[j].rq_nvec;
size = 0; size = 0;
for (i = 0; i < n_vec; i++) for (i = 0; i < n_vec; i++) {
dump_smb(iov[i].iov_base, iov[i].iov_len);
size += iov[i].iov_len; size += iov[i].iov_len;
}
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov, n_vec, size); iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC,
iov, n_vec, size);
rc = smb_send_kvec(server, &smb_msg, &sent); rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0) if (rc < 0)
...@@ -287,11 +312,12 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) ...@@ -287,11 +312,12 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
total_len += sent; total_len += sent;
/* now walk the page array and send each page in it */ /* now walk the page array and send each page in it */
for (i = 0; i < rqst->rq_npages; i++) { for (i = 0; i < rqst[j].rq_npages; i++) {
struct bio_vec bvec; struct bio_vec bvec;
bvec.bv_page = rqst->rq_pages[i]; bvec.bv_page = rqst[j].rq_pages[i];
rqst_page_get_length(rqst, i, &bvec.bv_len, &bvec.bv_offset); rqst_page_get_length(&rqst[j], i, &bvec.bv_len,
&bvec.bv_offset);
iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC,
&bvec, 1, bvec.bv_len); &bvec, 1, bvec.bv_len);
...@@ -301,6 +327,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) ...@@ -301,6 +327,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
total_len += sent; total_len += sent;
} }
}
uncork: uncork:
/* uncork it */ /* uncork it */
...@@ -308,9 +335,9 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) ...@@ -308,9 +335,9 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
(char *)&val, sizeof(val)); (char *)&val, sizeof(val));
if ((total_len > 0) && (total_len != smb_buf_length + 4)) { if ((total_len > 0) && (total_len != send_length)) {
cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n", cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n",
smb_buf_length + 4, total_len); send_length, total_len);
/* /*
* If we have only sent part of an SMB then the next SMB could * If we have only sent part of an SMB then the next SMB could
* be taken as the remainder of this one. We need to kill the * be taken as the remainder of this one. We need to kill the
...@@ -335,7 +362,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) ...@@ -335,7 +362,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
int rc; int rc;
if (!(flags & CIFS_TRANSFORM_REQ)) if (!(flags & CIFS_TRANSFORM_REQ))
return __smb_send_rqst(server, rqst); return __smb_send_rqst(server, 1, rqst);
if (!server->ops->init_transform_rq || if (!server->ops->init_transform_rq ||
!server->ops->free_transform_rq) { !server->ops->free_transform_rq) {
...@@ -347,7 +374,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) ...@@ -347,7 +374,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
if (rc) if (rc)
return rc; return rc;
rc = __smb_send_rqst(server, &cur_rqst); rc = __smb_send_rqst(server, 1, &cur_rqst);
server->ops->free_transform_rq(&cur_rqst); server->ops->free_transform_rq(&cur_rqst);
return rc; return rc;
} }
...@@ -365,7 +392,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, ...@@ -365,7 +392,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
iov[1].iov_base = (char *)smb_buffer + 4; iov[1].iov_base = (char *)smb_buffer + 4;
iov[1].iov_len = smb_buf_length; iov[1].iov_len = smb_buf_length;
return __smb_send_rqst(server, &rqst); return __smb_send_rqst(server, 1, &rqst);
} }
static int static int
...@@ -730,7 +757,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -730,7 +757,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
* to the same server. We may make this configurable later or * to the same server. We may make this configurable later or
* use ses->maxReq. * use ses->maxReq.
*/ */
rc = wait_for_free_request(ses->server, timeout, optype); rc = wait_for_free_request(ses->server, timeout, optype);
if (rc) if (rc)
return rc; return rc;
...@@ -766,8 +792,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -766,8 +792,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
smb311_update_preauth_hash(ses, rqst->rq_iov+1, smb311_update_preauth_hash(ses, rqst->rq_iov,
rqst->rq_nvec-1); rqst->rq_nvec);
#endif #endif
if (timeout == CIFS_ASYNC_OP) if (timeout == CIFS_ASYNC_OP)
...@@ -812,8 +838,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -812,8 +838,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
struct kvec iov = { struct kvec iov = {
.iov_base = buf, .iov_base = resp_iov->iov_base,
.iov_len = midQ->resp_buf_size .iov_len = resp_iov->iov_len
}; };
smb311_update_preauth_hash(ses, &iov, 1); smb311_update_preauth_hash(ses, &iov, 1);
} }
...@@ -872,49 +898,6 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, ...@@ -872,49 +898,6 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
return rc; return rc;
} }
/* Like SendReceive2 but iov[0] does not contain an rfc1002 header */
int
smb2_send_recv(const unsigned int xid, struct cifs_ses *ses,
struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
const int flags, struct kvec *resp_iov)
{
struct smb_rqst rqst;
struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
int rc;
int i;
__u32 count;
__be32 rfc1002_marker;
if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
GFP_KERNEL);
if (!new_iov)
return -ENOMEM;
} else
new_iov = s_iov;
/* 1st iov is an RFC1002 Session Message length */
memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
count = 0;
for (i = 1; i < n_vec + 1; i++)
count += new_iov[i].iov_len;
rfc1002_marker = cpu_to_be32(count);
new_iov[0].iov_base = &rfc1002_marker;
new_iov[0].iov_len = 4;
memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = new_iov;
rqst.rq_nvec = n_vec + 1;
rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
kfree(new_iov);
return rc;
}
int int
SendReceive(const unsigned int xid, struct cifs_ses *ses, SendReceive(const unsigned int xid, struct cifs_ses *ses,
struct smb_hdr *in_buf, struct smb_hdr *out_buf, struct smb_hdr *in_buf, struct smb_hdr *out_buf,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment