mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 16:11:38 +00:00
Misc. SMB3 fixes, including particularly important ones for signing, some minor documentation and debug improvements and another posix smb3.11 fix
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAlsmhmUACgkQiiy9cAdy T1FgTQwAqwTrVg6cf8EDqvWqk4MJUmGt8dvG0f8ikwa/oou8FspdQNSLnRpM5id5 xH/VbAULkCzNYqC8KO5d3SRAB/ZidJOBqzNPvpOdNiSvu+VfrC2kA9+NePXs41lf Ib+shOwGH2q2HKf8seLA2ivFZDBZLuAsKkYxQN4w4PPKEC8k3WZRYqEFw4OL1FDB v02+X3H5QDOFpVEIA69meWx8ezLnLtVI5PHWCj58/wbXOZpU3XO6klxl2XpccGQa MPBxOt3Ln1HhzEMPjcaB0TXhig8V0pOAhI6vsCasT6yN8orev5c1z5U2tz32Rgq0 U6qrTG1mUSD1Jl45kl0CDj2clzkA60XbG2nFkczQ0twoDvwK41xbn4HL+DcrzDWY FzRbMZ2wNb7UPUTUxBFh4DrBPdH97deyUMIn1wEYwin2MNveIE5qtS8nxSgJc8zG 3Tzed1SWGV/YEB794vMlFIRb2DZXWnzvjziKQy8aVHgmCcgWusl+75yKfvfJr8xx +D5LdNmu =KTNX -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
9ffc59d572
@ -42,9 +42,11 @@ Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
|
||||
Scott Lovenberg
|
||||
Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features)
|
||||
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)
|
||||
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
|
||||
@ -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
|
||||
and Dave Miller.
|
||||
|
||||
And thanks to the IBM LTC and Power test teams and SuSE testers for
|
||||
finding multiple bugs during excellent stress test runs.
|
||||
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.
|
||||
|
@ -1,3 +1,6 @@
|
||||
See https://wiki.samba.org/index.php/LinuxCIFSKernel for
|
||||
more current information.
|
||||
|
||||
Version 1.62
|
||||
------------
|
||||
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:
|
||||
|
||||
a) SMB3 (and SMB3.02) missing optional features:
|
||||
- multichannel (started), integration with RDMA
|
||||
- directory leases (improved metadata caching)
|
||||
- T10 copy offload (copy chunk, and "Duplicate Extents" ioctl
|
||||
- directory leases (improved metadata caching), started (root dir only)
|
||||
- T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
|
||||
currently the only two server side copy mechanisms supported)
|
||||
|
||||
b) improved sparse file support
|
||||
|
||||
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
|
||||
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
|
||||
exists. Also better integration with winbind for resolving SID owners
|
||||
|
||||
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
|
||||
|
||||
@ -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
|
||||
and simplify the code.
|
||||
|
||||
u) Finish up SMB3.1.1 dialect support
|
||||
|
||||
v) POSIX Extensions for SMB3.1.1
|
||||
v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added
|
||||
so far).
|
||||
|
||||
KNOWN BUGS
|
||||
====================================
|
||||
@ -92,8 +93,8 @@ Misc testing to do
|
||||
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
|
||||
|
||||
2) Improve xfstest's cifs enablement and adapt xfstests where needed to test
|
||||
cifs better
|
||||
2) Improve xfstest's cifs/smb3 enablement and adapt xfstests where needed to test
|
||||
cifs/smb3 better
|
||||
|
||||
3) Additional performance testing and optimization using iozone and similar -
|
||||
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)
|
||||
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)
|
||||
{
|
||||
struct list_head *tmp1, *tmp2, *tmp3;
|
||||
@ -312,6 +331,16 @@ skip_rdma:
|
||||
mid_entry->mid);
|
||||
}
|
||||
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);
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include <crypto/aead.h>
|
||||
|
||||
int __cifs_calc_signature(struct smb_rqst *rqst,
|
||||
int start,
|
||||
struct TCP_Server_Info *server, char *signature,
|
||||
struct shash_desc *shash)
|
||||
{
|
||||
@ -45,16 +44,27 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
|
||||
int rc;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
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)
|
||||
continue;
|
||||
if (iov[i].iov_base == NULL) {
|
||||
cifs_dbg(VFS, "null iovec entry\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (i == 1 && iov[1].iov_len <= 4)
|
||||
break; /* nothing to sign or corrupt header */
|
||||
|
||||
rc = crypto_shash_update(shash,
|
||||
iov[i].iov_base, iov[i].iov_len);
|
||||
if (rc) {
|
||||
@ -118,7 +128,7 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
|
||||
return rc;
|
||||
}
|
||||
|
||||
return __cifs_calc_signature(rqst, 1, server, signature,
|
||||
return __cifs_calc_signature(rqst, server, signature,
|
||||
&server->secmech.sdescmd5->shash);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,9 @@
|
||||
|
||||
#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
|
||||
*/
|
||||
@ -312,6 +315,10 @@ struct smb_version_operations {
|
||||
/* send echo request */
|
||||
int (*echo)(struct TCP_Server_Info *);
|
||||
/* 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 *,
|
||||
struct cifs_sb_info *);
|
||||
/* set info on created directory */
|
||||
@ -838,6 +845,13 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
|
||||
|
||||
#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
|
||||
*/
|
||||
@ -875,6 +889,20 @@ struct cifs_ses {
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
|
||||
#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
|
||||
@ -883,6 +911,14 @@ cap_unix(struct cifs_ses *ses)
|
||||
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
|
||||
* session
|
||||
@ -987,9 +1023,7 @@ struct cifs_tcon {
|
||||
struct fscache_cookie *fscache; /* cookie for share */
|
||||
#endif
|
||||
struct list_head pending_opens; /* list of incomplete opens */
|
||||
bool valid_root_fid:1; /* Do we have a useable root fid */
|
||||
struct mutex prfid_mutex; /* prevents reopen race after dead ses*/
|
||||
struct cifs_fid *prfid; /* handle to the directory at top of share */
|
||||
struct cached_fid crfid; /* Cached root fid */
|
||||
/* BB add field for back pointer to sb struct(s)? */
|
||||
};
|
||||
|
||||
|
@ -112,10 +112,6 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
|
||||
struct kvec *, int /* nvec to send */,
|
||||
int * /* type of buf returned */, const int flags,
|
||||
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,
|
||||
struct cifs_tcon *ptcon,
|
||||
struct smb_hdr *in_buf ,
|
||||
@ -544,7 +540,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const unsigned char *path, char *pbuf,
|
||||
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 shash_desc *shash);
|
||||
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);
|
||||
void cifs_aio_ctx_release(struct kref *refcount);
|
||||
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,
|
||||
struct sdesc **sdesc);
|
||||
|
@ -107,10 +107,10 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
|
||||
}
|
||||
spin_unlock(&tcon->open_file_lock);
|
||||
|
||||
mutex_lock(&tcon->prfid_mutex);
|
||||
tcon->valid_root_fid = false;
|
||||
memset(tcon->prfid, 0, sizeof(struct cifs_fid));
|
||||
mutex_unlock(&tcon->prfid_mutex);
|
||||
mutex_lock(&tcon->crfid.fid_mutex);
|
||||
tcon->crfid.is_valid = false;
|
||||
memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
|
||||
/*
|
||||
* BB Add call to invalidate_inodes(sb) for all superblocks mounted
|
||||
|
@ -57,9 +57,6 @@
|
||||
#include "smb2proto.h"
|
||||
#include "smbdirect.h"
|
||||
|
||||
#define CIFS_PORT 445
|
||||
#define RFC1001_PORT 139
|
||||
|
||||
extern mempool_t *cifs_req_poolp;
|
||||
extern bool disable_legacy_dialects;
|
||||
|
||||
@ -3029,8 +3026,11 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
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;
|
||||
printk_once(KERN_WARNING
|
||||
"SMB3.11 POSIX Extensions are experimental\n");
|
||||
}
|
||||
}
|
||||
#endif /* 311 */
|
||||
|
||||
|
@ -1575,6 +1575,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
|
||||
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 &
|
||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||
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)
|
||||
goto mkdir_out;
|
||||
}
|
||||
|
||||
server = tcon->ses->server;
|
||||
|
||||
if (!server->ops->mkdir) {
|
||||
rc = -ENOSYS;
|
||||
goto mkdir_out;
|
||||
|
@ -82,6 +82,7 @@ sesInfoAlloc(void)
|
||||
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
|
||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||
mutex_init(&ret_buf->session_mutex);
|
||||
spin_lock_init(&ret_buf->iface_lock);
|
||||
}
|
||||
return ret_buf;
|
||||
}
|
||||
@ -102,6 +103,7 @@ sesInfoFree(struct cifs_ses *buf_to_free)
|
||||
kfree(buf_to_free->user_name);
|
||||
kfree(buf_to_free->domainName);
|
||||
kzfree(buf_to_free->auth_key.response);
|
||||
kfree(buf_to_free->iface_list);
|
||||
kzfree(buf_to_free);
|
||||
}
|
||||
|
||||
@ -117,8 +119,9 @@ tconInfoAlloc(void)
|
||||
INIT_LIST_HEAD(&ret_buf->openFileList);
|
||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||
spin_lock_init(&ret_buf->open_file_lock);
|
||||
mutex_init(&ret_buf->prfid_mutex);
|
||||
ret_buf->prfid = kzalloc(sizeof(struct cifs_fid), GFP_KERNEL);
|
||||
mutex_init(&ret_buf->crfid.fid_mutex);
|
||||
ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
|
||||
GFP_KERNEL);
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
spin_lock_init(&ret_buf->stat_lock);
|
||||
#endif
|
||||
@ -136,7 +139,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
|
||||
atomic_dec(&tconInfoAllocCount);
|
||||
kfree(buf_to_free->nativeFileSystem);
|
||||
kzfree(buf_to_free->password);
|
||||
kfree(buf_to_free->prfid);
|
||||
kfree(buf_to_free->crfid.fid);
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,8 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/* SMB311 POSIX extensions paths do not include leading slash */
|
||||
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;
|
||||
}
|
||||
#endif /* 311 */
|
||||
@ -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, lease_break);
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
|
||||
lw->lease_state);
|
||||
|
||||
cifs_dbg(FYI, "Lease release rc %d\n", rc);
|
||||
cifs_put_tlink(lw->tlink);
|
||||
kfree(lw);
|
||||
@ -561,6 +563,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
|
||||
|
||||
open->oplock = lease_state;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
@ -603,6 +606,18 @@ smb2_is_valid_lease_break(char *buffer)
|
||||
return true;
|
||||
}
|
||||
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)
|
||||
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
|
||||
SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
{
|
||||
int rc;
|
||||
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,
|
||||
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
|
||||
NULL /* no data input */, 0 /* no data input */,
|
||||
(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);
|
||||
else if (ret_data_len < sizeof(struct network_interface_info_ioctl_rsp)) {
|
||||
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));
|
||||
goto out;
|
||||
}
|
||||
|
||||
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);
|
||||
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
|
||||
@ -331,13 +488,13 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||
struct cifs_open_parms oparams;
|
||||
int rc;
|
||||
__le16 srch_path = 0; /* Null - since an open of top of share */
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_II;
|
||||
|
||||
mutex_lock(&tcon->prfid_mutex);
|
||||
if (tcon->valid_root_fid) {
|
||||
mutex_lock(&tcon->crfid.fid_mutex);
|
||||
if (tcon->crfid.is_valid) {
|
||||
cifs_dbg(FYI, "found a cached root file handle\n");
|
||||
memcpy(pfid, tcon->prfid, sizeof(struct cifs_fid));
|
||||
mutex_unlock(&tcon->prfid_mutex);
|
||||
memcpy(pfid, tcon->crfid.fid, sizeof(struct cifs_fid));
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
if (rc == 0) {
|
||||
memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid));
|
||||
tcon->valid_root_fid = true;
|
||||
memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid));
|
||||
tcon->crfid.tcon = tcon;
|
||||
tcon->crfid.is_valid = true;
|
||||
}
|
||||
mutex_unlock(&tcon->prfid_mutex);
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -383,9 +541,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
if (rc)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
SMB3_request_interfaces(xid, tcon);
|
||||
#endif /* STATS2 */
|
||||
|
||||
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
||||
FS_ATTRIBUTE_INFORMATION);
|
||||
@ -436,7 +592,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
|
||||
if ((*full_path == 0) && tcon->valid_root_fid)
|
||||
if ((*full_path == 0) && tcon->crfid.is_valid)
|
||||
return 0;
|
||||
|
||||
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,
|
||||
struct smb_rqst *old_rq)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr =
|
||||
(struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base;
|
||||
(struct smb2_sync_hdr *)old_rq->rq_iov[0].iov_base;
|
||||
|
||||
memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
|
||||
tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
|
||||
@ -2171,14 +2327,13 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
|
||||
}
|
||||
|
||||
/* Assumes:
|
||||
* rqst->rq_iov[0] is rfc1002 length
|
||||
* rqst->rq_iov[1] is tranform header
|
||||
* rqst->rq_iov[2+] data to be encrypted/decrypted
|
||||
* rqst->rq_iov[0] is transform header
|
||||
* rqst->rq_iov[1+] data to be encrypted/decrypted
|
||||
*/
|
||||
static struct scatterlist *
|
||||
init_sg(struct smb_rqst *rqst, u8 *sign)
|
||||
{
|
||||
unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages;
|
||||
unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
struct scatterlist *sg;
|
||||
unsigned int i;
|
||||
@ -2189,10 +2344,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign)
|
||||
return NULL;
|
||||
|
||||
sg_init_table(sg, sg_len);
|
||||
smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len);
|
||||
for (i = 1; i < rqst->rq_nvec - 1; i++)
|
||||
smb2_sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base,
|
||||
rqst->rq_iov[i+1].iov_len);
|
||||
smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 20, assoc_data_len);
|
||||
for (i = 1; i < rqst->rq_nvec; i++)
|
||||
smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
|
||||
rqst->rq_iov[i].iov_len);
|
||||
for (j = 0; i < sg_len - 1; i++, j++) {
|
||||
unsigned int len, offset;
|
||||
|
||||
@ -2224,18 +2379,17 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Encrypt or decrypt @rqst message. @rqst has the following format:
|
||||
* iov[0] - rfc1002 length
|
||||
* iov[1] - transform header (associate data),
|
||||
* iov[2-N] and pages - data to encrypt.
|
||||
* On success return encrypted data in iov[2-N] and pages, leave iov[0-1]
|
||||
* Encrypt or decrypt @rqst message. @rqst[0] has the following format:
|
||||
* iov[0] - transform header (associate data),
|
||||
* iov[1-N] - SMB2 header and pages - data to encrypt.
|
||||
* On success return encrypted data in iov[1-N] and pages, leave iov[0]
|
||||
* untouched.
|
||||
*/
|
||||
static int
|
||||
crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
|
||||
{
|
||||
struct smb2_transform_hdr *tr_hdr =
|
||||
(struct smb2_transform_hdr *)rqst->rq_iov[1].iov_base;
|
||||
(struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
int rc = 0;
|
||||
struct scatterlist *sg;
|
||||
@ -2323,10 +2477,6 @@ free_req:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called from smb_send_rqst. At this point we have the rfc1002
|
||||
* header as the first element in the vector.
|
||||
*/
|
||||
static int
|
||||
smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
|
||||
struct smb_rqst *old_rq)
|
||||
@ -2335,7 +2485,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
|
||||
struct page **pages;
|
||||
struct smb2_transform_hdr *tr_hdr;
|
||||
unsigned int npages = old_rq->rq_npages;
|
||||
unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
|
||||
unsigned int orig_len;
|
||||
int i;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
@ -2355,18 +2505,14 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
|
||||
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),
|
||||
GFP_KERNEL);
|
||||
if (!iov)
|
||||
goto err_free_pages;
|
||||
|
||||
/* copy all iovs from the old except the 1st one (rfc1002 length) */
|
||||
memcpy(&iov[2], &old_rq->rq_iov[1],
|
||||
sizeof(struct kvec) * (old_rq->rq_nvec - 1));
|
||||
/* copy the rfc1002 iov */
|
||||
iov[0].iov_base = old_rq->rq_iov[0].iov_base;
|
||||
iov[0].iov_len = old_rq->rq_iov[0].iov_len;
|
||||
/* copy all iovs from the old */
|
||||
memcpy(&iov[1], &old_rq->rq_iov[0],
|
||||
sizeof(struct kvec) * old_rq->rq_nvec);
|
||||
|
||||
new_rq->rq_iov = iov;
|
||||
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,
|
||||
if (!tr_hdr)
|
||||
goto err_free_iov;
|
||||
|
||||
orig_len = smb2_rqst_len(old_rq, false);
|
||||
|
||||
/* fill the 2nd iov with a transform header */
|
||||
fill_transform_hdr(tr_hdr, orig_len, old_rq);
|
||||
new_rq->rq_iov[1].iov_base = tr_hdr;
|
||||
new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
|
||||
/* Update rfc1002 header */
|
||||
inc_rfc1001_len(new_rq->rq_iov[0].iov_base,
|
||||
sizeof(struct smb2_transform_hdr));
|
||||
new_rq->rq_iov[0].iov_base = tr_hdr;
|
||||
new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
|
||||
/* copy pages form the old */
|
||||
for (i = 0; i < npages; i++) {
|
||||
@ -2426,7 +2570,7 @@ smb3_free_transform_rq(struct smb_rqst *rqst)
|
||||
put_page(rqst->rq_pages[i]);
|
||||
kfree(rqst->rq_pages);
|
||||
/* free transform header */
|
||||
kfree(rqst->rq_iov[1].iov_base);
|
||||
kfree(rqst->rq_iov[0].iov_base);
|
||||
kfree(rqst->rq_iov);
|
||||
}
|
||||
|
||||
@ -2443,19 +2587,17 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
||||
unsigned int buf_data_size, struct page **pages,
|
||||
unsigned int npages, unsigned int page_data_size)
|
||||
{
|
||||
struct kvec iov[3];
|
||||
struct kvec iov[2];
|
||||
struct smb_rqst rqst = {NULL};
|
||||
int rc;
|
||||
|
||||
iov[0].iov_base = NULL;
|
||||
iov[0].iov_len = 0;
|
||||
iov[1].iov_base = buf;
|
||||
iov[1].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
iov[2].iov_base = buf + sizeof(struct smb2_transform_hdr);
|
||||
iov[2].iov_len = buf_data_size;
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
|
||||
iov[1].iov_len = buf_data_size;
|
||||
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 3;
|
||||
rqst.rq_nvec = 2;
|
||||
rqst.rq_pages = pages;
|
||||
rqst.rq_npages = npages;
|
||||
rqst.rq_pagesz = PAGE_SIZE;
|
||||
@ -2467,7 +2609,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
||||
if (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;
|
||||
|
||||
@ -3170,6 +3312,7 @@ struct smb_version_operations smb311_operations = {
|
||||
.set_compression = smb2_set_compression,
|
||||
.mkdir = smb2_mkdir,
|
||||
.mkdir_setinfo = smb2_mkdir_setinfo,
|
||||
.posix_mkdir = smb311_posix_mkdir,
|
||||
.rmdir = smb2_rmdir,
|
||||
.unlink = smb2_unlink,
|
||||
.rename = smb2_rename_path,
|
||||
|
@ -602,6 +602,7 @@ static void assemble_neg_contexts(struct smb2_negotiate_req *req,
|
||||
int
|
||||
SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_negotiate_req *req;
|
||||
struct smb2_negotiate_rsp *rsp;
|
||||
struct kvec iov[1];
|
||||
@ -673,7 +674,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
||||
iov[0].iov_base = (char *)req;
|
||||
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);
|
||||
rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base;
|
||||
/*
|
||||
@ -990,8 +995,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
|
||||
req->PreviousSessionId = sess_data->previous_session;
|
||||
|
||||
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 */
|
||||
if (server->sign)
|
||||
@ -1027,6 +1033,7 @@ static int
|
||||
SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
|
||||
{
|
||||
int rc;
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base;
|
||||
struct kvec rsp_iov = { NULL, 0 };
|
||||
|
||||
@ -1035,10 +1042,13 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
|
||||
cpu_to_le16(sizeof(struct smb2_sess_setup_req) - 1 /* pad */);
|
||||
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,
|
||||
sess_data->iov, 2,
|
||||
/* BB add code to build os and lm fields */
|
||||
rc = cifs_send_recv(sess_data->xid, sess_data->ses,
|
||||
&rqst,
|
||||
&sess_data->buf0_type,
|
||||
CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov);
|
||||
cifs_small_buf_release(sess_data->iov[0].iov_base);
|
||||
@ -1376,6 +1386,7 @@ out:
|
||||
int
|
||||
SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_logoff_req *req; /* response is also trivial struct */
|
||||
int rc = 0;
|
||||
struct TCP_Server_Info *server;
|
||||
@ -1413,7 +1424,11 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
|
||||
iov[0].iov_base = (char *)req;
|
||||
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);
|
||||
/*
|
||||
* No tcon so can't do
|
||||
@ -1443,6 +1458,7 @@ int
|
||||
SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
||||
struct cifs_tcon *tcon, const struct nls_table *cp)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_tree_connect_req *req;
|
||||
struct smb2_tree_connect_rsp *rsp = NULL;
|
||||
struct kvec iov[2];
|
||||
@ -1499,7 +1515,11 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
||||
!smb3_encryption_required(tcon))
|
||||
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);
|
||||
rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
|
||||
|
||||
@ -1563,6 +1583,7 @@ tcon_error_exit:
|
||||
int
|
||||
SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_tree_disconnect_req *req; /* response is trivial */
|
||||
int rc = 0;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
@ -1593,7 +1614,11 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
iov[0].iov_base = (char *)req;
|
||||
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);
|
||||
if (rc)
|
||||
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,
|
||||
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(©_path, ©_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
|
||||
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
__u8 *oplock, struct smb2_file_all_info *buf,
|
||||
struct kvec *err_iov, int *buftype)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_create_req *req;
|
||||
struct smb2_create_rsp *rsp;
|
||||
struct TCP_Server_Info *server;
|
||||
@ -2043,7 +2222,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
}
|
||||
#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);
|
||||
cifs_small_buf_release(req);
|
||||
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,
|
||||
char *in_data, u32 indatalen,
|
||||
char **out_data, u32 *plen /* returned data len */)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_ioctl_req *req;
|
||||
struct smb2_ioctl_rsp *rsp;
|
||||
struct cifs_ses *ses;
|
||||
@ -2189,7 +2373,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
||||
if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO)
|
||||
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);
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base;
|
||||
@ -2274,6 +2462,7 @@ int
|
||||
SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, int flags)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_close_req *req;
|
||||
struct smb2_close_rsp *rsp;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
@ -2301,7 +2490,11 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
iov[0].iov_base = (char *)req;
|
||||
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);
|
||||
rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
|
||||
|
||||
@ -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 *dlen)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_query_info_req *req;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
struct kvec iov[2];
|
||||
@ -2427,7 +2621,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
/* 1 for Buffer */
|
||||
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);
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||
|
||||
@ -2594,11 +2792,10 @@ SMB2_echo(struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb2_echo_req *req;
|
||||
int rc = 0;
|
||||
struct kvec iov[2];
|
||||
struct kvec iov[1];
|
||||
struct smb_rqst rqst = { .rq_iov = iov,
|
||||
.rq_nvec = 2 };
|
||||
.rq_nvec = 1 };
|
||||
unsigned int total_len;
|
||||
__be32 rfc1002_marker;
|
||||
|
||||
cifs_dbg(FYI, "In echo request\n");
|
||||
|
||||
@ -2614,11 +2811,8 @@ SMB2_echo(struct TCP_Server_Info *server)
|
||||
|
||||
req->sync_hdr.CreditRequest = cpu_to_le16(1);
|
||||
|
||||
iov[0].iov_len = 4;
|
||||
rfc1002_marker = cpu_to_be32(total_len);
|
||||
iov[0].iov_base = &rfc1002_marker;
|
||||
iov[1].iov_len = total_len;
|
||||
iov[1].iov_base = (char *)req;
|
||||
iov[0].iov_len = total_len;
|
||||
iov[0].iov_base = (char *)req;
|
||||
|
||||
rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL,
|
||||
server, CIFS_ECHO_OP);
|
||||
@ -2633,6 +2827,7 @@ int
|
||||
SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
||||
u64 volatile_fid)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_flush_req *req;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[1];
|
||||
@ -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_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);
|
||||
|
||||
if (rc != 0) {
|
||||
@ -2848,10 +3047,9 @@ smb2_async_readv(struct cifs_readdata *rdata)
|
||||
struct smb2_sync_hdr *shdr;
|
||||
struct cifs_io_parms io_parms;
|
||||
struct smb_rqst rqst = { .rq_iov = rdata->iov,
|
||||
.rq_nvec = 2 };
|
||||
.rq_nvec = 1 };
|
||||
struct TCP_Server_Info *server;
|
||||
unsigned int total_len;
|
||||
__be32 req_len;
|
||||
|
||||
cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
|
||||
__func__, rdata->offset, rdata->bytes);
|
||||
@ -2882,12 +3080,8 @@ smb2_async_readv(struct cifs_readdata *rdata)
|
||||
if (smb3_encryption_required(io_parms.tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req_len = cpu_to_be32(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;
|
||||
rdata->iov[0].iov_base = buf;
|
||||
rdata->iov[0].iov_len = total_len;
|
||||
|
||||
shdr = (struct smb2_sync_hdr *)buf;
|
||||
|
||||
@ -2926,6 +3120,7 @@ int
|
||||
SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
||||
unsigned int *nbytes, char **buf, int *buf_type)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
int resp_buftype, rc = -EACCES;
|
||||
struct smb2_read_plain_req *req = NULL;
|
||||
struct smb2_read_rsp *rsp = NULL;
|
||||
@ -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_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);
|
||||
|
||||
rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
|
||||
@ -3062,10 +3261,9 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
||||
struct smb2_sync_hdr *shdr;
|
||||
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct kvec iov[2];
|
||||
struct kvec iov[1];
|
||||
struct smb_rqst rqst = { };
|
||||
unsigned int total_len;
|
||||
__be32 rfc1002_marker;
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len);
|
||||
if (rc) {
|
||||
@ -3137,15 +3335,11 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
||||
v1->length = cpu_to_le32(wdata->mr->mr->length);
|
||||
}
|
||||
#endif
|
||||
/* 4 for rfc1002 length field and 1 for Buffer */
|
||||
iov[0].iov_len = 4;
|
||||
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;
|
||||
iov[0].iov_len = total_len - 1;
|
||||
iov[0].iov_base = (char *)req;
|
||||
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 2;
|
||||
rqst.rq_nvec = 1;
|
||||
rqst.rq_pages = wdata->pages;
|
||||
rqst.rq_offset = wdata->page_offset;
|
||||
rqst.rq_npages = wdata->nr_pages;
|
||||
@ -3153,7 +3347,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
||||
rqst.rq_tailsz = wdata->tailsz;
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
@ -3210,6 +3404,7 @@ int
|
||||
SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
|
||||
unsigned int *nbytes, struct kvec *iov, int n_vec)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
int rc = 0;
|
||||
struct smb2_write_req *req = NULL;
|
||||
struct smb2_write_rsp *rsp = NULL;
|
||||
@ -3251,7 +3446,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
|
||||
/* 1 for Buffer */
|
||||
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);
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
|
||||
@ -3323,6 +3522,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, int index,
|
||||
struct cifs_search_info *srch_inf)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_query_directory_req *req;
|
||||
struct smb2_query_directory_rsp *rsp = NULL;
|
||||
struct kvec iov[2];
|
||||
@ -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_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);
|
||||
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,
|
||||
u8 info_type, u32 additional_info, unsigned int num,
|
||||
void **data, unsigned int *size)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_set_info_req *req;
|
||||
struct smb2_set_info_rsp *rsp = NULL;
|
||||
struct kvec *iov;
|
||||
@ -3509,7 +3714,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
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);
|
||||
cifs_small_buf_release(req);
|
||||
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,
|
||||
const u64 persistent_fid, const u64 volatile_fid,
|
||||
__u8 oplock_level)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
int rc;
|
||||
struct smb2_oplock_break *req = NULL;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
@ -3692,7 +3902,11 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
iov[0].iov_base = (char *)req;
|
||||
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);
|
||||
|
||||
if (rc) {
|
||||
@ -3755,6 +3969,7 @@ int
|
||||
SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
struct kvec iov;
|
||||
struct kvec rsp_iov;
|
||||
@ -3773,7 +3988,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (smb3_encryption_required(tcon))
|
||||
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);
|
||||
if (rc) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
|
||||
@ -3798,6 +4017,7 @@ int
|
||||
SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, int level)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
struct kvec iov;
|
||||
struct kvec rsp_iov;
|
||||
@ -3829,7 +4049,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (smb3_encryption_required(tcon))
|
||||
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);
|
||||
if (rc) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
|
||||
@ -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 __u32 num_lock, struct smb2_lock_element *buf)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
int rc = 0;
|
||||
struct smb2_lock_req *req = NULL;
|
||||
struct kvec iov[2];
|
||||
@ -3900,7 +4125,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
iov[1].iov_len = count;
|
||||
|
||||
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);
|
||||
cifs_small_buf_release(req);
|
||||
if (rc) {
|
||||
@ -3934,6 +4164,7 @@ int
|
||||
SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
__u8 *lease_key, const __le32 lease_state)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
int rc;
|
||||
struct smb2_lease_ack *req = NULL;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
@ -3964,7 +4195,11 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
iov[0].iov_base = (char *)req;
|
||||
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);
|
||||
|
||||
if (rc) {
|
||||
|
@ -851,8 +851,11 @@ struct validate_negotiate_info_rsp {
|
||||
__le16 Dialect; /* Dialect in use for the connection */
|
||||
} __packed;
|
||||
|
||||
#define RSS_CAPABLE 0x00000001
|
||||
#define RDMA_CAPABLE 0x00000002
|
||||
#define RSS_CAPABLE cpu_to_le32(0x00000001)
|
||||
#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 {
|
||||
__le32 Next; /* next interface. zero if this is last one */
|
||||
@ -860,7 +863,21 @@ struct network_interface_info_ioctl_rsp {
|
||||
__le32 Capability; /* RSS or RDMA Capable */
|
||||
__le32 Reserved;
|
||||
__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;
|
||||
|
||||
#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,
|
||||
struct cifs_sb_info *cifs_sb, bool set_alloc);
|
||||
extern int smb2_set_file_info(struct inode *inode, const char *full_path,
|
||||
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,
|
||||
const char *name, struct cifs_sb_info *cifs_sb);
|
||||
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
|
||||
@ -109,6 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
|
||||
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
|
||||
extern void smb2_reconnect_server(struct work_struct *work);
|
||||
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
|
||||
|
@ -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 *sigptr = smb2_signature;
|
||||
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[iov_hdr_index].iov_base;
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
|
||||
struct cifs_ses *ses;
|
||||
|
||||
ses = smb2_find_smb_ses(server, shdr->SessionId);
|
||||
@ -204,7 +202,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr,
|
||||
rc = __cifs_calc_signature(rqst, server, sigptr,
|
||||
&server->secmech.sdeschmacsha256->shash);
|
||||
|
||||
if (!rc)
|
||||
@ -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 *sigptr = smb3_signature;
|
||||
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[iov_hdr_index].iov_base;
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
|
||||
struct cifs_ses *ses;
|
||||
|
||||
ses = smb2_find_smb_ses(server, shdr->SessionId);
|
||||
@ -447,7 +443,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr,
|
||||
rc = __cifs_calc_signature(rqst, server, sigptr,
|
||||
&server->secmech.sdesccmacaes->shash);
|
||||
|
||||
if (!rc)
|
||||
@ -462,7 +458,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc = 0;
|
||||
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) ||
|
||||
server->tcpStatus == CifsNeedNegotiate)
|
||||
@ -635,7 +631,7 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
|
||||
{
|
||||
int rc;
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
int rc;
|
||||
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;
|
||||
|
||||
smb2_seq_num_into_buf(server, shdr);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "smbdirect.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "cifsproto.h"
|
||||
#include "smb2proto.h"
|
||||
|
||||
static struct smbd_response *get_empty_queue_buffer(
|
||||
struct smbd_connection *info);
|
||||
@ -2087,7 +2088,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
|
||||
struct kvec vec;
|
||||
int nvecs;
|
||||
int size;
|
||||
unsigned int buflen = 0, remaining_data_length;
|
||||
unsigned int buflen, remaining_data_length;
|
||||
int start, i, j;
|
||||
int max_iov_size =
|
||||
info->max_send_size - sizeof(struct smbd_data_transfer);
|
||||
@ -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);
|
||||
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
|
||||
* rq_tailsz to PAGE_SIZE when the buffer has multiple pages and
|
||||
* ends at page boundary
|
||||
*/
|
||||
if (rqst->rq_npages) {
|
||||
if (rqst->rq_npages == 1)
|
||||
buflen += rqst->rq_tailsz;
|
||||
else
|
||||
buflen += rqst->rq_pagesz * (rqst->rq_npages - 1) -
|
||||
rqst->rq_offset + rqst->rq_tailsz;
|
||||
}
|
||||
buflen = smb2_rqst_len(rqst, true);
|
||||
|
||||
if (buflen + sizeof(struct smbd_data_transfer) >
|
||||
info->max_fragmented_send_size) {
|
||||
@ -2139,6 +2128,8 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
|
||||
goto done;
|
||||
}
|
||||
|
||||
iov = &rqst->rq_iov[1];
|
||||
|
||||
cifs_dbg(FYI, "Sending smb (RDMA): smb_len=%u\n", buflen);
|
||||
for (i = 0; i < rqst->rq_nvec-1; i++)
|
||||
dump_smb(iov[i].iov_base, iov[i].iov_len);
|
||||
|
@ -378,7 +378,7 @@ DEFINE_EVENT(smb3_open_err_class, smb3_##name, \
|
||||
TP_ARGS(xid, tid, sesid, create_options, desired_access, rc))
|
||||
|
||||
DEFINE_SMB3_OPEN_ERR_EVENT(open_err);
|
||||
|
||||
DEFINE_SMB3_OPEN_ERR_EVENT(posix_mkdir_err);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_open_done_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
@ -420,6 +420,7 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
|
||||
TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))
|
||||
|
||||
DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
|
||||
DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);
|
||||
|
||||
#endif /* _CIFS_TRACE_H */
|
||||
|
||||
|
@ -201,15 +201,24 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
rqst_len(struct smb_rqst *rqst)
|
||||
unsigned long
|
||||
smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker)
|
||||
{
|
||||
unsigned int i;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
struct kvec *iov;
|
||||
int nvec;
|
||||
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 */
|
||||
for (i = 0; i < rqst->rq_nvec; i++)
|
||||
for (i = 0; i < nvec; i++)
|
||||
buflen += iov[i].iov_len;
|
||||
|
||||
/*
|
||||
@ -236,18 +245,20 @@ rqst_len(struct smb_rqst *rqst)
|
||||
}
|
||||
|
||||
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;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
int n_vec = rqst->rq_nvec;
|
||||
unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
|
||||
unsigned long send_length;
|
||||
unsigned int i;
|
||||
int rc = 0;
|
||||
struct kvec *iov;
|
||||
int n_vec;
|
||||
unsigned int send_length = 0;
|
||||
unsigned int i, j;
|
||||
size_t total_len = 0, sent, size;
|
||||
struct socket *ssocket = server->ssocket;
|
||||
struct msghdr smb_msg;
|
||||
int val = 1;
|
||||
__be32 rfc1002_marker;
|
||||
|
||||
if (cifs_rdma_enabled(server) && server->smbd_conn) {
|
||||
rc = smbd_send(server->smbd_conn, rqst);
|
||||
goto smbd_done;
|
||||
@ -255,51 +266,67 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
||||
if (ssocket == NULL)
|
||||
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 */
|
||||
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
|
||||
(char *)&val, sizeof(val));
|
||||
|
||||
size = 0;
|
||||
for (i = 0; i < n_vec; i++)
|
||||
size += iov[i].iov_len;
|
||||
for (j = 0; j < num_rqst; j++)
|
||||
send_length += smb2_rqst_len(&rqst[j], true);
|
||||
rfc1002_marker = cpu_to_be32(send_length);
|
||||
|
||||
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov, n_vec, size);
|
||||
|
||||
rc = smb_send_kvec(server, &smb_msg, &sent);
|
||||
if (rc < 0)
|
||||
goto uncork;
|
||||
|
||||
total_len += sent;
|
||||
|
||||
/* now walk the page array and send each page in it */
|
||||
for (i = 0; i < rqst->rq_npages; i++) {
|
||||
struct bio_vec bvec;
|
||||
|
||||
bvec.bv_page = rqst->rq_pages[i];
|
||||
rqst_page_get_length(rqst, i, &bvec.bv_len, &bvec.bv_offset);
|
||||
|
||||
iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC,
|
||||
&bvec, 1, bvec.bv_len);
|
||||
/* 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)
|
||||
break;
|
||||
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;
|
||||
for (i = 0; i < n_vec; i++) {
|
||||
dump_smb(iov[i].iov_base, iov[i].iov_len);
|
||||
size += iov[i].iov_len;
|
||||
}
|
||||
|
||||
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC,
|
||||
iov, n_vec, size);
|
||||
|
||||
rc = smb_send_kvec(server, &smb_msg, &sent);
|
||||
if (rc < 0)
|
||||
goto uncork;
|
||||
|
||||
total_len += sent;
|
||||
|
||||
/* now walk the page array and send each page in it */
|
||||
for (i = 0; i < rqst[j].rq_npages; i++) {
|
||||
struct bio_vec bvec;
|
||||
|
||||
bvec.bv_page = rqst[j].rq_pages[i];
|
||||
rqst_page_get_length(&rqst[j], i, &bvec.bv_len,
|
||||
&bvec.bv_offset);
|
||||
|
||||
iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC,
|
||||
&bvec, 1, bvec.bv_len);
|
||||
rc = smb_send_kvec(server, &smb_msg, &sent);
|
||||
if (rc < 0)
|
||||
break;
|
||||
|
||||
total_len += sent;
|
||||
}
|
||||
}
|
||||
|
||||
uncork:
|
||||
@ -308,9 +335,9 @@ uncork:
|
||||
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
|
||||
(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",
|
||||
smb_buf_length + 4, total_len);
|
||||
send_length, total_len);
|
||||
/*
|
||||
* 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
|
||||
@ -335,7 +362,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
|
||||
int rc;
|
||||
|
||||
if (!(flags & CIFS_TRANSFORM_REQ))
|
||||
return __smb_send_rqst(server, rqst);
|
||||
return __smb_send_rqst(server, 1, rqst);
|
||||
|
||||
if (!server->ops->init_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)
|
||||
if (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);
|
||||
return rc;
|
||||
}
|
||||
@ -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_len = smb_buf_length;
|
||||
|
||||
return __smb_send_rqst(server, &rqst);
|
||||
return __smb_send_rqst(server, 1, &rqst);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -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
|
||||
* use ses->maxReq.
|
||||
*/
|
||||
|
||||
rc = wait_for_free_request(ses->server, timeout, optype);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -766,8 +792,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
|
||||
smb311_update_preauth_hash(ses, rqst->rq_iov+1,
|
||||
rqst->rq_nvec-1);
|
||||
smb311_update_preauth_hash(ses, rqst->rq_iov,
|
||||
rqst->rq_nvec);
|
||||
#endif
|
||||
|
||||
if (timeout == CIFS_ASYNC_OP)
|
||||
@ -812,8 +838,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
|
||||
struct kvec iov = {
|
||||
.iov_base = buf,
|
||||
.iov_len = midQ->resp_buf_size
|
||||
.iov_base = resp_iov->iov_base,
|
||||
.iov_len = resp_iov->iov_len
|
||||
};
|
||||
smb311_update_preauth_hash(ses, &iov, 1);
|
||||
}
|
||||
@ -872,49 +898,6 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
|
||||
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
|
||||
SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct smb_hdr *in_buf, struct smb_hdr *out_buf,
|
||||
|
Loading…
Reference in New Issue
Block a user