blob: 16bd4cf3bceba7f182a656b922e52d0c65059bc6 [file] [log] [blame]
Steve French929be902021-06-18 00:31:49 -05001// SPDX-License-Identifier: LGPL-2.1
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * fs/cifs/cifssmb.c
4 *
Steve Frenchf19159d2010-04-21 04:12:10 +00005 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * Author(s): Steve French (sfrench@us.ibm.com)
7 *
8 * Contains the routines for constructing the SMB PDUs themselves
9 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 */
11
12 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
13 /* These are mostly routines that operate on a pathname, or on a tree id */
14 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000015 /* treated slightly differently for reconnection purposes since we never */
16 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
18#include <linux/fs.h>
19#include <linux/kernel.h>
20#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090021#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040023#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040024#include <linux/swap.h>
25#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080026#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include "cifspdu.h"
28#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000029#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include "cifsproto.h"
31#include "cifs_unicode.h"
32#include "cifs_debug.h"
Pavel Shilovskyd9191312019-12-10 11:44:52 -080033#include "smb2proto.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040034#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070035#include "smbdirect.h"
Paulo Alcantara08744012018-11-14 17:24:29 -020036#ifdef CONFIG_CIFS_DFS_UPCALL
37#include "dfs_cache.h"
38#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40#ifdef CONFIG_CIFS_POSIX
41static struct {
42 int index;
43 char *name;
44} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000045#ifdef CONFIG_CIFS_WEAK_PW_HASH
46 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000047 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000048#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000049 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000050 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 {BAD_PROT, "\2"}
52};
53#else
54static struct {
55 int index;
56 char *name;
57} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000058#ifdef CONFIG_CIFS_WEAK_PW_HASH
59 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000060 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000061#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000062 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 {BAD_PROT, "\2"}
64};
65#endif
66
Steve French39798772006-05-31 22:40:51 +000067/* define the number of elements in the cifs dialect array */
68#ifdef CONFIG_CIFS_POSIX
69#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000070#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000071#else
72#define CIFS_NUM_PROT 2
73#endif /* CIFS_WEAK_PW_HASH */
74#else /* not posix */
75#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000076#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000077#else
78#define CIFS_NUM_PROT 1
79#endif /* CONFIG_CIFS_WEAK_PW_HASH */
80#endif /* CIFS_POSIX */
81
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040082/*
83 * Mark as invalid, all open files on tree connections since they
84 * were closed when session to server was lost.
85 */
86void
87cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040093 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -050094 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040095 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000097 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040098 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
Steve French3afca262016-09-22 18:58:16 -0500100 spin_unlock(&tcon->open_file_lock);
Steve French3d4ef9a2018-04-25 22:19:09 -0500101
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000102 mutex_lock(&tcon->crfid.fid_mutex);
103 tcon->crfid.is_valid = false;
Pavel Shilovskyd9191312019-12-10 11:44:52 -0800104 /* cached handle is not valid, so SMB2_CLOSE won't be sent below */
Ronnie Sahlberg45c0f1a2021-03-09 09:07:29 +1000105 close_cached_dir_lease_locked(&tcon->crfid);
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000106 memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
107 mutex_unlock(&tcon->crfid.fid_mutex);
Steve French3d4ef9a2018-04-25 22:19:09 -0500108
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400109 /*
110 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
111 * to this tcon.
112 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113}
114
Jeff Layton9162ab22009-09-03 12:07:17 -0400115/* reconnect the socket, tcon, and smb session if needed */
116static int
Steve French96daf2b2011-05-27 04:34:02 +0000117cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400118{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400119 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000120 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400121 struct TCP_Server_Info *server;
122 struct nls_table *nls_codepage;
Paulo Alcantara08744012018-11-14 17:24:29 -0200123 int retries;
Jeff Layton9162ab22009-09-03 12:07:17 -0400124
125 /*
126 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
127 * tcp and smb session status done differently for those three - in the
128 * calling routine
129 */
130 if (!tcon)
131 return 0;
132
133 ses = tcon->ses;
134 server = ses->server;
135
136 /*
137 * only tree disconnect, open, and write, (and ulogoff which does not
138 * have tcon) are allowed as we start force umount
139 */
140 if (tcon->tidStatus == CifsExiting) {
141 if (smb_command != SMB_COM_WRITE_ANDX &&
142 smb_command != SMB_COM_OPEN_ANDX &&
143 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500144 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
145 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400146 return -ENODEV;
147 }
148 }
149
Paulo Alcantara08744012018-11-14 17:24:29 -0200150 retries = server->nr_targets;
151
Jeff Layton9162ab22009-09-03 12:07:17 -0400152 /*
Paulo Alcantara08744012018-11-14 17:24:29 -0200153 * Give demultiplex thread up to 10 seconds to each target available for
154 * reconnect -- should be greater than cifs socket timeout which is 7
155 * seconds.
Jeff Layton9162ab22009-09-03 12:07:17 -0400156 */
157 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300158 rc = wait_event_interruptible_timeout(server->response_q,
159 (server->tcpStatus != CifsNeedReconnect),
160 10 * HZ);
161 if (rc < 0) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700162 cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
163 __func__);
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300164 return -ERESTARTSYS;
165 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400166
Steve Frenchfd88ce92011-04-12 01:01:14 +0000167 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400168 if (server->tcpStatus != CifsNeedReconnect)
169 break;
170
Ronnie Sahlberg09c40b12020-02-06 13:55:19 +1000171 if (retries && --retries)
Paulo Alcantara08744012018-11-14 17:24:29 -0200172 continue;
173
Jeff Layton9162ab22009-09-03 12:07:17 -0400174 /*
175 * on "soft" mounts we wait once. Hard mounts keep
176 * retrying until process is killed or server comes
177 * back on-line
178 */
Jeff Laytond4025392011-02-07 08:54:35 -0500179 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500180 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400181 return -EHOSTDOWN;
182 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200183 retries = server->nr_targets;
Jeff Layton9162ab22009-09-03 12:07:17 -0400184 }
185
186 if (!ses->need_reconnect && !tcon->need_reconnect)
187 return 0;
188
189 nls_codepage = load_nls_default();
190
191 /*
192 * need to prevent multiple threads trying to simultaneously
193 * reconnect the same SMB session
194 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000195 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200196
197 /*
198 * Recheck after acquire mutex. If another thread is negotiating
199 * and the server never sends an answer the socket will be closed
200 * and tcpStatus set to reconnect.
201 */
202 if (server->tcpStatus == CifsNeedReconnect) {
203 rc = -EHOSTDOWN;
204 mutex_unlock(&ses->session_mutex);
205 goto out;
206 }
207
Jeff Layton198b5682010-04-24 07:57:48 -0400208 rc = cifs_negotiate_protocol(0, ses);
209 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400210 rc = cifs_setup_session(0, ses, nls_codepage);
211
212 /* do we need to reconnect tcon? */
213 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000214 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400215 goto out;
216 }
217
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400218 cifs_mark_open_files_invalid(tcon);
Stefan Metzmacher565674d2020-07-21 09:36:38 -0300219 rc = cifs_tree_connect(0, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000220 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500221 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400222
Steve Frenchc318e6c2018-04-04 14:08:52 -0500223 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700224 pr_warn_once("reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400225 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500226 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400227
Jeff Layton9162ab22009-09-03 12:07:17 -0400228 atomic_inc(&tconInfoReconnectCount);
229
230 /* tell server Unix caps we support */
Stefan Metzmacher864138c2020-02-24 14:15:00 +0100231 if (cap_unix(ses))
Jeff Layton9162ab22009-09-03 12:07:17 -0400232 reset_cifs_unix_caps(0, tcon, NULL, NULL);
233
234 /*
235 * Removed call to reopen open files here. It is safer (and faster) to
236 * reopen files one at a time as needed in read and write.
237 *
238 * FIXME: what about file locks? don't we need to reclaim them ASAP?
239 */
240
241out:
242 /*
243 * Check if handle based operation so we know whether we can continue
244 * or not without returning to caller to reset file handle
245 */
246 switch (smb_command) {
247 case SMB_COM_READ_ANDX:
248 case SMB_COM_WRITE_ANDX:
249 case SMB_COM_CLOSE:
250 case SMB_COM_FIND_CLOSE2:
251 case SMB_COM_LOCKING_ANDX:
252 rc = -EAGAIN;
253 }
254
255 unload_nls(nls_codepage);
256 return rc;
257}
258
Steve Frenchad7a2922008-02-07 23:25:02 +0000259/* Allocate and return pointer to an SMB request buffer, and set basic
260 SMB information in the SMB header. If the return code is zero, this
261 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262static int
Steve French96daf2b2011-05-27 04:34:02 +0000263small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000264 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
Jeff Laytonf5695992010-09-29 15:27:08 -0400266 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Jeff Layton9162ab22009-09-03 12:07:17 -0400268 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000269 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 return rc;
271
272 *request_buf = cifs_small_buf_get();
273 if (*request_buf == NULL) {
274 /* BB should we add a retry in here if not a writepage? */
275 return -ENOMEM;
276 }
277
Steve French63135e02007-07-17 17:34:02 +0000278 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000279 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Steve French790fe572007-07-07 19:25:05 +0000281 if (tcon != NULL)
282 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700283
Jeff Laytonf5695992010-09-29 15:27:08 -0400284 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000285}
286
Steve French12b3b8f2006-02-09 21:12:47 +0000287int
Steve French50c2f752007-07-13 00:33:32 +0000288small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000289 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000290{
291 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000292 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000293
Steve French5815449d2006-02-14 01:36:20 +0000294 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000295 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000296 return rc;
297
Steve French04fdabe2006-02-10 05:52:50 +0000298 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400299 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000300 if (ses->capabilities & CAP_UNICODE)
301 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000302 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000303 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
304
305 /* uid, tid can stay at zero as set in header assemble */
306
Steve French50c2f752007-07-13 00:33:32 +0000307 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000308 this function is used after 1st of session setup requests */
309
310 return rc;
311}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313/* If the return code is zero, this function must fill in request_buf pointer */
314static int
Steve French96daf2b2011-05-27 04:34:02 +0000315__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400316 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 *request_buf = cifs_buf_get();
319 if (*request_buf == NULL) {
320 /* BB should we add a retry in here if not a writepage? */
321 return -ENOMEM;
322 }
323 /* Although the original thought was we needed the response buf for */
324 /* potential retries of smb operations it turns out we can determine */
325 /* from the mid flags when the request buffer can be resent without */
326 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000327 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000328 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000331 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Steve French790fe572007-07-07 19:25:05 +0000333 if (tcon != NULL)
334 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700335
Jeff Laytonf5695992010-09-29 15:27:08 -0400336 return 0;
337}
338
339/* If the return code is zero, this function must fill in request_buf pointer */
340static int
Steve French96daf2b2011-05-27 04:34:02 +0000341smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400342 void **request_buf, void **response_buf)
343{
344 int rc;
345
346 rc = cifs_reconnect_tcon(tcon, smb_command);
347 if (rc)
348 return rc;
349
350 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
351}
352
353static int
Steve French96daf2b2011-05-27 04:34:02 +0000354smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400355 void **request_buf, void **response_buf)
356{
357 if (tcon->ses->need_reconnect || tcon->need_reconnect)
358 return -EHOSTDOWN;
359
360 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
Steve French50c2f752007-07-13 00:33:32 +0000363static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
Jeff Layton12df83c2011-01-20 13:36:51 -0500365 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 /* check for plausible wct */
368 if (pSMB->hdr.WordCount < 10)
369 goto vt2_err;
370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500372 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
373 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
374 goto vt2_err;
375
Jeff Layton12df83c2011-01-20 13:36:51 -0500376 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
377 if (total_size >= 512)
378 goto vt2_err;
379
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400380 /* check that bcc is at least as big as parms + data, and that it is
381 * less than negotiated smb buffer
382 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500383 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
384 if (total_size > get_bcc(&pSMB->hdr) ||
385 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
386 goto vt2_err;
387
388 return 0;
389vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000390 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500392 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393}
Jeff Layton690c5222011-01-20 13:36:51 -0500394
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400395static int
Jeff Layton3f618222013-06-12 19:52:14 -0500396decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400397{
398 int rc = 0;
399 u16 count;
400 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500401 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400402
403 count = get_bcc(&pSMBr->hdr);
404 if (count < SMB1_CLIENT_GUID_SIZE)
405 return -EIO;
406
407 spin_lock(&cifs_tcp_ses_lock);
408 if (server->srv_count > 1) {
409 spin_unlock(&cifs_tcp_ses_lock);
410 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
411 cifs_dbg(FYI, "server UID changed\n");
412 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
413 }
414 } else {
415 spin_unlock(&cifs_tcp_ses_lock);
416 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
417 }
418
419 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500420 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400421 } else {
422 count -= SMB1_CLIENT_GUID_SIZE;
423 rc = decode_negTokenInit(
424 pSMBr->u.extended_response.SecurityBlob, count, server);
425 if (rc != 1)
426 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400427 }
428
429 return 0;
430}
431
Jeff Layton9ddec562013-05-26 07:00:58 -0400432int
Jeff Layton38d77c52013-05-26 07:01:00 -0400433cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400434{
Jeff Layton502858822013-06-27 12:45:00 -0400435 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
436 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400437 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
438
439 /*
440 * Is signing required by mnt options? If not then check
441 * global_secflags to see if it is there.
442 */
443 if (!mnt_sign_required)
444 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
445 CIFSSEC_MUST_SIGN);
446
447 /*
448 * If signing is required then it's automatically enabled too,
449 * otherwise, check to see if the secflags allow it.
450 */
451 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
452 (global_secflags & CIFSSEC_MAY_SIGN);
453
454 /* If server requires signing, does client allow it? */
455 if (srv_sign_required) {
456 if (!mnt_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700457 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400458 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400459 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400460 server->sign = true;
461 }
462
463 /* If client requires signing, does server allow it? */
464 if (mnt_sign_required) {
465 if (!srv_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700466 cifs_dbg(VFS, "Server does not support signing!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400467 return -ENOTSUPP;
468 }
469 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400470 }
471
Long Libb4c0412018-04-17 12:17:08 -0700472 if (cifs_rdma_enabled(server) && server->sign)
Joe Perchesa0a30362020-04-14 22:42:53 -0700473 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");
Long Libb4c0412018-04-17 12:17:08 -0700474
Jeff Layton9ddec562013-05-26 07:00:58 -0400475 return 0;
476}
477
Jeff Layton2190eca2013-05-26 07:00:57 -0400478#ifdef CONFIG_CIFS_WEAK_PW_HASH
479static int
Jeff Layton3f618222013-06-12 19:52:14 -0500480decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400481{
482 __s16 tmp;
483 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
484
485 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
486 return -EOPNOTSUPP;
487
Jeff Layton2190eca2013-05-26 07:00:57 -0400488 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
489 server->maxReq = min_t(unsigned int,
490 le16_to_cpu(rsp->MaxMpxCount),
491 cifs_max_pending);
492 set_credits(server, server->maxReq);
493 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jones Syue1f641d92020-04-13 09:37:23 +0800494 /* set up max_read for readpages check */
495 server->max_read = server->maxBuf;
Jeff Layton2190eca2013-05-26 07:00:57 -0400496 /* even though we do not use raw we might as well set this
497 accurately, in case we ever find a need for it */
498 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
499 server->max_rw = 0xFF00;
500 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
501 } else {
502 server->max_rw = 0;/* do not need to use raw anyway */
503 server->capabilities = CAP_MPX_MODE;
504 }
505 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
506 if (tmp == -1) {
507 /* OS/2 often does not set timezone therefore
508 * we must use server time to calc time zone.
509 * Could deviate slightly from the right zone.
510 * Smallest defined timezone difference is 15 minutes
511 * (i.e. Nepal). Rounding up/down is done to match
512 * this requirement.
513 */
514 int val, seconds, remain, result;
Arnd Bergmann95390202018-06-19 17:27:58 +0200515 struct timespec64 ts;
516 time64_t utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400517 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
518 rsp->SrvTime.Time, 0);
Arnd Bergmann95390202018-06-19 17:27:58 +0200519 cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
520 ts.tv_sec, utc,
521 utc - ts.tv_sec);
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700522 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400523 seconds = abs(val);
524 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
525 remain = seconds % MIN_TZ_ADJ;
526 if (remain >= (MIN_TZ_ADJ / 2))
527 result += MIN_TZ_ADJ;
528 if (val < 0)
529 result = -result;
530 server->timeAdj = result;
531 } else {
532 server->timeAdj = (int)tmp;
533 server->timeAdj *= 60; /* also in seconds */
534 }
535 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
536
537
538 /* BB get server time for time conversions and add
539 code to use it and timezone since this is not UTC */
540
541 if (rsp->EncryptionKeyLength ==
542 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
543 memcpy(server->cryptkey, rsp->EncryptionKey,
544 CIFS_CRYPTO_KEY_SIZE);
545 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
546 return -EIO; /* need cryptkey unless plain text */
547 }
548
549 cifs_dbg(FYI, "LANMAN negotiated\n");
550 return 0;
551}
552#else
553static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500554decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400555{
556 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
557 return -EOPNOTSUPP;
558}
559#endif
560
Jeff Layton91934002013-05-26 07:00:58 -0400561static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500562should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400563{
Jeff Layton3f618222013-06-12 19:52:14 -0500564 switch (sectype) {
565 case RawNTLMSSP:
566 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400567 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500568 case Unspecified:
569 if (global_secflags &
570 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
571 return true;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500572 fallthrough;
Jeff Layton3f618222013-06-12 19:52:14 -0500573 default:
574 return false;
575 }
Jeff Layton91934002013-05-26 07:00:58 -0400576}
577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400579CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
581 NEGOTIATE_REQ *pSMB;
582 NEGOTIATE_RSP *pSMBr;
583 int rc = 0;
584 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000585 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400586 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 u16 count;
588
Jeff Layton3534b852013-05-24 07:41:01 -0400589 if (!server) {
590 WARN(1, "%s: server is NULL!\n", __func__);
591 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 }
Jeff Layton3534b852013-05-24 07:41:01 -0400593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
595 (void **) &pSMB, (void **) &pSMBr);
596 if (rc)
597 return rc;
Steve French750d1152006-06-27 06:28:30 +0000598
Pavel Shilovsky88257362012-05-23 14:01:59 +0400599 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000600 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000601
Jeff Layton3f618222013-06-12 19:52:14 -0500602 if (should_set_ext_sec_flag(ses->sectype)) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700603 cifs_dbg(FYI, "Requesting extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000604 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
605 }
Steve French50c2f752007-07-13 00:33:32 +0000606
Steve French39798772006-05-31 22:40:51 +0000607 count = 0;
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000608 /*
609 * We know that all the name entries in the protocols array
610 * are short (< 16 bytes anyway) and are NUL terminated.
611 */
Steve French50c2f752007-07-13 00:33:32 +0000612 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000613 size_t len = strlen(protocols[i].name) + 1;
614
615 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
616 count += len;
Steve French39798772006-05-31 22:40:51 +0000617 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000618 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 pSMB->ByteCount = cpu_to_le16(count);
620
621 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
622 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000623 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000624 goto neg_err_exit;
625
Jeff Layton9bf67e52010-04-24 07:57:46 -0400626 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500627 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000628 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400629 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000630 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000631 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000632 could not negotiate a common dialect */
633 rc = -EOPNOTSUPP;
634 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000635 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400636 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500637 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400638 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000639 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000640 /* unknown wct */
641 rc = -EOPNOTSUPP;
642 goto neg_err_exit;
643 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400644 /* else wct == 17, NTLM or better */
645
Steve French96daf2b2011-05-27 04:34:02 +0000646 server->sec_mode = pSMBr->SecurityMode;
647 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500648 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000649
Steve French254e55e2006-06-04 05:53:15 +0000650 /* one byte, so no need to convert this or EncryptionKeyLen from
651 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300652 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
653 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400654 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000655 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400656 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Jones Syue1f641d92020-04-13 09:37:23 +0800657 /* set up max_read for readpages check */
658 server->max_read = server->maxBuf;
Steve Frencheca6acf2009-02-20 05:43:09 +0000659 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500660 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000661 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000662 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
663 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400664
Jeff Laytone598d1d82013-05-26 07:00:59 -0400665 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
666 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500667 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000668 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100669 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
670 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400671 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500672 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400673 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000674 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400675 } else {
676 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000677 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400678 }
Steve French254e55e2006-06-04 05:53:15 +0000679
680signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400681 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400682 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000683neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700684 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000685
Joe Perchesf96637b2013-05-04 22:12:25 -0500686 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return rc;
688}
689
690int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400691CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
693 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
Joe Perchesf96637b2013-05-04 22:12:25 -0500696 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500697
698 /* BB: do we need to check this? These should never be NULL. */
699 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
700 return -EIO;
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500703 * No need to return error on this operation if tid invalidated and
704 * closed on server already e.g. due to tcp session crashing. Also,
705 * the tcon is no longer on the list, so no need to take lock before
706 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 */
Steve French268875b2009-06-25 00:29:21 +0000708 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000709 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Steve French50c2f752007-07-13 00:33:32 +0000711 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700712 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500713 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 return rc;
Steve French133672e2007-11-13 22:41:37 +0000715
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400716 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700717 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500719 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Steve French50c2f752007-07-13 00:33:32 +0000721 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500722 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 if (rc == -EAGAIN)
724 rc = 0;
725
726 return rc;
727}
728
Jeff Layton766fdbb2011-01-11 07:24:21 -0500729/*
730 * This is a no-op for now. We're not really interested in the reply, but
731 * rather in the fact that the server sent one and that server->lstrp
732 * gets updated.
733 *
734 * FIXME: maybe we should consider checking that the reply matches request?
735 */
736static void
737cifs_echo_callback(struct mid_q_entry *mid)
738{
739 struct TCP_Server_Info *server = mid->callback_data;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800740 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741
742 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800743 add_credits(server, &credits, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500744}
745
746int
747CIFSSMBEcho(struct TCP_Server_Info *server)
748{
749 ECHO_REQ *smb;
750 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800751 struct kvec iov[2];
752 struct smb_rqst rqst = { .rq_iov = iov,
753 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500754
Joe Perchesf96637b2013-05-04 22:12:25 -0500755 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500756
757 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
758 if (rc)
759 return rc;
760
Steve French26c9cb62017-05-02 13:35:20 -0500761 if (server->capabilities & CAP_UNICODE)
762 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
763
Jeff Layton766fdbb2011-01-11 07:24:21 -0500764 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000765 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500766 smb->hdr.WordCount = 1;
767 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400768 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500769 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000770 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800771
772 iov[0].iov_len = 4;
773 iov[0].iov_base = smb;
774 iov[1].iov_len = get_rfc1002_length(smb);
775 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500776
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800777 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +1000778 server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500779 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500780 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500781
782 cifs_small_buf_release(smb);
783
784 return rc;
785}
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400788CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 LOGOFF_ANDX_REQ *pSMB;
791 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Joe Perchesf96637b2013-05-04 22:12:25 -0500793 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500794
795 /*
796 * BB: do we need to check validity of ses and server? They should
797 * always be valid since we have an active reference. If not, that
798 * should probably be a BUG()
799 */
800 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 return -EIO;
802
Steve Frenchd7b619c2010-02-25 05:36:46 +0000803 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000804 if (ses->need_reconnect)
805 goto session_already_dead; /* no need to send SMBlogoff if uid
806 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
808 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000809 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return rc;
811 }
812
Pavel Shilovsky88257362012-05-23 14:01:59 +0400813 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700814
Jeff Layton38d77c52013-05-26 07:01:00 -0400815 if (ses->server->sign)
816 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 pSMB->hdr.Uid = ses->Suid;
819
820 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400821 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700822 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000823session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000824 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000827 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 error */
829 if (rc == -EAGAIN)
830 rc = 0;
831 return rc;
832}
833
834int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400835CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
836 const char *fileName, __u16 type,
837 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000838{
839 TRANSACTION2_SPI_REQ *pSMB = NULL;
840 TRANSACTION2_SPI_RSP *pSMBr = NULL;
841 struct unlink_psx_rq *pRqD;
842 int name_len;
843 int rc = 0;
844 int bytes_returned = 0;
845 __u16 params, param_offset, offset, byte_count;
846
Joe Perchesf96637b2013-05-04 22:12:25 -0500847 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000848PsxDelete:
849 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
850 (void **) &pSMBr);
851 if (rc)
852 return rc;
853
854 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
855 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600856 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
857 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000858 name_len++; /* trailing null */
859 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000860 } else {
861 name_len = copy_path_name(pSMB->FileName, fileName);
Steve French2d785a52007-07-15 01:48:57 +0000862 }
863
864 params = 6 + name_len;
865 pSMB->MaxParameterCount = cpu_to_le16(2);
866 pSMB->MaxDataCount = 0; /* BB double check this with jra */
867 pSMB->MaxSetupCount = 0;
868 pSMB->Reserved = 0;
869 pSMB->Flags = 0;
870 pSMB->Timeout = 0;
871 pSMB->Reserved2 = 0;
872 param_offset = offsetof(struct smb_com_transaction2_spi_req,
873 InformationLevel) - 4;
874 offset = param_offset + params;
875
876 /* Setup pointer to Request Data (inode type) */
877 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
878 pRqD->type = cpu_to_le16(type);
879 pSMB->ParameterOffset = cpu_to_le16(param_offset);
880 pSMB->DataOffset = cpu_to_le16(offset);
881 pSMB->SetupCount = 1;
882 pSMB->Reserved3 = 0;
883 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
884 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
885
886 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
887 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
888 pSMB->ParameterCount = cpu_to_le16(params);
889 pSMB->TotalParameterCount = pSMB->ParameterCount;
890 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
891 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000892 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000893 pSMB->ByteCount = cpu_to_le16(byte_count);
894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000896 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500897 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000898 cifs_buf_release(pSMB);
899
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400900 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000901
902 if (rc == -EAGAIN)
903 goto PsxDelete;
904
905 return rc;
906}
907
908int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700909CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
910 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 DELETE_FILE_REQ *pSMB = NULL;
913 DELETE_FILE_RSP *pSMBr = NULL;
914 int rc = 0;
915 int bytes_returned;
916 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500917 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919DelFileRetry:
920 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
921 (void **) &pSMBr);
922 if (rc)
923 return rc;
924
925 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700926 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
927 PATH_MAX, cifs_sb->local_nls,
928 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 name_len++; /* trailing null */
930 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000931 } else {
932 name_len = copy_path_name(pSMB->fileName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 }
934 pSMB->SearchAttributes =
935 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
936 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000937 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 pSMB->ByteCount = cpu_to_le16(name_len + 1);
939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400941 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000942 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500943 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 cifs_buf_release(pSMB);
946 if (rc == -EAGAIN)
947 goto DelFileRetry;
948
949 return rc;
950}
951
952int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400953CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
954 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 DELETE_DIRECTORY_REQ *pSMB = NULL;
957 DELETE_DIRECTORY_RSP *pSMBr = NULL;
958 int rc = 0;
959 int bytes_returned;
960 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500961 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Joe Perchesf96637b2013-05-04 22:12:25 -0500963 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964RmDirRetry:
965 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
966 (void **) &pSMBr);
967 if (rc)
968 return rc;
969
970 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400971 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
972 PATH_MAX, cifs_sb->local_nls,
973 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 name_len++; /* trailing null */
975 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000976 } else {
977 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
979
980 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000981 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 pSMB->ByteCount = cpu_to_le16(name_len + 1);
983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400985 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000986 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500987 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 cifs_buf_release(pSMB);
990 if (rc == -EAGAIN)
991 goto RmDirRetry;
992 return rc;
993}
994
995int
Steve Frenchc3ca78e2019-09-25 00:32:13 -0500996CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
997 struct cifs_tcon *tcon, const char *name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300998 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
1000 int rc = 0;
1001 CREATE_DIRECTORY_REQ *pSMB = NULL;
1002 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1003 int bytes_returned;
1004 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001005 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Joe Perchesf96637b2013-05-04 22:12:25 -05001007 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008MkDirRetry:
1009 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1010 (void **) &pSMBr);
1011 if (rc)
1012 return rc;
1013
1014 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001015 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001016 PATH_MAX, cifs_sb->local_nls,
1017 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 name_len++; /* trailing null */
1019 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001020 } else {
1021 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
1023
1024 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001025 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1027 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001029 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001030 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001031 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 cifs_buf_release(pSMB);
1034 if (rc == -EAGAIN)
1035 goto MkDirRetry;
1036 return rc;
1037}
1038
Steve French2dd29d32007-04-23 22:07:35 +00001039int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001040CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1041 __u32 posix_flags, __u64 mode, __u16 *netfid,
1042 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1043 const char *name, const struct nls_table *nls_codepage,
1044 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001045{
1046 TRANSACTION2_SPI_REQ *pSMB = NULL;
1047 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1048 int name_len;
1049 int rc = 0;
1050 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001051 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001052 OPEN_PSX_REQ *pdata;
1053 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001054
Joe Perchesf96637b2013-05-04 22:12:25 -05001055 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001056PsxCreat:
1057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1058 (void **) &pSMBr);
1059 if (rc)
1060 return rc;
1061
1062 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1063 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001064 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1065 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001066 name_len++; /* trailing null */
1067 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001068 } else {
1069 name_len = copy_path_name(pSMB->FileName, name);
Steve French2dd29d32007-04-23 22:07:35 +00001070 }
1071
1072 params = 6 + name_len;
1073 count = sizeof(OPEN_PSX_REQ);
1074 pSMB->MaxParameterCount = cpu_to_le16(2);
1075 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1076 pSMB->MaxSetupCount = 0;
1077 pSMB->Reserved = 0;
1078 pSMB->Flags = 0;
1079 pSMB->Timeout = 0;
1080 pSMB->Reserved2 = 0;
1081 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001082 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001083 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001084 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001085 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001086 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001087 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001088 pdata->OpenFlags = cpu_to_le32(*pOplock);
1089 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1090 pSMB->DataOffset = cpu_to_le16(offset);
1091 pSMB->SetupCount = 1;
1092 pSMB->Reserved3 = 0;
1093 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1094 byte_count = 3 /* pad */ + params + count;
1095
1096 pSMB->DataCount = cpu_to_le16(count);
1097 pSMB->ParameterCount = cpu_to_le16(params);
1098 pSMB->TotalDataCount = pSMB->DataCount;
1099 pSMB->TotalParameterCount = pSMB->ParameterCount;
1100 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1101 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001102 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001103 pSMB->ByteCount = cpu_to_le16(byte_count);
1104 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1106 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001107 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001108 goto psx_create_err;
1109 }
1110
Joe Perchesf96637b2013-05-04 22:12:25 -05001111 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001112 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1113
Jeff Layton820a8032011-05-04 08:05:26 -04001114 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001115 rc = -EIO; /* bad smb */
1116 goto psx_create_err;
1117 }
1118
1119 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001120 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001121 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001122
Steve French2dd29d32007-04-23 22:07:35 +00001123 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001124 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001125 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1126 /* Let caller know file was created so we can set the mode. */
1127 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001128 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001129 *pOplock |= CIFS_CREATE_ACTION;
1130 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001131 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1132 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001133 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001134 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001135 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001136 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001137 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001138 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001139 goto psx_create_err;
1140 }
Steve French50c2f752007-07-13 00:33:32 +00001141 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001142 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001143 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001144 }
Steve French2dd29d32007-04-23 22:07:35 +00001145
1146psx_create_err:
1147 cifs_buf_release(pSMB);
1148
Steve French65bc98b2009-07-10 15:27:25 +00001149 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001150 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001151 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001152 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001153
1154 if (rc == -EAGAIN)
1155 goto PsxCreat;
1156
Steve French50c2f752007-07-13 00:33:32 +00001157 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001158}
1159
Steve Frencha9d02ad2005-08-24 23:06:05 -07001160static __u16 convert_disposition(int disposition)
1161{
1162 __u16 ofun = 0;
1163
1164 switch (disposition) {
1165 case FILE_SUPERSEDE:
1166 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1167 break;
1168 case FILE_OPEN:
1169 ofun = SMBOPEN_OAPPEND;
1170 break;
1171 case FILE_CREATE:
1172 ofun = SMBOPEN_OCREATE;
1173 break;
1174 case FILE_OPEN_IF:
1175 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1176 break;
1177 case FILE_OVERWRITE:
1178 ofun = SMBOPEN_OTRUNC;
1179 break;
1180 case FILE_OVERWRITE_IF:
1181 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1182 break;
1183 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001184 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 ofun = SMBOPEN_OAPPEND; /* regular open */
1186 }
1187 return ofun;
1188}
1189
Jeff Layton35fc37d2008-05-14 10:22:03 -07001190static int
1191access_flags_to_smbopen_mode(const int access_flags)
1192{
1193 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1194
1195 if (masked_flags == GENERIC_READ)
1196 return SMBOPEN_READ;
1197 else if (masked_flags == GENERIC_WRITE)
1198 return SMBOPEN_WRITE;
1199
1200 /* just go for read/write */
1201 return SMBOPEN_READWRITE;
1202}
1203
Steve Frencha9d02ad2005-08-24 23:06:05 -07001204int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001205SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001207 const int access_flags, const int create_options, __u16 *netfid,
1208 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 const struct nls_table *nls_codepage, int remap)
1210{
Colin Ian King032e0912021-06-13 15:01:23 +01001211 int rc;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 OPENX_REQ *pSMB = NULL;
1213 OPENX_RSP *pSMBr = NULL;
1214 int bytes_returned;
1215 int name_len;
1216 __u16 count;
1217
1218OldOpenRetry:
1219 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1220 (void **) &pSMBr);
1221 if (rc)
1222 return rc;
1223
1224 pSMB->AndXCommand = 0xFF; /* none */
1225
1226 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1227 count = 1; /* account for one byte pad to word boundary */
1228 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001229 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1230 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231 name_len++; /* trailing null */
1232 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001233 } else {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234 count = 0; /* no pad */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001235 name_len = copy_path_name(pSMB->fileName, fileName);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 }
1237 if (*pOplock & REQ_OPLOCK)
1238 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001239 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001241
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001243 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1245 /* set file as system file if special file such
1246 as fifo and server expecting SFU style and
1247 no Unix extensions */
1248
Steve French790fe572007-07-07 19:25:05 +00001249 if (create_options & CREATE_OPTION_SPECIAL)
1250 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001251 else /* BB FIXME BB */
1252 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253
Jeff Layton67750fb2008-05-09 22:28:02 +00001254 if (create_options & CREATE_OPTION_READONLY)
1255 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256
1257 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001258/* pSMB->CreateOptions = cpu_to_le32(create_options &
1259 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001261
1262 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001263 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001265 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266
1267 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001269 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001270 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001272 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 } else {
1274 /* BB verify if wct == 15 */
1275
Steve French582d21e2008-05-13 04:54:12 +00001276/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277
1278 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1279 /* Let caller know file was created so we can set the mode. */
1280 /* Do we care about the CreateAction in any other cases? */
1281 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001282/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 *pOplock |= CIFS_CREATE_ACTION; */
1284 /* BB FIXME END */
1285
Steve French790fe572007-07-07 19:25:05 +00001286 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001287 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1288 pfile_info->LastAccessTime = 0; /* BB fixme */
1289 pfile_info->LastWriteTime = 0; /* BB fixme */
1290 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001291 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001292 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001293 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001294 pfile_info->AllocationSize =
1295 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1296 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001297 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001298 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001299 }
1300 }
1301
1302 cifs_buf_release(pSMB);
1303 if (rc == -EAGAIN)
1304 goto OldOpenRetry;
1305 return rc;
1306}
1307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001309CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1310 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311{
Colin Ian King1afdea42019-07-23 16:09:19 +01001312 int rc;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001313 OPEN_REQ *req = NULL;
1314 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 int bytes_returned;
1316 int name_len;
1317 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001318 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1319 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001320 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001321 const struct nls_table *nls = cifs_sb->local_nls;
1322 int create_options = oparms->create_options;
1323 int desired_access = oparms->desired_access;
1324 int disposition = oparms->disposition;
1325 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
1327openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001328 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1329 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 if (rc)
1331 return rc;
1332
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001333 /* no commands go after this */
1334 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001336 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1337 /* account for one byte pad to word boundary */
1338 count = 1;
1339 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1340 path, PATH_MAX, nls, remap);
1341 /* trailing null */
1342 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001344 req->NameLength = cpu_to_le16(name_len);
1345 } else {
1346 /* BB improve check for buffer overruns BB */
1347 /* no pad */
1348 count = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001349 name_len = copy_path_name(req->fileName, path);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001350 req->NameLength = cpu_to_le16(name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001352
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001353 if (*oplock & REQ_OPLOCK)
1354 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1355 else if (*oplock & REQ_BATCHOPLOCK)
1356 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1357
1358 req->DesiredAccess = cpu_to_le32(desired_access);
1359 req->AllocationSize = 0;
1360
1361 /*
1362 * Set file as system file if special file such as fifo and server
1363 * expecting SFU style and no Unix extensions.
1364 */
1365 if (create_options & CREATE_OPTION_SPECIAL)
1366 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1367 else
1368 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1369
1370 /*
1371 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1372 * sensitive checks for other servers such as Samba.
1373 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001375 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Jeff Layton67750fb2008-05-09 22:28:02 +00001377 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001378 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001379
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001380 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1381 req->CreateDisposition = cpu_to_le32(disposition);
1382 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1383
Steve French09d1db52005-04-28 22:41:08 -07001384 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001385 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1386 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001389 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001391 req->ByteCount = cpu_to_le16(count);
1392 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1393 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001394 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001396 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001397 cifs_buf_release(req);
1398 if (rc == -EAGAIN)
1399 goto openRetry;
1400 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001402
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001403 /* 1 byte no need to le_to_cpu */
1404 *oplock = rsp->OplockLevel;
1405 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001406 oparms->fid->netfid = rsp->Fid;
Aurelien Aptel86f740f2020-02-21 11:19:06 +01001407 oparms->fid->access = desired_access;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001408
1409 /* Let caller know file was created so we can set the mode. */
1410 /* Do we care about the CreateAction in any other cases? */
1411 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1412 *oplock |= CIFS_CREATE_ACTION;
1413
1414 if (buf) {
1415 /* copy from CreationTime to Attributes */
1416 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1417 /* the file_info buf is endian converted by caller */
1418 buf->AllocationSize = rsp->AllocationSize;
1419 buf->EndOfFile = rsp->EndOfFile;
1420 buf->NumberOfLinks = cpu_to_le32(1);
1421 buf->DeletePending = 0;
1422 }
1423
1424 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 return rc;
1426}
1427
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001428/*
1429 * Discard any remaining data in the current SMB. To do this, we borrow the
1430 * current bigbuf.
1431 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001432int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001433cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001434{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001435 unsigned int rfclen = server->pdu_size;
1436 int remaining = rfclen + server->vals->header_preamble_size -
1437 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438
1439 while (remaining > 0) {
1440 int length;
1441
David Howellscf0604a2021-02-04 00:15:21 -06001442 length = cifs_discard_from_socket(server,
1443 min_t(size_t, remaining,
1444 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001445 if (length < 0)
1446 return length;
1447 server->total_read += length;
1448 remaining -= length;
1449 }
1450
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001451 return 0;
1452}
1453
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001454static int
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001455__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1456 bool malformed)
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001457{
1458 int length;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001459
Pavel Shilovsky350be252017-04-10 10:31:33 -07001460 length = cifs_discard_remaining_data(server);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001461 dequeue_mid(mid, malformed);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001462 mid->resp_buf = server->smallbuf;
1463 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001464 return length;
1465}
1466
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001467static int
1468cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1469{
1470 struct cifs_readdata *rdata = mid->callback_data;
1471
1472 return __cifs_readv_discard(server, mid, rdata->result);
1473}
1474
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001475int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001476cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1477{
1478 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001479 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001480 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001481 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001482 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001483 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001484 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001485
Joe Perchesf96637b2013-05-04 22:12:25 -05001486 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1487 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001488
1489 /*
1490 * read the rest of READ_RSP header (sans Data array), or whatever we
1491 * can if there's not enough data. At this point, we've read down to
1492 * the Mid.
1493 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001494 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001495 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001496
Al Viroa6137302016-01-09 19:37:16 -05001497 length = cifs_read_from_socket(server,
1498 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001499 if (length < 0)
1500 return length;
1501 server->total_read += length;
1502
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001503 if (server->ops->is_session_expired &&
1504 server->ops->is_session_expired(buf)) {
1505 cifs_reconnect(server);
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001506 return -1;
1507 }
1508
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001509 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -08001510 server->ops->is_status_pending(buf, server)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001511 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001512 return -1;
1513 }
1514
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001515 /* set up first two iov for signature check and to get credits */
1516 rdata->iov[0].iov_base = buf;
Pavel Shilovskybb1bccb2019-01-17 16:18:38 -08001517 rdata->iov[0].iov_len = server->vals->header_preamble_size;
1518 rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1519 rdata->iov[1].iov_len =
1520 server->total_read - server->vals->header_preamble_size;
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001521 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1522 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1523 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1524 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1525
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001526 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001527 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001528 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001529 cifs_dbg(FYI, "%s: server returned error %d\n",
1530 __func__, rdata->result);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001531 /* normal error on read response */
1532 return __cifs_readv_discard(server, mid, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001533 }
1534
1535 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001536 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001537 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1538 __func__, server->total_read,
1539 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001540 rdata->result = -EIO;
1541 return cifs_readv_discard(server, mid);
1542 }
1543
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001544 data_offset = server->ops->read_data_offset(buf) +
1545 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001546 if (data_offset < server->total_read) {
1547 /*
1548 * win2k8 sometimes sends an offset of 0 when the read
1549 * is beyond the EOF. Treat it as if the data starts just after
1550 * the header.
1551 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001552 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1553 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001554 data_offset = server->total_read;
1555 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1556 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001557 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1558 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001559 rdata->result = -EIO;
1560 return cifs_readv_discard(server, mid);
1561 }
1562
Joe Perchesf96637b2013-05-04 22:12:25 -05001563 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1564 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001565
1566 len = data_offset - server->total_read;
1567 if (len > 0) {
1568 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001569 length = cifs_read_from_socket(server,
1570 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001571 if (length < 0)
1572 return length;
1573 server->total_read += length;
1574 }
1575
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001576 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001577#ifdef CONFIG_CIFS_SMB_DIRECT
1578 use_rdma_mr = rdata->mr;
1579#endif
1580 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1581 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001582 /* data_len is corrupt -- discard frame */
1583 rdata->result = -EIO;
1584 return cifs_readv_discard(server, mid);
1585 }
1586
Jeff Layton8321fec2012-09-19 06:22:32 -07001587 length = rdata->read_into_pages(server, rdata, data_len);
1588 if (length < 0)
1589 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001590
Jeff Layton8321fec2012-09-19 06:22:32 -07001591 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001592
Joe Perchesf96637b2013-05-04 22:12:25 -05001593 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1594 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001595
1596 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001597 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001598 return cifs_readv_discard(server, mid);
1599
1600 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001601 mid->resp_buf = server->smallbuf;
1602 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001603 return length;
1604}
1605
1606static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001607cifs_readv_callback(struct mid_q_entry *mid)
1608{
1609 struct cifs_readdata *rdata = mid->callback_data;
1610 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1611 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001612 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1613 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001614 .rq_pages = rdata->pages,
Long Li6d3adb22018-09-20 21:18:38 +00001615 .rq_offset = rdata->page_offset,
Jeff Layton8321fec2012-09-19 06:22:32 -07001616 .rq_npages = rdata->nr_pages,
1617 .rq_pagesz = rdata->pagesz,
1618 .rq_tailsz = rdata->tailsz };
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001619 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001620
Joe Perchesf96637b2013-05-04 22:12:25 -05001621 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1622 __func__, mid->mid, mid->mid_state, rdata->result,
1623 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001624
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001625 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001626 case MID_RESPONSE_RECEIVED:
1627 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001628 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001629 int rc = 0;
1630
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001631 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001632 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001633 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001634 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1635 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001636 }
1637 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001638 task_io_account_read(rdata->got_bytes);
1639 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001640 break;
1641 case MID_REQUEST_SUBMITTED:
1642 case MID_RETRY_NEEDED:
1643 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001644 if (server->sign && rdata->got_bytes)
1645 /* reset bytes number since we can not check a sign */
1646 rdata->got_bytes = 0;
1647 /* FIXME: should this be counted toward the initiating task? */
1648 task_io_account_read(rdata->got_bytes);
1649 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001650 break;
1651 default:
1652 rdata->result = -EIO;
1653 }
1654
Jeff Laytonda472fc2012-03-23 14:40:53 -04001655 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001656 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001657 add_credits(server, &credits, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001658}
1659
1660/* cifs_async_readv - send an async write, and set up mid to handle result */
1661int
1662cifs_async_readv(struct cifs_readdata *rdata)
1663{
1664 int rc;
1665 READ_REQ *smb = NULL;
1666 int wct;
1667 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001668 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1669 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001670
Joe Perchesf96637b2013-05-04 22:12:25 -05001671 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1672 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001673
1674 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1675 wct = 12;
1676 else {
1677 wct = 10; /* old style read */
1678 if ((rdata->offset >> 32) > 0) {
1679 /* can not handle this big offset for old */
1680 return -EIO;
1681 }
1682 }
1683
1684 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1685 if (rc)
1686 return rc;
1687
1688 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1689 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1690
1691 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001692 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001693 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1694 if (wct == 12)
1695 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1696 smb->Remaining = 0;
1697 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1698 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1699 if (wct == 12)
1700 smb->ByteCount = 0;
1701 else {
1702 /* old style read */
1703 struct smb_com_readx_req *smbr =
1704 (struct smb_com_readx_req *)smb;
1705 smbr->ByteCount = 0;
1706 }
1707
1708 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001709 rdata->iov[0].iov_base = smb;
1710 rdata->iov[0].iov_len = 4;
1711 rdata->iov[1].iov_base = (char *)smb + 4;
1712 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001713
Jeff Layton6993f742012-05-16 07:13:17 -04001714 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001715 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08001716 cifs_readv_callback, NULL, rdata, 0, NULL);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001717
1718 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001719 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001720 else
1721 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001722
1723 cifs_small_buf_release(smb);
1724 return rc;
1725}
1726
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001728CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1729 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730{
1731 int rc = -EACCES;
1732 READ_REQ *pSMB = NULL;
1733 READ_RSP *pSMBr = NULL;
1734 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001735 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001736 int resp_buf_type = 0;
1737 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001738 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001739 __u32 pid = io_parms->pid;
1740 __u16 netfid = io_parms->netfid;
1741 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001742 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001743 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
Joe Perchesf96637b2013-05-04 22:12:25 -05001745 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001746 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001747 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001748 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001749 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001750 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001751 /* can not handle this big offset for old */
1752 return -EIO;
1753 }
1754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001757 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc)
1759 return rc;
1760
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001761 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1762 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1763
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 /* tcon and ses pointer are checked in smb_init */
1765 if (tcon->ses->server == NULL)
1766 return -ECONNABORTED;
1767
Steve Frenchec637e32005-12-12 20:53:18 -08001768 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001770 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001771 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001772 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 pSMB->Remaining = 0;
1775 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1776 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001777 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001778 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1779 else {
1780 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001781 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001782 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001783 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001784 }
Steve Frenchec637e32005-12-12 20:53:18 -08001785
1786 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001787 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001788 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1789 CIFS_LOG_ERROR, &rsp_iov);
1790 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001791 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001792 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001794 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 } else {
1796 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1797 data_length = data_length << 16;
1798 data_length += le16_to_cpu(pSMBr->DataLength);
1799 *nbytes = data_length;
1800
1801 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001802 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001804 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001805 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 rc = -EIO;
1807 *nbytes = 0;
1808 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001809 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001810 le16_to_cpu(pSMBr->DataOffset);
1811/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001812 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001813 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001814 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001815 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001816 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 }
1818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
Steve French790fe572007-07-07 19:25:05 +00001820 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001821 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001822 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001823 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001824 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001825 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001826 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001827 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001828 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001829 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001830
1831 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 since file handle passed in no longer valid */
1833 return rc;
1834}
1835
Steve Frenchec637e32005-12-12 20:53:18 -08001836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001838CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001839 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840{
1841 int rc = -EACCES;
1842 WRITE_REQ *pSMB = NULL;
1843 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001844 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 __u32 bytes_sent;
1846 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001847 __u32 pid = io_parms->pid;
1848 __u16 netfid = io_parms->netfid;
1849 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001850 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001851 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
Steve Frencha24e2d72010-04-03 17:20:21 +00001853 *nbytes = 0;
1854
Joe Perchesf96637b2013-05-04 22:12:25 -05001855 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001856 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001857 return -ECONNABORTED;
1858
Steve French790fe572007-07-07 19:25:05 +00001859 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001860 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001861 else {
Steve French1c955182005-08-30 20:58:07 -07001862 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001863 if ((offset >> 32) > 0) {
1864 /* can not handle big offset for old srv */
1865 return -EIO;
1866 }
1867 }
Steve French1c955182005-08-30 20:58:07 -07001868
1869 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 (void **) &pSMBr);
1871 if (rc)
1872 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001873
1874 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1875 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1876
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 /* tcon and ses pointer are checked in smb_init */
1878 if (tcon->ses->server == NULL)
1879 return -ECONNABORTED;
1880
1881 pSMB->AndXCommand = 0xFF; /* none */
1882 pSMB->Fid = netfid;
1883 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001884 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001885 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001886
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 pSMB->Reserved = 0xFFFFFFFF;
1888 pSMB->WriteMode = 0;
1889 pSMB->Remaining = 0;
1890
Steve French50c2f752007-07-13 00:33:32 +00001891 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 can send more if LARGE_WRITE_X capability returned by the server and if
1893 our buffer is big enough or if we convert to iovecs on socket writes
1894 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001895 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1897 } else {
1898 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1899 & ~0xFF;
1900 }
1901
1902 if (bytes_sent > count)
1903 bytes_sent = count;
1904 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001905 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001906 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001907 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001908 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 /* No buffer */
1910 cifs_buf_release(pSMB);
1911 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001912 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001913 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001914 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001915 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001916 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001917
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1919 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001920 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001921
Steve French790fe572007-07-07 19:25:05 +00001922 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001923 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001924 else { /* old style write has byte count 4 bytes earlier
1925 so 4 bytes pad */
1926 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001927 (struct smb_com_writex_req *)pSMB;
1928 pSMBW->ByteCount = cpu_to_le16(byte_count);
1929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001933 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001935 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 } else {
1937 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1938 *nbytes = (*nbytes) << 16;
1939 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301940
1941 /*
1942 * Mask off high 16 bits when bytes written as returned by the
1943 * server is greater than bytes requested by the client. Some
1944 * OS/2 servers are known to set incorrect CountHigh values.
1945 */
1946 if (*nbytes > count)
1947 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 }
1949
1950 cifs_buf_release(pSMB);
1951
Steve French50c2f752007-07-13 00:33:32 +00001952 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 since file handle passed in no longer valid */
1954
1955 return rc;
1956}
1957
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001958void
1959cifs_writedata_release(struct kref *refcount)
1960{
1961 struct cifs_writedata *wdata = container_of(refcount,
1962 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001963#ifdef CONFIG_CIFS_SMB_DIRECT
1964 if (wdata->mr) {
1965 smbd_deregister_mr(wdata->mr);
1966 wdata->mr = NULL;
1967 }
1968#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001969
1970 if (wdata->cfile)
1971 cifsFileInfo_put(wdata->cfile);
1972
Long Li8e7360f2018-05-30 12:47:56 -07001973 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001974 kfree(wdata);
1975}
1976
1977/*
1978 * Write failed with a retryable error. Resend the write request. It's also
1979 * possible that the page was redirtied so re-clean the page.
1980 */
1981static void
1982cifs_writev_requeue(struct cifs_writedata *wdata)
1983{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001984 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001985 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001986 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001987 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001988
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001989 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1990 i = 0;
1991 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001992 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001993 struct cifs_writedata *wdata2;
1994 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001995
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001996 wsize = server->ops->wp_retry_size(inode);
1997 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001998 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001999 if (!nr_pages) {
2000 rc = -ENOTSUPP;
2001 break;
2002 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002003 cur_len = nr_pages * PAGE_SIZE;
2004 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002005 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002006 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002007 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002008 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06002009 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002010
2011 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
2012 if (!wdata2) {
2013 rc = -ENOMEM;
2014 break;
2015 }
2016
2017 for (j = 0; j < nr_pages; j++) {
2018 wdata2->pages[j] = wdata->pages[i + j];
2019 lock_page(wdata2->pages[j]);
2020 clear_page_dirty_for_io(wdata2->pages[j]);
2021 }
2022
2023 wdata2->sync_mode = wdata->sync_mode;
2024 wdata2->nr_pages = nr_pages;
2025 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002026 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002027 wdata2->tailsz = tailsz;
2028 wdata2->bytes = cur_len;
2029
Aurelien Aptel86f740f2020-02-21 11:19:06 +01002030 rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08002031 &wdata2->cfile);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002032 if (!wdata2->cfile) {
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08002033 cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
2034 rc);
2035 if (!is_retryable_error(rc))
2036 rc = -EBADF;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002037 } else {
2038 wdata2->pid = wdata2->cfile->pid;
2039 rc = server->ops->async_writev(wdata2,
2040 cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002041 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002042
2043 for (j = 0; j < nr_pages; j++) {
2044 unlock_page(wdata2->pages[j]);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002045 if (rc != 0 && !is_retryable_error(rc)) {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002046 SetPageError(wdata2->pages[j]);
2047 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002048 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002049 }
2050 }
2051
Adam McCoya4813792020-05-13 11:53:30 +00002052 kref_put(&wdata2->refcount, cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002053 if (rc) {
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002054 if (is_retryable_error(rc))
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002055 continue;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002056 i += nr_pages;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002057 break;
2058 }
2059
2060 rest_len -= cur_len;
2061 i += nr_pages;
2062 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002063
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002064 /* cleanup remaining pages from the original wdata */
2065 for (; i < wdata->nr_pages; i++) {
2066 SetPageError(wdata->pages[i]);
2067 end_page_writeback(wdata->pages[i]);
2068 put_page(wdata->pages[i]);
2069 }
2070
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002071 if (rc != 0 && !is_retryable_error(rc))
2072 mapping_set_error(inode->i_mapping, rc);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002073 kref_put(&wdata->refcount, cifs_writedata_release);
2074}
2075
Jeff Laytonc2e87642012-03-23 14:40:55 -04002076void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002077cifs_writev_complete(struct work_struct *work)
2078{
2079 struct cifs_writedata *wdata = container_of(work,
2080 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002081 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082 int i = 0;
2083
2084 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002085 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002086 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002087 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002088 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2089 wdata->bytes);
2090 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2091 return cifs_writev_requeue(wdata);
2092
2093 for (i = 0; i < wdata->nr_pages; i++) {
2094 struct page *page = wdata->pages[i];
2095 if (wdata->result == -EAGAIN)
2096 __set_page_dirty_nobuffers(page);
2097 else if (wdata->result < 0)
2098 SetPageError(page);
2099 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002100 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101 }
2102 if (wdata->result != -EAGAIN)
2103 mapping_set_error(inode->i_mapping, wdata->result);
2104 kref_put(&wdata->refcount, cifs_writedata_release);
2105}
2106
2107struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002108cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002109{
Long Li8e7360f2018-05-30 12:47:56 -07002110 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002111 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002112 if (pages)
2113 return cifs_writedata_direct_alloc(pages, complete);
2114
2115 return NULL;
2116}
2117
2118struct cifs_writedata *
2119cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2120{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002121 struct cifs_writedata *wdata;
2122
Long Li8e7360f2018-05-30 12:47:56 -07002123 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002124 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002125 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002126 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002127 INIT_LIST_HEAD(&wdata->list);
2128 init_completion(&wdata->done);
2129 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002130 }
2131 return wdata;
2132}
2133
2134/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002135 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002136 * workqueue completion task.
2137 */
2138static void
2139cifs_writev_callback(struct mid_q_entry *mid)
2140{
2141 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002142 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002143 unsigned int written;
2144 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002145 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002146
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002147 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002148 case MID_RESPONSE_RECEIVED:
2149 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2150 if (wdata->result != 0)
2151 break;
2152
2153 written = le16_to_cpu(smb->CountHigh);
2154 written <<= 16;
2155 written += le16_to_cpu(smb->Count);
2156 /*
2157 * Mask off high 16 bits when bytes written as returned
2158 * by the server is greater than bytes requested by the
2159 * client. OS/2 servers are known to set incorrect
2160 * CountHigh values.
2161 */
2162 if (written > wdata->bytes)
2163 written &= 0xFFFF;
2164
2165 if (written < wdata->bytes)
2166 wdata->result = -ENOSPC;
2167 else
2168 wdata->bytes = written;
2169 break;
2170 case MID_REQUEST_SUBMITTED:
2171 case MID_RETRY_NEEDED:
2172 wdata->result = -EAGAIN;
2173 break;
2174 default:
2175 wdata->result = -EIO;
2176 break;
2177 }
2178
Jeff Laytonda472fc2012-03-23 14:40:53 -04002179 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002180 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002181 add_credits(tcon->ses->server, &credits, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002182}
2183
2184/* cifs_async_writev - send an async write, and set up mid to handle result */
2185int
Steve French4a5c80d2014-02-07 20:45:12 -06002186cifs_async_writev(struct cifs_writedata *wdata,
2187 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002188{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002189 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002190 WRITE_REQ *smb = NULL;
2191 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002192 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002193 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002194 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002195
2196 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2197 wct = 14;
2198 } else {
2199 wct = 12;
2200 if (wdata->offset >> 32 > 0) {
2201 /* can not handle big offset for old srv */
2202 return -EIO;
2203 }
2204 }
2205
2206 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2207 if (rc)
2208 goto async_writev_out;
2209
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002210 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2211 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002212
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002213 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002214 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002215 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2216 if (wct == 14)
2217 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2218 smb->Reserved = 0xFFFFFFFF;
2219 smb->WriteMode = 0;
2220 smb->Remaining = 0;
2221
2222 smb->DataOffset =
2223 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2224
2225 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002226 iov[0].iov_len = 4;
2227 iov[0].iov_base = smb;
2228 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2229 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002230
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002231 rqst.rq_iov = iov;
2232 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002233 rqst.rq_pages = wdata->pages;
Long Li6d3adb22018-09-20 21:18:38 +00002234 rqst.rq_offset = wdata->page_offset;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002235 rqst.rq_npages = wdata->nr_pages;
2236 rqst.rq_pagesz = wdata->pagesz;
2237 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002238
Joe Perchesf96637b2013-05-04 22:12:25 -05002239 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2240 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002241
2242 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2243 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2244
2245 if (wct == 14) {
2246 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2247 put_bcc(wdata->bytes + 1, &smb->hdr);
2248 } else {
2249 /* wct == 12 */
2250 struct smb_com_writex_req *smbw =
2251 (struct smb_com_writex_req *)smb;
2252 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2253 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002254 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002255 }
2256
2257 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002258 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08002259 cifs_writev_callback, NULL, wdata, 0, NULL);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002260
2261 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002262 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002263 else
Steve French4a5c80d2014-02-07 20:45:12 -06002264 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002265
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002266async_writev_out:
2267 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002268 return rc;
2269}
2270
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002271int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002272CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002273 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274{
Colin Ian King136a5dc2020-05-27 13:50:31 +01002275 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002277 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002278 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002279 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002280 __u32 pid = io_parms->pid;
2281 __u16 netfid = io_parms->netfid;
2282 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002283 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002284 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002285 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002287 *nbytes = 0;
2288
Joe Perchesf96637b2013-05-04 22:12:25 -05002289 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002290
Steve French4c3130e2008-12-09 00:28:16 +00002291 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002292 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002293 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002294 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002295 if ((offset >> 32) > 0) {
2296 /* can not handle big offset for old srv */
2297 return -EIO;
2298 }
2299 }
Steve French8cc64c62005-10-03 13:49:43 -07002300 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 if (rc)
2302 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002303
2304 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2305 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2306
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 /* tcon and ses pointer are checked in smb_init */
2308 if (tcon->ses->server == NULL)
2309 return -ECONNABORTED;
2310
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002311 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 pSMB->Fid = netfid;
2313 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002314 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002315 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 pSMB->Reserved = 0xFFFFFFFF;
2317 pSMB->WriteMode = 0;
2318 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002319
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002321 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
Steve French3e844692005-10-03 13:37:24 -07002323 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2324 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002325 /* header + 1 byte pad */
2326 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002327 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002328 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002329 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002330 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002331 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002332 pSMB->ByteCount = cpu_to_le16(count + 1);
2333 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002334 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002335 (struct smb_com_writex_req *)pSMB;
2336 pSMBW->ByteCount = cpu_to_le16(count + 5);
2337 }
Steve French3e844692005-10-03 13:37:24 -07002338 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002339 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002340 iov[0].iov_len = smb_hdr_len + 4;
2341 else /* wct == 12 pad bigger by four bytes */
2342 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002343
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002344 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2345 &rsp_iov);
2346 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002347 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002349 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002350 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002351 /* presumably this can not happen, but best to be safe */
2352 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002353 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002354 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002355 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2356 *nbytes = (*nbytes) << 16;
2357 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302358
2359 /*
2360 * Mask off high 16 bits when bytes written as returned by the
2361 * server is greater than bytes requested by the client. OS/2
2362 * servers are known to set incorrect CountHigh values.
2363 */
2364 if (*nbytes > count)
2365 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002368 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
Steve French50c2f752007-07-13 00:33:32 +00002370 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 since file handle passed in no longer valid */
2372
2373 return rc;
2374}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002375
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002376int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2377 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002378 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2379{
2380 int rc = 0;
2381 LOCK_REQ *pSMB = NULL;
2382 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002383 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002384 int resp_buf_type;
2385 __u16 count;
2386
Joe Perchesf96637b2013-05-04 22:12:25 -05002387 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2388 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002389
2390 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2391 if (rc)
2392 return rc;
2393
2394 pSMB->Timeout = 0;
2395 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2396 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2397 pSMB->LockType = lock_type;
2398 pSMB->AndXCommand = 0xFF; /* none */
2399 pSMB->Fid = netfid; /* netfid stays le */
2400
2401 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2402 inc_rfc1001_len(pSMB, count);
2403 pSMB->ByteCount = cpu_to_le16(count);
2404
2405 iov[0].iov_base = (char *)pSMB;
2406 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2407 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2408 iov[1].iov_base = (char *)buf;
2409 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2410
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002411 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002412 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
2413 CIFS_NO_RSP_BUF, &rsp_iov);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002414 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002415 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002416 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002417
2418 return rc;
2419}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002420
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002422CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002423 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002425 const __u32 numLock, const __u8 lockType,
2426 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427{
2428 int rc = 0;
2429 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002430/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002432 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 __u16 count;
2434
Joe Perchesf96637b2013-05-04 22:12:25 -05002435 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2436 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002437 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2438
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 if (rc)
2440 return rc;
2441
Steve French790fe572007-07-07 19:25:05 +00002442 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002443 /* no response expected */
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002444 flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002446 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002447 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2449 } else {
2450 pSMB->Timeout = 0;
2451 }
2452
2453 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2454 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2455 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002456 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 pSMB->AndXCommand = 0xFF; /* none */
2458 pSMB->Fid = smb_file_id; /* netfid stays le */
2459
Steve French790fe572007-07-07 19:25:05 +00002460 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002461 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /* BB where to store pid high? */
2463 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2464 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2465 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2466 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2467 count = sizeof(LOCKING_ANDX_RANGE);
2468 } else {
2469 /* oplock break */
2470 count = 0;
2471 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002472 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 pSMB->ByteCount = cpu_to_le16(count);
2474
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002475 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002476 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002477 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002478 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002479 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002480 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002481 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002482 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002483 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484
Steve French50c2f752007-07-13 00:33:32 +00002485 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 since file handle passed in no longer valid */
2487 return rc;
2488}
2489
2490int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002491CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002492 const __u16 smb_file_id, const __u32 netpid,
2493 const loff_t start_offset, const __u64 len,
2494 struct file_lock *pLockData, const __u16 lock_type,
2495 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002496{
2497 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2498 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002499 struct cifs_posix_lock *parm_data;
2500 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002501 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002502 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002503 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002504 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002505 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002506 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002507
Joe Perchesf96637b2013-05-04 22:12:25 -05002508 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002509
Steve French08547b02006-02-28 22:39:25 +00002510 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2511
2512 if (rc)
2513 return rc;
2514
2515 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2516
Steve French50c2f752007-07-13 00:33:32 +00002517 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002518 pSMB->MaxSetupCount = 0;
2519 pSMB->Reserved = 0;
2520 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002521 pSMB->Reserved2 = 0;
2522 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2523 offset = param_offset + params;
2524
Steve French08547b02006-02-28 22:39:25 +00002525 count = sizeof(struct cifs_posix_lock);
2526 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002527 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002528 pSMB->SetupCount = 1;
2529 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002530 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002531 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2532 else
2533 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2534 byte_count = 3 /* pad */ + params + count;
2535 pSMB->DataCount = cpu_to_le16(count);
2536 pSMB->ParameterCount = cpu_to_le16(params);
2537 pSMB->TotalDataCount = pSMB->DataCount;
2538 pSMB->TotalParameterCount = pSMB->ParameterCount;
2539 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002540 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002541 (((char *) &pSMB->hdr.Protocol) + offset);
2542
2543 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002544 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002545 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002546 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002547 pSMB->Timeout = cpu_to_le32(-1);
2548 } else
2549 pSMB->Timeout = 0;
2550
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002551 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002552 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002553 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002554
2555 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002556 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002557 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2558 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002559 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002560 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002561 if (waitFlag) {
2562 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2563 (struct smb_hdr *) pSMBr, &bytes_returned);
2564 } else {
Steve French133672e2007-11-13 22:41:37 +00002565 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002566 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002567 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002568 &resp_buf_type, timeout, &rsp_iov);
2569 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002570 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002571 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002572
Steve French08547b02006-02-28 22:39:25 +00002573 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002574 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002575 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002576 /* lock structure can be returned on get */
2577 __u16 data_offset;
2578 __u16 data_count;
2579 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002580
Jeff Layton820a8032011-05-04 08:05:26 -04002581 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002582 rc = -EIO; /* bad smb */
2583 goto plk_err_exit;
2584 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002585 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2586 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002587 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002588 rc = -EIO;
2589 goto plk_err_exit;
2590 }
2591 parm_data = (struct cifs_posix_lock *)
2592 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002593 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002594 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002595 else {
2596 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002597 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002598 pLockData->fl_type = F_RDLCK;
2599 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002600 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002601 pLockData->fl_type = F_WRLCK;
2602
Steve French5443d132011-03-13 05:08:25 +00002603 pLockData->fl_start = le64_to_cpu(parm_data->start);
2604 pLockData->fl_end = pLockData->fl_start +
2605 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002606 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002607 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002608 }
Steve French50c2f752007-07-13 00:33:32 +00002609
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002610plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002611 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002612
Steve French08547b02006-02-28 22:39:25 +00002613 /* Note: On -EAGAIN error only caller can retry on handle based calls
2614 since file handle passed in no longer valid */
2615
2616 return rc;
2617}
2618
2619
2620int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002621CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622{
2623 int rc = 0;
2624 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002625 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
2627/* do not retry on dead session on close */
2628 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002629 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 return 0;
2631 if (rc)
2632 return rc;
2633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002635 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002637 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002638 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002639 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002641 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002643 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 }
2645 }
2646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002648 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 rc = 0;
2650
2651 return rc;
2652}
2653
2654int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002655CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002656{
2657 int rc = 0;
2658 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002659 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002660
2661 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2662 if (rc)
2663 return rc;
2664
2665 pSMB->FileID = (__u16) smb_file_id;
2666 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002667 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002668 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002669 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002670 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002671 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002672
2673 return rc;
2674}
2675
2676int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002677CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002678 const char *from_name, const char *to_name,
2679 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680{
2681 int rc = 0;
2682 RENAME_REQ *pSMB = NULL;
2683 RENAME_RSP *pSMBr = NULL;
2684 int bytes_returned;
2685 int name_len, name_len2;
2686 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002687 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688
Joe Perchesf96637b2013-05-04 22:12:25 -05002689 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690renameRetry:
2691 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2692 (void **) &pSMBr);
2693 if (rc)
2694 return rc;
2695
2696 pSMB->BufferFormat = 0x04;
2697 pSMB->SearchAttributes =
2698 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2699 ATTR_DIRECTORY);
2700
2701 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002702 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2703 from_name, PATH_MAX,
2704 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 name_len++; /* trailing null */
2706 name_len *= 2;
2707 pSMB->OldFileName[name_len] = 0x04; /* pad */
2708 /* protocol requires ASCII signature byte on Unicode string */
2709 pSMB->OldFileName[name_len + 1] = 0x00;
2710 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002711 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002712 to_name, PATH_MAX, cifs_sb->local_nls,
2713 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2715 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002716 } else {
2717 name_len = copy_path_name(pSMB->OldFileName, from_name);
2718 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 name_len2++; /* signature byte */
2721 }
2722
2723 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002724 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 pSMB->ByteCount = cpu_to_le16(count);
2726
2727 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2728 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002729 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002730 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002731 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 cifs_buf_release(pSMB);
2734
2735 if (rc == -EAGAIN)
2736 goto renameRetry;
2737
2738 return rc;
2739}
2740
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002741int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002742 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002743 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744{
2745 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2746 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002747 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 char *data_offset;
2749 char dummy_string[30];
2750 int rc = 0;
2751 int bytes_returned = 0;
2752 int len_of_str;
2753 __u16 params, param_offset, offset, count, byte_count;
2754
Joe Perchesf96637b2013-05-04 22:12:25 -05002755 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2757 (void **) &pSMBr);
2758 if (rc)
2759 return rc;
2760
2761 params = 6;
2762 pSMB->MaxSetupCount = 0;
2763 pSMB->Reserved = 0;
2764 pSMB->Flags = 0;
2765 pSMB->Timeout = 0;
2766 pSMB->Reserved2 = 0;
2767 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2768 offset = param_offset + params;
2769
Steve Frenchf3717932021-07-07 13:34:47 -05002770 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2771 data_offset = (char *)(pSMB) + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 rename_info = (struct set_file_rename *) data_offset;
2773 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002774 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 pSMB->SetupCount = 1;
2776 pSMB->Reserved3 = 0;
2777 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2778 byte_count = 3 /* pad */ + params;
2779 pSMB->ParameterCount = cpu_to_le16(params);
2780 pSMB->TotalParameterCount = pSMB->ParameterCount;
2781 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2782 pSMB->DataOffset = cpu_to_le16(offset);
2783 /* construct random name ".cifs_tmp<inodenum><mid>" */
2784 rename_info->overwrite = cpu_to_le32(1);
2785 rename_info->root_fid = 0;
2786 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002787 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002788 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002789 len_of_str =
2790 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002791 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002793 len_of_str =
2794 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002795 target_name, PATH_MAX, nls_codepage,
2796 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 }
2798 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002799 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 byte_count += count;
2801 pSMB->DataCount = cpu_to_le16(count);
2802 pSMB->TotalDataCount = pSMB->DataCount;
2803 pSMB->Fid = netfid;
2804 pSMB->InformationLevel =
2805 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2806 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002807 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 pSMB->ByteCount = cpu_to_le16(byte_count);
2809 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002810 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002811 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002812 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002813 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2814 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002815
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 cifs_buf_release(pSMB);
2817
2818 /* Note: On -EAGAIN error only caller can retry on handle based calls
2819 since file handle passed in no longer valid */
2820
2821 return rc;
2822}
2823
2824int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002825CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2826 const char *fromName, const __u16 target_tid, const char *toName,
2827 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828{
2829 int rc = 0;
2830 COPY_REQ *pSMB = NULL;
2831 COPY_RSP *pSMBr = NULL;
2832 int bytes_returned;
2833 int name_len, name_len2;
2834 __u16 count;
2835
Joe Perchesf96637b2013-05-04 22:12:25 -05002836 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837copyRetry:
2838 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2839 (void **) &pSMBr);
2840 if (rc)
2841 return rc;
2842
2843 pSMB->BufferFormat = 0x04;
2844 pSMB->Tid2 = target_tid;
2845
2846 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2847
2848 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002849 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2850 fromName, PATH_MAX, nls_codepage,
2851 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 name_len++; /* trailing null */
2853 name_len *= 2;
2854 pSMB->OldFileName[name_len] = 0x04; /* pad */
2855 /* protocol requires ASCII signature byte on Unicode string */
2856 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002857 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002858 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2859 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2861 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002862 } else {
2863 name_len = copy_path_name(pSMB->OldFileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002865 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 name_len2++; /* signature byte */
2867 }
2868
2869 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002870 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 pSMB->ByteCount = cpu_to_le16(count);
2872
2873 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2874 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2875 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002876 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2877 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 }
Steve French0d817bc2008-05-22 02:02:03 +00002879 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
2881 if (rc == -EAGAIN)
2882 goto copyRetry;
2883
2884 return rc;
2885}
2886
2887int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002888CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002890 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891{
2892 TRANSACTION2_SPI_REQ *pSMB = NULL;
2893 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2894 char *data_offset;
2895 int name_len;
2896 int name_len_target;
2897 int rc = 0;
2898 int bytes_returned = 0;
2899 __u16 params, param_offset, offset, byte_count;
2900
Joe Perchesf96637b2013-05-04 22:12:25 -05002901 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902createSymLinkRetry:
2903 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2904 (void **) &pSMBr);
2905 if (rc)
2906 return rc;
2907
2908 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2909 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002910 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2911 /* find define for this maxpathcomponent */
2912 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 name_len++; /* trailing null */
2914 name_len *= 2;
2915
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002916 } else {
2917 name_len = copy_path_name(pSMB->FileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 }
2919 params = 6 + name_len;
2920 pSMB->MaxSetupCount = 0;
2921 pSMB->Reserved = 0;
2922 pSMB->Flags = 0;
2923 pSMB->Timeout = 0;
2924 pSMB->Reserved2 = 0;
2925 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002926 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 offset = param_offset + params;
2928
Steve Frenchded2d992021-07-01 20:44:27 -05002929 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2930 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2932 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002933 cifsConvertToUTF16((__le16 *) data_offset, toName,
2934 /* find define for this maxpathcomponent */
2935 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 name_len_target++; /* trailing null */
2937 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002938 } else {
2939 name_len_target = copy_path_name(data_offset, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 }
2941
2942 pSMB->MaxParameterCount = cpu_to_le16(2);
2943 /* BB find exact max on data count below from sess */
2944 pSMB->MaxDataCount = cpu_to_le16(1000);
2945 pSMB->SetupCount = 1;
2946 pSMB->Reserved3 = 0;
2947 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2948 byte_count = 3 /* pad */ + params + name_len_target;
2949 pSMB->DataCount = cpu_to_le16(name_len_target);
2950 pSMB->ParameterCount = cpu_to_le16(params);
2951 pSMB->TotalDataCount = pSMB->DataCount;
2952 pSMB->TotalParameterCount = pSMB->ParameterCount;
2953 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2954 pSMB->DataOffset = cpu_to_le16(offset);
2955 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2956 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002957 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 pSMB->ByteCount = cpu_to_le16(byte_count);
2959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002961 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002962 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002963 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2964 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965
Steve French0d817bc2008-05-22 02:02:03 +00002966 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
2968 if (rc == -EAGAIN)
2969 goto createSymLinkRetry;
2970
2971 return rc;
2972}
2973
2974int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002975CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002977 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978{
2979 TRANSACTION2_SPI_REQ *pSMB = NULL;
2980 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2981 char *data_offset;
2982 int name_len;
2983 int name_len_target;
2984 int rc = 0;
2985 int bytes_returned = 0;
2986 __u16 params, param_offset, offset, byte_count;
2987
Joe Perchesf96637b2013-05-04 22:12:25 -05002988 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989createHardLinkRetry:
2990 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2991 (void **) &pSMBr);
2992 if (rc)
2993 return rc;
2994
2995 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002996 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2997 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 name_len++; /* trailing null */
2999 name_len *= 2;
3000
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003001 } else {
3002 name_len = copy_path_name(pSMB->FileName, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 }
3004 params = 6 + name_len;
3005 pSMB->MaxSetupCount = 0;
3006 pSMB->Reserved = 0;
3007 pSMB->Flags = 0;
3008 pSMB->Timeout = 0;
3009 pSMB->Reserved2 = 0;
3010 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003011 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 offset = param_offset + params;
3013
Steve French819f9162021-07-01 17:46:23 -05003014 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
3015 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3017 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003018 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3019 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 name_len_target++; /* trailing null */
3021 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003022 } else {
3023 name_len_target = copy_path_name(data_offset, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 }
3025
3026 pSMB->MaxParameterCount = cpu_to_le16(2);
3027 /* BB find exact max on data count below from sess*/
3028 pSMB->MaxDataCount = cpu_to_le16(1000);
3029 pSMB->SetupCount = 1;
3030 pSMB->Reserved3 = 0;
3031 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3032 byte_count = 3 /* pad */ + params + name_len_target;
3033 pSMB->ParameterCount = cpu_to_le16(params);
3034 pSMB->TotalParameterCount = pSMB->ParameterCount;
3035 pSMB->DataCount = cpu_to_le16(name_len_target);
3036 pSMB->TotalDataCount = pSMB->DataCount;
3037 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3038 pSMB->DataOffset = cpu_to_le16(offset);
3039 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3040 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003041 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 pSMB->ByteCount = cpu_to_le16(byte_count);
3043 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003045 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003046 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003047 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3048 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049
3050 cifs_buf_release(pSMB);
3051 if (rc == -EAGAIN)
3052 goto createHardLinkRetry;
3053
3054 return rc;
3055}
3056
3057int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003058CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003059 const char *from_name, const char *to_name,
3060 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061{
3062 int rc = 0;
3063 NT_RENAME_REQ *pSMB = NULL;
3064 RENAME_RSP *pSMBr = NULL;
3065 int bytes_returned;
3066 int name_len, name_len2;
3067 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003068 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069
Joe Perchesf96637b2013-05-04 22:12:25 -05003070 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071winCreateHardLinkRetry:
3072
3073 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3074 (void **) &pSMBr);
3075 if (rc)
3076 return rc;
3077
3078 pSMB->SearchAttributes =
3079 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3080 ATTR_DIRECTORY);
3081 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3082 pSMB->ClusterCount = 0;
3083
3084 pSMB->BufferFormat = 0x04;
3085
3086 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3087 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003088 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3089 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 name_len++; /* trailing null */
3091 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003092
3093 /* protocol specifies ASCII buffer format (0x04) for unicode */
3094 pSMB->OldFileName[name_len] = 0x04;
3095 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003097 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003098 to_name, PATH_MAX, cifs_sb->local_nls,
3099 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3101 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003102 } else {
3103 name_len = copy_path_name(pSMB->OldFileName, from_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003105 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 name_len2++; /* signature byte */
3107 }
3108
3109 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003110 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 pSMB->ByteCount = cpu_to_le16(count);
3112
3113 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3114 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003115 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003116 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003117 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003118
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 cifs_buf_release(pSMB);
3120 if (rc == -EAGAIN)
3121 goto winCreateHardLinkRetry;
3122
3123 return rc;
3124}
3125
3126int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003127CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003128 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003129 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130{
3131/* SMB_QUERY_FILE_UNIX_LINK */
3132 TRANSACTION2_QPI_REQ *pSMB = NULL;
3133 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3134 int rc = 0;
3135 int bytes_returned;
3136 int name_len;
3137 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003138 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139
Joe Perchesf96637b2013-05-04 22:12:25 -05003140 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
3142querySymLinkRetry:
3143 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3144 (void **) &pSMBr);
3145 if (rc)
3146 return rc;
3147
3148 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3149 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003150 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3151 searchName, PATH_MAX, nls_codepage,
3152 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 name_len++; /* trailing null */
3154 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003155 } else {
3156 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 }
3158
3159 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3160 pSMB->TotalDataCount = 0;
3161 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003162 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 pSMB->MaxSetupCount = 0;
3164 pSMB->Reserved = 0;
3165 pSMB->Flags = 0;
3166 pSMB->Timeout = 0;
3167 pSMB->Reserved2 = 0;
3168 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003169 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 pSMB->DataCount = 0;
3171 pSMB->DataOffset = 0;
3172 pSMB->SetupCount = 1;
3173 pSMB->Reserved3 = 0;
3174 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3175 byte_count = params + 1 /* pad */ ;
3176 pSMB->TotalParameterCount = cpu_to_le16(params);
3177 pSMB->ParameterCount = pSMB->TotalParameterCount;
3178 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3179 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003180 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 pSMB->ByteCount = cpu_to_le16(byte_count);
3182
3183 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3184 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3185 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003186 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 } else {
3188 /* decode response */
3189
3190 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003192 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003193 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003195 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003196 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
Jeff Layton460b9692009-04-30 07:17:56 -04003198 data_start = ((char *) &pSMBr->hdr.Protocol) +
3199 le16_to_cpu(pSMBr->t2.DataOffset);
3200
Steve French0e0d2cf2009-05-01 05:27:32 +00003201 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3202 is_unicode = true;
3203 else
3204 is_unicode = false;
3205
Steve French737b7582005-04-28 22:41:06 -07003206 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003207 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3208 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003209 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003210 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 }
3212 }
3213 cifs_buf_release(pSMB);
3214 if (rc == -EAGAIN)
3215 goto querySymLinkRetry;
3216 return rc;
3217}
3218
Steve Frenchc52a95542011-02-24 06:16:22 +00003219/*
3220 * Recent Windows versions now create symlinks more frequently
3221 * and they use the "reparse point" mechanism below. We can of course
3222 * do symlinks nicely to Samba and other servers which support the
3223 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3224 * "MF" symlinks optionally, but for recent Windows we really need to
3225 * reenable the code below and fix the cifs_symlink callers to handle this.
3226 * In the interim this code has been moved to its own config option so
3227 * it is not compiled in by default until callers fixed up and more tested.
3228 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003230CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3231 __u16 fid, char **symlinkinfo,
3232 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
3234 int rc = 0;
3235 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003236 struct smb_com_transaction_ioctl_req *pSMB;
3237 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003238 bool is_unicode;
3239 unsigned int sub_len;
3240 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003241 struct reparse_symlink_data *reparse_buf;
3242 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003243 __u32 data_offset, data_count;
3244 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003246 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3248 (void **) &pSMBr);
3249 if (rc)
3250 return rc;
3251
3252 pSMB->TotalParameterCount = 0 ;
3253 pSMB->TotalDataCount = 0;
3254 pSMB->MaxParameterCount = cpu_to_le32(2);
3255 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003256 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 pSMB->MaxSetupCount = 4;
3258 pSMB->Reserved = 0;
3259 pSMB->ParameterOffset = 0;
3260 pSMB->DataCount = 0;
3261 pSMB->DataOffset = 0;
3262 pSMB->SetupCount = 4;
3263 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3264 pSMB->ParameterCount = pSMB->TotalParameterCount;
3265 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3266 pSMB->IsFsctl = 1; /* FSCTL */
3267 pSMB->IsRootFlag = 0;
3268 pSMB->Fid = fid; /* file handle always le */
3269 pSMB->ByteCount = 0;
3270
3271 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3272 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3273 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003274 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003275 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 }
Steve French989c7e52009-05-02 05:32:20 +00003277
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003278 data_offset = le32_to_cpu(pSMBr->DataOffset);
3279 data_count = le32_to_cpu(pSMBr->DataCount);
3280 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3281 /* BB also check enough total bytes returned */
3282 rc = -EIO; /* bad smb */
3283 goto qreparse_out;
3284 }
3285 if (!data_count || (data_count > 2048)) {
3286 rc = -EIO;
3287 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3288 goto qreparse_out;
3289 }
3290 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003291 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003292 ((char *)&pSMBr->hdr.Protocol + data_offset);
3293 if ((char *)reparse_buf >= end_of_smb) {
3294 rc = -EIO;
3295 goto qreparse_out;
3296 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003297 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3298 cifs_dbg(FYI, "NFS style reparse tag\n");
3299 posix_buf = (struct reparse_posix_data *)reparse_buf;
3300
3301 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3302 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3303 le64_to_cpu(posix_buf->InodeType));
3304 rc = -EOPNOTSUPP;
3305 goto qreparse_out;
3306 }
3307 is_unicode = true;
3308 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3309 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3310 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3311 rc = -EIO;
3312 goto qreparse_out;
3313 }
3314 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3315 sub_len, is_unicode, nls_codepage);
3316 goto qreparse_out;
3317 } else if (reparse_buf->ReparseTag !=
3318 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3319 rc = -EOPNOTSUPP;
3320 goto qreparse_out;
3321 }
3322
3323 /* Reparse tag is NTFS symlink */
3324 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3325 reparse_buf->PathBuffer;
3326 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3327 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003328 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3329 rc = -EIO;
3330 goto qreparse_out;
3331 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003332 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3333 is_unicode = true;
3334 else
3335 is_unicode = false;
3336
3337 /* BB FIXME investigate remapping reserved chars here */
3338 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3339 nls_codepage);
3340 if (!*symlinkinfo)
3341 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003343 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003345 /*
3346 * Note: On -EAGAIN error only caller can retry on handle based calls
3347 * since file handle passed in no longer valid.
3348 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 return rc;
3350}
3351
Steve Frenchc7f508a2013-10-14 15:27:32 -05003352int
3353CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3354 __u16 fid)
3355{
3356 int rc = 0;
3357 int bytes_returned;
3358 struct smb_com_transaction_compr_ioctl_req *pSMB;
3359 struct smb_com_transaction_ioctl_rsp *pSMBr;
3360
3361 cifs_dbg(FYI, "Set compression for %u\n", fid);
3362 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3363 (void **) &pSMBr);
3364 if (rc)
3365 return rc;
3366
3367 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3368
3369 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003370 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003371 pSMB->MaxParameterCount = 0;
3372 pSMB->MaxDataCount = 0;
3373 pSMB->MaxSetupCount = 4;
3374 pSMB->Reserved = 0;
3375 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003376 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003377 pSMB->DataOffset =
3378 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3379 compression_state) - 4); /* 84 */
3380 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003381 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003382 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003383 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003384 pSMB->IsFsctl = 1; /* FSCTL */
3385 pSMB->IsRootFlag = 0;
3386 pSMB->Fid = fid; /* file handle always le */
3387 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003388 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003389 inc_rfc1001_len(pSMB, 5);
3390
3391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3392 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3393 if (rc)
3394 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3395
3396 cifs_buf_release(pSMB);
3397
3398 /*
3399 * Note: On -EAGAIN error only caller can retry on handle based calls
3400 * since file handle passed in no longer valid.
3401 */
3402 return rc;
3403}
3404
3405
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406#ifdef CONFIG_CIFS_POSIX
3407
3408/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003409static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003410 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411{
3412 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003413 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3414 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3415 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003416/*
3417 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3418 ace->e_perm, ace->e_tag, ace->e_id);
3419*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
3421 return;
3422}
3423
3424/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003425static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3426 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427{
3428 int size = 0;
3429 int i;
3430 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003431 struct cifs_posix_ace *pACE;
3432 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003433 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434
3435 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3436 return -EOPNOTSUPP;
3437
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003438 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 count = le16_to_cpu(cifs_acl->access_entry_count);
3440 pACE = &cifs_acl->ace_array[0];
3441 size = sizeof(struct cifs_posix_acl);
3442 size += sizeof(struct cifs_posix_ace) * count;
3443 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003444 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003445 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3446 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 return -EINVAL;
3448 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003449 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 count = le16_to_cpu(cifs_acl->access_entry_count);
3451 size = sizeof(struct cifs_posix_acl);
3452 size += sizeof(struct cifs_posix_ace) * count;
3453/* skip past access ACEs to get to default ACEs */
3454 pACE = &cifs_acl->ace_array[count];
3455 count = le16_to_cpu(cifs_acl->default_entry_count);
3456 size += sizeof(struct cifs_posix_ace) * count;
3457 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003458 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 return -EINVAL;
3460 } else {
3461 /* illegal type */
3462 return -EINVAL;
3463 }
3464
3465 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003466 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003467 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003468 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 return -ERANGE;
3470 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003471 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3472
Steve Frenchff7feac2005-11-15 16:45:16 -08003473 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003474 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003475 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003476 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 }
3478 }
3479 return size;
3480}
3481
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303482static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003483 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484{
Steve Frenchff7feac2005-11-15 16:45:16 -08003485 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3486 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003488 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 /* Probably no need to le convert -1 on any arch but can not hurt */
3490 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003491 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003492 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003493/*
3494 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3495 ace->e_perm, ace->e_tag, ace->e_id);
3496*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497}
3498
3499/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003500static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3501 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502{
3503 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003504 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003505 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003506 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 int count;
3508 int i;
3509
Steve French790fe572007-07-07 19:25:05 +00003510 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 return 0;
3512
3513 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003514 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3515 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003516 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003517 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3518 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 return 0;
3520 }
3521 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003522 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003523 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003524 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003525 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003526 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003527 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003528 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003529 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 return 0;
3531 }
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303532 for (i = 0; i < count; i++)
3533 convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003534 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3536 rc += sizeof(struct cifs_posix_acl);
3537 /* BB add check to make sure ACL does not overflow SMB */
3538 }
3539 return rc;
3540}
3541
3542int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003543CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003544 const unsigned char *searchName,
3545 char *acl_inf, const int buflen, const int acl_type,
3546 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547{
3548/* SMB_QUERY_POSIX_ACL */
3549 TRANSACTION2_QPI_REQ *pSMB = NULL;
3550 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3551 int rc = 0;
3552 int bytes_returned;
3553 int name_len;
3554 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003555
Joe Perchesf96637b2013-05-04 22:12:25 -05003556 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557
3558queryAclRetry:
3559 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3560 (void **) &pSMBr);
3561 if (rc)
3562 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003563
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3565 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003566 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3567 searchName, PATH_MAX, nls_codepage,
3568 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 name_len++; /* trailing null */
3570 name_len *= 2;
3571 pSMB->FileName[name_len] = 0;
3572 pSMB->FileName[name_len+1] = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003573 } else {
3574 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 }
3576
3577 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3578 pSMB->TotalDataCount = 0;
3579 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003580 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 pSMB->MaxDataCount = cpu_to_le16(4000);
3582 pSMB->MaxSetupCount = 0;
3583 pSMB->Reserved = 0;
3584 pSMB->Flags = 0;
3585 pSMB->Timeout = 0;
3586 pSMB->Reserved2 = 0;
3587 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003588 offsetof(struct smb_com_transaction2_qpi_req,
3589 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 pSMB->DataCount = 0;
3591 pSMB->DataOffset = 0;
3592 pSMB->SetupCount = 1;
3593 pSMB->Reserved3 = 0;
3594 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3595 byte_count = params + 1 /* pad */ ;
3596 pSMB->TotalParameterCount = cpu_to_le16(params);
3597 pSMB->ParameterCount = pSMB->TotalParameterCount;
3598 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3599 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003600 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 pSMB->ByteCount = cpu_to_le16(byte_count);
3602
3603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003605 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003607 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 } else {
3609 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003610
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003613 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 rc = -EIO; /* bad smb */
3615 else {
3616 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3617 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3618 rc = cifs_copy_posix_acl(acl_inf,
3619 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003620 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 }
3622 }
3623 cifs_buf_release(pSMB);
3624 if (rc == -EAGAIN)
3625 goto queryAclRetry;
3626 return rc;
3627}
3628
3629int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003630CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003631 const unsigned char *fileName,
3632 const char *local_acl, const int buflen,
3633 const int acl_type,
3634 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635{
3636 struct smb_com_transaction2_spi_req *pSMB = NULL;
3637 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3638 char *parm_data;
3639 int name_len;
3640 int rc = 0;
3641 int bytes_returned = 0;
3642 __u16 params, byte_count, data_count, param_offset, offset;
3643
Joe Perchesf96637b2013-05-04 22:12:25 -05003644 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645setAclRetry:
3646 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003647 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 if (rc)
3649 return rc;
3650 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3651 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003652 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3653 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 name_len++; /* trailing null */
3655 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003656 } else {
3657 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 }
3659 params = 6 + name_len;
3660 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003661 /* BB find max SMB size from sess */
3662 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 pSMB->MaxSetupCount = 0;
3664 pSMB->Reserved = 0;
3665 pSMB->Flags = 0;
3666 pSMB->Timeout = 0;
3667 pSMB->Reserved2 = 0;
3668 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003669 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 offset = param_offset + params;
3671 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3672 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3673
3674 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003675 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
Steve French790fe572007-07-07 19:25:05 +00003677 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 rc = -EOPNOTSUPP;
3679 goto setACLerrorExit;
3680 }
3681 pSMB->DataOffset = cpu_to_le16(offset);
3682 pSMB->SetupCount = 1;
3683 pSMB->Reserved3 = 0;
3684 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3685 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3686 byte_count = 3 /* pad */ + params + data_count;
3687 pSMB->DataCount = cpu_to_le16(data_count);
3688 pSMB->TotalDataCount = pSMB->DataCount;
3689 pSMB->ParameterCount = cpu_to_le16(params);
3690 pSMB->TotalParameterCount = pSMB->ParameterCount;
3691 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003692 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 pSMB->ByteCount = cpu_to_le16(byte_count);
3694 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003695 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003696 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003697 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698
3699setACLerrorExit:
3700 cifs_buf_release(pSMB);
3701 if (rc == -EAGAIN)
3702 goto setAclRetry;
3703 return rc;
3704}
3705
Steve Frenchf654bac2005-04-28 22:41:04 -07003706/* BB fix tabs in this function FIXME BB */
3707int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003708CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003709 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003710{
Steve French50c2f752007-07-13 00:33:32 +00003711 int rc = 0;
3712 struct smb_t2_qfi_req *pSMB = NULL;
3713 struct smb_t2_qfi_rsp *pSMBr = NULL;
3714 int bytes_returned;
3715 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003716
Joe Perchesf96637b2013-05-04 22:12:25 -05003717 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003718 if (tcon == NULL)
3719 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003720
3721GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003722 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3723 (void **) &pSMBr);
3724 if (rc)
3725 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003726
Steve Frenchad7a2922008-02-07 23:25:02 +00003727 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003728 pSMB->t2.TotalDataCount = 0;
3729 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3730 /* BB find exact max data count below from sess structure BB */
3731 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3732 pSMB->t2.MaxSetupCount = 0;
3733 pSMB->t2.Reserved = 0;
3734 pSMB->t2.Flags = 0;
3735 pSMB->t2.Timeout = 0;
3736 pSMB->t2.Reserved2 = 0;
3737 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3738 Fid) - 4);
3739 pSMB->t2.DataCount = 0;
3740 pSMB->t2.DataOffset = 0;
3741 pSMB->t2.SetupCount = 1;
3742 pSMB->t2.Reserved3 = 0;
3743 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3744 byte_count = params + 1 /* pad */ ;
3745 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3746 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3747 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3748 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003749 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003750 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003751 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003752
Steve French790fe572007-07-07 19:25:05 +00003753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3754 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3755 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003756 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003757 } else {
3758 /* decode response */
3759 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003760 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003761 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003762 /* If rc should we check for EOPNOSUPP and
3763 disable the srvino flag? or in caller? */
3764 rc = -EIO; /* bad smb */
3765 else {
3766 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3767 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3768 struct file_chattr_info *pfinfo;
3769 /* BB Do we need a cast or hash here ? */
3770 if (count != 16) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003771 cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003772 rc = -EIO;
3773 goto GetExtAttrOut;
3774 }
3775 pfinfo = (struct file_chattr_info *)
3776 (data_offset + (char *) &pSMBr->hdr.Protocol);
3777 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003778 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003779 }
3780 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003781GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003782 cifs_buf_release(pSMB);
3783 if (rc == -EAGAIN)
3784 goto GetExtAttrRetry;
3785 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003786}
3787
Steve Frenchf654bac2005-04-28 22:41:04 -07003788#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
Jeff Layton79df1ba2010-12-06 12:52:08 -05003790/*
3791 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3792 * all NT TRANSACTS that we init here have total parm and data under about 400
3793 * bytes (to fit in small cifs buffer size), which is the case so far, it
3794 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3795 * returned setup area) and MaxParameterCount (returned parms size) must be set
3796 * by caller
3797 */
3798static int
3799smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003800 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003801 void **ret_buf)
3802{
3803 int rc;
3804 __u32 temp_offset;
3805 struct smb_com_ntransact_req *pSMB;
3806
3807 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3808 (void **)&pSMB);
3809 if (rc)
3810 return rc;
3811 *ret_buf = (void *)pSMB;
3812 pSMB->Reserved = 0;
3813 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3814 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003815 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003816 pSMB->ParameterCount = pSMB->TotalParameterCount;
3817 pSMB->DataCount = pSMB->TotalDataCount;
3818 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3819 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3820 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3821 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3822 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3823 pSMB->SubCommand = cpu_to_le16(sub_command);
3824 return 0;
3825}
3826
3827static int
3828validate_ntransact(char *buf, char **ppparm, char **ppdata,
3829 __u32 *pparmlen, __u32 *pdatalen)
3830{
3831 char *end_of_smb;
3832 __u32 data_count, data_offset, parm_count, parm_offset;
3833 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003834 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003835
3836 *pdatalen = 0;
3837 *pparmlen = 0;
3838
3839 if (buf == NULL)
3840 return -EINVAL;
3841
3842 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3843
Jeff Layton820a8032011-05-04 08:05:26 -04003844 bcc = get_bcc(&pSMBr->hdr);
3845 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003846 (char *)&pSMBr->ByteCount;
3847
3848 data_offset = le32_to_cpu(pSMBr->DataOffset);
3849 data_count = le32_to_cpu(pSMBr->DataCount);
3850 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3851 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3852
3853 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3854 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3855
3856 /* should we also check that parm and data areas do not overlap? */
3857 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003858 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003859 return -EINVAL;
3860 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003861 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003862 return -EINVAL;
3863 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003864 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003865 return -EINVAL;
3866 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003867 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3868 *ppdata, data_count, (data_count + *ppdata),
3869 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003870 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003871 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003872 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003873 return -EINVAL;
3874 }
3875 *pdatalen = data_count;
3876 *pparmlen = parm_count;
3877 return 0;
3878}
3879
Steve French0a4b92c2006-01-12 15:44:21 -08003880/* Get Security Descriptor (by handle) from remote server for a file or dir */
3881int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003882CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003883 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003884{
3885 int rc = 0;
3886 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003887 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003888 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003889 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003890
Joe Perchesf96637b2013-05-04 22:12:25 -05003891 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003892
Steve French630f3f0c2007-10-25 21:17:17 +00003893 *pbuflen = 0;
3894 *acl_inf = NULL;
3895
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003896 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003897 8 /* parm len */, tcon, (void **) &pSMB);
3898 if (rc)
3899 return rc;
3900
3901 pSMB->MaxParameterCount = cpu_to_le32(4);
3902 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3903 pSMB->MaxSetupCount = 0;
3904 pSMB->Fid = fid; /* file handle always le */
3905 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3906 CIFS_ACL_DACL);
3907 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003908 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003909 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003910 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003911
Steve Frencha761ac52007-10-18 21:45:27 +00003912 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003913 0, &rsp_iov);
3914 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003915 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003916 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003917 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003918 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003919 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003920 __u32 parm_len;
3921 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003922 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003923 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003924
3925/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003926 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003927 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003928 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003929 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003930 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003931
Joe Perchesf96637b2013-05-04 22:12:25 -05003932 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3933 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003934
3935 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3936 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003937 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003938 goto qsec_out;
3939 }
3940
3941/* BB check that data area is minimum length and as big as acl_len */
3942
Steve Frenchaf6f4612007-10-16 18:40:37 +00003943 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003944 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003945 cifs_dbg(VFS, "acl length %d does not match %d\n",
3946 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003947 if (*pbuflen > acl_len)
3948 *pbuflen = acl_len;
3949 }
Steve French0a4b92c2006-01-12 15:44:21 -08003950
Steve French630f3f0c2007-10-25 21:17:17 +00003951 /* check if buffer is big enough for the acl
3952 header followed by the smallest SID */
3953 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3954 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003955 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003956 rc = -EINVAL;
3957 *pbuflen = 0;
3958 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003959 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003960 if (*acl_inf == NULL) {
3961 *pbuflen = 0;
3962 rc = -ENOMEM;
3963 }
Steve French630f3f0c2007-10-25 21:17:17 +00003964 }
Steve French0a4b92c2006-01-12 15:44:21 -08003965 }
3966qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003967 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003968 return rc;
3969}
Steve French97837582007-12-31 07:47:21 +00003970
3971int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003972CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003973 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003974{
3975 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3976 int rc = 0;
3977 int bytes_returned = 0;
3978 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003979 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003980
3981setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003982 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003983 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003984 return rc;
Steve French97837582007-12-31 07:47:21 +00003985
3986 pSMB->MaxSetupCount = 0;
3987 pSMB->Reserved = 0;
3988
3989 param_count = 8;
3990 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3991 data_count = acllen;
3992 data_offset = param_offset + param_count;
3993 byte_count = 3 /* pad */ + param_count;
3994
3995 pSMB->DataCount = cpu_to_le32(data_count);
3996 pSMB->TotalDataCount = pSMB->DataCount;
3997 pSMB->MaxParameterCount = cpu_to_le32(4);
3998 pSMB->MaxDataCount = cpu_to_le32(16384);
3999 pSMB->ParameterCount = cpu_to_le32(param_count);
4000 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4001 pSMB->TotalParameterCount = pSMB->ParameterCount;
4002 pSMB->DataOffset = cpu_to_le32(data_offset);
4003 pSMB->SetupCount = 0;
4004 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4005 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4006
4007 pSMB->Fid = fid; /* file handle always le */
4008 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004009 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004010
4011 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004012 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4013 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004014 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004015 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004016 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004017
4018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4020
Joe Perchesf96637b2013-05-04 22:12:25 -05004021 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4022 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004023 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004024 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004025 cifs_buf_release(pSMB);
4026
4027 if (rc == -EAGAIN)
4028 goto setCifsAclRetry;
4029
4030 return (rc);
4031}
4032
Steve French0a4b92c2006-01-12 15:44:21 -08004033
Steve French6b8edfe2005-08-23 20:26:03 -07004034/* Legacy Query Path Information call for lookup to old servers such
4035 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004036int
4037SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4038 const char *search_name, FILE_ALL_INFO *data,
4039 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004040{
Steve Frenchad7a2922008-02-07 23:25:02 +00004041 QUERY_INFORMATION_REQ *pSMB;
4042 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004043 int rc = 0;
4044 int bytes_returned;
4045 int name_len;
4046
Joe Perchesf96637b2013-05-04 22:12:25 -05004047 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004048QInfRetry:
4049 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004050 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004051 if (rc)
4052 return rc;
4053
4054 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4055 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004056 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004057 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004058 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004059 name_len++; /* trailing null */
4060 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004061 } else {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004062 name_len = copy_path_name(pSMB->FileName, search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004063 }
4064 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004065 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004066 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004067 pSMB->ByteCount = cpu_to_le16(name_len);
4068
4069 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004070 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004071 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004072 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004073 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004074 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004075 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004076
4077 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004078 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004079 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004080 ts.tv_nsec = 0;
4081 ts.tv_sec = time;
4082 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004083 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4084 data->LastWriteTime = data->ChangeTime;
4085 data->LastAccessTime = 0;
4086 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004087 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004088 data->EndOfFile = data->AllocationSize;
4089 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004090 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004091 } else
4092 rc = -EIO; /* bad buffer passed in */
4093
4094 cifs_buf_release(pSMB);
4095
4096 if (rc == -EAGAIN)
4097 goto QInfRetry;
4098
4099 return rc;
4100}
4101
Jeff Laytonbcd53572010-02-12 07:44:16 -05004102int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004103CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004104 u16 netfid, FILE_ALL_INFO *pFindData)
4105{
4106 struct smb_t2_qfi_req *pSMB = NULL;
4107 struct smb_t2_qfi_rsp *pSMBr = NULL;
4108 int rc = 0;
4109 int bytes_returned;
4110 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004111
Jeff Laytonbcd53572010-02-12 07:44:16 -05004112QFileInfoRetry:
4113 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4114 (void **) &pSMBr);
4115 if (rc)
4116 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004117
Jeff Laytonbcd53572010-02-12 07:44:16 -05004118 params = 2 /* level */ + 2 /* fid */;
4119 pSMB->t2.TotalDataCount = 0;
4120 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4121 /* BB find exact max data count below from sess structure BB */
4122 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4123 pSMB->t2.MaxSetupCount = 0;
4124 pSMB->t2.Reserved = 0;
4125 pSMB->t2.Flags = 0;
4126 pSMB->t2.Timeout = 0;
4127 pSMB->t2.Reserved2 = 0;
4128 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4129 Fid) - 4);
4130 pSMB->t2.DataCount = 0;
4131 pSMB->t2.DataOffset = 0;
4132 pSMB->t2.SetupCount = 1;
4133 pSMB->t2.Reserved3 = 0;
4134 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4135 byte_count = params + 1 /* pad */ ;
4136 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4137 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4138 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4139 pSMB->Pad = 0;
4140 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004141 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004142 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004143
4144 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4145 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4146 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004147 cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004148 } else { /* decode response */
4149 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4150
4151 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4152 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004153 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004154 rc = -EIO; /* bad smb */
4155 else if (pFindData) {
4156 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4157 memcpy((char *) pFindData,
4158 (char *) &pSMBr->hdr.Protocol +
4159 data_offset, sizeof(FILE_ALL_INFO));
4160 } else
4161 rc = -ENOMEM;
4162 }
4163 cifs_buf_release(pSMB);
4164 if (rc == -EAGAIN)
4165 goto QFileInfoRetry;
4166
4167 return rc;
4168}
Steve French6b8edfe2005-08-23 20:26:03 -07004169
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004171CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004172 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004173 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004174 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004176 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 TRANSACTION2_QPI_REQ *pSMB = NULL;
4178 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4179 int rc = 0;
4180 int bytes_returned;
4181 int name_len;
4182 __u16 params, byte_count;
4183
Joe Perchesf96637b2013-05-04 22:12:25 -05004184 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185QPathInfoRetry:
4186 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4187 (void **) &pSMBr);
4188 if (rc)
4189 return rc;
4190
4191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4192 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004193 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004194 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 name_len++; /* trailing null */
4196 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004197 } else {
4198 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 }
4200
Steve French50c2f752007-07-13 00:33:32 +00004201 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 pSMB->TotalDataCount = 0;
4203 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004204 /* BB find exact max SMB PDU from sess structure BB */
4205 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 pSMB->MaxSetupCount = 0;
4207 pSMB->Reserved = 0;
4208 pSMB->Flags = 0;
4209 pSMB->Timeout = 0;
4210 pSMB->Reserved2 = 0;
4211 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004212 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 pSMB->DataCount = 0;
4214 pSMB->DataOffset = 0;
4215 pSMB->SetupCount = 1;
4216 pSMB->Reserved3 = 0;
4217 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4218 byte_count = params + 1 /* pad */ ;
4219 pSMB->TotalParameterCount = cpu_to_le16(params);
4220 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004221 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004222 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4223 else
4224 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004226 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 pSMB->ByteCount = cpu_to_le16(byte_count);
4228
4229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4231 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004232 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 } else { /* decode response */
4234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4235
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004236 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4237 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004238 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004240 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004241 rc = -EIO; /* 24 or 26 expected but we do not read
4242 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004243 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004244 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004246
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004247 /*
4248 * On legacy responses we do not read the last field,
4249 * EAsize, fortunately since it varies by subdialect and
4250 * also note it differs on Set vs Get, ie two bytes or 4
4251 * bytes depending but we don't care here.
4252 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004253 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004254 size = sizeof(FILE_INFO_STANDARD);
4255 else
4256 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004257 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004258 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 } else
4260 rc = -ENOMEM;
4261 }
4262 cifs_buf_release(pSMB);
4263 if (rc == -EAGAIN)
4264 goto QPathInfoRetry;
4265
4266 return rc;
4267}
4268
4269int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004270CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004271 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4272{
4273 struct smb_t2_qfi_req *pSMB = NULL;
4274 struct smb_t2_qfi_rsp *pSMBr = NULL;
4275 int rc = 0;
4276 int bytes_returned;
4277 __u16 params, byte_count;
4278
4279UnixQFileInfoRetry:
4280 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4281 (void **) &pSMBr);
4282 if (rc)
4283 return rc;
4284
4285 params = 2 /* level */ + 2 /* fid */;
4286 pSMB->t2.TotalDataCount = 0;
4287 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4288 /* BB find exact max data count below from sess structure BB */
4289 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4290 pSMB->t2.MaxSetupCount = 0;
4291 pSMB->t2.Reserved = 0;
4292 pSMB->t2.Flags = 0;
4293 pSMB->t2.Timeout = 0;
4294 pSMB->t2.Reserved2 = 0;
4295 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4296 Fid) - 4);
4297 pSMB->t2.DataCount = 0;
4298 pSMB->t2.DataOffset = 0;
4299 pSMB->t2.SetupCount = 1;
4300 pSMB->t2.Reserved3 = 0;
4301 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4302 byte_count = params + 1 /* pad */ ;
4303 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4304 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4305 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4306 pSMB->Pad = 0;
4307 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004308 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004309 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004310
4311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4312 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4313 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004314 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004315 } else { /* decode response */
4316 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4317
Jeff Layton820a8032011-05-04 08:05:26 -04004318 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004319 cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004320 rc = -EIO; /* bad smb */
4321 } else {
4322 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4323 memcpy((char *) pFindData,
4324 (char *) &pSMBr->hdr.Protocol +
4325 data_offset,
4326 sizeof(FILE_UNIX_BASIC_INFO));
4327 }
4328 }
4329
4330 cifs_buf_release(pSMB);
4331 if (rc == -EAGAIN)
4332 goto UnixQFileInfoRetry;
4333
4334 return rc;
4335}
4336
4337int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004338CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004340 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004341 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342{
4343/* SMB_QUERY_FILE_UNIX_BASIC */
4344 TRANSACTION2_QPI_REQ *pSMB = NULL;
4345 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4346 int rc = 0;
4347 int bytes_returned = 0;
4348 int name_len;
4349 __u16 params, byte_count;
4350
Joe Perchesf96637b2013-05-04 22:12:25 -05004351 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352UnixQPathInfoRetry:
4353 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4354 (void **) &pSMBr);
4355 if (rc)
4356 return rc;
4357
4358 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4359 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004360 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4361 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 name_len++; /* trailing null */
4363 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004364 } else {
4365 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 }
4367
Steve French50c2f752007-07-13 00:33:32 +00004368 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 pSMB->TotalDataCount = 0;
4370 pSMB->MaxParameterCount = cpu_to_le16(2);
4371 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004372 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 pSMB->MaxSetupCount = 0;
4374 pSMB->Reserved = 0;
4375 pSMB->Flags = 0;
4376 pSMB->Timeout = 0;
4377 pSMB->Reserved2 = 0;
4378 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004379 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 pSMB->DataCount = 0;
4381 pSMB->DataOffset = 0;
4382 pSMB->SetupCount = 1;
4383 pSMB->Reserved3 = 0;
4384 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4385 byte_count = params + 1 /* pad */ ;
4386 pSMB->TotalParameterCount = cpu_to_le16(params);
4387 pSMB->ParameterCount = pSMB->TotalParameterCount;
4388 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4389 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004390 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 pSMB->ByteCount = cpu_to_le16(byte_count);
4392
4393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4395 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004396 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 } else { /* decode response */
4398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4399
Jeff Layton820a8032011-05-04 08:05:26 -04004400 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004401 cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 rc = -EIO; /* bad smb */
4403 } else {
4404 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4405 memcpy((char *) pFindData,
4406 (char *) &pSMBr->hdr.Protocol +
4407 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004408 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 }
4410 }
4411 cifs_buf_release(pSMB);
4412 if (rc == -EAGAIN)
4413 goto UnixQPathInfoRetry;
4414
4415 return rc;
4416}
4417
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418/* xid, tcon, searchName and codepage are input parms, rest are returned */
4419int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004420CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004421 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004422 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004423 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424{
4425/* level 257 SMB_ */
4426 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4427 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004428 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 int rc = 0;
4430 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004431 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004433 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Joe Perchesf96637b2013-05-04 22:12:25 -05004435 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436
4437findFirstRetry:
4438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4439 (void **) &pSMBr);
4440 if (rc)
4441 return rc;
4442
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004443 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004444 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004445
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4447 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004448 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4449 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004450 /* We can not add the asterik earlier in case
4451 it got remapped to 0xF03A as if it were part of the
4452 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004454 if (msearch) {
4455 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4456 pSMB->FileName[name_len+1] = 0;
4457 pSMB->FileName[name_len+2] = '*';
4458 pSMB->FileName[name_len+3] = 0;
4459 name_len += 4; /* now the trailing null */
4460 /* null terminate just in case */
4461 pSMB->FileName[name_len] = 0;
4462 pSMB->FileName[name_len+1] = 0;
4463 name_len += 2;
4464 }
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004465 } else {
4466 name_len = copy_path_name(pSMB->FileName, searchName);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004467 if (msearch) {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004468 if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4469 name_len = PATH_MAX-2;
4470 /* overwrite nul byte */
4471 pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4472 pSMB->FileName[name_len] = '*';
4473 pSMB->FileName[name_len+1] = 0;
4474 name_len += 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 }
4477
4478 params = 12 + name_len /* includes null */ ;
4479 pSMB->TotalDataCount = 0; /* no EAs */
4480 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004481 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 pSMB->MaxSetupCount = 0;
4483 pSMB->Reserved = 0;
4484 pSMB->Flags = 0;
4485 pSMB->Timeout = 0;
4486 pSMB->Reserved2 = 0;
4487 byte_count = params + 1 /* pad */ ;
4488 pSMB->TotalParameterCount = cpu_to_le16(params);
4489 pSMB->ParameterCount = pSMB->TotalParameterCount;
4490 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004491 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4492 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 pSMB->DataCount = 0;
4494 pSMB->DataOffset = 0;
4495 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4496 pSMB->Reserved3 = 0;
4497 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4498 pSMB->SearchAttributes =
4499 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4500 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004501 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004502 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4504
4505 /* BB what should we set StorageType to? Does it matter? BB */
4506 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004507 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 pSMB->ByteCount = cpu_to_le16(byte_count);
4509
4510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4511 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004512 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
Steve French88274812006-03-09 22:21:45 +00004514 if (rc) {/* BB add logic to retry regular search if Unix search
4515 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004517 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004518
Steve French88274812006-03-09 22:21:45 +00004519 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
4521 /* BB eventually could optimize out free and realloc of buf */
4522 /* for this case */
4523 if (rc == -EAGAIN)
4524 goto findFirstRetry;
4525 } else { /* decode response */
4526 /* BB remember to free buffer if error BB */
4527 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004528 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004529 unsigned int lnoff;
4530
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004532 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 else
Steve French4b18f2a2008-04-29 00:06:05 +00004534 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535
4536 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
zhengbin01d1bd72019-12-25 11:30:21 +08004537 psrch_inf->smallBuf = false;
Steve French50c2f752007-07-13 00:33:32 +00004538 psrch_inf->srch_entries_start =
4539 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4542 le16_to_cpu(pSMBr->t2.ParameterOffset));
4543
Steve French790fe572007-07-07 19:25:05 +00004544 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004545 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 else
Steve French4b18f2a2008-04-29 00:06:05 +00004547 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
Steve French50c2f752007-07-13 00:33:32 +00004549 psrch_inf->entries_in_buffer =
4550 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004551 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004553 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004554 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004555 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004556 psrch_inf->last_entry = NULL;
4557 return rc;
4558 }
4559
Steve French0752f152008-10-07 20:03:33 +00004560 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004561 lnoff;
4562
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004563 if (pnetfid)
4564 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 } else {
4566 cifs_buf_release(pSMB);
4567 }
4568 }
4569
4570 return rc;
4571}
4572
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004573int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4574 __u16 searchHandle, __u16 search_flags,
4575 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576{
4577 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4578 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004579 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 char *response_data;
4581 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004582 int bytes_returned;
4583 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 __u16 params, byte_count;
4585
Joe Perchesf96637b2013-05-04 22:12:25 -05004586 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587
Steve French4b18f2a2008-04-29 00:06:05 +00004588 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 return -ENOENT;
4590
4591 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4592 (void **) &pSMBr);
4593 if (rc)
4594 return rc;
4595
Steve French50c2f752007-07-13 00:33:32 +00004596 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 byte_count = 0;
4598 pSMB->TotalDataCount = 0; /* no EAs */
4599 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004600 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 pSMB->MaxSetupCount = 0;
4602 pSMB->Reserved = 0;
4603 pSMB->Flags = 0;
4604 pSMB->Timeout = 0;
4605 pSMB->Reserved2 = 0;
4606 pSMB->ParameterOffset = cpu_to_le16(
4607 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4608 pSMB->DataCount = 0;
4609 pSMB->DataOffset = 0;
4610 pSMB->SetupCount = 1;
4611 pSMB->Reserved3 = 0;
4612 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4613 pSMB->SearchHandle = searchHandle; /* always kept as le */
4614 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004615 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4617 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004618 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619
4620 name_len = psrch_inf->resume_name_len;
4621 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004622 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4624 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004625 /* 14 byte parm len above enough for 2 byte null terminator */
4626 pSMB->ResumeFileName[name_len] = 0;
4627 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 } else {
4629 rc = -EINVAL;
4630 goto FNext2_err_exit;
4631 }
4632 byte_count = params + 1 /* pad */ ;
4633 pSMB->TotalParameterCount = cpu_to_le16(params);
4634 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004635 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004637
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4639 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004640 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 if (rc) {
4642 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004643 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004644 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004645 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004647 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 } else { /* decode response */
4649 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004650
Steve French790fe572007-07-07 19:25:05 +00004651 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004652 unsigned int lnoff;
4653
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 /* BB fixme add lock for file (srch_info) struct here */
4655 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004656 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 else
Steve French4b18f2a2008-04-29 00:06:05 +00004658 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 response_data = (char *) &pSMBr->hdr.Protocol +
4660 le16_to_cpu(pSMBr->t2.ParameterOffset);
4661 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4662 response_data = (char *)&pSMBr->hdr.Protocol +
4663 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004664 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004665 cifs_small_buf_release(
4666 psrch_inf->ntwrk_buf_start);
4667 else
4668 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 psrch_inf->srch_entries_start = response_data;
4670 psrch_inf->ntwrk_buf_start = (char *)pSMB;
zhengbin01d1bd72019-12-25 11:30:21 +08004671 psrch_inf->smallBuf = false;
Steve French790fe572007-07-07 19:25:05 +00004672 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004673 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 else
Steve French4b18f2a2008-04-29 00:06:05 +00004675 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004676 psrch_inf->entries_in_buffer =
4677 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 psrch_inf->index_of_last_entry +=
4679 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004680 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004681 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004682 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004683 psrch_inf->last_entry = NULL;
4684 return rc;
4685 } else
4686 psrch_inf->last_entry =
4687 psrch_inf->srch_entries_start + lnoff;
4688
Joe Perchesf96637b2013-05-04 22:12:25 -05004689/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4690 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691
4692 /* BB fixme add unlock here */
4693 }
4694
4695 }
4696
4697 /* BB On error, should we leave previous search buf (and count and
4698 last entry fields) intact or free the previous one? */
4699
4700 /* Note: On -EAGAIN error only caller can retry on handle based calls
4701 since file handle passed in no longer valid */
4702FNext2_err_exit:
4703 if (rc != 0)
4704 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 return rc;
4706}
4707
4708int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004709CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004710 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711{
4712 int rc = 0;
4713 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714
Joe Perchesf96637b2013-05-04 22:12:25 -05004715 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4717
4718 /* no sense returning error if session restarted
4719 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004720 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 return 0;
4722 if (rc)
4723 return rc;
4724
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 pSMB->FileID = searchHandle;
4726 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004727 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004728 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004729 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004730 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004731
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004732 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733
4734 /* Since session is dead, search handle closed on server already */
4735 if (rc == -EAGAIN)
4736 rc = 0;
4737
4738 return rc;
4739}
4740
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004742CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004743 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004744 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745{
4746 int rc = 0;
4747 TRANSACTION2_QPI_REQ *pSMB = NULL;
4748 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4749 int name_len, bytes_returned;
4750 __u16 params, byte_count;
4751
Joe Perchesf96637b2013-05-04 22:12:25 -05004752 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004753 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004754 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755
4756GetInodeNumberRetry:
4757 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004758 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 if (rc)
4760 return rc;
4761
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4763 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004764 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004765 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004766 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 name_len++; /* trailing null */
4768 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004769 } else {
4770 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 }
4772
4773 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4774 pSMB->TotalDataCount = 0;
4775 pSMB->MaxParameterCount = cpu_to_le16(2);
4776 /* BB find exact max data count below from sess structure BB */
4777 pSMB->MaxDataCount = cpu_to_le16(4000);
4778 pSMB->MaxSetupCount = 0;
4779 pSMB->Reserved = 0;
4780 pSMB->Flags = 0;
4781 pSMB->Timeout = 0;
4782 pSMB->Reserved2 = 0;
4783 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004784 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 pSMB->DataCount = 0;
4786 pSMB->DataOffset = 0;
4787 pSMB->SetupCount = 1;
4788 pSMB->Reserved3 = 0;
4789 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4790 byte_count = params + 1 /* pad */ ;
4791 pSMB->TotalParameterCount = cpu_to_le16(params);
4792 pSMB->ParameterCount = pSMB->TotalParameterCount;
4793 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4794 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004795 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 pSMB->ByteCount = cpu_to_le16(byte_count);
4797
4798 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4799 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4800 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004801 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 } else {
4803 /* decode response */
4804 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004806 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 /* If rc should we check for EOPNOSUPP and
4808 disable the srvino flag? or in caller? */
4809 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004810 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4812 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004813 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004815 if (count < 8) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004816 cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 rc = -EIO;
4818 goto GetInodeNumOut;
4819 }
4820 pfinfo = (struct file_internal_info *)
4821 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004822 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 }
4824 }
4825GetInodeNumOut:
4826 cifs_buf_release(pSMB);
4827 if (rc == -EAGAIN)
4828 goto GetInodeNumberRetry;
4829 return rc;
4830}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831
4832int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004833CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004834 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004835 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004836 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837{
4838/* TRANS2_GET_DFS_REFERRAL */
4839 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4840 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 int rc = 0;
4842 int bytes_returned;
4843 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004845 *num_of_nodes = 0;
4846 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847
Joe Perchesf96637b2013-05-04 22:12:25 -05004848 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004849 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004851
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004853 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 (void **) &pSMBr);
4855 if (rc)
4856 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004857
4858 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004859 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004860 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004861 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004863 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004865 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867
4868 if (ses->capabilities & CAP_UNICODE) {
4869 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4870 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004871 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004872 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004873 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 name_len++; /* trailing null */
4875 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004876 } else { /* BB improve the check for buffer overruns BB */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004877 name_len = copy_path_name(pSMB->RequestFileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 }
4879
Dan Carpenter65c3b202015-04-30 17:30:24 +03004880 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004881 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004882
Steve French50c2f752007-07-13 00:33:32 +00004883 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004884
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 params = 2 /* level */ + name_len /*includes null */ ;
4886 pSMB->TotalDataCount = 0;
4887 pSMB->DataCount = 0;
4888 pSMB->DataOffset = 0;
4889 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004890 /* BB find exact max SMB PDU from sess structure BB */
4891 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 pSMB->MaxSetupCount = 0;
4893 pSMB->Reserved = 0;
4894 pSMB->Flags = 0;
4895 pSMB->Timeout = 0;
4896 pSMB->Reserved2 = 0;
4897 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004898 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 pSMB->SetupCount = 1;
4900 pSMB->Reserved3 = 0;
4901 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4902 byte_count = params + 3 /* pad */ ;
4903 pSMB->ParameterCount = cpu_to_le16(params);
4904 pSMB->TotalParameterCount = pSMB->ParameterCount;
4905 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004906 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 pSMB->ByteCount = cpu_to_le16(byte_count);
4908
4909 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4911 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004912 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004913 goto GetDFSRefExit;
4914 }
4915 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004917 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004918 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004919 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004920 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004922
Joe Perchesf96637b2013-05-04 22:12:25 -05004923 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4924 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004925
4926 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004927 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4928 le16_to_cpu(pSMBr->t2.DataCount),
4929 num_of_nodes, target_nodes, nls_codepage,
4930 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004931 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004932
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004934 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935
4936 if (rc == -EAGAIN)
4937 goto getDFSRetry;
4938
4939 return rc;
4940}
4941
Steve French20962432005-09-21 22:05:57 -07004942/* Query File System Info such as free space to old servers such as Win 9x */
4943int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004944SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4945 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004946{
4947/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4948 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4949 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4950 FILE_SYSTEM_ALLOC_INFO *response_data;
4951 int rc = 0;
4952 int bytes_returned = 0;
4953 __u16 params, byte_count;
4954
Joe Perchesf96637b2013-05-04 22:12:25 -05004955 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004956oldQFSInfoRetry:
4957 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4958 (void **) &pSMBr);
4959 if (rc)
4960 return rc;
Steve French20962432005-09-21 22:05:57 -07004961
4962 params = 2; /* level */
4963 pSMB->TotalDataCount = 0;
4964 pSMB->MaxParameterCount = cpu_to_le16(2);
4965 pSMB->MaxDataCount = cpu_to_le16(1000);
4966 pSMB->MaxSetupCount = 0;
4967 pSMB->Reserved = 0;
4968 pSMB->Flags = 0;
4969 pSMB->Timeout = 0;
4970 pSMB->Reserved2 = 0;
4971 byte_count = params + 1 /* pad */ ;
4972 pSMB->TotalParameterCount = cpu_to_le16(params);
4973 pSMB->ParameterCount = pSMB->TotalParameterCount;
4974 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4975 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4976 pSMB->DataCount = 0;
4977 pSMB->DataOffset = 0;
4978 pSMB->SetupCount = 1;
4979 pSMB->Reserved3 = 0;
4980 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4981 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004982 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004983 pSMB->ByteCount = cpu_to_le16(byte_count);
4984
4985 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4986 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4987 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004988 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004989 } else { /* decode response */
4990 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4991
Jeff Layton820a8032011-05-04 08:05:26 -04004992 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004993 rc = -EIO; /* bad smb */
4994 else {
4995 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004996 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004997 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004998
Steve French50c2f752007-07-13 00:33:32 +00004999 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005000 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5001 FSData->f_bsize =
5002 le16_to_cpu(response_data->BytesPerSector) *
5003 le32_to_cpu(response_data->
5004 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005005 /*
5006 * much prefer larger but if server doesn't report
5007 * a valid size than 4K is a reasonable minimum
5008 */
5009 if (FSData->f_bsize < 512)
5010 FSData->f_bsize = 4096;
5011
Steve French20962432005-09-21 22:05:57 -07005012 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005013 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005014 FSData->f_bfree = FSData->f_bavail =
5015 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005016 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5017 (unsigned long long)FSData->f_blocks,
5018 (unsigned long long)FSData->f_bfree,
5019 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005020 }
5021 }
5022 cifs_buf_release(pSMB);
5023
5024 if (rc == -EAGAIN)
5025 goto oldQFSInfoRetry;
5026
5027 return rc;
5028}
5029
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005031CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5032 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033{
5034/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5035 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5036 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5037 FILE_SYSTEM_INFO *response_data;
5038 int rc = 0;
5039 int bytes_returned = 0;
5040 __u16 params, byte_count;
5041
Joe Perchesf96637b2013-05-04 22:12:25 -05005042 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043QFSInfoRetry:
5044 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5045 (void **) &pSMBr);
5046 if (rc)
5047 return rc;
5048
5049 params = 2; /* level */
5050 pSMB->TotalDataCount = 0;
5051 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005052 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 pSMB->MaxSetupCount = 0;
5054 pSMB->Reserved = 0;
5055 pSMB->Flags = 0;
5056 pSMB->Timeout = 0;
5057 pSMB->Reserved2 = 0;
5058 byte_count = params + 1 /* pad */ ;
5059 pSMB->TotalParameterCount = cpu_to_le16(params);
5060 pSMB->ParameterCount = pSMB->TotalParameterCount;
5061 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005062 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 pSMB->DataCount = 0;
5064 pSMB->DataOffset = 0;
5065 pSMB->SetupCount = 1;
5066 pSMB->Reserved3 = 0;
5067 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5068 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005069 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 pSMB->ByteCount = cpu_to_le16(byte_count);
5071
5072 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5074 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005075 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005077 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078
Jeff Layton820a8032011-05-04 08:05:26 -04005079 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 rc = -EIO; /* bad smb */
5081 else {
5082 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083
5084 response_data =
5085 (FILE_SYSTEM_INFO
5086 *) (((char *) &pSMBr->hdr.Protocol) +
5087 data_offset);
5088 FSData->f_bsize =
5089 le32_to_cpu(response_data->BytesPerSector) *
5090 le32_to_cpu(response_data->
5091 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005092 /*
5093 * much prefer larger but if server doesn't report
5094 * a valid size than 4K is a reasonable minimum
5095 */
5096 if (FSData->f_bsize < 512)
5097 FSData->f_bsize = 4096;
5098
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 FSData->f_blocks =
5100 le64_to_cpu(response_data->TotalAllocationUnits);
5101 FSData->f_bfree = FSData->f_bavail =
5102 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005103 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5104 (unsigned long long)FSData->f_blocks,
5105 (unsigned long long)FSData->f_bfree,
5106 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 }
5108 }
5109 cifs_buf_release(pSMB);
5110
5111 if (rc == -EAGAIN)
5112 goto QFSInfoRetry;
5113
5114 return rc;
5115}
5116
5117int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005118CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119{
5120/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5121 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5122 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5123 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5124 int rc = 0;
5125 int bytes_returned = 0;
5126 __u16 params, byte_count;
5127
Joe Perchesf96637b2013-05-04 22:12:25 -05005128 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129QFSAttributeRetry:
5130 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5131 (void **) &pSMBr);
5132 if (rc)
5133 return rc;
5134
5135 params = 2; /* level */
5136 pSMB->TotalDataCount = 0;
5137 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005138 /* BB find exact max SMB PDU from sess structure BB */
5139 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 pSMB->MaxSetupCount = 0;
5141 pSMB->Reserved = 0;
5142 pSMB->Flags = 0;
5143 pSMB->Timeout = 0;
5144 pSMB->Reserved2 = 0;
5145 byte_count = params + 1 /* pad */ ;
5146 pSMB->TotalParameterCount = cpu_to_le16(params);
5147 pSMB->ParameterCount = pSMB->TotalParameterCount;
5148 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005149 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 pSMB->DataCount = 0;
5151 pSMB->DataOffset = 0;
5152 pSMB->SetupCount = 1;
5153 pSMB->Reserved3 = 0;
5154 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5155 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005156 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 pSMB->ByteCount = cpu_to_le16(byte_count);
5158
5159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5161 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005162 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 } else { /* decode response */
5164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5165
Jeff Layton820a8032011-05-04 08:05:26 -04005166 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005167 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 rc = -EIO; /* bad smb */
5169 } else {
5170 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5171 response_data =
5172 (FILE_SYSTEM_ATTRIBUTE_INFO
5173 *) (((char *) &pSMBr->hdr.Protocol) +
5174 data_offset);
5175 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005176 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 }
5178 }
5179 cifs_buf_release(pSMB);
5180
5181 if (rc == -EAGAIN)
5182 goto QFSAttributeRetry;
5183
5184 return rc;
5185}
5186
5187int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005188CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189{
5190/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5191 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5192 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5193 FILE_SYSTEM_DEVICE_INFO *response_data;
5194 int rc = 0;
5195 int bytes_returned = 0;
5196 __u16 params, byte_count;
5197
Joe Perchesf96637b2013-05-04 22:12:25 -05005198 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199QFSDeviceRetry:
5200 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5201 (void **) &pSMBr);
5202 if (rc)
5203 return rc;
5204
5205 params = 2; /* level */
5206 pSMB->TotalDataCount = 0;
5207 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005208 /* BB find exact max SMB PDU from sess structure BB */
5209 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 pSMB->MaxSetupCount = 0;
5211 pSMB->Reserved = 0;
5212 pSMB->Flags = 0;
5213 pSMB->Timeout = 0;
5214 pSMB->Reserved2 = 0;
5215 byte_count = params + 1 /* pad */ ;
5216 pSMB->TotalParameterCount = cpu_to_le16(params);
5217 pSMB->ParameterCount = pSMB->TotalParameterCount;
5218 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005219 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220
5221 pSMB->DataCount = 0;
5222 pSMB->DataOffset = 0;
5223 pSMB->SetupCount = 1;
5224 pSMB->Reserved3 = 0;
5225 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5226 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005227 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 pSMB->ByteCount = cpu_to_le16(byte_count);
5229
5230 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5231 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5232 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005233 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 } else { /* decode response */
5235 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5236
Jeff Layton820a8032011-05-04 08:05:26 -04005237 if (rc || get_bcc(&pSMBr->hdr) <
5238 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 rc = -EIO; /* bad smb */
5240 else {
5241 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5242 response_data =
Steve French737b7582005-04-28 22:41:06 -07005243 (FILE_SYSTEM_DEVICE_INFO *)
5244 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 data_offset);
5246 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005247 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 }
5249 }
5250 cifs_buf_release(pSMB);
5251
5252 if (rc == -EAGAIN)
5253 goto QFSDeviceRetry;
5254
5255 return rc;
5256}
5257
5258int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005259CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260{
5261/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5262 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5263 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5264 FILE_SYSTEM_UNIX_INFO *response_data;
5265 int rc = 0;
5266 int bytes_returned = 0;
5267 __u16 params, byte_count;
5268
Joe Perchesf96637b2013-05-04 22:12:25 -05005269 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005271 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5272 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 if (rc)
5274 return rc;
5275
5276 params = 2; /* level */
5277 pSMB->TotalDataCount = 0;
5278 pSMB->DataCount = 0;
5279 pSMB->DataOffset = 0;
5280 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005281 /* BB find exact max SMB PDU from sess structure BB */
5282 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 pSMB->MaxSetupCount = 0;
5284 pSMB->Reserved = 0;
5285 pSMB->Flags = 0;
5286 pSMB->Timeout = 0;
5287 pSMB->Reserved2 = 0;
5288 byte_count = params + 1 /* pad */ ;
5289 pSMB->ParameterCount = cpu_to_le16(params);
5290 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005291 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5292 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 pSMB->SetupCount = 1;
5294 pSMB->Reserved3 = 0;
5295 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5296 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005297 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 pSMB->ByteCount = cpu_to_le16(byte_count);
5299
5300 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5301 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5302 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005303 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 } else { /* decode response */
5305 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5306
Jeff Layton820a8032011-05-04 08:05:26 -04005307 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 rc = -EIO; /* bad smb */
5309 } else {
5310 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5311 response_data =
5312 (FILE_SYSTEM_UNIX_INFO
5313 *) (((char *) &pSMBr->hdr.Protocol) +
5314 data_offset);
5315 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005316 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 }
5318 }
5319 cifs_buf_release(pSMB);
5320
5321 if (rc == -EAGAIN)
5322 goto QFSUnixRetry;
5323
5324
5325 return rc;
5326}
5327
Jeremy Allisonac670552005-06-22 17:26:35 -07005328int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005329CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005330{
5331/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5332 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5333 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5334 int rc = 0;
5335 int bytes_returned = 0;
5336 __u16 params, param_offset, offset, byte_count;
5337
Joe Perchesf96637b2013-05-04 22:12:25 -05005338 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005339SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005340 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005341 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5342 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005343 if (rc)
5344 return rc;
5345
5346 params = 4; /* 2 bytes zero followed by info level. */
5347 pSMB->MaxSetupCount = 0;
5348 pSMB->Reserved = 0;
5349 pSMB->Flags = 0;
5350 pSMB->Timeout = 0;
5351 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005352 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5353 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005354 offset = param_offset + params;
5355
5356 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005357 /* BB find exact max SMB PDU from sess structure BB */
5358 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005359 pSMB->SetupCount = 1;
5360 pSMB->Reserved3 = 0;
5361 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5362 byte_count = 1 /* pad */ + params + 12;
5363
5364 pSMB->DataCount = cpu_to_le16(12);
5365 pSMB->ParameterCount = cpu_to_le16(params);
5366 pSMB->TotalDataCount = pSMB->DataCount;
5367 pSMB->TotalParameterCount = pSMB->ParameterCount;
5368 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5369 pSMB->DataOffset = cpu_to_le16(offset);
5370
5371 /* Params. */
5372 pSMB->FileNum = 0;
5373 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5374
5375 /* Data. */
5376 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5377 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5378 pSMB->ClientUnixCap = cpu_to_le64(cap);
5379
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005380 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005381 pSMB->ByteCount = cpu_to_le16(byte_count);
5382
5383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5385 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005386 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005387 } else { /* decode response */
5388 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005389 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005390 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005391 }
5392 cifs_buf_release(pSMB);
5393
5394 if (rc == -EAGAIN)
5395 goto SETFSUnixRetry;
5396
5397 return rc;
5398}
5399
5400
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401
5402int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005403CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005404 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405{
5406/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5407 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5408 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5409 FILE_SYSTEM_POSIX_INFO *response_data;
5410 int rc = 0;
5411 int bytes_returned = 0;
5412 __u16 params, byte_count;
5413
Joe Perchesf96637b2013-05-04 22:12:25 -05005414 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415QFSPosixRetry:
5416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5417 (void **) &pSMBr);
5418 if (rc)
5419 return rc;
5420
5421 params = 2; /* level */
5422 pSMB->TotalDataCount = 0;
5423 pSMB->DataCount = 0;
5424 pSMB->DataOffset = 0;
5425 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005426 /* BB find exact max SMB PDU from sess structure BB */
5427 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 pSMB->MaxSetupCount = 0;
5429 pSMB->Reserved = 0;
5430 pSMB->Flags = 0;
5431 pSMB->Timeout = 0;
5432 pSMB->Reserved2 = 0;
5433 byte_count = params + 1 /* pad */ ;
5434 pSMB->ParameterCount = cpu_to_le16(params);
5435 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005436 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5437 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 pSMB->SetupCount = 1;
5439 pSMB->Reserved3 = 0;
5440 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5441 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005442 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 pSMB->ByteCount = cpu_to_le16(byte_count);
5444
5445 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5446 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5447 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005448 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 } else { /* decode response */
5450 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5451
Jeff Layton820a8032011-05-04 08:05:26 -04005452 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 rc = -EIO; /* bad smb */
5454 } else {
5455 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5456 response_data =
5457 (FILE_SYSTEM_POSIX_INFO
5458 *) (((char *) &pSMBr->hdr.Protocol) +
5459 data_offset);
5460 FSData->f_bsize =
5461 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005462 /*
5463 * much prefer larger but if server doesn't report
5464 * a valid size than 4K is a reasonable minimum
5465 */
5466 if (FSData->f_bsize < 512)
5467 FSData->f_bsize = 4096;
5468
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 FSData->f_blocks =
5470 le64_to_cpu(response_data->TotalBlocks);
5471 FSData->f_bfree =
5472 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005473 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 FSData->f_bavail = FSData->f_bfree;
5475 } else {
5476 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005477 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 }
Steve French790fe572007-07-07 19:25:05 +00005479 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005481 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005482 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005484 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 }
5486 }
5487 cifs_buf_release(pSMB);
5488
5489 if (rc == -EAGAIN)
5490 goto QFSPosixRetry;
5491
5492 return rc;
5493}
5494
5495
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005496/*
5497 * We can not use write of zero bytes trick to set file size due to need for
5498 * large file support. Also note that this SetPathInfo is preferred to
5499 * SetFileInfo based method in next routine which is only needed to work around
5500 * a sharing violation bugin Samba which this routine can run into.
5501 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005503CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005504 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5505 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506{
5507 struct smb_com_transaction2_spi_req *pSMB = NULL;
5508 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5509 struct file_end_of_file_info *parm_data;
5510 int name_len;
5511 int rc = 0;
5512 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005513 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005514
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 __u16 params, byte_count, data_count, param_offset, offset;
5516
Joe Perchesf96637b2013-05-04 22:12:25 -05005517 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518SetEOFRetry:
5519 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5520 (void **) &pSMBr);
5521 if (rc)
5522 return rc;
5523
5524 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5525 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005526 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5527 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 name_len++; /* trailing null */
5529 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005530 } else {
5531 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 }
5533 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005534 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005536 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 pSMB->MaxSetupCount = 0;
5538 pSMB->Reserved = 0;
5539 pSMB->Flags = 0;
5540 pSMB->Timeout = 0;
5541 pSMB->Reserved2 = 0;
5542 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005543 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005545 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005546 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5547 pSMB->InformationLevel =
5548 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5549 else
5550 pSMB->InformationLevel =
5551 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5552 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5554 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005555 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 else
5557 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005558 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 }
5560
5561 parm_data =
5562 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5563 offset);
5564 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5565 pSMB->DataOffset = cpu_to_le16(offset);
5566 pSMB->SetupCount = 1;
5567 pSMB->Reserved3 = 0;
5568 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5569 byte_count = 3 /* pad */ + params + data_count;
5570 pSMB->DataCount = cpu_to_le16(data_count);
5571 pSMB->TotalDataCount = pSMB->DataCount;
5572 pSMB->ParameterCount = cpu_to_le16(params);
5573 pSMB->TotalParameterCount = pSMB->ParameterCount;
5574 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005575 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 parm_data->FileSize = cpu_to_le64(size);
5577 pSMB->ByteCount = cpu_to_le16(byte_count);
5578 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5579 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005580 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005581 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582
5583 cifs_buf_release(pSMB);
5584
5585 if (rc == -EAGAIN)
5586 goto SetEOFRetry;
5587
5588 return rc;
5589}
5590
5591int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005592CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5593 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594{
5595 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 struct file_end_of_file_info *parm_data;
5597 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 __u16 params, param_offset, offset, byte_count, count;
5599
Joe Perchesf96637b2013-05-04 22:12:25 -05005600 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5601 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005602 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5603
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 if (rc)
5605 return rc;
5606
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005607 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5608 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005609
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 params = 6;
5611 pSMB->MaxSetupCount = 0;
5612 pSMB->Reserved = 0;
5613 pSMB->Flags = 0;
5614 pSMB->Timeout = 0;
5615 pSMB->Reserved2 = 0;
5616 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5617 offset = param_offset + params;
5618
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 count = sizeof(struct file_end_of_file_info);
5620 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005621 /* BB find exact max SMB PDU from sess structure BB */
5622 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 pSMB->SetupCount = 1;
5624 pSMB->Reserved3 = 0;
5625 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5626 byte_count = 3 /* pad */ + params + count;
5627 pSMB->DataCount = cpu_to_le16(count);
5628 pSMB->ParameterCount = cpu_to_le16(params);
5629 pSMB->TotalDataCount = pSMB->DataCount;
5630 pSMB->TotalParameterCount = pSMB->ParameterCount;
5631 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve Frenche3973ea2021-07-06 21:27:26 -05005632 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 parm_data =
Steve Frenche3973ea2021-07-06 21:27:26 -05005634 (struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 pSMB->DataOffset = cpu_to_le16(offset);
5636 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005637 pSMB->Fid = cfile->fid.netfid;
5638 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5640 pSMB->InformationLevel =
5641 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5642 else
5643 pSMB->InformationLevel =
5644 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005645 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5647 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005648 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 else
5650 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005651 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 }
5653 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005654 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005656 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005657 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005659 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5660 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 }
5662
Steve French50c2f752007-07-13 00:33:32 +00005663 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 since file handle passed in no longer valid */
5665
5666 return rc;
5667}
5668
Steve French50c2f752007-07-13 00:33:32 +00005669/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 an open handle, rather than by pathname - this is awkward due to
5671 potential access conflicts on the open, but it is unavoidable for these
5672 old servers since the only other choice is to go from 100 nanosecond DCE
5673 time and resort to the original setpathinfo level which takes the ancient
5674 DOS time format with 2 second granularity */
5675int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005676CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005677 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678{
5679 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 char *data_offset;
5681 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 __u16 params, param_offset, offset, byte_count, count;
5683
Joe Perchesf96637b2013-05-04 22:12:25 -05005684 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005685 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5686
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 if (rc)
5688 return rc;
5689
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005690 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5691 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005692
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 params = 6;
5694 pSMB->MaxSetupCount = 0;
5695 pSMB->Reserved = 0;
5696 pSMB->Flags = 0;
5697 pSMB->Timeout = 0;
5698 pSMB->Reserved2 = 0;
5699 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5700 offset = param_offset + params;
5701
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005702 data_offset = (char *)pSMB +
5703 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704
Steve French26f57362007-08-30 22:09:15 +00005705 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005707 /* BB find max SMB PDU from sess */
5708 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 pSMB->SetupCount = 1;
5710 pSMB->Reserved3 = 0;
5711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5712 byte_count = 3 /* pad */ + params + count;
5713 pSMB->DataCount = cpu_to_le16(count);
5714 pSMB->ParameterCount = cpu_to_le16(params);
5715 pSMB->TotalDataCount = pSMB->DataCount;
5716 pSMB->TotalParameterCount = pSMB->ParameterCount;
5717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5718 pSMB->DataOffset = cpu_to_le16(offset);
5719 pSMB->Fid = fid;
5720 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5721 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5722 else
5723 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5724 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005725 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005727 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005728 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005729 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005730 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005731 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5732 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733
Steve French50c2f752007-07-13 00:33:32 +00005734 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 since file handle passed in no longer valid */
5736
5737 return rc;
5738}
5739
Jeff Layton6d22f092008-09-23 11:48:35 -04005740int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005741CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005742 bool delete_file, __u16 fid, __u32 pid_of_opener)
5743{
5744 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5745 char *data_offset;
5746 int rc = 0;
5747 __u16 params, param_offset, offset, byte_count, count;
5748
Joe Perchesf96637b2013-05-04 22:12:25 -05005749 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005750 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5751
5752 if (rc)
5753 return rc;
5754
5755 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5756 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5757
5758 params = 6;
5759 pSMB->MaxSetupCount = 0;
5760 pSMB->Reserved = 0;
5761 pSMB->Flags = 0;
5762 pSMB->Timeout = 0;
5763 pSMB->Reserved2 = 0;
5764 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5765 offset = param_offset + params;
5766
Steve French2a780e82021-07-06 21:42:08 -05005767 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
5768 data_offset = (char *)(pSMB) + offset + 4;
Jeff Layton6d22f092008-09-23 11:48:35 -04005769
5770 count = 1;
5771 pSMB->MaxParameterCount = cpu_to_le16(2);
5772 /* BB find max SMB PDU from sess */
5773 pSMB->MaxDataCount = cpu_to_le16(1000);
5774 pSMB->SetupCount = 1;
5775 pSMB->Reserved3 = 0;
5776 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5777 byte_count = 3 /* pad */ + params + count;
5778 pSMB->DataCount = cpu_to_le16(count);
5779 pSMB->ParameterCount = cpu_to_le16(params);
5780 pSMB->TotalDataCount = pSMB->DataCount;
5781 pSMB->TotalParameterCount = pSMB->ParameterCount;
5782 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5783 pSMB->DataOffset = cpu_to_le16(offset);
5784 pSMB->Fid = fid;
5785 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5786 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005787 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005788 pSMB->ByteCount = cpu_to_le16(byte_count);
5789 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005790 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005791 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005792 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005793 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005794
5795 return rc;
5796}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005798static int
5799CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
5800 const char *fileName, const FILE_BASIC_INFO *data,
5801 const struct nls_table *nls_codepage,
5802 struct cifs_sb_info *cifs_sb)
5803{
5804 int oplock = 0;
5805 struct cifs_open_parms oparms;
5806 struct cifs_fid fid;
5807 int rc;
5808
5809 oparms.tcon = tcon;
5810 oparms.cifs_sb = cifs_sb;
5811 oparms.desired_access = GENERIC_WRITE;
5812 oparms.create_options = cifs_create_options(cifs_sb, 0);
5813 oparms.disposition = FILE_OPEN;
5814 oparms.path = fileName;
5815 oparms.fid = &fid;
5816 oparms.reconnect = false;
5817
5818 rc = CIFS_open(xid, &oparms, &oplock, NULL);
5819 if (rc)
5820 goto out;
5821
5822 rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
5823 CIFSSMBClose(xid, tcon, fid.netfid);
5824out:
5825
5826 return rc;
5827}
5828
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005830CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005831 const char *fileName, const FILE_BASIC_INFO *data,
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005832 const struct nls_table *nls_codepage,
5833 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834{
5835 TRANSACTION2_SPI_REQ *pSMB = NULL;
5836 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5837 int name_len;
5838 int rc = 0;
5839 int bytes_returned = 0;
5840 char *data_offset;
5841 __u16 params, param_offset, offset, byte_count, count;
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005842 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843
Joe Perchesf96637b2013-05-04 22:12:25 -05005844 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845
5846SetTimesRetry:
5847 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5848 (void **) &pSMBr);
5849 if (rc)
5850 return rc;
5851
5852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5853 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005854 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5855 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856 name_len++; /* trailing null */
5857 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005858 } else {
5859 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860 }
5861
5862 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005863 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005865 /* BB find max SMB PDU from sess structure BB */
5866 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 pSMB->MaxSetupCount = 0;
5868 pSMB->Reserved = 0;
5869 pSMB->Flags = 0;
5870 pSMB->Timeout = 0;
5871 pSMB->Reserved2 = 0;
5872 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005873 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874 offset = param_offset + params;
5875 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5876 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5877 pSMB->DataOffset = cpu_to_le16(offset);
5878 pSMB->SetupCount = 1;
5879 pSMB->Reserved3 = 0;
5880 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5881 byte_count = 3 /* pad */ + params + count;
5882
5883 pSMB->DataCount = cpu_to_le16(count);
5884 pSMB->ParameterCount = cpu_to_le16(params);
5885 pSMB->TotalDataCount = pSMB->DataCount;
5886 pSMB->TotalParameterCount = pSMB->ParameterCount;
5887 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5888 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5889 else
5890 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5891 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005892 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005893 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 pSMB->ByteCount = cpu_to_le16(byte_count);
5895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005897 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005898 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899
5900 cifs_buf_release(pSMB);
5901
5902 if (rc == -EAGAIN)
5903 goto SetTimesRetry;
5904
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005905 if (rc == -EOPNOTSUPP)
5906 return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
5907 nls_codepage, cifs_sb);
5908
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 return rc;
5910}
5911
Jeff Layton654cf142009-07-09 20:02:49 -04005912static void
5913cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5914 const struct cifs_unix_set_info_args *args)
5915{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005916 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005917 u64 mode = args->mode;
5918
Eric W. Biederman49418b22013-02-06 00:57:56 -08005919 if (uid_valid(args->uid))
5920 uid = from_kuid(&init_user_ns, args->uid);
5921 if (gid_valid(args->gid))
5922 gid = from_kgid(&init_user_ns, args->gid);
5923
Jeff Layton654cf142009-07-09 20:02:49 -04005924 /*
5925 * Samba server ignores set of file size to zero due to bugs in some
5926 * older clients, but we should be precise - we use SetFileSize to
5927 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005928 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005929 * zero instead of -1 here
5930 */
5931 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5932 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5933 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5934 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5935 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005936 data_offset->Uid = cpu_to_le64(uid);
5937 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005938 /* better to leave device as zero when it is */
5939 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5940 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5941 data_offset->Permissions = cpu_to_le64(mode);
5942
5943 if (S_ISREG(mode))
5944 data_offset->Type = cpu_to_le32(UNIX_FILE);
5945 else if (S_ISDIR(mode))
5946 data_offset->Type = cpu_to_le32(UNIX_DIR);
5947 else if (S_ISLNK(mode))
5948 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5949 else if (S_ISCHR(mode))
5950 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5951 else if (S_ISBLK(mode))
5952 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5953 else if (S_ISFIFO(mode))
5954 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5955 else if (S_ISSOCK(mode))
5956 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5957}
5958
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005960CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005961 const struct cifs_unix_set_info_args *args,
5962 u16 fid, u32 pid_of_opener)
5963{
5964 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005965 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005966 int rc = 0;
5967 u16 params, param_offset, offset, byte_count, count;
5968
Joe Perchesf96637b2013-05-04 22:12:25 -05005969 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005970 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5971
5972 if (rc)
5973 return rc;
5974
5975 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5976 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5977
5978 params = 6;
5979 pSMB->MaxSetupCount = 0;
5980 pSMB->Reserved = 0;
5981 pSMB->Flags = 0;
5982 pSMB->Timeout = 0;
5983 pSMB->Reserved2 = 0;
5984 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5985 offset = param_offset + params;
5986
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005987 data_offset = (char *)pSMB +
5988 offsetof(struct smb_hdr, Protocol) + offset;
5989
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005990 count = sizeof(FILE_UNIX_BASIC_INFO);
5991
5992 pSMB->MaxParameterCount = cpu_to_le16(2);
5993 /* BB find max SMB PDU from sess */
5994 pSMB->MaxDataCount = cpu_to_le16(1000);
5995 pSMB->SetupCount = 1;
5996 pSMB->Reserved3 = 0;
5997 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5998 byte_count = 3 /* pad */ + params + count;
5999 pSMB->DataCount = cpu_to_le16(count);
6000 pSMB->ParameterCount = cpu_to_le16(params);
6001 pSMB->TotalDataCount = pSMB->DataCount;
6002 pSMB->TotalParameterCount = pSMB->ParameterCount;
6003 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6004 pSMB->DataOffset = cpu_to_le16(offset);
6005 pSMB->Fid = fid;
6006 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6007 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006008 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006009 pSMB->ByteCount = cpu_to_le16(byte_count);
6010
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006011 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006012
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006013 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006014 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006015 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006016 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6017 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006018
6019 /* Note: On -EAGAIN error only caller can retry on handle based calls
6020 since file handle passed in no longer valid */
6021
6022 return rc;
6023}
6024
6025int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006026CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006027 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006028 const struct cifs_unix_set_info_args *args,
6029 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030{
6031 TRANSACTION2_SPI_REQ *pSMB = NULL;
6032 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6033 int name_len;
6034 int rc = 0;
6035 int bytes_returned = 0;
6036 FILE_UNIX_BASIC_INFO *data_offset;
6037 __u16 params, param_offset, offset, count, byte_count;
6038
Joe Perchesf96637b2013-05-04 22:12:25 -05006039 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040setPermsRetry:
6041 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6042 (void **) &pSMBr);
6043 if (rc)
6044 return rc;
6045
6046 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6047 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006048 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006049 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 name_len++; /* trailing null */
6051 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006052 } else {
6053 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 }
6055
6056 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006057 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006059 /* BB find max SMB PDU from sess structure BB */
6060 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061 pSMB->MaxSetupCount = 0;
6062 pSMB->Reserved = 0;
6063 pSMB->Flags = 0;
6064 pSMB->Timeout = 0;
6065 pSMB->Reserved2 = 0;
6066 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006067 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068 offset = param_offset + params;
Steve Frenchb019e112021-07-01 21:01:19 -05006069 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
6070 data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 memset(data_offset, 0, count);
6072 pSMB->DataOffset = cpu_to_le16(offset);
6073 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6074 pSMB->SetupCount = 1;
6075 pSMB->Reserved3 = 0;
6076 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6077 byte_count = 3 /* pad */ + params + count;
6078 pSMB->ParameterCount = cpu_to_le16(params);
6079 pSMB->DataCount = cpu_to_le16(count);
6080 pSMB->TotalParameterCount = pSMB->ParameterCount;
6081 pSMB->TotalDataCount = pSMB->DataCount;
6082 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6083 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006084 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006085
Jeff Layton654cf142009-07-09 20:02:49 -04006086 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087
6088 pSMB->ByteCount = cpu_to_le16(byte_count);
6089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006091 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006092 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093
Steve French0d817bc2008-05-22 02:02:03 +00006094 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 if (rc == -EAGAIN)
6096 goto setPermsRetry;
6097 return rc;
6098}
6099
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006101/*
6102 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6103 * function used by listxattr and getxattr type calls. When ea_name is set,
6104 * it looks for that attribute name and stuffs that value into the EAData
6105 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6106 * buffer. In both cases, the return value is either the length of the
6107 * resulting data or a negative error code. If EAData is a NULL pointer then
6108 * the data isn't copied to it, but the length is returned.
6109 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006110ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006111CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006112 const unsigned char *searchName, const unsigned char *ea_name,
6113 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006114 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115{
6116 /* BB assumes one setup word */
6117 TRANSACTION2_QPI_REQ *pSMB = NULL;
6118 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006119 int remap = cifs_remap(cifs_sb);
6120 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121 int rc = 0;
6122 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006123 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006125 struct fea *temp_fea;
6126 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006127 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006128 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006129 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130
Joe Perchesf96637b2013-05-04 22:12:25 -05006131 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132QAllEAsRetry:
6133 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6134 (void **) &pSMBr);
6135 if (rc)
6136 return rc;
6137
6138 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006139 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006140 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6141 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006142 list_len++; /* trailing null */
6143 list_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006144 } else {
6145 list_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 }
6147
Jeff Layton6e462b92010-02-10 16:18:26 -05006148 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149 pSMB->TotalDataCount = 0;
6150 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006151 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006152 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 pSMB->MaxSetupCount = 0;
6154 pSMB->Reserved = 0;
6155 pSMB->Flags = 0;
6156 pSMB->Timeout = 0;
6157 pSMB->Reserved2 = 0;
6158 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006159 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160 pSMB->DataCount = 0;
6161 pSMB->DataOffset = 0;
6162 pSMB->SetupCount = 1;
6163 pSMB->Reserved3 = 0;
6164 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6165 byte_count = params + 1 /* pad */ ;
6166 pSMB->TotalParameterCount = cpu_to_le16(params);
6167 pSMB->ParameterCount = pSMB->TotalParameterCount;
6168 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6169 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006170 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171 pSMB->ByteCount = cpu_to_le16(byte_count);
6172
6173 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6174 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6175 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006176 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006177 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006179
6180
6181 /* BB also check enough total bytes returned */
6182 /* BB we need to improve the validity checking
6183 of these trans2 responses */
6184
6185 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006186 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006187 rc = -EIO; /* bad smb */
6188 goto QAllEAsOut;
6189 }
6190
6191 /* check that length of list is not more than bcc */
6192 /* check that each entry does not go beyond length
6193 of list */
6194 /* check that each element of each entry does not
6195 go beyond end of list */
6196 /* validate_trans2_offsets() */
6197 /* BB check if start of smb + data_offset > &bcc+ bcc */
6198
6199 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6200 ea_response_data = (struct fealist *)
6201 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6202
Jeff Layton6e462b92010-02-10 16:18:26 -05006203 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006204 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006205 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006206 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006207 /* didn't find the named attribute */
6208 if (ea_name)
6209 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006210 goto QAllEAsOut;
6211 }
6212
Jeff Layton0cd126b2010-02-10 16:18:26 -05006213 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006214 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006215 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006216 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006217 rc = -EIO;
6218 goto QAllEAsOut;
6219 }
6220
Jeff Laytonf0d38682010-02-10 16:18:26 -05006221 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006222 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006223 temp_fea = ea_response_data->list;
6224 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006225 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006226 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006227 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006228
Jeff Layton6e462b92010-02-10 16:18:26 -05006229 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006230 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006231 /* make sure we can read name_len and value_len */
6232 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006233 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006234 rc = -EIO;
6235 goto QAllEAsOut;
6236 }
6237
6238 name_len = temp_fea->name_len;
6239 value_len = le16_to_cpu(temp_fea->value_len);
6240 list_len -= name_len + 1 + value_len;
6241 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006242 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006243 rc = -EIO;
6244 goto QAllEAsOut;
6245 }
6246
Jeff Layton31c05192010-02-10 16:18:26 -05006247 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006248 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006249 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006250 temp_ptr += name_len + 1;
6251 rc = value_len;
6252 if (buf_size == 0)
6253 goto QAllEAsOut;
6254 if ((size_t)value_len > buf_size) {
6255 rc = -ERANGE;
6256 goto QAllEAsOut;
6257 }
6258 memcpy(EAData, temp_ptr, value_len);
6259 goto QAllEAsOut;
6260 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006261 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006262 /* account for prefix user. and trailing null */
6263 rc += (5 + 1 + name_len);
6264 if (rc < (int) buf_size) {
6265 memcpy(EAData, "user.", 5);
6266 EAData += 5;
6267 memcpy(EAData, temp_ptr, name_len);
6268 EAData += name_len;
6269 /* null terminate name */
6270 *EAData = 0;
6271 ++EAData;
6272 } else if (buf_size == 0) {
6273 /* skip copy - calc size only */
6274 } else {
6275 /* stop before overrun buffer */
6276 rc = -ERANGE;
6277 break;
6278 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006279 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006280 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006281 temp_fea = (struct fea *)temp_ptr;
6282 }
6283
Jeff Layton31c05192010-02-10 16:18:26 -05006284 /* didn't find the named attribute */
6285 if (ea_name)
6286 rc = -ENODATA;
6287
Jeff Laytonf0d38682010-02-10 16:18:26 -05006288QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006289 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 if (rc == -EAGAIN)
6291 goto QAllEAsRetry;
6292
6293 return (ssize_t)rc;
6294}
6295
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006297CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6298 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006299 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006300 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301{
6302 struct smb_com_transaction2_spi_req *pSMB = NULL;
6303 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6304 struct fealist *parm_data;
6305 int name_len;
6306 int rc = 0;
6307 int bytes_returned = 0;
6308 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006309 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310
Joe Perchesf96637b2013-05-04 22:12:25 -05006311 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312SetEARetry:
6313 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6314 (void **) &pSMBr);
6315 if (rc)
6316 return rc;
6317
6318 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6319 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006320 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6321 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322 name_len++; /* trailing null */
6323 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006324 } else {
6325 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326 }
6327
6328 params = 6 + name_len;
6329
6330 /* done calculating parms using name_len of file name,
6331 now use name_len to calculate length of ea name
6332 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006333 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 name_len = 0;
6335 else
Steve French50c2f752007-07-13 00:33:32 +00006336 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006338 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006340 /* BB find max SMB PDU from sess */
6341 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 pSMB->MaxSetupCount = 0;
6343 pSMB->Reserved = 0;
6344 pSMB->Flags = 0;
6345 pSMB->Timeout = 0;
6346 pSMB->Reserved2 = 0;
6347 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006348 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 offset = param_offset + params;
6350 pSMB->InformationLevel =
6351 cpu_to_le16(SMB_SET_FILE_EA);
6352
Arnd Bergmannade7db92018-02-02 16:48:47 +01006353 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6355 pSMB->DataOffset = cpu_to_le16(offset);
6356 pSMB->SetupCount = 1;
6357 pSMB->Reserved3 = 0;
6358 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6359 byte_count = 3 /* pad */ + params + count;
6360 pSMB->DataCount = cpu_to_le16(count);
6361 parm_data->list_len = cpu_to_le32(count);
6362 parm_data->list[0].EA_flags = 0;
6363 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006364 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006366 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006367 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 parm_data->list[0].name[name_len] = 0;
6369 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6370 /* caller ensures that ea_value_len is less than 64K but
6371 we need to ensure that it fits within the smb */
6372
Steve French50c2f752007-07-13 00:33:32 +00006373 /*BB add length check to see if it would fit in
6374 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006375 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6376 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006377 memcpy(parm_data->list[0].name+name_len+1,
6378 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379
6380 pSMB->TotalDataCount = pSMB->DataCount;
6381 pSMB->ParameterCount = cpu_to_le16(params);
6382 pSMB->TotalParameterCount = pSMB->ParameterCount;
6383 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006384 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385 pSMB->ByteCount = cpu_to_le16(byte_count);
6386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6387 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006388 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006389 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390
6391 cifs_buf_release(pSMB);
6392
6393 if (rc == -EAGAIN)
6394 goto SetEARetry;
6395
6396 return rc;
6397}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398#endif