18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *   fs/cifs/cifssmb.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *   Copyright (C) International Business Machines  Corp., 2002,2010
58c2ecf20Sopenharmony_ci *   Author(s): Steve French (sfrench@us.ibm.com)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *   Contains the routines for constructing the SMB PDUs themselves
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
108c2ecf20Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as published
118c2ecf20Sopenharmony_ci *   by the Free Software Foundation; either version 2.1 of the License, or
128c2ecf20Sopenharmony_ci *   (at your option) any later version.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *   This library is distributed in the hope that it will be useful,
158c2ecf20Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
168c2ecf20Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
178c2ecf20Sopenharmony_ci *   the GNU Lesser General Public License for more details.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public License
208c2ecf20Sopenharmony_ci *   along with this library; if not, write to the Free Software
218c2ecf20Sopenharmony_ci *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
258c2ecf20Sopenharmony_ci /* These are mostly routines that operate on a pathname, or on a tree id     */
268c2ecf20Sopenharmony_ci /* (mounted volume), but there are eight handle based routines which must be */
278c2ecf20Sopenharmony_ci /* treated slightly differently for reconnection purposes since we never     */
288c2ecf20Sopenharmony_ci /* want to reuse a stale file handle and only the caller knows the file info */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <linux/fs.h>
318c2ecf20Sopenharmony_ci#include <linux/kernel.h>
328c2ecf20Sopenharmony_ci#include <linux/vfs.h>
338c2ecf20Sopenharmony_ci#include <linux/slab.h>
348c2ecf20Sopenharmony_ci#include <linux/posix_acl_xattr.h>
358c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
368c2ecf20Sopenharmony_ci#include <linux/swap.h>
378c2ecf20Sopenharmony_ci#include <linux/task_io_accounting_ops.h>
388c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
398c2ecf20Sopenharmony_ci#include "cifspdu.h"
408c2ecf20Sopenharmony_ci#include "cifsglob.h"
418c2ecf20Sopenharmony_ci#include "cifsacl.h"
428c2ecf20Sopenharmony_ci#include "cifsproto.h"
438c2ecf20Sopenharmony_ci#include "cifs_unicode.h"
448c2ecf20Sopenharmony_ci#include "cifs_debug.h"
458c2ecf20Sopenharmony_ci#include "smb2proto.h"
468c2ecf20Sopenharmony_ci#include "fscache.h"
478c2ecf20Sopenharmony_ci#include "smbdirect.h"
488c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL
498c2ecf20Sopenharmony_ci#include "dfs_cache.h"
508c2ecf20Sopenharmony_ci#endif
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX
538c2ecf20Sopenharmony_cistatic struct {
548c2ecf20Sopenharmony_ci	int index;
558c2ecf20Sopenharmony_ci	char *name;
568c2ecf20Sopenharmony_ci} protocols[] = {
578c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_WEAK_PW_HASH
588c2ecf20Sopenharmony_ci	{LANMAN_PROT, "\2LM1.2X002"},
598c2ecf20Sopenharmony_ci	{LANMAN2_PROT, "\2LANMAN2.1"},
608c2ecf20Sopenharmony_ci#endif /* weak password hashing for legacy clients */
618c2ecf20Sopenharmony_ci	{CIFS_PROT, "\2NT LM 0.12"},
628c2ecf20Sopenharmony_ci	{POSIX_PROT, "\2POSIX 2"},
638c2ecf20Sopenharmony_ci	{BAD_PROT, "\2"}
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci#else
668c2ecf20Sopenharmony_cistatic struct {
678c2ecf20Sopenharmony_ci	int index;
688c2ecf20Sopenharmony_ci	char *name;
698c2ecf20Sopenharmony_ci} protocols[] = {
708c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_WEAK_PW_HASH
718c2ecf20Sopenharmony_ci	{LANMAN_PROT, "\2LM1.2X002"},
728c2ecf20Sopenharmony_ci	{LANMAN2_PROT, "\2LANMAN2.1"},
738c2ecf20Sopenharmony_ci#endif /* weak password hashing for legacy clients */
748c2ecf20Sopenharmony_ci	{CIFS_PROT, "\2NT LM 0.12"},
758c2ecf20Sopenharmony_ci	{BAD_PROT, "\2"}
768c2ecf20Sopenharmony_ci};
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/* define the number of elements in the cifs dialect array */
808c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX
818c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_WEAK_PW_HASH
828c2ecf20Sopenharmony_ci#define CIFS_NUM_PROT 4
838c2ecf20Sopenharmony_ci#else
848c2ecf20Sopenharmony_ci#define CIFS_NUM_PROT 2
858c2ecf20Sopenharmony_ci#endif /* CIFS_WEAK_PW_HASH */
868c2ecf20Sopenharmony_ci#else /* not posix */
878c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_WEAK_PW_HASH
888c2ecf20Sopenharmony_ci#define CIFS_NUM_PROT 3
898c2ecf20Sopenharmony_ci#else
908c2ecf20Sopenharmony_ci#define CIFS_NUM_PROT 1
918c2ecf20Sopenharmony_ci#endif /* CONFIG_CIFS_WEAK_PW_HASH */
928c2ecf20Sopenharmony_ci#endif /* CIFS_POSIX */
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/*
958c2ecf20Sopenharmony_ci * Mark as invalid, all open files on tree connections since they
968c2ecf20Sopenharmony_ci * were closed when session to server was lost.
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_civoid
998c2ecf20Sopenharmony_cicifs_mark_open_files_invalid(struct cifs_tcon *tcon)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct cifsFileInfo *open_file = NULL;
1028c2ecf20Sopenharmony_ci	struct list_head *tmp;
1038c2ecf20Sopenharmony_ci	struct list_head *tmp1;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* list all files open on tree connection and mark them invalid */
1068c2ecf20Sopenharmony_ci	spin_lock(&tcon->open_file_lock);
1078c2ecf20Sopenharmony_ci	list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
1088c2ecf20Sopenharmony_ci		open_file = list_entry(tmp, struct cifsFileInfo, tlist);
1098c2ecf20Sopenharmony_ci		open_file->invalidHandle = true;
1108c2ecf20Sopenharmony_ci		open_file->oplock_break_cancelled = true;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci	spin_unlock(&tcon->open_file_lock);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	mutex_lock(&tcon->crfid.fid_mutex);
1158c2ecf20Sopenharmony_ci	tcon->crfid.is_valid = false;
1168c2ecf20Sopenharmony_ci	/* cached handle is not valid, so SMB2_CLOSE won't be sent below */
1178c2ecf20Sopenharmony_ci	close_shroot_lease_locked(&tcon->crfid);
1188c2ecf20Sopenharmony_ci	memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
1198c2ecf20Sopenharmony_ci	mutex_unlock(&tcon->crfid.fid_mutex);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/*
1228c2ecf20Sopenharmony_ci	 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
1238c2ecf20Sopenharmony_ci	 * to this tcon.
1248c2ecf20Sopenharmony_ci	 */
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/* reconnect the socket, tcon, and smb session if needed */
1288c2ecf20Sopenharmony_cistatic int
1298c2ecf20Sopenharmony_cicifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	int rc;
1328c2ecf20Sopenharmony_ci	struct cifs_ses *ses;
1338c2ecf20Sopenharmony_ci	struct TCP_Server_Info *server;
1348c2ecf20Sopenharmony_ci	struct nls_table *nls_codepage;
1358c2ecf20Sopenharmony_ci	int retries;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/*
1388c2ecf20Sopenharmony_ci	 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
1398c2ecf20Sopenharmony_ci	 * tcp and smb session status done differently for those three - in the
1408c2ecf20Sopenharmony_ci	 * calling routine
1418c2ecf20Sopenharmony_ci	 */
1428c2ecf20Sopenharmony_ci	if (!tcon)
1438c2ecf20Sopenharmony_ci		return 0;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	ses = tcon->ses;
1468c2ecf20Sopenharmony_ci	server = ses->server;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	/*
1498c2ecf20Sopenharmony_ci	 * only tree disconnect, open, and write, (and ulogoff which does not
1508c2ecf20Sopenharmony_ci	 * have tcon) are allowed as we start force umount
1518c2ecf20Sopenharmony_ci	 */
1528c2ecf20Sopenharmony_ci	if (tcon->tidStatus == CifsExiting) {
1538c2ecf20Sopenharmony_ci		if (smb_command != SMB_COM_WRITE_ANDX &&
1548c2ecf20Sopenharmony_ci		    smb_command != SMB_COM_OPEN_ANDX &&
1558c2ecf20Sopenharmony_ci		    smb_command != SMB_COM_TREE_DISCONNECT) {
1568c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
1578c2ecf20Sopenharmony_ci				 smb_command);
1588c2ecf20Sopenharmony_ci			return -ENODEV;
1598c2ecf20Sopenharmony_ci		}
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	retries = server->nr_targets;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	/*
1658c2ecf20Sopenharmony_ci	 * Give demultiplex thread up to 10 seconds to each target available for
1668c2ecf20Sopenharmony_ci	 * reconnect -- should be greater than cifs socket timeout which is 7
1678c2ecf20Sopenharmony_ci	 * seconds.
1688c2ecf20Sopenharmony_ci	 */
1698c2ecf20Sopenharmony_ci	while (server->tcpStatus == CifsNeedReconnect) {
1708c2ecf20Sopenharmony_ci		rc = wait_event_interruptible_timeout(server->response_q,
1718c2ecf20Sopenharmony_ci						      (server->tcpStatus != CifsNeedReconnect),
1728c2ecf20Sopenharmony_ci						      10 * HZ);
1738c2ecf20Sopenharmony_ci		if (rc < 0) {
1748c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
1758c2ecf20Sopenharmony_ci				 __func__);
1768c2ecf20Sopenharmony_ci			return -ERESTARTSYS;
1778c2ecf20Sopenharmony_ci		}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		/* are we still trying to reconnect? */
1808c2ecf20Sopenharmony_ci		if (server->tcpStatus != CifsNeedReconnect)
1818c2ecf20Sopenharmony_ci			break;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		if (retries && --retries)
1848c2ecf20Sopenharmony_ci			continue;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		/*
1878c2ecf20Sopenharmony_ci		 * on "soft" mounts we wait once. Hard mounts keep
1888c2ecf20Sopenharmony_ci		 * retrying until process is killed or server comes
1898c2ecf20Sopenharmony_ci		 * back on-line
1908c2ecf20Sopenharmony_ci		 */
1918c2ecf20Sopenharmony_ci		if (!tcon->retry) {
1928c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
1938c2ecf20Sopenharmony_ci			return -EHOSTDOWN;
1948c2ecf20Sopenharmony_ci		}
1958c2ecf20Sopenharmony_ci		retries = server->nr_targets;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (!ses->need_reconnect && !tcon->need_reconnect)
1998c2ecf20Sopenharmony_ci		return 0;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	nls_codepage = load_nls_default();
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/*
2048c2ecf20Sopenharmony_ci	 * need to prevent multiple threads trying to simultaneously
2058c2ecf20Sopenharmony_ci	 * reconnect the same SMB session
2068c2ecf20Sopenharmony_ci	 */
2078c2ecf20Sopenharmony_ci	mutex_lock(&ses->session_mutex);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/*
2108c2ecf20Sopenharmony_ci	 * Recheck after acquire mutex. If another thread is negotiating
2118c2ecf20Sopenharmony_ci	 * and the server never sends an answer the socket will be closed
2128c2ecf20Sopenharmony_ci	 * and tcpStatus set to reconnect.
2138c2ecf20Sopenharmony_ci	 */
2148c2ecf20Sopenharmony_ci	if (server->tcpStatus == CifsNeedReconnect) {
2158c2ecf20Sopenharmony_ci		rc = -EHOSTDOWN;
2168c2ecf20Sopenharmony_ci		mutex_unlock(&ses->session_mutex);
2178c2ecf20Sopenharmony_ci		goto out;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	rc = cifs_negotiate_protocol(0, ses);
2218c2ecf20Sopenharmony_ci	if (rc == 0 && ses->need_reconnect)
2228c2ecf20Sopenharmony_ci		rc = cifs_setup_session(0, ses, nls_codepage);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* do we need to reconnect tcon? */
2258c2ecf20Sopenharmony_ci	if (rc || !tcon->need_reconnect) {
2268c2ecf20Sopenharmony_ci		mutex_unlock(&ses->session_mutex);
2278c2ecf20Sopenharmony_ci		goto out;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	cifs_mark_open_files_invalid(tcon);
2318c2ecf20Sopenharmony_ci	rc = cifs_tree_connect(0, tcon, nls_codepage);
2328c2ecf20Sopenharmony_ci	mutex_unlock(&ses->session_mutex);
2338c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (rc) {
2368c2ecf20Sopenharmony_ci		pr_warn_once("reconnect tcon failed rc = %d\n", rc);
2378c2ecf20Sopenharmony_ci		goto out;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	atomic_inc(&tconInfoReconnectCount);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* tell server Unix caps we support */
2438c2ecf20Sopenharmony_ci	if (cap_unix(ses))
2448c2ecf20Sopenharmony_ci		reset_cifs_unix_caps(0, tcon, NULL, NULL);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/*
2478c2ecf20Sopenharmony_ci	 * Removed call to reopen open files here. It is safer (and faster) to
2488c2ecf20Sopenharmony_ci	 * reopen files one at a time as needed in read and write.
2498c2ecf20Sopenharmony_ci	 *
2508c2ecf20Sopenharmony_ci	 * FIXME: what about file locks? don't we need to reclaim them ASAP?
2518c2ecf20Sopenharmony_ci	 */
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ciout:
2548c2ecf20Sopenharmony_ci	/*
2558c2ecf20Sopenharmony_ci	 * Check if handle based operation so we know whether we can continue
2568c2ecf20Sopenharmony_ci	 * or not without returning to caller to reset file handle
2578c2ecf20Sopenharmony_ci	 */
2588c2ecf20Sopenharmony_ci	switch (smb_command) {
2598c2ecf20Sopenharmony_ci	case SMB_COM_READ_ANDX:
2608c2ecf20Sopenharmony_ci	case SMB_COM_WRITE_ANDX:
2618c2ecf20Sopenharmony_ci	case SMB_COM_CLOSE:
2628c2ecf20Sopenharmony_ci	case SMB_COM_FIND_CLOSE2:
2638c2ecf20Sopenharmony_ci	case SMB_COM_LOCKING_ANDX:
2648c2ecf20Sopenharmony_ci		rc = -EAGAIN;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	unload_nls(nls_codepage);
2688c2ecf20Sopenharmony_ci	return rc;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci/* Allocate and return pointer to an SMB request buffer, and set basic
2728c2ecf20Sopenharmony_ci   SMB information in the SMB header.  If the return code is zero, this
2738c2ecf20Sopenharmony_ci   function must have filled in request_buf pointer */
2748c2ecf20Sopenharmony_cistatic int
2758c2ecf20Sopenharmony_cismall_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
2768c2ecf20Sopenharmony_ci		void **request_buf)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	int rc;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	rc = cifs_reconnect_tcon(tcon, smb_command);
2818c2ecf20Sopenharmony_ci	if (rc)
2828c2ecf20Sopenharmony_ci		return rc;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	*request_buf = cifs_small_buf_get();
2858c2ecf20Sopenharmony_ci	if (*request_buf == NULL) {
2868c2ecf20Sopenharmony_ci		/* BB should we add a retry in here if not a writepage? */
2878c2ecf20Sopenharmony_ci		return -ENOMEM;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	header_assemble((struct smb_hdr *) *request_buf, smb_command,
2918c2ecf20Sopenharmony_ci			tcon, wct);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (tcon != NULL)
2948c2ecf20Sopenharmony_ci		cifs_stats_inc(&tcon->num_smbs_sent);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return 0;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ciint
3008c2ecf20Sopenharmony_cismall_smb_init_no_tc(const int smb_command, const int wct,
3018c2ecf20Sopenharmony_ci		     struct cifs_ses *ses, void **request_buf)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	int rc;
3048c2ecf20Sopenharmony_ci	struct smb_hdr *buffer;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	rc = small_smb_init(smb_command, wct, NULL, request_buf);
3078c2ecf20Sopenharmony_ci	if (rc)
3088c2ecf20Sopenharmony_ci		return rc;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	buffer = (struct smb_hdr *)*request_buf;
3118c2ecf20Sopenharmony_ci	buffer->Mid = get_next_mid(ses->server);
3128c2ecf20Sopenharmony_ci	if (ses->capabilities & CAP_UNICODE)
3138c2ecf20Sopenharmony_ci		buffer->Flags2 |= SMBFLG2_UNICODE;
3148c2ecf20Sopenharmony_ci	if (ses->capabilities & CAP_STATUS32)
3158c2ecf20Sopenharmony_ci		buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* uid, tid can stay at zero as set in header assemble */
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/* BB add support for turning on the signing when
3208c2ecf20Sopenharmony_ci	this function is used after 1st of session setup requests */
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return rc;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci/* If the return code is zero, this function must fill in request_buf pointer */
3268c2ecf20Sopenharmony_cistatic int
3278c2ecf20Sopenharmony_ci__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
3288c2ecf20Sopenharmony_ci			void **request_buf, void **response_buf)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	*request_buf = cifs_buf_get();
3318c2ecf20Sopenharmony_ci	if (*request_buf == NULL) {
3328c2ecf20Sopenharmony_ci		/* BB should we add a retry in here if not a writepage? */
3338c2ecf20Sopenharmony_ci		return -ENOMEM;
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci    /* Although the original thought was we needed the response buf for  */
3368c2ecf20Sopenharmony_ci    /* potential retries of smb operations it turns out we can determine */
3378c2ecf20Sopenharmony_ci    /* from the mid flags when the request buffer can be resent without  */
3388c2ecf20Sopenharmony_ci    /* having to use a second distinct buffer for the response */
3398c2ecf20Sopenharmony_ci	if (response_buf)
3408c2ecf20Sopenharmony_ci		*response_buf = *request_buf;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
3438c2ecf20Sopenharmony_ci			wct);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (tcon != NULL)
3468c2ecf20Sopenharmony_ci		cifs_stats_inc(&tcon->num_smbs_sent);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return 0;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/* If the return code is zero, this function must fill in request_buf pointer */
3528c2ecf20Sopenharmony_cistatic int
3538c2ecf20Sopenharmony_cismb_init(int smb_command, int wct, struct cifs_tcon *tcon,
3548c2ecf20Sopenharmony_ci	 void **request_buf, void **response_buf)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	int rc;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	rc = cifs_reconnect_tcon(tcon, smb_command);
3598c2ecf20Sopenharmony_ci	if (rc)
3608c2ecf20Sopenharmony_ci		return rc;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int
3668c2ecf20Sopenharmony_cismb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
3678c2ecf20Sopenharmony_ci			void **request_buf, void **response_buf)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	if (tcon->ses->need_reconnect || tcon->need_reconnect)
3708c2ecf20Sopenharmony_ci		return -EHOSTDOWN;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic int validate_t2(struct smb_t2_rsp *pSMB)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	unsigned int total_size;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	/* check for plausible wct */
3808c2ecf20Sopenharmony_ci	if (pSMB->hdr.WordCount < 10)
3818c2ecf20Sopenharmony_ci		goto vt2_err;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/* check for parm and data offset going beyond end of smb */
3848c2ecf20Sopenharmony_ci	if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
3858c2ecf20Sopenharmony_ci	    get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
3868c2ecf20Sopenharmony_ci		goto vt2_err;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
3898c2ecf20Sopenharmony_ci	if (total_size >= 512)
3908c2ecf20Sopenharmony_ci		goto vt2_err;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	/* check that bcc is at least as big as parms + data, and that it is
3938c2ecf20Sopenharmony_ci	 * less than negotiated smb buffer
3948c2ecf20Sopenharmony_ci	 */
3958c2ecf20Sopenharmony_ci	total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
3968c2ecf20Sopenharmony_ci	if (total_size > get_bcc(&pSMB->hdr) ||
3978c2ecf20Sopenharmony_ci	    total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
3988c2ecf20Sopenharmony_ci		goto vt2_err;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	return 0;
4018c2ecf20Sopenharmony_civt2_err:
4028c2ecf20Sopenharmony_ci	cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
4038c2ecf20Sopenharmony_ci		sizeof(struct smb_t2_rsp) + 16);
4048c2ecf20Sopenharmony_ci	return -EINVAL;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic int
4088c2ecf20Sopenharmony_cidecode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	int	rc = 0;
4118c2ecf20Sopenharmony_ci	u16	count;
4128c2ecf20Sopenharmony_ci	char	*guid = pSMBr->u.extended_response.GUID;
4138c2ecf20Sopenharmony_ci	struct TCP_Server_Info *server = ses->server;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	count = get_bcc(&pSMBr->hdr);
4168c2ecf20Sopenharmony_ci	if (count < SMB1_CLIENT_GUID_SIZE)
4178c2ecf20Sopenharmony_ci		return -EIO;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	spin_lock(&cifs_tcp_ses_lock);
4208c2ecf20Sopenharmony_ci	if (server->srv_count > 1) {
4218c2ecf20Sopenharmony_ci		spin_unlock(&cifs_tcp_ses_lock);
4228c2ecf20Sopenharmony_ci		if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
4238c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "server UID changed\n");
4248c2ecf20Sopenharmony_ci			memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
4258c2ecf20Sopenharmony_ci		}
4268c2ecf20Sopenharmony_ci	} else {
4278c2ecf20Sopenharmony_ci		spin_unlock(&cifs_tcp_ses_lock);
4288c2ecf20Sopenharmony_ci		memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	if (count == SMB1_CLIENT_GUID_SIZE) {
4328c2ecf20Sopenharmony_ci		server->sec_ntlmssp = true;
4338c2ecf20Sopenharmony_ci	} else {
4348c2ecf20Sopenharmony_ci		count -= SMB1_CLIENT_GUID_SIZE;
4358c2ecf20Sopenharmony_ci		rc = decode_negTokenInit(
4368c2ecf20Sopenharmony_ci			pSMBr->u.extended_response.SecurityBlob, count, server);
4378c2ecf20Sopenharmony_ci		if (rc != 1)
4388c2ecf20Sopenharmony_ci			return -EINVAL;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	return 0;
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ciint
4458c2ecf20Sopenharmony_cicifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	bool srv_sign_required = server->sec_mode & server->vals->signing_required;
4488c2ecf20Sopenharmony_ci	bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
4498c2ecf20Sopenharmony_ci	bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	/*
4528c2ecf20Sopenharmony_ci	 * Is signing required by mnt options? If not then check
4538c2ecf20Sopenharmony_ci	 * global_secflags to see if it is there.
4548c2ecf20Sopenharmony_ci	 */
4558c2ecf20Sopenharmony_ci	if (!mnt_sign_required)
4568c2ecf20Sopenharmony_ci		mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
4578c2ecf20Sopenharmony_ci						CIFSSEC_MUST_SIGN);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/*
4608c2ecf20Sopenharmony_ci	 * If signing is required then it's automatically enabled too,
4618c2ecf20Sopenharmony_ci	 * otherwise, check to see if the secflags allow it.
4628c2ecf20Sopenharmony_ci	 */
4638c2ecf20Sopenharmony_ci	mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
4648c2ecf20Sopenharmony_ci				(global_secflags & CIFSSEC_MAY_SIGN);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* If server requires signing, does client allow it? */
4678c2ecf20Sopenharmony_ci	if (srv_sign_required) {
4688c2ecf20Sopenharmony_ci		if (!mnt_sign_enabled) {
4698c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
4708c2ecf20Sopenharmony_ci			return -ENOTSUPP;
4718c2ecf20Sopenharmony_ci		}
4728c2ecf20Sopenharmony_ci		server->sign = true;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	/* If client requires signing, does server allow it? */
4768c2ecf20Sopenharmony_ci	if (mnt_sign_required) {
4778c2ecf20Sopenharmony_ci		if (!srv_sign_enabled) {
4788c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "Server does not support signing!\n");
4798c2ecf20Sopenharmony_ci			return -ENOTSUPP;
4808c2ecf20Sopenharmony_ci		}
4818c2ecf20Sopenharmony_ci		server->sign = true;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (cifs_rdma_enabled(server) && server->sign)
4858c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return 0;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_WEAK_PW_HASH
4918c2ecf20Sopenharmony_cistatic int
4928c2ecf20Sopenharmony_cidecode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	__s16 tmp;
4958c2ecf20Sopenharmony_ci	struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
4988c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	server->sec_mode = le16_to_cpu(rsp->SecurityMode);
5018c2ecf20Sopenharmony_ci	server->maxReq = min_t(unsigned int,
5028c2ecf20Sopenharmony_ci			       le16_to_cpu(rsp->MaxMpxCount),
5038c2ecf20Sopenharmony_ci			       cifs_max_pending);
5048c2ecf20Sopenharmony_ci	set_credits(server, server->maxReq);
5058c2ecf20Sopenharmony_ci	server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
5068c2ecf20Sopenharmony_ci	/* set up max_read for readpages check */
5078c2ecf20Sopenharmony_ci	server->max_read = server->maxBuf;
5088c2ecf20Sopenharmony_ci	/* even though we do not use raw we might as well set this
5098c2ecf20Sopenharmony_ci	accurately, in case we ever find a need for it */
5108c2ecf20Sopenharmony_ci	if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
5118c2ecf20Sopenharmony_ci		server->max_rw = 0xFF00;
5128c2ecf20Sopenharmony_ci		server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
5138c2ecf20Sopenharmony_ci	} else {
5148c2ecf20Sopenharmony_ci		server->max_rw = 0;/* do not need to use raw anyway */
5158c2ecf20Sopenharmony_ci		server->capabilities = CAP_MPX_MODE;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
5188c2ecf20Sopenharmony_ci	if (tmp == -1) {
5198c2ecf20Sopenharmony_ci		/* OS/2 often does not set timezone therefore
5208c2ecf20Sopenharmony_ci		 * we must use server time to calc time zone.
5218c2ecf20Sopenharmony_ci		 * Could deviate slightly from the right zone.
5228c2ecf20Sopenharmony_ci		 * Smallest defined timezone difference is 15 minutes
5238c2ecf20Sopenharmony_ci		 * (i.e. Nepal).  Rounding up/down is done to match
5248c2ecf20Sopenharmony_ci		 * this requirement.
5258c2ecf20Sopenharmony_ci		 */
5268c2ecf20Sopenharmony_ci		int val, seconds, remain, result;
5278c2ecf20Sopenharmony_ci		struct timespec64 ts;
5288c2ecf20Sopenharmony_ci		time64_t utc = ktime_get_real_seconds();
5298c2ecf20Sopenharmony_ci		ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
5308c2ecf20Sopenharmony_ci				    rsp->SrvTime.Time, 0);
5318c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
5328c2ecf20Sopenharmony_ci			 ts.tv_sec, utc,
5338c2ecf20Sopenharmony_ci			 utc - ts.tv_sec);
5348c2ecf20Sopenharmony_ci		val = (int)(utc - ts.tv_sec);
5358c2ecf20Sopenharmony_ci		seconds = abs(val);
5368c2ecf20Sopenharmony_ci		result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
5378c2ecf20Sopenharmony_ci		remain = seconds % MIN_TZ_ADJ;
5388c2ecf20Sopenharmony_ci		if (remain >= (MIN_TZ_ADJ / 2))
5398c2ecf20Sopenharmony_ci			result += MIN_TZ_ADJ;
5408c2ecf20Sopenharmony_ci		if (val < 0)
5418c2ecf20Sopenharmony_ci			result = -result;
5428c2ecf20Sopenharmony_ci		server->timeAdj = result;
5438c2ecf20Sopenharmony_ci	} else {
5448c2ecf20Sopenharmony_ci		server->timeAdj = (int)tmp;
5458c2ecf20Sopenharmony_ci		server->timeAdj *= 60; /* also in seconds */
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* BB get server time for time conversions and add
5518c2ecf20Sopenharmony_ci	code to use it and timezone since this is not UTC */
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (rsp->EncryptionKeyLength ==
5548c2ecf20Sopenharmony_ci			cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
5558c2ecf20Sopenharmony_ci		memcpy(server->cryptkey, rsp->EncryptionKey,
5568c2ecf20Sopenharmony_ci			CIFS_CRYPTO_KEY_SIZE);
5578c2ecf20Sopenharmony_ci	} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
5588c2ecf20Sopenharmony_ci		return -EIO; /* need cryptkey unless plain text */
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "LANMAN negotiated\n");
5628c2ecf20Sopenharmony_ci	return 0;
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci#else
5658c2ecf20Sopenharmony_cistatic inline int
5668c2ecf20Sopenharmony_cidecode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
5698c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci#endif
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic bool
5748c2ecf20Sopenharmony_cishould_set_ext_sec_flag(enum securityEnum sectype)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	switch (sectype) {
5778c2ecf20Sopenharmony_ci	case RawNTLMSSP:
5788c2ecf20Sopenharmony_ci	case Kerberos:
5798c2ecf20Sopenharmony_ci		return true;
5808c2ecf20Sopenharmony_ci	case Unspecified:
5818c2ecf20Sopenharmony_ci		if (global_secflags &
5828c2ecf20Sopenharmony_ci		    (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
5838c2ecf20Sopenharmony_ci			return true;
5848c2ecf20Sopenharmony_ci		fallthrough;
5858c2ecf20Sopenharmony_ci	default:
5868c2ecf20Sopenharmony_ci		return false;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ciint
5918c2ecf20Sopenharmony_ciCIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	NEGOTIATE_REQ *pSMB;
5948c2ecf20Sopenharmony_ci	NEGOTIATE_RSP *pSMBr;
5958c2ecf20Sopenharmony_ci	int rc = 0;
5968c2ecf20Sopenharmony_ci	int bytes_returned;
5978c2ecf20Sopenharmony_ci	int i;
5988c2ecf20Sopenharmony_ci	struct TCP_Server_Info *server = ses->server;
5998c2ecf20Sopenharmony_ci	u16 count;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (!server) {
6028c2ecf20Sopenharmony_ci		WARN(1, "%s: server is NULL!\n", __func__);
6038c2ecf20Sopenharmony_ci		return -EIO;
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
6078c2ecf20Sopenharmony_ci		      (void **) &pSMB, (void **) &pSMBr);
6088c2ecf20Sopenharmony_ci	if (rc)
6098c2ecf20Sopenharmony_ci		return rc;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	pSMB->hdr.Mid = get_next_mid(server);
6128c2ecf20Sopenharmony_ci	pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (should_set_ext_sec_flag(ses->sectype)) {
6158c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Requesting extended security\n");
6168c2ecf20Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	count = 0;
6208c2ecf20Sopenharmony_ci	/*
6218c2ecf20Sopenharmony_ci	 * We know that all the name entries in the protocols array
6228c2ecf20Sopenharmony_ci	 * are short (< 16 bytes anyway) and are NUL terminated.
6238c2ecf20Sopenharmony_ci	 */
6248c2ecf20Sopenharmony_ci	for (i = 0; i < CIFS_NUM_PROT; i++) {
6258c2ecf20Sopenharmony_ci		size_t len = strlen(protocols[i].name) + 1;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
6288c2ecf20Sopenharmony_ci		count += len;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
6318c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
6348c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6358c2ecf20Sopenharmony_ci	if (rc != 0)
6368c2ecf20Sopenharmony_ci		goto neg_err_exit;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	server->dialect = le16_to_cpu(pSMBr->DialectIndex);
6398c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
6408c2ecf20Sopenharmony_ci	/* Check wct = 1 error case */
6418c2ecf20Sopenharmony_ci	if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
6428c2ecf20Sopenharmony_ci		/* core returns wct = 1, but we do not ask for core - otherwise
6438c2ecf20Sopenharmony_ci		small wct just comes when dialect index is -1 indicating we
6448c2ecf20Sopenharmony_ci		could not negotiate a common dialect */
6458c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
6468c2ecf20Sopenharmony_ci		goto neg_err_exit;
6478c2ecf20Sopenharmony_ci	} else if (pSMBr->hdr.WordCount == 13) {
6488c2ecf20Sopenharmony_ci		server->negflavor = CIFS_NEGFLAVOR_LANMAN;
6498c2ecf20Sopenharmony_ci		rc = decode_lanman_negprot_rsp(server, pSMBr);
6508c2ecf20Sopenharmony_ci		goto signing_check;
6518c2ecf20Sopenharmony_ci	} else if (pSMBr->hdr.WordCount != 17) {
6528c2ecf20Sopenharmony_ci		/* unknown wct */
6538c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
6548c2ecf20Sopenharmony_ci		goto neg_err_exit;
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci	/* else wct == 17, NTLM or better */
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	server->sec_mode = pSMBr->SecurityMode;
6598c2ecf20Sopenharmony_ci	if ((server->sec_mode & SECMODE_USER) == 0)
6608c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "share mode security\n");
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	/* one byte, so no need to convert this or EncryptionKeyLen from
6638c2ecf20Sopenharmony_ci	   little endian */
6648c2ecf20Sopenharmony_ci	server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
6658c2ecf20Sopenharmony_ci			       cifs_max_pending);
6668c2ecf20Sopenharmony_ci	set_credits(server, server->maxReq);
6678c2ecf20Sopenharmony_ci	/* probably no need to store and check maxvcs */
6688c2ecf20Sopenharmony_ci	server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
6698c2ecf20Sopenharmony_ci	/* set up max_read for readpages check */
6708c2ecf20Sopenharmony_ci	server->max_read = server->maxBuf;
6718c2ecf20Sopenharmony_ci	server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
6728c2ecf20Sopenharmony_ci	cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
6738c2ecf20Sopenharmony_ci	server->capabilities = le32_to_cpu(pSMBr->Capabilities);
6748c2ecf20Sopenharmony_ci	server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
6758c2ecf20Sopenharmony_ci	server->timeAdj *= 60;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
6788c2ecf20Sopenharmony_ci		server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
6798c2ecf20Sopenharmony_ci		memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
6808c2ecf20Sopenharmony_ci		       CIFS_CRYPTO_KEY_SIZE);
6818c2ecf20Sopenharmony_ci	} else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
6828c2ecf20Sopenharmony_ci			server->capabilities & CAP_EXTENDED_SECURITY) {
6838c2ecf20Sopenharmony_ci		server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
6848c2ecf20Sopenharmony_ci		rc = decode_ext_sec_blob(ses, pSMBr);
6858c2ecf20Sopenharmony_ci	} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
6868c2ecf20Sopenharmony_ci		rc = -EIO; /* no crypt key only if plain text pwd */
6878c2ecf20Sopenharmony_ci	} else {
6888c2ecf20Sopenharmony_ci		server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
6898c2ecf20Sopenharmony_ci		server->capabilities &= ~CAP_EXTENDED_SECURITY;
6908c2ecf20Sopenharmony_ci	}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cisigning_check:
6938c2ecf20Sopenharmony_ci	if (!rc)
6948c2ecf20Sopenharmony_ci		rc = cifs_enable_signing(server, ses->sign);
6958c2ecf20Sopenharmony_cineg_err_exit:
6968c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "negprot rc %d\n", rc);
6998c2ecf20Sopenharmony_ci	return rc;
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ciint
7038c2ecf20Sopenharmony_ciCIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct smb_hdr *smb_buffer;
7068c2ecf20Sopenharmony_ci	int rc = 0;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In tree disconnect\n");
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	/* BB: do we need to check this? These should never be NULL. */
7118c2ecf20Sopenharmony_ci	if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
7128c2ecf20Sopenharmony_ci		return -EIO;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	/*
7158c2ecf20Sopenharmony_ci	 * No need to return error on this operation if tid invalidated and
7168c2ecf20Sopenharmony_ci	 * closed on server already e.g. due to tcp session crashing. Also,
7178c2ecf20Sopenharmony_ci	 * the tcon is no longer on the list, so no need to take lock before
7188c2ecf20Sopenharmony_ci	 * checking this.
7198c2ecf20Sopenharmony_ci	 */
7208c2ecf20Sopenharmony_ci	if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
7218c2ecf20Sopenharmony_ci		return 0;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
7248c2ecf20Sopenharmony_ci			    (void **)&smb_buffer);
7258c2ecf20Sopenharmony_ci	if (rc)
7268c2ecf20Sopenharmony_ci		return rc;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
7298c2ecf20Sopenharmony_ci	cifs_small_buf_release(smb_buffer);
7308c2ecf20Sopenharmony_ci	if (rc)
7318c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	/* No need to return error on this operation if tid invalidated and
7348c2ecf20Sopenharmony_ci	   closed on server already e.g. due to tcp session crashing */
7358c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
7368c2ecf20Sopenharmony_ci		rc = 0;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	return rc;
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci/*
7428c2ecf20Sopenharmony_ci * This is a no-op for now. We're not really interested in the reply, but
7438c2ecf20Sopenharmony_ci * rather in the fact that the server sent one and that server->lstrp
7448c2ecf20Sopenharmony_ci * gets updated.
7458c2ecf20Sopenharmony_ci *
7468c2ecf20Sopenharmony_ci * FIXME: maybe we should consider checking that the reply matches request?
7478c2ecf20Sopenharmony_ci */
7488c2ecf20Sopenharmony_cistatic void
7498c2ecf20Sopenharmony_cicifs_echo_callback(struct mid_q_entry *mid)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct TCP_Server_Info *server = mid->callback_data;
7528c2ecf20Sopenharmony_ci	struct cifs_credits credits = { .value = 1, .instance = 0 };
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	DeleteMidQEntry(mid);
7558c2ecf20Sopenharmony_ci	add_credits(server, &credits, CIFS_ECHO_OP);
7568c2ecf20Sopenharmony_ci}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ciint
7598c2ecf20Sopenharmony_ciCIFSSMBEcho(struct TCP_Server_Info *server)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	ECHO_REQ *smb;
7628c2ecf20Sopenharmony_ci	int rc = 0;
7638c2ecf20Sopenharmony_ci	struct kvec iov[2];
7648c2ecf20Sopenharmony_ci	struct smb_rqst rqst = { .rq_iov = iov,
7658c2ecf20Sopenharmony_ci				 .rq_nvec = 2 };
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In echo request\n");
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
7708c2ecf20Sopenharmony_ci	if (rc)
7718c2ecf20Sopenharmony_ci		return rc;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	if (server->capabilities & CAP_UNICODE)
7748c2ecf20Sopenharmony_ci		smb->hdr.Flags2 |= SMBFLG2_UNICODE;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/* set up echo request */
7778c2ecf20Sopenharmony_ci	smb->hdr.Tid = 0xffff;
7788c2ecf20Sopenharmony_ci	smb->hdr.WordCount = 1;
7798c2ecf20Sopenharmony_ci	put_unaligned_le16(1, &smb->EchoCount);
7808c2ecf20Sopenharmony_ci	put_bcc(1, &smb->hdr);
7818c2ecf20Sopenharmony_ci	smb->Data[0] = 'a';
7828c2ecf20Sopenharmony_ci	inc_rfc1001_len(smb, 3);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	iov[0].iov_len = 4;
7858c2ecf20Sopenharmony_ci	iov[0].iov_base = smb;
7868c2ecf20Sopenharmony_ci	iov[1].iov_len = get_rfc1002_length(smb);
7878c2ecf20Sopenharmony_ci	iov[1].iov_base = (char *)smb + 4;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
7908c2ecf20Sopenharmony_ci			     server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
7918c2ecf20Sopenharmony_ci	if (rc)
7928c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	cifs_small_buf_release(smb);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	return rc;
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ciint
8008c2ecf20Sopenharmony_ciCIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	LOGOFF_ANDX_REQ *pSMB;
8038c2ecf20Sopenharmony_ci	int rc = 0;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/*
8088c2ecf20Sopenharmony_ci	 * BB: do we need to check validity of ses and server? They should
8098c2ecf20Sopenharmony_ci	 * always be valid since we have an active reference. If not, that
8108c2ecf20Sopenharmony_ci	 * should probably be a BUG()
8118c2ecf20Sopenharmony_ci	 */
8128c2ecf20Sopenharmony_ci	if (!ses || !ses->server)
8138c2ecf20Sopenharmony_ci		return -EIO;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	mutex_lock(&ses->session_mutex);
8168c2ecf20Sopenharmony_ci	if (ses->need_reconnect)
8178c2ecf20Sopenharmony_ci		goto session_already_dead; /* no need to send SMBlogoff if uid
8188c2ecf20Sopenharmony_ci					      already closed due to reconnect */
8198c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
8208c2ecf20Sopenharmony_ci	if (rc) {
8218c2ecf20Sopenharmony_ci		mutex_unlock(&ses->session_mutex);
8228c2ecf20Sopenharmony_ci		return rc;
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	pSMB->hdr.Mid = get_next_mid(ses->server);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	if (ses->server->sign)
8288c2ecf20Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	pSMB->hdr.Uid = ses->Suid;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	pSMB->AndXCommand = 0xFF;
8338c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
8348c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
8358c2ecf20Sopenharmony_cisession_already_dead:
8368c2ecf20Sopenharmony_ci	mutex_unlock(&ses->session_mutex);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	/* if session dead then we do not need to do ulogoff,
8398c2ecf20Sopenharmony_ci		since server closed smb session, no sense reporting
8408c2ecf20Sopenharmony_ci		error */
8418c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
8428c2ecf20Sopenharmony_ci		rc = 0;
8438c2ecf20Sopenharmony_ci	return rc;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ciint
8478c2ecf20Sopenharmony_ciCIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
8488c2ecf20Sopenharmony_ci		 const char *fileName, __u16 type,
8498c2ecf20Sopenharmony_ci		 const struct nls_table *nls_codepage, int remap)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
8528c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
8538c2ecf20Sopenharmony_ci	struct unlink_psx_rq *pRqD;
8548c2ecf20Sopenharmony_ci	int name_len;
8558c2ecf20Sopenharmony_ci	int rc = 0;
8568c2ecf20Sopenharmony_ci	int bytes_returned = 0;
8578c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In POSIX delete\n");
8608c2ecf20Sopenharmony_ciPsxDelete:
8618c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
8628c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
8638c2ecf20Sopenharmony_ci	if (rc)
8648c2ecf20Sopenharmony_ci		return rc;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
8678c2ecf20Sopenharmony_ci		name_len =
8688c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
8698c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
8708c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
8718c2ecf20Sopenharmony_ci		name_len *= 2;
8728c2ecf20Sopenharmony_ci	} else {
8738c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fileName);
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	params = 6 + name_len;
8778c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
8788c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = 0; /* BB double check this with jra */
8798c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
8808c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
8818c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
8828c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
8838c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
8848c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
8858c2ecf20Sopenharmony_ci				InformationLevel) - 4;
8868c2ecf20Sopenharmony_ci	offset = param_offset + params;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	/* Setup pointer to Request Data (inode type) */
8898c2ecf20Sopenharmony_ci	pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
8908c2ecf20Sopenharmony_ci	pRqD->type = cpu_to_le16(type);
8918c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
8928c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
8938c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
8948c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
8958c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
8968c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + sizeof(struct unlink_psx_rq);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
8998c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
9008c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
9018c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
9028c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
9038c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
9048c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
9058c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
9068c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
9078c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
9088c2ecf20Sopenharmony_ci	if (rc)
9098c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Posix delete returned %d\n", rc);
9108c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
9158c2ecf20Sopenharmony_ci		goto PsxDelete;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	return rc;
9188c2ecf20Sopenharmony_ci}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ciint
9218c2ecf20Sopenharmony_ciCIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
9228c2ecf20Sopenharmony_ci	       struct cifs_sb_info *cifs_sb)
9238c2ecf20Sopenharmony_ci{
9248c2ecf20Sopenharmony_ci	DELETE_FILE_REQ *pSMB = NULL;
9258c2ecf20Sopenharmony_ci	DELETE_FILE_RSP *pSMBr = NULL;
9268c2ecf20Sopenharmony_ci	int rc = 0;
9278c2ecf20Sopenharmony_ci	int bytes_returned;
9288c2ecf20Sopenharmony_ci	int name_len;
9298c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ciDelFileRetry:
9328c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
9338c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
9348c2ecf20Sopenharmony_ci	if (rc)
9358c2ecf20Sopenharmony_ci		return rc;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
9388c2ecf20Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
9398c2ecf20Sopenharmony_ci					      PATH_MAX, cifs_sb->local_nls,
9408c2ecf20Sopenharmony_ci					      remap);
9418c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
9428c2ecf20Sopenharmony_ci		name_len *= 2;
9438c2ecf20Sopenharmony_ci	} else {
9448c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->fileName, name);
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci	pSMB->SearchAttributes =
9478c2ecf20Sopenharmony_ci	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
9488c2ecf20Sopenharmony_ci	pSMB->BufferFormat = 0x04;
9498c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, name_len + 1);
9508c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len + 1);
9518c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
9528c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
9538c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
9548c2ecf20Sopenharmony_ci	if (rc)
9558c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
9588c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
9598c2ecf20Sopenharmony_ci		goto DelFileRetry;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	return rc;
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ciint
9658c2ecf20Sopenharmony_ciCIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
9668c2ecf20Sopenharmony_ci	     struct cifs_sb_info *cifs_sb)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	DELETE_DIRECTORY_REQ *pSMB = NULL;
9698c2ecf20Sopenharmony_ci	DELETE_DIRECTORY_RSP *pSMBr = NULL;
9708c2ecf20Sopenharmony_ci	int rc = 0;
9718c2ecf20Sopenharmony_ci	int bytes_returned;
9728c2ecf20Sopenharmony_ci	int name_len;
9738c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBRmDir\n");
9768c2ecf20Sopenharmony_ciRmDirRetry:
9778c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
9788c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
9798c2ecf20Sopenharmony_ci	if (rc)
9808c2ecf20Sopenharmony_ci		return rc;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
9838c2ecf20Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
9848c2ecf20Sopenharmony_ci					      PATH_MAX, cifs_sb->local_nls,
9858c2ecf20Sopenharmony_ci					      remap);
9868c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
9878c2ecf20Sopenharmony_ci		name_len *= 2;
9888c2ecf20Sopenharmony_ci	} else {
9898c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->DirName, name);
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	pSMB->BufferFormat = 0x04;
9938c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, name_len + 1);
9948c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len + 1);
9958c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
9968c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
9978c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
9988c2ecf20Sopenharmony_ci	if (rc)
9998c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
10028c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
10038c2ecf20Sopenharmony_ci		goto RmDirRetry;
10048c2ecf20Sopenharmony_ci	return rc;
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ciint
10088c2ecf20Sopenharmony_ciCIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
10098c2ecf20Sopenharmony_ci	     struct cifs_tcon *tcon, const char *name,
10108c2ecf20Sopenharmony_ci	     struct cifs_sb_info *cifs_sb)
10118c2ecf20Sopenharmony_ci{
10128c2ecf20Sopenharmony_ci	int rc = 0;
10138c2ecf20Sopenharmony_ci	CREATE_DIRECTORY_REQ *pSMB = NULL;
10148c2ecf20Sopenharmony_ci	CREATE_DIRECTORY_RSP *pSMBr = NULL;
10158c2ecf20Sopenharmony_ci	int bytes_returned;
10168c2ecf20Sopenharmony_ci	int name_len;
10178c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBMkDir\n");
10208c2ecf20Sopenharmony_ciMkDirRetry:
10218c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
10228c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
10238c2ecf20Sopenharmony_ci	if (rc)
10248c2ecf20Sopenharmony_ci		return rc;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
10278c2ecf20Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
10288c2ecf20Sopenharmony_ci					      PATH_MAX, cifs_sb->local_nls,
10298c2ecf20Sopenharmony_ci					      remap);
10308c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
10318c2ecf20Sopenharmony_ci		name_len *= 2;
10328c2ecf20Sopenharmony_ci	} else {
10338c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->DirName, name);
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	pSMB->BufferFormat = 0x04;
10378c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, name_len + 1);
10388c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len + 1);
10398c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
10408c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
10418c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
10428c2ecf20Sopenharmony_ci	if (rc)
10438c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
10468c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
10478c2ecf20Sopenharmony_ci		goto MkDirRetry;
10488c2ecf20Sopenharmony_ci	return rc;
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ciint
10528c2ecf20Sopenharmony_ciCIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
10538c2ecf20Sopenharmony_ci		__u32 posix_flags, __u64 mode, __u16 *netfid,
10548c2ecf20Sopenharmony_ci		FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
10558c2ecf20Sopenharmony_ci		const char *name, const struct nls_table *nls_codepage,
10568c2ecf20Sopenharmony_ci		int remap)
10578c2ecf20Sopenharmony_ci{
10588c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
10598c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
10608c2ecf20Sopenharmony_ci	int name_len;
10618c2ecf20Sopenharmony_ci	int rc = 0;
10628c2ecf20Sopenharmony_ci	int bytes_returned = 0;
10638c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
10648c2ecf20Sopenharmony_ci	OPEN_PSX_REQ *pdata;
10658c2ecf20Sopenharmony_ci	OPEN_PSX_RSP *psx_rsp;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In POSIX Create\n");
10688c2ecf20Sopenharmony_ciPsxCreat:
10698c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
10708c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
10718c2ecf20Sopenharmony_ci	if (rc)
10728c2ecf20Sopenharmony_ci		return rc;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
10758c2ecf20Sopenharmony_ci		name_len =
10768c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
10778c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
10788c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
10798c2ecf20Sopenharmony_ci		name_len *= 2;
10808c2ecf20Sopenharmony_ci	} else {
10818c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, name);
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	params = 6 + name_len;
10858c2ecf20Sopenharmony_ci	count = sizeof(OPEN_PSX_REQ);
10868c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
10878c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);	/* large enough */
10888c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
10898c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
10908c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
10918c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
10928c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
10938c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
10948c2ecf20Sopenharmony_ci				InformationLevel) - 4;
10958c2ecf20Sopenharmony_ci	offset = param_offset + params;
10968c2ecf20Sopenharmony_ci	pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
10978c2ecf20Sopenharmony_ci	pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
10988c2ecf20Sopenharmony_ci	pdata->Permissions = cpu_to_le64(mode);
10998c2ecf20Sopenharmony_ci	pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
11008c2ecf20Sopenharmony_ci	pdata->OpenFlags =  cpu_to_le32(*pOplock);
11018c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
11028c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
11038c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
11048c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
11058c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
11068c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
11098c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
11108c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
11118c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
11128c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
11138c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
11148c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
11158c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
11168c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
11178c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
11188c2ecf20Sopenharmony_ci	if (rc) {
11198c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Posix create returned %d\n", rc);
11208c2ecf20Sopenharmony_ci		goto psx_create_err;
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "copying inode info\n");
11248c2ecf20Sopenharmony_ci	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
11278c2ecf20Sopenharmony_ci		rc = -EIO;	/* bad smb */
11288c2ecf20Sopenharmony_ci		goto psx_create_err;
11298c2ecf20Sopenharmony_ci	}
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	/* copy return information to pRetData */
11328c2ecf20Sopenharmony_ci	psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
11338c2ecf20Sopenharmony_ci			+ le16_to_cpu(pSMBr->t2.DataOffset));
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
11368c2ecf20Sopenharmony_ci	if (netfid)
11378c2ecf20Sopenharmony_ci		*netfid = psx_rsp->Fid;   /* cifs fid stays in le */
11388c2ecf20Sopenharmony_ci	/* Let caller know file was created so we can set the mode. */
11398c2ecf20Sopenharmony_ci	/* Do we care about the CreateAction in any other cases? */
11408c2ecf20Sopenharmony_ci	if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
11418c2ecf20Sopenharmony_ci		*pOplock |= CIFS_CREATE_ACTION;
11428c2ecf20Sopenharmony_ci	/* check to make sure response data is there */
11438c2ecf20Sopenharmony_ci	if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
11448c2ecf20Sopenharmony_ci		pRetData->Type = cpu_to_le32(-1); /* unknown */
11458c2ecf20Sopenharmony_ci		cifs_dbg(NOISY, "unknown type\n");
11468c2ecf20Sopenharmony_ci	} else {
11478c2ecf20Sopenharmony_ci		if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
11488c2ecf20Sopenharmony_ci					+ sizeof(FILE_UNIX_BASIC_INFO)) {
11498c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "Open response data too small\n");
11508c2ecf20Sopenharmony_ci			pRetData->Type = cpu_to_le32(-1);
11518c2ecf20Sopenharmony_ci			goto psx_create_err;
11528c2ecf20Sopenharmony_ci		}
11538c2ecf20Sopenharmony_ci		memcpy((char *) pRetData,
11548c2ecf20Sopenharmony_ci			(char *)psx_rsp + sizeof(OPEN_PSX_RSP),
11558c2ecf20Sopenharmony_ci			sizeof(FILE_UNIX_BASIC_INFO));
11568c2ecf20Sopenharmony_ci	}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_cipsx_create_err:
11598c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	if (posix_flags & SMB_O_DIRECTORY)
11628c2ecf20Sopenharmony_ci		cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
11638c2ecf20Sopenharmony_ci	else
11648c2ecf20Sopenharmony_ci		cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
11678c2ecf20Sopenharmony_ci		goto PsxCreat;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	return rc;
11708c2ecf20Sopenharmony_ci}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_cistatic __u16 convert_disposition(int disposition)
11738c2ecf20Sopenharmony_ci{
11748c2ecf20Sopenharmony_ci	__u16 ofun = 0;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	switch (disposition) {
11778c2ecf20Sopenharmony_ci		case FILE_SUPERSEDE:
11788c2ecf20Sopenharmony_ci			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
11798c2ecf20Sopenharmony_ci			break;
11808c2ecf20Sopenharmony_ci		case FILE_OPEN:
11818c2ecf20Sopenharmony_ci			ofun = SMBOPEN_OAPPEND;
11828c2ecf20Sopenharmony_ci			break;
11838c2ecf20Sopenharmony_ci		case FILE_CREATE:
11848c2ecf20Sopenharmony_ci			ofun = SMBOPEN_OCREATE;
11858c2ecf20Sopenharmony_ci			break;
11868c2ecf20Sopenharmony_ci		case FILE_OPEN_IF:
11878c2ecf20Sopenharmony_ci			ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
11888c2ecf20Sopenharmony_ci			break;
11898c2ecf20Sopenharmony_ci		case FILE_OVERWRITE:
11908c2ecf20Sopenharmony_ci			ofun = SMBOPEN_OTRUNC;
11918c2ecf20Sopenharmony_ci			break;
11928c2ecf20Sopenharmony_ci		case FILE_OVERWRITE_IF:
11938c2ecf20Sopenharmony_ci			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
11948c2ecf20Sopenharmony_ci			break;
11958c2ecf20Sopenharmony_ci		default:
11968c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "unknown disposition %d\n", disposition);
11978c2ecf20Sopenharmony_ci			ofun =  SMBOPEN_OAPPEND; /* regular open */
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci	return ofun;
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cistatic int
12038c2ecf20Sopenharmony_ciaccess_flags_to_smbopen_mode(const int access_flags)
12048c2ecf20Sopenharmony_ci{
12058c2ecf20Sopenharmony_ci	int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	if (masked_flags == GENERIC_READ)
12088c2ecf20Sopenharmony_ci		return SMBOPEN_READ;
12098c2ecf20Sopenharmony_ci	else if (masked_flags == GENERIC_WRITE)
12108c2ecf20Sopenharmony_ci		return SMBOPEN_WRITE;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	/* just go for read/write */
12138c2ecf20Sopenharmony_ci	return SMBOPEN_READWRITE;
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ciint
12178c2ecf20Sopenharmony_ciSMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
12188c2ecf20Sopenharmony_ci	    const char *fileName, const int openDisposition,
12198c2ecf20Sopenharmony_ci	    const int access_flags, const int create_options, __u16 *netfid,
12208c2ecf20Sopenharmony_ci	    int *pOplock, FILE_ALL_INFO *pfile_info,
12218c2ecf20Sopenharmony_ci	    const struct nls_table *nls_codepage, int remap)
12228c2ecf20Sopenharmony_ci{
12238c2ecf20Sopenharmony_ci	int rc = -EACCES;
12248c2ecf20Sopenharmony_ci	OPENX_REQ *pSMB = NULL;
12258c2ecf20Sopenharmony_ci	OPENX_RSP *pSMBr = NULL;
12268c2ecf20Sopenharmony_ci	int bytes_returned;
12278c2ecf20Sopenharmony_ci	int name_len;
12288c2ecf20Sopenharmony_ci	__u16 count;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ciOldOpenRetry:
12318c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
12328c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
12338c2ecf20Sopenharmony_ci	if (rc)
12348c2ecf20Sopenharmony_ci		return rc;
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	pSMB->AndXCommand = 0xFF;       /* none */
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
12398c2ecf20Sopenharmony_ci		count = 1;      /* account for one byte pad to word boundary */
12408c2ecf20Sopenharmony_ci		name_len =
12418c2ecf20Sopenharmony_ci		   cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
12428c2ecf20Sopenharmony_ci				      fileName, PATH_MAX, nls_codepage, remap);
12438c2ecf20Sopenharmony_ci		name_len++;     /* trailing null */
12448c2ecf20Sopenharmony_ci		name_len *= 2;
12458c2ecf20Sopenharmony_ci	} else {
12468c2ecf20Sopenharmony_ci		count = 0;      /* no pad */
12478c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->fileName, fileName);
12488c2ecf20Sopenharmony_ci	}
12498c2ecf20Sopenharmony_ci	if (*pOplock & REQ_OPLOCK)
12508c2ecf20Sopenharmony_ci		pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
12518c2ecf20Sopenharmony_ci	else if (*pOplock & REQ_BATCHOPLOCK)
12528c2ecf20Sopenharmony_ci		pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
12558c2ecf20Sopenharmony_ci	pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
12568c2ecf20Sopenharmony_ci	pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
12578c2ecf20Sopenharmony_ci	/* set file as system file if special file such
12588c2ecf20Sopenharmony_ci	   as fifo and server expecting SFU style and
12598c2ecf20Sopenharmony_ci	   no Unix extensions */
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	if (create_options & CREATE_OPTION_SPECIAL)
12628c2ecf20Sopenharmony_ci		pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
12638c2ecf20Sopenharmony_ci	else /* BB FIXME BB */
12648c2ecf20Sopenharmony_ci		pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	if (create_options & CREATE_OPTION_READONLY)
12678c2ecf20Sopenharmony_ci		pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	/* BB FIXME BB */
12708c2ecf20Sopenharmony_ci/*	pSMB->CreateOptions = cpu_to_le32(create_options &
12718c2ecf20Sopenharmony_ci						 CREATE_OPTIONS_MASK); */
12728c2ecf20Sopenharmony_ci	/* BB FIXME END BB */
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
12758c2ecf20Sopenharmony_ci	pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
12768c2ecf20Sopenharmony_ci	count += name_len;
12778c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
12808c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
12818c2ecf20Sopenharmony_ci			(struct smb_hdr *)pSMBr, &bytes_returned, 0);
12828c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
12838c2ecf20Sopenharmony_ci	if (rc) {
12848c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Error in Open = %d\n", rc);
12858c2ecf20Sopenharmony_ci	} else {
12868c2ecf20Sopenharmony_ci	/* BB verify if wct == 15 */
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci/*		*pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		*netfid = pSMBr->Fid;   /* cifs fid stays in le */
12918c2ecf20Sopenharmony_ci		/* Let caller know file was created so we can set the mode. */
12928c2ecf20Sopenharmony_ci		/* Do we care about the CreateAction in any other cases? */
12938c2ecf20Sopenharmony_ci	/* BB FIXME BB */
12948c2ecf20Sopenharmony_ci/*		if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
12958c2ecf20Sopenharmony_ci			*pOplock |= CIFS_CREATE_ACTION; */
12968c2ecf20Sopenharmony_ci	/* BB FIXME END */
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci		if (pfile_info) {
12998c2ecf20Sopenharmony_ci			pfile_info->CreationTime = 0; /* BB convert CreateTime*/
13008c2ecf20Sopenharmony_ci			pfile_info->LastAccessTime = 0; /* BB fixme */
13018c2ecf20Sopenharmony_ci			pfile_info->LastWriteTime = 0; /* BB fixme */
13028c2ecf20Sopenharmony_ci			pfile_info->ChangeTime = 0;  /* BB fixme */
13038c2ecf20Sopenharmony_ci			pfile_info->Attributes =
13048c2ecf20Sopenharmony_ci				cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
13058c2ecf20Sopenharmony_ci			/* the file_info buf is endian converted by caller */
13068c2ecf20Sopenharmony_ci			pfile_info->AllocationSize =
13078c2ecf20Sopenharmony_ci				cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
13088c2ecf20Sopenharmony_ci			pfile_info->EndOfFile = pfile_info->AllocationSize;
13098c2ecf20Sopenharmony_ci			pfile_info->NumberOfLinks = cpu_to_le32(1);
13108c2ecf20Sopenharmony_ci			pfile_info->DeletePending = 0;
13118c2ecf20Sopenharmony_ci		}
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
13158c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
13168c2ecf20Sopenharmony_ci		goto OldOpenRetry;
13178c2ecf20Sopenharmony_ci	return rc;
13188c2ecf20Sopenharmony_ci}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ciint
13218c2ecf20Sopenharmony_ciCIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
13228c2ecf20Sopenharmony_ci	  FILE_ALL_INFO *buf)
13238c2ecf20Sopenharmony_ci{
13248c2ecf20Sopenharmony_ci	int rc;
13258c2ecf20Sopenharmony_ci	OPEN_REQ *req = NULL;
13268c2ecf20Sopenharmony_ci	OPEN_RSP *rsp = NULL;
13278c2ecf20Sopenharmony_ci	int bytes_returned;
13288c2ecf20Sopenharmony_ci	int name_len;
13298c2ecf20Sopenharmony_ci	__u16 count;
13308c2ecf20Sopenharmony_ci	struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
13318c2ecf20Sopenharmony_ci	struct cifs_tcon *tcon = oparms->tcon;
13328c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
13338c2ecf20Sopenharmony_ci	const struct nls_table *nls = cifs_sb->local_nls;
13348c2ecf20Sopenharmony_ci	int create_options = oparms->create_options;
13358c2ecf20Sopenharmony_ci	int desired_access = oparms->desired_access;
13368c2ecf20Sopenharmony_ci	int disposition = oparms->disposition;
13378c2ecf20Sopenharmony_ci	const char *path = oparms->path;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ciopenRetry:
13408c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
13418c2ecf20Sopenharmony_ci		      (void **)&rsp);
13428c2ecf20Sopenharmony_ci	if (rc)
13438c2ecf20Sopenharmony_ci		return rc;
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	/* no commands go after this */
13468c2ecf20Sopenharmony_ci	req->AndXCommand = 0xFF;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
13498c2ecf20Sopenharmony_ci		/* account for one byte pad to word boundary */
13508c2ecf20Sopenharmony_ci		count = 1;
13518c2ecf20Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
13528c2ecf20Sopenharmony_ci					      path, PATH_MAX, nls, remap);
13538c2ecf20Sopenharmony_ci		/* trailing null */
13548c2ecf20Sopenharmony_ci		name_len++;
13558c2ecf20Sopenharmony_ci		name_len *= 2;
13568c2ecf20Sopenharmony_ci		req->NameLength = cpu_to_le16(name_len);
13578c2ecf20Sopenharmony_ci	} else {
13588c2ecf20Sopenharmony_ci		/* BB improve check for buffer overruns BB */
13598c2ecf20Sopenharmony_ci		/* no pad */
13608c2ecf20Sopenharmony_ci		count = 0;
13618c2ecf20Sopenharmony_ci		name_len = copy_path_name(req->fileName, path);
13628c2ecf20Sopenharmony_ci		req->NameLength = cpu_to_le16(name_len);
13638c2ecf20Sopenharmony_ci	}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	if (*oplock & REQ_OPLOCK)
13668c2ecf20Sopenharmony_ci		req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
13678c2ecf20Sopenharmony_ci	else if (*oplock & REQ_BATCHOPLOCK)
13688c2ecf20Sopenharmony_ci		req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	req->DesiredAccess = cpu_to_le32(desired_access);
13718c2ecf20Sopenharmony_ci	req->AllocationSize = 0;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	/*
13748c2ecf20Sopenharmony_ci	 * Set file as system file if special file such as fifo and server
13758c2ecf20Sopenharmony_ci	 * expecting SFU style and no Unix extensions.
13768c2ecf20Sopenharmony_ci	 */
13778c2ecf20Sopenharmony_ci	if (create_options & CREATE_OPTION_SPECIAL)
13788c2ecf20Sopenharmony_ci		req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
13798c2ecf20Sopenharmony_ci	else
13808c2ecf20Sopenharmony_ci		req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	/*
13838c2ecf20Sopenharmony_ci	 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
13848c2ecf20Sopenharmony_ci	 * sensitive checks for other servers such as Samba.
13858c2ecf20Sopenharmony_ci	 */
13868c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_UNIX)
13878c2ecf20Sopenharmony_ci		req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	if (create_options & CREATE_OPTION_READONLY)
13908c2ecf20Sopenharmony_ci		req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
13938c2ecf20Sopenharmony_ci	req->CreateDisposition = cpu_to_le32(disposition);
13948c2ecf20Sopenharmony_ci	req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	/* BB Expirement with various impersonation levels and verify */
13978c2ecf20Sopenharmony_ci	req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
13988c2ecf20Sopenharmony_ci	req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	count += name_len;
14018c2ecf20Sopenharmony_ci	inc_rfc1001_len(req, count);
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	req->ByteCount = cpu_to_le16(count);
14048c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
14058c2ecf20Sopenharmony_ci			 (struct smb_hdr *)rsp, &bytes_returned, 0);
14068c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
14078c2ecf20Sopenharmony_ci	if (rc) {
14088c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Error in Open = %d\n", rc);
14098c2ecf20Sopenharmony_ci		cifs_buf_release(req);
14108c2ecf20Sopenharmony_ci		if (rc == -EAGAIN)
14118c2ecf20Sopenharmony_ci			goto openRetry;
14128c2ecf20Sopenharmony_ci		return rc;
14138c2ecf20Sopenharmony_ci	}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	/* 1 byte no need to le_to_cpu */
14168c2ecf20Sopenharmony_ci	*oplock = rsp->OplockLevel;
14178c2ecf20Sopenharmony_ci	/* cifs fid stays in le */
14188c2ecf20Sopenharmony_ci	oparms->fid->netfid = rsp->Fid;
14198c2ecf20Sopenharmony_ci	oparms->fid->access = desired_access;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	/* Let caller know file was created so we can set the mode. */
14228c2ecf20Sopenharmony_ci	/* Do we care about the CreateAction in any other cases? */
14238c2ecf20Sopenharmony_ci	if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
14248c2ecf20Sopenharmony_ci		*oplock |= CIFS_CREATE_ACTION;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	if (buf) {
14278c2ecf20Sopenharmony_ci		/* copy from CreationTime to Attributes */
14288c2ecf20Sopenharmony_ci		memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
14298c2ecf20Sopenharmony_ci		/* the file_info buf is endian converted by caller */
14308c2ecf20Sopenharmony_ci		buf->AllocationSize = rsp->AllocationSize;
14318c2ecf20Sopenharmony_ci		buf->EndOfFile = rsp->EndOfFile;
14328c2ecf20Sopenharmony_ci		buf->NumberOfLinks = cpu_to_le32(1);
14338c2ecf20Sopenharmony_ci		buf->DeletePending = 0;
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	cifs_buf_release(req);
14378c2ecf20Sopenharmony_ci	return rc;
14388c2ecf20Sopenharmony_ci}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci/*
14418c2ecf20Sopenharmony_ci * Discard any remaining data in the current SMB. To do this, we borrow the
14428c2ecf20Sopenharmony_ci * current bigbuf.
14438c2ecf20Sopenharmony_ci */
14448c2ecf20Sopenharmony_ciint
14458c2ecf20Sopenharmony_cicifs_discard_remaining_data(struct TCP_Server_Info *server)
14468c2ecf20Sopenharmony_ci{
14478c2ecf20Sopenharmony_ci	unsigned int rfclen = server->pdu_size;
14488c2ecf20Sopenharmony_ci	int remaining = rfclen + server->vals->header_preamble_size -
14498c2ecf20Sopenharmony_ci		server->total_read;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	while (remaining > 0) {
14528c2ecf20Sopenharmony_ci		int length;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci		length = cifs_discard_from_socket(server,
14558c2ecf20Sopenharmony_ci				min_t(size_t, remaining,
14568c2ecf20Sopenharmony_ci				      CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
14578c2ecf20Sopenharmony_ci		if (length < 0)
14588c2ecf20Sopenharmony_ci			return length;
14598c2ecf20Sopenharmony_ci		server->total_read += length;
14608c2ecf20Sopenharmony_ci		remaining -= length;
14618c2ecf20Sopenharmony_ci	}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	return 0;
14648c2ecf20Sopenharmony_ci}
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_cistatic int
14678c2ecf20Sopenharmony_ci__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
14688c2ecf20Sopenharmony_ci		     bool malformed)
14698c2ecf20Sopenharmony_ci{
14708c2ecf20Sopenharmony_ci	int length;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	length = cifs_discard_remaining_data(server);
14738c2ecf20Sopenharmony_ci	dequeue_mid(mid, malformed);
14748c2ecf20Sopenharmony_ci	mid->resp_buf = server->smallbuf;
14758c2ecf20Sopenharmony_ci	server->smallbuf = NULL;
14768c2ecf20Sopenharmony_ci	return length;
14778c2ecf20Sopenharmony_ci}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_cistatic int
14808c2ecf20Sopenharmony_cicifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
14818c2ecf20Sopenharmony_ci{
14828c2ecf20Sopenharmony_ci	struct cifs_readdata *rdata = mid->callback_data;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	return  __cifs_readv_discard(server, mid, rdata->result);
14858c2ecf20Sopenharmony_ci}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ciint
14888c2ecf20Sopenharmony_cicifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
14898c2ecf20Sopenharmony_ci{
14908c2ecf20Sopenharmony_ci	int length, len;
14918c2ecf20Sopenharmony_ci	unsigned int data_offset, data_len;
14928c2ecf20Sopenharmony_ci	struct cifs_readdata *rdata = mid->callback_data;
14938c2ecf20Sopenharmony_ci	char *buf = server->smallbuf;
14948c2ecf20Sopenharmony_ci	unsigned int buflen = server->pdu_size +
14958c2ecf20Sopenharmony_ci		server->vals->header_preamble_size;
14968c2ecf20Sopenharmony_ci	bool use_rdma_mr = false;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
14998c2ecf20Sopenharmony_ci		 __func__, mid->mid, rdata->offset, rdata->bytes);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	/*
15028c2ecf20Sopenharmony_ci	 * read the rest of READ_RSP header (sans Data array), or whatever we
15038c2ecf20Sopenharmony_ci	 * can if there's not enough data. At this point, we've read down to
15048c2ecf20Sopenharmony_ci	 * the Mid.
15058c2ecf20Sopenharmony_ci	 */
15068c2ecf20Sopenharmony_ci	len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
15078c2ecf20Sopenharmony_ci							HEADER_SIZE(server) + 1;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	length = cifs_read_from_socket(server,
15108c2ecf20Sopenharmony_ci				       buf + HEADER_SIZE(server) - 1, len);
15118c2ecf20Sopenharmony_ci	if (length < 0)
15128c2ecf20Sopenharmony_ci		return length;
15138c2ecf20Sopenharmony_ci	server->total_read += length;
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	if (server->ops->is_session_expired &&
15168c2ecf20Sopenharmony_ci	    server->ops->is_session_expired(buf)) {
15178c2ecf20Sopenharmony_ci		cifs_reconnect(server);
15188c2ecf20Sopenharmony_ci		return -1;
15198c2ecf20Sopenharmony_ci	}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	if (server->ops->is_status_pending &&
15228c2ecf20Sopenharmony_ci	    server->ops->is_status_pending(buf, server)) {
15238c2ecf20Sopenharmony_ci		cifs_discard_remaining_data(server);
15248c2ecf20Sopenharmony_ci		return -1;
15258c2ecf20Sopenharmony_ci	}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	/* set up first two iov for signature check and to get credits */
15288c2ecf20Sopenharmony_ci	rdata->iov[0].iov_base = buf;
15298c2ecf20Sopenharmony_ci	rdata->iov[0].iov_len = server->vals->header_preamble_size;
15308c2ecf20Sopenharmony_ci	rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
15318c2ecf20Sopenharmony_ci	rdata->iov[1].iov_len =
15328c2ecf20Sopenharmony_ci		server->total_read - server->vals->header_preamble_size;
15338c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
15348c2ecf20Sopenharmony_ci		 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
15358c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
15368c2ecf20Sopenharmony_ci		 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	/* Was the SMB read successful? */
15398c2ecf20Sopenharmony_ci	rdata->result = server->ops->map_error(buf, false);
15408c2ecf20Sopenharmony_ci	if (rdata->result != 0) {
15418c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s: server returned error %d\n",
15428c2ecf20Sopenharmony_ci			 __func__, rdata->result);
15438c2ecf20Sopenharmony_ci		/* normal error on read response */
15448c2ecf20Sopenharmony_ci		return __cifs_readv_discard(server, mid, false);
15458c2ecf20Sopenharmony_ci	}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	/* Is there enough to get to the rest of the READ_RSP header? */
15488c2ecf20Sopenharmony_ci	if (server->total_read < server->vals->read_rsp_size) {
15498c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
15508c2ecf20Sopenharmony_ci			 __func__, server->total_read,
15518c2ecf20Sopenharmony_ci			 server->vals->read_rsp_size);
15528c2ecf20Sopenharmony_ci		rdata->result = -EIO;
15538c2ecf20Sopenharmony_ci		return cifs_readv_discard(server, mid);
15548c2ecf20Sopenharmony_ci	}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	data_offset = server->ops->read_data_offset(buf) +
15578c2ecf20Sopenharmony_ci		server->vals->header_preamble_size;
15588c2ecf20Sopenharmony_ci	if (data_offset < server->total_read) {
15598c2ecf20Sopenharmony_ci		/*
15608c2ecf20Sopenharmony_ci		 * win2k8 sometimes sends an offset of 0 when the read
15618c2ecf20Sopenharmony_ci		 * is beyond the EOF. Treat it as if the data starts just after
15628c2ecf20Sopenharmony_ci		 * the header.
15638c2ecf20Sopenharmony_ci		 */
15648c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
15658c2ecf20Sopenharmony_ci			 __func__, data_offset);
15668c2ecf20Sopenharmony_ci		data_offset = server->total_read;
15678c2ecf20Sopenharmony_ci	} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
15688c2ecf20Sopenharmony_ci		/* data_offset is beyond the end of smallbuf */
15698c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
15708c2ecf20Sopenharmony_ci			 __func__, data_offset);
15718c2ecf20Sopenharmony_ci		rdata->result = -EIO;
15728c2ecf20Sopenharmony_ci		return cifs_readv_discard(server, mid);
15738c2ecf20Sopenharmony_ci	}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
15768c2ecf20Sopenharmony_ci		 __func__, server->total_read, data_offset);
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	len = data_offset - server->total_read;
15798c2ecf20Sopenharmony_ci	if (len > 0) {
15808c2ecf20Sopenharmony_ci		/* read any junk before data into the rest of smallbuf */
15818c2ecf20Sopenharmony_ci		length = cifs_read_from_socket(server,
15828c2ecf20Sopenharmony_ci					       buf + server->total_read, len);
15838c2ecf20Sopenharmony_ci		if (length < 0)
15848c2ecf20Sopenharmony_ci			return length;
15858c2ecf20Sopenharmony_ci		server->total_read += length;
15868c2ecf20Sopenharmony_ci	}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	/* how much data is in the response? */
15898c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_SMB_DIRECT
15908c2ecf20Sopenharmony_ci	use_rdma_mr = rdata->mr;
15918c2ecf20Sopenharmony_ci#endif
15928c2ecf20Sopenharmony_ci	data_len = server->ops->read_data_length(buf, use_rdma_mr);
15938c2ecf20Sopenharmony_ci	if (!use_rdma_mr && (data_offset + data_len > buflen)) {
15948c2ecf20Sopenharmony_ci		/* data_len is corrupt -- discard frame */
15958c2ecf20Sopenharmony_ci		rdata->result = -EIO;
15968c2ecf20Sopenharmony_ci		return cifs_readv_discard(server, mid);
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	length = rdata->read_into_pages(server, rdata, data_len);
16008c2ecf20Sopenharmony_ci	if (length < 0)
16018c2ecf20Sopenharmony_ci		return length;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	server->total_read += length;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
16068c2ecf20Sopenharmony_ci		 server->total_read, buflen, data_len);
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	/* discard anything left over */
16098c2ecf20Sopenharmony_ci	if (server->total_read < buflen)
16108c2ecf20Sopenharmony_ci		return cifs_readv_discard(server, mid);
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	dequeue_mid(mid, false);
16138c2ecf20Sopenharmony_ci	mid->resp_buf = server->smallbuf;
16148c2ecf20Sopenharmony_ci	server->smallbuf = NULL;
16158c2ecf20Sopenharmony_ci	return length;
16168c2ecf20Sopenharmony_ci}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_cistatic void
16198c2ecf20Sopenharmony_cicifs_readv_callback(struct mid_q_entry *mid)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	struct cifs_readdata *rdata = mid->callback_data;
16228c2ecf20Sopenharmony_ci	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
16238c2ecf20Sopenharmony_ci	struct TCP_Server_Info *server = tcon->ses->server;
16248c2ecf20Sopenharmony_ci	struct smb_rqst rqst = { .rq_iov = rdata->iov,
16258c2ecf20Sopenharmony_ci				 .rq_nvec = 2,
16268c2ecf20Sopenharmony_ci				 .rq_pages = rdata->pages,
16278c2ecf20Sopenharmony_ci				 .rq_offset = rdata->page_offset,
16288c2ecf20Sopenharmony_ci				 .rq_npages = rdata->nr_pages,
16298c2ecf20Sopenharmony_ci				 .rq_pagesz = rdata->pagesz,
16308c2ecf20Sopenharmony_ci				 .rq_tailsz = rdata->tailsz };
16318c2ecf20Sopenharmony_ci	struct cifs_credits credits = { .value = 1, .instance = 0 };
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
16348c2ecf20Sopenharmony_ci		 __func__, mid->mid, mid->mid_state, rdata->result,
16358c2ecf20Sopenharmony_ci		 rdata->bytes);
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	switch (mid->mid_state) {
16388c2ecf20Sopenharmony_ci	case MID_RESPONSE_RECEIVED:
16398c2ecf20Sopenharmony_ci		/* result already set, check signature */
16408c2ecf20Sopenharmony_ci		if (server->sign) {
16418c2ecf20Sopenharmony_ci			int rc = 0;
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci			rc = cifs_verify_signature(&rqst, server,
16448c2ecf20Sopenharmony_ci						  mid->sequence_number);
16458c2ecf20Sopenharmony_ci			if (rc)
16468c2ecf20Sopenharmony_ci				cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
16478c2ecf20Sopenharmony_ci					 rc);
16488c2ecf20Sopenharmony_ci		}
16498c2ecf20Sopenharmony_ci		/* FIXME: should this be counted toward the initiating task? */
16508c2ecf20Sopenharmony_ci		task_io_account_read(rdata->got_bytes);
16518c2ecf20Sopenharmony_ci		cifs_stats_bytes_read(tcon, rdata->got_bytes);
16528c2ecf20Sopenharmony_ci		break;
16538c2ecf20Sopenharmony_ci	case MID_REQUEST_SUBMITTED:
16548c2ecf20Sopenharmony_ci	case MID_RETRY_NEEDED:
16558c2ecf20Sopenharmony_ci		rdata->result = -EAGAIN;
16568c2ecf20Sopenharmony_ci		if (server->sign && rdata->got_bytes)
16578c2ecf20Sopenharmony_ci			/* reset bytes number since we can not check a sign */
16588c2ecf20Sopenharmony_ci			rdata->got_bytes = 0;
16598c2ecf20Sopenharmony_ci		/* FIXME: should this be counted toward the initiating task? */
16608c2ecf20Sopenharmony_ci		task_io_account_read(rdata->got_bytes);
16618c2ecf20Sopenharmony_ci		cifs_stats_bytes_read(tcon, rdata->got_bytes);
16628c2ecf20Sopenharmony_ci		break;
16638c2ecf20Sopenharmony_ci	default:
16648c2ecf20Sopenharmony_ci		rdata->result = -EIO;
16658c2ecf20Sopenharmony_ci	}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	queue_work(cifsiod_wq, &rdata->work);
16688c2ecf20Sopenharmony_ci	DeleteMidQEntry(mid);
16698c2ecf20Sopenharmony_ci	add_credits(server, &credits, 0);
16708c2ecf20Sopenharmony_ci}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci/* cifs_async_readv - send an async write, and set up mid to handle result */
16738c2ecf20Sopenharmony_ciint
16748c2ecf20Sopenharmony_cicifs_async_readv(struct cifs_readdata *rdata)
16758c2ecf20Sopenharmony_ci{
16768c2ecf20Sopenharmony_ci	int rc;
16778c2ecf20Sopenharmony_ci	READ_REQ *smb = NULL;
16788c2ecf20Sopenharmony_ci	int wct;
16798c2ecf20Sopenharmony_ci	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
16808c2ecf20Sopenharmony_ci	struct smb_rqst rqst = { .rq_iov = rdata->iov,
16818c2ecf20Sopenharmony_ci				 .rq_nvec = 2 };
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
16848c2ecf20Sopenharmony_ci		 __func__, rdata->offset, rdata->bytes);
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES)
16878c2ecf20Sopenharmony_ci		wct = 12;
16888c2ecf20Sopenharmony_ci	else {
16898c2ecf20Sopenharmony_ci		wct = 10; /* old style read */
16908c2ecf20Sopenharmony_ci		if ((rdata->offset >> 32) > 0)  {
16918c2ecf20Sopenharmony_ci			/* can not handle this big offset for old */
16928c2ecf20Sopenharmony_ci			return -EIO;
16938c2ecf20Sopenharmony_ci		}
16948c2ecf20Sopenharmony_ci	}
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
16978c2ecf20Sopenharmony_ci	if (rc)
16988c2ecf20Sopenharmony_ci		return rc;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
17018c2ecf20Sopenharmony_ci	smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	smb->AndXCommand = 0xFF;	/* none */
17048c2ecf20Sopenharmony_ci	smb->Fid = rdata->cfile->fid.netfid;
17058c2ecf20Sopenharmony_ci	smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
17068c2ecf20Sopenharmony_ci	if (wct == 12)
17078c2ecf20Sopenharmony_ci		smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
17088c2ecf20Sopenharmony_ci	smb->Remaining = 0;
17098c2ecf20Sopenharmony_ci	smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
17108c2ecf20Sopenharmony_ci	smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
17118c2ecf20Sopenharmony_ci	if (wct == 12)
17128c2ecf20Sopenharmony_ci		smb->ByteCount = 0;
17138c2ecf20Sopenharmony_ci	else {
17148c2ecf20Sopenharmony_ci		/* old style read */
17158c2ecf20Sopenharmony_ci		struct smb_com_readx_req *smbr =
17168c2ecf20Sopenharmony_ci			(struct smb_com_readx_req *)smb;
17178c2ecf20Sopenharmony_ci		smbr->ByteCount = 0;
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	/* 4 for RFC1001 length + 1 for BCC */
17218c2ecf20Sopenharmony_ci	rdata->iov[0].iov_base = smb;
17228c2ecf20Sopenharmony_ci	rdata->iov[0].iov_len = 4;
17238c2ecf20Sopenharmony_ci	rdata->iov[1].iov_base = (char *)smb + 4;
17248c2ecf20Sopenharmony_ci	rdata->iov[1].iov_len = get_rfc1002_length(smb);
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	kref_get(&rdata->refcount);
17278c2ecf20Sopenharmony_ci	rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
17288c2ecf20Sopenharmony_ci			     cifs_readv_callback, NULL, rdata, 0, NULL);
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	if (rc == 0)
17318c2ecf20Sopenharmony_ci		cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
17328c2ecf20Sopenharmony_ci	else
17338c2ecf20Sopenharmony_ci		kref_put(&rdata->refcount, cifs_readdata_release);
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	cifs_small_buf_release(smb);
17368c2ecf20Sopenharmony_ci	return rc;
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ciint
17408c2ecf20Sopenharmony_ciCIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
17418c2ecf20Sopenharmony_ci	    unsigned int *nbytes, char **buf, int *pbuf_type)
17428c2ecf20Sopenharmony_ci{
17438c2ecf20Sopenharmony_ci	int rc = -EACCES;
17448c2ecf20Sopenharmony_ci	READ_REQ *pSMB = NULL;
17458c2ecf20Sopenharmony_ci	READ_RSP *pSMBr = NULL;
17468c2ecf20Sopenharmony_ci	char *pReadData = NULL;
17478c2ecf20Sopenharmony_ci	int wct;
17488c2ecf20Sopenharmony_ci	int resp_buf_type = 0;
17498c2ecf20Sopenharmony_ci	struct kvec iov[1];
17508c2ecf20Sopenharmony_ci	struct kvec rsp_iov;
17518c2ecf20Sopenharmony_ci	__u32 pid = io_parms->pid;
17528c2ecf20Sopenharmony_ci	__u16 netfid = io_parms->netfid;
17538c2ecf20Sopenharmony_ci	__u64 offset = io_parms->offset;
17548c2ecf20Sopenharmony_ci	struct cifs_tcon *tcon = io_parms->tcon;
17558c2ecf20Sopenharmony_ci	unsigned int count = io_parms->length;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
17588c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES)
17598c2ecf20Sopenharmony_ci		wct = 12;
17608c2ecf20Sopenharmony_ci	else {
17618c2ecf20Sopenharmony_ci		wct = 10; /* old style read */
17628c2ecf20Sopenharmony_ci		if ((offset >> 32) > 0)  {
17638c2ecf20Sopenharmony_ci			/* can not handle this big offset for old */
17648c2ecf20Sopenharmony_ci			return -EIO;
17658c2ecf20Sopenharmony_ci		}
17668c2ecf20Sopenharmony_ci	}
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	*nbytes = 0;
17698c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
17708c2ecf20Sopenharmony_ci	if (rc)
17718c2ecf20Sopenharmony_ci		return rc;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
17748c2ecf20Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	/* tcon and ses pointer are checked in smb_init */
17778c2ecf20Sopenharmony_ci	if (tcon->ses->server == NULL)
17788c2ecf20Sopenharmony_ci		return -ECONNABORTED;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	pSMB->AndXCommand = 0xFF;       /* none */
17818c2ecf20Sopenharmony_ci	pSMB->Fid = netfid;
17828c2ecf20Sopenharmony_ci	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
17838c2ecf20Sopenharmony_ci	if (wct == 12)
17848c2ecf20Sopenharmony_ci		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	pSMB->Remaining = 0;
17878c2ecf20Sopenharmony_ci	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
17888c2ecf20Sopenharmony_ci	pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
17898c2ecf20Sopenharmony_ci	if (wct == 12)
17908c2ecf20Sopenharmony_ci		pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
17918c2ecf20Sopenharmony_ci	else {
17928c2ecf20Sopenharmony_ci		/* old style read */
17938c2ecf20Sopenharmony_ci		struct smb_com_readx_req *pSMBW =
17948c2ecf20Sopenharmony_ci			(struct smb_com_readx_req *)pSMB;
17958c2ecf20Sopenharmony_ci		pSMBW->ByteCount = 0;
17968c2ecf20Sopenharmony_ci	}
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	iov[0].iov_base = (char *)pSMB;
17998c2ecf20Sopenharmony_ci	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
18008c2ecf20Sopenharmony_ci	rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
18018c2ecf20Sopenharmony_ci			  CIFS_LOG_ERROR, &rsp_iov);
18028c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
18038c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
18048c2ecf20Sopenharmony_ci	pSMBr = (READ_RSP *)rsp_iov.iov_base;
18058c2ecf20Sopenharmony_ci	if (rc) {
18068c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Send error in read = %d\n", rc);
18078c2ecf20Sopenharmony_ci	} else {
18088c2ecf20Sopenharmony_ci		int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
18098c2ecf20Sopenharmony_ci		data_length = data_length << 16;
18108c2ecf20Sopenharmony_ci		data_length += le16_to_cpu(pSMBr->DataLength);
18118c2ecf20Sopenharmony_ci		*nbytes = data_length;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci		/*check that DataLength would not go beyond end of SMB */
18148c2ecf20Sopenharmony_ci		if ((data_length > CIFSMaxBufSize)
18158c2ecf20Sopenharmony_ci				|| (data_length > count)) {
18168c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "bad length %d for count %d\n",
18178c2ecf20Sopenharmony_ci				 data_length, count);
18188c2ecf20Sopenharmony_ci			rc = -EIO;
18198c2ecf20Sopenharmony_ci			*nbytes = 0;
18208c2ecf20Sopenharmony_ci		} else {
18218c2ecf20Sopenharmony_ci			pReadData = (char *) (&pSMBr->hdr.Protocol) +
18228c2ecf20Sopenharmony_ci					le16_to_cpu(pSMBr->DataOffset);
18238c2ecf20Sopenharmony_ci/*			if (rc = copy_to_user(buf, pReadData, data_length)) {
18248c2ecf20Sopenharmony_ci				cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
18258c2ecf20Sopenharmony_ci				rc = -EFAULT;
18268c2ecf20Sopenharmony_ci			}*/ /* can not use copy_to_user when using page cache*/
18278c2ecf20Sopenharmony_ci			if (*buf)
18288c2ecf20Sopenharmony_ci				memcpy(*buf, pReadData, data_length);
18298c2ecf20Sopenharmony_ci		}
18308c2ecf20Sopenharmony_ci	}
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	if (*buf) {
18338c2ecf20Sopenharmony_ci		free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
18348c2ecf20Sopenharmony_ci	} else if (resp_buf_type != CIFS_NO_BUFFER) {
18358c2ecf20Sopenharmony_ci		/* return buffer to caller to free */
18368c2ecf20Sopenharmony_ci		*buf = rsp_iov.iov_base;
18378c2ecf20Sopenharmony_ci		if (resp_buf_type == CIFS_SMALL_BUFFER)
18388c2ecf20Sopenharmony_ci			*pbuf_type = CIFS_SMALL_BUFFER;
18398c2ecf20Sopenharmony_ci		else if (resp_buf_type == CIFS_LARGE_BUFFER)
18408c2ecf20Sopenharmony_ci			*pbuf_type = CIFS_LARGE_BUFFER;
18418c2ecf20Sopenharmony_ci	} /* else no valid buffer on return - leave as null */
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
18448c2ecf20Sopenharmony_ci		since file handle passed in no longer valid */
18458c2ecf20Sopenharmony_ci	return rc;
18468c2ecf20Sopenharmony_ci}
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ciint
18508c2ecf20Sopenharmony_ciCIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
18518c2ecf20Sopenharmony_ci	     unsigned int *nbytes, const char *buf)
18528c2ecf20Sopenharmony_ci{
18538c2ecf20Sopenharmony_ci	int rc = -EACCES;
18548c2ecf20Sopenharmony_ci	WRITE_REQ *pSMB = NULL;
18558c2ecf20Sopenharmony_ci	WRITE_RSP *pSMBr = NULL;
18568c2ecf20Sopenharmony_ci	int bytes_returned, wct;
18578c2ecf20Sopenharmony_ci	__u32 bytes_sent;
18588c2ecf20Sopenharmony_ci	__u16 byte_count;
18598c2ecf20Sopenharmony_ci	__u32 pid = io_parms->pid;
18608c2ecf20Sopenharmony_ci	__u16 netfid = io_parms->netfid;
18618c2ecf20Sopenharmony_ci	__u64 offset = io_parms->offset;
18628c2ecf20Sopenharmony_ci	struct cifs_tcon *tcon = io_parms->tcon;
18638c2ecf20Sopenharmony_ci	unsigned int count = io_parms->length;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	*nbytes = 0;
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	/* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
18688c2ecf20Sopenharmony_ci	if (tcon->ses == NULL)
18698c2ecf20Sopenharmony_ci		return -ECONNABORTED;
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES)
18728c2ecf20Sopenharmony_ci		wct = 14;
18738c2ecf20Sopenharmony_ci	else {
18748c2ecf20Sopenharmony_ci		wct = 12;
18758c2ecf20Sopenharmony_ci		if ((offset >> 32) > 0) {
18768c2ecf20Sopenharmony_ci			/* can not handle big offset for old srv */
18778c2ecf20Sopenharmony_ci			return -EIO;
18788c2ecf20Sopenharmony_ci		}
18798c2ecf20Sopenharmony_ci	}
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
18828c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
18838c2ecf20Sopenharmony_ci	if (rc)
18848c2ecf20Sopenharmony_ci		return rc;
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
18878c2ecf20Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	/* tcon and ses pointer are checked in smb_init */
18908c2ecf20Sopenharmony_ci	if (tcon->ses->server == NULL)
18918c2ecf20Sopenharmony_ci		return -ECONNABORTED;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	pSMB->AndXCommand = 0xFF;	/* none */
18948c2ecf20Sopenharmony_ci	pSMB->Fid = netfid;
18958c2ecf20Sopenharmony_ci	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
18968c2ecf20Sopenharmony_ci	if (wct == 14)
18978c2ecf20Sopenharmony_ci		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	pSMB->Reserved = 0xFFFFFFFF;
19008c2ecf20Sopenharmony_ci	pSMB->WriteMode = 0;
19018c2ecf20Sopenharmony_ci	pSMB->Remaining = 0;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	/* Can increase buffer size if buffer is big enough in some cases ie we
19048c2ecf20Sopenharmony_ci	can send more if LARGE_WRITE_X capability returned by the server and if
19058c2ecf20Sopenharmony_ci	our buffer is big enough or if we convert to iovecs on socket writes
19068c2ecf20Sopenharmony_ci	and eliminate the copy to the CIFS buffer */
19078c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
19088c2ecf20Sopenharmony_ci		bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
19098c2ecf20Sopenharmony_ci	} else {
19108c2ecf20Sopenharmony_ci		bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
19118c2ecf20Sopenharmony_ci			 & ~0xFF;
19128c2ecf20Sopenharmony_ci	}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	if (bytes_sent > count)
19158c2ecf20Sopenharmony_ci		bytes_sent = count;
19168c2ecf20Sopenharmony_ci	pSMB->DataOffset =
19178c2ecf20Sopenharmony_ci		cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
19188c2ecf20Sopenharmony_ci	if (buf)
19198c2ecf20Sopenharmony_ci		memcpy(pSMB->Data, buf, bytes_sent);
19208c2ecf20Sopenharmony_ci	else if (count != 0) {
19218c2ecf20Sopenharmony_ci		/* No buffer */
19228c2ecf20Sopenharmony_ci		cifs_buf_release(pSMB);
19238c2ecf20Sopenharmony_ci		return -EINVAL;
19248c2ecf20Sopenharmony_ci	} /* else setting file size with write of zero bytes */
19258c2ecf20Sopenharmony_ci	if (wct == 14)
19268c2ecf20Sopenharmony_ci		byte_count = bytes_sent + 1; /* pad */
19278c2ecf20Sopenharmony_ci	else /* wct == 12 */
19288c2ecf20Sopenharmony_ci		byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
19318c2ecf20Sopenharmony_ci	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
19328c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	if (wct == 14)
19358c2ecf20Sopenharmony_ci		pSMB->ByteCount = cpu_to_le16(byte_count);
19368c2ecf20Sopenharmony_ci	else { /* old style write has byte count 4 bytes earlier
19378c2ecf20Sopenharmony_ci		  so 4 bytes pad  */
19388c2ecf20Sopenharmony_ci		struct smb_com_writex_req *pSMBW =
19398c2ecf20Sopenharmony_ci			(struct smb_com_writex_req *)pSMB;
19408c2ecf20Sopenharmony_ci		pSMBW->ByteCount = cpu_to_le16(byte_count);
19418c2ecf20Sopenharmony_ci	}
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
19448c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
19458c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
19468c2ecf20Sopenharmony_ci	if (rc) {
19478c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in write = %d\n", rc);
19488c2ecf20Sopenharmony_ci	} else {
19498c2ecf20Sopenharmony_ci		*nbytes = le16_to_cpu(pSMBr->CountHigh);
19508c2ecf20Sopenharmony_ci		*nbytes = (*nbytes) << 16;
19518c2ecf20Sopenharmony_ci		*nbytes += le16_to_cpu(pSMBr->Count);
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci		/*
19548c2ecf20Sopenharmony_ci		 * Mask off high 16 bits when bytes written as returned by the
19558c2ecf20Sopenharmony_ci		 * server is greater than bytes requested by the client. Some
19568c2ecf20Sopenharmony_ci		 * OS/2 servers are known to set incorrect CountHigh values.
19578c2ecf20Sopenharmony_ci		 */
19588c2ecf20Sopenharmony_ci		if (*nbytes > count)
19598c2ecf20Sopenharmony_ci			*nbytes &= 0xFFFF;
19608c2ecf20Sopenharmony_ci	}
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
19658c2ecf20Sopenharmony_ci		since file handle passed in no longer valid */
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	return rc;
19688c2ecf20Sopenharmony_ci}
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_civoid
19718c2ecf20Sopenharmony_cicifs_writedata_release(struct kref *refcount)
19728c2ecf20Sopenharmony_ci{
19738c2ecf20Sopenharmony_ci	struct cifs_writedata *wdata = container_of(refcount,
19748c2ecf20Sopenharmony_ci					struct cifs_writedata, refcount);
19758c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_SMB_DIRECT
19768c2ecf20Sopenharmony_ci	if (wdata->mr) {
19778c2ecf20Sopenharmony_ci		smbd_deregister_mr(wdata->mr);
19788c2ecf20Sopenharmony_ci		wdata->mr = NULL;
19798c2ecf20Sopenharmony_ci	}
19808c2ecf20Sopenharmony_ci#endif
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	if (wdata->cfile)
19838c2ecf20Sopenharmony_ci		cifsFileInfo_put(wdata->cfile);
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	kvfree(wdata->pages);
19868c2ecf20Sopenharmony_ci	kfree(wdata);
19878c2ecf20Sopenharmony_ci}
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci/*
19908c2ecf20Sopenharmony_ci * Write failed with a retryable error. Resend the write request. It's also
19918c2ecf20Sopenharmony_ci * possible that the page was redirtied so re-clean the page.
19928c2ecf20Sopenharmony_ci */
19938c2ecf20Sopenharmony_cistatic void
19948c2ecf20Sopenharmony_cicifs_writev_requeue(struct cifs_writedata *wdata)
19958c2ecf20Sopenharmony_ci{
19968c2ecf20Sopenharmony_ci	int i, rc = 0;
19978c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(wdata->cfile->dentry);
19988c2ecf20Sopenharmony_ci	struct TCP_Server_Info *server;
19998c2ecf20Sopenharmony_ci	unsigned int rest_len;
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci	server = tlink_tcon(wdata->cfile->tlink)->ses->server;
20028c2ecf20Sopenharmony_ci	i = 0;
20038c2ecf20Sopenharmony_ci	rest_len = wdata->bytes;
20048c2ecf20Sopenharmony_ci	do {
20058c2ecf20Sopenharmony_ci		struct cifs_writedata *wdata2;
20068c2ecf20Sopenharmony_ci		unsigned int j, nr_pages, wsize, tailsz, cur_len;
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci		wsize = server->ops->wp_retry_size(inode);
20098c2ecf20Sopenharmony_ci		if (wsize < rest_len) {
20108c2ecf20Sopenharmony_ci			nr_pages = wsize / PAGE_SIZE;
20118c2ecf20Sopenharmony_ci			if (!nr_pages) {
20128c2ecf20Sopenharmony_ci				rc = -ENOTSUPP;
20138c2ecf20Sopenharmony_ci				break;
20148c2ecf20Sopenharmony_ci			}
20158c2ecf20Sopenharmony_ci			cur_len = nr_pages * PAGE_SIZE;
20168c2ecf20Sopenharmony_ci			tailsz = PAGE_SIZE;
20178c2ecf20Sopenharmony_ci		} else {
20188c2ecf20Sopenharmony_ci			nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
20198c2ecf20Sopenharmony_ci			cur_len = rest_len;
20208c2ecf20Sopenharmony_ci			tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
20218c2ecf20Sopenharmony_ci		}
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci		wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
20248c2ecf20Sopenharmony_ci		if (!wdata2) {
20258c2ecf20Sopenharmony_ci			rc = -ENOMEM;
20268c2ecf20Sopenharmony_ci			break;
20278c2ecf20Sopenharmony_ci		}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci		for (j = 0; j < nr_pages; j++) {
20308c2ecf20Sopenharmony_ci			wdata2->pages[j] = wdata->pages[i + j];
20318c2ecf20Sopenharmony_ci			lock_page(wdata2->pages[j]);
20328c2ecf20Sopenharmony_ci			clear_page_dirty_for_io(wdata2->pages[j]);
20338c2ecf20Sopenharmony_ci		}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci		wdata2->sync_mode = wdata->sync_mode;
20368c2ecf20Sopenharmony_ci		wdata2->nr_pages = nr_pages;
20378c2ecf20Sopenharmony_ci		wdata2->offset = page_offset(wdata2->pages[0]);
20388c2ecf20Sopenharmony_ci		wdata2->pagesz = PAGE_SIZE;
20398c2ecf20Sopenharmony_ci		wdata2->tailsz = tailsz;
20408c2ecf20Sopenharmony_ci		wdata2->bytes = cur_len;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci		rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
20438c2ecf20Sopenharmony_ci					    &wdata2->cfile);
20448c2ecf20Sopenharmony_ci		if (!wdata2->cfile) {
20458c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
20468c2ecf20Sopenharmony_ci				 rc);
20478c2ecf20Sopenharmony_ci			if (!is_retryable_error(rc))
20488c2ecf20Sopenharmony_ci				rc = -EBADF;
20498c2ecf20Sopenharmony_ci		} else {
20508c2ecf20Sopenharmony_ci			wdata2->pid = wdata2->cfile->pid;
20518c2ecf20Sopenharmony_ci			rc = server->ops->async_writev(wdata2,
20528c2ecf20Sopenharmony_ci						       cifs_writedata_release);
20538c2ecf20Sopenharmony_ci		}
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci		for (j = 0; j < nr_pages; j++) {
20568c2ecf20Sopenharmony_ci			unlock_page(wdata2->pages[j]);
20578c2ecf20Sopenharmony_ci			if (rc != 0 && !is_retryable_error(rc)) {
20588c2ecf20Sopenharmony_ci				SetPageError(wdata2->pages[j]);
20598c2ecf20Sopenharmony_ci				end_page_writeback(wdata2->pages[j]);
20608c2ecf20Sopenharmony_ci				put_page(wdata2->pages[j]);
20618c2ecf20Sopenharmony_ci			}
20628c2ecf20Sopenharmony_ci		}
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci		kref_put(&wdata2->refcount, cifs_writedata_release);
20658c2ecf20Sopenharmony_ci		if (rc) {
20668c2ecf20Sopenharmony_ci			if (is_retryable_error(rc))
20678c2ecf20Sopenharmony_ci				continue;
20688c2ecf20Sopenharmony_ci			i += nr_pages;
20698c2ecf20Sopenharmony_ci			break;
20708c2ecf20Sopenharmony_ci		}
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci		rest_len -= cur_len;
20738c2ecf20Sopenharmony_ci		i += nr_pages;
20748c2ecf20Sopenharmony_ci	} while (i < wdata->nr_pages);
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	/* cleanup remaining pages from the original wdata */
20778c2ecf20Sopenharmony_ci	for (; i < wdata->nr_pages; i++) {
20788c2ecf20Sopenharmony_ci		SetPageError(wdata->pages[i]);
20798c2ecf20Sopenharmony_ci		end_page_writeback(wdata->pages[i]);
20808c2ecf20Sopenharmony_ci		put_page(wdata->pages[i]);
20818c2ecf20Sopenharmony_ci	}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	if (rc != 0 && !is_retryable_error(rc))
20848c2ecf20Sopenharmony_ci		mapping_set_error(inode->i_mapping, rc);
20858c2ecf20Sopenharmony_ci	kref_put(&wdata->refcount, cifs_writedata_release);
20868c2ecf20Sopenharmony_ci}
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_civoid
20898c2ecf20Sopenharmony_cicifs_writev_complete(struct work_struct *work)
20908c2ecf20Sopenharmony_ci{
20918c2ecf20Sopenharmony_ci	struct cifs_writedata *wdata = container_of(work,
20928c2ecf20Sopenharmony_ci						struct cifs_writedata, work);
20938c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(wdata->cfile->dentry);
20948c2ecf20Sopenharmony_ci	int i = 0;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	if (wdata->result == 0) {
20978c2ecf20Sopenharmony_ci		spin_lock(&inode->i_lock);
20988c2ecf20Sopenharmony_ci		cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
20998c2ecf20Sopenharmony_ci		spin_unlock(&inode->i_lock);
21008c2ecf20Sopenharmony_ci		cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
21018c2ecf20Sopenharmony_ci					 wdata->bytes);
21028c2ecf20Sopenharmony_ci	} else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
21038c2ecf20Sopenharmony_ci		return cifs_writev_requeue(wdata);
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	for (i = 0; i < wdata->nr_pages; i++) {
21068c2ecf20Sopenharmony_ci		struct page *page = wdata->pages[i];
21078c2ecf20Sopenharmony_ci		if (wdata->result == -EAGAIN)
21088c2ecf20Sopenharmony_ci			__set_page_dirty_nobuffers(page);
21098c2ecf20Sopenharmony_ci		else if (wdata->result < 0)
21108c2ecf20Sopenharmony_ci			SetPageError(page);
21118c2ecf20Sopenharmony_ci		end_page_writeback(page);
21128c2ecf20Sopenharmony_ci		put_page(page);
21138c2ecf20Sopenharmony_ci	}
21148c2ecf20Sopenharmony_ci	if (wdata->result != -EAGAIN)
21158c2ecf20Sopenharmony_ci		mapping_set_error(inode->i_mapping, wdata->result);
21168c2ecf20Sopenharmony_ci	kref_put(&wdata->refcount, cifs_writedata_release);
21178c2ecf20Sopenharmony_ci}
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_cistruct cifs_writedata *
21208c2ecf20Sopenharmony_cicifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
21218c2ecf20Sopenharmony_ci{
21228c2ecf20Sopenharmony_ci	struct page **pages =
21238c2ecf20Sopenharmony_ci		kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
21248c2ecf20Sopenharmony_ci	if (pages)
21258c2ecf20Sopenharmony_ci		return cifs_writedata_direct_alloc(pages, complete);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	return NULL;
21288c2ecf20Sopenharmony_ci}
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_cistruct cifs_writedata *
21318c2ecf20Sopenharmony_cicifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
21328c2ecf20Sopenharmony_ci{
21338c2ecf20Sopenharmony_ci	struct cifs_writedata *wdata;
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
21368c2ecf20Sopenharmony_ci	if (wdata != NULL) {
21378c2ecf20Sopenharmony_ci		wdata->pages = pages;
21388c2ecf20Sopenharmony_ci		kref_init(&wdata->refcount);
21398c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&wdata->list);
21408c2ecf20Sopenharmony_ci		init_completion(&wdata->done);
21418c2ecf20Sopenharmony_ci		INIT_WORK(&wdata->work, complete);
21428c2ecf20Sopenharmony_ci	}
21438c2ecf20Sopenharmony_ci	return wdata;
21448c2ecf20Sopenharmony_ci}
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci/*
21478c2ecf20Sopenharmony_ci * Check the mid_state and signature on received buffer (if any), and queue the
21488c2ecf20Sopenharmony_ci * workqueue completion task.
21498c2ecf20Sopenharmony_ci */
21508c2ecf20Sopenharmony_cistatic void
21518c2ecf20Sopenharmony_cicifs_writev_callback(struct mid_q_entry *mid)
21528c2ecf20Sopenharmony_ci{
21538c2ecf20Sopenharmony_ci	struct cifs_writedata *wdata = mid->callback_data;
21548c2ecf20Sopenharmony_ci	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
21558c2ecf20Sopenharmony_ci	unsigned int written;
21568c2ecf20Sopenharmony_ci	WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
21578c2ecf20Sopenharmony_ci	struct cifs_credits credits = { .value = 1, .instance = 0 };
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	switch (mid->mid_state) {
21608c2ecf20Sopenharmony_ci	case MID_RESPONSE_RECEIVED:
21618c2ecf20Sopenharmony_ci		wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
21628c2ecf20Sopenharmony_ci		if (wdata->result != 0)
21638c2ecf20Sopenharmony_ci			break;
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci		written = le16_to_cpu(smb->CountHigh);
21668c2ecf20Sopenharmony_ci		written <<= 16;
21678c2ecf20Sopenharmony_ci		written += le16_to_cpu(smb->Count);
21688c2ecf20Sopenharmony_ci		/*
21698c2ecf20Sopenharmony_ci		 * Mask off high 16 bits when bytes written as returned
21708c2ecf20Sopenharmony_ci		 * by the server is greater than bytes requested by the
21718c2ecf20Sopenharmony_ci		 * client. OS/2 servers are known to set incorrect
21728c2ecf20Sopenharmony_ci		 * CountHigh values.
21738c2ecf20Sopenharmony_ci		 */
21748c2ecf20Sopenharmony_ci		if (written > wdata->bytes)
21758c2ecf20Sopenharmony_ci			written &= 0xFFFF;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci		if (written < wdata->bytes)
21788c2ecf20Sopenharmony_ci			wdata->result = -ENOSPC;
21798c2ecf20Sopenharmony_ci		else
21808c2ecf20Sopenharmony_ci			wdata->bytes = written;
21818c2ecf20Sopenharmony_ci		break;
21828c2ecf20Sopenharmony_ci	case MID_REQUEST_SUBMITTED:
21838c2ecf20Sopenharmony_ci	case MID_RETRY_NEEDED:
21848c2ecf20Sopenharmony_ci		wdata->result = -EAGAIN;
21858c2ecf20Sopenharmony_ci		break;
21868c2ecf20Sopenharmony_ci	default:
21878c2ecf20Sopenharmony_ci		wdata->result = -EIO;
21888c2ecf20Sopenharmony_ci		break;
21898c2ecf20Sopenharmony_ci	}
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	queue_work(cifsiod_wq, &wdata->work);
21928c2ecf20Sopenharmony_ci	DeleteMidQEntry(mid);
21938c2ecf20Sopenharmony_ci	add_credits(tcon->ses->server, &credits, 0);
21948c2ecf20Sopenharmony_ci}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci/* cifs_async_writev - send an async write, and set up mid to handle result */
21978c2ecf20Sopenharmony_ciint
21988c2ecf20Sopenharmony_cicifs_async_writev(struct cifs_writedata *wdata,
21998c2ecf20Sopenharmony_ci		  void (*release)(struct kref *kref))
22008c2ecf20Sopenharmony_ci{
22018c2ecf20Sopenharmony_ci	int rc = -EACCES;
22028c2ecf20Sopenharmony_ci	WRITE_REQ *smb = NULL;
22038c2ecf20Sopenharmony_ci	int wct;
22048c2ecf20Sopenharmony_ci	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
22058c2ecf20Sopenharmony_ci	struct kvec iov[2];
22068c2ecf20Sopenharmony_ci	struct smb_rqst rqst = { };
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
22098c2ecf20Sopenharmony_ci		wct = 14;
22108c2ecf20Sopenharmony_ci	} else {
22118c2ecf20Sopenharmony_ci		wct = 12;
22128c2ecf20Sopenharmony_ci		if (wdata->offset >> 32 > 0) {
22138c2ecf20Sopenharmony_ci			/* can not handle big offset for old srv */
22148c2ecf20Sopenharmony_ci			return -EIO;
22158c2ecf20Sopenharmony_ci		}
22168c2ecf20Sopenharmony_ci	}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
22198c2ecf20Sopenharmony_ci	if (rc)
22208c2ecf20Sopenharmony_ci		goto async_writev_out;
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
22238c2ecf20Sopenharmony_ci	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	smb->AndXCommand = 0xFF;	/* none */
22268c2ecf20Sopenharmony_ci	smb->Fid = wdata->cfile->fid.netfid;
22278c2ecf20Sopenharmony_ci	smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
22288c2ecf20Sopenharmony_ci	if (wct == 14)
22298c2ecf20Sopenharmony_ci		smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
22308c2ecf20Sopenharmony_ci	smb->Reserved = 0xFFFFFFFF;
22318c2ecf20Sopenharmony_ci	smb->WriteMode = 0;
22328c2ecf20Sopenharmony_ci	smb->Remaining = 0;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	smb->DataOffset =
22358c2ecf20Sopenharmony_ci	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	/* 4 for RFC1001 length + 1 for BCC */
22388c2ecf20Sopenharmony_ci	iov[0].iov_len = 4;
22398c2ecf20Sopenharmony_ci	iov[0].iov_base = smb;
22408c2ecf20Sopenharmony_ci	iov[1].iov_len = get_rfc1002_length(smb) + 1;
22418c2ecf20Sopenharmony_ci	iov[1].iov_base = (char *)smb + 4;
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	rqst.rq_iov = iov;
22448c2ecf20Sopenharmony_ci	rqst.rq_nvec = 2;
22458c2ecf20Sopenharmony_ci	rqst.rq_pages = wdata->pages;
22468c2ecf20Sopenharmony_ci	rqst.rq_offset = wdata->page_offset;
22478c2ecf20Sopenharmony_ci	rqst.rq_npages = wdata->nr_pages;
22488c2ecf20Sopenharmony_ci	rqst.rq_pagesz = wdata->pagesz;
22498c2ecf20Sopenharmony_ci	rqst.rq_tailsz = wdata->tailsz;
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "async write at %llu %u bytes\n",
22528c2ecf20Sopenharmony_ci		 wdata->offset, wdata->bytes);
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
22558c2ecf20Sopenharmony_ci	smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	if (wct == 14) {
22588c2ecf20Sopenharmony_ci		inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
22598c2ecf20Sopenharmony_ci		put_bcc(wdata->bytes + 1, &smb->hdr);
22608c2ecf20Sopenharmony_ci	} else {
22618c2ecf20Sopenharmony_ci		/* wct == 12 */
22628c2ecf20Sopenharmony_ci		struct smb_com_writex_req *smbw =
22638c2ecf20Sopenharmony_ci				(struct smb_com_writex_req *)smb;
22648c2ecf20Sopenharmony_ci		inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
22658c2ecf20Sopenharmony_ci		put_bcc(wdata->bytes + 5, &smbw->hdr);
22668c2ecf20Sopenharmony_ci		iov[1].iov_len += 4; /* pad bigger by four bytes */
22678c2ecf20Sopenharmony_ci	}
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	kref_get(&wdata->refcount);
22708c2ecf20Sopenharmony_ci	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
22718c2ecf20Sopenharmony_ci			     cifs_writev_callback, NULL, wdata, 0, NULL);
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	if (rc == 0)
22748c2ecf20Sopenharmony_ci		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
22758c2ecf20Sopenharmony_ci	else
22768c2ecf20Sopenharmony_ci		kref_put(&wdata->refcount, release);
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ciasync_writev_out:
22798c2ecf20Sopenharmony_ci	cifs_small_buf_release(smb);
22808c2ecf20Sopenharmony_ci	return rc;
22818c2ecf20Sopenharmony_ci}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ciint
22848c2ecf20Sopenharmony_ciCIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
22858c2ecf20Sopenharmony_ci	      unsigned int *nbytes, struct kvec *iov, int n_vec)
22868c2ecf20Sopenharmony_ci{
22878c2ecf20Sopenharmony_ci	int rc;
22888c2ecf20Sopenharmony_ci	WRITE_REQ *pSMB = NULL;
22898c2ecf20Sopenharmony_ci	int wct;
22908c2ecf20Sopenharmony_ci	int smb_hdr_len;
22918c2ecf20Sopenharmony_ci	int resp_buf_type = 0;
22928c2ecf20Sopenharmony_ci	__u32 pid = io_parms->pid;
22938c2ecf20Sopenharmony_ci	__u16 netfid = io_parms->netfid;
22948c2ecf20Sopenharmony_ci	__u64 offset = io_parms->offset;
22958c2ecf20Sopenharmony_ci	struct cifs_tcon *tcon = io_parms->tcon;
22968c2ecf20Sopenharmony_ci	unsigned int count = io_parms->length;
22978c2ecf20Sopenharmony_ci	struct kvec rsp_iov;
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	*nbytes = 0;
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
23048c2ecf20Sopenharmony_ci		wct = 14;
23058c2ecf20Sopenharmony_ci	} else {
23068c2ecf20Sopenharmony_ci		wct = 12;
23078c2ecf20Sopenharmony_ci		if ((offset >> 32) > 0) {
23088c2ecf20Sopenharmony_ci			/* can not handle big offset for old srv */
23098c2ecf20Sopenharmony_ci			return -EIO;
23108c2ecf20Sopenharmony_ci		}
23118c2ecf20Sopenharmony_ci	}
23128c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
23138c2ecf20Sopenharmony_ci	if (rc)
23148c2ecf20Sopenharmony_ci		return rc;
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
23178c2ecf20Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	/* tcon and ses pointer are checked in smb_init */
23208c2ecf20Sopenharmony_ci	if (tcon->ses->server == NULL)
23218c2ecf20Sopenharmony_ci		return -ECONNABORTED;
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	pSMB->AndXCommand = 0xFF;	/* none */
23248c2ecf20Sopenharmony_ci	pSMB->Fid = netfid;
23258c2ecf20Sopenharmony_ci	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
23268c2ecf20Sopenharmony_ci	if (wct == 14)
23278c2ecf20Sopenharmony_ci		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
23288c2ecf20Sopenharmony_ci	pSMB->Reserved = 0xFFFFFFFF;
23298c2ecf20Sopenharmony_ci	pSMB->WriteMode = 0;
23308c2ecf20Sopenharmony_ci	pSMB->Remaining = 0;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	pSMB->DataOffset =
23338c2ecf20Sopenharmony_ci	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
23368c2ecf20Sopenharmony_ci	pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
23378c2ecf20Sopenharmony_ci	/* header + 1 byte pad */
23388c2ecf20Sopenharmony_ci	smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
23398c2ecf20Sopenharmony_ci	if (wct == 14)
23408c2ecf20Sopenharmony_ci		inc_rfc1001_len(pSMB, count + 1);
23418c2ecf20Sopenharmony_ci	else /* wct == 12 */
23428c2ecf20Sopenharmony_ci		inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
23438c2ecf20Sopenharmony_ci	if (wct == 14)
23448c2ecf20Sopenharmony_ci		pSMB->ByteCount = cpu_to_le16(count + 1);
23458c2ecf20Sopenharmony_ci	else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
23468c2ecf20Sopenharmony_ci		struct smb_com_writex_req *pSMBW =
23478c2ecf20Sopenharmony_ci				(struct smb_com_writex_req *)pSMB;
23488c2ecf20Sopenharmony_ci		pSMBW->ByteCount = cpu_to_le16(count + 5);
23498c2ecf20Sopenharmony_ci	}
23508c2ecf20Sopenharmony_ci	iov[0].iov_base = pSMB;
23518c2ecf20Sopenharmony_ci	if (wct == 14)
23528c2ecf20Sopenharmony_ci		iov[0].iov_len = smb_hdr_len + 4;
23538c2ecf20Sopenharmony_ci	else /* wct == 12 pad bigger by four bytes */
23548c2ecf20Sopenharmony_ci		iov[0].iov_len = smb_hdr_len + 8;
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
23578c2ecf20Sopenharmony_ci			  &rsp_iov);
23588c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
23598c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
23608c2ecf20Sopenharmony_ci	if (rc) {
23618c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
23628c2ecf20Sopenharmony_ci	} else if (resp_buf_type == 0) {
23638c2ecf20Sopenharmony_ci		/* presumably this can not happen, but best to be safe */
23648c2ecf20Sopenharmony_ci		rc = -EIO;
23658c2ecf20Sopenharmony_ci	} else {
23668c2ecf20Sopenharmony_ci		WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
23678c2ecf20Sopenharmony_ci		*nbytes = le16_to_cpu(pSMBr->CountHigh);
23688c2ecf20Sopenharmony_ci		*nbytes = (*nbytes) << 16;
23698c2ecf20Sopenharmony_ci		*nbytes += le16_to_cpu(pSMBr->Count);
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci		/*
23728c2ecf20Sopenharmony_ci		 * Mask off high 16 bits when bytes written as returned by the
23738c2ecf20Sopenharmony_ci		 * server is greater than bytes requested by the client. OS/2
23748c2ecf20Sopenharmony_ci		 * servers are known to set incorrect CountHigh values.
23758c2ecf20Sopenharmony_ci		 */
23768c2ecf20Sopenharmony_ci		if (*nbytes > count)
23778c2ecf20Sopenharmony_ci			*nbytes &= 0xFFFF;
23788c2ecf20Sopenharmony_ci	}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
23838c2ecf20Sopenharmony_ci		since file handle passed in no longer valid */
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	return rc;
23868c2ecf20Sopenharmony_ci}
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ciint cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
23898c2ecf20Sopenharmony_ci	       const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
23908c2ecf20Sopenharmony_ci	       const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
23918c2ecf20Sopenharmony_ci{
23928c2ecf20Sopenharmony_ci	int rc = 0;
23938c2ecf20Sopenharmony_ci	LOCK_REQ *pSMB = NULL;
23948c2ecf20Sopenharmony_ci	struct kvec iov[2];
23958c2ecf20Sopenharmony_ci	struct kvec rsp_iov;
23968c2ecf20Sopenharmony_ci	int resp_buf_type;
23978c2ecf20Sopenharmony_ci	__u16 count;
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
24008c2ecf20Sopenharmony_ci		 num_lock, num_unlock);
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
24038c2ecf20Sopenharmony_ci	if (rc)
24048c2ecf20Sopenharmony_ci		return rc;
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
24078c2ecf20Sopenharmony_ci	pSMB->NumberOfLocks = cpu_to_le16(num_lock);
24088c2ecf20Sopenharmony_ci	pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
24098c2ecf20Sopenharmony_ci	pSMB->LockType = lock_type;
24108c2ecf20Sopenharmony_ci	pSMB->AndXCommand = 0xFF; /* none */
24118c2ecf20Sopenharmony_ci	pSMB->Fid = netfid; /* netfid stays le */
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
24148c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
24158c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	iov[0].iov_base = (char *)pSMB;
24188c2ecf20Sopenharmony_ci	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
24198c2ecf20Sopenharmony_ci			 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
24208c2ecf20Sopenharmony_ci	iov[1].iov_base = (char *)buf;
24218c2ecf20Sopenharmony_ci	iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
24248c2ecf20Sopenharmony_ci	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
24258c2ecf20Sopenharmony_ci			  CIFS_NO_RSP_BUF, &rsp_iov);
24268c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
24278c2ecf20Sopenharmony_ci	if (rc)
24288c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci	return rc;
24318c2ecf20Sopenharmony_ci}
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ciint
24348c2ecf20Sopenharmony_ciCIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
24358c2ecf20Sopenharmony_ci	    const __u16 smb_file_id, const __u32 netpid, const __u64 len,
24368c2ecf20Sopenharmony_ci	    const __u64 offset, const __u32 numUnlock,
24378c2ecf20Sopenharmony_ci	    const __u32 numLock, const __u8 lockType,
24388c2ecf20Sopenharmony_ci	    const bool waitFlag, const __u8 oplock_level)
24398c2ecf20Sopenharmony_ci{
24408c2ecf20Sopenharmony_ci	int rc = 0;
24418c2ecf20Sopenharmony_ci	LOCK_REQ *pSMB = NULL;
24428c2ecf20Sopenharmony_ci/*	LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
24438c2ecf20Sopenharmony_ci	int bytes_returned;
24448c2ecf20Sopenharmony_ci	int flags = 0;
24458c2ecf20Sopenharmony_ci	__u16 count;
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
24488c2ecf20Sopenharmony_ci		 (int)waitFlag, numLock);
24498c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci	if (rc)
24528c2ecf20Sopenharmony_ci		return rc;
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci	if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
24558c2ecf20Sopenharmony_ci		/* no response expected */
24568c2ecf20Sopenharmony_ci		flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
24578c2ecf20Sopenharmony_ci		pSMB->Timeout = 0;
24588c2ecf20Sopenharmony_ci	} else if (waitFlag) {
24598c2ecf20Sopenharmony_ci		flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
24608c2ecf20Sopenharmony_ci		pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
24618c2ecf20Sopenharmony_ci	} else {
24628c2ecf20Sopenharmony_ci		pSMB->Timeout = 0;
24638c2ecf20Sopenharmony_ci	}
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	pSMB->NumberOfLocks = cpu_to_le16(numLock);
24668c2ecf20Sopenharmony_ci	pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
24678c2ecf20Sopenharmony_ci	pSMB->LockType = lockType;
24688c2ecf20Sopenharmony_ci	pSMB->OplockLevel = oplock_level;
24698c2ecf20Sopenharmony_ci	pSMB->AndXCommand = 0xFF;	/* none */
24708c2ecf20Sopenharmony_ci	pSMB->Fid = smb_file_id; /* netfid stays le */
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	if ((numLock != 0) || (numUnlock != 0)) {
24738c2ecf20Sopenharmony_ci		pSMB->Locks[0].Pid = cpu_to_le16(netpid);
24748c2ecf20Sopenharmony_ci		/* BB where to store pid high? */
24758c2ecf20Sopenharmony_ci		pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
24768c2ecf20Sopenharmony_ci		pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
24778c2ecf20Sopenharmony_ci		pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
24788c2ecf20Sopenharmony_ci		pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
24798c2ecf20Sopenharmony_ci		count = sizeof(LOCKING_ANDX_RANGE);
24808c2ecf20Sopenharmony_ci	} else {
24818c2ecf20Sopenharmony_ci		/* oplock break */
24828c2ecf20Sopenharmony_ci		count = 0;
24838c2ecf20Sopenharmony_ci	}
24848c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
24858c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	if (waitFlag)
24888c2ecf20Sopenharmony_ci		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
24898c2ecf20Sopenharmony_ci			(struct smb_hdr *) pSMB, &bytes_returned);
24908c2ecf20Sopenharmony_ci	else
24918c2ecf20Sopenharmony_ci		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
24928c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
24938c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
24948c2ecf20Sopenharmony_ci	if (rc)
24958c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
24988c2ecf20Sopenharmony_ci	since file handle passed in no longer valid */
24998c2ecf20Sopenharmony_ci	return rc;
25008c2ecf20Sopenharmony_ci}
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ciint
25038c2ecf20Sopenharmony_ciCIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
25048c2ecf20Sopenharmony_ci		const __u16 smb_file_id, const __u32 netpid,
25058c2ecf20Sopenharmony_ci		const loff_t start_offset, const __u64 len,
25068c2ecf20Sopenharmony_ci		struct file_lock *pLockData, const __u16 lock_type,
25078c2ecf20Sopenharmony_ci		const bool waitFlag)
25088c2ecf20Sopenharmony_ci{
25098c2ecf20Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
25108c2ecf20Sopenharmony_ci	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
25118c2ecf20Sopenharmony_ci	struct cifs_posix_lock *parm_data;
25128c2ecf20Sopenharmony_ci	int rc = 0;
25138c2ecf20Sopenharmony_ci	int timeout = 0;
25148c2ecf20Sopenharmony_ci	int bytes_returned = 0;
25158c2ecf20Sopenharmony_ci	int resp_buf_type = 0;
25168c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
25178c2ecf20Sopenharmony_ci	struct kvec iov[1];
25188c2ecf20Sopenharmony_ci	struct kvec rsp_iov;
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Posix Lock\n");
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci	if (rc)
25258c2ecf20Sopenharmony_ci		return rc;
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ci	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	params = 6;
25308c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
25318c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
25328c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
25338c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
25348c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
25358c2ecf20Sopenharmony_ci	offset = param_offset + params;
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	count = sizeof(struct cifs_posix_lock);
25388c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
25398c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
25408c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
25418c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
25428c2ecf20Sopenharmony_ci	if (pLockData)
25438c2ecf20Sopenharmony_ci		pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
25448c2ecf20Sopenharmony_ci	else
25458c2ecf20Sopenharmony_ci		pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
25468c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
25478c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
25488c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
25498c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
25508c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
25518c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
25528c2ecf20Sopenharmony_ci	parm_data = (struct cifs_posix_lock *)
25538c2ecf20Sopenharmony_ci			(((char *) &pSMB->hdr.Protocol) + offset);
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci	parm_data->lock_type = cpu_to_le16(lock_type);
25568c2ecf20Sopenharmony_ci	if (waitFlag) {
25578c2ecf20Sopenharmony_ci		timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
25588c2ecf20Sopenharmony_ci		parm_data->lock_flags = cpu_to_le16(1);
25598c2ecf20Sopenharmony_ci		pSMB->Timeout = cpu_to_le32(-1);
25608c2ecf20Sopenharmony_ci	} else
25618c2ecf20Sopenharmony_ci		pSMB->Timeout = 0;
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci	parm_data->pid = cpu_to_le32(netpid);
25648c2ecf20Sopenharmony_ci	parm_data->start = cpu_to_le64(start_offset);
25658c2ecf20Sopenharmony_ci	parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
25688c2ecf20Sopenharmony_ci	pSMB->Fid = smb_file_id;
25698c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
25708c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
25718c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
25728c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
25738c2ecf20Sopenharmony_ci	if (waitFlag) {
25748c2ecf20Sopenharmony_ci		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
25758c2ecf20Sopenharmony_ci			(struct smb_hdr *) pSMBr, &bytes_returned);
25768c2ecf20Sopenharmony_ci	} else {
25778c2ecf20Sopenharmony_ci		iov[0].iov_base = (char *)pSMB;
25788c2ecf20Sopenharmony_ci		iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
25798c2ecf20Sopenharmony_ci		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
25808c2ecf20Sopenharmony_ci				&resp_buf_type, timeout, &rsp_iov);
25818c2ecf20Sopenharmony_ci		pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
25828c2ecf20Sopenharmony_ci	}
25838c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci	if (rc) {
25868c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
25878c2ecf20Sopenharmony_ci	} else if (pLockData) {
25888c2ecf20Sopenharmony_ci		/* lock structure can be returned on get */
25898c2ecf20Sopenharmony_ci		__u16 data_offset;
25908c2ecf20Sopenharmony_ci		__u16 data_count;
25918c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
25948c2ecf20Sopenharmony_ci			rc = -EIO;      /* bad smb */
25958c2ecf20Sopenharmony_ci			goto plk_err_exit;
25968c2ecf20Sopenharmony_ci		}
25978c2ecf20Sopenharmony_ci		data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
25988c2ecf20Sopenharmony_ci		data_count  = le16_to_cpu(pSMBr->t2.DataCount);
25998c2ecf20Sopenharmony_ci		if (data_count < sizeof(struct cifs_posix_lock)) {
26008c2ecf20Sopenharmony_ci			rc = -EIO;
26018c2ecf20Sopenharmony_ci			goto plk_err_exit;
26028c2ecf20Sopenharmony_ci		}
26038c2ecf20Sopenharmony_ci		parm_data = (struct cifs_posix_lock *)
26048c2ecf20Sopenharmony_ci			((char *)&pSMBr->hdr.Protocol + data_offset);
26058c2ecf20Sopenharmony_ci		if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
26068c2ecf20Sopenharmony_ci			pLockData->fl_type = F_UNLCK;
26078c2ecf20Sopenharmony_ci		else {
26088c2ecf20Sopenharmony_ci			if (parm_data->lock_type ==
26098c2ecf20Sopenharmony_ci					cpu_to_le16(CIFS_RDLCK))
26108c2ecf20Sopenharmony_ci				pLockData->fl_type = F_RDLCK;
26118c2ecf20Sopenharmony_ci			else if (parm_data->lock_type ==
26128c2ecf20Sopenharmony_ci					cpu_to_le16(CIFS_WRLCK))
26138c2ecf20Sopenharmony_ci				pLockData->fl_type = F_WRLCK;
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci			pLockData->fl_start = le64_to_cpu(parm_data->start);
26168c2ecf20Sopenharmony_ci			pLockData->fl_end = pLockData->fl_start +
26178c2ecf20Sopenharmony_ci					le64_to_cpu(parm_data->length) - 1;
26188c2ecf20Sopenharmony_ci			pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
26198c2ecf20Sopenharmony_ci		}
26208c2ecf20Sopenharmony_ci	}
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ciplk_err_exit:
26238c2ecf20Sopenharmony_ci	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
26268c2ecf20Sopenharmony_ci	   since file handle passed in no longer valid */
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	return rc;
26298c2ecf20Sopenharmony_ci}
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ciint
26338c2ecf20Sopenharmony_ciCIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
26348c2ecf20Sopenharmony_ci{
26358c2ecf20Sopenharmony_ci	int rc = 0;
26368c2ecf20Sopenharmony_ci	CLOSE_REQ *pSMB = NULL;
26378c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBClose\n");
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_ci/* do not retry on dead session on close */
26408c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
26418c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
26428c2ecf20Sopenharmony_ci		return 0;
26438c2ecf20Sopenharmony_ci	if (rc)
26448c2ecf20Sopenharmony_ci		return rc;
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	pSMB->FileID = (__u16) smb_file_id;
26478c2ecf20Sopenharmony_ci	pSMB->LastWriteTime = 0xFFFFFFFF;
26488c2ecf20Sopenharmony_ci	pSMB->ByteCount = 0;
26498c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
26508c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
26518c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
26528c2ecf20Sopenharmony_ci	if (rc) {
26538c2ecf20Sopenharmony_ci		if (rc != -EINTR) {
26548c2ecf20Sopenharmony_ci			/* EINTR is expected when user ctl-c to kill app */
26558c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "Send error in Close = %d\n", rc);
26568c2ecf20Sopenharmony_ci		}
26578c2ecf20Sopenharmony_ci	}
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	/* Since session is dead, file will be closed on server already */
26608c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
26618c2ecf20Sopenharmony_ci		rc = 0;
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	return rc;
26648c2ecf20Sopenharmony_ci}
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ciint
26678c2ecf20Sopenharmony_ciCIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
26688c2ecf20Sopenharmony_ci{
26698c2ecf20Sopenharmony_ci	int rc = 0;
26708c2ecf20Sopenharmony_ci	FLUSH_REQ *pSMB = NULL;
26718c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBFlush\n");
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
26748c2ecf20Sopenharmony_ci	if (rc)
26758c2ecf20Sopenharmony_ci		return rc;
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_ci	pSMB->FileID = (__u16) smb_file_id;
26788c2ecf20Sopenharmony_ci	pSMB->ByteCount = 0;
26798c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
26808c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
26818c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
26828c2ecf20Sopenharmony_ci	if (rc)
26838c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	return rc;
26868c2ecf20Sopenharmony_ci}
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ciint
26898c2ecf20Sopenharmony_ciCIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
26908c2ecf20Sopenharmony_ci	      const char *from_name, const char *to_name,
26918c2ecf20Sopenharmony_ci	      struct cifs_sb_info *cifs_sb)
26928c2ecf20Sopenharmony_ci{
26938c2ecf20Sopenharmony_ci	int rc = 0;
26948c2ecf20Sopenharmony_ci	RENAME_REQ *pSMB = NULL;
26958c2ecf20Sopenharmony_ci	RENAME_RSP *pSMBr = NULL;
26968c2ecf20Sopenharmony_ci	int bytes_returned;
26978c2ecf20Sopenharmony_ci	int name_len, name_len2;
26988c2ecf20Sopenharmony_ci	__u16 count;
26998c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBRename\n");
27028c2ecf20Sopenharmony_cirenameRetry:
27038c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
27048c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
27058c2ecf20Sopenharmony_ci	if (rc)
27068c2ecf20Sopenharmony_ci		return rc;
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	pSMB->BufferFormat = 0x04;
27098c2ecf20Sopenharmony_ci	pSMB->SearchAttributes =
27108c2ecf20Sopenharmony_ci	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
27118c2ecf20Sopenharmony_ci			ATTR_DIRECTORY);
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
27148c2ecf20Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
27158c2ecf20Sopenharmony_ci					      from_name, PATH_MAX,
27168c2ecf20Sopenharmony_ci					      cifs_sb->local_nls, remap);
27178c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
27188c2ecf20Sopenharmony_ci		name_len *= 2;
27198c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;	/* pad */
27208c2ecf20Sopenharmony_ci	/* protocol requires ASCII signature byte on Unicode string */
27218c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len + 1] = 0x00;
27228c2ecf20Sopenharmony_ci		name_len2 =
27238c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
27248c2ecf20Sopenharmony_ci				       to_name, PATH_MAX, cifs_sb->local_nls,
27258c2ecf20Sopenharmony_ci				       remap);
27268c2ecf20Sopenharmony_ci		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
27278c2ecf20Sopenharmony_ci		name_len2 *= 2;	/* convert to bytes */
27288c2ecf20Sopenharmony_ci	} else {
27298c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->OldFileName, from_name);
27308c2ecf20Sopenharmony_ci		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
27318c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
27328c2ecf20Sopenharmony_ci		name_len2++;	/* signature byte */
27338c2ecf20Sopenharmony_ci	}
27348c2ecf20Sopenharmony_ci
27358c2ecf20Sopenharmony_ci	count = 1 /* 1st signature byte */  + name_len + name_len2;
27368c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
27378c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
27408c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
27418c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
27428c2ecf20Sopenharmony_ci	if (rc)
27438c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in rename = %d\n", rc);
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
27468c2ecf20Sopenharmony_ci
27478c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
27488c2ecf20Sopenharmony_ci		goto renameRetry;
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci	return rc;
27518c2ecf20Sopenharmony_ci}
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ciint CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
27548c2ecf20Sopenharmony_ci		int netfid, const char *target_name,
27558c2ecf20Sopenharmony_ci		const struct nls_table *nls_codepage, int remap)
27568c2ecf20Sopenharmony_ci{
27578c2ecf20Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
27588c2ecf20Sopenharmony_ci	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
27598c2ecf20Sopenharmony_ci	struct set_file_rename *rename_info;
27608c2ecf20Sopenharmony_ci	char *data_offset;
27618c2ecf20Sopenharmony_ci	char dummy_string[30];
27628c2ecf20Sopenharmony_ci	int rc = 0;
27638c2ecf20Sopenharmony_ci	int bytes_returned = 0;
27648c2ecf20Sopenharmony_ci	int len_of_str;
27658c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, count, byte_count;
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Rename to File by handle\n");
27688c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
27698c2ecf20Sopenharmony_ci			(void **) &pSMBr);
27708c2ecf20Sopenharmony_ci	if (rc)
27718c2ecf20Sopenharmony_ci		return rc;
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	params = 6;
27748c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
27758c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
27768c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
27778c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
27788c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
27798c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
27808c2ecf20Sopenharmony_ci	offset = param_offset + params;
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
27838c2ecf20Sopenharmony_ci	rename_info = (struct set_file_rename *) data_offset;
27848c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
27858c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
27868c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
27878c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
27888c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
27898c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params;
27908c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
27918c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
27928c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
27938c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
27948c2ecf20Sopenharmony_ci	/* construct random name ".cifs_tmp<inodenum><mid>" */
27958c2ecf20Sopenharmony_ci	rename_info->overwrite = cpu_to_le32(1);
27968c2ecf20Sopenharmony_ci	rename_info->root_fid  = 0;
27978c2ecf20Sopenharmony_ci	/* unicode only call */
27988c2ecf20Sopenharmony_ci	if (target_name == NULL) {
27998c2ecf20Sopenharmony_ci		sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
28008c2ecf20Sopenharmony_ci		len_of_str =
28018c2ecf20Sopenharmony_ci			cifsConvertToUTF16((__le16 *)rename_info->target_name,
28028c2ecf20Sopenharmony_ci					dummy_string, 24, nls_codepage, remap);
28038c2ecf20Sopenharmony_ci	} else {
28048c2ecf20Sopenharmony_ci		len_of_str =
28058c2ecf20Sopenharmony_ci			cifsConvertToUTF16((__le16 *)rename_info->target_name,
28068c2ecf20Sopenharmony_ci					target_name, PATH_MAX, nls_codepage,
28078c2ecf20Sopenharmony_ci					remap);
28088c2ecf20Sopenharmony_ci	}
28098c2ecf20Sopenharmony_ci	rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
28108c2ecf20Sopenharmony_ci	count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
28118c2ecf20Sopenharmony_ci	byte_count += count;
28128c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
28138c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
28148c2ecf20Sopenharmony_ci	pSMB->Fid = netfid;
28158c2ecf20Sopenharmony_ci	pSMB->InformationLevel =
28168c2ecf20Sopenharmony_ci		cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
28178c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
28188c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
28198c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
28208c2ecf20Sopenharmony_ci	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
28218c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
28228c2ecf20Sopenharmony_ci	cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
28238c2ecf20Sopenharmony_ci	if (rc)
28248c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
28258c2ecf20Sopenharmony_ci			 rc);
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
28308c2ecf20Sopenharmony_ci		since file handle passed in no longer valid */
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	return rc;
28338c2ecf20Sopenharmony_ci}
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ciint
28368c2ecf20Sopenharmony_ciCIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
28378c2ecf20Sopenharmony_ci	    const char *fromName, const __u16 target_tid, const char *toName,
28388c2ecf20Sopenharmony_ci	    const int flags, const struct nls_table *nls_codepage, int remap)
28398c2ecf20Sopenharmony_ci{
28408c2ecf20Sopenharmony_ci	int rc = 0;
28418c2ecf20Sopenharmony_ci	COPY_REQ *pSMB = NULL;
28428c2ecf20Sopenharmony_ci	COPY_RSP *pSMBr = NULL;
28438c2ecf20Sopenharmony_ci	int bytes_returned;
28448c2ecf20Sopenharmony_ci	int name_len, name_len2;
28458c2ecf20Sopenharmony_ci	__u16 count;
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBCopy\n");
28488c2ecf20Sopenharmony_cicopyRetry:
28498c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
28508c2ecf20Sopenharmony_ci			(void **) &pSMBr);
28518c2ecf20Sopenharmony_ci	if (rc)
28528c2ecf20Sopenharmony_ci		return rc;
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	pSMB->BufferFormat = 0x04;
28558c2ecf20Sopenharmony_ci	pSMB->Tid2 = target_tid;
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
28608c2ecf20Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
28618c2ecf20Sopenharmony_ci					      fromName, PATH_MAX, nls_codepage,
28628c2ecf20Sopenharmony_ci					      remap);
28638c2ecf20Sopenharmony_ci		name_len++;     /* trailing null */
28648c2ecf20Sopenharmony_ci		name_len *= 2;
28658c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;     /* pad */
28668c2ecf20Sopenharmony_ci		/* protocol requires ASCII signature byte on Unicode string */
28678c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len + 1] = 0x00;
28688c2ecf20Sopenharmony_ci		name_len2 =
28698c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
28708c2ecf20Sopenharmony_ci				       toName, PATH_MAX, nls_codepage, remap);
28718c2ecf20Sopenharmony_ci		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
28728c2ecf20Sopenharmony_ci		name_len2 *= 2; /* convert to bytes */
28738c2ecf20Sopenharmony_ci	} else {
28748c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->OldFileName, fromName);
28758c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
28768c2ecf20Sopenharmony_ci		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
28778c2ecf20Sopenharmony_ci		name_len2++;    /* signature byte */
28788c2ecf20Sopenharmony_ci	}
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	count = 1 /* 1st signature byte */  + name_len + name_len2;
28818c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
28828c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
28858c2ecf20Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
28868c2ecf20Sopenharmony_ci	if (rc) {
28878c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
28888c2ecf20Sopenharmony_ci			 rc, le16_to_cpu(pSMBr->CopyCount));
28898c2ecf20Sopenharmony_ci	}
28908c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
28938c2ecf20Sopenharmony_ci		goto copyRetry;
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	return rc;
28968c2ecf20Sopenharmony_ci}
28978c2ecf20Sopenharmony_ci
28988c2ecf20Sopenharmony_ciint
28998c2ecf20Sopenharmony_ciCIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
29008c2ecf20Sopenharmony_ci		      const char *fromName, const char *toName,
29018c2ecf20Sopenharmony_ci		      const struct nls_table *nls_codepage, int remap)
29028c2ecf20Sopenharmony_ci{
29038c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
29048c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
29058c2ecf20Sopenharmony_ci	char *data_offset;
29068c2ecf20Sopenharmony_ci	int name_len;
29078c2ecf20Sopenharmony_ci	int name_len_target;
29088c2ecf20Sopenharmony_ci	int rc = 0;
29098c2ecf20Sopenharmony_ci	int bytes_returned = 0;
29108c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count;
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In Symlink Unix style\n");
29138c2ecf20Sopenharmony_cicreateSymLinkRetry:
29148c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
29158c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
29168c2ecf20Sopenharmony_ci	if (rc)
29178c2ecf20Sopenharmony_ci		return rc;
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
29208c2ecf20Sopenharmony_ci		name_len =
29218c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
29228c2ecf20Sopenharmony_ci				/* find define for this maxpathcomponent */
29238c2ecf20Sopenharmony_ci					PATH_MAX, nls_codepage, remap);
29248c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
29258c2ecf20Sopenharmony_ci		name_len *= 2;
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci	} else {
29288c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fromName);
29298c2ecf20Sopenharmony_ci	}
29308c2ecf20Sopenharmony_ci	params = 6 + name_len;
29318c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
29328c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
29338c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
29348c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
29358c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
29368c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
29378c2ecf20Sopenharmony_ci				InformationLevel) - 4;
29388c2ecf20Sopenharmony_ci	offset = param_offset + params;
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
29418c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
29428c2ecf20Sopenharmony_ci		name_len_target =
29438c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) data_offset, toName,
29448c2ecf20Sopenharmony_ci				/* find define for this maxpathcomponent */
29458c2ecf20Sopenharmony_ci					PATH_MAX, nls_codepage, remap);
29468c2ecf20Sopenharmony_ci		name_len_target++;	/* trailing null */
29478c2ecf20Sopenharmony_ci		name_len_target *= 2;
29488c2ecf20Sopenharmony_ci	} else {
29498c2ecf20Sopenharmony_ci		name_len_target = copy_path_name(data_offset, toName);
29508c2ecf20Sopenharmony_ci	}
29518c2ecf20Sopenharmony_ci
29528c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
29538c2ecf20Sopenharmony_ci	/* BB find exact max on data count below from sess */
29548c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
29558c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
29568c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
29578c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
29588c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + name_len_target;
29598c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(name_len_target);
29608c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
29618c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
29628c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
29638c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
29648c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
29658c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
29668c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
29678c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
29688c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
29698c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
29708c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
29718c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
29728c2ecf20Sopenharmony_ci	if (rc)
29738c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
29748c2ecf20Sopenharmony_ci			 rc);
29758c2ecf20Sopenharmony_ci
29768c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
29778c2ecf20Sopenharmony_ci
29788c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
29798c2ecf20Sopenharmony_ci		goto createSymLinkRetry;
29808c2ecf20Sopenharmony_ci
29818c2ecf20Sopenharmony_ci	return rc;
29828c2ecf20Sopenharmony_ci}
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ciint
29858c2ecf20Sopenharmony_ciCIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
29868c2ecf20Sopenharmony_ci		       const char *fromName, const char *toName,
29878c2ecf20Sopenharmony_ci		       const struct nls_table *nls_codepage, int remap)
29888c2ecf20Sopenharmony_ci{
29898c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
29908c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
29918c2ecf20Sopenharmony_ci	char *data_offset;
29928c2ecf20Sopenharmony_ci	int name_len;
29938c2ecf20Sopenharmony_ci	int name_len_target;
29948c2ecf20Sopenharmony_ci	int rc = 0;
29958c2ecf20Sopenharmony_ci	int bytes_returned = 0;
29968c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count;
29978c2ecf20Sopenharmony_ci
29988c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In Create Hard link Unix style\n");
29998c2ecf20Sopenharmony_cicreateHardLinkRetry:
30008c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
30018c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
30028c2ecf20Sopenharmony_ci	if (rc)
30038c2ecf20Sopenharmony_ci		return rc;
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
30068c2ecf20Sopenharmony_ci		name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
30078c2ecf20Sopenharmony_ci					      PATH_MAX, nls_codepage, remap);
30088c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
30098c2ecf20Sopenharmony_ci		name_len *= 2;
30108c2ecf20Sopenharmony_ci
30118c2ecf20Sopenharmony_ci	} else {
30128c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, toName);
30138c2ecf20Sopenharmony_ci	}
30148c2ecf20Sopenharmony_ci	params = 6 + name_len;
30158c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
30168c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
30178c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
30188c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
30198c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
30208c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
30218c2ecf20Sopenharmony_ci				InformationLevel) - 4;
30228c2ecf20Sopenharmony_ci	offset = param_offset + params;
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
30258c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
30268c2ecf20Sopenharmony_ci		name_len_target =
30278c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) data_offset, fromName,
30288c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
30298c2ecf20Sopenharmony_ci		name_len_target++;	/* trailing null */
30308c2ecf20Sopenharmony_ci		name_len_target *= 2;
30318c2ecf20Sopenharmony_ci	} else {
30328c2ecf20Sopenharmony_ci		name_len_target = copy_path_name(data_offset, fromName);
30338c2ecf20Sopenharmony_ci	}
30348c2ecf20Sopenharmony_ci
30358c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
30368c2ecf20Sopenharmony_ci	/* BB find exact max on data count below from sess*/
30378c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
30388c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
30398c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
30408c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
30418c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + name_len_target;
30428c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
30438c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
30448c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(name_len_target);
30458c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
30468c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
30478c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
30488c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
30498c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
30508c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
30518c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
30528c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
30538c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
30548c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
30558c2ecf20Sopenharmony_ci	if (rc)
30568c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
30578c2ecf20Sopenharmony_ci			 rc);
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
30608c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
30618c2ecf20Sopenharmony_ci		goto createHardLinkRetry;
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	return rc;
30648c2ecf20Sopenharmony_ci}
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ciint
30678c2ecf20Sopenharmony_ciCIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
30688c2ecf20Sopenharmony_ci		   const char *from_name, const char *to_name,
30698c2ecf20Sopenharmony_ci		   struct cifs_sb_info *cifs_sb)
30708c2ecf20Sopenharmony_ci{
30718c2ecf20Sopenharmony_ci	int rc = 0;
30728c2ecf20Sopenharmony_ci	NT_RENAME_REQ *pSMB = NULL;
30738c2ecf20Sopenharmony_ci	RENAME_RSP *pSMBr = NULL;
30748c2ecf20Sopenharmony_ci	int bytes_returned;
30758c2ecf20Sopenharmony_ci	int name_len, name_len2;
30768c2ecf20Sopenharmony_ci	__u16 count;
30778c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In CIFSCreateHardLink\n");
30808c2ecf20Sopenharmony_ciwinCreateHardLinkRetry:
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
30838c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
30848c2ecf20Sopenharmony_ci	if (rc)
30858c2ecf20Sopenharmony_ci		return rc;
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci	pSMB->SearchAttributes =
30888c2ecf20Sopenharmony_ci	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
30898c2ecf20Sopenharmony_ci			ATTR_DIRECTORY);
30908c2ecf20Sopenharmony_ci	pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
30918c2ecf20Sopenharmony_ci	pSMB->ClusterCount = 0;
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ci	pSMB->BufferFormat = 0x04;
30948c2ecf20Sopenharmony_ci
30958c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
30968c2ecf20Sopenharmony_ci		name_len =
30978c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
30988c2ecf20Sopenharmony_ci				       PATH_MAX, cifs_sb->local_nls, remap);
30998c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
31008c2ecf20Sopenharmony_ci		name_len *= 2;
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci		/* protocol specifies ASCII buffer format (0x04) for unicode */
31038c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;
31048c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
31058c2ecf20Sopenharmony_ci		name_len2 =
31068c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
31078c2ecf20Sopenharmony_ci				       to_name, PATH_MAX, cifs_sb->local_nls,
31088c2ecf20Sopenharmony_ci				       remap);
31098c2ecf20Sopenharmony_ci		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
31108c2ecf20Sopenharmony_ci		name_len2 *= 2;	/* convert to bytes */
31118c2ecf20Sopenharmony_ci	} else {
31128c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->OldFileName, from_name);
31138c2ecf20Sopenharmony_ci		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
31148c2ecf20Sopenharmony_ci		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
31158c2ecf20Sopenharmony_ci		name_len2++;	/* signature byte */
31168c2ecf20Sopenharmony_ci	}
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	count = 1 /* string type byte */  + name_len + name_len2;
31198c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, count);
31208c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(count);
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
31238c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
31248c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
31258c2ecf20Sopenharmony_ci	if (rc)
31268c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
31278c2ecf20Sopenharmony_ci
31288c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
31298c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
31308c2ecf20Sopenharmony_ci		goto winCreateHardLinkRetry;
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_ci	return rc;
31338c2ecf20Sopenharmony_ci}
31348c2ecf20Sopenharmony_ci
31358c2ecf20Sopenharmony_ciint
31368c2ecf20Sopenharmony_ciCIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
31378c2ecf20Sopenharmony_ci			const unsigned char *searchName, char **symlinkinfo,
31388c2ecf20Sopenharmony_ci			const struct nls_table *nls_codepage, int remap)
31398c2ecf20Sopenharmony_ci{
31408c2ecf20Sopenharmony_ci/* SMB_QUERY_FILE_UNIX_LINK */
31418c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
31428c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
31438c2ecf20Sopenharmony_ci	int rc = 0;
31448c2ecf20Sopenharmony_ci	int bytes_returned;
31458c2ecf20Sopenharmony_ci	int name_len;
31468c2ecf20Sopenharmony_ci	__u16 params, byte_count;
31478c2ecf20Sopenharmony_ci	char *data_start;
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ciquerySymLinkRetry:
31528c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
31538c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
31548c2ecf20Sopenharmony_ci	if (rc)
31558c2ecf20Sopenharmony_ci		return rc;
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
31588c2ecf20Sopenharmony_ci		name_len =
31598c2ecf20Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName,
31608c2ecf20Sopenharmony_ci					   searchName, PATH_MAX, nls_codepage,
31618c2ecf20Sopenharmony_ci					   remap);
31628c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
31638c2ecf20Sopenharmony_ci		name_len *= 2;
31648c2ecf20Sopenharmony_ci	} else {
31658c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, searchName);
31668c2ecf20Sopenharmony_ci	}
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
31698c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
31708c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
31718c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
31728c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
31738c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
31748c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
31758c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
31768c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
31778c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
31788c2ecf20Sopenharmony_ci	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
31798c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
31808c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
31818c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
31828c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
31838c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
31848c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
31858c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
31868c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
31878c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
31888c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
31898c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
31908c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
31938c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
31948c2ecf20Sopenharmony_ci	if (rc) {
31958c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
31968c2ecf20Sopenharmony_ci	} else {
31978c2ecf20Sopenharmony_ci		/* decode response */
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
32008c2ecf20Sopenharmony_ci		/* BB also check enough total bytes returned */
32018c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 2)
32028c2ecf20Sopenharmony_ci			rc = -EIO;
32038c2ecf20Sopenharmony_ci		else {
32048c2ecf20Sopenharmony_ci			bool is_unicode;
32058c2ecf20Sopenharmony_ci			u16 count = le16_to_cpu(pSMBr->t2.DataCount);
32068c2ecf20Sopenharmony_ci
32078c2ecf20Sopenharmony_ci			data_start = ((char *) &pSMBr->hdr.Protocol) +
32088c2ecf20Sopenharmony_ci					   le16_to_cpu(pSMBr->t2.DataOffset);
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_ci			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
32118c2ecf20Sopenharmony_ci				is_unicode = true;
32128c2ecf20Sopenharmony_ci			else
32138c2ecf20Sopenharmony_ci				is_unicode = false;
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci			/* BB FIXME investigate remapping reserved chars here */
32168c2ecf20Sopenharmony_ci			*symlinkinfo = cifs_strndup_from_utf16(data_start,
32178c2ecf20Sopenharmony_ci					count, is_unicode, nls_codepage);
32188c2ecf20Sopenharmony_ci			if (!*symlinkinfo)
32198c2ecf20Sopenharmony_ci				rc = -ENOMEM;
32208c2ecf20Sopenharmony_ci		}
32218c2ecf20Sopenharmony_ci	}
32228c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
32238c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
32248c2ecf20Sopenharmony_ci		goto querySymLinkRetry;
32258c2ecf20Sopenharmony_ci	return rc;
32268c2ecf20Sopenharmony_ci}
32278c2ecf20Sopenharmony_ci
32288c2ecf20Sopenharmony_ci/*
32298c2ecf20Sopenharmony_ci *	Recent Windows versions now create symlinks more frequently
32308c2ecf20Sopenharmony_ci *	and they use the "reparse point" mechanism below.  We can of course
32318c2ecf20Sopenharmony_ci *	do symlinks nicely to Samba and other servers which support the
32328c2ecf20Sopenharmony_ci *	CIFS Unix Extensions and we can also do SFU symlinks and "client only"
32338c2ecf20Sopenharmony_ci *	"MF" symlinks optionally, but for recent Windows we really need to
32348c2ecf20Sopenharmony_ci *	reenable the code below and fix the cifs_symlink callers to handle this.
32358c2ecf20Sopenharmony_ci *	In the interim this code has been moved to its own config option so
32368c2ecf20Sopenharmony_ci *	it is not compiled in by default until callers fixed up and more tested.
32378c2ecf20Sopenharmony_ci */
32388c2ecf20Sopenharmony_ciint
32398c2ecf20Sopenharmony_ciCIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
32408c2ecf20Sopenharmony_ci		    __u16 fid, char **symlinkinfo,
32418c2ecf20Sopenharmony_ci		    const struct nls_table *nls_codepage)
32428c2ecf20Sopenharmony_ci{
32438c2ecf20Sopenharmony_ci	int rc = 0;
32448c2ecf20Sopenharmony_ci	int bytes_returned;
32458c2ecf20Sopenharmony_ci	struct smb_com_transaction_ioctl_req *pSMB;
32468c2ecf20Sopenharmony_ci	struct smb_com_transaction_ioctl_rsp *pSMBr;
32478c2ecf20Sopenharmony_ci	bool is_unicode;
32488c2ecf20Sopenharmony_ci	unsigned int sub_len;
32498c2ecf20Sopenharmony_ci	char *sub_start;
32508c2ecf20Sopenharmony_ci	struct reparse_symlink_data *reparse_buf;
32518c2ecf20Sopenharmony_ci	struct reparse_posix_data *posix_buf;
32528c2ecf20Sopenharmony_ci	__u32 data_offset, data_count;
32538c2ecf20Sopenharmony_ci	char *end_of_smb;
32548c2ecf20Sopenharmony_ci
32558c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
32568c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
32578c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
32588c2ecf20Sopenharmony_ci	if (rc)
32598c2ecf20Sopenharmony_ci		return rc;
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = 0 ;
32628c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
32638c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le32(2);
32648c2ecf20Sopenharmony_ci	/* BB find exact data count max from sess structure BB */
32658c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
32668c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 4;
32678c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
32688c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = 0;
32698c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
32708c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
32718c2ecf20Sopenharmony_ci	pSMB->SetupCount = 4;
32728c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
32738c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
32748c2ecf20Sopenharmony_ci	pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
32758c2ecf20Sopenharmony_ci	pSMB->IsFsctl = 1; /* FSCTL */
32768c2ecf20Sopenharmony_ci	pSMB->IsRootFlag = 0;
32778c2ecf20Sopenharmony_ci	pSMB->Fid = fid; /* file handle always le */
32788c2ecf20Sopenharmony_ci	pSMB->ByteCount = 0;
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
32818c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
32828c2ecf20Sopenharmony_ci	if (rc) {
32838c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
32848c2ecf20Sopenharmony_ci		goto qreparse_out;
32858c2ecf20Sopenharmony_ci	}
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ci	data_offset = le32_to_cpu(pSMBr->DataOffset);
32888c2ecf20Sopenharmony_ci	data_count = le32_to_cpu(pSMBr->DataCount);
32898c2ecf20Sopenharmony_ci	if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
32908c2ecf20Sopenharmony_ci		/* BB also check enough total bytes returned */
32918c2ecf20Sopenharmony_ci		rc = -EIO;	/* bad smb */
32928c2ecf20Sopenharmony_ci		goto qreparse_out;
32938c2ecf20Sopenharmony_ci	}
32948c2ecf20Sopenharmony_ci	if (!data_count || (data_count > 2048)) {
32958c2ecf20Sopenharmony_ci		rc = -EIO;
32968c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
32978c2ecf20Sopenharmony_ci		goto qreparse_out;
32988c2ecf20Sopenharmony_ci	}
32998c2ecf20Sopenharmony_ci	end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
33008c2ecf20Sopenharmony_ci	reparse_buf = (struct reparse_symlink_data *)
33018c2ecf20Sopenharmony_ci				((char *)&pSMBr->hdr.Protocol + data_offset);
33028c2ecf20Sopenharmony_ci	if ((char *)reparse_buf >= end_of_smb) {
33038c2ecf20Sopenharmony_ci		rc = -EIO;
33048c2ecf20Sopenharmony_ci		goto qreparse_out;
33058c2ecf20Sopenharmony_ci	}
33068c2ecf20Sopenharmony_ci	if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
33078c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "NFS style reparse tag\n");
33088c2ecf20Sopenharmony_ci		posix_buf =  (struct reparse_posix_data *)reparse_buf;
33098c2ecf20Sopenharmony_ci
33108c2ecf20Sopenharmony_ci		if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
33118c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "unsupported file type 0x%llx\n",
33128c2ecf20Sopenharmony_ci				 le64_to_cpu(posix_buf->InodeType));
33138c2ecf20Sopenharmony_ci			rc = -EOPNOTSUPP;
33148c2ecf20Sopenharmony_ci			goto qreparse_out;
33158c2ecf20Sopenharmony_ci		}
33168c2ecf20Sopenharmony_ci		is_unicode = true;
33178c2ecf20Sopenharmony_ci		sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
33188c2ecf20Sopenharmony_ci		if (posix_buf->PathBuffer + sub_len > end_of_smb) {
33198c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "reparse buf beyond SMB\n");
33208c2ecf20Sopenharmony_ci			rc = -EIO;
33218c2ecf20Sopenharmony_ci			goto qreparse_out;
33228c2ecf20Sopenharmony_ci		}
33238c2ecf20Sopenharmony_ci		*symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
33248c2ecf20Sopenharmony_ci				sub_len, is_unicode, nls_codepage);
33258c2ecf20Sopenharmony_ci		goto qreparse_out;
33268c2ecf20Sopenharmony_ci	} else if (reparse_buf->ReparseTag !=
33278c2ecf20Sopenharmony_ci			cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
33288c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
33298c2ecf20Sopenharmony_ci		goto qreparse_out;
33308c2ecf20Sopenharmony_ci	}
33318c2ecf20Sopenharmony_ci
33328c2ecf20Sopenharmony_ci	/* Reparse tag is NTFS symlink */
33338c2ecf20Sopenharmony_ci	sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
33348c2ecf20Sopenharmony_ci				reparse_buf->PathBuffer;
33358c2ecf20Sopenharmony_ci	sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
33368c2ecf20Sopenharmony_ci	if (sub_start + sub_len > end_of_smb) {
33378c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "reparse buf beyond SMB\n");
33388c2ecf20Sopenharmony_ci		rc = -EIO;
33398c2ecf20Sopenharmony_ci		goto qreparse_out;
33408c2ecf20Sopenharmony_ci	}
33418c2ecf20Sopenharmony_ci	if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
33428c2ecf20Sopenharmony_ci		is_unicode = true;
33438c2ecf20Sopenharmony_ci	else
33448c2ecf20Sopenharmony_ci		is_unicode = false;
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci	/* BB FIXME investigate remapping reserved chars here */
33478c2ecf20Sopenharmony_ci	*symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
33488c2ecf20Sopenharmony_ci					       nls_codepage);
33498c2ecf20Sopenharmony_ci	if (!*symlinkinfo)
33508c2ecf20Sopenharmony_ci		rc = -ENOMEM;
33518c2ecf20Sopenharmony_ciqreparse_out:
33528c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_ci	/*
33558c2ecf20Sopenharmony_ci	 * Note: On -EAGAIN error only caller can retry on handle based calls
33568c2ecf20Sopenharmony_ci	 * since file handle passed in no longer valid.
33578c2ecf20Sopenharmony_ci	 */
33588c2ecf20Sopenharmony_ci	return rc;
33598c2ecf20Sopenharmony_ci}
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ciint
33628c2ecf20Sopenharmony_ciCIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
33638c2ecf20Sopenharmony_ci		    __u16 fid)
33648c2ecf20Sopenharmony_ci{
33658c2ecf20Sopenharmony_ci	int rc = 0;
33668c2ecf20Sopenharmony_ci	int bytes_returned;
33678c2ecf20Sopenharmony_ci	struct smb_com_transaction_compr_ioctl_req *pSMB;
33688c2ecf20Sopenharmony_ci	struct smb_com_transaction_ioctl_rsp *pSMBr;
33698c2ecf20Sopenharmony_ci
33708c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Set compression for %u\n", fid);
33718c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
33728c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
33738c2ecf20Sopenharmony_ci	if (rc)
33748c2ecf20Sopenharmony_ci		return rc;
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_ci	pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = 0;
33798c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = cpu_to_le32(2);
33808c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = 0;
33818c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = 0;
33828c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 4;
33838c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
33848c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = 0;
33858c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le32(2);
33868c2ecf20Sopenharmony_ci	pSMB->DataOffset =
33878c2ecf20Sopenharmony_ci		cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
33888c2ecf20Sopenharmony_ci				compression_state) - 4);  /* 84 */
33898c2ecf20Sopenharmony_ci	pSMB->SetupCount = 4;
33908c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
33918c2ecf20Sopenharmony_ci	pSMB->ParameterCount = 0;
33928c2ecf20Sopenharmony_ci	pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
33938c2ecf20Sopenharmony_ci	pSMB->IsFsctl = 1; /* FSCTL */
33948c2ecf20Sopenharmony_ci	pSMB->IsRootFlag = 0;
33958c2ecf20Sopenharmony_ci	pSMB->Fid = fid; /* file handle always le */
33968c2ecf20Sopenharmony_ci	/* 3 byte pad, followed by 2 byte compress state */
33978c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(5);
33988c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, 5);
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
34018c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
34028c2ecf20Sopenharmony_ci	if (rc)
34038c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
34048c2ecf20Sopenharmony_ci
34058c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
34068c2ecf20Sopenharmony_ci
34078c2ecf20Sopenharmony_ci	/*
34088c2ecf20Sopenharmony_ci	 * Note: On -EAGAIN error only caller can retry on handle based calls
34098c2ecf20Sopenharmony_ci	 * since file handle passed in no longer valid.
34108c2ecf20Sopenharmony_ci	 */
34118c2ecf20Sopenharmony_ci	return rc;
34128c2ecf20Sopenharmony_ci}
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci
34158c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX
34168c2ecf20Sopenharmony_ci
34178c2ecf20Sopenharmony_ci/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
34188c2ecf20Sopenharmony_cistatic void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
34198c2ecf20Sopenharmony_ci			     struct cifs_posix_ace *cifs_ace)
34208c2ecf20Sopenharmony_ci{
34218c2ecf20Sopenharmony_ci	/* u8 cifs fields do not need le conversion */
34228c2ecf20Sopenharmony_ci	ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
34238c2ecf20Sopenharmony_ci	ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
34248c2ecf20Sopenharmony_ci	ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
34258c2ecf20Sopenharmony_ci/*
34268c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "perm %d tag %d id %d\n",
34278c2ecf20Sopenharmony_ci		 ace->e_perm, ace->e_tag, ace->e_id);
34288c2ecf20Sopenharmony_ci*/
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_ci	return;
34318c2ecf20Sopenharmony_ci}
34328c2ecf20Sopenharmony_ci
34338c2ecf20Sopenharmony_ci/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
34348c2ecf20Sopenharmony_cistatic int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
34358c2ecf20Sopenharmony_ci			       const int acl_type, const int size_of_data_area)
34368c2ecf20Sopenharmony_ci{
34378c2ecf20Sopenharmony_ci	int size =  0;
34388c2ecf20Sopenharmony_ci	int i;
34398c2ecf20Sopenharmony_ci	__u16 count;
34408c2ecf20Sopenharmony_ci	struct cifs_posix_ace *pACE;
34418c2ecf20Sopenharmony_ci	struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
34428c2ecf20Sopenharmony_ci	struct posix_acl_xattr_header *local_acl = (void *)trgt;
34438c2ecf20Sopenharmony_ci
34448c2ecf20Sopenharmony_ci	if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
34458c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
34468c2ecf20Sopenharmony_ci
34478c2ecf20Sopenharmony_ci	if (acl_type == ACL_TYPE_ACCESS) {
34488c2ecf20Sopenharmony_ci		count = le16_to_cpu(cifs_acl->access_entry_count);
34498c2ecf20Sopenharmony_ci		pACE = &cifs_acl->ace_array[0];
34508c2ecf20Sopenharmony_ci		size = sizeof(struct cifs_posix_acl);
34518c2ecf20Sopenharmony_ci		size += sizeof(struct cifs_posix_ace) * count;
34528c2ecf20Sopenharmony_ci		/* check if we would go beyond end of SMB */
34538c2ecf20Sopenharmony_ci		if (size_of_data_area < size) {
34548c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
34558c2ecf20Sopenharmony_ci				 size_of_data_area, size);
34568c2ecf20Sopenharmony_ci			return -EINVAL;
34578c2ecf20Sopenharmony_ci		}
34588c2ecf20Sopenharmony_ci	} else if (acl_type == ACL_TYPE_DEFAULT) {
34598c2ecf20Sopenharmony_ci		count = le16_to_cpu(cifs_acl->access_entry_count);
34608c2ecf20Sopenharmony_ci		size = sizeof(struct cifs_posix_acl);
34618c2ecf20Sopenharmony_ci		size += sizeof(struct cifs_posix_ace) * count;
34628c2ecf20Sopenharmony_ci/* skip past access ACEs to get to default ACEs */
34638c2ecf20Sopenharmony_ci		pACE = &cifs_acl->ace_array[count];
34648c2ecf20Sopenharmony_ci		count = le16_to_cpu(cifs_acl->default_entry_count);
34658c2ecf20Sopenharmony_ci		size += sizeof(struct cifs_posix_ace) * count;
34668c2ecf20Sopenharmony_ci		/* check if we would go beyond end of SMB */
34678c2ecf20Sopenharmony_ci		if (size_of_data_area < size)
34688c2ecf20Sopenharmony_ci			return -EINVAL;
34698c2ecf20Sopenharmony_ci	} else {
34708c2ecf20Sopenharmony_ci		/* illegal type */
34718c2ecf20Sopenharmony_ci		return -EINVAL;
34728c2ecf20Sopenharmony_ci	}
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	size = posix_acl_xattr_size(count);
34758c2ecf20Sopenharmony_ci	if ((buflen == 0) || (local_acl == NULL)) {
34768c2ecf20Sopenharmony_ci		/* used to query ACL EA size */
34778c2ecf20Sopenharmony_ci	} else if (size > buflen) {
34788c2ecf20Sopenharmony_ci		return -ERANGE;
34798c2ecf20Sopenharmony_ci	} else /* buffer big enough */ {
34808c2ecf20Sopenharmony_ci		struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
34818c2ecf20Sopenharmony_ci
34828c2ecf20Sopenharmony_ci		local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
34838c2ecf20Sopenharmony_ci		for (i = 0; i < count ; i++) {
34848c2ecf20Sopenharmony_ci			cifs_convert_ace(&ace[i], pACE);
34858c2ecf20Sopenharmony_ci			pACE++;
34868c2ecf20Sopenharmony_ci		}
34878c2ecf20Sopenharmony_ci	}
34888c2ecf20Sopenharmony_ci	return size;
34898c2ecf20Sopenharmony_ci}
34908c2ecf20Sopenharmony_ci
34918c2ecf20Sopenharmony_cistatic void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
34928c2ecf20Sopenharmony_ci				     const struct posix_acl_xattr_entry *local_ace)
34938c2ecf20Sopenharmony_ci{
34948c2ecf20Sopenharmony_ci	cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
34958c2ecf20Sopenharmony_ci	cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
34968c2ecf20Sopenharmony_ci	/* BB is there a better way to handle the large uid? */
34978c2ecf20Sopenharmony_ci	if (local_ace->e_id == cpu_to_le32(-1)) {
34988c2ecf20Sopenharmony_ci	/* Probably no need to le convert -1 on any arch but can not hurt */
34998c2ecf20Sopenharmony_ci		cifs_ace->cifs_uid = cpu_to_le64(-1);
35008c2ecf20Sopenharmony_ci	} else
35018c2ecf20Sopenharmony_ci		cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
35028c2ecf20Sopenharmony_ci/*
35038c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "perm %d tag %d id %d\n",
35048c2ecf20Sopenharmony_ci		 ace->e_perm, ace->e_tag, ace->e_id);
35058c2ecf20Sopenharmony_ci*/
35068c2ecf20Sopenharmony_ci}
35078c2ecf20Sopenharmony_ci
35088c2ecf20Sopenharmony_ci/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
35098c2ecf20Sopenharmony_cistatic __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
35108c2ecf20Sopenharmony_ci			       const int buflen, const int acl_type)
35118c2ecf20Sopenharmony_ci{
35128c2ecf20Sopenharmony_ci	__u16 rc = 0;
35138c2ecf20Sopenharmony_ci	struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
35148c2ecf20Sopenharmony_ci	struct posix_acl_xattr_header *local_acl = (void *)pACL;
35158c2ecf20Sopenharmony_ci	struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
35168c2ecf20Sopenharmony_ci	int count;
35178c2ecf20Sopenharmony_ci	int i;
35188c2ecf20Sopenharmony_ci
35198c2ecf20Sopenharmony_ci	if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
35208c2ecf20Sopenharmony_ci		return 0;
35218c2ecf20Sopenharmony_ci
35228c2ecf20Sopenharmony_ci	count = posix_acl_xattr_count((size_t)buflen);
35238c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
35248c2ecf20Sopenharmony_ci		 count, buflen, le32_to_cpu(local_acl->a_version));
35258c2ecf20Sopenharmony_ci	if (le32_to_cpu(local_acl->a_version) != 2) {
35268c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
35278c2ecf20Sopenharmony_ci			 le32_to_cpu(local_acl->a_version));
35288c2ecf20Sopenharmony_ci		return 0;
35298c2ecf20Sopenharmony_ci	}
35308c2ecf20Sopenharmony_ci	cifs_acl->version = cpu_to_le16(1);
35318c2ecf20Sopenharmony_ci	if (acl_type == ACL_TYPE_ACCESS) {
35328c2ecf20Sopenharmony_ci		cifs_acl->access_entry_count = cpu_to_le16(count);
35338c2ecf20Sopenharmony_ci		cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
35348c2ecf20Sopenharmony_ci	} else if (acl_type == ACL_TYPE_DEFAULT) {
35358c2ecf20Sopenharmony_ci		cifs_acl->default_entry_count = cpu_to_le16(count);
35368c2ecf20Sopenharmony_ci		cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
35378c2ecf20Sopenharmony_ci	} else {
35388c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
35398c2ecf20Sopenharmony_ci		return 0;
35408c2ecf20Sopenharmony_ci	}
35418c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
35428c2ecf20Sopenharmony_ci		convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
35438c2ecf20Sopenharmony_ci	if (rc == 0) {
35448c2ecf20Sopenharmony_ci		rc = (__u16)(count * sizeof(struct cifs_posix_ace));
35458c2ecf20Sopenharmony_ci		rc += sizeof(struct cifs_posix_acl);
35468c2ecf20Sopenharmony_ci		/* BB add check to make sure ACL does not overflow SMB */
35478c2ecf20Sopenharmony_ci	}
35488c2ecf20Sopenharmony_ci	return rc;
35498c2ecf20Sopenharmony_ci}
35508c2ecf20Sopenharmony_ci
35518c2ecf20Sopenharmony_ciint
35528c2ecf20Sopenharmony_ciCIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
35538c2ecf20Sopenharmony_ci		   const unsigned char *searchName,
35548c2ecf20Sopenharmony_ci		   char *acl_inf, const int buflen, const int acl_type,
35558c2ecf20Sopenharmony_ci		   const struct nls_table *nls_codepage, int remap)
35568c2ecf20Sopenharmony_ci{
35578c2ecf20Sopenharmony_ci/* SMB_QUERY_POSIX_ACL */
35588c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
35598c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
35608c2ecf20Sopenharmony_ci	int rc = 0;
35618c2ecf20Sopenharmony_ci	int bytes_returned;
35628c2ecf20Sopenharmony_ci	int name_len;
35638c2ecf20Sopenharmony_ci	__u16 params, byte_count;
35648c2ecf20Sopenharmony_ci
35658c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
35668c2ecf20Sopenharmony_ci
35678c2ecf20Sopenharmony_ciqueryAclRetry:
35688c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
35698c2ecf20Sopenharmony_ci		(void **) &pSMBr);
35708c2ecf20Sopenharmony_ci	if (rc)
35718c2ecf20Sopenharmony_ci		return rc;
35728c2ecf20Sopenharmony_ci
35738c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
35748c2ecf20Sopenharmony_ci		name_len =
35758c2ecf20Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName,
35768c2ecf20Sopenharmony_ci					   searchName, PATH_MAX, nls_codepage,
35778c2ecf20Sopenharmony_ci					   remap);
35788c2ecf20Sopenharmony_ci		name_len++;     /* trailing null */
35798c2ecf20Sopenharmony_ci		name_len *= 2;
35808c2ecf20Sopenharmony_ci		pSMB->FileName[name_len] = 0;
35818c2ecf20Sopenharmony_ci		pSMB->FileName[name_len+1] = 0;
35828c2ecf20Sopenharmony_ci	} else {
35838c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, searchName);
35848c2ecf20Sopenharmony_ci	}
35858c2ecf20Sopenharmony_ci
35868c2ecf20Sopenharmony_ci	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
35878c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
35888c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
35898c2ecf20Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
35908c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
35918c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
35928c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
35938c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
35948c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
35958c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
35968c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(
35978c2ecf20Sopenharmony_ci		offsetof(struct smb_com_transaction2_qpi_req,
35988c2ecf20Sopenharmony_ci			 InformationLevel) - 4);
35998c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
36008c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
36018c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
36028c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
36038c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
36048c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
36058c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
36068c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
36078c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
36088c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
36098c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
36108c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
36118c2ecf20Sopenharmony_ci
36128c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
36138c2ecf20Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
36148c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
36158c2ecf20Sopenharmony_ci	if (rc) {
36168c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
36178c2ecf20Sopenharmony_ci	} else {
36188c2ecf20Sopenharmony_ci		/* decode response */
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
36218c2ecf20Sopenharmony_ci		/* BB also check enough total bytes returned */
36228c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 2)
36238c2ecf20Sopenharmony_ci			rc = -EIO;      /* bad smb */
36248c2ecf20Sopenharmony_ci		else {
36258c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
36268c2ecf20Sopenharmony_ci			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
36278c2ecf20Sopenharmony_ci			rc = cifs_copy_posix_acl(acl_inf,
36288c2ecf20Sopenharmony_ci				(char *)&pSMBr->hdr.Protocol+data_offset,
36298c2ecf20Sopenharmony_ci				buflen, acl_type, count);
36308c2ecf20Sopenharmony_ci		}
36318c2ecf20Sopenharmony_ci	}
36328c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
36338c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
36348c2ecf20Sopenharmony_ci		goto queryAclRetry;
36358c2ecf20Sopenharmony_ci	return rc;
36368c2ecf20Sopenharmony_ci}
36378c2ecf20Sopenharmony_ci
36388c2ecf20Sopenharmony_ciint
36398c2ecf20Sopenharmony_ciCIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
36408c2ecf20Sopenharmony_ci		   const unsigned char *fileName,
36418c2ecf20Sopenharmony_ci		   const char *local_acl, const int buflen,
36428c2ecf20Sopenharmony_ci		   const int acl_type,
36438c2ecf20Sopenharmony_ci		   const struct nls_table *nls_codepage, int remap)
36448c2ecf20Sopenharmony_ci{
36458c2ecf20Sopenharmony_ci	struct smb_com_transaction2_spi_req *pSMB = NULL;
36468c2ecf20Sopenharmony_ci	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
36478c2ecf20Sopenharmony_ci	char *parm_data;
36488c2ecf20Sopenharmony_ci	int name_len;
36498c2ecf20Sopenharmony_ci	int rc = 0;
36508c2ecf20Sopenharmony_ci	int bytes_returned = 0;
36518c2ecf20Sopenharmony_ci	__u16 params, byte_count, data_count, param_offset, offset;
36528c2ecf20Sopenharmony_ci
36538c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
36548c2ecf20Sopenharmony_cisetAclRetry:
36558c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
36568c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
36578c2ecf20Sopenharmony_ci	if (rc)
36588c2ecf20Sopenharmony_ci		return rc;
36598c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
36608c2ecf20Sopenharmony_ci		name_len =
36618c2ecf20Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
36628c2ecf20Sopenharmony_ci					   PATH_MAX, nls_codepage, remap);
36638c2ecf20Sopenharmony_ci		name_len++;     /* trailing null */
36648c2ecf20Sopenharmony_ci		name_len *= 2;
36658c2ecf20Sopenharmony_ci	} else {
36668c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fileName);
36678c2ecf20Sopenharmony_ci	}
36688c2ecf20Sopenharmony_ci	params = 6 + name_len;
36698c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
36708c2ecf20Sopenharmony_ci	/* BB find max SMB size from sess */
36718c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
36728c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
36738c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
36748c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
36758c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
36768c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
36778c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
36788c2ecf20Sopenharmony_ci				InformationLevel) - 4;
36798c2ecf20Sopenharmony_ci	offset = param_offset + params;
36808c2ecf20Sopenharmony_ci	parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
36818c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
36828c2ecf20Sopenharmony_ci
36838c2ecf20Sopenharmony_ci	/* convert to on the wire format for POSIX ACL */
36848c2ecf20Sopenharmony_ci	data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
36858c2ecf20Sopenharmony_ci
36868c2ecf20Sopenharmony_ci	if (data_count == 0) {
36878c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
36888c2ecf20Sopenharmony_ci		goto setACLerrorExit;
36898c2ecf20Sopenharmony_ci	}
36908c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
36918c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
36928c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
36938c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
36948c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
36958c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + data_count;
36968c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(data_count);
36978c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
36988c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
36998c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
37008c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
37018c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
37028c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
37038c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
37048c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
37058c2ecf20Sopenharmony_ci	if (rc)
37068c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
37078c2ecf20Sopenharmony_ci
37088c2ecf20Sopenharmony_cisetACLerrorExit:
37098c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
37108c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
37118c2ecf20Sopenharmony_ci		goto setAclRetry;
37128c2ecf20Sopenharmony_ci	return rc;
37138c2ecf20Sopenharmony_ci}
37148c2ecf20Sopenharmony_ci
37158c2ecf20Sopenharmony_ci/* BB fix tabs in this function FIXME BB */
37168c2ecf20Sopenharmony_ciint
37178c2ecf20Sopenharmony_ciCIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
37188c2ecf20Sopenharmony_ci	       const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
37198c2ecf20Sopenharmony_ci{
37208c2ecf20Sopenharmony_ci	int rc = 0;
37218c2ecf20Sopenharmony_ci	struct smb_t2_qfi_req *pSMB = NULL;
37228c2ecf20Sopenharmony_ci	struct smb_t2_qfi_rsp *pSMBr = NULL;
37238c2ecf20Sopenharmony_ci	int bytes_returned;
37248c2ecf20Sopenharmony_ci	__u16 params, byte_count;
37258c2ecf20Sopenharmony_ci
37268c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In GetExtAttr\n");
37278c2ecf20Sopenharmony_ci	if (tcon == NULL)
37288c2ecf20Sopenharmony_ci		return -ENODEV;
37298c2ecf20Sopenharmony_ci
37308c2ecf20Sopenharmony_ciGetExtAttrRetry:
37318c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
37328c2ecf20Sopenharmony_ci			(void **) &pSMBr);
37338c2ecf20Sopenharmony_ci	if (rc)
37348c2ecf20Sopenharmony_ci		return rc;
37358c2ecf20Sopenharmony_ci
37368c2ecf20Sopenharmony_ci	params = 2 /* level */ + 2 /* fid */;
37378c2ecf20Sopenharmony_ci	pSMB->t2.TotalDataCount = 0;
37388c2ecf20Sopenharmony_ci	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
37398c2ecf20Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
37408c2ecf20Sopenharmony_ci	pSMB->t2.MaxDataCount = cpu_to_le16(4000);
37418c2ecf20Sopenharmony_ci	pSMB->t2.MaxSetupCount = 0;
37428c2ecf20Sopenharmony_ci	pSMB->t2.Reserved = 0;
37438c2ecf20Sopenharmony_ci	pSMB->t2.Flags = 0;
37448c2ecf20Sopenharmony_ci	pSMB->t2.Timeout = 0;
37458c2ecf20Sopenharmony_ci	pSMB->t2.Reserved2 = 0;
37468c2ecf20Sopenharmony_ci	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
37478c2ecf20Sopenharmony_ci					       Fid) - 4);
37488c2ecf20Sopenharmony_ci	pSMB->t2.DataCount = 0;
37498c2ecf20Sopenharmony_ci	pSMB->t2.DataOffset = 0;
37508c2ecf20Sopenharmony_ci	pSMB->t2.SetupCount = 1;
37518c2ecf20Sopenharmony_ci	pSMB->t2.Reserved3 = 0;
37528c2ecf20Sopenharmony_ci	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
37538c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
37548c2ecf20Sopenharmony_ci	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
37558c2ecf20Sopenharmony_ci	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
37568c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
37578c2ecf20Sopenharmony_ci	pSMB->Pad = 0;
37588c2ecf20Sopenharmony_ci	pSMB->Fid = netfid;
37598c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
37608c2ecf20Sopenharmony_ci	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
37618c2ecf20Sopenharmony_ci
37628c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
37638c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
37648c2ecf20Sopenharmony_ci	if (rc) {
37658c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
37668c2ecf20Sopenharmony_ci	} else {
37678c2ecf20Sopenharmony_ci		/* decode response */
37688c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
37698c2ecf20Sopenharmony_ci		/* BB also check enough total bytes returned */
37708c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 2)
37718c2ecf20Sopenharmony_ci			/* If rc should we check for EOPNOSUPP and
37728c2ecf20Sopenharmony_ci			   disable the srvino flag? or in caller? */
37738c2ecf20Sopenharmony_ci			rc = -EIO;      /* bad smb */
37748c2ecf20Sopenharmony_ci		else {
37758c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
37768c2ecf20Sopenharmony_ci			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
37778c2ecf20Sopenharmony_ci			struct file_chattr_info *pfinfo;
37788c2ecf20Sopenharmony_ci			/* BB Do we need a cast or hash here ? */
37798c2ecf20Sopenharmony_ci			if (count != 16) {
37808c2ecf20Sopenharmony_ci				cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
37818c2ecf20Sopenharmony_ci				rc = -EIO;
37828c2ecf20Sopenharmony_ci				goto GetExtAttrOut;
37838c2ecf20Sopenharmony_ci			}
37848c2ecf20Sopenharmony_ci			pfinfo = (struct file_chattr_info *)
37858c2ecf20Sopenharmony_ci				 (data_offset + (char *) &pSMBr->hdr.Protocol);
37868c2ecf20Sopenharmony_ci			*pExtAttrBits = le64_to_cpu(pfinfo->mode);
37878c2ecf20Sopenharmony_ci			*pMask = le64_to_cpu(pfinfo->mask);
37888c2ecf20Sopenharmony_ci		}
37898c2ecf20Sopenharmony_ci	}
37908c2ecf20Sopenharmony_ciGetExtAttrOut:
37918c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
37928c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
37938c2ecf20Sopenharmony_ci		goto GetExtAttrRetry;
37948c2ecf20Sopenharmony_ci	return rc;
37958c2ecf20Sopenharmony_ci}
37968c2ecf20Sopenharmony_ci
37978c2ecf20Sopenharmony_ci#endif /* CONFIG_POSIX */
37988c2ecf20Sopenharmony_ci
37998c2ecf20Sopenharmony_ci/*
38008c2ecf20Sopenharmony_ci * Initialize NT TRANSACT SMB into small smb request buffer.  This assumes that
38018c2ecf20Sopenharmony_ci * all NT TRANSACTS that we init here have total parm and data under about 400
38028c2ecf20Sopenharmony_ci * bytes (to fit in small cifs buffer size), which is the case so far, it
38038c2ecf20Sopenharmony_ci * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
38048c2ecf20Sopenharmony_ci * returned setup area) and MaxParameterCount (returned parms size) must be set
38058c2ecf20Sopenharmony_ci * by caller
38068c2ecf20Sopenharmony_ci */
38078c2ecf20Sopenharmony_cistatic int
38088c2ecf20Sopenharmony_cismb_init_nttransact(const __u16 sub_command, const int setup_count,
38098c2ecf20Sopenharmony_ci		   const int parm_len, struct cifs_tcon *tcon,
38108c2ecf20Sopenharmony_ci		   void **ret_buf)
38118c2ecf20Sopenharmony_ci{
38128c2ecf20Sopenharmony_ci	int rc;
38138c2ecf20Sopenharmony_ci	__u32 temp_offset;
38148c2ecf20Sopenharmony_ci	struct smb_com_ntransact_req *pSMB;
38158c2ecf20Sopenharmony_ci
38168c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
38178c2ecf20Sopenharmony_ci				(void **)&pSMB);
38188c2ecf20Sopenharmony_ci	if (rc)
38198c2ecf20Sopenharmony_ci		return rc;
38208c2ecf20Sopenharmony_ci	*ret_buf = (void *)pSMB;
38218c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
38228c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le32(parm_len);
38238c2ecf20Sopenharmony_ci	pSMB->TotalDataCount  = 0;
38248c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
38258c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
38268c2ecf20Sopenharmony_ci	pSMB->DataCount  = pSMB->TotalDataCount;
38278c2ecf20Sopenharmony_ci	temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
38288c2ecf20Sopenharmony_ci			(setup_count * 2) - 4 /* for rfc1001 length itself */;
38298c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le32(temp_offset);
38308c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
38318c2ecf20Sopenharmony_ci	pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
38328c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(sub_command);
38338c2ecf20Sopenharmony_ci	return 0;
38348c2ecf20Sopenharmony_ci}
38358c2ecf20Sopenharmony_ci
38368c2ecf20Sopenharmony_cistatic int
38378c2ecf20Sopenharmony_civalidate_ntransact(char *buf, char **ppparm, char **ppdata,
38388c2ecf20Sopenharmony_ci		   __u32 *pparmlen, __u32 *pdatalen)
38398c2ecf20Sopenharmony_ci{
38408c2ecf20Sopenharmony_ci	char *end_of_smb;
38418c2ecf20Sopenharmony_ci	__u32 data_count, data_offset, parm_count, parm_offset;
38428c2ecf20Sopenharmony_ci	struct smb_com_ntransact_rsp *pSMBr;
38438c2ecf20Sopenharmony_ci	u16 bcc;
38448c2ecf20Sopenharmony_ci
38458c2ecf20Sopenharmony_ci	*pdatalen = 0;
38468c2ecf20Sopenharmony_ci	*pparmlen = 0;
38478c2ecf20Sopenharmony_ci
38488c2ecf20Sopenharmony_ci	if (buf == NULL)
38498c2ecf20Sopenharmony_ci		return -EINVAL;
38508c2ecf20Sopenharmony_ci
38518c2ecf20Sopenharmony_ci	pSMBr = (struct smb_com_ntransact_rsp *)buf;
38528c2ecf20Sopenharmony_ci
38538c2ecf20Sopenharmony_ci	bcc = get_bcc(&pSMBr->hdr);
38548c2ecf20Sopenharmony_ci	end_of_smb = 2 /* sizeof byte count */ + bcc +
38558c2ecf20Sopenharmony_ci			(char *)&pSMBr->ByteCount;
38568c2ecf20Sopenharmony_ci
38578c2ecf20Sopenharmony_ci	data_offset = le32_to_cpu(pSMBr->DataOffset);
38588c2ecf20Sopenharmony_ci	data_count = le32_to_cpu(pSMBr->DataCount);
38598c2ecf20Sopenharmony_ci	parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
38608c2ecf20Sopenharmony_ci	parm_count = le32_to_cpu(pSMBr->ParameterCount);
38618c2ecf20Sopenharmony_ci
38628c2ecf20Sopenharmony_ci	*ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
38638c2ecf20Sopenharmony_ci	*ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
38648c2ecf20Sopenharmony_ci
38658c2ecf20Sopenharmony_ci	/* should we also check that parm and data areas do not overlap? */
38668c2ecf20Sopenharmony_ci	if (*ppparm > end_of_smb) {
38678c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "parms start after end of smb\n");
38688c2ecf20Sopenharmony_ci		return -EINVAL;
38698c2ecf20Sopenharmony_ci	} else if (parm_count + *ppparm > end_of_smb) {
38708c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "parm end after end of smb\n");
38718c2ecf20Sopenharmony_ci		return -EINVAL;
38728c2ecf20Sopenharmony_ci	} else if (*ppdata > end_of_smb) {
38738c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "data starts after end of smb\n");
38748c2ecf20Sopenharmony_ci		return -EINVAL;
38758c2ecf20Sopenharmony_ci	} else if (data_count + *ppdata > end_of_smb) {
38768c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
38778c2ecf20Sopenharmony_ci			 *ppdata, data_count, (data_count + *ppdata),
38788c2ecf20Sopenharmony_ci			 end_of_smb, pSMBr);
38798c2ecf20Sopenharmony_ci		return -EINVAL;
38808c2ecf20Sopenharmony_ci	} else if (parm_count + data_count > bcc) {
38818c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "parm count and data count larger than SMB\n");
38828c2ecf20Sopenharmony_ci		return -EINVAL;
38838c2ecf20Sopenharmony_ci	}
38848c2ecf20Sopenharmony_ci	*pdatalen = data_count;
38858c2ecf20Sopenharmony_ci	*pparmlen = parm_count;
38868c2ecf20Sopenharmony_ci	return 0;
38878c2ecf20Sopenharmony_ci}
38888c2ecf20Sopenharmony_ci
38898c2ecf20Sopenharmony_ci/* Get Security Descriptor (by handle) from remote server for a file or dir */
38908c2ecf20Sopenharmony_ciint
38918c2ecf20Sopenharmony_ciCIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
38928c2ecf20Sopenharmony_ci		  struct cifs_ntsd **acl_inf, __u32 *pbuflen)
38938c2ecf20Sopenharmony_ci{
38948c2ecf20Sopenharmony_ci	int rc = 0;
38958c2ecf20Sopenharmony_ci	int buf_type = 0;
38968c2ecf20Sopenharmony_ci	QUERY_SEC_DESC_REQ *pSMB;
38978c2ecf20Sopenharmony_ci	struct kvec iov[1];
38988c2ecf20Sopenharmony_ci	struct kvec rsp_iov;
38998c2ecf20Sopenharmony_ci
39008c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "GetCifsACL\n");
39018c2ecf20Sopenharmony_ci
39028c2ecf20Sopenharmony_ci	*pbuflen = 0;
39038c2ecf20Sopenharmony_ci	*acl_inf = NULL;
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_ci	rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
39068c2ecf20Sopenharmony_ci			8 /* parm len */, tcon, (void **) &pSMB);
39078c2ecf20Sopenharmony_ci	if (rc)
39088c2ecf20Sopenharmony_ci		return rc;
39098c2ecf20Sopenharmony_ci
39108c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le32(4);
39118c2ecf20Sopenharmony_ci	/* BB TEST with big acls that might need to be e.g. larger than 16K */
39128c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
39138c2ecf20Sopenharmony_ci	pSMB->Fid = fid; /* file handle always le */
39148c2ecf20Sopenharmony_ci	pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
39158c2ecf20Sopenharmony_ci				     CIFS_ACL_DACL);
39168c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
39178c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, 11);
39188c2ecf20Sopenharmony_ci	iov[0].iov_base = (char *)pSMB;
39198c2ecf20Sopenharmony_ci	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
39208c2ecf20Sopenharmony_ci
39218c2ecf20Sopenharmony_ci	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
39228c2ecf20Sopenharmony_ci			  0, &rsp_iov);
39238c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
39248c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
39258c2ecf20Sopenharmony_ci	if (rc) {
39268c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
39278c2ecf20Sopenharmony_ci	} else {                /* decode response */
39288c2ecf20Sopenharmony_ci		__le32 *parm;
39298c2ecf20Sopenharmony_ci		__u32 parm_len;
39308c2ecf20Sopenharmony_ci		__u32 acl_len;
39318c2ecf20Sopenharmony_ci		struct smb_com_ntransact_rsp *pSMBr;
39328c2ecf20Sopenharmony_ci		char *pdata;
39338c2ecf20Sopenharmony_ci
39348c2ecf20Sopenharmony_ci/* validate_nttransact */
39358c2ecf20Sopenharmony_ci		rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
39368c2ecf20Sopenharmony_ci					&pdata, &parm_len, pbuflen);
39378c2ecf20Sopenharmony_ci		if (rc)
39388c2ecf20Sopenharmony_ci			goto qsec_out;
39398c2ecf20Sopenharmony_ci		pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
39408c2ecf20Sopenharmony_ci
39418c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "smb %p parm %p data %p\n",
39428c2ecf20Sopenharmony_ci			 pSMBr, parm, *acl_inf);
39438c2ecf20Sopenharmony_ci
39448c2ecf20Sopenharmony_ci		if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
39458c2ecf20Sopenharmony_ci			rc = -EIO;      /* bad smb */
39468c2ecf20Sopenharmony_ci			*pbuflen = 0;
39478c2ecf20Sopenharmony_ci			goto qsec_out;
39488c2ecf20Sopenharmony_ci		}
39498c2ecf20Sopenharmony_ci
39508c2ecf20Sopenharmony_ci/* BB check that data area is minimum length and as big as acl_len */
39518c2ecf20Sopenharmony_ci
39528c2ecf20Sopenharmony_ci		acl_len = le32_to_cpu(*parm);
39538c2ecf20Sopenharmony_ci		if (acl_len != *pbuflen) {
39548c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "acl length %d does not match %d\n",
39558c2ecf20Sopenharmony_ci				 acl_len, *pbuflen);
39568c2ecf20Sopenharmony_ci			if (*pbuflen > acl_len)
39578c2ecf20Sopenharmony_ci				*pbuflen = acl_len;
39588c2ecf20Sopenharmony_ci		}
39598c2ecf20Sopenharmony_ci
39608c2ecf20Sopenharmony_ci		/* check if buffer is big enough for the acl
39618c2ecf20Sopenharmony_ci		   header followed by the smallest SID */
39628c2ecf20Sopenharmony_ci		if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
39638c2ecf20Sopenharmony_ci		    (*pbuflen >= 64 * 1024)) {
39648c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
39658c2ecf20Sopenharmony_ci			rc = -EINVAL;
39668c2ecf20Sopenharmony_ci			*pbuflen = 0;
39678c2ecf20Sopenharmony_ci		} else {
39688c2ecf20Sopenharmony_ci			*acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
39698c2ecf20Sopenharmony_ci			if (*acl_inf == NULL) {
39708c2ecf20Sopenharmony_ci				*pbuflen = 0;
39718c2ecf20Sopenharmony_ci				rc = -ENOMEM;
39728c2ecf20Sopenharmony_ci			}
39738c2ecf20Sopenharmony_ci		}
39748c2ecf20Sopenharmony_ci	}
39758c2ecf20Sopenharmony_ciqsec_out:
39768c2ecf20Sopenharmony_ci	free_rsp_buf(buf_type, rsp_iov.iov_base);
39778c2ecf20Sopenharmony_ci	return rc;
39788c2ecf20Sopenharmony_ci}
39798c2ecf20Sopenharmony_ci
39808c2ecf20Sopenharmony_ciint
39818c2ecf20Sopenharmony_ciCIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
39828c2ecf20Sopenharmony_ci			struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
39838c2ecf20Sopenharmony_ci{
39848c2ecf20Sopenharmony_ci	__u16 byte_count, param_count, data_count, param_offset, data_offset;
39858c2ecf20Sopenharmony_ci	int rc = 0;
39868c2ecf20Sopenharmony_ci	int bytes_returned = 0;
39878c2ecf20Sopenharmony_ci	SET_SEC_DESC_REQ *pSMB = NULL;
39888c2ecf20Sopenharmony_ci	void *pSMBr;
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_cisetCifsAclRetry:
39918c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
39928c2ecf20Sopenharmony_ci	if (rc)
39938c2ecf20Sopenharmony_ci		return rc;
39948c2ecf20Sopenharmony_ci
39958c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
39968c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
39978c2ecf20Sopenharmony_ci
39988c2ecf20Sopenharmony_ci	param_count = 8;
39998c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
40008c2ecf20Sopenharmony_ci	data_count = acllen;
40018c2ecf20Sopenharmony_ci	data_offset = param_offset + param_count;
40028c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + param_count;
40038c2ecf20Sopenharmony_ci
40048c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le32(data_count);
40058c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
40068c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le32(4);
40078c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le32(16384);
40088c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le32(param_count);
40098c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le32(param_offset);
40108c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
40118c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le32(data_offset);
40128c2ecf20Sopenharmony_ci	pSMB->SetupCount = 0;
40138c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
40148c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
40158c2ecf20Sopenharmony_ci
40168c2ecf20Sopenharmony_ci	pSMB->Fid = fid; /* file handle always le */
40178c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
40188c2ecf20Sopenharmony_ci	pSMB->AclFlags = cpu_to_le32(aclflag);
40198c2ecf20Sopenharmony_ci
40208c2ecf20Sopenharmony_ci	if (pntsd && acllen) {
40218c2ecf20Sopenharmony_ci		memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
40228c2ecf20Sopenharmony_ci				data_offset, pntsd, acllen);
40238c2ecf20Sopenharmony_ci		inc_rfc1001_len(pSMB, byte_count + data_count);
40248c2ecf20Sopenharmony_ci	} else
40258c2ecf20Sopenharmony_ci		inc_rfc1001_len(pSMB, byte_count);
40268c2ecf20Sopenharmony_ci
40278c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
40288c2ecf20Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
40298c2ecf20Sopenharmony_ci
40308c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
40318c2ecf20Sopenharmony_ci		 bytes_returned, rc);
40328c2ecf20Sopenharmony_ci	if (rc)
40338c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
40348c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
40358c2ecf20Sopenharmony_ci
40368c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
40378c2ecf20Sopenharmony_ci		goto setCifsAclRetry;
40388c2ecf20Sopenharmony_ci
40398c2ecf20Sopenharmony_ci	return (rc);
40408c2ecf20Sopenharmony_ci}
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci
40438c2ecf20Sopenharmony_ci/* Legacy Query Path Information call for lookup to old servers such
40448c2ecf20Sopenharmony_ci   as Win9x/WinME */
40458c2ecf20Sopenharmony_ciint
40468c2ecf20Sopenharmony_ciSMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
40478c2ecf20Sopenharmony_ci		    const char *search_name, FILE_ALL_INFO *data,
40488c2ecf20Sopenharmony_ci		    const struct nls_table *nls_codepage, int remap)
40498c2ecf20Sopenharmony_ci{
40508c2ecf20Sopenharmony_ci	QUERY_INFORMATION_REQ *pSMB;
40518c2ecf20Sopenharmony_ci	QUERY_INFORMATION_RSP *pSMBr;
40528c2ecf20Sopenharmony_ci	int rc = 0;
40538c2ecf20Sopenharmony_ci	int bytes_returned;
40548c2ecf20Sopenharmony_ci	int name_len;
40558c2ecf20Sopenharmony_ci
40568c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
40578c2ecf20Sopenharmony_ciQInfRetry:
40588c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
40598c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
40608c2ecf20Sopenharmony_ci	if (rc)
40618c2ecf20Sopenharmony_ci		return rc;
40628c2ecf20Sopenharmony_ci
40638c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
40648c2ecf20Sopenharmony_ci		name_len =
40658c2ecf20Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName,
40668c2ecf20Sopenharmony_ci					   search_name, PATH_MAX, nls_codepage,
40678c2ecf20Sopenharmony_ci					   remap);
40688c2ecf20Sopenharmony_ci		name_len++;     /* trailing null */
40698c2ecf20Sopenharmony_ci		name_len *= 2;
40708c2ecf20Sopenharmony_ci	} else {
40718c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, search_name);
40728c2ecf20Sopenharmony_ci	}
40738c2ecf20Sopenharmony_ci	pSMB->BufferFormat = 0x04;
40748c2ecf20Sopenharmony_ci	name_len++; /* account for buffer type byte */
40758c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, (__u16)name_len);
40768c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len);
40778c2ecf20Sopenharmony_ci
40788c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
40798c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
40808c2ecf20Sopenharmony_ci	if (rc) {
40818c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
40828c2ecf20Sopenharmony_ci	} else if (data) {
40838c2ecf20Sopenharmony_ci		struct timespec64 ts;
40848c2ecf20Sopenharmony_ci		__u32 time = le32_to_cpu(pSMBr->last_write_time);
40858c2ecf20Sopenharmony_ci
40868c2ecf20Sopenharmony_ci		/* decode response */
40878c2ecf20Sopenharmony_ci		/* BB FIXME - add time zone adjustment BB */
40888c2ecf20Sopenharmony_ci		memset(data, 0, sizeof(FILE_ALL_INFO));
40898c2ecf20Sopenharmony_ci		ts.tv_nsec = 0;
40908c2ecf20Sopenharmony_ci		ts.tv_sec = time;
40918c2ecf20Sopenharmony_ci		/* decode time fields */
40928c2ecf20Sopenharmony_ci		data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
40938c2ecf20Sopenharmony_ci		data->LastWriteTime = data->ChangeTime;
40948c2ecf20Sopenharmony_ci		data->LastAccessTime = 0;
40958c2ecf20Sopenharmony_ci		data->AllocationSize =
40968c2ecf20Sopenharmony_ci			cpu_to_le64(le32_to_cpu(pSMBr->size));
40978c2ecf20Sopenharmony_ci		data->EndOfFile = data->AllocationSize;
40988c2ecf20Sopenharmony_ci		data->Attributes =
40998c2ecf20Sopenharmony_ci			cpu_to_le32(le16_to_cpu(pSMBr->attr));
41008c2ecf20Sopenharmony_ci	} else
41018c2ecf20Sopenharmony_ci		rc = -EIO; /* bad buffer passed in */
41028c2ecf20Sopenharmony_ci
41038c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
41048c2ecf20Sopenharmony_ci
41058c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
41068c2ecf20Sopenharmony_ci		goto QInfRetry;
41078c2ecf20Sopenharmony_ci
41088c2ecf20Sopenharmony_ci	return rc;
41098c2ecf20Sopenharmony_ci}
41108c2ecf20Sopenharmony_ci
41118c2ecf20Sopenharmony_ciint
41128c2ecf20Sopenharmony_ciCIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
41138c2ecf20Sopenharmony_ci		 u16 netfid, FILE_ALL_INFO *pFindData)
41148c2ecf20Sopenharmony_ci{
41158c2ecf20Sopenharmony_ci	struct smb_t2_qfi_req *pSMB = NULL;
41168c2ecf20Sopenharmony_ci	struct smb_t2_qfi_rsp *pSMBr = NULL;
41178c2ecf20Sopenharmony_ci	int rc = 0;
41188c2ecf20Sopenharmony_ci	int bytes_returned;
41198c2ecf20Sopenharmony_ci	__u16 params, byte_count;
41208c2ecf20Sopenharmony_ci
41218c2ecf20Sopenharmony_ciQFileInfoRetry:
41228c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
41238c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
41248c2ecf20Sopenharmony_ci	if (rc)
41258c2ecf20Sopenharmony_ci		return rc;
41268c2ecf20Sopenharmony_ci
41278c2ecf20Sopenharmony_ci	params = 2 /* level */ + 2 /* fid */;
41288c2ecf20Sopenharmony_ci	pSMB->t2.TotalDataCount = 0;
41298c2ecf20Sopenharmony_ci	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
41308c2ecf20Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
41318c2ecf20Sopenharmony_ci	pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
41328c2ecf20Sopenharmony_ci	pSMB->t2.MaxSetupCount = 0;
41338c2ecf20Sopenharmony_ci	pSMB->t2.Reserved = 0;
41348c2ecf20Sopenharmony_ci	pSMB->t2.Flags = 0;
41358c2ecf20Sopenharmony_ci	pSMB->t2.Timeout = 0;
41368c2ecf20Sopenharmony_ci	pSMB->t2.Reserved2 = 0;
41378c2ecf20Sopenharmony_ci	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
41388c2ecf20Sopenharmony_ci					       Fid) - 4);
41398c2ecf20Sopenharmony_ci	pSMB->t2.DataCount = 0;
41408c2ecf20Sopenharmony_ci	pSMB->t2.DataOffset = 0;
41418c2ecf20Sopenharmony_ci	pSMB->t2.SetupCount = 1;
41428c2ecf20Sopenharmony_ci	pSMB->t2.Reserved3 = 0;
41438c2ecf20Sopenharmony_ci	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
41448c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
41458c2ecf20Sopenharmony_ci	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
41468c2ecf20Sopenharmony_ci	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
41478c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
41488c2ecf20Sopenharmony_ci	pSMB->Pad = 0;
41498c2ecf20Sopenharmony_ci	pSMB->Fid = netfid;
41508c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
41518c2ecf20Sopenharmony_ci	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
41528c2ecf20Sopenharmony_ci
41538c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
41548c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
41558c2ecf20Sopenharmony_ci	if (rc) {
41568c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
41578c2ecf20Sopenharmony_ci	} else {		/* decode response */
41588c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
41598c2ecf20Sopenharmony_ci
41608c2ecf20Sopenharmony_ci		if (rc) /* BB add auto retry on EOPNOTSUPP? */
41618c2ecf20Sopenharmony_ci			rc = -EIO;
41628c2ecf20Sopenharmony_ci		else if (get_bcc(&pSMBr->hdr) < 40)
41638c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
41648c2ecf20Sopenharmony_ci		else if (pFindData) {
41658c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
41668c2ecf20Sopenharmony_ci			memcpy((char *) pFindData,
41678c2ecf20Sopenharmony_ci			       (char *) &pSMBr->hdr.Protocol +
41688c2ecf20Sopenharmony_ci			       data_offset, sizeof(FILE_ALL_INFO));
41698c2ecf20Sopenharmony_ci		} else
41708c2ecf20Sopenharmony_ci		    rc = -ENOMEM;
41718c2ecf20Sopenharmony_ci	}
41728c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
41738c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
41748c2ecf20Sopenharmony_ci		goto QFileInfoRetry;
41758c2ecf20Sopenharmony_ci
41768c2ecf20Sopenharmony_ci	return rc;
41778c2ecf20Sopenharmony_ci}
41788c2ecf20Sopenharmony_ci
41798c2ecf20Sopenharmony_ciint
41808c2ecf20Sopenharmony_ciCIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
41818c2ecf20Sopenharmony_ci		 const char *search_name, FILE_ALL_INFO *data,
41828c2ecf20Sopenharmony_ci		 int legacy /* old style infolevel */,
41838c2ecf20Sopenharmony_ci		 const struct nls_table *nls_codepage, int remap)
41848c2ecf20Sopenharmony_ci{
41858c2ecf20Sopenharmony_ci	/* level 263 SMB_QUERY_FILE_ALL_INFO */
41868c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
41878c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
41888c2ecf20Sopenharmony_ci	int rc = 0;
41898c2ecf20Sopenharmony_ci	int bytes_returned;
41908c2ecf20Sopenharmony_ci	int name_len;
41918c2ecf20Sopenharmony_ci	__u16 params, byte_count;
41928c2ecf20Sopenharmony_ci
41938c2ecf20Sopenharmony_ci	/* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
41948c2ecf20Sopenharmony_ciQPathInfoRetry:
41958c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
41968c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
41978c2ecf20Sopenharmony_ci	if (rc)
41988c2ecf20Sopenharmony_ci		return rc;
41998c2ecf20Sopenharmony_ci
42008c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
42018c2ecf20Sopenharmony_ci		name_len =
42028c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
42038c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
42048c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
42058c2ecf20Sopenharmony_ci		name_len *= 2;
42068c2ecf20Sopenharmony_ci	} else {
42078c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, search_name);
42088c2ecf20Sopenharmony_ci	}
42098c2ecf20Sopenharmony_ci
42108c2ecf20Sopenharmony_ci	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
42118c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
42128c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
42138c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
42148c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
42158c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
42168c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
42178c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
42188c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
42198c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
42208c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
42218c2ecf20Sopenharmony_ci	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
42228c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
42238c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
42248c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
42258c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
42268c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
42278c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
42288c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
42298c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
42308c2ecf20Sopenharmony_ci	if (legacy)
42318c2ecf20Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
42328c2ecf20Sopenharmony_ci	else
42338c2ecf20Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
42348c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
42358c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
42368c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
42378c2ecf20Sopenharmony_ci
42388c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
42398c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
42408c2ecf20Sopenharmony_ci	if (rc) {
42418c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
42428c2ecf20Sopenharmony_ci	} else {		/* decode response */
42438c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
42448c2ecf20Sopenharmony_ci
42458c2ecf20Sopenharmony_ci		if (rc) /* BB add auto retry on EOPNOTSUPP? */
42468c2ecf20Sopenharmony_ci			rc = -EIO;
42478c2ecf20Sopenharmony_ci		else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
42488c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
42498c2ecf20Sopenharmony_ci		else if (legacy && get_bcc(&pSMBr->hdr) < 24)
42508c2ecf20Sopenharmony_ci			rc = -EIO;  /* 24 or 26 expected but we do not read
42518c2ecf20Sopenharmony_ci					last field */
42528c2ecf20Sopenharmony_ci		else if (data) {
42538c2ecf20Sopenharmony_ci			int size;
42548c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
42558c2ecf20Sopenharmony_ci
42568c2ecf20Sopenharmony_ci			/*
42578c2ecf20Sopenharmony_ci			 * On legacy responses we do not read the last field,
42588c2ecf20Sopenharmony_ci			 * EAsize, fortunately since it varies by subdialect and
42598c2ecf20Sopenharmony_ci			 * also note it differs on Set vs Get, ie two bytes or 4
42608c2ecf20Sopenharmony_ci			 * bytes depending but we don't care here.
42618c2ecf20Sopenharmony_ci			 */
42628c2ecf20Sopenharmony_ci			if (legacy)
42638c2ecf20Sopenharmony_ci				size = sizeof(FILE_INFO_STANDARD);
42648c2ecf20Sopenharmony_ci			else
42658c2ecf20Sopenharmony_ci				size = sizeof(FILE_ALL_INFO);
42668c2ecf20Sopenharmony_ci			memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
42678c2ecf20Sopenharmony_ci			       data_offset, size);
42688c2ecf20Sopenharmony_ci		} else
42698c2ecf20Sopenharmony_ci		    rc = -ENOMEM;
42708c2ecf20Sopenharmony_ci	}
42718c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
42728c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
42738c2ecf20Sopenharmony_ci		goto QPathInfoRetry;
42748c2ecf20Sopenharmony_ci
42758c2ecf20Sopenharmony_ci	return rc;
42768c2ecf20Sopenharmony_ci}
42778c2ecf20Sopenharmony_ci
42788c2ecf20Sopenharmony_ciint
42798c2ecf20Sopenharmony_ciCIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
42808c2ecf20Sopenharmony_ci		 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
42818c2ecf20Sopenharmony_ci{
42828c2ecf20Sopenharmony_ci	struct smb_t2_qfi_req *pSMB = NULL;
42838c2ecf20Sopenharmony_ci	struct smb_t2_qfi_rsp *pSMBr = NULL;
42848c2ecf20Sopenharmony_ci	int rc = 0;
42858c2ecf20Sopenharmony_ci	int bytes_returned;
42868c2ecf20Sopenharmony_ci	__u16 params, byte_count;
42878c2ecf20Sopenharmony_ci
42888c2ecf20Sopenharmony_ciUnixQFileInfoRetry:
42898c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
42908c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
42918c2ecf20Sopenharmony_ci	if (rc)
42928c2ecf20Sopenharmony_ci		return rc;
42938c2ecf20Sopenharmony_ci
42948c2ecf20Sopenharmony_ci	params = 2 /* level */ + 2 /* fid */;
42958c2ecf20Sopenharmony_ci	pSMB->t2.TotalDataCount = 0;
42968c2ecf20Sopenharmony_ci	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
42978c2ecf20Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
42988c2ecf20Sopenharmony_ci	pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
42998c2ecf20Sopenharmony_ci	pSMB->t2.MaxSetupCount = 0;
43008c2ecf20Sopenharmony_ci	pSMB->t2.Reserved = 0;
43018c2ecf20Sopenharmony_ci	pSMB->t2.Flags = 0;
43028c2ecf20Sopenharmony_ci	pSMB->t2.Timeout = 0;
43038c2ecf20Sopenharmony_ci	pSMB->t2.Reserved2 = 0;
43048c2ecf20Sopenharmony_ci	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
43058c2ecf20Sopenharmony_ci					       Fid) - 4);
43068c2ecf20Sopenharmony_ci	pSMB->t2.DataCount = 0;
43078c2ecf20Sopenharmony_ci	pSMB->t2.DataOffset = 0;
43088c2ecf20Sopenharmony_ci	pSMB->t2.SetupCount = 1;
43098c2ecf20Sopenharmony_ci	pSMB->t2.Reserved3 = 0;
43108c2ecf20Sopenharmony_ci	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
43118c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
43128c2ecf20Sopenharmony_ci	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
43138c2ecf20Sopenharmony_ci	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
43148c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
43158c2ecf20Sopenharmony_ci	pSMB->Pad = 0;
43168c2ecf20Sopenharmony_ci	pSMB->Fid = netfid;
43178c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
43188c2ecf20Sopenharmony_ci	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
43198c2ecf20Sopenharmony_ci
43208c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
43218c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
43228c2ecf20Sopenharmony_ci	if (rc) {
43238c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
43248c2ecf20Sopenharmony_ci	} else {		/* decode response */
43258c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
43268c2ecf20Sopenharmony_ci
43278c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
43288c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
43298c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
43308c2ecf20Sopenharmony_ci		} else {
43318c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
43328c2ecf20Sopenharmony_ci			memcpy((char *) pFindData,
43338c2ecf20Sopenharmony_ci			       (char *) &pSMBr->hdr.Protocol +
43348c2ecf20Sopenharmony_ci			       data_offset,
43358c2ecf20Sopenharmony_ci			       sizeof(FILE_UNIX_BASIC_INFO));
43368c2ecf20Sopenharmony_ci		}
43378c2ecf20Sopenharmony_ci	}
43388c2ecf20Sopenharmony_ci
43398c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
43408c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
43418c2ecf20Sopenharmony_ci		goto UnixQFileInfoRetry;
43428c2ecf20Sopenharmony_ci
43438c2ecf20Sopenharmony_ci	return rc;
43448c2ecf20Sopenharmony_ci}
43458c2ecf20Sopenharmony_ci
43468c2ecf20Sopenharmony_ciint
43478c2ecf20Sopenharmony_ciCIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
43488c2ecf20Sopenharmony_ci		     const unsigned char *searchName,
43498c2ecf20Sopenharmony_ci		     FILE_UNIX_BASIC_INFO *pFindData,
43508c2ecf20Sopenharmony_ci		     const struct nls_table *nls_codepage, int remap)
43518c2ecf20Sopenharmony_ci{
43528c2ecf20Sopenharmony_ci/* SMB_QUERY_FILE_UNIX_BASIC */
43538c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
43548c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
43558c2ecf20Sopenharmony_ci	int rc = 0;
43568c2ecf20Sopenharmony_ci	int bytes_returned = 0;
43578c2ecf20Sopenharmony_ci	int name_len;
43588c2ecf20Sopenharmony_ci	__u16 params, byte_count;
43598c2ecf20Sopenharmony_ci
43608c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
43618c2ecf20Sopenharmony_ciUnixQPathInfoRetry:
43628c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
43638c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
43648c2ecf20Sopenharmony_ci	if (rc)
43658c2ecf20Sopenharmony_ci		return rc;
43668c2ecf20Sopenharmony_ci
43678c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
43688c2ecf20Sopenharmony_ci		name_len =
43698c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
43708c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
43718c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
43728c2ecf20Sopenharmony_ci		name_len *= 2;
43738c2ecf20Sopenharmony_ci	} else {
43748c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, searchName);
43758c2ecf20Sopenharmony_ci	}
43768c2ecf20Sopenharmony_ci
43778c2ecf20Sopenharmony_ci	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
43788c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
43798c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
43808c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
43818c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
43828c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
43838c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
43848c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
43858c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
43868c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
43878c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
43888c2ecf20Sopenharmony_ci	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
43898c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
43908c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
43918c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
43928c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
43938c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
43948c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
43958c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
43968c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
43978c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
43988c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
43998c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
44008c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
44018c2ecf20Sopenharmony_ci
44028c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
44038c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
44048c2ecf20Sopenharmony_ci	if (rc) {
44058c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
44068c2ecf20Sopenharmony_ci	} else {		/* decode response */
44078c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
44088c2ecf20Sopenharmony_ci
44098c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
44108c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
44118c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
44128c2ecf20Sopenharmony_ci		} else {
44138c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
44148c2ecf20Sopenharmony_ci			memcpy((char *) pFindData,
44158c2ecf20Sopenharmony_ci			       (char *) &pSMBr->hdr.Protocol +
44168c2ecf20Sopenharmony_ci			       data_offset,
44178c2ecf20Sopenharmony_ci			       sizeof(FILE_UNIX_BASIC_INFO));
44188c2ecf20Sopenharmony_ci		}
44198c2ecf20Sopenharmony_ci	}
44208c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
44218c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
44228c2ecf20Sopenharmony_ci		goto UnixQPathInfoRetry;
44238c2ecf20Sopenharmony_ci
44248c2ecf20Sopenharmony_ci	return rc;
44258c2ecf20Sopenharmony_ci}
44268c2ecf20Sopenharmony_ci
44278c2ecf20Sopenharmony_ci/* xid, tcon, searchName and codepage are input parms, rest are returned */
44288c2ecf20Sopenharmony_ciint
44298c2ecf20Sopenharmony_ciCIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
44308c2ecf20Sopenharmony_ci	      const char *searchName, struct cifs_sb_info *cifs_sb,
44318c2ecf20Sopenharmony_ci	      __u16 *pnetfid, __u16 search_flags,
44328c2ecf20Sopenharmony_ci	      struct cifs_search_info *psrch_inf, bool msearch)
44338c2ecf20Sopenharmony_ci{
44348c2ecf20Sopenharmony_ci/* level 257 SMB_ */
44358c2ecf20Sopenharmony_ci	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
44368c2ecf20Sopenharmony_ci	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
44378c2ecf20Sopenharmony_ci	T2_FFIRST_RSP_PARMS *parms;
44388c2ecf20Sopenharmony_ci	int rc = 0;
44398c2ecf20Sopenharmony_ci	int bytes_returned = 0;
44408c2ecf20Sopenharmony_ci	int name_len, remap;
44418c2ecf20Sopenharmony_ci	__u16 params, byte_count;
44428c2ecf20Sopenharmony_ci	struct nls_table *nls_codepage;
44438c2ecf20Sopenharmony_ci
44448c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
44458c2ecf20Sopenharmony_ci
44468c2ecf20Sopenharmony_cifindFirstRetry:
44478c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
44488c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
44498c2ecf20Sopenharmony_ci	if (rc)
44508c2ecf20Sopenharmony_ci		return rc;
44518c2ecf20Sopenharmony_ci
44528c2ecf20Sopenharmony_ci	nls_codepage = cifs_sb->local_nls;
44538c2ecf20Sopenharmony_ci	remap = cifs_remap(cifs_sb);
44548c2ecf20Sopenharmony_ci
44558c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
44568c2ecf20Sopenharmony_ci		name_len =
44578c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
44588c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
44598c2ecf20Sopenharmony_ci		/* We can not add the asterik earlier in case
44608c2ecf20Sopenharmony_ci		it got remapped to 0xF03A as if it were part of the
44618c2ecf20Sopenharmony_ci		directory name instead of a wildcard */
44628c2ecf20Sopenharmony_ci		name_len *= 2;
44638c2ecf20Sopenharmony_ci		if (msearch) {
44648c2ecf20Sopenharmony_ci			pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
44658c2ecf20Sopenharmony_ci			pSMB->FileName[name_len+1] = 0;
44668c2ecf20Sopenharmony_ci			pSMB->FileName[name_len+2] = '*';
44678c2ecf20Sopenharmony_ci			pSMB->FileName[name_len+3] = 0;
44688c2ecf20Sopenharmony_ci			name_len += 4; /* now the trailing null */
44698c2ecf20Sopenharmony_ci			/* null terminate just in case */
44708c2ecf20Sopenharmony_ci			pSMB->FileName[name_len] = 0;
44718c2ecf20Sopenharmony_ci			pSMB->FileName[name_len+1] = 0;
44728c2ecf20Sopenharmony_ci			name_len += 2;
44738c2ecf20Sopenharmony_ci		}
44748c2ecf20Sopenharmony_ci	} else {
44758c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, searchName);
44768c2ecf20Sopenharmony_ci		if (msearch) {
44778c2ecf20Sopenharmony_ci			if (WARN_ON_ONCE(name_len > PATH_MAX-2))
44788c2ecf20Sopenharmony_ci				name_len = PATH_MAX-2;
44798c2ecf20Sopenharmony_ci			/* overwrite nul byte */
44808c2ecf20Sopenharmony_ci			pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
44818c2ecf20Sopenharmony_ci			pSMB->FileName[name_len] = '*';
44828c2ecf20Sopenharmony_ci			pSMB->FileName[name_len+1] = 0;
44838c2ecf20Sopenharmony_ci			name_len += 2;
44848c2ecf20Sopenharmony_ci		}
44858c2ecf20Sopenharmony_ci	}
44868c2ecf20Sopenharmony_ci
44878c2ecf20Sopenharmony_ci	params = 12 + name_len /* includes null */ ;
44888c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;	/* no EAs */
44898c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(10);
44908c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
44918c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
44928c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
44938c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
44948c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
44958c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
44968c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
44978c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
44988c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
44998c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(
45008c2ecf20Sopenharmony_ci	      offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
45018c2ecf20Sopenharmony_ci		- 4);
45028c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
45038c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
45048c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */
45058c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
45068c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
45078c2ecf20Sopenharmony_ci	pSMB->SearchAttributes =
45088c2ecf20Sopenharmony_ci	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
45098c2ecf20Sopenharmony_ci			ATTR_DIRECTORY);
45108c2ecf20Sopenharmony_ci	pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
45118c2ecf20Sopenharmony_ci	pSMB->SearchFlags = cpu_to_le16(search_flags);
45128c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
45138c2ecf20Sopenharmony_ci
45148c2ecf20Sopenharmony_ci	/* BB what should we set StorageType to? Does it matter? BB */
45158c2ecf20Sopenharmony_ci	pSMB->SearchStorageType = 0;
45168c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
45178c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
45188c2ecf20Sopenharmony_ci
45198c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
45208c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
45218c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
45228c2ecf20Sopenharmony_ci
45238c2ecf20Sopenharmony_ci	if (rc) {/* BB add logic to retry regular search if Unix search
45248c2ecf20Sopenharmony_ci			rejected unexpectedly by server */
45258c2ecf20Sopenharmony_ci		/* BB Add code to handle unsupported level rc */
45268c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
45278c2ecf20Sopenharmony_ci
45288c2ecf20Sopenharmony_ci		cifs_buf_release(pSMB);
45298c2ecf20Sopenharmony_ci
45308c2ecf20Sopenharmony_ci		/* BB eventually could optimize out free and realloc of buf */
45318c2ecf20Sopenharmony_ci		/*    for this case */
45328c2ecf20Sopenharmony_ci		if (rc == -EAGAIN)
45338c2ecf20Sopenharmony_ci			goto findFirstRetry;
45348c2ecf20Sopenharmony_ci	} else { /* decode response */
45358c2ecf20Sopenharmony_ci		/* BB remember to free buffer if error BB */
45368c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
45378c2ecf20Sopenharmony_ci		if (rc == 0) {
45388c2ecf20Sopenharmony_ci			unsigned int lnoff;
45398c2ecf20Sopenharmony_ci
45408c2ecf20Sopenharmony_ci			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
45418c2ecf20Sopenharmony_ci				psrch_inf->unicode = true;
45428c2ecf20Sopenharmony_ci			else
45438c2ecf20Sopenharmony_ci				psrch_inf->unicode = false;
45448c2ecf20Sopenharmony_ci
45458c2ecf20Sopenharmony_ci			psrch_inf->ntwrk_buf_start = (char *)pSMBr;
45468c2ecf20Sopenharmony_ci			psrch_inf->smallBuf = false;
45478c2ecf20Sopenharmony_ci			psrch_inf->srch_entries_start =
45488c2ecf20Sopenharmony_ci				(char *) &pSMBr->hdr.Protocol +
45498c2ecf20Sopenharmony_ci					le16_to_cpu(pSMBr->t2.DataOffset);
45508c2ecf20Sopenharmony_ci			parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
45518c2ecf20Sopenharmony_ci			       le16_to_cpu(pSMBr->t2.ParameterOffset));
45528c2ecf20Sopenharmony_ci
45538c2ecf20Sopenharmony_ci			if (parms->EndofSearch)
45548c2ecf20Sopenharmony_ci				psrch_inf->endOfSearch = true;
45558c2ecf20Sopenharmony_ci			else
45568c2ecf20Sopenharmony_ci				psrch_inf->endOfSearch = false;
45578c2ecf20Sopenharmony_ci
45588c2ecf20Sopenharmony_ci			psrch_inf->entries_in_buffer =
45598c2ecf20Sopenharmony_ci					le16_to_cpu(parms->SearchCount);
45608c2ecf20Sopenharmony_ci			psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
45618c2ecf20Sopenharmony_ci				psrch_inf->entries_in_buffer;
45628c2ecf20Sopenharmony_ci			lnoff = le16_to_cpu(parms->LastNameOffset);
45638c2ecf20Sopenharmony_ci			if (CIFSMaxBufSize < lnoff) {
45648c2ecf20Sopenharmony_ci				cifs_dbg(VFS, "ignoring corrupt resume name\n");
45658c2ecf20Sopenharmony_ci				psrch_inf->last_entry = NULL;
45668c2ecf20Sopenharmony_ci				return rc;
45678c2ecf20Sopenharmony_ci			}
45688c2ecf20Sopenharmony_ci
45698c2ecf20Sopenharmony_ci			psrch_inf->last_entry = psrch_inf->srch_entries_start +
45708c2ecf20Sopenharmony_ci							lnoff;
45718c2ecf20Sopenharmony_ci
45728c2ecf20Sopenharmony_ci			if (pnetfid)
45738c2ecf20Sopenharmony_ci				*pnetfid = parms->SearchHandle;
45748c2ecf20Sopenharmony_ci		} else {
45758c2ecf20Sopenharmony_ci			cifs_buf_release(pSMB);
45768c2ecf20Sopenharmony_ci		}
45778c2ecf20Sopenharmony_ci	}
45788c2ecf20Sopenharmony_ci
45798c2ecf20Sopenharmony_ci	return rc;
45808c2ecf20Sopenharmony_ci}
45818c2ecf20Sopenharmony_ci
45828c2ecf20Sopenharmony_ciint CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
45838c2ecf20Sopenharmony_ci		 __u16 searchHandle, __u16 search_flags,
45848c2ecf20Sopenharmony_ci		 struct cifs_search_info *psrch_inf)
45858c2ecf20Sopenharmony_ci{
45868c2ecf20Sopenharmony_ci	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
45878c2ecf20Sopenharmony_ci	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
45888c2ecf20Sopenharmony_ci	T2_FNEXT_RSP_PARMS *parms;
45898c2ecf20Sopenharmony_ci	char *response_data;
45908c2ecf20Sopenharmony_ci	int rc = 0;
45918c2ecf20Sopenharmony_ci	int bytes_returned;
45928c2ecf20Sopenharmony_ci	unsigned int name_len;
45938c2ecf20Sopenharmony_ci	__u16 params, byte_count;
45948c2ecf20Sopenharmony_ci
45958c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In FindNext\n");
45968c2ecf20Sopenharmony_ci
45978c2ecf20Sopenharmony_ci	if (psrch_inf->endOfSearch)
45988c2ecf20Sopenharmony_ci		return -ENOENT;
45998c2ecf20Sopenharmony_ci
46008c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
46018c2ecf20Sopenharmony_ci		(void **) &pSMBr);
46028c2ecf20Sopenharmony_ci	if (rc)
46038c2ecf20Sopenharmony_ci		return rc;
46048c2ecf20Sopenharmony_ci
46058c2ecf20Sopenharmony_ci	params = 14; /* includes 2 bytes of null string, converted to LE below*/
46068c2ecf20Sopenharmony_ci	byte_count = 0;
46078c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;       /* no EAs */
46088c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(8);
46098c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
46108c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
46118c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
46128c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
46138c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
46148c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
46158c2ecf20Sopenharmony_ci	pSMB->ParameterOffset =  cpu_to_le16(
46168c2ecf20Sopenharmony_ci	      offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
46178c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
46188c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
46198c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
46208c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
46218c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
46228c2ecf20Sopenharmony_ci	pSMB->SearchHandle = searchHandle;      /* always kept as le */
46238c2ecf20Sopenharmony_ci	pSMB->SearchCount =
46248c2ecf20Sopenharmony_ci		cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
46258c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
46268c2ecf20Sopenharmony_ci	pSMB->ResumeKey = psrch_inf->resume_key;
46278c2ecf20Sopenharmony_ci	pSMB->SearchFlags = cpu_to_le16(search_flags);
46288c2ecf20Sopenharmony_ci
46298c2ecf20Sopenharmony_ci	name_len = psrch_inf->resume_name_len;
46308c2ecf20Sopenharmony_ci	params += name_len;
46318c2ecf20Sopenharmony_ci	if (name_len < PATH_MAX) {
46328c2ecf20Sopenharmony_ci		memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
46338c2ecf20Sopenharmony_ci		byte_count += name_len;
46348c2ecf20Sopenharmony_ci		/* 14 byte parm len above enough for 2 byte null terminator */
46358c2ecf20Sopenharmony_ci		pSMB->ResumeFileName[name_len] = 0;
46368c2ecf20Sopenharmony_ci		pSMB->ResumeFileName[name_len+1] = 0;
46378c2ecf20Sopenharmony_ci	} else {
46388c2ecf20Sopenharmony_ci		rc = -EINVAL;
46398c2ecf20Sopenharmony_ci		goto FNext2_err_exit;
46408c2ecf20Sopenharmony_ci	}
46418c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
46428c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
46438c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
46448c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
46458c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
46468c2ecf20Sopenharmony_ci
46478c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
46488c2ecf20Sopenharmony_ci			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
46498c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
46508c2ecf20Sopenharmony_ci	if (rc) {
46518c2ecf20Sopenharmony_ci		if (rc == -EBADF) {
46528c2ecf20Sopenharmony_ci			psrch_inf->endOfSearch = true;
46538c2ecf20Sopenharmony_ci			cifs_buf_release(pSMB);
46548c2ecf20Sopenharmony_ci			rc = 0; /* search probably was closed at end of search*/
46558c2ecf20Sopenharmony_ci		} else
46568c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "FindNext returned = %d\n", rc);
46578c2ecf20Sopenharmony_ci	} else {                /* decode response */
46588c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
46598c2ecf20Sopenharmony_ci
46608c2ecf20Sopenharmony_ci		if (rc == 0) {
46618c2ecf20Sopenharmony_ci			unsigned int lnoff;
46628c2ecf20Sopenharmony_ci
46638c2ecf20Sopenharmony_ci			/* BB fixme add lock for file (srch_info) struct here */
46648c2ecf20Sopenharmony_ci			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
46658c2ecf20Sopenharmony_ci				psrch_inf->unicode = true;
46668c2ecf20Sopenharmony_ci			else
46678c2ecf20Sopenharmony_ci				psrch_inf->unicode = false;
46688c2ecf20Sopenharmony_ci			response_data = (char *) &pSMBr->hdr.Protocol +
46698c2ecf20Sopenharmony_ci			       le16_to_cpu(pSMBr->t2.ParameterOffset);
46708c2ecf20Sopenharmony_ci			parms = (T2_FNEXT_RSP_PARMS *)response_data;
46718c2ecf20Sopenharmony_ci			response_data = (char *)&pSMBr->hdr.Protocol +
46728c2ecf20Sopenharmony_ci				le16_to_cpu(pSMBr->t2.DataOffset);
46738c2ecf20Sopenharmony_ci			if (psrch_inf->smallBuf)
46748c2ecf20Sopenharmony_ci				cifs_small_buf_release(
46758c2ecf20Sopenharmony_ci					psrch_inf->ntwrk_buf_start);
46768c2ecf20Sopenharmony_ci			else
46778c2ecf20Sopenharmony_ci				cifs_buf_release(psrch_inf->ntwrk_buf_start);
46788c2ecf20Sopenharmony_ci			psrch_inf->srch_entries_start = response_data;
46798c2ecf20Sopenharmony_ci			psrch_inf->ntwrk_buf_start = (char *)pSMB;
46808c2ecf20Sopenharmony_ci			psrch_inf->smallBuf = false;
46818c2ecf20Sopenharmony_ci			if (parms->EndofSearch)
46828c2ecf20Sopenharmony_ci				psrch_inf->endOfSearch = true;
46838c2ecf20Sopenharmony_ci			else
46848c2ecf20Sopenharmony_ci				psrch_inf->endOfSearch = false;
46858c2ecf20Sopenharmony_ci			psrch_inf->entries_in_buffer =
46868c2ecf20Sopenharmony_ci						le16_to_cpu(parms->SearchCount);
46878c2ecf20Sopenharmony_ci			psrch_inf->index_of_last_entry +=
46888c2ecf20Sopenharmony_ci				psrch_inf->entries_in_buffer;
46898c2ecf20Sopenharmony_ci			lnoff = le16_to_cpu(parms->LastNameOffset);
46908c2ecf20Sopenharmony_ci			if (CIFSMaxBufSize < lnoff) {
46918c2ecf20Sopenharmony_ci				cifs_dbg(VFS, "ignoring corrupt resume name\n");
46928c2ecf20Sopenharmony_ci				psrch_inf->last_entry = NULL;
46938c2ecf20Sopenharmony_ci				return rc;
46948c2ecf20Sopenharmony_ci			} else
46958c2ecf20Sopenharmony_ci				psrch_inf->last_entry =
46968c2ecf20Sopenharmony_ci					psrch_inf->srch_entries_start + lnoff;
46978c2ecf20Sopenharmony_ci
46988c2ecf20Sopenharmony_ci/*  cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
46998c2ecf20Sopenharmony_ci    psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
47008c2ecf20Sopenharmony_ci
47018c2ecf20Sopenharmony_ci			/* BB fixme add unlock here */
47028c2ecf20Sopenharmony_ci		}
47038c2ecf20Sopenharmony_ci
47048c2ecf20Sopenharmony_ci	}
47058c2ecf20Sopenharmony_ci
47068c2ecf20Sopenharmony_ci	/* BB On error, should we leave previous search buf (and count and
47078c2ecf20Sopenharmony_ci	last entry fields) intact or free the previous one? */
47088c2ecf20Sopenharmony_ci
47098c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
47108c2ecf20Sopenharmony_ci	since file handle passed in no longer valid */
47118c2ecf20Sopenharmony_ciFNext2_err_exit:
47128c2ecf20Sopenharmony_ci	if (rc != 0)
47138c2ecf20Sopenharmony_ci		cifs_buf_release(pSMB);
47148c2ecf20Sopenharmony_ci	return rc;
47158c2ecf20Sopenharmony_ci}
47168c2ecf20Sopenharmony_ci
47178c2ecf20Sopenharmony_ciint
47188c2ecf20Sopenharmony_ciCIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
47198c2ecf20Sopenharmony_ci	      const __u16 searchHandle)
47208c2ecf20Sopenharmony_ci{
47218c2ecf20Sopenharmony_ci	int rc = 0;
47228c2ecf20Sopenharmony_ci	FINDCLOSE_REQ *pSMB = NULL;
47238c2ecf20Sopenharmony_ci
47248c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In CIFSSMBFindClose\n");
47258c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
47268c2ecf20Sopenharmony_ci
47278c2ecf20Sopenharmony_ci	/* no sense returning error if session restarted
47288c2ecf20Sopenharmony_ci		as file handle has been closed */
47298c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
47308c2ecf20Sopenharmony_ci		return 0;
47318c2ecf20Sopenharmony_ci	if (rc)
47328c2ecf20Sopenharmony_ci		return rc;
47338c2ecf20Sopenharmony_ci
47348c2ecf20Sopenharmony_ci	pSMB->FileID = searchHandle;
47358c2ecf20Sopenharmony_ci	pSMB->ByteCount = 0;
47368c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
47378c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
47388c2ecf20Sopenharmony_ci	if (rc)
47398c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
47408c2ecf20Sopenharmony_ci
47418c2ecf20Sopenharmony_ci	cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
47428c2ecf20Sopenharmony_ci
47438c2ecf20Sopenharmony_ci	/* Since session is dead, search handle closed on server already */
47448c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
47458c2ecf20Sopenharmony_ci		rc = 0;
47468c2ecf20Sopenharmony_ci
47478c2ecf20Sopenharmony_ci	return rc;
47488c2ecf20Sopenharmony_ci}
47498c2ecf20Sopenharmony_ci
47508c2ecf20Sopenharmony_ciint
47518c2ecf20Sopenharmony_ciCIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
47528c2ecf20Sopenharmony_ci		      const char *search_name, __u64 *inode_number,
47538c2ecf20Sopenharmony_ci		      const struct nls_table *nls_codepage, int remap)
47548c2ecf20Sopenharmony_ci{
47558c2ecf20Sopenharmony_ci	int rc = 0;
47568c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
47578c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
47588c2ecf20Sopenharmony_ci	int name_len, bytes_returned;
47598c2ecf20Sopenharmony_ci	__u16 params, byte_count;
47608c2ecf20Sopenharmony_ci
47618c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
47628c2ecf20Sopenharmony_ci	if (tcon == NULL)
47638c2ecf20Sopenharmony_ci		return -ENODEV;
47648c2ecf20Sopenharmony_ci
47658c2ecf20Sopenharmony_ciGetInodeNumberRetry:
47668c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
47678c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
47688c2ecf20Sopenharmony_ci	if (rc)
47698c2ecf20Sopenharmony_ci		return rc;
47708c2ecf20Sopenharmony_ci
47718c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
47728c2ecf20Sopenharmony_ci		name_len =
47738c2ecf20Sopenharmony_ci			cifsConvertToUTF16((__le16 *) pSMB->FileName,
47748c2ecf20Sopenharmony_ci					   search_name, PATH_MAX, nls_codepage,
47758c2ecf20Sopenharmony_ci					   remap);
47768c2ecf20Sopenharmony_ci		name_len++;     /* trailing null */
47778c2ecf20Sopenharmony_ci		name_len *= 2;
47788c2ecf20Sopenharmony_ci	} else {
47798c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, search_name);
47808c2ecf20Sopenharmony_ci	}
47818c2ecf20Sopenharmony_ci
47828c2ecf20Sopenharmony_ci	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
47838c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
47848c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
47858c2ecf20Sopenharmony_ci	/* BB find exact max data count below from sess structure BB */
47868c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
47878c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
47888c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
47898c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
47908c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
47918c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
47928c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
47938c2ecf20Sopenharmony_ci		struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
47948c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
47958c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
47968c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
47978c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
47988c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
47998c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
48008c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
48018c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
48028c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
48038c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
48048c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
48058c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
48068c2ecf20Sopenharmony_ci
48078c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
48088c2ecf20Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
48098c2ecf20Sopenharmony_ci	if (rc) {
48108c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
48118c2ecf20Sopenharmony_ci	} else {
48128c2ecf20Sopenharmony_ci		/* decode response */
48138c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
48148c2ecf20Sopenharmony_ci		/* BB also check enough total bytes returned */
48158c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 2)
48168c2ecf20Sopenharmony_ci			/* If rc should we check for EOPNOSUPP and
48178c2ecf20Sopenharmony_ci			disable the srvino flag? or in caller? */
48188c2ecf20Sopenharmony_ci			rc = -EIO;      /* bad smb */
48198c2ecf20Sopenharmony_ci		else {
48208c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
48218c2ecf20Sopenharmony_ci			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
48228c2ecf20Sopenharmony_ci			struct file_internal_info *pfinfo;
48238c2ecf20Sopenharmony_ci			/* BB Do we need a cast or hash here ? */
48248c2ecf20Sopenharmony_ci			if (count < 8) {
48258c2ecf20Sopenharmony_ci				cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
48268c2ecf20Sopenharmony_ci				rc = -EIO;
48278c2ecf20Sopenharmony_ci				goto GetInodeNumOut;
48288c2ecf20Sopenharmony_ci			}
48298c2ecf20Sopenharmony_ci			pfinfo = (struct file_internal_info *)
48308c2ecf20Sopenharmony_ci				(data_offset + (char *) &pSMBr->hdr.Protocol);
48318c2ecf20Sopenharmony_ci			*inode_number = le64_to_cpu(pfinfo->UniqueId);
48328c2ecf20Sopenharmony_ci		}
48338c2ecf20Sopenharmony_ci	}
48348c2ecf20Sopenharmony_ciGetInodeNumOut:
48358c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
48368c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
48378c2ecf20Sopenharmony_ci		goto GetInodeNumberRetry;
48388c2ecf20Sopenharmony_ci	return rc;
48398c2ecf20Sopenharmony_ci}
48408c2ecf20Sopenharmony_ci
48418c2ecf20Sopenharmony_ciint
48428c2ecf20Sopenharmony_ciCIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
48438c2ecf20Sopenharmony_ci		const char *search_name, struct dfs_info3_param **target_nodes,
48448c2ecf20Sopenharmony_ci		unsigned int *num_of_nodes,
48458c2ecf20Sopenharmony_ci		const struct nls_table *nls_codepage, int remap)
48468c2ecf20Sopenharmony_ci{
48478c2ecf20Sopenharmony_ci/* TRANS2_GET_DFS_REFERRAL */
48488c2ecf20Sopenharmony_ci	TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
48498c2ecf20Sopenharmony_ci	TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
48508c2ecf20Sopenharmony_ci	int rc = 0;
48518c2ecf20Sopenharmony_ci	int bytes_returned;
48528c2ecf20Sopenharmony_ci	int name_len;
48538c2ecf20Sopenharmony_ci	__u16 params, byte_count;
48548c2ecf20Sopenharmony_ci	*num_of_nodes = 0;
48558c2ecf20Sopenharmony_ci	*target_nodes = NULL;
48568c2ecf20Sopenharmony_ci
48578c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
48588c2ecf20Sopenharmony_ci	if (ses == NULL || ses->tcon_ipc == NULL)
48598c2ecf20Sopenharmony_ci		return -ENODEV;
48608c2ecf20Sopenharmony_ci
48618c2ecf20Sopenharmony_cigetDFSRetry:
48628c2ecf20Sopenharmony_ci	/*
48638c2ecf20Sopenharmony_ci	 * Use smb_init_no_reconnect() instead of smb_init() as
48648c2ecf20Sopenharmony_ci	 * CIFSGetDFSRefer() may be called from cifs_reconnect_tcon() and thus
48658c2ecf20Sopenharmony_ci	 * causing an infinite recursion.
48668c2ecf20Sopenharmony_ci	 */
48678c2ecf20Sopenharmony_ci	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc,
48688c2ecf20Sopenharmony_ci				   (void **)&pSMB, (void **)&pSMBr);
48698c2ecf20Sopenharmony_ci	if (rc)
48708c2ecf20Sopenharmony_ci		return rc;
48718c2ecf20Sopenharmony_ci
48728c2ecf20Sopenharmony_ci	/* server pointer checked in called function,
48738c2ecf20Sopenharmony_ci	but should never be null here anyway */
48748c2ecf20Sopenharmony_ci	pSMB->hdr.Mid = get_next_mid(ses->server);
48758c2ecf20Sopenharmony_ci	pSMB->hdr.Tid = ses->tcon_ipc->tid;
48768c2ecf20Sopenharmony_ci	pSMB->hdr.Uid = ses->Suid;
48778c2ecf20Sopenharmony_ci	if (ses->capabilities & CAP_STATUS32)
48788c2ecf20Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
48798c2ecf20Sopenharmony_ci	if (ses->capabilities & CAP_DFS)
48808c2ecf20Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_DFS;
48818c2ecf20Sopenharmony_ci
48828c2ecf20Sopenharmony_ci	if (ses->capabilities & CAP_UNICODE) {
48838c2ecf20Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
48848c2ecf20Sopenharmony_ci		name_len =
48858c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
48868c2ecf20Sopenharmony_ci				       search_name, PATH_MAX, nls_codepage,
48878c2ecf20Sopenharmony_ci				       remap);
48888c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
48898c2ecf20Sopenharmony_ci		name_len *= 2;
48908c2ecf20Sopenharmony_ci	} else {	/* BB improve the check for buffer overruns BB */
48918c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->RequestFileName, search_name);
48928c2ecf20Sopenharmony_ci	}
48938c2ecf20Sopenharmony_ci
48948c2ecf20Sopenharmony_ci	if (ses->server->sign)
48958c2ecf20Sopenharmony_ci		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
48968c2ecf20Sopenharmony_ci
48978c2ecf20Sopenharmony_ci	pSMB->hdr.Uid = ses->Suid;
48988c2ecf20Sopenharmony_ci
48998c2ecf20Sopenharmony_ci	params = 2 /* level */  + name_len /*includes null */ ;
49008c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
49018c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
49028c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
49038c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = 0;
49048c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
49058c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4000);
49068c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
49078c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
49088c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
49098c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
49108c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
49118c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
49128c2ecf20Sopenharmony_ci	  struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
49138c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
49148c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
49158c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
49168c2ecf20Sopenharmony_ci	byte_count = params + 3 /* pad */ ;
49178c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
49188c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
49198c2ecf20Sopenharmony_ci	pSMB->MaxReferralLevel = cpu_to_le16(3);
49208c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
49218c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
49228c2ecf20Sopenharmony_ci
49238c2ecf20Sopenharmony_ci	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
49248c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
49258c2ecf20Sopenharmony_ci	if (rc) {
49268c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
49278c2ecf20Sopenharmony_ci		goto GetDFSRefExit;
49288c2ecf20Sopenharmony_ci	}
49298c2ecf20Sopenharmony_ci	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
49308c2ecf20Sopenharmony_ci
49318c2ecf20Sopenharmony_ci	/* BB Also check if enough total bytes returned? */
49328c2ecf20Sopenharmony_ci	if (rc || get_bcc(&pSMBr->hdr) < 17) {
49338c2ecf20Sopenharmony_ci		rc = -EIO;      /* bad smb */
49348c2ecf20Sopenharmony_ci		goto GetDFSRefExit;
49358c2ecf20Sopenharmony_ci	}
49368c2ecf20Sopenharmony_ci
49378c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d  Offset %d\n",
49388c2ecf20Sopenharmony_ci		 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
49398c2ecf20Sopenharmony_ci
49408c2ecf20Sopenharmony_ci	/* parse returned result into more usable form */
49418c2ecf20Sopenharmony_ci	rc = parse_dfs_referrals(&pSMBr->dfs_data,
49428c2ecf20Sopenharmony_ci				 le16_to_cpu(pSMBr->t2.DataCount),
49438c2ecf20Sopenharmony_ci				 num_of_nodes, target_nodes, nls_codepage,
49448c2ecf20Sopenharmony_ci				 remap, search_name,
49458c2ecf20Sopenharmony_ci				 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
49468c2ecf20Sopenharmony_ci
49478c2ecf20Sopenharmony_ciGetDFSRefExit:
49488c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
49498c2ecf20Sopenharmony_ci
49508c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
49518c2ecf20Sopenharmony_ci		goto getDFSRetry;
49528c2ecf20Sopenharmony_ci
49538c2ecf20Sopenharmony_ci	return rc;
49548c2ecf20Sopenharmony_ci}
49558c2ecf20Sopenharmony_ci
49568c2ecf20Sopenharmony_ci/* Query File System Info such as free space to old servers such as Win 9x */
49578c2ecf20Sopenharmony_ciint
49588c2ecf20Sopenharmony_ciSMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
49598c2ecf20Sopenharmony_ci	      struct kstatfs *FSData)
49608c2ecf20Sopenharmony_ci{
49618c2ecf20Sopenharmony_ci/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
49628c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
49638c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
49648c2ecf20Sopenharmony_ci	FILE_SYSTEM_ALLOC_INFO *response_data;
49658c2ecf20Sopenharmony_ci	int rc = 0;
49668c2ecf20Sopenharmony_ci	int bytes_returned = 0;
49678c2ecf20Sopenharmony_ci	__u16 params, byte_count;
49688c2ecf20Sopenharmony_ci
49698c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "OldQFSInfo\n");
49708c2ecf20Sopenharmony_cioldQFSInfoRetry:
49718c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
49728c2ecf20Sopenharmony_ci		(void **) &pSMBr);
49738c2ecf20Sopenharmony_ci	if (rc)
49748c2ecf20Sopenharmony_ci		return rc;
49758c2ecf20Sopenharmony_ci
49768c2ecf20Sopenharmony_ci	params = 2;     /* level */
49778c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
49788c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
49798c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
49808c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
49818c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
49828c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
49838c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
49848c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
49858c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
49868c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
49878c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
49888c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
49898c2ecf20Sopenharmony_ci	struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
49908c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
49918c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
49928c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
49938c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
49948c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
49958c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
49968c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
49978c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
49988c2ecf20Sopenharmony_ci
49998c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50008c2ecf20Sopenharmony_ci		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
50018c2ecf20Sopenharmony_ci	if (rc) {
50028c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
50038c2ecf20Sopenharmony_ci	} else {                /* decode response */
50048c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
50058c2ecf20Sopenharmony_ci
50068c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 18)
50078c2ecf20Sopenharmony_ci			rc = -EIO;      /* bad smb */
50088c2ecf20Sopenharmony_ci		else {
50098c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
50108c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "qfsinf resp BCC: %d  Offset %d\n",
50118c2ecf20Sopenharmony_ci				 get_bcc(&pSMBr->hdr), data_offset);
50128c2ecf20Sopenharmony_ci
50138c2ecf20Sopenharmony_ci			response_data = (FILE_SYSTEM_ALLOC_INFO *)
50148c2ecf20Sopenharmony_ci				(((char *) &pSMBr->hdr.Protocol) + data_offset);
50158c2ecf20Sopenharmony_ci			FSData->f_bsize =
50168c2ecf20Sopenharmony_ci				le16_to_cpu(response_data->BytesPerSector) *
50178c2ecf20Sopenharmony_ci				le32_to_cpu(response_data->
50188c2ecf20Sopenharmony_ci					SectorsPerAllocationUnit);
50198c2ecf20Sopenharmony_ci			/*
50208c2ecf20Sopenharmony_ci			 * much prefer larger but if server doesn't report
50218c2ecf20Sopenharmony_ci			 * a valid size than 4K is a reasonable minimum
50228c2ecf20Sopenharmony_ci			 */
50238c2ecf20Sopenharmony_ci			if (FSData->f_bsize < 512)
50248c2ecf20Sopenharmony_ci				FSData->f_bsize = 4096;
50258c2ecf20Sopenharmony_ci
50268c2ecf20Sopenharmony_ci			FSData->f_blocks =
50278c2ecf20Sopenharmony_ci			       le32_to_cpu(response_data->TotalAllocationUnits);
50288c2ecf20Sopenharmony_ci			FSData->f_bfree = FSData->f_bavail =
50298c2ecf20Sopenharmony_ci				le32_to_cpu(response_data->FreeAllocationUnits);
50308c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n",
50318c2ecf20Sopenharmony_ci				 (unsigned long long)FSData->f_blocks,
50328c2ecf20Sopenharmony_ci				 (unsigned long long)FSData->f_bfree,
50338c2ecf20Sopenharmony_ci				 FSData->f_bsize);
50348c2ecf20Sopenharmony_ci		}
50358c2ecf20Sopenharmony_ci	}
50368c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
50378c2ecf20Sopenharmony_ci
50388c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
50398c2ecf20Sopenharmony_ci		goto oldQFSInfoRetry;
50408c2ecf20Sopenharmony_ci
50418c2ecf20Sopenharmony_ci	return rc;
50428c2ecf20Sopenharmony_ci}
50438c2ecf20Sopenharmony_ci
50448c2ecf20Sopenharmony_ciint
50458c2ecf20Sopenharmony_ciCIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
50468c2ecf20Sopenharmony_ci	       struct kstatfs *FSData)
50478c2ecf20Sopenharmony_ci{
50488c2ecf20Sopenharmony_ci/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
50498c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
50508c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
50518c2ecf20Sopenharmony_ci	FILE_SYSTEM_INFO *response_data;
50528c2ecf20Sopenharmony_ci	int rc = 0;
50538c2ecf20Sopenharmony_ci	int bytes_returned = 0;
50548c2ecf20Sopenharmony_ci	__u16 params, byte_count;
50558c2ecf20Sopenharmony_ci
50568c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In QFSInfo\n");
50578c2ecf20Sopenharmony_ciQFSInfoRetry:
50588c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50598c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
50608c2ecf20Sopenharmony_ci	if (rc)
50618c2ecf20Sopenharmony_ci		return rc;
50628c2ecf20Sopenharmony_ci
50638c2ecf20Sopenharmony_ci	params = 2;	/* level */
50648c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
50658c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
50668c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
50678c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
50688c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
50698c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
50708c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
50718c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
50728c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
50738c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
50748c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
50758c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
50768c2ecf20Sopenharmony_ci		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
50778c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
50788c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
50798c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
50808c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
50818c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
50828c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
50838c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
50848c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
50858c2ecf20Sopenharmony_ci
50868c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50878c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
50888c2ecf20Sopenharmony_ci	if (rc) {
50898c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
50908c2ecf20Sopenharmony_ci	} else {		/* decode response */
50918c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
50928c2ecf20Sopenharmony_ci
50938c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 24)
50948c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
50958c2ecf20Sopenharmony_ci		else {
50968c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
50978c2ecf20Sopenharmony_ci
50988c2ecf20Sopenharmony_ci			response_data =
50998c2ecf20Sopenharmony_ci			    (FILE_SYSTEM_INFO
51008c2ecf20Sopenharmony_ci			     *) (((char *) &pSMBr->hdr.Protocol) +
51018c2ecf20Sopenharmony_ci				 data_offset);
51028c2ecf20Sopenharmony_ci			FSData->f_bsize =
51038c2ecf20Sopenharmony_ci			    le32_to_cpu(response_data->BytesPerSector) *
51048c2ecf20Sopenharmony_ci			    le32_to_cpu(response_data->
51058c2ecf20Sopenharmony_ci					SectorsPerAllocationUnit);
51068c2ecf20Sopenharmony_ci			/*
51078c2ecf20Sopenharmony_ci			 * much prefer larger but if server doesn't report
51088c2ecf20Sopenharmony_ci			 * a valid size than 4K is a reasonable minimum
51098c2ecf20Sopenharmony_ci			 */
51108c2ecf20Sopenharmony_ci			if (FSData->f_bsize < 512)
51118c2ecf20Sopenharmony_ci				FSData->f_bsize = 4096;
51128c2ecf20Sopenharmony_ci
51138c2ecf20Sopenharmony_ci			FSData->f_blocks =
51148c2ecf20Sopenharmony_ci			    le64_to_cpu(response_data->TotalAllocationUnits);
51158c2ecf20Sopenharmony_ci			FSData->f_bfree = FSData->f_bavail =
51168c2ecf20Sopenharmony_ci			    le64_to_cpu(response_data->FreeAllocationUnits);
51178c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n",
51188c2ecf20Sopenharmony_ci				 (unsigned long long)FSData->f_blocks,
51198c2ecf20Sopenharmony_ci				 (unsigned long long)FSData->f_bfree,
51208c2ecf20Sopenharmony_ci				 FSData->f_bsize);
51218c2ecf20Sopenharmony_ci		}
51228c2ecf20Sopenharmony_ci	}
51238c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
51248c2ecf20Sopenharmony_ci
51258c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
51268c2ecf20Sopenharmony_ci		goto QFSInfoRetry;
51278c2ecf20Sopenharmony_ci
51288c2ecf20Sopenharmony_ci	return rc;
51298c2ecf20Sopenharmony_ci}
51308c2ecf20Sopenharmony_ci
51318c2ecf20Sopenharmony_ciint
51328c2ecf20Sopenharmony_ciCIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
51338c2ecf20Sopenharmony_ci{
51348c2ecf20Sopenharmony_ci/* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
51358c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
51368c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
51378c2ecf20Sopenharmony_ci	FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
51388c2ecf20Sopenharmony_ci	int rc = 0;
51398c2ecf20Sopenharmony_ci	int bytes_returned = 0;
51408c2ecf20Sopenharmony_ci	__u16 params, byte_count;
51418c2ecf20Sopenharmony_ci
51428c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In QFSAttributeInfo\n");
51438c2ecf20Sopenharmony_ciQFSAttributeRetry:
51448c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
51458c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
51468c2ecf20Sopenharmony_ci	if (rc)
51478c2ecf20Sopenharmony_ci		return rc;
51488c2ecf20Sopenharmony_ci
51498c2ecf20Sopenharmony_ci	params = 2;	/* level */
51508c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
51518c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
51528c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
51538c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
51548c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
51558c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
51568c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
51578c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
51588c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
51598c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
51608c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
51618c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
51628c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
51638c2ecf20Sopenharmony_ci		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
51648c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
51658c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
51668c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
51678c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
51688c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
51698c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
51708c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
51718c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
51728c2ecf20Sopenharmony_ci
51738c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
51748c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
51758c2ecf20Sopenharmony_ci	if (rc) {
51768c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
51778c2ecf20Sopenharmony_ci	} else {		/* decode response */
51788c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
51798c2ecf20Sopenharmony_ci
51808c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 13) {
51818c2ecf20Sopenharmony_ci			/* BB also check if enough bytes returned */
51828c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
51838c2ecf20Sopenharmony_ci		} else {
51848c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
51858c2ecf20Sopenharmony_ci			response_data =
51868c2ecf20Sopenharmony_ci			    (FILE_SYSTEM_ATTRIBUTE_INFO
51878c2ecf20Sopenharmony_ci			     *) (((char *) &pSMBr->hdr.Protocol) +
51888c2ecf20Sopenharmony_ci				 data_offset);
51898c2ecf20Sopenharmony_ci			memcpy(&tcon->fsAttrInfo, response_data,
51908c2ecf20Sopenharmony_ci			       sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
51918c2ecf20Sopenharmony_ci		}
51928c2ecf20Sopenharmony_ci	}
51938c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
51948c2ecf20Sopenharmony_ci
51958c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
51968c2ecf20Sopenharmony_ci		goto QFSAttributeRetry;
51978c2ecf20Sopenharmony_ci
51988c2ecf20Sopenharmony_ci	return rc;
51998c2ecf20Sopenharmony_ci}
52008c2ecf20Sopenharmony_ci
52018c2ecf20Sopenharmony_ciint
52028c2ecf20Sopenharmony_ciCIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
52038c2ecf20Sopenharmony_ci{
52048c2ecf20Sopenharmony_ci/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
52058c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
52068c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
52078c2ecf20Sopenharmony_ci	FILE_SYSTEM_DEVICE_INFO *response_data;
52088c2ecf20Sopenharmony_ci	int rc = 0;
52098c2ecf20Sopenharmony_ci	int bytes_returned = 0;
52108c2ecf20Sopenharmony_ci	__u16 params, byte_count;
52118c2ecf20Sopenharmony_ci
52128c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In QFSDeviceInfo\n");
52138c2ecf20Sopenharmony_ciQFSDeviceRetry:
52148c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
52158c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
52168c2ecf20Sopenharmony_ci	if (rc)
52178c2ecf20Sopenharmony_ci		return rc;
52188c2ecf20Sopenharmony_ci
52198c2ecf20Sopenharmony_ci	params = 2;	/* level */
52208c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
52218c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
52228c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
52238c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
52248c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
52258c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
52268c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
52278c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
52288c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
52298c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
52308c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
52318c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
52328c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
52338c2ecf20Sopenharmony_ci		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
52348c2ecf20Sopenharmony_ci
52358c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
52368c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
52378c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
52388c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
52398c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
52408c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
52418c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
52428c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
52438c2ecf20Sopenharmony_ci
52448c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
52458c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
52468c2ecf20Sopenharmony_ci	if (rc) {
52478c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
52488c2ecf20Sopenharmony_ci	} else {		/* decode response */
52498c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
52508c2ecf20Sopenharmony_ci
52518c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) <
52528c2ecf20Sopenharmony_ci			  sizeof(FILE_SYSTEM_DEVICE_INFO))
52538c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
52548c2ecf20Sopenharmony_ci		else {
52558c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
52568c2ecf20Sopenharmony_ci			response_data =
52578c2ecf20Sopenharmony_ci			    (FILE_SYSTEM_DEVICE_INFO *)
52588c2ecf20Sopenharmony_ci				(((char *) &pSMBr->hdr.Protocol) +
52598c2ecf20Sopenharmony_ci				 data_offset);
52608c2ecf20Sopenharmony_ci			memcpy(&tcon->fsDevInfo, response_data,
52618c2ecf20Sopenharmony_ci			       sizeof(FILE_SYSTEM_DEVICE_INFO));
52628c2ecf20Sopenharmony_ci		}
52638c2ecf20Sopenharmony_ci	}
52648c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
52658c2ecf20Sopenharmony_ci
52668c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
52678c2ecf20Sopenharmony_ci		goto QFSDeviceRetry;
52688c2ecf20Sopenharmony_ci
52698c2ecf20Sopenharmony_ci	return rc;
52708c2ecf20Sopenharmony_ci}
52718c2ecf20Sopenharmony_ci
52728c2ecf20Sopenharmony_ciint
52738c2ecf20Sopenharmony_ciCIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
52748c2ecf20Sopenharmony_ci{
52758c2ecf20Sopenharmony_ci/* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
52768c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
52778c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
52788c2ecf20Sopenharmony_ci	FILE_SYSTEM_UNIX_INFO *response_data;
52798c2ecf20Sopenharmony_ci	int rc = 0;
52808c2ecf20Sopenharmony_ci	int bytes_returned = 0;
52818c2ecf20Sopenharmony_ci	__u16 params, byte_count;
52828c2ecf20Sopenharmony_ci
52838c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In QFSUnixInfo\n");
52848c2ecf20Sopenharmony_ciQFSUnixRetry:
52858c2ecf20Sopenharmony_ci	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
52868c2ecf20Sopenharmony_ci				   (void **) &pSMB, (void **) &pSMBr);
52878c2ecf20Sopenharmony_ci	if (rc)
52888c2ecf20Sopenharmony_ci		return rc;
52898c2ecf20Sopenharmony_ci
52908c2ecf20Sopenharmony_ci	params = 2;	/* level */
52918c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
52928c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
52938c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
52948c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
52958c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
52968c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(100);
52978c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
52988c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
52998c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
53008c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
53018c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
53028c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
53038c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
53048c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
53058c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
53068c2ecf20Sopenharmony_ci			smb_com_transaction2_qfsi_req, InformationLevel) - 4);
53078c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
53088c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
53098c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
53108c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
53118c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
53128c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
53138c2ecf20Sopenharmony_ci
53148c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
53158c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
53168c2ecf20Sopenharmony_ci	if (rc) {
53178c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
53188c2ecf20Sopenharmony_ci	} else {		/* decode response */
53198c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
53208c2ecf20Sopenharmony_ci
53218c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 13) {
53228c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
53238c2ecf20Sopenharmony_ci		} else {
53248c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
53258c2ecf20Sopenharmony_ci			response_data =
53268c2ecf20Sopenharmony_ci			    (FILE_SYSTEM_UNIX_INFO
53278c2ecf20Sopenharmony_ci			     *) (((char *) &pSMBr->hdr.Protocol) +
53288c2ecf20Sopenharmony_ci				 data_offset);
53298c2ecf20Sopenharmony_ci			memcpy(&tcon->fsUnixInfo, response_data,
53308c2ecf20Sopenharmony_ci			       sizeof(FILE_SYSTEM_UNIX_INFO));
53318c2ecf20Sopenharmony_ci		}
53328c2ecf20Sopenharmony_ci	}
53338c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
53348c2ecf20Sopenharmony_ci
53358c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
53368c2ecf20Sopenharmony_ci		goto QFSUnixRetry;
53378c2ecf20Sopenharmony_ci
53388c2ecf20Sopenharmony_ci
53398c2ecf20Sopenharmony_ci	return rc;
53408c2ecf20Sopenharmony_ci}
53418c2ecf20Sopenharmony_ci
53428c2ecf20Sopenharmony_ciint
53438c2ecf20Sopenharmony_ciCIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
53448c2ecf20Sopenharmony_ci{
53458c2ecf20Sopenharmony_ci/* level 0x200  SMB_SET_CIFS_UNIX_INFO */
53468c2ecf20Sopenharmony_ci	TRANSACTION2_SETFSI_REQ *pSMB = NULL;
53478c2ecf20Sopenharmony_ci	TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
53488c2ecf20Sopenharmony_ci	int rc = 0;
53498c2ecf20Sopenharmony_ci	int bytes_returned = 0;
53508c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count;
53518c2ecf20Sopenharmony_ci
53528c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SETFSUnixInfo\n");
53538c2ecf20Sopenharmony_ciSETFSUnixRetry:
53548c2ecf20Sopenharmony_ci	/* BB switch to small buf init to save memory */
53558c2ecf20Sopenharmony_ci	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
53568c2ecf20Sopenharmony_ci					(void **) &pSMB, (void **) &pSMBr);
53578c2ecf20Sopenharmony_ci	if (rc)
53588c2ecf20Sopenharmony_ci		return rc;
53598c2ecf20Sopenharmony_ci
53608c2ecf20Sopenharmony_ci	params = 4;	/* 2 bytes zero followed by info level. */
53618c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
53628c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
53638c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
53648c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
53658c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
53668c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
53678c2ecf20Sopenharmony_ci				- 4;
53688c2ecf20Sopenharmony_ci	offset = param_offset + params;
53698c2ecf20Sopenharmony_ci
53708c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(4);
53718c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
53728c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(100);
53738c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
53748c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
53758c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
53768c2ecf20Sopenharmony_ci	byte_count = 1 /* pad */ + params + 12;
53778c2ecf20Sopenharmony_ci
53788c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(12);
53798c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
53808c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
53818c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
53828c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
53838c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
53848c2ecf20Sopenharmony_ci
53858c2ecf20Sopenharmony_ci	/* Params. */
53868c2ecf20Sopenharmony_ci	pSMB->FileNum = 0;
53878c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
53888c2ecf20Sopenharmony_ci
53898c2ecf20Sopenharmony_ci	/* Data. */
53908c2ecf20Sopenharmony_ci	pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
53918c2ecf20Sopenharmony_ci	pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
53928c2ecf20Sopenharmony_ci	pSMB->ClientUnixCap = cpu_to_le64(cap);
53938c2ecf20Sopenharmony_ci
53948c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
53958c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
53968c2ecf20Sopenharmony_ci
53978c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
53988c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
53998c2ecf20Sopenharmony_ci	if (rc) {
54008c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
54018c2ecf20Sopenharmony_ci	} else {		/* decode response */
54028c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
54038c2ecf20Sopenharmony_ci		if (rc)
54048c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
54058c2ecf20Sopenharmony_ci	}
54068c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
54078c2ecf20Sopenharmony_ci
54088c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
54098c2ecf20Sopenharmony_ci		goto SETFSUnixRetry;
54108c2ecf20Sopenharmony_ci
54118c2ecf20Sopenharmony_ci	return rc;
54128c2ecf20Sopenharmony_ci}
54138c2ecf20Sopenharmony_ci
54148c2ecf20Sopenharmony_ci
54158c2ecf20Sopenharmony_ci
54168c2ecf20Sopenharmony_ciint
54178c2ecf20Sopenharmony_ciCIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
54188c2ecf20Sopenharmony_ci		   struct kstatfs *FSData)
54198c2ecf20Sopenharmony_ci{
54208c2ecf20Sopenharmony_ci/* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
54218c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_REQ *pSMB = NULL;
54228c2ecf20Sopenharmony_ci	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
54238c2ecf20Sopenharmony_ci	FILE_SYSTEM_POSIX_INFO *response_data;
54248c2ecf20Sopenharmony_ci	int rc = 0;
54258c2ecf20Sopenharmony_ci	int bytes_returned = 0;
54268c2ecf20Sopenharmony_ci	__u16 params, byte_count;
54278c2ecf20Sopenharmony_ci
54288c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In QFSPosixInfo\n");
54298c2ecf20Sopenharmony_ciQFSPosixRetry:
54308c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
54318c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
54328c2ecf20Sopenharmony_ci	if (rc)
54338c2ecf20Sopenharmony_ci		return rc;
54348c2ecf20Sopenharmony_ci
54358c2ecf20Sopenharmony_ci	params = 2;	/* level */
54368c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
54378c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
54388c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
54398c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
54408c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
54418c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(100);
54428c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
54438c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
54448c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
54458c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
54468c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
54478c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
54488c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
54498c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
54508c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
54518c2ecf20Sopenharmony_ci			smb_com_transaction2_qfsi_req, InformationLevel) - 4);
54528c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
54538c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
54548c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
54558c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
54568c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
54578c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
54588c2ecf20Sopenharmony_ci
54598c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
54608c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
54618c2ecf20Sopenharmony_ci	if (rc) {
54628c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
54638c2ecf20Sopenharmony_ci	} else {		/* decode response */
54648c2ecf20Sopenharmony_ci		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
54658c2ecf20Sopenharmony_ci
54668c2ecf20Sopenharmony_ci		if (rc || get_bcc(&pSMBr->hdr) < 13) {
54678c2ecf20Sopenharmony_ci			rc = -EIO;	/* bad smb */
54688c2ecf20Sopenharmony_ci		} else {
54698c2ecf20Sopenharmony_ci			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
54708c2ecf20Sopenharmony_ci			response_data =
54718c2ecf20Sopenharmony_ci			    (FILE_SYSTEM_POSIX_INFO
54728c2ecf20Sopenharmony_ci			     *) (((char *) &pSMBr->hdr.Protocol) +
54738c2ecf20Sopenharmony_ci				 data_offset);
54748c2ecf20Sopenharmony_ci			FSData->f_bsize =
54758c2ecf20Sopenharmony_ci					le32_to_cpu(response_data->BlockSize);
54768c2ecf20Sopenharmony_ci			/*
54778c2ecf20Sopenharmony_ci			 * much prefer larger but if server doesn't report
54788c2ecf20Sopenharmony_ci			 * a valid size than 4K is a reasonable minimum
54798c2ecf20Sopenharmony_ci			 */
54808c2ecf20Sopenharmony_ci			if (FSData->f_bsize < 512)
54818c2ecf20Sopenharmony_ci				FSData->f_bsize = 4096;
54828c2ecf20Sopenharmony_ci
54838c2ecf20Sopenharmony_ci			FSData->f_blocks =
54848c2ecf20Sopenharmony_ci					le64_to_cpu(response_data->TotalBlocks);
54858c2ecf20Sopenharmony_ci			FSData->f_bfree =
54868c2ecf20Sopenharmony_ci			    le64_to_cpu(response_data->BlocksAvail);
54878c2ecf20Sopenharmony_ci			if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
54888c2ecf20Sopenharmony_ci				FSData->f_bavail = FSData->f_bfree;
54898c2ecf20Sopenharmony_ci			} else {
54908c2ecf20Sopenharmony_ci				FSData->f_bavail =
54918c2ecf20Sopenharmony_ci				    le64_to_cpu(response_data->UserBlocksAvail);
54928c2ecf20Sopenharmony_ci			}
54938c2ecf20Sopenharmony_ci			if (response_data->TotalFileNodes != cpu_to_le64(-1))
54948c2ecf20Sopenharmony_ci				FSData->f_files =
54958c2ecf20Sopenharmony_ci				     le64_to_cpu(response_data->TotalFileNodes);
54968c2ecf20Sopenharmony_ci			if (response_data->FreeFileNodes != cpu_to_le64(-1))
54978c2ecf20Sopenharmony_ci				FSData->f_ffree =
54988c2ecf20Sopenharmony_ci				      le64_to_cpu(response_data->FreeFileNodes);
54998c2ecf20Sopenharmony_ci		}
55008c2ecf20Sopenharmony_ci	}
55018c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
55028c2ecf20Sopenharmony_ci
55038c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
55048c2ecf20Sopenharmony_ci		goto QFSPosixRetry;
55058c2ecf20Sopenharmony_ci
55068c2ecf20Sopenharmony_ci	return rc;
55078c2ecf20Sopenharmony_ci}
55088c2ecf20Sopenharmony_ci
55098c2ecf20Sopenharmony_ci
55108c2ecf20Sopenharmony_ci/*
55118c2ecf20Sopenharmony_ci * We can not use write of zero bytes trick to set file size due to need for
55128c2ecf20Sopenharmony_ci * large file support. Also note that this SetPathInfo is preferred to
55138c2ecf20Sopenharmony_ci * SetFileInfo based method in next routine which is only needed to work around
55148c2ecf20Sopenharmony_ci * a sharing violation bugin Samba which this routine can run into.
55158c2ecf20Sopenharmony_ci */
55168c2ecf20Sopenharmony_ciint
55178c2ecf20Sopenharmony_ciCIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
55188c2ecf20Sopenharmony_ci	      const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
55198c2ecf20Sopenharmony_ci	      bool set_allocation)
55208c2ecf20Sopenharmony_ci{
55218c2ecf20Sopenharmony_ci	struct smb_com_transaction2_spi_req *pSMB = NULL;
55228c2ecf20Sopenharmony_ci	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
55238c2ecf20Sopenharmony_ci	struct file_end_of_file_info *parm_data;
55248c2ecf20Sopenharmony_ci	int name_len;
55258c2ecf20Sopenharmony_ci	int rc = 0;
55268c2ecf20Sopenharmony_ci	int bytes_returned = 0;
55278c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
55288c2ecf20Sopenharmony_ci
55298c2ecf20Sopenharmony_ci	__u16 params, byte_count, data_count, param_offset, offset;
55308c2ecf20Sopenharmony_ci
55318c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SetEOF\n");
55328c2ecf20Sopenharmony_ciSetEOFRetry:
55338c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
55348c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
55358c2ecf20Sopenharmony_ci	if (rc)
55368c2ecf20Sopenharmony_ci		return rc;
55378c2ecf20Sopenharmony_ci
55388c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
55398c2ecf20Sopenharmony_ci		name_len =
55408c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
55418c2ecf20Sopenharmony_ci				       PATH_MAX, cifs_sb->local_nls, remap);
55428c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
55438c2ecf20Sopenharmony_ci		name_len *= 2;
55448c2ecf20Sopenharmony_ci	} else {
55458c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, file_name);
55468c2ecf20Sopenharmony_ci	}
55478c2ecf20Sopenharmony_ci	params = 6 + name_len;
55488c2ecf20Sopenharmony_ci	data_count = sizeof(struct file_end_of_file_info);
55498c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
55508c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(4100);
55518c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
55528c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
55538c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
55548c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
55558c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
55568c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
55578c2ecf20Sopenharmony_ci				InformationLevel) - 4;
55588c2ecf20Sopenharmony_ci	offset = param_offset + params;
55598c2ecf20Sopenharmony_ci	if (set_allocation) {
55608c2ecf20Sopenharmony_ci		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
55618c2ecf20Sopenharmony_ci			pSMB->InformationLevel =
55628c2ecf20Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
55638c2ecf20Sopenharmony_ci		else
55648c2ecf20Sopenharmony_ci			pSMB->InformationLevel =
55658c2ecf20Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
55668c2ecf20Sopenharmony_ci	} else /* Set File Size */  {
55678c2ecf20Sopenharmony_ci	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
55688c2ecf20Sopenharmony_ci		    pSMB->InformationLevel =
55698c2ecf20Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
55708c2ecf20Sopenharmony_ci	    else
55718c2ecf20Sopenharmony_ci		    pSMB->InformationLevel =
55728c2ecf20Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
55738c2ecf20Sopenharmony_ci	}
55748c2ecf20Sopenharmony_ci
55758c2ecf20Sopenharmony_ci	parm_data =
55768c2ecf20Sopenharmony_ci	    (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
55778c2ecf20Sopenharmony_ci				       offset);
55788c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
55798c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
55808c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
55818c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
55828c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
55838c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + data_count;
55848c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(data_count);
55858c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
55868c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
55878c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
55888c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
55898c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
55908c2ecf20Sopenharmony_ci	parm_data->FileSize = cpu_to_le64(size);
55918c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
55928c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
55938c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
55948c2ecf20Sopenharmony_ci	if (rc)
55958c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
55968c2ecf20Sopenharmony_ci
55978c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
55988c2ecf20Sopenharmony_ci
55998c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
56008c2ecf20Sopenharmony_ci		goto SetEOFRetry;
56018c2ecf20Sopenharmony_ci
56028c2ecf20Sopenharmony_ci	return rc;
56038c2ecf20Sopenharmony_ci}
56048c2ecf20Sopenharmony_ci
56058c2ecf20Sopenharmony_ciint
56068c2ecf20Sopenharmony_ciCIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
56078c2ecf20Sopenharmony_ci		   struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
56088c2ecf20Sopenharmony_ci{
56098c2ecf20Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
56108c2ecf20Sopenharmony_ci	struct file_end_of_file_info *parm_data;
56118c2ecf20Sopenharmony_ci	int rc = 0;
56128c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
56138c2ecf20Sopenharmony_ci
56148c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
56158c2ecf20Sopenharmony_ci		 (long long)size);
56168c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
56178c2ecf20Sopenharmony_ci
56188c2ecf20Sopenharmony_ci	if (rc)
56198c2ecf20Sopenharmony_ci		return rc;
56208c2ecf20Sopenharmony_ci
56218c2ecf20Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
56228c2ecf20Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
56238c2ecf20Sopenharmony_ci
56248c2ecf20Sopenharmony_ci	params = 6;
56258c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
56268c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
56278c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
56288c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
56298c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
56308c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
56318c2ecf20Sopenharmony_ci	offset = param_offset + params;
56328c2ecf20Sopenharmony_ci
56338c2ecf20Sopenharmony_ci	count = sizeof(struct file_end_of_file_info);
56348c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
56358c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
56368c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
56378c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
56388c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
56398c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
56408c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
56418c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
56428c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
56438c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
56448c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
56458c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
56468c2ecf20Sopenharmony_ci	parm_data =
56478c2ecf20Sopenharmony_ci		(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
56488c2ecf20Sopenharmony_ci				+ offset);
56498c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
56508c2ecf20Sopenharmony_ci	parm_data->FileSize = cpu_to_le64(size);
56518c2ecf20Sopenharmony_ci	pSMB->Fid = cfile->fid.netfid;
56528c2ecf20Sopenharmony_ci	if (set_allocation) {
56538c2ecf20Sopenharmony_ci		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
56548c2ecf20Sopenharmony_ci			pSMB->InformationLevel =
56558c2ecf20Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
56568c2ecf20Sopenharmony_ci		else
56578c2ecf20Sopenharmony_ci			pSMB->InformationLevel =
56588c2ecf20Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
56598c2ecf20Sopenharmony_ci	} else /* Set File Size */  {
56608c2ecf20Sopenharmony_ci	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
56618c2ecf20Sopenharmony_ci		    pSMB->InformationLevel =
56628c2ecf20Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
56638c2ecf20Sopenharmony_ci	    else
56648c2ecf20Sopenharmony_ci		    pSMB->InformationLevel =
56658c2ecf20Sopenharmony_ci				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
56668c2ecf20Sopenharmony_ci	}
56678c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
56688c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
56698c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
56708c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
56718c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
56728c2ecf20Sopenharmony_ci	if (rc) {
56738c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
56748c2ecf20Sopenharmony_ci			 rc);
56758c2ecf20Sopenharmony_ci	}
56768c2ecf20Sopenharmony_ci
56778c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
56788c2ecf20Sopenharmony_ci		since file handle passed in no longer valid */
56798c2ecf20Sopenharmony_ci
56808c2ecf20Sopenharmony_ci	return rc;
56818c2ecf20Sopenharmony_ci}
56828c2ecf20Sopenharmony_ci
56838c2ecf20Sopenharmony_ci/* Some legacy servers such as NT4 require that the file times be set on
56848c2ecf20Sopenharmony_ci   an open handle, rather than by pathname - this is awkward due to
56858c2ecf20Sopenharmony_ci   potential access conflicts on the open, but it is unavoidable for these
56868c2ecf20Sopenharmony_ci   old servers since the only other choice is to go from 100 nanosecond DCE
56878c2ecf20Sopenharmony_ci   time and resort to the original setpathinfo level which takes the ancient
56888c2ecf20Sopenharmony_ci   DOS time format with 2 second granularity */
56898c2ecf20Sopenharmony_ciint
56908c2ecf20Sopenharmony_ciCIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
56918c2ecf20Sopenharmony_ci		    const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
56928c2ecf20Sopenharmony_ci{
56938c2ecf20Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
56948c2ecf20Sopenharmony_ci	char *data_offset;
56958c2ecf20Sopenharmony_ci	int rc = 0;
56968c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
56978c2ecf20Sopenharmony_ci
56988c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
56998c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
57008c2ecf20Sopenharmony_ci
57018c2ecf20Sopenharmony_ci	if (rc)
57028c2ecf20Sopenharmony_ci		return rc;
57038c2ecf20Sopenharmony_ci
57048c2ecf20Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
57058c2ecf20Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
57068c2ecf20Sopenharmony_ci
57078c2ecf20Sopenharmony_ci	params = 6;
57088c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
57098c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
57108c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
57118c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
57128c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
57138c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
57148c2ecf20Sopenharmony_ci	offset = param_offset + params;
57158c2ecf20Sopenharmony_ci
57168c2ecf20Sopenharmony_ci	data_offset = (char *)pSMB +
57178c2ecf20Sopenharmony_ci			offsetof(struct smb_hdr, Protocol) + offset;
57188c2ecf20Sopenharmony_ci
57198c2ecf20Sopenharmony_ci	count = sizeof(FILE_BASIC_INFO);
57208c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
57218c2ecf20Sopenharmony_ci	/* BB find max SMB PDU from sess */
57228c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
57238c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
57248c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
57258c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
57268c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
57278c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
57288c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
57298c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
57308c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
57318c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
57328c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
57338c2ecf20Sopenharmony_ci	pSMB->Fid = fid;
57348c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
57358c2ecf20Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
57368c2ecf20Sopenharmony_ci	else
57378c2ecf20Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
57388c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
57398c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
57408c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
57418c2ecf20Sopenharmony_ci	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
57428c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
57438c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
57448c2ecf20Sopenharmony_ci	if (rc)
57458c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
57468c2ecf20Sopenharmony_ci			 rc);
57478c2ecf20Sopenharmony_ci
57488c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
57498c2ecf20Sopenharmony_ci		since file handle passed in no longer valid */
57508c2ecf20Sopenharmony_ci
57518c2ecf20Sopenharmony_ci	return rc;
57528c2ecf20Sopenharmony_ci}
57538c2ecf20Sopenharmony_ci
57548c2ecf20Sopenharmony_ciint
57558c2ecf20Sopenharmony_ciCIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
57568c2ecf20Sopenharmony_ci			  bool delete_file, __u16 fid, __u32 pid_of_opener)
57578c2ecf20Sopenharmony_ci{
57588c2ecf20Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
57598c2ecf20Sopenharmony_ci	char *data_offset;
57608c2ecf20Sopenharmony_ci	int rc = 0;
57618c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
57628c2ecf20Sopenharmony_ci
57638c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
57648c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
57658c2ecf20Sopenharmony_ci
57668c2ecf20Sopenharmony_ci	if (rc)
57678c2ecf20Sopenharmony_ci		return rc;
57688c2ecf20Sopenharmony_ci
57698c2ecf20Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
57708c2ecf20Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
57718c2ecf20Sopenharmony_ci
57728c2ecf20Sopenharmony_ci	params = 6;
57738c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
57748c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
57758c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
57768c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
57778c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
57788c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
57798c2ecf20Sopenharmony_ci	offset = param_offset + params;
57808c2ecf20Sopenharmony_ci
57818c2ecf20Sopenharmony_ci	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
57828c2ecf20Sopenharmony_ci
57838c2ecf20Sopenharmony_ci	count = 1;
57848c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
57858c2ecf20Sopenharmony_ci	/* BB find max SMB PDU from sess */
57868c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
57878c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
57888c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
57898c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
57908c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
57918c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
57928c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
57938c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
57948c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
57958c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
57968c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
57978c2ecf20Sopenharmony_ci	pSMB->Fid = fid;
57988c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
57998c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
58008c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
58018c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
58028c2ecf20Sopenharmony_ci	*data_offset = delete_file ? 1 : 0;
58038c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
58048c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
58058c2ecf20Sopenharmony_ci	if (rc)
58068c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
58078c2ecf20Sopenharmony_ci
58088c2ecf20Sopenharmony_ci	return rc;
58098c2ecf20Sopenharmony_ci}
58108c2ecf20Sopenharmony_ci
58118c2ecf20Sopenharmony_cistatic int
58128c2ecf20Sopenharmony_ciCIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
58138c2ecf20Sopenharmony_ci		     const char *fileName, const FILE_BASIC_INFO *data,
58148c2ecf20Sopenharmony_ci		     const struct nls_table *nls_codepage,
58158c2ecf20Sopenharmony_ci		     struct cifs_sb_info *cifs_sb)
58168c2ecf20Sopenharmony_ci{
58178c2ecf20Sopenharmony_ci	int oplock = 0;
58188c2ecf20Sopenharmony_ci	struct cifs_open_parms oparms;
58198c2ecf20Sopenharmony_ci	struct cifs_fid fid;
58208c2ecf20Sopenharmony_ci	int rc;
58218c2ecf20Sopenharmony_ci
58228c2ecf20Sopenharmony_ci	oparms.tcon = tcon;
58238c2ecf20Sopenharmony_ci	oparms.cifs_sb = cifs_sb;
58248c2ecf20Sopenharmony_ci	oparms.desired_access = GENERIC_WRITE;
58258c2ecf20Sopenharmony_ci	oparms.create_options = cifs_create_options(cifs_sb, 0);
58268c2ecf20Sopenharmony_ci	oparms.disposition = FILE_OPEN;
58278c2ecf20Sopenharmony_ci	oparms.path = fileName;
58288c2ecf20Sopenharmony_ci	oparms.fid = &fid;
58298c2ecf20Sopenharmony_ci	oparms.reconnect = false;
58308c2ecf20Sopenharmony_ci
58318c2ecf20Sopenharmony_ci	rc = CIFS_open(xid, &oparms, &oplock, NULL);
58328c2ecf20Sopenharmony_ci	if (rc)
58338c2ecf20Sopenharmony_ci		goto out;
58348c2ecf20Sopenharmony_ci
58358c2ecf20Sopenharmony_ci	rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
58368c2ecf20Sopenharmony_ci	CIFSSMBClose(xid, tcon, fid.netfid);
58378c2ecf20Sopenharmony_ciout:
58388c2ecf20Sopenharmony_ci
58398c2ecf20Sopenharmony_ci	return rc;
58408c2ecf20Sopenharmony_ci}
58418c2ecf20Sopenharmony_ci
58428c2ecf20Sopenharmony_ciint
58438c2ecf20Sopenharmony_ciCIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
58448c2ecf20Sopenharmony_ci		   const char *fileName, const FILE_BASIC_INFO *data,
58458c2ecf20Sopenharmony_ci		   const struct nls_table *nls_codepage,
58468c2ecf20Sopenharmony_ci		     struct cifs_sb_info *cifs_sb)
58478c2ecf20Sopenharmony_ci{
58488c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
58498c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
58508c2ecf20Sopenharmony_ci	int name_len;
58518c2ecf20Sopenharmony_ci	int rc = 0;
58528c2ecf20Sopenharmony_ci	int bytes_returned = 0;
58538c2ecf20Sopenharmony_ci	char *data_offset;
58548c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, byte_count, count;
58558c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
58568c2ecf20Sopenharmony_ci
58578c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SetTimes\n");
58588c2ecf20Sopenharmony_ci
58598c2ecf20Sopenharmony_ciSetTimesRetry:
58608c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
58618c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
58628c2ecf20Sopenharmony_ci	if (rc)
58638c2ecf20Sopenharmony_ci		return rc;
58648c2ecf20Sopenharmony_ci
58658c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
58668c2ecf20Sopenharmony_ci		name_len =
58678c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
58688c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
58698c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
58708c2ecf20Sopenharmony_ci		name_len *= 2;
58718c2ecf20Sopenharmony_ci	} else {
58728c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fileName);
58738c2ecf20Sopenharmony_ci	}
58748c2ecf20Sopenharmony_ci
58758c2ecf20Sopenharmony_ci	params = 6 + name_len;
58768c2ecf20Sopenharmony_ci	count = sizeof(FILE_BASIC_INFO);
58778c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
58788c2ecf20Sopenharmony_ci	/* BB find max SMB PDU from sess structure BB */
58798c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
58808c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
58818c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
58828c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
58838c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
58848c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
58858c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
58868c2ecf20Sopenharmony_ci				InformationLevel) - 4;
58878c2ecf20Sopenharmony_ci	offset = param_offset + params;
58888c2ecf20Sopenharmony_ci	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
58898c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
58908c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
58918c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
58928c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
58938c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
58948c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
58958c2ecf20Sopenharmony_ci
58968c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
58978c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
58988c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
58998c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
59008c2ecf20Sopenharmony_ci	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
59018c2ecf20Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
59028c2ecf20Sopenharmony_ci	else
59038c2ecf20Sopenharmony_ci		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
59048c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
59058c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
59068c2ecf20Sopenharmony_ci	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
59078c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
59088c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
59098c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
59108c2ecf20Sopenharmony_ci	if (rc)
59118c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
59128c2ecf20Sopenharmony_ci
59138c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
59148c2ecf20Sopenharmony_ci
59158c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
59168c2ecf20Sopenharmony_ci		goto SetTimesRetry;
59178c2ecf20Sopenharmony_ci
59188c2ecf20Sopenharmony_ci	if (rc == -EOPNOTSUPP)
59198c2ecf20Sopenharmony_ci		return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
59208c2ecf20Sopenharmony_ci					    nls_codepage, cifs_sb);
59218c2ecf20Sopenharmony_ci
59228c2ecf20Sopenharmony_ci	return rc;
59238c2ecf20Sopenharmony_ci}
59248c2ecf20Sopenharmony_ci
59258c2ecf20Sopenharmony_ci/* Can not be used to set time stamps yet (due to old DOS time format) */
59268c2ecf20Sopenharmony_ci/* Can be used to set attributes */
59278c2ecf20Sopenharmony_ci#if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
59288c2ecf20Sopenharmony_ci	  handling it anyway and NT4 was what we thought it would be needed for
59298c2ecf20Sopenharmony_ci	  Do not delete it until we prove whether needed for Win9x though */
59308c2ecf20Sopenharmony_ciint
59318c2ecf20Sopenharmony_ciCIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
59328c2ecf20Sopenharmony_ci		__u16 dos_attrs, const struct nls_table *nls_codepage)
59338c2ecf20Sopenharmony_ci{
59348c2ecf20Sopenharmony_ci	SETATTR_REQ *pSMB = NULL;
59358c2ecf20Sopenharmony_ci	SETATTR_RSP *pSMBr = NULL;
59368c2ecf20Sopenharmony_ci	int rc = 0;
59378c2ecf20Sopenharmony_ci	int bytes_returned;
59388c2ecf20Sopenharmony_ci	int name_len;
59398c2ecf20Sopenharmony_ci
59408c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SetAttrLegacy\n");
59418c2ecf20Sopenharmony_ci
59428c2ecf20Sopenharmony_ciSetAttrLgcyRetry:
59438c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
59448c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
59458c2ecf20Sopenharmony_ci	if (rc)
59468c2ecf20Sopenharmony_ci		return rc;
59478c2ecf20Sopenharmony_ci
59488c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
59498c2ecf20Sopenharmony_ci		name_len =
59508c2ecf20Sopenharmony_ci			ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
59518c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage);
59528c2ecf20Sopenharmony_ci		name_len++;     /* trailing null */
59538c2ecf20Sopenharmony_ci		name_len *= 2;
59548c2ecf20Sopenharmony_ci	} else {
59558c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->fileName, fileName);
59568c2ecf20Sopenharmony_ci	}
59578c2ecf20Sopenharmony_ci	pSMB->attr = cpu_to_le16(dos_attrs);
59588c2ecf20Sopenharmony_ci	pSMB->BufferFormat = 0x04;
59598c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, name_len + 1);
59608c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(name_len + 1);
59618c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
59628c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
59638c2ecf20Sopenharmony_ci	if (rc)
59648c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
59658c2ecf20Sopenharmony_ci
59668c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
59678c2ecf20Sopenharmony_ci
59688c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
59698c2ecf20Sopenharmony_ci		goto SetAttrLgcyRetry;
59708c2ecf20Sopenharmony_ci
59718c2ecf20Sopenharmony_ci	return rc;
59728c2ecf20Sopenharmony_ci}
59738c2ecf20Sopenharmony_ci#endif /* temporarily unneeded SetAttr legacy function */
59748c2ecf20Sopenharmony_ci
59758c2ecf20Sopenharmony_cistatic void
59768c2ecf20Sopenharmony_cicifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
59778c2ecf20Sopenharmony_ci			const struct cifs_unix_set_info_args *args)
59788c2ecf20Sopenharmony_ci{
59798c2ecf20Sopenharmony_ci	u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
59808c2ecf20Sopenharmony_ci	u64 mode = args->mode;
59818c2ecf20Sopenharmony_ci
59828c2ecf20Sopenharmony_ci	if (uid_valid(args->uid))
59838c2ecf20Sopenharmony_ci		uid = from_kuid(&init_user_ns, args->uid);
59848c2ecf20Sopenharmony_ci	if (gid_valid(args->gid))
59858c2ecf20Sopenharmony_ci		gid = from_kgid(&init_user_ns, args->gid);
59868c2ecf20Sopenharmony_ci
59878c2ecf20Sopenharmony_ci	/*
59888c2ecf20Sopenharmony_ci	 * Samba server ignores set of file size to zero due to bugs in some
59898c2ecf20Sopenharmony_ci	 * older clients, but we should be precise - we use SetFileSize to
59908c2ecf20Sopenharmony_ci	 * set file size and do not want to truncate file size to zero
59918c2ecf20Sopenharmony_ci	 * accidentally as happened on one Samba server beta by putting
59928c2ecf20Sopenharmony_ci	 * zero instead of -1 here
59938c2ecf20Sopenharmony_ci	 */
59948c2ecf20Sopenharmony_ci	data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
59958c2ecf20Sopenharmony_ci	data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
59968c2ecf20Sopenharmony_ci	data_offset->LastStatusChange = cpu_to_le64(args->ctime);
59978c2ecf20Sopenharmony_ci	data_offset->LastAccessTime = cpu_to_le64(args->atime);
59988c2ecf20Sopenharmony_ci	data_offset->LastModificationTime = cpu_to_le64(args->mtime);
59998c2ecf20Sopenharmony_ci	data_offset->Uid = cpu_to_le64(uid);
60008c2ecf20Sopenharmony_ci	data_offset->Gid = cpu_to_le64(gid);
60018c2ecf20Sopenharmony_ci	/* better to leave device as zero when it is  */
60028c2ecf20Sopenharmony_ci	data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
60038c2ecf20Sopenharmony_ci	data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
60048c2ecf20Sopenharmony_ci	data_offset->Permissions = cpu_to_le64(mode);
60058c2ecf20Sopenharmony_ci
60068c2ecf20Sopenharmony_ci	if (S_ISREG(mode))
60078c2ecf20Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_FILE);
60088c2ecf20Sopenharmony_ci	else if (S_ISDIR(mode))
60098c2ecf20Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_DIR);
60108c2ecf20Sopenharmony_ci	else if (S_ISLNK(mode))
60118c2ecf20Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
60128c2ecf20Sopenharmony_ci	else if (S_ISCHR(mode))
60138c2ecf20Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
60148c2ecf20Sopenharmony_ci	else if (S_ISBLK(mode))
60158c2ecf20Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
60168c2ecf20Sopenharmony_ci	else if (S_ISFIFO(mode))
60178c2ecf20Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_FIFO);
60188c2ecf20Sopenharmony_ci	else if (S_ISSOCK(mode))
60198c2ecf20Sopenharmony_ci		data_offset->Type = cpu_to_le32(UNIX_SOCKET);
60208c2ecf20Sopenharmony_ci}
60218c2ecf20Sopenharmony_ci
60228c2ecf20Sopenharmony_ciint
60238c2ecf20Sopenharmony_ciCIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
60248c2ecf20Sopenharmony_ci		       const struct cifs_unix_set_info_args *args,
60258c2ecf20Sopenharmony_ci		       u16 fid, u32 pid_of_opener)
60268c2ecf20Sopenharmony_ci{
60278c2ecf20Sopenharmony_ci	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
60288c2ecf20Sopenharmony_ci	char *data_offset;
60298c2ecf20Sopenharmony_ci	int rc = 0;
60308c2ecf20Sopenharmony_ci	u16 params, param_offset, offset, byte_count, count;
60318c2ecf20Sopenharmony_ci
60328c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
60338c2ecf20Sopenharmony_ci	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
60348c2ecf20Sopenharmony_ci
60358c2ecf20Sopenharmony_ci	if (rc)
60368c2ecf20Sopenharmony_ci		return rc;
60378c2ecf20Sopenharmony_ci
60388c2ecf20Sopenharmony_ci	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
60398c2ecf20Sopenharmony_ci	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
60408c2ecf20Sopenharmony_ci
60418c2ecf20Sopenharmony_ci	params = 6;
60428c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
60438c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
60448c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
60458c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
60468c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
60478c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
60488c2ecf20Sopenharmony_ci	offset = param_offset + params;
60498c2ecf20Sopenharmony_ci
60508c2ecf20Sopenharmony_ci	data_offset = (char *)pSMB +
60518c2ecf20Sopenharmony_ci			offsetof(struct smb_hdr, Protocol) + offset;
60528c2ecf20Sopenharmony_ci
60538c2ecf20Sopenharmony_ci	count = sizeof(FILE_UNIX_BASIC_INFO);
60548c2ecf20Sopenharmony_ci
60558c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
60568c2ecf20Sopenharmony_ci	/* BB find max SMB PDU from sess */
60578c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
60588c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
60598c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
60608c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
60618c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
60628c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
60638c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
60648c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
60658c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
60668c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
60678c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
60688c2ecf20Sopenharmony_ci	pSMB->Fid = fid;
60698c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
60708c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
60718c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
60728c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
60738c2ecf20Sopenharmony_ci
60748c2ecf20Sopenharmony_ci	cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
60758c2ecf20Sopenharmony_ci
60768c2ecf20Sopenharmony_ci	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
60778c2ecf20Sopenharmony_ci	cifs_small_buf_release(pSMB);
60788c2ecf20Sopenharmony_ci	if (rc)
60798c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
60808c2ecf20Sopenharmony_ci			 rc);
60818c2ecf20Sopenharmony_ci
60828c2ecf20Sopenharmony_ci	/* Note: On -EAGAIN error only caller can retry on handle based calls
60838c2ecf20Sopenharmony_ci		since file handle passed in no longer valid */
60848c2ecf20Sopenharmony_ci
60858c2ecf20Sopenharmony_ci	return rc;
60868c2ecf20Sopenharmony_ci}
60878c2ecf20Sopenharmony_ci
60888c2ecf20Sopenharmony_ciint
60898c2ecf20Sopenharmony_ciCIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
60908c2ecf20Sopenharmony_ci		       const char *file_name,
60918c2ecf20Sopenharmony_ci		       const struct cifs_unix_set_info_args *args,
60928c2ecf20Sopenharmony_ci		       const struct nls_table *nls_codepage, int remap)
60938c2ecf20Sopenharmony_ci{
60948c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_REQ *pSMB = NULL;
60958c2ecf20Sopenharmony_ci	TRANSACTION2_SPI_RSP *pSMBr = NULL;
60968c2ecf20Sopenharmony_ci	int name_len;
60978c2ecf20Sopenharmony_ci	int rc = 0;
60988c2ecf20Sopenharmony_ci	int bytes_returned = 0;
60998c2ecf20Sopenharmony_ci	FILE_UNIX_BASIC_INFO *data_offset;
61008c2ecf20Sopenharmony_ci	__u16 params, param_offset, offset, count, byte_count;
61018c2ecf20Sopenharmony_ci
61028c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SetUID/GID/Mode\n");
61038c2ecf20Sopenharmony_cisetPermsRetry:
61048c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
61058c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
61068c2ecf20Sopenharmony_ci	if (rc)
61078c2ecf20Sopenharmony_ci		return rc;
61088c2ecf20Sopenharmony_ci
61098c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
61108c2ecf20Sopenharmony_ci		name_len =
61118c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
61128c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
61138c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
61148c2ecf20Sopenharmony_ci		name_len *= 2;
61158c2ecf20Sopenharmony_ci	} else {
61168c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, file_name);
61178c2ecf20Sopenharmony_ci	}
61188c2ecf20Sopenharmony_ci
61198c2ecf20Sopenharmony_ci	params = 6 + name_len;
61208c2ecf20Sopenharmony_ci	count = sizeof(FILE_UNIX_BASIC_INFO);
61218c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
61228c2ecf20Sopenharmony_ci	/* BB find max SMB PDU from sess structure BB */
61238c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
61248c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
61258c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
61268c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
61278c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
61288c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
61298c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
61308c2ecf20Sopenharmony_ci				InformationLevel) - 4;
61318c2ecf20Sopenharmony_ci	offset = param_offset + params;
61328c2ecf20Sopenharmony_ci	data_offset =
61338c2ecf20Sopenharmony_ci	    (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
61348c2ecf20Sopenharmony_ci				      offset);
61358c2ecf20Sopenharmony_ci	memset(data_offset, 0, count);
61368c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
61378c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
61388c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
61398c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
61408c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
61418c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
61428c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
61438c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
61448c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
61458c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
61468c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
61478c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
61488c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
61498c2ecf20Sopenharmony_ci
61508c2ecf20Sopenharmony_ci	cifs_fill_unix_set_info(data_offset, args);
61518c2ecf20Sopenharmony_ci
61528c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
61538c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
61548c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
61558c2ecf20Sopenharmony_ci	if (rc)
61568c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
61578c2ecf20Sopenharmony_ci
61588c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
61598c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
61608c2ecf20Sopenharmony_ci		goto setPermsRetry;
61618c2ecf20Sopenharmony_ci	return rc;
61628c2ecf20Sopenharmony_ci}
61638c2ecf20Sopenharmony_ci
61648c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_XATTR
61658c2ecf20Sopenharmony_ci/*
61668c2ecf20Sopenharmony_ci * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
61678c2ecf20Sopenharmony_ci * function used by listxattr and getxattr type calls. When ea_name is set,
61688c2ecf20Sopenharmony_ci * it looks for that attribute name and stuffs that value into the EAData
61698c2ecf20Sopenharmony_ci * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
61708c2ecf20Sopenharmony_ci * buffer. In both cases, the return value is either the length of the
61718c2ecf20Sopenharmony_ci * resulting data or a negative error code. If EAData is a NULL pointer then
61728c2ecf20Sopenharmony_ci * the data isn't copied to it, but the length is returned.
61738c2ecf20Sopenharmony_ci */
61748c2ecf20Sopenharmony_cissize_t
61758c2ecf20Sopenharmony_ciCIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
61768c2ecf20Sopenharmony_ci		const unsigned char *searchName, const unsigned char *ea_name,
61778c2ecf20Sopenharmony_ci		char *EAData, size_t buf_size,
61788c2ecf20Sopenharmony_ci		struct cifs_sb_info *cifs_sb)
61798c2ecf20Sopenharmony_ci{
61808c2ecf20Sopenharmony_ci		/* BB assumes one setup word */
61818c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_REQ *pSMB = NULL;
61828c2ecf20Sopenharmony_ci	TRANSACTION2_QPI_RSP *pSMBr = NULL;
61838c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
61848c2ecf20Sopenharmony_ci	struct nls_table *nls_codepage = cifs_sb->local_nls;
61858c2ecf20Sopenharmony_ci	int rc = 0;
61868c2ecf20Sopenharmony_ci	int bytes_returned;
61878c2ecf20Sopenharmony_ci	int list_len;
61888c2ecf20Sopenharmony_ci	struct fealist *ea_response_data;
61898c2ecf20Sopenharmony_ci	struct fea *temp_fea;
61908c2ecf20Sopenharmony_ci	char *temp_ptr;
61918c2ecf20Sopenharmony_ci	char *end_of_smb;
61928c2ecf20Sopenharmony_ci	__u16 params, byte_count, data_offset;
61938c2ecf20Sopenharmony_ci	unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
61948c2ecf20Sopenharmony_ci
61958c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
61968c2ecf20Sopenharmony_ciQAllEAsRetry:
61978c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
61988c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
61998c2ecf20Sopenharmony_ci	if (rc)
62008c2ecf20Sopenharmony_ci		return rc;
62018c2ecf20Sopenharmony_ci
62028c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
62038c2ecf20Sopenharmony_ci		list_len =
62048c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
62058c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
62068c2ecf20Sopenharmony_ci		list_len++;	/* trailing null */
62078c2ecf20Sopenharmony_ci		list_len *= 2;
62088c2ecf20Sopenharmony_ci	} else {
62098c2ecf20Sopenharmony_ci		list_len = copy_path_name(pSMB->FileName, searchName);
62108c2ecf20Sopenharmony_ci	}
62118c2ecf20Sopenharmony_ci
62128c2ecf20Sopenharmony_ci	params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
62138c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = 0;
62148c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
62158c2ecf20Sopenharmony_ci	/* BB find exact max SMB PDU from sess structure BB */
62168c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
62178c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
62188c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
62198c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
62208c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
62218c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
62228c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(offsetof(
62238c2ecf20Sopenharmony_ci	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
62248c2ecf20Sopenharmony_ci	pSMB->DataCount = 0;
62258c2ecf20Sopenharmony_ci	pSMB->DataOffset = 0;
62268c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
62278c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
62288c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
62298c2ecf20Sopenharmony_ci	byte_count = params + 1 /* pad */ ;
62308c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = cpu_to_le16(params);
62318c2ecf20Sopenharmony_ci	pSMB->ParameterCount = pSMB->TotalParameterCount;
62328c2ecf20Sopenharmony_ci	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
62338c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
62348c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
62358c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
62368c2ecf20Sopenharmony_ci
62378c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
62388c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
62398c2ecf20Sopenharmony_ci	if (rc) {
62408c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
62418c2ecf20Sopenharmony_ci		goto QAllEAsOut;
62428c2ecf20Sopenharmony_ci	}
62438c2ecf20Sopenharmony_ci
62448c2ecf20Sopenharmony_ci
62458c2ecf20Sopenharmony_ci	/* BB also check enough total bytes returned */
62468c2ecf20Sopenharmony_ci	/* BB we need to improve the validity checking
62478c2ecf20Sopenharmony_ci	of these trans2 responses */
62488c2ecf20Sopenharmony_ci
62498c2ecf20Sopenharmony_ci	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
62508c2ecf20Sopenharmony_ci	if (rc || get_bcc(&pSMBr->hdr) < 4) {
62518c2ecf20Sopenharmony_ci		rc = -EIO;	/* bad smb */
62528c2ecf20Sopenharmony_ci		goto QAllEAsOut;
62538c2ecf20Sopenharmony_ci	}
62548c2ecf20Sopenharmony_ci
62558c2ecf20Sopenharmony_ci	/* check that length of list is not more than bcc */
62568c2ecf20Sopenharmony_ci	/* check that each entry does not go beyond length
62578c2ecf20Sopenharmony_ci	   of list */
62588c2ecf20Sopenharmony_ci	/* check that each element of each entry does not
62598c2ecf20Sopenharmony_ci	   go beyond end of list */
62608c2ecf20Sopenharmony_ci	/* validate_trans2_offsets() */
62618c2ecf20Sopenharmony_ci	/* BB check if start of smb + data_offset > &bcc+ bcc */
62628c2ecf20Sopenharmony_ci
62638c2ecf20Sopenharmony_ci	data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
62648c2ecf20Sopenharmony_ci	ea_response_data = (struct fealist *)
62658c2ecf20Sopenharmony_ci				(((char *) &pSMBr->hdr.Protocol) + data_offset);
62668c2ecf20Sopenharmony_ci
62678c2ecf20Sopenharmony_ci	list_len = le32_to_cpu(ea_response_data->list_len);
62688c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "ea length %d\n", list_len);
62698c2ecf20Sopenharmony_ci	if (list_len <= 8) {
62708c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "empty EA list returned from server\n");
62718c2ecf20Sopenharmony_ci		/* didn't find the named attribute */
62728c2ecf20Sopenharmony_ci		if (ea_name)
62738c2ecf20Sopenharmony_ci			rc = -ENODATA;
62748c2ecf20Sopenharmony_ci		goto QAllEAsOut;
62758c2ecf20Sopenharmony_ci	}
62768c2ecf20Sopenharmony_ci
62778c2ecf20Sopenharmony_ci	/* make sure list_len doesn't go past end of SMB */
62788c2ecf20Sopenharmony_ci	end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
62798c2ecf20Sopenharmony_ci	if ((char *)ea_response_data + list_len > end_of_smb) {
62808c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
62818c2ecf20Sopenharmony_ci		rc = -EIO;
62828c2ecf20Sopenharmony_ci		goto QAllEAsOut;
62838c2ecf20Sopenharmony_ci	}
62848c2ecf20Sopenharmony_ci
62858c2ecf20Sopenharmony_ci	/* account for ea list len */
62868c2ecf20Sopenharmony_ci	list_len -= 4;
62878c2ecf20Sopenharmony_ci	temp_fea = ea_response_data->list;
62888c2ecf20Sopenharmony_ci	temp_ptr = (char *)temp_fea;
62898c2ecf20Sopenharmony_ci	while (list_len > 0) {
62908c2ecf20Sopenharmony_ci		unsigned int name_len;
62918c2ecf20Sopenharmony_ci		__u16 value_len;
62928c2ecf20Sopenharmony_ci
62938c2ecf20Sopenharmony_ci		list_len -= 4;
62948c2ecf20Sopenharmony_ci		temp_ptr += 4;
62958c2ecf20Sopenharmony_ci		/* make sure we can read name_len and value_len */
62968c2ecf20Sopenharmony_ci		if (list_len < 0) {
62978c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "EA entry goes beyond length of list\n");
62988c2ecf20Sopenharmony_ci			rc = -EIO;
62998c2ecf20Sopenharmony_ci			goto QAllEAsOut;
63008c2ecf20Sopenharmony_ci		}
63018c2ecf20Sopenharmony_ci
63028c2ecf20Sopenharmony_ci		name_len = temp_fea->name_len;
63038c2ecf20Sopenharmony_ci		value_len = le16_to_cpu(temp_fea->value_len);
63048c2ecf20Sopenharmony_ci		list_len -= name_len + 1 + value_len;
63058c2ecf20Sopenharmony_ci		if (list_len < 0) {
63068c2ecf20Sopenharmony_ci			cifs_dbg(FYI, "EA entry goes beyond length of list\n");
63078c2ecf20Sopenharmony_ci			rc = -EIO;
63088c2ecf20Sopenharmony_ci			goto QAllEAsOut;
63098c2ecf20Sopenharmony_ci		}
63108c2ecf20Sopenharmony_ci
63118c2ecf20Sopenharmony_ci		if (ea_name) {
63128c2ecf20Sopenharmony_ci			if (ea_name_len == name_len &&
63138c2ecf20Sopenharmony_ci			    memcmp(ea_name, temp_ptr, name_len) == 0) {
63148c2ecf20Sopenharmony_ci				temp_ptr += name_len + 1;
63158c2ecf20Sopenharmony_ci				rc = value_len;
63168c2ecf20Sopenharmony_ci				if (buf_size == 0)
63178c2ecf20Sopenharmony_ci					goto QAllEAsOut;
63188c2ecf20Sopenharmony_ci				if ((size_t)value_len > buf_size) {
63198c2ecf20Sopenharmony_ci					rc = -ERANGE;
63208c2ecf20Sopenharmony_ci					goto QAllEAsOut;
63218c2ecf20Sopenharmony_ci				}
63228c2ecf20Sopenharmony_ci				memcpy(EAData, temp_ptr, value_len);
63238c2ecf20Sopenharmony_ci				goto QAllEAsOut;
63248c2ecf20Sopenharmony_ci			}
63258c2ecf20Sopenharmony_ci		} else {
63268c2ecf20Sopenharmony_ci			/* account for prefix user. and trailing null */
63278c2ecf20Sopenharmony_ci			rc += (5 + 1 + name_len);
63288c2ecf20Sopenharmony_ci			if (rc < (int) buf_size) {
63298c2ecf20Sopenharmony_ci				memcpy(EAData, "user.", 5);
63308c2ecf20Sopenharmony_ci				EAData += 5;
63318c2ecf20Sopenharmony_ci				memcpy(EAData, temp_ptr, name_len);
63328c2ecf20Sopenharmony_ci				EAData += name_len;
63338c2ecf20Sopenharmony_ci				/* null terminate name */
63348c2ecf20Sopenharmony_ci				*EAData = 0;
63358c2ecf20Sopenharmony_ci				++EAData;
63368c2ecf20Sopenharmony_ci			} else if (buf_size == 0) {
63378c2ecf20Sopenharmony_ci				/* skip copy - calc size only */
63388c2ecf20Sopenharmony_ci			} else {
63398c2ecf20Sopenharmony_ci				/* stop before overrun buffer */
63408c2ecf20Sopenharmony_ci				rc = -ERANGE;
63418c2ecf20Sopenharmony_ci				break;
63428c2ecf20Sopenharmony_ci			}
63438c2ecf20Sopenharmony_ci		}
63448c2ecf20Sopenharmony_ci		temp_ptr += name_len + 1 + value_len;
63458c2ecf20Sopenharmony_ci		temp_fea = (struct fea *)temp_ptr;
63468c2ecf20Sopenharmony_ci	}
63478c2ecf20Sopenharmony_ci
63488c2ecf20Sopenharmony_ci	/* didn't find the named attribute */
63498c2ecf20Sopenharmony_ci	if (ea_name)
63508c2ecf20Sopenharmony_ci		rc = -ENODATA;
63518c2ecf20Sopenharmony_ci
63528c2ecf20Sopenharmony_ciQAllEAsOut:
63538c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
63548c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
63558c2ecf20Sopenharmony_ci		goto QAllEAsRetry;
63568c2ecf20Sopenharmony_ci
63578c2ecf20Sopenharmony_ci	return (ssize_t)rc;
63588c2ecf20Sopenharmony_ci}
63598c2ecf20Sopenharmony_ci
63608c2ecf20Sopenharmony_ciint
63618c2ecf20Sopenharmony_ciCIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
63628c2ecf20Sopenharmony_ci	     const char *fileName, const char *ea_name, const void *ea_value,
63638c2ecf20Sopenharmony_ci	     const __u16 ea_value_len, const struct nls_table *nls_codepage,
63648c2ecf20Sopenharmony_ci	     struct cifs_sb_info *cifs_sb)
63658c2ecf20Sopenharmony_ci{
63668c2ecf20Sopenharmony_ci	struct smb_com_transaction2_spi_req *pSMB = NULL;
63678c2ecf20Sopenharmony_ci	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
63688c2ecf20Sopenharmony_ci	struct fealist *parm_data;
63698c2ecf20Sopenharmony_ci	int name_len;
63708c2ecf20Sopenharmony_ci	int rc = 0;
63718c2ecf20Sopenharmony_ci	int bytes_returned = 0;
63728c2ecf20Sopenharmony_ci	__u16 params, param_offset, byte_count, offset, count;
63738c2ecf20Sopenharmony_ci	int remap = cifs_remap(cifs_sb);
63748c2ecf20Sopenharmony_ci
63758c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "In SetEA\n");
63768c2ecf20Sopenharmony_ciSetEARetry:
63778c2ecf20Sopenharmony_ci	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
63788c2ecf20Sopenharmony_ci		      (void **) &pSMBr);
63798c2ecf20Sopenharmony_ci	if (rc)
63808c2ecf20Sopenharmony_ci		return rc;
63818c2ecf20Sopenharmony_ci
63828c2ecf20Sopenharmony_ci	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
63838c2ecf20Sopenharmony_ci		name_len =
63848c2ecf20Sopenharmony_ci		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
63858c2ecf20Sopenharmony_ci				       PATH_MAX, nls_codepage, remap);
63868c2ecf20Sopenharmony_ci		name_len++;	/* trailing null */
63878c2ecf20Sopenharmony_ci		name_len *= 2;
63888c2ecf20Sopenharmony_ci	} else {
63898c2ecf20Sopenharmony_ci		name_len = copy_path_name(pSMB->FileName, fileName);
63908c2ecf20Sopenharmony_ci	}
63918c2ecf20Sopenharmony_ci
63928c2ecf20Sopenharmony_ci	params = 6 + name_len;
63938c2ecf20Sopenharmony_ci
63948c2ecf20Sopenharmony_ci	/* done calculating parms using name_len of file name,
63958c2ecf20Sopenharmony_ci	now use name_len to calculate length of ea name
63968c2ecf20Sopenharmony_ci	we are going to create in the inode xattrs */
63978c2ecf20Sopenharmony_ci	if (ea_name == NULL)
63988c2ecf20Sopenharmony_ci		name_len = 0;
63998c2ecf20Sopenharmony_ci	else
64008c2ecf20Sopenharmony_ci		name_len = strnlen(ea_name, 255);
64018c2ecf20Sopenharmony_ci
64028c2ecf20Sopenharmony_ci	count = sizeof(*parm_data) + ea_value_len + name_len;
64038c2ecf20Sopenharmony_ci	pSMB->MaxParameterCount = cpu_to_le16(2);
64048c2ecf20Sopenharmony_ci	/* BB find max SMB PDU from sess */
64058c2ecf20Sopenharmony_ci	pSMB->MaxDataCount = cpu_to_le16(1000);
64068c2ecf20Sopenharmony_ci	pSMB->MaxSetupCount = 0;
64078c2ecf20Sopenharmony_ci	pSMB->Reserved = 0;
64088c2ecf20Sopenharmony_ci	pSMB->Flags = 0;
64098c2ecf20Sopenharmony_ci	pSMB->Timeout = 0;
64108c2ecf20Sopenharmony_ci	pSMB->Reserved2 = 0;
64118c2ecf20Sopenharmony_ci	param_offset = offsetof(struct smb_com_transaction2_spi_req,
64128c2ecf20Sopenharmony_ci				InformationLevel) - 4;
64138c2ecf20Sopenharmony_ci	offset = param_offset + params;
64148c2ecf20Sopenharmony_ci	pSMB->InformationLevel =
64158c2ecf20Sopenharmony_ci		cpu_to_le16(SMB_SET_FILE_EA);
64168c2ecf20Sopenharmony_ci
64178c2ecf20Sopenharmony_ci	parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
64188c2ecf20Sopenharmony_ci	pSMB->ParameterOffset = cpu_to_le16(param_offset);
64198c2ecf20Sopenharmony_ci	pSMB->DataOffset = cpu_to_le16(offset);
64208c2ecf20Sopenharmony_ci	pSMB->SetupCount = 1;
64218c2ecf20Sopenharmony_ci	pSMB->Reserved3 = 0;
64228c2ecf20Sopenharmony_ci	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
64238c2ecf20Sopenharmony_ci	byte_count = 3 /* pad */  + params + count;
64248c2ecf20Sopenharmony_ci	pSMB->DataCount = cpu_to_le16(count);
64258c2ecf20Sopenharmony_ci	parm_data->list_len = cpu_to_le32(count);
64268c2ecf20Sopenharmony_ci	parm_data->list[0].EA_flags = 0;
64278c2ecf20Sopenharmony_ci	/* we checked above that name len is less than 255 */
64288c2ecf20Sopenharmony_ci	parm_data->list[0].name_len = (__u8)name_len;
64298c2ecf20Sopenharmony_ci	/* EA names are always ASCII */
64308c2ecf20Sopenharmony_ci	if (ea_name)
64318c2ecf20Sopenharmony_ci		strncpy(parm_data->list[0].name, ea_name, name_len);
64328c2ecf20Sopenharmony_ci	parm_data->list[0].name[name_len] = 0;
64338c2ecf20Sopenharmony_ci	parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
64348c2ecf20Sopenharmony_ci	/* caller ensures that ea_value_len is less than 64K but
64358c2ecf20Sopenharmony_ci	we need to ensure that it fits within the smb */
64368c2ecf20Sopenharmony_ci
64378c2ecf20Sopenharmony_ci	/*BB add length check to see if it would fit in
64388c2ecf20Sopenharmony_ci	     negotiated SMB buffer size BB */
64398c2ecf20Sopenharmony_ci	/* if (ea_value_len > buffer_size - 512 (enough for header)) */
64408c2ecf20Sopenharmony_ci	if (ea_value_len)
64418c2ecf20Sopenharmony_ci		memcpy(parm_data->list[0].name+name_len+1,
64428c2ecf20Sopenharmony_ci		       ea_value, ea_value_len);
64438c2ecf20Sopenharmony_ci
64448c2ecf20Sopenharmony_ci	pSMB->TotalDataCount = pSMB->DataCount;
64458c2ecf20Sopenharmony_ci	pSMB->ParameterCount = cpu_to_le16(params);
64468c2ecf20Sopenharmony_ci	pSMB->TotalParameterCount = pSMB->ParameterCount;
64478c2ecf20Sopenharmony_ci	pSMB->Reserved4 = 0;
64488c2ecf20Sopenharmony_ci	inc_rfc1001_len(pSMB, byte_count);
64498c2ecf20Sopenharmony_ci	pSMB->ByteCount = cpu_to_le16(byte_count);
64508c2ecf20Sopenharmony_ci	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
64518c2ecf20Sopenharmony_ci			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
64528c2ecf20Sopenharmony_ci	if (rc)
64538c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
64548c2ecf20Sopenharmony_ci
64558c2ecf20Sopenharmony_ci	cifs_buf_release(pSMB);
64568c2ecf20Sopenharmony_ci
64578c2ecf20Sopenharmony_ci	if (rc == -EAGAIN)
64588c2ecf20Sopenharmony_ci		goto SetEARetry;
64598c2ecf20Sopenharmony_ci
64608c2ecf20Sopenharmony_ci	return rc;
64618c2ecf20Sopenharmony_ci}
64628c2ecf20Sopenharmony_ci#endif
6463