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