162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *   Copyright (C) International Business Machines  Corp., 2002,2010
562306a36Sopenharmony_ci *   Author(s): Steve French (sfrench@us.ibm.com)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *   Contains the routines for constructing the SMB PDUs themselves
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
1262306a36Sopenharmony_ci /* These are mostly routines that operate on a pathname, or on a tree id     */
1362306a36Sopenharmony_ci /* (mounted volume), but there are eight handle based routines which must be */
1462306a36Sopenharmony_ci /* treated slightly differently for reconnection purposes since we never     */
1562306a36Sopenharmony_ci /* want to reuse a stale file handle and only the caller knows the file info */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/fs.h>
1862306a36Sopenharmony_ci#include <linux/filelock.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/vfs.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h>
2362306a36Sopenharmony_ci#include <linux/pagemap.h>
2462306a36Sopenharmony_ci#include <linux/swap.h>
2562306a36Sopenharmony_ci#include <linux/task_io_accounting_ops.h>
2662306a36Sopenharmony_ci#include <linux/uaccess.h>
2762306a36Sopenharmony_ci#include "cifspdu.h"
2862306a36Sopenharmony_ci#include "cifsfs.h"
2962306a36Sopenharmony_ci#include "cifsglob.h"
3062306a36Sopenharmony_ci#include "cifsacl.h"
3162306a36Sopenharmony_ci#include "cifsproto.h"
3262306a36Sopenharmony_ci#include "cifs_unicode.h"
3362306a36Sopenharmony_ci#include "cifs_debug.h"
3462306a36Sopenharmony_ci#include "fscache.h"
3562306a36Sopenharmony_ci#include "smbdirect.h"
3662306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL
3762306a36Sopenharmony_ci#include "dfs_cache.h"
3862306a36Sopenharmony_ci#endif
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX
4162306a36Sopenharmony_cistatic struct {
4262306a36Sopenharmony_ci	int index;
4362306a36Sopenharmony_ci	char *name;
4462306a36Sopenharmony_ci} protocols[] = {
4562306a36Sopenharmony_ci	{CIFS_PROT, "\2NT LM 0.12"},
4662306a36Sopenharmony_ci	{POSIX_PROT, "\2POSIX 2"},
4762306a36Sopenharmony_ci	{BAD_PROT, "\2"}
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci#else
5062306a36Sopenharmony_cistatic struct {
5162306a36Sopenharmony_ci	int index;
5262306a36Sopenharmony_ci	char *name;
5362306a36Sopenharmony_ci} protocols[] = {
5462306a36Sopenharmony_ci	{CIFS_PROT, "\2NT LM 0.12"},
5562306a36Sopenharmony_ci	{BAD_PROT, "\2"}
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci#endif
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* define the number of elements in the cifs dialect array */
6062306a36Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX
6162306a36Sopenharmony_ci#define CIFS_NUM_PROT 2
6262306a36Sopenharmony_ci#else /* not posix */
6362306a36Sopenharmony_ci#define CIFS_NUM_PROT 1
6462306a36Sopenharmony_ci#endif /* CIFS_POSIX */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* reconnect the socket, tcon, and smb session if needed */
6862306a36Sopenharmony_cistatic int
6962306a36Sopenharmony_cicifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	int rc;
7262306a36Sopenharmony_ci	struct cifs_ses *ses;
7362306a36Sopenharmony_ci	struct TCP_Server_Info *server;
7462306a36Sopenharmony_ci	struct nls_table *nls_codepage = NULL;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/*
7762306a36Sopenharmony_ci	 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
7862306a36Sopenharmony_ci	 * tcp and smb session status done differently for those three - in the
7962306a36Sopenharmony_ci	 * calling routine
8062306a36Sopenharmony_ci	 */
8162306a36Sopenharmony_ci	if (!tcon)
8262306a36Sopenharmony_ci		return 0;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	ses = tcon->ses;
8562306a36Sopenharmony_ci	server = ses->server;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/*
8862306a36Sopenharmony_ci	 * only tree disconnect, open, and write, (and ulogoff which does not
8962306a36Sopenharmony_ci	 * have tcon) are allowed as we start umount
9062306a36Sopenharmony_ci	 */
9162306a36Sopenharmony_ci	spin_lock(&tcon->tc_lock);
9262306a36Sopenharmony_ci	if (tcon->status == TID_EXITING) {
9362306a36Sopenharmony_ci		if (smb_command != SMB_COM_TREE_DISCONNECT) {
9462306a36Sopenharmony_ci			spin_unlock(&tcon->tc_lock);
9562306a36Sopenharmony_ci			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
9662306a36Sopenharmony_ci				 smb_command);
9762306a36Sopenharmony_ci			return -ENODEV;
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	spin_unlock(&tcon->tc_lock);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciagain:
10362306a36Sopenharmony_ci	rc = cifs_wait_for_server_reconnect(server, tcon->retry);
10462306a36Sopenharmony_ci	if (rc)
10562306a36Sopenharmony_ci		return rc;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	spin_lock(&ses->chan_lock);
10862306a36Sopenharmony_ci	if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {
10962306a36Sopenharmony_ci		spin_unlock(&ses->chan_lock);
11062306a36Sopenharmony_ci		return 0;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	spin_unlock(&ses->chan_lock);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	mutex_lock(&ses->session_mutex);
11562306a36Sopenharmony_ci	/*
11662306a36Sopenharmony_ci	 * Recheck after acquire mutex. If another thread is negotiating
11762306a36Sopenharmony_ci	 * and the server never sends an answer the socket will be closed
11862306a36Sopenharmony_ci	 * and tcpStatus set to reconnect.
11962306a36Sopenharmony_ci	 */
12062306a36Sopenharmony_ci	spin_lock(&server->srv_lock);
12162306a36Sopenharmony_ci	if (server->tcpStatus == CifsNeedReconnect) {
12262306a36Sopenharmony_ci		spin_unlock(&server->srv_lock);
12362306a36Sopenharmony_ci		mutex_unlock(&ses->session_mutex);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		if (tcon->retry)
12662306a36Sopenharmony_ci			goto again;
12762306a36Sopenharmony_ci		rc = -EHOSTDOWN;
12862306a36Sopenharmony_ci		goto out;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci	spin_unlock(&server->srv_lock);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	nls_codepage = ses->local_nls;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/*
13562306a36Sopenharmony_ci	 * need to prevent multiple threads trying to simultaneously
13662306a36Sopenharmony_ci	 * reconnect the same SMB session
13762306a36Sopenharmony_ci	 */
13862306a36Sopenharmony_ci	spin_lock(&ses->ses_lock);
13962306a36Sopenharmony_ci	spin_lock(&ses->chan_lock);
14062306a36Sopenharmony_ci	if (!cifs_chan_needs_reconnect(ses, server) &&
14162306a36Sopenharmony_ci	    ses->ses_status == SES_GOOD) {
14262306a36Sopenharmony_ci		spin_unlock(&ses->chan_lock);
14362306a36Sopenharmony_ci		spin_unlock(&ses->ses_lock);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci		/* this means that we only need to tree connect */
14662306a36Sopenharmony_ci		if (tcon->need_reconnect)
14762306a36Sopenharmony_ci			goto skip_sess_setup;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		mutex_unlock(&ses->session_mutex);
15062306a36Sopenharmony_ci		goto out;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci	spin_unlock(&ses->chan_lock);
15362306a36Sopenharmony_ci	spin_unlock(&ses->ses_lock);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	rc = cifs_negotiate_protocol(0, ses, server);
15662306a36Sopenharmony_ci	if (!rc)
15762306a36Sopenharmony_ci		rc = cifs_setup_session(0, ses, server, nls_codepage);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* do we need to reconnect tcon? */
16062306a36Sopenharmony_ci	if (rc || !tcon->need_reconnect) {
16162306a36Sopenharmony_ci		mutex_unlock(&ses->session_mutex);
16262306a36Sopenharmony_ci		goto out;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciskip_sess_setup:
16662306a36Sopenharmony_ci	cifs_mark_open_files_invalid(tcon);
16762306a36Sopenharmony_ci	rc = cifs_tree_connect(0, tcon, nls_codepage);
16862306a36Sopenharmony_ci	mutex_unlock(&ses->session_mutex);
16962306a36Sopenharmony_ci	cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (rc) {
17262306a36Sopenharmony_ci		pr_warn_once("reconnect tcon failed rc = %d\n", rc);
17362306a36Sopenharmony_ci		goto out;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	atomic_inc(&tconInfoReconnectCount);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* tell server Unix caps we support */
17962306a36Sopenharmony_ci	if (cap_unix(ses))
18062306a36Sopenharmony_ci		reset_cifs_unix_caps(0, tcon, NULL, NULL);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/*
18362306a36Sopenharmony_ci	 * Removed call to reopen open files here. It is safer (and faster) to
18462306a36Sopenharmony_ci	 * reopen files one at a time as needed in read and write.
18562306a36Sopenharmony_ci	 *
18662306a36Sopenharmony_ci	 * FIXME: what about file locks? don't we need to reclaim them ASAP?
18762306a36Sopenharmony_ci	 */
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ciout:
19062306a36Sopenharmony_ci	/*
19162306a36Sopenharmony_ci	 * Check if handle based operation so we know whether we can continue
19262306a36Sopenharmony_ci	 * or not without returning to caller to reset file handle
19362306a36Sopenharmony_ci	 */
19462306a36Sopenharmony_ci	switch (smb_command) {
19562306a36Sopenharmony_ci	case SMB_COM_READ_ANDX:
19662306a36Sopenharmony_ci	case SMB_COM_WRITE_ANDX:
19762306a36Sopenharmony_ci	case SMB_COM_CLOSE:
19862306a36Sopenharmony_ci	case SMB_COM_FIND_CLOSE2:
19962306a36Sopenharmony_ci	case SMB_COM_LOCKING_ANDX:
20062306a36Sopenharmony_ci		rc = -EAGAIN;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return rc;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/* Allocate and return pointer to an SMB request buffer, and set basic
20762306a36Sopenharmony_ci   SMB information in the SMB header.  If the return code is zero, this
20862306a36Sopenharmony_ci   function must have filled in request_buf pointer */
20962306a36Sopenharmony_cistatic int
21062306a36Sopenharmony_cismall_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
21162306a36Sopenharmony_ci		void **request_buf)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	int rc;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	rc = cifs_reconnect_tcon(tcon, smb_command);
21662306a36Sopenharmony_ci	if (rc)
21762306a36Sopenharmony_ci		return rc;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	*request_buf = cifs_small_buf_get();
22062306a36Sopenharmony_ci	if (*request_buf == NULL) {
22162306a36Sopenharmony_ci		/* BB should we add a retry in here if not a writepage? */
22262306a36Sopenharmony_ci		return -ENOMEM;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	header_assemble((struct smb_hdr *) *request_buf, smb_command,
22662306a36Sopenharmony_ci			tcon, wct);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (tcon != NULL)
22962306a36Sopenharmony_ci		cifs_stats_inc(&tcon->num_smbs_sent);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciint
23562306a36Sopenharmony_cismall_smb_init_no_tc(const int smb_command, const int wct,
23662306a36Sopenharmony_ci		     struct cifs_ses *ses, void **request_buf)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	int rc;
23962306a36Sopenharmony_ci	struct smb_hdr *buffer;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	rc = small_smb_init(smb_command, wct, NULL, request_buf);
24262306a36Sopenharmony_ci	if (rc)
24362306a36Sopenharmony_ci		return rc;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	buffer = (struct smb_hdr *)*request_buf;
24662306a36Sopenharmony_ci	buffer->Mid = get_next_mid(ses->server);
24762306a36Sopenharmony_ci	if (ses->capabilities & CAP_UNICODE)
24862306a36Sopenharmony_ci		buffer->Flags2 |= SMBFLG2_UNICODE;
24962306a36Sopenharmony_ci	if (ses->capabilities & CAP_STATUS32)
25062306a36Sopenharmony_ci		buffer->Flags2 |= SMBFLG2_ERR_STATUS;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	/* uid, tid can stay at zero as set in header assemble */
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* BB add support for turning on the signing when
25562306a36Sopenharmony_ci	this function is used after 1st of session setup requests */
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return rc;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/* If the return code is zero, this function must fill in request_buf pointer */
26162306a36Sopenharmony_cistatic int
26262306a36Sopenharmony_ci__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
26362306a36Sopenharmony_ci			void **request_buf, void **response_buf)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	*request_buf = cifs_buf_get();
26662306a36Sopenharmony_ci	if (*request_buf == NULL) {
26762306a36Sopenharmony_ci		/* BB should we add a retry in here if not a writepage? */
26862306a36Sopenharmony_ci		return -ENOMEM;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci    /* Although the original thought was we needed the response buf for  */
27162306a36Sopenharmony_ci    /* potential retries of smb operations it turns out we can determine */
27262306a36Sopenharmony_ci    /* from the mid flags when the request buffer can be resent without  */
27362306a36Sopenharmony_ci    /* having to use a second distinct buffer for the response */
27462306a36Sopenharmony_ci	if (response_buf)
27562306a36Sopenharmony_ci		*response_buf = *request_buf;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
27862306a36Sopenharmony_ci			wct);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (tcon != NULL)
28162306a36Sopenharmony_ci		cifs_stats_inc(&tcon->num_smbs_sent);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return 0;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci/* If the return code is zero, this function must fill in request_buf pointer */
28762306a36Sopenharmony_cistatic int
28862306a36Sopenharmony_cismb_init(int smb_command, int wct, struct cifs_tcon *tcon,
28962306a36Sopenharmony_ci	 void **request_buf, void **response_buf)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	int rc;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	rc = cifs_reconnect_tcon(tcon, smb_command);
29462306a36Sopenharmony_ci	if (rc)
29562306a36Sopenharmony_ci		return rc;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int
30162306a36Sopenharmony_cismb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
30262306a36Sopenharmony_ci			void **request_buf, void **response_buf)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	spin_lock(&tcon->ses->chan_lock);
30562306a36Sopenharmony_ci	if (cifs_chan_needs_reconnect(tcon->ses, tcon->ses->server) ||
30662306a36Sopenharmony_ci	    tcon->need_reconnect) {
30762306a36Sopenharmony_ci		spin_unlock(&tcon->ses->chan_lock);
30862306a36Sopenharmony_ci		return -EHOSTDOWN;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci	spin_unlock(&tcon->ses->chan_lock);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int validate_t2(struct smb_t2_rsp *pSMB)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	unsigned int total_size;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* check for plausible wct */
32062306a36Sopenharmony_ci	if (pSMB->hdr.WordCount < 10)
32162306a36Sopenharmony_ci		goto vt2_err;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* check for parm and data offset going beyond end of smb */
32462306a36Sopenharmony_ci	if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
32562306a36Sopenharmony_ci	    get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
32662306a36Sopenharmony_ci		goto vt2_err;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
32962306a36Sopenharmony_ci	if (total_size >= 512)
33062306a36Sopenharmony_ci		goto vt2_err;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* check that bcc is at least as big as parms + data, and that it is
33362306a36Sopenharmony_ci	 * less than negotiated smb buffer
33462306a36Sopenharmony_ci	 */
33562306a36Sopenharmony_ci	total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
33662306a36Sopenharmony_ci	if (total_size > get_bcc(&pSMB->hdr) ||
33762306a36Sopenharmony_ci	    total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
33862306a36Sopenharmony_ci		goto vt2_err;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_civt2_err:
34262306a36Sopenharmony_ci	cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
34362306a36Sopenharmony_ci		sizeof(struct smb_t2_rsp) + 16);
34462306a36Sopenharmony_ci	return -EINVAL;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int
34862306a36Sopenharmony_cidecode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	int	rc = 0;
35162306a36Sopenharmony_ci	u16	count;
35262306a36Sopenharmony_ci	char	*guid = pSMBr->u.extended_response.GUID;
35362306a36Sopenharmony_ci	struct TCP_Server_Info *server = ses->server;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	count = get_bcc(&pSMBr->hdr);
35662306a36Sopenharmony_ci	if (count < SMB1_CLIENT_GUID_SIZE)
35762306a36Sopenharmony_ci		return -EIO;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	spin_lock(&cifs_tcp_ses_lock);
36062306a36Sopenharmony_ci	if (server->srv_count > 1) {
36162306a36Sopenharmony_ci		spin_unlock(&cifs_tcp_ses_lock);
36262306a36Sopenharmony_ci		if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
36362306a36Sopenharmony_ci			cifs_dbg(FYI, "server UID changed\n");
36462306a36Sopenharmony_ci			memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
36562306a36Sopenharmony_ci		}
36662306a36Sopenharmony_ci	} else {
36762306a36Sopenharmony_ci		spin_unlock(&cifs_tcp_ses_lock);
36862306a36Sopenharmony_ci		memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (count == SMB1_CLIENT_GUID_SIZE) {
37262306a36Sopenharmony_ci		server->sec_ntlmssp = true;
37362306a36Sopenharmony_ci	} else {
37462306a36Sopenharmony_ci		count -= SMB1_CLIENT_GUID_SIZE;
37562306a36Sopenharmony_ci		rc = decode_negTokenInit(
37662306a36Sopenharmony_ci			pSMBr->u.extended_response.SecurityBlob, count, server);
37762306a36Sopenharmony_ci		if (rc != 1)
37862306a36Sopenharmony_ci			return -EINVAL;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic bool
38562306a36Sopenharmony_cishould_set_ext_sec_flag(enum securityEnum sectype)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	switch (sectype) {
38862306a36Sopenharmony_ci	case RawNTLMSSP:
38962306a36Sopenharmony_ci	case Kerberos:
39062306a36Sopenharmony_ci		return true;
39162306a36Sopenharmony_ci	case Unspecified:
39262306a36Sopenharmony_ci		if (global_secflags &
39362306a36Sopenharmony_ci		    (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
39462306a36Sopenharmony_ci			return true;
39562306a36Sopenharmony_ci		fallthrough;
39662306a36Sopenharmony_ci	default:
39762306a36Sopenharmony_ci		return false;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ciint
40262306a36Sopenharmony_ciCIFSSMBNegotiate(const unsigned int xid,
40362306a36Sopenharmony_ci		 struct cifs_ses *ses,
40462306a36Sopenharmony_ci		 struct TCP_Server_Info *server)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	NEGOTIATE_REQ *pSMB;
40762306a36Sopenharmony_ci	NEGOTIATE_RSP *pSMBr;
40862306a36Sopenharmony_ci	int rc = 0;
40962306a36Sopenharmony_ci	int bytes_returned;
41062306a36Sopenharmony_ci	int i;
41162306a36Sopenharmony_ci	u16 count;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (!server) {
41462306a36Sopenharmony_ci		WARN(1, "%s: server is NULL!\n", __func__);
41562306a36Sopenharmony_ci		return -EIO;
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
41962306a36Sopenharmony_ci		      (void **) &pSMB, (void **) &pSMBr);
42062306a36Sopenharmony_ci	if (rc)
42162306a36Sopenharmony_ci		return rc;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	pSMB->hdr.Mid = get_next_mid(server);
42462306a36Sopenharmony_ci	pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (should_set_ext_sec_flag(ses->sectype)) {
42762306a36Sopenharmony_ci		cifs_dbg(FYI, "Requesting extended security\n");
42862306a36Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	count = 0;
43262306a36Sopenharmony_ci	/*
43362306a36Sopenharmony_ci	 * We know that all the name entries in the protocols array
43462306a36Sopenharmony_ci	 * are short (< 16 bytes anyway) and are NUL terminated.
43562306a36Sopenharmony_ci	 */
43662306a36Sopenharmony_ci	for (i = 0; i < CIFS_NUM_PROT; i++) {
43762306a36Sopenharmony_ci		size_t len = strlen(protocols[i].name) + 1;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		memcpy(&pSMB->DialectsArray[count], protocols[i].name, len);
44062306a36Sopenharmony_ci		count += len;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
44362306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
44662306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
44762306a36Sopenharmony_ci	if (rc != 0)
44862306a36Sopenharmony_ci		goto neg_err_exit;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	server->dialect = le16_to_cpu(pSMBr->DialectIndex);
45162306a36Sopenharmony_ci	cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
45262306a36Sopenharmony_ci	/* Check wct = 1 error case */
45362306a36Sopenharmony_ci	if ((pSMBr->hdr.WordCount <= 13) || (server->dialect == BAD_PROT)) {
45462306a36Sopenharmony_ci		/* core returns wct = 1, but we do not ask for core - otherwise
45562306a36Sopenharmony_ci		small wct just comes when dialect index is -1 indicating we
45662306a36Sopenharmony_ci		could not negotiate a common dialect */
45762306a36Sopenharmony_ci		rc = -EOPNOTSUPP;
45862306a36Sopenharmony_ci		goto neg_err_exit;
45962306a36Sopenharmony_ci	} else if (pSMBr->hdr.WordCount != 17) {
46062306a36Sopenharmony_ci		/* unknown wct */
46162306a36Sopenharmony_ci		rc = -EOPNOTSUPP;
46262306a36Sopenharmony_ci		goto neg_err_exit;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci	/* else wct == 17, NTLM or better */
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	server->sec_mode = pSMBr->SecurityMode;
46762306a36Sopenharmony_ci	if ((server->sec_mode & SECMODE_USER) == 0)
46862306a36Sopenharmony_ci		cifs_dbg(FYI, "share mode security\n");
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* one byte, so no need to convert this or EncryptionKeyLen from
47162306a36Sopenharmony_ci	   little endian */
47262306a36Sopenharmony_ci	server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
47362306a36Sopenharmony_ci			       cifs_max_pending);
47462306a36Sopenharmony_ci	set_credits(server, server->maxReq);
47562306a36Sopenharmony_ci	/* probably no need to store and check maxvcs */
47662306a36Sopenharmony_ci	server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
47762306a36Sopenharmony_ci	/* set up max_read for readahead check */
47862306a36Sopenharmony_ci	server->max_read = server->maxBuf;
47962306a36Sopenharmony_ci	server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
48062306a36Sopenharmony_ci	cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
48162306a36Sopenharmony_ci	server->capabilities = le32_to_cpu(pSMBr->Capabilities);
48262306a36Sopenharmony_ci	server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
48362306a36Sopenharmony_ci	server->timeAdj *= 60;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
48662306a36Sopenharmony_ci		server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
48762306a36Sopenharmony_ci		memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
48862306a36Sopenharmony_ci		       CIFS_CRYPTO_KEY_SIZE);
48962306a36Sopenharmony_ci	} else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
49062306a36Sopenharmony_ci			server->capabilities & CAP_EXTENDED_SECURITY) {
49162306a36Sopenharmony_ci		server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
49262306a36Sopenharmony_ci		rc = decode_ext_sec_blob(ses, pSMBr);
49362306a36Sopenharmony_ci	} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
49462306a36Sopenharmony_ci		rc = -EIO; /* no crypt key only if plain text pwd */
49562306a36Sopenharmony_ci	} else {
49662306a36Sopenharmony_ci		server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
49762306a36Sopenharmony_ci		server->capabilities &= ~CAP_EXTENDED_SECURITY;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (!rc)
50162306a36Sopenharmony_ci		rc = cifs_enable_signing(server, ses->sign);
50262306a36Sopenharmony_cineg_err_exit:
50362306a36Sopenharmony_ci	cifs_buf_release(pSMB);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	cifs_dbg(FYI, "negprot rc %d\n", rc);
50662306a36Sopenharmony_ci	return rc;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ciint
51062306a36Sopenharmony_ciCIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct smb_hdr *smb_buffer;
51362306a36Sopenharmony_ci	int rc = 0;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	cifs_dbg(FYI, "In tree disconnect\n");
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* BB: do we need to check this? These should never be NULL. */
51862306a36Sopenharmony_ci	if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
51962306a36Sopenharmony_ci		return -EIO;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/*
52262306a36Sopenharmony_ci	 * No need to return error on this operation if tid invalidated and
52362306a36Sopenharmony_ci	 * closed on server already e.g. due to tcp session crashing. Also,
52462306a36Sopenharmony_ci	 * the tcon is no longer on the list, so no need to take lock before
52562306a36Sopenharmony_ci	 * checking this.
52662306a36Sopenharmony_ci	 */
52762306a36Sopenharmony_ci	spin_lock(&tcon->ses->chan_lock);
52862306a36Sopenharmony_ci	if ((tcon->need_reconnect) || CIFS_ALL_CHANS_NEED_RECONNECT(tcon->ses)) {
52962306a36Sopenharmony_ci		spin_unlock(&tcon->ses->chan_lock);
53062306a36Sopenharmony_ci		return -EIO;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci	spin_unlock(&tcon->ses->chan_lock);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
53562306a36Sopenharmony_ci			    (void **)&smb_buffer);
53662306a36Sopenharmony_ci	if (rc)
53762306a36Sopenharmony_ci		return rc;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
54062306a36Sopenharmony_ci	cifs_small_buf_release(smb_buffer);
54162306a36Sopenharmony_ci	if (rc)
54262306a36Sopenharmony_ci		cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* No need to return error on this operation if tid invalidated and
54562306a36Sopenharmony_ci	   closed on server already e.g. due to tcp session crashing */
54662306a36Sopenharmony_ci	if (rc == -EAGAIN)
54762306a36Sopenharmony_ci		rc = 0;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	return rc;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci/*
55362306a36Sopenharmony_ci * This is a no-op for now. We're not really interested in the reply, but
55462306a36Sopenharmony_ci * rather in the fact that the server sent one and that server->lstrp
55562306a36Sopenharmony_ci * gets updated.
55662306a36Sopenharmony_ci *
55762306a36Sopenharmony_ci * FIXME: maybe we should consider checking that the reply matches request?
55862306a36Sopenharmony_ci */
55962306a36Sopenharmony_cistatic void
56062306a36Sopenharmony_cicifs_echo_callback(struct mid_q_entry *mid)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct TCP_Server_Info *server = mid->callback_data;
56362306a36Sopenharmony_ci	struct cifs_credits credits = { .value = 1, .instance = 0 };
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	release_mid(mid);
56662306a36Sopenharmony_ci	add_credits(server, &credits, CIFS_ECHO_OP);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ciint
57062306a36Sopenharmony_ciCIFSSMBEcho(struct TCP_Server_Info *server)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	ECHO_REQ *smb;
57362306a36Sopenharmony_ci	int rc = 0;
57462306a36Sopenharmony_ci	struct kvec iov[2];
57562306a36Sopenharmony_ci	struct smb_rqst rqst = { .rq_iov = iov,
57662306a36Sopenharmony_ci				 .rq_nvec = 2 };
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	cifs_dbg(FYI, "In echo request\n");
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
58162306a36Sopenharmony_ci	if (rc)
58262306a36Sopenharmony_ci		return rc;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (server->capabilities & CAP_UNICODE)
58562306a36Sopenharmony_ci		smb->hdr.Flags2 |= SMBFLG2_UNICODE;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* set up echo request */
58862306a36Sopenharmony_ci	smb->hdr.Tid = 0xffff;
58962306a36Sopenharmony_ci	smb->hdr.WordCount = 1;
59062306a36Sopenharmony_ci	put_unaligned_le16(1, &smb->EchoCount);
59162306a36Sopenharmony_ci	put_bcc(1, &smb->hdr);
59262306a36Sopenharmony_ci	smb->Data[0] = 'a';
59362306a36Sopenharmony_ci	inc_rfc1001_len(smb, 3);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	iov[0].iov_len = 4;
59662306a36Sopenharmony_ci	iov[0].iov_base = smb;
59762306a36Sopenharmony_ci	iov[1].iov_len = get_rfc1002_length(smb);
59862306a36Sopenharmony_ci	iov[1].iov_base = (char *)smb + 4;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
60162306a36Sopenharmony_ci			     server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
60262306a36Sopenharmony_ci	if (rc)
60362306a36Sopenharmony_ci		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	cifs_small_buf_release(smb);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	return rc;
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ciint
61162306a36Sopenharmony_ciCIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	LOGOFF_ANDX_REQ *pSMB;
61462306a36Sopenharmony_ci	int rc = 0;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/*
61962306a36Sopenharmony_ci	 * BB: do we need to check validity of ses and server? They should
62062306a36Sopenharmony_ci	 * always be valid since we have an active reference. If not, that
62162306a36Sopenharmony_ci	 * should probably be a BUG()
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci	if (!ses || !ses->server)
62462306a36Sopenharmony_ci		return -EIO;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	mutex_lock(&ses->session_mutex);
62762306a36Sopenharmony_ci	spin_lock(&ses->chan_lock);
62862306a36Sopenharmony_ci	if (CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
62962306a36Sopenharmony_ci		spin_unlock(&ses->chan_lock);
63062306a36Sopenharmony_ci		goto session_already_dead; /* no need to send SMBlogoff if uid
63162306a36Sopenharmony_ci					      already closed due to reconnect */
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci	spin_unlock(&ses->chan_lock);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
63662306a36Sopenharmony_ci	if (rc) {
63762306a36Sopenharmony_ci		mutex_unlock(&ses->session_mutex);
63862306a36Sopenharmony_ci		return rc;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	pSMB->hdr.Mid = get_next_mid(ses->server);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (ses->server->sign)
64462306a36Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	pSMB->hdr.Uid = ses->Suid;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	pSMB->AndXCommand = 0xFF;
64962306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
65062306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
65162306a36Sopenharmony_cisession_already_dead:
65262306a36Sopenharmony_ci	mutex_unlock(&ses->session_mutex);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* if session dead then we do not need to do ulogoff,
65562306a36Sopenharmony_ci		since server closed smb session, no sense reporting
65662306a36Sopenharmony_ci		error */
65762306a36Sopenharmony_ci	if (rc == -EAGAIN)
65862306a36Sopenharmony_ci		rc = 0;
65962306a36Sopenharmony_ci	return rc;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ciint
66362306a36Sopenharmony_ciCIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
66462306a36Sopenharmony_ci		 const char *fileName, __u16 type,
66562306a36Sopenharmony_ci		 const struct nls_table *nls_codepage, int remap)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
66862306a36Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
66962306a36Sopenharmony_ci	struct unlink_psx_rq *pRqD;
67062306a36Sopenharmony_ci	int name_len;
67162306a36Sopenharmony_ci	int rc = 0;
67262306a36Sopenharmony_ci	int bytes_returned = 0;
67362306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	cifs_dbg(FYI, "In POSIX delete\n");
67662306a36Sopenharmony_ciPsxDelete:
67762306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
67862306a36Sopenharmony_ci		      (void **) &pSMBr);
67962306a36Sopenharmony_ci	if (rc)
68062306a36Sopenharmony_ci		return rc;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
68362306a36Sopenharmony_ci		name_len =
68462306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
68562306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
68662306a36Sopenharmony_ci		name_len++;	/* trailing null */
68762306a36Sopenharmony_ci		name_len *= 2;
68862306a36Sopenharmony_ci	} else {
68962306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fileName);
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	params = 6 + name_len;
69362306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
69462306a36Sopenharmony_ci	pSMB->MaxDataCount = 0; /* BB double check this with jra */
69562306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
69662306a36Sopenharmony_ci	pSMB->Reserved = 0;
69762306a36Sopenharmony_ci	pSMB->Flags = 0;
69862306a36Sopenharmony_ci	pSMB->Timeout = 0;
69962306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
70062306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
70162306a36Sopenharmony_ci				InformationLevel) - 4;
70262306a36Sopenharmony_ci	offset = param_offset + params;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	/* Setup pointer to Request Data (inode type).
70562306a36Sopenharmony_ci	 * Note that SMB offsets are from the beginning of SMB which is 4 bytes
70662306a36Sopenharmony_ci	 * in, after RFC1001 field
70762306a36Sopenharmony_ci	 */
70862306a36Sopenharmony_ci	pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset + 4);
70962306a36Sopenharmony_ci	pRqD->type = cpu_to_le16(type);
71062306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
71162306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
71262306a36Sopenharmony_ci	pSMB->SetupCount = 1;
71362306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
71462306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
71562306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + sizeof(struct unlink_psx_rq);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
71862306a36Sopenharmony_ci	pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
71962306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
72062306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
72162306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
72262306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
72362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
72462306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
72562306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
72662306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
72762306a36Sopenharmony_ci	if (rc)
72862306a36Sopenharmony_ci		cifs_dbg(FYI, "Posix delete returned %d\n", rc);
72962306a36Sopenharmony_ci	cifs_buf_release(pSMB);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (rc == -EAGAIN)
73462306a36Sopenharmony_ci		goto PsxDelete;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	return rc;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ciint
74062306a36Sopenharmony_ciCIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
74162306a36Sopenharmony_ci	       struct cifs_sb_info *cifs_sb)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	DELETE_FILE_REQ *pSMB = NULL;
74462306a36Sopenharmony_ci	DELETE_FILE_RSP *pSMBr = NULL;
74562306a36Sopenharmony_ci	int rc = 0;
74662306a36Sopenharmony_ci	int bytes_returned;
74762306a36Sopenharmony_ci	int name_len;
74862306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ciDelFileRetry:
75162306a36Sopenharmony_ci	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
75262306a36Sopenharmony_ci		      (void **) &pSMBr);
75362306a36Sopenharmony_ci	if (rc)
75462306a36Sopenharmony_ci		return rc;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
75762306a36Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
75862306a36Sopenharmony_ci					      PATH_MAX, cifs_sb->local_nls,
75962306a36Sopenharmony_ci					      remap);
76062306a36Sopenharmony_ci		name_len++;	/* trailing null */
76162306a36Sopenharmony_ci		name_len *= 2;
76262306a36Sopenharmony_ci	} else {
76362306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->fileName, name);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci	pSMB->SearchAttributes =
76662306a36Sopenharmony_ci	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
76762306a36Sopenharmony_ci	pSMB->BufferFormat = 0x04;
76862306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, name_len + 1);
76962306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len + 1);
77062306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
77162306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
77262306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
77362306a36Sopenharmony_ci	if (rc)
77462306a36Sopenharmony_ci		cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	cifs_buf_release(pSMB);
77762306a36Sopenharmony_ci	if (rc == -EAGAIN)
77862306a36Sopenharmony_ci		goto DelFileRetry;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	return rc;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ciint
78462306a36Sopenharmony_ciCIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
78562306a36Sopenharmony_ci	     struct cifs_sb_info *cifs_sb)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	DELETE_DIRECTORY_REQ *pSMB = NULL;
78862306a36Sopenharmony_ci	DELETE_DIRECTORY_RSP *pSMBr = NULL;
78962306a36Sopenharmony_ci	int rc = 0;
79062306a36Sopenharmony_ci	int bytes_returned;
79162306a36Sopenharmony_ci	int name_len;
79262306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBRmDir\n");
79562306a36Sopenharmony_ciRmDirRetry:
79662306a36Sopenharmony_ci	rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
79762306a36Sopenharmony_ci		      (void **) &pSMBr);
79862306a36Sopenharmony_ci	if (rc)
79962306a36Sopenharmony_ci		return rc;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
80262306a36Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
80362306a36Sopenharmony_ci					      PATH_MAX, cifs_sb->local_nls,
80462306a36Sopenharmony_ci					      remap);
80562306a36Sopenharmony_ci		name_len++;	/* trailing null */
80662306a36Sopenharmony_ci		name_len *= 2;
80762306a36Sopenharmony_ci	} else {
80862306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->DirName, name);
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	pSMB->BufferFormat = 0x04;
81262306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, name_len + 1);
81362306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len + 1);
81462306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
81562306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
81662306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
81762306a36Sopenharmony_ci	if (rc)
81862306a36Sopenharmony_ci		cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	cifs_buf_release(pSMB);
82162306a36Sopenharmony_ci	if (rc == -EAGAIN)
82262306a36Sopenharmony_ci		goto RmDirRetry;
82362306a36Sopenharmony_ci	return rc;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ciint
82762306a36Sopenharmony_ciCIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
82862306a36Sopenharmony_ci	     struct cifs_tcon *tcon, const char *name,
82962306a36Sopenharmony_ci	     struct cifs_sb_info *cifs_sb)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	int rc = 0;
83262306a36Sopenharmony_ci	CREATE_DIRECTORY_REQ *pSMB = NULL;
83362306a36Sopenharmony_ci	CREATE_DIRECTORY_RSP *pSMBr = NULL;
83462306a36Sopenharmony_ci	int bytes_returned;
83562306a36Sopenharmony_ci	int name_len;
83662306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBMkDir\n");
83962306a36Sopenharmony_ciMkDirRetry:
84062306a36Sopenharmony_ci	rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
84162306a36Sopenharmony_ci		      (void **) &pSMBr);
84262306a36Sopenharmony_ci	if (rc)
84362306a36Sopenharmony_ci		return rc;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
84662306a36Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
84762306a36Sopenharmony_ci					      PATH_MAX, cifs_sb->local_nls,
84862306a36Sopenharmony_ci					      remap);
84962306a36Sopenharmony_ci		name_len++;	/* trailing null */
85062306a36Sopenharmony_ci		name_len *= 2;
85162306a36Sopenharmony_ci	} else {
85262306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->DirName, name);
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	pSMB->BufferFormat = 0x04;
85662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, name_len + 1);
85762306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len + 1);
85862306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
85962306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
86062306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
86162306a36Sopenharmony_ci	if (rc)
86262306a36Sopenharmony_ci		cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	cifs_buf_release(pSMB);
86562306a36Sopenharmony_ci	if (rc == -EAGAIN)
86662306a36Sopenharmony_ci		goto MkDirRetry;
86762306a36Sopenharmony_ci	return rc;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ciint
87162306a36Sopenharmony_ciCIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
87262306a36Sopenharmony_ci		__u32 posix_flags, __u64 mode, __u16 *netfid,
87362306a36Sopenharmony_ci		FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
87462306a36Sopenharmony_ci		const char *name, const struct nls_table *nls_codepage,
87562306a36Sopenharmony_ci		int remap)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
87862306a36Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
87962306a36Sopenharmony_ci	int name_len;
88062306a36Sopenharmony_ci	int rc = 0;
88162306a36Sopenharmony_ci	int bytes_returned = 0;
88262306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
88362306a36Sopenharmony_ci	OPEN_PSX_REQ *pdata;
88462306a36Sopenharmony_ci	OPEN_PSX_RSP *psx_rsp;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	cifs_dbg(FYI, "In POSIX Create\n");
88762306a36Sopenharmony_ciPsxCreat:
88862306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
88962306a36Sopenharmony_ci		      (void **) &pSMBr);
89062306a36Sopenharmony_ci	if (rc)
89162306a36Sopenharmony_ci		return rc;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
89462306a36Sopenharmony_ci		name_len =
89562306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
89662306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
89762306a36Sopenharmony_ci		name_len++;	/* trailing null */
89862306a36Sopenharmony_ci		name_len *= 2;
89962306a36Sopenharmony_ci	} else {
90062306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, name);
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	params = 6 + name_len;
90462306a36Sopenharmony_ci	count = sizeof(OPEN_PSX_REQ);
90562306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
90662306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);	/* large enough */
90762306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
90862306a36Sopenharmony_ci	pSMB->Reserved = 0;
90962306a36Sopenharmony_ci	pSMB->Flags = 0;
91062306a36Sopenharmony_ci	pSMB->Timeout = 0;
91162306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
91262306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
91362306a36Sopenharmony_ci				InformationLevel) - 4;
91462306a36Sopenharmony_ci	offset = param_offset + params;
91562306a36Sopenharmony_ci	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
91662306a36Sopenharmony_ci	pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset + 4);
91762306a36Sopenharmony_ci	pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
91862306a36Sopenharmony_ci	pdata->Permissions = cpu_to_le64(mode);
91962306a36Sopenharmony_ci	pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
92062306a36Sopenharmony_ci	pdata->OpenFlags =  cpu_to_le32(*pOplock);
92162306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
92262306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
92362306a36Sopenharmony_ci	pSMB->SetupCount = 1;
92462306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
92562306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
92662306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
92962306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
93062306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
93162306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
93262306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
93362306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
93462306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
93562306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
93662306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
93762306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
93862306a36Sopenharmony_ci	if (rc) {
93962306a36Sopenharmony_ci		cifs_dbg(FYI, "Posix create returned %d\n", rc);
94062306a36Sopenharmony_ci		goto psx_create_err;
94162306a36Sopenharmony_ci	}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	cifs_dbg(FYI, "copying inode info\n");
94462306a36Sopenharmony_ci	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
94762306a36Sopenharmony_ci		rc = -EIO;	/* bad smb */
94862306a36Sopenharmony_ci		goto psx_create_err;
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	/* copy return information to pRetData */
95262306a36Sopenharmony_ci	psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
95362306a36Sopenharmony_ci			+ le16_to_cpu(pSMBr->t2.DataOffset));
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
95662306a36Sopenharmony_ci	if (netfid)
95762306a36Sopenharmony_ci		*netfid = psx_rsp->Fid;   /* cifs fid stays in le */
95862306a36Sopenharmony_ci	/* Let caller know file was created so we can set the mode. */
95962306a36Sopenharmony_ci	/* Do we care about the CreateAction in any other cases? */
96062306a36Sopenharmony_ci	if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
96162306a36Sopenharmony_ci		*pOplock |= CIFS_CREATE_ACTION;
96262306a36Sopenharmony_ci	/* check to make sure response data is there */
96362306a36Sopenharmony_ci	if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
96462306a36Sopenharmony_ci		pRetData->Type = cpu_to_le32(-1); /* unknown */
96562306a36Sopenharmony_ci		cifs_dbg(NOISY, "unknown type\n");
96662306a36Sopenharmony_ci	} else {
96762306a36Sopenharmony_ci		if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
96862306a36Sopenharmony_ci					+ sizeof(FILE_UNIX_BASIC_INFO)) {
96962306a36Sopenharmony_ci			cifs_dbg(VFS, "Open response data too small\n");
97062306a36Sopenharmony_ci			pRetData->Type = cpu_to_le32(-1);
97162306a36Sopenharmony_ci			goto psx_create_err;
97262306a36Sopenharmony_ci		}
97362306a36Sopenharmony_ci		memcpy((char *) pRetData,
97462306a36Sopenharmony_ci			(char *)psx_rsp + sizeof(OPEN_PSX_RSP),
97562306a36Sopenharmony_ci			sizeof(FILE_UNIX_BASIC_INFO));
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_cipsx_create_err:
97962306a36Sopenharmony_ci	cifs_buf_release(pSMB);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	if (posix_flags & SMB_O_DIRECTORY)
98262306a36Sopenharmony_ci		cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
98362306a36Sopenharmony_ci	else
98462306a36Sopenharmony_ci		cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (rc == -EAGAIN)
98762306a36Sopenharmony_ci		goto PsxCreat;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	return rc;
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic __u16 convert_disposition(int disposition)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	__u16 ofun = 0;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	switch (disposition) {
99762306a36Sopenharmony_ci		case FILE_SUPERSEDE:
99862306a36Sopenharmony_ci			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
99962306a36Sopenharmony_ci			break;
100062306a36Sopenharmony_ci		case FILE_OPEN:
100162306a36Sopenharmony_ci			ofun = SMBOPEN_OAPPEND;
100262306a36Sopenharmony_ci			break;
100362306a36Sopenharmony_ci		case FILE_CREATE:
100462306a36Sopenharmony_ci			ofun = SMBOPEN_OCREATE;
100562306a36Sopenharmony_ci			break;
100662306a36Sopenharmony_ci		case FILE_OPEN_IF:
100762306a36Sopenharmony_ci			ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
100862306a36Sopenharmony_ci			break;
100962306a36Sopenharmony_ci		case FILE_OVERWRITE:
101062306a36Sopenharmony_ci			ofun = SMBOPEN_OTRUNC;
101162306a36Sopenharmony_ci			break;
101262306a36Sopenharmony_ci		case FILE_OVERWRITE_IF:
101362306a36Sopenharmony_ci			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
101462306a36Sopenharmony_ci			break;
101562306a36Sopenharmony_ci		default:
101662306a36Sopenharmony_ci			cifs_dbg(FYI, "unknown disposition %d\n", disposition);
101762306a36Sopenharmony_ci			ofun =  SMBOPEN_OAPPEND; /* regular open */
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci	return ofun;
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_cistatic int
102362306a36Sopenharmony_ciaccess_flags_to_smbopen_mode(const int access_flags)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (masked_flags == GENERIC_READ)
102862306a36Sopenharmony_ci		return SMBOPEN_READ;
102962306a36Sopenharmony_ci	else if (masked_flags == GENERIC_WRITE)
103062306a36Sopenharmony_ci		return SMBOPEN_WRITE;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	/* just go for read/write */
103362306a36Sopenharmony_ci	return SMBOPEN_READWRITE;
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ciint
103762306a36Sopenharmony_ciSMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
103862306a36Sopenharmony_ci	    const char *fileName, const int openDisposition,
103962306a36Sopenharmony_ci	    const int access_flags, const int create_options, __u16 *netfid,
104062306a36Sopenharmony_ci	    int *pOplock, FILE_ALL_INFO *pfile_info,
104162306a36Sopenharmony_ci	    const struct nls_table *nls_codepage, int remap)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	int rc;
104462306a36Sopenharmony_ci	OPENX_REQ *pSMB = NULL;
104562306a36Sopenharmony_ci	OPENX_RSP *pSMBr = NULL;
104662306a36Sopenharmony_ci	int bytes_returned;
104762306a36Sopenharmony_ci	int name_len;
104862306a36Sopenharmony_ci	__u16 count;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ciOldOpenRetry:
105162306a36Sopenharmony_ci	rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
105262306a36Sopenharmony_ci		      (void **) &pSMBr);
105362306a36Sopenharmony_ci	if (rc)
105462306a36Sopenharmony_ci		return rc;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	pSMB->AndXCommand = 0xFF;       /* none */
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
105962306a36Sopenharmony_ci		count = 1;      /* account for one byte pad to word boundary */
106062306a36Sopenharmony_ci		name_len =
106162306a36Sopenharmony_ci		   cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
106262306a36Sopenharmony_ci				      fileName, PATH_MAX, nls_codepage, remap);
106362306a36Sopenharmony_ci		name_len++;     /* trailing null */
106462306a36Sopenharmony_ci		name_len *= 2;
106562306a36Sopenharmony_ci	} else {
106662306a36Sopenharmony_ci		count = 0;      /* no pad */
106762306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->fileName, fileName);
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci	if (*pOplock & REQ_OPLOCK)
107062306a36Sopenharmony_ci		pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
107162306a36Sopenharmony_ci	else if (*pOplock & REQ_BATCHOPLOCK)
107262306a36Sopenharmony_ci		pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
107562306a36Sopenharmony_ci	pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
107662306a36Sopenharmony_ci	pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
107762306a36Sopenharmony_ci	/* set file as system file if special file such
107862306a36Sopenharmony_ci	   as fifo and server expecting SFU style and
107962306a36Sopenharmony_ci	   no Unix extensions */
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	if (create_options & CREATE_OPTION_SPECIAL)
108262306a36Sopenharmony_ci		pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
108362306a36Sopenharmony_ci	else /* BB FIXME BB */
108462306a36Sopenharmony_ci		pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (create_options & CREATE_OPTION_READONLY)
108762306a36Sopenharmony_ci		pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	/* BB FIXME BB */
109062306a36Sopenharmony_ci/*	pSMB->CreateOptions = cpu_to_le32(create_options &
109162306a36Sopenharmony_ci						 CREATE_OPTIONS_MASK); */
109262306a36Sopenharmony_ci	/* BB FIXME END BB */
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
109562306a36Sopenharmony_ci	pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
109662306a36Sopenharmony_ci	count += name_len;
109762306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
110062306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
110162306a36Sopenharmony_ci			(struct smb_hdr *)pSMBr, &bytes_returned, 0);
110262306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
110362306a36Sopenharmony_ci	if (rc) {
110462306a36Sopenharmony_ci		cifs_dbg(FYI, "Error in Open = %d\n", rc);
110562306a36Sopenharmony_ci	} else {
110662306a36Sopenharmony_ci	/* BB verify if wct == 15 */
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci/*		*pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		*netfid = pSMBr->Fid;   /* cifs fid stays in le */
111162306a36Sopenharmony_ci		/* Let caller know file was created so we can set the mode. */
111262306a36Sopenharmony_ci		/* Do we care about the CreateAction in any other cases? */
111362306a36Sopenharmony_ci	/* BB FIXME BB */
111462306a36Sopenharmony_ci/*		if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
111562306a36Sopenharmony_ci			*pOplock |= CIFS_CREATE_ACTION; */
111662306a36Sopenharmony_ci	/* BB FIXME END */
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci		if (pfile_info) {
111962306a36Sopenharmony_ci			pfile_info->CreationTime = 0; /* BB convert CreateTime*/
112062306a36Sopenharmony_ci			pfile_info->LastAccessTime = 0; /* BB fixme */
112162306a36Sopenharmony_ci			pfile_info->LastWriteTime = 0; /* BB fixme */
112262306a36Sopenharmony_ci			pfile_info->ChangeTime = 0;  /* BB fixme */
112362306a36Sopenharmony_ci			pfile_info->Attributes =
112462306a36Sopenharmony_ci				cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
112562306a36Sopenharmony_ci			/* the file_info buf is endian converted by caller */
112662306a36Sopenharmony_ci			pfile_info->AllocationSize =
112762306a36Sopenharmony_ci				cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
112862306a36Sopenharmony_ci			pfile_info->EndOfFile = pfile_info->AllocationSize;
112962306a36Sopenharmony_ci			pfile_info->NumberOfLinks = cpu_to_le32(1);
113062306a36Sopenharmony_ci			pfile_info->DeletePending = 0;
113162306a36Sopenharmony_ci		}
113262306a36Sopenharmony_ci	}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	cifs_buf_release(pSMB);
113562306a36Sopenharmony_ci	if (rc == -EAGAIN)
113662306a36Sopenharmony_ci		goto OldOpenRetry;
113762306a36Sopenharmony_ci	return rc;
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ciint
114162306a36Sopenharmony_ciCIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
114262306a36Sopenharmony_ci	  FILE_ALL_INFO *buf)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	int rc;
114562306a36Sopenharmony_ci	OPEN_REQ *req = NULL;
114662306a36Sopenharmony_ci	OPEN_RSP *rsp = NULL;
114762306a36Sopenharmony_ci	int bytes_returned;
114862306a36Sopenharmony_ci	int name_len;
114962306a36Sopenharmony_ci	__u16 count;
115062306a36Sopenharmony_ci	struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
115162306a36Sopenharmony_ci	struct cifs_tcon *tcon = oparms->tcon;
115262306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
115362306a36Sopenharmony_ci	const struct nls_table *nls = cifs_sb->local_nls;
115462306a36Sopenharmony_ci	int create_options = oparms->create_options;
115562306a36Sopenharmony_ci	int desired_access = oparms->desired_access;
115662306a36Sopenharmony_ci	int disposition = oparms->disposition;
115762306a36Sopenharmony_ci	const char *path = oparms->path;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ciopenRetry:
116062306a36Sopenharmony_ci	rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
116162306a36Sopenharmony_ci		      (void **)&rsp);
116262306a36Sopenharmony_ci	if (rc)
116362306a36Sopenharmony_ci		return rc;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* no commands go after this */
116662306a36Sopenharmony_ci	req->AndXCommand = 0xFF;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
116962306a36Sopenharmony_ci		/* account for one byte pad to word boundary */
117062306a36Sopenharmony_ci		count = 1;
117162306a36Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
117262306a36Sopenharmony_ci					      path, PATH_MAX, nls, remap);
117362306a36Sopenharmony_ci		/* trailing null */
117462306a36Sopenharmony_ci		name_len++;
117562306a36Sopenharmony_ci		name_len *= 2;
117662306a36Sopenharmony_ci		req->NameLength = cpu_to_le16(name_len);
117762306a36Sopenharmony_ci	} else {
117862306a36Sopenharmony_ci		/* BB improve check for buffer overruns BB */
117962306a36Sopenharmony_ci		/* no pad */
118062306a36Sopenharmony_ci		count = 0;
118162306a36Sopenharmony_ci		name_len = copy_path_name(req->fileName, path);
118262306a36Sopenharmony_ci		req->NameLength = cpu_to_le16(name_len);
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (*oplock & REQ_OPLOCK)
118662306a36Sopenharmony_ci		req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
118762306a36Sopenharmony_ci	else if (*oplock & REQ_BATCHOPLOCK)
118862306a36Sopenharmony_ci		req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	req->DesiredAccess = cpu_to_le32(desired_access);
119162306a36Sopenharmony_ci	req->AllocationSize = 0;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	/*
119462306a36Sopenharmony_ci	 * Set file as system file if special file such as fifo and server
119562306a36Sopenharmony_ci	 * expecting SFU style and no Unix extensions.
119662306a36Sopenharmony_ci	 */
119762306a36Sopenharmony_ci	if (create_options & CREATE_OPTION_SPECIAL)
119862306a36Sopenharmony_ci		req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
119962306a36Sopenharmony_ci	else
120062306a36Sopenharmony_ci		req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/*
120362306a36Sopenharmony_ci	 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
120462306a36Sopenharmony_ci	 * sensitive checks for other servers such as Samba.
120562306a36Sopenharmony_ci	 */
120662306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_UNIX)
120762306a36Sopenharmony_ci		req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	if (create_options & CREATE_OPTION_READONLY)
121062306a36Sopenharmony_ci		req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
121362306a36Sopenharmony_ci	req->CreateDisposition = cpu_to_le32(disposition);
121462306a36Sopenharmony_ci	req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	/* BB Expirement with various impersonation levels and verify */
121762306a36Sopenharmony_ci	req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
121862306a36Sopenharmony_ci	req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	count += name_len;
122162306a36Sopenharmony_ci	inc_rfc1001_len(req, count);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	req->ByteCount = cpu_to_le16(count);
122462306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
122562306a36Sopenharmony_ci			 (struct smb_hdr *)rsp, &bytes_returned, 0);
122662306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
122762306a36Sopenharmony_ci	if (rc) {
122862306a36Sopenharmony_ci		cifs_dbg(FYI, "Error in Open = %d\n", rc);
122962306a36Sopenharmony_ci		cifs_buf_release(req);
123062306a36Sopenharmony_ci		if (rc == -EAGAIN)
123162306a36Sopenharmony_ci			goto openRetry;
123262306a36Sopenharmony_ci		return rc;
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	/* 1 byte no need to le_to_cpu */
123662306a36Sopenharmony_ci	*oplock = rsp->OplockLevel;
123762306a36Sopenharmony_ci	/* cifs fid stays in le */
123862306a36Sopenharmony_ci	oparms->fid->netfid = rsp->Fid;
123962306a36Sopenharmony_ci	oparms->fid->access = desired_access;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	/* Let caller know file was created so we can set the mode. */
124262306a36Sopenharmony_ci	/* Do we care about the CreateAction in any other cases? */
124362306a36Sopenharmony_ci	if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
124462306a36Sopenharmony_ci		*oplock |= CIFS_CREATE_ACTION;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	if (buf) {
124762306a36Sopenharmony_ci		/* copy commonly used attributes */
124862306a36Sopenharmony_ci		memcpy(&buf->common_attributes,
124962306a36Sopenharmony_ci		       &rsp->common_attributes,
125062306a36Sopenharmony_ci		       sizeof(buf->common_attributes));
125162306a36Sopenharmony_ci		/* the file_info buf is endian converted by caller */
125262306a36Sopenharmony_ci		buf->AllocationSize = rsp->AllocationSize;
125362306a36Sopenharmony_ci		buf->EndOfFile = rsp->EndOfFile;
125462306a36Sopenharmony_ci		buf->NumberOfLinks = cpu_to_le32(1);
125562306a36Sopenharmony_ci		buf->DeletePending = 0;
125662306a36Sopenharmony_ci	}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	cifs_buf_release(req);
125962306a36Sopenharmony_ci	return rc;
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_cistatic void
126362306a36Sopenharmony_cicifs_readv_callback(struct mid_q_entry *mid)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	struct cifs_readdata *rdata = mid->callback_data;
126662306a36Sopenharmony_ci	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
126762306a36Sopenharmony_ci	struct TCP_Server_Info *server = tcon->ses->server;
126862306a36Sopenharmony_ci	struct smb_rqst rqst = { .rq_iov = rdata->iov,
126962306a36Sopenharmony_ci				 .rq_nvec = 2,
127062306a36Sopenharmony_ci				 .rq_iter_size = iov_iter_count(&rdata->iter),
127162306a36Sopenharmony_ci				 .rq_iter = rdata->iter };
127262306a36Sopenharmony_ci	struct cifs_credits credits = { .value = 1, .instance = 0 };
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
127562306a36Sopenharmony_ci		 __func__, mid->mid, mid->mid_state, rdata->result,
127662306a36Sopenharmony_ci		 rdata->bytes);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	switch (mid->mid_state) {
127962306a36Sopenharmony_ci	case MID_RESPONSE_RECEIVED:
128062306a36Sopenharmony_ci		/* result already set, check signature */
128162306a36Sopenharmony_ci		if (server->sign) {
128262306a36Sopenharmony_ci			int rc = 0;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci			rc = cifs_verify_signature(&rqst, server,
128562306a36Sopenharmony_ci						  mid->sequence_number);
128662306a36Sopenharmony_ci			if (rc)
128762306a36Sopenharmony_ci				cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
128862306a36Sopenharmony_ci					 rc);
128962306a36Sopenharmony_ci		}
129062306a36Sopenharmony_ci		/* FIXME: should this be counted toward the initiating task? */
129162306a36Sopenharmony_ci		task_io_account_read(rdata->got_bytes);
129262306a36Sopenharmony_ci		cifs_stats_bytes_read(tcon, rdata->got_bytes);
129362306a36Sopenharmony_ci		break;
129462306a36Sopenharmony_ci	case MID_REQUEST_SUBMITTED:
129562306a36Sopenharmony_ci	case MID_RETRY_NEEDED:
129662306a36Sopenharmony_ci		rdata->result = -EAGAIN;
129762306a36Sopenharmony_ci		if (server->sign && rdata->got_bytes)
129862306a36Sopenharmony_ci			/* reset bytes number since we can not check a sign */
129962306a36Sopenharmony_ci			rdata->got_bytes = 0;
130062306a36Sopenharmony_ci		/* FIXME: should this be counted toward the initiating task? */
130162306a36Sopenharmony_ci		task_io_account_read(rdata->got_bytes);
130262306a36Sopenharmony_ci		cifs_stats_bytes_read(tcon, rdata->got_bytes);
130362306a36Sopenharmony_ci		break;
130462306a36Sopenharmony_ci	default:
130562306a36Sopenharmony_ci		rdata->result = -EIO;
130662306a36Sopenharmony_ci	}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	queue_work(cifsiod_wq, &rdata->work);
130962306a36Sopenharmony_ci	release_mid(mid);
131062306a36Sopenharmony_ci	add_credits(server, &credits, 0);
131162306a36Sopenharmony_ci}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci/* cifs_async_readv - send an async write, and set up mid to handle result */
131462306a36Sopenharmony_ciint
131562306a36Sopenharmony_cicifs_async_readv(struct cifs_readdata *rdata)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	int rc;
131862306a36Sopenharmony_ci	READ_REQ *smb = NULL;
131962306a36Sopenharmony_ci	int wct;
132062306a36Sopenharmony_ci	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
132162306a36Sopenharmony_ci	struct smb_rqst rqst = { .rq_iov = rdata->iov,
132262306a36Sopenharmony_ci				 .rq_nvec = 2 };
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
132562306a36Sopenharmony_ci		 __func__, rdata->offset, rdata->bytes);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES)
132862306a36Sopenharmony_ci		wct = 12;
132962306a36Sopenharmony_ci	else {
133062306a36Sopenharmony_ci		wct = 10; /* old style read */
133162306a36Sopenharmony_ci		if ((rdata->offset >> 32) > 0)  {
133262306a36Sopenharmony_ci			/* can not handle this big offset for old */
133362306a36Sopenharmony_ci			return -EIO;
133462306a36Sopenharmony_ci		}
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
133862306a36Sopenharmony_ci	if (rc)
133962306a36Sopenharmony_ci		return rc;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
134262306a36Sopenharmony_ci	smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	smb->AndXCommand = 0xFF;	/* none */
134562306a36Sopenharmony_ci	smb->Fid = rdata->cfile->fid.netfid;
134662306a36Sopenharmony_ci	smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
134762306a36Sopenharmony_ci	if (wct == 12)
134862306a36Sopenharmony_ci		smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
134962306a36Sopenharmony_ci	smb->Remaining = 0;
135062306a36Sopenharmony_ci	smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
135162306a36Sopenharmony_ci	smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
135262306a36Sopenharmony_ci	if (wct == 12)
135362306a36Sopenharmony_ci		smb->ByteCount = 0;
135462306a36Sopenharmony_ci	else {
135562306a36Sopenharmony_ci		/* old style read */
135662306a36Sopenharmony_ci		struct smb_com_readx_req *smbr =
135762306a36Sopenharmony_ci			(struct smb_com_readx_req *)smb;
135862306a36Sopenharmony_ci		smbr->ByteCount = 0;
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	/* 4 for RFC1001 length + 1 for BCC */
136262306a36Sopenharmony_ci	rdata->iov[0].iov_base = smb;
136362306a36Sopenharmony_ci	rdata->iov[0].iov_len = 4;
136462306a36Sopenharmony_ci	rdata->iov[1].iov_base = (char *)smb + 4;
136562306a36Sopenharmony_ci	rdata->iov[1].iov_len = get_rfc1002_length(smb);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	kref_get(&rdata->refcount);
136862306a36Sopenharmony_ci	rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
136962306a36Sopenharmony_ci			     cifs_readv_callback, NULL, rdata, 0, NULL);
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	if (rc == 0)
137262306a36Sopenharmony_ci		cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
137362306a36Sopenharmony_ci	else
137462306a36Sopenharmony_ci		kref_put(&rdata->refcount, cifs_readdata_release);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	cifs_small_buf_release(smb);
137762306a36Sopenharmony_ci	return rc;
137862306a36Sopenharmony_ci}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ciint
138162306a36Sopenharmony_ciCIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
138262306a36Sopenharmony_ci	    unsigned int *nbytes, char **buf, int *pbuf_type)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	int rc = -EACCES;
138562306a36Sopenharmony_ci	READ_REQ *pSMB = NULL;
138662306a36Sopenharmony_ci	READ_RSP *pSMBr = NULL;
138762306a36Sopenharmony_ci	char *pReadData = NULL;
138862306a36Sopenharmony_ci	int wct;
138962306a36Sopenharmony_ci	int resp_buf_type = 0;
139062306a36Sopenharmony_ci	struct kvec iov[1];
139162306a36Sopenharmony_ci	struct kvec rsp_iov;
139262306a36Sopenharmony_ci	__u32 pid = io_parms->pid;
139362306a36Sopenharmony_ci	__u16 netfid = io_parms->netfid;
139462306a36Sopenharmony_ci	__u64 offset = io_parms->offset;
139562306a36Sopenharmony_ci	struct cifs_tcon *tcon = io_parms->tcon;
139662306a36Sopenharmony_ci	unsigned int count = io_parms->length;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
139962306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES)
140062306a36Sopenharmony_ci		wct = 12;
140162306a36Sopenharmony_ci	else {
140262306a36Sopenharmony_ci		wct = 10; /* old style read */
140362306a36Sopenharmony_ci		if ((offset >> 32) > 0)  {
140462306a36Sopenharmony_ci			/* can not handle this big offset for old */
140562306a36Sopenharmony_ci			return -EIO;
140662306a36Sopenharmony_ci		}
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	*nbytes = 0;
141062306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
141162306a36Sopenharmony_ci	if (rc)
141262306a36Sopenharmony_ci		return rc;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
141562306a36Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	/* tcon and ses pointer are checked in smb_init */
141862306a36Sopenharmony_ci	if (tcon->ses->server == NULL)
141962306a36Sopenharmony_ci		return -ECONNABORTED;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	pSMB->AndXCommand = 0xFF;       /* none */
142262306a36Sopenharmony_ci	pSMB->Fid = netfid;
142362306a36Sopenharmony_ci	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
142462306a36Sopenharmony_ci	if (wct == 12)
142562306a36Sopenharmony_ci		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	pSMB->Remaining = 0;
142862306a36Sopenharmony_ci	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
142962306a36Sopenharmony_ci	pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
143062306a36Sopenharmony_ci	if (wct == 12)
143162306a36Sopenharmony_ci		pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
143262306a36Sopenharmony_ci	else {
143362306a36Sopenharmony_ci		/* old style read */
143462306a36Sopenharmony_ci		struct smb_com_readx_req *pSMBW =
143562306a36Sopenharmony_ci			(struct smb_com_readx_req *)pSMB;
143662306a36Sopenharmony_ci		pSMBW->ByteCount = 0;
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	iov[0].iov_base = (char *)pSMB;
144062306a36Sopenharmony_ci	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
144162306a36Sopenharmony_ci	rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
144262306a36Sopenharmony_ci			  CIFS_LOG_ERROR, &rsp_iov);
144362306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
144462306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
144562306a36Sopenharmony_ci	pSMBr = (READ_RSP *)rsp_iov.iov_base;
144662306a36Sopenharmony_ci	if (rc) {
144762306a36Sopenharmony_ci		cifs_dbg(VFS, "Send error in read = %d\n", rc);
144862306a36Sopenharmony_ci	} else {
144962306a36Sopenharmony_ci		int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
145062306a36Sopenharmony_ci		data_length = data_length << 16;
145162306a36Sopenharmony_ci		data_length += le16_to_cpu(pSMBr->DataLength);
145262306a36Sopenharmony_ci		*nbytes = data_length;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci		/*check that DataLength would not go beyond end of SMB */
145562306a36Sopenharmony_ci		if ((data_length > CIFSMaxBufSize)
145662306a36Sopenharmony_ci				|| (data_length > count)) {
145762306a36Sopenharmony_ci			cifs_dbg(FYI, "bad length %d for count %d\n",
145862306a36Sopenharmony_ci				 data_length, count);
145962306a36Sopenharmony_ci			rc = -EIO;
146062306a36Sopenharmony_ci			*nbytes = 0;
146162306a36Sopenharmony_ci		} else {
146262306a36Sopenharmony_ci			pReadData = (char *) (&pSMBr->hdr.Protocol) +
146362306a36Sopenharmony_ci					le16_to_cpu(pSMBr->DataOffset);
146462306a36Sopenharmony_ci/*			if (rc = copy_to_user(buf, pReadData, data_length)) {
146562306a36Sopenharmony_ci				cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
146662306a36Sopenharmony_ci				rc = -EFAULT;
146762306a36Sopenharmony_ci			}*/ /* can not use copy_to_user when using page cache*/
146862306a36Sopenharmony_ci			if (*buf)
146962306a36Sopenharmony_ci				memcpy(*buf, pReadData, data_length);
147062306a36Sopenharmony_ci		}
147162306a36Sopenharmony_ci	}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	if (*buf) {
147462306a36Sopenharmony_ci		free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
147562306a36Sopenharmony_ci	} else if (resp_buf_type != CIFS_NO_BUFFER) {
147662306a36Sopenharmony_ci		/* return buffer to caller to free */
147762306a36Sopenharmony_ci		*buf = rsp_iov.iov_base;
147862306a36Sopenharmony_ci		if (resp_buf_type == CIFS_SMALL_BUFFER)
147962306a36Sopenharmony_ci			*pbuf_type = CIFS_SMALL_BUFFER;
148062306a36Sopenharmony_ci		else if (resp_buf_type == CIFS_LARGE_BUFFER)
148162306a36Sopenharmony_ci			*pbuf_type = CIFS_LARGE_BUFFER;
148262306a36Sopenharmony_ci	} /* else no valid buffer on return - leave as null */
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
148562306a36Sopenharmony_ci		since file handle passed in no longer valid */
148662306a36Sopenharmony_ci	return rc;
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ciint
149162306a36Sopenharmony_ciCIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
149262306a36Sopenharmony_ci	     unsigned int *nbytes, const char *buf)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	int rc = -EACCES;
149562306a36Sopenharmony_ci	WRITE_REQ *pSMB = NULL;
149662306a36Sopenharmony_ci	WRITE_RSP *pSMBr = NULL;
149762306a36Sopenharmony_ci	int bytes_returned, wct;
149862306a36Sopenharmony_ci	__u32 bytes_sent;
149962306a36Sopenharmony_ci	__u16 byte_count;
150062306a36Sopenharmony_ci	__u32 pid = io_parms->pid;
150162306a36Sopenharmony_ci	__u16 netfid = io_parms->netfid;
150262306a36Sopenharmony_ci	__u64 offset = io_parms->offset;
150362306a36Sopenharmony_ci	struct cifs_tcon *tcon = io_parms->tcon;
150462306a36Sopenharmony_ci	unsigned int count = io_parms->length;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	*nbytes = 0;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	/* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
150962306a36Sopenharmony_ci	if (tcon->ses == NULL)
151062306a36Sopenharmony_ci		return -ECONNABORTED;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES)
151362306a36Sopenharmony_ci		wct = 14;
151462306a36Sopenharmony_ci	else {
151562306a36Sopenharmony_ci		wct = 12;
151662306a36Sopenharmony_ci		if ((offset >> 32) > 0) {
151762306a36Sopenharmony_ci			/* can not handle big offset for old srv */
151862306a36Sopenharmony_ci			return -EIO;
151962306a36Sopenharmony_ci		}
152062306a36Sopenharmony_ci	}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
152362306a36Sopenharmony_ci		      (void **) &pSMBr);
152462306a36Sopenharmony_ci	if (rc)
152562306a36Sopenharmony_ci		return rc;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
152862306a36Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	/* tcon and ses pointer are checked in smb_init */
153162306a36Sopenharmony_ci	if (tcon->ses->server == NULL)
153262306a36Sopenharmony_ci		return -ECONNABORTED;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	pSMB->AndXCommand = 0xFF;	/* none */
153562306a36Sopenharmony_ci	pSMB->Fid = netfid;
153662306a36Sopenharmony_ci	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
153762306a36Sopenharmony_ci	if (wct == 14)
153862306a36Sopenharmony_ci		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	pSMB->Reserved = 0xFFFFFFFF;
154162306a36Sopenharmony_ci	pSMB->WriteMode = 0;
154262306a36Sopenharmony_ci	pSMB->Remaining = 0;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	/* Can increase buffer size if buffer is big enough in some cases ie we
154562306a36Sopenharmony_ci	can send more if LARGE_WRITE_X capability returned by the server and if
154662306a36Sopenharmony_ci	our buffer is big enough or if we convert to iovecs on socket writes
154762306a36Sopenharmony_ci	and eliminate the copy to the CIFS buffer */
154862306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
154962306a36Sopenharmony_ci		bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
155062306a36Sopenharmony_ci	} else {
155162306a36Sopenharmony_ci		bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
155262306a36Sopenharmony_ci			 & ~0xFF;
155362306a36Sopenharmony_ci	}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	if (bytes_sent > count)
155662306a36Sopenharmony_ci		bytes_sent = count;
155762306a36Sopenharmony_ci	pSMB->DataOffset =
155862306a36Sopenharmony_ci		cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
155962306a36Sopenharmony_ci	if (buf)
156062306a36Sopenharmony_ci		memcpy(pSMB->Data, buf, bytes_sent);
156162306a36Sopenharmony_ci	else if (count != 0) {
156262306a36Sopenharmony_ci		/* No buffer */
156362306a36Sopenharmony_ci		cifs_buf_release(pSMB);
156462306a36Sopenharmony_ci		return -EINVAL;
156562306a36Sopenharmony_ci	} /* else setting file size with write of zero bytes */
156662306a36Sopenharmony_ci	if (wct == 14)
156762306a36Sopenharmony_ci		byte_count = bytes_sent + 1; /* pad */
156862306a36Sopenharmony_ci	else /* wct == 12 */
156962306a36Sopenharmony_ci		byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
157262306a36Sopenharmony_ci	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
157362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (wct == 14)
157662306a36Sopenharmony_ci		pSMB->ByteCount = cpu_to_le16(byte_count);
157762306a36Sopenharmony_ci	else { /* old style write has byte count 4 bytes earlier
157862306a36Sopenharmony_ci		  so 4 bytes pad  */
157962306a36Sopenharmony_ci		struct smb_com_writex_req *pSMBW =
158062306a36Sopenharmony_ci			(struct smb_com_writex_req *)pSMB;
158162306a36Sopenharmony_ci		pSMBW->ByteCount = cpu_to_le16(byte_count);
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
158562306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
158662306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
158762306a36Sopenharmony_ci	if (rc) {
158862306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in write = %d\n", rc);
158962306a36Sopenharmony_ci	} else {
159062306a36Sopenharmony_ci		*nbytes = le16_to_cpu(pSMBr->CountHigh);
159162306a36Sopenharmony_ci		*nbytes = (*nbytes) << 16;
159262306a36Sopenharmony_ci		*nbytes += le16_to_cpu(pSMBr->Count);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci		/*
159562306a36Sopenharmony_ci		 * Mask off high 16 bits when bytes written as returned by the
159662306a36Sopenharmony_ci		 * server is greater than bytes requested by the client. Some
159762306a36Sopenharmony_ci		 * OS/2 servers are known to set incorrect CountHigh values.
159862306a36Sopenharmony_ci		 */
159962306a36Sopenharmony_ci		if (*nbytes > count)
160062306a36Sopenharmony_ci			*nbytes &= 0xFFFF;
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	cifs_buf_release(pSMB);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
160662306a36Sopenharmony_ci		since file handle passed in no longer valid */
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	return rc;
160962306a36Sopenharmony_ci}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci/*
161262306a36Sopenharmony_ci * Check the mid_state and signature on received buffer (if any), and queue the
161362306a36Sopenharmony_ci * workqueue completion task.
161462306a36Sopenharmony_ci */
161562306a36Sopenharmony_cistatic void
161662306a36Sopenharmony_cicifs_writev_callback(struct mid_q_entry *mid)
161762306a36Sopenharmony_ci{
161862306a36Sopenharmony_ci	struct cifs_writedata *wdata = mid->callback_data;
161962306a36Sopenharmony_ci	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
162062306a36Sopenharmony_ci	unsigned int written;
162162306a36Sopenharmony_ci	WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
162262306a36Sopenharmony_ci	struct cifs_credits credits = { .value = 1, .instance = 0 };
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	switch (mid->mid_state) {
162562306a36Sopenharmony_ci	case MID_RESPONSE_RECEIVED:
162662306a36Sopenharmony_ci		wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
162762306a36Sopenharmony_ci		if (wdata->result != 0)
162862306a36Sopenharmony_ci			break;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci		written = le16_to_cpu(smb->CountHigh);
163162306a36Sopenharmony_ci		written <<= 16;
163262306a36Sopenharmony_ci		written += le16_to_cpu(smb->Count);
163362306a36Sopenharmony_ci		/*
163462306a36Sopenharmony_ci		 * Mask off high 16 bits when bytes written as returned
163562306a36Sopenharmony_ci		 * by the server is greater than bytes requested by the
163662306a36Sopenharmony_ci		 * client. OS/2 servers are known to set incorrect
163762306a36Sopenharmony_ci		 * CountHigh values.
163862306a36Sopenharmony_ci		 */
163962306a36Sopenharmony_ci		if (written > wdata->bytes)
164062306a36Sopenharmony_ci			written &= 0xFFFF;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci		if (written < wdata->bytes)
164362306a36Sopenharmony_ci			wdata->result = -ENOSPC;
164462306a36Sopenharmony_ci		else
164562306a36Sopenharmony_ci			wdata->bytes = written;
164662306a36Sopenharmony_ci		break;
164762306a36Sopenharmony_ci	case MID_REQUEST_SUBMITTED:
164862306a36Sopenharmony_ci	case MID_RETRY_NEEDED:
164962306a36Sopenharmony_ci		wdata->result = -EAGAIN;
165062306a36Sopenharmony_ci		break;
165162306a36Sopenharmony_ci	default:
165262306a36Sopenharmony_ci		wdata->result = -EIO;
165362306a36Sopenharmony_ci		break;
165462306a36Sopenharmony_ci	}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	queue_work(cifsiod_wq, &wdata->work);
165762306a36Sopenharmony_ci	release_mid(mid);
165862306a36Sopenharmony_ci	add_credits(tcon->ses->server, &credits, 0);
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci/* cifs_async_writev - send an async write, and set up mid to handle result */
166262306a36Sopenharmony_ciint
166362306a36Sopenharmony_cicifs_async_writev(struct cifs_writedata *wdata,
166462306a36Sopenharmony_ci		  void (*release)(struct kref *kref))
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	int rc = -EACCES;
166762306a36Sopenharmony_ci	WRITE_REQ *smb = NULL;
166862306a36Sopenharmony_ci	int wct;
166962306a36Sopenharmony_ci	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
167062306a36Sopenharmony_ci	struct kvec iov[2];
167162306a36Sopenharmony_ci	struct smb_rqst rqst = { };
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
167462306a36Sopenharmony_ci		wct = 14;
167562306a36Sopenharmony_ci	} else {
167662306a36Sopenharmony_ci		wct = 12;
167762306a36Sopenharmony_ci		if (wdata->offset >> 32 > 0) {
167862306a36Sopenharmony_ci			/* can not handle big offset for old srv */
167962306a36Sopenharmony_ci			return -EIO;
168062306a36Sopenharmony_ci		}
168162306a36Sopenharmony_ci	}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
168462306a36Sopenharmony_ci	if (rc)
168562306a36Sopenharmony_ci		goto async_writev_out;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
168862306a36Sopenharmony_ci	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	smb->AndXCommand = 0xFF;	/* none */
169162306a36Sopenharmony_ci	smb->Fid = wdata->cfile->fid.netfid;
169262306a36Sopenharmony_ci	smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
169362306a36Sopenharmony_ci	if (wct == 14)
169462306a36Sopenharmony_ci		smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
169562306a36Sopenharmony_ci	smb->Reserved = 0xFFFFFFFF;
169662306a36Sopenharmony_ci	smb->WriteMode = 0;
169762306a36Sopenharmony_ci	smb->Remaining = 0;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	smb->DataOffset =
170062306a36Sopenharmony_ci	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	/* 4 for RFC1001 length + 1 for BCC */
170362306a36Sopenharmony_ci	iov[0].iov_len = 4;
170462306a36Sopenharmony_ci	iov[0].iov_base = smb;
170562306a36Sopenharmony_ci	iov[1].iov_len = get_rfc1002_length(smb) + 1;
170662306a36Sopenharmony_ci	iov[1].iov_base = (char *)smb + 4;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	rqst.rq_iov = iov;
170962306a36Sopenharmony_ci	rqst.rq_nvec = 2;
171062306a36Sopenharmony_ci	rqst.rq_iter = wdata->iter;
171162306a36Sopenharmony_ci	rqst.rq_iter_size = iov_iter_count(&wdata->iter);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	cifs_dbg(FYI, "async write at %llu %u bytes\n",
171462306a36Sopenharmony_ci		 wdata->offset, wdata->bytes);
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
171762306a36Sopenharmony_ci	smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	if (wct == 14) {
172062306a36Sopenharmony_ci		inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
172162306a36Sopenharmony_ci		put_bcc(wdata->bytes + 1, &smb->hdr);
172262306a36Sopenharmony_ci	} else {
172362306a36Sopenharmony_ci		/* wct == 12 */
172462306a36Sopenharmony_ci		struct smb_com_writex_req *smbw =
172562306a36Sopenharmony_ci				(struct smb_com_writex_req *)smb;
172662306a36Sopenharmony_ci		inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
172762306a36Sopenharmony_ci		put_bcc(wdata->bytes + 5, &smbw->hdr);
172862306a36Sopenharmony_ci		iov[1].iov_len += 4; /* pad bigger by four bytes */
172962306a36Sopenharmony_ci	}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	kref_get(&wdata->refcount);
173262306a36Sopenharmony_ci	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
173362306a36Sopenharmony_ci			     cifs_writev_callback, NULL, wdata, 0, NULL);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	if (rc == 0)
173662306a36Sopenharmony_ci		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
173762306a36Sopenharmony_ci	else
173862306a36Sopenharmony_ci		kref_put(&wdata->refcount, release);
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ciasync_writev_out:
174162306a36Sopenharmony_ci	cifs_small_buf_release(smb);
174262306a36Sopenharmony_ci	return rc;
174362306a36Sopenharmony_ci}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ciint
174662306a36Sopenharmony_ciCIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
174762306a36Sopenharmony_ci	      unsigned int *nbytes, struct kvec *iov, int n_vec)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	int rc;
175062306a36Sopenharmony_ci	WRITE_REQ *pSMB = NULL;
175162306a36Sopenharmony_ci	int wct;
175262306a36Sopenharmony_ci	int smb_hdr_len;
175362306a36Sopenharmony_ci	int resp_buf_type = 0;
175462306a36Sopenharmony_ci	__u32 pid = io_parms->pid;
175562306a36Sopenharmony_ci	__u16 netfid = io_parms->netfid;
175662306a36Sopenharmony_ci	__u64 offset = io_parms->offset;
175762306a36Sopenharmony_ci	struct cifs_tcon *tcon = io_parms->tcon;
175862306a36Sopenharmony_ci	unsigned int count = io_parms->length;
175962306a36Sopenharmony_ci	struct kvec rsp_iov;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	*nbytes = 0;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
176662306a36Sopenharmony_ci		wct = 14;
176762306a36Sopenharmony_ci	} else {
176862306a36Sopenharmony_ci		wct = 12;
176962306a36Sopenharmony_ci		if ((offset >> 32) > 0) {
177062306a36Sopenharmony_ci			/* can not handle big offset for old srv */
177162306a36Sopenharmony_ci			return -EIO;
177262306a36Sopenharmony_ci		}
177362306a36Sopenharmony_ci	}
177462306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
177562306a36Sopenharmony_ci	if (rc)
177662306a36Sopenharmony_ci		return rc;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
177962306a36Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	/* tcon and ses pointer are checked in smb_init */
178262306a36Sopenharmony_ci	if (tcon->ses->server == NULL)
178362306a36Sopenharmony_ci		return -ECONNABORTED;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	pSMB->AndXCommand = 0xFF;	/* none */
178662306a36Sopenharmony_ci	pSMB->Fid = netfid;
178762306a36Sopenharmony_ci	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
178862306a36Sopenharmony_ci	if (wct == 14)
178962306a36Sopenharmony_ci		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
179062306a36Sopenharmony_ci	pSMB->Reserved = 0xFFFFFFFF;
179162306a36Sopenharmony_ci	pSMB->WriteMode = 0;
179262306a36Sopenharmony_ci	pSMB->Remaining = 0;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	pSMB->DataOffset =
179562306a36Sopenharmony_ci	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
179862306a36Sopenharmony_ci	pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
179962306a36Sopenharmony_ci	/* header + 1 byte pad */
180062306a36Sopenharmony_ci	smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
180162306a36Sopenharmony_ci	if (wct == 14)
180262306a36Sopenharmony_ci		inc_rfc1001_len(pSMB, count + 1);
180362306a36Sopenharmony_ci	else /* wct == 12 */
180462306a36Sopenharmony_ci		inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
180562306a36Sopenharmony_ci	if (wct == 14)
180662306a36Sopenharmony_ci		pSMB->ByteCount = cpu_to_le16(count + 1);
180762306a36Sopenharmony_ci	else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
180862306a36Sopenharmony_ci		struct smb_com_writex_req *pSMBW =
180962306a36Sopenharmony_ci				(struct smb_com_writex_req *)pSMB;
181062306a36Sopenharmony_ci		pSMBW->ByteCount = cpu_to_le16(count + 5);
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci	iov[0].iov_base = pSMB;
181362306a36Sopenharmony_ci	if (wct == 14)
181462306a36Sopenharmony_ci		iov[0].iov_len = smb_hdr_len + 4;
181562306a36Sopenharmony_ci	else /* wct == 12 pad bigger by four bytes */
181662306a36Sopenharmony_ci		iov[0].iov_len = smb_hdr_len + 8;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
181962306a36Sopenharmony_ci			  &rsp_iov);
182062306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
182162306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
182262306a36Sopenharmony_ci	if (rc) {
182362306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
182462306a36Sopenharmony_ci	} else if (resp_buf_type == 0) {
182562306a36Sopenharmony_ci		/* presumably this can not happen, but best to be safe */
182662306a36Sopenharmony_ci		rc = -EIO;
182762306a36Sopenharmony_ci	} else {
182862306a36Sopenharmony_ci		WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
182962306a36Sopenharmony_ci		*nbytes = le16_to_cpu(pSMBr->CountHigh);
183062306a36Sopenharmony_ci		*nbytes = (*nbytes) << 16;
183162306a36Sopenharmony_ci		*nbytes += le16_to_cpu(pSMBr->Count);
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci		/*
183462306a36Sopenharmony_ci		 * Mask off high 16 bits when bytes written as returned by the
183562306a36Sopenharmony_ci		 * server is greater than bytes requested by the client. OS/2
183662306a36Sopenharmony_ci		 * servers are known to set incorrect CountHigh values.
183762306a36Sopenharmony_ci		 */
183862306a36Sopenharmony_ci		if (*nbytes > count)
183962306a36Sopenharmony_ci			*nbytes &= 0xFFFF;
184062306a36Sopenharmony_ci	}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
184562306a36Sopenharmony_ci		since file handle passed in no longer valid */
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	return rc;
184862306a36Sopenharmony_ci}
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ciint cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
185162306a36Sopenharmony_ci	       const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
185262306a36Sopenharmony_ci	       const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
185362306a36Sopenharmony_ci{
185462306a36Sopenharmony_ci	int rc = 0;
185562306a36Sopenharmony_ci	LOCK_REQ *pSMB = NULL;
185662306a36Sopenharmony_ci	struct kvec iov[2];
185762306a36Sopenharmony_ci	struct kvec rsp_iov;
185862306a36Sopenharmony_ci	int resp_buf_type;
185962306a36Sopenharmony_ci	__u16 count;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
186262306a36Sopenharmony_ci		 num_lock, num_unlock);
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
186562306a36Sopenharmony_ci	if (rc)
186662306a36Sopenharmony_ci		return rc;
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	pSMB->Timeout = 0;
186962306a36Sopenharmony_ci	pSMB->NumberOfLocks = cpu_to_le16(num_lock);
187062306a36Sopenharmony_ci	pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
187162306a36Sopenharmony_ci	pSMB->LockType = lock_type;
187262306a36Sopenharmony_ci	pSMB->AndXCommand = 0xFF; /* none */
187362306a36Sopenharmony_ci	pSMB->Fid = netfid; /* netfid stays le */
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
187662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
187762306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	iov[0].iov_base = (char *)pSMB;
188062306a36Sopenharmony_ci	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
188162306a36Sopenharmony_ci			 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
188262306a36Sopenharmony_ci	iov[1].iov_base = (char *)buf;
188362306a36Sopenharmony_ci	iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
188662306a36Sopenharmony_ci	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
188762306a36Sopenharmony_ci			  CIFS_NO_RSP_BUF, &rsp_iov);
188862306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
188962306a36Sopenharmony_ci	if (rc)
189062306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	return rc;
189362306a36Sopenharmony_ci}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ciint
189662306a36Sopenharmony_ciCIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
189762306a36Sopenharmony_ci	    const __u16 smb_file_id, const __u32 netpid, const __u64 len,
189862306a36Sopenharmony_ci	    const __u64 offset, const __u32 numUnlock,
189962306a36Sopenharmony_ci	    const __u32 numLock, const __u8 lockType,
190062306a36Sopenharmony_ci	    const bool waitFlag, const __u8 oplock_level)
190162306a36Sopenharmony_ci{
190262306a36Sopenharmony_ci	int rc = 0;
190362306a36Sopenharmony_ci	LOCK_REQ *pSMB = NULL;
190462306a36Sopenharmony_ci/*	LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
190562306a36Sopenharmony_ci	int bytes_returned;
190662306a36Sopenharmony_ci	int flags = 0;
190762306a36Sopenharmony_ci	__u16 count;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
191062306a36Sopenharmony_ci		 (int)waitFlag, numLock);
191162306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (rc)
191462306a36Sopenharmony_ci		return rc;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
191762306a36Sopenharmony_ci		/* no response expected */
191862306a36Sopenharmony_ci		flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
191962306a36Sopenharmony_ci		pSMB->Timeout = 0;
192062306a36Sopenharmony_ci	} else if (waitFlag) {
192162306a36Sopenharmony_ci		flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
192262306a36Sopenharmony_ci		pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
192362306a36Sopenharmony_ci	} else {
192462306a36Sopenharmony_ci		pSMB->Timeout = 0;
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	pSMB->NumberOfLocks = cpu_to_le16(numLock);
192862306a36Sopenharmony_ci	pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
192962306a36Sopenharmony_ci	pSMB->LockType = lockType;
193062306a36Sopenharmony_ci	pSMB->OplockLevel = oplock_level;
193162306a36Sopenharmony_ci	pSMB->AndXCommand = 0xFF;	/* none */
193262306a36Sopenharmony_ci	pSMB->Fid = smb_file_id; /* netfid stays le */
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	if ((numLock != 0) || (numUnlock != 0)) {
193562306a36Sopenharmony_ci		pSMB->Locks[0].Pid = cpu_to_le16(netpid);
193662306a36Sopenharmony_ci		/* BB where to store pid high? */
193762306a36Sopenharmony_ci		pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
193862306a36Sopenharmony_ci		pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
193962306a36Sopenharmony_ci		pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
194062306a36Sopenharmony_ci		pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
194162306a36Sopenharmony_ci		count = sizeof(LOCKING_ANDX_RANGE);
194262306a36Sopenharmony_ci	} else {
194362306a36Sopenharmony_ci		/* oplock break */
194462306a36Sopenharmony_ci		count = 0;
194562306a36Sopenharmony_ci	}
194662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
194762306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	if (waitFlag)
195062306a36Sopenharmony_ci		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
195162306a36Sopenharmony_ci			(struct smb_hdr *) pSMB, &bytes_returned);
195262306a36Sopenharmony_ci	else
195362306a36Sopenharmony_ci		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
195462306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
195562306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
195662306a36Sopenharmony_ci	if (rc)
195762306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
196062306a36Sopenharmony_ci	since file handle passed in no longer valid */
196162306a36Sopenharmony_ci	return rc;
196262306a36Sopenharmony_ci}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ciint
196562306a36Sopenharmony_ciCIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
196662306a36Sopenharmony_ci		const __u16 smb_file_id, const __u32 netpid,
196762306a36Sopenharmony_ci		const loff_t start_offset, const __u64 len,
196862306a36Sopenharmony_ci		struct file_lock *pLockData, const __u16 lock_type,
196962306a36Sopenharmony_ci		const bool waitFlag)
197062306a36Sopenharmony_ci{
197162306a36Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
197262306a36Sopenharmony_ci	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
197362306a36Sopenharmony_ci	struct cifs_posix_lock *parm_data;
197462306a36Sopenharmony_ci	int rc = 0;
197562306a36Sopenharmony_ci	int timeout = 0;
197662306a36Sopenharmony_ci	int bytes_returned = 0;
197762306a36Sopenharmony_ci	int resp_buf_type = 0;
197862306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
197962306a36Sopenharmony_ci	struct kvec iov[1];
198062306a36Sopenharmony_ci	struct kvec rsp_iov;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	cifs_dbg(FYI, "Posix Lock\n");
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	if (rc)
198762306a36Sopenharmony_ci		return rc;
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	params = 6;
199262306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
199362306a36Sopenharmony_ci	pSMB->Reserved = 0;
199462306a36Sopenharmony_ci	pSMB->Flags = 0;
199562306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
199662306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
199762306a36Sopenharmony_ci	offset = param_offset + params;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	count = sizeof(struct cifs_posix_lock);
200062306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
200162306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
200262306a36Sopenharmony_ci	pSMB->SetupCount = 1;
200362306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
200462306a36Sopenharmony_ci	if (pLockData)
200562306a36Sopenharmony_ci		pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
200662306a36Sopenharmony_ci	else
200762306a36Sopenharmony_ci		pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
200862306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
200962306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
201062306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
201162306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
201262306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
201362306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
201462306a36Sopenharmony_ci	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
201562306a36Sopenharmony_ci	parm_data = (struct cifs_posix_lock *)
201662306a36Sopenharmony_ci			(((char *)pSMB) + offset + 4);
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	parm_data->lock_type = cpu_to_le16(lock_type);
201962306a36Sopenharmony_ci	if (waitFlag) {
202062306a36Sopenharmony_ci		timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
202162306a36Sopenharmony_ci		parm_data->lock_flags = cpu_to_le16(1);
202262306a36Sopenharmony_ci		pSMB->Timeout = cpu_to_le32(-1);
202362306a36Sopenharmony_ci	} else
202462306a36Sopenharmony_ci		pSMB->Timeout = 0;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	parm_data->pid = cpu_to_le32(netpid);
202762306a36Sopenharmony_ci	parm_data->start = cpu_to_le64(start_offset);
202862306a36Sopenharmony_ci	parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
203162306a36Sopenharmony_ci	pSMB->Fid = smb_file_id;
203262306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
203362306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
203462306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
203562306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
203662306a36Sopenharmony_ci	if (waitFlag) {
203762306a36Sopenharmony_ci		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
203862306a36Sopenharmony_ci			(struct smb_hdr *) pSMBr, &bytes_returned);
203962306a36Sopenharmony_ci	} else {
204062306a36Sopenharmony_ci		iov[0].iov_base = (char *)pSMB;
204162306a36Sopenharmony_ci		iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
204262306a36Sopenharmony_ci		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
204362306a36Sopenharmony_ci				&resp_buf_type, timeout, &rsp_iov);
204462306a36Sopenharmony_ci		pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
204562306a36Sopenharmony_ci	}
204662306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	if (rc) {
204962306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
205062306a36Sopenharmony_ci	} else if (pLockData) {
205162306a36Sopenharmony_ci		/* lock structure can be returned on get */
205262306a36Sopenharmony_ci		__u16 data_offset;
205362306a36Sopenharmony_ci		__u16 data_count;
205462306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
205762306a36Sopenharmony_ci			rc = -EIO;      /* bad smb */
205862306a36Sopenharmony_ci			goto plk_err_exit;
205962306a36Sopenharmony_ci		}
206062306a36Sopenharmony_ci		data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
206162306a36Sopenharmony_ci		data_count  = le16_to_cpu(pSMBr->t2.DataCount);
206262306a36Sopenharmony_ci		if (data_count < sizeof(struct cifs_posix_lock)) {
206362306a36Sopenharmony_ci			rc = -EIO;
206462306a36Sopenharmony_ci			goto plk_err_exit;
206562306a36Sopenharmony_ci		}
206662306a36Sopenharmony_ci		parm_data = (struct cifs_posix_lock *)
206762306a36Sopenharmony_ci			((char *)&pSMBr->hdr.Protocol + data_offset);
206862306a36Sopenharmony_ci		if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
206962306a36Sopenharmony_ci			pLockData->fl_type = F_UNLCK;
207062306a36Sopenharmony_ci		else {
207162306a36Sopenharmony_ci			if (parm_data->lock_type ==
207262306a36Sopenharmony_ci					cpu_to_le16(CIFS_RDLCK))
207362306a36Sopenharmony_ci				pLockData->fl_type = F_RDLCK;
207462306a36Sopenharmony_ci			else if (parm_data->lock_type ==
207562306a36Sopenharmony_ci					cpu_to_le16(CIFS_WRLCK))
207662306a36Sopenharmony_ci				pLockData->fl_type = F_WRLCK;
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci			pLockData->fl_start = le64_to_cpu(parm_data->start);
207962306a36Sopenharmony_ci			pLockData->fl_end = pLockData->fl_start +
208062306a36Sopenharmony_ci				(le64_to_cpu(parm_data->length) ?
208162306a36Sopenharmony_ci				 le64_to_cpu(parm_data->length) - 1 : 0);
208262306a36Sopenharmony_ci			pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
208362306a36Sopenharmony_ci		}
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ciplk_err_exit:
208762306a36Sopenharmony_ci	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
209062306a36Sopenharmony_ci	   since file handle passed in no longer valid */
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	return rc;
209362306a36Sopenharmony_ci}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ciint
209762306a36Sopenharmony_ciCIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
209862306a36Sopenharmony_ci{
209962306a36Sopenharmony_ci	int rc = 0;
210062306a36Sopenharmony_ci	CLOSE_REQ *pSMB = NULL;
210162306a36Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBClose\n");
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci/* do not retry on dead session on close */
210462306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
210562306a36Sopenharmony_ci	if (rc == -EAGAIN)
210662306a36Sopenharmony_ci		return 0;
210762306a36Sopenharmony_ci	if (rc)
210862306a36Sopenharmony_ci		return rc;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	pSMB->FileID = (__u16) smb_file_id;
211162306a36Sopenharmony_ci	pSMB->LastWriteTime = 0xFFFFFFFF;
211262306a36Sopenharmony_ci	pSMB->ByteCount = 0;
211362306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
211462306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
211562306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
211662306a36Sopenharmony_ci	if (rc) {
211762306a36Sopenharmony_ci		if (rc != -EINTR) {
211862306a36Sopenharmony_ci			/* EINTR is expected when user ctl-c to kill app */
211962306a36Sopenharmony_ci			cifs_dbg(VFS, "Send error in Close = %d\n", rc);
212062306a36Sopenharmony_ci		}
212162306a36Sopenharmony_ci	}
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	/* Since session is dead, file will be closed on server already */
212462306a36Sopenharmony_ci	if (rc == -EAGAIN)
212562306a36Sopenharmony_ci		rc = 0;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	return rc;
212862306a36Sopenharmony_ci}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ciint
213162306a36Sopenharmony_ciCIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
213262306a36Sopenharmony_ci{
213362306a36Sopenharmony_ci	int rc = 0;
213462306a36Sopenharmony_ci	FLUSH_REQ *pSMB = NULL;
213562306a36Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBFlush\n");
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
213862306a36Sopenharmony_ci	if (rc)
213962306a36Sopenharmony_ci		return rc;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	pSMB->FileID = (__u16) smb_file_id;
214262306a36Sopenharmony_ci	pSMB->ByteCount = 0;
214362306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
214462306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
214562306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
214662306a36Sopenharmony_ci	if (rc)
214762306a36Sopenharmony_ci		cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	return rc;
215062306a36Sopenharmony_ci}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ciint CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
215362306a36Sopenharmony_ci		  struct dentry *source_dentry,
215462306a36Sopenharmony_ci		  const char *from_name, const char *to_name,
215562306a36Sopenharmony_ci		  struct cifs_sb_info *cifs_sb)
215662306a36Sopenharmony_ci{
215762306a36Sopenharmony_ci	int rc = 0;
215862306a36Sopenharmony_ci	RENAME_REQ *pSMB = NULL;
215962306a36Sopenharmony_ci	RENAME_RSP *pSMBr = NULL;
216062306a36Sopenharmony_ci	int bytes_returned;
216162306a36Sopenharmony_ci	int name_len, name_len2;
216262306a36Sopenharmony_ci	__u16 count;
216362306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBRename\n");
216662306a36Sopenharmony_cirenameRetry:
216762306a36Sopenharmony_ci	rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
216862306a36Sopenharmony_ci		      (void **) &pSMBr);
216962306a36Sopenharmony_ci	if (rc)
217062306a36Sopenharmony_ci		return rc;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	pSMB->BufferFormat = 0x04;
217362306a36Sopenharmony_ci	pSMB->SearchAttributes =
217462306a36Sopenharmony_ci	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
217562306a36Sopenharmony_ci			ATTR_DIRECTORY);
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
217862306a36Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
217962306a36Sopenharmony_ci					      from_name, PATH_MAX,
218062306a36Sopenharmony_ci					      cifs_sb->local_nls, remap);
218162306a36Sopenharmony_ci		name_len++;	/* trailing null */
218262306a36Sopenharmony_ci		name_len *= 2;
218362306a36Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;	/* pad */
218462306a36Sopenharmony_ci	/* protocol requires ASCII signature byte on Unicode string */
218562306a36Sopenharmony_ci		pSMB->OldFileName[name_len + 1] = 0x00;
218662306a36Sopenharmony_ci		name_len2 =
218762306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
218862306a36Sopenharmony_ci				       to_name, PATH_MAX, cifs_sb->local_nls,
218962306a36Sopenharmony_ci				       remap);
219062306a36Sopenharmony_ci		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
219162306a36Sopenharmony_ci		name_len2 *= 2;	/* convert to bytes */
219262306a36Sopenharmony_ci	} else {
219362306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->OldFileName, from_name);
219462306a36Sopenharmony_ci		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
219562306a36Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
219662306a36Sopenharmony_ci		name_len2++;	/* signature byte */
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	count = 1 /* 1st signature byte */  + name_len + name_len2;
220062306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
220162306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
220462306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
220562306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
220662306a36Sopenharmony_ci	if (rc)
220762306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in rename = %d\n", rc);
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	cifs_buf_release(pSMB);
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	if (rc == -EAGAIN)
221262306a36Sopenharmony_ci		goto renameRetry;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	return rc;
221562306a36Sopenharmony_ci}
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ciint CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
221862306a36Sopenharmony_ci		int netfid, const char *target_name,
221962306a36Sopenharmony_ci		const struct nls_table *nls_codepage, int remap)
222062306a36Sopenharmony_ci{
222162306a36Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
222262306a36Sopenharmony_ci	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
222362306a36Sopenharmony_ci	struct set_file_rename *rename_info;
222462306a36Sopenharmony_ci	char *data_offset;
222562306a36Sopenharmony_ci	char dummy_string[30];
222662306a36Sopenharmony_ci	int rc = 0;
222762306a36Sopenharmony_ci	int bytes_returned = 0;
222862306a36Sopenharmony_ci	int len_of_str;
222962306a36Sopenharmony_ci	__u16 params, param_offset, offset, count, byte_count;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	cifs_dbg(FYI, "Rename to File by handle\n");
223262306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
223362306a36Sopenharmony_ci			(void **) &pSMBr);
223462306a36Sopenharmony_ci	if (rc)
223562306a36Sopenharmony_ci		return rc;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	params = 6;
223862306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
223962306a36Sopenharmony_ci	pSMB->Reserved = 0;
224062306a36Sopenharmony_ci	pSMB->Flags = 0;
224162306a36Sopenharmony_ci	pSMB->Timeout = 0;
224262306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
224362306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
224462306a36Sopenharmony_ci	offset = param_offset + params;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
224762306a36Sopenharmony_ci	data_offset = (char *)(pSMB) + offset + 4;
224862306a36Sopenharmony_ci	rename_info = (struct set_file_rename *) data_offset;
224962306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
225062306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
225162306a36Sopenharmony_ci	pSMB->SetupCount = 1;
225262306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
225362306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
225462306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params;
225562306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
225662306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
225762306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
225862306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
225962306a36Sopenharmony_ci	/* construct random name ".cifs_tmp<inodenum><mid>" */
226062306a36Sopenharmony_ci	rename_info->overwrite = cpu_to_le32(1);
226162306a36Sopenharmony_ci	rename_info->root_fid  = 0;
226262306a36Sopenharmony_ci	/* unicode only call */
226362306a36Sopenharmony_ci	if (target_name == NULL) {
226462306a36Sopenharmony_ci		sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
226562306a36Sopenharmony_ci		len_of_str =
226662306a36Sopenharmony_ci			cifsConvertToUTF16((__le16 *)rename_info->target_name,
226762306a36Sopenharmony_ci					dummy_string, 24, nls_codepage, remap);
226862306a36Sopenharmony_ci	} else {
226962306a36Sopenharmony_ci		len_of_str =
227062306a36Sopenharmony_ci			cifsConvertToUTF16((__le16 *)rename_info->target_name,
227162306a36Sopenharmony_ci					target_name, PATH_MAX, nls_codepage,
227262306a36Sopenharmony_ci					remap);
227362306a36Sopenharmony_ci	}
227462306a36Sopenharmony_ci	rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
227562306a36Sopenharmony_ci	count = sizeof(struct set_file_rename) + (2 * len_of_str);
227662306a36Sopenharmony_ci	byte_count += count;
227762306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
227862306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
227962306a36Sopenharmony_ci	pSMB->Fid = netfid;
228062306a36Sopenharmony_ci	pSMB->InformationLevel =
228162306a36Sopenharmony_ci		cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
228262306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
228362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
228462306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
228562306a36Sopenharmony_ci	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
228662306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
228762306a36Sopenharmony_ci	cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
228862306a36Sopenharmony_ci	if (rc)
228962306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
229062306a36Sopenharmony_ci			 rc);
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	cifs_buf_release(pSMB);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
229562306a36Sopenharmony_ci		since file handle passed in no longer valid */
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	return rc;
229862306a36Sopenharmony_ci}
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ciint
230162306a36Sopenharmony_ciCIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
230262306a36Sopenharmony_ci	    const char *fromName, const __u16 target_tid, const char *toName,
230362306a36Sopenharmony_ci	    const int flags, const struct nls_table *nls_codepage, int remap)
230462306a36Sopenharmony_ci{
230562306a36Sopenharmony_ci	int rc = 0;
230662306a36Sopenharmony_ci	COPY_REQ *pSMB = NULL;
230762306a36Sopenharmony_ci	COPY_RSP *pSMBr = NULL;
230862306a36Sopenharmony_ci	int bytes_returned;
230962306a36Sopenharmony_ci	int name_len, name_len2;
231062306a36Sopenharmony_ci	__u16 count;
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBCopy\n");
231362306a36Sopenharmony_cicopyRetry:
231462306a36Sopenharmony_ci	rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
231562306a36Sopenharmony_ci			(void **) &pSMBr);
231662306a36Sopenharmony_ci	if (rc)
231762306a36Sopenharmony_ci		return rc;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	pSMB->BufferFormat = 0x04;
232062306a36Sopenharmony_ci	pSMB->Tid2 = target_tid;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
232562306a36Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
232662306a36Sopenharmony_ci					      fromName, PATH_MAX, nls_codepage,
232762306a36Sopenharmony_ci					      remap);
232862306a36Sopenharmony_ci		name_len++;     /* trailing null */
232962306a36Sopenharmony_ci		name_len *= 2;
233062306a36Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;     /* pad */
233162306a36Sopenharmony_ci		/* protocol requires ASCII signature byte on Unicode string */
233262306a36Sopenharmony_ci		pSMB->OldFileName[name_len + 1] = 0x00;
233362306a36Sopenharmony_ci		name_len2 =
233462306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
233562306a36Sopenharmony_ci				       toName, PATH_MAX, nls_codepage, remap);
233662306a36Sopenharmony_ci		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
233762306a36Sopenharmony_ci		name_len2 *= 2; /* convert to bytes */
233862306a36Sopenharmony_ci	} else {
233962306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->OldFileName, fromName);
234062306a36Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
234162306a36Sopenharmony_ci		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
234262306a36Sopenharmony_ci		name_len2++;    /* signature byte */
234362306a36Sopenharmony_ci	}
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	count = 1 /* 1st signature byte */  + name_len + name_len2;
234662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
234762306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
235062306a36Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
235162306a36Sopenharmony_ci	if (rc) {
235262306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
235362306a36Sopenharmony_ci			 rc, le16_to_cpu(pSMBr->CopyCount));
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci	cifs_buf_release(pSMB);
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	if (rc == -EAGAIN)
235862306a36Sopenharmony_ci		goto copyRetry;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	return rc;
236162306a36Sopenharmony_ci}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ciint
236462306a36Sopenharmony_ciCIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
236562306a36Sopenharmony_ci		      const char *fromName, const char *toName,
236662306a36Sopenharmony_ci		      const struct nls_table *nls_codepage, int remap)
236762306a36Sopenharmony_ci{
236862306a36Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
236962306a36Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
237062306a36Sopenharmony_ci	char *data_offset;
237162306a36Sopenharmony_ci	int name_len;
237262306a36Sopenharmony_ci	int name_len_target;
237362306a36Sopenharmony_ci	int rc = 0;
237462306a36Sopenharmony_ci	int bytes_returned = 0;
237562306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	cifs_dbg(FYI, "In Symlink Unix style\n");
237862306a36Sopenharmony_cicreateSymLinkRetry:
237962306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
238062306a36Sopenharmony_ci		      (void **) &pSMBr);
238162306a36Sopenharmony_ci	if (rc)
238262306a36Sopenharmony_ci		return rc;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
238562306a36Sopenharmony_ci		name_len =
238662306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
238762306a36Sopenharmony_ci				/* find define for this maxpathcomponent */
238862306a36Sopenharmony_ci					PATH_MAX, nls_codepage, remap);
238962306a36Sopenharmony_ci		name_len++;	/* trailing null */
239062306a36Sopenharmony_ci		name_len *= 2;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	} else {
239362306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fromName);
239462306a36Sopenharmony_ci	}
239562306a36Sopenharmony_ci	params = 6 + name_len;
239662306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
239762306a36Sopenharmony_ci	pSMB->Reserved = 0;
239862306a36Sopenharmony_ci	pSMB->Flags = 0;
239962306a36Sopenharmony_ci	pSMB->Timeout = 0;
240062306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
240162306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
240262306a36Sopenharmony_ci				InformationLevel) - 4;
240362306a36Sopenharmony_ci	offset = param_offset + params;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
240662306a36Sopenharmony_ci	data_offset = (char *)pSMB + offset + 4;
240762306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
240862306a36Sopenharmony_ci		name_len_target =
240962306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) data_offset, toName,
241062306a36Sopenharmony_ci				/* find define for this maxpathcomponent */
241162306a36Sopenharmony_ci					PATH_MAX, nls_codepage, remap);
241262306a36Sopenharmony_ci		name_len_target++;	/* trailing null */
241362306a36Sopenharmony_ci		name_len_target *= 2;
241462306a36Sopenharmony_ci	} else {
241562306a36Sopenharmony_ci		name_len_target = copy_path_name(data_offset, toName);
241662306a36Sopenharmony_ci	}
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
241962306a36Sopenharmony_ci	/* BB find exact max on data count below from sess */
242062306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
242162306a36Sopenharmony_ci	pSMB->SetupCount = 1;
242262306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
242362306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
242462306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + name_len_target;
242562306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(name_len_target);
242662306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
242762306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
242862306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
242962306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
243062306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
243162306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
243262306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
243362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
243462306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
243562306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
243662306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
243762306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
243862306a36Sopenharmony_ci	if (rc)
243962306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
244062306a36Sopenharmony_ci			 rc);
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	cifs_buf_release(pSMB);
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	if (rc == -EAGAIN)
244562306a36Sopenharmony_ci		goto createSymLinkRetry;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	return rc;
244862306a36Sopenharmony_ci}
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ciint
245162306a36Sopenharmony_ciCIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
245262306a36Sopenharmony_ci		       const char *fromName, const char *toName,
245362306a36Sopenharmony_ci		       const struct nls_table *nls_codepage, int remap)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
245662306a36Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
245762306a36Sopenharmony_ci	char *data_offset;
245862306a36Sopenharmony_ci	int name_len;
245962306a36Sopenharmony_ci	int name_len_target;
246062306a36Sopenharmony_ci	int rc = 0;
246162306a36Sopenharmony_ci	int bytes_returned = 0;
246262306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count;
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	cifs_dbg(FYI, "In Create Hard link Unix style\n");
246562306a36Sopenharmony_cicreateHardLinkRetry:
246662306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
246762306a36Sopenharmony_ci		      (void **) &pSMBr);
246862306a36Sopenharmony_ci	if (rc)
246962306a36Sopenharmony_ci		return rc;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
247262306a36Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
247362306a36Sopenharmony_ci					      PATH_MAX, nls_codepage, remap);
247462306a36Sopenharmony_ci		name_len++;	/* trailing null */
247562306a36Sopenharmony_ci		name_len *= 2;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	} else {
247862306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, toName);
247962306a36Sopenharmony_ci	}
248062306a36Sopenharmony_ci	params = 6 + name_len;
248162306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
248262306a36Sopenharmony_ci	pSMB->Reserved = 0;
248362306a36Sopenharmony_ci	pSMB->Flags = 0;
248462306a36Sopenharmony_ci	pSMB->Timeout = 0;
248562306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
248662306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
248762306a36Sopenharmony_ci				InformationLevel) - 4;
248862306a36Sopenharmony_ci	offset = param_offset + params;
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
249162306a36Sopenharmony_ci	data_offset = (char *)pSMB + offset + 4;
249262306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
249362306a36Sopenharmony_ci		name_len_target =
249462306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) data_offset, fromName,
249562306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
249662306a36Sopenharmony_ci		name_len_target++;	/* trailing null */
249762306a36Sopenharmony_ci		name_len_target *= 2;
249862306a36Sopenharmony_ci	} else {
249962306a36Sopenharmony_ci		name_len_target = copy_path_name(data_offset, fromName);
250062306a36Sopenharmony_ci	}
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
250362306a36Sopenharmony_ci	/* BB find exact max on data count below from sess*/
250462306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
250562306a36Sopenharmony_ci	pSMB->SetupCount = 1;
250662306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
250762306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
250862306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + name_len_target;
250962306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
251062306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
251162306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(name_len_target);
251262306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
251362306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
251462306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
251562306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
251662306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
251762306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
251862306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
251962306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
252062306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
252162306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
252262306a36Sopenharmony_ci	if (rc)
252362306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
252462306a36Sopenharmony_ci			 rc);
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	cifs_buf_release(pSMB);
252762306a36Sopenharmony_ci	if (rc == -EAGAIN)
252862306a36Sopenharmony_ci		goto createHardLinkRetry;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	return rc;
253162306a36Sopenharmony_ci}
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ciint CIFSCreateHardLink(const unsigned int xid,
253462306a36Sopenharmony_ci		       struct cifs_tcon *tcon,
253562306a36Sopenharmony_ci		       struct dentry *source_dentry,
253662306a36Sopenharmony_ci		       const char *from_name, const char *to_name,
253762306a36Sopenharmony_ci		       struct cifs_sb_info *cifs_sb)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	int rc = 0;
254062306a36Sopenharmony_ci	NT_RENAME_REQ *pSMB = NULL;
254162306a36Sopenharmony_ci	RENAME_RSP *pSMBr = NULL;
254262306a36Sopenharmony_ci	int bytes_returned;
254362306a36Sopenharmony_ci	int name_len, name_len2;
254462306a36Sopenharmony_ci	__u16 count;
254562306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	cifs_dbg(FYI, "In CIFSCreateHardLink\n");
254862306a36Sopenharmony_ciwinCreateHardLinkRetry:
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
255162306a36Sopenharmony_ci		      (void **) &pSMBr);
255262306a36Sopenharmony_ci	if (rc)
255362306a36Sopenharmony_ci		return rc;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	pSMB->SearchAttributes =
255662306a36Sopenharmony_ci	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
255762306a36Sopenharmony_ci			ATTR_DIRECTORY);
255862306a36Sopenharmony_ci	pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
255962306a36Sopenharmony_ci	pSMB->ClusterCount = 0;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	pSMB->BufferFormat = 0x04;
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
256462306a36Sopenharmony_ci		name_len =
256562306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
256662306a36Sopenharmony_ci				       PATH_MAX, cifs_sb->local_nls, remap);
256762306a36Sopenharmony_ci		name_len++;	/* trailing null */
256862306a36Sopenharmony_ci		name_len *= 2;
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci		/* protocol specifies ASCII buffer format (0x04) for unicode */
257162306a36Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;
257262306a36Sopenharmony_ci		pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
257362306a36Sopenharmony_ci		name_len2 =
257462306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
257562306a36Sopenharmony_ci				       to_name, PATH_MAX, cifs_sb->local_nls,
257662306a36Sopenharmony_ci				       remap);
257762306a36Sopenharmony_ci		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
257862306a36Sopenharmony_ci		name_len2 *= 2;	/* convert to bytes */
257962306a36Sopenharmony_ci	} else {
258062306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->OldFileName, from_name);
258162306a36Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
258262306a36Sopenharmony_ci		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
258362306a36Sopenharmony_ci		name_len2++;	/* signature byte */
258462306a36Sopenharmony_ci	}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	count = 1 /* string type byte */  + name_len + name_len2;
258762306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
258862306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
259162306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
259262306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
259362306a36Sopenharmony_ci	if (rc)
259462306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	cifs_buf_release(pSMB);
259762306a36Sopenharmony_ci	if (rc == -EAGAIN)
259862306a36Sopenharmony_ci		goto winCreateHardLinkRetry;
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	return rc;
260162306a36Sopenharmony_ci}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ciint
260462306a36Sopenharmony_ciCIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
260562306a36Sopenharmony_ci			const unsigned char *searchName, char **symlinkinfo,
260662306a36Sopenharmony_ci			const struct nls_table *nls_codepage, int remap)
260762306a36Sopenharmony_ci{
260862306a36Sopenharmony_ci/* SMB_QUERY_FILE_UNIX_LINK */
260962306a36Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
261062306a36Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
261162306a36Sopenharmony_ci	int rc = 0;
261262306a36Sopenharmony_ci	int bytes_returned;
261362306a36Sopenharmony_ci	int name_len;
261462306a36Sopenharmony_ci	__u16 params, byte_count;
261562306a36Sopenharmony_ci	char *data_start;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ciquerySymLinkRetry:
262062306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
262162306a36Sopenharmony_ci		      (void **) &pSMBr);
262262306a36Sopenharmony_ci	if (rc)
262362306a36Sopenharmony_ci		return rc;
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
262662306a36Sopenharmony_ci		name_len =
262762306a36Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName,
262862306a36Sopenharmony_ci					   searchName, PATH_MAX, nls_codepage,
262962306a36Sopenharmony_ci					   remap);
263062306a36Sopenharmony_ci		name_len++;	/* trailing null */
263162306a36Sopenharmony_ci		name_len *= 2;
263262306a36Sopenharmony_ci	} else {
263362306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, searchName);
263462306a36Sopenharmony_ci	}
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
263762306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
263862306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
263962306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
264062306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
264162306a36Sopenharmony_ci	pSMB->Reserved = 0;
264262306a36Sopenharmony_ci	pSMB->Flags = 0;
264362306a36Sopenharmony_ci	pSMB->Timeout = 0;
264462306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
264562306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
264662306a36Sopenharmony_ci	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
264762306a36Sopenharmony_ci	pSMB->DataCount = 0;
264862306a36Sopenharmony_ci	pSMB->DataOffset = 0;
264962306a36Sopenharmony_ci	pSMB->SetupCount = 1;
265062306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
265162306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
265262306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
265362306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
265462306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
265562306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
265662306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
265762306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
265862306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
266162306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
266262306a36Sopenharmony_ci	if (rc) {
266362306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
266462306a36Sopenharmony_ci	} else {
266562306a36Sopenharmony_ci		/* decode response */
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
266862306a36Sopenharmony_ci		/* BB also check enough total bytes returned */
266962306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 2)
267062306a36Sopenharmony_ci			rc = -EIO;
267162306a36Sopenharmony_ci		else {
267262306a36Sopenharmony_ci			bool is_unicode;
267362306a36Sopenharmony_ci			u16 count = le16_to_cpu(pSMBr->t2.DataCount);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci			data_start = ((char *) &pSMBr->hdr.Protocol) +
267662306a36Sopenharmony_ci					   le16_to_cpu(pSMBr->t2.DataOffset);
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
267962306a36Sopenharmony_ci				is_unicode = true;
268062306a36Sopenharmony_ci			else
268162306a36Sopenharmony_ci				is_unicode = false;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci			/* BB FIXME investigate remapping reserved chars here */
268462306a36Sopenharmony_ci			*symlinkinfo = cifs_strndup_from_utf16(data_start,
268562306a36Sopenharmony_ci					count, is_unicode, nls_codepage);
268662306a36Sopenharmony_ci			if (!*symlinkinfo)
268762306a36Sopenharmony_ci				rc = -ENOMEM;
268862306a36Sopenharmony_ci		}
268962306a36Sopenharmony_ci	}
269062306a36Sopenharmony_ci	cifs_buf_release(pSMB);
269162306a36Sopenharmony_ci	if (rc == -EAGAIN)
269262306a36Sopenharmony_ci		goto querySymLinkRetry;
269362306a36Sopenharmony_ci	return rc;
269462306a36Sopenharmony_ci}
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ciint cifs_query_reparse_point(const unsigned int xid,
269762306a36Sopenharmony_ci			     struct cifs_tcon *tcon,
269862306a36Sopenharmony_ci			     struct cifs_sb_info *cifs_sb,
269962306a36Sopenharmony_ci			     const char *full_path,
270062306a36Sopenharmony_ci			     u32 *tag, struct kvec *rsp,
270162306a36Sopenharmony_ci			     int *rsp_buftype)
270262306a36Sopenharmony_ci{
270362306a36Sopenharmony_ci	struct cifs_open_parms oparms;
270462306a36Sopenharmony_ci	TRANSACT_IOCTL_REQ *io_req = NULL;
270562306a36Sopenharmony_ci	TRANSACT_IOCTL_RSP *io_rsp = NULL;
270662306a36Sopenharmony_ci	struct cifs_fid fid;
270762306a36Sopenharmony_ci	__u32 data_offset, data_count;
270862306a36Sopenharmony_ci	__u8 *start, *end;
270962306a36Sopenharmony_ci	int io_rsp_len;
271062306a36Sopenharmony_ci	int oplock = 0;
271162306a36Sopenharmony_ci	int rc;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	if (cap_unix(tcon->ses))
271662306a36Sopenharmony_ci		return -EOPNOTSUPP;
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	oparms = (struct cifs_open_parms) {
271962306a36Sopenharmony_ci		.tcon = tcon,
272062306a36Sopenharmony_ci		.cifs_sb = cifs_sb,
272162306a36Sopenharmony_ci		.desired_access = FILE_READ_ATTRIBUTES,
272262306a36Sopenharmony_ci		.create_options = cifs_create_options(cifs_sb,
272362306a36Sopenharmony_ci						      OPEN_REPARSE_POINT),
272462306a36Sopenharmony_ci		.disposition = FILE_OPEN,
272562306a36Sopenharmony_ci		.path = full_path,
272662306a36Sopenharmony_ci		.fid = &fid,
272762306a36Sopenharmony_ci	};
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	rc = CIFS_open(xid, &oparms, &oplock, NULL);
273062306a36Sopenharmony_ci	if (rc)
273162306a36Sopenharmony_ci		return rc;
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon,
273462306a36Sopenharmony_ci		      (void **)&io_req, (void **)&io_rsp);
273562306a36Sopenharmony_ci	if (rc)
273662306a36Sopenharmony_ci		goto error;
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	io_req->TotalParameterCount = 0;
273962306a36Sopenharmony_ci	io_req->TotalDataCount = 0;
274062306a36Sopenharmony_ci	io_req->MaxParameterCount = cpu_to_le32(2);
274162306a36Sopenharmony_ci	/* BB find exact data count max from sess structure BB */
274262306a36Sopenharmony_ci	io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
274362306a36Sopenharmony_ci	io_req->MaxSetupCount = 4;
274462306a36Sopenharmony_ci	io_req->Reserved = 0;
274562306a36Sopenharmony_ci	io_req->ParameterOffset = 0;
274662306a36Sopenharmony_ci	io_req->DataCount = 0;
274762306a36Sopenharmony_ci	io_req->DataOffset = 0;
274862306a36Sopenharmony_ci	io_req->SetupCount = 4;
274962306a36Sopenharmony_ci	io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
275062306a36Sopenharmony_ci	io_req->ParameterCount = io_req->TotalParameterCount;
275162306a36Sopenharmony_ci	io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
275262306a36Sopenharmony_ci	io_req->IsFsctl = 1;
275362306a36Sopenharmony_ci	io_req->IsRootFlag = 0;
275462306a36Sopenharmony_ci	io_req->Fid = fid.netfid;
275562306a36Sopenharmony_ci	io_req->ByteCount = 0;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req,
275862306a36Sopenharmony_ci			 (struct smb_hdr *)io_rsp, &io_rsp_len, 0);
275962306a36Sopenharmony_ci	if (rc)
276062306a36Sopenharmony_ci		goto error;
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	data_offset = le32_to_cpu(io_rsp->DataOffset);
276362306a36Sopenharmony_ci	data_count = le32_to_cpu(io_rsp->DataCount);
276462306a36Sopenharmony_ci	if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 ||
276562306a36Sopenharmony_ci	    !data_count || data_count > 2048) {
276662306a36Sopenharmony_ci		rc = -EIO;
276762306a36Sopenharmony_ci		goto error;
276862306a36Sopenharmony_ci	}
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount;
277162306a36Sopenharmony_ci	start = (__u8 *)&io_rsp->hdr.Protocol + data_offset;
277262306a36Sopenharmony_ci	if (start >= end) {
277362306a36Sopenharmony_ci		rc = -EIO;
277462306a36Sopenharmony_ci		goto error;
277562306a36Sopenharmony_ci	}
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	*tag = le32_to_cpu(((struct reparse_data_buffer *)start)->ReparseTag);
277862306a36Sopenharmony_ci	rsp->iov_base = io_rsp;
277962306a36Sopenharmony_ci	rsp->iov_len = io_rsp_len;
278062306a36Sopenharmony_ci	*rsp_buftype = CIFS_LARGE_BUFFER;
278162306a36Sopenharmony_ci	CIFSSMBClose(xid, tcon, fid.netfid);
278262306a36Sopenharmony_ci	return 0;
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_cierror:
278562306a36Sopenharmony_ci	cifs_buf_release(io_req);
278662306a36Sopenharmony_ci	CIFSSMBClose(xid, tcon, fid.netfid);
278762306a36Sopenharmony_ci	return rc;
278862306a36Sopenharmony_ci}
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ciint
279162306a36Sopenharmony_ciCIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
279262306a36Sopenharmony_ci		    __u16 fid)
279362306a36Sopenharmony_ci{
279462306a36Sopenharmony_ci	int rc = 0;
279562306a36Sopenharmony_ci	int bytes_returned;
279662306a36Sopenharmony_ci	struct smb_com_transaction_compr_ioctl_req *pSMB;
279762306a36Sopenharmony_ci	struct smb_com_transaction_ioctl_rsp *pSMBr;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	cifs_dbg(FYI, "Set compression for %u\n", fid);
280062306a36Sopenharmony_ci	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
280162306a36Sopenharmony_ci		      (void **) &pSMBr);
280262306a36Sopenharmony_ci	if (rc)
280362306a36Sopenharmony_ci		return rc;
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_ci	pSMB->TotalParameterCount = 0;
280862306a36Sopenharmony_ci	pSMB->TotalDataCount = cpu_to_le32(2);
280962306a36Sopenharmony_ci	pSMB->MaxParameterCount = 0;
281062306a36Sopenharmony_ci	pSMB->MaxDataCount = 0;
281162306a36Sopenharmony_ci	pSMB->MaxSetupCount = 4;
281262306a36Sopenharmony_ci	pSMB->Reserved = 0;
281362306a36Sopenharmony_ci	pSMB->ParameterOffset = 0;
281462306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le32(2);
281562306a36Sopenharmony_ci	pSMB->DataOffset =
281662306a36Sopenharmony_ci		cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
281762306a36Sopenharmony_ci				compression_state) - 4);  /* 84 */
281862306a36Sopenharmony_ci	pSMB->SetupCount = 4;
281962306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
282062306a36Sopenharmony_ci	pSMB->ParameterCount = 0;
282162306a36Sopenharmony_ci	pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
282262306a36Sopenharmony_ci	pSMB->IsFsctl = 1; /* FSCTL */
282362306a36Sopenharmony_ci	pSMB->IsRootFlag = 0;
282462306a36Sopenharmony_ci	pSMB->Fid = fid; /* file handle always le */
282562306a36Sopenharmony_ci	/* 3 byte pad, followed by 2 byte compress state */
282662306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(5);
282762306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, 5);
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
283062306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
283162306a36Sopenharmony_ci	if (rc)
283262306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	cifs_buf_release(pSMB);
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci	/*
283762306a36Sopenharmony_ci	 * Note: On -EAGAIN error only caller can retry on handle based calls
283862306a36Sopenharmony_ci	 * since file handle passed in no longer valid.
283962306a36Sopenharmony_ci	 */
284062306a36Sopenharmony_ci	return rc;
284162306a36Sopenharmony_ci}
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci#ifdef CONFIG_FS_POSIX_ACL
284762306a36Sopenharmony_ci/**
284862306a36Sopenharmony_ci * cifs_init_posix_acl - convert ACL from cifs to POSIX ACL format
284962306a36Sopenharmony_ci * @ace: POSIX ACL entry to store converted ACL into
285062306a36Sopenharmony_ci * @cifs_ace: ACL in cifs format
285162306a36Sopenharmony_ci *
285262306a36Sopenharmony_ci * Convert an Access Control Entry from wire format to local POSIX xattr
285362306a36Sopenharmony_ci * format.
285462306a36Sopenharmony_ci *
285562306a36Sopenharmony_ci * Note that the @cifs_uid member is used to store both {g,u}id_t.
285662306a36Sopenharmony_ci */
285762306a36Sopenharmony_cistatic void cifs_init_posix_acl(struct posix_acl_entry *ace,
285862306a36Sopenharmony_ci				struct cifs_posix_ace *cifs_ace)
285962306a36Sopenharmony_ci{
286062306a36Sopenharmony_ci	/* u8 cifs fields do not need le conversion */
286162306a36Sopenharmony_ci	ace->e_perm = cifs_ace->cifs_e_perm;
286262306a36Sopenharmony_ci	ace->e_tag = cifs_ace->cifs_e_tag;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	switch (ace->e_tag) {
286562306a36Sopenharmony_ci	case ACL_USER:
286662306a36Sopenharmony_ci		ace->e_uid = make_kuid(&init_user_ns,
286762306a36Sopenharmony_ci				       le64_to_cpu(cifs_ace->cifs_uid));
286862306a36Sopenharmony_ci		break;
286962306a36Sopenharmony_ci	case ACL_GROUP:
287062306a36Sopenharmony_ci		ace->e_gid = make_kgid(&init_user_ns,
287162306a36Sopenharmony_ci				       le64_to_cpu(cifs_ace->cifs_uid));
287262306a36Sopenharmony_ci		break;
287362306a36Sopenharmony_ci	}
287462306a36Sopenharmony_ci	return;
287562306a36Sopenharmony_ci}
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci/**
287862306a36Sopenharmony_ci * cifs_to_posix_acl - copy cifs ACL format to POSIX ACL format
287962306a36Sopenharmony_ci * @acl: ACLs returned in POSIX ACL format
288062306a36Sopenharmony_ci * @src: ACLs in cifs format
288162306a36Sopenharmony_ci * @acl_type: type of POSIX ACL requested
288262306a36Sopenharmony_ci * @size_of_data_area: size of SMB we got
288362306a36Sopenharmony_ci *
288462306a36Sopenharmony_ci * This function converts ACLs from cifs format to POSIX ACL format.
288562306a36Sopenharmony_ci * If @acl is NULL then the size of the buffer required to store POSIX ACLs in
288662306a36Sopenharmony_ci * their uapi format is returned.
288762306a36Sopenharmony_ci */
288862306a36Sopenharmony_cistatic int cifs_to_posix_acl(struct posix_acl **acl, char *src,
288962306a36Sopenharmony_ci			     const int acl_type, const int size_of_data_area)
289062306a36Sopenharmony_ci{
289162306a36Sopenharmony_ci	int size =  0;
289262306a36Sopenharmony_ci	__u16 count;
289362306a36Sopenharmony_ci	struct cifs_posix_ace *pACE;
289462306a36Sopenharmony_ci	struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
289562306a36Sopenharmony_ci	struct posix_acl *kacl = NULL;
289662306a36Sopenharmony_ci	struct posix_acl_entry *pa, *pe;
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
289962306a36Sopenharmony_ci		return -EOPNOTSUPP;
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci	if (acl_type == ACL_TYPE_ACCESS) {
290262306a36Sopenharmony_ci		count = le16_to_cpu(cifs_acl->access_entry_count);
290362306a36Sopenharmony_ci		pACE = &cifs_acl->ace_array[0];
290462306a36Sopenharmony_ci		size = sizeof(struct cifs_posix_acl);
290562306a36Sopenharmony_ci		size += sizeof(struct cifs_posix_ace) * count;
290662306a36Sopenharmony_ci		/* check if we would go beyond end of SMB */
290762306a36Sopenharmony_ci		if (size_of_data_area < size) {
290862306a36Sopenharmony_ci			cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
290962306a36Sopenharmony_ci				 size_of_data_area, size);
291062306a36Sopenharmony_ci			return -EINVAL;
291162306a36Sopenharmony_ci		}
291262306a36Sopenharmony_ci	} else if (acl_type == ACL_TYPE_DEFAULT) {
291362306a36Sopenharmony_ci		count = le16_to_cpu(cifs_acl->access_entry_count);
291462306a36Sopenharmony_ci		size = sizeof(struct cifs_posix_acl);
291562306a36Sopenharmony_ci		size += sizeof(struct cifs_posix_ace) * count;
291662306a36Sopenharmony_ci		/* skip past access ACEs to get to default ACEs */
291762306a36Sopenharmony_ci		pACE = &cifs_acl->ace_array[count];
291862306a36Sopenharmony_ci		count = le16_to_cpu(cifs_acl->default_entry_count);
291962306a36Sopenharmony_ci		size += sizeof(struct cifs_posix_ace) * count;
292062306a36Sopenharmony_ci		/* check if we would go beyond end of SMB */
292162306a36Sopenharmony_ci		if (size_of_data_area < size)
292262306a36Sopenharmony_ci			return -EINVAL;
292362306a36Sopenharmony_ci	} else {
292462306a36Sopenharmony_ci		/* illegal type */
292562306a36Sopenharmony_ci		return -EINVAL;
292662306a36Sopenharmony_ci	}
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	/* Allocate number of POSIX ACLs to store in VFS format. */
292962306a36Sopenharmony_ci	kacl = posix_acl_alloc(count, GFP_NOFS);
293062306a36Sopenharmony_ci	if (!kacl)
293162306a36Sopenharmony_ci		return -ENOMEM;
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	FOREACH_ACL_ENTRY(pa, kacl, pe) {
293462306a36Sopenharmony_ci		cifs_init_posix_acl(pa, pACE);
293562306a36Sopenharmony_ci		pACE++;
293662306a36Sopenharmony_ci	}
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	*acl = kacl;
293962306a36Sopenharmony_ci	return 0;
294062306a36Sopenharmony_ci}
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci/**
294362306a36Sopenharmony_ci * cifs_init_ace - convert ACL entry from POSIX ACL to cifs format
294462306a36Sopenharmony_ci * @cifs_ace: the cifs ACL entry to store into
294562306a36Sopenharmony_ci * @local_ace: the POSIX ACL entry to convert
294662306a36Sopenharmony_ci */
294762306a36Sopenharmony_cistatic void cifs_init_ace(struct cifs_posix_ace *cifs_ace,
294862306a36Sopenharmony_ci			  const struct posix_acl_entry *local_ace)
294962306a36Sopenharmony_ci{
295062306a36Sopenharmony_ci	cifs_ace->cifs_e_perm = local_ace->e_perm;
295162306a36Sopenharmony_ci	cifs_ace->cifs_e_tag =  local_ace->e_tag;
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	switch (local_ace->e_tag) {
295462306a36Sopenharmony_ci	case ACL_USER:
295562306a36Sopenharmony_ci		cifs_ace->cifs_uid =
295662306a36Sopenharmony_ci			cpu_to_le64(from_kuid(&init_user_ns, local_ace->e_uid));
295762306a36Sopenharmony_ci		break;
295862306a36Sopenharmony_ci	case ACL_GROUP:
295962306a36Sopenharmony_ci		cifs_ace->cifs_uid =
296062306a36Sopenharmony_ci			cpu_to_le64(from_kgid(&init_user_ns, local_ace->e_gid));
296162306a36Sopenharmony_ci		break;
296262306a36Sopenharmony_ci	default:
296362306a36Sopenharmony_ci		cifs_ace->cifs_uid = cpu_to_le64(-1);
296462306a36Sopenharmony_ci	}
296562306a36Sopenharmony_ci}
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci/**
296862306a36Sopenharmony_ci * posix_acl_to_cifs - convert ACLs from POSIX ACL to cifs format
296962306a36Sopenharmony_ci * @parm_data: ACLs in cifs format to conver to
297062306a36Sopenharmony_ci * @acl: ACLs in POSIX ACL format to convert from
297162306a36Sopenharmony_ci * @acl_type: the type of POSIX ACLs stored in @acl
297262306a36Sopenharmony_ci *
297362306a36Sopenharmony_ci * Return: the number cifs ACL entries after conversion
297462306a36Sopenharmony_ci */
297562306a36Sopenharmony_cistatic __u16 posix_acl_to_cifs(char *parm_data, const struct posix_acl *acl,
297662306a36Sopenharmony_ci			       const int acl_type)
297762306a36Sopenharmony_ci{
297862306a36Sopenharmony_ci	__u16 rc = 0;
297962306a36Sopenharmony_ci	struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
298062306a36Sopenharmony_ci	const struct posix_acl_entry *pa, *pe;
298162306a36Sopenharmony_ci	int count;
298262306a36Sopenharmony_ci	int i = 0;
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci	if ((acl == NULL) || (cifs_acl == NULL))
298562306a36Sopenharmony_ci		return 0;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	count = acl->a_count;
298862306a36Sopenharmony_ci	cifs_dbg(FYI, "setting acl with %d entries\n", count);
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	/*
299162306a36Sopenharmony_ci	 * Note that the uapi POSIX ACL version is verified by the VFS and is
299262306a36Sopenharmony_ci	 * independent of the cifs ACL version. Changing the POSIX ACL version
299362306a36Sopenharmony_ci	 * is a uapi change and if it's changed we will pass down the POSIX ACL
299462306a36Sopenharmony_ci	 * version in struct posix_acl from the VFS. For now there's really
299562306a36Sopenharmony_ci	 * only one that all filesystems know how to deal with.
299662306a36Sopenharmony_ci	 */
299762306a36Sopenharmony_ci	cifs_acl->version = cpu_to_le16(1);
299862306a36Sopenharmony_ci	if (acl_type == ACL_TYPE_ACCESS) {
299962306a36Sopenharmony_ci		cifs_acl->access_entry_count = cpu_to_le16(count);
300062306a36Sopenharmony_ci		cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
300162306a36Sopenharmony_ci	} else if (acl_type == ACL_TYPE_DEFAULT) {
300262306a36Sopenharmony_ci		cifs_acl->default_entry_count = cpu_to_le16(count);
300362306a36Sopenharmony_ci		cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
300462306a36Sopenharmony_ci	} else {
300562306a36Sopenharmony_ci		cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
300662306a36Sopenharmony_ci		return 0;
300762306a36Sopenharmony_ci	}
300862306a36Sopenharmony_ci	FOREACH_ACL_ENTRY(pa, acl, pe) {
300962306a36Sopenharmony_ci		cifs_init_ace(&cifs_acl->ace_array[i++], pa);
301062306a36Sopenharmony_ci	}
301162306a36Sopenharmony_ci	if (rc == 0) {
301262306a36Sopenharmony_ci		rc = (__u16)(count * sizeof(struct cifs_posix_ace));
301362306a36Sopenharmony_ci		rc += sizeof(struct cifs_posix_acl);
301462306a36Sopenharmony_ci		/* BB add check to make sure ACL does not overflow SMB */
301562306a36Sopenharmony_ci	}
301662306a36Sopenharmony_ci	return rc;
301762306a36Sopenharmony_ci}
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ciint cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
302062306a36Sopenharmony_ci		    const unsigned char *searchName, struct posix_acl **acl,
302162306a36Sopenharmony_ci		    const int acl_type, const struct nls_table *nls_codepage,
302262306a36Sopenharmony_ci		    int remap)
302362306a36Sopenharmony_ci{
302462306a36Sopenharmony_ci/* SMB_QUERY_POSIX_ACL */
302562306a36Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
302662306a36Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
302762306a36Sopenharmony_ci	int rc = 0;
302862306a36Sopenharmony_ci	int bytes_returned;
302962306a36Sopenharmony_ci	int name_len;
303062306a36Sopenharmony_ci	__u16 params, byte_count;
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci	cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ciqueryAclRetry:
303562306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
303662306a36Sopenharmony_ci		(void **) &pSMBr);
303762306a36Sopenharmony_ci	if (rc)
303862306a36Sopenharmony_ci		return rc;
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
304162306a36Sopenharmony_ci		name_len =
304262306a36Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName,
304362306a36Sopenharmony_ci					   searchName, PATH_MAX, nls_codepage,
304462306a36Sopenharmony_ci					   remap);
304562306a36Sopenharmony_ci		name_len++;     /* trailing null */
304662306a36Sopenharmony_ci		name_len *= 2;
304762306a36Sopenharmony_ci		pSMB->FileName[name_len] = 0;
304862306a36Sopenharmony_ci		pSMB->FileName[name_len+1] = 0;
304962306a36Sopenharmony_ci	} else {
305062306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, searchName);
305162306a36Sopenharmony_ci	}
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
305462306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
305562306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
305662306a36Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
305762306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
305862306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
305962306a36Sopenharmony_ci	pSMB->Reserved = 0;
306062306a36Sopenharmony_ci	pSMB->Flags = 0;
306162306a36Sopenharmony_ci	pSMB->Timeout = 0;
306262306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
306362306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(
306462306a36Sopenharmony_ci		offsetof(struct smb_com_transaction2_qpi_req,
306562306a36Sopenharmony_ci			 InformationLevel) - 4);
306662306a36Sopenharmony_ci	pSMB->DataCount = 0;
306762306a36Sopenharmony_ci	pSMB->DataOffset = 0;
306862306a36Sopenharmony_ci	pSMB->SetupCount = 1;
306962306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
307062306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
307162306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
307262306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
307362306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
307462306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
307562306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
307662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
307762306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
308062306a36Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
308162306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
308262306a36Sopenharmony_ci	if (rc) {
308362306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
308462306a36Sopenharmony_ci	} else {
308562306a36Sopenharmony_ci		/* decode response */
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
308862306a36Sopenharmony_ci		/* BB also check enough total bytes returned */
308962306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 2)
309062306a36Sopenharmony_ci			rc = -EIO;      /* bad smb */
309162306a36Sopenharmony_ci		else {
309262306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
309362306a36Sopenharmony_ci			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
309462306a36Sopenharmony_ci			rc = cifs_to_posix_acl(acl,
309562306a36Sopenharmony_ci				(char *)&pSMBr->hdr.Protocol+data_offset,
309662306a36Sopenharmony_ci				acl_type, count);
309762306a36Sopenharmony_ci		}
309862306a36Sopenharmony_ci	}
309962306a36Sopenharmony_ci	cifs_buf_release(pSMB);
310062306a36Sopenharmony_ci	/*
310162306a36Sopenharmony_ci	 * The else branch after SendReceive() doesn't return EAGAIN so if we
310262306a36Sopenharmony_ci	 * allocated @acl in cifs_to_posix_acl() we are guaranteed to return
310362306a36Sopenharmony_ci	 * here and don't leak POSIX ACLs.
310462306a36Sopenharmony_ci	 */
310562306a36Sopenharmony_ci	if (rc == -EAGAIN)
310662306a36Sopenharmony_ci		goto queryAclRetry;
310762306a36Sopenharmony_ci	return rc;
310862306a36Sopenharmony_ci}
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ciint cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
311162306a36Sopenharmony_ci		    const unsigned char *fileName, const struct posix_acl *acl,
311262306a36Sopenharmony_ci		    const int acl_type, const struct nls_table *nls_codepage,
311362306a36Sopenharmony_ci		    int remap)
311462306a36Sopenharmony_ci{
311562306a36Sopenharmony_ci	struct smb_com_transaction2_spi_req *pSMB = NULL;
311662306a36Sopenharmony_ci	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
311762306a36Sopenharmony_ci	char *parm_data;
311862306a36Sopenharmony_ci	int name_len;
311962306a36Sopenharmony_ci	int rc = 0;
312062306a36Sopenharmony_ci	int bytes_returned = 0;
312162306a36Sopenharmony_ci	__u16 params, byte_count, data_count, param_offset, offset;
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci	cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
312462306a36Sopenharmony_cisetAclRetry:
312562306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
312662306a36Sopenharmony_ci		      (void **) &pSMBr);
312762306a36Sopenharmony_ci	if (rc)
312862306a36Sopenharmony_ci		return rc;
312962306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
313062306a36Sopenharmony_ci		name_len =
313162306a36Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
313262306a36Sopenharmony_ci					   PATH_MAX, nls_codepage, remap);
313362306a36Sopenharmony_ci		name_len++;     /* trailing null */
313462306a36Sopenharmony_ci		name_len *= 2;
313562306a36Sopenharmony_ci	} else {
313662306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fileName);
313762306a36Sopenharmony_ci	}
313862306a36Sopenharmony_ci	params = 6 + name_len;
313962306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
314062306a36Sopenharmony_ci	/* BB find max SMB size from sess */
314162306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
314262306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
314362306a36Sopenharmony_ci	pSMB->Reserved = 0;
314462306a36Sopenharmony_ci	pSMB->Flags = 0;
314562306a36Sopenharmony_ci	pSMB->Timeout = 0;
314662306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
314762306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
314862306a36Sopenharmony_ci				InformationLevel) - 4;
314962306a36Sopenharmony_ci	offset = param_offset + params;
315062306a36Sopenharmony_ci	parm_data = ((char *)pSMB) + sizeof(pSMB->hdr.smb_buf_length) + offset;
315162306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	/* convert to on the wire format for POSIX ACL */
315462306a36Sopenharmony_ci	data_count = posix_acl_to_cifs(parm_data, acl, acl_type);
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	if (data_count == 0) {
315762306a36Sopenharmony_ci		rc = -EOPNOTSUPP;
315862306a36Sopenharmony_ci		goto setACLerrorExit;
315962306a36Sopenharmony_ci	}
316062306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
316162306a36Sopenharmony_ci	pSMB->SetupCount = 1;
316262306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
316362306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
316462306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
316562306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + data_count;
316662306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(data_count);
316762306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
316862306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
316962306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
317062306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
317162306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
317262306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
317362306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
317462306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
317562306a36Sopenharmony_ci	if (rc)
317662306a36Sopenharmony_ci		cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_cisetACLerrorExit:
317962306a36Sopenharmony_ci	cifs_buf_release(pSMB);
318062306a36Sopenharmony_ci	if (rc == -EAGAIN)
318162306a36Sopenharmony_ci		goto setAclRetry;
318262306a36Sopenharmony_ci	return rc;
318362306a36Sopenharmony_ci}
318462306a36Sopenharmony_ci#else
318562306a36Sopenharmony_ciint cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
318662306a36Sopenharmony_ci		    const unsigned char *searchName, struct posix_acl **acl,
318762306a36Sopenharmony_ci		    const int acl_type, const struct nls_table *nls_codepage,
318862306a36Sopenharmony_ci		    int remap)
318962306a36Sopenharmony_ci{
319062306a36Sopenharmony_ci	return -EOPNOTSUPP;
319162306a36Sopenharmony_ci}
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ciint cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
319462306a36Sopenharmony_ci		    const unsigned char *fileName, const struct posix_acl *acl,
319562306a36Sopenharmony_ci		    const int acl_type, const struct nls_table *nls_codepage,
319662306a36Sopenharmony_ci		    int remap)
319762306a36Sopenharmony_ci{
319862306a36Sopenharmony_ci	return -EOPNOTSUPP;
319962306a36Sopenharmony_ci}
320062306a36Sopenharmony_ci#endif /* CONFIG_FS_POSIX_ACL */
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ciint
320362306a36Sopenharmony_ciCIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
320462306a36Sopenharmony_ci	       const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
320562306a36Sopenharmony_ci{
320662306a36Sopenharmony_ci	int rc = 0;
320762306a36Sopenharmony_ci	struct smb_t2_qfi_req *pSMB = NULL;
320862306a36Sopenharmony_ci	struct smb_t2_qfi_rsp *pSMBr = NULL;
320962306a36Sopenharmony_ci	int bytes_returned;
321062306a36Sopenharmony_ci	__u16 params, byte_count;
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	cifs_dbg(FYI, "In GetExtAttr\n");
321362306a36Sopenharmony_ci	if (tcon == NULL)
321462306a36Sopenharmony_ci		return -ENODEV;
321562306a36Sopenharmony_ci
321662306a36Sopenharmony_ciGetExtAttrRetry:
321762306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
321862306a36Sopenharmony_ci		      (void **) &pSMBr);
321962306a36Sopenharmony_ci	if (rc)
322062306a36Sopenharmony_ci		return rc;
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	params = 2 /* level */ + 2 /* fid */;
322362306a36Sopenharmony_ci	pSMB->t2.TotalDataCount = 0;
322462306a36Sopenharmony_ci	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
322562306a36Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
322662306a36Sopenharmony_ci	pSMB->t2.MaxDataCount = cpu_to_le16(4000);
322762306a36Sopenharmony_ci	pSMB->t2.MaxSetupCount = 0;
322862306a36Sopenharmony_ci	pSMB->t2.Reserved = 0;
322962306a36Sopenharmony_ci	pSMB->t2.Flags = 0;
323062306a36Sopenharmony_ci	pSMB->t2.Timeout = 0;
323162306a36Sopenharmony_ci	pSMB->t2.Reserved2 = 0;
323262306a36Sopenharmony_ci	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
323362306a36Sopenharmony_ci					       Fid) - 4);
323462306a36Sopenharmony_ci	pSMB->t2.DataCount = 0;
323562306a36Sopenharmony_ci	pSMB->t2.DataOffset = 0;
323662306a36Sopenharmony_ci	pSMB->t2.SetupCount = 1;
323762306a36Sopenharmony_ci	pSMB->t2.Reserved3 = 0;
323862306a36Sopenharmony_ci	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
323962306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
324062306a36Sopenharmony_ci	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
324162306a36Sopenharmony_ci	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
324262306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
324362306a36Sopenharmony_ci	pSMB->Pad = 0;
324462306a36Sopenharmony_ci	pSMB->Fid = netfid;
324562306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
324662306a36Sopenharmony_ci	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
324962306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
325062306a36Sopenharmony_ci	if (rc) {
325162306a36Sopenharmony_ci		cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
325262306a36Sopenharmony_ci	} else {
325362306a36Sopenharmony_ci		/* decode response */
325462306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
325562306a36Sopenharmony_ci		/* BB also check enough total bytes returned */
325662306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 2)
325762306a36Sopenharmony_ci			/* If rc should we check for EOPNOSUPP and
325862306a36Sopenharmony_ci			   disable the srvino flag? or in caller? */
325962306a36Sopenharmony_ci			rc = -EIO;      /* bad smb */
326062306a36Sopenharmony_ci		else {
326162306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
326262306a36Sopenharmony_ci			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
326362306a36Sopenharmony_ci			struct file_chattr_info *pfinfo;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci			if (count != 16) {
326662306a36Sopenharmony_ci				cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
326762306a36Sopenharmony_ci				rc = -EIO;
326862306a36Sopenharmony_ci				goto GetExtAttrOut;
326962306a36Sopenharmony_ci			}
327062306a36Sopenharmony_ci			pfinfo = (struct file_chattr_info *)
327162306a36Sopenharmony_ci				 (data_offset + (char *) &pSMBr->hdr.Protocol);
327262306a36Sopenharmony_ci			*pExtAttrBits = le64_to_cpu(pfinfo->mode);
327362306a36Sopenharmony_ci			*pMask = le64_to_cpu(pfinfo->mask);
327462306a36Sopenharmony_ci		}
327562306a36Sopenharmony_ci	}
327662306a36Sopenharmony_ciGetExtAttrOut:
327762306a36Sopenharmony_ci	cifs_buf_release(pSMB);
327862306a36Sopenharmony_ci	if (rc == -EAGAIN)
327962306a36Sopenharmony_ci		goto GetExtAttrRetry;
328062306a36Sopenharmony_ci	return rc;
328162306a36Sopenharmony_ci}
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci#endif /* CONFIG_POSIX */
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci/*
328662306a36Sopenharmony_ci * Initialize NT TRANSACT SMB into small smb request buffer.  This assumes that
328762306a36Sopenharmony_ci * all NT TRANSACTS that we init here have total parm and data under about 400
328862306a36Sopenharmony_ci * bytes (to fit in small cifs buffer size), which is the case so far, it
328962306a36Sopenharmony_ci * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
329062306a36Sopenharmony_ci * returned setup area) and MaxParameterCount (returned parms size) must be set
329162306a36Sopenharmony_ci * by caller
329262306a36Sopenharmony_ci */
329362306a36Sopenharmony_cistatic int
329462306a36Sopenharmony_cismb_init_nttransact(const __u16 sub_command, const int setup_count,
329562306a36Sopenharmony_ci		   const int parm_len, struct cifs_tcon *tcon,
329662306a36Sopenharmony_ci		   void **ret_buf)
329762306a36Sopenharmony_ci{
329862306a36Sopenharmony_ci	int rc;
329962306a36Sopenharmony_ci	__u32 temp_offset;
330062306a36Sopenharmony_ci	struct smb_com_ntransact_req *pSMB;
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
330362306a36Sopenharmony_ci				(void **)&pSMB);
330462306a36Sopenharmony_ci	if (rc)
330562306a36Sopenharmony_ci		return rc;
330662306a36Sopenharmony_ci	*ret_buf = (void *)pSMB;
330762306a36Sopenharmony_ci	pSMB->Reserved = 0;
330862306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le32(parm_len);
330962306a36Sopenharmony_ci	pSMB->TotalDataCount  = 0;
331062306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
331162306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
331262306a36Sopenharmony_ci	pSMB->DataCount  = pSMB->TotalDataCount;
331362306a36Sopenharmony_ci	temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
331462306a36Sopenharmony_ci			(setup_count * 2) - 4 /* for rfc1001 length itself */;
331562306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le32(temp_offset);
331662306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
331762306a36Sopenharmony_ci	pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
331862306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(sub_command);
331962306a36Sopenharmony_ci	return 0;
332062306a36Sopenharmony_ci}
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_cistatic int
332362306a36Sopenharmony_civalidate_ntransact(char *buf, char **ppparm, char **ppdata,
332462306a36Sopenharmony_ci		   __u32 *pparmlen, __u32 *pdatalen)
332562306a36Sopenharmony_ci{
332662306a36Sopenharmony_ci	char *end_of_smb;
332762306a36Sopenharmony_ci	__u32 data_count, data_offset, parm_count, parm_offset;
332862306a36Sopenharmony_ci	struct smb_com_ntransact_rsp *pSMBr;
332962306a36Sopenharmony_ci	u16 bcc;
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	*pdatalen = 0;
333262306a36Sopenharmony_ci	*pparmlen = 0;
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	if (buf == NULL)
333562306a36Sopenharmony_ci		return -EINVAL;
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	pSMBr = (struct smb_com_ntransact_rsp *)buf;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	bcc = get_bcc(&pSMBr->hdr);
334062306a36Sopenharmony_ci	end_of_smb = 2 /* sizeof byte count */ + bcc +
334162306a36Sopenharmony_ci			(char *)&pSMBr->ByteCount;
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci	data_offset = le32_to_cpu(pSMBr->DataOffset);
334462306a36Sopenharmony_ci	data_count = le32_to_cpu(pSMBr->DataCount);
334562306a36Sopenharmony_ci	parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
334662306a36Sopenharmony_ci	parm_count = le32_to_cpu(pSMBr->ParameterCount);
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	*ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
334962306a36Sopenharmony_ci	*ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	/* should we also check that parm and data areas do not overlap? */
335262306a36Sopenharmony_ci	if (*ppparm > end_of_smb) {
335362306a36Sopenharmony_ci		cifs_dbg(FYI, "parms start after end of smb\n");
335462306a36Sopenharmony_ci		return -EINVAL;
335562306a36Sopenharmony_ci	} else if (parm_count + *ppparm > end_of_smb) {
335662306a36Sopenharmony_ci		cifs_dbg(FYI, "parm end after end of smb\n");
335762306a36Sopenharmony_ci		return -EINVAL;
335862306a36Sopenharmony_ci	} else if (*ppdata > end_of_smb) {
335962306a36Sopenharmony_ci		cifs_dbg(FYI, "data starts after end of smb\n");
336062306a36Sopenharmony_ci		return -EINVAL;
336162306a36Sopenharmony_ci	} else if (data_count + *ppdata > end_of_smb) {
336262306a36Sopenharmony_ci		cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
336362306a36Sopenharmony_ci			 *ppdata, data_count, (data_count + *ppdata),
336462306a36Sopenharmony_ci			 end_of_smb, pSMBr);
336562306a36Sopenharmony_ci		return -EINVAL;
336662306a36Sopenharmony_ci	} else if (parm_count + data_count > bcc) {
336762306a36Sopenharmony_ci		cifs_dbg(FYI, "parm count and data count larger than SMB\n");
336862306a36Sopenharmony_ci		return -EINVAL;
336962306a36Sopenharmony_ci	}
337062306a36Sopenharmony_ci	*pdatalen = data_count;
337162306a36Sopenharmony_ci	*pparmlen = parm_count;
337262306a36Sopenharmony_ci	return 0;
337362306a36Sopenharmony_ci}
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci/* Get Security Descriptor (by handle) from remote server for a file or dir */
337662306a36Sopenharmony_ciint
337762306a36Sopenharmony_ciCIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
337862306a36Sopenharmony_ci		  struct cifs_ntsd **acl_inf, __u32 *pbuflen)
337962306a36Sopenharmony_ci{
338062306a36Sopenharmony_ci	int rc = 0;
338162306a36Sopenharmony_ci	int buf_type = 0;
338262306a36Sopenharmony_ci	QUERY_SEC_DESC_REQ *pSMB;
338362306a36Sopenharmony_ci	struct kvec iov[1];
338462306a36Sopenharmony_ci	struct kvec rsp_iov;
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci	cifs_dbg(FYI, "GetCifsACL\n");
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	*pbuflen = 0;
338962306a36Sopenharmony_ci	*acl_inf = NULL;
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci	rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
339262306a36Sopenharmony_ci			8 /* parm len */, tcon, (void **) &pSMB);
339362306a36Sopenharmony_ci	if (rc)
339462306a36Sopenharmony_ci		return rc;
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le32(4);
339762306a36Sopenharmony_ci	/* BB TEST with big acls that might need to be e.g. larger than 16K */
339862306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
339962306a36Sopenharmony_ci	pSMB->Fid = fid; /* file handle always le */
340062306a36Sopenharmony_ci	pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
340162306a36Sopenharmony_ci				     CIFS_ACL_DACL);
340262306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
340362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, 11);
340462306a36Sopenharmony_ci	iov[0].iov_base = (char *)pSMB;
340562306a36Sopenharmony_ci	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
340862306a36Sopenharmony_ci			  0, &rsp_iov);
340962306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
341062306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
341162306a36Sopenharmony_ci	if (rc) {
341262306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
341362306a36Sopenharmony_ci	} else {                /* decode response */
341462306a36Sopenharmony_ci		__le32 *parm;
341562306a36Sopenharmony_ci		__u32 parm_len;
341662306a36Sopenharmony_ci		__u32 acl_len;
341762306a36Sopenharmony_ci		struct smb_com_ntransact_rsp *pSMBr;
341862306a36Sopenharmony_ci		char *pdata;
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci/* validate_nttransact */
342162306a36Sopenharmony_ci		rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
342262306a36Sopenharmony_ci					&pdata, &parm_len, pbuflen);
342362306a36Sopenharmony_ci		if (rc)
342462306a36Sopenharmony_ci			goto qsec_out;
342562306a36Sopenharmony_ci		pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci		cifs_dbg(FYI, "smb %p parm %p data %p\n",
342862306a36Sopenharmony_ci			 pSMBr, parm, *acl_inf);
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci		if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
343162306a36Sopenharmony_ci			rc = -EIO;      /* bad smb */
343262306a36Sopenharmony_ci			*pbuflen = 0;
343362306a36Sopenharmony_ci			goto qsec_out;
343462306a36Sopenharmony_ci		}
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci/* BB check that data area is minimum length and as big as acl_len */
343762306a36Sopenharmony_ci
343862306a36Sopenharmony_ci		acl_len = le32_to_cpu(*parm);
343962306a36Sopenharmony_ci		if (acl_len != *pbuflen) {
344062306a36Sopenharmony_ci			cifs_dbg(VFS, "acl length %d does not match %d\n",
344162306a36Sopenharmony_ci				 acl_len, *pbuflen);
344262306a36Sopenharmony_ci			if (*pbuflen > acl_len)
344362306a36Sopenharmony_ci				*pbuflen = acl_len;
344462306a36Sopenharmony_ci		}
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci		/* check if buffer is big enough for the acl
344762306a36Sopenharmony_ci		   header followed by the smallest SID */
344862306a36Sopenharmony_ci		if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
344962306a36Sopenharmony_ci		    (*pbuflen >= 64 * 1024)) {
345062306a36Sopenharmony_ci			cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
345162306a36Sopenharmony_ci			rc = -EINVAL;
345262306a36Sopenharmony_ci			*pbuflen = 0;
345362306a36Sopenharmony_ci		} else {
345462306a36Sopenharmony_ci			*acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
345562306a36Sopenharmony_ci			if (*acl_inf == NULL) {
345662306a36Sopenharmony_ci				*pbuflen = 0;
345762306a36Sopenharmony_ci				rc = -ENOMEM;
345862306a36Sopenharmony_ci			}
345962306a36Sopenharmony_ci		}
346062306a36Sopenharmony_ci	}
346162306a36Sopenharmony_ciqsec_out:
346262306a36Sopenharmony_ci	free_rsp_buf(buf_type, rsp_iov.iov_base);
346362306a36Sopenharmony_ci	return rc;
346462306a36Sopenharmony_ci}
346562306a36Sopenharmony_ci
346662306a36Sopenharmony_ciint
346762306a36Sopenharmony_ciCIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
346862306a36Sopenharmony_ci			struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
346962306a36Sopenharmony_ci{
347062306a36Sopenharmony_ci	__u16 byte_count, param_count, data_count, param_offset, data_offset;
347162306a36Sopenharmony_ci	int rc = 0;
347262306a36Sopenharmony_ci	int bytes_returned = 0;
347362306a36Sopenharmony_ci	SET_SEC_DESC_REQ *pSMB = NULL;
347462306a36Sopenharmony_ci	void *pSMBr;
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_cisetCifsAclRetry:
347762306a36Sopenharmony_ci	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
347862306a36Sopenharmony_ci	if (rc)
347962306a36Sopenharmony_ci		return rc;
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
348262306a36Sopenharmony_ci	pSMB->Reserved = 0;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	param_count = 8;
348562306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
348662306a36Sopenharmony_ci	data_count = acllen;
348762306a36Sopenharmony_ci	data_offset = param_offset + param_count;
348862306a36Sopenharmony_ci	byte_count = 3 /* pad */  + param_count;
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le32(data_count);
349162306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
349262306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le32(4);
349362306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le32(16384);
349462306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le32(param_count);
349562306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le32(param_offset);
349662306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
349762306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le32(data_offset);
349862306a36Sopenharmony_ci	pSMB->SetupCount = 0;
349962306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
350062306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
350162306a36Sopenharmony_ci
350262306a36Sopenharmony_ci	pSMB->Fid = fid; /* file handle always le */
350362306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
350462306a36Sopenharmony_ci	pSMB->AclFlags = cpu_to_le32(aclflag);
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci	if (pntsd && acllen) {
350762306a36Sopenharmony_ci		memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
350862306a36Sopenharmony_ci				data_offset, pntsd, acllen);
350962306a36Sopenharmony_ci		inc_rfc1001_len(pSMB, byte_count + data_count);
351062306a36Sopenharmony_ci	} else
351162306a36Sopenharmony_ci		inc_rfc1001_len(pSMB, byte_count);
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
351462306a36Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
351762306a36Sopenharmony_ci		 bytes_returned, rc);
351862306a36Sopenharmony_ci	if (rc)
351962306a36Sopenharmony_ci		cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
352062306a36Sopenharmony_ci	cifs_buf_release(pSMB);
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_ci	if (rc == -EAGAIN)
352362306a36Sopenharmony_ci		goto setCifsAclRetry;
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci	return (rc);
352662306a36Sopenharmony_ci}
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci/* Legacy Query Path Information call for lookup to old servers such
353062306a36Sopenharmony_ci   as Win9x/WinME */
353162306a36Sopenharmony_ciint
353262306a36Sopenharmony_ciSMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
353362306a36Sopenharmony_ci		    const char *search_name, FILE_ALL_INFO *data,
353462306a36Sopenharmony_ci		    const struct nls_table *nls_codepage, int remap)
353562306a36Sopenharmony_ci{
353662306a36Sopenharmony_ci	QUERY_INFORMATION_REQ *pSMB;
353762306a36Sopenharmony_ci	QUERY_INFORMATION_RSP *pSMBr;
353862306a36Sopenharmony_ci	int rc = 0;
353962306a36Sopenharmony_ci	int bytes_returned;
354062306a36Sopenharmony_ci	int name_len;
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
354362306a36Sopenharmony_ciQInfRetry:
354462306a36Sopenharmony_ci	rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
354562306a36Sopenharmony_ci		      (void **) &pSMBr);
354662306a36Sopenharmony_ci	if (rc)
354762306a36Sopenharmony_ci		return rc;
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
355062306a36Sopenharmony_ci		name_len =
355162306a36Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName,
355262306a36Sopenharmony_ci					   search_name, PATH_MAX, nls_codepage,
355362306a36Sopenharmony_ci					   remap);
355462306a36Sopenharmony_ci		name_len++;     /* trailing null */
355562306a36Sopenharmony_ci		name_len *= 2;
355662306a36Sopenharmony_ci	} else {
355762306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, search_name);
355862306a36Sopenharmony_ci	}
355962306a36Sopenharmony_ci	pSMB->BufferFormat = 0x04;
356062306a36Sopenharmony_ci	name_len++; /* account for buffer type byte */
356162306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, (__u16)name_len);
356262306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len);
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
356562306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
356662306a36Sopenharmony_ci	if (rc) {
356762306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
356862306a36Sopenharmony_ci	} else if (data) {
356962306a36Sopenharmony_ci		struct timespec64 ts;
357062306a36Sopenharmony_ci		__u32 time = le32_to_cpu(pSMBr->last_write_time);
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci		/* decode response */
357362306a36Sopenharmony_ci		/* BB FIXME - add time zone adjustment BB */
357462306a36Sopenharmony_ci		memset(data, 0, sizeof(FILE_ALL_INFO));
357562306a36Sopenharmony_ci		ts.tv_nsec = 0;
357662306a36Sopenharmony_ci		ts.tv_sec = time;
357762306a36Sopenharmony_ci		/* decode time fields */
357862306a36Sopenharmony_ci		data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
357962306a36Sopenharmony_ci		data->LastWriteTime = data->ChangeTime;
358062306a36Sopenharmony_ci		data->LastAccessTime = 0;
358162306a36Sopenharmony_ci		data->AllocationSize =
358262306a36Sopenharmony_ci			cpu_to_le64(le32_to_cpu(pSMBr->size));
358362306a36Sopenharmony_ci		data->EndOfFile = data->AllocationSize;
358462306a36Sopenharmony_ci		data->Attributes =
358562306a36Sopenharmony_ci			cpu_to_le32(le16_to_cpu(pSMBr->attr));
358662306a36Sopenharmony_ci	} else
358762306a36Sopenharmony_ci		rc = -EIO; /* bad buffer passed in */
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_ci	cifs_buf_release(pSMB);
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	if (rc == -EAGAIN)
359262306a36Sopenharmony_ci		goto QInfRetry;
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	return rc;
359562306a36Sopenharmony_ci}
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ciint
359862306a36Sopenharmony_ciCIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
359962306a36Sopenharmony_ci		 u16 netfid, FILE_ALL_INFO *pFindData)
360062306a36Sopenharmony_ci{
360162306a36Sopenharmony_ci	struct smb_t2_qfi_req *pSMB = NULL;
360262306a36Sopenharmony_ci	struct smb_t2_qfi_rsp *pSMBr = NULL;
360362306a36Sopenharmony_ci	int rc = 0;
360462306a36Sopenharmony_ci	int bytes_returned;
360562306a36Sopenharmony_ci	__u16 params, byte_count;
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ciQFileInfoRetry:
360862306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
360962306a36Sopenharmony_ci		      (void **) &pSMBr);
361062306a36Sopenharmony_ci	if (rc)
361162306a36Sopenharmony_ci		return rc;
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci	params = 2 /* level */ + 2 /* fid */;
361462306a36Sopenharmony_ci	pSMB->t2.TotalDataCount = 0;
361562306a36Sopenharmony_ci	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
361662306a36Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
361762306a36Sopenharmony_ci	pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
361862306a36Sopenharmony_ci	pSMB->t2.MaxSetupCount = 0;
361962306a36Sopenharmony_ci	pSMB->t2.Reserved = 0;
362062306a36Sopenharmony_ci	pSMB->t2.Flags = 0;
362162306a36Sopenharmony_ci	pSMB->t2.Timeout = 0;
362262306a36Sopenharmony_ci	pSMB->t2.Reserved2 = 0;
362362306a36Sopenharmony_ci	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
362462306a36Sopenharmony_ci					       Fid) - 4);
362562306a36Sopenharmony_ci	pSMB->t2.DataCount = 0;
362662306a36Sopenharmony_ci	pSMB->t2.DataOffset = 0;
362762306a36Sopenharmony_ci	pSMB->t2.SetupCount = 1;
362862306a36Sopenharmony_ci	pSMB->t2.Reserved3 = 0;
362962306a36Sopenharmony_ci	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
363062306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
363162306a36Sopenharmony_ci	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
363262306a36Sopenharmony_ci	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
363362306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
363462306a36Sopenharmony_ci	pSMB->Pad = 0;
363562306a36Sopenharmony_ci	pSMB->Fid = netfid;
363662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
363762306a36Sopenharmony_ci	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
364062306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
364162306a36Sopenharmony_ci	if (rc) {
364262306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
364362306a36Sopenharmony_ci	} else {		/* decode response */
364462306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci		if (rc) /* BB add auto retry on EOPNOTSUPP? */
364762306a36Sopenharmony_ci			rc = -EIO;
364862306a36Sopenharmony_ci		else if (get_bcc(&pSMBr->hdr) < 40)
364962306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
365062306a36Sopenharmony_ci		else if (pFindData) {
365162306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
365262306a36Sopenharmony_ci			memcpy((char *) pFindData,
365362306a36Sopenharmony_ci			       (char *) &pSMBr->hdr.Protocol +
365462306a36Sopenharmony_ci			       data_offset, sizeof(FILE_ALL_INFO));
365562306a36Sopenharmony_ci		} else
365662306a36Sopenharmony_ci		    rc = -ENOMEM;
365762306a36Sopenharmony_ci	}
365862306a36Sopenharmony_ci	cifs_buf_release(pSMB);
365962306a36Sopenharmony_ci	if (rc == -EAGAIN)
366062306a36Sopenharmony_ci		goto QFileInfoRetry;
366162306a36Sopenharmony_ci
366262306a36Sopenharmony_ci	return rc;
366362306a36Sopenharmony_ci}
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_ciint
366662306a36Sopenharmony_ciCIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
366762306a36Sopenharmony_ci		 const char *search_name, FILE_ALL_INFO *data,
366862306a36Sopenharmony_ci		 int legacy /* old style infolevel */,
366962306a36Sopenharmony_ci		 const struct nls_table *nls_codepage, int remap)
367062306a36Sopenharmony_ci{
367162306a36Sopenharmony_ci	/* level 263 SMB_QUERY_FILE_ALL_INFO */
367262306a36Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
367362306a36Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
367462306a36Sopenharmony_ci	int rc = 0;
367562306a36Sopenharmony_ci	int bytes_returned;
367662306a36Sopenharmony_ci	int name_len;
367762306a36Sopenharmony_ci	__u16 params, byte_count;
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_ci	/* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
368062306a36Sopenharmony_ciQPathInfoRetry:
368162306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
368262306a36Sopenharmony_ci		      (void **) &pSMBr);
368362306a36Sopenharmony_ci	if (rc)
368462306a36Sopenharmony_ci		return rc;
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
368762306a36Sopenharmony_ci		name_len =
368862306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
368962306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
369062306a36Sopenharmony_ci		name_len++;	/* trailing null */
369162306a36Sopenharmony_ci		name_len *= 2;
369262306a36Sopenharmony_ci	} else {
369362306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, search_name);
369462306a36Sopenharmony_ci	}
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
369762306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
369862306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
369962306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
370062306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
370162306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
370262306a36Sopenharmony_ci	pSMB->Reserved = 0;
370362306a36Sopenharmony_ci	pSMB->Flags = 0;
370462306a36Sopenharmony_ci	pSMB->Timeout = 0;
370562306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
370662306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
370762306a36Sopenharmony_ci	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
370862306a36Sopenharmony_ci	pSMB->DataCount = 0;
370962306a36Sopenharmony_ci	pSMB->DataOffset = 0;
371062306a36Sopenharmony_ci	pSMB->SetupCount = 1;
371162306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
371262306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
371362306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
371462306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
371562306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
371662306a36Sopenharmony_ci	if (legacy)
371762306a36Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
371862306a36Sopenharmony_ci	else
371962306a36Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
372062306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
372162306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
372262306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
372562306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
372662306a36Sopenharmony_ci	if (rc) {
372762306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
372862306a36Sopenharmony_ci	} else {		/* decode response */
372962306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci		if (rc) /* BB add auto retry on EOPNOTSUPP? */
373262306a36Sopenharmony_ci			rc = -EIO;
373362306a36Sopenharmony_ci		else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
373462306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
373562306a36Sopenharmony_ci		else if (legacy && get_bcc(&pSMBr->hdr) < 24)
373662306a36Sopenharmony_ci			rc = -EIO;  /* 24 or 26 expected but we do not read
373762306a36Sopenharmony_ci					last field */
373862306a36Sopenharmony_ci		else if (data) {
373962306a36Sopenharmony_ci			int size;
374062306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ci			/*
374362306a36Sopenharmony_ci			 * On legacy responses we do not read the last field,
374462306a36Sopenharmony_ci			 * EAsize, fortunately since it varies by subdialect and
374562306a36Sopenharmony_ci			 * also note it differs on Set vs Get, ie two bytes or 4
374662306a36Sopenharmony_ci			 * bytes depending but we don't care here.
374762306a36Sopenharmony_ci			 */
374862306a36Sopenharmony_ci			if (legacy)
374962306a36Sopenharmony_ci				size = sizeof(FILE_INFO_STANDARD);
375062306a36Sopenharmony_ci			else
375162306a36Sopenharmony_ci				size = sizeof(FILE_ALL_INFO);
375262306a36Sopenharmony_ci			memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
375362306a36Sopenharmony_ci			       data_offset, size);
375462306a36Sopenharmony_ci		} else
375562306a36Sopenharmony_ci		    rc = -ENOMEM;
375662306a36Sopenharmony_ci	}
375762306a36Sopenharmony_ci	cifs_buf_release(pSMB);
375862306a36Sopenharmony_ci	if (rc == -EAGAIN)
375962306a36Sopenharmony_ci		goto QPathInfoRetry;
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci	return rc;
376262306a36Sopenharmony_ci}
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ciint
376562306a36Sopenharmony_ciCIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
376662306a36Sopenharmony_ci		 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
376762306a36Sopenharmony_ci{
376862306a36Sopenharmony_ci	struct smb_t2_qfi_req *pSMB = NULL;
376962306a36Sopenharmony_ci	struct smb_t2_qfi_rsp *pSMBr = NULL;
377062306a36Sopenharmony_ci	int rc = 0;
377162306a36Sopenharmony_ci	int bytes_returned;
377262306a36Sopenharmony_ci	__u16 params, byte_count;
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ciUnixQFileInfoRetry:
377562306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
377662306a36Sopenharmony_ci		      (void **) &pSMBr);
377762306a36Sopenharmony_ci	if (rc)
377862306a36Sopenharmony_ci		return rc;
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci	params = 2 /* level */ + 2 /* fid */;
378162306a36Sopenharmony_ci	pSMB->t2.TotalDataCount = 0;
378262306a36Sopenharmony_ci	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
378362306a36Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
378462306a36Sopenharmony_ci	pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
378562306a36Sopenharmony_ci	pSMB->t2.MaxSetupCount = 0;
378662306a36Sopenharmony_ci	pSMB->t2.Reserved = 0;
378762306a36Sopenharmony_ci	pSMB->t2.Flags = 0;
378862306a36Sopenharmony_ci	pSMB->t2.Timeout = 0;
378962306a36Sopenharmony_ci	pSMB->t2.Reserved2 = 0;
379062306a36Sopenharmony_ci	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
379162306a36Sopenharmony_ci					       Fid) - 4);
379262306a36Sopenharmony_ci	pSMB->t2.DataCount = 0;
379362306a36Sopenharmony_ci	pSMB->t2.DataOffset = 0;
379462306a36Sopenharmony_ci	pSMB->t2.SetupCount = 1;
379562306a36Sopenharmony_ci	pSMB->t2.Reserved3 = 0;
379662306a36Sopenharmony_ci	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
379762306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
379862306a36Sopenharmony_ci	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
379962306a36Sopenharmony_ci	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
380062306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
380162306a36Sopenharmony_ci	pSMB->Pad = 0;
380262306a36Sopenharmony_ci	pSMB->Fid = netfid;
380362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
380462306a36Sopenharmony_ci	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
380562306a36Sopenharmony_ci
380662306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
380762306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
380862306a36Sopenharmony_ci	if (rc) {
380962306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
381062306a36Sopenharmony_ci	} else {		/* decode response */
381162306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
381262306a36Sopenharmony_ci
381362306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
381462306a36Sopenharmony_ci			cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
381562306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
381662306a36Sopenharmony_ci		} else {
381762306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
381862306a36Sopenharmony_ci			memcpy((char *) pFindData,
381962306a36Sopenharmony_ci			       (char *) &pSMBr->hdr.Protocol +
382062306a36Sopenharmony_ci			       data_offset,
382162306a36Sopenharmony_ci			       sizeof(FILE_UNIX_BASIC_INFO));
382262306a36Sopenharmony_ci		}
382362306a36Sopenharmony_ci	}
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci	cifs_buf_release(pSMB);
382662306a36Sopenharmony_ci	if (rc == -EAGAIN)
382762306a36Sopenharmony_ci		goto UnixQFileInfoRetry;
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci	return rc;
383062306a36Sopenharmony_ci}
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ciint
383362306a36Sopenharmony_ciCIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
383462306a36Sopenharmony_ci		     const unsigned char *searchName,
383562306a36Sopenharmony_ci		     FILE_UNIX_BASIC_INFO *pFindData,
383662306a36Sopenharmony_ci		     const struct nls_table *nls_codepage, int remap)
383762306a36Sopenharmony_ci{
383862306a36Sopenharmony_ci/* SMB_QUERY_FILE_UNIX_BASIC */
383962306a36Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
384062306a36Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
384162306a36Sopenharmony_ci	int rc = 0;
384262306a36Sopenharmony_ci	int bytes_returned = 0;
384362306a36Sopenharmony_ci	int name_len;
384462306a36Sopenharmony_ci	__u16 params, byte_count;
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci	cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
384762306a36Sopenharmony_ciUnixQPathInfoRetry:
384862306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
384962306a36Sopenharmony_ci		      (void **) &pSMBr);
385062306a36Sopenharmony_ci	if (rc)
385162306a36Sopenharmony_ci		return rc;
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
385462306a36Sopenharmony_ci		name_len =
385562306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
385662306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
385762306a36Sopenharmony_ci		name_len++;	/* trailing null */
385862306a36Sopenharmony_ci		name_len *= 2;
385962306a36Sopenharmony_ci	} else {
386062306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, searchName);
386162306a36Sopenharmony_ci	}
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
386462306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
386562306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
386662306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
386762306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
386862306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
386962306a36Sopenharmony_ci	pSMB->Reserved = 0;
387062306a36Sopenharmony_ci	pSMB->Flags = 0;
387162306a36Sopenharmony_ci	pSMB->Timeout = 0;
387262306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
387362306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
387462306a36Sopenharmony_ci	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
387562306a36Sopenharmony_ci	pSMB->DataCount = 0;
387662306a36Sopenharmony_ci	pSMB->DataOffset = 0;
387762306a36Sopenharmony_ci	pSMB->SetupCount = 1;
387862306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
387962306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
388062306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
388162306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
388262306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
388362306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
388462306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
388562306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
388662306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
388762306a36Sopenharmony_ci
388862306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
388962306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
389062306a36Sopenharmony_ci	if (rc) {
389162306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
389262306a36Sopenharmony_ci	} else {		/* decode response */
389362306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
389662306a36Sopenharmony_ci			cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
389762306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
389862306a36Sopenharmony_ci		} else {
389962306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
390062306a36Sopenharmony_ci			memcpy((char *) pFindData,
390162306a36Sopenharmony_ci			       (char *) &pSMBr->hdr.Protocol +
390262306a36Sopenharmony_ci			       data_offset,
390362306a36Sopenharmony_ci			       sizeof(FILE_UNIX_BASIC_INFO));
390462306a36Sopenharmony_ci		}
390562306a36Sopenharmony_ci	}
390662306a36Sopenharmony_ci	cifs_buf_release(pSMB);
390762306a36Sopenharmony_ci	if (rc == -EAGAIN)
390862306a36Sopenharmony_ci		goto UnixQPathInfoRetry;
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_ci	return rc;
391162306a36Sopenharmony_ci}
391262306a36Sopenharmony_ci
391362306a36Sopenharmony_ci/* xid, tcon, searchName and codepage are input parms, rest are returned */
391462306a36Sopenharmony_ciint
391562306a36Sopenharmony_ciCIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
391662306a36Sopenharmony_ci	      const char *searchName, struct cifs_sb_info *cifs_sb,
391762306a36Sopenharmony_ci	      __u16 *pnetfid, __u16 search_flags,
391862306a36Sopenharmony_ci	      struct cifs_search_info *psrch_inf, bool msearch)
391962306a36Sopenharmony_ci{
392062306a36Sopenharmony_ci/* level 257 SMB_ */
392162306a36Sopenharmony_ci	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
392262306a36Sopenharmony_ci	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
392362306a36Sopenharmony_ci	T2_FFIRST_RSP_PARMS *parms;
392462306a36Sopenharmony_ci	struct nls_table *nls_codepage;
392562306a36Sopenharmony_ci	unsigned int lnoff;
392662306a36Sopenharmony_ci	__u16 params, byte_count;
392762306a36Sopenharmony_ci	int bytes_returned = 0;
392862306a36Sopenharmony_ci	int name_len, remap;
392962306a36Sopenharmony_ci	int rc = 0;
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ci	cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_cifindFirstRetry:
393462306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
393562306a36Sopenharmony_ci		      (void **) &pSMBr);
393662306a36Sopenharmony_ci	if (rc)
393762306a36Sopenharmony_ci		return rc;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	nls_codepage = cifs_sb->local_nls;
394062306a36Sopenharmony_ci	remap = cifs_remap(cifs_sb);
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
394362306a36Sopenharmony_ci		name_len =
394462306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
394562306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
394662306a36Sopenharmony_ci		/* We can not add the asterik earlier in case
394762306a36Sopenharmony_ci		it got remapped to 0xF03A as if it were part of the
394862306a36Sopenharmony_ci		directory name instead of a wildcard */
394962306a36Sopenharmony_ci		name_len *= 2;
395062306a36Sopenharmony_ci		if (msearch) {
395162306a36Sopenharmony_ci			pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
395262306a36Sopenharmony_ci			pSMB->FileName[name_len+1] = 0;
395362306a36Sopenharmony_ci			pSMB->FileName[name_len+2] = '*';
395462306a36Sopenharmony_ci			pSMB->FileName[name_len+3] = 0;
395562306a36Sopenharmony_ci			name_len += 4; /* now the trailing null */
395662306a36Sopenharmony_ci			/* null terminate just in case */
395762306a36Sopenharmony_ci			pSMB->FileName[name_len] = 0;
395862306a36Sopenharmony_ci			pSMB->FileName[name_len+1] = 0;
395962306a36Sopenharmony_ci			name_len += 2;
396062306a36Sopenharmony_ci		}
396162306a36Sopenharmony_ci	} else {
396262306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, searchName);
396362306a36Sopenharmony_ci		if (msearch) {
396462306a36Sopenharmony_ci			if (WARN_ON_ONCE(name_len > PATH_MAX-2))
396562306a36Sopenharmony_ci				name_len = PATH_MAX-2;
396662306a36Sopenharmony_ci			/* overwrite nul byte */
396762306a36Sopenharmony_ci			pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
396862306a36Sopenharmony_ci			pSMB->FileName[name_len] = '*';
396962306a36Sopenharmony_ci			pSMB->FileName[name_len+1] = 0;
397062306a36Sopenharmony_ci			name_len += 2;
397162306a36Sopenharmony_ci		}
397262306a36Sopenharmony_ci	}
397362306a36Sopenharmony_ci
397462306a36Sopenharmony_ci	params = 12 + name_len /* includes null */ ;
397562306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;	/* no EAs */
397662306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(10);
397762306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
397862306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
397962306a36Sopenharmony_ci	pSMB->Reserved = 0;
398062306a36Sopenharmony_ci	pSMB->Flags = 0;
398162306a36Sopenharmony_ci	pSMB->Timeout = 0;
398262306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
398362306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
398462306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
398562306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
398662306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(
398762306a36Sopenharmony_ci	      offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
398862306a36Sopenharmony_ci		- 4);
398962306a36Sopenharmony_ci	pSMB->DataCount = 0;
399062306a36Sopenharmony_ci	pSMB->DataOffset = 0;
399162306a36Sopenharmony_ci	pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */
399262306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
399362306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
399462306a36Sopenharmony_ci	pSMB->SearchAttributes =
399562306a36Sopenharmony_ci	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
399662306a36Sopenharmony_ci			ATTR_DIRECTORY);
399762306a36Sopenharmony_ci	pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
399862306a36Sopenharmony_ci	pSMB->SearchFlags = cpu_to_le16(search_flags);
399962306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
400062306a36Sopenharmony_ci
400162306a36Sopenharmony_ci	/* BB what should we set StorageType to? Does it matter? BB */
400262306a36Sopenharmony_ci	pSMB->SearchStorageType = 0;
400362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
400462306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
400762306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
400862306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ci	if (rc) {
401162306a36Sopenharmony_ci		/*
401262306a36Sopenharmony_ci		 * BB: add logic to retry regular search if Unix search rejected
401362306a36Sopenharmony_ci		 * unexpectedly by server.
401462306a36Sopenharmony_ci		 */
401562306a36Sopenharmony_ci		/* BB: add code to handle unsupported level rc */
401662306a36Sopenharmony_ci		cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
401762306a36Sopenharmony_ci		cifs_buf_release(pSMB);
401862306a36Sopenharmony_ci		/*
401962306a36Sopenharmony_ci		 * BB: eventually could optimize out free and realloc of buf for
402062306a36Sopenharmony_ci		 * this case.
402162306a36Sopenharmony_ci		 */
402262306a36Sopenharmony_ci		if (rc == -EAGAIN)
402362306a36Sopenharmony_ci			goto findFirstRetry;
402462306a36Sopenharmony_ci		return rc;
402562306a36Sopenharmony_ci	}
402662306a36Sopenharmony_ci	/* decode response */
402762306a36Sopenharmony_ci	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
402862306a36Sopenharmony_ci	if (rc) {
402962306a36Sopenharmony_ci		cifs_buf_release(pSMB);
403062306a36Sopenharmony_ci		return rc;
403162306a36Sopenharmony_ci	}
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci	psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
403462306a36Sopenharmony_ci	psrch_inf->ntwrk_buf_start = (char *)pSMBr;
403562306a36Sopenharmony_ci	psrch_inf->smallBuf = false;
403662306a36Sopenharmony_ci	psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol +
403762306a36Sopenharmony_ci		le16_to_cpu(pSMBr->t2.DataOffset);
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci	parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol +
404062306a36Sopenharmony_ci					le16_to_cpu(pSMBr->t2.ParameterOffset));
404162306a36Sopenharmony_ci	psrch_inf->endOfSearch = !!parms->EndofSearch;
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci	psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
404462306a36Sopenharmony_ci	psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
404562306a36Sopenharmony_ci		psrch_inf->entries_in_buffer;
404662306a36Sopenharmony_ci	lnoff = le16_to_cpu(parms->LastNameOffset);
404762306a36Sopenharmony_ci	if (CIFSMaxBufSize < lnoff) {
404862306a36Sopenharmony_ci		cifs_dbg(VFS, "ignoring corrupt resume name\n");
404962306a36Sopenharmony_ci		psrch_inf->last_entry = NULL;
405062306a36Sopenharmony_ci	} else {
405162306a36Sopenharmony_ci		psrch_inf->last_entry = psrch_inf->srch_entries_start + lnoff;
405262306a36Sopenharmony_ci		if (pnetfid)
405362306a36Sopenharmony_ci			*pnetfid = parms->SearchHandle;
405462306a36Sopenharmony_ci	}
405562306a36Sopenharmony_ci	return 0;
405662306a36Sopenharmony_ci}
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_ciint CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
405962306a36Sopenharmony_ci		 __u16 searchHandle, __u16 search_flags,
406062306a36Sopenharmony_ci		 struct cifs_search_info *psrch_inf)
406162306a36Sopenharmony_ci{
406262306a36Sopenharmony_ci	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
406362306a36Sopenharmony_ci	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
406462306a36Sopenharmony_ci	T2_FNEXT_RSP_PARMS *parms;
406562306a36Sopenharmony_ci	unsigned int name_len;
406662306a36Sopenharmony_ci	unsigned int lnoff;
406762306a36Sopenharmony_ci	__u16 params, byte_count;
406862306a36Sopenharmony_ci	char *response_data;
406962306a36Sopenharmony_ci	int bytes_returned;
407062306a36Sopenharmony_ci	int rc = 0;
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_ci	cifs_dbg(FYI, "In FindNext\n");
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_ci	if (psrch_inf->endOfSearch)
407562306a36Sopenharmony_ci		return -ENOENT;
407662306a36Sopenharmony_ci
407762306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
407862306a36Sopenharmony_ci		(void **) &pSMBr);
407962306a36Sopenharmony_ci	if (rc)
408062306a36Sopenharmony_ci		return rc;
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_ci	params = 14; /* includes 2 bytes of null string, converted to LE below*/
408362306a36Sopenharmony_ci	byte_count = 0;
408462306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;       /* no EAs */
408562306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(8);
408662306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
408762306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
408862306a36Sopenharmony_ci	pSMB->Reserved = 0;
408962306a36Sopenharmony_ci	pSMB->Flags = 0;
409062306a36Sopenharmony_ci	pSMB->Timeout = 0;
409162306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
409262306a36Sopenharmony_ci	pSMB->ParameterOffset =  cpu_to_le16(
409362306a36Sopenharmony_ci	      offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
409462306a36Sopenharmony_ci	pSMB->DataCount = 0;
409562306a36Sopenharmony_ci	pSMB->DataOffset = 0;
409662306a36Sopenharmony_ci	pSMB->SetupCount = 1;
409762306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
409862306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
409962306a36Sopenharmony_ci	pSMB->SearchHandle = searchHandle;      /* always kept as le */
410062306a36Sopenharmony_ci	pSMB->SearchCount =
410162306a36Sopenharmony_ci		cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
410262306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
410362306a36Sopenharmony_ci	pSMB->ResumeKey = psrch_inf->resume_key;
410462306a36Sopenharmony_ci	pSMB->SearchFlags = cpu_to_le16(search_flags);
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	name_len = psrch_inf->resume_name_len;
410762306a36Sopenharmony_ci	params += name_len;
410862306a36Sopenharmony_ci	if (name_len < PATH_MAX) {
410962306a36Sopenharmony_ci		memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
411062306a36Sopenharmony_ci		byte_count += name_len;
411162306a36Sopenharmony_ci		/* 14 byte parm len above enough for 2 byte null terminator */
411262306a36Sopenharmony_ci		pSMB->ResumeFileName[name_len] = 0;
411362306a36Sopenharmony_ci		pSMB->ResumeFileName[name_len+1] = 0;
411462306a36Sopenharmony_ci	} else {
411562306a36Sopenharmony_ci		cifs_buf_release(pSMB);
411662306a36Sopenharmony_ci		return -EINVAL;
411762306a36Sopenharmony_ci	}
411862306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
411962306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
412062306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
412162306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
412262306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
412562306a36Sopenharmony_ci			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
412662306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci	if (rc) {
412962306a36Sopenharmony_ci		cifs_buf_release(pSMB);
413062306a36Sopenharmony_ci		if (rc == -EBADF) {
413162306a36Sopenharmony_ci			psrch_inf->endOfSearch = true;
413262306a36Sopenharmony_ci			rc = 0; /* search probably was closed at end of search*/
413362306a36Sopenharmony_ci		} else {
413462306a36Sopenharmony_ci			cifs_dbg(FYI, "FindNext returned = %d\n", rc);
413562306a36Sopenharmony_ci		}
413662306a36Sopenharmony_ci		return rc;
413762306a36Sopenharmony_ci	}
413862306a36Sopenharmony_ci
413962306a36Sopenharmony_ci	/* decode response */
414062306a36Sopenharmony_ci	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
414162306a36Sopenharmony_ci	if (rc) {
414262306a36Sopenharmony_ci		cifs_buf_release(pSMB);
414362306a36Sopenharmony_ci		return rc;
414462306a36Sopenharmony_ci	}
414562306a36Sopenharmony_ci	/* BB fixme add lock for file (srch_info) struct here */
414662306a36Sopenharmony_ci	psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
414762306a36Sopenharmony_ci	response_data = (char *)&pSMBr->hdr.Protocol +
414862306a36Sopenharmony_ci		le16_to_cpu(pSMBr->t2.ParameterOffset);
414962306a36Sopenharmony_ci	parms = (T2_FNEXT_RSP_PARMS *)response_data;
415062306a36Sopenharmony_ci	response_data = (char *)&pSMBr->hdr.Protocol +
415162306a36Sopenharmony_ci		le16_to_cpu(pSMBr->t2.DataOffset);
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci	if (psrch_inf->smallBuf)
415462306a36Sopenharmony_ci		cifs_small_buf_release(psrch_inf->ntwrk_buf_start);
415562306a36Sopenharmony_ci	else
415662306a36Sopenharmony_ci		cifs_buf_release(psrch_inf->ntwrk_buf_start);
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ci	psrch_inf->srch_entries_start = response_data;
415962306a36Sopenharmony_ci	psrch_inf->ntwrk_buf_start = (char *)pSMB;
416062306a36Sopenharmony_ci	psrch_inf->smallBuf = false;
416162306a36Sopenharmony_ci	psrch_inf->endOfSearch = !!parms->EndofSearch;
416262306a36Sopenharmony_ci	psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
416362306a36Sopenharmony_ci	psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer;
416462306a36Sopenharmony_ci	lnoff = le16_to_cpu(parms->LastNameOffset);
416562306a36Sopenharmony_ci	if (CIFSMaxBufSize < lnoff) {
416662306a36Sopenharmony_ci		cifs_dbg(VFS, "ignoring corrupt resume name\n");
416762306a36Sopenharmony_ci		psrch_inf->last_entry = NULL;
416862306a36Sopenharmony_ci	} else {
416962306a36Sopenharmony_ci		psrch_inf->last_entry =
417062306a36Sopenharmony_ci			psrch_inf->srch_entries_start + lnoff;
417162306a36Sopenharmony_ci	}
417262306a36Sopenharmony_ci	/* BB fixme add unlock here */
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci	/*
417562306a36Sopenharmony_ci	 * BB: On error, should we leave previous search buf
417662306a36Sopenharmony_ci	 * (and count and last entry fields) intact or free the previous one?
417762306a36Sopenharmony_ci	 *
417862306a36Sopenharmony_ci	 * Note: On -EAGAIN error only caller can retry on handle based calls
417962306a36Sopenharmony_ci	 * since file handle passed in no longer valid.
418062306a36Sopenharmony_ci	 */
418162306a36Sopenharmony_ci	return 0;
418262306a36Sopenharmony_ci}
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_ciint
418562306a36Sopenharmony_ciCIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
418662306a36Sopenharmony_ci	      const __u16 searchHandle)
418762306a36Sopenharmony_ci{
418862306a36Sopenharmony_ci	int rc = 0;
418962306a36Sopenharmony_ci	FINDCLOSE_REQ *pSMB = NULL;
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBFindClose\n");
419262306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
419362306a36Sopenharmony_ci
419462306a36Sopenharmony_ci	/* no sense returning error if session restarted
419562306a36Sopenharmony_ci		as file handle has been closed */
419662306a36Sopenharmony_ci	if (rc == -EAGAIN)
419762306a36Sopenharmony_ci		return 0;
419862306a36Sopenharmony_ci	if (rc)
419962306a36Sopenharmony_ci		return rc;
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_ci	pSMB->FileID = searchHandle;
420262306a36Sopenharmony_ci	pSMB->ByteCount = 0;
420362306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
420462306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
420562306a36Sopenharmony_ci	if (rc)
420662306a36Sopenharmony_ci		cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
420762306a36Sopenharmony_ci
420862306a36Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
420962306a36Sopenharmony_ci
421062306a36Sopenharmony_ci	/* Since session is dead, search handle closed on server already */
421162306a36Sopenharmony_ci	if (rc == -EAGAIN)
421262306a36Sopenharmony_ci		rc = 0;
421362306a36Sopenharmony_ci
421462306a36Sopenharmony_ci	return rc;
421562306a36Sopenharmony_ci}
421662306a36Sopenharmony_ci
421762306a36Sopenharmony_ciint
421862306a36Sopenharmony_ciCIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
421962306a36Sopenharmony_ci		      const char *search_name, __u64 *inode_number,
422062306a36Sopenharmony_ci		      const struct nls_table *nls_codepage, int remap)
422162306a36Sopenharmony_ci{
422262306a36Sopenharmony_ci	int rc = 0;
422362306a36Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
422462306a36Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
422562306a36Sopenharmony_ci	int name_len, bytes_returned;
422662306a36Sopenharmony_ci	__u16 params, byte_count;
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_ci	cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
422962306a36Sopenharmony_ci	if (tcon == NULL)
423062306a36Sopenharmony_ci		return -ENODEV;
423162306a36Sopenharmony_ci
423262306a36Sopenharmony_ciGetInodeNumberRetry:
423362306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
423462306a36Sopenharmony_ci		      (void **) &pSMBr);
423562306a36Sopenharmony_ci	if (rc)
423662306a36Sopenharmony_ci		return rc;
423762306a36Sopenharmony_ci
423862306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
423962306a36Sopenharmony_ci		name_len =
424062306a36Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName,
424162306a36Sopenharmony_ci					   search_name, PATH_MAX, nls_codepage,
424262306a36Sopenharmony_ci					   remap);
424362306a36Sopenharmony_ci		name_len++;     /* trailing null */
424462306a36Sopenharmony_ci		name_len *= 2;
424562306a36Sopenharmony_ci	} else {
424662306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, search_name);
424762306a36Sopenharmony_ci	}
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
425062306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
425162306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
425262306a36Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
425362306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
425462306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
425562306a36Sopenharmony_ci	pSMB->Reserved = 0;
425662306a36Sopenharmony_ci	pSMB->Flags = 0;
425762306a36Sopenharmony_ci	pSMB->Timeout = 0;
425862306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
425962306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
426062306a36Sopenharmony_ci		struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
426162306a36Sopenharmony_ci	pSMB->DataCount = 0;
426262306a36Sopenharmony_ci	pSMB->DataOffset = 0;
426362306a36Sopenharmony_ci	pSMB->SetupCount = 1;
426462306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
426562306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
426662306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
426762306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
426862306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
426962306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
427062306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
427162306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
427262306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
427562306a36Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
427662306a36Sopenharmony_ci	if (rc) {
427762306a36Sopenharmony_ci		cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
427862306a36Sopenharmony_ci	} else {
427962306a36Sopenharmony_ci		/* decode response */
428062306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
428162306a36Sopenharmony_ci		/* BB also check enough total bytes returned */
428262306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 2)
428362306a36Sopenharmony_ci			/* If rc should we check for EOPNOSUPP and
428462306a36Sopenharmony_ci			disable the srvino flag? or in caller? */
428562306a36Sopenharmony_ci			rc = -EIO;      /* bad smb */
428662306a36Sopenharmony_ci		else {
428762306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
428862306a36Sopenharmony_ci			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
428962306a36Sopenharmony_ci			struct file_internal_info *pfinfo;
429062306a36Sopenharmony_ci			/* BB Do we need a cast or hash here ? */
429162306a36Sopenharmony_ci			if (count < 8) {
429262306a36Sopenharmony_ci				cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
429362306a36Sopenharmony_ci				rc = -EIO;
429462306a36Sopenharmony_ci				goto GetInodeNumOut;
429562306a36Sopenharmony_ci			}
429662306a36Sopenharmony_ci			pfinfo = (struct file_internal_info *)
429762306a36Sopenharmony_ci				(data_offset + (char *) &pSMBr->hdr.Protocol);
429862306a36Sopenharmony_ci			*inode_number = le64_to_cpu(pfinfo->UniqueId);
429962306a36Sopenharmony_ci		}
430062306a36Sopenharmony_ci	}
430162306a36Sopenharmony_ciGetInodeNumOut:
430262306a36Sopenharmony_ci	cifs_buf_release(pSMB);
430362306a36Sopenharmony_ci	if (rc == -EAGAIN)
430462306a36Sopenharmony_ci		goto GetInodeNumberRetry;
430562306a36Sopenharmony_ci	return rc;
430662306a36Sopenharmony_ci}
430762306a36Sopenharmony_ci
430862306a36Sopenharmony_ciint
430962306a36Sopenharmony_ciCIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
431062306a36Sopenharmony_ci		const char *search_name, struct dfs_info3_param **target_nodes,
431162306a36Sopenharmony_ci		unsigned int *num_of_nodes,
431262306a36Sopenharmony_ci		const struct nls_table *nls_codepage, int remap)
431362306a36Sopenharmony_ci{
431462306a36Sopenharmony_ci/* TRANS2_GET_DFS_REFERRAL */
431562306a36Sopenharmony_ci	TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
431662306a36Sopenharmony_ci	TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
431762306a36Sopenharmony_ci	int rc = 0;
431862306a36Sopenharmony_ci	int bytes_returned;
431962306a36Sopenharmony_ci	int name_len;
432062306a36Sopenharmony_ci	__u16 params, byte_count;
432162306a36Sopenharmony_ci	*num_of_nodes = 0;
432262306a36Sopenharmony_ci	*target_nodes = NULL;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
432562306a36Sopenharmony_ci	if (ses == NULL || ses->tcon_ipc == NULL)
432662306a36Sopenharmony_ci		return -ENODEV;
432762306a36Sopenharmony_ci
432862306a36Sopenharmony_cigetDFSRetry:
432962306a36Sopenharmony_ci	/*
433062306a36Sopenharmony_ci	 * Use smb_init_no_reconnect() instead of smb_init() as
433162306a36Sopenharmony_ci	 * CIFSGetDFSRefer() may be called from cifs_reconnect_tcon() and thus
433262306a36Sopenharmony_ci	 * causing an infinite recursion.
433362306a36Sopenharmony_ci	 */
433462306a36Sopenharmony_ci	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc,
433562306a36Sopenharmony_ci				   (void **)&pSMB, (void **)&pSMBr);
433662306a36Sopenharmony_ci	if (rc)
433762306a36Sopenharmony_ci		return rc;
433862306a36Sopenharmony_ci
433962306a36Sopenharmony_ci	/* server pointer checked in called function,
434062306a36Sopenharmony_ci	but should never be null here anyway */
434162306a36Sopenharmony_ci	pSMB->hdr.Mid = get_next_mid(ses->server);
434262306a36Sopenharmony_ci	pSMB->hdr.Tid = ses->tcon_ipc->tid;
434362306a36Sopenharmony_ci	pSMB->hdr.Uid = ses->Suid;
434462306a36Sopenharmony_ci	if (ses->capabilities & CAP_STATUS32)
434562306a36Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
434662306a36Sopenharmony_ci	if (ses->capabilities & CAP_DFS)
434762306a36Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_DFS;
434862306a36Sopenharmony_ci
434962306a36Sopenharmony_ci	if (ses->capabilities & CAP_UNICODE) {
435062306a36Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
435162306a36Sopenharmony_ci		name_len =
435262306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
435362306a36Sopenharmony_ci				       search_name, PATH_MAX, nls_codepage,
435462306a36Sopenharmony_ci				       remap);
435562306a36Sopenharmony_ci		name_len++;	/* trailing null */
435662306a36Sopenharmony_ci		name_len *= 2;
435762306a36Sopenharmony_ci	} else {	/* BB improve the check for buffer overruns BB */
435862306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->RequestFileName, search_name);
435962306a36Sopenharmony_ci	}
436062306a36Sopenharmony_ci
436162306a36Sopenharmony_ci	if (ses->server->sign)
436262306a36Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
436362306a36Sopenharmony_ci
436462306a36Sopenharmony_ci	pSMB->hdr.Uid = ses->Suid;
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_ci	params = 2 /* level */  + name_len /*includes null */ ;
436762306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
436862306a36Sopenharmony_ci	pSMB->DataCount = 0;
436962306a36Sopenharmony_ci	pSMB->DataOffset = 0;
437062306a36Sopenharmony_ci	pSMB->MaxParameterCount = 0;
437162306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
437262306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
437362306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
437462306a36Sopenharmony_ci	pSMB->Reserved = 0;
437562306a36Sopenharmony_ci	pSMB->Flags = 0;
437662306a36Sopenharmony_ci	pSMB->Timeout = 0;
437762306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
437862306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
437962306a36Sopenharmony_ci	  struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
438062306a36Sopenharmony_ci	pSMB->SetupCount = 1;
438162306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
438262306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
438362306a36Sopenharmony_ci	byte_count = params + 3 /* pad */ ;
438462306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
438562306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
438662306a36Sopenharmony_ci	pSMB->MaxReferralLevel = cpu_to_le16(3);
438762306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
438862306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
438962306a36Sopenharmony_ci
439062306a36Sopenharmony_ci	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
439162306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
439262306a36Sopenharmony_ci	if (rc) {
439362306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
439462306a36Sopenharmony_ci		goto GetDFSRefExit;
439562306a36Sopenharmony_ci	}
439662306a36Sopenharmony_ci	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
439762306a36Sopenharmony_ci
439862306a36Sopenharmony_ci	/* BB Also check if enough total bytes returned? */
439962306a36Sopenharmony_ci	if (rc || get_bcc(&pSMBr->hdr) < 17) {
440062306a36Sopenharmony_ci		rc = -EIO;      /* bad smb */
440162306a36Sopenharmony_ci		goto GetDFSRefExit;
440262306a36Sopenharmony_ci	}
440362306a36Sopenharmony_ci
440462306a36Sopenharmony_ci	cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d  Offset %d\n",
440562306a36Sopenharmony_ci		 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
440662306a36Sopenharmony_ci
440762306a36Sopenharmony_ci	/* parse returned result into more usable form */
440862306a36Sopenharmony_ci	rc = parse_dfs_referrals(&pSMBr->dfs_data,
440962306a36Sopenharmony_ci				 le16_to_cpu(pSMBr->t2.DataCount),
441062306a36Sopenharmony_ci				 num_of_nodes, target_nodes, nls_codepage,
441162306a36Sopenharmony_ci				 remap, search_name,
441262306a36Sopenharmony_ci				 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
441362306a36Sopenharmony_ci
441462306a36Sopenharmony_ciGetDFSRefExit:
441562306a36Sopenharmony_ci	cifs_buf_release(pSMB);
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci	if (rc == -EAGAIN)
441862306a36Sopenharmony_ci		goto getDFSRetry;
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_ci	return rc;
442162306a36Sopenharmony_ci}
442262306a36Sopenharmony_ci
442362306a36Sopenharmony_ci/* Query File System Info such as free space to old servers such as Win 9x */
442462306a36Sopenharmony_ciint
442562306a36Sopenharmony_ciSMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
442662306a36Sopenharmony_ci	      struct kstatfs *FSData)
442762306a36Sopenharmony_ci{
442862306a36Sopenharmony_ci/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
442962306a36Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
443062306a36Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
443162306a36Sopenharmony_ci	FILE_SYSTEM_ALLOC_INFO *response_data;
443262306a36Sopenharmony_ci	int rc = 0;
443362306a36Sopenharmony_ci	int bytes_returned = 0;
443462306a36Sopenharmony_ci	__u16 params, byte_count;
443562306a36Sopenharmony_ci
443662306a36Sopenharmony_ci	cifs_dbg(FYI, "OldQFSInfo\n");
443762306a36Sopenharmony_cioldQFSInfoRetry:
443862306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
443962306a36Sopenharmony_ci		(void **) &pSMBr);
444062306a36Sopenharmony_ci	if (rc)
444162306a36Sopenharmony_ci		return rc;
444262306a36Sopenharmony_ci
444362306a36Sopenharmony_ci	params = 2;     /* level */
444462306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
444562306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
444662306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
444762306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
444862306a36Sopenharmony_ci	pSMB->Reserved = 0;
444962306a36Sopenharmony_ci	pSMB->Flags = 0;
445062306a36Sopenharmony_ci	pSMB->Timeout = 0;
445162306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
445262306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
445362306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
445462306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
445562306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
445662306a36Sopenharmony_ci	struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
445762306a36Sopenharmony_ci	pSMB->DataCount = 0;
445862306a36Sopenharmony_ci	pSMB->DataOffset = 0;
445962306a36Sopenharmony_ci	pSMB->SetupCount = 1;
446062306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
446162306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
446262306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
446362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
446462306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
446562306a36Sopenharmony_ci
446662306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
446762306a36Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
446862306a36Sopenharmony_ci	if (rc) {
446962306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
447062306a36Sopenharmony_ci	} else {                /* decode response */
447162306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
447262306a36Sopenharmony_ci
447362306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 18)
447462306a36Sopenharmony_ci			rc = -EIO;      /* bad smb */
447562306a36Sopenharmony_ci		else {
447662306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
447762306a36Sopenharmony_ci			cifs_dbg(FYI, "qfsinf resp BCC: %d  Offset %d\n",
447862306a36Sopenharmony_ci				 get_bcc(&pSMBr->hdr), data_offset);
447962306a36Sopenharmony_ci
448062306a36Sopenharmony_ci			response_data = (FILE_SYSTEM_ALLOC_INFO *)
448162306a36Sopenharmony_ci				(((char *) &pSMBr->hdr.Protocol) + data_offset);
448262306a36Sopenharmony_ci			FSData->f_bsize =
448362306a36Sopenharmony_ci				le16_to_cpu(response_data->BytesPerSector) *
448462306a36Sopenharmony_ci				le32_to_cpu(response_data->
448562306a36Sopenharmony_ci					SectorsPerAllocationUnit);
448662306a36Sopenharmony_ci			/*
448762306a36Sopenharmony_ci			 * much prefer larger but if server doesn't report
448862306a36Sopenharmony_ci			 * a valid size than 4K is a reasonable minimum
448962306a36Sopenharmony_ci			 */
449062306a36Sopenharmony_ci			if (FSData->f_bsize < 512)
449162306a36Sopenharmony_ci				FSData->f_bsize = 4096;
449262306a36Sopenharmony_ci
449362306a36Sopenharmony_ci			FSData->f_blocks =
449462306a36Sopenharmony_ci			       le32_to_cpu(response_data->TotalAllocationUnits);
449562306a36Sopenharmony_ci			FSData->f_bfree = FSData->f_bavail =
449662306a36Sopenharmony_ci				le32_to_cpu(response_data->FreeAllocationUnits);
449762306a36Sopenharmony_ci			cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n",
449862306a36Sopenharmony_ci				 (unsigned long long)FSData->f_blocks,
449962306a36Sopenharmony_ci				 (unsigned long long)FSData->f_bfree,
450062306a36Sopenharmony_ci				 FSData->f_bsize);
450162306a36Sopenharmony_ci		}
450262306a36Sopenharmony_ci	}
450362306a36Sopenharmony_ci	cifs_buf_release(pSMB);
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_ci	if (rc == -EAGAIN)
450662306a36Sopenharmony_ci		goto oldQFSInfoRetry;
450762306a36Sopenharmony_ci
450862306a36Sopenharmony_ci	return rc;
450962306a36Sopenharmony_ci}
451062306a36Sopenharmony_ci
451162306a36Sopenharmony_ciint
451262306a36Sopenharmony_ciCIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
451362306a36Sopenharmony_ci	       struct kstatfs *FSData)
451462306a36Sopenharmony_ci{
451562306a36Sopenharmony_ci/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
451662306a36Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
451762306a36Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
451862306a36Sopenharmony_ci	FILE_SYSTEM_INFO *response_data;
451962306a36Sopenharmony_ci	int rc = 0;
452062306a36Sopenharmony_ci	int bytes_returned = 0;
452162306a36Sopenharmony_ci	__u16 params, byte_count;
452262306a36Sopenharmony_ci
452362306a36Sopenharmony_ci	cifs_dbg(FYI, "In QFSInfo\n");
452462306a36Sopenharmony_ciQFSInfoRetry:
452562306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
452662306a36Sopenharmony_ci		      (void **) &pSMBr);
452762306a36Sopenharmony_ci	if (rc)
452862306a36Sopenharmony_ci		return rc;
452962306a36Sopenharmony_ci
453062306a36Sopenharmony_ci	params = 2;	/* level */
453162306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
453262306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
453362306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
453462306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
453562306a36Sopenharmony_ci	pSMB->Reserved = 0;
453662306a36Sopenharmony_ci	pSMB->Flags = 0;
453762306a36Sopenharmony_ci	pSMB->Timeout = 0;
453862306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
453962306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
454062306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
454162306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
454262306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
454362306a36Sopenharmony_ci		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
454462306a36Sopenharmony_ci	pSMB->DataCount = 0;
454562306a36Sopenharmony_ci	pSMB->DataOffset = 0;
454662306a36Sopenharmony_ci	pSMB->SetupCount = 1;
454762306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
454862306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
454962306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
455062306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
455162306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
455262306a36Sopenharmony_ci
455362306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
455462306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
455562306a36Sopenharmony_ci	if (rc) {
455662306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
455762306a36Sopenharmony_ci	} else {		/* decode response */
455862306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 24)
456162306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
456262306a36Sopenharmony_ci		else {
456362306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci			response_data =
456662306a36Sopenharmony_ci			    (FILE_SYSTEM_INFO
456762306a36Sopenharmony_ci			     *) (((char *) &pSMBr->hdr.Protocol) +
456862306a36Sopenharmony_ci				 data_offset);
456962306a36Sopenharmony_ci			FSData->f_bsize =
457062306a36Sopenharmony_ci			    le32_to_cpu(response_data->BytesPerSector) *
457162306a36Sopenharmony_ci			    le32_to_cpu(response_data->
457262306a36Sopenharmony_ci					SectorsPerAllocationUnit);
457362306a36Sopenharmony_ci			/*
457462306a36Sopenharmony_ci			 * much prefer larger but if server doesn't report
457562306a36Sopenharmony_ci			 * a valid size than 4K is a reasonable minimum
457662306a36Sopenharmony_ci			 */
457762306a36Sopenharmony_ci			if (FSData->f_bsize < 512)
457862306a36Sopenharmony_ci				FSData->f_bsize = 4096;
457962306a36Sopenharmony_ci
458062306a36Sopenharmony_ci			FSData->f_blocks =
458162306a36Sopenharmony_ci			    le64_to_cpu(response_data->TotalAllocationUnits);
458262306a36Sopenharmony_ci			FSData->f_bfree = FSData->f_bavail =
458362306a36Sopenharmony_ci			    le64_to_cpu(response_data->FreeAllocationUnits);
458462306a36Sopenharmony_ci			cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n",
458562306a36Sopenharmony_ci				 (unsigned long long)FSData->f_blocks,
458662306a36Sopenharmony_ci				 (unsigned long long)FSData->f_bfree,
458762306a36Sopenharmony_ci				 FSData->f_bsize);
458862306a36Sopenharmony_ci		}
458962306a36Sopenharmony_ci	}
459062306a36Sopenharmony_ci	cifs_buf_release(pSMB);
459162306a36Sopenharmony_ci
459262306a36Sopenharmony_ci	if (rc == -EAGAIN)
459362306a36Sopenharmony_ci		goto QFSInfoRetry;
459462306a36Sopenharmony_ci
459562306a36Sopenharmony_ci	return rc;
459662306a36Sopenharmony_ci}
459762306a36Sopenharmony_ci
459862306a36Sopenharmony_ciint
459962306a36Sopenharmony_ciCIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
460062306a36Sopenharmony_ci{
460162306a36Sopenharmony_ci/* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
460262306a36Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
460362306a36Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
460462306a36Sopenharmony_ci	FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
460562306a36Sopenharmony_ci	int rc = 0;
460662306a36Sopenharmony_ci	int bytes_returned = 0;
460762306a36Sopenharmony_ci	__u16 params, byte_count;
460862306a36Sopenharmony_ci
460962306a36Sopenharmony_ci	cifs_dbg(FYI, "In QFSAttributeInfo\n");
461062306a36Sopenharmony_ciQFSAttributeRetry:
461162306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
461262306a36Sopenharmony_ci		      (void **) &pSMBr);
461362306a36Sopenharmony_ci	if (rc)
461462306a36Sopenharmony_ci		return rc;
461562306a36Sopenharmony_ci
461662306a36Sopenharmony_ci	params = 2;	/* level */
461762306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
461862306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
461962306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
462062306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
462162306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
462262306a36Sopenharmony_ci	pSMB->Reserved = 0;
462362306a36Sopenharmony_ci	pSMB->Flags = 0;
462462306a36Sopenharmony_ci	pSMB->Timeout = 0;
462562306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
462662306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
462762306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
462862306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
462962306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
463062306a36Sopenharmony_ci		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
463162306a36Sopenharmony_ci	pSMB->DataCount = 0;
463262306a36Sopenharmony_ci	pSMB->DataOffset = 0;
463362306a36Sopenharmony_ci	pSMB->SetupCount = 1;
463462306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
463562306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
463662306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
463762306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
463862306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
463962306a36Sopenharmony_ci
464062306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
464162306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
464262306a36Sopenharmony_ci	if (rc) {
464362306a36Sopenharmony_ci		cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
464462306a36Sopenharmony_ci	} else {		/* decode response */
464562306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
464662306a36Sopenharmony_ci
464762306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 13) {
464862306a36Sopenharmony_ci			/* BB also check if enough bytes returned */
464962306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
465062306a36Sopenharmony_ci		} else {
465162306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
465262306a36Sopenharmony_ci			response_data =
465362306a36Sopenharmony_ci			    (FILE_SYSTEM_ATTRIBUTE_INFO
465462306a36Sopenharmony_ci			     *) (((char *) &pSMBr->hdr.Protocol) +
465562306a36Sopenharmony_ci				 data_offset);
465662306a36Sopenharmony_ci			memcpy(&tcon->fsAttrInfo, response_data,
465762306a36Sopenharmony_ci			       sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
465862306a36Sopenharmony_ci		}
465962306a36Sopenharmony_ci	}
466062306a36Sopenharmony_ci	cifs_buf_release(pSMB);
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci	if (rc == -EAGAIN)
466362306a36Sopenharmony_ci		goto QFSAttributeRetry;
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_ci	return rc;
466662306a36Sopenharmony_ci}
466762306a36Sopenharmony_ci
466862306a36Sopenharmony_ciint
466962306a36Sopenharmony_ciCIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
467062306a36Sopenharmony_ci{
467162306a36Sopenharmony_ci/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
467262306a36Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
467362306a36Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
467462306a36Sopenharmony_ci	FILE_SYSTEM_DEVICE_INFO *response_data;
467562306a36Sopenharmony_ci	int rc = 0;
467662306a36Sopenharmony_ci	int bytes_returned = 0;
467762306a36Sopenharmony_ci	__u16 params, byte_count;
467862306a36Sopenharmony_ci
467962306a36Sopenharmony_ci	cifs_dbg(FYI, "In QFSDeviceInfo\n");
468062306a36Sopenharmony_ciQFSDeviceRetry:
468162306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
468262306a36Sopenharmony_ci		      (void **) &pSMBr);
468362306a36Sopenharmony_ci	if (rc)
468462306a36Sopenharmony_ci		return rc;
468562306a36Sopenharmony_ci
468662306a36Sopenharmony_ci	params = 2;	/* level */
468762306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
468862306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
468962306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
469062306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
469162306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
469262306a36Sopenharmony_ci	pSMB->Reserved = 0;
469362306a36Sopenharmony_ci	pSMB->Flags = 0;
469462306a36Sopenharmony_ci	pSMB->Timeout = 0;
469562306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
469662306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
469762306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
469862306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
469962306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
470062306a36Sopenharmony_ci		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
470162306a36Sopenharmony_ci
470262306a36Sopenharmony_ci	pSMB->DataCount = 0;
470362306a36Sopenharmony_ci	pSMB->DataOffset = 0;
470462306a36Sopenharmony_ci	pSMB->SetupCount = 1;
470562306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
470662306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
470762306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
470862306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
470962306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
471262306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
471362306a36Sopenharmony_ci	if (rc) {
471462306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
471562306a36Sopenharmony_ci	} else {		/* decode response */
471662306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
471762306a36Sopenharmony_ci
471862306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) <
471962306a36Sopenharmony_ci			  sizeof(FILE_SYSTEM_DEVICE_INFO))
472062306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
472162306a36Sopenharmony_ci		else {
472262306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
472362306a36Sopenharmony_ci			response_data =
472462306a36Sopenharmony_ci			    (FILE_SYSTEM_DEVICE_INFO *)
472562306a36Sopenharmony_ci				(((char *) &pSMBr->hdr.Protocol) +
472662306a36Sopenharmony_ci				 data_offset);
472762306a36Sopenharmony_ci			memcpy(&tcon->fsDevInfo, response_data,
472862306a36Sopenharmony_ci			       sizeof(FILE_SYSTEM_DEVICE_INFO));
472962306a36Sopenharmony_ci		}
473062306a36Sopenharmony_ci	}
473162306a36Sopenharmony_ci	cifs_buf_release(pSMB);
473262306a36Sopenharmony_ci
473362306a36Sopenharmony_ci	if (rc == -EAGAIN)
473462306a36Sopenharmony_ci		goto QFSDeviceRetry;
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci	return rc;
473762306a36Sopenharmony_ci}
473862306a36Sopenharmony_ci
473962306a36Sopenharmony_ciint
474062306a36Sopenharmony_ciCIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
474162306a36Sopenharmony_ci{
474262306a36Sopenharmony_ci/* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
474362306a36Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
474462306a36Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
474562306a36Sopenharmony_ci	FILE_SYSTEM_UNIX_INFO *response_data;
474662306a36Sopenharmony_ci	int rc = 0;
474762306a36Sopenharmony_ci	int bytes_returned = 0;
474862306a36Sopenharmony_ci	__u16 params, byte_count;
474962306a36Sopenharmony_ci
475062306a36Sopenharmony_ci	cifs_dbg(FYI, "In QFSUnixInfo\n");
475162306a36Sopenharmony_ciQFSUnixRetry:
475262306a36Sopenharmony_ci	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
475362306a36Sopenharmony_ci				   (void **) &pSMB, (void **) &pSMBr);
475462306a36Sopenharmony_ci	if (rc)
475562306a36Sopenharmony_ci		return rc;
475662306a36Sopenharmony_ci
475762306a36Sopenharmony_ci	params = 2;	/* level */
475862306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
475962306a36Sopenharmony_ci	pSMB->DataCount = 0;
476062306a36Sopenharmony_ci	pSMB->DataOffset = 0;
476162306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
476262306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
476362306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(100);
476462306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
476562306a36Sopenharmony_ci	pSMB->Reserved = 0;
476662306a36Sopenharmony_ci	pSMB->Flags = 0;
476762306a36Sopenharmony_ci	pSMB->Timeout = 0;
476862306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
476962306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
477062306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
477162306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
477262306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
477362306a36Sopenharmony_ci			smb_com_transaction2_qfsi_req, InformationLevel) - 4);
477462306a36Sopenharmony_ci	pSMB->SetupCount = 1;
477562306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
477662306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
477762306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
477862306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
477962306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
478062306a36Sopenharmony_ci
478162306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
478262306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
478362306a36Sopenharmony_ci	if (rc) {
478462306a36Sopenharmony_ci		cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
478562306a36Sopenharmony_ci	} else {		/* decode response */
478662306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 13) {
478962306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
479062306a36Sopenharmony_ci		} else {
479162306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
479262306a36Sopenharmony_ci			response_data =
479362306a36Sopenharmony_ci			    (FILE_SYSTEM_UNIX_INFO
479462306a36Sopenharmony_ci			     *) (((char *) &pSMBr->hdr.Protocol) +
479562306a36Sopenharmony_ci				 data_offset);
479662306a36Sopenharmony_ci			memcpy(&tcon->fsUnixInfo, response_data,
479762306a36Sopenharmony_ci			       sizeof(FILE_SYSTEM_UNIX_INFO));
479862306a36Sopenharmony_ci		}
479962306a36Sopenharmony_ci	}
480062306a36Sopenharmony_ci	cifs_buf_release(pSMB);
480162306a36Sopenharmony_ci
480262306a36Sopenharmony_ci	if (rc == -EAGAIN)
480362306a36Sopenharmony_ci		goto QFSUnixRetry;
480462306a36Sopenharmony_ci
480562306a36Sopenharmony_ci
480662306a36Sopenharmony_ci	return rc;
480762306a36Sopenharmony_ci}
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_ciint
481062306a36Sopenharmony_ciCIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
481162306a36Sopenharmony_ci{
481262306a36Sopenharmony_ci/* level 0x200  SMB_SET_CIFS_UNIX_INFO */
481362306a36Sopenharmony_ci	TRANSACTION2_SETFSI_REQ *pSMB = NULL;
481462306a36Sopenharmony_ci	TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
481562306a36Sopenharmony_ci	int rc = 0;
481662306a36Sopenharmony_ci	int bytes_returned = 0;
481762306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count;
481862306a36Sopenharmony_ci
481962306a36Sopenharmony_ci	cifs_dbg(FYI, "In SETFSUnixInfo\n");
482062306a36Sopenharmony_ciSETFSUnixRetry:
482162306a36Sopenharmony_ci	/* BB switch to small buf init to save memory */
482262306a36Sopenharmony_ci	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
482362306a36Sopenharmony_ci					(void **) &pSMB, (void **) &pSMBr);
482462306a36Sopenharmony_ci	if (rc)
482562306a36Sopenharmony_ci		return rc;
482662306a36Sopenharmony_ci
482762306a36Sopenharmony_ci	params = 4;	/* 2 bytes zero followed by info level. */
482862306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
482962306a36Sopenharmony_ci	pSMB->Reserved = 0;
483062306a36Sopenharmony_ci	pSMB->Flags = 0;
483162306a36Sopenharmony_ci	pSMB->Timeout = 0;
483262306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
483362306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
483462306a36Sopenharmony_ci				- 4;
483562306a36Sopenharmony_ci	offset = param_offset + params;
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(4);
483862306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
483962306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(100);
484062306a36Sopenharmony_ci	pSMB->SetupCount = 1;
484162306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
484262306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
484362306a36Sopenharmony_ci	byte_count = 1 /* pad */ + params + 12;
484462306a36Sopenharmony_ci
484562306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(12);
484662306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
484762306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
484862306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
484962306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
485062306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
485162306a36Sopenharmony_ci
485262306a36Sopenharmony_ci	/* Params. */
485362306a36Sopenharmony_ci	pSMB->FileNum = 0;
485462306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
485562306a36Sopenharmony_ci
485662306a36Sopenharmony_ci	/* Data. */
485762306a36Sopenharmony_ci	pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
485862306a36Sopenharmony_ci	pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
485962306a36Sopenharmony_ci	pSMB->ClientUnixCap = cpu_to_le64(cap);
486062306a36Sopenharmony_ci
486162306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
486262306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
486362306a36Sopenharmony_ci
486462306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
486562306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
486662306a36Sopenharmony_ci	if (rc) {
486762306a36Sopenharmony_ci		cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
486862306a36Sopenharmony_ci	} else {		/* decode response */
486962306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
487062306a36Sopenharmony_ci		if (rc)
487162306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
487262306a36Sopenharmony_ci	}
487362306a36Sopenharmony_ci	cifs_buf_release(pSMB);
487462306a36Sopenharmony_ci
487562306a36Sopenharmony_ci	if (rc == -EAGAIN)
487662306a36Sopenharmony_ci		goto SETFSUnixRetry;
487762306a36Sopenharmony_ci
487862306a36Sopenharmony_ci	return rc;
487962306a36Sopenharmony_ci}
488062306a36Sopenharmony_ci
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_ci
488362306a36Sopenharmony_ciint
488462306a36Sopenharmony_ciCIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
488562306a36Sopenharmony_ci		   struct kstatfs *FSData)
488662306a36Sopenharmony_ci{
488762306a36Sopenharmony_ci/* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
488862306a36Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
488962306a36Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
489062306a36Sopenharmony_ci	FILE_SYSTEM_POSIX_INFO *response_data;
489162306a36Sopenharmony_ci	int rc = 0;
489262306a36Sopenharmony_ci	int bytes_returned = 0;
489362306a36Sopenharmony_ci	__u16 params, byte_count;
489462306a36Sopenharmony_ci
489562306a36Sopenharmony_ci	cifs_dbg(FYI, "In QFSPosixInfo\n");
489662306a36Sopenharmony_ciQFSPosixRetry:
489762306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
489862306a36Sopenharmony_ci		      (void **) &pSMBr);
489962306a36Sopenharmony_ci	if (rc)
490062306a36Sopenharmony_ci		return rc;
490162306a36Sopenharmony_ci
490262306a36Sopenharmony_ci	params = 2;	/* level */
490362306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
490462306a36Sopenharmony_ci	pSMB->DataCount = 0;
490562306a36Sopenharmony_ci	pSMB->DataOffset = 0;
490662306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
490762306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
490862306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(100);
490962306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
491062306a36Sopenharmony_ci	pSMB->Reserved = 0;
491162306a36Sopenharmony_ci	pSMB->Flags = 0;
491262306a36Sopenharmony_ci	pSMB->Timeout = 0;
491362306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
491462306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
491562306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
491662306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
491762306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
491862306a36Sopenharmony_ci			smb_com_transaction2_qfsi_req, InformationLevel) - 4);
491962306a36Sopenharmony_ci	pSMB->SetupCount = 1;
492062306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
492162306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
492262306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
492362306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
492462306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
492562306a36Sopenharmony_ci
492662306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
492762306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
492862306a36Sopenharmony_ci	if (rc) {
492962306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
493062306a36Sopenharmony_ci	} else {		/* decode response */
493162306a36Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
493262306a36Sopenharmony_ci
493362306a36Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 13) {
493462306a36Sopenharmony_ci			rc = -EIO;	/* bad smb */
493562306a36Sopenharmony_ci		} else {
493662306a36Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
493762306a36Sopenharmony_ci			response_data =
493862306a36Sopenharmony_ci			    (FILE_SYSTEM_POSIX_INFO
493962306a36Sopenharmony_ci			     *) (((char *) &pSMBr->hdr.Protocol) +
494062306a36Sopenharmony_ci				 data_offset);
494162306a36Sopenharmony_ci			FSData->f_bsize =
494262306a36Sopenharmony_ci					le32_to_cpu(response_data->BlockSize);
494362306a36Sopenharmony_ci			/*
494462306a36Sopenharmony_ci			 * much prefer larger but if server doesn't report
494562306a36Sopenharmony_ci			 * a valid size than 4K is a reasonable minimum
494662306a36Sopenharmony_ci			 */
494762306a36Sopenharmony_ci			if (FSData->f_bsize < 512)
494862306a36Sopenharmony_ci				FSData->f_bsize = 4096;
494962306a36Sopenharmony_ci
495062306a36Sopenharmony_ci			FSData->f_blocks =
495162306a36Sopenharmony_ci					le64_to_cpu(response_data->TotalBlocks);
495262306a36Sopenharmony_ci			FSData->f_bfree =
495362306a36Sopenharmony_ci			    le64_to_cpu(response_data->BlocksAvail);
495462306a36Sopenharmony_ci			if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
495562306a36Sopenharmony_ci				FSData->f_bavail = FSData->f_bfree;
495662306a36Sopenharmony_ci			} else {
495762306a36Sopenharmony_ci				FSData->f_bavail =
495862306a36Sopenharmony_ci				    le64_to_cpu(response_data->UserBlocksAvail);
495962306a36Sopenharmony_ci			}
496062306a36Sopenharmony_ci			if (response_data->TotalFileNodes != cpu_to_le64(-1))
496162306a36Sopenharmony_ci				FSData->f_files =
496262306a36Sopenharmony_ci				     le64_to_cpu(response_data->TotalFileNodes);
496362306a36Sopenharmony_ci			if (response_data->FreeFileNodes != cpu_to_le64(-1))
496462306a36Sopenharmony_ci				FSData->f_ffree =
496562306a36Sopenharmony_ci				      le64_to_cpu(response_data->FreeFileNodes);
496662306a36Sopenharmony_ci		}
496762306a36Sopenharmony_ci	}
496862306a36Sopenharmony_ci	cifs_buf_release(pSMB);
496962306a36Sopenharmony_ci
497062306a36Sopenharmony_ci	if (rc == -EAGAIN)
497162306a36Sopenharmony_ci		goto QFSPosixRetry;
497262306a36Sopenharmony_ci
497362306a36Sopenharmony_ci	return rc;
497462306a36Sopenharmony_ci}
497562306a36Sopenharmony_ci
497662306a36Sopenharmony_ci
497762306a36Sopenharmony_ci/*
497862306a36Sopenharmony_ci * We can not use write of zero bytes trick to set file size due to need for
497962306a36Sopenharmony_ci * large file support. Also note that this SetPathInfo is preferred to
498062306a36Sopenharmony_ci * SetFileInfo based method in next routine which is only needed to work around
498162306a36Sopenharmony_ci * a sharing violation bugin Samba which this routine can run into.
498262306a36Sopenharmony_ci */
498362306a36Sopenharmony_ciint
498462306a36Sopenharmony_ciCIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
498562306a36Sopenharmony_ci	      const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
498662306a36Sopenharmony_ci	      bool set_allocation)
498762306a36Sopenharmony_ci{
498862306a36Sopenharmony_ci	struct smb_com_transaction2_spi_req *pSMB = NULL;
498962306a36Sopenharmony_ci	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
499062306a36Sopenharmony_ci	struct file_end_of_file_info *parm_data;
499162306a36Sopenharmony_ci	int name_len;
499262306a36Sopenharmony_ci	int rc = 0;
499362306a36Sopenharmony_ci	int bytes_returned = 0;
499462306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
499562306a36Sopenharmony_ci
499662306a36Sopenharmony_ci	__u16 params, byte_count, data_count, param_offset, offset;
499762306a36Sopenharmony_ci
499862306a36Sopenharmony_ci	cifs_dbg(FYI, "In SetEOF\n");
499962306a36Sopenharmony_ciSetEOFRetry:
500062306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
500162306a36Sopenharmony_ci		      (void **) &pSMBr);
500262306a36Sopenharmony_ci	if (rc)
500362306a36Sopenharmony_ci		return rc;
500462306a36Sopenharmony_ci
500562306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
500662306a36Sopenharmony_ci		name_len =
500762306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
500862306a36Sopenharmony_ci				       PATH_MAX, cifs_sb->local_nls, remap);
500962306a36Sopenharmony_ci		name_len++;	/* trailing null */
501062306a36Sopenharmony_ci		name_len *= 2;
501162306a36Sopenharmony_ci	} else {
501262306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, file_name);
501362306a36Sopenharmony_ci	}
501462306a36Sopenharmony_ci	params = 6 + name_len;
501562306a36Sopenharmony_ci	data_count = sizeof(struct file_end_of_file_info);
501662306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
501762306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4100);
501862306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
501962306a36Sopenharmony_ci	pSMB->Reserved = 0;
502062306a36Sopenharmony_ci	pSMB->Flags = 0;
502162306a36Sopenharmony_ci	pSMB->Timeout = 0;
502262306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
502362306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
502462306a36Sopenharmony_ci				InformationLevel) - 4;
502562306a36Sopenharmony_ci	offset = param_offset + params;
502662306a36Sopenharmony_ci	if (set_allocation) {
502762306a36Sopenharmony_ci		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
502862306a36Sopenharmony_ci			pSMB->InformationLevel =
502962306a36Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
503062306a36Sopenharmony_ci		else
503162306a36Sopenharmony_ci			pSMB->InformationLevel =
503262306a36Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
503362306a36Sopenharmony_ci	} else /* Set File Size */  {
503462306a36Sopenharmony_ci	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
503562306a36Sopenharmony_ci		    pSMB->InformationLevel =
503662306a36Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
503762306a36Sopenharmony_ci	    else
503862306a36Sopenharmony_ci		    pSMB->InformationLevel =
503962306a36Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
504062306a36Sopenharmony_ci	}
504162306a36Sopenharmony_ci
504262306a36Sopenharmony_ci	parm_data =
504362306a36Sopenharmony_ci	    (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
504462306a36Sopenharmony_ci				       offset);
504562306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
504662306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
504762306a36Sopenharmony_ci	pSMB->SetupCount = 1;
504862306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
504962306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
505062306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + data_count;
505162306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(data_count);
505262306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
505362306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
505462306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
505562306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
505662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
505762306a36Sopenharmony_ci	parm_data->FileSize = cpu_to_le64(size);
505862306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
505962306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
506062306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
506162306a36Sopenharmony_ci	if (rc)
506262306a36Sopenharmony_ci		cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
506362306a36Sopenharmony_ci
506462306a36Sopenharmony_ci	cifs_buf_release(pSMB);
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci	if (rc == -EAGAIN)
506762306a36Sopenharmony_ci		goto SetEOFRetry;
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_ci	return rc;
507062306a36Sopenharmony_ci}
507162306a36Sopenharmony_ci
507262306a36Sopenharmony_ciint
507362306a36Sopenharmony_ciCIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
507462306a36Sopenharmony_ci		   struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
507562306a36Sopenharmony_ci{
507662306a36Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
507762306a36Sopenharmony_ci	struct file_end_of_file_info *parm_data;
507862306a36Sopenharmony_ci	int rc = 0;
507962306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
508062306a36Sopenharmony_ci
508162306a36Sopenharmony_ci	cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
508262306a36Sopenharmony_ci		 (long long)size);
508362306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
508462306a36Sopenharmony_ci
508562306a36Sopenharmony_ci	if (rc)
508662306a36Sopenharmony_ci		return rc;
508762306a36Sopenharmony_ci
508862306a36Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
508962306a36Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
509062306a36Sopenharmony_ci
509162306a36Sopenharmony_ci	params = 6;
509262306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
509362306a36Sopenharmony_ci	pSMB->Reserved = 0;
509462306a36Sopenharmony_ci	pSMB->Flags = 0;
509562306a36Sopenharmony_ci	pSMB->Timeout = 0;
509662306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
509762306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
509862306a36Sopenharmony_ci	offset = param_offset + params;
509962306a36Sopenharmony_ci
510062306a36Sopenharmony_ci	count = sizeof(struct file_end_of_file_info);
510162306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
510262306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
510362306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
510462306a36Sopenharmony_ci	pSMB->SetupCount = 1;
510562306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
510662306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
510762306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
510862306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
510962306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
511062306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
511162306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
511262306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
511362306a36Sopenharmony_ci	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
511462306a36Sopenharmony_ci	parm_data =
511562306a36Sopenharmony_ci		(struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
511662306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
511762306a36Sopenharmony_ci	parm_data->FileSize = cpu_to_le64(size);
511862306a36Sopenharmony_ci	pSMB->Fid = cfile->fid.netfid;
511962306a36Sopenharmony_ci	if (set_allocation) {
512062306a36Sopenharmony_ci		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
512162306a36Sopenharmony_ci			pSMB->InformationLevel =
512262306a36Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
512362306a36Sopenharmony_ci		else
512462306a36Sopenharmony_ci			pSMB->InformationLevel =
512562306a36Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
512662306a36Sopenharmony_ci	} else /* Set File Size */  {
512762306a36Sopenharmony_ci	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
512862306a36Sopenharmony_ci		    pSMB->InformationLevel =
512962306a36Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
513062306a36Sopenharmony_ci	    else
513162306a36Sopenharmony_ci		    pSMB->InformationLevel =
513262306a36Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
513362306a36Sopenharmony_ci	}
513462306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
513562306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
513662306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
513762306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
513862306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
513962306a36Sopenharmony_ci	if (rc) {
514062306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
514162306a36Sopenharmony_ci			 rc);
514262306a36Sopenharmony_ci	}
514362306a36Sopenharmony_ci
514462306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
514562306a36Sopenharmony_ci		since file handle passed in no longer valid */
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_ci	return rc;
514862306a36Sopenharmony_ci}
514962306a36Sopenharmony_ci
515062306a36Sopenharmony_ci/* Some legacy servers such as NT4 require that the file times be set on
515162306a36Sopenharmony_ci   an open handle, rather than by pathname - this is awkward due to
515262306a36Sopenharmony_ci   potential access conflicts on the open, but it is unavoidable for these
515362306a36Sopenharmony_ci   old servers since the only other choice is to go from 100 nanosecond DCE
515462306a36Sopenharmony_ci   time and resort to the original setpathinfo level which takes the ancient
515562306a36Sopenharmony_ci   DOS time format with 2 second granularity */
515662306a36Sopenharmony_ciint
515762306a36Sopenharmony_ciCIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
515862306a36Sopenharmony_ci		    const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
515962306a36Sopenharmony_ci{
516062306a36Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
516162306a36Sopenharmony_ci	char *data_offset;
516262306a36Sopenharmony_ci	int rc = 0;
516362306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
516462306a36Sopenharmony_ci
516562306a36Sopenharmony_ci	cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
516662306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
516762306a36Sopenharmony_ci
516862306a36Sopenharmony_ci	if (rc)
516962306a36Sopenharmony_ci		return rc;
517062306a36Sopenharmony_ci
517162306a36Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
517262306a36Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
517362306a36Sopenharmony_ci
517462306a36Sopenharmony_ci	params = 6;
517562306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
517662306a36Sopenharmony_ci	pSMB->Reserved = 0;
517762306a36Sopenharmony_ci	pSMB->Flags = 0;
517862306a36Sopenharmony_ci	pSMB->Timeout = 0;
517962306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
518062306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
518162306a36Sopenharmony_ci	offset = param_offset + params;
518262306a36Sopenharmony_ci
518362306a36Sopenharmony_ci	data_offset = (char *)pSMB +
518462306a36Sopenharmony_ci			offsetof(struct smb_hdr, Protocol) + offset;
518562306a36Sopenharmony_ci
518662306a36Sopenharmony_ci	count = sizeof(FILE_BASIC_INFO);
518762306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
518862306a36Sopenharmony_ci	/* BB find max SMB PDU from sess */
518962306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
519062306a36Sopenharmony_ci	pSMB->SetupCount = 1;
519162306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
519262306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
519362306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
519462306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
519562306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
519662306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
519762306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
519862306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
519962306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
520062306a36Sopenharmony_ci	pSMB->Fid = fid;
520162306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
520262306a36Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
520362306a36Sopenharmony_ci	else
520462306a36Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
520562306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
520662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
520762306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
520862306a36Sopenharmony_ci	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
520962306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
521062306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
521162306a36Sopenharmony_ci	if (rc)
521262306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
521362306a36Sopenharmony_ci			 rc);
521462306a36Sopenharmony_ci
521562306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
521662306a36Sopenharmony_ci		since file handle passed in no longer valid */
521762306a36Sopenharmony_ci
521862306a36Sopenharmony_ci	return rc;
521962306a36Sopenharmony_ci}
522062306a36Sopenharmony_ci
522162306a36Sopenharmony_ciint
522262306a36Sopenharmony_ciCIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
522362306a36Sopenharmony_ci			  bool delete_file, __u16 fid, __u32 pid_of_opener)
522462306a36Sopenharmony_ci{
522562306a36Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
522662306a36Sopenharmony_ci	char *data_offset;
522762306a36Sopenharmony_ci	int rc = 0;
522862306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
522962306a36Sopenharmony_ci
523062306a36Sopenharmony_ci	cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
523162306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
523262306a36Sopenharmony_ci
523362306a36Sopenharmony_ci	if (rc)
523462306a36Sopenharmony_ci		return rc;
523562306a36Sopenharmony_ci
523662306a36Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
523762306a36Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
523862306a36Sopenharmony_ci
523962306a36Sopenharmony_ci	params = 6;
524062306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
524162306a36Sopenharmony_ci	pSMB->Reserved = 0;
524262306a36Sopenharmony_ci	pSMB->Flags = 0;
524362306a36Sopenharmony_ci	pSMB->Timeout = 0;
524462306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
524562306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
524662306a36Sopenharmony_ci	offset = param_offset + params;
524762306a36Sopenharmony_ci
524862306a36Sopenharmony_ci	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
524962306a36Sopenharmony_ci	data_offset = (char *)(pSMB) + offset + 4;
525062306a36Sopenharmony_ci
525162306a36Sopenharmony_ci	count = 1;
525262306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
525362306a36Sopenharmony_ci	/* BB find max SMB PDU from sess */
525462306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
525562306a36Sopenharmony_ci	pSMB->SetupCount = 1;
525662306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
525762306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
525862306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
525962306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
526062306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
526162306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
526262306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
526362306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
526462306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
526562306a36Sopenharmony_ci	pSMB->Fid = fid;
526662306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
526762306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
526862306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
526962306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
527062306a36Sopenharmony_ci	*data_offset = delete_file ? 1 : 0;
527162306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
527262306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
527362306a36Sopenharmony_ci	if (rc)
527462306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
527562306a36Sopenharmony_ci
527662306a36Sopenharmony_ci	return rc;
527762306a36Sopenharmony_ci}
527862306a36Sopenharmony_ci
527962306a36Sopenharmony_cistatic int
528062306a36Sopenharmony_ciCIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
528162306a36Sopenharmony_ci		     const char *fileName, const FILE_BASIC_INFO *data,
528262306a36Sopenharmony_ci		     const struct nls_table *nls_codepage,
528362306a36Sopenharmony_ci		     struct cifs_sb_info *cifs_sb)
528462306a36Sopenharmony_ci{
528562306a36Sopenharmony_ci	int oplock = 0;
528662306a36Sopenharmony_ci	struct cifs_open_parms oparms;
528762306a36Sopenharmony_ci	struct cifs_fid fid;
528862306a36Sopenharmony_ci	int rc;
528962306a36Sopenharmony_ci
529062306a36Sopenharmony_ci	oparms = (struct cifs_open_parms) {
529162306a36Sopenharmony_ci		.tcon = tcon,
529262306a36Sopenharmony_ci		.cifs_sb = cifs_sb,
529362306a36Sopenharmony_ci		.desired_access = GENERIC_WRITE,
529462306a36Sopenharmony_ci		.create_options = cifs_create_options(cifs_sb, 0),
529562306a36Sopenharmony_ci		.disposition = FILE_OPEN,
529662306a36Sopenharmony_ci		.path = fileName,
529762306a36Sopenharmony_ci		.fid = &fid,
529862306a36Sopenharmony_ci	};
529962306a36Sopenharmony_ci
530062306a36Sopenharmony_ci	rc = CIFS_open(xid, &oparms, &oplock, NULL);
530162306a36Sopenharmony_ci	if (rc)
530262306a36Sopenharmony_ci		goto out;
530362306a36Sopenharmony_ci
530462306a36Sopenharmony_ci	rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
530562306a36Sopenharmony_ci	CIFSSMBClose(xid, tcon, fid.netfid);
530662306a36Sopenharmony_ciout:
530762306a36Sopenharmony_ci
530862306a36Sopenharmony_ci	return rc;
530962306a36Sopenharmony_ci}
531062306a36Sopenharmony_ci
531162306a36Sopenharmony_ciint
531262306a36Sopenharmony_ciCIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
531362306a36Sopenharmony_ci		   const char *fileName, const FILE_BASIC_INFO *data,
531462306a36Sopenharmony_ci		   const struct nls_table *nls_codepage,
531562306a36Sopenharmony_ci		     struct cifs_sb_info *cifs_sb)
531662306a36Sopenharmony_ci{
531762306a36Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
531862306a36Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
531962306a36Sopenharmony_ci	int name_len;
532062306a36Sopenharmony_ci	int rc = 0;
532162306a36Sopenharmony_ci	int bytes_returned = 0;
532262306a36Sopenharmony_ci	char *data_offset;
532362306a36Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
532462306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
532562306a36Sopenharmony_ci
532662306a36Sopenharmony_ci	cifs_dbg(FYI, "In SetTimes\n");
532762306a36Sopenharmony_ci
532862306a36Sopenharmony_ciSetTimesRetry:
532962306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
533062306a36Sopenharmony_ci		      (void **) &pSMBr);
533162306a36Sopenharmony_ci	if (rc)
533262306a36Sopenharmony_ci		return rc;
533362306a36Sopenharmony_ci
533462306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
533562306a36Sopenharmony_ci		name_len =
533662306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
533762306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
533862306a36Sopenharmony_ci		name_len++;	/* trailing null */
533962306a36Sopenharmony_ci		name_len *= 2;
534062306a36Sopenharmony_ci	} else {
534162306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fileName);
534262306a36Sopenharmony_ci	}
534362306a36Sopenharmony_ci
534462306a36Sopenharmony_ci	params = 6 + name_len;
534562306a36Sopenharmony_ci	count = sizeof(FILE_BASIC_INFO);
534662306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
534762306a36Sopenharmony_ci	/* BB find max SMB PDU from sess structure BB */
534862306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
534962306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
535062306a36Sopenharmony_ci	pSMB->Reserved = 0;
535162306a36Sopenharmony_ci	pSMB->Flags = 0;
535262306a36Sopenharmony_ci	pSMB->Timeout = 0;
535362306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
535462306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
535562306a36Sopenharmony_ci				InformationLevel) - 4;
535662306a36Sopenharmony_ci	offset = param_offset + params;
535762306a36Sopenharmony_ci	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
535862306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
535962306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
536062306a36Sopenharmony_ci	pSMB->SetupCount = 1;
536162306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
536262306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
536362306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
536462306a36Sopenharmony_ci
536562306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
536662306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
536762306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
536862306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
536962306a36Sopenharmony_ci	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
537062306a36Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
537162306a36Sopenharmony_ci	else
537262306a36Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
537362306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
537462306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
537562306a36Sopenharmony_ci	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
537662306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
537762306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
537862306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
537962306a36Sopenharmony_ci	if (rc)
538062306a36Sopenharmony_ci		cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
538162306a36Sopenharmony_ci
538262306a36Sopenharmony_ci	cifs_buf_release(pSMB);
538362306a36Sopenharmony_ci
538462306a36Sopenharmony_ci	if (rc == -EAGAIN)
538562306a36Sopenharmony_ci		goto SetTimesRetry;
538662306a36Sopenharmony_ci
538762306a36Sopenharmony_ci	if (rc == -EOPNOTSUPP)
538862306a36Sopenharmony_ci		return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
538962306a36Sopenharmony_ci					    nls_codepage, cifs_sb);
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_ci	return rc;
539262306a36Sopenharmony_ci}
539362306a36Sopenharmony_ci
539462306a36Sopenharmony_cistatic void
539562306a36Sopenharmony_cicifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
539662306a36Sopenharmony_ci			const struct cifs_unix_set_info_args *args)
539762306a36Sopenharmony_ci{
539862306a36Sopenharmony_ci	u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
539962306a36Sopenharmony_ci	u64 mode = args->mode;
540062306a36Sopenharmony_ci
540162306a36Sopenharmony_ci	if (uid_valid(args->uid))
540262306a36Sopenharmony_ci		uid = from_kuid(&init_user_ns, args->uid);
540362306a36Sopenharmony_ci	if (gid_valid(args->gid))
540462306a36Sopenharmony_ci		gid = from_kgid(&init_user_ns, args->gid);
540562306a36Sopenharmony_ci
540662306a36Sopenharmony_ci	/*
540762306a36Sopenharmony_ci	 * Samba server ignores set of file size to zero due to bugs in some
540862306a36Sopenharmony_ci	 * older clients, but we should be precise - we use SetFileSize to
540962306a36Sopenharmony_ci	 * set file size and do not want to truncate file size to zero
541062306a36Sopenharmony_ci	 * accidentally as happened on one Samba server beta by putting
541162306a36Sopenharmony_ci	 * zero instead of -1 here
541262306a36Sopenharmony_ci	 */
541362306a36Sopenharmony_ci	data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
541462306a36Sopenharmony_ci	data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
541562306a36Sopenharmony_ci	data_offset->LastStatusChange = cpu_to_le64(args->ctime);
541662306a36Sopenharmony_ci	data_offset->LastAccessTime = cpu_to_le64(args->atime);
541762306a36Sopenharmony_ci	data_offset->LastModificationTime = cpu_to_le64(args->mtime);
541862306a36Sopenharmony_ci	data_offset->Uid = cpu_to_le64(uid);
541962306a36Sopenharmony_ci	data_offset->Gid = cpu_to_le64(gid);
542062306a36Sopenharmony_ci	/* better to leave device as zero when it is  */
542162306a36Sopenharmony_ci	data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
542262306a36Sopenharmony_ci	data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
542362306a36Sopenharmony_ci	data_offset->Permissions = cpu_to_le64(mode);
542462306a36Sopenharmony_ci
542562306a36Sopenharmony_ci	if (S_ISREG(mode))
542662306a36Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_FILE);
542762306a36Sopenharmony_ci	else if (S_ISDIR(mode))
542862306a36Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_DIR);
542962306a36Sopenharmony_ci	else if (S_ISLNK(mode))
543062306a36Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
543162306a36Sopenharmony_ci	else if (S_ISCHR(mode))
543262306a36Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
543362306a36Sopenharmony_ci	else if (S_ISBLK(mode))
543462306a36Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
543562306a36Sopenharmony_ci	else if (S_ISFIFO(mode))
543662306a36Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_FIFO);
543762306a36Sopenharmony_ci	else if (S_ISSOCK(mode))
543862306a36Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_SOCKET);
543962306a36Sopenharmony_ci}
544062306a36Sopenharmony_ci
544162306a36Sopenharmony_ciint
544262306a36Sopenharmony_ciCIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
544362306a36Sopenharmony_ci		       const struct cifs_unix_set_info_args *args,
544462306a36Sopenharmony_ci		       u16 fid, u32 pid_of_opener)
544562306a36Sopenharmony_ci{
544662306a36Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
544762306a36Sopenharmony_ci	char *data_offset;
544862306a36Sopenharmony_ci	int rc = 0;
544962306a36Sopenharmony_ci	u16 params, param_offset, offset, byte_count, count;
545062306a36Sopenharmony_ci
545162306a36Sopenharmony_ci	cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
545262306a36Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
545362306a36Sopenharmony_ci
545462306a36Sopenharmony_ci	if (rc)
545562306a36Sopenharmony_ci		return rc;
545662306a36Sopenharmony_ci
545762306a36Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
545862306a36Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
545962306a36Sopenharmony_ci
546062306a36Sopenharmony_ci	params = 6;
546162306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
546262306a36Sopenharmony_ci	pSMB->Reserved = 0;
546362306a36Sopenharmony_ci	pSMB->Flags = 0;
546462306a36Sopenharmony_ci	pSMB->Timeout = 0;
546562306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
546662306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
546762306a36Sopenharmony_ci	offset = param_offset + params;
546862306a36Sopenharmony_ci
546962306a36Sopenharmony_ci	data_offset = (char *)pSMB +
547062306a36Sopenharmony_ci			offsetof(struct smb_hdr, Protocol) + offset;
547162306a36Sopenharmony_ci
547262306a36Sopenharmony_ci	count = sizeof(FILE_UNIX_BASIC_INFO);
547362306a36Sopenharmony_ci
547462306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
547562306a36Sopenharmony_ci	/* BB find max SMB PDU from sess */
547662306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
547762306a36Sopenharmony_ci	pSMB->SetupCount = 1;
547862306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
547962306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
548062306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
548162306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
548262306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
548362306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
548462306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
548562306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
548662306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
548762306a36Sopenharmony_ci	pSMB->Fid = fid;
548862306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
548962306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
549062306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
549162306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
549262306a36Sopenharmony_ci
549362306a36Sopenharmony_ci	cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
549462306a36Sopenharmony_ci
549562306a36Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
549662306a36Sopenharmony_ci	cifs_small_buf_release(pSMB);
549762306a36Sopenharmony_ci	if (rc)
549862306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
549962306a36Sopenharmony_ci			 rc);
550062306a36Sopenharmony_ci
550162306a36Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
550262306a36Sopenharmony_ci		since file handle passed in no longer valid */
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_ci	return rc;
550562306a36Sopenharmony_ci}
550662306a36Sopenharmony_ci
550762306a36Sopenharmony_ciint
550862306a36Sopenharmony_ciCIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
550962306a36Sopenharmony_ci		       const char *file_name,
551062306a36Sopenharmony_ci		       const struct cifs_unix_set_info_args *args,
551162306a36Sopenharmony_ci		       const struct nls_table *nls_codepage, int remap)
551262306a36Sopenharmony_ci{
551362306a36Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
551462306a36Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
551562306a36Sopenharmony_ci	int name_len;
551662306a36Sopenharmony_ci	int rc = 0;
551762306a36Sopenharmony_ci	int bytes_returned = 0;
551862306a36Sopenharmony_ci	FILE_UNIX_BASIC_INFO *data_offset;
551962306a36Sopenharmony_ci	__u16 params, param_offset, offset, count, byte_count;
552062306a36Sopenharmony_ci
552162306a36Sopenharmony_ci	cifs_dbg(FYI, "In SetUID/GID/Mode\n");
552262306a36Sopenharmony_cisetPermsRetry:
552362306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
552462306a36Sopenharmony_ci		      (void **) &pSMBr);
552562306a36Sopenharmony_ci	if (rc)
552662306a36Sopenharmony_ci		return rc;
552762306a36Sopenharmony_ci
552862306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
552962306a36Sopenharmony_ci		name_len =
553062306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
553162306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
553262306a36Sopenharmony_ci		name_len++;	/* trailing null */
553362306a36Sopenharmony_ci		name_len *= 2;
553462306a36Sopenharmony_ci	} else {
553562306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, file_name);
553662306a36Sopenharmony_ci	}
553762306a36Sopenharmony_ci
553862306a36Sopenharmony_ci	params = 6 + name_len;
553962306a36Sopenharmony_ci	count = sizeof(FILE_UNIX_BASIC_INFO);
554062306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
554162306a36Sopenharmony_ci	/* BB find max SMB PDU from sess structure BB */
554262306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
554362306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
554462306a36Sopenharmony_ci	pSMB->Reserved = 0;
554562306a36Sopenharmony_ci	pSMB->Flags = 0;
554662306a36Sopenharmony_ci	pSMB->Timeout = 0;
554762306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
554862306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
554962306a36Sopenharmony_ci				InformationLevel) - 4;
555062306a36Sopenharmony_ci	offset = param_offset + params;
555162306a36Sopenharmony_ci	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
555262306a36Sopenharmony_ci	data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
555362306a36Sopenharmony_ci	memset(data_offset, 0, count);
555462306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
555562306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
555662306a36Sopenharmony_ci	pSMB->SetupCount = 1;
555762306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
555862306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
555962306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
556062306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
556162306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
556262306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
556362306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
556462306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
556562306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
556662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
556762306a36Sopenharmony_ci
556862306a36Sopenharmony_ci	cifs_fill_unix_set_info(data_offset, args);
556962306a36Sopenharmony_ci
557062306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
557162306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
557262306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
557362306a36Sopenharmony_ci	if (rc)
557462306a36Sopenharmony_ci		cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
557562306a36Sopenharmony_ci
557662306a36Sopenharmony_ci	cifs_buf_release(pSMB);
557762306a36Sopenharmony_ci	if (rc == -EAGAIN)
557862306a36Sopenharmony_ci		goto setPermsRetry;
557962306a36Sopenharmony_ci	return rc;
558062306a36Sopenharmony_ci}
558162306a36Sopenharmony_ci
558262306a36Sopenharmony_ci#ifdef CONFIG_CIFS_XATTR
558362306a36Sopenharmony_ci/*
558462306a36Sopenharmony_ci * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
558562306a36Sopenharmony_ci * function used by listxattr and getxattr type calls. When ea_name is set,
558662306a36Sopenharmony_ci * it looks for that attribute name and stuffs that value into the EAData
558762306a36Sopenharmony_ci * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
558862306a36Sopenharmony_ci * buffer. In both cases, the return value is either the length of the
558962306a36Sopenharmony_ci * resulting data or a negative error code. If EAData is a NULL pointer then
559062306a36Sopenharmony_ci * the data isn't copied to it, but the length is returned.
559162306a36Sopenharmony_ci */
559262306a36Sopenharmony_cissize_t
559362306a36Sopenharmony_ciCIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
559462306a36Sopenharmony_ci		const unsigned char *searchName, const unsigned char *ea_name,
559562306a36Sopenharmony_ci		char *EAData, size_t buf_size,
559662306a36Sopenharmony_ci		struct cifs_sb_info *cifs_sb)
559762306a36Sopenharmony_ci{
559862306a36Sopenharmony_ci		/* BB assumes one setup word */
559962306a36Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
560062306a36Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
560162306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
560262306a36Sopenharmony_ci	struct nls_table *nls_codepage = cifs_sb->local_nls;
560362306a36Sopenharmony_ci	int rc = 0;
560462306a36Sopenharmony_ci	int bytes_returned;
560562306a36Sopenharmony_ci	int list_len;
560662306a36Sopenharmony_ci	struct fealist *ea_response_data;
560762306a36Sopenharmony_ci	struct fea *temp_fea;
560862306a36Sopenharmony_ci	char *temp_ptr;
560962306a36Sopenharmony_ci	char *end_of_smb;
561062306a36Sopenharmony_ci	__u16 params, byte_count, data_offset;
561162306a36Sopenharmony_ci	unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
561262306a36Sopenharmony_ci
561362306a36Sopenharmony_ci	cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
561462306a36Sopenharmony_ciQAllEAsRetry:
561562306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
561662306a36Sopenharmony_ci		      (void **) &pSMBr);
561762306a36Sopenharmony_ci	if (rc)
561862306a36Sopenharmony_ci		return rc;
561962306a36Sopenharmony_ci
562062306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
562162306a36Sopenharmony_ci		list_len =
562262306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
562362306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
562462306a36Sopenharmony_ci		list_len++;	/* trailing null */
562562306a36Sopenharmony_ci		list_len *= 2;
562662306a36Sopenharmony_ci	} else {
562762306a36Sopenharmony_ci		list_len = copy_path_name(pSMB->FileName, searchName);
562862306a36Sopenharmony_ci	}
562962306a36Sopenharmony_ci
563062306a36Sopenharmony_ci	params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
563162306a36Sopenharmony_ci	pSMB->TotalDataCount = 0;
563262306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
563362306a36Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
563462306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
563562306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
563662306a36Sopenharmony_ci	pSMB->Reserved = 0;
563762306a36Sopenharmony_ci	pSMB->Flags = 0;
563862306a36Sopenharmony_ci	pSMB->Timeout = 0;
563962306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
564062306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
564162306a36Sopenharmony_ci	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
564262306a36Sopenharmony_ci	pSMB->DataCount = 0;
564362306a36Sopenharmony_ci	pSMB->DataOffset = 0;
564462306a36Sopenharmony_ci	pSMB->SetupCount = 1;
564562306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
564662306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
564762306a36Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
564862306a36Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
564962306a36Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
565062306a36Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
565162306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
565262306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
565362306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
565462306a36Sopenharmony_ci
565562306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
565662306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
565762306a36Sopenharmony_ci	if (rc) {
565862306a36Sopenharmony_ci		cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
565962306a36Sopenharmony_ci		goto QAllEAsOut;
566062306a36Sopenharmony_ci	}
566162306a36Sopenharmony_ci
566262306a36Sopenharmony_ci
566362306a36Sopenharmony_ci	/* BB also check enough total bytes returned */
566462306a36Sopenharmony_ci	/* BB we need to improve the validity checking
566562306a36Sopenharmony_ci	of these trans2 responses */
566662306a36Sopenharmony_ci
566762306a36Sopenharmony_ci	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
566862306a36Sopenharmony_ci	if (rc || get_bcc(&pSMBr->hdr) < 4) {
566962306a36Sopenharmony_ci		rc = -EIO;	/* bad smb */
567062306a36Sopenharmony_ci		goto QAllEAsOut;
567162306a36Sopenharmony_ci	}
567262306a36Sopenharmony_ci
567362306a36Sopenharmony_ci	/* check that length of list is not more than bcc */
567462306a36Sopenharmony_ci	/* check that each entry does not go beyond length
567562306a36Sopenharmony_ci	   of list */
567662306a36Sopenharmony_ci	/* check that each element of each entry does not
567762306a36Sopenharmony_ci	   go beyond end of list */
567862306a36Sopenharmony_ci	/* validate_trans2_offsets() */
567962306a36Sopenharmony_ci	/* BB check if start of smb + data_offset > &bcc+ bcc */
568062306a36Sopenharmony_ci
568162306a36Sopenharmony_ci	data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
568262306a36Sopenharmony_ci	ea_response_data = (struct fealist *)
568362306a36Sopenharmony_ci				(((char *) &pSMBr->hdr.Protocol) + data_offset);
568462306a36Sopenharmony_ci
568562306a36Sopenharmony_ci	list_len = le32_to_cpu(ea_response_data->list_len);
568662306a36Sopenharmony_ci	cifs_dbg(FYI, "ea length %d\n", list_len);
568762306a36Sopenharmony_ci	if (list_len <= 8) {
568862306a36Sopenharmony_ci		cifs_dbg(FYI, "empty EA list returned from server\n");
568962306a36Sopenharmony_ci		/* didn't find the named attribute */
569062306a36Sopenharmony_ci		if (ea_name)
569162306a36Sopenharmony_ci			rc = -ENODATA;
569262306a36Sopenharmony_ci		goto QAllEAsOut;
569362306a36Sopenharmony_ci	}
569462306a36Sopenharmony_ci
569562306a36Sopenharmony_ci	/* make sure list_len doesn't go past end of SMB */
569662306a36Sopenharmony_ci	end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
569762306a36Sopenharmony_ci	if ((char *)ea_response_data + list_len > end_of_smb) {
569862306a36Sopenharmony_ci		cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
569962306a36Sopenharmony_ci		rc = -EIO;
570062306a36Sopenharmony_ci		goto QAllEAsOut;
570162306a36Sopenharmony_ci	}
570262306a36Sopenharmony_ci
570362306a36Sopenharmony_ci	/* account for ea list len */
570462306a36Sopenharmony_ci	list_len -= 4;
570562306a36Sopenharmony_ci	temp_fea = &ea_response_data->list;
570662306a36Sopenharmony_ci	temp_ptr = (char *)temp_fea;
570762306a36Sopenharmony_ci	while (list_len > 0) {
570862306a36Sopenharmony_ci		unsigned int name_len;
570962306a36Sopenharmony_ci		__u16 value_len;
571062306a36Sopenharmony_ci
571162306a36Sopenharmony_ci		list_len -= 4;
571262306a36Sopenharmony_ci		temp_ptr += 4;
571362306a36Sopenharmony_ci		/* make sure we can read name_len and value_len */
571462306a36Sopenharmony_ci		if (list_len < 0) {
571562306a36Sopenharmony_ci			cifs_dbg(FYI, "EA entry goes beyond length of list\n");
571662306a36Sopenharmony_ci			rc = -EIO;
571762306a36Sopenharmony_ci			goto QAllEAsOut;
571862306a36Sopenharmony_ci		}
571962306a36Sopenharmony_ci
572062306a36Sopenharmony_ci		name_len = temp_fea->name_len;
572162306a36Sopenharmony_ci		value_len = le16_to_cpu(temp_fea->value_len);
572262306a36Sopenharmony_ci		list_len -= name_len + 1 + value_len;
572362306a36Sopenharmony_ci		if (list_len < 0) {
572462306a36Sopenharmony_ci			cifs_dbg(FYI, "EA entry goes beyond length of list\n");
572562306a36Sopenharmony_ci			rc = -EIO;
572662306a36Sopenharmony_ci			goto QAllEAsOut;
572762306a36Sopenharmony_ci		}
572862306a36Sopenharmony_ci
572962306a36Sopenharmony_ci		if (ea_name) {
573062306a36Sopenharmony_ci			if (ea_name_len == name_len &&
573162306a36Sopenharmony_ci			    memcmp(ea_name, temp_ptr, name_len) == 0) {
573262306a36Sopenharmony_ci				temp_ptr += name_len + 1;
573362306a36Sopenharmony_ci				rc = value_len;
573462306a36Sopenharmony_ci				if (buf_size == 0)
573562306a36Sopenharmony_ci					goto QAllEAsOut;
573662306a36Sopenharmony_ci				if ((size_t)value_len > buf_size) {
573762306a36Sopenharmony_ci					rc = -ERANGE;
573862306a36Sopenharmony_ci					goto QAllEAsOut;
573962306a36Sopenharmony_ci				}
574062306a36Sopenharmony_ci				memcpy(EAData, temp_ptr, value_len);
574162306a36Sopenharmony_ci				goto QAllEAsOut;
574262306a36Sopenharmony_ci			}
574362306a36Sopenharmony_ci		} else {
574462306a36Sopenharmony_ci			/* account for prefix user. and trailing null */
574562306a36Sopenharmony_ci			rc += (5 + 1 + name_len);
574662306a36Sopenharmony_ci			if (rc < (int) buf_size) {
574762306a36Sopenharmony_ci				memcpy(EAData, "user.", 5);
574862306a36Sopenharmony_ci				EAData += 5;
574962306a36Sopenharmony_ci				memcpy(EAData, temp_ptr, name_len);
575062306a36Sopenharmony_ci				EAData += name_len;
575162306a36Sopenharmony_ci				/* null terminate name */
575262306a36Sopenharmony_ci				*EAData = 0;
575362306a36Sopenharmony_ci				++EAData;
575462306a36Sopenharmony_ci			} else if (buf_size == 0) {
575562306a36Sopenharmony_ci				/* skip copy - calc size only */
575662306a36Sopenharmony_ci			} else {
575762306a36Sopenharmony_ci				/* stop before overrun buffer */
575862306a36Sopenharmony_ci				rc = -ERANGE;
575962306a36Sopenharmony_ci				break;
576062306a36Sopenharmony_ci			}
576162306a36Sopenharmony_ci		}
576262306a36Sopenharmony_ci		temp_ptr += name_len + 1 + value_len;
576362306a36Sopenharmony_ci		temp_fea = (struct fea *)temp_ptr;
576462306a36Sopenharmony_ci	}
576562306a36Sopenharmony_ci
576662306a36Sopenharmony_ci	/* didn't find the named attribute */
576762306a36Sopenharmony_ci	if (ea_name)
576862306a36Sopenharmony_ci		rc = -ENODATA;
576962306a36Sopenharmony_ci
577062306a36Sopenharmony_ciQAllEAsOut:
577162306a36Sopenharmony_ci	cifs_buf_release(pSMB);
577262306a36Sopenharmony_ci	if (rc == -EAGAIN)
577362306a36Sopenharmony_ci		goto QAllEAsRetry;
577462306a36Sopenharmony_ci
577562306a36Sopenharmony_ci	return (ssize_t)rc;
577662306a36Sopenharmony_ci}
577762306a36Sopenharmony_ci
577862306a36Sopenharmony_ciint
577962306a36Sopenharmony_ciCIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
578062306a36Sopenharmony_ci	     const char *fileName, const char *ea_name, const void *ea_value,
578162306a36Sopenharmony_ci	     const __u16 ea_value_len, const struct nls_table *nls_codepage,
578262306a36Sopenharmony_ci	     struct cifs_sb_info *cifs_sb)
578362306a36Sopenharmony_ci{
578462306a36Sopenharmony_ci	struct smb_com_transaction2_spi_req *pSMB = NULL;
578562306a36Sopenharmony_ci	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
578662306a36Sopenharmony_ci	struct fealist *parm_data;
578762306a36Sopenharmony_ci	int name_len;
578862306a36Sopenharmony_ci	int rc = 0;
578962306a36Sopenharmony_ci	int bytes_returned = 0;
579062306a36Sopenharmony_ci	__u16 params, param_offset, byte_count, offset, count;
579162306a36Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
579262306a36Sopenharmony_ci
579362306a36Sopenharmony_ci	cifs_dbg(FYI, "In SetEA\n");
579462306a36Sopenharmony_ciSetEARetry:
579562306a36Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
579662306a36Sopenharmony_ci		      (void **) &pSMBr);
579762306a36Sopenharmony_ci	if (rc)
579862306a36Sopenharmony_ci		return rc;
579962306a36Sopenharmony_ci
580062306a36Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
580162306a36Sopenharmony_ci		name_len =
580262306a36Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
580362306a36Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
580462306a36Sopenharmony_ci		name_len++;	/* trailing null */
580562306a36Sopenharmony_ci		name_len *= 2;
580662306a36Sopenharmony_ci	} else {
580762306a36Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fileName);
580862306a36Sopenharmony_ci	}
580962306a36Sopenharmony_ci
581062306a36Sopenharmony_ci	params = 6 + name_len;
581162306a36Sopenharmony_ci
581262306a36Sopenharmony_ci	/* done calculating parms using name_len of file name,
581362306a36Sopenharmony_ci	now use name_len to calculate length of ea name
581462306a36Sopenharmony_ci	we are going to create in the inode xattrs */
581562306a36Sopenharmony_ci	if (ea_name == NULL)
581662306a36Sopenharmony_ci		name_len = 0;
581762306a36Sopenharmony_ci	else
581862306a36Sopenharmony_ci		name_len = strnlen(ea_name, 255);
581962306a36Sopenharmony_ci
582062306a36Sopenharmony_ci	count = sizeof(*parm_data) + 1 + ea_value_len + name_len;
582162306a36Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
582262306a36Sopenharmony_ci	/* BB find max SMB PDU from sess */
582362306a36Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
582462306a36Sopenharmony_ci	pSMB->MaxSetupCount = 0;
582562306a36Sopenharmony_ci	pSMB->Reserved = 0;
582662306a36Sopenharmony_ci	pSMB->Flags = 0;
582762306a36Sopenharmony_ci	pSMB->Timeout = 0;
582862306a36Sopenharmony_ci	pSMB->Reserved2 = 0;
582962306a36Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
583062306a36Sopenharmony_ci				InformationLevel) - 4;
583162306a36Sopenharmony_ci	offset = param_offset + params;
583262306a36Sopenharmony_ci	pSMB->InformationLevel =
583362306a36Sopenharmony_ci		cpu_to_le16(SMB_SET_FILE_EA);
583462306a36Sopenharmony_ci
583562306a36Sopenharmony_ci	parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
583662306a36Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
583762306a36Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
583862306a36Sopenharmony_ci	pSMB->SetupCount = 1;
583962306a36Sopenharmony_ci	pSMB->Reserved3 = 0;
584062306a36Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
584162306a36Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
584262306a36Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
584362306a36Sopenharmony_ci	parm_data->list_len = cpu_to_le32(count);
584462306a36Sopenharmony_ci	parm_data->list.EA_flags = 0;
584562306a36Sopenharmony_ci	/* we checked above that name len is less than 255 */
584662306a36Sopenharmony_ci	parm_data->list.name_len = (__u8)name_len;
584762306a36Sopenharmony_ci	/* EA names are always ASCII */
584862306a36Sopenharmony_ci	if (ea_name)
584962306a36Sopenharmony_ci		strncpy(parm_data->list.name, ea_name, name_len);
585062306a36Sopenharmony_ci	parm_data->list.name[name_len] = '\0';
585162306a36Sopenharmony_ci	parm_data->list.value_len = cpu_to_le16(ea_value_len);
585262306a36Sopenharmony_ci	/* caller ensures that ea_value_len is less than 64K but
585362306a36Sopenharmony_ci	we need to ensure that it fits within the smb */
585462306a36Sopenharmony_ci
585562306a36Sopenharmony_ci	/*BB add length check to see if it would fit in
585662306a36Sopenharmony_ci	     negotiated SMB buffer size BB */
585762306a36Sopenharmony_ci	/* if (ea_value_len > buffer_size - 512 (enough for header)) */
585862306a36Sopenharmony_ci	if (ea_value_len)
585962306a36Sopenharmony_ci		memcpy(parm_data->list.name + name_len + 1,
586062306a36Sopenharmony_ci		       ea_value, ea_value_len);
586162306a36Sopenharmony_ci
586262306a36Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
586362306a36Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
586462306a36Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
586562306a36Sopenharmony_ci	pSMB->Reserved4 = 0;
586662306a36Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
586762306a36Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
586862306a36Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
586962306a36Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
587062306a36Sopenharmony_ci	if (rc)
587162306a36Sopenharmony_ci		cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
587262306a36Sopenharmony_ci
587362306a36Sopenharmony_ci	cifs_buf_release(pSMB);
587462306a36Sopenharmony_ci
587562306a36Sopenharmony_ci	if (rc == -EAGAIN)
587662306a36Sopenharmony_ci		goto SetEARetry;
587762306a36Sopenharmony_ci
587862306a36Sopenharmony_ci	return rc;
587962306a36Sopenharmony_ci}
588062306a36Sopenharmony_ci#endif
5881