blob: a14d3f533301a76eb9fdb36908299d7f9b6e1b9d [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
2770 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2771 rename_info = (struct set_file_rename *) data_offset;
2772 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002773 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 pSMB->SetupCount = 1;
2775 pSMB->Reserved3 = 0;
2776 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2777 byte_count = 3 /* pad */ + params;
2778 pSMB->ParameterCount = cpu_to_le16(params);
2779 pSMB->TotalParameterCount = pSMB->ParameterCount;
2780 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2781 pSMB->DataOffset = cpu_to_le16(offset);
2782 /* construct random name ".cifs_tmp<inodenum><mid>" */
2783 rename_info->overwrite = cpu_to_le32(1);
2784 rename_info->root_fid = 0;
2785 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002786 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002787 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002788 len_of_str =
2789 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002790 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002792 len_of_str =
2793 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002794 target_name, PATH_MAX, nls_codepage,
2795 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 }
2797 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002798 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 byte_count += count;
2800 pSMB->DataCount = cpu_to_le16(count);
2801 pSMB->TotalDataCount = pSMB->DataCount;
2802 pSMB->Fid = netfid;
2803 pSMB->InformationLevel =
2804 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2805 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002806 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 pSMB->ByteCount = cpu_to_le16(byte_count);
2808 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002810 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002811 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002812 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2813 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002814
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 cifs_buf_release(pSMB);
2816
2817 /* Note: On -EAGAIN error only caller can retry on handle based calls
2818 since file handle passed in no longer valid */
2819
2820 return rc;
2821}
2822
2823int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002824CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2825 const char *fromName, const __u16 target_tid, const char *toName,
2826 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827{
2828 int rc = 0;
2829 COPY_REQ *pSMB = NULL;
2830 COPY_RSP *pSMBr = NULL;
2831 int bytes_returned;
2832 int name_len, name_len2;
2833 __u16 count;
2834
Joe Perchesf96637b2013-05-04 22:12:25 -05002835 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836copyRetry:
2837 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2838 (void **) &pSMBr);
2839 if (rc)
2840 return rc;
2841
2842 pSMB->BufferFormat = 0x04;
2843 pSMB->Tid2 = target_tid;
2844
2845 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2846
2847 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002848 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2849 fromName, PATH_MAX, nls_codepage,
2850 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 name_len++; /* trailing null */
2852 name_len *= 2;
2853 pSMB->OldFileName[name_len] = 0x04; /* pad */
2854 /* protocol requires ASCII signature byte on Unicode string */
2855 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002856 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002857 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2858 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2860 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002861 } else {
2862 name_len = copy_path_name(pSMB->OldFileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002864 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 name_len2++; /* signature byte */
2866 }
2867
2868 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002869 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 pSMB->ByteCount = cpu_to_le16(count);
2871
2872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2874 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002875 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2876 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 }
Steve French0d817bc2008-05-22 02:02:03 +00002878 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879
2880 if (rc == -EAGAIN)
2881 goto copyRetry;
2882
2883 return rc;
2884}
2885
2886int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002887CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002889 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890{
2891 TRANSACTION2_SPI_REQ *pSMB = NULL;
2892 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2893 char *data_offset;
2894 int name_len;
2895 int name_len_target;
2896 int rc = 0;
2897 int bytes_returned = 0;
2898 __u16 params, param_offset, offset, byte_count;
2899
Joe Perchesf96637b2013-05-04 22:12:25 -05002900 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901createSymLinkRetry:
2902 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2903 (void **) &pSMBr);
2904 if (rc)
2905 return rc;
2906
2907 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2908 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002909 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2910 /* find define for this maxpathcomponent */
2911 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 name_len++; /* trailing null */
2913 name_len *= 2;
2914
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002915 } else {
2916 name_len = copy_path_name(pSMB->FileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 }
2918 params = 6 + name_len;
2919 pSMB->MaxSetupCount = 0;
2920 pSMB->Reserved = 0;
2921 pSMB->Flags = 0;
2922 pSMB->Timeout = 0;
2923 pSMB->Reserved2 = 0;
2924 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002925 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 offset = param_offset + params;
2927
Steve Frenchded2d992021-07-01 20:44:27 -05002928 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2929 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2931 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002932 cifsConvertToUTF16((__le16 *) data_offset, toName,
2933 /* find define for this maxpathcomponent */
2934 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 name_len_target++; /* trailing null */
2936 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002937 } else {
2938 name_len_target = copy_path_name(data_offset, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 }
2940
2941 pSMB->MaxParameterCount = cpu_to_le16(2);
2942 /* BB find exact max on data count below from sess */
2943 pSMB->MaxDataCount = cpu_to_le16(1000);
2944 pSMB->SetupCount = 1;
2945 pSMB->Reserved3 = 0;
2946 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2947 byte_count = 3 /* pad */ + params + name_len_target;
2948 pSMB->DataCount = cpu_to_le16(name_len_target);
2949 pSMB->ParameterCount = cpu_to_le16(params);
2950 pSMB->TotalDataCount = pSMB->DataCount;
2951 pSMB->TotalParameterCount = pSMB->ParameterCount;
2952 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2953 pSMB->DataOffset = cpu_to_le16(offset);
2954 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2955 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002956 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 pSMB->ByteCount = cpu_to_le16(byte_count);
2958 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2959 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002960 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002961 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002962 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2963 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
Steve French0d817bc2008-05-22 02:02:03 +00002965 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
2967 if (rc == -EAGAIN)
2968 goto createSymLinkRetry;
2969
2970 return rc;
2971}
2972
2973int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002974CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002976 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977{
2978 TRANSACTION2_SPI_REQ *pSMB = NULL;
2979 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2980 char *data_offset;
2981 int name_len;
2982 int name_len_target;
2983 int rc = 0;
2984 int bytes_returned = 0;
2985 __u16 params, param_offset, offset, byte_count;
2986
Joe Perchesf96637b2013-05-04 22:12:25 -05002987 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988createHardLinkRetry:
2989 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2990 (void **) &pSMBr);
2991 if (rc)
2992 return rc;
2993
2994 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002995 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2996 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 name_len++; /* trailing null */
2998 name_len *= 2;
2999
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003000 } else {
3001 name_len = copy_path_name(pSMB->FileName, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 }
3003 params = 6 + name_len;
3004 pSMB->MaxSetupCount = 0;
3005 pSMB->Reserved = 0;
3006 pSMB->Flags = 0;
3007 pSMB->Timeout = 0;
3008 pSMB->Reserved2 = 0;
3009 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003010 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 offset = param_offset + params;
3012
Steve French819f9162021-07-01 17:46:23 -05003013 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
3014 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3016 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003017 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3018 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 name_len_target++; /* trailing null */
3020 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003021 } else {
3022 name_len_target = copy_path_name(data_offset, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 }
3024
3025 pSMB->MaxParameterCount = cpu_to_le16(2);
3026 /* BB find exact max on data count below from sess*/
3027 pSMB->MaxDataCount = cpu_to_le16(1000);
3028 pSMB->SetupCount = 1;
3029 pSMB->Reserved3 = 0;
3030 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3031 byte_count = 3 /* pad */ + params + name_len_target;
3032 pSMB->ParameterCount = cpu_to_le16(params);
3033 pSMB->TotalParameterCount = pSMB->ParameterCount;
3034 pSMB->DataCount = cpu_to_le16(name_len_target);
3035 pSMB->TotalDataCount = pSMB->DataCount;
3036 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3037 pSMB->DataOffset = cpu_to_le16(offset);
3038 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3039 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003040 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 pSMB->ByteCount = cpu_to_le16(byte_count);
3042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003044 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003045 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003046 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3047 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048
3049 cifs_buf_release(pSMB);
3050 if (rc == -EAGAIN)
3051 goto createHardLinkRetry;
3052
3053 return rc;
3054}
3055
3056int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003057CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003058 const char *from_name, const char *to_name,
3059 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060{
3061 int rc = 0;
3062 NT_RENAME_REQ *pSMB = NULL;
3063 RENAME_RSP *pSMBr = NULL;
3064 int bytes_returned;
3065 int name_len, name_len2;
3066 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003067 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
Joe Perchesf96637b2013-05-04 22:12:25 -05003069 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070winCreateHardLinkRetry:
3071
3072 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3073 (void **) &pSMBr);
3074 if (rc)
3075 return rc;
3076
3077 pSMB->SearchAttributes =
3078 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3079 ATTR_DIRECTORY);
3080 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3081 pSMB->ClusterCount = 0;
3082
3083 pSMB->BufferFormat = 0x04;
3084
3085 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3086 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003087 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3088 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 name_len++; /* trailing null */
3090 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003091
3092 /* protocol specifies ASCII buffer format (0x04) for unicode */
3093 pSMB->OldFileName[name_len] = 0x04;
3094 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003096 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003097 to_name, PATH_MAX, cifs_sb->local_nls,
3098 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3100 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003101 } else {
3102 name_len = copy_path_name(pSMB->OldFileName, from_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003104 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 name_len2++; /* signature byte */
3106 }
3107
3108 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003109 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 pSMB->ByteCount = cpu_to_le16(count);
3111
3112 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3113 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003114 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003115 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003116 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003117
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 cifs_buf_release(pSMB);
3119 if (rc == -EAGAIN)
3120 goto winCreateHardLinkRetry;
3121
3122 return rc;
3123}
3124
3125int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003126CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003127 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003128 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129{
3130/* SMB_QUERY_FILE_UNIX_LINK */
3131 TRANSACTION2_QPI_REQ *pSMB = NULL;
3132 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3133 int rc = 0;
3134 int bytes_returned;
3135 int name_len;
3136 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003137 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
Joe Perchesf96637b2013-05-04 22:12:25 -05003139 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140
3141querySymLinkRetry:
3142 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3143 (void **) &pSMBr);
3144 if (rc)
3145 return rc;
3146
3147 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3148 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003149 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3150 searchName, PATH_MAX, nls_codepage,
3151 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 name_len++; /* trailing null */
3153 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003154 } else {
3155 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 }
3157
3158 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3159 pSMB->TotalDataCount = 0;
3160 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003161 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 pSMB->MaxSetupCount = 0;
3163 pSMB->Reserved = 0;
3164 pSMB->Flags = 0;
3165 pSMB->Timeout = 0;
3166 pSMB->Reserved2 = 0;
3167 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003168 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 pSMB->DataCount = 0;
3170 pSMB->DataOffset = 0;
3171 pSMB->SetupCount = 1;
3172 pSMB->Reserved3 = 0;
3173 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3174 byte_count = params + 1 /* pad */ ;
3175 pSMB->TotalParameterCount = cpu_to_le16(params);
3176 pSMB->ParameterCount = pSMB->TotalParameterCount;
3177 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3178 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003179 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 pSMB->ByteCount = cpu_to_le16(byte_count);
3181
3182 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3183 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3184 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003185 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 } else {
3187 /* decode response */
3188
3189 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003191 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003192 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003194 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003195 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
Jeff Layton460b9692009-04-30 07:17:56 -04003197 data_start = ((char *) &pSMBr->hdr.Protocol) +
3198 le16_to_cpu(pSMBr->t2.DataOffset);
3199
Steve French0e0d2cf2009-05-01 05:27:32 +00003200 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3201 is_unicode = true;
3202 else
3203 is_unicode = false;
3204
Steve French737b7582005-04-28 22:41:06 -07003205 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003206 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3207 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003208 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003209 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 }
3211 }
3212 cifs_buf_release(pSMB);
3213 if (rc == -EAGAIN)
3214 goto querySymLinkRetry;
3215 return rc;
3216}
3217
Steve Frenchc52a95542011-02-24 06:16:22 +00003218/*
3219 * Recent Windows versions now create symlinks more frequently
3220 * and they use the "reparse point" mechanism below. We can of course
3221 * do symlinks nicely to Samba and other servers which support the
3222 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3223 * "MF" symlinks optionally, but for recent Windows we really need to
3224 * reenable the code below and fix the cifs_symlink callers to handle this.
3225 * In the interim this code has been moved to its own config option so
3226 * it is not compiled in by default until callers fixed up and more tested.
3227 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003229CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3230 __u16 fid, char **symlinkinfo,
3231 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232{
3233 int rc = 0;
3234 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003235 struct smb_com_transaction_ioctl_req *pSMB;
3236 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003237 bool is_unicode;
3238 unsigned int sub_len;
3239 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003240 struct reparse_symlink_data *reparse_buf;
3241 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003242 __u32 data_offset, data_count;
3243 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003245 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3247 (void **) &pSMBr);
3248 if (rc)
3249 return rc;
3250
3251 pSMB->TotalParameterCount = 0 ;
3252 pSMB->TotalDataCount = 0;
3253 pSMB->MaxParameterCount = cpu_to_le32(2);
3254 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003255 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 pSMB->MaxSetupCount = 4;
3257 pSMB->Reserved = 0;
3258 pSMB->ParameterOffset = 0;
3259 pSMB->DataCount = 0;
3260 pSMB->DataOffset = 0;
3261 pSMB->SetupCount = 4;
3262 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3263 pSMB->ParameterCount = pSMB->TotalParameterCount;
3264 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3265 pSMB->IsFsctl = 1; /* FSCTL */
3266 pSMB->IsRootFlag = 0;
3267 pSMB->Fid = fid; /* file handle always le */
3268 pSMB->ByteCount = 0;
3269
3270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3271 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3272 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003273 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003274 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 }
Steve French989c7e52009-05-02 05:32:20 +00003276
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003277 data_offset = le32_to_cpu(pSMBr->DataOffset);
3278 data_count = le32_to_cpu(pSMBr->DataCount);
3279 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3280 /* BB also check enough total bytes returned */
3281 rc = -EIO; /* bad smb */
3282 goto qreparse_out;
3283 }
3284 if (!data_count || (data_count > 2048)) {
3285 rc = -EIO;
3286 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3287 goto qreparse_out;
3288 }
3289 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003290 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003291 ((char *)&pSMBr->hdr.Protocol + data_offset);
3292 if ((char *)reparse_buf >= end_of_smb) {
3293 rc = -EIO;
3294 goto qreparse_out;
3295 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003296 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3297 cifs_dbg(FYI, "NFS style reparse tag\n");
3298 posix_buf = (struct reparse_posix_data *)reparse_buf;
3299
3300 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3301 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3302 le64_to_cpu(posix_buf->InodeType));
3303 rc = -EOPNOTSUPP;
3304 goto qreparse_out;
3305 }
3306 is_unicode = true;
3307 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3308 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3309 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3310 rc = -EIO;
3311 goto qreparse_out;
3312 }
3313 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3314 sub_len, is_unicode, nls_codepage);
3315 goto qreparse_out;
3316 } else if (reparse_buf->ReparseTag !=
3317 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3318 rc = -EOPNOTSUPP;
3319 goto qreparse_out;
3320 }
3321
3322 /* Reparse tag is NTFS symlink */
3323 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3324 reparse_buf->PathBuffer;
3325 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3326 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003327 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3328 rc = -EIO;
3329 goto qreparse_out;
3330 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003331 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3332 is_unicode = true;
3333 else
3334 is_unicode = false;
3335
3336 /* BB FIXME investigate remapping reserved chars here */
3337 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3338 nls_codepage);
3339 if (!*symlinkinfo)
3340 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003342 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003344 /*
3345 * Note: On -EAGAIN error only caller can retry on handle based calls
3346 * since file handle passed in no longer valid.
3347 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 return rc;
3349}
3350
Steve Frenchc7f508a2013-10-14 15:27:32 -05003351int
3352CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3353 __u16 fid)
3354{
3355 int rc = 0;
3356 int bytes_returned;
3357 struct smb_com_transaction_compr_ioctl_req *pSMB;
3358 struct smb_com_transaction_ioctl_rsp *pSMBr;
3359
3360 cifs_dbg(FYI, "Set compression for %u\n", fid);
3361 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3362 (void **) &pSMBr);
3363 if (rc)
3364 return rc;
3365
3366 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3367
3368 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003369 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003370 pSMB->MaxParameterCount = 0;
3371 pSMB->MaxDataCount = 0;
3372 pSMB->MaxSetupCount = 4;
3373 pSMB->Reserved = 0;
3374 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003375 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003376 pSMB->DataOffset =
3377 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3378 compression_state) - 4); /* 84 */
3379 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003380 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003381 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003382 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003383 pSMB->IsFsctl = 1; /* FSCTL */
3384 pSMB->IsRootFlag = 0;
3385 pSMB->Fid = fid; /* file handle always le */
3386 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003387 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003388 inc_rfc1001_len(pSMB, 5);
3389
3390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3391 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3392 if (rc)
3393 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3394
3395 cifs_buf_release(pSMB);
3396
3397 /*
3398 * Note: On -EAGAIN error only caller can retry on handle based calls
3399 * since file handle passed in no longer valid.
3400 */
3401 return rc;
3402}
3403
3404
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405#ifdef CONFIG_CIFS_POSIX
3406
3407/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003408static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003409 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410{
3411 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003412 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3413 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3414 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003415/*
3416 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3417 ace->e_perm, ace->e_tag, ace->e_id);
3418*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419
3420 return;
3421}
3422
3423/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003424static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3425 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426{
3427 int size = 0;
3428 int i;
3429 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003430 struct cifs_posix_ace *pACE;
3431 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003432 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433
3434 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3435 return -EOPNOTSUPP;
3436
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003437 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 count = le16_to_cpu(cifs_acl->access_entry_count);
3439 pACE = &cifs_acl->ace_array[0];
3440 size = sizeof(struct cifs_posix_acl);
3441 size += sizeof(struct cifs_posix_ace) * count;
3442 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003443 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003444 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3445 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 return -EINVAL;
3447 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003448 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 count = le16_to_cpu(cifs_acl->access_entry_count);
3450 size = sizeof(struct cifs_posix_acl);
3451 size += sizeof(struct cifs_posix_ace) * count;
3452/* skip past access ACEs to get to default ACEs */
3453 pACE = &cifs_acl->ace_array[count];
3454 count = le16_to_cpu(cifs_acl->default_entry_count);
3455 size += sizeof(struct cifs_posix_ace) * count;
3456 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003457 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 return -EINVAL;
3459 } else {
3460 /* illegal type */
3461 return -EINVAL;
3462 }
3463
3464 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003465 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003466 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003467 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 return -ERANGE;
3469 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003470 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3471
Steve Frenchff7feac2005-11-15 16:45:16 -08003472 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003473 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003474 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003475 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 }
3477 }
3478 return size;
3479}
3480
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303481static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003482 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483{
Steve Frenchff7feac2005-11-15 16:45:16 -08003484 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3485 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003487 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 /* Probably no need to le convert -1 on any arch but can not hurt */
3489 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003490 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003491 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003492/*
3493 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3494 ace->e_perm, ace->e_tag, ace->e_id);
3495*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496}
3497
3498/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003499static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3500 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501{
3502 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003503 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003504 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003505 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 int count;
3507 int i;
3508
Steve French790fe572007-07-07 19:25:05 +00003509 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 return 0;
3511
3512 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003513 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3514 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003515 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003516 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3517 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 return 0;
3519 }
3520 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003521 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003522 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003523 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003524 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003525 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003526 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003527 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003528 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 return 0;
3530 }
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303531 for (i = 0; i < count; i++)
3532 convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003533 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3535 rc += sizeof(struct cifs_posix_acl);
3536 /* BB add check to make sure ACL does not overflow SMB */
3537 }
3538 return rc;
3539}
3540
3541int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003542CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003543 const unsigned char *searchName,
3544 char *acl_inf, const int buflen, const int acl_type,
3545 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546{
3547/* SMB_QUERY_POSIX_ACL */
3548 TRANSACTION2_QPI_REQ *pSMB = NULL;
3549 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3550 int rc = 0;
3551 int bytes_returned;
3552 int name_len;
3553 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003554
Joe Perchesf96637b2013-05-04 22:12:25 -05003555 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556
3557queryAclRetry:
3558 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3559 (void **) &pSMBr);
3560 if (rc)
3561 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003562
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3564 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003565 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3566 searchName, PATH_MAX, nls_codepage,
3567 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 name_len++; /* trailing null */
3569 name_len *= 2;
3570 pSMB->FileName[name_len] = 0;
3571 pSMB->FileName[name_len+1] = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003572 } else {
3573 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 }
3575
3576 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3577 pSMB->TotalDataCount = 0;
3578 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003579 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 pSMB->MaxDataCount = cpu_to_le16(4000);
3581 pSMB->MaxSetupCount = 0;
3582 pSMB->Reserved = 0;
3583 pSMB->Flags = 0;
3584 pSMB->Timeout = 0;
3585 pSMB->Reserved2 = 0;
3586 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003587 offsetof(struct smb_com_transaction2_qpi_req,
3588 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 pSMB->DataCount = 0;
3590 pSMB->DataOffset = 0;
3591 pSMB->SetupCount = 1;
3592 pSMB->Reserved3 = 0;
3593 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3594 byte_count = params + 1 /* pad */ ;
3595 pSMB->TotalParameterCount = cpu_to_le16(params);
3596 pSMB->ParameterCount = pSMB->TotalParameterCount;
3597 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3598 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003599 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 pSMB->ByteCount = cpu_to_le16(byte_count);
3601
3602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003604 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003606 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 } else {
3608 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003609
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003612 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 rc = -EIO; /* bad smb */
3614 else {
3615 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3616 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3617 rc = cifs_copy_posix_acl(acl_inf,
3618 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003619 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 }
3621 }
3622 cifs_buf_release(pSMB);
3623 if (rc == -EAGAIN)
3624 goto queryAclRetry;
3625 return rc;
3626}
3627
3628int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003629CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003630 const unsigned char *fileName,
3631 const char *local_acl, const int buflen,
3632 const int acl_type,
3633 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634{
3635 struct smb_com_transaction2_spi_req *pSMB = NULL;
3636 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3637 char *parm_data;
3638 int name_len;
3639 int rc = 0;
3640 int bytes_returned = 0;
3641 __u16 params, byte_count, data_count, param_offset, offset;
3642
Joe Perchesf96637b2013-05-04 22:12:25 -05003643 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644setAclRetry:
3645 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003646 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 if (rc)
3648 return rc;
3649 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3650 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003651 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3652 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 name_len++; /* trailing null */
3654 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003655 } else {
3656 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 }
3658 params = 6 + name_len;
3659 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003660 /* BB find max SMB size from sess */
3661 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 pSMB->MaxSetupCount = 0;
3663 pSMB->Reserved = 0;
3664 pSMB->Flags = 0;
3665 pSMB->Timeout = 0;
3666 pSMB->Reserved2 = 0;
3667 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003668 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 offset = param_offset + params;
3670 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3671 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3672
3673 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003674 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
Steve French790fe572007-07-07 19:25:05 +00003676 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 rc = -EOPNOTSUPP;
3678 goto setACLerrorExit;
3679 }
3680 pSMB->DataOffset = cpu_to_le16(offset);
3681 pSMB->SetupCount = 1;
3682 pSMB->Reserved3 = 0;
3683 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3684 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3685 byte_count = 3 /* pad */ + params + data_count;
3686 pSMB->DataCount = cpu_to_le16(data_count);
3687 pSMB->TotalDataCount = pSMB->DataCount;
3688 pSMB->ParameterCount = cpu_to_le16(params);
3689 pSMB->TotalParameterCount = pSMB->ParameterCount;
3690 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003691 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 pSMB->ByteCount = cpu_to_le16(byte_count);
3693 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003694 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003695 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003696 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697
3698setACLerrorExit:
3699 cifs_buf_release(pSMB);
3700 if (rc == -EAGAIN)
3701 goto setAclRetry;
3702 return rc;
3703}
3704
Steve Frenchf654bac2005-04-28 22:41:04 -07003705/* BB fix tabs in this function FIXME BB */
3706int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003707CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003708 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003709{
Steve French50c2f752007-07-13 00:33:32 +00003710 int rc = 0;
3711 struct smb_t2_qfi_req *pSMB = NULL;
3712 struct smb_t2_qfi_rsp *pSMBr = NULL;
3713 int bytes_returned;
3714 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003715
Joe Perchesf96637b2013-05-04 22:12:25 -05003716 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003717 if (tcon == NULL)
3718 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003719
3720GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003721 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3722 (void **) &pSMBr);
3723 if (rc)
3724 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003725
Steve Frenchad7a2922008-02-07 23:25:02 +00003726 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003727 pSMB->t2.TotalDataCount = 0;
3728 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3729 /* BB find exact max data count below from sess structure BB */
3730 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3731 pSMB->t2.MaxSetupCount = 0;
3732 pSMB->t2.Reserved = 0;
3733 pSMB->t2.Flags = 0;
3734 pSMB->t2.Timeout = 0;
3735 pSMB->t2.Reserved2 = 0;
3736 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3737 Fid) - 4);
3738 pSMB->t2.DataCount = 0;
3739 pSMB->t2.DataOffset = 0;
3740 pSMB->t2.SetupCount = 1;
3741 pSMB->t2.Reserved3 = 0;
3742 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3743 byte_count = params + 1 /* pad */ ;
3744 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3745 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3746 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3747 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003748 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003749 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003750 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003751
Steve French790fe572007-07-07 19:25:05 +00003752 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3753 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3754 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003755 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003756 } else {
3757 /* decode response */
3758 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003759 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003760 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003761 /* If rc should we check for EOPNOSUPP and
3762 disable the srvino flag? or in caller? */
3763 rc = -EIO; /* bad smb */
3764 else {
3765 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3766 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3767 struct file_chattr_info *pfinfo;
3768 /* BB Do we need a cast or hash here ? */
3769 if (count != 16) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003770 cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003771 rc = -EIO;
3772 goto GetExtAttrOut;
3773 }
3774 pfinfo = (struct file_chattr_info *)
3775 (data_offset + (char *) &pSMBr->hdr.Protocol);
3776 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003777 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003778 }
3779 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003780GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003781 cifs_buf_release(pSMB);
3782 if (rc == -EAGAIN)
3783 goto GetExtAttrRetry;
3784 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003785}
3786
Steve Frenchf654bac2005-04-28 22:41:04 -07003787#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788
Jeff Layton79df1ba2010-12-06 12:52:08 -05003789/*
3790 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3791 * all NT TRANSACTS that we init here have total parm and data under about 400
3792 * bytes (to fit in small cifs buffer size), which is the case so far, it
3793 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3794 * returned setup area) and MaxParameterCount (returned parms size) must be set
3795 * by caller
3796 */
3797static int
3798smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003799 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003800 void **ret_buf)
3801{
3802 int rc;
3803 __u32 temp_offset;
3804 struct smb_com_ntransact_req *pSMB;
3805
3806 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3807 (void **)&pSMB);
3808 if (rc)
3809 return rc;
3810 *ret_buf = (void *)pSMB;
3811 pSMB->Reserved = 0;
3812 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3813 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003814 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003815 pSMB->ParameterCount = pSMB->TotalParameterCount;
3816 pSMB->DataCount = pSMB->TotalDataCount;
3817 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3818 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3819 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3820 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3821 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3822 pSMB->SubCommand = cpu_to_le16(sub_command);
3823 return 0;
3824}
3825
3826static int
3827validate_ntransact(char *buf, char **ppparm, char **ppdata,
3828 __u32 *pparmlen, __u32 *pdatalen)
3829{
3830 char *end_of_smb;
3831 __u32 data_count, data_offset, parm_count, parm_offset;
3832 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003833 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003834
3835 *pdatalen = 0;
3836 *pparmlen = 0;
3837
3838 if (buf == NULL)
3839 return -EINVAL;
3840
3841 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3842
Jeff Layton820a8032011-05-04 08:05:26 -04003843 bcc = get_bcc(&pSMBr->hdr);
3844 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003845 (char *)&pSMBr->ByteCount;
3846
3847 data_offset = le32_to_cpu(pSMBr->DataOffset);
3848 data_count = le32_to_cpu(pSMBr->DataCount);
3849 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3850 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3851
3852 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3853 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3854
3855 /* should we also check that parm and data areas do not overlap? */
3856 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003857 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003858 return -EINVAL;
3859 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003860 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003861 return -EINVAL;
3862 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003863 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003864 return -EINVAL;
3865 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003866 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3867 *ppdata, data_count, (data_count + *ppdata),
3868 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003869 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003870 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003871 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003872 return -EINVAL;
3873 }
3874 *pdatalen = data_count;
3875 *pparmlen = parm_count;
3876 return 0;
3877}
3878
Steve French0a4b92c2006-01-12 15:44:21 -08003879/* Get Security Descriptor (by handle) from remote server for a file or dir */
3880int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003881CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003882 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003883{
3884 int rc = 0;
3885 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003886 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003887 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003888 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003889
Joe Perchesf96637b2013-05-04 22:12:25 -05003890 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003891
Steve French630f3f0c2007-10-25 21:17:17 +00003892 *pbuflen = 0;
3893 *acl_inf = NULL;
3894
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003895 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003896 8 /* parm len */, tcon, (void **) &pSMB);
3897 if (rc)
3898 return rc;
3899
3900 pSMB->MaxParameterCount = cpu_to_le32(4);
3901 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3902 pSMB->MaxSetupCount = 0;
3903 pSMB->Fid = fid; /* file handle always le */
3904 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3905 CIFS_ACL_DACL);
3906 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003907 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003908 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003909 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003910
Steve Frencha761ac52007-10-18 21:45:27 +00003911 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003912 0, &rsp_iov);
3913 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003914 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003915 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003916 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003917 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003918 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003919 __u32 parm_len;
3920 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003921 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003922 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003923
3924/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003925 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003926 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003927 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003928 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003929 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003930
Joe Perchesf96637b2013-05-04 22:12:25 -05003931 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3932 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003933
3934 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3935 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003936 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003937 goto qsec_out;
3938 }
3939
3940/* BB check that data area is minimum length and as big as acl_len */
3941
Steve Frenchaf6f4612007-10-16 18:40:37 +00003942 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003943 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003944 cifs_dbg(VFS, "acl length %d does not match %d\n",
3945 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003946 if (*pbuflen > acl_len)
3947 *pbuflen = acl_len;
3948 }
Steve French0a4b92c2006-01-12 15:44:21 -08003949
Steve French630f3f0c2007-10-25 21:17:17 +00003950 /* check if buffer is big enough for the acl
3951 header followed by the smallest SID */
3952 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3953 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003954 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003955 rc = -EINVAL;
3956 *pbuflen = 0;
3957 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003958 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003959 if (*acl_inf == NULL) {
3960 *pbuflen = 0;
3961 rc = -ENOMEM;
3962 }
Steve French630f3f0c2007-10-25 21:17:17 +00003963 }
Steve French0a4b92c2006-01-12 15:44:21 -08003964 }
3965qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003966 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003967 return rc;
3968}
Steve French97837582007-12-31 07:47:21 +00003969
3970int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003971CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003972 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003973{
3974 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3975 int rc = 0;
3976 int bytes_returned = 0;
3977 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003978 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003979
3980setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003981 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003982 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003983 return rc;
Steve French97837582007-12-31 07:47:21 +00003984
3985 pSMB->MaxSetupCount = 0;
3986 pSMB->Reserved = 0;
3987
3988 param_count = 8;
3989 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3990 data_count = acllen;
3991 data_offset = param_offset + param_count;
3992 byte_count = 3 /* pad */ + param_count;
3993
3994 pSMB->DataCount = cpu_to_le32(data_count);
3995 pSMB->TotalDataCount = pSMB->DataCount;
3996 pSMB->MaxParameterCount = cpu_to_le32(4);
3997 pSMB->MaxDataCount = cpu_to_le32(16384);
3998 pSMB->ParameterCount = cpu_to_le32(param_count);
3999 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4000 pSMB->TotalParameterCount = pSMB->ParameterCount;
4001 pSMB->DataOffset = cpu_to_le32(data_offset);
4002 pSMB->SetupCount = 0;
4003 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4004 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4005
4006 pSMB->Fid = fid; /* file handle always le */
4007 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004008 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004009
4010 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004011 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4012 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004013 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004014 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004015 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004016
4017 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4018 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4019
Joe Perchesf96637b2013-05-04 22:12:25 -05004020 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4021 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004022 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004023 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004024 cifs_buf_release(pSMB);
4025
4026 if (rc == -EAGAIN)
4027 goto setCifsAclRetry;
4028
4029 return (rc);
4030}
4031
Steve French0a4b92c2006-01-12 15:44:21 -08004032
Steve French6b8edfe2005-08-23 20:26:03 -07004033/* Legacy Query Path Information call for lookup to old servers such
4034 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004035int
4036SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4037 const char *search_name, FILE_ALL_INFO *data,
4038 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004039{
Steve Frenchad7a2922008-02-07 23:25:02 +00004040 QUERY_INFORMATION_REQ *pSMB;
4041 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004042 int rc = 0;
4043 int bytes_returned;
4044 int name_len;
4045
Joe Perchesf96637b2013-05-04 22:12:25 -05004046 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004047QInfRetry:
4048 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004049 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004050 if (rc)
4051 return rc;
4052
4053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4054 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004055 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004056 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004057 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004058 name_len++; /* trailing null */
4059 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004060 } else {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004061 name_len = copy_path_name(pSMB->FileName, search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004062 }
4063 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004064 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004065 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004066 pSMB->ByteCount = cpu_to_le16(name_len);
4067
4068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004070 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004071 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004072 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004073 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004074 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004075
4076 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004077 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004078 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004079 ts.tv_nsec = 0;
4080 ts.tv_sec = time;
4081 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004082 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4083 data->LastWriteTime = data->ChangeTime;
4084 data->LastAccessTime = 0;
4085 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004086 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004087 data->EndOfFile = data->AllocationSize;
4088 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004089 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004090 } else
4091 rc = -EIO; /* bad buffer passed in */
4092
4093 cifs_buf_release(pSMB);
4094
4095 if (rc == -EAGAIN)
4096 goto QInfRetry;
4097
4098 return rc;
4099}
4100
Jeff Laytonbcd53572010-02-12 07:44:16 -05004101int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004102CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004103 u16 netfid, FILE_ALL_INFO *pFindData)
4104{
4105 struct smb_t2_qfi_req *pSMB = NULL;
4106 struct smb_t2_qfi_rsp *pSMBr = NULL;
4107 int rc = 0;
4108 int bytes_returned;
4109 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004110
Jeff Laytonbcd53572010-02-12 07:44:16 -05004111QFileInfoRetry:
4112 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4113 (void **) &pSMBr);
4114 if (rc)
4115 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004116
Jeff Laytonbcd53572010-02-12 07:44:16 -05004117 params = 2 /* level */ + 2 /* fid */;
4118 pSMB->t2.TotalDataCount = 0;
4119 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4120 /* BB find exact max data count below from sess structure BB */
4121 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4122 pSMB->t2.MaxSetupCount = 0;
4123 pSMB->t2.Reserved = 0;
4124 pSMB->t2.Flags = 0;
4125 pSMB->t2.Timeout = 0;
4126 pSMB->t2.Reserved2 = 0;
4127 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4128 Fid) - 4);
4129 pSMB->t2.DataCount = 0;
4130 pSMB->t2.DataOffset = 0;
4131 pSMB->t2.SetupCount = 1;
4132 pSMB->t2.Reserved3 = 0;
4133 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4134 byte_count = params + 1 /* pad */ ;
4135 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4136 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4137 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4138 pSMB->Pad = 0;
4139 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004140 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004141 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004142
4143 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4144 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4145 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004146 cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004147 } else { /* decode response */
4148 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4149
4150 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4151 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004152 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004153 rc = -EIO; /* bad smb */
4154 else if (pFindData) {
4155 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4156 memcpy((char *) pFindData,
4157 (char *) &pSMBr->hdr.Protocol +
4158 data_offset, sizeof(FILE_ALL_INFO));
4159 } else
4160 rc = -ENOMEM;
4161 }
4162 cifs_buf_release(pSMB);
4163 if (rc == -EAGAIN)
4164 goto QFileInfoRetry;
4165
4166 return rc;
4167}
Steve French6b8edfe2005-08-23 20:26:03 -07004168
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004170CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004171 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004172 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004173 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004175 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 TRANSACTION2_QPI_REQ *pSMB = NULL;
4177 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4178 int rc = 0;
4179 int bytes_returned;
4180 int name_len;
4181 __u16 params, byte_count;
4182
Joe Perchesf96637b2013-05-04 22:12:25 -05004183 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184QPathInfoRetry:
4185 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4186 (void **) &pSMBr);
4187 if (rc)
4188 return rc;
4189
4190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4191 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004192 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004193 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 name_len++; /* trailing null */
4195 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004196 } else {
4197 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 }
4199
Steve French50c2f752007-07-13 00:33:32 +00004200 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 pSMB->TotalDataCount = 0;
4202 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004203 /* BB find exact max SMB PDU from sess structure BB */
4204 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 pSMB->MaxSetupCount = 0;
4206 pSMB->Reserved = 0;
4207 pSMB->Flags = 0;
4208 pSMB->Timeout = 0;
4209 pSMB->Reserved2 = 0;
4210 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004211 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 pSMB->DataCount = 0;
4213 pSMB->DataOffset = 0;
4214 pSMB->SetupCount = 1;
4215 pSMB->Reserved3 = 0;
4216 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4217 byte_count = params + 1 /* pad */ ;
4218 pSMB->TotalParameterCount = cpu_to_le16(params);
4219 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004220 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004221 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4222 else
4223 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004225 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 pSMB->ByteCount = cpu_to_le16(byte_count);
4227
4228 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4229 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4230 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004231 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 } else { /* decode response */
4233 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4234
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004235 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4236 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004237 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004239 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004240 rc = -EIO; /* 24 or 26 expected but we do not read
4241 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004242 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004243 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004245
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004246 /*
4247 * On legacy responses we do not read the last field,
4248 * EAsize, fortunately since it varies by subdialect and
4249 * also note it differs on Set vs Get, ie two bytes or 4
4250 * bytes depending but we don't care here.
4251 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004252 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004253 size = sizeof(FILE_INFO_STANDARD);
4254 else
4255 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004256 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004257 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 } else
4259 rc = -ENOMEM;
4260 }
4261 cifs_buf_release(pSMB);
4262 if (rc == -EAGAIN)
4263 goto QPathInfoRetry;
4264
4265 return rc;
4266}
4267
4268int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004269CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004270 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4271{
4272 struct smb_t2_qfi_req *pSMB = NULL;
4273 struct smb_t2_qfi_rsp *pSMBr = NULL;
4274 int rc = 0;
4275 int bytes_returned;
4276 __u16 params, byte_count;
4277
4278UnixQFileInfoRetry:
4279 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4280 (void **) &pSMBr);
4281 if (rc)
4282 return rc;
4283
4284 params = 2 /* level */ + 2 /* fid */;
4285 pSMB->t2.TotalDataCount = 0;
4286 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4287 /* BB find exact max data count below from sess structure BB */
4288 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4289 pSMB->t2.MaxSetupCount = 0;
4290 pSMB->t2.Reserved = 0;
4291 pSMB->t2.Flags = 0;
4292 pSMB->t2.Timeout = 0;
4293 pSMB->t2.Reserved2 = 0;
4294 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4295 Fid) - 4);
4296 pSMB->t2.DataCount = 0;
4297 pSMB->t2.DataOffset = 0;
4298 pSMB->t2.SetupCount = 1;
4299 pSMB->t2.Reserved3 = 0;
4300 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4301 byte_count = params + 1 /* pad */ ;
4302 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4303 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4304 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4305 pSMB->Pad = 0;
4306 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004307 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004308 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004309
4310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4312 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004313 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004314 } else { /* decode response */
4315 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4316
Jeff Layton820a8032011-05-04 08:05:26 -04004317 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004318 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 -05004319 rc = -EIO; /* bad smb */
4320 } else {
4321 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4322 memcpy((char *) pFindData,
4323 (char *) &pSMBr->hdr.Protocol +
4324 data_offset,
4325 sizeof(FILE_UNIX_BASIC_INFO));
4326 }
4327 }
4328
4329 cifs_buf_release(pSMB);
4330 if (rc == -EAGAIN)
4331 goto UnixQFileInfoRetry;
4332
4333 return rc;
4334}
4335
4336int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004337CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004339 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004340 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341{
4342/* SMB_QUERY_FILE_UNIX_BASIC */
4343 TRANSACTION2_QPI_REQ *pSMB = NULL;
4344 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4345 int rc = 0;
4346 int bytes_returned = 0;
4347 int name_len;
4348 __u16 params, byte_count;
4349
Joe Perchesf96637b2013-05-04 22:12:25 -05004350 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351UnixQPathInfoRetry:
4352 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4353 (void **) &pSMBr);
4354 if (rc)
4355 return rc;
4356
4357 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4358 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004359 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4360 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 name_len++; /* trailing null */
4362 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004363 } else {
4364 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 }
4366
Steve French50c2f752007-07-13 00:33:32 +00004367 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 pSMB->TotalDataCount = 0;
4369 pSMB->MaxParameterCount = cpu_to_le16(2);
4370 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004371 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 pSMB->MaxSetupCount = 0;
4373 pSMB->Reserved = 0;
4374 pSMB->Flags = 0;
4375 pSMB->Timeout = 0;
4376 pSMB->Reserved2 = 0;
4377 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004378 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 pSMB->DataCount = 0;
4380 pSMB->DataOffset = 0;
4381 pSMB->SetupCount = 1;
4382 pSMB->Reserved3 = 0;
4383 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4384 byte_count = params + 1 /* pad */ ;
4385 pSMB->TotalParameterCount = cpu_to_le16(params);
4386 pSMB->ParameterCount = pSMB->TotalParameterCount;
4387 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4388 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004389 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 pSMB->ByteCount = cpu_to_le16(byte_count);
4391
4392 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4393 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4394 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004395 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 } else { /* decode response */
4397 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4398
Jeff Layton820a8032011-05-04 08:05:26 -04004399 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004400 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 -07004401 rc = -EIO; /* bad smb */
4402 } else {
4403 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4404 memcpy((char *) pFindData,
4405 (char *) &pSMBr->hdr.Protocol +
4406 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004407 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 }
4409 }
4410 cifs_buf_release(pSMB);
4411 if (rc == -EAGAIN)
4412 goto UnixQPathInfoRetry;
4413
4414 return rc;
4415}
4416
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417/* xid, tcon, searchName and codepage are input parms, rest are returned */
4418int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004419CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004420 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004421 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004422 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423{
4424/* level 257 SMB_ */
4425 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4426 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004427 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 int rc = 0;
4429 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004430 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004432 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
Joe Perchesf96637b2013-05-04 22:12:25 -05004434 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
4436findFirstRetry:
4437 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4438 (void **) &pSMBr);
4439 if (rc)
4440 return rc;
4441
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004442 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004443 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004444
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4446 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004447 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4448 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004449 /* We can not add the asterik earlier in case
4450 it got remapped to 0xF03A as if it were part of the
4451 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004453 if (msearch) {
4454 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4455 pSMB->FileName[name_len+1] = 0;
4456 pSMB->FileName[name_len+2] = '*';
4457 pSMB->FileName[name_len+3] = 0;
4458 name_len += 4; /* now the trailing null */
4459 /* null terminate just in case */
4460 pSMB->FileName[name_len] = 0;
4461 pSMB->FileName[name_len+1] = 0;
4462 name_len += 2;
4463 }
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004464 } else {
4465 name_len = copy_path_name(pSMB->FileName, searchName);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004466 if (msearch) {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004467 if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4468 name_len = PATH_MAX-2;
4469 /* overwrite nul byte */
4470 pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4471 pSMB->FileName[name_len] = '*';
4472 pSMB->FileName[name_len+1] = 0;
4473 name_len += 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 }
4476
4477 params = 12 + name_len /* includes null */ ;
4478 pSMB->TotalDataCount = 0; /* no EAs */
4479 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004480 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 pSMB->MaxSetupCount = 0;
4482 pSMB->Reserved = 0;
4483 pSMB->Flags = 0;
4484 pSMB->Timeout = 0;
4485 pSMB->Reserved2 = 0;
4486 byte_count = params + 1 /* pad */ ;
4487 pSMB->TotalParameterCount = cpu_to_le16(params);
4488 pSMB->ParameterCount = pSMB->TotalParameterCount;
4489 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004490 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4491 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 pSMB->DataCount = 0;
4493 pSMB->DataOffset = 0;
4494 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4495 pSMB->Reserved3 = 0;
4496 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4497 pSMB->SearchAttributes =
4498 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4499 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004500 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004501 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4503
4504 /* BB what should we set StorageType to? Does it matter? BB */
4505 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004506 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 pSMB->ByteCount = cpu_to_le16(byte_count);
4508
4509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004511 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512
Steve French88274812006-03-09 22:21:45 +00004513 if (rc) {/* BB add logic to retry regular search if Unix search
4514 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004516 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004517
Steve French88274812006-03-09 22:21:45 +00004518 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519
4520 /* BB eventually could optimize out free and realloc of buf */
4521 /* for this case */
4522 if (rc == -EAGAIN)
4523 goto findFirstRetry;
4524 } else { /* decode response */
4525 /* BB remember to free buffer if error BB */
4526 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004527 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004528 unsigned int lnoff;
4529
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004531 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 else
Steve French4b18f2a2008-04-29 00:06:05 +00004533 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534
4535 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
zhengbin01d1bd72019-12-25 11:30:21 +08004536 psrch_inf->smallBuf = false;
Steve French50c2f752007-07-13 00:33:32 +00004537 psrch_inf->srch_entries_start =
4538 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4541 le16_to_cpu(pSMBr->t2.ParameterOffset));
4542
Steve French790fe572007-07-07 19:25:05 +00004543 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004544 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 else
Steve French4b18f2a2008-04-29 00:06:05 +00004546 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547
Steve French50c2f752007-07-13 00:33:32 +00004548 psrch_inf->entries_in_buffer =
4549 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004550 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004552 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004553 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004554 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004555 psrch_inf->last_entry = NULL;
4556 return rc;
4557 }
4558
Steve French0752f152008-10-07 20:03:33 +00004559 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004560 lnoff;
4561
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004562 if (pnetfid)
4563 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 } else {
4565 cifs_buf_release(pSMB);
4566 }
4567 }
4568
4569 return rc;
4570}
4571
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004572int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4573 __u16 searchHandle, __u16 search_flags,
4574 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575{
4576 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4577 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004578 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 char *response_data;
4580 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004581 int bytes_returned;
4582 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 __u16 params, byte_count;
4584
Joe Perchesf96637b2013-05-04 22:12:25 -05004585 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586
Steve French4b18f2a2008-04-29 00:06:05 +00004587 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 return -ENOENT;
4589
4590 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4591 (void **) &pSMBr);
4592 if (rc)
4593 return rc;
4594
Steve French50c2f752007-07-13 00:33:32 +00004595 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 byte_count = 0;
4597 pSMB->TotalDataCount = 0; /* no EAs */
4598 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004599 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 pSMB->MaxSetupCount = 0;
4601 pSMB->Reserved = 0;
4602 pSMB->Flags = 0;
4603 pSMB->Timeout = 0;
4604 pSMB->Reserved2 = 0;
4605 pSMB->ParameterOffset = cpu_to_le16(
4606 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4607 pSMB->DataCount = 0;
4608 pSMB->DataOffset = 0;
4609 pSMB->SetupCount = 1;
4610 pSMB->Reserved3 = 0;
4611 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4612 pSMB->SearchHandle = searchHandle; /* always kept as le */
4613 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004614 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4616 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004617 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618
4619 name_len = psrch_inf->resume_name_len;
4620 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004621 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4623 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004624 /* 14 byte parm len above enough for 2 byte null terminator */
4625 pSMB->ResumeFileName[name_len] = 0;
4626 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 } else {
4628 rc = -EINVAL;
4629 goto FNext2_err_exit;
4630 }
4631 byte_count = params + 1 /* pad */ ;
4632 pSMB->TotalParameterCount = cpu_to_le16(params);
4633 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004634 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004636
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4638 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004639 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 if (rc) {
4641 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004642 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004643 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004644 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004646 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 } else { /* decode response */
4648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004649
Steve French790fe572007-07-07 19:25:05 +00004650 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004651 unsigned int lnoff;
4652
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 /* BB fixme add lock for file (srch_info) struct here */
4654 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004655 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 else
Steve French4b18f2a2008-04-29 00:06:05 +00004657 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 response_data = (char *) &pSMBr->hdr.Protocol +
4659 le16_to_cpu(pSMBr->t2.ParameterOffset);
4660 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4661 response_data = (char *)&pSMBr->hdr.Protocol +
4662 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004663 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004664 cifs_small_buf_release(
4665 psrch_inf->ntwrk_buf_start);
4666 else
4667 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 psrch_inf->srch_entries_start = response_data;
4669 psrch_inf->ntwrk_buf_start = (char *)pSMB;
zhengbin01d1bd72019-12-25 11:30:21 +08004670 psrch_inf->smallBuf = false;
Steve French790fe572007-07-07 19:25:05 +00004671 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004672 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 else
Steve French4b18f2a2008-04-29 00:06:05 +00004674 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004675 psrch_inf->entries_in_buffer =
4676 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 psrch_inf->index_of_last_entry +=
4678 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004679 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004680 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004681 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004682 psrch_inf->last_entry = NULL;
4683 return rc;
4684 } else
4685 psrch_inf->last_entry =
4686 psrch_inf->srch_entries_start + lnoff;
4687
Joe Perchesf96637b2013-05-04 22:12:25 -05004688/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4689 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
4691 /* BB fixme add unlock here */
4692 }
4693
4694 }
4695
4696 /* BB On error, should we leave previous search buf (and count and
4697 last entry fields) intact or free the previous one? */
4698
4699 /* Note: On -EAGAIN error only caller can retry on handle based calls
4700 since file handle passed in no longer valid */
4701FNext2_err_exit:
4702 if (rc != 0)
4703 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 return rc;
4705}
4706
4707int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004708CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004709 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710{
4711 int rc = 0;
4712 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713
Joe Perchesf96637b2013-05-04 22:12:25 -05004714 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4716
4717 /* no sense returning error if session restarted
4718 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004719 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 return 0;
4721 if (rc)
4722 return rc;
4723
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 pSMB->FileID = searchHandle;
4725 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004726 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004727 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004728 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004729 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004730
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004731 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732
4733 /* Since session is dead, search handle closed on server already */
4734 if (rc == -EAGAIN)
4735 rc = 0;
4736
4737 return rc;
4738}
4739
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004741CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004742 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004743 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744{
4745 int rc = 0;
4746 TRANSACTION2_QPI_REQ *pSMB = NULL;
4747 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4748 int name_len, bytes_returned;
4749 __u16 params, byte_count;
4750
Joe Perchesf96637b2013-05-04 22:12:25 -05004751 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004752 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004753 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754
4755GetInodeNumberRetry:
4756 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004757 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 if (rc)
4759 return rc;
4760
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4762 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004763 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004764 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004765 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 name_len++; /* trailing null */
4767 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004768 } else {
4769 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 }
4771
4772 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4773 pSMB->TotalDataCount = 0;
4774 pSMB->MaxParameterCount = cpu_to_le16(2);
4775 /* BB find exact max data count below from sess structure BB */
4776 pSMB->MaxDataCount = cpu_to_le16(4000);
4777 pSMB->MaxSetupCount = 0;
4778 pSMB->Reserved = 0;
4779 pSMB->Flags = 0;
4780 pSMB->Timeout = 0;
4781 pSMB->Reserved2 = 0;
4782 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004783 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 pSMB->DataCount = 0;
4785 pSMB->DataOffset = 0;
4786 pSMB->SetupCount = 1;
4787 pSMB->Reserved3 = 0;
4788 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4789 byte_count = params + 1 /* pad */ ;
4790 pSMB->TotalParameterCount = cpu_to_le16(params);
4791 pSMB->ParameterCount = pSMB->TotalParameterCount;
4792 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4793 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004794 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 pSMB->ByteCount = cpu_to_le16(byte_count);
4796
4797 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4798 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4799 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004800 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 } else {
4802 /* decode response */
4803 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004805 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 /* If rc should we check for EOPNOSUPP and
4807 disable the srvino flag? or in caller? */
4808 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004809 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4811 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004812 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004814 if (count < 8) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004815 cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 rc = -EIO;
4817 goto GetInodeNumOut;
4818 }
4819 pfinfo = (struct file_internal_info *)
4820 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004821 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 }
4823 }
4824GetInodeNumOut:
4825 cifs_buf_release(pSMB);
4826 if (rc == -EAGAIN)
4827 goto GetInodeNumberRetry;
4828 return rc;
4829}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830
4831int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004832CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004833 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004834 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004835 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836{
4837/* TRANS2_GET_DFS_REFERRAL */
4838 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4839 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 int rc = 0;
4841 int bytes_returned;
4842 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004844 *num_of_nodes = 0;
4845 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846
Joe Perchesf96637b2013-05-04 22:12:25 -05004847 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004848 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004850
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004852 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 (void **) &pSMBr);
4854 if (rc)
4855 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004856
4857 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004858 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004859 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004860 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004862 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004864 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866
4867 if (ses->capabilities & CAP_UNICODE) {
4868 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4869 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004870 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004871 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004872 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 name_len++; /* trailing null */
4874 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004875 } else { /* BB improve the check for buffer overruns BB */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004876 name_len = copy_path_name(pSMB->RequestFileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 }
4878
Dan Carpenter65c3b202015-04-30 17:30:24 +03004879 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004880 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004881
Steve French50c2f752007-07-13 00:33:32 +00004882 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004883
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 params = 2 /* level */ + name_len /*includes null */ ;
4885 pSMB->TotalDataCount = 0;
4886 pSMB->DataCount = 0;
4887 pSMB->DataOffset = 0;
4888 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004889 /* BB find exact max SMB PDU from sess structure BB */
4890 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 pSMB->MaxSetupCount = 0;
4892 pSMB->Reserved = 0;
4893 pSMB->Flags = 0;
4894 pSMB->Timeout = 0;
4895 pSMB->Reserved2 = 0;
4896 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004897 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 pSMB->SetupCount = 1;
4899 pSMB->Reserved3 = 0;
4900 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4901 byte_count = params + 3 /* pad */ ;
4902 pSMB->ParameterCount = cpu_to_le16(params);
4903 pSMB->TotalParameterCount = pSMB->ParameterCount;
4904 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004905 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 pSMB->ByteCount = cpu_to_le16(byte_count);
4907
4908 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4910 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004911 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004912 goto GetDFSRefExit;
4913 }
4914 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004916 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004917 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004918 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004919 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004921
Joe Perchesf96637b2013-05-04 22:12:25 -05004922 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4923 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004924
4925 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004926 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4927 le16_to_cpu(pSMBr->t2.DataCount),
4928 num_of_nodes, target_nodes, nls_codepage,
4929 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004930 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004931
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004933 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934
4935 if (rc == -EAGAIN)
4936 goto getDFSRetry;
4937
4938 return rc;
4939}
4940
Steve French20962432005-09-21 22:05:57 -07004941/* Query File System Info such as free space to old servers such as Win 9x */
4942int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004943SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4944 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004945{
4946/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4947 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4948 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4949 FILE_SYSTEM_ALLOC_INFO *response_data;
4950 int rc = 0;
4951 int bytes_returned = 0;
4952 __u16 params, byte_count;
4953
Joe Perchesf96637b2013-05-04 22:12:25 -05004954 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004955oldQFSInfoRetry:
4956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4957 (void **) &pSMBr);
4958 if (rc)
4959 return rc;
Steve French20962432005-09-21 22:05:57 -07004960
4961 params = 2; /* level */
4962 pSMB->TotalDataCount = 0;
4963 pSMB->MaxParameterCount = cpu_to_le16(2);
4964 pSMB->MaxDataCount = cpu_to_le16(1000);
4965 pSMB->MaxSetupCount = 0;
4966 pSMB->Reserved = 0;
4967 pSMB->Flags = 0;
4968 pSMB->Timeout = 0;
4969 pSMB->Reserved2 = 0;
4970 byte_count = params + 1 /* pad */ ;
4971 pSMB->TotalParameterCount = cpu_to_le16(params);
4972 pSMB->ParameterCount = pSMB->TotalParameterCount;
4973 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4974 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4975 pSMB->DataCount = 0;
4976 pSMB->DataOffset = 0;
4977 pSMB->SetupCount = 1;
4978 pSMB->Reserved3 = 0;
4979 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4980 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004981 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004982 pSMB->ByteCount = cpu_to_le16(byte_count);
4983
4984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4986 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004987 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004988 } else { /* decode response */
4989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4990
Jeff Layton820a8032011-05-04 08:05:26 -04004991 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004992 rc = -EIO; /* bad smb */
4993 else {
4994 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004995 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004996 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004997
Steve French50c2f752007-07-13 00:33:32 +00004998 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004999 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5000 FSData->f_bsize =
5001 le16_to_cpu(response_data->BytesPerSector) *
5002 le32_to_cpu(response_data->
5003 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005004 /*
5005 * much prefer larger but if server doesn't report
5006 * a valid size than 4K is a reasonable minimum
5007 */
5008 if (FSData->f_bsize < 512)
5009 FSData->f_bsize = 4096;
5010
Steve French20962432005-09-21 22:05:57 -07005011 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005012 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005013 FSData->f_bfree = FSData->f_bavail =
5014 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005015 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5016 (unsigned long long)FSData->f_blocks,
5017 (unsigned long long)FSData->f_bfree,
5018 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005019 }
5020 }
5021 cifs_buf_release(pSMB);
5022
5023 if (rc == -EAGAIN)
5024 goto oldQFSInfoRetry;
5025
5026 return rc;
5027}
5028
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005030CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5031 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032{
5033/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5034 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5035 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5036 FILE_SYSTEM_INFO *response_data;
5037 int rc = 0;
5038 int bytes_returned = 0;
5039 __u16 params, byte_count;
5040
Joe Perchesf96637b2013-05-04 22:12:25 -05005041 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042QFSInfoRetry:
5043 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5044 (void **) &pSMBr);
5045 if (rc)
5046 return rc;
5047
5048 params = 2; /* level */
5049 pSMB->TotalDataCount = 0;
5050 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005051 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 pSMB->MaxSetupCount = 0;
5053 pSMB->Reserved = 0;
5054 pSMB->Flags = 0;
5055 pSMB->Timeout = 0;
5056 pSMB->Reserved2 = 0;
5057 byte_count = params + 1 /* pad */ ;
5058 pSMB->TotalParameterCount = cpu_to_le16(params);
5059 pSMB->ParameterCount = pSMB->TotalParameterCount;
5060 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005061 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 pSMB->DataCount = 0;
5063 pSMB->DataOffset = 0;
5064 pSMB->SetupCount = 1;
5065 pSMB->Reserved3 = 0;
5066 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5067 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005068 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 pSMB->ByteCount = cpu_to_le16(byte_count);
5070
5071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5073 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005074 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077
Jeff Layton820a8032011-05-04 08:05:26 -04005078 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 rc = -EIO; /* bad smb */
5080 else {
5081 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082
5083 response_data =
5084 (FILE_SYSTEM_INFO
5085 *) (((char *) &pSMBr->hdr.Protocol) +
5086 data_offset);
5087 FSData->f_bsize =
5088 le32_to_cpu(response_data->BytesPerSector) *
5089 le32_to_cpu(response_data->
5090 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005091 /*
5092 * much prefer larger but if server doesn't report
5093 * a valid size than 4K is a reasonable minimum
5094 */
5095 if (FSData->f_bsize < 512)
5096 FSData->f_bsize = 4096;
5097
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 FSData->f_blocks =
5099 le64_to_cpu(response_data->TotalAllocationUnits);
5100 FSData->f_bfree = FSData->f_bavail =
5101 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005102 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5103 (unsigned long long)FSData->f_blocks,
5104 (unsigned long long)FSData->f_bfree,
5105 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 }
5107 }
5108 cifs_buf_release(pSMB);
5109
5110 if (rc == -EAGAIN)
5111 goto QFSInfoRetry;
5112
5113 return rc;
5114}
5115
5116int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005117CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118{
5119/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5120 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5121 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5122 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5123 int rc = 0;
5124 int bytes_returned = 0;
5125 __u16 params, byte_count;
5126
Joe Perchesf96637b2013-05-04 22:12:25 -05005127 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128QFSAttributeRetry:
5129 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5130 (void **) &pSMBr);
5131 if (rc)
5132 return rc;
5133
5134 params = 2; /* level */
5135 pSMB->TotalDataCount = 0;
5136 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005137 /* BB find exact max SMB PDU from sess structure BB */
5138 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 pSMB->MaxSetupCount = 0;
5140 pSMB->Reserved = 0;
5141 pSMB->Flags = 0;
5142 pSMB->Timeout = 0;
5143 pSMB->Reserved2 = 0;
5144 byte_count = params + 1 /* pad */ ;
5145 pSMB->TotalParameterCount = cpu_to_le16(params);
5146 pSMB->ParameterCount = pSMB->TotalParameterCount;
5147 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005148 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 pSMB->DataCount = 0;
5150 pSMB->DataOffset = 0;
5151 pSMB->SetupCount = 1;
5152 pSMB->Reserved3 = 0;
5153 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5154 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005155 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 pSMB->ByteCount = cpu_to_le16(byte_count);
5157
5158 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5159 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5160 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005161 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 } else { /* decode response */
5163 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5164
Jeff Layton820a8032011-05-04 08:05:26 -04005165 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005166 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 rc = -EIO; /* bad smb */
5168 } else {
5169 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5170 response_data =
5171 (FILE_SYSTEM_ATTRIBUTE_INFO
5172 *) (((char *) &pSMBr->hdr.Protocol) +
5173 data_offset);
5174 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005175 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 }
5177 }
5178 cifs_buf_release(pSMB);
5179
5180 if (rc == -EAGAIN)
5181 goto QFSAttributeRetry;
5182
5183 return rc;
5184}
5185
5186int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005187CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188{
5189/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5190 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5191 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5192 FILE_SYSTEM_DEVICE_INFO *response_data;
5193 int rc = 0;
5194 int bytes_returned = 0;
5195 __u16 params, byte_count;
5196
Joe Perchesf96637b2013-05-04 22:12:25 -05005197 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198QFSDeviceRetry:
5199 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5200 (void **) &pSMBr);
5201 if (rc)
5202 return rc;
5203
5204 params = 2; /* level */
5205 pSMB->TotalDataCount = 0;
5206 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005207 /* BB find exact max SMB PDU from sess structure BB */
5208 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 pSMB->MaxSetupCount = 0;
5210 pSMB->Reserved = 0;
5211 pSMB->Flags = 0;
5212 pSMB->Timeout = 0;
5213 pSMB->Reserved2 = 0;
5214 byte_count = params + 1 /* pad */ ;
5215 pSMB->TotalParameterCount = cpu_to_le16(params);
5216 pSMB->ParameterCount = pSMB->TotalParameterCount;
5217 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005218 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219
5220 pSMB->DataCount = 0;
5221 pSMB->DataOffset = 0;
5222 pSMB->SetupCount = 1;
5223 pSMB->Reserved3 = 0;
5224 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5225 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005226 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 pSMB->ByteCount = cpu_to_le16(byte_count);
5228
5229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5231 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005232 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 } else { /* decode response */
5234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5235
Jeff Layton820a8032011-05-04 08:05:26 -04005236 if (rc || get_bcc(&pSMBr->hdr) <
5237 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 rc = -EIO; /* bad smb */
5239 else {
5240 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5241 response_data =
Steve French737b7582005-04-28 22:41:06 -07005242 (FILE_SYSTEM_DEVICE_INFO *)
5243 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 data_offset);
5245 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005246 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 }
5248 }
5249 cifs_buf_release(pSMB);
5250
5251 if (rc == -EAGAIN)
5252 goto QFSDeviceRetry;
5253
5254 return rc;
5255}
5256
5257int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005258CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259{
5260/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5261 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5262 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5263 FILE_SYSTEM_UNIX_INFO *response_data;
5264 int rc = 0;
5265 int bytes_returned = 0;
5266 __u16 params, byte_count;
5267
Joe Perchesf96637b2013-05-04 22:12:25 -05005268 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005270 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5271 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 if (rc)
5273 return rc;
5274
5275 params = 2; /* level */
5276 pSMB->TotalDataCount = 0;
5277 pSMB->DataCount = 0;
5278 pSMB->DataOffset = 0;
5279 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005280 /* BB find exact max SMB PDU from sess structure BB */
5281 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 pSMB->MaxSetupCount = 0;
5283 pSMB->Reserved = 0;
5284 pSMB->Flags = 0;
5285 pSMB->Timeout = 0;
5286 pSMB->Reserved2 = 0;
5287 byte_count = params + 1 /* pad */ ;
5288 pSMB->ParameterCount = cpu_to_le16(params);
5289 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005290 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5291 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 pSMB->SetupCount = 1;
5293 pSMB->Reserved3 = 0;
5294 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5295 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005296 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 pSMB->ByteCount = cpu_to_le16(byte_count);
5298
5299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5301 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005302 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 } else { /* decode response */
5304 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5305
Jeff Layton820a8032011-05-04 08:05:26 -04005306 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 rc = -EIO; /* bad smb */
5308 } else {
5309 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5310 response_data =
5311 (FILE_SYSTEM_UNIX_INFO
5312 *) (((char *) &pSMBr->hdr.Protocol) +
5313 data_offset);
5314 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005315 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 }
5317 }
5318 cifs_buf_release(pSMB);
5319
5320 if (rc == -EAGAIN)
5321 goto QFSUnixRetry;
5322
5323
5324 return rc;
5325}
5326
Jeremy Allisonac670552005-06-22 17:26:35 -07005327int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005328CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005329{
5330/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5331 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5332 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5333 int rc = 0;
5334 int bytes_returned = 0;
5335 __u16 params, param_offset, offset, byte_count;
5336
Joe Perchesf96637b2013-05-04 22:12:25 -05005337 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005338SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005339 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005340 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5341 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005342 if (rc)
5343 return rc;
5344
5345 params = 4; /* 2 bytes zero followed by info level. */
5346 pSMB->MaxSetupCount = 0;
5347 pSMB->Reserved = 0;
5348 pSMB->Flags = 0;
5349 pSMB->Timeout = 0;
5350 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005351 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5352 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005353 offset = param_offset + params;
5354
5355 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005356 /* BB find exact max SMB PDU from sess structure BB */
5357 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005358 pSMB->SetupCount = 1;
5359 pSMB->Reserved3 = 0;
5360 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5361 byte_count = 1 /* pad */ + params + 12;
5362
5363 pSMB->DataCount = cpu_to_le16(12);
5364 pSMB->ParameterCount = cpu_to_le16(params);
5365 pSMB->TotalDataCount = pSMB->DataCount;
5366 pSMB->TotalParameterCount = pSMB->ParameterCount;
5367 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5368 pSMB->DataOffset = cpu_to_le16(offset);
5369
5370 /* Params. */
5371 pSMB->FileNum = 0;
5372 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5373
5374 /* Data. */
5375 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5376 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5377 pSMB->ClientUnixCap = cpu_to_le64(cap);
5378
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005379 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005380 pSMB->ByteCount = cpu_to_le16(byte_count);
5381
5382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5383 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5384 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005385 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005386 } else { /* decode response */
5387 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005388 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005389 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005390 }
5391 cifs_buf_release(pSMB);
5392
5393 if (rc == -EAGAIN)
5394 goto SETFSUnixRetry;
5395
5396 return rc;
5397}
5398
5399
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400
5401int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005402CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005403 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404{
5405/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5406 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5407 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5408 FILE_SYSTEM_POSIX_INFO *response_data;
5409 int rc = 0;
5410 int bytes_returned = 0;
5411 __u16 params, byte_count;
5412
Joe Perchesf96637b2013-05-04 22:12:25 -05005413 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414QFSPosixRetry:
5415 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5416 (void **) &pSMBr);
5417 if (rc)
5418 return rc;
5419
5420 params = 2; /* level */
5421 pSMB->TotalDataCount = 0;
5422 pSMB->DataCount = 0;
5423 pSMB->DataOffset = 0;
5424 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005425 /* BB find exact max SMB PDU from sess structure BB */
5426 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 pSMB->MaxSetupCount = 0;
5428 pSMB->Reserved = 0;
5429 pSMB->Flags = 0;
5430 pSMB->Timeout = 0;
5431 pSMB->Reserved2 = 0;
5432 byte_count = params + 1 /* pad */ ;
5433 pSMB->ParameterCount = cpu_to_le16(params);
5434 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005435 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5436 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 pSMB->SetupCount = 1;
5438 pSMB->Reserved3 = 0;
5439 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5440 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005441 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 pSMB->ByteCount = cpu_to_le16(byte_count);
5443
5444 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5445 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5446 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005447 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 } else { /* decode response */
5449 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5450
Jeff Layton820a8032011-05-04 08:05:26 -04005451 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 rc = -EIO; /* bad smb */
5453 } else {
5454 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5455 response_data =
5456 (FILE_SYSTEM_POSIX_INFO
5457 *) (((char *) &pSMBr->hdr.Protocol) +
5458 data_offset);
5459 FSData->f_bsize =
5460 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005461 /*
5462 * much prefer larger but if server doesn't report
5463 * a valid size than 4K is a reasonable minimum
5464 */
5465 if (FSData->f_bsize < 512)
5466 FSData->f_bsize = 4096;
5467
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 FSData->f_blocks =
5469 le64_to_cpu(response_data->TotalBlocks);
5470 FSData->f_bfree =
5471 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005472 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 FSData->f_bavail = FSData->f_bfree;
5474 } else {
5475 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005476 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 }
Steve French790fe572007-07-07 19:25:05 +00005478 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005480 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005481 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005483 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 }
5485 }
5486 cifs_buf_release(pSMB);
5487
5488 if (rc == -EAGAIN)
5489 goto QFSPosixRetry;
5490
5491 return rc;
5492}
5493
5494
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005495/*
5496 * We can not use write of zero bytes trick to set file size due to need for
5497 * large file support. Also note that this SetPathInfo is preferred to
5498 * SetFileInfo based method in next routine which is only needed to work around
5499 * a sharing violation bugin Samba which this routine can run into.
5500 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005502CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005503 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5504 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505{
5506 struct smb_com_transaction2_spi_req *pSMB = NULL;
5507 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5508 struct file_end_of_file_info *parm_data;
5509 int name_len;
5510 int rc = 0;
5511 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005512 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005513
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 __u16 params, byte_count, data_count, param_offset, offset;
5515
Joe Perchesf96637b2013-05-04 22:12:25 -05005516 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517SetEOFRetry:
5518 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5519 (void **) &pSMBr);
5520 if (rc)
5521 return rc;
5522
5523 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5524 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005525 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5526 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 name_len++; /* trailing null */
5528 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005529 } else {
5530 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 }
5532 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005533 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005535 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 pSMB->MaxSetupCount = 0;
5537 pSMB->Reserved = 0;
5538 pSMB->Flags = 0;
5539 pSMB->Timeout = 0;
5540 pSMB->Reserved2 = 0;
5541 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005542 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005544 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005545 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5546 pSMB->InformationLevel =
5547 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5548 else
5549 pSMB->InformationLevel =
5550 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5551 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5553 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005554 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 else
5556 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005557 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 }
5559
5560 parm_data =
5561 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5562 offset);
5563 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5564 pSMB->DataOffset = cpu_to_le16(offset);
5565 pSMB->SetupCount = 1;
5566 pSMB->Reserved3 = 0;
5567 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5568 byte_count = 3 /* pad */ + params + data_count;
5569 pSMB->DataCount = cpu_to_le16(data_count);
5570 pSMB->TotalDataCount = pSMB->DataCount;
5571 pSMB->ParameterCount = cpu_to_le16(params);
5572 pSMB->TotalParameterCount = pSMB->ParameterCount;
5573 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005574 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 parm_data->FileSize = cpu_to_le64(size);
5576 pSMB->ByteCount = cpu_to_le16(byte_count);
5577 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5578 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005579 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005580 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581
5582 cifs_buf_release(pSMB);
5583
5584 if (rc == -EAGAIN)
5585 goto SetEOFRetry;
5586
5587 return rc;
5588}
5589
5590int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005591CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5592 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593{
5594 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 struct file_end_of_file_info *parm_data;
5596 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 __u16 params, param_offset, offset, byte_count, count;
5598
Joe Perchesf96637b2013-05-04 22:12:25 -05005599 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5600 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005601 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5602
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 if (rc)
5604 return rc;
5605
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005606 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5607 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005608
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 params = 6;
5610 pSMB->MaxSetupCount = 0;
5611 pSMB->Reserved = 0;
5612 pSMB->Flags = 0;
5613 pSMB->Timeout = 0;
5614 pSMB->Reserved2 = 0;
5615 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5616 offset = param_offset + params;
5617
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 count = sizeof(struct file_end_of_file_info);
5619 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005620 /* BB find exact max SMB PDU from sess structure BB */
5621 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 pSMB->SetupCount = 1;
5623 pSMB->Reserved3 = 0;
5624 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5625 byte_count = 3 /* pad */ + params + count;
5626 pSMB->DataCount = cpu_to_le16(count);
5627 pSMB->ParameterCount = cpu_to_le16(params);
5628 pSMB->TotalDataCount = pSMB->DataCount;
5629 pSMB->TotalParameterCount = pSMB->ParameterCount;
5630 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5631 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005632 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5633 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 pSMB->DataOffset = cpu_to_le16(offset);
5635 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005636 pSMB->Fid = cfile->fid.netfid;
5637 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5639 pSMB->InformationLevel =
5640 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5641 else
5642 pSMB->InformationLevel =
5643 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005644 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5646 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005647 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 else
5649 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005650 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 }
5652 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005653 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005655 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005656 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005658 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5659 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 }
5661
Steve French50c2f752007-07-13 00:33:32 +00005662 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 since file handle passed in no longer valid */
5664
5665 return rc;
5666}
5667
Steve French50c2f752007-07-13 00:33:32 +00005668/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 an open handle, rather than by pathname - this is awkward due to
5670 potential access conflicts on the open, but it is unavoidable for these
5671 old servers since the only other choice is to go from 100 nanosecond DCE
5672 time and resort to the original setpathinfo level which takes the ancient
5673 DOS time format with 2 second granularity */
5674int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005675CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005676 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677{
5678 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679 char *data_offset;
5680 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 __u16 params, param_offset, offset, byte_count, count;
5682
Joe Perchesf96637b2013-05-04 22:12:25 -05005683 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005684 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5685
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 if (rc)
5687 return rc;
5688
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005689 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5690 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005691
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 params = 6;
5693 pSMB->MaxSetupCount = 0;
5694 pSMB->Reserved = 0;
5695 pSMB->Flags = 0;
5696 pSMB->Timeout = 0;
5697 pSMB->Reserved2 = 0;
5698 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5699 offset = param_offset + params;
5700
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005701 data_offset = (char *)pSMB +
5702 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703
Steve French26f57362007-08-30 22:09:15 +00005704 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005706 /* BB find max SMB PDU from sess */
5707 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708 pSMB->SetupCount = 1;
5709 pSMB->Reserved3 = 0;
5710 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5711 byte_count = 3 /* pad */ + params + count;
5712 pSMB->DataCount = cpu_to_le16(count);
5713 pSMB->ParameterCount = cpu_to_le16(params);
5714 pSMB->TotalDataCount = pSMB->DataCount;
5715 pSMB->TotalParameterCount = pSMB->ParameterCount;
5716 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5717 pSMB->DataOffset = cpu_to_le16(offset);
5718 pSMB->Fid = fid;
5719 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5720 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5721 else
5722 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5723 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005724 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005726 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005727 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005728 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005729 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005730 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5731 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732
Steve French50c2f752007-07-13 00:33:32 +00005733 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734 since file handle passed in no longer valid */
5735
5736 return rc;
5737}
5738
Jeff Layton6d22f092008-09-23 11:48:35 -04005739int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005740CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005741 bool delete_file, __u16 fid, __u32 pid_of_opener)
5742{
5743 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5744 char *data_offset;
5745 int rc = 0;
5746 __u16 params, param_offset, offset, byte_count, count;
5747
Joe Perchesf96637b2013-05-04 22:12:25 -05005748 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005749 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5750
5751 if (rc)
5752 return rc;
5753
5754 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5755 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5756
5757 params = 6;
5758 pSMB->MaxSetupCount = 0;
5759 pSMB->Reserved = 0;
5760 pSMB->Flags = 0;
5761 pSMB->Timeout = 0;
5762 pSMB->Reserved2 = 0;
5763 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5764 offset = param_offset + params;
5765
5766 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5767
5768 count = 1;
5769 pSMB->MaxParameterCount = cpu_to_le16(2);
5770 /* BB find max SMB PDU from sess */
5771 pSMB->MaxDataCount = cpu_to_le16(1000);
5772 pSMB->SetupCount = 1;
5773 pSMB->Reserved3 = 0;
5774 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5775 byte_count = 3 /* pad */ + params + count;
5776 pSMB->DataCount = cpu_to_le16(count);
5777 pSMB->ParameterCount = cpu_to_le16(params);
5778 pSMB->TotalDataCount = pSMB->DataCount;
5779 pSMB->TotalParameterCount = pSMB->ParameterCount;
5780 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5781 pSMB->DataOffset = cpu_to_le16(offset);
5782 pSMB->Fid = fid;
5783 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5784 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005785 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005786 pSMB->ByteCount = cpu_to_le16(byte_count);
5787 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005788 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005789 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005790 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005791 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005792
5793 return rc;
5794}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005796static int
5797CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
5798 const char *fileName, const FILE_BASIC_INFO *data,
5799 const struct nls_table *nls_codepage,
5800 struct cifs_sb_info *cifs_sb)
5801{
5802 int oplock = 0;
5803 struct cifs_open_parms oparms;
5804 struct cifs_fid fid;
5805 int rc;
5806
5807 oparms.tcon = tcon;
5808 oparms.cifs_sb = cifs_sb;
5809 oparms.desired_access = GENERIC_WRITE;
5810 oparms.create_options = cifs_create_options(cifs_sb, 0);
5811 oparms.disposition = FILE_OPEN;
5812 oparms.path = fileName;
5813 oparms.fid = &fid;
5814 oparms.reconnect = false;
5815
5816 rc = CIFS_open(xid, &oparms, &oplock, NULL);
5817 if (rc)
5818 goto out;
5819
5820 rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
5821 CIFSSMBClose(xid, tcon, fid.netfid);
5822out:
5823
5824 return rc;
5825}
5826
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005828CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005829 const char *fileName, const FILE_BASIC_INFO *data,
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005830 const struct nls_table *nls_codepage,
5831 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832{
5833 TRANSACTION2_SPI_REQ *pSMB = NULL;
5834 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5835 int name_len;
5836 int rc = 0;
5837 int bytes_returned = 0;
5838 char *data_offset;
5839 __u16 params, param_offset, offset, byte_count, count;
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005840 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841
Joe Perchesf96637b2013-05-04 22:12:25 -05005842 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843
5844SetTimesRetry:
5845 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5846 (void **) &pSMBr);
5847 if (rc)
5848 return rc;
5849
5850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5851 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005852 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5853 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 name_len++; /* trailing null */
5855 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005856 } else {
5857 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 }
5859
5860 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005861 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005863 /* BB find max SMB PDU from sess structure BB */
5864 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865 pSMB->MaxSetupCount = 0;
5866 pSMB->Reserved = 0;
5867 pSMB->Flags = 0;
5868 pSMB->Timeout = 0;
5869 pSMB->Reserved2 = 0;
5870 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005871 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 offset = param_offset + params;
5873 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5874 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5875 pSMB->DataOffset = cpu_to_le16(offset);
5876 pSMB->SetupCount = 1;
5877 pSMB->Reserved3 = 0;
5878 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5879 byte_count = 3 /* pad */ + params + count;
5880
5881 pSMB->DataCount = cpu_to_le16(count);
5882 pSMB->ParameterCount = cpu_to_le16(params);
5883 pSMB->TotalDataCount = pSMB->DataCount;
5884 pSMB->TotalParameterCount = pSMB->ParameterCount;
5885 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5886 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5887 else
5888 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5889 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005890 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005891 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 pSMB->ByteCount = cpu_to_le16(byte_count);
5893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005895 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005896 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897
5898 cifs_buf_release(pSMB);
5899
5900 if (rc == -EAGAIN)
5901 goto SetTimesRetry;
5902
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005903 if (rc == -EOPNOTSUPP)
5904 return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
5905 nls_codepage, cifs_sb);
5906
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 return rc;
5908}
5909
Jeff Layton654cf142009-07-09 20:02:49 -04005910static void
5911cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5912 const struct cifs_unix_set_info_args *args)
5913{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005914 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005915 u64 mode = args->mode;
5916
Eric W. Biederman49418b22013-02-06 00:57:56 -08005917 if (uid_valid(args->uid))
5918 uid = from_kuid(&init_user_ns, args->uid);
5919 if (gid_valid(args->gid))
5920 gid = from_kgid(&init_user_ns, args->gid);
5921
Jeff Layton654cf142009-07-09 20:02:49 -04005922 /*
5923 * Samba server ignores set of file size to zero due to bugs in some
5924 * older clients, but we should be precise - we use SetFileSize to
5925 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005926 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005927 * zero instead of -1 here
5928 */
5929 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5930 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5931 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5932 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5933 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005934 data_offset->Uid = cpu_to_le64(uid);
5935 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005936 /* better to leave device as zero when it is */
5937 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5938 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5939 data_offset->Permissions = cpu_to_le64(mode);
5940
5941 if (S_ISREG(mode))
5942 data_offset->Type = cpu_to_le32(UNIX_FILE);
5943 else if (S_ISDIR(mode))
5944 data_offset->Type = cpu_to_le32(UNIX_DIR);
5945 else if (S_ISLNK(mode))
5946 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5947 else if (S_ISCHR(mode))
5948 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5949 else if (S_ISBLK(mode))
5950 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5951 else if (S_ISFIFO(mode))
5952 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5953 else if (S_ISSOCK(mode))
5954 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5955}
5956
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005958CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005959 const struct cifs_unix_set_info_args *args,
5960 u16 fid, u32 pid_of_opener)
5961{
5962 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005963 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005964 int rc = 0;
5965 u16 params, param_offset, offset, byte_count, count;
5966
Joe Perchesf96637b2013-05-04 22:12:25 -05005967 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005968 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5969
5970 if (rc)
5971 return rc;
5972
5973 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5974 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5975
5976 params = 6;
5977 pSMB->MaxSetupCount = 0;
5978 pSMB->Reserved = 0;
5979 pSMB->Flags = 0;
5980 pSMB->Timeout = 0;
5981 pSMB->Reserved2 = 0;
5982 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5983 offset = param_offset + params;
5984
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005985 data_offset = (char *)pSMB +
5986 offsetof(struct smb_hdr, Protocol) + offset;
5987
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005988 count = sizeof(FILE_UNIX_BASIC_INFO);
5989
5990 pSMB->MaxParameterCount = cpu_to_le16(2);
5991 /* BB find max SMB PDU from sess */
5992 pSMB->MaxDataCount = cpu_to_le16(1000);
5993 pSMB->SetupCount = 1;
5994 pSMB->Reserved3 = 0;
5995 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5996 byte_count = 3 /* pad */ + params + count;
5997 pSMB->DataCount = cpu_to_le16(count);
5998 pSMB->ParameterCount = cpu_to_le16(params);
5999 pSMB->TotalDataCount = pSMB->DataCount;
6000 pSMB->TotalParameterCount = pSMB->ParameterCount;
6001 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6002 pSMB->DataOffset = cpu_to_le16(offset);
6003 pSMB->Fid = fid;
6004 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6005 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006006 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006007 pSMB->ByteCount = cpu_to_le16(byte_count);
6008
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006009 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006010
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006011 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006012 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006013 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006014 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6015 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006016
6017 /* Note: On -EAGAIN error only caller can retry on handle based calls
6018 since file handle passed in no longer valid */
6019
6020 return rc;
6021}
6022
6023int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006024CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006025 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006026 const struct cifs_unix_set_info_args *args,
6027 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028{
6029 TRANSACTION2_SPI_REQ *pSMB = NULL;
6030 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6031 int name_len;
6032 int rc = 0;
6033 int bytes_returned = 0;
6034 FILE_UNIX_BASIC_INFO *data_offset;
6035 __u16 params, param_offset, offset, count, byte_count;
6036
Joe Perchesf96637b2013-05-04 22:12:25 -05006037 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038setPermsRetry:
6039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6040 (void **) &pSMBr);
6041 if (rc)
6042 return rc;
6043
6044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6045 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006046 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006047 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 name_len++; /* trailing null */
6049 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006050 } else {
6051 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 }
6053
6054 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006055 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006057 /* BB find max SMB PDU from sess structure BB */
6058 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 pSMB->MaxSetupCount = 0;
6060 pSMB->Reserved = 0;
6061 pSMB->Flags = 0;
6062 pSMB->Timeout = 0;
6063 pSMB->Reserved2 = 0;
6064 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006065 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 offset = param_offset + params;
6067 data_offset =
6068 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6069 offset);
6070 memset(data_offset, 0, count);
6071 pSMB->DataOffset = cpu_to_le16(offset);
6072 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6073 pSMB->SetupCount = 1;
6074 pSMB->Reserved3 = 0;
6075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6076 byte_count = 3 /* pad */ + params + count;
6077 pSMB->ParameterCount = cpu_to_le16(params);
6078 pSMB->DataCount = cpu_to_le16(count);
6079 pSMB->TotalParameterCount = pSMB->ParameterCount;
6080 pSMB->TotalDataCount = pSMB->DataCount;
6081 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6082 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006083 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006084
Jeff Layton654cf142009-07-09 20:02:49 -04006085 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086
6087 pSMB->ByteCount = cpu_to_le16(byte_count);
6088 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6089 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006090 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006091 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092
Steve French0d817bc2008-05-22 02:02:03 +00006093 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 if (rc == -EAGAIN)
6095 goto setPermsRetry;
6096 return rc;
6097}
6098
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006100/*
6101 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6102 * function used by listxattr and getxattr type calls. When ea_name is set,
6103 * it looks for that attribute name and stuffs that value into the EAData
6104 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6105 * buffer. In both cases, the return value is either the length of the
6106 * resulting data or a negative error code. If EAData is a NULL pointer then
6107 * the data isn't copied to it, but the length is returned.
6108 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006110CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006111 const unsigned char *searchName, const unsigned char *ea_name,
6112 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006113 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114{
6115 /* BB assumes one setup word */
6116 TRANSACTION2_QPI_REQ *pSMB = NULL;
6117 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006118 int remap = cifs_remap(cifs_sb);
6119 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 int rc = 0;
6121 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006122 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006123 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006124 struct fea *temp_fea;
6125 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006126 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006127 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006128 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129
Joe Perchesf96637b2013-05-04 22:12:25 -05006130 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131QAllEAsRetry:
6132 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6133 (void **) &pSMBr);
6134 if (rc)
6135 return rc;
6136
6137 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006138 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006139 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6140 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006141 list_len++; /* trailing null */
6142 list_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006143 } else {
6144 list_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145 }
6146
Jeff Layton6e462b92010-02-10 16:18:26 -05006147 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148 pSMB->TotalDataCount = 0;
6149 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006150 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006151 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 pSMB->MaxSetupCount = 0;
6153 pSMB->Reserved = 0;
6154 pSMB->Flags = 0;
6155 pSMB->Timeout = 0;
6156 pSMB->Reserved2 = 0;
6157 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006158 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 pSMB->DataCount = 0;
6160 pSMB->DataOffset = 0;
6161 pSMB->SetupCount = 1;
6162 pSMB->Reserved3 = 0;
6163 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6164 byte_count = params + 1 /* pad */ ;
6165 pSMB->TotalParameterCount = cpu_to_le16(params);
6166 pSMB->ParameterCount = pSMB->TotalParameterCount;
6167 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6168 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006169 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170 pSMB->ByteCount = cpu_to_le16(byte_count);
6171
6172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6174 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006175 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006176 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178
6179
6180 /* BB also check enough total bytes returned */
6181 /* BB we need to improve the validity checking
6182 of these trans2 responses */
6183
6184 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006185 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006186 rc = -EIO; /* bad smb */
6187 goto QAllEAsOut;
6188 }
6189
6190 /* check that length of list is not more than bcc */
6191 /* check that each entry does not go beyond length
6192 of list */
6193 /* check that each element of each entry does not
6194 go beyond end of list */
6195 /* validate_trans2_offsets() */
6196 /* BB check if start of smb + data_offset > &bcc+ bcc */
6197
6198 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6199 ea_response_data = (struct fealist *)
6200 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6201
Jeff Layton6e462b92010-02-10 16:18:26 -05006202 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006203 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006204 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006205 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006206 /* didn't find the named attribute */
6207 if (ea_name)
6208 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006209 goto QAllEAsOut;
6210 }
6211
Jeff Layton0cd126b2010-02-10 16:18:26 -05006212 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006213 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006214 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006215 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006216 rc = -EIO;
6217 goto QAllEAsOut;
6218 }
6219
Jeff Laytonf0d38682010-02-10 16:18:26 -05006220 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006221 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006222 temp_fea = ea_response_data->list;
6223 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006224 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006225 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006226 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006227
Jeff Layton6e462b92010-02-10 16:18:26 -05006228 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006229 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006230 /* make sure we can read name_len and value_len */
6231 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006232 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006233 rc = -EIO;
6234 goto QAllEAsOut;
6235 }
6236
6237 name_len = temp_fea->name_len;
6238 value_len = le16_to_cpu(temp_fea->value_len);
6239 list_len -= name_len + 1 + value_len;
6240 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006241 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006242 rc = -EIO;
6243 goto QAllEAsOut;
6244 }
6245
Jeff Layton31c05192010-02-10 16:18:26 -05006246 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006247 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006248 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006249 temp_ptr += name_len + 1;
6250 rc = value_len;
6251 if (buf_size == 0)
6252 goto QAllEAsOut;
6253 if ((size_t)value_len > buf_size) {
6254 rc = -ERANGE;
6255 goto QAllEAsOut;
6256 }
6257 memcpy(EAData, temp_ptr, value_len);
6258 goto QAllEAsOut;
6259 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006260 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006261 /* account for prefix user. and trailing null */
6262 rc += (5 + 1 + name_len);
6263 if (rc < (int) buf_size) {
6264 memcpy(EAData, "user.", 5);
6265 EAData += 5;
6266 memcpy(EAData, temp_ptr, name_len);
6267 EAData += name_len;
6268 /* null terminate name */
6269 *EAData = 0;
6270 ++EAData;
6271 } else if (buf_size == 0) {
6272 /* skip copy - calc size only */
6273 } else {
6274 /* stop before overrun buffer */
6275 rc = -ERANGE;
6276 break;
6277 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006278 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006279 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006280 temp_fea = (struct fea *)temp_ptr;
6281 }
6282
Jeff Layton31c05192010-02-10 16:18:26 -05006283 /* didn't find the named attribute */
6284 if (ea_name)
6285 rc = -ENODATA;
6286
Jeff Laytonf0d38682010-02-10 16:18:26 -05006287QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006288 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 if (rc == -EAGAIN)
6290 goto QAllEAsRetry;
6291
6292 return (ssize_t)rc;
6293}
6294
Linus Torvalds1da177e2005-04-16 15:20:36 -07006295int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006296CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6297 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006298 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006299 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300{
6301 struct smb_com_transaction2_spi_req *pSMB = NULL;
6302 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6303 struct fealist *parm_data;
6304 int name_len;
6305 int rc = 0;
6306 int bytes_returned = 0;
6307 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006308 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309
Joe Perchesf96637b2013-05-04 22:12:25 -05006310 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311SetEARetry:
6312 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6313 (void **) &pSMBr);
6314 if (rc)
6315 return rc;
6316
6317 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6318 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006319 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6320 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 name_len++; /* trailing null */
6322 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006323 } else {
6324 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325 }
6326
6327 params = 6 + name_len;
6328
6329 /* done calculating parms using name_len of file name,
6330 now use name_len to calculate length of ea name
6331 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006332 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333 name_len = 0;
6334 else
Steve French50c2f752007-07-13 00:33:32 +00006335 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006337 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006339 /* BB find max SMB PDU from sess */
6340 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 pSMB->MaxSetupCount = 0;
6342 pSMB->Reserved = 0;
6343 pSMB->Flags = 0;
6344 pSMB->Timeout = 0;
6345 pSMB->Reserved2 = 0;
6346 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006347 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 offset = param_offset + params;
6349 pSMB->InformationLevel =
6350 cpu_to_le16(SMB_SET_FILE_EA);
6351
Arnd Bergmannade7db92018-02-02 16:48:47 +01006352 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6354 pSMB->DataOffset = cpu_to_le16(offset);
6355 pSMB->SetupCount = 1;
6356 pSMB->Reserved3 = 0;
6357 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6358 byte_count = 3 /* pad */ + params + count;
6359 pSMB->DataCount = cpu_to_le16(count);
6360 parm_data->list_len = cpu_to_le32(count);
6361 parm_data->list[0].EA_flags = 0;
6362 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006363 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006365 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006366 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 parm_data->list[0].name[name_len] = 0;
6368 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6369 /* caller ensures that ea_value_len is less than 64K but
6370 we need to ensure that it fits within the smb */
6371
Steve French50c2f752007-07-13 00:33:32 +00006372 /*BB add length check to see if it would fit in
6373 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006374 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6375 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006376 memcpy(parm_data->list[0].name+name_len+1,
6377 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378
6379 pSMB->TotalDataCount = pSMB->DataCount;
6380 pSMB->ParameterCount = cpu_to_le16(params);
6381 pSMB->TotalParameterCount = pSMB->ParameterCount;
6382 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006383 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384 pSMB->ByteCount = cpu_to_le16(byte_count);
6385 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6386 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006387 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006388 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389
6390 cifs_buf_release(pSMB);
6391
6392 if (rc == -EAGAIN)
6393 goto SetEARetry;
6394
6395 return rc;
6396}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397#endif